"""
This implements the client credentials flow explained here -
https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow

Everything here refers to the current web api reference - https://developer.spotify.com/documentation/web-api/reference/

Sections of API covered:
    - Browse
    - Artists
    - Tracks
    - Albums
    - Search
    - Personalization

Sections of API not covered:
    - Follow
    - Library
    - Player
    - Playlists
    - User Profile
"""

import json
import base64
import os
import time
import requests
from math import ceil
from datetime import datetime
import itertools

TOKEN_URL = "https://accounts.spotify.com/api/token"
ACCESS_URL = "https://api.spotify.com/v1/me"
BASE_URL = "https://api.spotify.com/v1/"

# All possible Category IDs
CAT_IDS = ['toplists', 'pop', 'hiphop', 'mood', 'workout', 'decades', 'country', 'focus', 'latin', 'chill', 'edm_dance',
           'rnb', 'rock', 'indie_alt', 'roots', 'party', 'sleep', 'classical', 'jazz', 'inspirational']

def grouper(n, iterable, padvalue=None):
    """
    Split a list into n even chunks
    """
    return itertools.zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)

class Spotify:
    def __init__(self, client_id=None, client_secret=None):
        self._client_id = client_id
        self._client_secret = client_secret

        # If none we assume defined in ENV
        if client_id is None:
            self._client_id = os.getenv('SPOTIFY_ID')
            self._client_secret = os.getenv('SPOTIFY_SECRET')

            if self._client_id is None:
                raise Exception("The SPOTIFY_ID or SPOTIFY_SECRET ENV variable don't exist")

        self._access_token = {}
        self._token_start_time = None
        self.get_access_token()

    def get_access_token(self):
        """
        Get the refresh token and use to exchange or exchange the authorization code for a token

        :param: refresh_token: Refresh to get auth token

        :return: None
        """
        post_data = {"grant_type": "client_credentials"}

        auth_str = bytes('{}:{}'.format(self._client_id, self._client_secret), 'utf-8')
        b64_auth_str = base64.b64encode(auth_str).decode('utf-8')

        # So we know when it expires
        self._token_start_time = time.time()

        headers = {"Authorization": "Basic {}".format(b64_auth_str)}
        post_request = requests.post(TOKEN_URL, data=post_data, headers=headers)

        self._access_token = json.loads(post_request.text)

    def token_expired(self):
        """
        If the current token has expired

        :return: boolean - True if expired
        """
        return time.time() - self._token_start_time >= self._access_token['expires_in']

    def query(self, query_type, payload):
        """
        Query the specified data

        :param query_type: Query to make
        :param payload: Associated parameters

        :return: response json
        """
        if self.token_expired():
            self.get_access_token()

        url = f"{BASE_URL}{query_type}"
        headers = {"Authorization": "Bearer {}".format(self._access_token['access_token'])}

        response = requests.get(url, headers=headers, params=payload)
        time.sleep(3)

        return json.loads(response.content)

    def path_query(self, query_type, payload, path_params):
        """
        When making a query with a modified path

        :param query_type: Query to make
        :param payload: Associated parameters
        :param path_params: Parameters to add to path -> must be in correct order

        :return: response json
        """
        query_type = "/".join([query_type, *path_params])
        return self.query(query_type, payload)

    def get_ids(self, search_vals, search_type):
        """
        Get associated ids for a group of searched items

        :param search_vals: What you are searching for
        :param search_type: Type of item you are searching for

        :return: ids -> List of corresponding ids
        """
        # I only use the api endpoint that allows 1 or more artists
        # So we come here whenever there exist the single and multiple options
        # So for ease just convert to a list
        if isinstance(search_vals, str):
            search_vals = [search_vals]

        # Search one at a time
        ids = []
        for search_val in search_vals:
            search_items = self.search(search_val, search_type).get(f"{search_type}s", [])

            if search_items and len(search_items['items']) > 0:
                ids.append(search_items['items'][0]['id'])
            else:
                print(search_val, "not found")

        return ids

    def get_id(self, search_val, search_type):
        """
        Get associated id for a one searched item

        :param search_val: What you are searching for
        :param search_type: Type of item you are searching for

        :return: id or None
        """
        response = self.get_ids([search_val], search_type)
        if response:
            return response[0]

    #################################################################
    ##########################  Search API ##########################
    #################################################################

    def search(self, search_data, search_type, limit=3, market="US", offset=0):
        """
        Search for data

        https://api.spotify.com/v1/search

        :param search_data: Search input
        :param search_type: Type of search you are conducting - ['artist', 'album', 'playlist', 'track']
        :param limit: Number of albums to return
        :param market: Only get from specific market where playable
        :param offset: index of first result to return

        :return: response data
        """
        if not search_type in ['artist', 'album', 'playlist', 'track'] and isinstance(search_data, str):
            print("Not a valid search type")
        else:
            payload = {
                'q': search_data,
                'type': search_type,
                'limit': limit,
                'market': market,
                'offset': offset
            }
            return self.query("search", payload)

    #################################################################
    ##########################  Browse API ##########################
    #################################################################

    def get_categories(self, country="US", locale="US", limit=20, offset=0):
        """
        Get all the music categories available

        https://api.spotify.com/v1/browse/categories

        :param country: Where content is playable
        :param locale: language
        :param limit: results to return
        :param offset: index of first result to return

        :return: response data
        """
        payload = {"country": country, "limit": limit, "locale": locale, "offset": offset}
        path_params = ["categories"]

        return self.path_query("browse", payload, path_params)['categories']['items']

    def get_category(self, category, country="US", locale="US"):
        """
        Get the info for a given category

        https://api.spotify.com/v1/browse/categories/{category_id}

        :param category: id of category
        :param country: exists for supplied country
        :param locale: language

        :return: dict of info
        """
        if category.lower() not in CAT_IDS:
            raise ValueError(f"{category} is not one of the possible category ids")

        payload = {"country": country, "locale": locale}
        path_params = ["categories", category.lower()]

        return self.path_query("browse", payload, path_params)

    def get_category_playlists(self, category, country="US", limit=20, offset=0):
        """
        Get the info for a given category

        https://api.spotify.com/v1/browse/categories/{category_id}/playlists

        :param category: id of category
        :param country: country to get for
        :param limit: # of items to return
        :param offset: index of first item to return

        :return: list of info
        """
        if category.lower() not in CAT_IDS:
            raise ValueError(f"{category} is not one of the possible category ids")

        if not 51 > limit > 0:
            raise ValueError("Can only retrieve a maximum of 50 category playlists")

        payload = {"country": country, "limit": limit, "offset": offset}
        path_params = ["categories", category.lower(), "playlists"]

        results = self.path_query("browse", payload, path_params)
        return results['playlists']['items'] if 'playlists' in results else []

    def get_genre_seeds(self):
        """
        Get all the possible genres

        https://api.spotify.com/v1/recommendations/available-genre-seeds

        :return: List of genres
        """
        return self.path_query("recommendations", {}, ["available-genre-seeds"]).get("genres", [])

    # TODO: Get this to work
    # TODO: Add min, max, and target params for tuneable track attributes
    def get_recommendations(self, seed_artists, seed_tracks, seed_genres, limit=20, market="US"):
        """
        Get recommendations for new music

        https://api.spotify.com/v1/recommendations

        :param seed_artists: Up to 5 artists -> Must be IDs
        :param seed_tracks: Up to 5 tracks -> Must be IDs
        :param seed_genres: Up to 5 genres
        :param limit: # to return
        :param market: country

        :return:
        """
        if not 101 > limit > 0:
            raise ValueError("Can only retrieve a maximum of 100 recommendations")

        # If supply strings for any of the seeds then convert to a list
        if isinstance(seed_artists, str):
            seed_artists = [seed_artists]
        if isinstance(seed_genres, str):
            seed_genres = [seed_genres]
        if isinstance(seed_tracks, str):
            seed_tracks = [seed_tracks]

        payload = {
            "seed_artists": ",".join(seed_artists),
            "seed_genres": ",".join(seed_genres),
            "seed_tracks": ",".join(seed_tracks),
            "limit": limit,
            "market": market
        }

        return self.query("recommendations", payload).get("tracks", [])

    def get_featured_playlists(self, timestamp=None, country="US", locale="US", limit=20, offset=0):
        """
        Get all featured playlists

        # TODO: https://api.spotify.com/v1/browse/featured-playlists

        :param timestamp: ISO-8601 format
        :param country: market
        :param locale: language
        :param limit: results to return
        :param offset: index to begin at

        :return: list of featured playlists
        """
        # Needs to be ISO-8601 format
        if timestamp is None:
            iso = datetime.now().isoformat()
            timestamp = iso[0:iso.find(".")]
        else:
            try:
                datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
            except ValueError:
                raise ValueError("The timestamp isn't in the correct format should be %Y-%m-%dT%H:%M:%S")

        if not 51 > limit > 0:
            raise ValueError("Can only retrieve a maximum of 50 featured playlists")

        payload = {
            "timestamp": timestamp,
            "country": country,
            "locale": locale,
            "limit": limit,
            "offset": offset
        }
        path_params = ['featured-playlists']

        results = self.path_query("browse", payload, path_params)
        return results['playlists']['items'] if 'playlists' in results else []

    def get_new_releases(self, country="US", limit=20, offset=0):
        """
        Get the new album releases on spotify

        https://api.spotify.com/v1/browse/new-releases

        :param country: country to get for
        :param limit: # of items to return
        :param offset: index of first item to return

        :return: list of album objects
        """
        if not 51 > limit > 0:
            raise ValueError("Can only retrieve a maximum of 50 new releases")

        payload = {"country": country, "limit": limit, "offset": offset}
        path_params = ['new-releases']

        return self.path_query("browse", payload, path_params).get("albums", [])

    #################################################################
    ##########################  Artist API ##########################
    #################################################################

    def get_artists(self, artists, artist_id=False):
        """
        Get the data for a given artists name or id

        https://api.spotify.com/v1/artists

        :param artists: Artist to query -> List, str, int
        :param artist_id: If supplying ids or names

        :return: list of artist objects
        """
        if len(artists) > 50:
            raise ValueError("Can only retrieve a maximum of 50 artists")

        if not artist_id:
            artists = self.get_ids(artists, "artist")

        if artists:
            payload = {"ids": ",".join(artists)}
            results = self.query("artists", payload)

            return results.get("artists", [])

    def get_artist_albums(self, artist, artist_id=False, include_groups=None, limit=20):
        """
        Get the albums for an artist

        https://api.spotify.com/v1/artists/{id}/albums

        :param artist: Name or id of artist
        :param artist_id: If supplying ids or names
        :param include_groups: str, list, None
        :param limit: Number to return

        :return: list of album objects
        """
        if not 51 > limit > 0:
            raise ValueError("Can only retrieve a maximum of 50 artist albums")

        if not artist_id:
            artist = self.get_id(artist, "artist")

        if artist is not None:
            if isinstance(include_groups, list):
                include_groups = ",".join(include_groups)
            elif isinstance(include_groups, str):
                include_groups += ","
            else:
                include_groups = ",".join(['album', 'single', 'appears_on', 'compilation'])

            payload = {"include_groups": include_groups, "limit": limit}
            path_params = [artist, "albums"]

            results = self.path_query("artists", payload, path_params)
            return results.get("items", [])

    def get_top_tracks(self, artist, country, artist_id=False):
        """
        Get the top tracks for an artist

        https://api.spotify.com/v1/artists/{id}/top-tracks

        :param artist: name or id of artist
        :param country: Country to get shift from
        :param artist_id: If providing id

        :return: list of track objects
        """
        if not artist_id:
            artist = self.get_id(artist, "artist")

        if artist is not None:
            payload = {"country": country}
            path_params = [artist, 'top-tracks']

            results = self.path_query("artists", payload, path_params)
            return results.get("tracks", [])

    def get_related_artists(self, artist, artist_id=False):
        """
        Get the related artist for a given artist

        https://api.spotify.com/v1/artists/{id}/related-artists

        :param artist: ID or name of artist
        :param artist_id: If supplied id

        :return: List of related artist objects
        """
        if not artist_id:
            artist = self.get_id(artist, "artist")

        if artist is not None:
            path_params = [artist, 'related-artists']
            results = self.path_query("artists", {}, path_params)

            return results.get("artists", [])

    #################################################################
    ##########################  Albums API ##########################
    #################################################################

    def get_albums(self, albums, album_id=False, market="US"):
        """
        Get album info for # of albums

        https://api.spotify.com/v1/albums

        :param albums: Names or ids of albums - list, int, str
        :param album_id: If supplying ids
        :param market: Market to draw from

        :return: list of album objects
        """
        if isinstance(albums, list) and len(albums) > 20:
            raise ValueError("Can only request a maximum of 20 albums")

        if not album_id:
            albums = self.get_ids(albums, "album")

        if albums:
            payload = {"ids": ",".join(albums), "market": market}
            results = self.query("albums", payload)

            return results.get("albums", [])

    def get_album_tracks(self, album, album_id=False, limit=20, market='US'):
        """
        Get the tracks for a given album

        https://api.spotify.com/v1/albums/{id}/tracks

        :param album: Name or id of album
        :param album_id: If supplying ids or name
        :param limit: # of items to return
        :param market: Market to take from

        :return: list of album tracks
        """
        if not 51 > limit > 0:
            raise ValueError("Limit must be between 0 and 50")

        if not album_id:
            album = self.get_id(album, "album")

        if album is not None:
            payload = {"limit": limit, "market": market}
            path_params = [album, "tracks"]

            results = self.path_query("albums", payload, path_params)
            return results.get("items", [])

    #################################################################
    ##########################  Tracks API ##########################
    #################################################################

    def get_tracks(self, tracks, track_id=False, market="US"):
        """
        Get list of track information

        https://api.spotify.com/v1/tracks

        :param tracks: IDs or names of tracks
        :param track_id: If supplied ids or name
        :param market: where to drawn info from

        :return: list of tracks
        """
        if isinstance(tracks, list) and len(tracks) > 50:
            raise ValueError("Can only request a maximum of 50 tracks")

        if not track_id:
            tracks = self.get_ids(tracks, "track")

        if tracks:
            payload = {"ids": ",".join(tracks), "market": market}
            results = self.query("tracks", payload)

            return results.get("tracks", [])

    def get_audio_features(self, tracks, track_id=False):
        """
        Get audio features for multiple tracks

        https://api.spotify.com/v1/audio-features

        :param tracks: IDs or names of tracks
        :param track_id: If supplied ids or name

        :return: list of tracks
        """
        if not track_id:
            tracks = self.get_ids(tracks, "track")

        if tracks:
            # Limit of 100 tracks per GET so we'll chop it up
            # and do it 100 (or less) at a time
            if len(tracks) > 100:
                results = []
                for chunk in list(grouper(ceil(len(tracks)/100), tracks)):
                    # When not divisible by 100 we'll get Nones added on
                    chunk = list(filter(None.__ne__, chunk))

                    chunk_query = self.query("audio-features", {"ids": ",".join(chunk)})
                    results.append(chunk_query.get("audio_features", []))

                # Flatten list
                return list(itertools.chain.from_iterable(results))
            else:
                results = self.query("audio-features", {"ids": ",".join(tracks)})
                return results.get("audio_features", [])

    def get_audio_analysis(self, track, track_id=False):
        """
        Get audio analysis for a single tracks

        https://api.spotify.com/v1/audio-analysis/{id}

        :param track: ID or names of track
        :param track_id: If supplied ids or name

        :return: list of dicts (each is a track)
        """
        if not track_id:
            track = self.get_id(track, "track")

        if track is not None:
            return self.path_query("audio-analysis", {}, [track])['tracks']

    #################################################################
    ########################  Playlist API ##########################
    #################################################################

    def get_playlist(self, playlist_id):
        """
        Get info on playlist

        :param playlist_id spotify id for playlist

        :return: dict of info
        """
        path_params = [playlist_id]
        return self.path_query("playlists", {}, path_params)

    def get_playlist_tracks(self, playlist_id):
        """
        Returns the tracks in a playlist

        https://api.spotify.com/v1/playlists/{playlist_id}

        :param playlist_id: spotify id for playlist
        :param num_tracks: Number of tracks to return

        :return: list of tracks (each is a dict)
        """
        limit = 100
        tracks = []
        path_params = [playlist_id, "tracks"]

        num_tracks = self.get_playlist(playlist_id)['tracks']['total']

        # The Api only allows 100 at a time
        # We can change the offset (index) where to start from though
        # So we keep going through the list taking 100 at a time
        for offset in range(0, num_tracks, limit):
            payload = {"offset": offset}
            query_tracks = self.path_query("playlists", payload, path_params)['items']

            # Add tracks for this query to the total tracks gotten so far
            for t in query_tracks:
                tracks.append(t)

        return tracks


