import shutil
import tempfile
from http import HTTPStatus

from django.urls import reverse
from django.test import Client, TestCase, override_settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.conf import settings

from ..models import Post, Group, Comment
from ..forms import PostForm

# Создаем временную папку для медиа-файлов;
# на момент теста медиа папка будет переопределена
TEMP_MEDIA_ROOT = tempfile.mkdtemp(dir=settings.BASE_DIR)

User = get_user_model()

@override_settings(MEDIA_ROOT=TEMP_MEDIA_ROOT)
class PostCreateFormTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user = User.objects.create(username='TestUserForm')
        cls.group = Group.objects.create(
            title='Заголовок тестовой группы',
            slug='test-slug',
            description='Тестовое описание',
        )
        cls.other_group = Group.objects.create(
            title='Заголовок новой группы',
            slug='new-slug',
            description='Тестовое описание',
        )
        cls.post = Post.objects.create(
            author=cls.user,
            text='Тестовый пост',
            group=cls.group,
        )
        cls.form = PostForm()

    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()
        # Модуль shutil - библиотека Python с удобными инструментами
        # для управления файлами и директориями:
        # создание, удаление, копирование, перемещение, изменение папок и файлов
        # Метод shutil.rmtree удаляет директорию и всё её содержимое
        shutil.rmtree(TEMP_MEDIA_ROOT, ignore_errors=True)

    def setUp(self):
        self.guest_client = Client()
        self.authorized_client = Client()
        self.authorized_client.force_login(PostCreateFormTest.user)
        cache.clear()

    def test_create_post(self):
        post_count = Post.objects.count()
        small_gif = (
            b'\x47\x49\x46\x38\x39\x61\x02\x00'
            b'\x01\x00\x80\x00\x00\x00\x00\x00'
            b'\xFF\xFF\xFF\x21\xF9\x04\x00\x00'
            b'\x00\x00\x00\x2C\x00\x00\x00\x00'
            b'\x02\x00\x01\x00\x00\x02\x02\x0C'
            b'\x0A\x00\x3B'
        )
        uploaded = SimpleUploadedFile(
            name='small.gif',
            content=small_gif,
            content_type='image/gif'
        )
        form_data = {
            'author': self.user,
            'text': self.post.text,
            'group': self.group.pk,
            'image': uploaded
        }
        response = self.authorized_client.post(
            reverse('posts:post_create'),
            data=form_data,
            follow=True
        )
        self.assertRedirects(response, reverse(
            'posts:profile',
            kwargs={'username': self.user}
        ))
        last_post = Post.objects.order_by('pub_date').last()
        self.assertTrue(
            Post.objects.filter(
                group=self.group.pk,
                text=self.post.text,
                image='posts/small.gif',
            ).exists()
        )
        self.assertEqual(last_post.image.name,
                         'posts/' + form_data['image'].name)
        self.assertEqual(last_post.text, form_data['text'])
        self.assertEqual(last_post.group.id, form_data['group'])
        self.assertEqual(Post.objects.count(), post_count + 1)

    def test_edit_text_in_post(self):
        post_count = Post.objects.count()
        form_data = {
            'text': 'Редактированный пост',
            'group': self.other_group.id
        }
        response = self.authorized_client.post(
            reverse('posts:post_edit', kwargs={'post_id': self.post.id}),
            data=form_data,
            follow=True,
        )
        self.assertRedirects(response, reverse(
            'posts:post_detail',
            kwargs={'post_id': self.post.id}
        ))
        post = Post.objects.get(id=self.post.id)
        self.assertEqual(form_data['text'], post.text)
        self.assertEqual(self.other_group, post.group)
        self.assertEqual(Post.objects.count(), post_count)

    def test_comment_for_auth_user(self):
        post = Post.objects.create(
            text='Test post.',
            author=self.user,
        )
        comments_count = post.comments.count()
        form_data = {
            'text': 'Тестовый комментарий',
            'post': post.id,
            'author': self.user.id
        }
        response = self.authorized_client.post(
            reverse('posts:add_comment', kwargs={'post_id': post.id}),
            data=form_data,
            follow=True,
        )
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertEqual(post.comments.count(), comments_count + 1)


from collections import deque
def solution(maps):
    answer = []
    visited = [[False] * len(maps[0]) for _ in range(len(maps))]
    dx, dy = [-1,1,0,0], [0,0,-1,1]

    for i in range(len(maps)):
        for j in range(len(maps[0])):
            if not visited[i][j] and maps[i][j] != "X":
                visited[i][j] = True
                temp = int(maps[i][j])
                q = deque()
                q.append([i,j])
                while q:
                    x, y = q.popleft()
                    for k in range(4):
                        nx, ny = x + dx[k], y + dy[k]
                        if 0 <= nx < len(maps) and 0 <= ny < len(maps[0]):
                            if not visited[nx][ny] and maps[nx][ny] != "X":
                                temp += int(maps[nx][ny])
                                q.append([nx,ny])
                                visited[nx][ny] = True
                answer.append(temp)
    return sorted(answer) if answer != [] else [-1]


# options.py

"""
This module is an integeral part of the program
MMA - Musical Midi Accompaniment.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Bob van der Poel <bob@mellowood.ca>

"""

import getopt
import sys
import os
import tempfile

import MMA.docs
import MMA.parse
import MMA.chords
import MMA.volume
import MMA.exits

from . import gbl
from MMA.common import *
from MMA.macro import macros

cmdSMF = None

def cmdLine(l):
    """ Try to take a mma input line and parse it like a command line.
        An empty CmdLine is just ignored. """

    if l:
        opts(l)

def cmdError(e):
    """ Illegal internal command line options."""

    error("CmdLine: the command line option '%s' is not permitted in a MMA script." % e)

def opts(l=None):
    """ Option parser.
         FIXME: this code segment is much too long!
    """

    if not l:
        l = sys.argv[1:]
        internal = False
    else:
        internal = True

    try:
        opts, args = getopt.gnu_getopt(
                         l, "b:B:dpsS:ri:wneom:f:M:cLgGvVD:01PT:I:x:", [])
    except getopt.GetoptError:
        usage()

    for o, a in opts:
        if o == '-b':
            setBarRange(a)

        elif o == '-B':
            setBarRange(a)
            gbl.barRange.append("ABS")

        elif o in ('-d', '-o', '-p', '-s', '-r', '-w', '-n', '-e', '-c'):
            import MMA.debug   # circular dep. problem
            MMA.debug.cmdLineDebug(o[-1])

        elif o == '-S':
            ln = a.split('=', 1)
            macros.setvar(ln)

        elif o == '-L':
            gbl.printProcessed = True

        elif o == '-f':
            import MMA.paths
            gbl.outfile = a
            if internal:
                warning("Output filename overwritten by -f CmdLine option.")
                MMA.paths.createOutfileName(".mid")

        elif o == '-i':
            import MMA.paths
            if internal:
                cmdError("-i")
            MMA.paths.setRC(a)

        elif o == '-g':
            if internal:
                cmdError("-g")
            gbl.makeGrvDefs = 1

        elif o == '-G':
            if internal:
                cmdError("-G")
            gbl.makeGrvDefs = 2

        elif o == '-m':
            try:
                a = int(a)
            except:
                error("Expecting -m arg to be a integer")
            gbl.maxBars = a

        elif o == '-v':
            print("%s" % gbl.version)
            if not internal:
                sys.exit(0)

        elif o == '-M':
            global cmdSMF
            if a in ['0', '1']:
                cmdSMF = a
            else:
                error("Only a '0' or '1' is permitted for the -M arg")

        elif o == '-T':   # set tracks to generate, mute all others
            gbl.muteTracks = a.upper().split(',')

        elif o == '-D':
            if internal:
                cmdError("-D..")
            if a == 'xl':
                gbl.createDocs = 1

            elif a == 'xh':
                gbl.createDocs = 2

            elif a == 's':
                gbl.createDocs = 3

            elif a == 'gh':
                gbl.createDocs = 4

            elif a == 'js':
                gbl.createDocs = 5

            elif a == 'bo':
                gbl.createDocs = 99

            elif a == 'k':
                import MMA.alloc
                # important! Needs a space before the trailing LF for mma.el
                print("Base track names: %s \n" %
                      ' '.join([a for a in sorted(MMA.alloc.trkClasses)]))
                print("Commands: %s BEGIN END DEFAULT\n" %
                      ' '.join([a for a in sorted(MMA.parse.simpleFuncs)]))
                print("TrackCommands: %s \n" %
                      ' '.join([a for a in sorted(MMA.parse.trackFuncs)]))
                print("Not complete ... subcommands, comments, chords...")
                sys.exit(0)

            else:
                print("Unknown option: '-D%s'." % a)
                usage()

        elif o == '-0':
            import MMA.sync
            MMA.sync.synchronize(['START'])

        elif o == '-1':
            import MMA.sync
            MMA.sync.synchronize(['END'])

        elif o == '-P':
            gbl.playFile = 1

        elif o == '-I':
            # We use -I for plugin help and overload it to discard
            # the plugin security. Use -II for security override.
            # It does mean you can't have plugin called "I", but
            # you could use "i" and it'll work.
            import MMA.regplug
            if a == 'I':
                MMA.regplug.secOverRide = True

            # Plugin help. Note we have not loaded any plugins at this
            # point. pluginHelp() will find the plugin, register it and
            # call its help function.
            else:
                MMA.regplug.pluginHelp(a)
                sys.exit(0)

        elif o == '-V':
            import MMA.file

            if internal:   # can't have a -V in a -V :)
                cmdError("-V")

            gbl.playFile = 2  # signal create and play groove
            if not args:
                error("-V: option requires Groove Name.")

            _, tfile = tempfile.mkstemp(prefix="MMA_", suffix=".mma")
            op = open(tfile, "w")
            groove = ''
            cmds = []
            chords = "I, vi, ii, V7"
            count = 4
            for g in args:
                if '=' in g:
                    c = g.split('=')
                    if c[0].upper() == 'CHORDS':
                        chords = c[1]
                    elif c[0].upper() == "COUNT":
                        count = c[1]
                        try:
                            count = int(count)
                        except:
                            error("-V: expecting integer for Count.")
                    else:
                        cmds.append(c)
                elif groove:
                    error("-V: Only one groove name permitted.")
                else:
                    groove = g
            if not groove:
                error("-V: no groove name specified.")

            op.write("Groove %s\n" % groove)
            for g in cmds:
                op.write("%s %s \n" % (g[0], g[1]))
            chords = chords.split(',')
            while len(chords) < count:
                chords += chords
            chords = chords[:count]
            for c in chords:
                op.write("%s\n" % c)

            op.close()

            # we can only have one scratch file, so no fear of overload.
            # otherwise we might need to explicity delete file here.
            MMA.exits.files.append(tfile)

            args = [tfile]  # fake the CLI so mma thinks the created file is yours

        elif o=='-x':  # any one of some xtra, seldom used, options
            import MMA.xtra
            MMA.xtra.xoption(a, args)

        else:
            usage()      # unreachable??

    if internal:
        return

    # a few sanity checks

    #if  MMA.writeMid.splitOutput:
    #    if gbl.playFile:
    #        error("The -P (play) option is not compatible with channel/track splitting.")
    #    if gbl.infile == 1:
    #        error("The '-' (read from stdin) is not compatible with channel/track splitting.")

    # we have processed all the args. Should just have a filename left

    if len(args) > 1:
        usage("Only one input filename is permitted, %s given on command line." % len(args))

    if gbl.infile:
        usage("Input filename already assigned ... should not happen.")

    if args:
        gbl.infile = args[0]

    # if a single '-' is left on the cmd line user want stdin. We set the
    # the input filename to numeric 1 which can't be entered.

    if gbl.infile == '-':
        gbl.infile = 1

        if not gbl.outfile:
            import MMA.debug   # circular dep. problem
            if not(MMA.debug.noOutput):
                error("Input from STDIN specified. Use -f to set an output filename.")

