'''
Author       : Lancercmd
Date         : 2020-12-14 13:29:38
LastEditors  : Lancercmd
LastEditTime : 2021-07-19 07:52:15
Description  : None
GitHub       : https://github.com/Lancercmd
'''
from binascii import b2a_base64
from copy import deepcopy
from hashlib import sha1
from hmac import new
from random import randint
from sys import maxsize, version_info
from time import time

from aiohttp import request
from loguru import logger
from nonebot import get_driver
from nonebot.adapters import Bot, Event
from nonebot.adapters.cqhttp.event import (GroupMessageEvent, MessageEvent,
                                           PrivateMessageEvent)
from nonebot.exception import ActionFailed
from nonebot.permission import Permission
from nonebot.plugin import on_command
from nonebot.typing import T_State

try:
    import ujson as json
except ImportError:
    import json

config = get_driver().config

translate = on_command(
    '翻译', aliases={'机翻'}, block=True
)

@translate.permission_updater
async def _(bot: Bot, event: Event, state: T_State, permission: Permission):
    message_type = event.message_type
    user_id = event.get_user_id()
    group_id = None
    if isinstance(event, GroupMessageEvent):
        group_id = event.group_id

    async def _onFocus(bot: Bot, event: Event):
        if isinstance(event, GroupMessageEvent):
            return event.message_type == message_type and event.get_user_id() == user_id and await permission(bot, event) and event.group_id == group_id
        elif isinstance(event, PrivateMessageEvent):
            return event.message_type == message_type and event.get_user_id() == user_id and await permission(bot, event)
    return Permission(_onFocus)

async def getReqSign(params: dict) -> str:
    common = {
        'Action': 'TextTranslate',
        'Region': f'{config.tencentcloud_common_region}',
        'Timestamp': int(time()),
        'Nonce': randint(1, maxsize),
        'SecretId': f'{config.tencentcloud_common_secretid}',
        'Version': '2018-03-21',
    }
    params.update(common)
    sign_str = 'POSTtmt.tencentcloudapi.com/?'
    sign_str += '&'.join('%s=%s' % (k, params[k]) for k in sorted(params))
    secret_key = config.tencentcloud_common_secretkey
    if version_info[0] > 2:
        sign_str = bytes(sign_str, 'utf-8')
        secret_key = bytes(secret_key, 'utf-8')
    hashed = new(secret_key, sign_str, sha1)
    signature = b2a_base64(hashed.digest())[:-1]
    if version_info[0] > 2:
        signature = signature.decode()
    return signature

@translate.handle()
async def _(bot: Bot, event: Event, state: T_State):
    if isinstance(event, MessageEvent):
        available = [
            # 'auto',
            'zh', 'zh-TW', 'en', 'ja', 'ko', 'fr',
            'es', 'it', 'de', 'tr', 'ru', 'pt',
            'vi', 'id', 'th', 'ms', 'ar', 'hi'
        ]
        state['available'] = ' | '.join(available)
        state['valid'] = deepcopy(available)
        if event.get_plaintext():
            for language in available:
                if event.get_plaintext().startswith(language):
                    state['Source'] = language
                    break
            if 'Source' in state:
                input = event.get_plaintext().split(' ', 2)
                available.remove('zh-TW')
                if state['Source'] == 'zh-TW':
                    available.remove('zh')
                if state['Source'] != 'en':
                    for i in ['ar', 'hi']:
                        available.remove(i)
                if not state['Source'] in ['zh', 'zh-TW', 'en']:
                    for i in ['vi', 'id', 'th', 'ms']:
                        available.remove(i)
                if state['Source'] in ['ja', 'ko', 'vi', 'id', 'th', 'ms', 'ar', 'hi']:
                    for i in ['fr', 'es', 'it', 'de', 'tr', 'ru', 'pt']:
                        available.remove(i)
                if not state['Source'] in ['zh', 'zh-TW', 'en', 'ja', 'ko']:
                    for i in ['ja', 'ko']:
                        available.remove(i)
                if state['Source'] in ['ar', 'hi']:
                    available.remove('zh')
                try:
                    available.remove(state['Source'])
                except ValueError:
                    pass
                if len(available) == 1:
                    state['Target'] = available[0]
                    if len(input) == 3:
                        state['SourceText'] = input[2]
                    else:
                        state['SourceText'] = input[1]
                elif len(input) == 3:
                    state['Target'] = input[1]
                    state['SourceText'] = input[2]
                elif len(input) == 2:
                    for language in available:
                        if input[0] in available:
                            state['Target'] = input[1]
                        else:
                            state['SourceText'] = input[1]
            else:
                state['SourceText'] = event.get_plaintext()
        message = f'请选择输入语种，可选值如下~\n{state["available"]}'
        if 'header' in state:
            message = ''.join([state['header'], f'{message}'])
        state['prompt'] = message
    else:
        logger.warning('Not supported: translator')
        return

@translate.got('Source', prompt='{prompt}')
async def _(bot: Bot, event: Event, state: T_State):
    if isinstance(event, MessageEvent):
        available = deepcopy(state['valid'])
        if state['Source'].lower() == 'jp':
            state['Source'] = 'ja'
        elif not state['Source'] in state['valid']:
            message = f'不支持的输入语种 {state["Source"]}'
            if 'header' in state:
                message = ''.join([state['header'], f'{message}'])
            try:
                await translate.finish(message)
            except ActionFailed as e:
                logger.error(
                    f'ActionFailed | {e.info["msg"].lower()} | retcode = {e.info["retcode"]} | {e.info["wording"]}'
                )
                return
        available.remove('zh-TW')
        if state['Source'] == 'zh-TW':
            available.remove('zh')
        if state['Source'] != 'en':
            for i in ['ar', 'hi']:
                available.remove(i)
        if not state['Source'] in ['zh', 'zh-TW', 'en']:
            for i in ['vi', 'id', 'th', 'ms']:
                available.remove(i)
        if state['Source'] in ['ja', 'ko', 'vi', 'id', 'th', 'ms', 'ar', 'hi']:
            for i in ['fr', 'es', 'it', 'de', 'tr', 'ru', 'pt']:
                available.remove(i)
        if not state['Source'] in ['zh', 'zh-TW', 'en', 'ja', 'ko']:
            for i in ['ja', 'ko']:
                available.remove(i)
        if state['Source'] in ['ar', 'hi']:
            available.remove('zh')
        try:
            available.remove(state['Source'])
        except ValueError:
            pass
        if len(available) == 1:
            state['Target'] = available[0]
        else:
            state['available'] = ' | '.join(available)
            state['valid'] = deepcopy(available)
        message = f'请选择目标语种，可选值如下~\n{state["available"]}'
        if 'header' in state:
            message = ''.join([state['header'], f'{message}'])
        state['prompt'] = message
    else:
        logger.warning('Not supported: translator')
        return

@translate.got('Target', prompt='{prompt}')
async def _(bot: Bot, event: Event, state: T_State):
    if isinstance(event, MessageEvent):
        if state['Target'].lower() == 'jp':
            state['Target'] = 'ja'
        elif not state['Target'] in state['valid']:
            message = f'不支持的目标语种 {state["Target"]}'
            if 'header' in state:
                message = ''.join([state['header'], f'{message}'])
            try:
                await translate.finish(message)
            except ActionFailed as e:
                logger.error(
                    f'ActionFailed | {e.info["msg"].lower()} | retcode = {e.info["retcode"]} | {e.info["wording"]}'
                )
                return
        message = '请输入要翻译的内容~'
        if 'header' in state:
            message = ''.join([state['header'], f'{message}'])
        state['prompt'] = message
    else:
        logger.warning('Not supported: translator')
        return

@translate.got('SourceText', prompt='{prompt}')
async def _(bot: Bot, event: Event, state: T_State):
    if isinstance(event, MessageEvent):
        endpoint = 'https://tmt.tencentcloudapi.com'
        params = {
            'Source': state['Source'],
            'SourceText': state['SourceText'],
            'Target': state['Target'],
            'ProjectId': 0,
        }
        params['Signature'] = await getReqSign(params)
        async with request(
            'POST',
            endpoint,
            data=params
        ) as resp:
            code = resp.status
            if code != 200:
                message = '※ 网络异常，请稍后再试~'
                if 'header' in state:
                    message = ''.join([state['header'], f'{message}'])
                try:
                    await translate.finish(message)
                except ActionFailed as e:
                    logger.error(
                        f'ActionFailed | {e.info["msg"].lower()} | retcode = {e.info["retcode"]} | {e.info["wording"]}'
                    )
                    return
            data = json.loads(await resp.read())['Response']
        if 'Error' in data:
            message = '\n'.join([
                f'<{data["Error"]["Code"]}> {data["Error"]["Message"]}',
                f'RequestId: {data["RequestId"]}'
            ])
            if 'header' in state:
                message = ''.join([state['header'], f'{message}'])
            try:
                await translate.finish(message)
            except ActionFailed as e:
                logger.error(
                    f'ActionFailed | {e.info["msg"].lower()} | retcode = {e.info["retcode"]} | {e.info["wording"]}'
                )
                return
        message = data['TargetText']
        if 'header' in state:
            message = ''.join([state['header'], f'{message}'])
        try:
            await translate.finish(message)
        except ActionFailed as e:
            logger.error(
                f'ActionFailed | {e.info["msg"].lower()} | retcode = {e.info["retcode"]} | {e.info["wording"]}'
            )
            return
    else:
        logger.warning('Not supported: translator')
        return


# https://leetcode.com/problems/find-the-celebrity/
# T: O(n)
# S: O(1)

# The knows API is already defined for you.
# @param a, person a
# @param b, person b
# @return a boolean, whether a knows b
# def knows(a, b):