#!/usr/bin/env python

# claridge_motif_mark.py

import re
import sys
import argparse
import cairo
import math
import random

parser = argparse.ArgumentParser(description="Creates a visualization of one to seven sequence motifs across a sequence or multiple sequences provided in UCSC format.\nRequires a FASTA file of the sequences to be visualized and a list of motifs to be visualized.\nSince a random color generator is used, if the output color scheme is unfavorable, run script again.")
parser.add_argument('-f','--fasta', help='absolute path to FASTA file of sequences to be searched (/path/to/<FASTA_FILE>).', required=True, type=str)
parser.add_argument('-m','--motifs', help='absolute path to the text file containing the list of motifs to be visualized, formatted as one motif per line (/path/to/<MOTIF_FILE>).', required=True, type=str)
args = parser.parse_args()

#####################################################################################
##### Define Higher Order Functions #################################################
#####################################################################################

##### Functions for file formatting and information

def fasta_twofer(filepath):
    '''Takes in a FASTA file and creates a new FASTA file called "sequences_twofer.fasta"
    that only has two lines for every FASTA entry.'''
    first_line = True
    with open(filepath,"r") as fasta, open("./sequences_twofer.fasta", "w+") as out:
        for line in fasta:
            if first_line and line.startswith(">"):     ### If the first line, print line without "\n" because print statement appends "\n"
                out.write(line.strip())
                out.write("\n")
                first_line = False     ### Never run through this part of the looping system again
            elif not first_line and line.startswith(">"):     ### Print "\n" preceeding all deflines
                out.write("\n")
                out.write(line.strip())
                out.write("\n")
            else:
                out.write(line.strip("\n"))     ### Strip "\n" from all sequence lines

def longest_sequence(filepath):
    '''Takes in a FASTA file and returns the length of the longest sequence in the file.'''
    with open(filepath,"r") as fasta:
        length = 0
        for line in fasta:
            line = line.strip()
            if line.startswith(">") == True:
                pass
            elif line.startswith(">") == False:
                new_length = len(line)
                if new_length > length:
                    length = new_length
                else:
                    pass
    return length

def count_lines(infile):
    '''Opens the input file and returns the number of lines in the file.'''
    with open(infile) as file:
        for i, line in enumerate(file):
            pass
    return i + 1

##### Functions for finding the motif positions

def motif2regex(filepath):
    '''Takes the list of motifs and returns a dictionary of regular expressions that will search for that motif in
    a given sequence, regardless of case. Keys are motifs; values are regex motifs.'''
    motif_dict = {}
    with open(filepath) as motif_list:
        for motif in motif_list:
            motif = motif.strip("\n")
            motif_upper = motif.upper()
            motif_components = list(motif_upper)
            for i in range(0, len(motif_components)):
                motif_components[i] = iupac.get(motif_components[i])
                regex_motif = "".join(motif_components)
                motif_dict[motif] = regex_motif
    return motif_dict

def lengths_intex(sequence):
    '''From a given UCSC sequence, i.e. lower case intron, upper case exon, lower case intron,
    this function returns a list of length four: length of the sequence, length of the first intron,
    length of the exon, and length of the second intron.'''
    sequence = sequence.strip()
    pattern = re.compile(r'([a-z]+)([A-Z]+)([a-z]+)')
    res = re.match(pattern, sequence)
    if len(res.groups()) != 3:
        raise ValueError("ERROR: Exiting program. Sequence is not in UCSC format.")
    lengths = [sequence, len(sequence), len(res.group(1)), len(res.group(2)), len(res.group(3))]
    return lengths

def sequence_parser(filepath):
    with open(filepath, "r+") as file:
        seq_details = {}
        header = ""
        sequence = ""
        first_line = True
        for line in file:
            if line.startswith(">") == True:
                line = line.strip()
                if first_line == False:
                    seq_details[header] = lengths_intex(sequence)
                header = line
                sequence = ""
            else:
                sequence = line
                first_line = False
        seq_details[header] = lengths_intex(sequence)
    return seq_details

def motif_position(motif_dict, header, sequence):
    '''Takes a motif in regular-expression format and searches for all instances of that motif
    in the provided sequence. Returns a list of 2-item lists containing start positions and lengths.
    Since Python idexes starting at 0, 1 is added to the start position to account for pixels when making the image.'''
    positions = {}
    for motif in motif_dict.keys():
        for match in re.finditer(motif_dict[motif], sequence):
            s = match.start()
            e = match.end()
            if header + "_" + motif in positions:
                positions[header + "_" + motif].append([s + 1, e - s])
            elif header + "_" + motif not in positions:
                positions[header + "_" + motif] = [[s + 1, e - s]]
    return positions

def get_all_positions(fasta_f, motif_f):
    seq_details = sequence_parser(fasta_f)
    motif_dict = motif2regex(motif_f)
    all_positions = []
    for info in seq_details.items():
        # info[0] is the header
        # info[1] is the list of details
        # info[1][0] is the sequence
        # info[1][1] is the sequence length
        # info[1][2] is the length of intron 1
        # info[1][3] is the length of the exon
        # info[1][4] is the length of intron 2
        positions = motif_position(motif_dict, header = info[0], sequence = info[1][0])
        positions["intron1"] = info[1][2]
        positions["exon"] = info[1][3]
        positions["intron2"] = info[1][4]
        all_positions.append(positions)
    return all_positions

