"""
This goes through your Plex_ TV library, on your *local* server, and tries to *shrink* episodes (using HEVC_ video quality 28) that start off with a bit rate *above* a certain level, by default 2000 kbps.

Lots of words, huh?

This can *either* tell a table of TV show data on your locally running Plex_ server, on your selected library. Each row is information about a TV show on the Plex_ library; columns are TV show name, and number of episodes above the default bit rate. Rows are organized from *most* number of episodes to fewest, and only includes those TV shows that have :math:`\ge 1` high bitrate episodes.

.. _Plex: https://plex.tv
.. _HEVC: https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding
"""
import os, sys, logging, time, pandas, numpy, json, subprocess, shutil, re, redis
from enum import Enum
from howdy.core import core, session
from howdy.tv import tv, get_token, tv_attic, get_tvdb_api, TMDBShowIds
from howdy.music import music
from howdy.movie import tmdb_apiKey
from pathos.multiprocessing import Pool, cpu_count
from tabulate import tabulate
from shutil import which
from argparse import ArgumentParser

_MINBITRATE   = 1000
_ffmpeg_exec  = which( 'ffmpeg' )
_ffprobe_exec = which( 'ffprobe' )
assert( _ffmpeg_exec is not None )
assert( _ffprobe_exec is not None )

def get_tv_library_local( library_name = 'TV Shows' ):
    fullURL, token = core.checkServerCredentials( doLocal=True )
    library_names = list( core.get_libraries( token = token ).values( ) )
    assert( library_name in library_names )
    #
    tvdata = core.get_library_data(
        library_name, token = token, num_threads = cpu_count( ) )
    return tvdata

class DATAFORMAT( Enum ):
    IS_AVI_OR_MPEG = 1
    IS_LATER = 2

    @classmethod
    def check_format( cls, fullpath ):
        basename = os.path.basename( fullpath ).lower( )
        if any( map(lambda suffix: basename.endswith( '.%s' % suffix ), ( 'avi', 'mpg', 'mpeg' ) ) ):
            return DATAFORMAT.IS_AVI_OR_MPEG
        return DATAFORMAT.IS_LATER

def get_all_durations_dataframe( tvdata, min_bitrate = 2000, mode_dataformat = DATAFORMAT.IS_LATER ):
    if mode_dataformat == DATAFORMAT.IS_LATER: assert( min_bitrate >= _MINBITRATE )
    sizes = [ ]
    durations = [ ]
    shows = [ ]
    seasons = [ ]
    epnos = [ ]
    names = [ ]
    paths = [ ]

    for show in tvdata:
        for seasno in tvdata[show]['seasons']:
            for epno in tvdata[show]['seasons'][seasno]['episodes']:
                mypath = tvdata[show]['seasons'][seasno]['episodes'][epno]['path']
                if mode_dataformat != DATAFORMAT.check_format( mypath ):
                    continue
                durations.append( tvdata[show]['seasons'][seasno]['episodes'][epno]['duration'])
                sizes.append( tvdata[show]['seasons'][seasno]['episodes'][epno]['size'] )
                shows.append( show )
                seasons.append( seasno )
                epnos.append( epno )
                names.append( tvdata[show]['seasons'][seasno]['episodes'][epno]['title'] )
                paths.append( mypath )
    df = pandas.DataFrame({'sizes (MB)' : numpy.array(sizes)/1024**2, 'durations (s)' : durations,
                           'shows' : shows, 'seasons' : seasons, 'epnos' : epnos, 'names' : names,
                          'paths' : paths })
    df['bitrate (kbps)'] = numpy.array( df['sizes (MB)'] ) / numpy.array( df['durations (s)']) * 1024 * 8
    df_sub = df[ (df['bitrate (kbps)'] > min_bitrate ) ].sort_values('bitrate (kbps)', ascending = True).copy( )
    return df_sub

def summarize_shows_dataframe( df_sub ):
    def _get_num_shows( showname ):
        return {
            'num shows' : len( df_sub[ df_sub.shows == showname ] ),
            'min kbps' : df_sub[ df_sub.shows == showname ]['bitrate (kbps)'].min( ),
            'med kbps' : numpy.median( df_sub[ df_sub.shows == showname ]['bitrate (kbps)'] ),
            'max kbps' : df_sub[ df_sub.shows == showname ]['bitrate (kbps)'].max( ),
            }
    dict_of_shows = dict(map(lambda showname: ( showname, _get_num_shows( showname ) ),
                             set( df_sub.shows ) ) )
    df = pandas.DataFrame( {
        'shows' : sorted( dict_of_shows ),
        'num episodes' : list(map(lambda showname: dict_of_shows[ showname ][ 'num shows' ], sorted( dict_of_shows ) ) ),
        'min kbps'     : list(map(lambda showname: dict_of_shows[ showname ][ 'min kbps'  ], sorted( dict_of_shows ) ) ),
        'med kbps'     : list(map(lambda showname: dict_of_shows[ showname ][ 'med kbps'  ], sorted( dict_of_shows ) ) ),
        'max kbps'     : list(map(lambda showname: dict_of_shows[ showname ][ 'max kbps'  ], sorted( dict_of_shows ) ) ),
        } )
    df = df.sort_values( 'num episodes', ascending = False ).copy( )
    return df

def single_show_summary_dataframe( df_sub, showname, mode_dataformat = DATAFORMAT.IS_LATER ):
    df_show = df_sub[ df_sub.shows == showname ].copy( )
    assert( len( df_show ) != 0 )
    if mode_dataformat == DATAFORMAT.IS_AVI_OR_MPEG:
        return df_show
    #
    def get_ffprobe_json( filename ):
        stdout_val = subprocess.check_output(
            [ _ffprobe_exec, '-v', 'quiet', '-show_streams',
             '-show_format', '-print_format', 'json', filename ],
            stderr = subprocess.STDOUT )
        file_info = json.loads( stdout_val )
        return file_info

    def is_hevc( filename ):
        data = get_ffprobe_json( filename )
        return data['streams'][0]['codec_name'].lower( ) == 'hevc'

    with Pool( processes = min( cpu_count( ), len( df_show ) ) ) as pool:
        dict_of_episodes_hevc = dict( pool.map(
            lambda filename: ( filename, is_hevc( filename ) ),
            list( df_show.paths ) ) )
        df_show[ 'is hevc' ] = list(map(lambda filename: dict_of_episodes_hevc[ filename ],
                                        list( df_show.paths ) ) )
        return df_show

def summarize_single_show( df_sub, showname, minbitrate, mode_dataformat = DATAFORMAT.IS_LATER ):
    df_show = single_show_summary_dataframe( df_sub, showname, mode_dataformat = mode_dataformat )
    #
    ## now report it out
    print( 'information for %s, which has %d episodes >= %d kbps.\n' % ( showname, len( df_show ), minbitrate ) )
    data = [ [ 'NUM EPISODES', len( df_show ) ], ]
    data.append( [ 'MIN KBPS', df_show[ 'bitrate (kbps)' ].min( ) ] )
    data.append( [ 'MED KBPS', numpy.median( df_show[ 'bitrate (kbps)' ] ) ] )
    data.append( [ 'MAX KBPS', df_show[ 'bitrate (kbps)' ].max( ) ] )
    if mode_dataformat == DATAFORMAT.IS_AVI_OR_MPEG:
        print( '%s\n' % tabulate( data, headers = [ 'PARAMETER', 'INFO' ] ) )
        return
    #
    if len( df_show[ df_show[ 'is hevc' ] == True ] ) == 0:
        print( '%s\n' % tabulate( data, headers = [ 'PARAMETER', 'INFO' ] ) )
        return
    #
    ## now HEVC episodes
    df_show_ishevc = df_show[ df_show[ 'is hevc' ] == True ].copy( )
    data.append( [ 'NUM HEVC EPISODES', len( df_show_ishevc ) ] )
    data.append( [ 'MIN KBPS HEVC', df_show_ishevc[ 'bitrate (kbps)' ].min( ) ] )
    data.append( [ 'MED KBPS HEVC', numpy.median( df_show_ishevc[ 'bitrate (kbps)' ] ) ] )
    data.append( [ 'MAX KBPS HEVC', df_show_ishevc[ 'bitrate (kbps)' ].max( ) ] )
    print( '%s\n' % tabulate( data, headers = [ 'PARAMETER', 'INFO' ] ) )

def process_single_show( df_sub, showname, do_hevc = True, qual = 28, output_json_file = 'processed_stuff.json' ):
    #
    ## check we have nice and HandBrakeCLI
    nice_exec = which( 'nice' )
    hcli_exec = which( 'HandBrakeCLI' )
    assert( nice_exec is not None )
    assert( hcli_exec is not None )
    #
    df_show = single_show_summary_dataframe( df_sub, showname )
    df_show_sub = df_show.copy( )
    if not do_hevc:
        df_show_sub = df_show[ df_show[ 'is hevc' ] == False ].copy( )
    #
    ## now process those shows SLOWLY
    time00 = time.perf_counter( )
    df_show_sorted = df_show_sub.sort_values(by=['seasons', 'epnos']).reset_index( )
    episodes_sorted = list( df_show_sorted.paths )
    list_processed = [
        "found %02d files to dehydrate in '%'." % (
            len( episodes_sorted ), showname ), ]
    json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )
    for idx, filename in enumerate(episodes_sorted):
        time0 = time.perf_counter( )
        newfile = os.path.basename( filename )
        stdout_val = subprocess.check_output([
            nice_exec, '-n', '19', hcli_exec,
            '-i', filename, '-e', 'x265', '-q', '%d' % qual, '-E', 'av_aac', '-B', '160',
            '-a', ','.join(map(lambda num: '%d' % num, range(1,35))),
            '-s', ','.join(map(lambda num: '%d' % num, range(1,35))),
            '-o', newfile ],
            stderr = subprocess.PIPE )
        #
        os.chmod(newfile, 0o644 )
        shutil.move( newfile, filename )
        dt0 = time.perf_counter( ) - time0
        print('processed episode %02d / %02d in %0.3f seconds' % (
            idx + 1, len( episodes_sorted ), dt0 ) )
        list_processed.append( 'processed episode %02d / %02d in %0.3f seconds' % (
            idx + 1, len( episodes_sorted ), dt0 ) )
        json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )
    dt00 = time.perf_counter( ) - time00
    print( 'took %0.3f seconds to process %d episodes' % (
        dt00, len( episodes_sorted ) ) )
    list_processed.append( 'took %0.3f seconds to process %d episodes' % (
        dt00, len( episodes_sorted ) ) )
    json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )

