import os
import sys
import datetime
import xarray as xr
import pismx.open

# processed runs
PROC_RUNS = ['alpcyc4.2km.grip.0820', 'alpcyc4.2km.grip.1040.pp',
             'alpcyc4.2km.epica.0970', 'alpcyc4.2km.epica.1220.pp',
             'alpcyc4.2km.md012444.0800', 'alpcyc4.2km.md012444.1060.pp',
             'alpcyc4.1km.epica.1220.pp']

# global attributes
GLOB_ATTRS = dict(
    title='Alpine ice sheet deglaciation aggregated variables',
    author='Julien Seguinot',
    institution='ETH Zürich, Switzerland',
    command='{user}@{host} {time}: {cmdl}\n'.format(
        user=os.getlogin(), host=os.uname()[1], cmdl=' '.join(sys.argv),
        time=datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')),
    comment="""Aggregated dataset contents:
* Spatial variables aggregated in time corresponding to the last model output
before final deglaciation.
""")

def postprocess_extra(run_path):
    """Postprocess extra dataset for one run."""

    # output file and subtitle
    _, res, rec, *other = os.path.basename(run_path).split('.')
    out_file = 'processed/alpdeg.{}.{}.{}.agg.nc'.format(
        res, rec[:4], 'pp' if 'pp' in other else 'cp')

    # load output data (in the future combine='by_coords' will be the default)
    print("postprocessing " + out_file + "...")
    boot = pismx.open.dataset(
        '~/pism/input/boot/'+'alps.srtm.hus12.gou11simi.{}.nc'.format(res))
    ex = pismx.open.mfdataset(run_path+'/ex.???????.nc')

    # init postprocessed dataset with global attributes
    pp = xr.Dataset(attrs=ex.attrs, coords=dict(lon=ex.lon, lat=ex.lat))
    pp.attrs.update(
        subtitle='{} {} simulation {} precipitation reductions'.format(
            res, rec.upper(), 'with' if 'pp' in other else 'without'),
        **GLOB_ATTRS)
    pp.attrs.update(history=pp.command+pp.history)

    # compute grid size
    dt = ex.age[0] - ex.age[1]
    dt = dt*1e3  # convert ka to a

    # compute last ice cover transgressive variables
    idx = (ex.thk >= 1)[::-1].argmax(axis=0).compute()
    pp['deglacage'] = (ex.age[-idx].where(idx > 0)).assign_attrs(
        long_name='last ice cover age', units=ex.age.units)

    # compute last basal velocity transgressive variables
    # compute index first (xarray indexing with dask array issue #2511)
    idx = ((ex.thk >= 1)*(ex.velbase_mag >= 1))[::-1].argmax(axis=0).compute()
    pp['lastslipa'] = ex.age[-idx].where(idx > 0).assign_attrs(
        long_name='last basal velocity age', units=ex.age.units)
    pp['lastslipu'] = ex.uvelbase[-idx].where(idx > 0).assign_attrs(
        long_name='last basal velocity x-component', units=ex.uvelbase.units)
    pp['lastslipv'] = ex.vvelbase[-idx].where(idx > 0).assign_attrs(
        long_name='last basal velocity y-component', units=ex.vvelbase.units)
    pp.drop('time')

    # export to netcdf
    pp.to_netcdf(out_file, mode='w', encoding={var: dict(
        zlib=True, shuffle=True, complevel=1) for var in pp.variables})

    # close datasets
    boot.close()
    ex.close()
    pp.close()

def main():
    """Main program called during execution."""

    # create directory if missing
    if not os.path.exists('processed'):
        os.makedirs('processed')

    # activate dask client http://localhost:8787/status
    # from dask.distributed import Client
    # print(Client().scheduler_info()['services'])

    # postprocess selected runs
    for run in PROC_RUNS:
        postprocess_extra(os.environ['HOME'] + '/pism/output/e9d2d1f/' + run)

if __name__ == '__main__':
    main()


import pandas as pd
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier

data = pd.read_csv("studdent.csv")

feature = ["total","days"]

x = data[feature]
y = data["gender"]

model = DecisionTreeClassifier()
dtree = model.fit(x,y)
tree.plot_tree(dtree,feature_names=feature)


import time
import json
import random
import requests
from tqdm import tqdm
import pandas as pd
from bs4 import BeautifulSoup

'''
Workspace : Colab
It takes about 2 Hours 22 minutes to collect 300 reviews for each 10000 games.
get_n_appids(n=10000) takes about 15 minutes
more details in steam api 'reference' section in the readme.md

'''

def get_n_reviews(appid, n=300):
    '''
    Latest game reviews like Hades are not loaded.
    '''
    global reviews
    start = time.time()
    cursor = '*'
    params = {
            'json' : 1,
            'filter' : 'all',
            'language' : 'korean', #if you want english replace the parameter with 'english'.
            'day_range' : 9223372036854775807,
            'review_type' : 'all',
            'purchase_type' : 'all'
            }

    params['cursor'] = cursor.encode()
    params['num_per_page'] = 100

    while len(reviews) < n:
        url = 'https://store.steampowered.com/appreviews/'
        response = requests.get(url=url+str(appid), params=params, headers={'User-Agent': 'Mozilla/5.0'}).json()
        reviews += response['reviews']
        if len(response['reviews']) < 100:
            break
        params['cursor'] = response['cursor'].encode()
        time.sleep(random.random()+1) # for Max retries error

def get_n_appids(n=1000, mode='all'):
    '''
    mode = all, topselleres, etc..
    if mode == all : About 100K games can be viewd
    if mode == topsellers : only 3K games can be viewed

    '''
    appids = []
    if mode == 'all':
        url = f'https://store.steampowered.com/search/?&page='
    if mode == 'topselleres':
        url = f'https://store.steampowered.com/search/?category1=998&filter={mode}&page='
    page = 1

    while page*25 < n:
        start = time.time()
        page += 1
        response = requests.get(url=url+str(page), headers={'User-Agent': 'Mozilla/5.0'})
        soup = BeautifulSoup(response.text, 'html.parser')
        for row in soup.find_all(class_='search_result_row'):
            try:
                app_id = int(row['data-ds-appid'])
                #If the game has dlc, multiple lists are created here
            except ValueError:
                app_id = int(row['data-ds-appid'][0])
            except KeyError:
                app_id = int(json.loads(row['data-ds-bundle-data'])['m_rgItems'][0]['m_rgIncludedAppIDs'][0])
            appids.append(app_id)

        time.sleep(random.random()+1) # for Max retries error

        if page==2:
            print(f'only one loop spending time :{time.time()-start}')

    return appids[:n]

if __name__ == '__main__':

    #It takes about 24 minutes to load a list of 10K games.
    app_ids = get_n_appids(n=10000)

    reviews = []
    user_ids = []
    game_ids = []
    num_games = []
    num_reviews = []
    play_times = []
    ratings = []
    vote_conf = []
    weights = []
    game_reviews = []

    for game_id in tqdm(app_ids[:3000]):
        get_n_reviews(game_id) #make reviews

        #print(f'Complete {i}th game review collection')

        if len(reviews) == 0:
            continue

        #start = time.time()
        for idx in range(len(reviews)):
            user_ids.append(reviews[idx]['author']['steamid'])
            game_ids.append(game_id)
            try:
                play_times.append(reviews[idx]['author']['playtime_at_review'])
            except KeyError:
                '''
                many game reivews have no 'playtime_at_review' property
                in this caes replace playtime_at_review -> playtime_forever
                '''
                play_times.append(reviews[idx]['author']['playtime_forever'])
            num_games.append(reviews[idx]['author']['num_games_owned'])
            num_reviews.append(reviews[idx]['author']['num_reviews'])
            ratings.append(1 if reviews[idx]['voted_up'] else 0)
            vote_conf.append(int(reviews[idx]['votes_up']) + int(reviews[idx]['votes_funny']))
            weights.append(reviews[idx]['weighted_vote_score'])
            game_reviews.append(reviews[idx]['review'])

        reviews = [] #global variable initialization
        #print(f'inner loop spending time : {time.time()-start}')

    steam_ratings = pd.DataFrame({'user_ids':user_ids,
                              'game_ids':game_ids,
                              'num_games_owned':num_games,
                              'num_reviews':num_reviews,
                              'play_times':play_times,
                              'ratings':ratings,
                              'vote_conf':vote_conf,
                              'weights':weights,
                              'game_reviews':game_reviews})
    steam_ratings.to_csv('ratings.csv', encoding='utf-8-sig')


# Question:

# Given an n x n matrix where each of the rows and columns is sorted in ascending order, return the kth smallest element in the matrix.

# Note that it is the kth smallest element in the sorted order, not the kth distinct element.

# You must find a solution with a memory complexity better than O(n2).

# Input: matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
# Output: 13
# Explanation: The elements in the matrix are [1,5,9,10,11,12,13,13,15], and the 8th smallest number is 13

matrix = [[-5]]
k = 1
a = []
for i in matrix:
    for j in i:
        a.append(j)
sorted(a)[k-1]

378. Kth Smallest Element in a Sorted Matrix(DC).py


'''borf.borf: for running borf'''

import argparse
import os
import sys
import re
from Bio import SeqIO
import pandas as pd
from .get_orfs import get_orfs, write_orf_fasta, write_orf_data, write_orf_cds, batch_iterator

def main():

    parser = argparse.ArgumentParser(description='Get orf predicitions from a nucleotide fasta file')

    parser.add_argument('Fasta', metavar='fasta_file', type=str, help='fasta file to predict ORFs')
    parser.add_argument('-o', '--output_path', type=str, help='path to write output files. [OUTPUT_PATH].pep and [OUTPUT_PATH].txt (default: input .fa file name)')
    parser.add_argument('-s', '--strand', action='store_true', help='Predict orfs for both strands')
    parser.add_argument('-a', '--all_orfs', action='store_true', help='Return all ORFs for each sequence longer than the cutoff')
    parser.add_argument('-l', '--orf_length', type=int, default=100, help='Minimum ORF length (AA). (default: %(default)d)')
    parser.add_argument('-u', '--upstream_incomplete_length', type=int, default=50, help='Minimum length (AA) of uninterupted sequence upstream of ORF to be included for incomplete_5prime transcripts (default: %(default)d)')
    parser.add_argument('-c', '--genetic_code', type=int, default=1, help='Genetic code (int: 1-14) to use for translation (default: %(default)d). See https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi for list')
    parser.add_argument('-b', '--batch_size', type=int, default=10000, help='Number of fasta records to read in in each batch')
    parser.add_argument('-f', '--force_overwrite', action='store_true', help='Force overwriting of output files?')

    args = parser.parse_args()

    input_file = args.Fasta

    if args.output_path is None:
        output_path = os.path.splitext(input_file)[0]
    else:
        output_path = args.output_path

    output_path_pep = output_path + '.pep'
    output_path_txt = output_path + '.txt'
    output_path_cds = output_path + '.cds'

    # check if files exist already
    if os.path.isfile(output_path_pep) or os.path.isfile(output_path_txt) or os.path.isfile(output_path_cds):

        if os.path.isfile(output_path_pep) and os.path.isfile(output_path_txt) and os.path.isfile(output_path_cds):
             print(output_path_pep + ", " + output_path_txt + " and " + output_path_cds  + " already exist")
        elif os.path.isfile(output_path_pep) and os.path.isfile(output_path_txt):
             print(output_path_pep + " and " + output_path_txt + " already exist")
        elif os.path.isfile(output_path_pep) and os.path.isfile(output_path_cds):
             print(output_path_pep + " and " + output_path_cds + " already exist")
        elif os.path.isfile(output_path_cds) and os.path.isfile(output_path_txt):
             print(output_path_txt + " and " + output_path_cds + " already exist")
        elif os.path.isfile(output_path_pep):
            print(output_path_pep + " already exists")
        elif os.path.isfile(output_path_cds):
            print(output_path_cds + " already exists")
        else:
            print(output_path_txt + " already exists")

        if not args.force_overwrite:
            overwrite = input("Do you want to overwrite these files? ([Y]/n): ").lower().strip()[:1]
            if not (overwrite == "y" or overwrite == ""):
                sys.exit(1)
            else:
                # remove old files so you don't append new data to old files
                if os.path.isfile(output_path_pep):
                    os.remove(output_path_pep)
                if os.path.isfile(output_path_txt):
                    os.remove(output_path_txt)
                if os.path.isfile(output_path_cds):
                    os.remove(output_path_cds)
        else:
            print('Overwriting files')
            if os.path.isfile(output_path_pep):
                os.remove(output_path_pep)
            if os.path.isfile(output_path_txt):
                os.remove(output_path_txt)
            if os.path.isfile(output_path_cds):
                os.remove(output_path_cds)

    # number of sequences
    n_seqs = 0
    for record in SeqIO.parse(input_file, 'fasta'):
        n_seqs += 1

    batch_size = args.batch_size

    record_iter = SeqIO.parse(open(input_file), 'fasta')

    strand_warning = False
    for i, batch in enumerate(batch_iterator(record_iter, batch_size)):
        all_sequences = []
        for record in batch:
            all_sequences.append(record.upper())

        if i == 0:
            # check strandedness

            orf_data = get_orfs(all_sequences, both_strands=True,
                                min_orf_length=args.orf_length, all_orfs=True,
                                min_upstream_length=args.upstream_incomplete_length,
                                genetic_code=args.genetic_code)

            orf_data_strand_bias = orf_data.sort_values(by='orf_length', ascending = False)
            orf_data_strand_bias = orf_data_strand_bias.drop_duplicates('id', keep='first')

            if len(orf_data_strand_bias) >= 10:

                pos_bias = (orf_data_strand_bias['strand'][orf_data_strand_bias['orf_class'] == "complete"] == "+").sum()
                neg_bias = (orf_data_strand_bias['strand'][orf_data_strand_bias['orf_class'] == "complete"] == "-").sum()
                positive_strand_bias = pos_bias / (pos_bias+neg_bias)

                if positive_strand_bias > 0.7 and args.strand == True:
                    #data is likely from a stranded assembly.
                    print("Are you sure your input .fasta file isn't stranded?")
                    print(str(positive_strand_bias*100)+ "% of transcripts have the longest ORF on the + strand")
                    strand_warning = True

                if positive_strand_bias <= 0.7 and args.strand == False:
                    print("Are you sure your input .fasta file is stranded?")
                    print(str(positive_strand_bias*100)+ "% of transcripts have the longest ORF on the + strand")
                    strand_warning = True

            if args.strand == False:
                orf_data = orf_data[orf_data['strand'] == '+']
            if args.all_orfs == False:
                idx = orf_data.groupby(['id'])['orf_length'].transform(max) == orf_data['orf_length']
                orf_data = orf_data[idx]
                orf_data['isoform_number'] = 1
                orf_data['fasta_id'] = [re.sub("[.]orf[0-9]*",".orf1", x) for x in orf_data['fasta_id']]

        else:
            orf_data = get_orfs(all_sequences, both_strands=args.strand,
                                min_orf_length=args.orf_length, all_orfs=args.all_orfs,
                                min_upstream_length=args.upstream_incomplete_length,
                                genetic_code=args.genetic_code)

        # extract nt seqs at CDS
        nucleotide_seq = []
        nucleotide_id = []
        for seq_string in all_sequences:
            nucleotide_seq.append(str(seq_string.seq))
            nucleotide_id.append(str(seq_string.id))
        seq_df = pd.DataFrame(list(zip(nucleotide_id, nucleotide_seq)), columns=['id', 'nt_seq'])

        # merge orfs with all_sequences
        orf_data = pd.merge(seq_df, orf_data,  on='id', how='right')
        orf_data['cds_seq'] = orf_data.apply(lambda x: x['nt_seq'][(x['start_site_nt']-1):x['stop_site_nt']], axis=1)

        write_orf_data(orf_data, output_path_txt)
        write_orf_fasta(orf_data, output_path_pep)
        write_orf_cds(orf_data, output_path_cds)

        start_seq_n = (i*batch_size) + 1
        end_seq_n = min(start_seq_n + (batch_size - 1), n_seqs)
        print("Processed sequences " + str(start_seq_n) + " to " + str(end_seq_n) + " of " + str(n_seqs))

    print("Done with borf.")
    print("Results in " + output_path_pep + " and " + output_path_txt + " and " + output_path_cds)

    if strand_warning == True:
        print("This data caused a warning based on strandedness. Please check the top of the log for details and rerun with appropriate flags if neccessary.")


import os
import sys
import time

from PIL import Image, ImageDraw, ImageFont

from cuars import faces
import adargb

io = adargb.BoardIO()
display = adargb.Display(135, 240)

table = faces.Table(240, 135, os.listdir(os.getcwd()))
font = ImageFont.truetype("fonts/BebasNeue.otf", 22)
image = Image.new("RGB", (240, 135))
draw = ImageDraw.Draw(image)

def main():
    print("Interface should appear on the RGB display now")
    while True:
        # Display image.
        for badge in table.badges:
            rect = (badge.x, badge.y,
                    badge.x + badge.width, badge.y + badge.height)
            bgcolor, color = badge.bgcolor, badge.color
            name = badge.name
            draw.rectangle(rect, outline=bgcolor, fill=bgcolor)
            draw.text(rect, name, font=font, fill=color)
        display.show(image, 270)
        # Accept input
        if not io.B.value and not io.A.value:  # both buttons pressed
            print("restart")
        elif io.B.value and not io.A.value:  # button 1 pressed
            print("select")
        elif io.A.value and not io.B.value:  # button 2 pressed
            print("start")
        # Wait for refresh
        time.sleep(0.1)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("Keyboard Interrupt (Control-C)...")
    io.backlight.value = not io.backlight.value
    sys.exit()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def dfs(self, root: TreeNode, k: int):
        v = True
        cnt = 1
        if root.left:
            r = self.dfs(root.left, k)
            cnt += r[1]
            if (r[0] != None):
                return r
            else:
                k -= r[1]

        if k<=1:
            return [root.val, cnt]
        k -= 1

        if root.right:
            r =  self.dfs(root.right, k)
            if (r[0] != None):
                return r
            else:
                k -= r[1]
                cnt += r[1]
        return [None, cnt]

    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        r = self.dfs(root,k)
        return r[0]

kth-smallest-element-in-a-bst/2022-07-06 19.34.54 - Accepted - runtime 80ms - memory 18MB.py


import math
#solution too slow, but you can check up online for dynamic programming or even better, binary search
class Solution:
    def isPrime(self, n: int) -> bool:
        prime_flag = 0
        if(n > 1):
            for i in range(2, int(math.sqrt(n)) + 1):
                if (n % i == 0):
                    prime_flag = 1
                    break
            if (prime_flag == 0):
                return True
            else:
                return False
        else:
            return False
    def nthUglyNumber(self, n: int) -> int:
        if n == 1: return 1
        if n == 2: return 2
        if n == 3: return 3
        if n == 4: return 4
        if n == 5: return 5
        if n == 6: return 6
        count = 6
        i = 7
        while count < n:
            i += 1
            add = True
            for j in range(7, i//2+1):
                if self.isPrime(j):
                    if i % j == 0:
                        add = False
                        break
            if add and not self.isPrime(i):
                count += 1
        return i

#tests
solution = Solution()
print(solution.nthUglyNumber(124))

LeetCode/2Medium/python/264. Ugly Number II.py


print("Welcome to the Love Calculator!")
name1 = input("What is your name? \n")
name2 = input("What is their name? \n")
name = name1.lower() + name2.lower()
count_t = int(name.count("t"))
count_r = int(name.count("r"))
count_u = int(name.count("u"))
count_e = int(name.count("e"))
count_l = int(name.count("l"))
count_o = int(name.count("o"))
count_v = int(name.count("v"))
percent = str(count_t + count_r + count_u + count_e) + str(count_l + count_o + count_v + count_e)
if int(percent) > 100:
  print("your score is 100%' you go together like fufu and eru")

else:
  if int(percent) < 10 or int(percent) >90:
    print("Your Score is " + percent+"%," + "you go togehter like coke and mentos")
  elif int(percent) > 40 and int(percent) <50:
    print("your score is " + percent + "%," + " you are alright together")
  else:
    print("your score is" + percent +" %")


import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 16, 2, 1)
        self.conv2 = nn.Conv2d(16, 32, 2, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(18432, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = nn.ReLU()(x)
        x = nn.MaxPool2d(2, 1)(x)
        x = self.dropout1(x)
        x = self.conv2(x)
        x = nn.ReLU()(x)
        x = nn.MaxPool2d(2, 1)(x)
        x = self.dropout2(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = nn.ReLU()(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output

class Mclr_Logistic(nn.Module):
    def __init__(self, input_dim = 784, output_dim = 10):
        super(Mclr_Logistic, self).__init__()
        self.fc1 = nn.Linear(input_dim, output_dim)

    def forward(self, x):
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        output = F.log_softmax(x, dim=1)
        return output

class Mclr_CrossEntropy(nn.Module):
    def __init__(self, input_dim = 784, output_dim = 10):
        super(Mclr_CrossEntropy, self).__init__()
        self.linear = torch.nn.Linear(input_dim, output_dim)

    def forward(self, x):
        x = torch.flatten(x, 1)
        outputs = self.linear(x)
        return outputs

class DNN(nn.Module):
    def __init__(self, input_dim = 784, mid_dim = 100, output_dim = 10):
        super(DNN, self).__init__()
        # define network layers
        self.fc1 = nn.Linear(input_dim, mid_dim)
        self.fc2 = nn.Linear(mid_dim, output_dim)

    def forward(self, x):
        # define forward pass
        x = torch.flatten(x, 1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        x = F.log_softmax(x, dim=1)
        return x

class CifarNet(nn.Module):
    def __init__(self):
        super(CifarNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return F.log_softmax(x, dim=1)

#################################
##### Neural Network model #####
#################################

cfg = {
    'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}

class VGG(nn.Module):
    def __init__(self, vgg_name):
        super(VGG, self).__init__()
        self.features = self._make_layers(cfg[vgg_name])
        self.classifier = nn.Sequential(
            nn.Linear(512, 512),
            nn.ReLU(True),
            nn.Linear(512, 512),
            nn.ReLU(True),
            nn.Linear(512, 10)
        )

    def forward(self, x):
        out = self.features(x)
        out = out.view(out.size(0), -1)
        out = self.classifier(out)
        output = F.log_softmax(out, dim=1)
        return output

    def _make_layers(self, cfg):
        layers = []
        in_channels = 3
        for x in cfg:
            if x == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            else:
                layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
                           nn.BatchNorm2d(x),
                           nn.ReLU(inplace=True)]
                in_channels = x
        layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
        return nn.Sequential(*layers)

class CNNCifar(nn.Module):
    def __init__(self, num_classes):
        super(CNNCifar, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 100)
        self.fc3 = nn.Linear(100, num_classes)

        self.weight_keys = [['fc1.weight', 'fc1.bias'],
                            ['fc2.weight', 'fc2.bias'],
                            ['fc3.weight', 'fc3.bias'],
                            ['conv2.weight', 'conv2.bias'],
                            ['conv1.weight', 'conv1.bias'],
                            ]

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return F.log_softmax(x, dim=1)


import math
import torch
import torch.nn as nn

from fairseq.data.data_utils import collate_tokens
from transformers import BartTokenizer

class ConditionalSequenceGenerator:
    """Conditional sequence generator for calculating prior and posterior probability."""
    def __init__(self, bart):
        self.bart = bart
        self.tokenizer = BartTokenizer.from_pretrained("facebook/bart-large", local_files_only=False)

        self.encode_func = bart.encode
        self.decode_func = bart.decode
        self.max_positions = bart.max_positions
        if type(self.max_positions) == int:
            self.max_positions = [self.max_positions]
        self.encode_line = bart.task.source_dictionary.encode_line

        self._initialize()

    def _initialize(self):
        """Set BART model to evaluation mode."""
        self.bart.cuda()
        self.bart.eval()
        self.bart.half()

    def tokenize_target(self, input_str, left_pad=False, append_eos=False):
        """BPE-encode a sentence (or multiple sentences).

        Args:
            input_str (str or List[str]): input sentence to be tokenized.
            left_pad (bool): self-explained.

        Return:
            prev_output_tokens (torch.Tensor): [batch_size, length]
            target (torch.Tensor): [batch_size, length]
            tgt_lengths (torch.Tensor): [batch_size]

        """
        if type(input_str) == type(''):
            input_str = [input_str]

        prev_ids, tgt_ids = [], []

        for ins in input_str:
            tokens = self.bart.bpe.encode(ins)  # <mask>: 1279 27932 29
            calibration = 1
            if len(tokens.split(" ")) > min(self.max_positions) - calibration:
                tokens = " ".join(tokens.split(" ")[: min(self.max_positions) - calibration])

            if append_eos:
                tokens = "<s> " + tokens
            prev_tokens = "</s> " + tokens
            tgt_tokens = tokens + " </s>"

            tgt_ids.append(self.encode_line(tgt_tokens, append_eos=False).long())
            prev_ids.append(self.encode_line(prev_tokens, append_eos=False).long())

        prev_output_tokens = collate_tokens(prev_ids, pad_idx=1, left_pad=left_pad).cuda()
        target = collate_tokens(tgt_ids, pad_idx=1, left_pad=left_pad).cuda()
        tgt_lengths = torch.sum(target != 1, dim=1).cuda()

        return prev_output_tokens, target, tgt_lengths

    def tokenize(self, input_str, append_bos=False, append_eos=True, left_pad=True):
        """BPE-encode a sentence (or multiple sentences).

        Args:
            input_str (str or List[str]): input sentence to be tokenized.
            append_bos (bool): self-explained.
            append_eos (bool): self-explained.

        Return:
            input_ids (torch.Tensor): [batch_size, length]
            src_lengths (torch.Tensor): [batch_size]
        """
        if type(input_str) == type(''):
            input_str = [input_str]

        input_ids = []
        for ins in input_str:
            tokens = self.bart.bpe.encode(ins)  # <mask>: 1279 27932 29
            calibration = sum([append_bos, append_eos])
            if len(tokens.split(" ")) > min(self.max_positions) - calibration:
                tokens = " ".join(tokens.split(" ")[: min(self.max_positions) - calibration])

            tokens = "<s> " + tokens if append_bos else tokens
            tokens = tokens + " </s>" if append_eos else tokens
            ids = self.encode_line(tokens, append_eos=False).long()
            input_ids.append(ids)

        input_ids = collate_tokens(input_ids, pad_idx=1, left_pad=left_pad).cuda()
        input_lengths = torch.sum(input_ids != 1, dim=1).cuda()

        return input_ids, input_lengths

    def tokenize_with_mask(self, input_str):
        """Tokenize sentence with a special <mask> token in it.

        Args:
            input_str (str or List[str]): input sentence to be tokenized.

        Return:
            input_ids (torch.Tensor): [batch_size, length]
            src_lengths (torch.Tensor): [batch_size]
        """
        input_ids = self.tokenizer(input_str, return_tensors='pt', padding=True)['input_ids'].cuda()
        input_lengths = torch.sum(input_ids != 1, dim=1).cuda()
        return input_ids, input_lengths

    def encode_decode(self, src_input, tgt_input, mask_filling=False):
        """
        Args:
            src_input: (List[str])
            tgt_input: (List[str])

        """
        if mask_filling:
            src_tokens, src_lengths = self.tokenize_with_mask(src_input)
            prev_output_tokens, target, tgt_lengths = self.tokenize_target(tgt_input, left_pad=False, append_eos=True)
        else:
            src_tokens, src_lengths = self.tokenize(src_input, append_bos=False)
            prev_output_tokens, target, tgt_lengths = self.tokenize_target(tgt_input, left_pad=False)

        with torch.no_grad():
            encoder_out = self.bart.model.encoder(src_tokens, src_lengths=src_lengths)
            decoder_out = self.bart.model.decoder(prev_output_tokens, encoder_out=encoder_out, features_only=False)

            probs = nn.functional.softmax(decoder_out[0], dim=-1)
            tgt_token_probs = torch.gather(probs, 2, target.unsqueeze(-1)).squeeze(2)

            # mask <pad> with probability 1.0
            max_tgt_length = tgt_lengths.max().item()
            tgt_lengths = tgt_lengths - 1
            tgt_mask = torch.arange(max_tgt_length)[None, :].cuda() < tgt_lengths[:, None]
            tgt_token_probs.masked_fill_(tgt_mask == False, 1.0)

        return tgt_token_probs, target

    def generate(self, src_input, tgt_input=None):
        """Conditional generation.

        Args:
            src_input (str or List[str]): input source sentence to be tokenized.
            tgt_input (str or List[str]): input target sentence to be tokenized.
        """
        input_ids, lengths = self.tokenize(src_input, append_bos=False)

        target_ids = None
        if tgt_input is not None:
            assert len(src_input) == len(tgt_input), "source & target length should match."
            target_ids, _ = self.tokenize(tgt_input, append_bos=False, left_pad=False)

        with torch.no_grad():
            encoder_output = self.encode_sequence(input_ids, lengths)
            decoder_output = self.decode_sequence(encoder_output,
                                                  target_ids=target_ids,
                                                  prefix_tokens=[2])
        return decoder_output

    def mask_filling(self, src_input, tgt_input=None):
        """
        Filling the mask in sentence(s).
        """
        input_ids, lengths = self.tokenize_with_mask(src_input)

        target_ids = None
        if tgt_input is not None:
            assert len(src_input) == len(tgt_input), "source & target length should match."
            target_ids, _ = self.tokenize(tgt_input, left_pad=False)

        with torch.no_grad():
            encoder_output = self.encode_sequence(input_ids, lengths)
            decoder_output = self.decode_sequence(encoder_output,
                                                  target_ids=target_ids,
                                                  prefix_tokens=[2, 0])
        return decoder_output

    def encode_sequence(self, input_ids, lengths):
        return self.bart.model.encoder(input_ids, src_lengths=lengths)

    def decode_sequence(
        self,
        encoder_out,
        target_ids=None,
        min_decode_step=3,
        max_decode_step=100,
        pad_id=1,
        eos_id=2,
        prefix_tokens=[2, 0],
    ):
        batch_size = encoder_out['encoder_padding_mask'][0].shape[0]
        init_input = torch.tensor([prefix_tokens] * batch_size, dtype=torch.long).cuda()
        token_probs, tokens = None, [[] for i in range(batch_size)]
        end_mask = torch.tensor([False] * batch_size).cuda()

        softmax = nn.Softmax(dim=1)
        for step in range(max_decode_step):
            decoder_outputs = self.bart.model.decoder(init_input, encoder_out, features_only=False)
            logits = decoder_outputs[0][:, -1, :]  # logits: [batch_size, vocab]
            attn = decoder_outputs[1]['attn'][0]  # [batch_size, prev_token_len, src_token_len]

            if step + 1 < min_decode_step:
                logits[:, eos_id] = -math.inf  # mask <EOS> token when within minimal step
            logits[:, pad_id], logits[:, 0] = -math.inf, -math.inf  # never select <PAD> & <BOS> token
            probs = softmax(logits)  # probs: [batch_size, vocab]

            # select tokens
            if target_ids is not None:
                selected_token = target_ids[:, step]
            else:
                value, indices = torch.topk(probs, 5, dim=1)
                selected_token = indices[:, 0]

            selected_token = selected_token.masked_fill(end_mask, pad_id)
            init_input = torch.cat([init_input, selected_token.unsqueeze(1)], dim=-1)

            probs = torch.gather(probs, 1, selected_token.unsqueeze(1)).detach()
            probs = probs.masked_fill(end_mask.unsqueeze(1), 1.0)

            # str & probability
            token_probs = probs if token_probs is None else torch.cat([token_probs, probs], dim=-1)
            for t, s in zip(tokens, selected_token):
                t.append(self.decode_func(s.unsqueeze(0)) if s.item() != pad_id else '<pad>')

            # stop generation when all finished
            end_mask = torch.logical_or(end_mask, selected_token == eos_id)
            if end_mask.sum().item() == batch_size:
                break

        return init_input, tokens, token_probs


from typing import Any, Dict, Type, TypeVar, Union

import attr

from ..types import UNSET, Unset

T = TypeVar("T", bound="CodatPublicApiModelsClientsBankingSettingsModelsBankIntegration")

@attr.s(auto_attribs=True)
class CodatPublicApiModelsClientsBankingSettingsModelsBankIntegration:
    """
    Attributes:
        name (Union[Unset, None, str]):
        integration_guid (Union[Unset, None, str]):
        selected (Union[Unset, bool]):
    """

    name: Union[Unset, None, str] = UNSET
    integration_guid: Union[Unset, None, str] = UNSET
    selected: Union[Unset, bool] = UNSET

    def to_dict(self) -> Dict[str, Any]:
        name = self.name
        integration_guid = self.integration_guid
        selected = self.selected

        field_dict: Dict[str, Any] = {}
        field_dict.update({})
        if name is not UNSET:
            field_dict["name"] = name
        if integration_guid is not UNSET:
            field_dict["integrationGuid"] = integration_guid
        if selected is not UNSET:
            field_dict["selected"] = selected

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        name = d.pop("name", UNSET)

        integration_guid = d.pop("integrationGuid", UNSET)

        selected = d.pop("selected", UNSET)

        codat_public_api_models_clients_banking_settings_models_bank_integration = cls(
            name=name,
            integration_guid=integration_guid,
            selected=selected,
        )

        return codat_public_api_models_clients_banking_settings_models_bank_integration


from swagger_server.models import AgeGroup, Image, LanguageSpec, Phone, UserId
from swagger_server.models.age_group import AgeGroupEnum
from swagger_server.models.language_spec import LanguageSpecEnum
from swagger_server.repository.user import User

import random
from typing import List, Optional, Tuple

u1 = User(id=1, age_group=AgeGroupEnum.G_18, language=LanguageSpecEnum.RU_RU, image="", name="1", phone="")  # our user

u2 = User(id=2, age_group=AgeGroupEnum.G_18_25, language=LanguageSpecEnum.RU_RU, image="", name="2", phone="")
u3 = User(id=3, age_group=AgeGroupEnum.G_26_35, language=LanguageSpecEnum.EN_US, image="", name="3", phone="")
u4 = User(id=4, age_group=AgeGroupEnum.G_36_45, language=LanguageSpecEnum.FR_FR, image="", name="4", phone="")

partners = [u2, u3, u4]

Score = int

def age_to_scale(age: AgeGroupEnum) -> Score:
    scale = {
        AgeGroupEnum.G_18: 1,
        AgeGroupEnum.G_18_25: 2,
        AgeGroupEnum.G_26_35: 3,
        AgeGroupEnum.G_36_45: 4,
        AgeGroupEnum.G_45: 5,
    }
    return scale[age]

def age_score(lhs: AgeGroupEnum, rhs: AgeGroupEnum) -> Score:
    """
    :return: Score in range 0..4
    """
    lhs_scale = age_to_scale(lhs)
    rhs_scale = age_to_scale(rhs)
    return abs(lhs_scale - rhs_scale)

def language_score(lhs: LanguageSpecEnum, rhs: LanguageSpecEnum) -> Score:
    """
    :return: Score in range 0..3
    """
    if lhs == rhs:
        return 0
    else:
        return 3

BEST_SCORE: Score = age_score(AgeGroupEnum.G_18, AgeGroupEnum.G_18) \
                    + language_score(LanguageSpecEnum.RU_RU, LanguageSpecEnum.RU_RU)

WORST_SCORE: Score = age_score(AgeGroupEnum.G_18, AgeGroupEnum.G_45) \
                     + language_score(LanguageSpecEnum.RU_RU, LanguageSpecEnum.EN_US)

def match_users(user: User, online: List[User]) -> Optional[Tuple[User, Score]]:
    """
    Match users based on heuristic score. The less the score -- the better.

    :param user: current user
    :param online: other users
    :return:
    """
    online = [u for u in online if u.id != user.id]  # sanity check

    if len(online) == 0:
        return None

    scores = [0] * len(online)
    for i in range(len(online)):
        scores[i] += age_score(user.age_group, online[i].age_group)
        scores[i] += language_score(user.language, online[i].language)

    best_score = min(scores)
    bestest = [idx for idx, score in enumerate(scores) if score == best_score]

    assert len(bestest) != 0, "should never happen"
    lucky_idx = random.choice(bestest)

    lucky_user = online[lucky_idx]
    return lucky_user, best_score

print(match_users(u1, partners))


#!/usr/bin/env python3

def psfstudy(band_path, ztfname, filtercode, logger, args):
    import pathlib
    import gc
    import traceback

    import numpy as np
    from numpy.polynomial.polynomial import Polynomial
    import matplotlib.pyplot as plt
    import matplotlib
    from matplotlib.cm import ScalarMappable
    from matplotlib.colorbar import Colorbar
    from saunerie.plottools import binplot
    import pandas as pd
    from dask import delayed, compute

    from deppol_utils import quadrants_from_band_path
    from utils import get_header_from_quadrant_path, plot_ztf_focal_plan_values, ListTable, match_by_gaia_catalogs, quadrant_name_explode, match_to_gaia

    matplotlib.use('Agg')

    output_path = band_path.joinpath("psfstudy")
    output_path.mkdir(exist_ok=True)

    quadrant_paths = quadrants_from_band_path(band_path, logger)

    # Remove bad QC quadrants
    def _quadrant_good(quadrant_path):
        if not quadrant_path.joinpath("match_gaia.success").exists():
            return False

        if len(ListTable.from_filename(quadrant_path.joinpath("psfstars.list")).df) < 150:
            return False

        return True

    print("Found {} quadrants".format(len(quadrant_paths)))
    # quadrant_paths = list(filter(_quadrant_good, quadrant_paths))
    # print("After QC: {}".format(len(quadrant_paths)))

    min_mag, max_mag = 13., 19.
    low_bin, high_bin = 14, 17

    def _process_quadrant(quadrant_path, cat1, cat2):
        def _cat_to_name(cat):
            if cat == 'flux':
                return "PSF"
            else:
                return "Aperture-" + cat[-1]

        def _is_aperture(cat):
            return 'apfl' in cat

        def _get_cat_from_name(cat, refexp=None):
            path = quadrant_path
            if refexp:
                path = quadrant_path.with_name(refexp + quadrant_path.name[28:])

            if cat == 'flux':
                with pd.HDFStore(path.joinpath("matched_stars.hd5")) as hdfstore:
                    cat_df = hdfstore.get('/matched_stars')
            else:
                cat_df = ListTable.from_filename(path.joinpath("standalone_stars.list")).df

            return cat_df

        def _get_gaia_cat(refexp=None):
            path = quadrant_path
            if refexp:
                path = quadrant_path.with_name(refexp + quadrant_path.name[28:])

            with pd.HDFStore(path.joinpath("matched_stars.hd5")) as hdfstore:
                cat_gaia_df = hdfstore.get('/matched_gaia_stars')

            return cat_gaia_df

        if not _quadrant_good(quadrant_path):
            return

        try:
            refexp = None
            if cat1[:3] == 'ref':
                refexp = args.refexp
                cat1 = cat1[3:]

            quadrant_header = get_header_from_quadrant_path(quadrant_path)
            expid = int(quadrant_header['expid'])
            mjd = float(quadrant_header['obsmjd'])
            ccdid = int(quadrant_header['ccdid'])
            qid = int(quadrant_header['qid'])
            skylev = float(quadrant_header['sexsky'])
            moonillf = float(quadrant_header['moonillf'])
            seeing = float(quadrant_header['seeing'])
            airmass = float(quadrant_header['airmass'])

            year, month, day, _, _, ccdid, qid = quadrant_name_explode(quadrant_path.name)

            exposure_output_path = output_path.joinpath("{}-{}-{}-{}".format(year, month, day, expid))
            exposure_output_path.mkdir(exist_ok=True)

            # First load catalogs
            cat1_df = _get_cat_from_name(cat1, refexp=refexp)
            cat2_df = _get_cat_from_name(cat2)

            if refexp:
                cat1_gaia_df = _get_gaia_cat(refexp)
                cat2_gaia_df = _get_gaia_cat()
            else:
                cat1_gaia_df = _get_gaia_cat()
                cat2_gaia_df = cat1_gaia_df

            if _is_aperture(cat1):
                cat1_df['gaiaid'] = match_to_gaia(cat1_df, cat1_gaia_df)

            if _is_aperture(cat2):
                cat2_df['gaiaid'] = match_to_gaia(cat2_df, cat2_gaia_df)

            # Match catalogs to Gaia
            # i = match_pixel_space(cat_gaia_df[['x', 'y']].to_records(), cat2_df[['x', 'y']].to_records(), radius=1.)

            # cat2_df = cat2_df.iloc[i[i>=0]].reset_index(drop=True)
            # cat_gaia_df = cat_gaia_df.iloc[i[i>=0]].reset_index(drop=True)
            # cat1_df = cat1_df.iloc[i>=0].reset_index(drop=True)
            print(cat1_df)
            print(cat2_df)
            cat1_df, cat2_df, cat_gaia_df = match_by_gaia_catalogs(cat1_df, cat2_df, cat1_gaia_df, cat2_gaia_df)

            # Convert ADU flux into mag
            cat1_df['mag'] = -2.5*np.log10(cat1_df[cat1])
            cat2_df['mag'] = -2.5*np.log10(cat2_df[cat2])
            cat1_df['emag'] = -1.08*cat1_df['e'+cat1]/cat1_df[cat1]
            cat2_df['emag'] = -1.08*cat2_df['e'+cat2]/cat2_df[cat2]

            if _is_aperture(cat1):
                aper_size_1 = list(set(cat1_df['rad'+cat1[-1]]))[0]

            if _is_aperture(cat2):
                aper_size_2 = list(set(cat2_df['rad'+cat2[-1]]))[0]

            # Compute delta flux between PSF and aperture photometry
            deltamag = (cat1_df['mag'] - cat2_df['mag']).to_numpy()
            deltamag = deltamag - np.mean(deltamag)
            edeltamag = np.sqrt(cat1_df['emag']**2+cat2_df['emag']**2).to_numpy()

            # Bin delta flux
            plt.figure(figsize=(7., 4.))
            gmag_binned, deltamag_binned, edeltamag_binned = binplot(cat_gaia_df['gmag'].to_numpy(), deltamag, robust=True, data=False, scale=True, weights=1./edeltamag**2, bins=np.linspace(min_mag, max_mag, 8), color='black', zorder=15)

            bin_mask = (edeltamag_binned > 0.)
            gmag_binned = gmag_binned[bin_mask]
            deltamag_binned = np.array(deltamag_binned)[bin_mask]
            edeltamag_binned = edeltamag_binned[bin_mask]

            # Fit polynomials on delta mag bins
            poly0, ([poly0_chi2], _, _, _) = Polynomial.fit(gmag_binned, deltamag_binned, 0, w=1./edeltamag_binned, full=True)
            poly1, ([poly1_chi2], _, _, _) = Polynomial.fit(gmag_binned, deltamag_binned, 1, w=1./edeltamag_binned, full=True)
            poly2, ([poly2_chi2], _, _, _) = Polynomial.fit(gmag_binned, deltamag_binned, 2, w=1./edeltamag_binned, full=True)

            poly0_chi2 = poly0_chi2/(len(gmag_binned)-1)
            poly1_chi2 = poly1_chi2/(len(gmag_binned)-2)
            poly2_chi2 = poly2_chi2/(len(gmag_binned)-3)

            # Compute rough delta mag on delta mag bins
            low_bin_idx = np.argmin(np.abs(gmag_binned-low_bin))
            high_bin_idx = np.argmin(np.abs(gmag_binned-high_bin))
            low_bin_indices = list(set([max([0, low_bin_idx-1]), low_bin_idx, low_bin_idx+1]))
            high_bin_indices = list(set([high_bin_idx-1, high_bin_idx, min([high_bin_idx+1, len(gmag_binned)-1])]))
            bin_low = np.average(deltamag_binned[low_bin_indices], weights=1./edeltamag_binned[low_bin_indices])
            bin_high = np.average(deltamag_binned[high_bin_indices], weights=1./edeltamag_binned[high_bin_indices])
            deltamag_bin = bin_high-bin_low

            # Start plot
            name1 = _cat_to_name(cat1)
            name2 = _cat_to_name(cat2)

            if _is_aperture(cat1):
                name1 += " {:.2f} px".format(aper_size_1)

            if _is_aperture(cat2):
                name2 += " {:.2f} px".format(aper_size_2)

            plt.title("{} - {} [mag]\n({}-{}-{}) CCD={} Q={}\nSky level={:.2f}".format(name1, name2, year, month, day, ccdid, qid, skylev))
            plt.grid()
            gmag_space = np.linspace(min_mag, max_mag, 100)
            plt.plot(gmag_space, poly0(gmag_space), ls='-', lw=1.5, color='grey', label="Constant - $\chi^2_\\nu={:.3f}$".format(poly0_chi2), zorder=10)
            plt.plot(gmag_space, poly1(gmag_space), ls='dotted', lw=1.5, color='grey', label="Linear - $\chi^2_\\nu={:.3f}$".format(poly1_chi2), zorder=10)
            plt.plot(gmag_space, poly2(gmag_space), ls='--', lw=1.5, color='grey', label="Quadratic - $\chi^2_\\nu={:.3f}$".format(poly2_chi2), zorder=10)
            plt.errorbar(cat_gaia_df['gmag'].to_numpy(), deltamag, yerr=edeltamag, lw=0., marker='.', markersize=1.5, zorder=0, color='xkcd:light blue')
            plt.legend(fontsize='small', loc='upper left')
            plt.xlabel("$g_\mathrm{Gaia}$ [mag]")
            plt.ylabel("$\Delta_M$ [mag]")
            plt.text(14., -0.1, "$\Delta M_{{{}-{}}}={:.5f}$".format(low_bin, high_bin, deltamag_bin), bbox=dict(boxstyle="round", ec='grey', fc='xkcd:light blue'))
            plt.xlim(min_mag, max_mag)
            plt.ylim(-0.2, 0.2)

            plt.tight_layout()
            plt.savefig(exposure_output_path.joinpath(quadrant_path.name), dpi=200.)
            plt.close()

            print(".", end="", flush=True)

            return {'quadrant': quadrant_path.name,
                    'date': "{}-{}-{}".format(year, month, day),
                    'mjd': mjd,
                    'expid': expid,
                    'ccdid': ccdid,
                    'qid': qid,
                    'skylev': skylev,
                    'deltamag': deltamag_bin,
                    'poly0_chi2': poly0_chi2,
                    'poly1_chi2': poly1_chi2,
                    'poly2_chi2': poly2_chi2,
                    'seeing': seeing,
                    'airmass': airmass}

        except Exception as e:
            print(quadrant_path)
            print(e)
            print(traceback.format_exc())

    # d = [_process_quadrant(quadrant_path) for quadrant_path in quadrant_paths]

    tasks = [delayed(_process_quadrant)(quadrant_path, 'flux', 'apfl6') for quadrant_path in quadrant_paths]
    results = compute(tasks)

    # pairs = [('flux', 'apfl6'), ('refflux', 'flux')]
    pairs = [('refflux', 'flux'), ('flux', 'apfl6')]
    print("")
    print("Done.")
    results = list(filter(lambda x: x is not None, results[0]))
    df = pd.DataFrame(results)
    df.to_parquet(band_path.joinpath("myquadrants.parquet"))

    cmap = 'coolwarm'
    def _plot_focal_plane(exposure, vmin, vmax, val):
        cm = ScalarMappable(cmap=cmap)
        cm.set_clim(vmin=vmin, vmax=vmax)

        fig = plt.figure(figsize=(5., 6.), constrained_layout=False)
        f1, f2 = fig.subfigures(ncols=1, nrows=2, height_ratios=[12., 0.3], wspace=-1., hspace=-1.)
        f1.suptitle("\n{}-{}-{}\n$\Delta m$ [mag]".format(exposure[4:8], exposure[8:10], filtercode), fontsize='large')
        plot_ztf_focal_plan_values(f1, delta_mags[exposure], vmin=vmin, vmax=vmax, cmap=cmap, scalar=True)
        ax2 = f2.add_subplot(clip_on=False)
        f2.subplots_adjust(bottom=-5, top=5.)
        ax2.set_position((0.2, 0, 0.6, 1))
        cb = f1.colorbar(cm, cax=ax2, orientation='horizontal')
        ax2.set_clip_on(False)
        ax2.minorticks_on()
        ax2.tick_params(direction='inout')
        plt.savefig(output_path.joinpath("{}-{}_dmag_focal_plane.png".format(exposure, filtercode)), dpi=200., bbox_inches='tight', pad_inches=0.1)
        plt.close()

    fp_vals = {'PSF-Aper': {'limits': 0.2, 'val': lambda x: x.deltamag}}
    for exposure in exposures:
        _plot_focal_plane_dmag(exposure, -vext, vext)


# -*- coding: utf-8 -*-
"""
Created on Sun Nov 29 10:24:57 2020

@author: David Medina
"""

import tkinter as tk
import encriptadores as cy

" Modulo para controlar la funcion de cifrar de la ventana inicial "

# Funcion para agregar espacios
def space(wn,col,n):
    for i in range(n):
        a = tk.Label(wn, text = " ")
        a.config(bg = col)
        a.pack()

# Funcion para definir una etiqueta
def etiquetaimportante (wn,texto,X,Y):
    e = tk.Label(wn,text =texto)
    e.config(font ="Arial 12" ,fg = "red",bg ="LightBlue2")
    e.place(x=X,y=Y )

# Funcion para el boton encriptar
def Encriptar(n0,n1,n2):
    wn = tk.Toplevel()
    wn.title("Cypher: Codigo")
    textmes = n0.get()
    textmet= n1.get()
    textkey= n2.get()

    mensaje = str(textmes)
    llave = int(textkey)
    modo = "encrypt"
    metodo =str(textmet).lower()

    if metodo == "cesar":

        x = cy.cesarCypher(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")

    elif metodo == "cesar rev" or modo == "cesar_rev" :
        x = cy.Cesar_rev(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")

    elif metodo == "trasp" or modo == "trasposicion":
        x = cy.cifrado_transposicion(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")
    else:
        et0 = tk.Label(wn,text = "Metodo"+ " " + metodo + " " +"desconocido")
        et0.grid(row=5,column=1)

# Funcion para el boton desencriptar

def Desencriptar(n0,n1,n2):
    wn = tk.Toplevel()
    wn.title("Cypher: Codigo")

    textmes = n0.get()
    textmet= n1.get()
    textkey= n2.get()

    mensaje = str(textmes)
    llave = int(textkey)
    modo = "decrypt"
    metodo =str(textmet).lower()

    if metodo == "cesar":

        x = cy.cesarCypher(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")

    elif metodo == "cesar rev" or modo == "cesar_rev" :
        x = cy.Cesar_rev(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")

    elif metodo == "trasp" or modo == "trasposicion":
        x = cy.cifrado_transposicion(mensaje,llave,modo)
        et0 = tk.Label(wn,text = "Codigo encriptado:")
        et0.config(font = "Arial 10", fg= "red")

        bet = tk.Entry(wn,fg = "red")
        bet.insert(0,x)
        bet.config(font = "Helvetica 12", fg= "red")

        et0.pack(side = "top")
        bet.pack(side = "left")

    else:
        et0 = tk.Label(wn,text = "Metodo"+ " " + metodo + " " +"desconocido")
        et0.grid(row=5,column=1)

# Funcion principal para control de ventana cifrar

def cifrar():
    wn2 = tk.Toplevel()
    wn2.geometry("510x355+400+250")
    wn2.title(" Cypher.Py : Cifrar mensaje")
    wn2.config(bg = "LightBlue2")
    wn2.resizable(False, False)

    # Texto en la ventana

    sub_mensaje = tk.Label(wn2, text = " Ingrese el mensaje a cifrar: " )
    sub_mensaje.config(bg = "LightBlue2")
    sub_mensaje.grid(row = 0, column =0)
    sub2_mensaje = tk.Label(wn2, text = "Ej: Hola ")
    sub2_mensaje.config(bg = "LightBlue2")
    sub2_mensaje.grid(row = 0, column =3)

    sub_cifrado = tk.Label(wn2, text = " Metodo de cifrado a utilizar: " )
    sub_cifrado.config(bg = "LightBlue2")
    sub_cifrado.grid(row = 1, column =0)
    sub2_cifrado = tk.Label(wn2, text = "Como: Cesar, Cesar rev, Trasp" )
    sub2_cifrado.config(bg = "LightBlue2")
    sub2_cifrado.grid(row = 1, column =3)

    sub_key = tk.Label(wn2, text = "Llave a utilizar en el cifrado:" )
    sub_key.config(bg = "LightBlue2")
    sub_key.grid(row = 2, column =0)
    sub2_key = tk.Label(wn2, text = "Ej: 1,2,3,..., MAX 99 " )
    sub2_key.config(bg = "LightBlue2")
    sub2_key.grid(row = 2, column =3)

    # Cajas de texto de la venta
    box_mensaje = tk.Entry(wn2, font = "Garamond 12", borderwidth = 5, justify = "center")
    box_mensaje.focus()
    box_mensaje.grid(row = 0, column =1)

    box_metodo = tk.Entry(wn2, font = "Garamond 12", borderwidth = 5, justify = "center")
    box_metodo.grid(row = 1, column =1)

    box_key = tk.Entry(wn2, font = "Garamond 12", borderwidth = 5, justify = "center")
    box_key.grid(row = 2, column =1)

    # Botones de la ventana

    boton_encriptar =tk.Button(wn2, text = " Encriptar  ",command = lambda:(Encriptar(box_mensaje,box_metodo,box_key),etiquetaimportante(wn2,"Guarda la llave, la necesitaras para desencriptar el mensaje",50,130)))
    boton_encriptar.config(padx = 25, pady = 5,fg = "Darkorange3", bg = "snow",activebackground="firebrick3")
    boton_encriptar.place(x =140 , y = 96)

    boton_desencriptar =tk.Button(wn2, text = "Desencriptar",command = lambda:Desencriptar(box_mensaje,box_metodo,box_key))
    boton_desencriptar.config(padx = 16, pady = 5,fg = "Darkorange3", bg = "snow",activebackground="firebrick3")
    boton_desencriptar.place(x =260 , y = 95)

    boton_atras =tk.Button(wn2, text = "Atras",command = wn2.destroy)
    boton_atras.config(padx = 16, pady = 5,fg = "Darkorange3", bg = "snow",activebackground="firebrick3",
                       font = "Arial 12")
    boton_atras.place(x =215 , y = 315)


"""
The first frame should be of the static background i.e. without any objects.
"""

import cv2
import pandas
from datetime import datetime

first_frame = None
status_list = [None, None]
timestamp = []
df = pandas.DataFrame(columns=['Start', 'End'])
video = cv2.VideoCapture(0)

while True:
    check, frame = video.read()
    status = 0  # no object in frame
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # See docs: https://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html
    # This is done to reduce noise and increase accuracy
    gray_frame = cv2.GaussianBlur(gray_frame, (21, 21), 0)

    if first_frame is None:
        first_frame = gray_frame
        continue

    # Difference between the pixel values of two frames
    delta_frame = cv2.absdiff(first_frame, gray_frame)
    print(delta_frame)

    # pixels with difference greater than 30 will be colored white(255)
    # it returns a tuple with the frame object as the second element
    thresh_frame = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY)[1]

    # this is done smooth out the threshold
    # removes the black holes from the threshold frame
    thresh_frame = cv2.dilate(thresh_frame, None, iterations=2)

    # draw contours
    (_, contours, _) = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        if cv2.contourArea(contour) < 10000:  # to detect bigger objects, give big pixel number
            continue
        status = 1  # object detected
        (x, y, w, h) = cv2.boundingRect(contour)
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 3)

    cv2.imshow('object detection', gray_frame)
    cv2.imshow('delta frame', delta_frame)
    cv2.imshow('thresh frame', thresh_frame)
    cv2.imshow('color frame', frame)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        if status == 1:
            timestamp.append(datetime.now())
        break

    status_list.append(status)

    if status_list[-2] == 0 and status_list[-1] == 1:
        timestamp.append(datetime.now())
    elif status_list[-2] == 1 and status_list[-1] == 0:
        timestamp.append(datetime.now())

print('first:')
print(first_frame)

for i in range(0, len(timestamp), 2):
    df = df.append({'Start': timestamp[i], 'End': timestamp[i+1]}, ignore_index=True)
df.to_csv('timestamp.csv')

video.release()
cv2.destroyAllWindows()


from typing import TYPE_CHECKING
from magicgui import magic_factory
if TYPE_CHECKING:
    import napari

def connect_events(widget):
    """
    Connect widget events to make some visible/invisible depending on others
    """

    def toggle_median_n_widget(event):
        widget.median_n.visible = event
    # Connect events
    widget.apply_median.changed.connect(toggle_median_n_widget)
    # Intial visibility states
    widget.median_n.visible = False

    def toggle_tile_widget(event):
        widget.tile.visible = event
    # Connect events
    widget.tile.changed.connect(toggle_tile_widget)
    # Intial visibility states
    widget.tile.visible = False

@magic_factory(widget_init=connect_events)
def phasor_plot(image_layer: "napari.layers.Image",
                harmonic: int = 1,
                threshold: int = 0,
                apply_median: bool = False,
                median_n: int = 1,
                tile: bool = False,
                vertical_dim: int = 1024,
                horizontal_dim: int = 1024,
                vertical_im: int = 1,
                horizontal_im: int = 1,
                v_overlapping_per: float = 0.05,
                h_overlapping_per: float = 0.05,
                store_dir: bool = False, # set true for bidirectional storing
                napari_viewer: "napari.Viewer" = None) -> None:
    """Calculate phasor components from HSI image and plot them.
    Parameters
    ----------
    image_layer : napari.layers.Image
        napari image layer with HSI data.
    harmonic : int, optional
        the harmonic to display in the phasor plot, by default 1
    threshold : int, optional
        pixels with summed intensity below this threshold will be discarded, by default 0
    apply_median : bool, optional
        apply median filter to image before phasor calculation, by default False (median_n is ignored)
    median_n : int, optional
        number of iterations of median filter, by default 1
    napari_viewer : napari.Viewer, optional
        napari viewer instance, by default None
    """

    import numpy as np
    import pandas as pd
    from napari.layers import Labels
    import dask.array as da

    from napari_hsi_phasor.hsitools import phasor, median_filter, tilephasor, stitching
    from napari_hsi_phasor._plotter import PhasorPlotterWidget
    from skimage.segmentation import relabel_sequential

    image = image_layer.data

    if tile:
        dc, g, s = tilephasor(image, vertical_dim, horizontal_dim, harmonic=harmonic)
        dc = stitching(dc, vertical_im, horizontal_im, h_overlapping_per, v_overlapping_per, store_dir)
        g = stitching(g, vertical_im, horizontal_im, h_overlapping_per, v_overlapping_per, store_dir)
        s = stitching(s, vertical_im, horizontal_im, h_overlapping_per, v_overlapping_per, store_dir)

    else:
        dc, g, s = phasor(image, harmonic=harmonic)

    if apply_median:
        g = median_filter(g, median_n)
        s = median_filter(s, median_n)

    dc = dc[np.newaxis, np.newaxis, :, :]
    g = g[np.newaxis, np.newaxis, :, :]
    s = s[np.newaxis, np.newaxis, :, :]

    space_mask = dc > threshold
    label_image = np.arange(np.prod(dc.shape)).reshape(dc.shape) + 1
    label_image[~space_mask] = 0
    label_image = relabel_sequential(label_image)[0]
    label_column = np.ravel(label_image[space_mask])

    g_flat_masked = np.ravel(g[space_mask])
    s_flat_masked = np.ravel(s[space_mask])
    if isinstance(g, da.Array):
        g_flat_masked.compute_chunk_sizes()
        s_flat_masked.compute_chunk_sizes()

    phasor_components = pd.DataFrame({
        'label': np.ravel(label_image[space_mask]),
        'G': g_flat_masked,
        'S': s_flat_masked})
    table = phasor_components

    frame = np.arange(dc.shape[0])
    frame = np.repeat(frame, np.prod(dc.shape[1:]))
    table['frame'] = frame[space_mask.ravel()]

    # The layer has to be created here so the plotter can be filled properly
    # below. Overwrite layer if it already exists.
    for layer in napari_viewer.layers:
        if (isinstance(layer, Labels)) & (layer.name == 'Labelled_pixels_from_' + image_layer.name):
            labels_layer = layer
            labels_layer.data = label_image
            labels_layer.features = table
            break
    else:
        labels_layer = napari_viewer.add_labels(label_image,
                                                name='Labelled_pixels_from_' + image_layer.name,
                                                features=table,
                                                scale=image_layer.scale[1:],
                                                visible=False)

    # Check if plotter was alrerady added to dock_widgets
    # TO DO: avoid using private method access to napari_viewer.window._dock_widgets (will be deprecated)
    dock_widgets_names = [key for key,
                                  value in napari_viewer.window._dock_widgets.items()]
    if 'Phasor Plotter Widget (napari-hsi-phasor)' not in dock_widgets_names:
        plotter_widget = PhasorPlotterWidget(napari_viewer)
        napari_viewer.window.add_dock_widget(
            plotter_widget, name='Phasor Plotter Widget (napari-hsi-phasor)')
    else:
        widgets = napari_viewer.window._dock_widgets['Phasor Plotter Widget (napari-hsi-phasor)']
        plotter_widget = widgets.findChild(PhasorPlotterWidget)

    # Get labels layer with labelled pixels (labels)
    plotter_widget.labels_select.value = [
        choice for choice in plotter_widget.labels_select.choices if choice.name.startswith("Labelled_pixels")][0]
    # Set G and S as features to plot (update_axes_list method clears Comboboxes)
    plotter_widget.plot_x_axis.setCurrentIndex(1)
    plotter_widget.plot_y_axis.setCurrentIndex(2)
    plotter_widget.plotting_type.setCurrentIndex(1)

    # Show parent (PlotterWidget) so that run function can run properly
    plotter_widget.parent().show()
    # Disconnect selector to reset collection of points in plotter
    # (it gets reconnected when 'run' method is run)
    plotter_widget.graphics_widget.selector.disconnect()
    plotter_widget.run(labels_layer.features,
                       plotter_widget.plot_x_axis.currentText(),
                       plotter_widget.plot_y_axis.currentText())
    plotter_widget.axes_limits()
    return


class User: #class name PascalCase
    def __init__(self,user_id, username): #called everytime you create new object.
        self.id = user_id
        self.username = username
        #default value.
        self.followers = 0
        self.following = 0

    def follow(self, user):
        user.followers += 1
        self.following += 1

user_1 = User("001","Pratik")
user_2 = User("002","Rohit")
user_1.follow(user_2)

print(f"{user_1.username} = followers {user_1.followers} : following {user_1.following}")

print(f"{user_2.username} = followers {user_2.followers} : following {user_2.following}")

# print(user_1.username) #object.attribute
# print(user_2.username)
# print(user_1.followers)

#Remember.
#attributes are the things that object has. like variable.
#methods are the things that object does.
#when function attached to object then its called a method.

#how do access attribute of class.
#object.attribute
# user_2.id = "002"  #assigned value


import logging
import time
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Optional, Tuple, Union

from pydantic import BaseModel, PrivateAttr  # pylint: disable=no-name-in-module
from sqlalchemy import Column, DateTime, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.session import Session
from sxm.models import XMChannel, XMLiveChannel

COOLDOWN_SHORT = 10
COOLDOWN_MED = 60
COOLDOWN_LONG = 600

Base = declarative_base()

class DBSong(Base):
    __tablename__ = "songs"

    guid = Column(String, primary_key=True)
    title = Column(String, index=True)
    artist = Column(String, index=True)
    album = Column(String, nullable=True)
    air_time = Column(DateTime)
    channel = Column(String)
    file_path = Column(String)
    image_url = Column(String, nullable=True)

class Song(BaseModel):
    guid: str
    title: str
    artist: str
    album: Optional[str]
    air_time: datetime
    channel: str
    file_path: str
    image_url: Optional[str]

    class Config:
        orm_mode = True

    @property
    def air_time_smart(self):
        return self.air_time.replace(tzinfo=timezone.utc)

    @staticmethod
    def get_pretty_name(
        title: Optional[str], artist: Optional[str], bold: bool = False
    ) -> str:
        """Returns a formatted name of song"""

        if title is None:
            title = ""

        if artist is None:
            artist = ""

        mod = ""
        if bold:
            mod = "**"

        return f'{mod}"{title}"{mod} by {mod}{artist}{mod}'

    @property
    def pretty_name(self) -> str:
        """Returns a formatted name of song"""

        return Song.get_pretty_name(self.title, self.artist)

    @property
    def bold_name(self) -> str:
        """Returns a formatted name of song"""

        return Song.get_pretty_name(self.title, self.artist, True)

class DBEpisode(Base):
    __tablename__ = "episodes"

    guid = Column(String, primary_key=True)
    title = Column(String, index=True)
    show = Column(String, nullable=True, index=True)
    air_time = Column(DateTime)
    channel = Column(String)
    file_path = Column(String)
    image_url = Column(String, nullable=True)

class Episode(BaseModel):
    guid: str
    title: str
    show: str
    air_time: datetime
    channel: str
    file_path: str
    image_url: Optional[str]

    class Config:
        orm_mode = True

    @staticmethod
    def get_pretty_name(
        title: Optional[str],
        show: Optional[str],
        air_time: Optional[datetime],
        bold: bool = False,
    ) -> str:
        """Returns a formatted name of show"""

        if title is None:
            title = ""

        if show is None:
            show = ""

        mod = ""
        if bold:
            mod = "**"

        if air_time is None:
            f'{mod}"{title}"{mod} ({show})'
        return f'{mod}"{title}"{mod} ({show}) from {air_time}'

    @property
    def pretty_name(self) -> str:
        """Returns a formatted name of show"""

        return Episode.get_pretty_name(self.title, self.show, self.air_time)

    @property
    def bold_name(self) -> str:
        """Returns a formatted name of show"""

        return Episode.get_pretty_name(self.title, self.show, self.air_time, True)

class PlayerState(BaseModel):
    stream_url: Optional[str] = None
    stream_channel: Optional[str] = None
    processed_folder: Optional[str] = None
    db_reset: bool = False
    sxm_running: bool = False
    player_name: Optional[str] = None

    _db: Optional[Session] = PrivateAttr(None)
    _raw_channels: Optional[List[dict]] = PrivateAttr(None)
    _raw_live: Optional[dict] = PrivateAttr(None)
    _channels: Optional[List[XMChannel]] = PrivateAttr(None)
    _live: Optional[XMLiveChannel] = PrivateAttr(None)
    _failures: int = PrivateAttr(0)
    _cooldown: float = PrivateAttr(0)
    _last_failure: float = PrivateAttr(0)
    _start_time: Optional[datetime] = PrivateAttr(None)
    _time_offset: Optional[timedelta] = PrivateAttr(None)

    _channels_lookup_cache: Dict[str, XMChannel] = PrivateAttr({})

    @property
    def stream_data(self) -> Tuple[Optional[str], Optional[str]]:
        return (self.stream_channel, self.stream_url)

    def update_stream_data(self, value: Tuple[Optional[str], Optional[str]]) -> None:
        self.stream_channel = value[0]
        self.stream_url = value[1]

    @property
    def channels(self) -> List[XMChannel]:
        """Returns list of `XMChannel`"""

        if self._channels is None:
            if self._raw_channels is None:
                return []
            self._channels = []
            for channel in self._raw_channels:
                self._channels.append(XMChannel.from_dict(channel))
        return self._channels

    def update_channels(self, value: Optional[List[dict]]) -> None:
        """
        Sets channel key in internal `_raw_channels`.
        """

        self._channels = None
        self._channels_lookup_cache = {}
        self._raw_channels = value

        if self._raw_channels is None:
            self.stream_url = None
            self.stream_channel = None

    def get_raw_channels(self) -> Optional[List[dict]]:
        return self._raw_channels

    @property
    def db(self) -> Union[Session, None]:
        if self._db is None and self.processed_folder is not None:
            from .utils import init_db

            self._db = init_db(self.processed_folder, reset=self.db_reset)
        return self._db

    @property
    def live(self) -> Union[XMLiveChannel, None]:
        """Returns current `XMLiveChannel`"""

        return self._live

    def update_live(self, value: dict) -> None:
        """Sets live key in internal `_raw_live`."""

        now = datetime.now(timezone.utc)
        self._live = None
        self._raw_live = value

        if self._raw_live is not None:
            self._live = XMLiveChannel.from_dict(self._raw_live)

            if self._live.tune_time is not None:
                self._time_offset = now - self._live.tune_time

            if self._start_time is None:
                if self._live.tune_time is None:
                    self._start_time = now
                else:
                    self._start_time = self._live.tune_time
        else:
            self._time_offset = 0
            self._start_time = None

    def get_raw_live(
        self,
    ) -> Tuple[Optional[datetime], Optional[timedelta], Optional[dict]]:
        return (self._start_time, self._time_offset, self._raw_live)

    def set_raw_live(
        self,
        live_data: Tuple[Optional[datetime], Optional[timedelta], Optional[dict]],
    ):
        self._start_time = live_data[0]
        self._time_offset = live_data[1]
        self._raw_live = live_data[2]

        if self._raw_live is not None:
            self._live = XMLiveChannel.from_dict(self._raw_live)

    @property
    def radio_time(self) -> Union[datetime, None]:
        """Returns current time for the radio"""

        if self.live is None:
            return None

        now = datetime.now(timezone.utc)
        if self._time_offset is not None:
            return now - self._time_offset
        return now

    @property
    def start_time(self) -> Optional[datetime]:
        """Returns the start time for the current SiriusXM channel"""

        if self.live is None:
            return None
        return self._start_time

    @property
    def is_connected(self) -> bool:
        is_connected = self._raw_channels is not None
        if is_connected and time.monotonic() - self._last_failure > 300:
            self._failures = 0
        return is_connected

    @property
    def can_connect(self) -> bool:
        return time.monotonic() > self._cooldown

    def mark_attempt(self, logger: logging.Logger) -> float:
        if self.can_connect:
            self.mark_failure()
            extra_seconds = self.increase_cooldown()

            logger.info(
                "Attempting to connect SXM Client (next in " f"{extra_seconds} seconds)"
            )
            return True
        return False

    def increase_cooldown(self) -> float:
        extra_seconds = 0
        if self._failures < 3:
            extra_seconds = COOLDOWN_SHORT
        elif self._failures < 5:
            extra_seconds = COOLDOWN_MED
        else:
            extra_seconds = COOLDOWN_LONG

        self._cooldown = time.monotonic() + extra_seconds

        return extra_seconds

    def mark_failure(self) -> float:
        self._failures += 1
        self._last_failure = time.monotonic()
        return self._cooldown

    def get_channel(self, name: str) -> Optional[XMChannel]:
        """Returns channel from list of `channels` with given name"""

        name = name.lower()
        if name not in self._channels_lookup_cache:
            for channel in self.channels:
                if (
                    channel.name.lower() == name
                    or channel.id.lower() == name
                    or str(channel.channel_number) == name
                ):
                    self._channels_lookup_cache[name] = channel
                    break
        return self._channels_lookup_cache.get(name)


import time
import sys
import os

import pygame

#  import game object classes
from level import Level
from player import Player
from robot import Robot
from apple import Apple

#  import constant definitions
from macros import *

#  for mathematical operations
import numpy as np

class Game:
    def __init__(self, game_window_name="Hamham"):
        #  initialize pygame stuff
        pygame.display.init()
        pygame.mixer.init()
        pygame.display.set_caption(game_window_name)
        self.screen = pygame.display.set_mode(game_window_size)
        self.clock = pygame.time.Clock()

        #wall_width = self.wall.get_width()
        wall_width = 36

		# Load images
        self.wall = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/wall.png').convert(), (wall_width, wall_width))

        self.apple = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/apple_bg.png').convert(), (wall_width, wall_width))
        self.floor = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/floor.png').convert(), (wall_width, wall_width))
        self.grass = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/grass.png').convert(), (wall_width, wall_width))

        self.player_right = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/pacman_bg.png').convert(), (wall_width, wall_width))
        self.player_up = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/pacman_bg.png').convert(), (wall_width, wall_width)), 90.0)
        self.player_left = pygame.transform.flip(pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/pacman_bg.png').convert(), (wall_width, wall_width)), True, False)
        self.player_down = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/pacman_bg.png').convert(), (wall_width, wall_width)), -90.0)
        self.player_image = self.player_right
        self.player_images = [self.player_right, self.player_up, self.player_left, self.player_down]

        self.robot = pygame.transform.scale(pygame.image.load(os.path.dirname(os.path.abspath(__file__)) + '/images/robot_bg.png').convert(), (wall_width, wall_width))

        #  load sounds
        self.win_sound = pygame.mixer.Sound(os.path.dirname(os.path.abspath(__file__)) + '/sounds/tada.wav')
        self.lose_sound = pygame.mixer.Sound(os.path.dirname(os.path.abspath(__file__)) + '/sounds/fail_trombone_4s.wav')

		# Dictionary to map images to characters in level matrix
        self.images = {'W': self.wall,
                    'A': self.apple,
                    'F': self.floor,
                    'G': self.grass,
                    'P': self.player_image,
                    'R': self.robot}

        self.current_level = None
        self.current_level_number = 0

		#  player object
        self.player = None

		#  robots
        self.robots = []

        self.game_finished = False
        self.player_alive = True

        """
        Current level statistics
        """
        #  number of apples player collected so far in curret level
        self.collected_apple_count = 0

        #  number of all apples in the initial level configuration
        self.total_apple_count = 0

        #  number of time steps elapsed in a level
        self.elapsed_time_step = 0

        #
        self.distance_to_closest_apple = 0

        self.crashed_into_wall = False

    def draw_level(self, level_matrix):
        # Get image size to print on screen
        box_size = self.wall.get_width()

        # Print images for matrix
        for i in range(0, len(level_matrix)):
            for c in range(0, len(level_matrix[i])):
                self.screen.blit(self.images[level_matrix[i][c]], (c * box_size, i * box_size))
        pygame.display.update()

    def init_level(self, level):
        self.current_level = Level(level)
        #self.draw_level(self.current_level.get_matrix())

        #  mark game as not finished
        self.game_finished = False
        self.player_alive = True

        #  number of time steps elapsed in a level
        self.elapsed_time_step = 0

        #  initialize number of apples player collected so far in curret level
        self.collected_apple_count = 0

        #  create player object
        player_pos = self.current_level.get_player_pos()
        player_current_row = player_pos[0]
        player_current_col = player_pos[1]
        self.player = Player(player_current_row, player_current_col)

        #  create robots
        self.robots = []
        robot_positions = self.current_level.get_robot_positions()
        for pos in robot_positions:
            r = pos[0]
            c = pos[1]
            self.robots.append(Robot(r, c, self.current_level.get_matrix()))

        #  create apples
        self.apples = []
        apple_positions = self.current_level.get_apple_positions()
        for pos in apple_positions:
            r = pos[0]
            c = pos[1]
            self.apples.append(Apple(r, c))

        #  count number of apples
        self.total_apple_count = len(self.apples)
        #print("Number of apples in the level ", self.total_apple_count)

        #  whether played tried to move into wall at last step
        self.crashed_into_wall = False

    """
    Calculates distance between player and the closest apple to player
    """
    def get_closest_apple_to_player(self):
        player_pos = self.player.get_pos()
        pr = player_pos[0]
        pc = player_pos[1]

        minDist = 1000
        closestApple = None
        for apple in self.apples:
            apple_pos = apple.get_pos()
            rr = apple_pos[0]
            rc = apple_pos[1]
            dist = np.abs(pr - rr) + np.abs(pc - rc)
            if (dist < minDist):
                minDist = dist
                closestApple = apple

        return (closestApple, minDist)

    def step(self, player_direction, render=True):
        matrix = self.current_level.get_matrix()
        self.current_level.save_history(matrix)

        #Print apples
        #print(self.current_level.get_apple_positions())

        #  robots movement
        for robot in self.robots:
            #robot_old_pos = robot.get_pos()
            #robot_old_row = robot_old_pos[0]
            #robot_old_col = robot_old_pos[1]

            robot_dir = robot.choose_dir()
            robot_new_pos = robot.move(robot_dir)
            robot_next_row = robot_new_pos[0]
            robot_next_col = robot_new_pos[1]

		#  save old position of the player
        player_current_pos = self.player.get_pos()
        player_current_row = player_current_pos[0]
        player_current_col = player_current_pos[1]

		#  calculate new position of the player
        player_next_pos = self.player.move(player_direction)
        player_next_row = player_next_pos[0]
        player_next_col = player_next_pos[1]

        #  resolve static collision for robots
        for robot in self.robots:
            robot_prev_pos = robot.get_prev_pos()
            robot_prev_row = robot_prev_pos[0]
            robot_prev_col = robot_prev_pos[1]

            robot_next_pos = robot.get_pos()
            robot_next_row = robot_next_pos[0]
            robot_next_col = robot_next_pos[1]

            next_cell = matrix[robot_next_row][robot_next_col]
            if next_cell == "F":
                #  next cell is floor
                pass
            elif ((next_cell == "G")
                  or (next_cell == "W")
                  or (next_cell == "A")):
                #  next cell is grass or wall or apple
                #robot cant pass here
                robot.current_pos = robot_prev_pos
            elif (next_cell == "R"):
                #  go into another robot
                pass
            elif (next_cell == "P"):
                #  will resolve later
                pass

        #  resolve static collisions for player
        next_cell = matrix[player_next_row][player_next_col]
        if (next_cell == "F"):
            #  next cell is floor
            pass
        elif (next_cell == "W"):
            #  next cell is wall
            #player cant pass here
            self.player.current_pos = self.player.prev_pos
            self.crashed_into_wall = True
        elif (next_cell == "G"):
            #  next cell is grass
            #player removes grass
            matrix[player_next_row][player_next_col] = "P"
        elif (next_cell == 'A'):
            #  next cell is apple
            #player removes apple
            matrix[player_next_row][player_next_col] = "P"
        elif (next_cell == "R"):
            #  next square is robot
            #will resolve later
            pass

        #  check if player collected an apple
        #  TO DO: create a 2d apple grid for faster check
        new_apples = []
        for apple in self.apples:
            apple_pos = apple.get_pos()
            apple_row = apple_pos[0]
            apple_col = apple_pos[1]
            if (player_next_row == apple_row and player_next_col == apple_col):
                #player removes apple
                #  check if game is finished
                self.collected_apple_count += 1
                if (self.collected_apple_count == self.total_apple_count):
                    self.game_finished = True
            else:
                new_apples.append(apple)
        self.apples = new_apples

        player_next_row = self.player.current_pos[0]
        player_next_col = self.player.current_pos[1]

        #  resolve dynamic player-robot collisions
        for robot in self.robots:
            robot_prev_pos = robot.get_prev_pos()
            robot_prev_row = robot_prev_pos[0]
            robot_prev_col = robot_prev_pos[1]

            robot_next_pos = robot.get_pos()
            robot_next_row = robot_next_pos[0]
            robot_next_col = robot_next_pos[1]

            #  CASE 1
            #player and robot moves into same cell
            if (robot_next_row == player_next_row and robot_next_col == player_next_col):
                #print("CASE 1: Player and robot {} moved into same cell!".format(robot.get_id()))
                self.player_alive = False
                self.game_finished = True

            #  CASE 2
            #player in cell C1, robot in cell C2
            #player moves from C1 to C2
            #robot moves from C3 to C4
            #C1 == C4 AND C2 == C3
            if (player_current_pos == robot_next_pos and player_next_pos == robot_prev_pos):
                #print("CASE 2: Player and robot {} passed by!".format(robot.get_id()))
                self.player_alive = False
                self.game_finished = True

        #  update game matrix
        level_matrix = self.current_level.get_matrix()
        for robot in self.robots:
            robot_old_pos = robot.get_prev_pos()
            robot_old_row = robot_old_pos[0]
            robot_old_col = robot_old_pos[1]
            robot_new_pos = robot.get_pos()
            robot_next_row = robot_new_pos[0]
            robot_next_col = robot_new_pos[1]

            level_matrix[robot_old_row][robot_old_col] = "F"
            level_matrix[robot_next_row][robot_next_col] = "R"
        player_prev_row = self.player.get_prev_row()
        player_prev_col = self.player.get_prev_col()
        player_next_row = self.player.get_row()
        player_next_col = self.player.get_col()

        #  if there is not a robot in the previous cell of player, clear it
        if (level_matrix[player_prev_row][player_prev_col] != "R"):
            level_matrix[player_prev_row][player_prev_col] = "F"
        level_matrix[player_next_row][player_next_col] = "P"

        #  draw
        if (render):
            self.images["P"] = self.player_images[self.player.current_facing_index]
            self.draw_level(matrix)

        self.elapsed_time_step += 1

        #remaining_apple_count = len(self.current_level.get_apple_positions())
        #print("Number of remaining apples: ", remaining_apple_count)

        #  check if game is finished
        if (self.game_finished):
            if (self.player_alive):
                #  player collected all apples
                #print("Level completed!")
                return RESULT_PLAYER_WON
            else:
                #  player is dead
                #print("Player is killed by the robot!")
                return RESULT_PLAYER_DEAD
        else:
            return RESULT_GAME_CONTINUE

    #  function when a human player plays the game
    def start_level_human(self, level_index):
        self.init_level(level_index)
        self.draw_level(self.current_level.get_matrix())

		#  number of all apples in the initial level configuration
        self.total_apple_count = len(self.apples)

        #  at each time step, distance of player to the closest apple
        apple_distance_rewards = []

        #  negative reward if crash into wall
        wall_crash_penalties = []

        self.distance_to_closest_apple = self.get_closest_apple_to_player()[1]

        #  game loop
        while True:
            result = 0

            #  manual input
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    #self.craft_features()

                    if event.key == pygame.K_RIGHT:
                        result = self.step("R", render=True)
                    elif event.key == pygame.K_UP:
                        result = self.step("U", render=True)
                    elif event.key == pygame.K_LEFT:
                        result = self.step("L", render=True)
                    elif event.key == pygame.K_DOWN:
                        result = self.step("D", render=True)
                    elif event.key == pygame.K_SPACE:
                        result = self.step("PASS", render=True)
                    #elif event.key == pygame.K_u:
                    #    self.draw_level(self.current_level.undo())
                    elif event.key == pygame.K_r:
                        self.init_level(self.current_level_number)
                        result = RESULT_GAME_CONTINUE
                    elif event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()

                elif event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

            if (result == RESULT_PLAYER_WON or result == RESULT_PLAYER_DEAD):
                sound_channel = None
                if (result == RESULT_PLAYER_WON):
                    #print("WON")
                    sound_channel = self.win_sound.play()
                else:
                    #print("LOSE")
                    sound_channel = self.lose_sound.play()

                #  wait for sound to end
                while sound_channel.get_busy() == True:
                    continue
                break
            else:
                #
                new_closest_apple_dist = self.get_closest_apple_to_player()[1]
                if (new_closest_apple_dist > self.distance_to_closest_apple):
                    apple_distance_rewards.append(MOVING_AWAY_FROM_APPLE)
                elif (new_closest_apple_dist < self.distance_to_closest_apple):
                    apple_distance_rewards.append(GETTING_CLOSER_TO_APPLE_REWARD)
                self.distance_to_closest_apple = new_closest_apple_dist

                if (self.crashed_into_wall):
                    self.crashed_into_wall = False
                    wall_crash_penalties.append(WALL_CRASH_PENALTY)

        #  if killed by robot, give penalty
        robot_death_penalty = 0
        if (result == RESULT_PLAYER_DEAD):
            robot_death_penalty = ROBOT_DEATH_PENALTY

        #  return a tuple of
        #(number of collected apples, elapsed time step)
        return (self.collected_apple_count, apple_distance_rewards, wall_crash_penalties,
                self.elapsed_time_step, robot_death_penalty)

    """
    R T L U blocked (4)
    R T L U contains a robot or is adjacent to a robot (4)
    closest apple vector components (2)

    returns a feature vector containing above 10 features
    """
    def craft_features(self):
        player_pos = self.player.get_pos()
        pr = player_pos[0]
        pc = player_pos[1]
        matrix = self.current_level.get_matrix()

        #  features showing whether 4 cardinal direction cells blocked or not
        checked_cell = matrix[pr][pc+1]
        right_blocked = int( (checked_cell == "W") )
        checked_cell = matrix[pr-1][pc]
        up_blocked = int( (checked_cell == "W") )
        checked_cell = matrix[pr][pc-1]
        left_blocked = int( (checked_cell == "W") )
        checked_cell = matrix[pr+1][pc]
        down_blocked = int( (checked_cell == "W") )

        #  features showing whether 4 cardinal direction cells contains robot danger or not
        drs = [0, -1, 0, 1]
        dcs = [1, 0, -1, 0]
        matrix_height = len(matrix)
        matrix_width = len(matrix[0])
        robot_vector = np.zeros(4)
        for c in range(4):
            #  calculate cth adjacent cell
            adj_cell_row = pr + drs[c]
            adj_cell_col = pc + dcs[c]

            #  check if there is a robot in the cell
            if (matrix[adj_cell_row][adj_cell_col] == "R"):
                robot_vector[c] = 1.0
                continue

            #  check if there is a robot danger in the cell
            for dr in drs:
                for dc in dcs:
                    if (adj_cell_row + dr >= 0 and adj_cell_row + dr < matrix_height
                        and adj_cell_col + dc >= 0 and adj_cell_col + dc < matrix_width
                        and matrix[adj_cell_row + dr][adj_cell_col + dc] == "R"):
                        robot_vector[c] = 1.0
                        break

        #right_robot = int( (checked_cell == "R") )
        #up_robot = int( (checked_cell == "R") )
        #left_robot = int( (checked_cell == "R") )
        #down_robot = int( (checked_cell == "R") )

        #
        blocked_vector = np.array([right_blocked, up_blocked, left_blocked, down_blocked])
        #robot_vector = np.array([right_robot, up_robot, left_robot, down_robot])

        #  calculate vector that shows the apple direction
        closest_apple = self.get_closest_apple_to_player()[0]
        closest_apple_pos = closest_apple.get_pos()
        closest_apple_row = closest_apple_pos[0]
        closest_apple_col = closest_apple_pos[1]
        closest_apple_vector = np.array([closest_apple_row - pr, closest_apple_col - pc])

        #  normalize direction vector
        closest_apple_vector_norm = np.linalg.norm(closest_apple_vector)
        if (closest_apple_vector_norm == 0):
            closest_apple_vector_norm = len(matrix)
        closest_apple_vector = closest_apple_vector / closest_apple_vector_norm

        #  obtain feature vector by merging blocked and direction vectors
        feature_vector = np.concatenate([blocked_vector, robot_vector, closest_apple_vector])

        #print("--- MATRIX ---")
        #print(matrix)
        #print("--- FEATURES ---")
        #print(feature_vector)

        #  return feature vector
        return feature_vector

    def start_level_computer(self, level_index, agent,
                             render=False, play_sound=False,
                             max_episode_length=150,
                             use_crafted_features=True,
                             test=False):
        self.init_level(level_index)

        if (render):
            self.draw_level(self.current_level.get_matrix())

		#  number of all apples in the initial level configuration
        self.total_apple_count = len(self.apples)

        #  at each time step, distance of player to the closest apple
        apple_distance_rewards = []

        #  negative reward if crash into wall
        wall_crash_penalties = []

        self.distance_to_closest_apple = self.get_closest_apple_to_player()[1]

        while True:
            result = 0

            #  input source will use matrix to decide
            matrix = self.current_level.get_matrix()

            network_input = None
            if (use_crafted_features):
                network_input = self.craft_features()
            else:
                #  convert grid to network input
                network_input = agent.grid_to_network_input(matrix)
            chosen_action = agent.decide_move(network_input)

            #  apply decided action
            result = self.step(chosen_action, render=render)

            #  if we want to render our agent, wait some time
            if (render):
                self.clock.tick(FPS)

            #  check if game finished
            if (result == RESULT_PLAYER_WON or result == RESULT_PLAYER_DEAD):
                if (play_sound):
                    sound_channel = None
                    if (result == RESULT_PLAYER_WON):
                        sound_channel = self.win_sound.play()
                    else:
                        sound_channel = self.lose_sound.play()

                    #  wait for sound to end
                    while sound_channel.get_busy() == True:
                        continue
                break
            else:
                #
                new_closest_apple_dist = self.get_closest_apple_to_player()[1]
                if (new_closest_apple_dist > self.distance_to_closest_apple):
                    apple_distance_rewards.append(MOVING_AWAY_FROM_APPLE)
                elif (new_closest_apple_dist < self.distance_to_closest_apple):
                    apple_distance_rewards.append(GETTING_CLOSER_TO_APPLE_REWARD)
                self.distance_to_closest_apple = new_closest_apple_dist

                if (self.crashed_into_wall):
                    self.crashed_into_wall = False
                    wall_crash_penalties.append(WALL_CRASH_PENALTY)

            #  check if we reached episode length
            if (self.elapsed_time_step >= max_episode_length):
                break

        #  if killed by robot, give penalty
        robot_death_penalty = 0
        if (result == RESULT_PLAYER_DEAD):
            robot_death_penalty = ROBOT_DEATH_PENALTY

        #  return a tuple of
        #(number of collected apples, elapsed time step)
        return (self.collected_apple_count, apple_distance_rewards, wall_crash_penalties,
                self.elapsed_time_step, robot_death_penalty)