import os
from youtubesearchpython import VideosSearch
import eyed3
import requests
from tqdm import tqdm
from yt_dlp import YoutubeDL
import os
from pydub import AudioSegment
from pathlib import Path
from spotube_package.dependency_handler import DependencyHandler

COVER_PHOTO = "/cover_photo.jpg"

def get_lyrics(name_search, artist_search, genius_obj):
    sep1 = "ft."
    sep2 = "feat"
    sep3 = "(feat"
    sep4 = "(ft."
    sep5 = "(feat."
    name_search = name_search.split(sep1)[0]
    name_search = name_search.split(sep2)[0]
    name_search = name_search.split(sep3)[0]
    name_search = name_search.split(sep4)[0]
    name_search = name_search.split(sep5)[0]
    genius_song = genius_obj.search_song(name_search, artist_search)
    formatted_lyrics = genius_song.lyrics.rsplit(" ", 1)[0].replace("EmbedShare", "")
    formatted_lyrics = formatted_lyrics.rsplit(" ", 1)[0] + "".join(
        [i for i in formatted_lyrics.rsplit(" ", 1)[1] if not i.isdigit()]
    )
    return formatted_lyrics

def set_tags(song_info, genius_obj, directory):
    audio_file = eyed3.load(directory + "/" + song_info["name"] + ".mp3")

    if audio_file.tag is None:
        audio_file.initTag()

    audio_file.tag.images.set(
        3, open(directory + COVER_PHOTO, "rb").read(), "image/jpeg"
    )
    formatted_artist_string = song_info["artist"].replace(",", ";")
    audio_file.tag.artist = formatted_artist_string
    audio_file.tag.title = song_info["name"]
    audio_file.tag.album = song_info["album"]
    audio_file.tag.year = song_info["year"]

    try:
        audio_file.tag.lyrics.set(
            get_lyrics(song_info["name"], song_info["artist"], genius_obj)
        )
    except Exception:
        pass

    audio_file.tag.save()
    os.remove(directory + COVER_PHOTO)

def format_artists(artist_list):
    artist_combined = ""

    for artist_in_list in artist_list:
        if artist_combined != "":
            artist_combined += ", "
        artist_combined += artist_in_list["name"]

    return artist_combined

def get_link(song_info):
    min_difference = song_info["duration"]
    video_search = VideosSearch(song_info["name"] + " " + song_info["artist"], limit=3)
    best_link = None

    for search_result in video_search.result()["result"]:
        duration_str = search_result["duration"].replace(":", " ").split()
        duration_int = int(duration_str[0]) * 60000 + int(duration_str[1]) * 1000

        if abs(duration_int - song_info["duration"]) < min_difference:
            min_difference = abs(duration_int - song_info["duration"])
            best_link = search_result["link"]

    if best_link is None:
        best_link = ""

    return best_link

def download_image(song_info, directory):
    # Get the Cover Art
    image_url = song_info["url"]
    r = requests.get(image_url)
    with open(directory + COVER_PHOTO, "wb") as f:
        f.write(r.content)

def download_song(given_link, song_info, downloader, directory):
    attempts = 0

    while attempts <= 3:
        try:
            downloader.extract_info(given_link)
            default_song_name = "/downloaded_song.mp3"

            # Overwrite the file, if it exists
            if os.path.exists(directory + "/" + song_info["name"] + ".mp3"):
                os.remove(directory + "/" + song_info["name"] + ".mp3")
            os.rename(directory + default_song_name, directory + "/" + song_info["name"] + ".mp3")
            return

        except Exception as e:  # pragma: no cover
            print(str(e))
            attempts += 1
            continue

def get_songs(playlist_link, spotify_api):
    results = spotify_api.playlist_items(playlist_link, additional_types=("track",))

    songs = results["items"]

    while results["next"]:
        results = spotify_api.next(results)
        songs.extend(results["items"])

    return songs

# Handle message delivery in UI mode
def send_message(channel, type, contents):
    if channel is not None:
        channel.put({"type": type, "contents": contents})

def get_elapsed(progressbar):
    elapsed = progressbar.format_dict["elapsed"]
    return elapsed

def get_eta(progressbar):
    rate = progressbar.format_dict["rate"]
    remaining = (
        (progressbar.total - progressbar.n) / rate if rate and progressbar.total else 0
    )
    return remaining

# Return formatted song data in a dictionary
def format_song_data(song):
    song = song["track"]
    cover_art = song["album"]["images"][0]["url"]
    year = song["album"]["release_date"].replace("-", " ").split()[0]
    name = song["name"]
    artist = format_artists(song["artists"])
    album = song["album"]["name"]
    duration = int(song["duration_ms"])
    info_dict = {
        "name": name,
        "artist": artist,
        "album": album,
        "year": year,
        "duration": duration,
        "url": cover_art,
    }

    return info_dict

def download_playlist(
    playlist_url, authenticator, channel, termination_channel, directory, display_bar=True
):
    # Set up the folder for the songs
    if not os.path.isdir(directory):
        Path(directory).mkdir(parents=True, exist_ok=True)

    audio_downloader = create_audio_downloader(directory)

    songs = get_songs(playlist_url, authenticator.spotify_auth)

    if display_bar:
        filename = None
    else:
        filename = open(os.devnull, "w")

    # Set the tqdm progress bar
    playlist_size = len(songs)
    playlist_progress = tqdm(
        total=playlist_size,
        desc="Playlist Progress",
        position=0,
        leave=False,
        file=filename,
    )

    success_counter = 0
    failure_counter = 0

    for song in songs:
        # Set song progress bar
        song_progress = tqdm(
            total=4,
            desc=song["track"]["name"],
            position=1,
            leave=False,
            file=filename,
        )

        # Retrieve Formatted Song Data
        song_progress.set_description(song_progress.desc + ": Formatting Information")
        song_progress.update(n=1)
        info_dict = format_song_data(song)

        # Download Cover Art, to preview to UI
        download_image(info_dict, directory)

        # Send Message to UI
        send_message(
            channel,
            type="song_title",
            contents="{} by {}".format(
                info_dict["name"], info_dict["artist"].split(",")[0]
            ),
        )

        # Search for the best candidate
        song_progress.set_description(info_dict["name"] + ": Selecting Best Link")
        song_progress.update(n=1)
        link = get_link(info_dict)
        if link == "":
            continue

        # Download the song
        try:
            song_progress.set_description(info_dict["name"] + ": Downloading Song")
            song_progress.update(n=1)
            download_song(link, info_dict, audio_downloader, directory)

            # Edit the ID3 Tags
            song_progress.set_description(info_dict["name"] + ": Setting Tags")
            song_progress.update(n=1)
            set_tags(info_dict, authenticator.genius_auth, directory)

            # Move to the designated folder
            song_progress.set_description(
                info_dict["name"] + ": Moving to designated folder"
            )
            song_progress.update(n=1)
            success_counter += 1

        except Exception as e:  # pragma: no cover
            failure_counter += 1
            print(str(e))
            continue
        song_progress.close()

        # Update tqdm progress bar
        playlist_progress.update(n=1)
        send_message(
            channel,
            type="progress",
            contents=[playlist_progress.n, playlist_progress.total, success_counter, failure_counter],
        )

        elapsed = get_elapsed(playlist_progress)
        eta = get_eta(playlist_progress)
        send_message(channel, type="eta_update", contents=[elapsed, eta])

        # Check for termination message
        if not termination_channel.empty():
            message = termination_channel.get()
            if message == "EXIT":
                return

    normalize_volume_levels(directory)

    playlist_progress.close()

    send_message(channel, type="download_complete", contents=[])

# Create downloader object, pass options
def create_audio_downloader(directory: str) -> YoutubeDL:
    if not DependencyHandler.ffmpeg_installed():
        audio_downloader: YoutubeDL = YoutubeDL(
            {
                "format": "bestaudio",
                "ffmpeg_location": ".",
                "postprocessors": [
                    {
                        "key": "FFmpegExtractAudio",
                        "preferredcodec": "mp3",
                        "preferredquality": "192",
                    }
                ],
                "outtmpl": directory + "/downloaded_song.%(ext)s",
                "quiet": "true",
                "no_warnings": "true",
                "noprogress": "true",
            }
        )

    else:
        audio_downloader: YoutubeDL = YoutubeDL(
            {
                "format": "bestaudio",
                "postprocessors": [
                    {
                        "key": "FFmpegExtractAudio",
                        "preferredcodec": "mp3",
                        "preferredquality": "192",
                    }
                ],
                "outtmpl": directory + "/downloaded_song.%(ext)s",
                "quiet": "true",
                "no_warnings": "true",
                "noprogress": "true",
            }
        )
    return audio_downloader

def match_target_amplitude(sound: AudioSegment, target_dbfs: int) -> AudioSegment:
    change_in_dbfs = target_dbfs - sound.dBFS
    return sound.apply_gain(change_in_dbfs)

def normalize_volume_levels(directory: str) -> None:
    if not DependencyHandler.ffmpeg_installed():  # pragma: no cover
        print("WARNING: ffmpeg not found in PATH, volume normalization skipped.")
        return

    if not os.path.isdir(directory):
        raise ValueError("Invalid directory")

    abs_path: str = os.path.abspath(directory)

    files:[str] = os.listdir(directory)

    normalization_progress: tqdm = tqdm(
        total=len(files), desc="Normalizing Sound", position=0, leave=False
    )
    for file in files:
        if file.endswith(".mp3"):
            sound: AudioSegment = AudioSegment.from_file(abs_path + "/" + file, "mp3")
            normalized_sound: AudioSegment = match_target_amplitude(sound, -14.0)
            normalized_sound.export(abs_path + "/" + file, format="mp3")
            normalization_progress.update(n=1)


""" DisplayOriginSwap (dos)

Swaps the position of two displays using the displayplacer command line utility.
Provides a workaround to the issue where Macs will randomly reverse the screen arrangement of identical external displays.
"""

import subprocess
import sys

def get_display_list():

    # Create a list to store extracted displayplacer data as dictionaries
    display_list = []

    # Run the "displayplacer list" command and split it into lines
    output = subprocess.run(["displayplacer", "list"], capture_output=True).stdout.decode()
    lines = output.strip().split("\n")

    # Temporary dictionary to store data for each display
    current_display_data = {}

    print("Detected screens:")
    # Find lines that contain either the id, resolution or origin, and split at the colon.
    # Append the data to the dictionaries and add them to the display_list list.

    for line in lines:
        if "Persistent screen id:" in line:
            current_display_data["screen_id"] = line.split(":")[1].strip()

        if "Type:" in line:
            current_display_data["type"] = line.split(":")[1].strip()

        if "Resolution:" in line:
            current_display_data["resolution"] = line.split(":")[1].strip()

        if "Origin:" in line:
            current_display_data["origin"] = line.split(":")[1].strip()
            display_list.append(current_display_data)
            screen_index = display_list.index(current_display_data)
            print(f"screen {screen_index}: {current_display_data}")
            current_display_data = {}
    return(display_list)

def validate_inputs(displays_to_swap, display_list):
    # Check if the display indexes in displays_to_swap are within the range of available displays.
    if any(d >= len(display_list) for d in displays_to_swap):
        print("Error: One or more display indexes in displays_to_swap do not reference a detected screen.")
        sys.exit(1)