class Solution(object):
    def findCelebrity(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n < 2:
            return -1
        possible = 0
        for i in range(1, n):
            if knows(possible, i):
                possible = i
        for i in range(n):
            if possible != i and (knows(possible, i) or not knows(i, possible)):
                return -1
        return possible


import numpy as np
import os
from load_data import load_data_hdf5_simple, get_max_id_hdf5, save_data_hdf5_simple
from CEDAR2019_params_simple import facilParams

def linear_comb_n(files, ids, rng, gmin=0.95, gmax=1.05, random_roll = False):
    """Produces linear combination of N data examples specified in the list ids, using random mixture between each example
    and also including a random gain factor.
    """

    N = len(ids)

    # Get random coefficients that add up to 1
    c = rng.dirichlet(np.ones(N), size=1)[0]

    # Get a random gain factor by which to multiply all data.
    #   If N=1, just let this be 1, since in this case we only want to save the example itself.
    if N > 1:
        g = rng.uniform(gmin, gmax)
    else:
        g = 1.0

    # Get first example
    data_comb = load_data_hdf5_simple(files[0], ids[0])["data"]

    # Roll this example if desired (a form of augmentation to maximize utility of few noise examples)
    if random_roll:
        shape_x = np.shape(data_comb)[1]
        shape_y = np.shape(data_comb)[2]
        data_comb = np.roll(data_comb, shift=(0, rng.integers(0,shape_x), rng.integers(0,shape_y)))

    # Multiply by first mix coefficient
    data_comb *= c[0]

    # Add next N-1 examples
    for i in np.arange(1,N):
        data_add = load_data_hdf5_simple(files[i], ids[i])["data"]
        if random_roll:
            data_add = np.roll(data_add, shift=(0, rng.integers(0,shape_x), rng.integers(0,shape_y)))
        data_comb += c[i]*data_add

    # Multiply by total gain
    data_comb *= g

    return(data_comb)

def linear_comb_n_wrapper(comb_list, examples_files, h5filepaths, h5filepath_save, start_id, rng, gmin=0.95, gmax=1.05, random_roll=False):

    num_combs = np.shape(comb_list)[0]
    if comb_list.ndim == 1:
        comb_list = np.reshape(comb_list,(num_combs,1))

    for i,id in enumerate(np.arange(start_id, start_id + num_combs)):

        # Get appropriate files and ID in the file
        h5files = list(h5filepaths[l] for l in examples_files[comb_list[i,:]][:,0])
        ids_in_file = examples_files[comb_list[i,:]][:,1]

        data_comb = linear_comb_n(h5files, ids_in_file, rng, gmin, gmax, random_roll)
        label = 0
        clutter = 2

        data_dict = {"data": data_comb}#, "match": match}
        attrs_dict = {"label": label, "clutter": clutter, "id": id}

        save_data_hdf5_simple(h5filepath_save, id, data_dict, attrs_dict)

    return(start_id + num_combs)

if __name__ == "__main__":

    # Script that grabs examples of non-meteors from test set and turns them into a set of "noise" examples,
    #   with data augmentation to turn the small amount of designated examples into a large set
    #   Examples of clutter/noise are already pre-designated within the test sets.

    # Uncomment whichever facility to use
    #facility_str = "RISR-N"
    facility_str = "MHO"
    #facility_str = "JRO"
    files = []

    # Add noise file to list (normally this script can account for multiple files but here it's hardcoded for just one)
    noise_dir = f"{facility_str}/noise_examples/"
    files.append(f"{noise_dir}/noise_examples_small.h5")

    # Generate new HDF5 file where all augmented noise examples will be generated
    noise_h5file = f"{noise_dir}/noise_examples.h5"

    # Get parameters for the chosen facility
    facility_p = facilParams[facility_str]

    # Form array that specifies which file a particular example is in and what id it is in the file.
    # Needed when gathering examples from multiple HDF5 files (not used here but useful)
    examples_files = []
    examples_files_include = []
    for j,filepath in enumerate(files):

        num_examples = get_max_id_hdf5(filepath)

        i = 0
        for id in range(num_examples):
            data = load_data_hdf5_simple(filepath, id)
            examples_files.append([j, id])

    # Turn this into Numpy array
    examples_files = np.array(examples_files)
    num_examples_tot = np.shape(examples_files)[0]

    # Initialize random number generator
    rng = np.random.default_rng(seed=42)

    # Determine examples to include
    noise_avail_rng = np.arange(num_examples_tot)
    rng.shuffle(noise_avail_rng)
    noise_ids = noise_avail_rng[:num_examples_tot]

    # Save all instances of noise as they are (i.e. no combinations)
    start_id = 0
    start_id = linear_comb_n_wrapper(noise_ids, examples_files, files, noise_h5file, start_id, rng, gmin=1, gmax=1, random_roll=False)

    # Save some instances with random roll enabled (data augmentation)
    start_id = linear_comb_n_wrapper(noise_ids, examples_files, files, noise_h5file, start_id, rng, gmin=1, gmax=1, random_roll=True)
    start_id = linear_comb_n_wrapper(noise_ids, examples_files, files, noise_h5file, start_id, rng, gmin=1, gmax=1, random_roll=True)
    start_id = linear_comb_n_wrapper(noise_ids, examples_files, files, noise_h5file, start_id, rng, gmin=1, gmax=1, random_roll=True)

    # Save some linear combinations of instances with random roll
    nnoise_2_comb = num_examples*6 #num_noise_include*10

    # Determine what linear combinations of 2 separate noise examples to make
    noise_combs = noise_ids[rng.integers(num_examples, size=(nnoise_2_comb, 2))]
    start_id = linear_comb_n_wrapper(noise_combs, examples_files, files, noise_h5file, start_id, rng, gmin=1, gmax=1, random_roll=True)


# coding: utf-8
from __future__ import absolute_import

# Standard imports
import logging

# Internal imports
from aoiktracecall.util import indent_by_level

# Debug logger.
# Initialized in `get_debug_logger`.
_DEBUG_LOGGER = None

# Info logger.
# Initialized in `get_info_logger`.
_INFO_LOGGER = None

# Error logger.
# Initialized in `get_error_logger`.
_ERROR_LOGGER = None

def set_debug_logger(logger):
    # Use global
    global _DEBUG_LOGGER

    # Set logger
    _DEBUG_LOGGER = logger

def get_debug_logger():
    # Use global
    global _DEBUG_LOGGER

    # If logger is not initialized
    if _DEBUG_LOGGER is None:
        # Get logger
        _DEBUG_LOGGER = logging.getLogger(
            'aoiktracecall.logging.DEBUG_LOGGER'
        )

        # Disable propagation
        _DEBUG_LOGGER.propagate = False

        # Set logging level
        _DEBUG_LOGGER.setLevel(logging.DEBUG)

    # Return logger
    return _DEBUG_LOGGER

def set_info_logger(logger):
    # Use global
    global _INFO_LOGGER

    # Set logger
    _INFO_LOGGER = logger

def get_info_logger():
    # Use global
    global _INFO_LOGGER

    # If logger is not initialized
    if _INFO_LOGGER is None:
        # Get logger
        _INFO_LOGGER = logging.getLogger(
            'aoiktracecall.logging.INFO_LOGGER'
        )

        # Disable propagation
        _INFO_LOGGER.propagate = False

        # Set logging level
        _INFO_LOGGER.setLevel(logging.INFO)

    # Return logger
    return _INFO_LOGGER

def set_error_logger(logger):
    # Use global
    global _ERROR_LOGGER

    # Set logger
    _ERROR_LOGGER = logger

def get_error_logger():
    # Use global
    global _ERROR_LOGGER

    # If logger is not initialized
    if _ERROR_LOGGER is None:
        # Get logger
        _ERROR_LOGGER = logging.getLogger(
            'aoiktracecall.logging.ERROR_LOGGER'
        )

        # Disable propagation
        _ERROR_LOGGER.propagate = False

        # Set logging level
        _ERROR_LOGGER.setLevel(logging.INFO)

    # Return logger
    return _ERROR_LOGGER

def print_debug(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_debug_logger()

        # Send text to logger
        logger.debug(text)

def print_info(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_info_logger()

        # Send text to logger
        logger.info(text)

def print_error(text, indent=True):
    # If have text
    if text:
        # If need indent the text
        if indent:
            # Indent the text
            text = indent_by_level(text)

        # Get logger
        logger = get_error_logger()

        # Send text to logger
        logger.error(text)


from odoo import fields,models,_,api

class ResPartner(models.Model):

    _inherit = 'res.partner'

    inmate_name = fields.Char(string="Inmates Name")
    inmate_identifier = fields.Selection([('male','Male'),
    										('female','Female'),
    										('gendernon','Gender Nonconforming/Gender Nonbinary'),
    										('transmale','Transgender Male'),
    										('transfemale','Transgender Female'),
    										('None','Other/None'),
    										('decline','Declined to Answer')],string="Inmate Identifies As")
    inmate_suicide_watch = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Was the inmate placed on suicide watch ?')
    inmate_prea_risk = fields.Selection([('yes', 'Yes'),
    									 ('no', 'No'),
    									 ('victim','Victim'),
    									 ('aggresor','Aggresor')], string='Was the inmate flagged as a PREA risk ?')
    inmate_health_issue = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Did the inmate indicate serious mental health issues ?')
    health_issue_note = fields.Text('Note')
    inmate_serious_health_issue = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Did the inmate indicate serious medical issues ?')
    srs_health_issue_note = fields.Text('Note')
    inmate_assault = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Did the inmate assault a staff member')
    inmate_gang = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Did the inmate gang or security threat group affiliation ?')
    completed_by = fields.Char('Completed BY')
    fingerprint_id = fields.Char('Fingerprint ID')
    class_date = fields.Date('Date')
    class_state_id = fields.Char('State Id')
    inmate_first_name = fields.Char('First Name')
    class_fbi_number = fields.Char('FBI Number')
    class_state = fields.Selection([('indiana','Indiana'),
    						('hawaii','Hawaii'),
    						('gendernon','Gender Nonconforming/Gender Nonbinary'),
    						('michigan','Michigan'),
    						('ohio','Ohio')],string="state")
    severe_current_charges = fields.Selection([('Moc','MIsd or Civil'),
    											('low','Low'),
    											('mod','Moderate'),
    											('high','High'),
    											('highest','Highest')],string="SEVERITY OF CURRENT CHARGES/CONVICTIONS")
    serious_felony = fields.Selection([('Moc','MIsd or Civil'),
    									('low','Low'),
    									('mod','Moderate'),
    									('high','High'),
    									('highest','Highest')],string="MOST SERIOUS FELONY CONVICTIONS PAST 10 YEARS")
    institutional_assault = fields.Selection([('none','None'),
    										('assault','Assault not involving use of a weapon'),
    										('sexassault','Predatory or Sexual Assault with or without injury'),
    										('weaponassault','Assault involving use of a weapon or resulting is serious injury')],
    										string="INSTITUTIONAL ASSAULT/FIGHT HISTORY PAST 10 YEAR")
    escape_history = fields.Selection([('noescape','No escape or attempts'),
    									('walkaway','Walk-away from non-secure/minimum security or failure to return'),
    									('withoutviolence','Escape from medium/maximum facility without violence'),
    									('withviolence','Escape from medium/maximum facility with violence')],
    									string="ESCAPE HISTORY")
    disciplinary_history = fields.Selection([('none','None or one (1) minor'),
    									('two','Two or more Minor'),
    									('tampering','Tampering with jail security equipment'),
    									('nonpredatory','Non-Predatory Major Incident(s)'),
    									('predatory','Predatory Major Incident(s)')],
    									string="INSTITUTIONAL DISCIPLINARY HISTORY (Past ten years)")
    prior_felony = fields.Selection([('none','None'),
    									('lom','Low or Moderate'),
    									('high','High'),
    									('highest','Highest')],string="PRIOR FELONY CONVICTIONS PAST 10 YEARS ( excluding questions 1 and 2 above)")

    prior_doc_timereserved = fields.Selection([('20','No prior DOC history or more than 20 years DOC me'),
    									('4','Four years or less DOC '),
    									('520','Between 5 to 20 years DOC me'),
    									],string="PRIOR DOC TIMESERVE")
    age = fields.Selection([('38o','Age 38 or over'),
    						('18l','Youthful Offender (less than 18)'),
    						('b28','Age Between 28 - 37'),
    						('b18','Age Between 18 - 27')],string="Age")

    inmate_custody = fields.Selection([('minimum','Minimum'),
    									('medium','Medium'),
    									('maximum','Maximum')],string="Custody")
    inmate_housing = fields.Selection([('gp','General Population'),
    									('pc','Productive Custody'),
    									('med','Medical'),
    									('as','Administrative Segregation'),
    									('mh','Mental Health'),
    									('other','Other')
    									],string="Housing")
    housing_note = fields.Text('Housing Note')
    reason_for_place = fields.Text('REASON(S) FOR PLACEMENT IF THIS DEPARTS FROM RECOMMENDED LEVELS:')
    supervisor_review = fields.Char('SUPERVISOR’S REVIEW / APPROVAL')
    date_housing = fields.Date('Date')


import numpy as np
import torch
import matplotlib.pyplot as plt
import copy

from . import densities
from . import preisach

import gpytorch

#hybrid hysteresis/GP
class HybridGP(torch.nn.Module):
    def __init__(self,
                 hysteresis_model,
                 density_model,
                 train_x, train_y, lk,
                 priors = None):

        super(HybridGP, self).__init__()

        self.h_module = Hysteresis(hysteresis_model, density_model)
        self.gp_module = ExactGP(train_x, train_y, lk)

    def forward(x):
        B = self.h_module(x)
        return self.gp_module(B)

#impliment a hysteresis module as a subclass of torch.nn
class Hysteresis(torch.nn.Module):
    def __init__(self,
                 hysteresis_model,
                 density_model,
                 priors = None):

        super(Hysteresis, self).__init__()

        #register parameters from density model
        #for name, item in density_model.params.items():
        #    self.register_parameter(name,item)

        self.density_model = density_model
        self.hysteresis_model = hysteresis_model

    def forward(self, x):
        self.hysteresis_model.set_applied_field(x)
        self.hysteresis_model.propagate_states()

        return self.hysteresis_model.calculate_magnetization(
            self.density_model).reshape(-1,1)

    def predict(self, x):
        return self.hysteresis_model.predict_magnetization(x,
                                                           self.density_model).reshape(-1,1)

class HysteresisExact(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, lk, hyst_module):
        super(HysteresisExact, self).__init__(train_x, train_y, lk)

        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(
            gpytorch.kernels.RBFKernel())

        self.hyst_module = hyst_module

    def forward(self, x):
        '''
        NOTE: remember that the argument passed to x here is a union between training and test data
              when self.training = False
        - we need to re-do the hysteresis model (call calculate_magnetization) for the training data
          but when we predict future values we need to call predict_magnetization

        '''
        if self.training:
            B = self.hyst_module(x)
        else:
            #note: to allow batch training self.train_inputs is a tuple of tensors, need first index
            # not the case for passing x!
            n_train = self.train_inputs[0].shape[0]
            #print(f'x:{x}')

            B_train = self.hyst_module(x[:n_train])
            #print(f'B_train:{B_train}')

            B_test = self.hyst_module.predict(x[n_train:]).float()
            #print(f'B_test:{B_test}')

            #concat
            B = torch.cat((B_train, B_test),axis = 0)
            #print(f'B:{B}')

        mean = self.mean_module(B)
        covar = self.covar_module(B)

        return gpytorch.distributions.MultivariateNormal(mean, covar)

    def get_manifold_model(self):
        #from this model create a copy GP that predicts from manifold space, not input space

        #get manifold inputs and outputs
        #note will not work for batch mode!
        manifold_inputs = self.hyst_module(self.train_inputs[0])
        manifold_outputs = self.train_targets

        #define new model - use deep copies so modifications to new model do not change orig model
        manifold_lk = copy.deepcopy(self.likelihood)
        manifold_model = ExactGP(manifold_inputs, manifold_outputs, manifold_lk)

        #set model cov and mean function to copy
        manifold_model.mean_module = copy.deepcopy(self.mean_module)
        manifold_model.covar_module = copy.deepcopy(self.covar_module)

        return manifold_model

class ExactGP(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, lk):
        super(ExactGP, self).__init__(train_x, train_y, lk)

        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(
            gpytorch.kernels.RBFKernel())

    def forward(self, x):
        mean = self.mean_module(x)
        covar = self.covar_module(x)

        return gpytorch.distributions.MultivariateNormal(mean, covar)

def train_model(model, likelihood, x, y, iter_steps = 250, lr = 0.1, fname = ''):
    # Find optimal model hyperparameters
    model.train()
    likelihood.train()

    # Use the adam optimizer
    for name, param in model.named_parameters():
        print(f'{name}:{param.requires_grad}')

    optimizer = torch.optim.Adam(model.parameters(), lr = lr)

    # "Loss" for GPs - the marginal log likelihood
    mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)

    best_loss = 10000
    for i in range(iter_steps):
        optimizer.zero_grad()
        output = model(x)
        loss = -mll(output, y)
        loss.backward(retain_graph=True)
        if loss.item() < best_loss:
            best_param = copy.deepcopy(model.state_dict())
            best_loss = loss.item()

        if i % 10 == 0:
            print('Iter %d - Loss: %.3f - Best loss %.3f' % (i + 1, loss.item(), best_loss))

        optimizer.step()

    #set model params to the best
    model.load_state_dict(best_param)

    torch.save(model.state_dict(), f'{fname}model.pth')


#!/usr/bin/env python2
import cv2
import os
import sys
import numpy as np
sys.path.append('.')
import tensorflow as tf
import detect_face
import random
from mtcnn.mtcnn import MTCNN

def speeds(obstacle):
    speed = []
    for i in range(60):
        a = random.randint(45, 80)
        speed.append(round(a))
        speed.sort()
        # low is a list of speeds to slower

    #print(speed)
    #print(len(speed))
    if obstacle == False:
        return random.choice(speed)

    else:
        return 0

def main():

    video_capture = cv2.VideoCapture('sample2.mp4')

    #video_capture.set(3, 640)
    #video_capture.set(4, 480)

    minsize =30 # minimum size of face
    threshold = [ 0.6, 0.7, 0.7 ]  # three steps's threshold
    factor = 0.709 # scale factor
    detect_features = MTCNN()

    sess = tf.Session()
    with sess.as_default():
        pnet, rnet, onet = detect_face.create_mtcnn(sess, None)
        while(True):
            ret, frame = video_capture.read()
            if not ret:
                break
            # Display the resulting frame
            img = frame[:,:,0:3]
            boxes, _ = detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)

            for i in range(boxes.shape[0]):
                result = detect_features.detect_faces(img)
                pt1 = (int(boxes[i][0]), int(boxes[i][1]))
                pt2 = (int(boxes[i][2]), int(boxes[i][3]))

                if len(result) == 0:
                        print('no pedestrians')
                        a = speeds(obstacle=False)
                        dp1 =(100, 300)
                        dp2 =(400,600)
                        cv2.rectangle(frame, dp1, dp2, thickness=-1, color=(0, 255, 0))
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        num1 = 'Pedestrians: '+str(len(result))
                        cv2.putText(img,num1,(100,400), font, 1.0,(255,255,255),2,cv2.LINE_AA)
                        num2 = 'Speed: '+str(a)
                        cv2.putText(img,num2,(100,450), font, 1.0,(255,255,255),2,cv2.LINE_AA)

                else :
                        a = speeds(obstacle=True)
                        dp1 =(100, 300)
                        dp2 =(400,600)
                        cv2.rectangle(frame, dp1, dp2, thickness=-1, color=(0, 0, 255))
                        font = cv2.FONT_HERSHEY_SIMPLEX
                        num1 = 'Pedestrians: '+str(len(result))
                        cv2.putText(img,num1,(100,400), font, 1.0,(255,255,255),2,cv2.LINE_AA)
                        num2 = 'Speed: '+str(a)
                        cv2.putText(img,num2,(100,450), font, 1.0,(255,255,255),2,cv2.LINE_AA)

                for j in range(len(result)):
                        bounding_box = result[j]['box']
                        keypoints = result[j]['keypoints']
                        cv2.rectangle(frame, pt1, pt2, color=(0, 255, 0))
                        print(boxes)
                        cv2.circle(img,(keypoints['left_eye']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['right_eye']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['nose']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['mouth_left']), 2, (0,155,255), 2)
                        cv2.circle(img,(keypoints['mouth_right']), 2, (0,155,255), 2)

            cv2.namedWindow('Video', cv2.WINDOW_NORMAL)
            #cv2.rectangle(frame, pt1, pt2, color=(0, 255, 0))
            cv2.resizeWindow('Video', 1800,900)
            cv2.imshow('Video', frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                print("Ended Simulation")
                break

    video_capture.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()


from myqml import QtCore, QtCharts

import random
import math

class DataSource(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.m_index = -1
        self.m_data = []

        self.generateData(0, 5, 1024)

    @QtCore.Slot(QtCharts.QXYSeries)
    def update(self, series):
        if series:
            # Column index
            self.m_index += 1
            if self.m_index > len(self.m_data) - 1:
                self.m_index = 0

            points = self.m_data[self.m_index]
            series.replace(points)

    def _gen_dat(self, type_, row, col):
        if type_ == 0 or type_ == 'sin':
            y = math.sin(math.pi / 50 * col) + 0.5 + random.random()
            x = col
        else:
            y = row / 10
            x = col
        return QtCore.QPointF(x, y)

    @QtCore.Slot(int, int, int)
    @QtCore.Slot(str, int, int)
    def generateData(self, type_, rowCount, colCount):
        # rowCount is really the channel count and colCount is really the number of samples
        self.m_data = [[self._gen_dat(type_, row, col) for col in range(colCount)] for row in range(rowCount)]


import sys
import argparse
import os
from os.path import join, dirname, isdir, isfile, exists, abspath

import torch
import torch.nn as nn
import torch.nn.functional as F

import yaml
from easydict import EasyDict
import data
import models
# import util.util as util
import util.html as html

def reset_config(args):
    this_dir = dirname(abspath(__file__))
    default_cfg_path = join(this_dir, 'configs/default_configs.yaml')
    cfg = yaml.load(open(default_cfg_path))
    cfg = EasyDict(cfg)
    # add attr from args
    for k, v in args._get_kwargs():
        if k == 'gpu_ids': v = [int(vid) for vid in v.split(',')]
        cfg[k] = v
    # add attr from model specific
    model_cfg_path = join(this_dir, 'configs/{}.yaml'.format(args.model))
    model_cfg = yaml.load(open(model_cfg_path))
    model_cfg = EasyDict(model_cfg)
    for k, v in model_cfg.items():
        cfg[k] = v

    # reset attr fixed for test
    cfg.num_threads = 0
    cfg.batch_size = 1
    cfg.serial_batches = True
    cfg.no_flip = True
    cfg.isTrain = False # test fixed
    return cfg

def create_dataset(cfg):
    dataset = eval('data.' + cfg.dataset_mode.capitalize() + 'Dataset')(cfg)
    print('dataset [{}] was created'.format(type(dataset).__name__))
    dataset_size = len(dataset)
    print('The number of training images = {}'.format(dataset_size))

    dataloader = torch.utils.data.DataLoader(
        dataset, batch_size=cfg.batch_size,
        shuffle=True if cfg.isTrain else False,
        num_workers=int(cfg.num_threads),
        drop_last=True if cfg.phase=='train' else False,
    )
    return dataloader, dataset_size

def create_model(cfg):
    model = eval('models.' + cfg.model.upper() + 'Model')(cfg)
    return model

def main(args):
    cfg = reset_config(args)
    dataset, dataset_size = create_dataset(cfg)
    model = create_model(cfg)

    vis_dir = join(cfg.results_dir, cfg.name, '{}_{}'.format(cfg.phase, cfg.epoch))
    print('creating web directory {}'.format(vis_dir))
    vispage = html.HTML(vis_dir, 'Experiment = {}, Phase = {}, Epoch = {}'.format(cfg.name, cfg.phase, cfg.epoch))

    for i, data in enumerate(dataset):
        if i == 0:
            model.data_dependent_initialize(data)
            model.setup(cfg)
            model.parallelize()
            model.eval()

        model.set_input(data)
        model.test()
        visuals = model.get_current_visuals()
        img_path = model.get_image_paths()
        if i % 5 == 0:
            print('processing (%04d)-th image... %s' % (i, img_path))
        vispage.save_images(visuals, img_path, width=cfg.display_winsize)
    vispage.save()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='argument parse for test scripts')
    parser.add_argument('--dataroot', type=str)
    parser.add_argument('--gpu_ids', default='0', type=str)
    parser.add_argument('--name', default='', type=str)
    parser.add_argument('--model', default='cut', type=str)
    parser.add_argument('--phase', default='train', type=str, help='train (or val/test) set')
    parser.add_argument('--results_dir', default='./results', type=str)
    parser.add_argument('--epoch', type=str, default='latest', help='resume model epoch')
    parser.add_argument('--verbose', action='store_true', help='True with more debug info')

    args = parser.parse_args()
    main(args)


size = int(input())
address = []
visited = [[0 for _ in range(size)] for _ in range(size)]
answer =[]
counter = -1

for i in range(size):
    address.append(list(map(int, input())))

def DFS(row,col):
    if (visited[row][col] == 0):
        visited[row][col] += 1
        if (address[row][col] == 1):
            answer[counter] +=1
            if (row>0):
                if (visited[row-1][col]==0):
                    DFS(row-1,col)
            if (col>0):
                if (visited[row][col-1]==0):
                    DFS(row,col-1)
            if (row<size-1):
                if (visited[row+1][col]==0):
                    DFS(row+1,col)
            if (col<size-1):
                if (visited[row][col+1]==0):
                    DFS(row,col+1)

for i in range(size):
    for j in range(size):
        if (visited[i][j] == 0 and address[i][j] == 1):
            answer.append(0)
            counter += 1
        DFS(i,j)

print(counter+1)
answer.sort()
for i in range(len(answer)):
    print(answer[i])


"""
@Author: Furkan Kirlangic
@Last Revision: 22.12.2021
"""

import base64
import socket
from multiprocessing import Queue

import cv2
import imutils
import numpy as np
from cv2 import cv2 as cv

SIZE = 65536  # UDP data transfer size in bytes

class Udp:
    """
    If data will be sent, the device is called server.
    If client, addr is client address
    If server, addr is client address
    """

    def __init__(self, port: int, addr: str, client=False):  # client true if receiving
        self.im_queue = Queue(10)
        self.transfer_queue = Queue(10)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, SIZE)
        self.host_ip = addr
        self.port = port
        self.socket_address = (self.host_ip, self.port)

        # self.socket.bind(self.socket_address)

        if client == True:
            while True:
                try:
                    self.socket.bind(self.socket_address)
                    print("Binded successfully")
                    break
                except:
                    pass

    """                                   Video Stream                                            """
    """-------------------------------------------------------------------------------------------"""

    def vid_stream(self, width: int, height: int, im_quality: int, cam_id: int):
        cap = cv.VideoCapture(cam_id)  # device id is left zero, will be updated later when cameras are connected
        client_addr = self.socket_address
        while cap.isOpened():
            _, frame = cap.read()
            frame = imutils.resize(frame, width=width, height=height)

            encoded, buffer = cv.imencode('.jpg', frame, [cv.IMWRITE_JPEG_QUALITY, im_quality])
            message = base64.b64encode(buffer)
            try:
                self.socket.sendto(message, client_addr)
            except:

                print('Cannot send image over UDP')
            """cv.imshow('transmitting', frame)
            key = cv.waitKey(1) & 0xFF
            if key == ord('q'):
                self.socket.close()
                break
            """

    def get_vid_stream(self):
        while True:
            packet, _ = self.socket.recvfrom(SIZE)
            data = base64.b64decode(packet, ' /')
            npdata = np.fromstring(data, dtype=np.uint8)
            frame = cv.imdecode(npdata, 1)

            try:
                self.im_queue.put(frame)

                # cv2.imshow("fram", frame)
                # cv2.waitKey(0)
            except:
                print('Cannot put frame to queue')
            """cv.imshow("receiving", frame)
            key = cv.waitKey(1) & 0xFF
            if key == ord('q'):
                self.socket.close()
                break"""

    """                                 Non-video UDP transmission                                """
    """-------------------------------------------------------------------------------------------"""

    def send_msg(self, qOut: Queue):
        while True:
            message = qOut.get()
            if type(message) != bytearray:
                message = bytearray(message)
            try:
                self.socket.sendto(message, self.socket_address)
            except:
                print('Cannot send UDP message')

    def receive_msg(self):
        while True:
            try:
                message, _ = self.socket.recvfrom(SIZE)
                if type(message) != bytearray:
                    message = bytearray(message)
                # print(list(message))
                self.transfer_queue.put(message)
            except:
                print('Cannot receive UDP message')


"""
Written by DaehwaKim
>> daehwa.github.io
"""
import numpy as np
import cv2
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from load_param import cap, cap2, frame_from, frame_to, rs_offset, opti_offset

plt.ion()
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d') # Axe3D object
r_start, r_end = -500,500
visShPoints, = ax.plot(range(r_start,r_end), range(r_start,r_end), range(r_start,r_end),alpha=0.6, linestyle="", marker=".", c='g')
visNosePoints, = ax.plot(range(r_start,r_end), range(r_start,r_end), range(r_start,r_end),alpha=0.6, linestyle="", marker=".", c='y')
visTruePoints, = ax.plot(range(r_start,r_end), range(r_start,r_end), range(r_start,r_end),alpha=0.6, linestyle="", marker=".", c='b')
visPredPoints, = ax.plot(range(r_start,r_end), range(r_start,r_end), range(r_start,r_end),alpha=0.6, linestyle="", marker=".", c='r')
xaxis, yaxis, zaxis = np.array([[-400,0,0],[400,0,0]]), np.array([[0,-400,0],[0,400,0]]), np.array([[0,0,-400],[0,0,400]])
visBodyAxisX, = ax.plot(xaxis[:,0], xaxis[:,1], xaxis[:,2],alpha=0.6, c='r')
visBodyAxisY, = ax.plot(yaxis[:,0], yaxis[:,1], yaxis[:,2],alpha=0.6, c='g')
visBodyAxisZ, = ax.plot(zaxis[:,0], zaxis[:,1], zaxis[:,2],alpha=0.6, c='b')
visCamAxisX, = ax.plot(xaxis[:,0], xaxis[:,1], xaxis[:,2],alpha=0.6, c='r')
visCamAxisY, = ax.plot(yaxis[:,0], yaxis[:,1], yaxis[:,2],alpha=0.6, c='g')
visCamAxisZ, = ax.plot(zaxis[:,0], zaxis[:,1], zaxis[:,2],alpha=0.6, c='b')
visTruthAxisX, = ax.plot(xaxis[:,0], xaxis[:,1], xaxis[:,2],alpha=0.6, c='r')
visTruthAxisY, = ax.plot(yaxis[:,0], yaxis[:,1], yaxis[:,2],alpha=0.6, c='g')
visTruthAxisZ, = ax.plot(zaxis[:,0], zaxis[:,1], zaxis[:,2],alpha=0.6, c='b')
ax.set_xlabel('$x$',); ax.set_ylabel('$y$'); ax.set_zlabel('$z$')

def visualize_3d(opti_obj, ec_obj):
    t = opti_obj.center
    p = ec_obj.center_phone

    # distance = t - p
    # print("error:",distance," (mm)")

    Shpt, Nose = ec_obj.ShoulderPts_inlier, ec_obj.center_phone
    xunit, yunit, zunit = ec_obj.xunit_phone, ec_obj.yunit_phone, ec_obj.zunit_phone
    xaxis, yaxis, zaxis = np.array([p, p + xunit*100]), np.array([p, p + yunit*100]), np.array([p, p + zunit*100])
    xunit_, yunit_, zunit_ = opti_obj.x_axis, opti_obj.y_axis, opti_obj.z_axis
    xaxis_, yaxis_, zaxis_ = np.array([t, t + xunit_*100]), np.array([t, t + yunit_*100]), np.array([t, t + zunit_*100])
    visShPoints.set_data(Shpt[:,0], Shpt[:,1])
    visShPoints.set_3d_properties(Shpt[:,2], zdir="z")
    visNosePoints.set_data(Nose[0], Nose[1])
    visNosePoints.set_3d_properties(Nose[2], zdir="z")
    visTruePoints.set_data(t[0], t[1])
    visTruePoints.set_3d_properties(t[2], zdir="z")
    visPredPoints.set_data(p[0], p[1])
    visPredPoints.set_3d_properties(p[2], zdir="z")
    visCamAxisX.set_data(xaxis[:,0], xaxis[:,1])
    visCamAxisX.set_3d_properties(xaxis[:,2], zdir="z")
    visCamAxisY.set_data(yaxis[:,0], yaxis[:,1])
    visCamAxisY.set_3d_properties(yaxis[:,2], zdir="z")
    visCamAxisZ.set_data(zaxis[:,0], zaxis[:,1])
    visCamAxisZ.set_3d_properties(zaxis[:,2], zdir="z")
    visTruthAxisX.set_data(xaxis_[:,0], xaxis_[:,1])
    visTruthAxisX.set_3d_properties(xaxis_[:,2], zdir="z")
    visTruthAxisY.set_data(yaxis_[:,0], yaxis_[:,1])
    visTruthAxisY.set_3d_properties(yaxis_[:,2], zdir="z")
    visTruthAxisZ.set_data(zaxis_[:,0], zaxis_[:,1])
    visTruthAxisZ.set_3d_properties(zaxis_[:,2], zdir="z")
    fig.canvas.draw()
    fig.canvas.flush_events()

if not(cap.isOpened()):
    print("No video source")
    exit()
frames = []
frames2 = []
needupdate = True
for i in range(0,rs_offset):
    cap2.read()
ret, frame = cap.read()
ret2, frame2 = cap2.read()
frames.append(frame)
frames2.append(frame2)
i = 0
offset = np.array([0,0,0])
def streaming(opti_obj, ec_obj):
    global i, needupdate, frames, frames2, frame, frame2
    key = cv2.waitKey(2)
    # if(i == offset_sampl_frame):
    #     global offset
    #     offset = ec_obj.center_phone - opti_obj.center
    if(opti_obj == None or not ec_obj.valid or i < frame_to):
        i = i+1
        ret, frame = cap.read()
        ret2, frame2 = cap2.read()
        frames.append(frame)
        frames2.append(frame2)
        needupdate = True
        return
    if key == ord('d') or i < frame_to:
        i = i+1
        if(len(frames) > i):
            frame = frames[i]
            frame2 = frames2[i]
        else:
            ret, frame = cap.read()
            ret2, frame2 = cap2.read()
            frames.append(frame)
            frames2.append(frame2)
        needupdate = True
        print("Current Frame:"+str(i))
        # x_angle, _ = angleNaxis(opti_obj.x_axis,ec_obj.phone_xunit)
        # y_angle, _ = angleNaxis(opti_obj.y_axis,ec_obj.phone_yunit)
        # z_angle, _ = angleNaxis(opti_obj.z_axis,ec_obj.phone_zunit)
        # print(x_angle,y_angle,z_angle)
        needupdate = True
    elif key == ord('a'):
        i = i-1
        frame = frames[i]
        frame2 = frames2[i]
        needupdate = True
        print("Current Frame:"+str(i))
    if(needupdate):
        visualize_3d(opti_obj,ec_obj)
        if not(len(frames) > i):
            frames.append(frame)
            frames2.append(frame2)
    needupdate = False

def get_frame_num():
    return i

def get_images():
    return frames[i], frames2[i]


import sys, os, random, datetime, mimetypes, pygame, json
from numbers import Number
from functools import partial
from time import time as get_time, gmtime, strftime
from pygame.locals import *
from .Globals import Globals
from .utils import load_module, register_cell, register_keydown, rand_maze, rand_pos, rand_color, roundup, animate, score_pos
from .Sprite import Sprite
from .Actor import Actor
from .Level import Level
from .constants import *
import traceback
import io
from zipfile import ZipFile

levels = []
current_level = None
current_level_idx = 0
globs = None
show_grid = False
update_game = True
game_over = False
sounds = {}
images = {}
actors = {}
callbacks = []
DEFAULT_COLOR = (220, 220, 220)
_background_color = _background = DEFAULT_COLOR
DISPLAY_MAIN = '__main__'
displays = {}
display_active = DISPLAY_MAIN

def background(bg = None):
    """ set the background color or image """
    global _background, _background_color
    if bg is None:
        from urllib.request import urlopen
        import io
        image_str = urlopen('http://picsum.photos/'+str(WIDTH)+'/'+str(HEIGHT)+'/?random').read()
        image_file = io.BytesIO(image_str)
        _background = pygame.image.load(image_file).convert()
        return

    if isinstance(bg, str):
        if not os.path.isdir('backgrounds'):
            sys.exit('ERROR: background images need to be stored in the \'backgrounds\' directory')
            return
        files = os.listdir('backgrounds')
        for file in files:
            nfile = '%s.' % file
            if nfile.lower().startswith(bg.lower()):
                _background = pygame.image.load(os.path.join('backgrounds', file)).convert()
                break
        else:
            sys.exit('ERROR: background image doesn\'t exist. File must be saved in \'backgrounds\' directory: ' + bg)

        #size background to fix screen
        _background = pygame.transform.scale(_background, (WIDTH, HEIGHT))
    elif isinstance(bg, Sprite):
        globs.sprites.remove(bg)
        globs.backgrounds.append(bg)
    else :
        _background = _background_color = bg

def display(eventkey, name, wrapper=None):
    """ create a new pygame drawing surface that is triggered when eventkey is pressed.
        any active game is paused when the display is swapped """

    if FULLSCREEN:
        surface = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.HWSURFACE)
    else:
        surface = pygame.display.set_mode((WIDTH, HEIGHT), pygame.DOUBLEBUF | pygame.HWSURFACE)
    surface.fill((0, 0, 0))

    displays[name] = (surface, wrapper)

    if eventkey is not None:
        register_keydown(eventkey, partial(_display_swap, name))

    return surface