##### Functions for drawing the introns, exons, and motifs

def draw_intex(intron1, exon, intron2, start):
    '''Draws the introns and exon of a sequence with one pixel corresponding to one base.'''
    # draw whole length of intron1 + exon + intron2
    context.set_source_rgb(0, 0, 0)
    context.set_line_width(1)
    context.move_to(start[0], start[1])
    context.line_to(start[0] + intron1 + exon + intron2, start[1])
    context.stroke()

    # draw wider exon
    context.set_line_width(14)
    context.move_to(start[0] + intron1, start[1])
    context.line_to(start[0] + intron1 + exon, start[1])
    context.stroke()

def draw_title(start, gene, info):
    '''Draws in the gene name and sequence information.'''
    # draw gene name
    context.set_font_size(15)
    context.set_source_rgb(0, 0, 0)
    context.move_to(start[0] - 325, start[1] - 5)
    context.show_text(gene)

    # draw sequence information
    context.set_font_size(10)
    context.move_to(start[0] - 325, start[1] + 5)
    context.show_text(info)

def draw_legend(start, motif, r, g, b):
    '''Draws in the colored motif legend.'''
    context.set_source_rgb(r, g, b)
    context.set_line_width(18)
    context.move_to(start[0] - 325, start[1] + spacing)
    context.show_text(motif)

def draw_motif(start, motif_position):
    '''Draws in a motif based on the start position and length of the motif.
    One pixel corresponds to one base.'''
    # draw motif
    context.move_to(start[0] + motif_position[0], start[1])
    context.line_to(start[0] + motif_position[0] + motif_position[1], start[1])
    context.stroke()

    # draw indicator tick mark
    context.move_to(start[0] + motif_position[0] + 0.25 * motif_position[1], start[1] - 15)
    context.show_text("|")

#####################################################################################
##### Check and Organize Files ######################################################
#####################################################################################

# set limit for number of motifs; too many motifs gets really messy
if count_lines(args.motifs) > 7:
    raise ValueError("ERROR: Exiting program. Too many motifs were supplied (maximum 7).")

# convert input fasta to have two lines per entry
fasta_twofer(args.fasta)

#####################################################################################
##### Make Dictionaries #############################################################
#####################################################################################

### IUPAC ambiguity codes and associated regular expressions for ignoring case
iupac = {"A":"[Aa]", "T":"[TtUu]", "C":"[Cc]", "G":"[Gg]", "U":"[TtUu]",
         "M":"[AaCc]", "R":"[AaGg]", "W":"[AaTtUu]",
         "S":"[CcGg]", "Y":"[CcTtUu]", "K":"[GgTtUu]",
         "V":"[AaCcGg]", "H":"[AaCcTtUu]", "D":"[AaGgTtUu]", "B":"[CcGgTtUu]",
         "N":"[AaTtCcGgUu]"}

### motif color dictionary
color_dict = {}
with open(args.motifs) as motif_list:
    for motif in motif_list:
        motif = motif.strip("\n")
        r = random.random()
        g = random.random()
        b = random.random()
        color_dict[motif] = [r, g, b]

####################################################################################
##### Find Motifs in Sequences ######################################################
#####################################################################################

all_positions = get_all_positions(fasta_f = "./sequences_twofer.fasta", motif_f = args.motifs)

#####################################################################################
##### Generate Visualizations #######################################################
#####################################################################################

# set up Cairo surface
surface_width = longest_sequence("./sequences_twofer.fasta") + 350 + 25
surface_height = count_lines("./sequences_twofer.fasta") / 2 * 135

surface = cairo.SVGSurface("./motif_mark.svg", surface_width, surface_height)
context = cairo.Context(surface)
context.set_line_width(1)
start = [350,100] # [x, y]

for one_position in all_positions: # for each sequence...
    # draw the introns and exon
    draw_intex(one_position["intron1"], one_position["exon"], one_position["intron2"], start)
    # initialize spacing variable for drawing the legend
    spacing = 20

    for motif_group in one_position.items(): # for each motif found in this sequence...
        # motif_group[0] is the header line with the attached motif
        # motif_group[1] is the list of motif starting positions and lengths

        if motif_group[0].startswith(">"):
            motif = motif_group[0].split("_")[1]
            details = motif_group[0].split("_")[0][1:]
            gene = details.split(" ")[0]
            info = " ".join(details.split(" ")[1:])

            # draw in the gene name and legend
            draw_title(start, gene, info)
            draw_legend(start, motif, color_dict[motif][0], color_dict[motif][1], color_dict[motif][2])

            # add spacing between legend entries
            spacing += 15

            for m in motif_group[1]:
                draw_motif(start, m)

    # add spacing before next sequence
    start = [start[0], start[1] + 100]

surface.finish()

print("Finished.")
sys.exit()


"""
Given a string s, find the length of the longest substring without repeating characters.

Example 1:

Input: s = "ababccbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:

Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:

Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.

Constraints:

0 <= s.length <= 5 * 104
s consists of English letters, digits, symbols and spaces.
"""

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        if len(s) == 1:
            return 1
        max_len = 1
        start = 0
        end = 1
        while end < len(s):
            if s[end] in s[start:end]:
                max_len = max(max_len, end - start)
                start = s[start:end].index(s[end]) + 1
            end += 1
        max_len = max(max_len, end - start)
        return max_len
    # how best to do this
    # length of longest substring
    # idea one, two pointers
    # and a string, if it is in the current subs string then sub string ends

    def lengthOfLongestSubstring2(self, s: str) -> int:
        """
        :type s: str
        :rtype: int
        """
        # if not s, saying if s doesnt exist then return 0
        if not s:
            return 0
        # if len(s) == 1 then can just return 1
        if len(s) == 1:
            return 1
        max_len = 1
        start = 0
        end = 1
        while end < len(s):
            #print(start, end, s[start:end], s[end])
            if s[end] in s[start:end]:  # when an repition has occured
                # print([s[end]])
                # decide if its bigger then previouse maximum
                max_len = max(max_len, end - start)
                # find index position of the first letter that has been repeated and move start to step after. do this by doing start ++
                start += s[start:end].index(s[end])+1
                #print("start = ", start)
            end += 1
        max_len = max(max_len, end - start)
        return max_len

    def lengthOfLongestSubstring3(self, s: str) -> int:
        n = len(s)
        ans = 0
        # mp stores the current index of a character
        mp = {}

        i = 0
        # try to extend the range [i, j]
        for j in range(n):
            if s[j] in mp:
                i = max(mp[s[j]], i)

            ans = max(ans, j - i + 1)
            mp[s[j]] = j + 1

        return ans

print(Solution().lengthOfLongestSubstring3("ababccbb"), "expected 3")  # 3
print(Solution().lengthOfLongestSubstring3("bbbbb"), "expected 1")  # 1
print(Solution().lengthOfLongestSubstring3("pwwkew"), "expected 3")  # 3


import numpy

from ipie.utils.backend import arraylib as xp

def set_rng_seed(seed, comm):
    if seed is None:
        # only set "random" part of seed on parent processor so we can reproduce
        # results in when running in parallel.
        if comm.rank == 0:
            seed = numpy.array([numpy.random.randint(0, 1e8)], dtype="i4")
            # Can't directly json serialise numpy arrays
        else:
            seed = numpy.empty(1, dtype="i4")
        comm.Bcast(seed, root=0)
        seed = seed[0]
    seed = seed + comm.rank
    xp.random.seed(seed)
    if comm.rank == 0:
        print(f"# random seed is {seed}")
    # assert False, f"{seed} {comm.rank}"
    return seed


from rest_framework import generics,mixins
from backend.models import Subject,Calender,Register,Group,SubjectCondition
from backend.api.serializers import (SubjectSerializers,CalenderSerializer,
                                     RegisterSerializer,GroupSerializer,
                                     SubjectConditionSerializer)
import json
from django.http import HttpResponse

class SubjectListCreateAPIView(generics.ListCreateAPIView):
    # queryset = Subject.objects.filter(name_group_id=2)
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializers

class SubjectDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    # queryset = Subject.objects.filter(name_group_id=2)
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializers

class CalenderListCreateAPIView(mixins.ListModelMixin,
                                mixins.CreateModelMixin,
                                generics.GenericAPIView):
    # queryset = Subject.objects.filter(name_group_id=2)
    queryset = Calender.objects.all()
    serializer_class = CalenderSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self,request,*args,**kwargs):
        mydata = json.loads(request.body)
        print(mydata)
        self.create(request, *args, **kwargs)
        return HttpResponse("Got json data")

class RegisterListCreateAPIView(generics.ListCreateAPIView):
    # queryset = Register.objects.filter(name_group_id=2)
    queryset = Register.objects.all()
    serializer_class = RegisterSerializer

class GroupListCreateAPIView(generics.ListCreateAPIView):
    # queryset = Register.objects.filter(name_group_id=2)
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

class SubjectConditionListCreateAPIView(generics.ListCreateAPIView):
    # queryset = Register.objects.filter(name_group_id=2)
    queryset = SubjectCondition.objects.all()
    serializer_class = SubjectConditionSerializer


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

import matplotlib.pyplot as plt
import numpy as np
import scipy.io.wavfile as wav
import csv
import tradataset as td

def morph_close(audio, fs=44100, n=1024):

    result=np.zeros(np.size(audio))
    l=n/2+1
    audio_abs=np.abs(audio)
    for i in range(l,len(audio)-l):
        result[i]=np.max(audio_abs[i-l:i+l])
    t = np.arange(len(result)) * (float(n)/fs)

    return result, t, audio_abs

def set_threshold(fragment):

    silence_file = fragment + '_silence.wav'
    activity_file = fragment + '_activity.wav'

    fs, audio_silence = wav.read(silence_file)
    fs, audio_activity = wav.read(activity_file)

    frame_size=512

    mc_silence, t_mc_silence, dummy = morph_close(audio_silence, fs, n=frame_size)
    mc_activity, t_mc_activity, dummy = morph_close(audio_activity, fs, n=frame_size)

    plt.figure()
    plt.hist([mc_activity, mc_silence], bins = 200)
    plt.grid()
    plt.axis('tight')
    plt.show()

    var_activity = np.var(mc_activity)
    var_silence = np.var(mc_silence)

    return var_activity, var_silence

if __name__ == "__main__":

    dataset = td.load_list()

    fragment = dataset[9]

    audio_file = fragment + '_mono.wav'
    gt_file = fragment + '.csv'

    fs, audio = wav.read(audio_file)
    t = np.arange(len(audio)) * (1/float(fs))

    audio_closed, t_mc, audio_abs = morph_close(audio, 4*880+1)