def print_display_info(displays_to_swap, display_list):
    print("\nSwapping display origin of screens:")
    for i, d in enumerate(displays_to_swap):
        print(f"screen {d}: type:{display_list[d]['type']} resolution:{display_list[d]['resolution']} \t current origin:{display_list[d]['origin']} \t new origin:{display_list[displays_to_swap[1 - i]]['origin']}")

def swap_displays(displays_to_swap, display_list):
    displayplacer_arguments = [
        f"id:{display_list[d]['screen_id']} resolution:{display_list[d]['resolution']} origin:{display_list[displays_to_swap[1 - i]]['origin']}"
        for i, d in enumerate(displays_to_swap)
    ]

    print("\nExecuting:")
    print(f"displayplacer \"{displayplacer_arguments[0]}\" \"{displayplacer_arguments[1]}\"")

    output = subprocess.run(["displayplacer", displayplacer_arguments[0], displayplacer_arguments[1]], check=True, capture_output=True).stdout.decode()

    print(output)

def main():
    displays_to_swap = (1, 2)
    display_list = get_display_list()

    validate_inputs(displays_to_swap, display_list)
    print_display_info(displays_to_swap, display_list)
    swap_displays(displays_to_swap, display_list)

if __name__ == "__main__":
    main()


"""Punter.  Watches current path (or another path) for changes and executes
command(s) when a change is detected.  Uses watchdog to track file changes.

Usage:
    punt [-w <path> ...] [-l] [-t 5] <commands>...
    punt (-h | --help)
    punt --version

Options:
    -t <time>      Minimum time to delay between consecutive runs [default: 1]
    -w <path> ...  Which path(s) to watch
    -l             Only tracks local files (disables recusive)
"""
import time
import sys
import os
import os.path
import traceback
from subprocess import call

from docopt import docopt
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

import pkg_resources  # part of setuptools
version = pkg_resources.require("punt")[0].version

def run():
    arguments = docopt(__doc__, version='punt ' + version)

    if not arguments['-w']:
        watch_paths = [os.getcwd()]
    else:
        watch_paths = []
        for watch in arguments['-w']:
            watch = os.path.abspath(watch)
            if not os.path.isfile(watch):
                sys.stderr.write("Error: {watch} does not exist".format(watch=watch))
            watch_paths.append(watch)

    recursive = not arguments['-l']
    try:
        timeout = float(arguments['-t'])
    except ValueError:
        sys.stderr.write("Error: 'timeout' must be a number\n")
        return
    commands = arguments['<commands>']

    class Regenerate(FileSystemEventHandler):
        last_run = None

        def on_any_event(self, event, alert=True):
            if self.last_run and time.time() - self.last_run < timeout:
                return
            self.last_run = time.time()

            try:
                sys.stderr.write("\033[2J\033[H\033[3J")
                sys.stderr.write('Watching %s for changes\n' % ', '.join(watch_paths))
                for command in commands:
                    desc = command.splitlines()[0]
                    if "\n" in command:
                        desc += "..."
                    sys.stderr.write("Running {0}\n".format(desc))
                    call(command, shell=True)
                sys.stderr.write("...done.\n")
            except OSError as e:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                traceback.print_exception(exc_type, exc_value, exc_traceback, file=sys.stderr)
                sys.stderr.write("Error (%s): %s\n" % (type(e).__name__, e.message))

    observer = Observer()
    handler = Regenerate()

    for watch in watch_paths:
        observer.schedule(handler, path=watch, recursive=recursive)
    observer.start()

    try:
        handler.on_any_event(None, False)  # run the first time, no alert
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        sys.stderr.write('!!! Stopping\n')
        observer.stop()
    observer.join()

if __name__ == "__main__":
    run()


#
# Protocol class
#
import numpy as np

class Protocol:
    """A Pharmokinetic (PK) protocol

    Parameters
    ----------
    dosing_type: str
        type of dosing, either intravenous or subcutaneous
    dosing_pattern: str
        dosing protocol, either instanteneous or continuous
    dose: numeric or list
        the amount of drug that enters the body
        numeric: for continuous dosing
        list: for instantaneous dosing
    T: list
        the time points when the drug is given
        only for instantaneous dosing
    absorption_rate: numeric
        absorption rate for subcutaneous dosing. If dosing is intravenous, then not defined  # noqa
    """
    def __init__(self, dosing_type, dosing_pattern, dose, T=None, absorption_rate=None):  # noqa
        self.dose, self.dosing_pattern, self.dosing_type,= dose, str(dosing_pattern), str(dosing_type),  # noqa

        if self.dosing_pattern == 'instantaneous':
            self.T = T
            if type(dose) != list:
                raise TypeError('Not correct format for dose, please use list')
            if type(T) != list:
                raise TypeError('Not correct format for dosing times, please use list')  # noqa
            if len(T) != len(dose):
                raise ValueError('Times and dose shots out of sync')

        elif self.dosing_pattern == 'continuous':
            self.T = None
            if type(dose) != float and type(dose) != int:
                raise TypeError('Not correct format for dose, please use float')  # noqa

        else:
            raise KeyError('Not correct dosing pattern')

        if self.dosing_type == 'subcutaneous':
            self.absorption_rate = absorption_rate
        elif self.dosing_type == 'intravenous':
            self.absorption_rate = None
        else:
            raise KeyError('Not correct dosing type, either intravenous or subcutaneous')  # noqa

    def create_dose_function(self, t):
        """ Creates dose function

        Create a function that models the way in which the drug enters the system.  # noqa
        Makes use of dosing pattern, dosing time and dosing type.

        :param t: time variable for the equation
        :returns: dose function
        """
        def bump_fn(t, inject_time, height, sharpness, width):
            """ Smooth step function for the dose function

            Parameters
            ----------
            inject_time: numeric
                the time the drug is injected to the system
            height: numeric
                the amount of drug, which translates to the height of the function  # noqa
            sharpness: numeric
                the steepness of the step function
            width: numeric
                the length of time when the drug is introducted

            """
            return height / (1 + np.exp(- sharpness * (t - inject_time))) - height / (1 + np.exp(- sharpness * (t - inject_time - width)))  # noqa

        sharpness = 30
        # Defines the steepness of the step function
        # Not defined by user

        dose_function = []
        if self.dosing_pattern == 'instantaneous':

            width = 0.1
            # Defines the width of the function
            # Not defined by user under the instantaneous case
            for i in range(len(self.T)):
                dose_function.append(bump_fn(t, self.T[i], self.dose[i], sharpness, width))  # noqa

        elif self.dosing_pattern == 'continuous':
            dose_function.append(self.dose)

            # for i in range(int(t_time/60)):
            #     dose_function.append(bump_fn(t,i,self.dose,sharpness,self.dose_period))

        return sum(dose_function)

    def create_subcutaneous_comp_function(self, t, q):
        """ Construct the function for subcutaneous compartment of the PK model

        Create a function that models the way in which the drug is absorbed by the system.  # noqa
        Uses absorption rate if dosing type is subcutaneous.

        :param t: time variable
        :param q: quantity to drug
        :returns: subcutaneous_comp_function

        """
        if self.dosing_type == 'subcutaneous':
            subcutaneous_comp_function = self.absorption_rate * q
        elif self.dosing_type == 'intravenous':
            subcutaneous_comp_function = self.create_dose_function(t)

        return subcutaneous_comp_function


# The rootfs generator, this script can only be run on a debian environment
# as it uses `mmdebstrap`, which is only available on debian distros

import shutil
import sys

# check if mmdebstrap exists
if shutil.which("mmdebstrap") is None:
    print("mmdebstrap does not exists", file=sys.stderr)
    exit(1)

import subprocess
import toml

# load the config file
config = None
with open("config.toml", "r") as f:
    config = toml.load(f)

# generate the sources-list and write it to a file
sources = "\n".join(config["build"]["sources-list"])
with open("mmdebstrap-sources.list", "w") as f:
    f.write(sources)
    f.flush()

mmdebstrap_process = subprocess.Popen(
    [
     "mmdebstrap",
     "--architectures=" + config["build"]["arch"],
     "--verbose",
     "--format=tar",
     "--include=" + ",".join(config["build"]["packages"]),
    ],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    shell=True
)

tar_output = mmdebstrap_process.communicate(input=sources.encode())[0]
mmdebstrap_process.wait()

with open("output.tar", "wb") as f:
    f.write(tar_output)


import turtle as t
from random import randrange

wn = t.Screen()
wn.title("Bouncing Balls")
wn.bgcolor("light yellow")
wn.setup(width=800, height=600)

# ball 1
ball1 = t.Turtle()
ball1.shape('circle')
ball1.color('red')
ball1.penup()
ball1.speed(0)
ball1.goto(100,0)

# ball 2
ball2 = t.Turtle()
ball2.shape('circle')
ball2.color('blue')
ball2.penup()
ball2.speed(0)
ball2.goto(-100,0)

def moveUp():
    x = ball1.xcor()
    y = ball1.ycor()
    ball1.goto(x, y+10)
def moveDown():
    x = ball1.xcor()
    y = ball1.ycor()
    ball1.goto(x, y-10)
def moveLeft():
    x = ball1.xcor()
    y = ball1.ycor()
    ball1.goto(x-10, y)
def moveRight():
    x = ball1.xcor()
    y = ball1.ycor()
    ball1.goto(x+10, y)

wn.listen()
wn.onkeypress(moveUp, 'Up')
wn.onkeypress(moveDown, 'Down')
wn.onkeypress(moveLeft, 'Left')
wn.onkeypress(moveRight, 'Right')

ball1.dx=randrange(-400, 400)
ball1.dy=randrange(-300, 300)

while True:
    wn.update()
    if ((ball1.xcor()>400 or ball1.xcor()<-400) and
     (ball1.ycor()>300 or ball1.ycor()<-300)):
        ball1.setx(ball1.xcor() - ball1.dx)
        ball1.sety(ball1.ycor() - ball1.dy)
        ball1.goto(0, 0)

    ball1.dx=randrange(-400, 400)
    ball1.dy=randrange(-300, 300)
    ball1.penup()
    ball1.speed(5)
    ball1.setx(ball1.xcor() + ball1.dx)
    ball1.sety(ball1.ycor() + ball1.dy)

# this is new line


import os, sys
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import json

from pytorch_forecasting import TemporalFusionTransformer, DeepAR

sys.path.insert(0, './src/prep')
from preprocess import load_data, generate_time_series, cleanup

def check_save_dir(save_dir):
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    if len(os.listdir(save_dir)) != 0:
        proceed = input('Experiment directory not empty, continue? [y/n]: ')
        if proceed != 'y':
            print('Aborted')
            sys.exit()

def update(i):
    idx_available_low = data_hh.index[data_hh['time_idx'] == i][0]
    idx_available_high = data_hh.index[data_hh['time_idx'] == encoder_length + i][0]
    idx_target_low = data_hh.index[data_hh['time_idx'] == encoder_length + i][0]
    idx_target_high = data_hh.index[data_hh['time_idx'] == encoder_length + i + prediction_length][0]

    available_data = data_hh[idx_available_low:idx_available_high]
    target_data = data_hh[idx_target_low:idx_target_high]
    # target_data.loc[target_data.index, 'cumulative_energy_volume'] = np.zeros(prediction_length)

    test_prediction, test_x = best_model.predict(pd.concat([available_data, target_data], ignore_index=True), mode="raw", return_x=True)

    ax.clear()
    best_model.plot_prediction(test_x, test_prediction, idx=0, show_future_observed=True, plot_attention=False, ax=ax)