def usage(msg=''):
    """ Usage message. """

    txt = [
        "MMA - Musical Midi Accompaniment",
        "  Copyright 2003-22, Bob van der Poel. Version %s" % gbl.version,
        "  Distributed under the terms of the GNU Public License.",
        "  Usage: mma [opts ...] INFILE [opts ...]",
        "",
        "Options:",
        " -b <n> Limit compilation to n1-n2 bars (comment numbers)",
        " -B <n> Like -b but for absolute bar numbers",
        " -c    display default Channel assignments",
        " -d    enable lots of Debugging messages",
        " -Dk   print list of MMA keywords",
        " -Dxl  eXtract Latex doc blocks from file",
        " -Dxh  eXtract HTML doc blocks from file",
        " -Dgh  extract HTML Groove doc",
        " -Djs  extract JSON Groove information from file",
        " -Dbo  extract text for browser app",
        " -Ds   extract sequence lists from file",
        " -e    show parsed/Expanded lines",
        " -f <file>  set output Filename",
        " -g    update Groove dependency database",
        " -G    create Groove dependency database",
        " -i <file> specify init (mmarc) file",
        " -I <plugin> print docs for plugin if available",
        " -II   skip permissions test for plugins (Dangerous!)",
        " -L    show order of bars processed",
        " -m <x> set Maxbars (default == 500)",
        " -M <x> set SMF to 0 or 1",
        " -n    No generation of midi output",
        " -o    show complete filenames when Opened",
        " -p    display Patterns as they are defined",
        " -P    play song (don't save) with player",
        " -r    display Running progress",
        " -s    display Sequence info during run",
        " -S <var[=data]>  Set macro 'var' to 'data'",
        " -T <tracks> Limit generation to specified tracks",
        " -v    display Version number",
        " -V <groove [options]> preview play groove",
        " -w    disable Warning messages",
        " -xCHORDS=<chord list> test listed chords for validity",
        " -xNOCREDIT disable MMA credits in Midi Meta track",
        " -xCHECKFILE=<filename> check chords in file",
        " -xTSplit  create midi for each track",
        " -xCSplit  create MIDI for each channel",
        " -0    create sync at start of all channel tracks",
        " -1    create sync at end of all channel tracks",
        " -     a single hyphen signals to use STDIN instead of a file"]

    for a in txt:
        print(a)

    if msg:
        print("\n%s" % msg)

    sys.exit(1)

def setBarRange(v):
    """ Set a range of bars to compile. This is the -B/b option."""

    if gbl.barRange:
        error("Only one -b or -B permitted.")

    for ll in v.split(','):

        l = ll.split("-")

        if len(l) == 2:
            s, e = l
            try:
                s = int(s)
                e = int(e)
            except:
                usage("-B/b ranges must be integers, not '%s'." % l)

            for a in range(s, e + 1):
                gbl.barRange.append(str(a))

        elif len(l) == 1:
            try:
                s = int(l[0])
            except:
                usage("-B/b range must be an integer, not '%s'." % l[0])
            gbl.barRange.append(str(s))

        else:
            usage("-B/b option expecting N1-N2,N3... not '%s'." % v)


import cv2
import numpy as np

balon_cascade = cv2.CascadeClassifier('/media/yesill/Yerel Disk/Programlama/Projeler/uav/cascades/cascades/91p2381n16stage.xml')

cap = cv2.VideoCapture(0)

while cap.isOpened():
    success, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    objects = balon_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=8)
    for (x,y,w,h) in objects:
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 3)
        cv2.putText(frame, f"balon", (x, y+5), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 255, 0), 2)
        roi_color = frame[y:y+h, x:x+w]

    cv2.imshow("title", frame)

    command = cv2.waitKey(1)
    if command & 0xFF == ord('q'):
        print(f'program sonlandirildi')
        break
    elif command & 0xFF == ord('r'):
        print(f'kirmizi balonlağg tespit ediliyoğg')
    elif command & 0xFF == ord('g'):
        print(f'yeschill balonlağg tespit ediliyoğg')
    elif command & 0xFF == ord('b'):
        print(f'movi balonlağg tespit ediliyoğg')

cap.release()
cv2.destroyAllWindows()


#!/share/data1/zhangy/software/miniconda/envs/bio37/bin/python
import re
import sys
import argparse

def get_args():
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument("i", metavar="", help="download the result of search for ko number")
    args = parser.parse_args()
    return args