#    plt.figure(figsize=(18,6))
#    plt.plot(t_mc, audio_abs, 'r', label='wave')
#    plt.plot(t_mc, audio_closed, 'k', label='envelope')
#    plt.grid()

    onset=[]
    notes=[]
    cr = csv.reader(open(gt_file,"rb"))
    for row in cr:
        onset.append(row[0])
        notes.append(row[1])
    onset = np.array(onset, 'float32')
    i=0
    aux_vad_gt = np.empty([0,], 'int8')
    for note in notes:
        if note=='0':
            aux_vad_gt = np.r_[aux_vad_gt,0]
        else:
            aux_vad_gt = np.r_[aux_vad_gt,1]
        i=i+1
    j=0
    vad_gt = np.empty([len(t),], 'int8')
    for i in range(1,len(onset)):
        while (j<len(t) and t[j]>=onset[i-1] and t[j]<=onset[i]):
            vad_gt[j]=aux_vad_gt[i-1]
            j=j+1

#    plt.figure(figsize=(18,6))
#    plt.subplot(2,1,1)
#    plt.plot(t,audio)
#    plt.plot(t,(2**12)*vad_gt, label='VAD_gt')
#    plt.grid()
#    plt.title(fragment)
#    plt.tight_layout()
#    plt.subplot(2,1,2)
#    plt.plot(t_mc,audio_closed, label='envelope')
#    plt.plot(t,(2**12)*vad_gt, label='VAD_gt')
#    plt.grid()
#    plt.xlabel('Time (s)')
#    plt.legend(loc='best')
#    plt.tight_layout()
#    plt.show()

#%%
#    thershold_activity, thershold_silence = set_threshold(fragment)

    silence_file = fragment + '_silence.wav'
    activity_file = fragment + '_activity.wav'

    fs, audio_silence = wav.read(silence_file)
    fs, audio_activity = wav.read(activity_file)

    frame_size=512

    mc_silence, t_mc_silence, dummy = morph_close(audio_silence, fs, n=frame_size)
    mc_activity, t_mc_activity, dummy = morph_close(audio_activity, fs, n=frame_size)

    mean_activity = np.mean(mc_activity)
    mean_silence = np.mean(mc_silence)
    stddev_activity = np.sqrt(np.var(mc_activity))
    stddev_silence = np.sqrt(np.var(mc_silence))

#%%
    plt.figure(figsize=(18,6))
    plt.hist([mc_activity, mc_silence], bins = 100)
    plt.grid()
    plt.axvline(mean_activity-stddev_activity, color='r', linestyle='dashed', linewidth=2)
    plt.axvline(mean_silence+stddev_silence, color='y', linestyle='dashed', linewidth=2)
    plt.axis('tight')
    plt.show()

#%%
#    plt.figure(figsize=(18,6))
#    plt.subplot(2,1,1)
#    plt.plot(t,audio)
#    plt.plot(t,(2**12)*vad_gt, label='VAD_gt')
#    plt.grid()
#    plt.title(fragment)
#    plt.tight_layout()
#    plt.subplot(2,1,2)
#    plt.plot(t,audio_closed, label='envelope')
#    plt.plot(t,np.ones(len(t))*(mean_activity-stddev_activity),label='threshold')
#    plt.plot(t,(2**12)*vad_gt, label='VAD_gt')
#    plt.grid()
#    plt.xlabel('Time (s)')
#    plt.legend(loc='best')
#    plt.tight_layout()
#    plt.show()

#%% APPLY THRESHOLD

    thr=mean_activity-3.5*stddev_activity/4
    aux = np.clip(audio_closed, 0, thr)
    aux[aux<thr] = 0
    aux = aux/thr
    plt.figure(figsize=(18,6))
    plt.plot(t,audio, color='black', alpha=0.3, label='Waveform')
    plt.fill_between(t, -(2**12)*aux,(2**12)*aux*0.5, facecolor='yellow', label='VAD', alpha=0.6)
    plt.fill_between(t, -(2**12)*vad_gt*0.5,(2**12)*vad_gt, facecolor='cyan', label='GT', alpha=0.6)
    plt.grid()
    plt.axis('tight')
    plt.legend(loc='lower right', fancybox=True, framealpha=0.5)
    plt.show()
#    plt.savefig('docs/prueba.pdf', dpi=600)


#연월일 달력
import sys
sys.stdin = open("input.txt","r")
months = list(range(1,13))
days = [31,28,31,30,31,30,31,31,30,31,30,31]
for t in range(1,int(input())+1):
    ymd = input()
    y,m,d = ymd[0:4],ymd[4:6],ymd[6:8]
    if int(d)<=days[int(m)-1] and int(m) in months:
        print(f'#{t} {y}/{m}/{d}')
    else:
        print(f'#{t} -1')