def process_single_show_avi( df_sub, showname, qual = 20, output_json_file = 'processed_stuff_avi.json' ):
    #
    ## check we have nice and HandBrakeCLI
    nice_exec = which( 'nice' )
    hcli_exec = which( 'HandBrakeCLI' )
    assert( nice_exec is not None )
    assert( hcli_exec is not None )
    #
    df_show_sub = single_show_summary_dataframe(
        df_sub, showname, mode_dataformat = DATAFORMAT.IS_AVI_OR_MPEG )
    #
    ## now process those shows SLOWLY
    time00 = time.perf_counter( )
    df_show_sorted = df_show_sub.sort_values(by=['seasons', 'epnos']).reset_index( )
    episodes_sorted = list( df_show_sorted.paths )
    list_processed = [
        "found %02d files to deavify in '%'." % (
            len( episodes_sorted ), showname ), ]
    json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )
    #
    ## first go through redis database to see if shows are running
    for idx, filename in enumerate(episodes_sorted):
        time0 = time.perf_counter( )
        dirname = os.path.dirname( filename )
        newfile = re.sub( '\.avi$', '.mkv', os.path.basename( filename ) )
        try:
            stdout_val = subprocess.check_output([
                nice_exec, '-n', '19', hcli_exec,
                '-i', filename, '-e', 'x265', '-q', '%d' % qual, '-B', '160',
                '-a', ','.join(map(lambda num: '%d' % num, range(1,35))),
                '-o', newfile ],
                stderr = subprocess.PIPE )
            #
            os.chmod(newfile, 0o644 )
            shutil.move( newfile, dirname )
            os.remove( filename )
            dt0 = time.perf_counter( ) - time0
            print('processed episode %02d / %02d in %0.3f seconds' % (
                idx + 1, len( episodes_sorted ), dt0 ) )
            list_processed.append( 'processed episode %02d / %02d in %0.3f seconds' % (
                idx + 1, len( episodes_sorted ), dt0 ) )
        except:
            try: os.remove( newfile )
            except: pass
            dt0 = time.perf_counter( ) - time0
            print('failed episode %02d / %02d in %0.3f seconds' % (
                idx + 1, len( episodes_sorted ), dt0 ) )
            list_processed.append( 'failed episode %02d / %02d in %0.3f seconds' % (
                idx + 1, len( episodes_sorted ), dt0 ) )
        json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )
    dt00 = time.perf_counter( ) - time00
    print( 'took %0.3f seconds to process %d episodes' % (
        dt00, len( episodes_sorted ) ) )
    list_processed.append( 'took %0.3f seconds to process %d episodes' % (
        dt00, len( episodes_sorted ) ) )
    json.dump( list_processed, open( output_json_file, 'w' ), indent = 1 )

def main( ):
    parser = ArgumentParser( )
    #
    ## top level arguments
    parser.add_argument( '-t', '--tvlibrary', dest='tvlibrary', type=str, action = 'store', default = 'TV Shows',
                        help = 'Name of the TV library on the local PLEX server. Default is "TV Shows".' )
    parser.add_argument( '-M', '--minbitrate', dest = 'minbitrate', type = int, action = 'store', default = 2000,
                        help = ' '.join([
                            'The minimum total bitrate (in kbps) of episodes to dehydrate. Must be >= %d kbps.' % _MINBITRATE,
                            'Default is 2000 kbps.']))
    parser.add_argument( '--info', dest='do_info', action='store_true', default = False,
                        help = 'If chosen, then turn on INFO logging.' )
    #
    ## check on which TV shows are candidates for dehydration, or to dehydrate specific TV shows.
    subparsers = parser.add_subparsers( help = 'Choose on whether to list the TV shows to dehydrate, or to dehydrate a TV show.',
                                       dest = 'choose_option' )
    parser_listcandidates = subparsers.add_parser( 'list',      help = 'If chosen, then list the TV shows to dehydrate.' )
    parser_dehydrate      = subparsers.add_parser( 'dehydrate', help = 'If chosen, then dehydrate a single TV show.' )
    #
    ## list TV shows, do nothing more
    #
    ## dehydrate a single TV show
    parser_dehydrate.add_argument( '-s', '--show', metavar = 'SHOW', dest = 'parser_dehydrate_show', type = str, action = 'store',
                                  required = True, help = 'Name of a TV show (with episodes to dehydrate).' )
    parser_dehydrate.add_argument( '-I', dest = 'parser_dehydrate_do_info', action = 'store_true', default = False,
                                  help = 'If chosen, then only print out info on the selected TV show.' )
    parser_dehydrate.add_argument( '-Q', '--quality', dest = 'parser_dehydrate_quality', metavar = 'QUALITY', type = int, action = 'store',
                                  default = 28, help = 'Will dehydrate shows using HEVC video codec with this quality. Default is 28. Must be >= 20.' )
    parser_dehydrate.add_argument( '-N', '--nohevc', dest = 'parser_dehydrate_do_hevc', action = 'store_false', default = True,
                                  help = 'If chosen, then only process the big episodes that are NOT HEVC. Default is to process everything.' )
    parser_dehydrate.add_argument( '-J', '--jsonfile', dest = 'parser_dehydrate_jsonfile', metavar = 'JSONFILE', type = str, action = 'store', default = 'processed_stuff.json',
                                  help = 'Name of the JSON file to store progress-as-you-go-along on TV show dehydration. Default file name = "processed_stuff.json".' )
    #
    ## parsing arguments
    time0 = time.perf_counter( )
    args = parser.parse_args( )
    assert( args.minbitrate >= _MINBITRATE )
    logger = logging.getLogger( )
    if args.do_info: logger.setLevel( logging.INFO )
    df_sub = get_all_durations_dataframe(
        get_tv_library_local( library_name = args.tvlibrary ),
        min_bitrate = args.minbitrate )
    shownames = set( df_sub.shows )
    #
    ## list TV shows
    if args.choose_option == 'list':
        df_shows = summarize_shows_dataframe( df_sub )
        print( 'found %d shows and %d episodes with episodes >= %d kbps.' % (
            len( df_shows ), df_shows['num episodes'].sum( ), args.minbitrate ) )
        data = list(zip( list(df_shows.shows), list( df_shows['num episodes'] ),
                        list( df_shows[ 'min kbps' ] ), list( df_shows[ 'med kbps' ] ),
                        list( df_shows[ 'max kbps' ] ) ) )
        print( '%s\n' % tabulate( data, headers = [ 'SHOW', 'NUM EPISODES', 'MIN KBPS', 'MED KBPS', 'MAX KPBS' ] ) )
        print( 'took %0.3f seconds to process.' % ( time.perf_counter( ) - time0 ) )
        return
    #
    ## dehydrate single show
    elif args.choose_option == 'dehydrate':
        showname = args.parser_dehydrate_show
        assert( showname in shownames )
        jsonfile = os.path.expanduser( args.parser_dehydrate_jsonfile )
        assert( os.path.basename( jsonfile ).endswith( '.json' ) )
        #
        ## just do info then return
        if args.parser_dehydrate_do_info:
            summarize_single_show( df_sub, showname, args.minbitrate )
            print( 'took %0.3f seconds to process.' % ( time.perf_counter( ) - time0 ) )
            return
        #
        ## now do the big thing
        quality = args.parser_dehydrate_quality
        assert( quality >= 20 )
        process_single_show( df_sub, showname, do_hevc = args.parser_dehydrate_do_hevc,
                            qual = quality, output_json_file = jsonfile )

def main_avis( ):
    parser = ArgumentParser( )
    #
    ## top level arguments
    parser.add_argument( '-t', '--tvlibrary', dest='tvlibrary', type=str, action = 'store', default = 'TV Shows',
                        help = 'Name of the TV library on the local PLEX server. Default is "TV Shows".' )
    parser.add_argument( '--info', dest='do_info', action='store_true', default = False,
                        help = 'If chosen, then turn on INFO logging.' )
    #
    ## check on which TV shows are candidates for dehydration, or to deavify specific TV shows.
    subparsers = parser.add_subparsers( help = 'Choose on whether to list the TV shows to deavify, or to deavify a TV show, that have episodes that are AVI files.',
                                       dest = 'choose_option' )
    parser_listcandidates = subparsers.add_parser( 'list',    help = 'If chosen, then list the TV shows to deavify (ones that have AVI file episodes).' )
    parser_deavify      = subparsers.add_parser( 'deavify', help = 'If chosen, then deavify a single TV show.' )
    #
    ## list TV shows, do nothing more
    #
    ## deavify a single TV show
    parser_deavify.add_argument( '-s', '--show', metavar = 'SHOW', dest = 'parser_deavify_show', type = str, action = 'store',
                                  required = True, help = 'Name of a TV show (with episodes to deavify).' )
    parser_deavify.add_argument( '-I', dest = 'parser_deavify_do_info', action = 'store_true', default = False,
                                  help = 'If chosen, then only print out info on the selected TV show.' )
    parser_deavify.add_argument( '-Q', '--quality', dest = 'parser_deavify_quality', metavar = 'QUALITY', type = int, action = 'store',
                                  default = 21, help = 'Will deavify shows using HEVC video codec with this quality. Default is 21. Must be >= 18.' )
    parser_dehydrate.add_argument( '-J', '--jsonfile', dest = 'parser_deavify_jsonfile', metavar = 'JSONFILE', type = str, action = 'store', default = 'processed_stuff_avi.json',
                                  help = 'Name of the JSON file to store progress-as-you-go-along on TV show dehydration. Default file name = "processed_stuff_avi.json".' )
    #
    ## parsing arguments
    time0 = time.perf_counter( )
    args = parser.parse_args( )
    logger = logging.getLogger( )
    if args.do_info: logger.setLevel( logging.INFO )
    df_sub = get_all_durations_dataframe(
        get_tv_library_local( library_name = args.tvlibrary ),
        min_bitrate = 0.0, mode_dataformat = DATAFORMAT.IS_AVI_OR_MPEG )
    shownames = set( df_sub.shows )
    #
    ## list TV shows
    if args.choose_option == 'list':
        df_shows = summarize_shows_dataframe( df_sub )
        print( 'found %d shows and %d AVI episodes.' % (
            len( df_shows ), df_shows['num episodes'].sum( ) ) )
        data = list(zip( list(df_shows.shows), list( df_shows['num episodes'] ),
                        list( df_shows[ 'min kbps' ] ), list( df_shows[ 'med kbps' ] ),
                        list( df_shows[ 'max kbps' ] ) ) )
        print( '%s\n' % tabulate( data, headers = [ 'SHOW', 'NUM EPISODES', 'MIN KBPS', 'MED KBPS', 'MAX KPBS' ] ) )
        print( 'took %0.3f seconds to process.' % ( time.perf_counter( ) - time0 ) )
        return
    #
    ## deavify single show
    elif args.choose_option == 'deavify':
        showname = args.parser_deavify_show
        assert( showname in shownames )
        jsonfile = os.path.expanduser( args.parser_deavify_jsonfile )
        assert( os.path.basename( jsonfile ).endswith( '.json' ) )
        #
        ## just do info then return
        if args.parser_deavify_do_info:
            summarize_single_show( df_sub, showname, 0.0, mode_dataformat = DATAFORMAT.IS_AVI_OR_MPEG )
            print( 'took %0.3f seconds to process.' % ( time.perf_counter( ) - time0 ) )
            return
        #
        ## now the big thing
        quality = args.parser_deavify_quality
        assert( quality >= 20 )
        process_single_show_avi( df_sub, showname, qual = quality )


import asyncio
from commands.botcommand import BotCommand, assert_text, _s
from botdata import Group

class CreateGroup(BotCommand):
    def __init__(self, telegram_id, bot):
        super(CreateGroup, self).__init__(telegram_id, bot)
        self.current_handler = self.initial_handler

    key = "/creategroup"
    description = "Creates a group"
    auth_level = 4

    @asyncio.coroutine
    def initial_handler(self, msg, chat_handler):
        self.current_handler = self.handle_group_name
        yield from chat_handler.sender.sendMessage(_s["msg_groupnameq"])

    @asyncio.coroutine
    def handle_group_name(self, msg, chat_handler):
        if (yield from assert_text(msg, chat_handler)):
            group_name = msg["text"]
            if len(Group.select().where(Group.group_name == group_name))>0:
                yield from chat_handler.sender.sendMessage(_s["msg_groupname_exists"])
            else:
                self.finished()
                Group.create(group_name=group_name)
                yield from chat_handler.sender.sendMessage(_s["msg_group_created"])


from dotenv import load_dotenv
import pandas as pd
from supabase import create_client, Client
import os
import streamlit as st

load_dotenv()

url: str = os.getenv("SUPABASE_URL")
key: str = os.getenv("SUPABASE_KEY")
supabase: Client = create_client(url, key)
storage_url = os.getenv("SUPABASE_STORAGE_URL")

st.set_page_config(layout='wide', initial_sidebar_state='expanded')

if 'yuvraj' not in st.session_state:

    st.session_state['yuvraj'] = 0

counter = st.session_state.yuvraj