def main(file_):
    f = open(file_, 'r')
    for line in f:
        # 找定位行
        if re.search(r"div\s+style=.width:600px.>", line.strip()):
            # 解析
            pattern = re.compile(r'
(.*?)

\s+(K\d{5})\s+(.*?)

')
            gene_iter = re.finditer(pattern, line.strip())
            for gene in gene_iter:
                print(f'{gene.group(1)}\t{gene.group(2)}\t{gene.group(3)}')
    f.close()

if __name__ == "__main__":
    args = get_args()
    input_file = args.i
    main(input_file)


import numpy as np
import pandas as pd
import argparse
from datetime import datetime
import matplotlib.pyplot as plt
from statistics import mean
from collections import defaultdict
from pprint import pprint
import warnings
import math
from matplotlib.backends.backend_pdf import PdfPages

def main():
    parser = argparse.ArgumentParser(description="A program for processing the trade raw files")
    parser.add_argument('-f', '--trading_file', type=str, required=True,
                        help='Please provide the input raw trading CSV file which is needed to be processed'
                             'Headers should be as first row of the file, and data should be in th')
    parser.add_argument('-re', '--reporter', type=str, required=True,
                        help='Please provide the reporter country name')
    parser.add_argument('-pa', '--partner', type=str, required=True,
                        help='Please provide the partner country name')
    parser.add_argument('-flow', '--flow', type=str, required=True,
                        help='Please provide the flow')
    #parser.add_argument('-y', '--year', type=int, nargs='?', default=2019,
                        #help='Please provide the year, default value is 2019')
    #parser.add_argument('-cat', '--category_id', type=int, required=True,
                        #help='Please provide the two-digit category id (for example 61)')
    parser.add_argument('-o', '--output_file', type=str, required=True,
                        help='Please provide the output file name where you want to store the processed file')

    args = parser.parse_args()

    delivarable2(args.reporter, args.partner, args.flow, args.trading_file, args.output_file)

def delivarable2(re, pa, flow, trading, out, k=20):
    #Import Data
    data = pd.read_csv(trading)
    del data['Unnamed: 0']

    #dataimport = data[data['FLOW']=="export"]

    datareq1=data[data['DECLARANT']== re]
    datareq2=datareq1[datareq1['PARTNER']== pa]
    #datareq3=datareq2[datareq2['check']== cat]
    datareq3 = datareq2[datareq2['FLOW']==flow]
    #datareq4=datareq3[(datareq3['PERIOD']/100).astype(int)== 2015]
    #datareq5 = datareq4.sort_values(by = 'VALUE_IN_EUROS', ascending=False)
    datareq6=datareq3.groupby('PRODUCT_ID', as_index=False, sort=False).agg({'VALUE_IN_EUROS':'sum', 'PERIOD':'first'})

    df = pd.DataFrame(datareq6['PRODUCT_ID'], columns=['PRODUCT_ID','Year 2015','Year 2016','Year 2017','Year 2018', 'Year 2019'])
    for ind in range(20):
        if(int(datareq6['PERIOD'][ind]/100)==2015):
            df['Year 2015'][ind]=datareq6['VALUE_IN_EUROS'][ind]
        else:
            if(int(datareq6['PERIOD'][ind]/100)==2016):
                df['Year 2016'][ind]=datareq6['VALUE_IN_EUROS'][ind]
            if(int(datareq6['PERIOD'][ind]/100)==2017):
                df['Year 2017'][ind]=datareq6['VALUE_IN_EUROS'][ind]
            if(int(datareq6['PERIOD'][ind]/100)==2018):
                df['Year 2018'][ind]=datareq6['VALUE_IN_EUROS'][ind]
            if(int(datareq6['PERIOD'][ind]/100)==2019):
                df['Year 2019'][ind]=datareq6['VALUE_IN_EUROS'][ind]

    df['Year 2015']=df['Year 2015'].fillna(0)
    df['Year 2016']=df['Year 2016'].fillna(0)
    df['Year 2017']=df['Year 2017'].fillna(0)
    df['Year 2018']=df['Year 2018'].fillna(0)
    df['Year 2019']=df['Year 2019'].fillna(0)
    df_final=df.head(20)
    print(df_final)
    fig, ax =plt.subplots(figsize=(21,6))
    ax.axis('tight')
    ax.axis('off')
    the_table = ax.table(cellText=df_final.values,colLabels=df_final.columns,loc='center')
    pp = PdfPages(out)
    pp.savefig(fig, bbox_inches='tight')
    pp.close()

if __name__ == '__main__':
    main()


"""
- Basic Concpets of SVM.
- Concpets of "linear separability" and "maximum margin".
- XOR Problem by utilizing kernels to achieve non-linear separation.
"""

# Gram Matrix [ Kernel Matrix]
#A' = [K(A,A), K(A,B), K(A,C), K(A,D)]
#B' = [K(B,A), K(B,B), K(B,C), K(B,D)]
#C' = [K(C,A), K(C,B), K(C,C), K(C,D)]
#D' = [K(D,A), K(D,B), K(D,C), K(D,D)]

"""
#Types of Kernels
#Linear
K(x,y) = x(T)*y

#Polynomial
K(x,y) = (x(T)*y+c)^d

#Sigmoid
K(x,y) = tanh(gamma*x(T)*y+c)

#Radial Basis function(RBF):
K(x,y) = exp(-gamma*||x-y||^2)
"""

from sklearn.cross_validation import train_test_split
from sklearn.metrics import classification_report
from sklearn.svm import SVC
import numpy as np

# generate the XOR data
tl = np.random.uniform(size=(100, 2)) + np.array([-2.0, 2.0])
tr = np.random.uniform(size=(100, 2)) + np.array([2.0, 2.0])
br = np.random.uniform(size=(100, 2)) + np.array([2.0, -2.0])
bl = np.random.uniform(size=(100, 2)) + np.array([-2.0, -2.0])
X = np.vstack([tl, tr, br, bl])
y = np.hstack([[1] * len(tl), [-1] * len(tr), [1] * len(br), [-1] * len(bl)])

# construct the training and testing split by taking 75% of the data for training
# and 25% for testing
(trainData, testData, trainLabels, testLabels) = train_test_split(X, y, test_size=0.25,
	random_state=42)

# train the linear SVM model, evaluate it, and show the results
print("[RESULTS] SVM w/ Linear Kernel")
model = SVC(kernel="linear")
model.fit(trainData, trainLabels)
print(classification_report(testLabels, model.predict(testData)))
print("")

# train the SVM + poly. kernel model, evaluate it, and show the results
print("[RESULTS] SVM w/ Polynomial Kernel")
model = SVC(kernel="poly", degree=2, coef0=1)
model.fit(trainData, trainLabels)
print(classification_report(testLabels, model.predict(testData)))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   File Name：     run_experiment
   Description :
   Author :       chenhao
   date：          2021/4/6
-------------------------------------------------
   Change Activity:
                   2021/4/6:
-------------------------------------------------
"""

import os
import logging
import traceback

import shutil

import fire

from config_ai.experiments import ExperimentFactory

logger = logging.getLogger(__name__)

def run_experiment(config_path):
    experiment = ExperimentFactory.create(config_path=config_path)
    try:
        experiment.run()
    except Exception as e:
        logger.error("run experiment failed, clean experiment files...")
        experiment_path = experiment.experiment_path
        if os.path.exists(experiment_path):
            logger.info(f"removing failed experiment :{experiment_path}")
            shutil.rmtree(experiment_path)
        logger.exception("")

if __name__ == '__main__':
    fire.Fire(run_experiment)


#!/usr/bin/python
import sys
import re
from date_time import date_time
from subprocess import call
from subprocess import check_output
import subprocess

def download_from_swift(cont,obj):
    src_cmd=". /home/ubuntu/.novarc;"
    swift_cmd=src_cmd + "swift download " + cont + " --skip-identical --prefix " + obj
    sys.stderr.write(date_time() + swift_cmd + "\n")
    try:
        check=check_output(swift_cmd,shell=True,stderr=subprocess.PIPE)
    except:
        sys.stderr.write(date_time() + "Download of " + obj + " from " + cont + " failed\n")
        exit(1)
    return 0
if __name__ == "__main__":
    import argparse
    parser=argparse.ArgumentParser(description='Simple download module to get files from swift.  Can use prefix or whole object name')
    parser.add_argument('-c','--container',action='store',dest='cont',help='Swift container, i.e. PANCAN')
    parser.add_argument('-o','--object',action='store',dest='obj',help='Swift object name/prefix, i.e. RAW/2015-1234')

    if len(sys.argv)==1:
        parser.print_help()
        sys.exit(1)

    inputs=parser.parse_args()
    (cont,obj)=(inputs.cont,inputs.obj)
    download_from_swift(cont,obj)


# pylint: disable=C0111,R0903

"""Shows when a key is pressed

Parameters:
    * keys.keys: Comma-separated list of keys to monitor (defaults to "")
"""

import core.module
import core.widget
import core.decorators
import core.event

import util.format

from pynput.keyboard import Listener

NAMES = {
    "Key.cmd": "cmd",
    "Key.ctrl": "ctrl",
    "Key.shift": "shift",
    "Key.alt": "alt",
}

class Module(core.module.Module):
    @core.decorators.never
    def __init__(self, config, theme):
        super().__init__(config, theme, [])

        self._listener = Listener(on_press=self._key_press, on_release=self._key_release)

        self._keys = util.format.aslist(self.parameter("keys", "Key.cmd,Key.ctrl,Key.alt,Key.shift"))

        for k in self._keys:
            self.add_widget(name=k, full_text=self._display_name(k), hidden=True)
        self._listener.start()

    def _display_name(self, key):
        return NAMES.get(key, key)

    def _key_press(self, key):
        key = str(key)
        if not key in self._keys: return
        self.widget(key).hidden = False
        core.event.trigger("update", [self.id], redraw_only=False)

    def _key_release(self, key):
        key = str(key)
        if not key in self._keys: return
        self.widget(key).hidden = True
        core.event.trigger("update", [self.id], redraw_only=False)

    def state(self, widget):
        return widget.name

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4


"""Demo of shared c-types with numpy"""

import multiprocessing as mp

from multiprocessing import sharedctypes
from numpy import ctypeslib

def fill_array(arr, value):
    arr.fill(value)

if __name__ == '__main__':

    # Create an array of integers on c-level
    raw_array = sharedctypes.RawArray('i', 4)

    # Convert the raw array into a numpy c-object
    array = ctypeslib.as_array(raw_array)

    # Reshape in-place
    array.shape = (2, 2)

    # Create two processes which write on different rows of `array`
    process1 = mp.Process(target=fill_array, args=(array[0, :], 5))
    process2 = mp.Process(target=fill_array, args=(array[1, :], 7))

    # Start both processes and wait for them to finish
    process1.start()
    process2.start()
    process1.join()
    process2.join()

    print(array)  # [[5 5] \ [7 7]]


import sys
import os
sys.path.append(os.path.join(os.path.abspath(__file__).rsplit('/', 2)[0], 'accessory'))  # LLaMA2-Accessory/accessory

import numpy as np
import torch
import torch.distributed as dist
import multiprocessing as mp

from fairscale.nn.model_parallel import initialize as fs_init

from model.meta import MetaModel

from util.misc import setup_for_distributed
from util.tensor_parallel import load_tensor_parallel_model_list
from util.tensor_type import default_tensor_type
from data.transform import get_transform
from data.conversation.lib import conv_templates, SeparatorStyle
from PIL import Image

# *********************** Begin Configuration ***********************
# todo Please modify the following variables to fit your environment and needs

SPHINX_TYPE = "SPHINX-1k"  # "SPHINX" or "SPHINX-1k"
TOKENIZER_PATH = "/PATH/TO/tokenizer.model"  # path to llama tokenizer
PRETRAINED_PATH = "/PATH/TO/PRETRAINED"

IMAGE_PATH = "examples/1.jpg"  # image for inference, can be None as SPHINX also supports text-only dialog
INSTRUCTION = "Please describe the image in detail."

MODEL_PARALLEL_SIZE = 2  # equal to the number of GPUs to use for inference, current either 1 or 2 is supported

# ************************ End Configuration ************************

if SPHINX_TYPE == "SPHINX-1k":
    LLAMA_TYPE = "llama_ens5" # SPHINX-1k
elif SPHINX_TYPE == "SPHINX":
    LLAMA_TYPE = "llama_ens"
else:
    raise ValueError(f"unknown SPHINX type {SPHINX_TYPE}")

def main(world_size=1, rank=0) -> None:
    # ****************** Begin Environment Setup ******************

    # SPHINX model definition relies on fairscale model parallel
    # so distributed process groups need to be initialized even if when only one gpu is used
    dist.init_process_group(
        backend="nccl", rank=rank, world_size=world_size,
        init_method=f"tcp://127.0.0.1:23560",
    )
    fs_init.initialize_model_parallel(model_parallel_size_=world_size)
    torch.cuda.set_device(rank)

    torch.manual_seed(1)
    np.random.seed(1)

    # block output from ranks other than rank 0
    setup_for_distributed(rank == 0)

    # ******************* End Environment Setup *******************

    # ******************** Begin Create Model *********************

    with default_tensor_type(dtype=torch.float16, device="cuda"):
        model = MetaModel(
            LLAMA_TYPE, llama_config=[], tokenizer_path=TOKENIZER_PATH,
            with_visual=True, max_seq_len=4096,
        )
    print("Loading pretrained weights ...")
    load_result = load_tensor_parallel_model_list(model, [PRETRAINED_PATH])
    print("load result:\n", load_result)
    assert load_result == {'missing_keys': [], 'unexpected_keys': []}, "checkpoint and model mismatch"
    model.eval()

    # ********************* End Create Model *********************

    # ****************** Begin Construct Input *******************

    if IMAGE_PATH is not None:
        image = Image.open(IMAGE_PATH)
        image = image.convert("RGB")
        target_size = getattr(model.llma, 'image_size', 224)  # 448 for SPHINX-1k, 224 for SPHINX
        image = get_transform("padded_resize", target_size)(image).unsqueeze(0).cuda().half()
    else:
        image = None  # SPHINX also supports text-only dialog

    conv = conv_templates["v1"].copy()

    conv.append_message("Human", INSTRUCTION)
    conv.append_message("Assistant", None)

    prompt = conv.get_prompt()
    print(prompt)

    # ******************* End Construct Input ********************

    # ********************* Begin Inference **********************

    conv_sep = (
        conv.sep
        if conv.sep_style == SeparatorStyle.SINGLE
        else conv.sep2
    )  # conv_sep marks the end of response

    with torch.cuda.amp.autocast(dtype=torch.float16):

        for stream_response in model.stream_generate(
            prompt, image, max_gen_len=512, temperature=0.1, top_p=0.75
        ):
            end_pos = stream_response["text"].find(conv_sep)
            if end_pos != -1:  # response ends
                stream_response["text"] = (
                    stream_response['text'][:end_pos].rstrip() + "\n"
                )
                break

    print(stream_response['text'])

    # ********************** End Inference ***********************

if __name__ == "__main__":
    if MODEL_PARALLEL_SIZE == 1:
        main(world_size=1, rank=0)
    elif MODEL_PARALLEL_SIZE == 2:
        mp.set_start_method("spawn")
        for rank in range(MODEL_PARALLEL_SIZE):
            process = mp.Process(
                target=main,
                args=(MODEL_PARALLEL_SIZE, rank),
            )
            process.start()
    else:
        raise ValueError("Currently only 1 or 2 is supported for MODEL_PARALLEL_SIZE")


import sys
from PySide2 import QtCore, QtWidgets

class DialogWindow(QtWidgets.QDialog):  # QtWidgets.QDialog를 상속받음.
 def __init__(self):
  QtWidgets.QDialog.__init__(self)
  self.setWindowTitle("Dialog Window")  # 대화 상자 맨 위의 window title을 Dialog Window로 설정.
  vbox = QtWidgets.QVBoxLayout(self)  # vertical 1개
  hbox1 = QtWidgets.QHBoxLayout()
  hbox2 = QtWidgets.QHBoxLayout()   # horizontal 2개
  self.ok = QtWidgets.QPushButton("OK", self)   # OK push button
  self.cancel = QtWidgets.QPushButton("Cancel", self)   # Cancel push button

  vbox.addLayout(hbox1)
  vbox.addLayout(hbox2)   # vertical 2개.

  hbox1.addWidget(QtWidgets.QLabel("Enter your name", self))    # addWidget으로 1번째 horizontal 줄에 Qlabel 넣음.
  self.lineedit = QtWidgets.QLineEdit(self)
  hbox1.addWidget(self.lineedit)    # QLineEdit 넣음.
  hbox2.addWidget(self.ok)    # 2번째 horizontal 줄에 self.ok 에 저장돼있던 OK push button 넣음.
  hbox2.addWidget(self.cancel)

  self.ok.clicked.connect(self.accept)    # OK button 클릭 시, accept
  self.cancel.clicked.connect(self.reject)

if __name__ == "__main__":
 app = QtWidgets.QApplication(sys.argv)
 dg = DialogWindow()
 result = dg.exec_()
 if result == QtWidgets.QDialog.Accepted:
  print("Your name is", dg.lineedit.text())
 elif result == QtWidgets.QDialog.Rejected:
  print("Input canceled")


# importing modules
import itertools
from collections import Counter
from Progress_bar import *

# create a counter dictionary of letter frequencies
def getFrequency(_words):
    concatenation= ''.join(map(str, _words))
    return Counter(concatenation)

# average the letter frequency across the numbers of letters in the counter dictionary keys
def averageFrequency(_letter_scores):
    for key in _letter_scores.keys():
        _letter_scores[key] = _letter_scores[key]/len(_letter_scores.keys())
    return _letter_scores

# create a counter dictionary for letter frequencies per location in word:
def letterPositionFrequency(_words):
    concatenation = ["", "", "", "", ""]
    for _word in _words:
        for _letter, index in zip(_word, range(5)):
            concatenation[index]+=_letter
    return [Counter(concatenation[0]), Counter(concatenation[1]), Counter(concatenation[2]), Counter(concatenation[3]), Counter(concatenation[4])]

# average the letter positional frequency across the numbers of letters in the counter dictionary keys
def averagePositionalFrequency(_letter_positions):
    for position in _letter_positions:
        for key in position.keys():
            position[key] = position[key] / len(position.keys())
    return _letter_positions

# get the score of a word using the letter scores (by frequency) found earlier
def getFrequencyScore(_word, _letter_scores):
    score = 0
    for letter in _word:
        score += _letter_scores[letter]
    return score

# get the score of a word using the letter positional scores (by frequency) found earlier
def getPositionalScore(_word, _letter_positions):
    score = 0
    for letter, index in zip(_word, range(5)):
        score += _letter_positions[index][letter]
    return score

# creating a list of all possible permutations of received feedback for a guessed word
def possibleCombinations():
    N = 5  # number of objects (e.g. slots)
    possible_values = [-1, 0, 1]  # -1 wrong letter, 0 right letter wrong place, 1 right letter right place
    # using itertools to create the permutations in question
    result = list(itertools.product(possible_values, repeat=N))
    # removing the option to guess the word on the first try, not statistically significant or interesting
    result.remove((1, 1, 1, 1, 1))
    return result

# check the remaining words after playing the first word and comparing it with a combination of a given answer (received feedback for a guessed word)
def checkWordAndCombo(_combination, _word, _words):
    vowles = ['a','e','i','o','u']
    # -1 wrong letter, 0 right letter wrong place, 1 right letter right place
    words_to_check = _words.copy()
    misplaced_letters = []
    refreshed_list = []
    for slot, index in zip(_combination, range(5)):
        if slot == -1:
            if _word[index] == "_":
                continue
            # if the letter is not in the target word at all, clear the words with that letter at that location
            words_to_check = [x for x in words_to_check if ((_word[index] not in x or _word[index] in vowles) and _word[index] != x[index])]
        elif slot == 0:
            # if the letter is not in the target word at a specific location, clear the words with that letter at that location
            words_to_check = [x for x in words_to_check if x[index] != _word[index]]
            # add the letter to a collection of misplaced letters
            misplaced_letters.append(_word[index])
        elif slot == 1:
            # if the letter is in the target word at the correct location, clear the words with that don't have that letter at that location
            words_to_check = [x for x in words_to_check if x[index] == _word[index]]
        else:
            continue
    if misplaced_letters:
        # if there were misplaced letters, create a new list of words that contain all the misplaced letters
        for a_word in words_to_check:
            test_condition = all(letter in a_word for letter in misplaced_letters)
            if test_condition:
                refreshed_list.append(a_word)
        return refreshed_list
    return words_to_check

# check all the words against all the combinations of possible outcomes (242 possible outcomes against ~2300 words in the Wordle answer bank)
def rankStartingScore(_combinations, _words, _letter_scores, _letter_positions, showProgress=False):
    starting_rank = []
    # Initial call to print 0% progress
    if showProgress:
        printProgressBarPyCharm(0, len(_words), prefix='Progress:', suffix='Complete', length=50)
    # iterate over all the words in the word bank
    for a_word, progress in zip(_words, range(len(_words))):
        current_word = ["", 0]  # word and score combo
        current_word[0] = a_word
        NonZero = 0
        # for each word, iterate over all the possible received feedback
        for combination in _combinations:
            # add all possible next turns given the data (all remaining words given the answer received)
            current_word[1] += len(checkWordAndCombo(combination, a_word, _words))
            # count the number of times there was any possible future data - 0 options left means the word is either very unique,
            # therefore not providing a lot of data, or we were right on the first guess - low possibility with low statistical significance
            if len(checkWordAndCombo(combination, a_word, _words)) != 0:
                NonZero += 1
        # average the score of all possible next-turn words divided by iterations that provided data
        if NonZero > 0:
            current_word[1] = current_word[1]/NonZero
        else:
            current_word[1] = 1
        starting_rank.append([current_word[0], current_word[1], len(set(a_word)), getFrequencyScore(current_word[0], _letter_scores), getPositionalScore(current_word[0], _letter_positions)])
        # calculate the final score
        starting_rank[-1].append((1/starting_rank[-1][1])*starting_rank[-1][2]*starting_rank[-1][3]*starting_rank[-1][4])
        # Update Progress Bar
        if showProgress:
            printProgressBarPyCharm(progress, len(_words), prefix='Progress:', suffix='Complete', length=50)
    if showProgress:
        printProgressBarPyCharm(100, 100, prefix='Progress:', suffix='Complete', length=50)
    starting_rank.sort(key=lambda x: x[5], reverse=True)
    return starting_rank


"""
Title           :tinyimagenet_tester.py
Description     :Easy Tiny ImageNet benchmark
Author          :Ilke Cugu
Date Created    :17-06-2019
Date Modified   :02-05-2020
version         :1.4.1
python_version  :3.6.6
"""
import os
import keras
import numpy as np
from overrides import overrides
from keras.utils.data_utils import get_file
from keras.callbacks import LearningRateScheduler
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import load_img, img_to_array
from applications.microresnet.MicroResNet import MicroResNet
from sklearn.model_selection import StratifiedShuffleSplit
from testers.Base_tester import Base_tester

class tinyimagenet_tester(Base_tester):
	def __init__(self, wait=False):
		"""
		Conditional constructor to enable creating testers without immediately triggering the dataset loader.

		# Arguments
			:param wait: (bool) If True, then the constructor will onyl create the instance and
								wait for manual activation to actually load the dataset
		"""
		super(tinyimagenet_tester, self).__init__()
		self.dataset_path = None
		self.x_train_mean = None
		self.label_dict = {}

		if not wait:
			self.activate()

	def activate(self):
		"""
		Call this function to manually start dataset deployment
		"""
		# Deploy the dataset
		self.dim_x = 64
		self.dim_y = 64
		self.dataset = self.load_data()
		(self.x_train, self.y_train), (self.x_val, self.y_val), (self.x_test, self.y_test) = self.dataset
		self.preprocess_dataset()

		# Split the train and validation sets
		self.training_set_size = int(self.x_train.shape[0])
		self.val_set_size = int(self.x_val.shape[0])
		self.test_set_size = int(self.x_test.shape[0])

		# Turn the labels into one-hot-vector form
		self.y_train = keras.utils.to_categorical(self.y_train, self.get_n_classes())
		self.y_val = keras.utils.to_categorical(self.y_val, self.get_n_classes())
		self.y_test = keras.utils.to_categorical(self.y_test, self.get_n_classes())

	@overrides
	def preprocess_dataset(self):
		# Normalize the data
		self.x_train = self.x_train.astype('float32') / 255.0
		self.x_val = self.x_val.astype('float32') / 255.0
		self.x_test = self.x_test.astype('float32') / 255.0

		self.x_train_mean = np.mean(self.x_train, axis=0)
		self.x_train -= self.x_train_mean
		self.x_val -= self.x_train_mean
		self.x_test -= self.x_train_mean

	def load_data(self):
		"""
		Loads tiny-imagenet dataset.

		:return: tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
		"""
		dirname = 'tiny-imagenet-200.zip'
		origin = 'http://cs231n.stanford.edu/tiny-imagenet-200.zip'
		path = get_file(dirname, origin=origin, extract=True, archive_format="zip")
		path = path.split(".zip")[0]
		self.dataset_path = path

		num_train_samples = 100000
		num_test_samples = 10000

		x = np.empty((num_train_samples, self.dim_x, self.dim_y, 3), dtype='uint8')
		y = np.empty((num_train_samples,), dtype='uint8')

		x_test = np.empty((num_test_samples, self.dim_x, self.dim_y, 3), dtype='uint8')
		y_test = np.empty((num_test_samples,), dtype='uint8')

		# Deploy labels
		self.read_labels(path)
		reverse_label_dict = {v: k for k,v in self.label_dict.items()}

		# Gather training data
		counter = 0
		fpath = os.path.join(path, "train")
		for i in range(len(self.label_dict)):
			dir_path = os.path.join(fpath, self.label_dict[i], "images")
			files = os.listdir(dir_path)
			for file in files:
				if file.endswith("JPEG") or file.endswith("jpeg"):
					img_path = os.path.join(dir_path, file)
					img = img_to_array(load_img(img_path))
					x[counter, :, :, :] = img
					y[counter] = i
					counter += 1

		# Then split that into train/val sets
		train_val_split = StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=13)
		for i_train, i_val in train_val_split.split(x, y):
			x_train, x_val = x[i_train], x[i_val]
			y_train, y_val = y[i_train], y[i_val]

		# Gather the original validation data as the new test set
		counter = 0
		fpath = os.path.join(path, "val")
		label_file_path = os.path.join(fpath, "val_annotations.txt")
		with open(label_file_path, "r") as label_file:
			for line in label_file:
				temp = line[:-1].split("\t")
				img_path = os.path.join(fpath, "images", temp[0])
				img = img_to_array(load_img(img_path))
				label = reverse_label_dict[temp[1]]
				x_test[counter, :, :, :] = img
				y_test[counter] = label
				counter += 1

		return (x_train, y_train), (x_val, y_val), (x_test, y_test)

	def load_test_data(self):
		x_test = np.empty((10000, self.dim_x, self.dim_y, 3), dtype='uint8')

		# Gather test data
		counter = 0
		test_img_names = []
		fpath = os.path.join(self.dataset_path, "test", "images")
		files = os.listdir(fpath)
		for file in files:
			if file.endswith("JPEG") or file.endswith("jpeg"):
				img_path = os.path.join(fpath, file)
				img = img_to_array(load_img(img_path))
				test_img_names.append(file)
				x_test[counter, :, :, :] = img
				counter += 1

		# Preprocess the test set
		x_test = x_test.astype('float32') / 255.0
		x_test -= self.x_train_mean

		return x_test, test_img_names

	def read_labels(self, path):
		fpath = os.path.join(path, "wnids.txt")
		with open(fpath, "r") as label_file:
			i = 0
			for line in label_file:
				self.label_dict[i] = line[:-1]
				i += 1

	def createImgGenerator(self):
		return ImageDataGenerator(
			# set input mean to 0 over the dataset
			featurewise_center=False,
			# set each sample mean to 0
			samplewise_center=False,
			# divide inputs by std of dataset
			featurewise_std_normalization=False,
			# divide each input by its std
			samplewise_std_normalization=False,
			# apply ZCA whitening
			zca_whitening=False,
			# epsilon for ZCA whitening
			zca_epsilon=1e-06,
			# randomly rotate images in the range (deg 0 to 180)
			rotation_range=0,
			# randomly shift images horizontally
			width_shift_range=0.1,
			# randomly shift images vertically
			height_shift_range=0.1,
			# set range for random shear
			shear_range=0.,
			# set range for random zoom
			zoom_range=0.,
			# set range for random channel shifts
			channel_shift_range=0.,
			# set mode for filling points outside the input boundaries
			fill_mode='nearest',
			# value used for fill_mode = "constant"
			cval=0.,
			# randomly flip images
			horizontal_flip=True,
			# randomly flip images
			vertical_flip=False,
			# set rescaling factor (applied before any other transformation)
			rescale=None,
			# set function that will be applied on each input
			preprocessing_function=None,
			# image data format, either "channels_first" or "channels_last"
			data_format="channels_last"
		)

	def lr_schedule(self, epoch):
		"""
		Learning rate scheduler for CIFAR-10 as part of callbacks during training

		Adopted from https://keras.io/examples/cifar10_resnet/

		# Arguments
			:param epoch: (int) # of epochs

		:return: new learning rate
		"""
		lr = self.base_lr
		if epoch > 180:
			lr *= 0.5e-3
		elif epoch > 160:
			lr *= 1e-3
		elif epoch > 120:
			lr *= 1e-2
		elif epoch > 80:
			lr *= 1e-1
		return lr

	@overrides
	def get_n_classes(self):
		return 200

	@overrides
	def evaluate(self, model):
		return model.evaluate(self.x_test, self.y_test, verbose=0)

	@overrides
	def predict(self, model):
		return model.predict(self.x_test, verbose=0)

	def print_predictions(self, model_name, preds, img_names):
		file_name = "%s_preds.txt" % model_name
		with open(file_name, "w+") as preds_file:
			for i in range(len(img_names)):
				entry = "%s %s\n" % (img_names[i], np.argmax(preds[i]))
				preds_file.write(entry)

	@overrides
	def run(self, model,
			optimizer="adam",
			lr=1e-3,
			momentum=None,
			decay=None,
			loss='categorical_crossentropy',
			batch_size=128,
			epochs=200,
			verbose=0,
			callbacks=None,
			schedule_lr=True,
			custom_lr_scheduler=None,
			print_preds_for_test_set=False):
		"""
		Runs the benchmark

		# Arguments
			:param model: Keras model (including MicroResNet)
			:param optimizer: (string) name of the selected Keras optimizer
			:param lr: (float) learning rate
			:param momentum: (float) only relevant for the optimization algorithms that use momentum
			:param decay: (float) only relevant for the optimization algorithms that use weight decay
			:param loss: (string) name of the selected Keras loss function
			:param batch_size: (int) # of inputs in a mini-batch
			:param epochs: (int) # of full training passes
			:param verbose: (int) Keras verbose argument
			:param callbacks: list of Keras callbacks
			:param schedule_lr: (bool) enable/disable learning rate scheduler (default or custom)
			:param custom_lr_scheduler: user defined learning rate scheduler
			:param print_preds_for_test_set: (bool) enables printing out the test set predictions of the trained model

		:return: (history, score)
		"""
		# tiny-imagenet Specific configurations
		self.base_lr = lr
		new_callbacks = [] if callbacks is None else callbacks
		if schedule_lr and custom_lr_scheduler is None:
			lr_scheduler = LearningRateScheduler(self.lr_schedule, verbose=verbose)
			new_callbacks.extend([lr_scheduler])
		elif schedule_lr and custom_lr_scheduler is not None:
			new_callbacks.append(custom_lr_scheduler)

		# Compile the model
		optimizer = self.get_optimizer(optimizer, lr=lr, momentum=momentum, decay=decay)
		model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])

		# Training & validation data preparation
		trainImgGenerator = self.createImgGenerator()
		trainGenerator = trainImgGenerator.flow(self.x_train, self.y_train, batch_size=batch_size, shuffle=True, seed=13)

		# Train the model
		_model = model.model if isinstance(model, MicroResNet) else model
		hist = _model.fit_generator(
			trainGenerator,
			epochs=epochs,
			verbose=verbose,
			steps_per_epoch=self.training_set_size // batch_size,
			validation_data=(self.x_val, self.y_val),
			class_weight='auto',
			callbacks=new_callbacks
		)

		# Evaluate the model with the val data
		score = _model.evaluate(self.x_test, self.y_test, verbose=verbose)

		# Print out the model predictions for the test data to upload the tiny-imagenet test server
		if print_preds_for_test_set:
			new_x_test, img_names = self.load_test_data()
			preds = model.predict(new_x_test, verbose=verbose)
			self.print_predictions(model.name, preds, img_names)

		return hist, score


from .oot_constants import *
from .oot_utility import *

from ..utility import *

from bpy.utils import register_class, unregister_class
from io import BytesIO
import bpy, bmesh, os, math, re, shutil, mathutils
from .oot_scene_room import *

ootEnumConveyer = [
	("None", "None", "None"),
	("Land", "Land", "Land"),
	("Water", "Water", "Water"),
]

ootEnumFloorSetting = [
	("Custom", "Custom", "Custom"),
	("0x00", "Default", "Default"),
	("0x05", "Void (Small)", "Void (Small)"),
	("0x06", "Grab Wall", "Grab Wall"),
	("0x08", "Stop Air Momentum", "Stop Air Momentum"),
	("0x09", "Fall Instead Of Jumping", "Fall Instead Of Jumping"),
	("0x0B", "Dive", "Dive"),
	("0x0C", "Void (Large)", "Void (Large)"),
]

ootEnumWallSetting = [
	("Custom", "Custom", "Custom"),
	("0x00", "None", "None"),
	("0x01", "No Ledge Grab", "No Ledge Grab"),
	("0x02", "Ladder", "Ladder"),
	("0x03", "Ladder Top", "Ladder Top"),
	("0x04", "Vines", "Vines"),
	("0x05", "Crawl Space", "Crawl Space"),
	("0x06", "Crawl Space 2", "Crawl Space 2"),
	("0x07", "Push Block", "Push Block"),
]

ootEnumFloorProperty = [
	("Custom", "Custom", "Custom"),
	("0x00", "None", "None"),
	("0x01", "Haunted Wasteland Camera", "Haunted Wasteland Camera"),
	("0x02", "Hurt Floor (Spikes)", "Hurt Floor (Spikes)"),
	("0x03", "Hurt Floor (Lava)", "Hurt Floor (Lava)"),
	("0x04", "Shallow Sand", "Shallow Sand"),
	("0x05", "Slippery", "Slippery"),
	("0x06", "No Fall Damage", "No Fall Damage"),
	("0x07", "Quicksand Crossing (Epona Uncrossable)", "Quicksand Crossing (Epona Uncrossable)"),
	("0x08", "Jabu Jabu's Belly", "Jabu Jabu's Belly"),
	("0x09", "Void", "Void"),
	("0x0A", "Link Looks Up", "Link Looks Up"),
	("0x0B", "Quicksand Crossing (Epona Crossable)", "Quicksand Crossing (Epona Crossable)")
]

ootEnumCollisionTerrain = [
	("Custom", "Custom", "Custom"),
	("0x00", "Walkable", "Walkable"),
	("0x01", "Steep", "Steep"),
	("0x02", "Walkable (Preserves Exit Flags)", "Walkable (Preserves Exit Flags)"),
	("0x03", "Walkable (?)", "Walkable (?)"),
]

ootEnumCollisionSound = [
	("Custom", "Custom", "Custom"),
	("0x00", "Earth", "Earth"),
	("0x01", "Sand", "Sand"),
	("0x02", "Stone", "Stone"),
	("0x03", "Wet Stone", "Wet Stone"),
	("0x04", "Shallow Water", "Shallow Water"),
	("0x05", "Water", "Water"),
	("0x06", "Grass", "Grass"),
	("0x07", "Lava/Goo", "Lava/Goo"),
	("0x08", "Earth", "Earth"),
	("0x09", "Wooden Plank", "Wooden Plank"),
	("0x0A", "Packed Earth/Wood", "Packed Earth/Wood"),
	("0x0B", "Earth", "Earth"),
	("0x0C", "Ceramic/Ice", "Ceramic/Ice"),
	("0x0D", "Loose Earth", "Loose Earth"),
]

ootEnumConveyorSpeed = [
	("Custom", "Custom", "Custom"),
	("0x00", "None", "None"),
	("0x01", "Slow", "Slow"),
	("0x02", "Medium", "Medium"),
	("0x03", "Fast", "Fast"),
]

ootEnumCameraSType = [
	("Custom", "Custom", "Custom"),
	("CAM_SET_NONE", "None", "None"),
    ("CAM_SET_NORMAL0", "Normal0", "Normal0"),
    ("CAM_SET_NORMAL1", "Normal1", "Normal1"),
    ("CAM_SET_DUNGEON0", "Dungeon0", "Dungeon0"),
    ("CAM_SET_DUNGEON1", "Dungeon1", "Dungeon1"),
    ("CAM_SET_NORMAL3", "Normal3", "Normal3"),
    ("CAM_SET_HORSE0", "Horse0", "Horse0"),
    ("CAM_SET_BOSS_GOMA", "Boss_goma", "Boss_goma"),
    ("CAM_SET_BOSS_DODO", "Boss_dodo", "Boss_dodo"),
    ("CAM_SET_BOSS_BARI", "Boss_bari", "Boss_bari"),
    ("CAM_SET_BOSS_FGANON", "Boss_fganon", "Boss_fganon"),
    ("CAM_SET_BOSS_BAL", "Boss_bal", "Boss_bal"),
    ("CAM_SET_BOSS_SHADES", "Boss_shades", "Boss_shades"),
    ("CAM_SET_BOSS_MOFA", "Boss_mofa", "Boss_mofa"),
    ("CAM_SET_TWIN0", "Twin0", "Twin0"),
    ("CAM_SET_TWIN1", "Twin1", "Twin1"),
    ("CAM_SET_BOSS_GANON1", "Boss_ganon1", "Boss_ganon1"),
    ("CAM_SET_BOSS_GANON2", "Boss_ganon2", "Boss_ganon2"),
    ("CAM_SET_TOWER0", "Tower0", "Tower0"),
    ("CAM_SET_TOWER1", "Tower1", "Tower1"),
    ("CAM_SET_FIXED0", "Fixed0", "Fixed0"),
    ("CAM_SET_FIXED1", "Fixed1", "Fixed1"),
    ("CAM_SET_CIRCLE0", "Circle0", "Circle0"),
    ("CAM_SET_CIRCLE2", "Circle2", "Circle2"),
    ("CAM_SET_CIRCLE3", "Circle3", "Circle3"),
    ("CAM_SET_PREREND0", "Prerend0", "Prerend0"),
    ("CAM_SET_PREREND1", "Prerend1", "Prerend1"),
    ("CAM_SET_PREREND3", "Prerend3", "Prerend3"),
    ("CAM_SET_DOOR0", "Door0", "Door0"),
    ("CAM_SET_DOORC", "Doorc", "Doorc"),
    ("CAM_SET_RAIL3", "Rail3", "Rail3"),
    ("CAM_SET_START0", "Start0", "Start0"),
    ("CAM_SET_START1", "Start1", "Start1"),
    ("CAM_SET_FREE0", "Free0", "Free0"),
    ("CAM_SET_FREE2", "Free2", "Free2"),
    ("CAM_SET_CIRCLE4", "Circle4", "Circle4"),
    ("CAM_SET_CIRCLE5", "Circle5", "Circle5"),
    ("CAM_SET_DEMO0", "Demo0", "Demo0"),
    ("CAM_SET_DEMO1", "Demo1", "Demo1"),
    ("CAM_SET_MORI1", "Mori1", "Mori1"),
    ("CAM_SET_ITEM0", "Item0", "Item0"),
    ("CAM_SET_ITEM1", "Item1", "Item1"),
    ("CAM_SET_DEMO3", "Demo3", "Demo3"),
    ("CAM_SET_DEMO4", "Demo4", "Demo4"),
    ("CAM_SET_UFOBEAN", "Ufobean", "Ufobean"),
    ("CAM_SET_LIFTBEAN", "Liftbean", "Liftbean"),
    ("CAM_SET_SCENE0", "Scene0", "Scene0"),
    ("CAM_SET_SCENE1", "Scene1", "Scene1"),
    ("CAM_SET_HIDAN1", "Hidan1", "Hidan1"),
    ("CAM_SET_HIDAN2", "Hidan2", "Hidan2"),
    ("CAM_SET_MORI2", "Mori2", "Mori2"),
    ("CAM_SET_MORI3", "Mori3", "Mori3"),
    ("CAM_SET_TAKO", "Tako", "Tako"),
    ("CAM_SET_SPOT05A", "Spot05a", "Spot05a"),
    ("CAM_SET_SPOT05B", "Spot05b", "Spot05b"),
    ("CAM_SET_HIDAN3", "Hidan3", "Hidan3"),
    ("CAM_SET_ITEM2", "Item2", "Item2"),
    ("CAM_SET_CIRCLE6", "Circle6", "Circle6"),
    ("CAM_SET_NORMAL2", "Normal2", "Normal2"),
    ("CAM_SET_FISHING", "Fishing", "Fishing"),
    ("CAM_SET_DEMOC", "Democ", "Democ"),
    ("CAM_SET_UO_FIBER", "Uo_fiber", "Uo_fiber"),
    ("CAM_SET_DUNGEON2", "Dungeon2", "Dungeon2"),
    ("CAM_SET_TEPPEN", "Teppen", "Teppen"),
    ("CAM_SET_CIRCLE7", "Circle7", "Circle7"),
    ("CAM_SET_NORMAL4", "Normal4", "Normal4"),
]

class OOTCollisionVertex:
	def __init__(self, position):
		self.position = position

class OOTCollisionPolygon:
	def __init__(self, indices, normal, distance):
		self.indices = indices
		self.normal = normal
		self.distance = distance

	def convertShort02(self, ignoreCamera, ignoreActor, ignoreProjectile):
		vertPart = self.indices[0] & 0x1FFF
		colPart = (1 if ignoreCamera else 0) +\
			(2 if ignoreActor else 0) +\
			(4 if ignoreProjectile else 0)

		return vertPart | (colPart << 13)

	def convertShort04(self, enableConveyor):
		vertPart = self.indices[1] & 0x1FFF
		conveyorPart = 1 if enableConveyor else 0

		return vertPart | (conveyorPart << 13)

	def convertShort06(self):
		return self.indices[2] & 0x1FFF

class OOTPolygonType:
	def __eq__(self, other):
		return \
			self.eponaBlock == other.eponaBlock and\
			self.decreaseHeight == other.decreaseHeight and\
			self.floorSetting == other.floorSetting and\
			self.wallSetting == other.wallSetting and\
			self.floorProperty == other.floorProperty and\
			self.exitID == other.exitID and\
			self.cameraID == other.cameraID and\
			self.isWallDamage == other.isWallDamage and\
			self.enableConveyor == other.enableConveyor and\
			self.conveyorRotation == other.conveyorRotation and\
			self.conveyorSpeed == other.conveyorSpeed and\
			self.hookshotable == other.hookshotable and\
			self.echo == other.echo and\
			self.lightingSetting == other.lightingSetting and\
			self.terrain == other.terrain and\
			self.sound == other.sound and\
			self.ignoreCameraCollision == other.ignoreCameraCollision and\
			self.ignoreActorCollision == other.ignoreActorCollision and\
			self.ignoreProjectileCollision == other.ignoreProjectileCollision

	def __ne__(self, other):
		return \
			self.eponaBlock != other.eponaBlock or\
			self.decreaseHeight != other.decreaseHeight or\
			self.floorSetting != other.floorSetting or\
			self.wallSetting != other.wallSetting or\
			self.floorProperty != other.floorProperty or\
			self.exitID != other.exitID or\
			self.cameraID != other.cameraID or\
			self.isWallDamage != other.isWallDamage or\
			self.enableConveyor != other.enableConveyor or\
			self.conveyorRotation != other.conveyorRotation or\
			self.conveyorSpeed != other.conveyorSpeed or\
			self.hookshotable != other.hookshotable or\
			self.echo != other.echo or\
			self.lightingSetting != other.lightingSetting or\
			self.terrain != other.terrain or\
			self.sound != other.sound or\
			self.ignoreCameraCollision != other.ignoreCameraCollision or\
			self.ignoreActorCollision != other.ignoreActorCollision or\
			self.ignoreProjectileCollision != other.ignoreProjectileCollision

	def __hash__(self):
		return hash((self.eponaBlock,
			self.decreaseHeight,
			self.floorSetting,
			self.wallSetting,
			self.floorProperty,
			self.exitID,
			self.cameraID,
			self.isWallDamage,
			self.enableConveyor,
			self.conveyorRotation,
			self.conveyorSpeed,
			self.hookshotable,
			self.echo,
			self.lightingSetting,
			self.terrain,
			self.sound,
			self.ignoreCameraCollision,
			self.ignoreActorCollision,
			self.ignoreProjectileCollision))

	def __init__(self):
		self.eponaBlock = None #eponaBlock
		self.decreaseHeight = None #decreaseHeight
		self.floorSetting = None #floorSetting
		self.wallSetting = None #wallSetting
		self.floorProperty = None #floorProperty
		self.exitID = None #exitID
		self.cameraID = None #cameraID
		self.isWallDamage = None #isWallDamage
		self.enableConveyor = None
		self.conveyorRotation = None #conveyorDirection
		self.conveyorSpeed = None #conveyorSpeed
		self.hookshotable = None #hookshotable
		self.echo = None #echo
		self.lightingSetting = None #lightingSetting
		self.terrain = None #terrain
		self.sound = None #sound
		self.ignoreCameraCollision = None
		self.ignoreActorCollision = None
		self.ignoreProjectileCollision = None

	def convertHigh(self):
		value = ((1 if self.eponaBlock else 0) << 31) |\
			((1 if self.decreaseHeight else 0) << 30) |\
			(int(self.floorSetting, 16) << 26) |\
			(int(self.wallSetting, 16) << 21) |\
			(int(self.floorProperty, 16) << 13) |\
			(self.exitID << 8) |\
			(self.cameraID << 0)

		return convertIntTo2sComplement(value, 4, False)

	def convertLow(self):
		value = ((1 if self.isWallDamage else 0) << 27) |\
			(self.conveyorRotation << 21) |\
			(self.conveyorSpeed << 18) |\
			((1 if self.hookshotable else 0) << 17) |\
			(int(self.echo, 16) << 11) |\
			(self.lightingSetting << 6) |\
			(int(self.terrain, 16) << 4) |\
			(int(self.sound, 16) << 0)

		return convertIntTo2sComplement(value, 4, False)

class OOTCollision:
	def __init__(self, ownerName):
		self.ownerName = ownerName
		self.bounds = []
		self.vertices = []
		# dict of polygon type : polygon list
		self.polygonGroups = {}
		self.cameraData = None
		self.waterBoxes = []

	def polygonCount(self):
		count = 0
		for polygonType, polygons in self.polygonGroups.items():
			count += len(polygons)
		return count

	def headerName(self):
		return self.ownerName + "_collisionHeader"

	def verticesName(self):
		return self.ownerName + "_vertices"

	def polygonsName(self):
		return self.ownerName + "_polygons"

	def polygonTypesName(self):
		return self.ownerName + "_polygonTypes"

	def camDataName(self):
		return self.ownerName + "_camData"

	def waterBoxesName(self):
		return self.ownerName + "_waterBoxes"

def getPolygonType(collisionProp):
	polygonType = OOTPolygonType()
	polygonType.ignoreCameraCollision = collisionProp.ignoreCameraCollision
	polygonType.ignoreActorCollision = collisionProp.ignoreActorCollision
	polygonType.ignoreProjectileCollision = collisionProp.ignoreProjectileCollision
	polygonType.eponaBlock = collisionProp.eponaBlock
	polygonType.decreaseHeight = collisionProp.decreaseHeight
	polygonType.floorSetting = getCustomProperty(collisionProp, 'floorSetting')
	polygonType.wallSetting = getCustomProperty(collisionProp, 'wallSetting')
	polygonType.floorProperty = getCustomProperty(collisionProp, 'floorProperty')
	polygonType.exitID = collisionProp.exitID
	polygonType.cameraID = collisionProp.cameraID
	polygonType.isWallDamage = collisionProp.isWallDamage
	polygonType.enableConveyor = collisionProp.conveyorOption == "Land"
	if collisionProp.conveyorOption != "None":
		polygonType.conveyorRotation = int(collisionProp.conveyorRotation / (2 * math.pi) * 0x3F)
		polygonType.conveyorSpeed = int(getCustomProperty(collisionProp, 'conveyorSpeed'), 16) + \
			(4 if collisionProp.conveyorKeepMomentum else 0)
	else:
		polygonType.conveyorRotation = 0
		polygonType.conveyorSpeed = 0

	polygonType.hookshotable = collisionProp.hookshotable
	polygonType.echo = collisionProp.echo
	polygonType.lightingSetting = collisionProp.lightingSetting
	polygonType.terrain = getCustomProperty(collisionProp, "terrain")
	polygonType.sound = getCustomProperty(collisionProp, "sound")
	return polygonType

class OOTWaterBox(BoxEmpty):
	def __init__(self, roomIndex, lightingSetting, cameraSetting, position, scale, emptyScale):
		self.roomIndex = roomIndex
		self.lightingSetting = lightingSetting
		self.cameraSetting = cameraSetting
		BoxEmpty.__init__(self, position, scale, emptyScale)

	def propertyData(self):
		value = (int(self.roomIndex) << 13) |\
			(self.lightingSetting << 8) |\
			(self.cameraSetting << 0)
		return convertIntTo2sComplement(value, 4, False)

class OOTCameraData:
	def __init__(self, ownerName):
		self.ownerName = ownerName
		self.camPosDict = {}

	def camDataName(self):
		return self.ownerName + "_camData"

	def camPositionsName(self):
		return self.ownerName + "_camPosData"

	def validateCamPositions(self):
		count = 0
		while count < len(self.camPosDict):
			if count not in self.camPosDict:
				raise PluginError("Error: Camera positions do not have a consecutive list of indices.\n" +\
					"Missing index: " + str(count))
			count = count + 1

class OOTCameraPosData:
	def __init__(self, camSType, hasPositionData, position, rotation, fov, jfifID):
		self.camSType = camSType
		self.position = position
		self.rotation = rotation
		self.fov = fov
		self.jfifID = jfifID
		self.unknown = -1
		self.hasPositionData = hasPositionData

class OOTCameraPositionProperty(bpy.types.PropertyGroup):
	index : bpy.props.IntProperty(min = 0)
	jfifID : bpy.props.StringProperty(default = "-1")
	camSType : bpy.props.EnumProperty(items = ootEnumCameraSType, default = 'CAM_SET_NONE')
	camSTypeCustom : bpy.props.StringProperty(default = "CAM_SET_NONE")
	hasPositionData : bpy.props.BoolProperty(default = True, name = "Has Position Data")

class OOTCameraPositionPropertyRef(bpy.types.PropertyGroup):
	camera : bpy.props.PointerProperty(type = bpy.types.Camera)

class OOTMaterialCollisionProperty(bpy.types.PropertyGroup):
	expandTab : bpy.props.BoolProperty()

	ignoreCameraCollision : bpy.props.BoolProperty()
	ignoreActorCollision : bpy.props.BoolProperty()
	ignoreProjectileCollision : bpy.props.BoolProperty()

	eponaBlock : bpy.props.BoolProperty()
	decreaseHeight : bpy.props.BoolProperty()
	floorSettingCustom : bpy.props.StringProperty(default = '0x00')
	floorSetting : bpy.props.EnumProperty(items = ootEnumFloorSetting, default = "0x00")
	wallSettingCustom : bpy.props.StringProperty(default = '0x00')
	wallSetting : bpy.props.EnumProperty(items = ootEnumWallSetting, default = "0x00")
	floorPropertyCustom : bpy.props.StringProperty(default = '0x00')
	floorProperty : bpy.props.EnumProperty(items = ootEnumFloorProperty, default = "0x00")
	exitID : bpy.props.IntProperty(default = 0, min = 0)
	cameraID : bpy.props.IntProperty(default = 0, min = 0)
	isWallDamage : bpy.props.BoolProperty()
	conveyorOption : bpy.props.EnumProperty(items = ootEnumConveyer)
	conveyorRotation : bpy.props.FloatProperty(min = 0, max = 2 * math.pi, subtype = "ANGLE")
	conveyorSpeed : bpy.props.EnumProperty(items = ootEnumConveyorSpeed, default = "0x00")
	conveyorSpeedCustom : bpy.props.StringProperty(default = "0x00")
	conveyorKeepMomentum : bpy.props.BoolProperty()
	hookshotable : bpy.props.BoolProperty()
	echo : bpy.props.StringProperty(default = "0x00")
	lightingSetting : bpy.props.IntProperty(default = 0, min = 0)
	terrainCustom : bpy.props.StringProperty(default = '0x00')
	terrain : bpy.props.EnumProperty(items = ootEnumCollisionTerrain, default = "0x00")
	soundCustom : bpy.props.StringProperty(default = '0x00')
	sound : bpy.props.EnumProperty(items = ootEnumCollisionSound, default = "0x00")

class OOTWaterBoxProperty(bpy.types.PropertyGroup):
	lighting : bpy.props.IntProperty(name = 'Lighting', min = 0)
	camera: bpy.props.IntProperty(name = "Camera", min = 0)

def drawWaterBoxProperty(layout, waterBoxProp):
	box = layout.column()
	#box.box().label(text = "Properties")
	prop_split(box, waterBoxProp, 'lighting', "Lighting")
	prop_split(box, waterBoxProp, 'camera', "Camera")
	box.label(text = "Defined by top face of box empty.")
	box.label(text = "No rotation allowed.")

def drawCameraPosProperty(layout, cameraRefProp, index, headerIndex, objName):
	camBox = layout.box()
	prop_split(camBox, cameraRefProp, "camera", "Camera " + str(index))
	drawCollectionOps(camBox, index, "Camera Position", headerIndex, objName)

class OOT_CameraPosPanel(bpy.types.Panel):
	bl_label = "Camera Position Inspector"
	bl_idname = "OBJECT_PT_OOT_Camera_Position_Inspector"
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "object"
	bl_options = {'HIDE_HEADER'}

	@classmethod
	def poll(cls, context):
		return (context.scene.gameEditorMode == "OOT" and isinstance(context.object.data, bpy.types.Camera))

	def draw(self, context):
		box = self.layout.box()
		obj = context.object

		box.box().label(text = "Camera Data")
		drawEnumWithCustom(box, obj.ootCameraPositionProperty, "camSType", "Camera S Type", "")
		prop_split(box, obj.ootCameraPositionProperty, "index", "Camera Index")
		if obj.ootCameraPositionProperty.hasPositionData:
			prop_split(box, obj.data, "angle", "Field Of View")
			prop_split(box, obj.ootCameraPositionProperty, "jfifID", "JFIF ID")
		box.prop(obj.ootCameraPositionProperty, 'hasPositionData')

		#drawParentSceneRoom(box, context.object)

class OOT_CollisionPanel(bpy.types.Panel):
	bl_label = "Collision Inspector"
	bl_idname = "MATERIAL_PT_OOT_Collision_Inspector"
	bl_space_type = 'PROPERTIES'
	bl_region_type = 'WINDOW'
	bl_context = "material"
	bl_options = {'HIDE_HEADER'}

	@classmethod
	def poll(cls, context):
		return (context.scene.gameEditorMode == "OOT" and context.material is not None)

	def draw(self, context):
		box = self.layout.box().column()
		collisionProp = context.material.ootCollisionProperty

		box.prop(collisionProp, 'expandTab', text = "OOT Collision Properties",
			icon = 'TRIA_DOWN' if collisionProp.expandTab else \
			'TRIA_RIGHT')
		if collisionProp.expandTab:
			prop_split(box, collisionProp, "exitID", "Exit ID")
			prop_split(box, collisionProp, "cameraID", "Camera ID")
			prop_split(box, collisionProp, "echo", "Echo")
			prop_split(box, collisionProp, "lightingSetting", "Lighting")
			drawEnumWithCustom(box, collisionProp, "terrain", "Terrain", "")
			drawEnumWithCustom(box, collisionProp, "sound", "Sound", "")

			box.prop(collisionProp, "eponaBlock", text = "Blocks Epona")
			box.prop(collisionProp, "decreaseHeight", text = "Decrease Height 1 Unit")
			box.prop(collisionProp, "isWallDamage", text = "Is Wall Damage")
			box.prop(collisionProp, "hookshotable", text = "Hookshotable")

			drawEnumWithCustom(box, collisionProp, "floorSetting", "Floor Setting", "")
			drawEnumWithCustom(box, collisionProp, "wallSetting", "Wall Setting", "")
			drawEnumWithCustom(box, collisionProp, "floorProperty", "Floor Property", "")

			box.prop(collisionProp, "ignoreCameraCollision", text = "Ignore Camera Collision")
			box.prop(collisionProp, "ignoreActorCollision", text = "Ignore Actor Collision")
			box.prop(collisionProp, "ignoreProjectileCollision", text = "Ignore Projectile Collision")
			prop_split(box, collisionProp, "conveyorOption", "Conveyor Option")
			if collisionProp.conveyorOption != "None":
				prop_split(box, collisionProp, "conveyorRotation", "Conveyor Rotation")
				drawEnumWithCustom(box, collisionProp, 'conveyorSpeed', "Conveyor Speed", "")
				if collisionProp.conveyorSpeed != "Custom":
					box.prop(collisionProp, "conveyorKeepMomentum", text = "Keep Momentum")

# water boxes handled by level writer
def exportCollisionCommon(collision, obj, transformMatrix, includeChildren, name):
	bpy.ops.object.select_all(action = 'DESELECT')
	obj.select_set(True)

	# dict of collisionType : faces
	collisionDict = {}

	addCollisionTriangles(obj, collisionDict, includeChildren, transformMatrix, collision.bounds)
	for polygonType, faces in collisionDict.items():
		collision.polygonGroups[polygonType] = []
		for (faceVerts, normal, distance) in faces:
			indices = []
			for roundedPosition in faceVerts:
				index = collisionVertIndex(roundedPosition, collision.vertices)
				if index is None:
					collision.vertices.append(OOTCollisionVertex(roundedPosition))
					indices.append(len(collision.vertices) - 1)
				else:
					indices.append(index)
			collision.polygonGroups[polygonType].append(OOTCollisionPolygon(indices, normal, distance))

def exportCollisionToC(originalObj, transformMatrix, includeChildren, name, isCustomExport, folderName,
	exportPath):
	collision = OOTCollision(name)
	collision.cameraData = OOTCameraData(name)

	if bpy.context.scene.exportHiddenGeometry:
		hiddenObjs = unhideAllAndGetHiddenList(bpy.context.scene)

	# Don't remove ignore_render, as we want to resuse this for collision
	obj, allObjs = \
		ootDuplicateHierarchy(originalObj, None, True, OOTObjectCategorizer())

	if bpy.context.scene.exportHiddenGeometry:
		hideObjsInList(hiddenObjs)

	try:
		exportCollisionCommon(collision, obj, transformMatrix, includeChildren, name)
		ootCleanupScene(originalObj, allObjs)
	except Exception as e:
		ootCleanupScene(originalObj, allObjs)
		raise Exception(str(e))

	collisionC = ootCollisionToC(collision)

	data = CData()
	data.source += '#include "ultra64.h"\n#include "z64.h"\n#include "macros.h"\n'
	if not isCustomExport:
		data.source += '#include "' + folderName + '.h"\n\n'
	else:
		data.source += '\n'

	data.append(collisionC)

	path = ootGetPath(exportPath, isCustomExport, 'assets/objects/', folderName, False, False)
	writeCData(data,
		os.path.join(path, name + '.h'),
		os.path.join(path, name + '.c'))

	if not isCustomExport:
		addIncludeFiles(folderName, path, name)

def updateBounds(position, bounds):
	if len(bounds) == 0:
		bounds.append([position[0], position[1], position[2]])
		bounds.append([position[0], position[1], position[2]])
		return

	minBounds = bounds[0]
	maxBounds = bounds[1]
	for i in range(3):
		if position[i] < minBounds[i]:
			minBounds[i] = position[i]
		if position[i] > maxBounds[i]:
			maxBounds[i] = position[i]

def addCollisionTriangles(obj, collisionDict, includeChildren, transformMatrix, bounds):
	if isinstance(obj.data, bpy.types.Mesh) and not obj.ignore_collision:
		if len(obj.data.materials) == 0:
			raise PluginError(obj.name + " must have a material associated with it.")
		obj.data.calc_loop_triangles()
		for face in obj.data.loop_triangles:
			material = obj.material_slots[face.material_index].material
			polygonType = getPolygonType(material.ootCollisionProperty)

			planePoint = transformMatrix @ obj.data.vertices[face.vertices[0]].co
			(x1, y1, z1) = roundPosition(planePoint)
			(x2, y2, z2) = roundPosition(transformMatrix @ obj.data.vertices[face.vertices[1]].co)
			(x3, y3, z3) = roundPosition(transformMatrix @ obj.data.vertices[face.vertices[2]].co)

			updateBounds((x1, y1, z1), bounds)
			updateBounds((x2, y2, z2), bounds)
			updateBounds((x3, y3, z3), bounds)

			faceNormal = (transformMatrix.inverted().transposed() @ face.normal).normalized()
			normal = convertNormalizedVectorToShort(faceNormal)
			distance = int(round(-1 * (
				faceNormal[0] * planePoint[0] + \
				faceNormal[1] * planePoint[1] + \
				faceNormal[2] * planePoint[2])))
			distance = convertIntTo2sComplement(distance, 2, True)

			nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2)
			ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2)
			nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)
			magSqr = nx * nx + ny * ny + nz * nz

			if magSqr <= 0:
				print("Ignore denormalized triangle.")
				continue

			if polygonType not in collisionDict:
				collisionDict[polygonType] = []

			positions = sorted((
				(x1, y1, z1),
				(x2, y2, z2),
				(x3, y3, z3)), key=lambda x: x[1]) # sort by min y to avoid minY bug

			collisionDict[polygonType].append((positions, normal, distance))

	if includeChildren:
		for child in obj.children:
			addCollisionTriangles(child, collisionDict, includeChildren, transformMatrix @ child.matrix_local, bounds)

def roundPosition(position):
	#return [int.from_bytes(int(round(value)).to_bytes(2, 'big', signed = True), 'big') for value in position]
	return (int(round(position[0])),
		int(round(position[1])),
		int(round(position[2])))

def collisionVertIndex(vert, vertArray):
	for i in range(len(vertArray)):
		colVert = vertArray[i]
		if colVert.position == vert:
			return i
	return None

def ootCollisionVertexToC(vertex):
	return "{ " + str(vertex.position[0]) + ", " +\
		str(vertex.position[1]) + ", " +\
		str(vertex.position[2]) + " },\n"

def ootCollisionPolygonToC(polygon, ignoreCamera, ignoreActor, ignoreProjectile, enableConveyor, polygonTypeIndex):
	return "{ " + format(polygonTypeIndex, "#06x") + ', ' +\
		format(polygon.convertShort02(ignoreCamera, ignoreActor, ignoreProjectile), "#06x") + ', ' +\
		format(polygon.convertShort04(enableConveyor), "#06x") + ', ' +\
		format(polygon.convertShort06(), "#06x") + ', ' +\
		format(polygon.normal[0], "#06x") + ', ' +\
		format(polygon.normal[1], "#06x") + ', ' +\
		format(polygon.normal[2], "#06x") + ', ' +\
		format(polygon.distance, "#06x") + ' },\n'

def ootPolygonTypeToC(polygonType):
	return " " + format(polygonType.convertHigh(), "#010x") + ', ' +\
		format(polygonType.convertLow(), "#010x") + ',\n'

def ootWaterBoxToC(waterBox):
	return "{ " + str(waterBox.low[0]) + ", " +\
		str(waterBox.height) + ", " +\
		str(waterBox.low[1]) + ", " +\
		str(waterBox.high[0] - waterBox.low[0]) + ", " +\
		str(waterBox.high[1] - waterBox.low[1]) + ", " +\
		format(waterBox.propertyData(), "#010x") + ' },\n'

def ootCameraDataToC(camData):
	posC = CData()
	camC = CData()
	if len(camData.camPosDict) > 0:

		camDataName = "CamData " + camData.camDataName() + "[" + str(len(camData.camPosDict)) + "]"

		camC.source = camDataName + ' = {\n'
		camC.header = "extern " + camDataName + ';\n'

		camPosIndex = 0
		for i in range(len(camData.camPosDict)):
			camC.source += '\t' + ootCameraEntryToC(camData.camPosDict[i], camData, camPosIndex)
			if camData.camPosDict[i].hasPositionData:
				posC.source += ootCameraPosToC(camData.camPosDict[i])
				camPosIndex += 3
		posC.source += '};\n\n'
		camC.source += '};\n\n'

		posDataName = "Vec3s " + camData.camPositionsName() + '[' + str(camPosIndex) + ']'
		posC.header = "extern " + posDataName + ';\n'
		posC.source = posDataName + " = {\n" + posC.source

	posC.append(camC)
	return posC

def ootCameraPosToC(camPos):
	return "\t{ " +\
		str(camPos.position[0]) + ', ' +\
		str(camPos.position[1]) + ', ' +\
		str(camPos.position[2]) + ' },\n\t{ ' +\
		str(camPos.rotation[0]) + ', ' +\
		str(camPos.rotation[1]) + ', ' +\
		str(camPos.rotation[2]) + ' },\n\t{ ' +\
		str(camPos.fov) + ', ' +\
		str(camPos.jfifID) + ', ' +\
		str(camPos.unknown) + ' },\n'

def ootCameraEntryToC(camPos, camData, camPosIndex):
	return "{ " +\
		str(camPos.camSType) + ', ' +\
		('3' if camPos.hasPositionData else '0') + ', ' +\
		(("&" + camData.camPositionsName()  + '[' + str(camPosIndex) + ']')
		if camPos.hasPositionData else "0") + ' },\n'

def ootCollisionToC(collision):
	data = CData()

	data.append(ootCameraDataToC(collision.cameraData))

	if len(collision.polygonGroups) > 0:
		data.header += "extern u32 " + collision.polygonTypesName() + "[];\n"
		data.header += "extern CollisionPoly " + collision.polygonsName() + "[];\n"
		polygonTypeC = "u32 " + collision.polygonTypesName() + "[] = {\n"
		polygonC = "CollisionPoly " + collision.polygonsName() + "[] = {\n"
		polygonIndex = 0
		for polygonType, polygons in collision.polygonGroups.items():
			polygonTypeC += '\t' + ootPolygonTypeToC(polygonType)
			for polygon in polygons:
				polygonC += '\t' + ootCollisionPolygonToC(polygon,
					polygonType.ignoreCameraCollision,
					polygonType.ignoreActorCollision,
					polygonType.ignoreProjectileCollision,
					polygonType.enableConveyor,
					polygonIndex)
			polygonIndex += 1
		polygonTypeC += '};\n\n'
		polygonC += '};\n\n'

		data.source += polygonTypeC + polygonC
		polygonTypesName = collision.polygonTypesName()
		polygonsName = collision.polygonsName()
	else:
		polygonTypesName = '0'
		polygonsName = '0'

	if len(collision.vertices) > 0:
		data.header += "extern Vec3s " + collision.verticesName() + "[" + str(len(collision.vertices)) + "];\n"
		data.source += "Vec3s " + collision.verticesName() + "[" + str(len(collision.vertices)) + "] = {\n"
		for vertex in collision.vertices:
			data.source += '\t' + ootCollisionVertexToC(vertex)
		data.source += '};\n\n'
		collisionVerticesName = collision.verticesName()
	else:
		collisionVerticesName = '0'

	if len(collision.waterBoxes) > 0:
		data.header += "extern WaterBox " + collision.waterBoxesName() + "[];\n"
		data.source += "WaterBox " + collision.waterBoxesName() + "[] = {\n"
		for waterBox in collision.waterBoxes:
			data.source += '\t' + ootWaterBoxToC(waterBox)
		data.source += '};\n\n'
		waterBoxesName = collision.waterBoxesName()
	else:
		waterBoxesName = '0'

	if len(collision.cameraData.camPosDict) > 0:
		camDataName = "&" + collision.camDataName()
	else:
		camDataName = '0'

	data.header += "extern CollisionHeader " + collision.headerName() + ';\n'
	data.source += "CollisionHeader " + collision.headerName() + ' = { '

	if len(collision.bounds) == 2:
		for bound in range(2): # min, max bound
			for field in range(3): # x, y, z
				data.source += str(collision.bounds[bound][field]) + ', '
	else:
		data.source += '0, 0, 0, 0, 0, 0, '

	data.source += \
		str(len(collision.vertices)) + ', ' +\
		collisionVerticesName + ', ' +\
		str(collision.polygonCount()) + ", " +\
		polygonsName + ', ' +\
		polygonTypesName + ', ' +\
		camDataName + ', ' +\
		str(len(collision.waterBoxes)) + ", " +\
		waterBoxesName + ' };\n\n'

	return data

class OOT_ExportCollision(bpy.types.Operator):
	# set bl_ properties
	bl_idname = 'object.oot_export_collision'
	bl_label = "Export Collision"
	bl_options = {'REGISTER', 'UNDO', 'PRESET'}

	def execute(self, context):
		obj = None
		if context.mode != 'OBJECT':
			bpy.ops.object.mode_set(mode = "OBJECT")
		if len(context.selected_objects) == 0:
			raise PluginError("No object selected.")
		obj = context.active_object
		if type(obj.data) is not bpy.types.Mesh:
			raise PluginError("No mesh object selected.")

		finalTransform = mathutils.Matrix.Scale(context.scene.ootActorBlenderScale, 4)

		try:
			scaleValue = bpy.context.scene.ootBlenderScale
			finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector((
				scaleValue, scaleValue, scaleValue))).to_4x4()

			includeChildren = context.scene.ootColIncludeChildren
			name = context.scene.ootColName
			isCustomExport = context.scene.ootColCustomExport
			folderName = context.scene.ootColFolder
			exportPath = bpy.path.abspath(context.scene.ootColExportPath)

			filepath = ootGetObjectPath(isCustomExport, exportPath, folderName)
			exportCollisionToC(obj, finalTransform, includeChildren, name, isCustomExport, folderName,
				filepath)

			self.report({'INFO'}, 'Success!')
			return {'FINISHED'}

		except Exception as e:
			if context.mode != 'OBJECT':
				bpy.ops.object.mode_set(mode = 'OBJECT')
			raisePluginError(self, e)
			return {'CANCELLED'} # must return a set

class OOT_ExportCollisionPanel(bpy.types.Panel):
	bl_idname = "OOT_PT_export_collision"
	bl_label = "OOT Collision Exporter"
	bl_space_type = 'VIEW_3D'
	bl_region_type = 'UI'
	bl_category = 'OOT'

	@classmethod
	def poll(cls, context):
		return True

	# called every frame
	def draw(self, context):
		col = self.layout.column()
		col.operator(OOT_ExportCollision.bl_idname)

		prop_split(col, context.scene, 'ootColName', 'Name')
		if context.scene.ootColCustomExport:
			prop_split(col, context.scene, 'ootColExportPath', "Custom Folder")
		else:
			prop_split(col, context.scene, 'ootColFolder', 'Object')
		col.prop(context.scene, 'ootColCustomExport')
		col.prop(context.scene, 'ootColIncludeChildren')

oot_col_classes = (
	OOT_ExportCollision,
	OOTWaterBoxProperty,
	OOTCameraPositionPropertyRef,
	OOTCameraPositionProperty,
	OOTMaterialCollisionProperty,
)

oot_col_panel_classes = (
	OOT_CollisionPanel,
	OOT_CameraPosPanel,
	OOT_ExportCollisionPanel,
)

def oot_col_panel_register():
	for cls in oot_col_panel_classes:
		register_class(cls)

def oot_col_panel_unregister():
	for cls in oot_col_panel_classes:
		unregister_class(cls)

def oot_col_register():
	for cls in oot_col_classes:
		register_class(cls)

	# Collision
	bpy.types.Scene.ootColExportPath = bpy.props.StringProperty(
		name = 'Directory', subtype = 'FILE_PATH')
	bpy.types.Scene.ootColExportLevel = bpy.props.EnumProperty(items = ootEnumSceneID,
		name = 'Level Used By Collision', default = 'SCENE_YDAN')
	bpy.types.Scene.ootColIncludeChildren = bpy.props.BoolProperty(
		name = 'Include child objects', default = True)
	bpy.types.Scene.ootColName = bpy.props.StringProperty(
		name = 'Name', default = 'collision')
	bpy.types.Scene.ootColLevelName = bpy.props.StringProperty(
		name = 'Name', default = 'SCENE_YDAN')
	bpy.types.Scene.ootColCustomExport = bpy.props.BoolProperty(
		name = 'Custom Export Path')
	bpy.types.Scene.ootColFolder = bpy.props.StringProperty(
		name = 'Object Name', default = "gameplay_keep")

	bpy.types.Object.ootCameraPositionProperty = bpy.props.PointerProperty(type = OOTCameraPositionProperty)
	bpy.types.Material.ootCollisionProperty = bpy.props.PointerProperty(type = OOTMaterialCollisionProperty)

def oot_col_unregister():
	# Collision
	del bpy.types.Scene.ootColExportPath
	del bpy.types.Scene.ootColExportLevel
	del bpy.types.Scene.ootColName
	del bpy.types.Scene.ootColLevelName
	del bpy.types.Scene.ootColIncludeChildren
	del bpy.types.Scene.ootColCustomExport
	del bpy.types.Scene.ootColFolder

	for cls in reversed(oot_col_classes):
		unregister_class(cls)


from django.urls import path
from django.contrib import admin
from . import views
"""from django.contrib.auth import as auth_views"""
urlpatterns = [
    path('',views.home,name='home'),
    path('otp/<uid>', views.otpVerify, name='otp'),
    path('signin/',views.signin,name='signin'),
    path('signup/',views.signup,name='signup'),
    path('logout/',views.logout_acc,name='logout'),
    path('profile/',views.profile,name='profile'),
    path('advice/',views.advice,name='advice'),
    path('doctors/',views.doctor,name='doctor'),
    path('payment/',views.payment,name='payment'),
    path('sucess/',views.sucess,name='sucess'),
]


# global imports
import json
import random
import time
import os
import sys

# local imports
from experiences.quic_web_browse import launchTests

# global vars
TOPOS_FP = './../topos.json'
GRAPHS_FP = './../test_graphs.json'
TG_PAIRS = './../pairs_topos_graphs.json'
random.seed(42)

def getNetemToTuple(topo):
    '''in json -> tuple (0 0 loss 1.69%) is stored as [0, 0, loss 1.69%]
        revert it back to tuple, otherwise error is produced
    '''
    topo[0]['netem'][0] = (topo[0]['netem'][0][0], topo[0]['netem'][0][1], topo[0]['netem'][0][2])
    topo[0]['netem'][1] = (topo[0]['netem'][1][0], topo[0]['netem'][1][1], topo[0]['netem'][1][2])
    return topo

def load_or_generate_pairs():
    if not os.path.isfile(TG_PAIRS):
        with open(TOPOS_FP, 'r') as fp:
            topos = json.load(fp)
        with open(GRAPHS_FP, 'r') as fp:
            graphs = json.load(fp)

        tuple_list = []
        for i in range(len(topos)):
            for j in range(len(graphs)):
                tuple_list.append((i, j))

        pairs = random.sample(tuple_list, 100)
        output = []
        for (t, g) in pairs:
            pair = {
                'graph': graphs[g],
                'topo': topos[t]
            }
            output.append(pair)
        with open(TG_PAIRS, 'w') as fp:
            json.dump(output, fp, indent=4)
        return output
    else:
        with open(TG_PAIRS, 'r') as fp:
            pairs = json.load(fp)
        return pairs

def restart_nn_inference(bdw_path1, bdw_path2):
    PYTHON_NN_INFERENCE = 'python3.6'

    def send_cmd(cmd):
        import subprocess
        REMOTE_PORT = '22'
        REMOTE_HOST = 'mininet@192.168.122.157'
        ssh_cmd = ["ssh", "-p", REMOTE_PORT, REMOTE_HOST, cmd]
        subprocess.Popen(ssh_cmd,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        shell=False)

    send_cmd("killall {}".format(PYTHON_NN_INFERENCE))
    time.sleep(0.5)
    spawn_cmd = "{} {} {} {}".format("python3.6", "./git/nn_testing/nn_inference.py",str(bdw_path1), str(bdw_path2))
    send_cmd(spawn_cmd)

def main():
    if len(sys.argv[1:]) < 1:
        print ("Not enough arguments")
        exit(-1)

    graphs_to_execute = sys.argv[1:]
    graphs_to_execute = [(int(g)-1) for g in graphs_to_execute]
    pairs = load_or_generate_pairs()

    counter = 1
    for g in graphs_to_execute:
        p = pairs[g]
        print (p)

        graph = p['graph']['file']
        topo = getNetemToTuple([p['topo']])

        bdw_path1 = p['topo']['paths'][0]['bandwidth']
        bdw_path2 = p['topo']['paths'][1]['bandwidth']

        # fp.write("{},\t{},\t{}\n".format(counter, graph, p['topo']))
        counter += 1

        try:
            start = time.time()
            restart_nn_inference(bdw_path1, bdw_path2)
            launchTests(topo, graph)
            end = time.time()

            diff = int(start - end)
            print("runtime: {}s".format(diff))
        except Exception as ex:
            print (ex)

if __name__ == "__main__":
    main()


import pandas as pd
import numpy as np
from tqdm import tqdm

class Word2vec(object):
    def __init__(self, window_size, embedding_dimension) -> None:
        self.window_size = window_size
        self.embedding_dimension = embedding_dimension

        self.data = None
        self.word_to_id = None
        self.id_to_word = None
        self.vocab_size = None

    def fit(self, path_to_data):
        df = pd.read_csv(path_to_data, index_col=False)
        df.drop(['Unnamed: 0'], axis=1, inplace=True)
        data = df.unstack().values

        self.data = data
        self._generate_word_to_id()
        self._generate_id_to_word()
        self.vocab_size = len(self.word_to_id)

    def _generate_word_to_id(self):
        word_to_id = dict()
        cnt = 0
        for review in self.data:
            for char in review.split(' '):
                if char not in word_to_id:
                    word_to_id[char] = cnt
                    cnt += 1
        self.word_to_id = word_to_id

    def _generate_id_to_word(self):
        self.id_to_word = {str(v):k for k,v in self.word_to_id.items()}

    def _get_low_context(self, idx, review):
        low_idx = np.max([0, idx-self.window_size])
        return review[low_idx:idx]

    def _get_high_context(self, idx, review):
        high_idx = np.min([len(review), idx+self.window_size])
        return review[idx:high_idx]

    def _concat_context(self, low, high):
        return low + high

    def _one_hot_encode_word(self, word):
        encoded = np.zeros(self.vocab_size, dtype=np.int)
        word_id = self.word_to_id[word]
        encoded[word_id] = 1
        return encoded

    def _one_hot_encode_context(self, context):
        encoded_context = np.zeros(self.vocab_size, dtype=np.int)
        for word in context:
            encoded_context[self.word_to_id[word]] = 1
        return encoded_context

    def generate_training_data(self, n=-1):
        X = []
        y = []
        reviews = self.data
        for k, review in tqdm(enumerate(reviews), desc='Generating training set'):
            if k == n:
                break
            else:
                words_review = review.split(' ')
                if '' in words_review:
                    words_review.remove('')
                elif ' ' in words_review:
                    words_review.remove(' ')
                for i, word in enumerate(words_review):

                    mid_word = word

                    low_context = self._get_low_context(idx=i, review=words_review)
                    high_context = self._get_high_context(idx=i+1, review=words_review)
                    context = self._concat_context(low_context, high_context)

                    encoded_mid_word = self._one_hot_encode_word(word=mid_word)
                    encoded_context = self._one_hot_encode_context(context=context)

                    X.append(encoded_mid_word)
                    y.append(encoded_context)

        return np.array(X), np.array(y)

    def get_word_with_id(self, id):
        return self.id_to_word[str(id)]


#! /usr/bin/env python3

''' Scraping Image '''

import requests
import bs4

res = requests.get('https://en.wikipedia.org/wiki/Cicada_3301')
soup = bs4.BeautifulSoup(res.text, 'lxml')

image_info = soup.select('.thumbimage')
print(type(image_info))
print(len(image_info))
print(image_info)
print(image_info[0])

cicada = image_info[0]

image_link = 'http:'+ cicada['src']
print(image_link)

cicada_image = requests.get(image_link, 'lxml')
with open('cicada_image.jpg', 'wb') as f:
    f.write(cicada_image.content)


from typing import List

def insertionSort(array: List[int]) -> None:
    """Main insertion sort algorithm\n
    Sorts array in-place; returns None
    """
    for i in range(1, len(array)):  # Iterate through entire array
        comparator = array[i]  # Make comparison with this value
        for section in range(i - 1, -2, -1):  # Iterate through array from i backwards
            if (
                comparator > array[section]
            ):  # Insert comparator into the array, in its correct position
                array[section + 1] = comparator
                break
            else:
                array[section + 1] = array[
                    section
                ]  # If comparator <= array[section], move array[section] forward to make space
        else:
            array[
                section + 1
            ] = comparator  # If loop wasn't broken, insert comparator in the right spot

if __name__ == "__main__":
    try:
        from utils import randomSequence
    except ModuleNotFoundError:
        import os, sys  # Import shuffler from parent directory

        dir_path = os.path.dirname(os.path.realpath(__file__))
        parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
        sys.path.insert(0, parent_dir_path)
        from utils import randomSequence

    print("INSERTION SORT")

    shuffledArray = randomSequence(0, 1000)

    print(shuffledArray, "\n")

    insertionSort(shuffledArray)

    print(shuffledArray)


import time
from test_slowdb import test_slowdb
from test_init import test_cache_ports_registered
from test_get_key import test_get_non_existing_key, test_get_existing_key
from test_put_key import (
    test_put_non_existing_key,
    test_put_existing_key,
    test_put_cache_aside,
)
from test_lru_cache import test_lru_cache
from test_consistent_hashing import test_consistent_hashing
from test_ch_distribution import test_consistent_hashing_distribution
from test_replication import test_replication
from test_fault_tolerance import test_fault_tolerance
from test_concurrent_get import test_concurrency_get
from test_cache_communication import test_cache_communication
import threading
import os
import subprocess
import signal
import argparse

def kill_process_on_port(port):
    """
    Kill the process using the specified port
    :param port: port number
    :return: None
    """
    command = f"lsof -i :{port} -t"
    try:
        result = subprocess.check_output(command, shell=True, text=True)
        pids = result.strip().split("\n")
        for pid in pids:
            if pid:
                os.kill(int(pid), signal.SIGTERM)
    except subprocess.CalledProcessError:
        # No process found using the specified port
        pass

def main(kill_ports, stop_event=None):
    """
    Start the SlowDB server, the cache cluster and the cache servers
    :param stop_event: stop event
    :return: None
    """
    if kill_ports:
        print("Killing processes on ports")
        for port in [10000, 8001, 8002, 8010, 8000]:
            kill_process_on_port(port)

    cache_ports = [8001, 8002, 8010]

    # Start the SlowDB server
    slowdb_process = subprocess.Popen(["python3", "slowdb.py"])

    cluster_process = subprocess.Popen(["python3", "cache_proxy.py", "10000"])
    time.sleep(2)
    # Start the cache servers
    cache_processes = [
        subprocess.Popen(["python3", "cache_server.py", str(port), "10000"])
        for port in cache_ports
    ]

    if stop_event:
        stop_event.wait()
        slowdb_process.terminate()
        cluster_process.terminate()
        for process in cache_processes:
            process.terminate()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Run tests with optional kill_ports flag')
    parser.add_argument('--kill_ports', type=bool, default=False,
                        help='Set to True to kill processes on ports, default is False')

    args = parser.parse_args()
    score = 0
    main_thread = threading.Thread(target=main, args=(args.kill_ports,))
    main_thread.start()
    time.sleep(5)
    print("------------------start of test----------------------")
    tests = [
        test_lru_cache,
        test_consistent_hashing,
        test_slowdb,
        test_cache_ports_registered,
        test_get_non_existing_key,
        test_get_existing_key,
        test_put_non_existing_key,
        test_put_existing_key,
        test_cache_communication,
        test_put_cache_aside,
        test_consistent_hashing_distribution,
        test_replication,
        test_fault_tolerance,
        test_concurrency_get
    ]
    for test in tests:
        result = test()
        if result != 0:
            score += result
            print(f"{test.__name__}: PASS +{result}")
        else:
            print(f"{test.__name__}: FAIL")
    print("------------------end of test----------------------")
    print(f"Total Score: {score} / 200")
    main_thread.join()