"""create chatroom

Revision ID: 0b589322b935
Revises: 7a116296822b
Create Date: 2019-10-26 16:19:19.456316

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = '0b589322b935'
down_revision = '7a116296822b'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        'Chatroom',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('created_at', sa.DateTime(), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
    )
    op.add_column('User', sa.Column('chatroom_id', sa.Integer(), nullable=True))
    op.create_foreign_key(None, 'User', 'Chatroom', ['chatroom_id'], ['id'])
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint(None, 'User', type_='foreignkey')
    op.drop_column('User', 'chatroom_id')
    op.drop_table('Chatroom')
    # ### end Alembic commands ###


import cv2
import numpy as np
import time
import paint
# import draw
# import draw2
import os

def old():
    cap = cv2.VideoCapture('videos/chm.flv')
    # Check if camera opened successfully
    if (cap.isOpened() == False):
        print("Error opening video stream or file")
    i = 0
    while (cap.isOpened()):
        ret, frame = cap.read()
        if ret == True:
            try:
                o = paint.drawRandBg(frame, blur=None)
                o.save(f"outputs/chm/{i}.png", "PNG")
            except:
                pass
            i += 1
        else:
            break
    cap.release()
    cv2.destroyAllWindows()

def makeVideo(inputVideoPath: str, output: str, cutFrames: int = 1, w: int = 1, h: int = 1, blur: int = 0):
    """
    输出的视频没有音频轨道没有原视频对比,请放入其他剪辑软件中自行添加.另,如果w和h调的特别大的话,视频分辨率会超级高.
    :param input:输入视频的路径
    :param output:输出视频的路径,请以".avi"结尾
    :param cutFrames:抽帧频率,比如填1的话,则原视频每一帧都会处理后加入新视频中;填2的话,原视频每2帧会有一帧处理后加入新视频中
    :param w:横向画板数
    :param h:纵向画板数
    :param blur:控制线条加粗,设为0的话不做加粗处理.不为0的话只能填单数,即1,3,5,7等.某些情况下线条加粗比较符合像素风,请按需取用
    :return:None
    """
    inVideo = cv2.VideoCapture(inputVideoPath)
    inFps = inVideo.get(cv2.CAP_PROP_FPS)
    outFps = inFps / cutFrames
    framesCount = int(inVideo.get(cv2.CAP_PROP_FRAME_COUNT))

    outVideo = cv2.VideoWriter(output, cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), outFps,
                               (37 * 20 * w + 278 + 262, 22 * 20 * h + 110 + 170))
    if (inVideo.isOpened() == False):
        print("Error opening video stream or file")
    i = 0
    while (inVideo.isOpened()):
        ret, frame = inVideo.read()
        if ret == True:
            if i % cutFrames == 0:
                try:
                    o = paint.drawN(frame,w=w,h=h, blur=blur)
                    img = cv2.cvtColor(np.asarray(o), cv2.COLOR_RGB2BGR)
                except:
                    pass
                else:
                    outVideo.write(img)
                print(f"{i:>10} of {framesCount} frames handdled")
            i += 1
        else:
            break
    inVideo.release()
    outVideo.release()

def futuresMakeVideo(inputVideoPath: str, output: str, cutFrames: int = 1, w: int = 1, h: int = 1, blur: int = 0,works=os.cpu_count()):
    from concurrent import futures

    inVideo = cv2.VideoCapture(inputVideoPath)
    inFps = inVideo.get(cv2.CAP_PROP_FPS)
    outFps = inFps / cutFrames
    framesCount = int(inVideo.get(cv2.CAP_PROP_FRAME_COUNT))
    inVideo.get()
    outVideo = cv2.VideoWriter(output, cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), outFps,
                               (37 * 20 * w + 278 + 262, 22 * 20 * h + 110 + 170))
    if (inVideo.isOpened() == False):
        print("Error opening video stream or file")

    works = works if 0 < works <= os.cpu_count() else os.cpu_count()
    toHanddle = {}
    handdledFrames = {}
    readVideoI = 0
    handdleVideoI = 0
    def readOneGroup():
        nonlocal readVideoI
        for x in range(works):
            ret, frame = inVideo.read()
            toHanddle[str(readVideoI)] = frame
            readVideoI += 1
        return toHanddle

    def handdleFrame(x:int):
        nonlocal toHanddle,handdledFrames,handdleVideoI
        sx = str(x)
        frame = toHanddle[sx]
        handdledFrame = paint.drawN(frame, w=w, h=h, blur=blur)
        handdledFrame = cv2.cvtColor(np.asarray(handdledFrame), cv2.COLOR_RGB2BGR)
        handdledFrames[sx] = handdledFrame
        for i in range(handdleVideoI,x + 1):
            si = str(i)
            if si in handdledFrames.keys():
                outVideo.write(handdledFrames[si])
                handdleVideoI += 1
            else:
                continue
        if toHanddle.__len__() <= 16:
            readOneGroup()
    handdled = 0
    readOneGroup()
    readOneGroup()
    print(toHanddle)
    with futures.ProcessPoolExecutor(works) as exe:
        all_task = [exe.submit(handdleFrame,i) for i in range(framesCount)]
        for future in futures.as_completed(all_task):
            handdled += 1
            print(f"{handdled}/{framesCount} handdled")
    inVideo.release()
    outVideo.release()

def futuresMakeVideoFuck(inputVideoPath: str, output: str, cutFrames: int = 1, w: int = 1, h: int = 1, blur: int = 0,works=os.cpu_count()):
    from concurrent import futures

    inVideo = cv2.VideoCapture(inputVideoPath)
    inFps = inVideo.get(cv2.CAP_PROP_FPS)
    outFps = inFps / cutFrames
    framesCount = int(inVideo.get(cv2.CAP_PROP_FRAME_COUNT))
    outVideo = cv2.VideoWriter(output, cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), outFps,
                               (37 * 20 * w + 278 + 262, 22 * 20 * h + 110 + 170))
    if (inVideo.isOpened() == False):
        print("Error opening video stream or file")

    works = works if 0 < works <= os.cpu_count() else os.cpu_count()
    frames = []
    while (inVideo.isOpened()):
        ret, frame = inVideo.read()
        if ret == True:
            frames.append(frame)
    def handdleOne(frame):
        o = paint.drawN(frame, w=w, h=h, blur=blur)
        img = cv2.cvtColor(np.asarray(o), cv2.COLOR_RGB2BGR)
        pass
    with futures.ProcessPoolExecutor(works) as exe:
        all_task = [exe.submit(handdleFrame, i) for i in range(framesCount)]
        for future in futures.as_completed(all_task):
            handdled += 1
            print(f"{handdled}/{framesCount} handdled")
    inVideo.release()
    outVideo.release()

if __name__ == '__main__':
    # makeVideo("videos/sjw.mp4", "sjw.avi",1,4,4)
    futuresMakeVideoFuck("videos/ng.mp4", "ng.avi",1,1,1)
    # print("1" in {"1":3}.keys())
    # x = 0
    # for n in range(x,10):
    #     print(n)
    #     x = 5


import os
import platform
import psutil
import math
import curses

def main_menu():
     stdscr.clear()
     stdscr.refresh()
     stdscr.border(0)

     stdscr.addstr(5, 5, 'Get information about your system', curses.A_BOLD)
     stdscr.addstr(6, 5, 'Press t for terminal :', curses.A_BOLD)
     stdscr.addstr(7, 5, 'Press s for system :', curses.A_BOLD)
     stdscr.addstr(8, 5, 'Press m for memory :', curses.A_BOLD)
     stdscr.addstr(9, 5, 'Press d for disk :', curses.A_BOLD)
     stdscr.addstr(10, 5, 'Press w for swap_memory :', curses.A_BOLD)
     stdscr.addstr(12, 5, 'Press q to close this screen', curses.A_NORMAL)
     while True:
            # stay in this loop till the user presses 'q'
            ch = stdscr.getch(12,50)
            if ch == ord('q'):
                break
            elif ch == ord('t'):
                terminal()
            elif ch == ord('s'):
                system()
            elif ch == ord('m'):
                memory()
            elif ch == ord('d'):
                disk()
            elif ch == ord('w'):
                swap_memory()
        # -- End of user code
def system():
  stdscr.clear()
  stdscr.refresh()
  curses.echo()
  stdscr.addstr(2, 5, "---------------------------------------------------------------------------")
  stdscr.addstr(3, 5, "The name of the system is " + str(platform.node()))
  stdscr.addstr(4, 5, "The platform of the system is " + str(platform.platform()))
  stdscr.addstr(5, 5, "The architecture of the system is " + str(platform.architecture()))
  stdscr.addstr(6, 5, "The version of the system is " + str(platform.release()))
  stdscr.addstr(7, 5, "---------------------------------------------------------------------------")
  stdscr.refresh()
  curses.napms(6000)
  main_menu()
def terminal():
  stdscr.clear()
  stdscr.refresh()
  curses.echo()
  stdscr.addstr(2, 5, "---------------------------------------------------------------------------")
  stdscr.addstr(3, 5, "the number of characters in your terminal is " + str(os.get_terminal_size().columns))
  stdscr.addstr(4, 5, "the number of lines in your terminal is " + str(os.get_terminal_size().lines))
  stdscr.addstr(5, 5, "---------------------------------------------------------------------------")
  stdscr.refresh()
  curses.napms(3000)
  main_menu()
def memory():
  stdscr.clear()
  stdscr.refresh()
  curses.echo()
  stdscr.addstr(2, 5, "---------------------------------------------------------------------------")
  stdscr.addstr(3, 5, "the total memory in your RAM is " + str(math.ceil(psutil.virtual_memory().total / 1024**3)) + "GB")
  stdscr.addstr(4, 5, "the available memory in your RAM is " + str(math.ceil(psutil.virtual_memory().available / 1024**3)) + "GB")
  stdscr.addstr(5, 5, "the used memory in your RAM is " + str(math.ceil(psutil.virtual_memory().used / 1024**3)) + "GB")
  stdscr.addstr(6, 5, "the free memory in your RAM is " + str(math.ceil(psutil.virtual_memory().free / 1024**3)) + "GB")
  stdscr.addstr(7, 5, "---------------------------------------------------------------------------")
  stdscr.refresh()
  curses.napms(6000)
  main_menu()
def swap_memory():
  stdscr.clear()
  stdscr.refresh()
  curses.echo()
  stdscr.addstr(2, 5, "---------------------------------------------------------------------------")
  stdscr.addstr(3, 5, "the total swap memory is " + str(math.ceil(psutil.swap_memory().total / 1024**3)) + "GB")
  stdscr.addstr(4, 5, "the swap memory percent is " + str(math.ceil(psutil.swap_memory().percent)))
  stdscr.addstr(5, 5, "the used swap memory is " + str(math.ceil(psutil.swap_memory().used / 1024**3)) + "GB")
  stdscr.addstr(6, 5, "the free swap memory is " + str(math.ceil(psutil.swap_memory().free / 1024**3)) + "GB")
  stdscr.addstr(7, 5, "---------------------------------------------------------------------------")
  stdscr.refresh()
  curses.napms(6000)
  main_menu()
def disk():
  stdscr.clear()
  stdscr.refresh()
  curses.echo()
  stdscr.addstr(2, 5, "---------------------------------------------------------------------------")
  stdscr.addstr(4, 5, "the total disk memory is " + str(math.ceil(psutil.disk_usage('/').total / 1024**3)) + "GB")
  stdscr.addstr(5, 5, "the disk memory percent is " + str(math.ceil(psutil.disk_usage('/').percent)) + "%")
  stdscr.addstr(6, 5, "the used disk memory is " + str(math.ceil(psutil.disk_usage('/').used / 1024**3)) + "GB")
  stdscr.addstr(7, 5, "the free disk memory is " + str(math.ceil(psutil.disk_usage('/').free / 1024**3)) + "GB")
  stdscr.addstr(8, 5, "---------------------------------------------------------------------------")
  stdscr.refresh()
  curses.napms(7500)
  main_menu()

stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)

main_menu()

stdscr.keypad(0)
curses.echo()
curses.nocbreak()
curses.endwin()


import torch

class model:
    def __init__(self,weights_path) -> None:
        self.model = torch.hub.load('WongKinYiu/yolov7', 'custom', weights_path, force_reload = False, trust_repo=True)

    def get_results(self,images):
        results = self.model(images)
        result_table = results.pandas().xyxy[0]

        confidence = 0

        xmin_bbox = -1
        ymin_bbox = -1
        xmax_bbox = -1
        ymax_bbox = -1
        name = -1

        for _, row in result_table.iterrows():
            if (row["confidence"] > confidence):
                confidence = row["confidence"]
                xmin_bbox = int(row["xmin"])
                ymin_bbox = int(row["ymin"])
                xmax_bbox = int(row["xmax"])
                ymax_bbox = int(row["ymax"])
                name = row["name"]

        results_array = [[xmin_bbox, ymin_bbox, xmax_bbox, ymax_bbox], name]
        return results_array


with open("input.txt", "r") as input_file:
    INPUT = input_file.read().strip()

EXAMPLE = """35
20
15
25
47
40
62
55
65
95
102
117
150
182
127
219
299
277
309
576"""

def parse_raw(data_raw: str) -> list:
    return [int(e) for e in data_raw.splitlines()]

def part_one(data_raw, length_to_check=5):
    for index, elem in enumerate(parse_raw(data_raw)[length_to_check:]):
        prev_five = parse_raw(data_raw)[index: index + length_to_check]
        check = False
        for i, a in enumerate(prev_five):
            for j, b in enumerate(prev_five):
                if i != j and a + b == elem:
                    check = True
        if not check:
            return elem

assert part_one(EXAMPLE) == 127
print("First error in XMAS protocol (first part answer) is:", part_one(INPUT, 25))

def part_two(data_raw, length_to_check=5):
    data = parse_raw(data_raw)
    first_error = part_one(data_raw, length_to_check)
    for i, a in enumerate(data):
        for j, b in enumerate(data):
            current_range = data[i:j + 1]
            if j > i and first_error == sum(current_range):
                return max(current_range) + min(current_range)

assert part_two(EXAMPLE) == 62
print("Encryption weakness in XMAS protocol (second part answer) is:", part_two(INPUT, 25))


#!/usr/bin/python3

from Possibilities import Possibilities

# SolveSudoku - child class of Possibilities and solves by
# adding possible to sudoku

class SolveSudoku(Possibilities):
    def solve_puzzle(self):
        m = n = 0
        for i in range(9):
            for j in range(9):
                # add if len of possible values is 1 and
                # value to be replaced is 0
                if len(self.possible[i][j]) == 1 and self.sudoku[i][j] == 0:
                    n += 1
                    self.sudoku[i][j] = self.possible[i][j][0]
        if m == n:
            # check if done solving possible
            self.done1 = True


# coding: utf-8

# common preamble
import os
import sys
import inspect
import numpy as np
root = os.path.dirname(__file__)
sys.path.append('{0}/../'.format(root))
incasa = '__CASAPY_PYTHONDIR' in os.environ
if incasa:
    from taskinit import casalog as logger
else:
    from viparc.log import pythonlog as logger

# unique preamble
import pyfits as fits
from viparc.map import DefaultConverter, PointingConverter

# definition of task
def mbconvertscantomap(method='default', rcpfile=None, pixels=[], gain='point', pixel=None, gridsizes=[6.0,6.0], gridrefvals=[0.0,0.0], label=''):
    depth = [s[3] for s in inspect.stack()].index('<module>')
    mbglobals = sys._getframe(depth).f_globals
    taskname = sys._getframe().f_code.co_name
    logger.origin(taskname)

    mbsc = mbglobals['__mbscans__'][label]

    if method == 'default':
        rcpfile = os.path.expanduser(rcpfile)
        converter = DefaultConverter(rcpfile, pixels, gain, gridsizes, gridrefvals)
        logger.post('method: default')
        logger.post('RCP: {0}'.format(os.path.basename(rcpfile)))
    elif method == 'pointing':
        converter = PointingConverter(pixel, gridsizes, gridrefvals)
        logger.post('method: pointing')
        logger.post('pixel to be processed: {0}'.format(pixel))

    mbmp = mbsc.tomap(converter)
    mbmp.recordtask(taskname)
    mbglobals['__mbmaps__'].append(mbmp)

    logger.post('map is successfully converted from MBScan')
    logger.post('new MBMap is now stored as __mbmaps__[0]')


import json
import os
import copy
from common.bean.frame import Frame
from common.bean.instruction_status import InstructionStatus
from View.bean.ui_data import UIData
from View.bean.instruction_full_status import InstructionFullStatus
from View.bean.instruction_extend import InstructionExtend
from View.bean.opcode import opcodesOf
from View.bean.debug import writeTestTmpFile, print_UID

class Workflow:
    path: str = "../tmp"
    frames: list = []
    UIDs: list = []
    IFSList: list = []

    def __init__(self):
        self.path = "tmp"
        self.frames = []
        self.realFrames = []
        self.UIDs = []
        self.IFSList = []

    def readTmpFile(self, path: str):
        with open(path, 'r') as f:
            self.frames = json.load(f)

    def updateIFSList(self, currentCycle: int, updates: list) -> list:
        for update in updates:
            if update.stage == "issue":
                newInstrStat = InstructionFullStatus()
                newInstrStat.instruction = update.instruction
                newInstrStat.issueStartCycle = currentCycle
                self.IFSList.append(newInstrStat)
            elif update.stage == "read":
                for IFS in self.IFSList:
                    if IFS.issueStartCycle == update.instruction.issueCycle:
                        IFS.readStartCycle = currentCycle
                        break
            elif update.stage == "execute":
                for IFS in self.IFSList:
                    if IFS.issueStartCycle == update.instruction.issueCycle:
                        IFS.exeStartCycle = currentCycle
                        break
            elif update.stage == "wb":
                for IFS in self.IFSList:
                    if IFS.issueStartCycle == update.instruction.issueCycle:
                        IFS.writeResultStartCycle = currentCycle
                        break
            elif update.stage == "stall":
                pass
            else:
                print("Unknown Stage Status: "+update.stage+"..Aborting")
                os.abort()
        return self.IFSList

    def buildExtendList(self, sources: list) -> list:
        results = []
        for source in sources:
            result = InstructionExtend()
            result.instruction = source.instruction
            result.operationCode = opcodesOf(source.instruction)
            results.append(result)
        return results

    def buildUIData(self):
        for frameDict in self.frames:
            frame = Frame.newFrame(frameDict)
            self.realFrames.append(frame)

        killTarget = []
        for idx, frame in enumerate(self.realFrames):
            for idxInstr, instr in enumerate(frame.instructionStatusList):
                if instr.stage == "execute" and idx != len(self.realFrames)-1:
                    find = False
                    for futureFrame in self.realFrames[idx+1:]:
                        for instr2 in futureFrame.instructionStatusList:
                            if instr.instruction.issueCycle == instr2.instruction.issueCycle and instr2.stage == "execute":
                                killTarget.append([idx, instr.instruction.issueCycle])
                                find = True
                                break
                        if find is True:
                            break

        for idx, frame in enumerate(self.realFrames):
            newISL = []
            for instr in frame.instructionStatusList:
                if [idx, instr.instruction.issueCycle] not in killTarget:
                    newISL.append(instr)
            frame.instructionStatusList = copy.deepcopy(newISL)

        for frame in self.realFrames:
            UID = UIData()
            UID.instructionFullStatusList = self.updateIFSList(frame.currentCycle, frame.instructionStatusList)
            UID.functionUnitStatus = frame.functionUnitStatus
            UID.registerStatusList = frame.registerStatusList
            UID.registerValueList = frame.registerValueList
            UID.instructionExtendList = self.buildExtendList(UID.instructionFullStatusList)
            UID.stallList = frame.stallList
            UID.log = frame.log
            UID.ProgramCounter = frame.ProgramCounter
            self.UIDs.append(copy.deepcopy(UID))

    def toUIData(self, dst: int) -> UIData:
        return self.UIDs[dst]

    def lengthOfUIDs(self):
        return len(self.UIDs)

    def workflow(self):
        # writeTestTmpFile()
        # callSimulator()
        self.readTmpFile(self.path)
        self.buildUIData()
        # callUI()

        # f = open("out.txt", "w")
        # print_UID(self.toUIData(0), f)
        # print_UID(self.toUIData(1), f)
        # f.close()

# Workflow.workflow(Workflow)


import os
import shutil

from simphony.cuds.abc_particles import ABCParticles
from simphony.cuds.abc_lattice import ABCLattice
from simphony.cuds.abc_mesh import ABCMesh

from simphony_aviz.util import (run_aviz,
                                temp_particles_filename,
                                create_xyz_file)

def snapshot(cuds, filename):
    """ Save a snapshot of the cuds object using the default visualisation.

    Parameters
    ----------
    cuds : {ABCMesh, ABCParticles, ABCLattice}
        The CUDS dataset to be shown.
    filename : string
        The filename to use for the output file.

    Raises
    ------
    TypeError:
        If the container type is not supported by the engine.

    """
    if isinstance(cuds, ABCParticles):
        with temp_particles_filename() as temp_xyz_filename:
            create_xyz_file(cuds, temp_xyz_filename)
            run_aviz([temp_xyz_filename, "-snapq"])
            snapshot_dir = os.path.dirname(os.path.realpath(temp_xyz_filename))
            snapshot_file = _find_png(snapshot_dir)
            shutil.copyfile(snapshot_file, filename)
    elif isinstance(cuds, ABCLattice) or isinstance(cuds, ABCMesh):
        raise TypeError("Only Particles can be shown by AViz")
    else:
        msg = 'Provided object {} is not of any known cuds type'
        raise TypeError(msg.format(type(cuds)))

def _find_png(directory):
    """ Return the filename of the first found png file

    Parameters
    ----------
    directory: string
        the directory where pngs are searched for

    """
    for filename in os.listdir(directory):
        name, file_extension = os.path.splitext(filename.lower())
        if file_extension == ".png":
            return os.path.join(directory, filename)
    else:
        raise RuntimeError("Could not find created snapshot")


#!/usr/bin/python
# coding=utf-8
'''
__author__ = 'sunp'
__date__ = '2019/2/22'
'''
from array import array

class BitSet(object):
    '''
    to be optimized: handle `pos >= self.size()`
    '''
    def __init__(self, capacity):
        self.capacity = capacity
        self.unit_size = 8
        self.unit_count = int(capacity / self.unit_size) + 1
        self.arr = array('B', [0] * self.unit_count)

    def set(self, pos=-1):
        if pos == -1:
            mask = (1 << self.unit_size) - 1
            for i in range(self.unit_count):
                self.arr[i] |= mask
        else:
            idx, offset = self._pair(pos)
            self.arr[idx] |= (1 << offset)

    def get(self, pos):
        idx, offset = self._pair(pos)
        return (self.arr[idx] >> offset) & 1

    def reset(self, pos=-1):
        if pos == -1:
            for i in range(self.unit_count):
                self.arr[i] = 0
        else:
            idx, offset = self._pair(pos)
            self.arr[idx] &= ~(1 << offset)

    def flip(self, pos=-1):
        if pos == -1:
            for i in range(self.unit_count):
                self.arr[i] = ~self.arr[i]
        else:
            idx, offset = self._pair(pos)
            self.arr[idx] ^= (1 << offset)

    def size(self):
        return self.unit_count * self.unit_size

    def show(self):
        print(self.arr)

    def _pair(self, pos):
        idx = int(pos / self.unit_size)
        offset = pos % self.unit_size
        return idx, offset

if __name__ == '__main__':
    test = BitSet(20)

    assert test.size() == 24
    assert test.get(0) == 0
    test.set(0)
    assert test.get(0) == 1
    test.reset(0)
    assert test.get(0) == 0
    test.flip(0)
    assert test.get(0) == 1
    test.flip(0)
    assert test.get(0) == 0


from data_prepare import DataPrepare
from bilsmt_crf import BiLSTM_CRF
from torch import optim
import torch
import os

def train(dp: DataPrepare):
    x_sent, x_tags, mask = dp.prepare_data()
    model = BiLSTM_CRF(len(dp.vocab), len(dp.tags))
    optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)

    for epoch in range(300):  # normally you would NOT do 300 epochs, it is toy data

        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        model.zero_grad()

        # Step 2. Get our inputs ready for the network, that is,
        # turn them into Tensors of word indices.
        sentence_in = x_sent
        targets = x_tags

        # Step 3. Run our forward pass.
        loss = model.loss(sentence_in, targets, mask=mask)

        # Step 4. Compute the loss, gradients, and update the parameters by
        # calling optimizer.step()
        loss.backward()
        optimizer.step()
    return model

def better_print(raw, path, dict):
    for sen, p in zip(raw, path):
        labels = {}
        p = [dict[x] for x in p]

        index = 0
        key = []
        value = ""
        while index < len(p):
            if 'B' in p[index] or 'I' in p[index]:
                key.append(sen[index])
                value = p[index]
            else:
                if (len(key) > 0):
                    keys = ''.join(key)
                    labels[keys] = value.split('_')[0]
                    key = []
                    value = ""
            index += 1

        print("语句是: %s" % sen)
        print(f"提取的实体有: {labels}")

if __name__ == '__main__':
    dp = DataPrepare(os.getcwd() + '/doccano.json')
    model = train(dp)
    with torch.no_grad():
        xx_sent, mask = dp.predict(["奥雷连诺上校在马孔多"])
        _, seqs = model(xx_sent, mask=mask)
        better_print(["奥雷连诺上校在马孔多"], seqs, dp.dict)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 17 05:09:07 2018

@author: saket11
"""