def animate(h, frames, render=False, save_dir='animations'):
    global ax
    fig, ax = plt.subplots()

    anim = animation.FuncAnimation(fig, func=update, frames=frames)

    writer = animation.writers['ffmpeg']()
    anim.save('{}/pred-{}-hh-{}.mp4'.format(save_dir, config['prediction_length'], h), writer=writer, dpi=100)
    if render:
        plt.show()

if __name__ == '__main__':

    # load model
    experiment = "logs/baseline"
    best_model_path = f"{experiment}/models/default/version_0/checkpoints/epoch=2-step=89.ckpt"

    # Define save directory
    save_dir = f"{experiment}/animations"
    check_save_dir(save_dir)
    with open(f"{experiment}/config.json", 'r') as f:
        config = json.load(f)

    if config["type"] == "tft":
        best_model = TemporalFusionTransformer.load_from_checkpoint(best_model_path)
    elif config["type"] == "deepar":
        best_model = DeepAR.load_from_checkpoint(best_model_path)

    num = {'15min': 15, '30min': 30, '1hour': 60}
    prediction_length = int(config['prediction_length'] * 60 / num[config['resolution']])
    encoder_length = int(config['context_length'] * 60 / num[config['resolution']])

    # Load test data
    n_hh = 20
    file = './src/data/LD2011_2014.txt'
    data = load_data(file, hh_start=-n_hh-1, hh_end=-1, start='2014-01-01 00:15:00', stop="2015-01-01 00:00:00")
    data = cleanup(data)

    households = [0]
    for h in households:
        # select household
        data_hh = generate_time_series(data.iloc[:, h:h+1], resolution=config['resolution'])
        data_hh.index = data_hh['time_idx']

        animate(h, frames=2*144, save_dir=save_dir, render=False)


import pandas as pd
import matplotlib.pyplot as plt

def compute_mean_std_r2_scores(scores):
    """
    """
    scores_mean = pd.Series(scores.mean(axis=1))
    scores_std = pd.Series(scores.std(axis=1))

    return scores_mean, scores_std

aliases = {'age': 'Age',
           'age_at_assessment': 'Age at assessment',
           'fluid_intelligence': 'Fluid intelligence',
           'neuroticism': 'Neuroticism'}

train_sizes = {'age': [100, 500, 1000, 1500, 2000, 2500, 3000, 3500, 3700],
               'age_at_assessment': [100, 500, 1000, 1500, 2000, 2500, 3000, 3600],
               'fluid_intelligence': [100, 500, 1000, 1500, 2000, 2500, 3000, 3500, 3700],
               'neuroticism': [100, 500, 1000, 1500, 2000, 2500, 3000, 3195]}

targets = ['age', 'fluid_intelligence', 'neuroticism']

colors = {'train': 'r',
          'validation': 'g'}

df = []

for curve_type in ['train', 'validation']:
    color = colors[curve_type]
    for i, target in enumerate(targets):
        data = {}
        this_sizes = train_sizes[target]
        scores = pd.read_csv('inputs/{}_scores_predict_{}.csv'.format(curve_type,
                                                                        target))
        scores = scores.drop('Unnamed: 0', axis=1)
        scores_mean, scores_std = compute_mean_std_r2_scores(scores)
        data['mean'] = scores_mean
        data['std'] = scores_std
        data['target'] = pd.Series([aliases[target]] * len(scores_mean),
                                   index=scores_mean.index)
        data['learning_type'] = pd.Series([curve_type] * len(scores_mean),
                                          index=scores_mean.index)
        data['train_sizes'] = pd.Series(train_sizes[target])
        df.append(pd.concat(data, axis=1))

df = pd.concat(df)
df.to_csv('learning_curves.csv', index=False)


import json
import pprint
from datetime import datetime
from inventoryMethods import *
from collections import deque
from copy import deepcopy

transactions = json.load(open("transactions.txt"))
inventory = {}
sales = []
totalSales = {} # No use yet, but required to total return metrics

specified_order = False # This is a filler, for the transactionReader

# Accounting rules, tentatively prefer FIFO as base case
FIFO = True
LIFO = not FIFO

# Inventory creation - parse through all transactions
for key in sorted(transactions.keys()): # Sorted keys matter here because inventory creation follows strict sequence
    for transaction in transactions[key]:
        if transaction["Type"] == "BUY":
            # Add item to inventory
            basis = {key: transaction["Price"], "Quantity": transaction["Quantity"]}
            try:
                if FIFO:
                    inventory[transaction["SKU"]].append(basis)
                elif LIFO:
                    inventory[transaction["SKU"]].insert(0, basis)
            except KeyError:
                inventory[transaction["SKU"]] = [basis]
        elif transaction["Type"] == "SELL":
            # Remove item from inventory
            if specified_order:
                specified_order = False # Filler action - should search inventory for items to move to sales
            else:
                costIndex = 0
                removeCount = 0

                # Cost detail for sales array
                tempDetailSKU = {"Cost": []}

                while removeCount < transaction["Quantity"]:
                    # Move items from inventory to sales array
                    inventoryClone = deepcopy(inventory[transaction["SKU"]][0])
                    tempDetailSKU["Cost"].append(inventoryClone)
                    incrementalRemoved = min(inventoryClone["Quantity"], transaction["Quantity"] - removeCount)
                    tempDetailSKU["Cost"][costIndex]["Quantity"] = deepcopy(incrementalRemoved)
                    costIndex += 1

                    # Remove sold items from inventory
                    removeCount += incrementalRemoved
                    if incrementalRemoved >= inventory[transaction["SKU"]][0]["Quantity"]:
                        inventory[transaction["SKU"]].pop(0)
                        if inventory[transaction["SKU"]] == []:
                            inventory.pop(transaction["SKU"], None) # Maintain "Active Inventory"
                    else:
                        inventory[transaction["SKU"]][0]["Quantity"] -= incrementalRemoved # Reduce inventory quantity

                # Sale detail for sales array
                tempSaleDetail = {
                    key: transaction["Price"],
                    "Quantity": transaction["Quantity"]
                    }
                tempDetailSKU["Sale"] = [tempSaleDetail]
                tempDetailSKU["SKU"] = transaction["SKU"]
                sales.append(tempDetailSKU)

            # Add subtype/subcategory for presale, or create separate - presales do not work with IRR calculations
        elif transaction["Type"] == "TRADE":
            processTrade(transaction, inventory, specified_order, sales)
        else:
            print("Not a valid transaction")

# Testing
print("Transactions=====================================")
pprint.pprint(transactions)
print("Inventory=====================================")
pprint.pprint(inventory)
print("Sales=====================================")
pprint.pprint(sales)

json.dump(inventory, open("inventory.txt", 'w'))
json.dump(sales, open("sales.txt", 'w'))


from tkinter import *

def readBoth():
    maxLenghtOfTopHundrets = 100
    minimumWordLenght = 3
    gameRules = []
    sortedGameRules = []
    amountOfNumbers = []
    allowedWords = []

    topHundretsNumbers = []
    topHundretsWords = []

    countUp = 0
    topAllHundrets = ""

    validwords='wordlist.txt'
    lettervalues='letterValues.txt'

    #opens both files to read them
    with open(validwords, "r") as f:
        allWords = f.read().splitlines()

    #makes a list with the gamerules
    with open(lettervalues, "r") as f:
        for line in f:
            gameRules += line.lower().split(":")

        for each in gameRules:
            onepart = each.replace("\n", "")
            try:
                onepart = int(onepart)
            except:
                pass
            sortedGameRules.append(onepart)

        #makes a dictionnary
        itter = iter(sortedGameRules)
        dictionnaryRule = dict(zip(itter, itter))

        #calculates every letter trought the dictionnary
        #will also skip the words with lenght over the value of minimumWordLenght
    for eachWord in allWords:
        if not len(eachWord) <= minimumWordLenght:
            currentNumber = 0
            for eachLetter in eachWord:
                currentNumber += dictionnaryRule[eachLetter]
            amountOfNumbers.append(currentNumber)
            allowedWords.append(eachWord)

    #will take the top 100 words in value
    for each in range(maxLenghtOfTopHundrets):
        countUp += 1
        PlaceAndWord = amountOfNumbers.index(max(amountOfNumbers))
        #extra, all numbers and words in these 2 lists
        topHundretsNumbers.append(amountOfNumbers[PlaceAndWord])
        topHundretsWords.append(allowedWords[PlaceAndWord])

        topAllHundrets += (str(countUp) + ". " + allowedWords[PlaceAndWord] + "- Valueying :" + str(amountOfNumbers[PlaceAndWord]) + " Points\n")
        del amountOfNumbers[PlaceAndWord]
        del allowedWords[PlaceAndWord]

    #shows on window
    show(topAllHundrets)

#for a Tkinter window
def show(content):
    window = Tk()

    showWindow = Text(window, height=30)
    showWindow.insert('1.0', content)
    showWindow.grid()

    showWindow.configure(state=DISABLED)

    window.title("Leaderboard")
    window.geometry("500x500")
    window.mainloop()

readBoth()


from google.cloud import bigquery
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "C:/Users/bdebe/Documents/GIT/TAMIDS/datacompetition-71e5d3ebc025.json"

client = bigquery.Client()
bucket_name = 'snappy-guard-200200'

for x in range(10,78):
    try:
        currentCom = str(x)
        tableName = 'community_' + str(currentCom)
        destinationName = 'testing_data/' + tableName + '.csv'
        destination_uri = 'gs://{}/{}'.format(bucket_name, destinationName)
        dataset_ref = client.dataset('taxidataTest')
        table_ref = dataset_ref.table(tableName)
        extract_job = client.extract_table(
            table_ref, destination_uri)  # API request
        extract_job.result()
        print("COMPLETE: " + currentCom)
    except:
        print("Issue with: " + currentCom + "--" + tableName)


class GameStats:
    """跟踪游戏的统计信息"""

    def __init__(self, ai_game):
        """初始化统计信息"""
        self.settings = ai_game.settings
        self.reset_stats()
        self.game_active = False
        self.score_filename = "high_score.txt"
        self.level = 1
        self._get_high_score()

    def reset_stats(self):
        """初始化在游戏运行期间可能发生变化的量"""
        self.ship_left = self.settings.ship_limit
        self.score = 0
        self.level = 1
    def _get_high_score(self):
        try:
            with open(self.score_filename) as f:
                content = f.read().strip()
                self.high_score = int(content)
        except FileNotFoundError:
            self.high_score = 0

    def write_high_score(self):
        with open(self.score_filename, 'w') as f:
            f.write(str(self.high_score))


"""
PCA with missing data

authors: Cliff Anderson-Bergman
         Kina Kincher-Winoto
"""
import numpy as np
from ._decomposer import _Decomposer
from . import pca_tools as pt