def get_store_data():
    data = supabase.table('store_audits').select(
        'id', 'created_at', 'image2_id', 'store_name').eq('image2_audited', 'FALSE').eq('program_name', 'YUVRAJ').execute()
    return data

st.write("### Yuvraj Store Audits")
st.divider()

df_alerts1 = pd.DataFrame.from_records(get_store_data().data)

total_images = df_alerts1.shape[0]
col1, col2 = st.columns([1, 3], gap='large')
with col1:
    st.write(f"##### Total Images: {total_images}")

    df_alerts1['created_at'] = pd.to_datetime(df_alerts1['created_at'])

st.divider()
id = df_alerts1.loc[counter, 'id']
image = df_alerts1.loc[counter, 'image2_id']
date = df_alerts1.loc[counter, 'created_at'].strftime('%d')
month = df_alerts1.loc[counter, 'created_at'].strftime('%b')
time = df_alerts1.loc[counter, 'created_at'].strftime('%X')
store = df_alerts1.loc[counter, 'store_name']
if int(date) <= 15:
    cycle = "Cycle1"
else:
    cycle = "Cycle2"

image_url = storage_url + image

msg = "Date: " + date + " " + month + " " + \
    time + " |  " + cycle + " |  " + store
with col2:
    st.write(f"##### {msg}")

col3, col4 = st.columns([2, 1], gap='large')
with col3:
    st.image(image_url, use_column_width='auto')

def increment_counter():
    st.session_state.yuvraj += 1

with col4:
    with st.form("Yuvraj Store Audit", clear_on_submit=True):
        image_correct = st.checkbox("Image Correct")
        image_quality = st.checkbox("Image Quality")
        window_exist = st.checkbox("Window Exists")
        eye_level = st.checkbox("Eye Level")
        backing_sheet = st.checkbox("Backing Sheet")
        four_shelf_strip = st.checkbox("4 Shelf Strip")
        num_window_kits = st.number_input(
            'Number of Window Kits', min_value=0, max_value=10)
        stock_quantity = st.number_input(
            'Stock Quantity', min_value=0, max_value=10)
        submitted = st.form_submit_button("Submit", on_click=increment_counter)
        if submitted:
            st.session_state.counter = st.session_state.counter + 1
            data_insert = supabase.table('yuvraj').insert(
                {'image_correct': image_correct, 'image_quality': image_quality, 'month': month,
                 'cycle': cycle, 'window_exist': window_exist, 'eye_level': eye_level, 'backing_sheet': backing_sheet, 'four_shelf_strip': four_shelf_strip, 'num_window_kits': num_window_kits, 'stock_quantity': stock_quantity}).execute()

            data, count = supabase.table('store_audits').update(
                {'image2_audited': True}).eq('id', id).execute()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Imports
from sklearn.model_selection import KFold
from DNNModel import *
from numpy import *
from external_functions import *
import matplotlib
matplotlib.use('Agg')
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import SGD, RMSprop, Adadelta, Adam

class DNNMTModel(DNNModel):

    def create_DNN_model(self, print_model=True):
        print("Creating DNN model")
        fundamental_parameters = ['dropout', 'output_activation', 'optimization', 'learning_rate',
                                  'units_in_input_layer',
                                  'units_in_hidden_layers', 'nb_epoch', 'batch_size']
        for param in fundamental_parameters:
            if self.parameters[param] == None:
                print("Parameter not set: " + param)
                return
        self.print_parameter_values()
        model = Sequential()
        # Input layer
        model.add(Dense(self.parameters['units_in_input_layer'], input_dim=self.feature_number, activation='relu'))
        model.add(Dropout(self.parameters['dropout']))
        # constructing all hidden layers
        for layer in self.parameters['units_in_hidden_layers']:
            model.add(Dense(layer, activation='relu'))
            model.add(Dropout(self.parameters['dropout']))
        # constructing the final layer - Multi task DNN - 6 endpoints predicts the outcome given an input X.
        model.add(Dense(6, activation=self.parameters['output_activation']))
        if self.parameters['optimization'] == 'SGD':
            optim = SGD()
            optim.lr.set_value(self.parameters['learning_rate'])
        elif self.parameters['optimization'] == 'RMSprop':
            optim = RMSprop()
            optim.lr.set_value(self.parameters['learning_rate'])
        elif self.parameters['optimization'] == 'Adam':
            optim = Adam()
        elif self.parameters['optimization'] == 'Adadelta':
            optim = Adadelta()
        model.compile(loss='binary_crossentropy', optimizer=optim, metrics=[matthews_correlation])
        if self.verbose == 1: str(model.summary())
        self.model = model
        print("DNN model sucessfully created")

    def model_selection(self, X, y, n_iter_search=2, n_folds=2):
        print("Selecting best DNN model")
        seed = 7
        old_parameters = self.parameters.copy()
        self.model_selection_history = []
        for iteration in range(n_iter_search):
            mean_train_matthews_correlation = []
            mean_train_loss = []
            mean_val_matthews_correlation = []
            mean_val_loss = []
            mean_time_fit = []
            print("Iteration no. " + str(iteration + 1))
            new_parameters = self.batch_parameter_shufller()
            temp_values = new_parameters.copy()
            for key in new_parameters:
                self.parameters[key] = new_parameters[key]
            i = 0
            kf = KFold(n_splits=n_folds, shuffle=False, random_state=seed)
            for train, valid in kf.split(X, y):
                print("Running Fold " + str(i + 1) + str("/") + str(n_folds))
                X_train, X_valid = X[train], X[valid]
                y_train, y_valid = y[train], y[valid]
                self.create_DNN_model()
                self.create_DNN_model()
                time_fit = self.fit_model(X_train, X_valid, y_train, y_valid)
                train_scores = self.model.evaluate(X_train, y_train)
                train_matthews_correlation = train_scores[1]
                train_loss = train_scores[0]
                val_scores = self.model.evaluate(X_valid, y_valid)
                val_matthews_correlation = val_scores[1]
                val_loss = val_scores[0]
                self.print_fit_results(train_scores, val_scores)
                mean_train_matthews_correlation.append(train_matthews_correlation)
                mean_train_loss.append(train_loss)
                mean_val_matthews_correlation.append(val_matthews_correlation)
                mean_val_loss.append(val_loss)
                mean_time_fit.append(time_fit)
                temp_values['train_matthews_correlation_' + str(i + 1)] = train_matthews_correlation
                temp_values['train_loss_' + str(i + 1)] = train_loss
                temp_values['val_matthews_correlation_' + str(i + 1)] = val_matthews_correlation
                temp_values['val_loss_' + str(i + 1)] = val_loss
                temp_values['time_fit_' + str(i + 1)] = time_fit
                i += 1
            temp_values['mean_train_matthews_correlation'] = np.mean(mean_train_matthews_correlation)
            temp_values['mean_train_loss'] = np.mean(mean_train_loss)
            temp_values['mean_val_matthews_correlation'] = np.mean(mean_val_matthews_correlation)
            temp_values['mean_val_loss'] = np.mean(mean_val_loss)
            temp_values['mean_time_fit'] = np.mean(mean_time_fit)
            self.model_selection_history.append(temp_values)
        self.parameters = old_parameters.copy()
        print("Best DNN model successfully selected")

    def cv_fit(self, X, y, cv=5):
        if self.parameters['nb_epoch'] and self.parameters['batch_size']:
            cvscores = []
            cvhistory = []
            i = 0
            kf = KFold(n_splits=cv, shuffle=False, random_state=1)
            for train, valid in kf.split(X, y):
                print("Running Fold " + str(i + 1) + str("/") + str(cv))
                X_train, X_valid = X[train], X[valid]
                y_train, y_valid = y[train], y[valid]
                self.create_DNN_model()
                time_fit = self.fit_model(X_train, X_valid, y_train, y_valid)
                cvscores.append(self.evaluate_model(X_valid, y_valid))
                cvhistory.append(self.history)
                i += 1
        return cvscores, cvhistory

    def evaluate_model(self, X_test, y_test):
        print("Evaluating model with hold out test set.")
        scores = dict()
        endpoints = ['endpoint_Sex', 'endpoint_EFSAll', 'endpoint_ClassLabel', 'endpoint_OSAll', 'endpoint_OSHR',
                     'endpoint_EFSHR']
        predictions = self.model.predict(X_test).round().astype(int)
        print(predictions)
        print(y_test)
        scores['roc_auc'] = []
        scores['accuracy'] = []
        scores['f1_score'] = []
        scores['mcc'] = []
        scores['precision'] = []
        scores['recall'] = []
        scores['log_loss'] = []
        for column in range(predictions.shape[1]):
            y_true = y_test[:, column]
            y_pred = predictions[:, column]
            scores['roc_auc'].append(roc_auc_score(y_true, y_pred))
            scores['accuracy'].append(accuracy_score(y_true, y_pred))
            scores['f1_score'].append(f1_score(y_true, y_pred))
            scores['mcc'].append(matthews_corrcoef(y_true, y_pred))
            scores['precision'].append(precision_score(y_true, y_pred))
            scores['recall'].append(recall_score(y_true, y_pred))
            scores['log_loss'].append(log_loss(y_true, y_pred))
        for i in range(len(endpoints)):
            print(endpoints[i])
            for metric, score in scores.items():
                print(metric + ': ' + str(score[i]))
        return scores

    def format_scores_cv(self, scores_cv_list):
        form_scores = dict()
        for key in scores_cv_list[0].keys():
            form_scores[key] = []
        for score in scores_cv_list:
            form_scores['roc_auc'].append(score['roc_auc'])
            form_scores['accuracy'].append(score['accuracy'])
            form_scores['f1_score'].append(score['f1_score'])
            form_scores['mcc'].append(score['mcc'])
            form_scores['precision'].append(score['precision'])
            form_scores['recall'].append(score['recall'])
            form_scores['log_loss'].append(score['log_loss'])
        mean_scores = dict()
        sd_scores = dict()
        for key in form_scores.keys():
            mean_scores[key] = []
            sd_scores[key] = []
        for key, value in mean_scores.items():
            mean_scores[key] = [[] for i in range(6)]
            sd_scores[key] = [[] for i in range(6)]
        for endpoint in range(6):

            for metric in form_scores.keys():
                temp_cv_array = []
                for fold in range(self.cv):
                    temp_cv_array.append(form_scores[metric][fold][endpoint])
                mean_scores[metric][endpoint] = np.mean(temp_cv_array)
                sd_scores[metric][endpoint] = np.std(temp_cv_array)
            for metric in mean_scores.keys():
                print(metric, ': ', str(mean_scores[metric][endpoint]), ' +/- ', sd_scores[metric][endpoint])
        return mean_scores, sd_scores

    def write_report(self, mean_scores, sd_scores, root_dir, file_name):
        if not os.path.exists(root_dir):
            os.makedirs(root_dir)
        i = 0
        while os.path.exists(root_dir + '/' + file_name + '_report_' + str(i) + '.txt'):
            i += 1
        final_path = os.path.join(root_dir, file_name + '_report_' + str(i) + '.txt')
        print("Writing report file with path: " + final_path)
        endpoints = ['endpoint_Sex', 'endpoint_EFSAll', 'endpoint_ClassLabel', 'endpoint_OSAll', 'endpoint_OSHR',
                     'endpoint_EFSHR']
        out = open(final_path, 'w')
        out.write('Hyperparameters')
        out.write('\n')
        out.write('=' * 25)
        out.write('\n')
        for key in sorted(self.parameters):
            out.write(key + ": " + str(self.parameters[key]))
            out.write('\n')
        out.write('\n')
        out.write('Scores')
        out.write('\n')
        out.write("=" * 25)
        out.write('\n')
        for i in range(len(endpoints)):
            out.write('\n')
            out.write(endpoints[i])
            out.write('\n')
            for metric in mean_scores.keys():
                out.write(str(metric) + ': ' + str(mean_scores[metric][i]) + ' +/- ' + str(sd_scores[metric][i]))
                out.write('\n')
        out.close()
        print("Report file successfully written.")