def _display_swap(name) :
    """ used to swap display surfaces. pauses any active game """
    global display_active, update_game

    if display_active == name:
        # swap to main
        displays[name][1].destroy()
        display_active = DISPLAY_MAIN
        update_game = not update_game
    else:
        if display_active != DISPLAY_MAIN:
            displays[display_active][1].destroy()
        # swap to something else
        if display_active == DISPLAY_MAIN:
            update_game = not update_game
        display_active = name
        displays[name][1].setup()

def init(path, width = 800, height = 800, title = 'Predigame', bg = (220, 220, 220), fullscreen = False, collisions = True, **kwargs):
    global globs, RUN_PATH, WIDTH, HEIGHT, FPS, GRID_SIZE, SURF, FULLSCREEN, COLLISIONS, clock, start_time, sounds

    RUN_PATH = path
    WIDTH, HEIGHT = width, height
    FPS = kwargs.get('fps', 45)
    GRID_SIZE = kwargs.get('grid', 50)
    FULLSCREEN = fullscreen
    COLLISIONS = collisions
    pygame.mixer.pre_init(22050, -16, 2, 1024) # sound delay fix
    pygame.init()
    pygame.display.set_caption(title)
    SURF = display(None, DISPLAY_MAIN)
    clock = pygame.time.Clock()

    background(bg)

    globs = Globals(WIDTH, HEIGHT, GRID_SIZE, COLLISIONS)
    Globals.instance = globs

    loading_font = pygame.font.Font(None, 72)
    SURF.blit(loading_font.render('LOADING...', True, (235, 235, 235)), (25, 25))
    pygame.display.update()

    images['__error__'] = pygame.image.load(os.path.join(os.path.dirname(__file__), 'images', 'error.png'))
    images['__screenshot__'] = pygame.image.load(os.path.join(os.path.dirname(__file__), 'images', 'screenshot.png'))

    start_time = get_time()