class PCA(_Decomposer):
    """
    Class for PCA

    """
    def __init__(self, rank=1, tol=0.01):
        _Decomposer.__init__(self, rank, tol)
        self.__colMeans = None
        self.__colSds = None

    @property
    def colMeans(self):
        return(self.__colMeans)
    @colMeans.setter
    def colMeans(self, colMeans):
        self.__colMeans = colMeans

    @property
    def colSds(self):
        return(self.__colSds)
    @colSds.setter
    def colSds(self, colSds):
        self.__colSds = colSds

    def fit(self, X, U0=None, V0=None, tol=0.001, post_svd=True,
        method="alt_newt", max_iters=100, center = True, scale = True,
        verbose = False):
        """
        Fits PCA with scaling
        """
        return self._fit(X, U0, V0, tol, post_svd, method,
                         max_iters, center, scale, verbose = verbose)

    def _fit(self, X, U0, V0, tol,
             post_svd, method, max_iters,
             center, scale, verbose = False):
        self.data = X
        nRows = X.shape[0]
        nCols = X.shape[1]
        mask = np.logical_not( np.isnan(X) )
        # Step 1: Standardize data
        stdzInfo = pt.stdzData(X, center = center, scale = scale)
        X_use = stdzInfo["data"]
        self.colMeans = stdzInfo["colMeans"]
        self.colSds = stdzInfo["colSds"]

        # Step 2: Initialize Factors
        if U0 is None or U0.shape != (nRows,self.rank):
            U0 = np.random.normal(scale=0.1, size=(nRows, self.rank))
        if V0 is None or V0.shape != (nCols, self.rank):
            V0 = np.random.normal(scale=0.1, size=(nCols, self.rank))

        U = U0
        V = V0

        # Step 3: Alternating Least Squares
        iter = 0
        err = np.infty
        old_loss = pt.pcaLoss(U, V, X_use)
        while( (iter < max_iters) & (err > tol)):
            iter = iter + 1
            U = pt.updateU(U, V, X_use, mask)
            V = pt.updateV(U, V, X_use, mask)
            new_loss = pt.pcaLoss(U, V, X_use)
            err = old_loss - new_loss
            old_loss = new_loss
            if(verbose):
                print("Current Loss = ", new_loss)

        self.U = U
        self.V = V

        theta = U @ V.transpose()
        fitted = pt.unStdzData(stdzInfo, theta)

        self.fitted = fitted


# -*- coding: utf-8 -*-
"""
Created on Wed Feb 16 22:28:52 2022

@author: madha
"""

from selenium.webdriver.common.by import By
from selenium import webdriver
from collections import OrderedDict
import requests
import re
import pandas as pd
import csv
import os

def return_timestamp(a):
    return a[1]

chromeDriverPath = "C:/users/madha/chromedriver.exe"
driver = webdriver.Chrome(executable_path = chromeDriverPath)

lookupDf = pd.read_csv("C:/users/madha/documents/wikiproject/userboxProjectLookup.csv")
lookup = {}
for i in lookupDf.index:
    lookup[lookupDf["project"][i]] = lookupDf["id"][i]

userboxInputVarsPath = "C:/users/madha/dropbox/wikiproject_data_download/wikiproject_userboxes.xlsx"
userboxInputsDf = pd.read_excel(userboxInputVarsPath)
groupedInputs = userboxInputsDf.groupby("Project")

statsPath = "C:/users/madha/documents/wikiproject/user_lists/userbox_joindates_stats.csv"
statsPathExists = os.path.exists(statsPath)
with open(statsPath, "a", newline = "", encoding = "utf-8") as statsCsv:
    statsWriter = csv.writer(statsCsv, quoting = csv.QUOTE_MINIMAL)
    if not statsPathExists:
        statsWriter.writerow(["project", "numberOfUsers", "numberFailed"])
    for project, group in groupedInputs:
        print(project)
        outputPath = "C:/users/madha/documents/wikiproject/user_lists/userbox_projects/" + str(lookup[project]) + ".csv"
        failedPath = "C:/users/madha/documents/wikiproject/user_lists/userbox_projects/failed/" + str(lookup[project]) + ".csv"
        # load saved state from previous iteration
        alreadyDone = set()
        alreadyFailed = set()
        if os.path.exists(outputPath):
            doneDf = pd.read_csv(outputPath, encoding = "utf-8")
            for doneUser in doneDf["user"]:
                alreadyDone.add(doneUser)
        if os.path.exists(failedPath):
            alreadyFailedDf = pd.read_csv(failedPath, encoding = "utf-8")
            for failedUser in alreadyFailedDf["user"]:
                alreadyFailed.add(failedUser)
        with open(outputPath, "a", newline = "", encoding = "utf-8") as outputCsv:
            writer = csv.writer(outputCsv, quoting = csv.QUOTE_MINIMAL)
            if os.path.getsize(outputPath) == 0:
                writer.writerow(["user", "join-date", "project", "matchedText", "matchedPage", "type"])

            group.reset_index(drop = True, inplace = True)
            categoryPage = "https://en.wikipedia.org/wiki/" + group["Page"][0]
            if pd.notna(group["type"][0]):
                projectType = group["type"][0]
            else:
                projectType = "s"
            driver.get(categoryPage)
            users = OrderedDict()

            # get names of all pages with userbox
            cont = True
            while(cont):
                links = driver.find_elements(By.TAG_NAME, "a")
                cont = False
                contLink = None
                for link in links:
                    if link.text == "next page":
                        contLink = link
                        cont = True
                    if link.text.startswith("User:"):
                        username = link.text[5:].split("/", maxsplit = 1)[0]
                        if username not in users.keys():
                            users[username] = []
                        users[username].append(link.text)
                if contLink:
                    contLink.click()

            S = requests.Session()
            URL = "https://en.wikipedia.org/w/api.php"
            with open(failedPath, "a", newline = "", encoding = "utf-8") as failedCsv:
                failedWriter = csv.writer(failedCsv, quoting = csv.QUOTE_MINIMAL)
                if os.path.getsize(failedPath) == 0:
                    failedWriter.writerow(["user", "project"])
                numberFailed = len(alreadyFailed)
                for user, pages in users.items():
                    if user in alreadyDone or user in alreadyFailed:
                        continue
                    PARAMS = {
                        "action": "query",
                        "prop": "revisions",
                        "rvprop": "content|timestamp",
                        "rvdir": "newer",
                        "rvlimit": "max",
                        "rvslots": "main",
                        "format":"json",
                        "formatversion": "2"
                    }

                    matchFound = False
                    matches = []
                    for page in pages:
                        print(page)
                        PARAMS["titles"] = page
                        PARAMS.pop("rvcontinue", None)
                        # get revision history of page
                        while(True):
                            R = S.get(url = URL, params = PARAMS)
                            json = R.json()
                            revs = json["query"]["pages"][0]["revisions"]
                            # search revisions for appearance of regex
                            for rev in revs:
                                timestamp = rev["timestamp"]
                                # content could be revision-deleted
                                if "content" in rev["slots"]["main"].keys():
                                    content = rev["slots"]["main"]["content"]
                                else:
                                    continue
                                for regex in group["Regex"]:
                                    match = re.search(regex, content, flags = re.IGNORECASE)
                                    if match:
                                        matches.append([user, timestamp, project, match.group(0), page, projectType])
                                        matchFound = True
                                        break
                                if matchFound:
                                    break
                            if matchFound:
                                break
                            if "continue" in json.keys() and "rvcontinue" in json["continue"].keys():
                                PARAMS["rvcontinue"] = json["continue"]["rvcontinue"]
                            else:
                                break
                    if len(matches) > 0:
                        earliestMatch = min(matches, key = return_timestamp)
                        writer.writerow(earliestMatch)
                    else:
                        failedWriter.writerow([user, project])
                        numberFailed += 1
        statsWriter.writerow([project, len(users), numberFailed])


from flask import Blueprint, request, jsonify
import traceback
from config.config import Config
from models.meal import Meals
import jwt
from auth.verify_token import verify_user

meal_route = Blueprint('meal_route', __name__)

@meal_route.route('/meals', methods=['POST'])
def create_meal():
    try:

        if not verify_user(request.headers.get('x-access-token')):
            return jsonify({
                'accepted': False,
                'message': 'invalid token'
            }), 406

        if not request.form.get('calories'):
            return jsonify({
                'accepted': False,
                'message': 'calories is a required field'
            }), 406

        if not request.form.get('category'):
            return jsonify({
                'accepted': False,
                'message': 'category is a required field'
            }), 406

        if not request.form.get('isIngredient'):
            return jsonify({
                'accepted': False,
                'message': 'isIngredient is a required field'
            }), 406

        if not request.form.get('isSelected'):
            return jsonify({
                'accepted': False,
                'message': 'isSelected is a required field'
            }), 406

        if not request.form.get('name'):
            return jsonify({
                'accepted': False,
                'message': 'name is a required field'
            }), 406

        if not request.form.get('recipe'):
            return jsonify({
                'accepted': False,
                'message': 'recipe field is a required field'
            }), 406

        if not request.form.get('servingSize'):
            return jsonify({
                'accepted': False,
                'message': 'serving size is a required field'
            }), 406

        if not request.form.get('taken'):
            return jsonify({
                'accepted': False,
                'message': 'taken is a required field'
            }), 406

        if not request.form.get('unit'):
            return jsonify({
                'accepted': False,
                'message': 'unit is a required field'
            }), 406

        Meals(
            calories=request.form.get('calories'),
            category=request.form.get('category'),
            isIngredient=request.form.get('isIngredient'),
            isSelected=request.form.get('isSelected'),
            name=request.form.get('name'),
            recipe=request.form.get('recipe'),
            servingSize=request.form.get('servingSize'),
            taken=request.form.get('taken'),
            unit=request.form.get('unit')
        ).save()

        return jsonify({
            'accepted': True,
            'message': 'meal created successfully'
        }), 200

    except Exception:
        traceback.print_exc()
        return jsonify({
            'accepted': False,
            'message': 'internal server error'
        }), 500

@meal_route.route('/meals/<int:page>', methods=['GET'])
def get_meals(page):

    try:

        if not verify_user(request.headers.get('x-access-token')):
            return jsonify({
                'accepted': False,
                'message': 'invalid token'
            }), 406

        meals = []
        if page == 1:
            for meal in Meals.objects.limit(10):
                meals.append({
                    meal.name: {
                        'calories': meal.calories,
                        'category': meal.category,
                        'id': str(meal.id),
                        'isIngredient': meal.isIngredient,
                        'isSelected': meal.isSelected,
                        'name': meal.name,
                        'recipe': meal.recipe,
                        'servingSize': meal.servingSize,
                        'taken': meal.taken,
                        'unit': meal.unit
                    }
                })

            return jsonify(meals), 200

        for meal in Meals.objects.skip((page-1)*10).limit(10):
            meals.append({
                meal.name: {
                    'calories': meal.calories,
                    'category': meal.category,
                    'id': str(meal.id),
                    'isIngredient': meal.isIngredient,
                    'isSelected': meal.isSelected,
                    'name': meal.name,
                    'recipe': meal.recipe,
                    'servingSize': meal.servingSize,
                    'taken': meal.taken,
                    'unit': meal.unit
                }
            })
        return jsonify(meals), 200
    except Exception:
        traceback.print_exc()
        return jsonify({
            'accepted': False,
            'message': 'internal server error'
        })


# CPSC 231 ASSIGNMENT TWO PART 2: Ball and Spring in Two Dimensions         Coded by 10099049; Michael Hung

########################################## variable definitions ###########################################

l = 200.0       # length of the spring at equilibrium
k = 1.0         # spring constant
g = 9.8         # acceleration due to gravity
t = 0.02        # time interval
m = 10.0        # mass of the ball
vx = 2.0        # initial horizontal velocity of the ball
vy = 0.0        # initial vertical velocity of the ball

xB = 200.0      # initial horizontal position of ball
yB = 300.0      # initial vertical position of ball