from pythainlp.tokenize import word_tokenize
import json

"""
Training Data

Edit here to add intents
===========================================================================

"""

intents = [{
    "name": "playsong",
    "patterns": [
        'เปิดเพลง','เล่นเพลง'
    ]
}, {
    "name": "checkcalendar",
    "patterns": [
        'บอกการแจ้งเตือนปฏิทิน','ดูปฏิทิน', 'มีการแจ้งเตือน','เช็คปฏิทิน','เช็คการแจ้งเตือน',"ดูการแจ้งเตือน",'เช็คแจ้งเตือน'
    ]
},{
    "name": "setreminder",
    "patterns": [
        'ตั้งการแจ้งเตือนใหม่'
    ]
},{
    "name": "email",
    "patterns": [
        'เช็คเมล์','เช็คอีเมล','เช็คinbox','ตรวจอีเมล','ตรวจเมล์'
    ]
}]

"""

===========================================================================

"""

"""Get classes of intent from data"""
classes = list(map(lambda intent: intent['name'], intents))

"""Create frequency table with each class and its corresponding words"""
class_words = {}
corpus_words = {}
for intent in intents:
  class_words[intent['name']] = []
  for pattern in intent['patterns']:
    for word in word_tokenize(pattern,engine='newmm'):
      if word not in corpus_words:
        corpus_words[word] = 1
      else:
        corpus_words[word] += 1
      class_words[intent['name']].extend([word])

print("Word in each class:")
print(class_words)
print("\n")
print("All words with frequency")
print(corpus_words)

with open('corpus/class.txt', 'w') as f:
    json.dump(class_words, f)
with open('corpus/words.txt', 'w') as f:
    json.dump(corpus_words, f)


"""
HOW TO USE:
>>> path_source_db = 'db.sqlite'
>>> path_target_db = 'db_backup.sqlite'
>>> target_db_alias = 'target_db'
>>> check_name(target_db_alias)

>>> with get_connection(path_source_db, path_target_db, target_db_alias) as conn:
>>>     tables = get_all_tables(conn)
>>>     backup_tables = get_references(conn, tables=tables)
>>>     new_data = []

>>>     for table in backup_tables:
>>>         check_name(table)
>>>         diff_rows = db_diff(
>>>             conn=conn,
>>>             table_name=table,
>>>             target_db_alias=target_db_alias,
>>>         )
>>>     if diff_rows:
>>>        new_data.append((table, diff_rows))

>>> for table, rows in new_data[::-1]:
>>>     if diff_rows:
>>>         copy_rows(
>>>             conn=conn,
>>>             table_name=table,
>>>             rows=rows,
>>>             target_db_alias=target_db_alias,
>>>        )

>>> conn.commit()

"""

import os
import re
import sqlite3
from contextlib import contextmanager
from typing import Any, List, Tuple, Optional

RE_REFERENCES = re.compile(r'references ["]*([A-z0-9]+)["]*', re.IGNORECASE)