def _create_image(name, pos, center, size, tag):
    img = images[name]
    rect = img.get_rect()
    new_width = 0
    new_height = 0
    if size > Globals.MAX_SIZE:
        size = Globals.MAX_SIZE
    if rect.width >= rect.height:
        new_width = size * float(globs.GRID_SIZE)
        new_height = rect.height * (new_width / rect.width)
    elif rect.width < rect.height:
        new_height = size * float(globs.GRID_SIZE)
        new_width = rect.width * (new_height / rect.height)
    rect.size = new_width, new_height
    if center is not None:
        rect.topleft = (center[0] * float(globs.GRID_SIZE)) - rect.width/2.0, (center[1] * float(globs.GRID_SIZE)) - rect.height/2.0
    else:
        rect.topleft = pos[0] * float(globs.GRID_SIZE), pos[1] * float(globs.GRID_SIZE)

    s = Sprite(img, rect, tag, name=name)
    return s

def _create_actor(actions, name, pos, center, size, abortable, tag):
    img = actions['idle'][0]
    rect = img.get_rect()
    new_width = 0
    new_height = 0
    if rect.width >= rect.height:
        new_width = size * float(globs.GRID_SIZE)
        new_height = rect.height * (new_width / rect.width)
    elif rect.width < rect.height:
        new_height = size * float(globs.GRID_SIZE)
        new_width = rect.width * (new_height / rect.height)
    rect.size = new_width, new_height
    if center is not None:
        rect.topleft = (center[0] * float(globs.GRID_SIZE)) - rect.width/2.0, (center[1] * float(globs.GRID_SIZE)) - rect.height/2.0
    else:
        rect.topleft = pos[0] * float(globs.GRID_SIZE), pos[1] * float(globs.GRID_SIZE)

    s = Actor(actions, rect, tag, abortable, name=name)
    return s