xS = 20.0       # horizontal position of fixed end of spring
yS = 20.0       # vertical position of fixed end of spring

timer = 5000   # timer to end the loop

########################################### function definitions ###########################################

def force_g(m, g):                                  # Calculates the force of gravity
    return m * g

def d_new(position, v, t):                          # Updates the position of the ball
    return position + v * t

def length_spr(xB, yB, xS, yS):                       # Updates the length of the spring
    x_change = xB - xS
    y_change = yB - yS
    l_new = (x_change ** 2 + y_change ** 2) ** 0.5
    return l_new

def force_dir(position, spring_position, l):        # Updates the direction of force
    return (position - spring_position) / l

def force_spr(k, l, l_new, xy_dir):              # Updates the force exerted by the spring
    return -k * (l_new - l) * xy_dir

########################################### animating the ball ############################################

print("graphicsflush False")

while timer > 0:

    l_new = length_spr(xB, yB, xS, yS)

    Fnet_x = force_spr(k, l, l_new, force_dir(xB, xS, l))
    Fnet_y = force_spr(k, l, l_new, force_dir(yB, yS, l)) + force_g(m, g)

    vx += (Fnet_x / m) * t
    vy += (Fnet_y / m) * t

    xB += vx * t
    yB += vy * t

    timer -= 1

    print("color 0 0 0")
    print("clear")

    print("color 200 255 155")
    print("line 0 10 1000 10")

    print("color 100 100 100")
    print("line", 400, 11, xB + 400, yB)

    print("color 255 0 0")
    print("fillcircle", xB + 400, yB, "20")

    print("refresh")


class Test:
    name = "test"  # class variable
    def __init__(self):
        self.name2 = 'name'  # instance variable
        self.name = 'abc'
        # Test.name = 'abc'

t = Test()
print(t.name, t.name2)
print(Test.name)


'''
 rmtoo
   Free and Open Source Requirements Management Tool

 This file contains the internals handling of the
 configuration classes.

 (c) 2011 by flonatel GmhH & Co. KG

 For licensing details see COPYING
'''
from types import DictType, StringType, UnicodeType
from rmtoo.lib.configuration.CfgEx import CfgEx

class InternalCfg:
    '''Internal configuration utility class.'''

    def __init__(self):
        '''Hide utility class constructor.'''
        assert(False)

    @staticmethod
    def convert_key(key):
        '''If the key is a string, it is converted to the internally
           used list of strings.
           The original string is split at '.'.'''
        if type(key) in [StringType, UnicodeType]:
            return InternalCfg.parse_key_string(key)
        return key

    @staticmethod
    def parse_key_string(key):
        '''Parses the given string and splits it up for using with
           the configuration dictionary'''
        return key.split('.')

    @staticmethod
    def get_value(key, ldict):
        '''Returns the key from the given dictionary.
           If this is not the last part of the key, this method
           is called recursively.'''
        assert(type(ldict) == DictType)
        assert(len(key) > 0)
        if key[0] not in ldict:
            raise CfgEx("(Sub-)Key [%s] not found." % key[0])
        val = ldict[key[0]]
        # No more keys to go for.
        if len(key) == 1:
            return val
        if type(val) != DictType:
            raise CfgEx("(Sub-)Type of configuration for key [%s] not a "
                        "dictionary " % key[0])
        return InternalCfg.get_value(key[1:], val)

    @staticmethod
    def change(ldict, key, empty_val, change_func):
        '''Change the given key with the help of the change_func.
           If value does not exists, the empty_val is used for
           initial initialization.'''
        assert(type(ldict) == DictType)
        assert(len(key) > 0)

        # Only use the given empty value for the last value in the
        # key-chain.  All others must be dictionaries.
        if key[0] not in ldict:
            if len(key) > 1:
                ldict[key[0]] = {}
            else:
                ldict[key[0]] = empty_val

        if len(key) == 1:
            # Really insert the value (if not there).
            change_func(ldict, key[0])
            return

        InternalCfg.change(ldict[key[0]], key[1:], empty_val, change_func)

    @staticmethod
    def set_value(ldict, key, value):
        '''Sets the value for the appropriate key.
           If the key has already a value (i.e. exists)
           a CfgEx is raised.'''
        def assign_value(ldict, key):
            '''Change function for a dictionary.'''
            ldict[key] = value

        InternalCfg.change(ldict, key, None, assign_value)

    @staticmethod
    def append_list(ldict, key, value):
        '''Appends the value to the list at key.
           If key is not available a new list is created.'''
        def append_value(ldict, key):
            '''Change function for a list.'''
            ldict[key].append(value)

        InternalCfg.change(ldict, key, [], append_value)


import sys
sys.dont_write_bytecode = True

import unittest
from datetime import datetime, timedelta

def dates_within(dt1, dt2, limit, units):
    """ Helper function to several others.
        returns True if dt1 and dt2 are within limit units, where
        dt1, dt2 are instances of datetime
        limit is a number
        units is a string in ('days', 'months', 'years')
    """
    units = units.lower()
    conversion = {'days':1, 'months':30.4, 'years':365.25}
    return ((abs((dt1 - dt2).days) / conversion[units]) < limit) if units in ('days', 'months', 'years') else None

def i_dates_in_future(individuals):
    """ US01: No Date in individuals can happen after current date.
        Tests that any given individual has only valid dates.
                True: Date is valid
                False: Date is invalid because is in the future
    """
    for date in [individuals.birthday, individuals.deathday]:
        if date != "N/A" and date < datetime.today():
            return True
        else:
            print("ERROR: INDIVIDUAL: US01: individual with ID", individuals.id, "contains date", date.date(), "which occurs in the future")
            return False

def f_dates_in_future(families):
    """ US01: No Date in a family can happen after current date
        Tests that any given family has only valid dates.
                True: Date is valid
                False: Date is invalid because is in the future
    """
    for date in [families.marriage, families.divorce]:
        if date != "N/A" and date < datetime.today():
            return True
        else:
            print("ERROR: FAMILY: US01: family with ID", families.id, "contains date", date.date(), "which occurs in the future")
            return False

def ageGreaterThan(individual):
    """ US07: No individual can live more than 150 years.
            False: Individual lives more than 150 years.
    """
    dt2 = individual.deathday if individual.deathday != 'N/A' else datetime.today()
    if dates_within(individual.birthday, dt2, 150, 'years'):
            return True
    else:
            print("ERROR: INDIVIDUAL: US07", individual.name, "with ID", individual.id, "lives more than 150 years. Birth date is", individual.birthday.date())
            return False

def birthBeforeMarriage(individual, family):
    """ US08: Children should be born after marriage of parents
    and not more than 9 months after their divorce
    """
    if individual.birthday < family.marriage and individual.famc != "N/A":
        print("ERROR: INDIVIDUAL: US08", individual.name, "with ID", individual.id, "is born before his/her parents got married")
        return False
    if family.divorce != "N/A" and individual.birthday > (family.divorce + timedelta(days=30*9)):
        print("ERROR: INDIVIDUAL: US08", individual.name, "with ID", individual.id, "is born over 9 months after his parents divorce")
        return False
    else:
        return True

def birthBeforeDeath(individual, mom, dad):
    """ US09: Child should be born before death of mother
    and before 9 months after death of father """
    if mom.deathday != "N/A" and individual.birthday > mom.deathday:
        print("ERROR: INDIVIDUAL: US09", individual.name, "with ID", individual.id, "is born after his/her mom died")
        return False
    if dad.deathday != "N/A" and individual.birthday > (dad.deathday + timedelta(days=9*30)):
        print("ERROR: INDIVIDUAL: US09", individual.name, "with ID", individual.id, "is born over 9 months after his/her dad died")
        return False
    else:
        return True

def chk_living_married(individual):
    """ US30: Helper function for US30. Checks if individual meets conditions of being alive and married"""
    return True if individual.fams != 'N/A' and individual.deathday == 'N/A' else False

def list_living_married(individuals):
    """ US30: Uses chk_living_married to decide which individuals to add to the LivingMarried list """
    livingMarried = [individual.id for individual in individuals.values() if chk_living_married(individual) == True]
    print("US30: These are the individuals who are Married and still alive:")
    print(livingMarried)
    return(livingMarried)

def chk_living_single(individual):
    """ US31: Helper function for US31. Checks if individual meets conditions of being alive, older than 30 and never been married"""
    return True if individual.fams == 'N/A' and individual.deathday == 'N/A' and not(dates_within(individual.birthday, datetime.today(), 30, 'years')) else False

def list_living_single(individuals):
    """ US31: Uses chk_living_single to decide which individuals to add to the LivingSingle list """
    livingSingle = [individual.id for individual in individuals.values() if chk_living_single(individual) == True]
    print("US31: These are the individuals who are Single, alive, and over 30 years old:")
    print(livingSingle)
    return(livingSingle)

def list_deceased(individuals):
    """ US29: checks individuals in a GEDCOM to see if they meet the condition of being deceased, and lists them """
    deceased = [individual.id for individual in individuals.values() if individual.deathday != 'N/A']
    print("US29: These are the individuals who are deceased:")
    print(deceased)
    return(deceased)

def list_orphan(individual, mom, dad):
    """ US33: Uses chk_orphan to decide which individuals to add to the orphans list """
    orphans = []
    if mom.deathday != "N/A" and dad.deathday != "N/A" and dates_within(individual.birthday, datetime.today(), 18, "years"):
        orphans.append(individual.id)
    print("These are the individuals who are younger than 18, and who's parents are both dead:")
    print(orphans)
    return(orphans)

def main(individuals, families):

    # for individuals, families in individuals.values(), families.values():
    #     IDatesInFuture(indi, fam)

    list_living_married(individuals)
    list_living_single(individuals)

    for family in families.values():
        f_dates_in_future(family)

    for individual in individuals.values():
        ageGreaterThan(individual)
        i_dates_in_future(individual)
        if individual.famc != "N/A":
            birthBeforeMarriage(individual, families[individual.famc])
            birthBeforeDeath(individual, individuals[families[individual.famc].wife], individuals[families[individual.famc].husband])
            list_orphan(individual, individuals[families[individual.famc].wife], individuals[families[individual.famc].husband])


from flask import Flask, request, render_template, jsonify
from flask_uwsgi_websocket import GeventWebSocket
from blockchain import *
from param import *
import asyncio
import websockets

# As a trival center, the server should maintain the pear list as
# well as transaction pool for nodes.
peerList = set()
txnPool = []

# HTTP Interface Methods
app = Flask(__name__)
ws = GeventWebSocket(app)

def initServer():
    ''' Start the HTTP server. The port can be set
        in other files. '''
    app.run(host = '0.0.0.0', port = HTTP_port, debug = True)
    return

@app.route('/', methods = ['GET'])
def home():
    return render_template('home.html')

@app.route('/showChain', methods = ['GET'])
def showChain():
    global blockchain
    return blockchain.getJSON()

@app.route('/getIP', methods = ['GET'])
def getIP():
    return request.remote_addr

@app.route('/addPeer', methods = ['GET', 'POST'])
def addPeer():
    global peerList
    peerList.add(request.remote_addr)
    return '
'.join([str(x) for x in peerList])

@app.route('/broadcastTxn', methods = ['GET'])
def broadcastTxn_get():
    return render_template('mine.html')

