from __future__ import division
import cv2
import numpy as np

# global
# HSV 色值：
GREEN = [40, 65, 13, 80, 255, 255]  # Green
YELLOW = [20, 103, 80, 40, 255, 255]  # Yellow
BLUE = [94, 81, 82, 126, 255, 255]  # Blue
RED = [0, 144, 0, 20, 255, 255]   # Red

# default value: Blue 蓝色
lowHue = BLUE[0]
lowSat = BLUE[1]
lowVal = BLUE[2]
highHue = BLUE[3]
highSat = BLUE[4]
highVal = BLUE[5]

# 排列：green, yellow, blue, red
defaultColor = [0, 0, 1, 0]  # 蓝色
color = "BLUE"  # 现在的颜色
blueColor = (255, 0, 0)  # 蓝色
greenColor = (0, 255, 0)  # 绿色
redColor = (0, 0, 255)  # 红色

# 图像色调和追踪
def frame_mask_contour(image):
    frameHSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

    colorLow = np.array([lowHue, lowSat, lowVal])
    colorHigh = np.array([highHue, highSat, highVal])

    mask = cv2.inRange(frameHSV, colorLow, colorHigh)

    # get contours
    contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    contour_sizes = [(cv2.contourArea(contour), contour) for contour in contours]

    count = len(contour_sizes)

    found = False
    i=0
    if count > 0:

        for cnt in contours:
            area = cv2.contourArea(cnt)
            if area > 4000:
                x, y, w, h = cv2.boundingRect(cnt)
                i=i+1
                print(i)
                cv2.rectangle(image, (x, y), (x + w, y + h), greenColor, 2)
                print(x,y,w,h)
                found = True
                if i == 1 :
                    square = "x={} , y={} , x+w={} , y+h={}".format(x,y,x+w,y+h)
                    area = "S = {}".format(w*h)
                    cv2.putText(image, square,(50,100),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                    cv2.putText(image, area,(50,150),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                elif i == 2:
                    square = "x={} , y={} , x+w={} , y+h={}".format(x,y,x+w,y+h)
                    area = "S = {}".format(w*h)
                    cv2.putText(image, square,(50,200),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                    cv2.putText(image, area,(50,250),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                elif i == 3:
                    square = "x={} , y={} , x+w={} , y+h={}".format(x,y,x+w,y+h)
                    area = "S = {}".format(w*h)
                    cv2.putText(image, square,(50,300),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                    cv2.putText(image, area,(50,350),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                elif i == 4:
                    square = "x={} , y={} , x+w={} , y+h={}".format(x,y,x+w,y+h)
                    area = "S = {}".format(w*h)
                    cv2.putText(image, square,(50,400),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                    cv2.putText(image, area,(50,450),cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
                else:
                    continue
    if found:
        text = f'Found {color} object'
        print(text)
        cv2.putText(image, text, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)
    else:
        text = "Not Found!"
        print("Not Found! 没有找到！")
        cv2.putText(image, text, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, redColor, 2)

    return mask, image

# 绿色控制
def greenCtrl(val):
    global defaultColor, color
    color = 'GREEN'
    defaultColor = [1, 0, 0, 0]
    assignColor(GREEN)
# 黄色控制
def yellowCtrl(val):
    global defaultColor, color
    color = 'YELLOW'
    defaultColor = [0, 1, 0, 0]
    assignColor(YELLOW)
# 蓝色控制
def blueCtrl(val):
    global defaultColor, color
    color = 'BLUE'
    defaultColor = [0, 0, 1, 0]
    assignColor(BLUE)
# 红色控制
def redCtrl(val):
    global defaultColor, color
    color = 'RED'
    defaultColor = [0, 0, 0, 1]
    assignColor(RED)

vidCapture = cv2.VideoCapture(0)

vidCapture.set(cv2.CAP_PROP_FRAME_WIDTH,800)#FRAME_WIDTH = 800
vidCapture.set(cv2.CAP_PROP_FRAME_HEIGHT,600)#FRAME_HEIGHT = 600

video_win = 'Frame'
cv2.namedWindow(video_win, cv2.WINDOW_AUTOSIZE)
cv2.moveWindow(video_win, 855, 0)
'''
# =====================================
# Window 窗口： Demo
# =====================================
demo_win = 'Demo'
cv2.namedWindow(demo_win)
cv2.moveWindow(demo_win, 205, 0)
'''

while True:

    # Get webcam frame.获取网络摄像头帧。
    _, frame = vidCapture.read()

    # Show the original image.显示原始图像。
    demo, frame_contour = frame_mask_contour(frame)
    cv2.imshow(video_win, frame_contour)
    #cv2.imshow(demo_win, demo)

    key = cv2.waitKey(10)

vidCapture.release()  # release()释放摄像头
cv2.destroyAllWindows()  # 调用destroyAllWindows()关闭所有图像窗口。


import pandas as pd
from tsfresh import extract_features, select_features
from os import listdir
from os.path import isfile, join
from auto_feature_extraction.config import *

def select():
	features_files = [f for f in listdir(features_dir) if isfile(join(features_dir, f))]

	# Select features individually from each of the signal components
	train = pd.DataFrame()
	test = pd.DataFrame()
	for f_file in features_files:  # One file for each signal component

		print(f"loading {f_file}")
		features = pd.read_csv(features_dir + f_file)

		train_x = features.iloc[:validation_split_i].drop('y', axis=1)
		test_x = features.iloc[validation_split_i:].drop('y', axis=1)
		train_y = features.iloc[:validation_split_i].y
		test_y = features.iloc[validation_split_i:].y

		# Feature selection must be always done from the train set!
		print("selecting features...")
		train_features_selected = select_features(train_x, train_y, fdr_level=fdr_level)

		print(f"selected {len( train_features_selected.columns )} features.")

		comp_train = train_features_selected.copy()
		comp_test = test_x[train_features_selected.columns].copy()

		train = pd.concat([train, comp_train], axis=1)
		test = pd.concat([test, comp_test], axis=1)

	train['y'] = train_y
	test['y'] = test_y

	print(f"saving {train_file}")
	train.to_csv(train_file, index=None)

	print(f"saving {test_file}")
	test.to_csv(test_file, index=None)

if __name__ == '__main__':
	select()


import tensorflow as tf
from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2_as_graph

def get_flops(model: tf.keras.models.Model, batch_size: int = 1):
    real_model = tf.function(model).get_concrete_function(tf.TensorSpec([batch_size] + model.inputs[0].shape[1:], model.inputs[0].dtype))
    frozen_func, graph_def = convert_variables_to_constants_v2_as_graph(real_model)

    run_meta = tf.compat.v1.RunMetadata()
    opts = tf.compat.v1.profiler.ProfileOptionBuilder.float_operation()
    flops = tf.compat.v1.profiler.profile(graph=frozen_func.graph, run_meta=run_meta, cmd='op', options=opts)

    return flops.total_float_ops


from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity
from CustomDecorators import *
from flask import jsonify, make_response
from models.category import CategoryModel
from models.item import ItemModel

class Category(Resource):
    parse = reqparse.RequestParser()
    parse.add_argument('cat_name', type=str, required=True)

    @admin_required
    def post(self):
        data = Category.parse.parse_args()
        category = CategoryModel.find_by_cat_name(data['cat_name'])
        if category:
            return {
                "CategoryAlreadyExistsError": {
                    "message": "Category with given name already exists"
                }}, 400

        category = CategoryModel(data['cat_name'])
        category.save_to_db()
        return {
            "message": "Category Create Successfully"
        }, 200

    def get(self, id):
        category = CategoryModel.find_by_cat_name(id)
        if category:
            return category.json()
        return {
            "CategoryNotFound": {
                "Category with given name already exists"
            }}, 400

    @admin_required
    def delete(self,id):
        # parse = reqparse.RequestParser()
        # data = parse.parse_args()
        category = CategoryModel.find_by_cat_id(id)
        if category:
            category.delete_from_db()
            return {
                "status": 200,
                "message": "Category Deleted"
            }
        return{
            "status": 404,
            "NotFoundError": "Category not Found.."
        }

    @admin_required
    def put(self, id):
        parse = reqparse.RequestParser()
        parse.add_argument('cat_name', type=str, required=True)
        Category = CategoryModel.find_by_cat_id(id)
        if Category:
            data = parse.parse_args()
            Category.cat_name = data["cat_name"]
            Category.save_to_db()
            return {"updated": True, "data": Category.json()}, 200

class CategoryList(Resource):
    def get(self):
        cats = [category.json() for category in CategoryModel.query.all()]
        return {"TotalItems": len(cats), "Categories": cats,  "status": 'ok'}, 200


def summary(outroot='summary-18.05.17'):

    from hsaquery import overlaps
    from grizli import utils

    overlaps.summary_table(output='pointing_summary')

    tab = utils.GTable.gread('pointing_summary.fits')

    roots = tab['NAME']

    tab['Full'] = ['Full'.format(root.replace('+','%2B')) for root in roots]

    tab['fp'] = [' '.format(root.replace('+','%2B')) for root in roots]

    tab['zhist'] = [' '.format(root.replace('+','%2B')) for root in roots]

    #cols = ['NAME', 'RA', 'DEC', 'E(B-V)', 'GalLat', 'GalLon', 'NFILT', 'filter', 'target', 'target_description', 'proposal_id', 'pi_name', 'TexpG102', 'PAG102', 'TexpG141', 'PAG141', 'MAST', 'Full', 'fp', 'zhist']
    cols = ['NAME', 'RA', 'DEC', 'E(B-V)', 'GalLat', 'GalLon', 'NFILT', 'filter', 'target', 'proposal_id', 'pi_name', 'TexpG102', 'PAG102', 'TexpG141', 'PAG141', 'MAST', 'Full', 'fp', 'zhist']

    tab[cols].write_sortable_html(outroot+'.html', replace_braces=True, localhost=False, max_lines=50000, table_id=None, table_class='display compact', css=None, filter_columns=['mag_auto', 'z_map', 'bic_diff', 'chinu', 'zwidth1', 'is_point', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII'], use_json=False)

    print('aws s3 cp {0}.html s3://aws-grivam/Pipeline/ --acl public-read'.format(outroot))

def regenerate_webpages(outroot='master'):
    """

    roots=`python -c "from grizli_aws import catalogs; roots, dates = catalogs.get_roots(verbose=False); print('\n'.join(roots))"`

    roots=`ls *phot.fits | sed "s/_phot/ /" | awk '{print $1}'`

    # ACS
    BUCKET=grizli-grism

    roots=`ls ../*footprint.fits | sed "s/\// /g" | sed "s/_foot/ /" | awk '{print $2}'`

    for root in $roots; do
        if [ ! -e ${root}.info.fits ]; then
            aws s3 cp s3://${BUCKET}/Pipeline/${root}/Extractions/${root}.info.fits ./
            #aws s3 cp s3://${BUCKET}/Pipeline/${root}/Extractions/${root}_phot.fits ./
        else
            echo $root
        fi
    done

    for root in $roots; do
        aws s3 ls s3://aws-grivam/Pipeline/${root}/Extractions/ > /tmp/x
        echo $root
        grep beams.fits /tmp/x | wc
        grep full.fits /tmp/x | wc
    done

    """
    import glob
    import numpy as np

    from grizli import utils
    from astropy import table
    ## retrieve

    roots = [file.split('.info')[0] for file in glob.glob('*info.fits')]

    fpi = open('sync_to_s3.sh', 'w')
    fpi.write('# \n')
    fpi.close()

    tables = []

    for root in roots:
        fit = utils.GTable.gread(root+'.info.fits')
        phot = utils.GTable.gread(root+'_phot.fits')
        ix, dr = phot.match_to_catalog_sky(fit)
        fit['phot_dr'] = dr
        for c in phot.colnames:
            if c not in fit.colnames:
                fit[c] = phot[ix][c]
            else:
                pass
                #print(c)

        print(root, len(fit))

        # # DQ on mag differences
        # apcorr = fit['flux_auto']/fit['flux_aper_1']
        # m140 = 23.9-2.5*np.log10(fit['f140w_flux_aper_1']*apcorr)
        # dm140 = m140-fit['mag_wfc3,ir,f140w']
        # mask = fit['{0}_mask_aper_{1}'.format('f140w', 1)]
        # bad =  mask > 0.2*np.percentile(mask[np.isfinite(mask)], 99.5)
        # dm140[bad] = np.nan
        #
        # m160 = 23.9-2.5*np.log10(fit['f160w_flux_aper_1']*apcorr)
        # dm160 = m160-fit['mag_wfc3,ir,f160w']
        # mask = fit['{0}_mask_aper_{1}'.format('f160w', 1)]
        # bad =  mask > 0.2*np.percentile(mask[np.isfinite(mask)], 99.5)
        # dm160[bad] = np.nan
        #
        # dm = dm140
        # dm[(~np.isfinite(dm140)) & np.isfinite(dm160)] = dm160[(~np.isfinite(dm140)) & np.isfinite(dm160)]
        # dm[~np.isfinite(dm)] = -99
        #
        # fit['fit_dmag'] = dm
        # fit['fit_dmag'].format = '4.1f'

        # Point source
        pa = np.polyfit([16, 21, 24, 25.5], [4.5, 2.6, 2.3, 2.1], 2)
        py = np.polyval(pa, fit['mag_auto'])
        point_source = (fit['flux_radius'] < py) #& (fit['mag_auto'] < 23)
        fit['is_point'] = point_source*2-1

        bad = (fit['mag_auto'] > 22) & (fit['flux_radius'] < 1.2)
        fit['too_small'] = bad*2-1

        N = len(fit)
        aws_col = {}
        for c in ['png_stack', 'png_full', 'png_line']:
            aws_col[c] = []

        for i in range(N):
            root = fit['root'][i]

            aws = 'https://s3.amazonaws.com/aws-grivam/Pipeline/{0}/Extractions/{0}'.format(root)

            for c in ['png_stack', 'png_full', 'png_line']:
                pre = fit[c][i]
                aws_col[c].append(pre.replace(root, aws).replace(root, root.replace('+','%2B')))

        for c in ['png_stack', 'png_full', 'png_line']:
            fit['aws_'+c] = aws_col[c]

        fit['log_mass'] = np.log10(fit['stellar_mass'])
        fit['log_mass'].format = '.2f'

        cols = ['root', 'idx','ra', 'dec', 't_g102', 't_g141', 'mag_auto', 'is_point', 'z_map', 'chinu', 'bic_diff', 'zwidth1', 'a_image', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass', 'png_stack', 'png_full', 'png_line']

        # Check grisms
        cols = ['root', 'idx','ra', 'dec', 'mag_auto', 'is_point', 'z_map', 'z02', 'z97', 'chinu', 'bic_diff', 'zwidth1', 'a_image', 'flux_radius', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass', 'aws_png_stack', 'aws_png_full', 'aws_png_line']
        for grism in ['g800l', 'g102', 'g141'][::-1]:
            if np.isfinite(fit['t_'+grism]).sum() > 0:
                cols.insert(4, 't_'+grism)

        fit['ra'].format = '.4f'
        fit['dec'].format = '.4f'
        fit['z02'].format = '.2f'
        fit['z97'].format = '.2f'
        fit['flux_radius'].format = '.1f'
        fit['mag_auto'].format = '.2f'
        fit['t_g800l'].format = '.0f'
        fit['t_g102'].format = '.0f'
        fit['t_g141'].format = '.0f'
        fit['zq'].format = '.1f'
        fit['zwidth1'].format = '.3f'
        fit['bic_diff'].format = '.0f'
        fit['a_image'].format = '.1f'
        for l in ['Ha','OIII','Hb','OII','SIII']:
            fit['sn_'+l].format = '.1f'

        fit[cols].write_sortable_html(root+'-full.html', replace_braces=True, localhost=False, max_lines=50000, table_id=None, table_class='display compact', css=None, filter_columns=['mag_auto', 'z_map', 'z02', 'z97', 'bic_diff', 'chinu', 'a_image', 'flux_radius', 'zwidth1', 'is_point', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII'], use_json=True)

        if '+' in root:
            ext = 'html'
            lines = open(root+'-full.'+ext).readlines()
            for i, line in enumerate(lines):
                if root in line:
                    lines[i] = line.replace(root, root.replace('+', '%2B'))

            fp = open(root+'-full.'+ext,'w')
            fp.writelines(lines)
            fp.close()

            ext = 'json'
            lines = open(root+'-full.'+ext).readlines()
            for i, line in enumerate(lines):
                if (root in line) & ('href' in line):
                    lines[i] = line.replace(root, root.replace('+', '%2B'))

            fp = open(root+'-full.'+ext,'w')
            fp.writelines(lines)
            fp.close()

        fpi = open('sync_to_s3.sh', 'a')
        fpi.write('aws s3 cp {0}-full.html s3://aws-grivam/Pipeline/{0}/Extractions/ --acl public-read\n'.format(root))
        fpi.write('aws s3 cp {0}-full.json s3://aws-grivam/Pipeline/{0}/Extractions/ --acl public-read\n'.format(root))
        fpi.close()

        tables.append(fit)

    master = table.vstack(tables)

    cols = ['root', 'idx','ra', 'dec', 'mag_auto', 'is_point', 'z_map', 'z02', 'z97', 'chinu', 'bic_diff', 'zwidth1', 'a_image', 'flux_radius', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass', 'aws_png_stack', 'aws_png_full', 'aws_png_line']
    for grism in ['g800l', 'g102', 'g141'][::-1]:
        if np.isfinite(master['t_'+grism]).sum() > 0:
            cols.insert(4, 't_'+grism)

    master[cols].write_sortable_html(outroot+'.html', replace_braces=True, localhost=False, max_lines=500000, table_id=None, table_class='display compact', css=None, filter_columns=['mag_auto', 't_g102', 't_g141', 'z_map', 'z02', 'z97', 'bic_diff', 'chinu', 'a_image', 'flux_radius', 'zwidth1', 'is_point', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass'], use_json=True)

    #sel = master['bic_diff'] > 30
    #master[sel][cols].write_sortable_html(outroot+'.html', replace_braces=True, localhost=False, max_lines=500000, table_id=None, table_class='display compact', css=None, filter_columns=['mag_auto', 't_g102', 't_g141', 'z_map', 'z02', 'z97', 'bic_diff', 'chinu', 'a_image', 'flux_radius', 'zwidth1', 'is_point', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass'], use_json=True)

    new = utils.GTable()
    for col in fit.colnames:
        new[col] = master[col]

    new.write(outroot+'.fits', overwrite=True)

    print('aws s3 cp {0}.html s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))
    print('aws s3 cp {0}.json s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))
    print('aws s3 cp {0}.fits s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))

    print ('bash sync_to_s3.sh')

def master_catalog(outroot='grizli-18.05.17-full', bucket='grizli-v1', files=None):

    import glob
    import numpy as np

    from grizli import utils
    from astropy import table
    ## retrieve

    if files is None:
        files = glob.glob('*info.fits')

    roots = [file.split('.info')[0] for file in files]

    tabs = [utils.GTable.gread(root+'.info.fits') for root in roots]
    fit = utils.GTable(table.vstack(tabs))

    fit['flux_radius'].format = '.1f'

    N = len(fit)
    aws_col = {}
    for c in ['png_stack', 'png_full', 'png_line', 'png_rgb']:
        aws_col[c] = []

    #bucket='aws-grivam'
    #bucket='grizli-grism'
    #bucket='grizli'

    for i in range(N):
        root = fit['root'][i]

        aws = 'https://s3.amazonaws.com/{0}/Pipeline/{1}/Extractions/{1}'.format(bucket, root)

        for c in ['png_stack', 'png_full', 'png_line']:
            pre = fit[c].filled()[i]
            aws_col[c].append(pre.replace(root, aws).replace(root, root.replace('+','%2B')))

        pre = fit['png_rgb'].filled()[i]
        aws_col['png_rgb'].append(pre.replace('../Thumbnails/', '').replace(root, aws).replace('Extractions', 'Thumbnails').replace(root,  root.replace('+','%2B')))

    for c in ['png_stack', 'png_full', 'png_line', 'png_rgb']:
        fit['aws_'+c] = aws_col[c]

    fit['aws_png_sed'] = [l.replace('full.png','sed.png') for l in fit['aws_png_full']]

    psx = [16, 18.5, 21, 24, 25.5]
    psy = [8, 4., 2.6, 2.3, 2.1]

    # New pixel scale
    psy = np.array(psy)*0.06/0.1

    # ACS
    if False:
        psx = [16, 21, 24, 25.5, 27]
        psy = [4.5, 2.9, 2.9, 2.6, 2.6]

    pa = np.polyfit(psx, psy, 2)
    py = np.interp(fit['mag_auto'], psx, psy)

    # Point source
    point_source = (fit['flux_radius'] < py) & (fit['mag_auto'] < 25.5)
    #point_source = (fit['flux_radius'] < py) & (fit['mag_auto'] < 24) # ACS
    fit['is_point'] = point_source*1

    fit['log_mass'] = np.log10(fit['stellar_mass'])
    fit['log_mass'].format = '.2f'

    ############
    # Warnings for ambiguous line IDs
    dz_line = np.array([5007, 6563])*(1./5007.-1/6563.)
    col = 'ambiguous_HaOIII'

    dz_line = np.array([3727, 6563])*(1./3727.-1/6563.)
    col = 'ambiguous_HaOII'

    zw1 = fit['zwidth1']/(1+fit['z_map'])
    zw2 = fit['zwidth2']/(1+fit['z_map'])
    fit['zw1'] = zw1
    fit['zw1'].format = '.3f'
    fit['zw2'] = zw2
    fit['zw2'].format = '.3f'

    for dz_line, col in zip([np.array([5007, 6563])*(1./5007.-1/6563.), np.array([3727, 6563])*(1./3727.-1/6563.)], ['ambiguous_HaOIII', 'ambiguous_HaOII']):
        if col in fit.colnames: fit.remove_column(col)

        for dz_i in dz_line:
            if col not in fit.colnames:
                fit[col] = np.abs(zw1 - dz_i) < 0.008
            else:
                fit[col] |= np.abs(zw1 - dz_i) < 0.008

    amb = fit['ambiguous_HaOIII']*1+fit['ambiguous_HaOII']*2

    ############
    # Reliable redshifts, based on 3D-HST COSMOS
    ambiguous = (fit['ambiguous_HaOIII'] | fit['ambiguous_HaOII']) & (zw2 / zw1 < 1.1)
    fit['ambiguous'] = ambiguous

    # Define ambigous as wide zwidth but <= N isolated peaks with width
    # ambig_sigma
    ambig_sigma = 0.005
    ambig_npeak = 2
    ambig_logprob = np.log10(1/np.sqrt(np.pi*ambig_sigma**2)/ambig_npeak)
    fit.meta['pdf_max'] = ambig_logprob, 'log_pdf_max limit for ambigous lines'

    fit['ambiguous'] = (zw1 > 0.2) & (fit['log_pdf_max'] > ambig_logprob)

    min_risk_lim = 0.4
    fit['ambiguous'] &= fit['min_risk'] < min_risk_lim
    fit.meta['min_risk'] = min_risk_lim, 'min_risk limit for ambigous lines'

    fit['ok_width'] = (fit['zw1'] < 0.02) | fit['ambiguous']
    fit['ok_width'].format = 'd'

    fit['bic_diff_spl'] = fit['bic_spl'] - fit['bic_temp']
    fit['bic_diff_spl'].format = '.0f'

    # Overall data quality
    fit['use_spec'] = (fit['ok_width'])
    fit['use_spec'] &= (fit['chinu'] < 10)
    fit['use_spec'] &= (fit['bic_diff'] > 0) | ((fit['bic_diff'] > -30) & (fit['min_risk'] < 0.05))
    fit['use_spec'] &= (fit['flux_radius'] > 1)

    dz_risk = (fit['z_map'] - fit['z_risk'])/(1+fit['z_map'])
    fit['use_spec'] &= np.abs(dz_risk) < 0.01

    fit['dchi'] = (fit['chimax'] - fit['chimin'])/(fit['chimin']/fit['dof'])
    fit['dchi'].format = '.1f'

    # ACS GLASS
    if False:
        fit['use_spec'] &= (fit['flux_radius'] > 1.9)

    fit['use_spec'].format = 'd'

    fit['z_map'].format = '.4f'
    fit['chinu'].format = '.2f'

    fit['min_risk'].format = '.2f'

    fit['ra'].format = '.4f'
    fit['dec'].format = '.4f'
    fit['mag_auto'].format = '.2f'
    fit['t_g102'].format = '.0f'
    fit['t_g141'].format = '.0f'
    fit['zq'].format = '.1f'
    fit['zwidth1'].format = '.3f'
    fit['bic_diff'].format = '.0f'
    fit['a_image'].format = '.1f'
    fit['log_pdf_max'].format = '.2f'

    for l in ['Ha','OIII','Hb','OII','SIII']:
        fit['sn_'+l].format = '.1f'

    cols = ['root', 'idx','ra', 'dec', 't_g800l', 't_g102', 't_g141', 'mag_auto', 'is_point', 'flux_radius', 'z_map', 'use_spec', 'chinu', 'bic_diff', 'min_risk', 'log_pdf_max', 'zw1', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'd4000', 'd4000_e', 'aws_png_stack', 'aws_png_full', 'aws_png_rgb', 'aws_png_line']

    try:
        pred = run_classify(fit)
        fit['pred'] = pred
        cols.insert(10, 'pred')
        print('Prediction!')
    except:
        pass

    # for g in ['g102', 'g141', 'g800l']:
    #     if 't_'+g in fit.colnames:
    #         bad = ~np.isfinite(fit['t_'+g])
    #         fit['t_'+g][bad] = 0.
    #
    #         if fit['t_'+g].max() == 0:
    #             pop = True
    #         else:
    #             pop = False
    #     else:
    #         pop = True
    #
    #     if pop:
    #         cols.pop(cols.index('t_'+g))

    filter_cols = cols[2:-4]

    if 'sparcs' in outroot:
        cols += ['aws_png_sed']

    #filter_cols = ['mag_auto', 'z_map', 'z02', 'z97', 'bic_diff', 'chinu', 'flux_radius', 'zw1', 'use_spec', 'is_point', 'sn_SIII', 'sn_Ha', 'sn_OIII', 'sn_Hb', 'sn_OII', 'log_mass', 't_g800l', 't_g102', 't_g141']

    if False:
        clip = (fit['bic_diff'] > 20) & (fit['chinu'] < 2) & (fit['zwidth1'] < 0.01)
    else:
        clip = fit['ra'] > 0

    print('Clip: {0}'.format((~clip).sum()))

    new = utils.GTable()
    for col in fit.colnames:
        new[col] = fit[col][clip]

    new.write(outroot+'.fits', overwrite=True)

    print('aws s3 cp {0}.fits s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))

    #fit = fit[clip]

    # Boolean columns
    for c in cols:
        if c not in new.colnames:
            continue

        if isinstance(new[c][0], np.bool_):
            #print(c)
            new[c] = new[c]*1

    new[cols].filled(fill_value=-1).write_sortable_html(outroot+'.html', replace_braces=True, localhost=False, max_lines=50000, table_id=None, table_class='display compact', css=None, filter_columns=filter_cols, use_json=True)

    print('aws s3 cp {0}.html s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))
    print('aws s3 cp {0}.json s3://aws-grivam/Pipeline/ --acl public-read\n'.format(outroot))

    if False:
        leg = utils.read_catalog('../../Cutouts/legac_meeting.cat')
        idx, dr = fit.match_to_catalog_sky(leg)
        clip = (dr.value < 0.4)

        f = fit[idx][clip]
        f['z_spec'] = leg['z_spec'][clip]
        f['legac_id'] = ['m{0}_{1}'.format(m, i) for m, i in zip(leg['mask'][clip], leg['id'][clip])]
        f['legac_use'] = leg['use'][clip]

        lc = cols.copy()

        for c in ['legac_id', 'legac_use', 'z_spec'][::-1]:
            lc.insert(3, c)

        f['legac_use'].format = '0d'
        f['z_spec'].format = '.4f'

        f[lc].filled(fill_value=-1).write_sortable_html('may2019_legac.html', replace_braces=True, localhost=False, max_lines=50000, table_id=None, table_class='display compact', css=None, filter_columns=filter_cols, use_json=False)

    # ######################
    # # use_spec versions
    # outroot += '.use_spec'
    # clip &= (fit['use_spec'])

def summary_table(output_table='summary_glass-acs-2018.05.21'
):
    from hsaquery import overlaps
    from grizli import utils

    overlaps.summary_table(output=output_table)

    tab = utils.GTable.gread(output_table+'.fits')

    tab['Browse'] = ['Browse'.format(root.replace('+', '%2B')) for root in tab['NAME']]

    pixscale = np.array([0.06]*len(tab))
    pixscale[9:] = 0.03
    tab['driz_scale'] = pixscale

    url = "http://archive.stsci.edu/hst/search.php?action=Search&RA={0}&DEC={1}&radius=5.&sci_aec=S"
    root_url = [('{2}').format(line['RA'], line['DEC'], line['NAME']) for line in tab]

    tab['root'] = root_url

    cols = ['NAME', 'RA', 'DEC', 'MW_EBV', 'filter', 'proposal_id', 'proposal_pi', 'driz_scale', 'MAST', 'Browse']
    tab[cols].write_sortable_html(output_table+'.html', use_json=False, localhost=False, max_lines=1000)

    print('aws s3 cp {0}.html s3://aws-grivam/Pipeline/ --acl public-read'.format(output_table))


from common import *

def test_server_available():
    assert server()

    for endpoint in ('/','/functions','/metrics'):
        response = requests.get(f'{server()}{endpoint}')
        assert response.status_code==200

def BuildModel_Simple():
    m = sdk.Model()

    m.TimeStart = 0
    m.TimeSteps = 10
    m.NumPaths = 10000
    m.Add(sdk.IndependentGaussian())
    m.Add(sdk.BrownianMotion(0.1,0.2,2)) # start, drift, diffusion

    m.evaluations.append(sdk.EvaluationPoint(0,2))

    return m

def test_simple_model():
    er = run( BuildModel_Simple() )
    print(er)
    assert len(er.names)==1

def test_functions_endpoint():
    response = requests.get(f'{server()}/functions').json()
    for j in response:
        f = sdk.UpdaterDoc()
        sdk.UpdaterDoc_to_json(j,f)


def find_perfect_square(n):
    rec = [0]*(n+1)

    # 1 is a perfect square.
    for j in range(n+1):
        rec[j] = j

    lmt = int(n**0.5)
    for i in range(2, lmt+1):
        sqr = i*i

        max_count = int(n/sqr) + 1
        for k in range(1, max_count):
            for j in range(k*sqr, n+1):
                rec[j] = min(rec[j], rec[j-k*sqr]+k)

    return rec[n]

if __name__ == '__main__':
    print(find_perfect_square(15))


import torch.optim as optim
import torchvision.transforms as T

# For list of supported models use timm.list_models
MODEL_NAME = "resnet18"
NUM_ClASSES = 10
IN_CHANNELS = 3

USE_TORCHVISION = False  # If you need to use timm models set to False.

# USE_TORCHVISION = True # Should use Torchvision Models or timm models
PRETRAINED = True  # If True -> Fine Tuning else Scratch Training
EPOCHS = 5
TRAIN_BATCH_SIZE = 512  # Training Batch Size
VALID_BATCH_SIZE = 512  # Validation Batch Size
NUM_WORKERS = 4  # Workers for training and validation

EARLY_STOPPING = True  # If you need early stoppoing for validation loss
SAVE_PATH = "{}.pt".format(MODEL_NAME)

# IMG_WIDTH = 224  # Width of the image
# IMG_HEIGHT = 224  # Height of the image
MOMENTUM = 0.8  # Use only for SGD
LEARNING_RATE = 1e-3  # Learning Rate
SEED = 42

LOG_INTERVAL = 300  # Interval to print between epoch

# Train and validation Transforms which you would like
train_transforms = T.Compose([T.ToTensor(), T.Normalize((0.5,), (0.5,))])
valid_transforms = T.Compose([T.ToTensor(), T.Normalize((0.5,), (0.5,))])

# Classes to be detected.
FASHION_MNIST_CLASSES = (
    "T-shirt/top",
    "Trouser",
    "Pullover",
    "Dress",
    "Coat",
    "Sandal",
    "Shirt",
    "Sneaker",
    "Bag",
    "Ankle Boot",
)
# Classes to be detected.
CIFAR10_CLASSES = (
    "airplane",
    "automobile",
    "bird",
    "cat",
    "deer",
    "dog",
    "frog",
    "horse",
    "ship",
    "truck",
)


import datetime
from typing import Any, Dict, List, Optional, Type, TypeVar, Union, cast

import attr
from dateutil.parser import isoparse

from ..types import UNSET, Unset

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

@attr.s(auto_attribs=True)
class PatchedStepInvocation:
    """Dynamically removes fields from serializer.
    https://stackoverflow.com/questions/27935558/dynamically-exclude-or-include-a-field-in-django-rest-framework-serializer"""

    url: Union[Unset, str] = UNSET
    id: Union[Unset, int] = UNSET
    step: Union[Unset, str] = UNSET
    release: Union[Unset, str] = UNSET
    invoker: Union[Unset, List[str]] = UNSET
    origin: Union[Unset, Optional[str]] = UNSET
    created: Union[Unset, datetime.datetime] = UNSET
    additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        url = self.url
        id = self.id
        step = self.step
        release = self.release
        invoker: Union[Unset, List[Any]] = UNSET
        if not isinstance(self.invoker, Unset):
            invoker = self.invoker

        origin = self.origin
        created: Union[Unset, str] = UNSET
        if not isinstance(self.created, Unset):
            created = self.created.isoformat()

        field_dict: Dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if url is not UNSET:
            field_dict["url"] = url
        if id is not UNSET:
            field_dict["id"] = id
        if step is not UNSET:
            field_dict["step"] = step
        if release is not UNSET:
            field_dict["release"] = release
        if invoker is not UNSET:
            field_dict["invoker"] = invoker
        if origin is not UNSET:
            field_dict["origin"] = origin
        if created is not UNSET:
            field_dict["created"] = created

        return field_dict

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

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

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

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

        invoker = cast(List[str], d.pop("invoker", UNSET))

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

        created: Union[Unset, datetime.datetime] = UNSET
        _created = d.pop("created", UNSET)
        if not isinstance(_created, Unset):
            created = isoparse(_created)

        patched_step_invocation = cls(
            url=url,
            id=id,
            step=step,
            release=release,
            invoker=invoker,
            origin=origin,
            created=created,
        )

        patched_step_invocation.additional_properties = d
        return patched_step_invocation

    @property
    def additional_keys(self) -> List[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties


from django.conf import settings
from django.contrib.auth import (
    login as auth_login,
    logout as auth_logout,
    REDIRECT_FIELD_NAME
)
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.shortcuts import redirect, render, resolve_url, reverse
from django.utils.http import is_safe_url
from django.utils.translation import ugettext_lazy as _
from django.views import View

from clublink.cms.forms import LoginForm
from clublink.clubs.models import Club, Department
from clublink.users.models import User

from clublink.cms.views import CMSView

def login(request):
    redirect_to = request.GET.get(REDIRECT_FIELD_NAME, '')

    # Ensure the user-originating redirection URL is safe.
    if not is_safe_url(url=redirect_to, host=request.get_host()):
        redirect_to = resolve_url(reverse('home'))
    form = LoginForm()

    if request.user.is_authenticated:
        if redirect_to == request.path:
            return redirect(resolve_url(settings.LOGIN_REDIRECT_URL))
        return redirect(redirect_to)
    elif request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            auth_login(request, form.get_user())
            return redirect(redirect_to)

    return render(request, 'cms/login.jinja', {'form': form})

def logout(request):
    auth_logout(request)
    return redirect(reverse('home'))

class HomeView(CMSView):
    def get(self, request, *args, **kwargs):
        return render(request, 'cms/dashboard/home.jinja')

class ListView(View):
    title = ''
    queryset = None
    list_fields = None
    per_page = 10
    actions = (
        ('delete_items', _('Delete selected')),
    )

    def get_queryset(self, request):
        return self.queryset

    def delete_items(self, request):
        item_pks = request.POST.get('items', [])
        items = self.get_queryset(request).filter(pk__in=item_pks)
        items.delete()

    def get(self, request):
        per_page = request.GET.get('per_page', self.per_page)
        paginator = Paginator(self.get_queryset(request), per_page)

        page = request.GET.get('page')
        try:
            items = paginator.page(page)
        except PageNotAnInteger:
            items = paginator.page(1)
        except EmptyPage:
            page = paginator.num_pages
            items = paginator.page(page)

        return render(request, 'cms/list.jinja', {
            'items': items, 'list_fields': self.list_fields, 'page': page, 'per_page': per_page,
            'title': self.title})

    def post(self, request):
        action = request.POST.get('action')

        for a in self.actions:
            if a[0] == action:
                fn = getattr(self, a[1])
                if callable(fn):
                    fn(request)

        return self.get(request)

class UserListView(ListView):
    title = _('User Accounts')
    list_fields = (
        ('username', _('Username')),
        ('first_name', _('First Name')),
        ('last_name', _('Last Name')),
        ('membership_number', _('Membership Number')),
    )
    queryset = User.objects.all()

class ClubListView(ListView):
    title = _('Clubs')
    list_fields = (
        ('name', _('Name')),
        ('slug', _('Slug')),
        ('code', _('Club Number')),
    )
    queryset = Club.objects.all()

class DepartmentListView(ListView):
    title = _('Departments')
    list_fields = (
        ('name', _('Name')),
        ('number', _('Department Number')),
        ('hidden', _('Hidden')),
    )
    queryset = Department.objects.all()


import pytest
from rest_framework.test import APIClient
from django.urls import reverse
from website.models import Trip
from website.models.profile import UserDetail
import mock
from rest_framework.response import Response
from website.api.v1.main_page.serializers import TripSerializerRetrieve
from django.shortcuts import get_object_or_404
from website.api.v1.main_page import views

@pytest.fixture
def ApiClient():
    # anonymous user
    client = APIClient()
    return client

@pytest.fixture
def CommonBusiness():
    trip = Trip.objects.create(
        pk = 10,
        appear_in_search=False,
    )
    return trip

@pytest.mark.django_db
class TestTripRetrieve():
    url = reverse(
            'website:main-page:retrieve-trip', kwargs={
            "pk": 10,
            })
    def test_trip_retrieve_response_200(self, ApiClient,CommonBusiness):
        with mock.patch('website.api.v1.main_page.views.TripViewSet.retrieve') as mock_trip_retrieve:
            trip = get_object_or_404(Trip, pk=CommonBusiness.pk, appear_in_search=False)
            serializer = TripSerializerRetrieve(trip)
            mock_trip_retrieve.return_value = Response(serializer.data)

            response = ApiClient.get(self.url)
            assert response.status_code == 200


# generator of knapsack instances

import random

seed = 1
random.seed(seed)

items = 10
instance = dict()
for i in range(items):
    instance[i] = {}
    instance[i]['profit'] = 0
    instance[i]['weight'] = 0

name = "generated_"+str(items)


def MapFunction(data):
    cur_results = []
    words = data.split()
    for word in words:
        cur_results.append((word, 1))
    return cur_results

def ReduceFunction(key, values):
    result = sum(values)
    return (key, result)

def MapReduce(data):
    cur_results = []
    for sentence in data:
        cur_results.extend(MapFunction(sentence))

    FinalResults = []
    key_values = {}
    for key, value in cur_results:
        if key not in key_values:
            key_values[key] = []
        key_values[key].append(value)

    for key, values in key_values.items():
        FinalResults.append(ReduceFunction(key, values))

    return FinalResults

# 测试代码
# data1 = ["reviewing development work produced by third party agencies"," This will give you a deeper opportunity to take your skills and turn them to practical use in assisting real-world clients", "the internship will give the successful candidate the chance for more practical","The internship pays the Glasgow Living Wage","his has an option for hybrid working in our City Centre office in Glasgow"]
# data2 = ["Hello world", "Hello frank", "frank is awesome","Hello jack"]

import threading
import time

class Node(threading.Thread):
    def __init__(self, node_id):
        threading.Thread.__init__(self)
        self.node_id = node_id
        self.tasks = []
        self.busy = False

    def run(self):
        print("Node", self.node_id, "started")
        while True:
            if len(self.tasks) > 0:
                self.busy = True
                task = self.tasks.pop(0)  # get a task
                # print("Node", self.node_id, "processing task:", task)
                results = MapReduce([task])  # process the task
                # print("Node", self.node_id, "results:", results)
                time.sleep(10)  # simulate time-consuming task
                # print("Node", self.node_id, "finished processing task:", task)
                self.busy = False

class TaskScheduler:
    def __init__(self, nodes):
        self.nodes = nodes

    def assign_task(self, tasks):
        # Assign each task to a node
        for task in tasks:
            while True:  # keep trying until the task is assigned
                for node in self.nodes:
                    if not node.busy:  # find an idle node
                        node.tasks.append(task)  # assign the task
                        print("Assigned task:", task, "to node", node.node_id)
                        break
                else:  # if no idle node is found
                    continue  # try again
                break  # if the task is assigned, move on to the next task

data = ["task1 happy join happy", "task2 like hi hi hi hi", "task3 like dede", "task4 hello hi", "task5 hi"]
num_nodes = 2

nodes = [Node(i) for i in range(num_nodes)]
scheduler = TaskScheduler(nodes)

for node in nodes:
    node.start()
scheduler.assign_task(data)

for node in nodes:
    node.join()


import streamlit as st
import pandas as pd
import numpy as np
#import seaborn as sns
#import matplotlib.pyplot as plt
import plotly.express as px
from PIL import Image

# Page layout
st.set_page_config(page_title='Churn Analysis FinTech', page_icon=':bar_chart:', layout='wide')

df = pd.read_csv('fintech_dashboard.csv')
DATA = {
    'df':df
}

PAGES = {
    'Overall Churn Rate': 'overall_churn_rate',
    'Age Groups': 'age_groups',
    'Housing Status': 'housing_status',
    'Payment Types': 'payment_types',
    'Deposits & Withdrawals': 'deposits_withdrawals',
    'Mobile App Usages': 'app_downloaded',
    'Credit Card Application': 'credit_card_application',
    'Customer Satisfaction': 'customer_satisfaction',
    'Rewards Earned': 'rewards_earned'
}

# Set the default page
DEFAULT_PAGE = 'Overall Churn Rate'

# st.dataframe(df)
st.markdown('Explore the overall churn rate and its variation across customer segments.')
st.title('Churn Analysis FinTech')

# Sidebar with clickable links to page
page = st.sidebar.selectbox('Navigate to:', ['Overall Churn Rate', 'Age Groups', 'Housing Status', 'Payment Types',
                                             'Deposits & Withdrawals', 'Mobile App Usages', 'Credit Card Application',
                                             'Customer Satisfaction', 'Rewards Earned', 'Dashboard'])
image = Image.open('churn-rate.png')
st.sidebar.image(image)

# if page != 'Dashboard':
#     # Display dataset
#     st.subheader('Dataset')
#     st.dataframe(df)

# Calculate the overall churn rate
overall_churn_rate = df['churn'].mean()

# Display overall churn rate
# st.subheader('Overall Churn Rate')
# st.write(f'The overall churn rate in the FinTech company is {overall_churn_rate:.2%}')

# Define layout for each page
if page == 'Dashboard':
    st.subheader('Dashboard')
    # Dashboard Visuals
    overall_churn_rate = df['churn'].mean()
    st.write(f'The overall churn rate is: {overall_churn_rate:.2%}')

    age_group_churn_rate = df.groupby('age')['churn'].mean().reset_index()
    fig_age = px.bar(age_group_churn_rate, x='age', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate Across Age Groups')
    st.plotly_chart(fig_age)

    housing_churn_rate = df.groupby('housing')['churn'].mean().reset_index()
    fig_housing = px.bar(housing_churn_rate, x='housing', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate Based on Housing Status')
    st.plotly_chart(fig_housing)

    payment_churn_rate = df.groupby('payment_type')['churn'].mean().reset_index()
    fig_payment = px.bar(payment_churn_rate, x='payment_type', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate for Different Payment Types')
    st.plotly_chart(fig_payment)

    avg_deposits = df.groupby('churn')['deposits'].mean()
    avg_withdrawals = df.groupby('churn')['withdrawal'].mean()
    data = pd.DataFrame({'Churn': avg_deposits.index, 'Avg Deposits': avg_deposits.values, 'Avg Withdrawals': avg_withdrawals.values})
    fig_deposits_withdrawals = px.bar(data, x='Churn', y=['Avg Deposits', 'Avg Withdrawals'],
                                     labels={'value': 'Amount', 'variable': 'Transaction Type'},
                                     title='Average Deposits and Withdrawals for Churned vs. Non-Churned Customers')
    st.plotly_chart(fig_deposits_withdrawals)

    app_downloads_churn = df.groupby('churn')['app_downloaded'].value_counts(normalize=True).unstack().reset_index()
    app_downloads_churn = pd.melt(app_downloads_churn, id_vars='churn', value_vars=[0, 1],
                                  value_name='Percentage', var_name='App Downloaded')
    fig_app_downloads = px.bar(app_downloads_churn, x='churn', y='Percentage', color='App Downloaded',
                               labels={'churn': 'Churn Status', 'Percentage': 'Percentage'},
                               title='App Downloads and Churn Rate')
    st.plotly_chart(fig_app_downloads)

    credit_card_app_status = df.groupby('churn')['cc_application_begin'].value_counts(normalize=True).unstack().reset_index()
    credit_card_app_status = pd.melt(credit_card_app_status, id_vars='churn', value_vars=[0, 1],
                                     value_name='Percentage', var_name='Application Status')
    fig_credit_card_app = px.bar(credit_card_app_status, x='churn', y='Percentage', color='Application Status',
                                 labels={'churn': 'Churn Status', 'Percentage': 'Percentage'},
                                 title='Credit Card Application Status and Churn Rate')
    st.plotly_chart(fig_credit_card_app)

    fig_customer_satisfaction = px.box(df, x='churn', y=['cc_liked', 'cc_disliked'],
                                       labels={'churn': 'Churn Status', 'value': 'Satisfaction Score'},
                                       title='Customer Satisfaction: Likes and Dislikes')
    st.plotly_chart(fig_customer_satisfaction)

    fig_rewards_earned = px.histogram(df, x='rewards_earned', color='churn', barmode='overlay',
                                      labels={'churn': 'Churn Status', 'rewards_earned': 'Rewards Earned'},
                                      title='Rewards Earned Distribution')
    st.plotly_chart(fig_rewards_earned)

if page == 'Overall Churn Rate':
    st.subheader('Overall Churn Rate')
    # Calculate overall churn rate
    overall_churn_rate = df['churn'].mean()
    st.write(f'The overall churn rate in the FinTech company is: {overall_churn_rate:.2%}')

     # Create a pie chart for the overall churn rate
    churn_count = df['churn'].value_counts()
    fig = px.pie(
        churn_count,
        names=churn_count.index,
        values=churn_count.values,
        labels=['Not Churned', 'Churned'],
        title='Churn Distribution'
    )
    st.plotly_chart(fig)
    st.dataframe(df)
elif page == 'Age Groups':
        # Bar plot showing churn rate across age groups
        age_group_churn_rate = df.groupby('age')['churn'].mean().reset_index()
        fig_age = px.bar(age_group_churn_rate, x='age', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate Across Age Groups')
        # Display visualization and dataset below it
        st.plotly_chart(fig_age)

# Page 3: Housing Status
elif page == 'Housing Status':
        # Bar plot showing churn rate based on housing status
        housing_churn_rate = df.groupby('housing')['churn'].mean().reset_index()
        fig_housing = px.bar(housing_churn_rate, x='housing', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate Based on Housing Status')
        st.plotly_chart(fig_housing)

# Page 4: Payment Types
elif page == 'Payment Types':
        # Bar plot showing churn rate for different payment types
        payment_churn_rate = df.groupby('payment_type')['churn'].mean().reset_index()
        fig_payment = px.bar(payment_churn_rate, x='payment_type', y='churn', labels={'churn': 'Churn Rate'}, title='Churn Rate for Different Payment Types')
        st.plotly_chart(fig_payment)

# Page 5: Deposits & Withdrawals
elif page == 'Deposits & Withdrawals':
        st.subheader('Deposits and Withdrawals Analysis')

        # Visualization related to deposits and withdrawals (customize according to your specific question)
        # Example: Bar plot showing average deposits and withdrawals for churned vs. non-churned customers
        avg_deposits = df.groupby('churn')['deposits'].mean()
        avg_withdrawals = df.groupby('churn')['withdrawal'].mean()
        data = pd.DataFrame({'Churn': avg_deposits.index, 'Avg Deposits': avg_deposits.values, 'Avg Withdrawals': avg_withdrawals.values})
        fig_deposits_withdrawals = px.bar(data, x='Churn', y=['Avg Deposits', 'Avg Withdrawals'],
                                        labels={'value': 'Amount', 'variable': 'Transaction Type'},
                                        title='Average Deposits and Withdrawals for Churned vs. Non-Churned Customers')
        st.plotly_chart(fig_deposits_withdrawals)

# Page 6: Mobile Apps Usage
elif page == 'Mobile App Usages':
        st.subheader('Mobile App Usages Analysis')

        app_downloads_churn = df.groupby('churn')['app_downloaded'].value_counts(normalize=True).unstack().reset_index()
        app_downloads_churn = pd.melt(app_downloads_churn, id_vars='churn', value_vars=[0, 1],
                                  value_name='Percentage', var_name='App Downloaded')
        fig_grouped_bar = px.bar(app_downloads_churn, x='churn', y='Percentage', color='App Downloaded',
                             labels={'churn': 'Churn Status', 'Percentage': 'Percentage'},
                             title='App Downloads and Churn Rate', barmode='group')
        st.plotly_chart(fig_grouped_bar)

# Page 7: Credit Card Application
elif page == 'Credit Card Application':
        st.subheader('Credit Card Application Analysis')
        credit_card_app_status = df.groupby('churn')['cc_application_begin'].value_counts(normalize=True).unstack().reset_index()
        credit_card_app_status = pd.melt(credit_card_app_status, id_vars='churn', value_vars=[0, 1],
                                        value_name='Percentage', var_name='Application Status')
        fig_credit_card_app = px.bar(credit_card_app_status, x='churn', y='Percentage', color='Application Status',
                                    labels={'churn': 'Churn Status', 'Percentage': 'Percentage'},
                                    title='Credit Card Application Status and Churn Rate')
        st.plotly_chart(fig_credit_card_app)

# Page 8: Customer Satisfaction
elif page == 'Customer Satisfaction':
        st.subheader("Customer's Overall Experience")
        # Stacked bar plot showing counts of likes and dislikes for each churn status
        customer_satisfaction_counts = df.groupby(['churn', 'cc_liked', 'cc_disliked']).size().reset_index(name='Count')
        color_discrete_map = {'0': 'lightgrey', '1': 'red'}
        fig_customer_satisfaction = px.bar(customer_satisfaction_counts, x='churn', y='Count', color='cc_liked',
                                       labels={'churn': 'Churn Status', 'Count': 'Count'},
                                       title="Customer Satisfaction: Likes and Dislikes",
                                       barmode='stack')
        st.plotly_chart(fig_customer_satisfaction)

# Page 9: Rewards Earned
elif page == 'Rewards Earned':
        st.subheader('Reward Points earned by Customers who left the bank.')
        fig_rewards_earned = px.histogram(df, x='rewards_earned', color='churn', barmode='overlay',
                                        labels={'churn': 'Churn Status', 'rewards_earned': 'Rewards Earned'},
                                        title='Rewards Earned Distribution')
        st.plotly_chart(fig_rewards_earned)


import pandas as pd
import nltk
import numpy as np

def init_df(buffer, events):
    df = pd.DataFrame()
    df["text_buffer"] = buffer
    df["events"] = events
    return df

def extract_sent(df):
    sentence_buffer = []
    num_sentences = []

    for text in df["text_buffer"]:
        sentences = nltk.tokenize.sent_tokenize(text)
        sentence_buffer.append(sentences)
        num_sentences.append(len(sentences))

    df["sentences"] = sentence_buffer
    df["num_sentences"] = num_sentences

    return df

def extract_event_name(df):
    df["event_name"] = df["events"].apply(lambda x: x["eventName"])
    return df

def correct_sent_num(df):
    df = df.groupby("num_sentences", group_keys=True).apply(lambda x: x)
    df = df.sort_index()

    num_sentences = np.array(df["num_sentences"])
    event_names = np.array(df["event_name"])

    start_idx = 0
    select_flag = False

    for idx, event in enumerate(event_names):
        if event == "suggestion-get":
            start_idx = idx
        if event == "suggestion-select":
            select_flag = True
        if select_flag and event == "text-insert":
            if num_sentences[start_idx] == num_sentences[idx]:
                end_idx = idx + 1
            elif num_sentences[start_idx] < num_sentences[idx]:
                end_idx = idx
            for i in range(start_idx, end_idx):
                num_sentences[i] += 1
            select_flag = False

    df["num_sentences"] = num_sentences

    return df

def compute_seq(events):

    # Remove suggestion-open, suggestion-hover, suggestion-down suggestion-up
    events = np.delete(events, np.where(events == "suggestion-open"))
    events = np.delete(events, np.where(events == "suggestion-hover"))
    events = np.delete(events, np.where(events == "suggestion-down"))
    events = np.delete(events, np.where(events == "suggestion-up"))

    # Remove suggestion-reopen (for now; unsure of its impact)
    events = np.delete(events, np.where(events == "suggestion-reopen"))

    # Remove text-insert after suggestion-select
    select_flag = False
    new_events = []
    for idx, event in enumerate(events):
        if event == "suggestion-select":
            select_flag = True
        if event == "text-insert" and select_flag:
            select_flag = False
            continue
        new_events.append(event)
    events = np.array(new_events)

    # Identify GPT-3 modifications
    select_flag = False
    new_events = []
    for idx, event in enumerate(events):
        if event == "suggestion-select":
            select_flag = True
        if event == "text-insert":
            select_flag = False
        if (event == "cursor-backward" or event == "cursor-select" or event == "text-delete") and select_flag:
            select_flag = False
            event = "gpt3-modify"
        new_events.append(event)
    events = np.array(new_events)

    # Remove cursor-forward, cursor-backward, cursor-select
    events = np.delete(events, np.where(events == "cursor-forward"))
    events = np.delete(events, np.where(events == "cursor-backward"))
    events = np.delete(events, np.where(events == "cursor-select"))

    # Remove text-delete
    events = np.delete(events, np.where(events == "text-delete"))

    # Remove suggestion-close
    events = np.delete(events, np.where(events == "suggestion-close"))

    # Identify GTP-3 calls
    events = events.tolist()
    start_idx = 0
    api_flag = False
    pop_idx = []
    for idx, event in enumerate(events):
        if event == "suggestion-get":
            start_idx = idx
            api_flag = True
        if event == "suggestion-select" and api_flag:
            api_flag = False
            for i in range(start_idx, idx):
                pop_idx.append(i)
    events = np.array(events)
    events = np.delete(events, pop_idx)

    # Group together text-inserts
    new_events = []
    temp = []
    for event in events:
        if event == "text-insert":
            temp.append(event)
        else:
            if len(temp) != 0:
                new_events.append("text-insert")
            new_events.append(event)
            temp = []
    if len(temp) != 0:
        new_events.append("text-insert")
    events = np.array(new_events)

    # Rename sequences
    seq_name_dict = {
        "system-initialize": "prompt",
        "text-insert": "user",
        "suggestion-get": "empty-call",
        "suggestion-select": "gpt3-call",
        "gpt3-modify": "modify-gpt3",
    }
    new_events = [seq_name_dict[event] for event in events]
    events = np.array(new_events)

    return events

def get_sent_num_and_event_seq(df):

    temp_dict = {
        "num_sent": [],
        "sequence": [],
    }

    for num in np.unique(df["num_sentences"]):
        # sent = np.array(df[df["num_sentences"] == num]["text_buffer"])[-1]
        event_seq = np.array(df[df["num_sentences"] == num]["event_name"])
        temp_dict["num_sent"].append(num)
        temp_dict["sequence"].append(compute_seq(event_seq))

    # Bug fix for prompt deletion
    if temp_dict["num_sent"][0] == 0:
        for idx in range(len(temp_dict["sequence"])):
            if "prompt" in temp_dict["sequence"][idx]:
                temp_arr = temp_dict["sequence"][idx]
                temp_dict["sequence"][idx] = np.delete(temp_arr, np.where(temp_arr == "prompt"))

    return temp_dict

def generate_event_seq(buffer, events):

    df = init_df(buffer, events)
    df = extract_sent(df)
    df = extract_event_name(df)
    df = correct_sent_num(df)

    readable_sent_seq = get_sent_num_and_event_seq(df)

    return readable_sent_seq


from direct.gui.OnscreenImage import OnscreenImage
from pandac.PandaModules import TransparencyAttrib, VBase3
from direct.showbase.DirectObject import DirectObject
from direct.gui.DirectGui import DirectButton, DGG
from direct.interval.IntervalGlobal import Sequence, LerpHprInterval

from gui.Popup import Popup
from gui.AlertPopup import AlertPopup
from gui.FullscreenPopup import FullscreenPopup
from event.ClientEvent import ServerJoinResponseEvent
import Settings
import SettingsController
import Globals

"""
egg-texture-cards -o Button_Offline.egg -p 500,75 offline.png offline_over.png
egg-texture-cards -o Button_Multiplayer.egg -p 500,75 multiplayer.png multiplayer_over.png
egg-texture-cards -o Button_Options.egg -p 500,75 options.png options_over.png
egg-texture-cards -o Button_Exit.egg -p 500,75 exit.png exit_over.png

"""

class MainMenu(DirectObject):

    def __init__(self):
        self.node = aspect2d.attachNewNode('MainMenu')
        self.buttons = []
        self.LoadContent()
        self.SetupEventHandlers()

    def SetupEventHandlers(self):
        self.accept(ServerJoinResponseEvent.EventName, self.OnServerJoinResponseEvent)

    def LoadContent(self):
        bg = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/background.png', scale = (2, 1, 1))
        bg.setTransparency(TransparencyAttrib.MAlpha)
        bg.reparentTo(self.node)
        bg.setBin('fixed', 1)

        title = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/title.png')
        title.setTransparency(TransparencyAttrib.MAlpha)
        title.reparentTo(self.node)

        self.spinner = OnscreenImage(image = 'Assets/Images/Menus/MainMenu/loadingSpinner.png', pos = (-0.15, 1, 0.15), scale = 128.0/1024.0)
        self.spinner.setTransparency(TransparencyAttrib.MAlpha)
        self.spinner.reparentTo(base.a2dBottomRight)
        self.spinner.setBin('gui-popup', 0)
        self.spinner.hide()

        self.LoadButton('Button_Offline', 'offline', 'offline_over', 0, 0.2, self.OnButtonClicked, ['offline'])
        self.LoadButton('Button_Multiplayer', 'multiplayer', 'multiplayer_over', 0, 0, self.OnButtonClicked, ['multiplayer'])
        self.LoadButton('Button_Options', 'options', 'options_over', 0, -0.2, self.OnButtonClicked, ['options'])
        self.LoadButton('Button_Exit', 'exit', 'exit_over', 0, -0.4, self.OnButtonClicked, ['exit'])

    def LoadButton(self, egg, up, over, x, y, cmd, args):
        maps = loader.loadModel("Assets/Images/Menus/MainMenu/%s" % (egg))
        b = DirectButton(geom = (maps.find('**/%s' % (up)),
                         maps.find('**/%s' % (over)),
                         maps.find('**/%s' % (over)),
                         maps.find('**/%s' % (up))),
                         command = cmd,
                         extraArgs = args,
                         pressEffect = 0,
                         relief = None,
                         rolloverSound = None,
                         clickSound = None,
                         pos = (x, 1, y),
                         scale = (1, 1, 75.0/500.0))
        b.reparentTo(self.node)
        self.buttons.append(b)

    def OnButtonClicked(self, buttonText):
        if(buttonText == 'multiplayer'):
            Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/multiplayer.rml').Show()
            self.DisableButtons()
            self.acceptOnce('multiplayerPopupClose', self.OnMultiplayerClose)

        elif(buttonText == 'options'):
            Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/options.rml').Show()
            self.DisableButtons()
            self.acceptOnce('optionsPopupClose', self.OnOptionsClose)

        elif(buttonText == 'exit'):
            self.CreateAlertPopup('Exit Game', 'Do you really want to exit?', self.OnExitPopupOkay, self.OnExitPopupCancel)

        elif(buttonText == 'offline'):
            Globals.ROCKET_CONTEXT.LoadDocument('Assets/libRocket/offline.rml').Show()
            self.DisableButtons()
            self.acceptOnce('offlinePopupClose', self.OnOfflineClose)

    def CreatePopup(self, title, fields, values, onOkay, onCancel):
        p = Popup(title, fields, values, onOkay, onCancel)
        self.OnPopupCreated(p)

    def CreateAlertPopup(self, title, text, onOkay, onCancel):
        p = AlertPopup(title, text, onOkay, onCancel)
        self.OnPopupCreated(p)

    def CreateFullScreenPopup(self, title, fields, values, onOkay, onCancel):
        p = FullscreenPopup(title, fields, values, onOkay, onCancel)
        self.OnPopupCreated(p)

    def OnOfflineClose(self, accept):
        if(accept):
            SettingsController.SaveClientSettings()
            taskMgr.doMethodLater(0.1, messenger.send, 'as', ['startOffline'])
        self.EnableButtons()

    def OnOptionsClose(self, accept):
        if(accept):
            SettingsController.SaveClientSettings()
        self.EnableButtons()

    def OnMultiplayerClose(self, accept):
        if(accept):
            SettingsController.SaveClientSettings()
            self.StartLoadingSpinner()
            self.DisableButtons()
            taskMgr.doMethodLater(0.1, messenger.send, 'as1', ['mainMenuMulti'])
        else:
            self.EnableButtons()

    def DisableButtons(self):
        for b in self.buttons:
            b['state'] = DGG.DISABLED

    def EnableButtons(self):
        for b in self.buttons:
            b['state'] = DGG.NORMAL

    def OnAlertPopupClose(self, popup):
        self.DestroyPopup(popup)

    def OnExitPopupOkay(self, popup):
        self.DestroyPopup(popup)
        messenger.send('mainMenuExit')

    def OnExitPopupCancel(self, popup):
        self.DestroyPopup(popup)

    def OnPopupCreated(self, popup):
        self.DisableButtons()

    def DestroyPopup(self, popup):
        popup.Destroy()
        del popup

        self.EnableButtons()

    def Hide(self):
        self.node.hide()

    def Show(self):
        self.node.show()

    def StartLoadingSpinner(self):
        self.spinner.show()
        self.spinSequence = Sequence(LerpHprInterval(self.spinner, 2, VBase3(0, 0, 180), VBase3(0, 0, 0)),
                                     LerpHprInterval(self.spinner, 2, VBase3(0, 0, 360), VBase3(0, 0, 180)))
        self.spinSequence.loop()

    def StopLoadingSpinner(self):
        self.spinSequence.finish()
        self.spinner.hide()

    def OnServerJoinResponseEvent(self, event):
        self.StopLoadingSpinner()
        self.EnableButtons()
        if(not event.GetResponse()):
            p = AlertPopup('Join Game Failed', event.GetReason(), self.ClosePopup, self.ClosePopup)
            self.OnPopupCreated(p)

    def ClosePopup(self, popup):
        self.DestroyPopup(popup)


import pandas as pd
import numpy as np
import pdfplumber
import re
import zipfile
import os

def unzipper(zip):
    """
    unzips zipfile and stores content in tempfolder on same level directory.
    returns list of directories of pdf files in temp folder.
    ______
    takes in the zipfile.
    """
    path = 'data'
    with zipfile.ZipFile(zip, 'r') as zip_ref:
        zip_ref.extractall(path)

    files = os.listdir(path)
    dirs = [os.path.join(path, file) for file in files if file.endswith('.pdf') or file.endswith('.PDF')]

    return dirs

def pdf_parser(files):
    """
    Returns a df filled with buy and sell information of the input PDF files.
    ________
    Takes in files, a list of directories or bytes files (pdfplumber).
    """
    print('pdf_parser was called.')

    df = pd.DataFrame()
    for file in files:
        with pdfplumber.open(file) as pdf:
            pages = [page.extract_text() for page in pdf.pages]

        match = [p.start() for p in re.finditer('Nominale', pages[0])]
        trans = pages[0][match[0]:].split('\n')
        action = re.findall('Wertpapier Abrechnung (\w+)', pages[0])

        if action:
            # if 'Abrechnung' was found
            val = re.findall(r'Stück (\d+)', trans[1])[0]
            wkn = trans[1].replace(')', '').split('(')[1]
            date = re.findall(r'Datum (\d+.\d+.\d+)', pages[0])[0]

            # assemble df
            data = [val, wkn, date]
            columns = [action[0], 'WKN', 'Datum']

            # scan 2nd page
            if action[0] == 'Verkauf':
                buy = [p.start() for p in re.finditer('Ber\wcksichtigte Anschaffungsgesch\wfte', pages[1])][0]
    #             columns2 = columns + pages[1][buy:].split('\n')[1].split()
                columns2 = columns + ['Geschäft',
                                      'Auftragsnr.',
                                      'Ausführ.-tag',
                                      'Whr./St.',
                                      'Nennwert/Stück',
                                      'AS-Kosten',
                                      'Erlös', 'ant.Ergebnis',
                                      'Land']
                data2 = data + pages[1][buy:].split('\n')[2].split()
                try:
                    new_df = pd.DataFrame([data2], columns=columns2)
                except:
                    new_df = (pd.DataFrame([data], columns=columns))
                    print(f"couldn't process 2nd page of file: {file}")

            else:
                rate = re.findall(r'Ausf\whrungskurs(\d+,\d+)', pages[0])[0]
                data.append(rate)
                columns.append('Kurs')
                new_df = pd.DataFrame([data], columns=columns)

            df = pd.concat([df, new_df])

    return df


import bpy
from bpy.props import StringProperty, BoolProperty
from ... utils.collection import get_groups_collection, get_scene_collections

class CreateCollection(bpy.types.Operator):
    bl_idname = "machin3.create_collection"
    bl_label = "MACHIN3: Create Collection"
    bl_description = "description"
    bl_options = {'REGISTER', 'UNDO'}

    def update_name(self, context):
        name = self.name.strip()
        col = bpy.data.collections.get(name)

        if col:
            self.isduplicate = True
        else:
            self.isduplicate = False

    name: StringProperty("Collection Name", default="", update=update_name)

    isduplicate: BoolProperty("is duplicate name")

    def draw(self, context):
        layout = self.layout

        column = layout.column()

        column.prop(self, "name", text="Name")
        if self.isduplicate:
            column.label(text="Collection '%s' exists already" % (self.name.strip()), icon='ERROR')

    def invoke(self, context, event):
        wm = context.window_manager

        return wm.invoke_props_dialog(self, width=300)

    def execute(self, context):
        name = self.name.strip()

        col = bpy.data.collections.new(name=name)

        acol = context.view_layer.active_layer_collection.collection
        acol.children.link(col)

        self.name = ''

        return {'FINISHED'}

class RemoveFromCollection(bpy.types.Operator):
    bl_idname = "machin3.remove_from_collection"
    bl_label = "MACHIN3: Remove from Collection"
    bl_description = "Remove Selection from a Collection"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        view = context.space_data
        return view.type == 'VIEW_3D' and context.selected_objects

    def execute(self, context):

        if context.active_object not in context.selected_objects:
            context.view_layer.objects.active = context.selected_objects[0]

        bpy.ops.collection.objects_remove('INVOKE_DEFAULT')

        return {'FINISHED'}

class AddToCollection(bpy.types.Operator):
    bl_idname = "machin3.add_to_collection"
    bl_label = "MACHIN3: Add to Collection"
    bl_description = "Add Selection to a Collection"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        view = context.space_data

        if view.type == 'VIEW_3D' and context.selected_objects:

            if view.local_view:
                for area in context.screen.areas:
                    if area.type == 'OUTLINER':
                        return True
            else:
                return True

    def execute(self, context):
        view = context.space_data

        if view.local_view:
            for area in context.screen.areas:
                if area.type == 'OUTLINER':
                    override = {'area': area}
                    break

            bpy.ops.object.link_to_collection(override, 'INVOKE_DEFAULT')

        else:
            bpy.ops.object.link_to_collection('INVOKE_DEFAULT')

        return {'FINISHED'}

class MoveToCollection(bpy.types.Operator):
    bl_idname = "machin3.move_to_collection"
    bl_label = "MACHIN3: Move to Collection"
    bl_description = "Move Selection to a Collection"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        view = context.space_data

        if view.type == 'VIEW_3D' and context.selected_objects:

            if view.local_view:
                for area in context.screen.areas:
                    if area.type == 'OUTLINER':
                        return True
            else:
                return True

    def execute(self, context):
        view = context.space_data

        if view.local_view:
            for area in context.screen.areas:
                if area.type == 'OUTLINER':
                    override = {'area': area}
                    break

            bpy.ops.object.move_to_collection(override, 'INVOKE_DEFAULT')

        else:
            bpy.ops.object.move_to_collection('INVOKE_DEFAULT')

        return {'FINISHED'}

class Purge(bpy.types.Operator):
    bl_idname = "machin3.purge_collections"
    bl_label = "MACHIN3: Purge Collections"
    bl_description = "Remove empty Collections"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        for col in get_scene_collections(context.scene):
            if not any([col.children, col.objects]):
                print("Removing collection '%s'." % (col.name))
                bpy.data.collections.remove(col, do_unlink=True)

        return {'FINISHED'}

class Select(bpy.types.Operator):
    bl_idname = "machin3.select_collection"
    bl_label = "MACHIN3: (De)Select Collection"
    bl_description = "Select Collection Objects\nSHIFT: Select all Collection Objects\nALT: Deselect Collection Objects\nSHIFT+ALT: Deselect all Collection Objects\nCTRL: Toggle Viewport Selection of Collection Objects"
    bl_options = {'REGISTER'}

    name: StringProperty()
    force_all: BoolProperty()

    def invoke(self, context, event):
        col = bpy.data.collections.get(self.name, context.scene.collection)

        objects = col.all_objects if event.shift or self.force_all else col.objects

        if objects:
            hideselect = objects[0].hide_select

            if col:
                for obj in objects:
                    if event.alt:
                        obj.select_set(False)

                    elif event.ctrl:
                        if obj.name in col.objects:
                            obj.hide_select = not hideselect

                    else:
                        obj.select_set(True)

        self.force_all = False
        return {'FINISHED'}


import numpy as np
import agent as a

class AgentPool(object):
    def __init__(self, min_agent_count, objects):
        """ init
        min_agent_count: mininum number of agents for the pool
        objects: a list of the scenario's objects
        """
        self._min_agent_count = min_agent_count
        self._objects = objects
        self._pool = []

        while self.get_agent_count() < self._min_agent_count:
            self.add_agent()

    def add_agent(self):
        entity_id = np.random.randint(len(self._objects))
        if np.random.randint(100) < 50:
            self._pool.append(a.DetectorAgent(entity_id))
        else:
            self._pool.append(a.SituationAgent(entity_id))

    def get_agent(self):
        self.add_agent()
        return self._pool.pop(0)

    def get_agent_count(self):
        return len(self._pool)


# Define constants.
MAX_STARS = 40
MIN_STARS = 5

def main():

    # Read the data values from the user.
    values = []
    input_str = input("Enter a value (blank to quit): ")
    while input_str != "":
        values.append(float(input_str))
        input_str = input("Enter a value (blank to quit): ")

    # Identify the largest value, smallest value, and spread.
    largest = max(values)
    smallest = min(values)
    spread = largest - smallest

    # Display the bars.
    for i in range(0, len(values)):
        print("*" * (MIN_STARS + round((values[i] - smallest) / spread * (MAX_STARS - MIN_STARS))))

if __name__ == "__main__":

    main()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def rightSideView(self, root: TreeNode) -> list:
        if not root: return []
        queue = [[],[]]
        ans = []
        queue[0].append(root)

        while queue[0]:
            node = queue[0].pop(0)

            if node.left:
                queue[1].append(node.left)
            if node.right:
                queue[1].append(node.right)

            if not queue[0]:
                ans.append(node.val)
                queue[0],queue[1] = queue[1],queue[0]

        return ans

Medium/199. Binary Tree Right Side View.py


# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a cointegration script file.
"""

import numpy as np
import pandas as pd
import tushare as ts
import matplotlib.pyplot as plt
import statsmodels.api as sm

def find_cointegration_pairs(dataframe):
    # to obtain the length of dataframe
    n = dataframe.shape[1]
    # initialize the matrix of p-value
    pvalue_matrix = np.ones((n, n))
    # to obtain column name
    keys = dataframe.keys()
    # initialize the array of cointegration
    pairs = []
    for i in range(n):
        for j in range(i + 1, n):
            stock1 = dataframe[keys[i]]
            stock2 = dataframe[keys[j]]
            result = sm.tsa.stattools.coint(stock1, stock2)
            pvalue = result[1]
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.05:
                pairs.append((keys[i], keys[j], pvalue))
    return pvalue_matrix, pairs

stock = pd.DataFrame()
stock_list = ['601169', '600036']
df = ts.get_k_data(stock_list[0])[['date', 'close']].set_index('date')
df.columns = [stock_list[0]]

for z in stock_list[1:]:
    ds = ts.get_k_data(z)[['date', 'close']].set_index('date')
    ds.columns = [z]
    df = df.merge(ds, right_index=True, left_index=True)

# obtain matrix, pair
pvalues, stock_pairs = find_cointegration_pairs(df)

stock_601169 = df['601169']
stock_600036 = df['600036']
stock_601169.plot()
stock_600036.plot()
plt.xlabel('Time')
plt.ylabel('Price')
plt.legend(['601169', '600036'])


from pathlib import Path
import numpy as np
import re
from bisect import bisect_left
from copy import deepcopy
from itertools import compress
reg = re.compile(r"(y|x)=(\d+), (y|x)=(\d+)\.\.(\d+)")

def main():
    data_folder = Path(".").resolve()
    data = data_folder.joinpath("input.txt").read_text()

    res = Reservoir(data)
    res.flow()
    res.print_ground()
    print(f"The water can reach {res.count_water()} tiles")
    print(f"There are {res.count_rest_water()} tiles left after the spring stops.")

class Reservoir():

    def __init__(self,data):
        data = data.split("\n")

        ax = {'x':1,'y':0}
        sep = '..'
        for i,line in enumerate(data):
            m = reg.match(line).group(1,2,3,4,5)
            data[i] = [[],[]]
            data[i][ax[m[0]]] = [int(m[1])]
            data[i][ax[m[2]]] = [int(m[3]),int(m[4])]

        self.lims = [[0,0],[500,500]]
        self.lowest_y = None
        for line in data:
            for j,dim in enumerate(line):
                for point in dim:
                    if point > self.lims[j][1]:
                        self.lims[j][1] = point

                    if point < self.lims[j][0]:
                        self.lims[j][0] = point

                    if (j == 0) and ((self.lowest_y is None) or (point < self.lowest_y)) :
                            self.lowest_y = point

        self.lims[1][0] -= 1
        self.lims[1][1] += 1

        self.size = (self.lims[0][1]+1,self.lims[1][1]-self.lims[1][0]+1)

        self.ground = np.full(self.size,ord('.'),dtype=int)
        for line in data:
            if len(line[1]) == 2:
                self.ground[line[0][0],(line[1][0]-self.lims[1][0]):(line[1][1]+1-self.lims[1][0])] = ord('#')
            else:
                self.ground[line[0][0]:(line[0][1]+1),line[1][0]-self.lims[1][0]] = ord('#')

        self.spring = (0,500-self.lims[1][0])
        self.ground[self.spring[0],self.spring[1]] = ord('+')
        self.flowing = [self.spring]

    def print_ground(self):
        s = ""
        col_size = self.lims[1][1]
        col_digits = len(str(col_size))
        row_size = self.lims[0][1]
        row_digits = len(str(row_size))

        form_str = "{:" + str(col_digits) + "d}"
        for j in range(col_digits):
            s += " "*row_digits
            for loc in range(self.lims[1][0],self.lims[1][1]+1):
                loc_str = form_str.format(loc)
                s += loc_str[j]
            s += "\n"

        form_str = "{:" + str(row_digits) + "d}"
        for y in range(row_size+1):
            s += form_str.format(y)
            for k in self.ground[y]:
                s += chr(k)
            s += "\n"
        data_folder = Path(".").resolve()
        data_folder.joinpath("output.txt").write_text(s)

    def flow_step(self):
        active = [True]*len(self.flowing)
        active_len = len(active)
        for j,tile in enumerate(self.flowing):
            if active[j]:
                below = (tile[0]+1,tile[1])
                left = (tile[0],tile[1]-1)
                right = (tile[0],tile[1]+1)
                if below[0] >= self.size[0]:
                    active[j] = False
                elif self.ground[below] == ord('.'):
                    self.ground[below] = ord('|')
                    self.flowing.append(below)
                    active.append(True)
                elif self.ground[below] in [ord('~'),ord('#')]:
                    i_l = 1
                    left_below = (tile[0]+1,tile[1]-i_l)
                    while (self.ground[left] in [ord('.'),ord('|')]) and (self.ground[left_below] in [ord('~'),ord('#')]):
                        i_l += 1
                        left = (tile[0],tile[1]-i_l)
                        left_below = (tile[0]+1,tile[1]-i_l)

                    i_r = 1
                    right_below = (tile[0]+1,tile[1]+i_r)
                    while (self.ground[right] in [ord('.'),ord('|')]) and (self.ground[right_below] in [ord('~'),ord('#')]):
                        i_r += 1
                        right = (tile[0],tile[1]+i_r)
                        right_below = (tile[0]+1,tile[1]+i_r)

                    if (self.ground[right] == ord('#')) and (self.ground[left] == ord('#')):
                        self.ground[tile[0],(left[1]+1):right[1]] = ord('~')
                        for k,_ in enumerate(active):
                            if (self.flowing[k][0] == tile[0]) and (left[1] < self.flowing[k][1] < right[1]):
                                active[k] = False
                    else:
                        closed_left = int(self.ground[left] not in [ord('.'),ord('|')])
                        open_right = int(self.ground[right] in [ord('.'),ord('|')])
                        self.ground[tile[0],(left[1]+closed_left):(right[1]+open_right)] = ord('|')
                        if not closed_left:
                            self.flowing.append(left)
                            active.append(True)
                        if open_right:
                            self.flowing.append(right)
                            active.append(True)
                        active[j] = False

        self.flowing = list(compress(self.flowing,active))

        return (len(active) != active_len) or (sum(active) != active_len)

    def flow(self):
        while self.flow_step():
            pass

    def count_water(self):
        return np.sum(np.isin(self.ground[self.lowest_y:],[ord('|'),ord('~')]))

    def count_rest_water(self):
        return np.sum(self.ground[self.lowest_y:] == ord('~'))

if __name__ == "__main__":
    main()


import cv2
import numpy as np
import glob
import re

img_array = []
files = sorted(glob.glob('C:\\Users\\Rodrigo\\Documents\\GitHub\\computerVision\\images\\output\\brighter\\*.png'))
files = sorted(files, key=lambda x:float(re.findall("(\d+)",x)[0]))
outputPath = 'C:\\Users\\Rodrigo\\Documents\\GitHub\\computerVision\\images\\output\\videos\\'

for filename in files:
    print(filename)
    img = cv2.imread(filename)
    height, width, layers = img.shape
    size = (width,height)
    img_array.append(img)

out = cv2.VideoWriter('project.avi',cv2.VideoWriter_fourcc(*'DIVX'), 60, size)

for i in range(len(img_array)):
    out.write(img_array[i])
out.release()


import os
from dotenv import load_dotenv
from dataclasses import dataclass, asdict
import os
import openai
from metaphor_python import Metaphor
import html2text
from gtts import gTTS, lang

# set up environment
load_dotenv()

# Class represents information about the articles collected (title, author, published date, content, url)
@dataclass
class Article:
    title: str
    author: str
    published_date: str
    content: str
    summary : str
    url: str

    # Represents instance as dictionary
    def dict(self) -> dict:
        return asdict(self)

# Class represents the text to speech service (find articles, translation, SSML conversion, audio generation)
class Audicle:

    # Message codes used
    generate_query_message = "You are a helpful assistant that generates search queries based on user questions. Only generate one search query. The query should help find articles related to the users query. If the user uses abbreviations, expand these to full phrases. If the user inputs something you don’t understand, look for the articles closest to their search."
    summarize_text_message = "You are a helpful assistant that summarizes the content of a webpage. Summarize the user's input. Only output the summary."
    text_to_ssml_message = "You are a helpful assistant that converts extracted HTML text to SSML using Google Cloud's SSML reference. Convert the user's input while retaining the semantic meaning. Only output the SSML text."
    clean_message = "You are a helpful assistant that makes sure that sentences make sense logically and grammatically based on user input. Make sure the sentence flows correctly and is grammatically correct. Wherever it says null, ignore these fields and continue."

    # Supported language conversions
    supported_lang =  {k: v.lower() for k, v in lang.tts_langs().items()}

    def __init__(self):

        self.openai_key = os.getenv('OPENAI_API_KEY')
        openai.api_key = self.openai_key
        self.metaphor = Metaphor(os.getenv('METAPHOR_API_KEY'))

    def main(self) -> None:

        # Ask user prelim questions for inputs
        topic = input("Hello! Thanks for using Audicle. What kind of article do you want to read today?\n")

        # Make sure requested language is supported
        listen_lang = input("Great! Is there a specific language you'd like to listen in? Please write out the full name of the language.\n")
        while listen_lang.lower() not in self.supported_lang.values():
            listen_lang = input("Sorry, that language is not supported. Please select a language from this list: https://cloud.google.com/text-to-speech/docs/voices\n")

        # Generate query
        query = self.generate(self.generate_query_message, topic)

        print("Loading your article...")

        # Seach for primary article and extract contents
        article = self.metaphor.search(query, num_results = 1, use_autoprompt=True)
        article_list = []
        contents = article.get_contents().contents
        result = article.results
        for i in range(len(contents)):
            article_list.append(self.scrape(result[i].title, result[i].author, result[i].published_date, contents[i].extract, contents[i].url, contents[i].id))

        # Find similar articles and extract contents
        similar_articles = self.metaphor.find_similar(url = article_list[0].url, num_results = 3)
        contents = similar_articles.get_contents().contents
        result = similar_articles.results
        for i in range(len(contents)):
            article_list.append(self.scrape(result[i].title, result[i].author, result[i].published_date, contents[i].extract, contents[i].url, contents[i].id))

        # Assign name to each article
        main, similar1, similar2, similar3 = [i for i in article_list]

        # Give audio file + thanks for listening message
        self.audio_file(main, similar1, similar2, similar3, listen_lang)
        print(self.thanks_for_listening(main, similar1, similar2, similar3))

    # Generate appropriate text output based on user input
    def generate(self, message: str, query: str) -> str:
        completion = openai.ChatCompletion.create(
            model = "gpt-3.5-turbo",
            messages = [
                {"role": "system", "content": message},
                {"role": "user", "content": query},
            ]
        )
        return completion.choices[0].message.content

    # Extract content from query output to create list of Articles
    def scrape(self, title: str, author: str, date: str, content: str, url: str, id_num: str) -> Article:
        article_temp = Article(title = title, author = author, published_date = date, content = content, summary = content, url = url)
        self.get_contents(article_temp, id_num)
        self.html_to_plain(article_temp)
        self.summarize(article_temp)
        return article_temp

    # Retrieve contents
    def get_contents(self, article: Article, id_num = str) -> None:
        content = self.metaphor.get_contents(id_num)
        for content in content.contents:
            article.content = content.extract

    # Convert extracted HTML text to plain text
    def html_to_plain(self, article: Article) -> None:
        convert = html2text.html2text(article.content)
        article.content = convert

    # Update content summary
    def summarize(self, article: Article) -> None:
        summary = self.generate(self.summarize_text_message, article.content)
        article.summary = summary

    # Generate standard reading format ("script") for audio generation
    def text_to_script(self, main: Article, first: Article, second: Article, third: Article) -> str:
        script = f"Here is {main.title} written by {main.author} on {main.published_date}. {main.content}. For further reading, check out {first.title} by {first.author} which discusses {first.summary}. Additionally, you can check out {second.title} by {second.author} or {third.title} by {third.author}."
        script = self.generate(self.clean_message, script)
        return script
        #return self.generate(self.text_to_ssml_message, script)

    # Generate audio delivery message
    def thanks_for_listening(self, main: Article, first: Article, second: Article, third: Article) -> str:
        message = f"Happy listening! This article discusses {main.summary}. For further reads, check out {first.title} by {first.author} at {first.url}, {second.title} by {second.author} at {second.url}, or {third.title} by {third.author} at {third.url}. If you’d like to listen to any of these articles, run the tool again and type the title into search!"
        return self.generate(self.clean_message, message)

    # Create and deliver audio
    def audio_file(self, main: Article, first: Article, second: Article, third: Article, language: str) -> None:
        audio = gTTS(self.text_to_script(main, first, second, third), lang = "".join([key for key, value in self.supported_lang.items() if value == language]))
        title = f"{main.title}.mp3"
        audio.save(title)

if __name__ == '__main__':
    audicle = Audicle()
    audicle.main()


'''This program is run separately and manually to add new entries in the
csv file that is not in the database, to the database.
'''

import csv
import sqlite3

db_connection = sqlite3.connect('events.db')
db_cursor = db_connection.cursor()
db_cursor.execute('''DROP TABLE IF EXISTS events''')
db_cursor.execute('''CREATE TABLE events (
serial int NOT NULL PRIMARY KEY,
eventdate date,
name varchar,
event varchar,
priority int)'''
                  )

with open('events.csv', newline='') as csvfile:
    csvobj = csv.reader(csvfile)
    serial_nums = [x[0]
                   for x in db_cursor.execute('SELECT serial FROM events')]
    for item in csvobj:
        if int(item[0]) not in serial_nums:
            db_cursor.execute(
                "INSERT INTO events VALUES (?, ?, ?, ?, ?)", item)

db_connection.commit()
db_connection.close()


from collections import deque

def solution(board: list[str]):
    answer = 0
    dx = [1,0,-1,0]
    dy = [0,1,0,-1]
    n = len(board)
    m = len(board[0])

    q = deque()
    matrix = [[0 for _ in range(len(board[0]))] for _ in range(len(board))]

    for idx in range(len(board)):
        for jdx in range(len(board[0])):
            if board[idx][jdx] == 'R':
                q.append((idx,jdx))
                matrix[idx][jdx] = 1

    while q:
        x,y = q.popleft()
        if board[x][y] == 'G':
            return matrix[x][y]-1

        for i in range(4):
            nx = x
            ny = y
            while True:
                nx += dx[i]
                ny += dy[i]
                if nx < 0 or nx >= n or ny < 0 or ny >= m:
                    nx -= dx[i]
                    ny -= dy[i]
                    break
                if 0<=nx<n and 0<=ny<m and board[nx][ny] == 'D':
                    nx -= dx[i]
                    ny -= dy[i]
                    break

            if matrix[nx][ny] == 0:
                matrix[nx][ny] = matrix[x][y]+1
                q.append((nx,ny))
    return -1

print(solution(["...D..R", ".D.G...", "....D.D", "D....D.", "..D...."]))
print(solution([".D.R", "....", ".G..", "...D"]))


# Build file tree
tree = {'parent': None, 'dirs': {}, 'files': []}
with open('input-07.txt', 'r') as file:
	for line in file:
		arg = line.strip().split()
		if   arg[1] == 'ls':
			continue
		elif arg[1] == 'cd':
			if   arg[2] == '..':
				# Go up
				current_dir = current_dir['parent']
			elif arg[2] == '/':
				# Go to root
				current_dir = tree
			else:
				# Go to directory
				current_dir = current_dir['dirs'][arg[2]]
		elif arg[0] == 'dir':
			# Add dir
			current_dir['dirs'][arg[1]] = {
					'parent': current_dir,
					'dirs': {},
					'files': []
					}
		else:
			# Add file
			current_dir['files'].append(int(arg[0]))

def dir_print(dir, depth = 0):
	if depth == 0:
		print('/')
	for k, v in dir['dirs'].items():
		print('. ' * (depth - 1) + '└ ' + k)
		dir_print(v, depth + 1)
	for f in dir['files']:
		print('. ' * depth + str(f))

def dir_size(dir, rsizes):
	size = sum(dir['files'])
	for k, v in dir['dirs'].items():
		size += dir_size(v, rsizes)
	rsizes.append(size)
	return size

# dir_print(tree)

THRESHOLD = 100e3
TOTAL = 70e6
FREE = 30e6
sizes = []
used = dir_size(tree, sizes)

print('Answer 1:', sum(s for s in sizes if s <= THRESHOLD))
print('Answer 2:', min(s for s in sizes if s >= FREE - (TOTAL - used)))