def dnn_mt_model_fit(dropout, output_activation, optimization, learning_rate, units_in_input_layer,
                  units_in_hidden_layers, nb_epoch, batch_size, early_stopping, patience, root_dir, file_name, cv=5,
                  **kwargs):
    dnn = DNNMTModel(kwargs)
    dnn.parameters = {

        'dropout': dropout,
        'output_activation': output_activation,
        'optimization': optimization,
        'learning_rate': learning_rate,
        'units_in_input_layer': units_in_input_layer,
        'units_in_hidden_layers': units_in_hidden_layers,
        'nb_epoch': nb_epoch,
        'batch_size': batch_size,
        'early_stopping': early_stopping,
        'patience': patience

    }
    dnn.create_DNN_model()
    if not dnn.splitted:
        cv_scores, cv_history = dnn.cv_fit(dnn.X, dnn.y, cv)
        dnn.print_fit_results()
        dnn.plot_model_performance(cv_history, root_dir, file_name)
        mean_scores, sd_scores = dnn.format_scores_cv(cv_scores)
        dnn.write_report(mean_scores, sd_scores, root_dir, file_name)
    else:
        cv_scores, cv_history = dnn.cv_fit(dnn.X_test, dnn.y_test, cv)
        dnn.print_fit_results()
        dnn.plot_model_performance(cv_history, root_dir, file_name)
        mean_scores, sd_scores = dnn.format_scores_cv(cv_scores)
        dnn.write_report(mean_scores, sd_scores, root_dir, file_name)

def dnn_mt_model_selection_split(X_train, X_test, y_train, y_test, root_dir, experiment_designation, n_iter=10, cv=5):
    dnn = DNNMTModel(X_train=X_train, X_test=X_test, y_train=y_train, y_test=y_test, cv=cv)
    file_name = experiment_designation
    dnn.model_selection(dnn.X_train, dnn.y_train, n_iter, cv)
    dnn.write_model_selection_results(root_dir, file_name)
    dnn.select_best_model()
    dnn.create_DNN_model()
    cv_scores, cv_history = dnn.cv_fit(dnn.X_test, dnn.y_test, cv)
    dnn.plot_model_performance(cv_history, root_dir, file_name)
    mean_scores, sd_scores = dnn.format_scores_cv(cv_scores)
    dnn.write_report(mean_scores, sd_scores, root_dir, file_name)

def dnn_mt_model_selection_cv(X, y, root_dir, experiment_designation, n_iter=10, cv=5):
    dnn = DNNMTModel(X=X, y=y, cv=cv)
    file_name = experiment_designation
    dnn.model_selection(dnn.X, dnn.y, n_iter, cv)
    dnn.write_model_selection_results(root_dir, file_name)
    dnn.select_best_model()
    dnn.create_DNN_model()
    cv_scores, cv_history = dnn.cv_fit(dnn.X, dnn.y, cv)
    dnn.plot_model_performance(cv_history, root_dir, file_name)
    mean_scores, sd_scores = dnn.format_scores_cv(cv_scores)
    dnn.write_report(mean_scores, sd_scores, root_dir, file_name)


#!/usr/bin/env python
import os
import sys

import http.client
from urllib.parse import urlencode
import xml.etree.ElementTree as ET

from argparse import ArgumentParser, RawTextHelpFormatter

DESCRIPTION = """

© Prifysgol Bangor University

"""

marytts_p2ipa_mapping = {'A':'ä','{':'æ','@':'ɐ','O':'ɔ','aU':'aʊ','AI':'aɪ','b':'b','tS':'tʃ',
'd':'d','D':'ð','E':'ɛ','r=':'ɝ','EI':'eɪ','f':'f','g':'ɡ','h':'h','I':'ɪ','i':'i','dZ':'dʒ',
'k':'k','l':'l','m':'m','n':'n','N':'ŋ','@U':'oʊ','OI':'ɔɪ','p':'p','r':'ɹ','s':'s','S':'ʃ','t':'t',
'T':'θ','U':'ʊ','u':'u','V':'ɐ','v':'v','w':'w','j':'j','z':'z','Z':'ʒ'}

class MaryTTSAPI(object):

    def __init__(self):

        self.marytts_host = "127.0.0.1"
        self.marytts_port = 59125

    def get_allophones_xml(self, lang, text):
        """Given a message in message,
           return a response in the appropriate
           format."""

        raw_params = {"INPUT_TEXT": text,
                "INPUT_TYPE": "TEXT",
                "OUTPUT_TYPE": "ALLOPHONES",
                "LOCALE": lang,
                }

        params = urlencode(raw_params)
        headers = {}

        # Open connection to self.host, self.port.
        conn = http.client.HTTPConnection(self.marytts_host, self.marytts_port)

        conn.request("POST", "/process", params, headers)
        response = conn.getresponse()
        if response.status != 200:
            #print response.getheaders()
            raise RuntimeError("{0}: {1}".format(response.status, response.reason))
        return response.read()

    def g2a(self, lang, text):
        t = ''
        ns = {'m':'http://mary.dfki.de/2002/MaryXML'}

        allophones_xml = self.get_allophones_xml(lang, text)
        root = ET.fromstring(allophones_xml)

        for syllable in root.findall('./m:p/m:s/m:phrase/m:t/m:syllable', ns):
            for phoneme in syllable.findall('./m:ph', ns):
                mp = phoneme.attrib['p']
                t = t + marytts_p2ipa_mapping[mp]

            if 'stress' in syllable.attrib:
                stress = syllable.attrib['stress']
                if (stress == "1"):
                    t = t + "'"

            t = t + "."

        t = t[:-1]
        return t

def main(wordlist_file_path, locale, output_file_path, **args):
    mtts = MaryTTSAPI()
    with open(output_file_path, "w", encoding='utf-8') as out:
        with open(wordlist_file_path, "r", encoding='utf-8') as wordlist:
            for word in wordlist:
               word = word.rstrip()
               a = mtts.g2a(locale, word)
               print (a)
               out.write("%s\t%s\n" % (word, a))

if __name__ == "__main__":
    parser = ArgumentParser(description=DESCRIPTION, formatter_class=RawTextHelpFormatter)
    parser.add_argument("-w", dest="wordlist_file_path", required=True, help="lleoliad ffeiliau geiriau / location of wordlist file")
    parser.add_argument("-l", dest="locale", required=True, help="iaith ffeil rhestr geiriau / locale of word list")
    parser.add_argument("-o", dest="output_file_path", default="g2a.dict")
    parser.set_defaults(func=main)
    args = parser.parse_args()
    args.func(**vars(args))


import matplotlib.pyplot as plt
import pandas as pd
import pylab as pl
import numpy as np
from sklearn import linear_model
from sklearn.metrics import r2_score
from sklearn.preprocessing import PolynomialFeatures
from sklearn import linear_model
from scipy.optimize import curve_fit
'exec(%matplotlib inline)'

# # LINEAR
# x = np.arange(-5.0, 5.0, 0.1)
# y = 2*(x) + 3
# y_noise = 2*np.random.normal(size=x.size)
# ydata = y + y_noise
# fig1 = plt.figure(1)
# plt.plot(x, ydata, 'bo')
# plt.plot(x, y, 'r')
# plt.ylabel('Dependent Variable')
# plt.xlabel('Independet Variable')

# # CUBIC
# y1 = 1*(x**3) + 1*(x**2) + 1*x + 3
# y1_noise = 20 * np.random.normal(size=x.size)
# ydata1 = y1 + y1_noise
# fig2 = plt.figure(2)
# plt.plot(x, ydata1,  'bo')
# plt.plot(x,y1, 'r')
# plt.ylabel('Dependent Variable')
# plt.xlabel('Indepdendent Variable')

# # QUADRATIC
# y2 = np.power(x,2)
# y2_noise = 2 * np.random.normal(size=x.size)
# ydata2 = y2 + y2_noise
# fig3 = plt.figure(3)
# plt.plot(x, ydata2,  'bo')
# plt.plot(x,y2, 'r')
# plt.ylabel('Dependent Variable')
# plt.xlabel('Indepdendent Variable')

# # EXPONENTIAL
# y3= np.exp(x)
# fig4 = plt.figure(4)
# plt.plot(x,y3)
# plt.ylabel('Dependent Variable')
# plt.xlabel('Indepdendent Variable')

# # LOGARITHMIC
# y4 = np.log(x)
# fig5 = plt.figure(5)
# plt.plot(x,y4)
# plt.ylabel('Dependent Variable')
# plt.xlabel('Indepdendent Variable')

# # SIGMOIDAL/LOGISTIC
# y5 = 1-4/(1+np.power(3, x-2))
# fig6 = plt.figure(6)
# plt.plot(x,y5)
# plt.ylabel('Dependent Variable')
# plt.xlabel('Indepdendent Variable')
# plt.show()

df = pd.read_csv("china_gdp.csv")
df.head(10)

x_data, y_data = (df["Year"].values, df["Value"].values)
plt.figure(figsize=(8,5))
plt.plot(x_data, y_data, 'ro')
plt.xlabel("Year")
plt.ylabel("Value")

def sigmoid(x, Beta_1, Beta_2):
	y = 1/(1 + np.exp(-Beta_1*(x - Beta_2)))
	return y

xdata = x_data/max(x_data)
ydata = y_data/max(y_data)

popt, pcov = curve_fit(sigmoid, xdata, ydata)
print("beta_1 = %f, beta_2 = %f" % (popt[0],popt[1]))

x = np.linspace(1960, 2015, 55)
x = x/max(x)
plt.figure(figsize=(8,5))
y = sigmoid(x, *popt)
plt.plot(xdata, ydata, 'ro', label='data')
plt.plot(x, y, linewidth=3.0, label='fit')
plt.legend(loc='best')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()

# FOR ACCURACY OF THE MODEL:
msk = np.random.rand(len(df)) < 0.8
train_x = xdata[msk]
test_x = xdata[~msk]
train_y = ydata[msk]
test_y = ydata[~msk]

# build the model using train set
popt1, pcov1 = curve_fit(sigmoid, train_x, train_y)

# predict using test set
y_hat = sigmoid(test_x, *popt1)