@app.route('/broadcastTxn', methods = ['POST'])
def broadcastTxn_post():
    # TODO: The TXN here ought to be a object instead of str.
    data1 = request.form['data1']   # Output address
    data2 = request.form['data2']   # amount
    global blockchain, txnPool
    index = blockchain.getLength()
    ID = calculateHash(str(data1) + str(data2) + str(index))
    txn = "
{Transaction ID: " + str(ID) + "
IN: " + str(SENDDEFAULT_publickey) + "->
OUT: " + str(data1) + "
Amount: " + str(data2) + "Coins}"
    txnPool.append(txn)
    return 'OK message sent!'

@app.route('/showPool', methods = ['GET'])
def showPool():
    return ' '.join([i for i in txnPool])

@app.route('/getConnectAddress', methods = ['GET', 'POST'])
def getConnectAddress():
    return render_template('peerConnect.html')

@ws.route('/getConnect')
def getConnect_ws(wscon):
    count = 0
    users = {}
    users[wscon.id] = wscon
    while True:
        message = wscon.receive()
        if message is not None:
            for id in users:
                users[id].send(message, count)
                count += 1
        else:
            break
    del users[wscon.id]

# P2P Interface Methods
def initListen():
    ''' Set up a websocket listener on local host and port. '''
    start_websocket = websockets.serve(setupConnect, '0.0.0.0', P2P_port)
    print('Start listening on 0.0.0.0:', P2P_port)
    asyncio.get_event_loop().run_until_complete(start_websocket)
    asyncio.get_event_loop().run_forever()

async def setupConnect(websocket, path):
    ''' Set up a ONE-TIME connect listener. Receive the Client info and
    return the blockchain info.'''
    global blockchain
    queryJSON = await websocket.recv()
    query = json.loads(queryJSON)
    print(query)
    clientInfo = query['ClientInfo']
    peerList.add(clientInfo)
    if query['Query'] == P2P_query_ALLBLOCK:
        blockInfo = blockchain.getJSON()
        await websocket.send(blockInfo)
    else:
        await websocket.send("Hi")

if __name__ == '__main__':
    #initServer()
    initListen()


# -*- coding: utf-8 -*-

"""
 Abstract: These classes are implementations of the core concept 'object', as defined in coreconcepts.py
           The class is written in an object-oriented style.
"""

__author__ = "Eric Ahlgren"
__copyright__ = "Copyright 2014"
__credits__ = ["Eric Ahlgren", "Andrea Ballatore"]
__license__ = ""
__version__ = "0.1"
__maintainer__ = ""
__email__ = ""
__date__ = "December 2014"
__status__ = "Development"

import ogr

from utils import _init_log
from coreconcepts import CcObject, CcObjectSet

log = _init_log("objects")

VALID_RELATIONS = ('Intersects','Equals','Disjoint','Touches','Crosses','Within','Contains','Overlaps')

def from_file(filepath):
    shp = ogr.Open(filepath)

    return OgrShpObjectSet(shp)

class OgrShpObject(CcObject):
    """
    Subclass of Abstract Object (CcObject) in the ArcMap Shapefile format
    """
    def __init__( self, filepath, objIndex ):
        shpfile =  ogr.Open(filepath)
        layer = shpfile.GetLayer(0)
        self.sObj = layer.GetFeature(objIndex)

    def bounds( self ):
        #Get geometery
        geom = self.sObj.GetGeometryRef()
        env = geom.GetEnvelope()
        #Return bounds in form (MinX, MaxX, MinY, MaxY)
        return env

    def relation( self, obj, relType ):

        if relType not in VALID_RELATIONS:
            raise ValueError("{0} is not a valid value for 'relType'.".format(relType))

        #Get geometeries
        geom1 = self.sObj.GetGeometryRef()
        geom2 = obj.sObj.GetGeometryRef()
        return getattr(geom1,relType)(geom2) #getattr is equivalent to geom1.relType

    def property( self, prop ):
        #Get index of property - note: index 13 is building name
        index = self.sObj.GetFieldIndex(prop)

        if index == -1:
            raise ValueError("{0} is not a valid property.".format(prop))

        propDefn = self.sObj.GetFieldDefnRef(index)
        propType = propDefn.GetType()
        #Return value as a propType
        if propType == "OFTInteger":
            value = self.sObj.GetFieldAsInteger(index)
        elif propType == "OFTReal":
            value = self.sObj.GetFieldAsDouble(index)
        elif propType == "OFTString":
            value = self.sObj.GetFieldAsString(index)
        elif propType == "OFTBinary":
            value = self.sObj.GetFieldAsBinary(index)
        elif propType == "OFTDateTime":
            value = self.sObj.GetFieldAsDateTime(index)
        else:
            value = self.sObj.GetFieldAsString(index)
        return value

    def identity( self, obj ):
        return self.relation( obj, 'Equals' )

    def buffer(self, val, units=None):
        """
        NOTES:
        * Not dealing with units yet. OGR doesn't perform geodesic buffering, so need to reproject
        if data is in unprojected coordinate system (eg, WGS84) in order to specify miles, kilometers, etc.?
        """

        geom = self.sObj.GetGeometryRef()

        return geom.Buffer(val)

    def to_ogr_datasource(self):
        pass

class OgrShpObjectSet(CcObjectSet):
    def __init__(self, shp):
        """
        NOTE: Should this class contain a list of ArcShpObjects, or just refer to the ogr layer?
        """
        self.shp = shp
        self.layer = shp.GetLayer(0)

    def bounds(self):
        """
        Return bounds of entire ObjectSet in form of (MinX, MaxX, MinY, MaxY)
        """

        return self.layer.GetExtent()

    def buffer(self, val):
        """
        Buffer all objects in this set.

        NOTES:
        * Return self or new ObjectSet?
        * Not dealing with units yet. OGR doesn't perform geodesic buffering, so need to reproject
        if data is in unprojected coordinate system (eg, WGS84) in order to specify miles, kilometers, etc.?
        """

        for indx in xrange(self.layer.GetFeatureCount()):
            feature = self.layer.GetFeature(indx)
            geom = feature.GetGeometryRef()
            buffered = geom.Buffer(val)
            feature.SetGeometry(buffered)


def plus_one_naive(n):
    res = int("".join(map(str, n)))
    res = res + 1
    x1 = [int(x) for x in str(res)]
    return x1

def plus_one(A):
    A[-1] += 1
    for i in reversed(range(1, len(A))):
        print(A[i])
        if A[i] != 10:
            break
        A[i] = 0
        A[i-1] += 1
    if A[0] == 10:
        A[0] = 1
        A.append(0)
    return A

digits = [9, 9, 9]
print(plus_one_naive(digits))
print(plus_one(digits))

increment and arbitrary precision integer.py


import microbit
import radio
import random

DEFAULT_SETTINGS = {
    "length": 16,
    "queue": 128,
    "channel": 64,
    "data_rate": radio.RATE_2MBIT
}
BLANK_IMAGE = "00000:00000:00000:00000:00000"