def db_diff(
    conn: sqlite3.Connection,
    table_name: str,
    target_db_alias: str,
) -> List[Tuple[Any]]:
    """Compare the same tables in two databases and return new or updated rows from the source table.
    """
    source_table_columns = conn.execute("SELECT * FROM main.PRAGMA_TABLE_INFO(?);",
                                        (table_name,)).fetchall()
    target_table_columns = conn.execute(f"SELECT * FROM {target_db_alias}.PRAGMA_TABLE_INFO(?);",
                                        (table_name,)).fetchall()

    column_errors = []
    columns_only_in_source = set(source_table_columns) - set(target_table_columns)
    if columns_only_in_source:
        column_errors.append(f"Backup table has not columns: {', '.join(columns_only_in_source)}")

    columns_only_in_backup = set(target_table_columns) - set(source_table_columns)
    if columns_only_in_backup:
        column_errors.append(f"Backup table has extra columns: {', '.join(columns_only_in_backup)}")

    if column_errors:
        raise ValueError('\n'.join(column_errors))

    columns = ', '.join(c for _, c, *_ in source_table_columns)

    q = f"""
        SELECT {columns}
        FROM (
            SELECT 1 AS db, {columns} FROM {target_db_alias}.`{table_name}`
            UNION ALL
            SELECT 2 AS db, {columns} FROM main.`{table_name}`
        ) q1
        group by {columns} having sum(db)=2;
    """

    diff_rows = conn.execute(q).fetchall()

    return diff_rows

def copy_rows(
    conn: sqlite3.Connection,
    table_name: str,
    rows: List[Tuple[Any]],
    target_db_alias: str,
):
    if not rows:
        raise ValueError("rows attribute is empty")

    placeholders = ', '.join('?' for _ in range(len(rows[0])))
    q = f"INSERT OR REPLACE INTO {target_db_alias}.`{table_name}` VALUES ({placeholders})"
    conn.executemany(q, rows)

def get_references(conn: sqlite3.Connection, tables: List[str]) -> List[str]:
    """Get target tables with reference tables in child to parent order
    """
    tables_copy = tables[:]
    references = []
    while tables_copy:
        on_ref_table = tables_copy.pop(0)

        if on_ref_table not in references:
            references.append(on_ref_table)

        sql = conn.execute("select sql from main.sqlite_master where tbl_name=?",
                           (on_ref_table,)).fetchone()
        ref_tables = RE_REFERENCES.findall(sql[0])

        for table in ref_tables:
            if table in references:
                references.sort(key=table.__eq__)
            elif table not in tables_copy:
                tables_copy.append(table)

            references.append(table)

    return references

def get_all_tables(conn: sqlite3.Connection):
    tables = conn.execute("SELECT name FROM main.sqlite_master WHERE type='table';").fetchall()
    return [t[0] for t in tables]

@contextmanager
def get_connection(
    path_source_db: str,
    path_target_db: str,
    target_db_alias: str,
) -> sqlite3.Connection:
    if not os.path.exists(path_source_db):
        raise FileNotFoundError(f"Database {path_source_db} not found")

    if not os.path.exists(path_target_db):
        raise FileNotFoundError(f"Database {path_target_db} not found")

    conn = sqlite3.connect(path_source_db)
    conn.execute("ATTACH DATABASE ? AS ?;", (path_target_db, target_db_alias))

    try:
        yield conn
    finally:
        conn.close()

def check_name(table_name: str):
    for symbol in table_name:
        if symbol.isalnum() or symbol.isdigit() or symbol in ('_', '-'):
            continue
        raise ValueError(f"You shouldn't use the table name - {table_name}")


from flask import Blueprint, request, session, render_template
from flask.ext.wtf import Form, SelectField, BooleanField
from flask.views import MethodView
from app import app
from models import Image
from urlparse import urljoin
import datetime

images = Blueprint('images', __name__, template_folder='templates')

class SortForm(Form):
    sort_by = SelectField(u'Sort by', choices=[('date_added', 'Date Added'),
                                               ('num_views', 'Num Views')])
    sort_order = SelectField(u'Sort order', choices=[('desc', 'Desc'),
                                                     ('asc', 'Asc')])
    num_per_page = SelectField(u'Num per page', choices=[('25', '25'),
                                                         ('50', '50'),
                                                         ('100', '100'),
                                                         ('999999999', 'All')])

class ListView(MethodView):
    def set_sorting(self):
        if request.form.get('sort_order'):
            session['sort_order'] = request.form.get('sort_order')

        if request.form.get('sort_by'):
            session['sort_by'] = request.form.get('sort_by')

        if request.form.get('num_per_page'):
            session['num_per_page'] = request.form.get('num_per_page')

    def get_context(self, pagenum):
        images = Image.get_sorted_list()

        try:
            num_per_page = session['num_per_page']
        except KeyError:
            num_per_page = 25
            session['num_per_page'] = num_per_page

        images = images.paginate(pagenum,
                                 int(num_per_page), False)

        form = SortForm(formdata=request.form)

        # reflect current setting in form
        try:
            form.sort_order.data = session['sort_order']
        except KeyError:
            pass

        try:
            form.sort_by.data = session['sort_by']
        except KeyError:
            pass

        try:
            form.num_per_page.data = session['num_per_page']
        except KeyError:
            pass

        context = {
            "images": images,
            "form": form
        }
        return context

    def get(self, pagenum):
        context = self.get_context(pagenum)
        return render_template('images/list.html', **context)

    def post(self, pagenum=1):
        self.set_sorting()
        context = self.get_context(pagenum)
        return render_template('images/gallery.html', **context)

class DetailView(MethodView):
    def get(self, filename):
        image = Image.query.filter_by(filename=filename).first_or_404()
        image.inc_num_views()
        return render_template('images/detail.html', image=image)

class RssView(MethodView):
    def make_external_url(self, url):
        static_image_url = urljoin(request.url_root, app.config['STATIC_URL'])
        return urljoin(static_image_url, url)

    def get(self):
        from werkzeug.contrib.atom import AtomFeed
        feed = AtomFeed('Kthnxbai Recent Images',
                    feed_url=request.url, url=request.url_root)

        images = Image.query.order_by(Image.added_on.desc()) \
                      .limit(15).all()

        for image in images:
            image_url = self.make_external_url(
                    '.'.join((image.filename, image.ext)))
            title = image.added_on.strftime('%d/%m/%Y')

            feed.add(title,
                     unicode('<img src="%s">' % image_url),
                     content_type='html',
                     author='kthnxbai',
                     url=image_url,
                     updated=image.added_on
                     )

        return feed.get_response()

images.add_url_rule('/', view_func=ListView.as_view('list'),
                    defaults={'pagenum': 1})
images.add_url_rule('/<int:pagenum>/', view_func=ListView.as_view('list'))

images.add_url_rule('/reorder/<int:pagenum>/',
                    view_func=ListView.as_view('list'))
images.add_url_rule('/reorder/', view_func=ListView.as_view('list'))

images.add_url_rule('/detail/<filename>/',
                    view_func=DetailView.as_view('detail'))

images.add_url_rule('/latest.atom',
                    view_func=RssView.as_view('rss'))


from tkinter import *
from tkinter import ttk, filedialog

from dao.output_config_dao import OutputConfigDao
from model.output_config_model import OutputConfigModel
from utils.window_util import WindowUtil

class ProgressWindow:

    def __init__(self):
        self.win = None
        self.progress = None

    def show(self):
        window = Tk()
        window.title('提示')
        window_util = WindowUtil(window)
        # w,h
        window_util.set_size(180, 100)
        window_util.disable_resize()
        window_util.center_on_screen()

        self.win = window
        self.init_text(window)
        self.init_progress(window)
        window.columnconfigure(0, weight=1)
        window.rowconfigure(0, weight=1)

    def stop(self):
        self.win.quit()

    def init_progress(self, par_frame):
        self.progress = ttk.Progressbar(par_frame, orient=HORIZONTAL, length=100)
        self.progress.grid(column=0, row=1, sticky=(E,W))
        self.progress.start()

    def init_text(self, par_frame):
        ttk.Label(par_frame, text='生成中...').grid(row=0, column=0, padx=10, pady=10)


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

"""
There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5
"""

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        nums = []
        length = len(nums1) + len(nums2)
        i = j = 0
        for _ in range(length):
            if i < len(nums1) and j < len(nums2):
                if nums1[i] <= nums2[j]:
                    nums.append(nums1[i])
                    i += 1
                else:
                    nums.append(nums2[j])
                    j += 1
            elif i < len(nums1):
                nums.append(nums1[i])
                i += 1
            else:
                nums.append(nums2[j])
                j += 1
        half = length // 2
        return (nums[half] + nums[~half]) / 2


# 1. 트리의 높이를 계산해서 출력하시오.treeHeight(3) --> 3
# 2. 높이가 3 인 노드들을 출력하시오.(7, 8, 9, 10, 11)
# 3. 3 번 노드가 루트인 트리의 전체 노드수 treeSize(3) --> 8
# 4. 8번 노드와 10 번 노드의 공통조상을 출력하시오.(1, 3)
import sys

sys.stdin = open('tree_input.txt')

V, E = map(int, input().split())
arr = list(map(int, input().split()))
L = [0] * (V + 1)
R = [0] * (V + 1)
P = [0] * (V + 1)

for i in range(0, E*2, 2):
    u, v = arr[i], arr[i+1]
    if L[u] == 0:
        L[u] = v
    else:
        R[u] = v

    P[v] = u

def tree_height(v, cnt=-1):
    if v == 0:
        return cnt

    height = tree_height(P[v], cnt+1)

    return height

def tree_size(v):
    global cnt
    if v == 0:
        return

    tree_size(L[v])
    tree_size(R[v])
    cnt += 1

def common_parent(v1, v2):
    p_v1 = v1
    p_v2 = v2
    cnt_1 = []
    cnt_2 = []
    while p_v1 != 0:
        p_v1 = P[p_v1]
        cnt_1.append(p_v1)

    while p_v2 != 0:
        p_v2 = P[p_v2]
        cnt_2.append(p_v2)

    result = []
    for i in cnt_1:
        if i in cnt_2:
            result.append(i)

    result.remove(0)
    return result

print(tree_height(4))

for i in range(1, 13):
    if tree_height(i) == 3:
        print(i, end=' ')

print()

cnt = 0
tree_size(3)
print(cnt)
print(common_parent(8, 10))


from selenium import webdriver
from ProfilePerusahaanTercatat import ProfilePerusahaanTercatat
import csv

def print_to_file(array, file_name):
    with open(file_name, "w") as txt_file:
        for line in array:
            txt_file.write("".join(line) + "\n")