def _create_rectangle(color, pos, size, outline, tag):
    rect = pygame.Rect(pos[0] * globs.GRID_SIZE, pos[1] * globs.GRID_SIZE, size[0] * globs.GRID_SIZE, size[1] * globs.GRID_SIZE)
    surface = pygame.Surface(rect.size)
    surface.fill(_background_color)
    surface.set_colorkey(_background_color)
    pygame.draw.rect(surface, color, (0, 0, rect.width, rect.height), outline)

    return Sprite(surface, rect, tag, name=color)

def _create_circle(color, pos, size, outline, tag):
    rect = pygame.Rect(pos[0] * globs.GRID_SIZE, pos[1] * globs.GRID_SIZE, size * globs.GRID_SIZE, size * globs.GRID_SIZE)
    surface = pygame.Surface(rect.size)
    surface.fill(_background_color)
    surface.set_colorkey(_background_color)
    pygame.draw.circle(surface, color, (rect.width // 2, rect.height // 2), rect.width // 2, outline)

    return Sprite(surface, rect, tag, name=color)

def _create_ellipse(color, pos, size, outline, tag):
    rect = pygame.Rect(pos[0] * globs.GRID_SIZE, pos[1] * globs.GRID_SIZE, size[0] * globs.GRID_SIZE, size[1] * globs.GRID_SIZE)
    surface = pygame.Surface(rect.size)
    surface.fill(_background_color)
    surface.set_colorkey(_background_color)
    pygame.draw.ellipse(surface, color, (0, 0, rect.width, rect.height), outline)

    return Sprite(surface, rect, tag, name=color)

def _check_image_size(ifile):
    """ make sure we don't load humongo images """
    from PIL import Image
    img = Image.open(ifile)
    basewidth = 250
    if img.size[0] > basewidth or img.size[1] > basewidth:
        print('checking image (' + ifile + ') size --> ' + str(img.size))
        wpercent = (basewidth/float(img.size[0]))
        hsize = int((float(img.size[1])*float(wpercent)))
        img = img.resize((basewidth,hsize), Image.ANTIALIAS)
        img.save(ifile)

def level(_level):
    """ create a game with levels """
    if _level is None:
        return
    if not isinstance(_level, Level) and not isinstance(_level, list):
        sys.exit('Levels must be subclases of the Level class or a list of level functions --> ' + str(_level))
    global current_level, globs
    current_level = _level
    globs = Globals(WIDTH, HEIGHT, GRID_SIZE, COLLISIONS)
    Globals.instance = globs
    if isinstance(current_level, Level):
        current_level.setup()
    else:
        global levels
        levels = _level
        current_level = Level()
        current_level.setup = levels[current_level_idx].setup
        current_level.completed = levels[current_level_idx].completed
        current_level.setup()

def image(name = None, pos = None, center = None, size = 1, tag = '', order=FRONT):
    if not name:
        if os.path.isdir('images/'):
            imgs = []
            mime_types = ('image/png', 'image/jpeg', 'image/gif')
            for img in os.listdir('images/'):
                if mimetypes.guess_type(img)[0] in mime_types:
                    imgs.append(img)
            if len(imgs):
                name = os.path.splitext(random.choice(imgs))[0]
            else:
                name = '__error__'
        else:
            name = '__error__'

    if not name in images:
        cname = '%s.' % name
        if os.path.isdir('images/'):
            for img in os.listdir('images/'):
                cimg = '%s' % img
                if cimg.lower().startswith(cname.lower()) :
                    try:
                        ifile = os.path.join('images', img)
                        _check_image_size(ifile)
                        img = pygame.image.load(ifile)
                        images[name] = img
                    except:
                        traceback.print_exc(file=sys.stdout)
                        continue

                    break
            else: # if no image is found and the loop continues ubroken
                name = '__error__'
        else:
            name = '__error__'

    if not center and not pos:
        pos = rand_pos(size - 1, size - 1)

    img = _create_image(name, pos, center, size, tag)
    if order == FRONT:
       globs.sprites.append(img)
    else:
       globs.sprites.insert(0, img)
    if center:
        register_cell(center, img)
    else:
        register_cell(pos, img)

    return img

def actor(name = None, pos = None, center = None, size = 1, abortable = False, tag = ''):
    if not name:
        sys.exit('ERROR: Actor name is missing!')
    if not os.path.isdir('actors'):
        sys.exit('ERROR:  \'actors\' directory is missing')

    loaded = False
    states = {}

    if name in actors:
        loaded = True
        states = actors[name]
    else:
        files = os.listdir('actors')
        cname = '%s.' % name
        for file in files:
            cfile = '%s' % file
            if cfile.lower().startswith(cname.lower()):
                pga_file = os.path.join('actors', file)
                try:
                    with ZipFile(pga_file) as pga:
                        lst = pga.namelist()
                        for f in lst:
                            if f.endswith('.png'):
                                state = f.split('/')[0]
                                if not state in states:
                                    states[state] = []
                                with pga.open(f) as afile:
                                    states[state].append(pygame.image.load(io.BytesIO(afile.read())))
                                    loaded = True
                    actors[name] = states
                    break
                except:
                    traceback.print_exc(file=sys.stdout)
                    sys.exit('Unable to find or load actor ' + str(name) + '. actors/' + str(name) + '.pga. may be bad!')
        else:
            sys.exit('ERROR: actor {} does not exist.'.format(name))

    if not loaded:
        sys.exit('Unable to find or load actor ' + str(name) + '. Does actors/' + str(name) + '.pga exist?')

    if not center and not pos:
        pos = rand_pos(size - 1, size - 1)

    img = _create_actor(states, name, pos, center, size, abortable, tag)
    globs.sprites.append(img)
    if center:
        register_cell(center, img)
    else:
        register_cell(pos, img)
    return img

def maze(name=None, callback=None):

    if not callback:
        callback = partial(shape, RECT)

    if not name:
        return rand_maze(callback)

    path = 'mazes/' + name + '.json'

    cells = json.load(open(path, 'r'))

    for cell in cells:
        s = callback(pos=(cell[0], cell[1]), tag='wall')
        register_cell(s.pos, s)

def shape(shape = None, color = None, pos = None, size = (1, 1), tag = '', **kwargs):
    if not shape:
        shape = random.choice(['circle', 'rect', 'ellipse'])

    if not color:
        color = rand_color()

    if isinstance(size, (int, float)):
        size = (size, size)

    if not pos:
        pos = rand_pos(size[0] - 1, size[1] - 1)

    outline = kwargs.get('outline', 0)

    if shape == 'circle':
        shape = _create_circle(color, pos, size[0], outline, tag)
    elif shape == 'rect':
        shape = _create_rectangle(color, pos, size, outline, tag)
    elif shape == 'ellipse':
        shape = _create_ellipse(color, pos, size, outline, tag)
    else:
        print('Shape, ' + shape + ', is not a valid shape name')
        return False

    globs.sprites.append(shape)
    register_cell(pos, shape)
    return shape

def text(string, color = None, pos = None, size = 1, tag = ''):
    """
        draw a text sprite

        :param string: the text to display

        :param color: the color to use to display (default is to select a random color)

        :param pos: the position of the sprite in grid coordinates (default is on center of game canvas)

        :param size: the size of the text font (default is 1)
    """
    string = str(string)
    size = int(size * globs.GRID_SIZE)
    font = pygame.font.Font(None, size)
    font_width, font_height = font.size(string)

    if not color:
        color = rand_color()

    if not pos:
        pos = (globs.WIDTH / 2 -  font_width / 2) / globs.GRID_SIZE, (globs.HEIGHT / 2 - font_height / 2) / globs.GRID_SIZE

    pos = pos[0] * GRID_SIZE, pos[1] * GRID_SIZE

    surface = font.render(string, True, color)
    text = Sprite(surface, pygame.Rect(pos[0], pos[1], font_width, font_height), tag)

    globs.sprites.append(text)
    return globs.sprites[-1]

def sound(name = None, plays = 1, duration = 0):
    """
        play a sound (wav or ogg file). Sounds must be stored in the `sounds/` directory.

        :param name: the name of the sound to play

        :param plays: the number of times to play the sound (default is 1)

        :param duration: the amount of time (in seconds) to play the sound clip (default plays the entire clip)
    """
    plays = plays - 1
    duration = int(duration * 1000)

    path = None
    snd_exts = ('wav', 'ogg')
    if name:
        path = 'sounds/' + name + '.'
        for ext in snd_exts:
            if os.path.isfile(path + ext.lower()):
                path += ext.lower()
                break

            if os.path.isfile(path + ext.upper()):
                path += ext.upper()
                break
        else:
            print('Error: Sound ' + name + ' not found')
    else:
        if os.path.isdir('sounds/'):
            snds = []
            for snd in os.listdir('sounds/'):
                for ext in snd_exts:
                    if snd.lower().endswith(ext):
                        snds.append(snd)
            if len(snds):
                path = 'sounds/' + random.choice(snds)
                name = path[7:-4]
            else:
                print('Error: No sound files found')
        else:
            print('Error: Sounds directory does not exist')

    if not name in sounds:
        snd = pygame.mixer.Sound(path)
        sounds[name] = snd

    sounds[name].play(plays, duration)

def grid():
    """
        show the grid cells on the game canvas
    """
    global show_grid
    show_grid = True

def time():
    """
        returns the time (in seconds) since the start of the game
    """
    return float('%.3f'%(get_time() - start_time))

def callback(function, wait, repeat=0):
    """
        register a time based callback function

        :param function: pointer to a callback function

        :param wait: the amount of time to **wait** for the callback to execute.

        :param repeat: the number of times this callback should repeat (default 0)
    """
    callbacks.append({'cb': function, 'time': get_time() + wait, 'wait': wait, 'repeat' : repeat})

def reset_score(**kwargs):
    """
        forces a reset for a given scoreboard element

        :param pos: the corner position of the scoreboard. Default is `UPPER_LEFT`. Options inclue `UPPER_RIGHT`, `LOWER_LEFT`, and `LOWER_RIGHT`.
    """
    pos = kwargs.get('pos', UPPER_LEFT)
    global score_dict
    try:
        globs.sprites.remove(score_dict[pos]['sprite'])
        del score_dict[pos]
        score(**kwargs)
    except:
        return

def get_score(pos=UPPER_LEFT):
    """ returns the score value in the corresponding positional score box """
    global score_dict
    try:
        scoreboard = score_dict[pos]
        return scoreboard['value']
    except:
        return 0

def score(value = 0, **kwargs):
    """
        Predigame scoring functions. Any game may have four separate
        scoreboards on the game - one in each corner. *NOTE:* all parameters,
        besides value, are only applied at scoreboard construction time.

        :param value: some scoring value (default is 0). the semantics of the value depends on the scoring `method`

        :param pos: the corner position of the scoreboard. Default is `UPPER_LEFT`. Options inclue `UPPER_RIGHT`, `LOWER_LEFT`, and `LOWER_RIGHT`.

        :param color: the color of the scoring block (default is (25, 25, 25)).

        :param size: the size (in grid cells) of the scoreboard text (default is 0.75).

        :param method: the type of scoreboard to create. options include `ACCUMULATE` (value added/subtracted to score), `VALUE` (simply display the current value), `TIMER` (count time as defined by `step`)

        :param step: applies to `method=TIMER` and sets the operation of the timer. Default is -1 (count up by seconds).

        :param goal: applies to `method=TIMER`. a goal metric of the scoreboard. If the goal is reached a `callback` will be invoked.

        :param prefix: optional text that can be provided to the start of the scoreboard.

        :param callback: optional callback to invoke when the `method=TIMER` reaches a goal.

    """
    if isinstance(value, Number):
        if value > 1000 or value < -1000:
            print('Mean scoring rejected value %s'%str(value))
            value = 0

    color = kwargs.get('color', None)
    size = kwargs.get('size', 0.75)
    pos = kwargs.get('pos', UPPER_LEFT)
    method = kwargs.get('method', ACCUMULATE)
    cb = kwargs.get('callback', None)
    sformat = kwargs.get('format', '%H:%M:%S')
    goal = kwargs.get('goal', 0)
    step = kwargs.get('step', -1)
    prefix = kwargs.get('prefix', None)
    grid_position = score_pos(pos)

    global score_dict
    try:
        score_dict
    except:
        score_dict = {}

    scoreboard = None
    try:
        scoreboard = score_dict[pos]
        if scoreboard['sprite']:
            globs.sprites.remove(scoreboard['sprite'])
    except:
        scoreboard = {
            'value': value,
            'step' : step,
            'sprite': None,
            'size': size,
            'color': (25,25,25),
            'pos': grid_position,
            'method' : method,
            'callback' : cb,
            'format' : sformat,
            'goal' : goal,
            'prefix' : prefix
        }

    scoreboard['size'] = int(size * globs.GRID_SIZE)

    if scoreboard['method'] == TIMER:
        scoreboard['value'] += scoreboard['step']
        if (scoreboard['step'] > 0 and scoreboard['value'] < scoreboard['goal']) or (scoreboard['step'] < 0 and scoreboard['value'] > scoreboard['goal']):
            callback(partial(score, pos=pos), 1)
        elif scoreboard['callback'] is not None:
            scoreboard['callback']()
    elif scoreboard['method'] == ACCUMULATE:
        if isinstance(value, Number):
            scoreboard['value'] += value
        else:
            scoreboard['value'] = value
    elif scoreboard['method'] == VALUE:
        scoreboard['value'] = value

    string = str(scoreboard['value'])
    if scoreboard['method'] == TIMER:
        string = strftime(scoreboard['format'], gmtime(scoreboard['value']))

    if scoreboard['prefix']:
        string = scoreboard['prefix'] + ' ' + string
    font = pygame.font.Font(None, scoreboard['size'])
    font_width, font_height = font.size(string)
    if color:
        scoreboard['color'] = color
    surface = font.render(string, True, scoreboard['color'])
    scoreboard['pos'] = grid_position[0] * globs.GRID_SIZE, grid_position[1] * globs.GRID_SIZE
    if pos == UPPER_RIGHT or pos == LOWER_RIGHT:
        scoreboard['sprite'] = Sprite(surface, pygame.Rect(scoreboard['pos'][0]-font_width, scoreboard['pos'][1], font_width, font_height), globs)
    else:
        scoreboard['sprite'] = Sprite(surface, pygame.Rect(scoreboard['pos'][0], scoreboard['pos'][1], font_width, font_height), globs)
    globs.sprites.append(scoreboard['sprite'])
    score_dict[pos] = scoreboard
    return scoreboard['value']

def timer(value=30, pos=LOWER_RIGHT, color=BLACK, prefix='Time Remaining: ', callback=None):
    if callback is None:
        def __gameover__():
           text('GAME OVER')
           gameover(0.5)
        callback = __gameover__
    score(pos=pos, method=TIMER, value=value, color=color, prefix=prefix, step=-1, goal=0,callback=callback)

def stopwatch(value=0, goal=999, pos=LOWER_LEFT, color=BLACK, prefix='Duration: ', callback=None):
    if callback is None:
        def __gameover__():
           text('GAME OVER')
           gameover(0.5)
        callback = __gameover__
    score(pos=pos, color=color, value=value, method=TIMER,
          step=1, goal=goal, prefix=prefix, callback=callback)

def destroyall():
    del globs.sprites[:]
    del globs.backgrounds[:]

def pause():
    pygame.event.post(pygame.event.Event(USEREVENT, action = 'pause'))

def resume():
    global update_game
    update_game = True

def gameover(delay=0.5, exit=None):
    """
        end the current game

        :param delay: the amount of time to wait before ending

        :param exit: if set the game will end with the provided exit code
    """
    def _gameover():
        global game_over
        game_over = True
        if exit is not None:
            sys.exit(exit)
    callback(_gameover, delay)

def garbagecollect():
    import gc
    gc.collect(0)
    gc.collect(1)
    gc.collect(2)

def reset(**kwargs):
    global game_over, current_level, score_dict
    game_over = False
    current_level = None
    score_dict = {}

    destroyall()
    globs.keys_registered['keydown'] = {}
    globs.keys_registered['keyup'] = {}
    globs.tags = {}
    del globs.animations[:]
    del callbacks[:]
    if not kwargs.get('soft', False):
        Globals.cache = {}
        from . import api
        code, mod = load_module(RUN_PATH, api)
        exec(code, mod.__dict__)

    garbagecollect()

    global start_time
    start_time = get_time()
    resume()

def quit():
    pygame.quit()
    sys.exit()

def screenshot(directory = 'screenshots', filename = None):
    if not os.path.isdir(directory):
        os.makedirs(directory)
    if not filename:
        filename = pygame.display.get_caption()[0] + ' - ' + str(datetime.datetime.today()) + '.jpg'
    pygame.image.save(SURF, os.path.join(directory, filename))

    size = 100 / globs.GRID_SIZE
    pos = (globs.WIDTH / globs.GRID_SIZE) / 2 - size / 2, (globs.HEIGHT / globs.GRID_SIZE) / 2 - (size / 1.36) / 2

    img = _create_image('__screenshot__', pos, None, size, '')
    globs.sprites.append(img)
    camera = globs.sprites[-1]
    animate(camera, 0.45, camera.destroy, size = size / 1.5)

def _draw_grid():
    for x in range(0, globs.WIDTH, globs.GRID_SIZE):
        pygame.draw.line(SURF, (0, 0, 0), (x, 0), (x, globs.HEIGHT))
    for y in range(0, globs.HEIGHT, globs.GRID_SIZE):
        pygame.draw.line(SURF, (0, 0, 0), (0, y), (globs.WIDTH, y))

def _update_animation(animation, delta):
    animation.update(delta)

def _update(delta):
    time = get_time()
    for sprite in globs.backgrounds:
        sprite._update(delta)

    for sprite in globs.sprites:
        sprite._update(delta)

    animations = globs.animations

    for animation in animations:
        animation.update(delta + 1000 * (get_time() - time))

    for index, animation in enumerate(animations):
        if animation.finished:
            del globs.animations[index]
            animation.finish()

    for _callback in callbacks:
        if _callback['time'] <= get_time():
            _callback['cb']()
            if _callback['repeat'] > 1:
                callback(_callback['cb'], _callback['wait'], _callback['repeat']-1)
            elif _callback['repeat'] == FOREVER:
                callback(_callback['cb'], _callback['wait'], FOREVER)
            callbacks.remove(_callback)

    if current_level is not None:
        if current_level.completed():
            next_level = None
            if len(levels) > 0:
                global current_level_idx
                current_level_idx = current_level_idx + 1
                if current_level_idx < len(levels):
                   next_level = Level()
                   next_level.setup = levels[current_level_idx].setup
                   next_level.completed = levels[current_level_idx].completed
            else:
                next_level = current_level.next()

            if next_level is not None:
                reset(soft=True)
                level(next_level)
            else:
                sys.exit('Game successfully completed all levels.')

def _draw(SURF):

    if isinstance(_background, pygame.Surface) :
        SURF.blit(_background, (0,0))
    else:
        SURF.fill(_background_color)

    for sprite in globs.backgrounds:
        sprite._draw(SURF)

    globs.cells = {}
    for sprite in globs.sprites:
        register_cell(sprite.pos, sprite)
        sprite._draw(SURF)

    if show_grid:
        _draw_grid()

def main_loop():
    global update_game
    for event in pygame.event.get():

        if event.type == QUIT:
            pygame.quit()
            sys.exit()

        # lost focus
        #if event.type == ACTIVEEVENT and event.gain == 0:
        #    pause()
        #elif event.type == ACTIVEEVENT:
        #    resume()

        if event.type == KEYDOWN:

            # ignore all the other key presses
            # complete any in process animations
            # TODO: there should be restrictions on
            #       on how this can be used

            #for key in globs.keys_pressed:
            #    globs.keys_pressed.remove(key)

            for animation in globs.animations:
                animation.abort()

            key = pygame.key.name(event.key)
            if key in globs.keys_registered['keydown']:
                for callback in globs.keys_registered['keydown'][key]:
                    callback()

            if not key in globs.keys_pressed:
                globs.keys_pressed.append(key)

            if key == 'escape':
                pygame.event.post(pygame.event.Event(QUIT))

            if key == 'f12':
                screenshot()

        if event.type == KEYUP:
            key = pygame.key.name(event.key)
            if key in globs.keys_registered['keyup']:
                for callback in globs.keys_registered['keyup'][key]:
                    callback()

            if key in globs.keys_pressed:
                globs.keys_pressed.remove(key)

        if event.type == MOUSEBUTTONDOWN:
            for sprite in globs.sprites:
                if sprite.rect.collidepoint(event.pos):
                    sprite._handle_click(event.button, event.pos)

        if event.type == USEREVENT:
            if event.action == 'pause' and update_game and not game_over:
                update_game = False
                _update(clock.get_time())
                _draw(SURF)

    if display_active == DISPLAY_MAIN and (update_game and not game_over):
        mx, my = pygame.mouse.get_pos()
        for sprite in globs.mouse_motion:
                sprite.pos = (mx/globs.GRID_SIZE - sprite.width/2,
                    my/globs.GRID_SIZE - sprite.height/2)
        _update(clock.get_time())
        _draw(SURF)

    if display_active != DISPLAY_MAIN:
        displays[display_active][1].update(clock.get_time())
        displays[display_active][1].draw(displays[display_active][0])

    pygame.display.flip()
    clock.tick(FPS)


from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from contextlib import redirect_stdout
from sklearn import svm
import face_recognition
import os
import cv2
import time

print("[INFO] initilizing paths")

start_time=time.time()

program_dir = os.getcwd()
input_dir = os.path.join(program_dir,'input')
output_dir = os.path.join(program_dir,'output')
image_dir = os.path.join(input_dir,'image')
video_dir = os.path.join(input_dir,'video')
random_dir = os.path.join(input_dir,'random')

image_name = os.listdir(image_dir)[0]
video_name = os.listdir(video_dir)[0]

image_path = os.path.join(image_dir, image_name)
video_path = os.path.join(video_dir, video_name)

start_time2=time.time()

print("[INFO] known image encoding")

known_encodings = []
known_names = []
for image_name in os.listdir(image_dir) :
    image_path = os.path.join(image_dir, image_name)
    known_image = face_recognition.load_image_file(image_path)
    known_encoding = face_recognition.face_encodings(known_image)[0]
    known_encodings.append(known_encoding)
    known_names.append('known')

for image_name in os.listdir(random_dir) :
    image_path = os.path.join(random_dir, image_name)
    known_image = face_recognition.load_image_file(image_path)
    known_encoding = face_recognition.face_encodings(known_image)[0]
    known_encodings.append(known_encoding)
    known_names.append('unknown')

clf = svm.SVC(gamma ='scale')
clf.fit(known_encodings, known_names)

start_time3=time.time()

video = cv2.VideoCapture(video_path)
video_fps = video.get(cv2.CAP_PROP_FPS)
video_frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
video_length = video_frame_count/video_fps

matches, match_count = list(), 0
timer, my_fps, my_skip = 0.0, 1/2, 5/2
os.chdir(output_dir)

print('[INFO] finding matches')
while (timer <= video_length) :
    #print('setting video')
    video.set(cv2.CAP_PROP_POS_MSEC,timer*1000)
    #print('reading image')
    hasFrames, image = video.read()
    # print('getting encodings')
    encodings = face_recognition.face_encodings(image)
    # print('finding current time')
    minutes = int(timer//60)
    seconds = int(timer%60)
    # print('no encodings check')
    if (encodings == []) :
        timer = timer + my_fps
        continue
    # print('predicting')
    if 'known' in clf.predict(encodings) :
        match_count = match_count + 1
        matches.append(timer)
        timer = timer + my_skip
        print("[INFO] found match no {} at {}:{}".format(match_count,minutes, seconds))
    else :
        timer = timer + my_fps
    print("[INFO] finished {}:{}".format(minutes, seconds))

start_time4 = time.time()

print("[INFO] found {0} matches".format(match_count))

n = len(matches)
clip_no = 1
i = 1

while(i < n) :
    clip_start = max(matches[i]-2.5,0)
    while((i+1 < n) and (matches[i+1] - matches[i] <= 6)) :
        i = i+1
    clip_stop = min(matches[i]+2.5,matches[n-1])
    clip_name = 'clip'+str(clip_no)+'.mp4'
    with open('log.txt', 'w') as f:
        with redirect_stdout(f):
            ffmpeg_extract_subclip(video_path, clip_start, clip_stop, targetname=clip_name)
    clip_no = clip_no+1
    i = i+1
print("[INFO] successfully completed in : {}".format(time.strftime('%H:%M:%S', time.gmtime(start_time4-start_time))))


'''This section introduces two classes used by pulsar
:ref:`wsgi application <apps-wsgi>` to pass a request/response state
during an HTTP request.
The :class:`WsgiRequest` is a thin wrapper around a WSGI ``environ``
dictionary.
It contains only the ``environ`` as its private data.
The :class:`WsgiResponse`, which is available in the
:class:`WsgiRequest.response` attribute, is an iterable over bytestring with
several utility methods for manipulating headers and asynchronous content.

Environ Mixin
=====================

.. autoclass:: EnvironMixin
   :members:
   :member-order: bysource

.. _app-wsgi-request:

Wsgi Request
=====================

.. autoclass:: WsgiRequest
   :members:
   :member-order: bysource

.. _wsgi-response:

Wsgi Response
=====================

.. autoclass:: WsgiResponse
   :members:
   :member-order: bysource

.. _WSGI: http://www.wsgi.org
.. _AJAX: http://en.wikipedia.org/wiki/Ajax_(programming)
.. _TLS: http://en.wikipedia.org/wiki/Transport_Layer_Security
'''
import re
from functools import reduce
from io import BytesIO

from pulsar import Future, coroutine_return
from pulsar.utils.system import json
from pulsar.utils.multipart import parse_form_data, parse_options_header
from pulsar.utils.structures import AttributeDictionary
from pulsar.utils.httpurl import (Headers, SimpleCookie, responses,
                                  has_empty_content, ispy3k,
                                  ENCODE_URL_METHODS, JSON_CONTENT_TYPES,
                                  remove_double_slash, iri_to_uri)

from .content import HtmlDocument
from .utils import (set_wsgi_request_class, set_cookie, query_dict,
                    parse_accept_header)
from .structures import ContentAccept, CharsetAccept, LanguageAccept

__all__ = ['EnvironMixin', 'WsgiResponse',
           'WsgiRequest', 'cached_property']

MAX_BUFFER_SIZE = 2**16
absolute_http_url_re = re.compile(r"^https?://", re.I)

def cached_property(f):
    name = f.__name__

    def _(self):
        if name not in self.cache:
            self.cache[name] = f(self)
        return self.cache[name]
    return property(_, doc=f.__doc__)

def wsgi_encoder(gen, encoding):
    for data in gen:
        if not isinstance(data, bytes):
            yield data.encode(encoding)
        else:
            yield data

class WsgiResponse(object):
    '''A WSGI response.

    Instances are callable using the standard WSGI call and, importantly,
    iterable::

        response = WsgiResponse(200)

    A :class:`WsgiResponse` is an iterable over bytes to send back to the
    requesting client.

    .. attribute:: status_code

        Integer indicating the HTTP status, (i.e. 200)

    .. attribute:: response

        String indicating the HTTP status (i.e. 'OK')

    .. attribute:: status

        String indicating the HTTP status code and response (i.e. '200 OK')

    .. attribute:: content_type

        The content type of this response. Can be ``None``.

    .. attribute:: headers

        The :class:`.Headers` container for this response.

    .. attribute:: environ

        The dictionary of WSGI environment if passed to the constructor.

    .. attribute:: cookies

        A python :class:`SimpleCookie` container of cookies included in the
        request as well as cookies set during the response.
    '''
    _started = False
    DEFAULT_STATUS_CODE = 200

    def __init__(self, status=None, content=None, response_headers=None,
                 content_type=None, encoding=None, environ=None,
                 can_store_cookies=True):
        self.environ = environ
        self.status_code = status or self.DEFAULT_STATUS_CODE
        self.encoding = encoding
        self.cookies = SimpleCookie()
        self.headers = Headers(response_headers, kind='server')
        self.content = content
        self._can_store_cookies = can_store_cookies
        if content_type is not None:
            self.content_type = content_type
        if environ:
            cookie = environ.get('HTTP_COOKIE')
            if cookie:
                self.cookies.load(cookie)

    @property
    def started(self):
        return self._started

    @property
    def path(self):
        if self.environ:
            return self.environ.get('PATH_INFO', '')

    @property
    def method(self):
        if self.environ:
            return self.environ.get('REQUEST_METHOD')

    @property
    def connection(self):
        if self.environ:
            return self.environ.get('pulsar.connection')

    @property
    def environ_cache(self):
        if self.environ:
            return self.environ.get('pulsar.cache')

    def _get_content(self):
        return self._content

    def _set_content(self, content):
        if not self._started:
            if content is None:
                content = ()
            elif ispy3k:
                if isinstance(content, str):
                    if not self.encoding:   # use utf-8 if not set
                        self.encoding = 'utf-8'
                    content = content.encode(self.encoding)
            else:   # pragma    nocover
                if isinstance(content, unicode):
                    if not self.encoding:  # use utf-8 if not set
                        self.encoding = 'utf-8'
                    content = content.encode(self.encoding)
            if isinstance(content, bytes):
                content = (content,)
            self._content = content
        else:
            raise RuntimeError('Cannot set content. Already iterated')
    content = property(_get_content, _set_content)

    def _get_content_type(self):
        return self.headers.get('content-type')

    def _set_content_type(self, typ):
        if typ:
            self.headers['content-type'] = typ
        else:
            self.headers.pop('content-type', None)
    content_type = property(_get_content_type, _set_content_type)

    @property
    def response(self):
        return responses.get(self.status_code)

    @property
    def status(self):
        return '%s %s' % (self.status_code, self.response)

    def __str__(self):
        return self.status

    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self)

    @property
    def is_streamed(self):
        '''Check if the response is streamed.

        A streamed response is an iterable with no length information.
        In this case streamed means that there is no information about
        the number of iterations.

        This is usually `True` if a generator is passed to the response object.
        '''
        try:
            len(self.content)
        except TypeError:
            return True
        return False

    def can_set_cookies(self):
        if self.status_code < 400:
            return self._can_store_cookies

    def length(self):
        if not self.is_streamed:
            return reduce(lambda x, y: x+len(y), self.content, 0)

    def __iter__(self):
        if self._started:
            raise RuntimeError('WsgiResponse can be iterated once only')
        self._started = True
        if self.is_streamed:
            return wsgi_encoder(self.content, self.encoding or 'utf-8')
        else:
            return iter(self.content)

    def __len__(self):
        return len(self.content)

    def close(self):
        if self.is_streamed:
            self.content.close()

    def set_cookie(self, key, **kwargs):
        """
        Sets a cookie.

        ``expires`` can be a string in the correct format or a
        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
        object then ``max_age`` will be calculated.
        """
        set_cookie(self.cookies, key, **kwargs)

    def delete_cookie(self, key, path='/', domain=None):
        set_cookie(self.cookies, key, max_age=0, path=path, domain=domain,
                   expires='Thu, 01-Jan-1970 00:00:00 GMT')

    def get_headers(self):
        '''The list of headers for this response
        '''
        headers = self.headers
        if has_empty_content(self.status_code, self.method):
            headers.pop('content-type', None)
            headers.pop('content-length', None)
            self._content = ()
        else:
            if not self.is_streamed:
                cl = 0
                for c in self.content:
                    cl += len(c)
                if cl == 0 and self.content_type in JSON_CONTENT_TYPES:
                    self._content = (b'{}',)
                    cl = len(self._content[0])
                headers['Content-Length'] = str(cl)
            ct = self.content_type
            # content type encoding available
            if self.encoding:
                ct = ct or 'text/plain'
                if 'charset=' not in ct:
                    ct = '%s; charset=%s' % (ct, self.encoding)
            if ct:
                headers['Content-Type'] = ct
        if self.can_set_cookies():
            for c in self.cookies.values():
                headers.add_header('Set-Cookie', c.OutputString())
        return list(headers)

    def has_header(self, header):
        return header in self.headers
    __contains__ = has_header

    def __setitem__(self, header, value):
        self.headers[header] = value

    def __getitem__(self, header):
        return self.headers[header]

class EnvironMixin(object):
    '''A wrapper around a WSGI_ environ.

    Instances of this class have the :attr:`environ` attribute as their
    only private data. Every other attribute is stored in the :attr:`environ`
    itself at the ``pulsar.cache`` wsgi-extension key.

    .. attribute:: environ

        WSGI_ environ dictionary
    '''
    __slots__ = ('environ',)

    def __init__(self, environ, name=None):
        self.environ = environ
        if 'pulsar.cache' not in environ:
            environ['pulsar.cache'] = AttributeDictionary()
            self.cache.mixins = {}
        if name:
            self.cache.mixins[name] = self

    @property
    def cache(self):
        '''An :ref:`attribute dictionary <attribute-dictionary>` of
pulsar-specific data stored in the :attr:`environ` at the wsgi-extension
key ``pulsar.cache``.'''
        return self.environ['pulsar.cache']

    @property
    def connection(self):
        '''The :class:`.Connection` handling the request
        '''
        return self.environ.get('pulsar.connection')

    @property
    def _loop(self):
        '''Event loop if :attr:`connection` is available.
        '''
        c = self.connection
        if c:
            return c._loop

    def __getattr__(self, name):
        mixin = self.cache.mixins.get(name)
        if mixin is None:
            raise AttributeError("'%s' object has no attribute '%s'" %
                                 (self.__class__.__name__, name))
        return mixin

    def get(self, key, default=None):
        '''Shortcut to the :attr:`environ` get method.'''
        return self.environ.get(key, default)

class WsgiRequest(EnvironMixin):
    '''An :class:`EnvironMixin` for wsgi requests.'''
    def __init__(self, environ, app_handler=None, urlargs=None):
        super(WsgiRequest, self).__init__(environ)
        self.cache.cfg = environ.get('pulsar.cfg', {})
        if app_handler:
            self.cache.app_handler = app_handler
            self.cache.urlargs = urlargs

    def __repr__(self):
        return self.path

    def __str__(self):
        return self.__repr__()

    @cached_property
    def content_types(self):
        '''List of content types this client supports as
        :class:`.ContentAccept` object.

        Obtained form the ``Accept`` request header.
        '''
        return parse_accept_header(self.environ.get('HTTP_ACCEPT'),
                                   ContentAccept)

    @cached_property
    def charsets(self):
        '''List of charsets this client supports as
        :class:`.CharsetAccept` object.

        Obtained form the ``Accept-Charset`` request header.
        '''
        return parse_accept_header(self.environ.get('HTTP_ACCEPT_CHARSET'),
                                   CharsetAccept)

    @cached_property
    def encodings(self):
        """List of encodings this client supports as
        :class:`.Accept` object.

        Obtained form the ``Accept-Charset`` request header.
        Encodings in a HTTP term are compression encodings such as gzip.
        For charsets have a look at :attr:`charsets` attribute.
        """
        return parse_accept_header(self.environ.get('HTTP_ACCEPT_ENCODING'))

    @cached_property
    def languages(self):
        """List of languages this client accepts as
        :class:`.LanguageAccept` object.

        Obtained form the ``Accept-Language`` request header.
        """
        return parse_accept_header(self.environ.get('HTTP_ACCEPT_LANGUAGE'),
                                   LanguageAccept)

    @property
    def app_handler(self):
        '''The WSGI application handling this request.'''
        return self.cache.app_handler

    @property
    def urlargs(self):
        '''Dictionary of url parameters obtained when matching a
:ref:`router <wsgi-router>` with this request :attr:`path`.'''
        return self.cache.urlargs

    @property
    def cfg(self):
        '''The :ref:`config container <settings>` of the server
        '''
        return self.cache.cfg

    @property
    def ipaddress(self):
        '''internet protocol address of the client
        '''
        return self.environ.get('REMOTE_ADDR')

    @cached_property
    def response(self):
        '''The :class:`WsgiResponse` for this client request.
        '''
        return WsgiResponse(environ=self.environ)

    #######################################################################
    #    environ shortcuts
    @property
    def is_xhr(self):
        '''``True`` if this is an AJAX_ request
        '''
        return self.environ.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'

    @property
    def is_secure(self):
        '''``True`` if this request is via a TLS_ connection
        '''
        return self.environ.get('HTTPS') == 'on'

    @property
    def path(self):
        '''Shortcut to the :attr:`~EnvironMixin.environ` ``PATH_INFO`` value.
        '''
        return self.environ.get('PATH_INFO', '/')

    @property
    def method(self):
        '''The request method (uppercase).'''
        return self.environ['REQUEST_METHOD']

    @cached_property
    def encoding(self):
        return self.content_type_options[1].get('charset', 'utf-8')

    @cached_property
    def content_type_options(self):
        content_type = self.environ.get('CONTENT_TYPE')
        if content_type:
            return parse_options_header(content_type)
        else:
            return None, {}

    def data_and_files(self, data=True, files=True):
        '''Retrieve body data.

        Returns a two-elements tuple of a
        :class:`~.MultiValueDict` containing data from
        the request body, and data from uploaded files.

        If the body data is not ready, return a :class:`.Future`
        which results in the tuple.

        The result is cached.
        '''
        value = self.cache.data_and_files
        if not value:
            return self._data_and_files(data, files)
        elif data and files:
            return value
        elif data:
            return value[0]
        elif files:
            return value[1]
        else:
            return None

    def body_data(self):
        '''A :class:`~.MultiValueDict` containing data from the request body.
        '''
        return self.data_and_files(files=False)

    def _data_and_files(self, data=True, files=True):
        result = {}, None
        stream = self.environ.get('wsgi.input')
        chunk = None
        try:
            if self.method not in ENCODE_URL_METHODS and stream:
                chunk = stream.read()
                if isinstance(chunk, Future):
                    chunk = yield chunk
                content_type, options = self.content_type_options
                charset = options.get('charset', 'utf-8')
                if content_type in JSON_CONTENT_TYPES:
                    result = json.loads(chunk.decode(charset)), None
                else:
                    self.environ['wsgi.input'] = BytesIO(chunk)
                    result = parse_form_data(self.environ, charset)
        finally:
            self.cache.data_and_files = result
            if chunk is not None:
                self.environ['wsgi.input'] = BytesIO(chunk)
        coroutine_return(self.data_and_files(data, files))

    @cached_property
    def url_data(self):
        '''A (cached) dictionary containing data from the ``QUERY_STRING``
        in :attr:`~.EnvironMixin.environ`.
        '''
        return query_dict(self.environ.get('QUERY_STRING', ''),
                          encoding=self.encoding)

    @cached_property
    def html_document(self):
        '''Return a cached instance of :class:`.HtmlDocument`.'''
        return HtmlDocument()

    def get_host(self, use_x_forwarded=True):
        """Returns the HTTP host using the environment or request headers."""
        # We try three options, in order of decreasing preference.
        if use_x_forwarded and ('HTTP_X_FORWARDED_HOST' in self.environ):
            host = self.environ['HTTP_X_FORWARDED_HOST']
        elif 'HTTP_HOST' in self.environ:
            host = self.environ['HTTP_HOST']
        else:
            # Reconstruct the host using the algorithm from PEP 333.
            host = self.environ['SERVER_NAME']
            server_port = str(self.environ['SERVER_PORT'])
            if server_port != ('443' if self.is_secure else '80'):
                host = '%s:%s' % (host, server_port)
        return host

    def full_path(self, *args, **query):
        '''Return a full path'''
        path = None
        if args:
            if len(args) > 1:
                raise TypeError("full_url() takes exactly 1 argument "
                                "(%s given)" % len(args))
            path = args[0]
        if path is None:
            path = self.path
            if not query:
                query = self.url_data
        elif not path.startswith('/'):
            path = remove_double_slash('%s/%s' % (self.path, path))
        return iri_to_uri(path, query)

    def absolute_uri(self, location=None, scheme=None):
        '''Builds an absolute URI from ``location`` and variables
        available in this request.

        If no ``location`` is specified, the relative URI is built from
        :meth:`full_path`.
        '''
        if not location or not absolute_http_url_re.match(location):
            location = self.full_path(location)
            if not scheme:
                scheme = self.is_secure and 'https' or 'http'
            base = '%s://%s' % (scheme, self.get_host())
            return '%s%s' % (base, location)
        elif not scheme:
            return iri_to_uri(location)
        else:
            raise ValueError('Absolute location with scheme not valid')

set_wsgi_request_class(WsgiRequest)