# evaluation
print("Mean absolute error: %.2f" % np.mean(np.absolute(y_hat - test_y)))
print("Residual sum of squares (MSE): %.2f" % np.mean((y_hat - test_y) ** 2))
print("R2-score: %.2f" % r2_score(y_hat , test_y))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 24 14:56:40 2020
@author: hoeren
This script will repack the given .tar.gz or .tgz file in chunks no bigger
than denoted by the
"""
import argparse
import os
import sys
import tarfile
import gzip

import filetype
from tqdm import tqdm

from . import __version__

def is_tar_file(FileName):
    """This function returns true if the supplied FileName holds the magic number for a .tar file."""
    if not os.path.isfile(FileName):
        return False
    kind = filetype.guess(FileName)
    if kind is not None and kind.extension == 'tar':
        return True
    return False

def is_gz_file(FileName):
    """This function returns true if the supplied FileName holds the magic number for a .gz file."""
    if not os.path.isfile(FileName):
        return False
    kind = filetype.guess(FileName)
    if kind is not None and kind.extension == 'gz':
        return True
    return False

def is_tar_gz_file(FileName):
    """This function returns true if the supplied FileName holds the magic number for .gz file, AND
    the uncompressed contents holds the magic number for a .tar file."""
    if is_gz_file(FileName):
        with gzip.open(FileName, 'rb') as fp:
            contents = fp.read(1024)
        kind = filetype.guess(contents)
        if kind is not None and kind.extension == 'tar':
            return True
    return False

def pack_size(size_str):
    """This function returns the pack size in bytes from a given string.
       A negative number will be returned on fail.
    """
    if len(size_str)<3:
        return -1
    multiplier = size_str[-2:]  # KB, MB or GB
    try:
        size_base = float(size_str[:-2])
    except ValueError:
        return -1
    if multiplier == 'KB':
        size = int(size_base * 1024)
    elif multiplier == 'MB':
        size = int(size_base * 1024 * 1024)
    elif multiplier == 'GB':
        size = int(size_base * 1024 * 1024 * 1024)
    else:
        return -1
    return size

def pack(args):
    """This function packs 'args.SOURCE' (which is guaranteed to be a) directory
       in chunks no bigger than args.size bytes to a .tar file (or a .tar.gz
       file if args.compress is True) The resulting file(s) are generated in
       the args.DESTINATION directory. The resulting file(s) are named after
       the last part of args.SOURCE.
    """
    source_base, source_name = os.path.split(args.SOURCE)
    chunk_sequence = 0
    chunk_size = 0
    destination_base = os.path.join(args.DESTINATION, source_name)
    if args.compress:
        archive_name = f'{destination_base}.{chunk_sequence:02d}.tar.gz'
        destination = tarfile.open(archive_name, 'w|gz')
    else:
        archive_name = f'{destination_base}.{chunk_sequence:02d}.tar'
        destination = tarfile.open(archive_name, 'w')
    if not args.quiet:
        pbar = tqdm(total=args.size,
                    desc=f"{os.path.basename(archive_name)}",
                    leave=True,
                    ascii=False,
                    unit='Bytes')

    for Root, Dirs, Files in os.walk(args.SOURCE):
        for File in Files:
            file_to_add = os.path.join(Root, File)
            file_to_store = file_to_add.replace(source_base, '')[1:]  # cut also the starting '/'
            file_to_add_size = os.path.getsize(file_to_add)
            if chunk_size + file_to_add_size > args.size:
                destination.close()
                chunk_sequence += 1
                chunk_size = 0

                if args.compress:
                    archive_name = f'{destination_base}.{chunk_sequence:02d}.tar.gz'
                    destination = tarfile.open(archive_name, 'w|gz')
                else:
                    archive_name = f'{destination_base}.{chunk_sequence:02d}.tar'
                    destination = tarfile.open(archive_name, 'w')

                if not args.quiet:
                    pbar.close()
                    pbar = tqdm(total=args.size,
                                desc=f"{os.path.basename(archive_name)}",
                                leave=True,
                                ascii=False,
                                unit='Bytes')
            chunk_size += file_to_add_size
            destination.add(file_to_add, arcname=file_to_store)
            if not args.quiet:
                pbar.update(file_to_add_size)
    if not args.quiet:
        pbar.close()
    destination.close()

def repack(args):
    """This function re-packs 'args.SOURCE' (which is guaranteed to be a) .tar
       or .tag.gz file in chunks no bigger than args.size bytes to a .tar file
       (or a .tar.gz file if args.compress is True) The resulting file(s) are
       generated in the args.DESTINATION directory. The resulting file(s) are
       named after the last part of args.SOURCE (minus the .tar or .tar.gz part)
    """
    source_base, source_name = os.path.split(args.SOURCE)
    if is_tar_file(args.SOURCE):
        source = tarfile.open(args.SOURCE, "r")
        if source_name.endswith('.tar'):
            source_name = source_name.replace('.tar', '')
    elif is_tar_gz_file(args.SOURCE):
        source = tarfile.open(args.SOURCE, "r:gz")
        if source_name.endswith('.tar.gz'):
            source_name = source_name.replace('.tar.gz', '')
        if source_name.endswith('.tgz'):
            source_name = source_name.replace('.tgz', '')
    else:
        raise Exception("shouldn't be able to reach this point")
    chunk_sequence = 0
    chunk_size = 0
    destination_base = os.path.join(args.DESTINATION, source_name)

    if args.compress:
        archive_name = f'{destination_base}.{chunk_sequence:02d}.tar.gz'
        destination = tarfile.open(archive_name, 'w|gz')
    else:
        archive_name = f'{destination_base}.{chunk_sequence:02d}.tar'
        destination = tarfile.open(archive_name, 'w')

    if not args.quiet:
        pbar = tqdm(total=args.size,
                    desc=f"{os.path.basename(archive_name)}",
                    leave=True,
                    ascii=False,
                    unit=' Bytes')

    catalog = source.getmembers()

    for item in catalog:
        if item.isreg:
            file_to_repack = source.extractfile(item)

        if item.size + chunk_size > args.size:
            destination.close()
            chunk_sequence += 1
            chunk_size = 0

            if args.compress:
                archive_name = f'{destination_base}.{chunk_sequence:02d}.tar.gz'
                destination = tarfile.open(archive_name, 'w|gz')
            else:
                archive_name = f'{destination_base}.{chunk_sequence:02d}.tar'
                destination = tarfile.open(archive_name, 'w')

            if not args.quiet:
                pbar.close()
                pbar = tqdm(total=args.size,
                            desc=f"{os.path.basename(archive_name)}",
                            leave=True,
                            ascii=False,
                            unit=' Bytes')

        if item.isreg:
            chunk_size += item.size
            destination.addfile(item, file_to_repack)
        else:
            destination.addfile(item)

        if not args.quiet:
            pbar.update(item.size)
    if not args.quiet:
        pbar.close()
    destination.close()

def starz(args):
    size = pack_size(args.size)
    if size < 0:
        print(f"Can not interprete '{args.size}'")
        sys.exit(2)
    args.size = size

    if args.version:
        print(f"starz Version {__version__}")
        sys.exit(0)

    if args.DESTINATION.startswith('~'):
        args.DESTINATION = os.path.expanduser(args.DESTINATION)
    args.DESTINATION = os.path.abspath(os.path.realpath(args.DESTINATION))
    if os.path.exists(args.DESTINATION):
        if not os.path.isdir(args.DESTINATION):
            print(f"DESTINATION '{args.DESTINATION}' is to be a directory!")
            sys.exit(3)
    else:
        os.makedirs(args.DESTINATION, exist_ok=True)

    if args.SOURCE.startswith('~'):
        args.SOURCE = os.path.expanduser(args.SOURCE)
    args.SOURCE = os.path.abspath(os.path.realpath(args.SOURCE))
    if not os.path.exists(args.SOURCE):
        print(f"SOURCE '{args.SOURCE}' does not exist.")
        sys.exit(4)
    elif os.path.isdir(args.SOURCE):
        pack(args)
    elif is_tar_file(args.SOURCE) or is_tar_gz_file(args.SOURCE):
        repack(args)
    else:
        print(f"SOURCE '{args.SOURCE}' is not a directory, neither a .tar nor .tar.gz file.")
        sys.exit(5)

def main():
    parser = argparse.ArgumentParser(description='Pack a directory or re-pack a .tag(.gz) file in smaller .tar(.gz) chunks.')

    parser.add_argument('-s', '--size',
                        required=True,
                        help='maximum size (eg. 5GB or 3.14MB)')

    parser.add_argument('-c', '--compress',
                        action='store_true',
                        default=False,
                        help="compress (gzip) the resulting .tar files into .tar.gz")

    parser.add_argument('-q', '--quiet',
                        action='store_true',
                        default=False,
                        help='surpress the progress bar')

    parser.add_argument('-v', '--version',
                        action='store_true',
                        default=False,
                        help="print the version number")

    parser.add_argument('SOURCE',
                        help='path to either a .tar(.gz) file or a directory')

    parser.add_argument('DESTINATION',
                        nargs='?',
                        default=os.getcwd(),
                        help='destination directory (default is current working directory)')

    args = parser.parse_args()
    starz(args)

if __name__ == "__main__":
    main()


def df_optimized(df, verbose=True, **kwargs):
    """
    Reduces size of dataframe by downcasting numerical columns
    :param df: input dataframe
    :param verbose: print size reduction if set to True
    :param kwargs:
    :return:
    """
    in_size = df.memory_usage(index=True).sum()
    for type in ["float", "integer"]:
        l_cols = list(df.select_dtypes(include=type))
        for col in l_cols:
            df[col] = pd.to_numeric(df[col], downcast=type)
            if type == "float":
                df[col] = pd.to_numeric(df[col], downcast="integer")
    out_size = df.memory_usage(index=True).sum()
    ratio = (1 - round(out_size / in_size, 2)) * 100
    GB = out_size / 1000000000
    if verbose:
        print("optimized size by {} % | {} GB".format(ratio, GB))
    return df

##############################################################################################
import subprocess
import sys

def install_packages(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

#install_packages("fitter")

#############################################################################################
def installed_packages(package):
    result=package in sys.modules
    print(result)

#installed_packages("distributions")

###################################################################################
import scipy.stats as ss
import numpy as np
import matplotlib.pyplot as plt

plt.style.use('seaborn') # pretty matplotlib plots
plt.rcParams['figure.figsize'] = (12, 8)

def plot_normal(x_range=[0, 1], mu=0.5, sigma=0.1, cdf=False, **kwargs):
    '''
    Plots the normal distribution function for a given x range
    If mu and sigma are not provided, standard normal is plotted
    If cdf=True cumulative distribution is plotted
    Passes any keyword arguments to matplotlib plot function
    '''
    x = np.linspace(x_range[0], x_range[1], 5000)
    if cdf:
        y = ss.norm.cdf(x, mu, sigma)
    else:
        y = ss.norm.pdf(x, mu, sigma)
    plt.plot(x, y, **kwargs)

#plot_normal(mu=0.5, sigma=0.1)

########################################################

import tensorflow_probability as tfp
import numpy as np
import matplotlib.pyplot as plt
tfd = tfp.distributions
plt.style.use('seaborn') # pretty matplotlib plots
plt.rcParams['figure.figsize'] = (12, 8)

def plot_sinar(x_range=[0, 1], mu=0.5, sigma=0.1,skewness = 1.2,tailweight=0, cdf=False, **kwargs):
    '''
    Plots the SinhArcsinh distribution function for a given x range
    If mu and sigma are not provided, default distribution paramters are used
    If cdf=True cumulative distribution is plotted
    Passes any keyword arguments to matplotlib plot function
    '''
    sinar=tfd.SinhArcsinh(mu, sigma, skewness, tailweight)
    x = np.linspace(x_range[0], x_range[1], 5000)
    if cdf:
        y = sinar.cdf(x)
    else:
        y = sinar.prob(x)
    plt.plot(x, y, **kwargs)

#mu= 0.2,sigma = 0.2,,nu = 1.2, tau = 0.1
#plot_sinar(mu= 0.1,sigma = 0.6,skewness=1.2,tailweight=2,cdf=False)

########################################################
from plotnine import ggplot, aes, geom_line, theme_minimal,stat_function

def plot_sinar(x_range=[0, 1], mu=0.5, sigma=0.1,skewness = 1.2,tailweight=0, cdf=False):

    sinar=tfd.SinhArcsinh(mu, sigma, skewness, tailweight)
    x = np.linspace(x_range[0], x_range[1], 5000)
    if cdf:
        y = sinar.cdf(x)
    else:
        y = sinar.prob(x)
    dt=pd.DataFrame({"x":x,"y":y})
    return ggplot(dt) +aes(x="x", y="y") + geom_line() + theme_minimal()

plot_sinar(mu= 0.1,sigma = 0.6,skewness=1.2,tailweight=2,cdf=False)

########################################################
from sklearn.preprocessing import FunctionTransformer
import numpy as np

def cyclic_encoding(period,dates):
    cyc={"sin":FunctionTransformer(lambda x: np.sin(x / period * 2 * np.pi)).fit_transform(dates),
     "cos":FunctionTransformer(lambda x: np.cos(x / period * 2 * np.pi)).fit_transform(dates)}
    return pd.DataFrame(cyc)


import pygame.time
from object import *
from settings import *
import math

keys = {                                    # The list of keys for input
    "up": False,                            # UP arrow key
    "down": False,                          # DOWN arrow key
    "left": False,                          # LEFT arrow key
    "right": False,                         # RIGHT arrow key
    "enter": False,                         # ENTER key
    "space": False,                         # SPACEBAR key
    "f": False                              # F key
}

def sign(num):                              # returns +1 or -1 depending on whether the number is positive or negative
    if num > 0:                             # if 0 or greater
        return 1                            # return 1
    else:                                   # otherwise
        return -1                           # return -1

def limit_vector2(game_object):
    if abs(game_object.y_velocity) > PLAYER_SPEED:
        game_object.y_velocity = sign(game_object.y_velocity) * PLAYER_SPEED / 2
    if abs(game_object.x_velocity) > PLAYER_SPEED:
        game_object.x_velocity = sign(game_object.x_velocity) * PLAYER_SPEED / 2

def limit_vector(game_object):
    velocity = math.sqrt(game_object.y_velocity * game_object.y_velocity + game_object.x_velocity * game_object.x_velocity)
    if abs(velocity) > PLAYER_SPEED:
        game_object.x_velocity = sign(game_object.x_velocity) * PLAYER_SPEED * game_object.x_velocity * game_object.x_velocity / (velocity * velocity)
        game_object.y_velocity = sign(game_object.y_velocity) * PLAYER_SPEED * game_object.y_velocity * game_object.y_velocity / (velocity * velocity)

def bound_check(game_object,X_UB,Y_UB,X_LB=0,Y_LB=0):
    if (game_object.x + game_object.width >= X_UB):
        return False
    elif (game_object.x <= X_LB):
        return False
    if (game_object.y + game_object.height >= Y_UB):
        return False
    elif (game_object.y <= Y_LB):
        return False
    return True

def bound_screen_space(game_object):
    if (game_object.x + game_object.width >= SCREEN_WIDTH):
        game_object.x = SCREEN_WIDTH - game_object.width
        game_object.x_velocity = -game_object.x_velocity
    elif (game_object.x <= 0):
        game_object.x = 0
        game_object.x_velocity = -game_object.x_velocity

    if (game_object.y + game_object.height >= SCREEN_HEIGHT):
        game_object.y = SCREEN_HEIGHT - game_object.height
        game_object.y_velocity = -game_object.y_velocity
    elif (game_object.y <= 0):
        game_object.y = 0
        game_object.y_velocity = -game_object.y_velocity

def set_input(event):                                       # Set the keys as pressed or no pressed
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP or event.key == pygame.K_w:
            keys['up'] = True
        elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
            keys['down'] = True
        elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
            keys['left'] = True
        elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
            keys['right'] = True
        elif event.key == pygame.K_SPACE:
            keys['space'] = True
        elif event.key == pygame.K_f:
            keys['f'] = True

    if event.type == pygame.KEYUP:
        if event.key == pygame.K_UP or event.key == pygame.K_w:
            keys['up'] = False
        elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
            keys['down'] = False
        elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
            keys['left'] = False
        elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
            keys['right'] = False
        elif event.key == pygame.K_SPACE:
            keys['space'] = False
        elif event.key == pygame.K_f:
            keys['f'] = False

def manage_input(player,obj_list):
    if(not player.alive):
        return
                                                            # MOVEMENT CONTROLS
    if keys['up']:
        player.y_velocity = player.y_velocity - 1
        player.angle = 90
    if keys['down']:
        player.y_velocity = player.y_velocity + 1
        player.angle = 270
    if keys['left']:
        player.x_velocity = player.x_velocity - 1
        player.angle = 180
    if keys['right']:
        player.x_velocity = player.x_velocity + 1
        player.angle = 0
                                                            # COMPOUND MOVEMENT CONTROLS, MULTIPLE KEYS PRESSED
    if keys['up']:
        if keys['left']:
            player.angle = 135
        if keys['right']:
            player.angle = 45
    if keys['down']:
        if keys['left']:
            player.angle = 225
        if keys['right']:
            player.angle = 315
                                                            # ATTACKS AND SPECIAL ACTIONS
    if keys['space']:
        player.warp()                                       # trigger player special
    if keys['f']:
        player.attack(obj_list)

def to_radian(angle):                                       # converts degree to radian units
    return math.pi*angle/180

def collide_check(object1,object2):                         # checks whether two objects are colliding with each other

    if (abs(object1.x + object1.width * 0.5 - object2.x - object2.width * 0.5)) < 0.5*(object1.width + object2.width) and \
       (abs(object1.y + object1.height * 0.5 - object2.y - object2.height * 0.5)) < 0.5 * (object1.height + object2.height):
            return True
    return False


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

""" Tests for the `piecewiselinear` module."""

import pytest
from pytest import approx
import numpy as np
from scipy.integrate import quad
from ufoldy.piecewisefunction import PLF, PCF

def argsort(seq):
    return sorted(range(len(seq)), key=seq.__getitem__)

@pytest.fixture
def small():
    x = [0, 1, 3]
    y = [1, 2, -1]

    norm = 2.5
    integral13 = 1.0
    integral15 = 1.0

    return x, y, norm, integral13, integral15

def test_PLF_init_from_sorted_list(small):
    x, y, *r = small

    p = PLF(x, y)

    for i in range(len(x)):
        assert x[i] == p.x[i]
        assert y[i] == p.y[i]

def test_PLF_init_from_unsorted_list(small):
    x, y, *r = small

    x = x[::-1]
    y = y[::-1]

    p = PLF(x, y)

    xx = x.copy()
    yy = y.copy()

    idx = argsort(xx)

    for i in range(len(x)):
        assert xx[idx[i]] == p.x[i]
        assert yy[idx[i]] == p.y[i]

def test_PLF_init_wrong_xlist():
    x = []
    y = [1, 2, 3]

    with pytest.raises(ValueError):
        p = PLF(x, y)

def test_PLF_init_wrong_ylist():
    x = [1, 2, 3]
    y = []

    with pytest.raises(ValueError):
        p = PLF(x, y)

def test_PLF_init_noncompatlist():
    x = [1, 2]
    y = [1, 2, 3]

    with pytest.raises(ValueError):
        p = PLF(x, y)

def test_PLF_init_nparray(small):
    x, y, *r = small

    xa = np.array(x)
    ya = np.array(y)

    p = PLF(xa, ya)

    for i in range(len(x)):
        assert xa[i] == p.x[i]
        assert ya[i] == p.y[i]

def test_PLF_init_x2darray():
    x = np.array([[1, 2], [3, 4]])
    y = np.array([1, 2, 3, 4])

    with pytest.raises(ValueError):
        p = PLF(x, y)

def test_PLF_init_y2darray():
    x = np.array([1, 2, 3, 4])
    y = np.array([[1, 2], [3, 4]])

    with pytest.raises(ValueError):
        p = PLF(x, y)

def test_PLF_evaluate(small):
    x, y, *r = small

    p = PLF(x, y)

    assert p(-1) == approx(0.0)
    assert p(0) == approx(1.0)
    assert p(0.5) == approx(1.5)
    assert p(1) == approx(2)
    assert p(2) == approx(0.5)
    assert p(7 / 3) == approx(0.0)
    assert p(3) == approx(-1.0)
    assert p(4) == approx(0.0)

    assert p([-1, 0, 0.5, 1, 2, 7 / 3, 3, 4]) == approx(
        np.array([0.0, 1.0, 1.5, 2.0, 0.5, 0.0, -1.0, 0.0])
    )

def test_PLF_init_normalized(small):
    x, y, *r = small

    p = PLF(x, y, normalize=True)

    assert p.norm() == approx(1.0)

def test_PLF_init_normalized_to_number(small):
    x, y, *r = small

    p = PLF(x, y, normalize=True, normvalue=8.0)

    assert p.norm() == approx(8.0)

def test_PLF_init_emptyxy():
    p = PLF([], [])

    assert p.x[0] == approx(0.0)
    assert p.x[1] == approx(1.0)
    assert p.y[0] == approx(0.0)
    assert p.y[1] == approx(0.0)

def test_PLF_xsetter(small):
    x, y, *r = small

    p = PLF(x, y)

    with pytest.raises(ValueError):
        p.x = [-1]

def test_PLF_ysetter(small):
    x, y, *r = small

    p = PLF(x, y)

    p.y = [1, 1, 3]

    assert p.y[0] == approx(1.0)

    assert p(0.5) == approx(1.0)

def test_PLF_ysetter_wrongshape(small):
    x, y, *r = small

    p = PLF(x, y)

    newy = [1, 2]

    with pytest.raises(ValueError):
        p.y = newy

def test_PLF_slopes_setter(small):
    x, y, *r = small

    p = PLF(x, y)

    with pytest.raises(ValueError):
        p.slopes = 1.0

def test_PLF_str(small):
    x, y, *r = small

    p = PLF(x, y)

    strval = "[+0.0000e+00, +1.0000e+00, +3.0000e+00]\n[+1.0000e+00, +2.0000e+00, -1.0000e+00]"

    assert f"{p}" == strval

def test_PLF_norm(small):
    x, y, norm, *r = small

    p = PLF(x, y)

    assert norm == approx(p.norm())

def test_PLF_norm_partial1(small):
    x, y, *r = small

    p = PLF(x, y)

    assert p.norm(1) == approx(1.0)

def test_PLF_norm_partial2(small):
    x, y, *r = small

    p = PLF(x, y)

    assert p.norm(0, 1) == approx(1.5)

def test_PLF_insert_node_before_left(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes(-1, -1)

    assert p(-0.5) == approx(0.0)

def test_PLF_insert_node_after_right(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes(4, 1)

    assert p(3.5) == approx(0.0)

def test_PLF_insert_node(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes(0.5, 1)

    assert p(0.25) == approx(1.0)
    assert p(0.5) == approx(1.0)
    assert p(1.0) == approx(2.0)

def test_PLF_insert_node_noy(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes(7 / 3)

    assert p(-1) == approx(0.0)
    assert p(0) == approx(1.0)
    assert p(0.5) == approx(1.5)
    assert p(1) == approx(2)
    assert p(2) == approx(0.5)
    assert p(7 / 3) == approx(0.0)
    assert p(3) == approx(-1.0)
    assert p(4) == approx(0.0)

def test_PLF_insert_nodes(small):
    x, y, *r = small

    p = PLF(x, y)
    q = PLF(x, y)

    newx = [(p.x[i] + p.x[i + 1]) / 2 for i in range(2)]
    newy = p(newx)

    q.insert_nodes(newx, newy)

    evalx = np.linspace(x[0], x[-1], 11)

    for xx in evalx:
        assert p(xx) == approx(q(xx))

def test_PLF_insert_nodes_mixed(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes([0.5, 1], [0, 0])

    assert p(-1) == approx(0.0)
    assert p(0) == approx(1.0)
    assert p(0.5) == approx(0.0)
    assert p(1) == approx(0)
    assert p(2) == approx(-0.5)
    assert p(3) == approx(-1.0)
    assert p(4) == approx(0.0)

def test_PLF_insert_nodes_mixed2(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes([0.5, 1], [1.5, 2])

    assert p(-1) == approx(0.0)
    assert p(0) == approx(1.0)
    assert p(0.5) == approx(1.5)
    assert p(1) == approx(2)
    assert p(2) == approx(0.5)
    assert p(7 / 3) == approx(0.0)
    assert p(3) == approx(-1.0)
    assert p(4) == approx(0.0)

def test_PLF_insert_nodes_mixed_noy(small):
    x, y, *r = small

    p = PLF(x, y)

    p.insert_nodes([0.5, 1])

    assert p(-1) == approx(0.0)
    assert p(0) == approx(1.0)
    assert p(0.5) == approx(1.5)
    assert p(1) == approx(2)
    assert p(2) == approx(0.5)
    assert p(7 / 3) == approx(0.0)
    assert p(3) == approx(-1.0)
    assert p(4) == approx(0.0)

def test_PCF_insert_nodes_sim(small):
    x, y, *r = small

    p = PCF(x, y)

    x = p.x
    y = p.y

    p.insert_nodes(x)

    assert p.x == approx(x)
    assert p.y == approx(y)

def test_PLF_refine_lin():
    x = np.array([-2, 0, 2])
    y = np.array([1, 2, 1])

    p = PLF(x, y)

    p.refine_lin()

    assert (p.x) == approx(np.array([-2, -1, 0, 1, 2]))

def test_PLF_refine_log():
    x = np.power(10.0, [-2, 0, 2])
    y = np.array([1, 2, 1])

    p = PLF(x, y)

    p.refine_log()

    assert (np.log10(p.x)) == approx(np.array([-2, -1, 0, 1, 2]))

def test_PLF_copy(small):
    x, y, *r = small

    a = PLF(x, y)

    b = a.copy()

    assert np.any(a.x == b.x) and not a.x is b.x
    assert np.any(a.y == b.y) and not a.y is b.y

def test_PLF_flat_noy():
    a = PLF.flat(-1, 1)

    assert a.x[0] == approx(-1.0)
    assert a.x[1] == approx(+1.0)
    assert a.y[0] == approx(0.5)
    assert a.y[1] == approx(0.5)

def test_PLF_flat_y():
    a = PLF.flat(-1, 1, 10)

    assert a.x[0] == approx(-1.0)
    assert a.x[1] == approx(+1.0)
    assert a.y[0] == approx(10.0)
    assert a.y[1] == approx(10.0)

def test_PLF_flat_swapx():
    a = PLF.flat(+1, -1)

    assert a.x[0] == approx(-1.0)
    assert a.x[1] == approx(+1.0)
    assert a.y[0] == approx(0.5)
    assert a.y[1] == approx(0.5)

def test_PCF_eval(small):
    x, y, *r = small

    p = PCF(x, y)

    assert p.y[-1] == p.y[-2]

def test_PCF_eval(small):
    x, y, *r = small

    p = PCF(x, y)

    xeval = [-1.0, +0.0, +0.5, +1.0, +2.0, +3.0, +4.0]
    yeval = [0.0, +1.0, +1.0, +2.0, +2.0, +0.0, 0.0]

    for xe, ye in zip(xeval, yeval):
        assert p(xe) == approx(ye)

def test_PCF_slopes(small):
    x, y, *r = small

    p = PCF(x, y)

    assert p.slopes == approx(np.ones(2))

def test_PCF_norm(small):
    x, y, *r = small

    p = PCF(x, y)

    assert p.norm() == approx(5.0)

def test_PCF_copy(small):
    x, y, *r = small

    a = PCF(x, y)

    b = a.copy()

    assert np.any(a.x == b.x) and not a.x is b.x
    assert np.any(a.y == b.y) and not a.y is b.y

def test_plf_partial_integrals(small):
    x, y, *r = small

    a = PLF(x, y)

    b = PCF([0, 1, 3], [1, 1, 1])

    cnodes = np.array(
        [[0, 1, 3], [-1, 1, 3], [0.5, 1, 3], [-1, 1, 4], [-1, 1, 2], [0.5, 1, 2]]
    )

    cvals = np.array([0.5, 1, np.nan])

    convs = np.array(
        [[1.5, 1.0], [1.5, 1.0], [0.875, 1.0], [1.5, 1.0], [1.5, 1.25], [0.875, 1.25]]
    )

    for c, cint in zip(cnodes, convs):
        b = PCF(c, cvals)
        res = a.partial_integrals(b)
        assert res == approx(cint)

def test_convolute(small):
    x, y, *r = small

    a = PLF(x, y)

    cnodes = np.array(
        [[0, 1, 3], [-1, 1, 3], [0.5, 1, 3], [-1, 1, 4], [-1, 1, 2], [0.5, 1, 2]]
    )
    cvals = np.array([0.5, 1, np.nan])

    convs = np.array([1.75, 1.75, 1.4375, 1.75, 2, 1.6875])

    for c, cint in zip(cnodes, convs):
        b = PCF(c, cvals)
        res = a.convolute(b)
        assert res == approx(cint)


import os
import re

import cv2

from plate import Plate

def get_plate_section(plate, flag_write):
    output_dir = 'output/plate'
    plate_section = Plate()
    # BRAND
    # BRAND_x_left = int(14.5 / design_w_plate * w_plate + 0.5 - float_range_x)
    # if BRAND_x_left < 0:
    #     BRAND_x_left = 0
    # BRAND_x_right = int(50.5 / design_w_plate * w_plate + 0.5 + float_range_x)
    # if BRAND_x_right > design_w_plate * resize_time:
    #     BRAND_x_right = design_w_plate * resize_time
    # BRAND_y_up = int(1 / design_h_plate * h_plate + 0.5 - float_range_y)
    # if BRAND_y_up < 0:
    #     BRAND_y_up = 0
    # BRAND_y_down = int(5 / design_h_plate * h_plate + 0.5 + float_range_y)
    # if BRAND_y_down > design_h_plate *resize_time:
    #     BRAND_y_down = design_h_plate *resize_time
    BRAND_x_left = 75
    BRAND_x_right = 295
    BRAND_y_up = 5
    BRAND_y_down = 40
    plate_section.BRAND = plate[BRAND_y_up: BRAND_y_down, BRAND_x_left: BRAND_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'brand.png'), plate_section.BRAND)

    # COUNTRY
    # COUNTRY_x_left = int(66.5 / design_w_plate * w_plate + 0.5 - float_range_x)
    # COUNTRY_x_right = int(88 / design_w_plate * w_plate + 0.5 + float_range_x)
    # COUNTRY_y_up = int(1 / design_h_plate * h_plate + 0.5 - float_range_y)
    # COUNTRY_y_down = int(5 / design_h_plate * h_plate + 0.5 + float_range_y)
    COUNTRY_x_left = 380
    COUNTRY_x_right = 615
    COUNTRY_y_up = 1
    COUNTRY_y_down = 35
    plate_section.COUNTRY = plate[COUNTRY_y_up: COUNTRY_y_down, COUNTRY_x_left: COUNTRY_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'country.png'), plate_section.COUNTRY)

    # TYPE
    # TYPE_x_left = int(20.5 / design_w_plate * w_plate + 0.5 - float_range_x)
    # TYPE_x_right = int(36.4 / design_w_plate * w_plate + 0.5 + float_range_x)
    # TYPE_y_up = int(6 / design_h_plate * h_plate + 0.5 - float_range_y)
    # TYPE_y_down = int(10 / design_h_plate * h_plate + 0.5 + float_range_y)
    TYPE_x_left = 110
    TYPE_x_right = 400
    TYPE_y_up = 30
    TYPE_y_down = 70
    plate_section.TYPE = plate[TYPE_y_up: TYPE_y_down, TYPE_x_left: TYPE_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'type.png'), plate_section.TYPE)

    # NUMBER
    # NUMBER_x_left = int(20.5 / design_w_plate * w_plate + 0.5 - float_range_x)
    # NUMBER_x_right = int(36.4 / design_w_plate * w_plate + 0.5 + float_range_x)
    # NUMBER_y_up = int(6 / design_h_plate * h_plate + 0.5 - float_range_y)
    # NUMBER_y_down = int(10 / design_h_plate * h_plate + 0.5 + float_range_y)
    NUMBER_x_left = 105
    NUMBER_x_right = 550
    NUMBER_y_up = 60
    NUMBER_y_down = 100
    plate_section.NUMBER = plate[NUMBER_y_up: NUMBER_y_down, NUMBER_x_left: NUMBER_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'number.png'), plate_section.NUMBER)

    # ENGINE MODEL
    ENGINE_x_left = 100
    ENGINE_x_right = 200
    ENGINE_y_up = 90
    ENGINE_y_down = 130
    plate_section.ENGINE = plate[ENGINE_y_up: ENGINE_y_down, ENGINE_x_left: ENGINE_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'engine.png'), plate_section.ENGINE)

    # POWER
    POWER_x_left = 120
    POWER_x_right = 250
    POWER_y_up = 120
    POWER_y_down = 160
    plate_section.POWER = plate[POWER_y_up: POWER_y_down, POWER_x_left: POWER_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'power.png'), plate_section.POWER)

    # GVM
    GVM_x_left = 150
    GVM_x_right = 280
    GVM_y_up = 150
    GVM_y_down = 190
    plate_section.GVM = plate[GVM_y_up: GVM_y_down, GVM_x_left: GVM_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'gvm.png'), plate_section.GVM)

    # ENGINE SIZE
    SIZE_x_left = 390
    SIZE_x_right = 570
    SIZE_y_up = 90
    SIZE_y_down = 130
    plate_section.SIZE = plate[SIZE_y_up: SIZE_y_down, SIZE_x_left: SIZE_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'size.png'), plate_section.SIZE)

    # DATEy
    DATEy_x_left = 325
    DATEy_x_right = 420
    DATEy_y_up = 120
    DATEy_y_down = 160
    plate_section.DATEy = plate[DATEy_y_up: DATEy_y_down, DATEy_x_left: DATEy_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'datey.png'), plate_section.DATEy)

    # DATEm
    DATEm_x_left = 430
    DATEm_x_right = 520
    DATEm_y_up = 120
    DATEm_y_down = 160
    plate_section.DATEm = plate[DATEm_y_up: DATEm_y_down, DATEm_x_left: DATEm_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'datem.png'), plate_section.DATEm)

    # OCCUPANTS
    OCCUPANTS_x_left = 370
    OCCUPANTS_x_right = 440
    OCCUPANTS_y_up = 150
    OCCUPANTS_y_down = 190
    plate_section.OCCUPANTS = plate[OCCUPANTS_y_up: OCCUPANTS_y_down, OCCUPANTS_x_left: OCCUPANTS_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'occupants.png'), plate_section.OCCUPANTS)

    # MANUFACTURER
    MANUFACTURER_x_left = 110
    MANUFACTURER_x_right = 550
    MANUFACTURER_y_up = 210
    MANUFACTURER_y_down = 250
    plate_section.MANUFACTURER = plate[MANUFACTURER_y_up: MANUFACTURER_y_down, MANUFACTURER_x_left: MANUFACTURER_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'manufacturer.png'), plate_section.MANUFACTURER)

    # MANUFACTURERn1
    MANUFACTURERn1_x_left = 100
    MANUFACTURERn1_x_right = 460
    MANUFACTURERn1_y_up = 240
    MANUFACTURERn1_y_down = 280
    plate_section.MANUFACTURERn1 = plate[MANUFACTURERn1_y_up: MANUFACTURERn1_y_down, MANUFACTURERn1_x_left: MANUFACTURERn1_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'manufacturer_n1.png'), plate_section.MANUFACTURERn1)

    # MANUFACTURERn2
    MANUFACTURERn2_x_left = 100
    MANUFACTURERn2_x_right = 390
    MANUFACTURERn2_y_up = 270
    MANUFACTURERn2_y_down = 310
    plate_section.MANUFACTURERn2 = plate[MANUFACTURERn2_y_up: MANUFACTURERn2_y_down, MANUFACTURERn2_x_left: MANUFACTURERn2_x_right]
    if flag_write:
        cv2.imwrite(os.path.join(output_dir, 'manufacturer_n2.png'), plate_section.MANUFACTURERn2)

    return plate_section


import csv
import numpy as np
import torch
import torch.nn.functional as F
import torchvision.utils as utils
from sklearn import metrics
import pandas as pd

def get_output_target(test_csv, result_file, label, label_dict):
    # groundtruth
    test_df = pd.read_csv(test_csv)
    gt = [label_dict[test_df.loc[idx, label]] for idx in range(len(test_df))]
    # prediction
    pred = []
    with open(result_file, 'r', newline='') as csv_file:
        reader = csv.reader(csv_file, delimiter=',')
        for row in reader:
            prob = np.array(list(map(float, row)))
            pred.append(np.argmax(prob))
    return pred, gt

def metrics_all(test_csv, result_file, label, label_dict):
    labels = [0,1,2]
    pred, gt = get_output_target(test_csv, result_file, label, label_dict)
    recall = metrics.recall_score(gt, pred, average=None)
    precision = metrics.precision_score(gt, pred, average=None, zero_division=0)
    cm = metrics.confusion_matrix(gt, pred, labels=labels)
    f1 =  metrics.f1_score(gt, pred, labels = labels, average='micro')
    bal_acc = metrics.balanced_accuracy_score(gt, pred)
    kappa = metrics.cohen_kappa_score(gt, pred)
    return precision, recall, cm, f1, bal_acc, kappa #auroc


import sys, os
import setuptools

def read(filename):
    return open(os.path.join(os.path.dirname(__file__), filename)).read()

setuptools.setup(
    name='python-whois',
    version='0.8.2',
    description="Whois querying and parsing of domain registration information.",
    long_description=read('README.rst'),
    install_requires=[
        'future',
    ],
    classifiers=[
        'Environment :: Web Environment',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Topic :: Internet :: WWW/HTTP',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 3',
    ],
    keywords='whois, python',
    author='Richard Penman',
    author_email='richard.penman@gmail.com',
    url='https://github.com/richardpenman/whois',
    license='MIT',
    packages=['whois'],
    package_dir={'whois':'whois'},
    extras_require={
        'better date conversion': ["python-dateutil"]
    },
    test_suite='nose.collector',
    tests_require=['nose', 'simplejson'],
    include_package_data=True,
    zip_safe=False
)


import enum

class Components_names(enum.Enum):
    Bulge = 'Bulge'
    Thin_disk = 'Thin disk'
    Thick_disk = 'Thick disk'
    Exponential_disk = 'Exponential disk'
    Dark_halo = 'Dark halo'
    Burkert_halo = 'Burkert halo'

def input_component(component):

    component_mass = 10
    component_scale_a = 2
    component_scale_b = 2
    print('Set the guess parameters for', component.value)
    try:
        component_mass = float(input('Mass (in M_sun):'))
    except:
        print('No valid Mass for', component, '. It will be taken the default mass:', component_mass, 'M_sun')

    try:
        component_scale_a = float(input('Radial Scale Length (in kpc):'))
    except:
        print('No valid Radial Scale Length for', component, '. It will be taken the default Radial Scale Lenght:', component_scale_a, 'kpc')

    if component not in [Components_names.Exponential_disk, Components_names.Dark_halo, Components_names.Burkert_halo]:
        try:
            component_scale_b = float(input('Vertical Scale Length (in kpc):'))
        except:
            print('No valid Vertical Scale Length for', component, '. It will be taken the default Vertical Scale Lenght:', component_scale_b, 'kpc')

    return component_mass, component_scale_a, component_scale_b

m, a, b = input_component(Components_names.Bulge)
print(m, a, b)

m, a, b = input_component(Components_names.Exponential_disk)
print(m, a, b)


from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
import copy

app = Dash(__name__)

# Example Data
d = {'Cost': [1, 3, 2], 'Carbon Emission': [7, 5, 6], 'Time': [20, 50, 30],
     'Type': ['Car', 'Bike', 'Bus']}
df_trav = pd.DataFrame(data=d)
df = copy.deepcopy(df_trav.iloc[:, :-1])
df_n = (df - df.mean()) / df.std()
df_n['Type'] = df_trav['Type'].copy()

app.layout = html.Div([
    html.H4('Pareto Optimal Curve Example'),
    dcc.Graph(id="graph"),
    html.P("Cost Weight:"),
    dcc.Slider(
        id='cost_slider',
        min=0, max=5, step=0.1,
        value=1
    ),
    html.P("Carbon Emission Weight:"),
    dcc.Slider(
        id='carbon_slider',
        min=0, max=5, step=0.1,
        value=1
    ),
    html.P("Time:"),
    dcc.Slider(
        id='time_slider',
        min=0, max=5, step=0.1,
        value=4
    ),

])

@app.callback(
    Output("graph", "figure"),
    Input("time_slider", "value"),
    Input("carbon_slider", "value"),
    Input("time_slider", "value")
)
def update_bar_chart(cost_w, carbon_w, time_w):
    df_g = df_n.copy()
    df_g['Cost'] = df_n['Cost'] * cost_w
    df_g['Carbon Emission'] = df_n['Carbon Emission'] * carbon_w
    df_g['Time'] = df_n['Time'] * time_w

    fig = px.scatter_3d(df_g,
                        x='Cost', y='Carbon Emission', z='Time',
                        color="Type",
                        hover_data=['Type', 'Time', 'Cost', 'Carbon Emission'])
    return fig

app.run_server(debug=True)


#!/usr/bin/env python
# coding: utf-8

# In[1]:

# 리뷰 인덱스를 찾는 함수
def get_review_idx(little_menu):
    for i in range(len(little_menu)):
        if little_menu[i].text == '리뷰':
            return i+1

# In[2]:

def collect_review(url):
    from bs4 import BeautifulSoup
    from selenium import webdriver
    import requests
    import time
    import pandas as pd

    options = webdriver.ChromeOptions()
    options.add_experimental_option("excludeSwitches", ["enable-logging"])
    options.add_argument('start-maximized')

    driver = webdriver.Chrome(executable_path = 'C:/Users/WooCheol Kwon/Python_Notebooks/chromedriver.exe', options=options)
    driver.implicitly_wait(1)
#     driver.get('https://map.naver.com/v5/?c=14128298.7324875,4524422.5047163,14,0,0,0,dh')
    driver.get(url)
    driver.implicitly_wait(1)
    time.sleep(2)

    # 리스트 보여지게 클릭
    driver.find_element_by_id('baseMap').click()

    # 음식점 버튼 클릭
    driver.find_element_by_xpath('//*[@id="container"]/shrinkable-layout/div/app-base/bubble-filter/bubble-filter-list/div/ul/li[2]/button').click()
    driver.implicitly_wait(5)

    """
    Selenium은 페이지 조작을 위해 사용하고, BeautifulSoup를 이용해 원하는 텍스트 값을 추출
    """

    """
    res_name: 식당이름
    res_subclass: 분야
    res_reviewcnt: 리뷰 수
    res_score: 식당별점
    res_address: 식당주소
    res_review: 리뷰
    """
    res_name = []
    res_subclass = []
    res_score = []
    res_address = []
    res_review = []
    res_review_point = []

    for i in range(1, 51):
        # #document안의 내용이 스크롤 바를 내리지 않으면 숨겨저 있는 구조이므로,
        # 10개마다 새로고침되는 특성을 이용해 스크롤을 내린다.
        if i%10 == 0:
            iframe = driver.find_elements_by_xpath('//*[@id="searchIframe"]')[0]
            driver.switch_to.frame(iframe)
            driver.execute_script("arguments[0].scrollIntoView(true);",driver.find_elements_by_xpath(f'//*[@id ="_pcmap_list_scroll_container"]/ul/li[{i}]/div/a[1]')[0])
            time.sleep(5)
            # 기본 프레임으로 이동
            driver.switch_to.default_content()

        # #document안의 태그를 참조하기 위해 driver 변경
        iframe = driver.find_elements_by_xpath('//*[@id="searchIframe"]')[0]
        driver.switch_to.frame(iframe)
        time.sleep(5)

        driver.find_elements_by_xpath(f'//*[@id ="_pcmap_list_scroll_container"]/ul/li[{i}]/div/a[1]')[0].click()
        time.sleep(5)

        # 기본 프레임으로 이동
        driver.switch_to.default_content()

        iframe2 = driver.find_elements_by_xpath('//*[@id = "entryIframe"]')[0]
        driver.switch_to.frame(iframe2)

        # res_name
        res_name.append(driver.find_elements_by_xpath('//*[@class = "place_section_content"]/div/div/span/span[1]')[0].text)

        # res_subclass
        res_subclass.append(driver.find_elements_by_xpath('//*[@class = "place_section_content"]/div/div/span/span[2]')[0].text)

        # res_score
        tmp_score = driver.find_elements_by_xpath('//*[@class = "place_section_content"]/div/div/div/span/em')
        if len(tmp_score) == 0:
            res_score.append('0')
        else:
            res_score.append(driver.find_elements_by_xpath('//*[@class = "place_section_content"]/div/div/div/span/em')[0].text)

        # res_address
        tmp_address = driver.find_elements_by_xpath('//*[@class = "_2yqUQ"]')
        if len(tmp_address) == 0:
            res_address.append('')
        else:
            res_address.append(driver.find_elements_by_xpath('//*[@class = "_2yqUQ"]')[0].text)

        """
        리뷰 버튼을 찾고 클릭해서 보여줘야 한다.
        """
        # 1) 메뉴에서 리뷰 인덱스를 찾는다.
        little_menu = driver.find_elements_by_xpath('//*[@class="_2MDmw"]/a')
        # 2) 찾은 인덱스로 클릭
        if len(driver.find_elements_by_xpath(f'//*[@class="_2MDmw"]/a[{get_review_idx(little_menu)}]')) < 1:
            little_menu = driver.find_elements_by_xpath('//*[@class="eg-flick-camera"]/a')
            driver.find_elements_by_xpath(f'//*[@class="eg-flick-camera"]/a[{get_review_idx(little_menu)}]')[0].click()
        else:
            driver.find_elements_by_xpath(f'//*[@class="_2MDmw"]/a[{get_review_idx(little_menu)}]')[0].click()

        # 3) 리뷰가 10개 미만일 경우, 모든 리뷰 클릭
        # 4) 리뷰가 10개 초과일 경우, 모든 리뷰 클릭 후 더보기 클릭 -> 반복
        # 5) 현재 리뷰 10개만 추출하는 것으로 가정하고 코드 작성
        review_cnt = len(driver.find_elements_by_xpath('//*[@class = "_1QS0G "]/li'))

        if review_cnt == 0:
            print("리뷰 없음")
        elif review_cnt < 10:
            for j in range(review_cnt):
                # 리뷰 펼쳐보기 해주기
                try:
                    driver.find_elements_by_xpath("//span[contains(@class,'WoYOw')]")[j].click()
                except:
                    # 후기로 사진만 올리고 글을 작성하지 않은 경우가 있어 pass
                    pass
        else:
            for j in range(review_cnt):
                # 리뷰 펼쳐보기 해주기
                try:
                    driver.find_elements_by_xpath("//span[contains(@class,'WoYOw')]")[j].click()
                except:
                    # 후기로 사진만 올리고 글을 작성하지 않은 경우가 있어 pass
                    pass

                # 더보기 클릭(기능 생략 추후 많은 리뷰를 끌어모으기 위해 추가)

        page_text = BeautifulSoup(driver.page_source, 'html.parser')
        tmp_review = ""
        tmp_review_point = ""
        for li in page_text.find_all("li", {"class": "_2Cv-r"}):
            if li.find("span", {"class": "WoYOw"}):
                tmp_review += li.find("span",{"class": "WoYOw"}).text + "|"
                tmp_review_point += li.find("span", {"class": "_2tObC"}).text + "|"

        res_review.append(tmp_review[:-1])
        res_review_point.append(tmp_review_point[:-1])
        print(i, '번째 음식점 완료!')

        # 기본 프레임으로 이동
        driver.switch_to.default_content()

    # 데이터를 데이터프레임의 형태로 변환하여 txt 또는 csv 파일로 출력
    df = pd.DataFrame({'res_name': res_name, 'res_subclass': res_subclass, 'res_score': res_score, 'res_address': res_address,'res_review': res_review, 'res_review_point': res_review_point})
    df.to_csv('review.csv', index = None)

# In[ ]:

Collect Data and Write into DB/Collect_Review_Restaurant.py