if __name__ == "__main__":
    browser = webdriver.Chrome(
        executable_path=r"C:\\Users\\adyak\\Project\\TA\\scrapper\\chromedriver_win32\\chromedriver.exe"
    )
    # anggotaBursa = ProfileAnggotaBursa(browser, "idx.co.id")
    # anggotaBursa.fetch_data()
    perusahaan_tercatat = ProfilePerusahaanTercatat(browser, "idx.co.id")
    stock_names = []
    with open("delisted_company.csv", "r") as file:
        reader = csv.reader(file)
        for row in reader:
            stock_names.append([row[0], row[1], row[2]])
    fetched_data = []
    for stock_data in stock_names:
        [stock, enlisting_date, delisting_date] = stock_data
        temp = perusahaan_tercatat.fetch_company(
            f"https://www.idx.co.id/perusahaan-tercatat/profil-perusahaan-tercatat/detail-profile-perusahaan-tercatat/?kodeEmiten={stock}", stock, fetched_data)
        perusahaan_tercatat.insert_relation(
            stock, 'Tanggal Pencatatan', enlisting_date)
        perusahaan_tercatat.insert_relation(
            stock, 'Delisting Date', delisting_date)

    perusahaan_relation, perusahaan_entity = perusahaan_tercatat.relation_list, perusahaan_tercatat.main_entity_list
    print_to_file(perusahaan_relation, "relation_raw.csv")
    print_to_file(perusahaan_entity, "entity.csv")


# Dan Thayer
# PID control servo motor and distance sensor.. just messing around

from range_sensor import measure_distance

# gains
k_p = 1.0
k_d = 1.0
k_i = 0.001

def run(target_dist, debug=False):
    """
    Sense distance and drive motor towards a given target
    :param target_dist: distance in cm
    :return:
    """
    sum_err = 0.0
    last_err = 0.0
    while 1:
        dist = measure_distance()
        err = target_dist - dist
        sum_err += err
        signal = k_p*err + k_i*sum_err + k_d*(err-last_err)
        control(signal)
        last_err = err
        if debug:
            print("dist={}, err={}, sum={}, signal={}".format(dist, err, sum_err, signal))

def control(input):
    print("control w/ input ", input)

if __name__ == "__main__":
    print("starting control loop...")
    run(target_dist=4.0, debug=True)


import os
import argparse
from dotenv import load_dotenv
from pytube import YouTube

load_dotenv()

VIDEO_STORE_PATH = os.getenv('VIDEO_STORE_PATH')
AUDIO_STORE_PATH = os.getenv('AUDIO_STORE_PATH')

parser = argparse.ArgumentParser()
parser.add_argument("-a", "--audio-only", help="Download audio only", action="store_true")
parser.add_argument("-e", "--extension", help="Extension for saved file")
parser.add_argument("source", help="Youtube URL of the video to download")
parser.add_argument("file_name", help="Final filename in local system")

def progress_func(stream, bytes, bytes_remaining):
    total = stream.filesize
    downloaded = total - bytes_remaining
    completed = int(downloaded / total * 100)
    end = '\r' if completed < 100 else '\n'
    print(f"Downloading... [{'#' * completed}{'.' * (100 - completed)}] {completed}%", end=end)

def download(audio: bool, source: str, file_name: str, extension: str) -> None:
    try:
        yt = YouTube(source, on_progress_callback=progress_func)
    except:
        print('Connection Error')

    try:
        if audio:
            print('Downloading Audio only...')
            ext = extension if extension else 'mp3'
            media = yt.streams.get_audio_only()
            media.download(AUDIO_STORE_PATH, f'{file_name}.{ext}')
        else:
            print('Downloading Video content...')
            ext = extension if extension else 'mp4'
            media = yt.streams.filter(file_extension='mp4').get_highest_resolution()
            media.download(VIDEO_STORE_PATH, f'{file_name}.{ext}')
    except Exception as e:
        print("There was an error during the download!", e)
    else:
        print('Download completed successfully!')

def main() -> None:
    args = parser.parse_args()
    download(args.audio_only, args.source, args.file_name, args.extension)

if __name__ == '__main__':
    main()


import datetime
import os
from django.http import HttpResponse
from django.shortcuts import render
from app import settings

FILES_ARRAY = os.listdir(settings.FILES_PATH)

def file_list(request, date=None):
    template_name = 'index.html'
    all_files = []
    context = {}
    if date:
        context['date'] = date.date()
    # Реализуйте алгоритм подготавливающий контекстные данные для шаблона по примеру:
    for file in FILES_ARRAY:
        file_stat = os.stat(f'{settings.FILES_PATH}/{file}')
        file_info = {
            'name': file,
            'ctime': datetime.datetime.fromtimestamp(file_stat.st_ctime),
            'mtime': datetime.datetime.fromtimestamp(file_stat.st_mtime),
        }
        all_files.append(file_info)
    context['files'] = all_files
    return render(request, template_name, context=context)

def file_content(request, name):
    file_path = os.path.join(settings.FILES_PATH, name)
    if os.path.exists(file_path):
        with open(os.path.join(settings.FILES_PATH, name),
                  encoding='utf-8') as f:
            file_data = f.read()
        return render(
            request,
            'file_content.html',
            context={
                'file_name': name,
                'file_content': file_data
            }
        )
    else:
        return HttpResponse("404. Запрошенный файл не существует", status=404)


import os
import sys
import pandas as pd
import numpy as np
import logging
import csv
import phonenumbers
import us
from email_validator import validate_email
import yagmail
import matplotlib.pyplot as plt
import datetime

os.chdir(os.path.dirname(__file__))
logging.basicConfig(filename ='logFile.log',filemode = "w",format="%(asctime)s:%(levelname)s:%(message)s",level= logging.INFO)

def get_processing_file(files):
    logging.info("Extracting the file that needs to be processed")
    files = check_format(files)
    if len(files) == 0:
        logging.error("NO CSV files in the correct format")
        return None

    f1 = max(files)
    files.remove(f1)
    f2 = max(files)

    f = check_2_recent_files(f1,f2)

    return f

def check_format(files):
    logging.info("Checking the format")
    if len(files) == 0:
        logging.error("No CSV files in the current dir")
        return list()

    for f in files:
        if f[:15] != "NYL_FieldAgent_" and f[15:-4].isdigit() == False:
            files.remove(f)

    return files

def check_2_recent_files(f1,f2):
    logging.info("checking the two recent files")
    try:
        file1 = open(f1)
    except:
        logging.exception("File didnt open correctly")
        return None
    else:
        reader = csv.reader(file1)
        l1= len(list(reader))
        file1.close()

    try:
        file2 = open(f2)
    except:
        logging.exception("File didnt open correctly")
        return None
    else:
        reader = csv.reader(file2)
        l2= len(list(reader))
        file2.close()

    diff = l1 - l2
    if diff > 500 or diff < -500:
        logging.exception("The difference is more than 500 lines")
        return None
    else:
        return f1

def addFile(f):
    logging.info("Adding the file name")
    try:
        ref = open("NYL_lst.txt","a+")
    except:
        logging.exception("Reference File does not exist")
    else:
        ref.write(f+"\n")
        logging.info("File name was added to the refrence file")
        ref.close()

def Check_refrence_file(f):
    logging.info("checking if the file is in the refrence file")
    try:
        ref = open("NYL_lst.txt","r+")
    except:
        logging.exception("Reference File does not exist")
        return True
    else:
        data = ref.readlines()
        for i in data:
            if i == f+"\n":
                logging.info("The file has been processed already")
                return False
        return True

def sendEmail():
    logging.info("Sending an email")

    receiver = "adamx083@gmail.com"
    body = "This is the log file"
    filename = "logFile.log"

    yag = yagmail.SMTP("adamx083@gmail.com")
    yag.send(
        to=receiver,
        subject="Log File",
        contents=body,
        attachments=filename,
    )

def processing(f):

    logging.info("Processing the file = %s"%f)
    df = pd.read_csv(f)
    headers = set(df)
    df = change_headers(df,headers)

    check_state( df['Agency State'].dropna())
    check_state( df['Agent State'].dropna())

    check_phonenumbers( df["Agency Phone Number"].dropna())
    check_phonenumbers( df["Agent Phone Number"].dropna())

    email_col = df['Agent Email Address'].dropna()
    check_email(email_col)
    visualizing(df)
    addFile(f)

def change_headers(df,headers):
    if 'Agent Writing Contract Start Date (Carrier appointment start date)' in headers:
        logging.info("Changing column name")
        df.rename(columns={'Agent Writing Contract Start Date (Carrier appointment start date)':'Agent Writing Contract Start Date'},inplace = True)

    if 'Agent Writing Contract Status (actually active and cancelled\'s should come in two different files)' in headers:
        df.rename(columns={'Agent Writing Contract Status (actually active and cancelled\'s should come in two different files)':'Agent Writing Contract Status'},inplace = True)
        logging.info("Changing the column name")
    return df

def check_phonenumbers(phone_col):
    logging.info("Checking for invalid Phone Numbers")
    for pn in phone_col:
        pn = pn.replace(".","")
        if pn.isdigit() == False or len(pn) < 2:
            #missing data
            #logging.error("Missing phone number: %s: " %pn)
            continue
        else:
            y = phonenumbers.parse(pn, "US")
            if phonenumbers.is_possible_number(y) == False:
                #invalid number
                logging.error("Invalid phone number: %s: " %pn)

def check_state(state_col):
    logging.info("Checking for invalid State Name")
    for st in state_col:
        if us.states.lookup(st) == None:
            #invalid State
            logging.error("Invalid state name: %s " %st)
    return

def check_email(email_col):
    logging.info("Checking for invalid Email Address")
    for e in email_col:
        try:
            validate_email(e)
        except:
            #invalid Email
            logging.exception("Invalid email: %s" %e)
    return

def getGraph(df):

    df10 = df[["Agency State","Agent Id"]].groupby("Agency State").agg("count")

    fig = plt.figure(figsize=(20, 3))
    state = list(df10.index)    #x axis
    count = list(df10["Agent Id"].values) #y axis
    y = np.arange(0,47)
    ax = fig.add_axes([0,0,1,1])
    ax.bar(state,count,width = 0.3)
    ax.set_frame_on(True)
    ax.xaxis.set_ticks(y)
    ax.set_xlabel('States')
    ax.set_ylabel('Number of Agents')
    plt.savefig('graph1.png')
    logging.info("Graph 1 is saved")

def visualizing(df):
    df9 = df.transpose()
    logging.info("Data frame of the headers as index:")
    logging.info(df9)
    logging.info("------------------------------------")

    getGraph(df)

    df11 = df[['Agent Last Name','Agent Writing Contract Start Date','Date when an agent became A2O']]
    logging.info("Dataframe which gives the Agent Name , Agent Writing ContractStart Date , Date when an agent became A2O")
    logging.info(df11)
    logging.info("------------------------------------")

if __name__ == "__main__":

    files = filter(os.path.isfile, os.listdir( os.curdir ) )  # files only
    files = [ f for f in os.listdir( os.curdir ) if os.path.isfile(f) and f[-3:] == "csv"] #list comprehension version.

    f = get_processing_file(files)

    if f != None:
        if Check_refrence_file(f):#     # check if the file is been processed before
            #(true = not been processed before)
            processing(f) #process the file
            #sendEmail()
        else:
            print("the file was processed before")
            #sendEmail()