def get_ident(wait=1000):
    max_ident = 0
    loading_display = microbit.Image(BLANK_IMAGE)
    wait /= 25

    configure_radio()
    for pixel in sorted(range(25), key=lambda x: random.random()):
        start = microbit.running_time()
        message = radio.receive_bytes()
        while message:
            try:
                sender, *_ = message
                max_ident = max(max_ident, sender)
            except ValueError:
                pass

            message = radio.receive_bytes()

        loading_display.set_pixel(pixel % 5, pixel // 5, 9)
        microbit.display.show(loading_display)
        end = microbit.running_time() - start
        if end < wait:
            microbit.sleep(wait - end)

    microbit.display.scroll("#{}".format(max_ident + 1))
    return max_ident + 1

def configure_radio(power=7):
    radio.config(power=power, **DEFAULT_SETTINGS)

def echolocate(me):
    configure_radio(7)
    radio.send_bytes(bytes([me, 255]))
    for power in range(8):
        configure_radio(power)
        radio.send_bytes(bytes([me, power]))

    microbit.sleep(10)

    message = radio.receive_bytes()
    while message:
        try:
            user, payload = message
            yield user, payload
        except ValueError:
            pass
        message = radio.receive_bytes()

if __name__ == "__main__":
    radio.on()

    while True:
        distance = {}

        ident = get_ident()
        duplicated = False

        while True:
            for user, packet in echolocate(ident):
                if user == ident:
                    duplicated = True
                    break

                if packet == 255:
                    if user in distance:
                        (n, p, l), _ = distance[user]
                        distance[user] = (9, n, p), microbit.running_time()
                    else:
                        distance[user] = (9, 9, 9), microbit.running_time()
                else:
                    if user in distance:
                        (n, p, l), _ = distance[user]
                        n = min(n, packet)
                        distance[user] = (n, p, l), microbit.running_time()

            if duplicated:
                microbit.sleep(random.randint(100, 5000))
                break

            bars = []

            now = microbit.running_time()

            for bit, ((n, p, l), seen) in sorted(distance.items(), key=lambda x: x[0]):
                if seen + 250 < now:
                    del distance[bit]
                    continue

                power = (n + p + l) // 3
                bar = "9" + "9" * min(4, power // 2) + "4" if power % 2 else ""
                bar += "0" * (5 - len(bar))
                bars.append(bar)

            for _ in range(5 - len(bars)):
                bars.append("".join(str(random.choice(range(4))) for _ in range(5)))

            microbit.display.show(microbit.Image(":".join(bars)))


from collections import defaultdict
import sys

input = sys.stdin.readline

N = int(input())
M = int(input())

def init() :
  route_list_a = list()
  route_list_b = list()
  for i in range(M) :
    start, end = map(int, input().split())
    if end == 0 :
      end += N
    if start > end :
      route_list_b.append((i+1, start, end+N))
    else :
      route_list_a.append((i+1, start, end))

  return route_list_a, route_list_b

def traversal(lst, mode = 1) :

  lst.sort(key = lambda x : (x[1], -x[2]))
  result = list()
  for idx, start, end in lst :
    if result and result[-1][2] >= end :
      continue
    result.append((idx, start, end))

  return result

def extract(lst1, lst2) :
  result = list()

  if lst2 :
    result.extend([x[0] for x in lst2])
    _, min_start, _ = lst2[0]
    _, _, max_end = lst2[-1]
    lst1 = [ x for x in lst1 if not ( x[1] >= min_start or x[2] <= max_end-N ) ]

  result.extend([x[0] for x in lst1])
  result.sort()

  return result

def solve() :
  route_list_a, route_list_b = init()
  result1 = traversal(route_list_a, 1)
  result2 = traversal(route_list_b, 2)

  result = extract(result1, result2)
  print(*result)

solve()


import sys

sys.exit()

#1

# december= 1st month of winter
# dec, jan, feb = winter (12, 1, 2)
# march, april, may = spring (3,4,5)
# jun, july, august = summer (6,7,8)
# sept, oct, nov = autumn (9,10,11)

seasons = ("winter", "spring", "summer", "autumn")

month = input("Enter the no. of a month (1-12): ")
if month in ('12', '1', '2'):
    s = seasons[0]
elif month in ('3', '4', '5'):
    s = seasons[1]
elif month in ('6', '7', '8'):
    s = seasons[2]
else:
    s = seasons[3]

print(f"The season in month no. {month} is {s}.")

#2

print("Enter an empty string if you want to quit.")
x = 1
names = set()

while x > 0:
    n = input("Enter a name:")
    if n != "":
        if n not in names:
            print("New name")
        if n in names:
            print("Existing name")
        names.add(n)
    else:
        break

print("The names are: ")
for n in names:
    print(n)

#3

airport = {"VNKT": "Kathmandu-International",
           "OTHH": "Qatar-International",
           "EFHK": "Helsinki-Vanta",
           "VNPL": "Solukhumbu-Phaplu",
           "VNPK": "Pokhara-International"}

print("Press A: To proceed to a new airport\n"
      "Press B: To find the information of the existing airport\n"
      "Press C: To quit.")

a = 0
while a < 1:
    print()
    opt = input("Choose one from the above options: ").upper()
    if opt == 'C':
        print("You chose to quit.")
        break
    elif opt == 'A':
        code = input("Enter the ICAO code: ").upper()
        ap = input("Enter the name of the airport: ").capitalize()
        print("You can select new options until you choose to quit.")
    elif opt == 'B':
        i_code = input("Enter the ICAO code: ").upper()
        print(f'This is {airport[i_code]} airport.')
        print("You can select new options until you choose to quit.")
    else:
        continue


# coding=utf-8
import shotgun_api3
import json
from shotgrid import sg

class sg_file(object):
    '''
    equivalent of 'file' table in tactic
    '''
    file_data = None
    file_name = None

class sg_version(object):
    '''
    equivalent of 'snapshot' table in tactic
    '''
    version_raw = None
    s_publish = None

    def __init__(self, version):
        self.version_raw = version
        self.scan_version()
        return

    def scan_version(self):
        return

class sg_task(object):
    task = None
    s_versions = None

    def __init__(self, task):
        self.task = sg.sg.find_one('Task', [['id', 'is', task['id']]], sg.get_fields('Task'))
        self.scan_task()
        return

    def scan_task(self):
        versions = sg.sg.find('Version', [['sg_task', 'is', self.task]], sg.get_fields('Version'))
        if not versions: return
        for version in versions:
            if self.s_versions is None: self.s_versions = []
            self.s_versions.append(sg_version(version))
        return

class sg_element(object):
    # in case a %table%_code is found, such as 'rig_code', %table% is sought for and:
    element_raw = None  # this is the raw rappresentation
    element_full_raw = None
    element_class = None
    # tasks
    s_tasks = None

    def __init__(self, element):
        self.element_raw = element
        self.element_full_raw = element
        self.element_class = element
        self.scan_element()
        return

    def scan_element(self):
        if 'tasks' not in self.element_raw: return
        for s_task in self.element_raw['tasks']:
            if self.s_tasks is None: self.s_tasks = []
            self.s_tasks.append(sg_task(s_task))
        return

class sg_entity(object):
    '''
    A SObject is the equivalent of an 'entity' in Shotgrid.
    'Asset','Shot','Sequence' and 'Episode' do exists in both project setup
    Each SObject/Entity has its own set of tasks, which depends on the type of SObject/Entity
    '''
    entity_code = None
    elements_raw = None
    elements = None

    def __init__(self, entity_code, elements):
        self.entity_code = entity_code
        self.elements_raw = elements
        if not self.elements_raw: return
        self.scan_entity()
        return

    def scan_entity(self):
        for element in self.elements_raw:
            if self.elements is None: self.elements = []
            self.elements.append(sg_element(element))

class sg_project(object):
    project_code = None
    sg_project = None
    sg_entities = None
    sg_task_templates = None
    sg_steps = None
    def __init__(self, project_code):
        self.project_code = project_code
        self.sg_project = None
        self.init_project()
        if self.sg_project:
            self.scan_sg_project()
        else:
            print('cannot find project "{}"'.format(self.project_code))
        return
    def init_project(self):
        fields = sg.get_fields('Project')
        self.sg_project = sg.sg.find_one("Project", [['name', 'is', self.project_code]], fields)
        return self.sg_project
    def scan_sg_project(self):
        for stype in ['Asset', 'Shot', 'Sequence', 'Episode', 'Rig']:
            s_entity_code_d = sg.get_entity_from_name(stype)
            s_entity_name = (list(s_entity_code_d.keys())[0])
            s_entity_code = s_entity_code_d[s_entity_name]
            print('------------ {} -------------- {}'.format(s_entity_code, s_entity_name))
            s_elements = sg.sg.find(s_entity_code, [['project', 'is', {'type': 'Project', 'id': self.sg_project['id']}]], sg.get_fields(s_entity_code))
            if self.sg_entities is None: self.sg_entities = []
            self.sg_entities.append(sg_entity(s_entity_code_d, s_elements))
        #
        self.sg_task_templates = sg.sg.find('TaskTemplate', [], sg.get_fields('TaskTemplate'))
        self.sg_steps = sg.sg.find('Step', [], sg.get_fields('Step'))
        print('done')
        return
    def get_entities(self):
        return ([list(x.entity_code.keys())[0] for x in self.sg_entities])

def create_project(sg_project):
    print('going to create project {}'.format(sg_project.project_code))
    return


DIR_TO_ARANGE = ["/home/vicky/Downloads/"]
EXT_INTEREST = [
    "pdf",
    "zip",
    "jpeg",
    "jpg",
    "png",
    "docx",
    "pptx",
    "csv",
    "xlsx",
    "CSV",
    "ipynb",
    "out",
    "gz",
    "epub",
    "mp4",
    "mp3",
    "html",
    "txt",
    "PNG",
    "xz",
    "ino",
    "apk",
    "log",
    "svg",
    "tar",
    "exe",
    "bin",
    "gpx",
    "avi",
    "bak",
    "dwg",
]


import numpy as np
import seaborn as sb
import torch
from optbinning import ContinuousOptimalBinning

from . import MyFunctions
from . import MVG

class SummaryTimeSeries:

    def __init__(self, time_points, mean_trend, std_trend, data_bins, X,Y, cell_densities):
        self.time_points = np.asarray(time_points)
        self.mean_trend = np.asarray(mean_trend)
        self.std_trend = np.asarray(std_trend)
        self.data_bins = data_bins
        self.X = X
        self.Y = Y
        self.cell_densities = cell_densities
        self.intpl_means = None
        self.intpl_stds = None

    def plot_mean_trend(self, color='blue'):
        sb.lineplot(x=self.time_points, y=self.mean_trend, linewidth=3, color=color)

    def reverse_time_series(self):

        self.time_points = self.time_points[::-1]
        self.mean_trend = self.mean_trend[::-1]
        self.std_trend = self.std_trend[::-1]
      #  self.data_bins = self.data_bins[::-1]
        self.X = self.X [::-1]
        self.Y = self.Y[::-1]
        self.cell_densities = self.cell_densities[::-1]
        self.intpl_means = self.intpl_means[::-1]
        self.intpl_stds = self.intpl_stds[::-1]

class Prepocessor:

    def __init__(self, *args):
        if len(args)>1:
            GEX_MAT =args[0]
            pseudotime_series = args[1]
            m = args[2]
            WINDOW_SIZE = args[3]
            optimal_binning = args[4]
            opt_binning = args[5]
            self.GEX_MAT = GEX_MAT
            self.pseudotime_series = pseudotime_series
            self.compute_cell_density_trend(WINDOW_SIZE, m=m, optimal_binning=optimal_binning, opt_binning = opt_binning)
        else:
            self.GEX_MAT = None
            self.pseudotime_series = None
            self.cell_densities = None

    def create_summary_trends(self, X, Y):
        # remember we have 100 synthetic cells per each time point
        mean_trend = []
        std_trend = []
        data_bins = []
        for t in range(len(self.artificial_time_points)):
            data_points = Y[X== self.artificial_time_points[t]]
            mean_trend.append(np.mean(data_points) )
            std_trend.append(np.std(data_points) )
            data_bins.append(data_points)

        return SummaryTimeSeries(self.artificial_time_points, mean_trend, std_trend, data_bins,X,Y,self.cell_densities)

    # data = dataframe, pseudotime series = array of pseudotimes for cells
    def create_equal_len_time_bins(self, gene, N_BINS = 10):
        bins_indices = np.linspace(np.min(self.pseudotime_series), np.max(self.pseudotime_series), N_BINS+1 ) # bin margins
        bins_indices[N_BINS] = np.max(self.pseudotime_series) + 0.00001 # small jitter added to consistently mark the bin boundaries as [), [), .... ]]
        data_bins = []
        time_bins = []
        bin_compositions = []

        for i in range(len(bins_indices)):
            if(i==len(bins_indices)-1):
                break
            t = np.logical_and(self.pseudotime_series >= bins_indices[i], self.pseudotime_series < bins_indices[i+1])
            data_bins = data_bins + list(self.GEX_MAT.loc[t,gene])
            bin_compositions.append(len(self.GEX_MAT.loc[t,gene]))
            time_bins = time_bins + list(np.repeat(bins_indices[i+1], len(self.GEX_MAT[t])))
        return bins_indices[1:len(bins_indices)], time_bins, np.asarray(data_bins), bin_compositions

    # **** CellAlign paper's interpolation method based on Gaussian Kernel
    def interpolate_time_series(self, gene): # WINDOW_SIZE = 0.1 # default value used in CellAlign

        intpl_gex = []
        for intpl_i in range(len(self.artificial_time_points)):
            weights = self.cell_weights[intpl_i]
            weighted_sum = 0.0
            for cell_i in range(len(self.pseudotime_series)):
                weighted_sum = weighted_sum + (weights[cell_i]*self.GEX_MAT[gene][cell_i])
            weighted_sum = weighted_sum/np.sum(weights)
            intpl_gex.append(weighted_sum)
        intpl_gex = np.asarray(intpl_gex).flatten()

        # min max normalisation
        scaled_intpl_gex = []
        for i in range(len(intpl_gex)):
            scaled_intpl_gex.append((intpl_gex[i] - np.min(intpl_gex))/(np.max(intpl_gex) - np.min(intpl_gex) ))
        return scaled_intpl_gex, self.artificial_time_points

    # Interpolation of distributions based on Gaussian kernel (similar to above method but we get a distribution of artificial cells for interpolated time points now)
    #  weighted mean and weighted std based dist interpolation
    # Extending the CellAlign interpolation method based on Gaussian Kernel
    def interpolate_time_series_distributions(self, gene, N=50, CONST_STD= False,WEIGHT_BY_CELL_DENSITY=False, ESTIMATE = True, user_given_std =[]):

        torch.manual_seed(1)
        intpl_gex = []
        all_time_points = []
        intpl_means = []
        intpl_stds = []

        for intpl_i in range(len(self.artificial_time_points)):

            # estimate weighted mean and weighted variance
            #if(ESTIMATE):
            if(user_given_std[intpl_i] <0):
                weights = self.cell_weights[intpl_i]
                weighted_sum = 0.0
                for cell_i in range(len(self.pseudotime_series)):
                    weighted_sum = weighted_sum + (weights[cell_i]*self.GEX_MAT[gene][cell_i])
                weighted_sum = weighted_sum/np.sum(weights)
                dist_mean = weighted_sum

                if(CONST_STD): # for getting just the average trend across
                    dist_std = 0.1
                else: # tweighted standard deviation
                    real_mean = np.mean(self.GEX_MAT[gene])
                    weighted_sum_std = 0.0
                    for cell_i in range(len(self.pseudotime_series)):
                        weighted_sum_std = weighted_sum_std + (weights[cell_i]*(( self.GEX_MAT[gene][cell_i] - real_mean) ** 2))
                    n = len(self.pseudotime_series)
                    weighted_std = np.sqrt(weighted_sum_std/(np.sum(weights) * (n-1)/n))
                    if(WEIGHT_BY_CELL_DENSITY):
                        weighted_std = weighted_std * self.cell_densities[intpl_i] # weighting according to cell density
                    dist_std = weighted_std
                if(dist_std==0 or np.isnan(dist_std)): # case of single data point or no data points
                    #print('!!!! ALERT ---- DIST STD =0 nan')
                    dist_std = 0.01#0.1 #np.mean(summary_series_obj.std_trend)
            else:
                dist_mean = 0.0
                dist_std =  user_given_std[intpl_i] #
            D,temp1,temp2 = MyFunctions.generate_random_dataset(N, dist_mean, dist_std)

            intpl_gex.append(D)
            intpl_means.append(dist_mean)
            intpl_stds.append(dist_std)
            all_time_points.append(np.repeat(self.artificial_time_points[intpl_i], N))

        return [np.asarray(intpl_gex).flatten(), np.asarray(all_time_points).flatten(), self.artificial_time_points, intpl_means, intpl_stds]

    def prepare_interpolated_gene_expression_series(self, gene, CONST_STD=False, WEIGHT_BY_CELL_DENSITY=False,  ESTIMATE = True, user_given_std =[]):
        intpl_out = self.interpolate_time_series_distributions(gene, CONST_STD=CONST_STD, WEIGHT_BY_CELL_DENSITY= WEIGHT_BY_CELL_DENSITY, ESTIMATE=ESTIMATE, user_given_std=user_given_std)
        X = intpl_out[1]; Y =  intpl_out[0]; artificial_time_points = intpl_out[2]
        obj = self.create_summary_trends(X,Y)
        obj.intpl_means = intpl_out[3]
        obj.intpl_stds = intpl_out[4]

        self.all_time_points = X # [TODO] -- repeats the same thing! To be done efficiently later!!!!

        return obj

    def get_optimal_binning(self, time_var_arr, n_points):
        x = time_var_arr
        optb = ContinuousOptimalBinning(name='pseudotime', dtype="numerical", max_n_bins=n_points)
        # this pacakge uses mixed integer programming based optimization to determine an optimal binning
        optb.fit(x, x)
        return optb.splits

    def compute_cell_density_trend(self, WINDOW_SIZE = 0.1, m=50, optimal_binning = False, opt_binning = []): # TODO LATEST TEST 07/01/2023 earlier used 0.15 for early Jan runs

        artificial_time_points = []
        if(optimal_binning):
            artificial_time_points = opt_binning
        else:
            for j in range(1,m):
                artificial_time_points.append((j-1)/(m-1))
            artificial_time_points.append(1.0)

            artificial_time_points = np.asarray(artificial_time_points)
            artificial_time_points = artificial_time_points[artificial_time_points >= np.min(self.pseudotime_series)]
            artificial_time_points = artificial_time_points[artificial_time_points <= np.max(self.pseudotime_series)]
            if(artificial_time_points[0]!=0.0):
                artificial_time_points = np.asarray([0] + list(artificial_time_points))

        cell_densities = []
        cell_weights = {}

        for intpl_i in range(len(artificial_time_points)):
            weights = []
            for cell_i in range(len(self.pseudotime_series)):
                w_i = np.exp(-((self.pseudotime_series[cell_i] - artificial_time_points[intpl_i])**2)/(WINDOW_SIZE**2))
                weights.append(w_i)
            # weighted cell density
            cell_densities.append(np.sum(weights))
            cell_weights[intpl_i] = np.asarray(weights)
        cell_densities = np.asarray(cell_densities)
        cell_densities = cell_densities/len(self.pseudotime_series)

        self.cell_weights = cell_weights
        self.artificial_time_points = artificial_time_points
        self.cell_densities = cell_densities

        return cell_weights, artificial_time_points, cell_densities

# Later TODO: make superclass SummaryTimeSeries for both univariate and multivariate cases
class SummaryTimeSeriesMVG:

    def __init__(self, time_points, data_bins):
        self.time_points = np.asarray(time_points)
        self.data_bins = data_bins

        self.mean_trends = []
        for data_bin in data_bins:
            data_bin = torch.tensor(np.asarray(data_bin) )
            μ, C = MVG.compute_mml_estimates(data_bin, data_bin.shape[1], data_bin.shape[0])
            self.mean_trends.append(μ)

class Utils:

    def minmax_normalise(arr):

        norm_arr = []
        arr = np.asarray(arr)
        arr_max = np.max(arr)
        arr_min = np.min(arr)
        for i in range(len(arr)):
            norm_arr.append((arr[i] - arr_min )/(arr_max  - arr_min ))
        return norm_arr

    # computes distributional distance under the MML framework
    def compute_mml_dist(ref_adata_subset,query_adata_subset, gene):

        ref_data = np.asarray(ref_adata_subset[:,gene].X.todense()).flatten()
        query_data = np.asarray(query_adata_subset[:,gene].X.todense()).flatten()
        μ_S = np.mean(ref_data)
        μ_T = np.mean(query_data)
        σ_S =np.std(ref_data)
        σ_T =np.std(query_data)
        #print(μ_S,μ_T)
        if(not np.any(ref_data)):
            σ_S = 0.1
        if(not np.any(query_data)):
            σ_T = 0.1

        I_ref_model, I_refdata_g_ref_model = MyFunctions.run_dist_compute_v3(ref_data, μ_S, σ_S)
        I_query_model, I_querydata_g_query_model = MyFunctions.run_dist_compute_v3(query_data, μ_T, σ_T)
        I_ref_model, I_querydata_g_ref_model = MyFunctions.run_dist_compute_v3(query_data, μ_S, σ_S)
        I_query_model, I_refdata_g_query_model = MyFunctions.run_dist_compute_v3(ref_data, μ_T, σ_T)

        match_encoding_len1 = I_ref_model + I_querydata_g_ref_model + I_refdata_g_ref_model
        match_encoding_len1 = match_encoding_len1/(len(query_data)+len(ref_data))
        match_encoding_len2 = I_query_model + I_refdata_g_query_model + I_querydata_g_query_model
        match_encoding_len2 = match_encoding_len2/(len(query_data)+len(ref_data))
        match_encoding_len = (match_encoding_len1 + match_encoding_len2 )/2.0

        null = (I_ref_model + I_refdata_g_ref_model + I_query_model + I_querydata_g_query_model)/(len(query_data)+len(ref_data))
        match_compression =   match_encoding_len - null
        #print(match_compression)
        #sb.kdeplot(ref_data, fill=True)
        #sb.kdeplot(query_data, fill=True)
        return match_compression

def refine_pseudotime(adata):
    average_ctype_mean_times = {}

    for ctype in np.unique(adata.obs.ANNOTATION_COMB):
        average_ctype_mean_times[ctype] = np.mean(adata[adata.obs.ANNOTATION_COMB==ctype].obs.time)

    adata.obs['refined_time'] = adata.obs.time

    ctype_Ls = {}
    ctype_Us = {}

    for ctype in np.unique(adata.obs.ANNOTATION_COMB):
        ctype_adata = adata[adata.obs.ANNOTATION_COMB==ctype]
        Q1,Q3 = np.percentile( ctype_adata.obs.time, [25,75])
        IQR = Q3-Q1
        U = Q3+(1.5 * IQR)
        L = Q1-(1.5 * IQR)
        ctype_Ls[ctype] = L
        ctype_Us[ctype] = U

    for i in range(adata.shape[0]):
        ctype = adata.obs.ANNOTATION_COMB[i]
        if(adata.obs.time[i]<ctype_Ls[ctype] or adata.obs.time[i]>ctype_Us[ctype]):
            adata.obs['refined_time'][i] = average_ctype_mean_times[ctype]

    return Utils.minmax_normalise(np.asarray(adata.obs.refined_time))


from baumanecbank_common import ApplicationBb

from telegram import (
    Update,
    InlineKeyboardMarkup,
    InlineKeyboardButton
)
from telegram.ext import ContextTypes, ConversationHandler

CALBACK_EMPLOYEE_PREFIX   = "employee_"
CALBACK_EMPLOYEE_TEMPLATE = "employee_*"
CALBACK_EMPLOYEE_PATTERN  = "employee_{employee.employee_client_uuid}"

SALARY_FUNCTION = 'salary'

SALARY_AWAIT_AMOUNT,SALARY_CLOSE_AWAIT = range(2)

async def salary_start_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    app: ApplicationBb = context.application
    await update.message.reply_markdown(
        app.i18n.app['salary']['employees'],
        reply_markup=InlineKeyboardMarkup.from_column([
            InlineKeyboardButton(
                app.i18n.app['salary']['employee_template'].format(employee=employee),
                callback_data=CALBACK_EMPLOYEE_PATTERN.format(employee=employee)
            )
            for employee in app.pgcon.get_employees_by_account_chat_id(update.effective_user.id)
        ])
    )

async def salary_callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    await update.callback_query.answer()
    app: ApplicationBb = context.application
    employee_uuid = update.callback_query.data.removeprefix(CALBACK_EMPLOYEE_PREFIX)
    client = app.pgcon.get_client_by_uuid(employee_uuid)
    context.user_data['client'] = client
    await update.callback_query.message.reply_markdown(
        app.i18n.app['salary']['callback'].format(client=client),
        reply_markup=app.keyboard_amount
    )
    return SALARY_AWAIT_AMOUNT

async def salary_amount_input_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    app: ApplicationBb = context.application
    amount = float(update.message.text.replace(',', '.'))
    context.user_data["amount"] = amount
    await update.message.reply_markdown(
        app.i18n.app['salary']['amount_input'].format(
            amount=amount,
            govtax=amount*0.13,
            client=context.user_data['client']
        ),
        reply_markup=app.keyboard_close
    )
    return SALARY_CLOSE_AWAIT

async def salary_amount_invalid_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    app: ApplicationBb = context.application
    await update.message.reply_markdown(
        app.i18n.app['salary']['amount_invalid'],
        reply_markup=app.keyboard_amount
    )
    return SALARY_AWAIT_AMOUNT

async def salary_close_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    app: ApplicationBb = context.application
    amount  = context.user_data["amount"]
    client  = context.user_data["client"]
    account = app.pgcon.get_account_by_chat_id(update.message.chat_id)

    if not account.is_government and account.balance < amount:
        await update.message.reply_markdown(
            app.i18n.app['salary']['balance_not_enough'],
            reply_markup=app.keyboard_main
        )
        return ConversationHandler.END

    err = app.pgcon.create_salary(account.firm_card_code_id, client.card_code_id, amount)
    if err is not None:
        await update.message.reply_markdown(
            app.i18n.app['salary']['error'],
            reply_markup=app.keyboard_main
        )
        return ConversationHandler.END

    await update.message.reply_markdown(
        app.i18n.app['salary']['success'],
        reply_markup=app.keyboard_main
    )
    return ConversationHandler.END


#!/usr/bin/python3

# JISCTF 2020 Quals - Ransomware chall

import base64

with open("flag.enc", "rb") as cipher:
    c = cipher.read()

plaintext = base64.b64decode(c)

while 'jisctf' not in str(plaintext):
    plaintext = base64.b64decode(plaintext)
    #print(plaintext)
    # Extraction du PNG trouvé
    if '\\n\\rGNP' in str(plaintext):
        print('writing png')
        f=open("test","wb")
        f.write(plaintext)
        f.close()