"""empty message

Revision ID: b96f3a390985
Revises:
Create Date: 2022-10-11 12:02:04.313388

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from datetime import datetime

# revision identifiers, used by Alembic.
revision = 'b96f3a390985'
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    document_status_table = op.create_table('DocumentStatus',
        sa.Column('statusid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('name', sa.String(length=120), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('isactive', sa.Boolean(), nullable=False),
        sa.PrimaryKeyConstraint('statusid')
    )

    op.bulk_insert(
        document_status_table,
        [
            {'name':'new', 'isactive':True, 'description': 'New'},
            {'name':'inprogress', 'isactive':True, 'description': 'In progress'},
            {'name':'saved', 'isactive':True, 'description': 'Saved'},
        ]
    )

    documents_table = op.create_table('Documents',
        sa.Column('documentid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('version', sa.Integer(), primary_key=True, nullable=False),
        sa.Column('filename', sa.String(length=120), nullable=False),
        sa.Column('filepath', sa.String(length=255), nullable=False),
        sa.Column('attributes', postgresql.JSON(astext_type=sa.Text()), nullable=True),
        sa.Column('foiministryrequestid', sa.Integer(), nullable=False),
        sa.Column('createdby', postgresql.JSON(astext_type=sa.Text()), nullable=False),
        sa.Column('created_at', sa.DateTime(), nullable=False, default=datetime.now),
        sa.Column('updatedby', postgresql.JSON(astext_type=sa.Text()), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.Column('statusid', sa.Integer(), nullable=False),
        sa.Column('pagecount', sa.Integer(), nullable=True, default=0),
        sa.PrimaryKeyConstraint('documentid', 'version'),
        sa.ForeignKeyConstraint(['statusid'], ['DocumentStatus.statusid'], )
    )

    document_tag_table = op.create_table('DocumentTags',
        sa.Column('tagid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('documentid', sa.Integer(), nullable=False),
        sa.Column('documentversion', sa.Integer(), nullable=False),
        sa.Column('tag', postgresql.JSON(astext_type=sa.Text()), nullable=True),
        sa.Column('createdby', postgresql.JSON(astext_type=sa.Text()), nullable=False),
        sa.Column('created_at', sa.DateTime(), nullable=False, default=datetime.now),
        sa.PrimaryKeyConstraint('tagid'),
        sa.ForeignKeyConstraint(['documentid', 'documentversion'], ['Documents.documentid', 'Documents.version'], )
    )

    op.create_table('Annotations',
        sa.Column('annotationid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('annotationname', sa.String(length=120), unique=True, nullable=False),
        sa.Column('documentid', sa.Integer(), nullable=False),
        sa.Column('documentversion', sa.Integer(), nullable=False),
        sa.Column('annotation', sa.Text(), nullable=False),
        sa.Column('pagenumber', sa.Integer(), nullable=False),
        sa.Column('isactive', sa.Boolean(), nullable=False, default=True),
        sa.Column('createdby', postgresql.JSON(astext_type=sa.Text()), nullable=False),
        sa.Column('created_at', sa.DateTime(), nullable=False, default=datetime.now),
        sa.Column('updatedby', postgresql.JSON(astext_type=sa.Text()), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('annotationid'),
        sa.ForeignKeyConstraint(['documentid', 'documentversion'], ['Documents.documentid', 'Documents.version'], )
    )

    program_areas_table =  op.create_table('ProgramAreas',
        sa.Column('programareaid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('name', sa.String(length=120), nullable=False),
        sa.Column('type', sa.String(length=120), nullable=False),
        sa.Column('bcgovcode', sa.String(length=120), nullable=False),
        sa.Column('iaocode', sa.String(length=120), nullable=False),
        sa.Column('isactive', sa.Boolean(), nullable=False),
        sa.PrimaryKeyConstraint('programareaid')
    )

    op.bulk_insert(
        program_areas_table,
        [
            {'name':'Ministry of Advanced Education and Skills Training','type':'BC GOV Ministry','isactive':True,'bcgovcode':'AEST','iaocode':'AED'},
            {'name':'Ministry of Agriculture and Food','type':'BC GOV Ministry','isactive':True,'bcgovcode':'AGR','iaocode':'AGR'},
            {'name':'Ministry of Attorney General','type':'BC GOV Ministry','isactive':True,'bcgovcode':'AG','iaocode':'MAG'},
            {'name':'Ministry of Children and Family Development','type':'BC GOV Ministry','isactive':True,'bcgovcode':'MCF','iaocode':'CFD'},
            {'name':'Ministry of Citizens’ Services','type':'BC GOV Ministry','isactive':True,'bcgovcode':'CITZ','iaocode':'CTZ'},
            {'name':'Ministry of Education and Childcare','type':'BC GOV Ministry','isactive':True,'bcgovcode':'EDU','iaocode':'EDU'},
            {'name':'Ministry of Energy, Mines and Low Carbon Innovation','type':'BC GOV Ministry','isactive':True,'bcgovcode':'EMLI','iaocode':'EML'},
            {'name':'Ministry of Environment and Climate Change Strategy','type':'BC GOV Ministry','isactive':True,'bcgovcode':'ENV','iaocode':'MOE'},
            {'name':'Ministry of Finance','type':'BC GOV Ministry','isactive':True,'bcgovcode':'FIN','iaocode':'FIN'},
            {'name':'Ministry of Forests','type':'BC GOV Ministry','isactive':True,'bcgovcode':'FOR','iaocode':'FOR'},
            {'name':'Ministry of Health','type':'BC GOV Ministry','isactive':True,'bcgovcode':'HLTH','iaocode':'HLTH'},
            {'name':'Ministry of Indigenous Relations and Reconciliation','type':'BC GOV Ministry','isactive':True,'bcgovcode':'IRR','iaocode':'IRR'},
            {'name':'Ministry of Jobs, Economic Recovery and Innovation','type':'BC GOV Ministry','isactive':True,'bcgovcode':'JERI','iaocode':'JER'},
            {'name':'Ministry of Labour','type':'BC GOV Ministry','isactive':True,'bcgovcode':'LBR','iaocode':'LBR'},
            {'name':'Ministry of Mental Health and Addictions','type':'BC GOV Ministry','isactive':True,'bcgovcode':'MMHA','iaocode':'MHA'},
            {'name':'Ministry of Municipal Affairs','type':'BC GOV Ministry','isactive':True,'bcgovcode':'MUNI','iaocode':'MMA'},
            {'name':'Ministry of Public Safety and Solicitor General','type':'BC GOV Ministry','isactive':True,'bcgovcode':'PSSG','iaocode':'PSS'},
            {'name':'Ministry of Social Development and Poverty Reduction','type':'BC GOV Ministry','isactive':True,'bcgovcode':'SDPR','iaocode':'MSD'},
            {'name':'Ministry of Tourism, Arts, Culture and Sport','type':'BC GOV Ministry','isactive':True,'bcgovcode':'TACS','iaocode':'TAC'},
            {'name':'Ministry of Transportation and Infrastructure','type':'BC GOV Ministry','isactive':True,'bcgovcode':'TRAN','iaocode':'TRA'},
            {'name':'BC Coroners Service','type':'Other','isactive':True,'bcgovcode':'OCC','iaocode':'OCC'},
            {'name':'BC Public Service Agency','type':'Other','isactive':True,'bcgovcode':'PSA','iaocode':'PSA'},
            {'name':'Board Resourcing and Development Office','type':'Other','isactive':True,'bcgovcode':'BRD','iaocode':'BRD'},
            {'name':'Community Living BC','type':'Other','isactive':True,'bcgovcode':'CLB','iaocode':'CLB'},
            {'name':'Crown Agencies Secretariat','type':'Other','isactive':True,'bcgovcode':'CAS','iaocode':'CAS'},
            {'name':'Emergency Management BC','type':'Other','isactive':True,'bcgovcode':'EMBC','iaocode':'EMB'},
            {'name':'Environmental Assessment Office','type':'Other','isactive':True,'bcgovcode':'EAO','iaocode':'EAO'},
            {'name':'Government Communications and Public Engagement','type':'Other','isactive':True,'bcgovcode':'GCPE','iaocode':'GCP'},
            {'name':'Independent Investigations Office','type':'Other','isactive':True,'bcgovcode':'IIO','iaocode':'IIO'},
            {'name':'Office of the Premier','type':'Other','isactive':True,'bcgovcode':'PREM','iaocode':'OOP'},
            {'name':'Liquor Distribution Branch','type':'Other','isactive':True,'bcgovcode':'LDB','iaocode':'LDB'},
            {'name':'Transportation Investment Corporation','type':'Other','isactive':True,'bcgovcode':'TIC','iaocode':'TIC'},
            {'name':'Order of British Columbia Advisory Council','type':'Other','isactive':True,'bcgovcode':'OBC','iaocode':'OBC'},
            {'name':'Medal of Good Citizenship Selection Committee','type':'Other','isactive':True,'bcgovcode':'MGC','iaocode':'MGC'},
            {'name':'Declaration Act Secretariat','type':'BC GOV Ministry','isactive':True,'bcgovcode':'DAS','iaocode':'DAS'},
            {'name':'Lands, Water and Resource Stewardship','type':'BC GOV Ministry','isactive':True,'bcgovcode':'LWR','iaocode':'LWR'}
        ]
    )

    programarea_division_table =  op.create_table('ProgramAreaDivisions',
        sa.Column('divisionid', sa.Integer(), primary_key=True, nullable=False),
        sa.Column('programareaid', sa.Integer(), nullable=False),
        sa.Column('name', sa.String(length=120), nullable=False),
        sa.Column('isactive', sa.Boolean(), nullable=False),
        sa.Column('createdby', sa.String(length=120), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('divisionid'),
        sa.ForeignKeyConstraint(['programareaid'], ['ProgramAreas.programareaid'], )
    )

    op.bulk_insert(
        programarea_division_table,
        [
            {'divisionid':1, 'programareaid':6, 'name':'Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':2, 'programareaid':6, 'name':'Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':3, 'programareaid':6, 'name':'Education Programs', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':4, 'programareaid':6, 'name':'Learning', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':5, 'programareaid':6, 'name':'Services & Technology', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':6, 'programareaid':6, 'name':'Governance & Analytics', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':7, 'programareaid':6, 'name':'Resource Management', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':8, 'programareaid':16, 'name':'Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':9, 'programareaid':16, 'name':'Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':10, 'programareaid':16, 'name':'Management Services', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':11, 'programareaid':16, 'name':'Immigration Services and Strategic Planning', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':12, 'programareaid':16, 'name':'Local Government', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':13, 'programareaid':14, 'name':'Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':14, 'programareaid':14, 'name':'Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':15, 'programareaid':14, 'name':'Labour', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':16, 'programareaid':14, 'name':'Management Services', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':17, 'programareaid':14, 'name':'Policy and Legislation', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':18, 'programareaid':14, 'name':'Employment Standards', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':19, 'programareaid':14, 'name':'Workers’ Advisor’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':20, 'programareaid':14, 'name':'Employers’ Advisor’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':21, 'programareaid':13, 'name':'Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':22, 'programareaid':13, 'name':'Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':23, 'programareaid':13, 'name':'Management Services', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':24, 'programareaid':13, 'name':'Trade & Industry Development', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':25, 'programareaid':13, 'name':'Small Business & Economic Development', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':27, 'programareaid':13, 'name':'Mass Timber Implementation', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':28, 'programareaid':13, 'name':'Innovation, Technology & Investment Capital', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':29, 'programareaid':13, 'name':'Investment & Innovation', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':30, 'programareaid':19, 'name':'Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':31, 'programareaid':19, 'name':'Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':32, 'programareaid':19, 'name':'Sport and Creative Sector', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':33, 'programareaid':19, 'name':'Management Services', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':34, 'programareaid':19, 'name':'Arts & Culture', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':35, 'programareaid':19, 'name':'Tourism Sector Strategy', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':36, 'programareaid':14, 'name':'Assistant Deputy Minister’s Office', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':37, 'programareaid':6, 'name':'Child Care', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()},
            {'divisionid':38, 'programareaid':6, 'name':'Minister of State', 'isactive':True, 'createdby':'system', 'created_at':datetime.now()}
        ]
    )

    s3_account_table =  op.create_table('OperatingTeamS3ServiceAccounts',
        sa.Column('teamid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False),
        sa.Column('usergroup', sa.String(length=120), nullable=False),
        sa.Column('accesskey', sa.String(length=255), nullable=False),
        sa.Column('secret', sa.String(length=255), nullable=False),
        sa.Column('type', sa.String(length=120), nullable=False),
        sa.Column('isactive', sa.Boolean(), nullable=False),
        sa.PrimaryKeyConstraint('teamid')
    )

    op.bulk_insert(
        s3_account_table,
        [
            {'usergroup':'intake', 'accesskey':'12345', 'secret':'12345', 'type':'iao', 'isactive':True},
            {'usergroup':'flex', 'accesskey':'12345', 'secret':'12345', 'type':'iao', 'isactive':True},
            {'usergroup':'processing', 'accesskey':'12345', 'secret':'12345', 'type':'iao', 'isactive':True},
            {'usergroup':'AEST Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'AGR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'AG Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'BRD Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'CAS Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'CITZ Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'CLB Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'DAS Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'EAO Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'EDU Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'EMBC Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'EMLI Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'ENV Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'FIN Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'FOR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'GCPE Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'HLTH Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'IIO Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'IRR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'JERI Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'LBR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'LDB Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'LWR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'MCF Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'MGC Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'MMHA Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'MUNI Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'OBC Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'OCC Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'PREM Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'PSA Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'PSSG Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'SDPR Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'TACS Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'TIC Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True},
            {'usergroup':'TRAN Ministry Team', 'accesskey':'12345', 'secret':'12345', 'type':'ministry', 'isactive':True}
        ]
    )

    docment_path_mapper = op.create_table('DocumentPathMapper',
        sa.Column('documentpathid', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('category', sa.Text,nullable=False),
        sa.Column('bucket', sa.Text,nullable=False),
        sa.Column('attributes', sa.Text,nullable=True),
        sa.Column('isactive', sa.Boolean(), nullable=False),
        sa.Column('createdby', sa.String(length=120), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=True, default=datetime.now),
        sa.Column('updatedby', sa.String(length=120), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('documentpathid')
    )

    op.bulk_insert(
        docment_path_mapper,
        [
            {'category':'Attachments','bucket':'$environment-forms-foirequests','isactive':True,'createdby':'System'},
            {'category':'Records','bucket':'$bcgovcode-$environment','isactive':True,'createdby':'System'}
        ]
    )

def downgrade():
    op.drop_table('Documents')
    op.drop_table('DocumentTags')
    op.drop_table('DocumentStatus')
    op.drop_table('Annotations')
    op.drop_table('ProgramAreas')
    op.drop_table('ProgramAreaDivisions')
    op.drop_table('OperatingTeamS3ServiceAccounts')
    op.drop_table('DocumentPathMapper')


from typing import Iterable, Dict, Any

import requests
from requests.models import Response

from osrm.responses import RouteResponse

def format_coords(coords) -> str:
    coords = ";".join([f"{lon},{lat}" for lat, lon in coords])
    return coords

def format_options(options: Dict[str, Any]) -> str:
    options = "&".join([f"{op}={val}" for op, val in options.items()])
    if options:
        return "?" + options
    return options

def format_request(
    host: str,
    service: str,
    coords: Iterable[Iterable[float]],
    options: Dict[str, Any] = None,
    profile: str = "driving",
    version: str = "v1",
) -> str:
    coords = format_coords(coords)
    options = "" if options is None else format_options(options)
    req = f"http://{host}/{service}/{version}/{profile}/{coords}{options}"
    return req

class Client:
    def __init__(self, host: str = None):
        if host is None:
            host = "router.project-osrm.org"
        self.host = host

    def request(
        self,
        service: str,
        coords: Iterable[Iterable[float]],
        options: Dict[str, Any] = None,
        profile: str = "driving",
        version: str = "v1",
    ):
        req = format_request(self.host, service, coords, options, profile, version)
        response = requests.get(req)
        return response

    def route(self, coords, options=None, profile="driving", version="v1"):
        response = self.request("route", coords, options, profile, version)
        return RouteResponse(response)


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

import os, yaml, django, hashlib
from test_weather import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE','test_weather.settings')
django.setup()

from apis.models import App

def init_app_data():
    old_apps = App.objects.all()
    path = os.path.join(settings.BASE_DIR, 'app.yaml')
    with open(path, 'r', encoding='utf-8') as f:
        apps = yaml.load(f)
        published = apps.get('published')
        for item in published:
            item = item.get('app')
            src = item.get('category') + item.get('application')
            appid = hashlib.md5(src.encode('utf8')).hexdigest()
            if len(App.objects.filter(appid=appid)) == 1:
                app = App.objects.filter(appid=appid)[0]
            else:
                app = App()
            app.appid = appid
            app.name = item.get('name')
            print(app.name)
            app.application = item.get('application')
            app.url = item.get('url')
            app.publish_date = item.get('publish_date')
            app.category = item.get('category')
            app.desc = item.get('desc')
            app.save()

if __name__ == "__main__":
    init_app_data()


import logging
from qdrant_client import qdrant_client

class QdrantClient:
    client = None

    def connect(self, host: str = None, port: int = None, api_key: str = None):
        """Connect to Qdrant"""
        if host:
            host = host.replace("http://", "")
            host = host.replace("https://", "")
        try:
            self.client = qdrant_client.QdrantClient(
                host=host,
                port=port,
                api_key=api_key,
            )
        except Exception as e:
            logging.error(f"[Qdrant Connection] {e}")


import pandas as pd
import numpy as np
import datetime
from sklearn import preprocessing, svm
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split, cross_validate
from sklearn.linear_model import LinearRegression

from sklearn import linear_model
from sklearn.svm import LinearSVR
from sklearn.pipeline import make_pipeline

import matplotlib
import matplotlib.pyplot as plt

path_all = 'C:\\Users\\Captain\\Crypto\\Data\\bitcoin_new.csv'
# df = pd.read_csv(path_all, sep=',', index_col=['Date'])
df = pd.read_csv(path_all,
                 usecols=["Date", "Price", 'Open', 'High', 'Low', 'Vol.', 'Change %'],
                 parse_dates=True,
                 index_col=["Date"])

df['HL'] = (df['High'] - df['Low']) / (df['Low'] * 100)
for_col = 'Price'
forecast = int(30)
df['label'] = df[for_col].shift(-forecast)
# df['label'] = df[for_col]

X = np.array(df.drop(['label'], 1))
X = preprocessing.scale(X)
X_forecast_out = X[-forecast:]
X = X[:-forecast]
y = np.array(df['label'])
y = y[:-forecast]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

ridge_def = linear_model.Ridge(alpha=200)
ridge_def.fit(X_train, y_train)
# Test
accuracy = ridge_def.score(X_test, y_test)
print("Accuracy of Ridge Regression: ", accuracy)

for_out = ridge_def.predict(X_forecast_out)

Xnew, _ = make_regression(n_samples=30, n_features=len(df.columns) - 1, noise=0.1, random_state=1)
Xnew = np.array(Xnew)
Xnew = preprocessing.scale(Xnew)
print(Xnew)
ridge_out = ridge_def.predict(Xnew)
#
#
predicted = np.array([])
for t in range(0, 30):
    predicted = np.append(predicted, ridge_out[t])

print(predicted)

# df.dropna(inplace=True)
# df['Predicted'] = np.nan
# last_date1 = df.iloc[-1].name
# last_unix1 = last_date1.timestamp()
# one_day1 = 86400
# next_unix1 = last_unix1 + one_day1
#
# for t in ridge_out:
#     next_date1 = datetime.datetime.fromtimestamp(next_unix1)
#     next_unix1 += 86400
#     df.loc[next_date1] = [np.nan for _ in range(len(df.columns)-1)]+[t]

df.dropna(inplace=True)
df['forecast'] = np.nan
# last_date = df.iloc[-1].name + pd.Timedelta(forecast, unit='D')
last_date = df.iloc[-1].name
# print(last_date)
last_unix = last_date.timestamp()
one_day = 86400
next_unix = last_unix + one_day

for i in for_out:
    next_date = datetime.datetime.fromtimestamp(next_unix)
    next_unix += 86400
    df.loc[next_date] = [np.nan for _ in range(len(df.columns) - 1)] + [i]

df['Price'].plot(figsize=(15, 6), color="green")
df['forecast'].plot(figsize=(15, 6), color="orange")
# df['Predicted'].plot(figsize=(15, 6), color="purple")
plt.xlim(xmin=datetime.date(2020, 6, 1))
plt.xlim(xmax=datetime.date(2020, 9, 1))
plt.ylim(ymin=500)
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
# plt.show()

# out_data = [df.forecast]
# df_out = pd.DataFrame(out_data)
# df_out = df_out.T
# df_out.to_csv('./ridge_test3.csv')


import json
import yaml
# load json file
with open('data.json') as json_file:
    data = json.load(json_file)

# Write a Python script to select the name of the first person in the first group
print("-----------------------1-------------------------")

# select first group and first person
first_group = data['groups'][0]['group']
first_person = first_group['members'][0]

# print the name of the first person
print(first_person['person_name'])

# Write a Python script to make a list of all names and email addresses
print("-------------------2---------------------------")

# create empty lists to store names and emails
names = []
emails = []

# iterate through groups and members
for group in data['groups']:
    for member in group['group']['members']:
        names.append(member['person_name'])
        emails.append(member['email'])

# print the lists
print("Names:", names)
print("Emails:", emails)

# Write a Python script to make a list of all names and email addresses of DEVASC_B
print("-----------------------3-----------------------")

# create empty lists to store names and emails
names = []
emails = []

# iterate through groups and members
for group in data['groups']:
    if group['group']['group_name'] == 'DEVASC_B':
        for member in group['group']['members']:
            names.append(member['person_name'])
            emails.append(member['email'])

# print the lists
print("Names:", names)
print("Emails:", emails)

print('')
print(">>>>>>>>>>>>>>>>>>>")
print('convert json to yaml')
print('>>>>>>>>>>>>>>>>>>>>>')
yaml_data = yaml.dump(data)
print(yaml_data)


from odoo import models, fields, api
from datetime import datetime, date

class HrEmployee(models.Model):
    _inherit = "hr.employee"

    # Nationalité & Autre Information
    x_nationalite_id = fields.Many2one('ref_nationalite', default=lambda self: self.env['ref_nationalite'].search(
        [('code_nationalite', '=', 'BF')]), string='Nationalité')
    matricule_genere = fields.Char(string="Matricule")
    matricule = fields.Char(string="Mle Fonctionnaire ")
    x_type_piece_id = fields.Many2one("hr_typepiece", string="Type pièce", required=True)
    ref_identification = fields.Char(string='Ref.Identification', required=True)
    # Information de  contact
    tel = fields.Char(string='Telephone', required=True)
    personne_id = fields.Char('Personne à prevenir en cas de besoin', required=True)
    x_email = fields.Char(string="Email")
    # Statut
    genre = fields.Selection([
        ('masculin', 'Masculin'), ('feminin', 'Feminin'),
        ('autre', 'Autre')],
        string='Genre', default="masculin")
    situation_marital = fields.Selection([
        ('celibataire', 'Célibataire'),
        ('marie', 'Marié(e)'),
        ('concubinage', 'Concubinage'),
        ('veuf(ve)', 'Veuf(ve)'),
        ('divorce', 'Divorcé(e)')],
        string='Etat civil', default="celibataire")
    charge_femme = fields.Integer(string="Charge femme", required=True)
    charge_enfant = fields.Integer(string="Charge enfant", required=True, compute="calcul_charge_enfant")
    charge = fields.Integer(store=True, string="Charge total", readonly=True, compute="calcul_charge")
    x_montant_charge = fields.Float(string="Montant charge", readonly=True, store=True, compute='mnt_charge_field')

    # Naissance
    x_date_naissance = fields.Date(string='Date de naissance', required=True)
    x_nb_annee_retraite = fields.Many2one("hr_nbreannee", string="Age de retraite", required=True)
    x_date_retraite = fields.Date(string='Date retraite', compute="_compute_date_retraite")
    lieu_naiss = fields.Many2one('ref_localite', string='Lieu de naissance')
    # Éducation
    x_diplome_id = fields.Many2one("hr_diplome", string="Dernier diplôme")
    x_diplome_recrut_id = fields.Many2one("hr_diplome", string="Diplôme de recrutement")
    branche = fields.Char(string="Branche d'étude")
    ecole = fields.Char(string="Ecole/Université")
    observations = fields.Html(string='Observations')

    # Informations professionnelles
    type_id = fields.Many2one(comodel_name='hr_contract_type', string='Type contrat')  # type contrat
    x_categorie_employe_id = fields.Many2one("hr_catemp", string="Catégorie employé", required=True)
    struct_id = fields.Many2one("hr.payroll.structure", string="Type employé",
                                required=True)  # type employe/srtuture salariale
    struct_id_code = fields.Char(string='Struct_id_code', required=False, related="struct_id.code")
    x_emploi_id = fields.Many2one("hr_emploi", string="Emploi", required=True, )
    x_fonction_id = fields.Many2one("hr_fonctionss", string="Fonction", required=True)
    hr_service = fields.Many2one("hr_service", string="Service")
    x_unite_id = fields.Many2one("hr_unite", string="Unite", required=False)
    x_zone_id = fields.Many2one("hr_zone", string="Zone", required=True)
    x_mode_paiement = fields.Selection([
        ('billetage', 'Billetage'),
        ('virement', 'Virement'),
    ], string="Mode de Paiement", default='virement', required=True)
    num_banque = fields.Char('N° compte bancaire', required=True)
    x_banque_id = fields.Many2one('res.bank', 'Banque', required=True)
    intitule = fields.Char(string="Intitulé du compte")

    date_sercice = fields.Date(string="Date Service")

    # Situation administrative de l'agent dans l'Etat
    x_classees_id = fields.Many2one('hr_classe', string='Classe')
    x_categorie_id = fields.Many2one('hr_categorie', string='Catégorie')
    x_echelle_id = fields.Many2one('hr_echelle', string='Echelle')
    x_echellon_id = fields.Many2one('hr_echellon', string='Echelon')
    x_classification = fields.Char(store=True, string="Classification")
    date_modiff = fields.Date(string='Date effet', default=date.today())
    date_debut = fields.Date(string="Date d'engagement", default=date.today())
    date_fin = fields.Date(string="Date fin")
    x_solde_indiciaire = fields.Float(string="Solde Indiciaire", readonly=True,
                                      compute="cal_sal_base")  # salaire de base des fonctionnaires
    x_solde_indiciaire_net = fields.Float(string="Salaire de base", compute="cal_sal_base",
                                          readonly=True)  # salaire de base des fonctionnaires + montant residence
    x_indice = fields.Float(string='Indice', compute="cal_sal_base")

    # Situation administrative de l'agent dans l'EPE
    x_categorie_c_id = fields.Many2one('hr_categorie', string='Catégorie', required=False)
    x_echelle_c_id = fields.Many2one('hr_echelle', string='Echelle', required=False)
    x_echellon_c_id = fields.Many2one('hr_echellon', required=False, string='Echelon')
    x_solde_indiciaire_ctrct = fields.Float(string="Salaire de base", required=True)  # salaire de base des contractuels

    date_embauche = fields.Date(string="Date d'embauche", default=date.today())
    date_fin_embauche = fields.Date(string="Date fin")
    date_modiff = fields.Date(string='Date effet', default=date.today())

    # CALCUL DE L'EMOLUMENT
    x_emolument_ctrct = fields.Float(string="Emolument Brut")
    x_taux_retenu_emolmt = fields.Float(string="Taux retenue (%)")
    x_mnt_taux_retenu_emolmt = fields.Float(string="Montant Taux")
    x_emolument_ctrct_net = fields.Float(string="Emolument Net", readonly=True)

    # Declaration variables Indemnités
    x_indem_resp = fields.Float(string="Indemn.Resp", readonly=False)
    x_indem_astr = fields.Float(string="Indemn.Astreinte", compute="cal_indem_astr")
    x_indem_techn = fields.Float(string="Indemn.Technicité", readonly=False)
    x_indem_specif = fields.Float(string="Indemn.Spécifique GRH", readonly=False)
    x_indem_loge = fields.Float(string="Indemn.Logement", readonly=False)
    x_indem_transp = fields.Float(string="Indemn.Transport", readonly=False)
    x_indem_inform = fields.Float(string="Indemn.Informatique", readonly=False)
    x_indem_exploit = fields.Float(string="Indemn.Exploitation-Réseau", readonly=False)
    x_indem_finance = fields.Float(string="Indemn.Resp.Financière", readonly=False)
    x_indem_garde = fields.Float(string="Indemn.Garde", readonly=False)
    x_indem_risque = fields.Float(string="Indemn.Risque.Contagion", readonly=False)
    x_indem_suj = fields.Float(string="Indemn.Sujétion Géographique", readonly=False)
    x_indem_form = fields.Float(string="Indemn.Formation", readonly=False)
    x_indem_caisse = fields.Float(string="Indemn.Caisse", readonly=False)
    x_indem_veste = fields.Float(string="Indemn.Vestimentaire", readonly=False)
    x_indem_spec_inspect_trav = fields.Float(string="Indemn.Spécifique Inspecteur de Travail", readonly=False)
    x_indem_spec_inspect_ifc = fields.Float(string="Indemn.Spécifique Forfaitaire Compensatrice", readonly=False)
    x_indem_spec_inspect_irp = fields.Float(string="Indemn.Spécifique de Responsabilité Pécunière", readonly=False)
    x_indem_spec_inspect_ish = fields.Float(string="Indemn.Spécifique Harmonisée Personnel MENA et MESRSI",
                                            readonly=False)
    x_indem_prime_rendement = fields.Float(string="Prime rendement", readonly=False)
    x_indemnite_residence = fields.Float(string='Indemnité de residence', compute="cal_x_indemnite_residence")
    x_allocation_familial = fields.Float(store=True, string='Allocation Familiale', compute='mnt_alloc')

    # exoneration
    x_indem_resp_exo = fields.Float(store=True, string="Exo.Resp", readonly=True,
                                    compute='calcul_exoneration_responsabilite')
    x_indem_astr_exo = fields.Float(store=True, string="Exo.Astreinte", readonly=True,
                                    compute='calcul_exoneration_astreintes')
    x_indem_techn_exo = fields.Float(store=True, string="Exo.Technicité", readonly=True,
                                     compute='calcul_exoneration_technicites')
    x_indem_specif_exo = fields.Float(store=True, string="Exo.Spécifique GRH", readonly=True,
                                      compute='calcul_exoneration_specifiques')
    x_indem_specif_it_exo = fields.Float(store=True, string="Exo.Spécifique IT", readonly=True,
                                         compute='calcul_exoneration_specifiques_it')
    x_indem_specif_irp_exo = fields.Float(store=True, string="Exo.Spécifique IRP", readonly=True,
                                          compute='calcul_exoneration_specifiques_irp')
    x_indem_specif_ifc_exo = fields.Float(store=True, string="Exo.Spécifique IFC", readonly=True,
                                          compute='calcul_exoneration_specifiques_ifc')
    x_indem_specif_ish_exo = fields.Float(store=True, string="Exo.Spécifique ISH", readonly=True,
                                          compute='calcul_exoneration_specifiques_ish')
    x_total_exo = fields.Float(store=True, string="Exo.Total", readonly=True, compute='calcul_exoneration_total')
    x_indem_loge_exo = fields.Float(store=True, string="Exo.Logement", readonly=True,
                                    compute='calcul_exoneration_logement')
    x_indem_transp_exo = fields.Float(store=True, string="Exo.Transport", readonly=True,
                                      compute='calcul_exoneration_transport')
    x_indem_inform_exo = fields.Float(store=True, string="Exo.Informatique", readonly=True,
                                      compute='calcul_exoneration_informatique')
    x_indem_exploit_exo = fields.Float(store=True, string="Exo.Exploitation-Réseau", readonly=True,
                                       compute='calcul_exoneration_exploitation')
    x_indem_finance_exo = fields.Float(store=True, string="Exo.Resp.Financière", readonly=True,
                                       compute='calcul_exoneration_resp_finance')
    x_indem_garde_exo = fields.Float(store=True, string="Exo.Garde", readonly=True, compute='calcul_exoneration_garde')
    x_indem_risque_exo = fields.Float(store=True, string="Exo.Risque.Contagion", readonly=True,
                                      compute='calcul_exoneration_risque')
    x_indem_suj_exo = fields.Float(store=True, string="Exo.Sujétion Géographique", readonly=True,
                                   compute='calcul_exoneration_sujetion')
    x_indem_form_exo = fields.Float(store=True, string="Exo.Formation", readonly=True,
                                    compute='calcul_exoneration_formation')
    x_indem_caisse_exo = fields.Float(store=True, string="Exo.Caisse", readonly=True,
                                      compute='calcul_exoneration_caisse')
    x_indem_veste_exo = fields.Float(store=True, string="Exo.Vestimentaire", readonly=True,
                                     compute='calcul_exoneration_veste')
    x_indem_residence_exo = fields.Float(store=True, string="Exo.Résidence", readonly=True,
                                         compute='calcul_exoneration_residence')
    x_prime_exo = fields.Float(store=True, string="Exo.Prime Rendement", readonly=True,
                               compute='calcul_exoneration_prime')

    # Information Salariale
    x_salaire_base = fields.Float(string="Salaire de base", required=True, compute='cal_sal_base_c_f')
    x_total_indemnites = fields.Float(store=True, string="Totale indemnité", readonly=True, compute='cal_total_indem')
    x_remuneration_total = fields.Float("Rémunération totale", readonly=True, store=True,
                                        compute='calcul_remuneration_total')
    x_salaire_brut = fields.Float(store=True, string="Salaire Brut", readonly=True, compute='calcul_salaire_brut')
    mnt_total_retenues = fields.Float(string='Totale retenue', store=True, readonly=True, compute='cal_total_retenue')
    x_abattement_forfaitaire = fields.Float(store=True, string="Abattement forfaitaire", readonly=True,
                                            compute='calcul_abattement')  # Abattement
    x_salaire_net_imposable = fields.Float(store=True, string="Base imposable", readonly=True,
                                           compute='calcul_sni')  # SNI

    # cotisation sociale
    x_mnt_carfo = fields.Float(string="Montant CARFO", readonly=False)  # Montant CARFO = 8% du salaire de base
    x_mnt_patronal_carfo = fields.Float(string="Part Patronale CARFO",
                                        readonly=False)  # Montant CARFO Patronal = 15.5% du salaire de base
    x_mnt_cnss = fields.Float(string="Montant CNSS", readonly=False, store=True,
                              compute='mnt_cnss_field')  # Montant CNSS = 5.5% de la remuneration total
    x_mnt_patronal_cnss = fields.Float(string="Part Patronale CNSS", readonly=False,
                                       store=True)  # Montant CNSS Patronal = 16% de la remuneration total
    # Retenue IUTS
    x_retenue_iuts = fields.Float(string="IUTS 0 Charge", readonly=False, store=True, compute='retenue_iuts_field')
    x_iuts_net = fields.Float(string="IUTS avec Charge", readonly=True, compute='net_iuts_fields')
    x_net_payer = fields.Float(string="Net à payer", readonly=False, store=True,
                               compute='net_payer_field')  # Net à payer fonctionnaire

    # Affectation du solde indiciaire et calcul du salaire de base fonctionnaire
    @api.depends('x_echellon_id', 'x_classees_id', 'x_echelle_id', 'x_categorie_id')
    def cal_sal_base(self):
        for rec in self:
            val_class = int(rec.x_classees_id)
            val_echel = int(rec.x_echelle_id)
            val_echellon = int(rec.x_echellon_id)
            val_cat = int(rec.x_categorie_id)
            if val_class != False and val_echel != False and val_echellon != False and val_cat != False:
                res = self.env['hr_grillesalariale'].search(
                    [('x_echellon_id', '=', val_echellon), ('x_class_id', '=', val_class),
                     ('x_categorie_id', '=', val_cat),
                     ('x_echelle_id', '=', val_echel)])
                rec.x_solde_indiciaire = round(res.x_salbase)  # x_salbase=solde indiciaire
                x_indemnite_residence = round((res.x_salbase * 10 / 100) + 0.1)  # 0.1:permet de mieux arrondir
                rec.x_solde_indiciaire_net = rec.x_solde_indiciaire + x_indemnite_residence  # solde indiciaire_net= salaire de base
                rec.x_indice = round(res.x_indice)
            else:
                rec.x_solde_indiciaire = 0
                rec.x_indemnite_residence = 0
                rec.x_solde_indiciaire_net = 0
                rec.x_indice = 0

    # def write(self, vals):
    #     struct_id = self.struct_id
    #     vals['struct_id'] = None
    #     super(HrEmployee, self).write(vals)
    #     print(self.struct_id)
    #     vals['struct_id'] = struct_id
    #     return super(HrEmployee, self).write(vals)

    @api.depends('x_solde_indiciaire', 'struct_id')
    def cal_x_indemnite_residence(self):
        for rec in self:
            if rec.struct_id.code == 'FCT_MD':
                rec.x_indemnite_residence = round((rec.x_solde_indiciaire * 10 / 100) + 0.1)
            else:
                rec.x_indemnite_residence = 0

    # fonction de recherche permettant de retourner le salaire de base dans la grille des contractuels en fonction
    # des paramètres
    @api.onchange('x_echellon_c_id', 'x_echelle_c_id', 'x_categorie_c_id')
    def cal_sal_basec(self):
        for rec in self:
            val_echel_c = int(rec.x_echelle_c_id)
            val_echellon_c = int(rec.x_echellon_c_id)
            val_struct = int(rec.company_id.id)
            val_cat_c = int(rec.x_categorie_c_id)
            if val_echel_c != False and val_echellon_c != False and val_cat_c != False and val_struct != False:
                res = self.env['hr_grillesalariale_contractuel'].search(
                    [('x_echellon_c_id', '=', val_echellon_c), ('x_categorie_c_id', '=', val_cat_c),
                     ('x_echelle_c_id', '=', val_echel_c), ('company_id', '=', val_struct)])
                rec.x_solde_indiciaire_ctrct = round(res.x_salbase_ctrt)
            else:
                rec.x_solde_indiciaire_ctrct = 0

    # Affectation
    @api.depends('x_solde_indiciaire', 'x_solde_indiciaire_ctrct', 'struct_id')
    def cal_sal_base_c_f(self):
        for rec in self:
            rec.x_salaire_base = 0
            if rec.struct_id.code == 'FCT_MD':
                rec.x_salaire_base = rec.x_solde_indiciaire_net
            if rec.struct_id.code in ('CTRCT', 'FCT_DETACH'):
                rec.x_salaire_base = rec.x_solde_indiciaire_ctrct

                # fonction qui permet d'additionner les indemnités

    @api.depends('x_indem_resp', 'x_indem_astr', 'x_indem_techn', 'x_indem_specif', 'x_indem_spec_inspect_trav',
                 'x_indem_spec_inspect_irp', 'x_indem_spec_inspect_ish', 'x_indem_spec_inspect_ifc', 'x_indem_loge',
                 'x_indem_transp', 'x_indem_inform', 'x_indem_exploit', 'x_indem_finance', 'x_indem_garde',
                 'x_indem_risque', 'x_indem_suj', 'x_indem_form', 'x_indem_caisse', 'x_solde_indiciaire',
                 'x_indem_prime_rendement')
    def cal_total_indem(self):
        for val in self:
            val.x_total_indemnites = round(
                val.x_indem_resp + val.x_indem_astr + val.x_indem_techn + val.x_indem_specif
                + val.x_indem_spec_inspect_trav + val.x_indem_spec_inspect_irp + val.x_indem_spec_inspect_ish
                + val.x_indem_spec_inspect_ifc + val.x_indem_loge + val.x_indem_transp + val.x_indem_inform
                + val.x_indem_exploit + val.x_indem_finance + val.x_indem_garde + val.x_indem_risque
                + val.x_indem_suj + val.x_indem_form + val.x_indem_caisse + val.x_indem_prime_rendement + val.x_indemnite_residence)

    @api.depends('x_salaire_base', 'x_total_indemnites')
    def calcul_remuneration_total(self):
        for rec in self:
            if rec.struct_id.code == 'FCT_MD':
                rec.x_remuneration_total = (rec.x_solde_indiciaire + rec.x_total_indemnites)
            if rec.struct_id.code in ('CTRCT', 'FCT_DETACH'):
                rec.x_remuneration_total = (rec.x_salaire_base + rec.x_total_indemnites)

    # fonction qui permet d'avoir le montant carfo à partir du salaire de base
    @api.onchange('struct_id', 'x_solde_indiciaire')
    def mnt_carfo_fields(self):
        for rec in self:
            if rec.struct_id.code in ('FCT_MD', 'FCT_DETACH'):
                rec.x_mnt_carfo = round((rec.x_solde_indiciaire * 8) / 100)
                rec.x_mnt_patronal_carfo = round((rec.x_solde_indiciaire * 15.5) / 100)

                rec.x_mnt_cnss = 0.0
                rec.x_mnt_patronal_cnss = 0.0

    # fonction qui permet d'avoir le montant cnss à partir du salaire de base
    @api.depends('struct_id', 'x_remuneration_total')
    def mnt_cnss_field(self):
        for val in self:
            if val.struct_id.code == 'CTRCT':
                resul = round((val.x_remuneration_total * 5.5) / 100)
                if resul > 33000:
                    val.x_mnt_cnss = 33000
                    val.x_mnt_patronal_cnss = 96000
                else:
                    val.x_mnt_cnss = round((val.x_remuneration_total * 5.5) / 100)
                    val.x_mnt_patronal_cnss = round((val.x_remuneration_total * 16) / 100)

                val.x_mnt_carfo = 0.0
                val.x_mnt_patronal_carfo = 0.0

    # fonction qui permet d'avoir le montant cnss à partir du salaire de base
    @api.depends('x_mnt_carfo', 'x_mnt_cnss', 'x_iuts_net')
    def cal_total_retenue(self):
        for rec in self:
            rec.mnt_total_retenues = rec.x_mnt_carfo + rec.x_mnt_cnss + rec.x_iuts_net

    # calcul du salaire brut pour le fonctionnaire puisque Rénumeration Totale déjà connue
    @api.depends('x_remuneration_total', 'x_mnt_carfo', 'x_salaire_base')
    def calcul_salaire_brut(self):
        for vals in self:
            cnss_deductible = 0
            if vals.struct_id.code == 'CTRCT':
                cnss_sb = vals.x_salaire_base * 0.08
                cnss_rt = vals.x_remuneration_total * (5.5 / 100)
                cnss_deductible = min([cnss_sb, cnss_rt, 33000])

            vals.x_salaire_brut = vals.x_remuneration_total - cnss_deductible - vals.x_mnt_carfo

    # calcul abattement forfaitaire
    @api.depends('x_salaire_base', 'x_solde_indiciaire')
    def calcul_abattement(self):
        for vals in self:
            x_cat = vals.x_categorie_c_id.name
            x_cat_f = vals.x_categorie_id.name
            if vals.struct_id.code in ('CTRCT', 'FCT_DETACH'):
                if x_cat == '1' or x_cat == '2' or x_cat == '6':
                    vals.x_abattement_forfaitaire = round((vals.x_salaire_base * 20) / 100)
                else:
                    vals.x_abattement_forfaitaire = round((vals.x_salaire_base * 25) / 100)
            if vals.struct_id.code == 'FCT_MD':
                if x_cat_f == 'A' or x_cat_f == 'B' or x_cat_f == 'P':
                    vals.x_abattement_forfaitaire = round((vals.x_solde_indiciaire * 20) / 100)
                else:
                    vals.x_abattement_forfaitaire = round((vals.x_solde_indiciaire * 25) / 100)

    # calcul DU SALAIRE NET IMPOSABLE (SNI)
    @api.depends('x_salaire_brut', 'x_total_exo', 'x_abattement_forfaitaire')
    def calcul_sni(self):
        for vals in self:
            val1 = vals.x_salaire_brut - vals.x_total_exo - vals.x_abattement_forfaitaire
            val2 = val1 - (val1 % 100)
            vals.x_salaire_net_imposable = val2

    # fonction qui permet d'avoir la de l'iuts
    @api.depends('x_salaire_net_imposable')
    def retenue_iuts_field(self):
        for val in self:
            if 0 <= val.x_salaire_net_imposable <= 30000.0:
                val.x_retenue_iuts = round(val.x_salaire_net_imposable * 0)
            elif 30001.0 <= val.x_salaire_net_imposable <= 50000.0:
                val.x_retenue_iuts = round((val.x_salaire_net_imposable - 30001.0) * 12.1 / 100)
            elif 50001.0 <= val.x_salaire_net_imposable <= 80000.0:
                val.x_retenue_iuts = round(((val.x_salaire_net_imposable - 50001.0) * 13.9 / 100) + 2420)
            elif 80001.0 <= val.x_salaire_net_imposable <= 120000.0:
                val.x_retenue_iuts = round(((val.x_salaire_net_imposable - 80001.0) * 15.7 / 100) + 6590)
            elif 120001.0 <= val.x_salaire_net_imposable <= 170000.0:
                val.x_retenue_iuts = round(((val.x_salaire_net_imposable - 120001.0) * 18.4 / 100) + 12870)
            elif 170001.0 <= val.x_salaire_net_imposable <= 250000.0:
                val.x_retenue_iuts = round(((val.x_salaire_net_imposable - 170001.0) * 21.7 / 100) + 22070)
            else:
                val.x_retenue_iuts = round(((val.x_salaire_net_imposable - 250001.0) * 25 / 100) + 39430)

    # fonction qui permet d'avoir le montant en fonction du nombre de charge pour les deux
    @api.depends('charge', 'x_retenue_iuts')
    def mnt_charge_field(self):
        for val in self:
            if val.charge == 0:
                val.x_montant_charge = round(val.x_retenue_iuts * 0)
            elif val.charge == 1:
                val.x_montant_charge = round((val.x_retenue_iuts * 8) / 100)
            elif val.charge == 2:
                val.x_montant_charge = round((val.x_retenue_iuts * 10) / 100)
            elif val.charge == 3:
                val.x_montant_charge = round((val.x_retenue_iuts * 12) / 100)
            else:
                val.x_montant_charge = round((val.x_retenue_iuts * 14) / 100)

    # fonction qui permet d'avoir le montant net de l'iuts pour le contractuel 031002
    @api.depends('x_retenue_iuts', 'x_montant_charge')
    def net_iuts_fields(self):
        for val in self:
            val.x_iuts_net = round(val.x_retenue_iuts - val.x_montant_charge)

    # fonction qui permet d'avoir le montant net à payer pour le fonctionnaires
    @api.depends('x_remuneration_total', 'x_allocation_familial', 'mnt_total_retenues', )
    def net_payer_field(self):
        for val in self:
            val.x_net_payer = round(
                val.x_remuneration_total + val.x_allocation_familial - val.mnt_total_retenues)

    # fonction de calcul du montant de l'allocation
    @api.depends('charge', 'struct_id')
    def mnt_alloc(self):
        for vals in self:
            if vals.struct_id.code in ('FCT_MD', 'FCT_DETACH'):
                vals.x_allocation_familial = vals.charge_enfant * 2000
            else:
                vals.x_allocation_familial = 0

    # Calcul exonérations
    @api.depends('x_indem_resp', 'x_salaire_brut')
    def calcul_exoneration_responsabilite(self):
        for vals in self:
            indem_resp = vals.x_indem_resp
            premiere_limite_res = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_resp_exo = min([premiere_limite_res, indem_resp, 50000])

    @api.depends('x_indem_astr', 'x_salaire_brut')
    def calcul_exoneration_astreintes(self):
        for vals in self:
            premiere_limite_astr = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_astr_exo = min([premiere_limite_astr, vals.x_indem_astr, 50000])

    # indemnités de technicités
    @api.depends('x_indem_techn', 'x_salaire_brut')
    def calcul_exoneration_technicites(self):
        for vals in self:
            premiere_limite_tech = round((vals.x_salaire_brut * 5) / 100)
            x_indem_techn = round(vals.x_indem_techn)
            vals.x_indem_techn_exo = min([premiere_limite_tech, x_indem_techn, 50000])

    # indemnités de spécifiques GRH
    @api.depends('x_indem_specif', 'x_salaire_brut')
    def calcul_exoneration_specifiques(self):
        for vals in self:
            vals.x_indem_specif_exo = 0
            premiere_limite_spec = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_specif_exo = min([premiere_limite_spec, vals.x_indem_specif, 50000])

    # indemnités de spécifiques IT
    @api.depends('x_indem_spec_inspect_trav', 'x_salaire_brut')
    def calcul_exoneration_specifiques_it(self):
        for vals in self:
            premiere_limite_spec_it = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_specif_it_exo = min([premiere_limite_spec_it, vals.x_indem_spec_inspect_trav, 50000])

    # indemnités de spécifiques IRP
    @api.depends('x_indem_spec_inspect_irp', 'x_salaire_brut')
    def calcul_exoneration_specifiques_irp(self):
        for vals in self:
            premiere_limite_spec_irp = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_specif_irp_exo = min([premiere_limite_spec_irp, vals.x_indem_spec_inspect_irp, 50000])

    # indemnités de spécifiques ISH
    @api.depends('x_indem_spec_inspect_ish', 'x_salaire_brut')
    def calcul_exoneration_specifiques_ish(self):
        for vals in self:
            premiere_limite_spec_ish = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_specif_ish_exo = min([premiere_limite_spec_ish, vals.x_indem_spec_inspect_ish, 30000])

    # indemnités de spécifiques IFC
    @api.depends('x_indem_spec_inspect_ifc', 'x_salaire_brut')
    def calcul_exoneration_specifiques_ifc(self):
        for vals in self:
            premiere_limite_ifc = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_specif_ifc_exo = min([premiere_limite_ifc, vals.x_indem_spec_inspect_ifc, 50000])

    # indemnités d'informatiques
    @api.depends('x_indem_inform', 'x_salaire_brut')
    def calcul_exoneration_informatique(self):
        for vals in self:
            premiere_limite_info = round(vals.x_salaire_brut * 0.05)
            vals.x_indem_inform_exo = min([premiere_limite_info, vals.x_indem_inform, 50000])

    # indemnités de exploitations reseaux
    @api.depends('x_indem_exploit', 'x_salaire_brut')
    def calcul_exoneration_exploitation(self):
        for vals in self:
            premiere_limite_exploi = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_exploit_exo = min([premiere_limite_exploi, vals.x_indem_exploit, 50000])

    # indemnités de responsabilités financières
    @api.depends('x_indem_finance', 'x_salaire_brut')
    def calcul_exoneration_resp_finance(self):
        for vals in self:
            premiere_limite_finance = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_finance_exo = min([premiere_limite_finance, vals.x_indem_finance, 50000])

    # indemnités de garde
    @api.depends('x_indem_garde', 'x_salaire_brut')
    def calcul_exoneration_garde(self):
        for vals in self:
            premiere_limite_garde = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_garde_exo = min([premiere_limite_garde, vals.x_indem_garde, 50000])

    # indemnités de risque
    @api.depends('x_indem_risque', 'x_salaire_brut')
    def calcul_exoneration_risque(self):
        for vals in self:
            premiere_limite_risque = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_risque_exo = min([premiere_limite_risque, vals.x_indem_risque, 50000])

    # indemnités de sujetion
    @api.depends('x_indem_suj', 'x_salaire_brut')
    def calcul_exoneration_sujetion(self):
        for vals in self:
            premiere_limite_suj = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_suj_exo = min([premiere_limite_suj, vals.x_indem_suj, 50000])

    # indemnités de formation
    @api.depends('x_indem_form', 'x_salaire_brut')
    def calcul_exoneration_formation(self):
        for vals in self:
            premiere_limite_form = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_form_exo = min([premiere_limite_form, vals.x_indem_form, 50000])

    # indemnités de caisse
    @api.depends('x_indem_caisse', 'x_salaire_brut')
    def calcul_exoneration_caisse(self):
        for vals in self:
            premiere_limite_caisse = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_caisse_exo = min([premiere_limite_caisse, vals.x_indem_caisse, 50000])

    # indemnités de veste
    @api.depends('x_indem_veste', 'x_salaire_brut')
    def calcul_exoneration_veste(self):
        for vals in self:
            premiere_limite_veste = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_veste_exo = min([premiere_limite_veste, vals.x_indem_veste, 50000])

    # indemnités de residence
    @api.depends('x_solde_indiciaire', 'x_salaire_brut')
    def calcul_exoneration_residence(self):
        for vals in self:
            if vals.struct_id.code == 'FCT_MD':
                premiere_limite = round((vals.x_salaire_brut * 5) / 100)
                vals.x_indem_residence_exo = min([premiere_limite, vals.x_solde_indiciaire, 50000])
            else:
                vals.x_indem_residence_exo = 0

    # exoneration prime de rendement
    @api.depends('x_indem_prime_rendement', 'x_salaire_brut')
    def calcul_exoneration_prime(self):
        for vals in self:
            premiere_limite = round((vals.x_salaire_brut * 5) / 100)
            vals.x_prime_exo = min([premiere_limite, vals.x_indem_prime_rendement, 50000])

    @api.depends('x_indem_loge', 'x_salaire_brut')
    def calcul_exoneration_logement(self):
        for vals in self:
            premiere_limite_log = round((vals.x_salaire_brut * 20) / 100)
            vals.x_indem_loge_exo = min([premiere_limite_log, vals.x_indem_loge, 75000])

    @api.depends('x_indem_transp', 'x_salaire_brut')
    def calcul_exoneration_transport(self):
        for vals in self:
            premiere_limite_trans = round((vals.x_salaire_brut * 5) / 100)
            vals.x_indem_transp_exo = min([premiere_limite_trans, vals.x_indem_transp, 30000])

    @api.depends('x_indem_resp_exo', 'x_indem_astr_exo', 'x_indem_techn_exo', 'x_indem_specif_exo',
                 'x_indem_specif_it_exo', 'x_indem_specif_ifc_exo', 'x_indem_specif_irp_exo',
                 'x_indem_specif_ish_exo', 'x_indem_loge_exo', 'x_indem_transp_exo', 'x_indem_inform_exo',
                 'x_indem_exploit_exo', 'x_indem_finance_exo', 'x_indem_garde_exo', 'x_indem_risque_exo',
                 'x_indem_suj_exo', 'x_indem_form_exo', 'x_indem_caisse_exo', 'x_indem_veste_exo', 'x_prime_exo',
                 'x_indem_residence_exo')
    def calcul_exoneration_total(self):
        for vals in self:
            vals.x_total_exo = vals.x_indem_resp_exo + vals.x_indem_astr_exo + vals.x_indem_techn_exo + vals.x_indem_specif_exo + vals.x_indem_loge_exo + vals.x_indem_transp_exo + vals.x_indem_inform_exo + vals.x_indem_exploit_exo + vals.x_indem_finance_exo + vals.x_indem_garde_exo + vals.x_indem_risque_exo + vals.x_indem_suj_exo + vals.x_indem_form_exo + vals.x_indem_caisse_exo + vals.x_indem_veste_exo + vals.x_indem_specif_it_exo + vals.x_indem_specif_ifc_exo + vals.x_indem_specif_irp_exo + vals.x_indem_specif_ish_exo + vals.x_prime_exo + vals.x_indem_residence_exo

    @api.depends('charge_femme', 'charge_enfant')
    def calcul_charge(self):
        self.charge = self.charge_femme + self.charge_enfant

    enfants_ids = fields.One2many('hr_employee_enfant', 'employee_id', string="Enfant", index=True)
    x_acte_ids = fields.One2many('hr_piece_detachement', 'x_employees_id', string='Joindre acte Detachement')
    x_acte_dec_ids = fields.One2many('hr_piece_disposition', 'x_employees_id', string='Joindre acte Decision')
    x_actes_ids = fields.One2many('hr_decret_nomination', 'x_employees_id', string='Joindre acte de nomination')
    x_dossier_ind_ids = fields.One2many('hr_dossier_individuel', 'x_employees_id', string='Joindre Fichiers')
    x_note_ids = fields.One2many(
        comodel_name='hr_employee_note',
        inverse_name='employee_id',
        string='Notes',
        required=False)

    # FONCTION DE calcul de la date de depart a la retraite d'un employe
    @api.depends("x_date_naissance", "x_nb_annee_retraite")
    def _compute_date_retraite(self):
        for rec in self:
            rec.x_date_retraite = None
            if rec.x_nb_annee_retraite or rec.x_date_naissance:
                anne = int(rec.x_nb_annee_retraite.name)
                date1 = rec.x_date_naissance.strftime("%Y-%m-%d")
                date2 = rec.x_date_naissance.year + anne
                rec.x_date_retraite = datetime(date2, rec.x_date_naissance.month, rec.x_date_naissance.day, 0, 0, 0,
                                               0).date()

    @api.depends('enfants_ids')
    def calcul_charge_enfant(self):
        for val in self:
            charge_enfant = 0
            for e in val.enfants_ids:
                if e.etat == "1" and e.age <= 15:
                    charge_enfant = charge_enfant + 1
                elif e.etat == "2" and e.age <= 17:
                    charge_enfant = charge_enfant + 1
                elif e.etat == "3" and e.age <= 20:
                    charge_enfant = charge_enfant + 1
                elif e.etat == "4":
                    charge_enfant = charge_enfant + 1

            val.charge_enfant = charge_enfant

class HrEmployeesEnfant(models.Model):
    _name = "hr_employee_enfant"

    name = fields.Char(string="Nom et Prénoms", required=True)
    date_naissance = fields.Date(string='Date naissance', required=True, default=date.today())
    age = fields.Integer(string="Age", compute="calcul_age")

    est_pris = fields.Boolean(string='Est_pris', required=False, compute="cal_est_pris")

    etat = fields.Selection([
        ('1', 'Ordinaire'),
        ('2', 'Apprentissage'),
        ('3', 'Etude'),
        ('4', 'Besoin Spécifique'),
    ], 'Status', default='1', required=True)

    sexe = fields.Selection([
        ('M', 'Masculin'),
        ('F', 'Feminin'),
    ], 'Sexe', default='M', index=True, required=True)

    employee_id = fields.Many2one('hr.employee', string='Employé', required=True)

    @api.depends('date_naissance')
    def calcul_age(self):
        for val in self:
            val.age = 0
            if val.date_naissance:
                start_date = date.today()
                end_date = val.date_naissance
                val.age = (start_date - end_date).days / 365

    @api.depends('etat', 'age')
    def cal_est_pris(self):
        for val in self:
            if val.etat == "1" and val.age <= 15:
                val.est_pris = True
            elif val.etat == "2" and val.age <= 17:
                val.est_pris = True
            elif val.etat == "3" and val.age <= 20:
                val.est_pris = True
            elif val.etat == "4":
                val.est_pris = True
            else:
                val.est_pris = False

# Creation de la classe hr_employee_ fichier_oint_line permettant d'ajouter un  acte de detachement
class HrEmployeePieceDetachement(models.Model):
    _name = "hr_piece_detachement"
    x_employees_id = fields.Many2one('hr.employee', string='Employee')
    date_acte = fields.Date(string="Date acte")
    date_effet = fields.Date(string="Date effet")
    date_fin = fields.Date(string="Date fin")
    ref_acte = fields.Char(string="Ref acte")
    fichier_joint = fields.Binary(string='Joindre acte', attachment=True)

# Creation de la classe hr_employee_ decret_nomination permettant d'ajouter un  acte de nomination
class HrEmployeeDecretNomination(models.Model):
    _name = "hr_decret_nomination"
    x_employees_id = fields.Many2one('hr.employee', string='Employee')
    date_nomination = fields.Date(string="Date nomination")
    date_effet = fields.Date(string="Date effet")
    date_fin = fields.Date(string="Date fin")
    ref_acte = fields.Char(string="Ref acte nomination")
    fichier_joint = fields.Binary(string='Joindre acte', attachment=True)
    etat_nomination = fields.Selection([
        ('1', "En cours"),
        ('2', "Terminé"),
    ], required=True, string="Etat Nomination", default=1)

# Creation de la classe hr_employee_ fichier_oint_line permettant d'ajouter un  acte de decision
class HrEmployeePieceDecision(models.Model):
    _name = "hr_piece_disposition"
    x_employees_id = fields.Many2one('hr.employee', string='Employee')
    date_acte_dec = fields.Date(string="Date acte disposition")
    date_effet_dec = fields.Date(string="Date effet disposition")
    date_fin_dec = fields.Date(string="Date fin disposition")
    ref_acte_dec = fields.Char(string="Ref acte disposition")
    fichier_joint_dec = fields.Binary(string='Joindre acte disposition', attachment=True)

# Creation de la classe hr_employee_ fichier_joint_line permettant de suivre le dossier individuel du personnel
class HrEmployeeDossierIndividuel(models.Model):
    _name = "hr_dossier_individuel"
    x_employees_id = fields.Many2one('hr.employee', string='Employee')
    date_op = fields.Date(string="Date", default=date.today())
    objet_ligne = fields.Char(string="Intitulé")
    fichier_joint = fields.Binary(string='Joindre Fichier', attachment=True)

class HrEmployeeNote(models.Model):
    _name = "hr_employee_note"

    note = fields.Integer(string='Note', required=False)
    employee_id = fields.Many2one(
        comodel_name='hr.employee',
        string='Employee',
        required=False)

    @api.model
    def annee_selection(self):
        year = 2000  # replace 2000 with your a start year
        year_list = []
        while year != 2100:  # replace 2030 with your end year
            year_list.append((str(year), str(year)))
            year += 1
        return year_list

    def _default_annee(self):
        print(fields.Date.context_today(self).year)
        return str(fields.Date.context_today(self).year)

    annee = fields.Selection(
        annee_selection,
        string="Année",
        default=_default_annee)


#Flask-Mail

from flask import Flask
from flask_mail import Mail, Message

app = Flask(__name__)

def send(subject, msg, from_email, to_email):
    mail = Mail(app)
    msg = Message(subject, [to_email], body, sender=from_email)
    mail.send(msg) # Sensitive{code}


from django.urls import path
from .views import RegisterView, LoginView, logout_view

app_name = 'accounts'
urlpatterns = [
    path('register/', RegisterView.as_view(), name='register'),
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', logout_view, name='logout'),

]


'''
Created on 30-Jul-2016

@author: vijay
'''

import logging
import sys, time, math, os, os.path

import wx
import wx.richtext
from src.view.views.calibre.book.browser.SearchBook import FindingBook
from src.view.views.calibre.book.browser.BookDescriptionPanel import RichTextPanel
import re

logger = logging.getLogger('extensive')

class PropertyPhotoPanel(wx.Panel):

    def __init__(self, parent=None, book=None):
        wx.Panel.__init__(self, parent, id=-1)
        self.Bind(wx.EVT_SIZE, self.OnSize, self)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        self.parent = parent
        self.bitmap = None
        self.currentBook = book

    def OnContextMenu(self, event):
        logger.debug("OnContextMenu\n")

        # only do this part the first time so the events are only bound once
        #
        # Yet another anternate way to do IDs. Some prefer them up top to
        # avoid clutter, some prefer them close to the object of interest
        # for clarity.
        if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewId()
            self.popupID2 = wx.NewId()
            self.popupID3 = wx.NewId()
            self.popupID4 = wx.NewId()
        # make a menu
        menu = wx.Menu()
        # Show how to put an icon in the menu
        item = wx.MenuItem(menu, self.popupID1, "Copy book cover")
#         bmp = images.Smiles.GetBitmap()
#         item.SetBitmap(bmp)
        menu.AppendItem(item)
        # add some other items
        menu.Append(self.popupID2, "Download book cover")
        menu.Append(self.popupID3, "Generate book cover")
        menu.Append(self.popupID4, "Open book")

        self.Bind(wx.EVT_MENU, self.OnCopyToClipboard, id=self.popupID1)
        self.Bind(wx.EVT_MENU, self.downloadCover, id=self.popupID2)
        self.Bind(wx.EVT_MENU, self.generateCover, id=self.popupID3)
        self.Bind(wx.EVT_MENU, self.openBook, id=self.popupID4)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(menu)
        menu.Destroy()

    def downloadCover(self, event):
        logger.debug('downloadCover')

    def generateCover(self, event):
        logger.debug('generateCover')

    def openBook(self, event):
        logger.debug('openBook')

    def OnCopyToClipboard(self, event):
        logger.debug('OnCopyToClipboard')

        d = wx.BitmapDataObject(self.bitmap)
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(d)
            wx.TheClipboard.Flush()
            wx.TheClipboard.Close()
            logger.debug("Image copied to cliboard.\n")
        else:
            logger.debug("Couldn't open clipboard!\n")

    def OnSize(self, event):
        self.changeBitmapWorker()
        logger.debug('onsize')

    def OnPaint(self, evt):
        if self.bitmap != None:
            dc = wx.BufferedPaintDC(self)
            dc.Clear()
            dc.DrawBitmap(self.bitmap, 0, 0)
        else:
            pass

    def getImageFilePath(self):
        imgFilePath = os.path.join(self.currentBook.bookPath, self.currentBook.bookImgName)
        if not os.path.exists(imgFilePath):
            directory = '.'
            pattern = re.compile(r"\-(\d*)\.jpg$")
            for file in os.listdir(directory):
                print(file)
                m = pattern.search(file)
                if m:
#                     print(m.groups())
                    imgFilePath = m.group()
                    bookImgName = self.currentBook.bookImgName.replace('.jpg', m.group())
                    imgFilePath = os.path.join(self.currentBook.bookPath, bookImgName)
        return imgFilePath

    def changeBitmapWorker(self):
#         relevant_path = "/docs/LiClipse Workspace/img/wallpaper"
#         imgFileName=self.getImgFileName(relevant_path)
#         imgFilePath=os.path.join(relevant_path,imgFileName[0] )
        imgFilePath = self.getImageFilePath()

#         img2 =  imgFilePath=os.path.join(relevant_path,imgFileName[1] )
        logger.debug(f'PropertyPhotoPanel GetSize {self.GetSize()}')
        NewW, NewH = self.GetSize()
        if  NewW > 0 and NewH > 0:
            img = wx.Image(imgFilePath, wx.BITMAP_TYPE_ANY)
            img = img.Scale(NewW, NewH)
            self.bitmap = wx.Bitmap(img)
            self.Refresh()

class BookPropertyPanel(wx.Panel):

    def __init__(self, parent, book):
        wx.Panel.__init__(self, parent)

#         self.panel = wx.Panel(self, wx.ID_ANY)
        self.currentBook = book

        self.photoPanel = PropertyPhotoPanel(self, book=self.currentBook)
#         self.rt = wx.richtext.RichTextCtrl(self, style=wx.VSCROLL | wx.HSCROLL | wx.NO_BORDER)
        self.rt = RichTextPanel(self, self.currentBook)
#         img1 = wx.Image(os.path.join(self.currentBook.bookPath, self.currentBook.bookImgName), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
#         img=wx.Bitmap(os.path.join(book.bookPath, book.bookImgName))
        logger.debug('BookPropertyPanel size: %s', self.GetParent().GetSize())
        img1 = self.scale_bitmap()
        img = wx.Image(240, 240)
#         self.imageCtrl = wx.StaticBitmap(self.photoPanel, wx.ID_ANY, wx.BitmapFromImage(img))
#         self.imageCtrl = wx.StaticBitmap(self.photoPanel, wx.ID_ANY, img1, name="anotherEmptyImage")
#         self.imageCtrl.Bind(wx.EVT_LEFT_DOWN, self.onImageClick)

        topsizer = wx.BoxSizer(wx.VERTICAL)
        hBox = wx.BoxSizer(wx.HORIZONTAL)
#         self.pg = self.createPropetyGrid(self.currentBook)

        vBox = wx.BoxSizer(wx.VERTICAL)
#         vBox.Add(self.pg, 1, wx.EXPAND, 2)
        vBox.Add(self.rt, 1, wx.EXPAND, 1)
        hBox.Add(self.photoPanel, 2, wx.EXPAND, 5)
        hBox.Add(vBox, 3, wx.EXPAND, 5)

#         topsizer.Add(hBox, 3, wx.EXPAND)
#         rowsizer = wx.BoxSizer(wx.HORIZONTAL)

#         next = wx.Button(self.panel, -1, "Next")
#         previous = wx.Button(self.panel, -1, "Previous")
#         cancel = wx.Button(self.panel, -1, "Cancel")
#         ok = wx.Button(self.panel, -1, "Ok")
#         downloadMetadata = wx.Button(self.panel, -1, "Download metadata")
#         downloadCover = wx.Button(self.panel, -1, "Download cover")
#         generateCover = wx.Button(self.panel, -1, "Generate cover")

#         next.Bind(wx.EVT_BUTTON, self.onNext)
#         previous.Bind(wx.EVT_BUTTON, self.onPrevious)
#         ok.Bind(wx.EVT_BUTTON, self.onOk)
#         cancel.Bind(wx.EVT_BUTTON, self.onCancel)
#         downloadMetadata.Bind(wx.EVT_BUTTON, self.onDownloadMetadata)
#         downloadCover.Bind(wx.EVT_BUTTON, self.onDownloadCover)
#         generateCover.Bind(wx.EVT_BUTTON, self.onGenerateCover)

#         rowsizer.Add(previous, 1)
#         rowsizer.Add(next, 1)
#         rowsizer.Add(cancel, 1)
#         rowsizer.Add(ok, 1)
#         rowsizer.Add(downloadMetadata, 1)
#         rowsizer.Add(downloadCover, 1)
#         rowsizer.Add(generateCover, 1)
#         topsizer.Add(rowsizer, 0, wx.EXPAND)

#         self.panel.SetSizer(topsizer)
#         topsizer.SetSizeHints(self.panel)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(hBox, 1, wx.EXPAND)
        self.sizer.Fit(self)
        self.SetSizer(self.sizer)
#         self.SetAutoLayout(True)
    def getImageFilePath(self):
        os.chdir(self.currentBook.bookPath)
        imgFilePath = os.path.join(self.currentBook.bookPath, self.currentBook.bookImgName)
        if not os.path.exists(imgFilePath):
            directory = '.'
            pattern = re.compile(r"\-(\d*)\.jpg$")
            for file in os.listdir(directory):
                print(file)
                m = pattern.search(file)
                if m:
#                     print(m.groups())
                    imgFilePath = m.group()
                    bookImgName = self.currentBook.bookImgName.replace('.jpg', m.group())
                    imgFilePath = os.path.join(self.currentBook.bookPath, bookImgName)
        return imgFilePath
    #----------------------------------------------------------------------

    def scale_bitmap(self, width=None, height=None):
        bitmap = wx.Image(self.getImageFilePath(), wx.BITMAP_TYPE_JPEG).ConvertToBitmap()
        image = bitmap.ConvertToImage()
        if width and height:
            image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
        result = wx.Bitmap(image)
        return result

class BookPropertyFrame(wx.Frame):

    def __init__(self, parent, book):
        wx.Frame.__init__(self, parent, -1, title='Edit Book Metadata', size=(1100, 650))
        self.panel = BookPropertyPanel(self, book)
        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
#         self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Show()

    # Makes sure the user was intending to quit the application
    def OnCloseFrame(self, event):
        self.OnExitApp(event)

    # Destroys the main frame which quits the wxPython application
    def OnExitApp(self, event):
        self.Destroy()

if __name__ == '__main__':
    books = FindingBook(libraryPath=r'C:\new\library').findAllBooks()
    book = None
    for b in books:
        book = b
        break
#     print book
    app = wx.App(0)
    frame = BookPropertyFrame(None, book)
    app.MainLoop()


#! /usr/bin/env python
# -*- coding:UTF-8 -*-

import unittest
from public.HTMLTestReportCN import HTMLTestRunner
import time

test_case_dir = '\\testcases'

def create_suite():
    test_suits = unittest.TestSuite()

    discover = unittest.defaultTestLoader.discover(
        test_case_dir,
        pattern='test*',
        top_level_dir=None
    )

    for test_suit in discover:
        for test_case in test_suit:
            test_suits.addTest(test_case)
            print(test_suits)

    return test_suits

all_test_cases = create_suite()

now = time.strftime('%Y-%m_%d-%H_%M_%S', time.localtime())

file_name = '\\report\\' + now + 'result.html'

with open(file_name, 'wb') as fp:
    runner = HTMLTestRunner(
        stream=fp,
        title=u'web自动化测试报告',
        description=u'用例具体执行情况如下：'
    )

runner.run(all_test_cases)


import pandas as pd
import numpy as np
import string
import re
from nltk.stem.snowball import SnowballStemmer
from nltk.corpus import stopwords
import nltk
import gensim
from gensim.models import CoherenceModel
from gensim import corpora
import tqdm
import pyLDAvis.gensim_models
import pickle
import pyLDAvis
import pyLDAvis.sklearn
import tqdm
from gensim.matutils import hellinger,kullback_leibler,jensen_shannon
from scipy.spatial.distance import jensenshannon

def compute_coherence_values(corpus, dictionary, k, a, b):
    lda_model = gensim.models.LdaModel(corpus=corpus,
                                           id2word=dictionary,
                                           num_topics=k,
                                           random_state=100,
                                           chunksize=100,
                                           passes=10,
                                           alpha=a,
                                           eta=b)

    coherence_model_lda = CoherenceModel(model=lda_model, texts=final_data['paper'], dictionary=dictionary, coherence='c_v')

    return coherence_model_lda.get_coherence()

def parse_topic_string(topic):
    # takes the string returned by model.show_topics()
    # split on strings to get topics and the probabilities
    topic = topic.split('+')
    # list to store topic bows
    topic_bow = []
    for word in topic:
        # split probability and word
        prob, word = word.split('*')
        # get rid of spaces and quote marks
        word = word.replace(" ", "").replace('"', '')
        # convert to word_type
        word = lda_model.id2word.doc2bow([word])[0][0]
        topic_bow.append((word, float(prob)))
    return topic_bow

if __name__ == '__main__':

    list_of_terms = ['imprint','molecular','polym','mip','abstract','analysi','appli','develop','effect','function',
                     'g','good','high','linear','method','mmip','model','modifi','molecul','phase','rang','relat',
                     'respect','result','sampl','show','standard','studi','use','howev','system','differ','author',
                     'present','approach']
    data = pd.read_excel('Dataset4LDA.xlsx')
    exclude = set(string.punctuation)
    exclude.remove('-')
    joined_rows = []
    stemmer = SnowballStemmer("english")
    stopwords = stopwords.words('english')
    stopwords.append('the')
    stopwords.append('a')
    joined_questions = pd.DataFrame(columns=['paper'])
    final_patents = pd.DataFrame(columns=['paper'])
    final_data = pd.DataFrame(columns=['paper'])
    for index,row in data.iterrows():
        join = row['TI'] + '.' + row['AB']

        joined_questions = joined_questions.append({'paper':join},ignore_index=True)
    #

    joined_questions = joined_questions.apply(lambda x: x.astype(str).str.lower())
    joined_questions['cleaned'] = joined_questions['paper'].apply(lambda x:''.join([i for i in x if i not in exclude]))
    joined_questions['tokenized'] = joined_questions.apply(lambda row: nltk.word_tokenize(row['cleaned']), axis=1)
    joined_questions['no_stop'] = joined_questions['tokenized'].apply(lambda x: [item for item in x if item not in stopwords])
    joined_questions['stemmed'] = joined_questions['no_stop'].apply(lambda x: [stemmer.stem(y) for y in x])

    for index, row in joined_questions.iterrows():
        final_terms = []
        for term in row['stemmed']:
            if term not in list_of_terms:
                final_terms.append(term)
        if not final_terms:
            final_patents = final_patents.append({'paper': ['empty', 'paper']}, ignore_index=True)
        else:
            final_patents = final_patents.append({'paper': final_terms}, ignore_index=True)

    for index, row in final_patents.iterrows():
        final_terms = []
        for term in row['paper']:
            if not term.isnumeric():
                final_terms.append(term)
        if not final_terms:
            final_data = final_data.append({'paper': ['empty', 'paper']}, ignore_index=True)
        else:
            final_data = final_data.append({'paper': final_terms}, ignore_index=True)
    final_data.to_excel('trial.xlsx')
    dictionary = corpora.Dictionary(final_data['paper'])
    bow_corpus = [dictionary.doc2bow(row) for row in final_data['paper']]
    lda_model = gensim.models.LdaModel(corpus=bow_corpus,
                                       id2word=dictionary,
                                       num_topics=7,
                                       random_state=100,
                                       chunksize=100,
                                       passes=10,
                                       alpha=0.61,
                                       eta=0.61,per_word_topics=True,minimum_probability=0.0)

    coherence_model_lda = CoherenceModel(model=lda_model, texts=final_data['paper'], dictionary=dictionary, coherence='c_v')
    print(coherence_model_lda.get_coherence())
    # lda_visualization = pyLDAvis.gensim_models.prepare(lda_model, bow_corpus, dictionary, mds='mmds',
    #                                                    sort_topics=False)
    # pyLDAvis.save_html(lda_visualization, 'lda_7_topics_molecular_titles_abstracts_removed_terms.html')

    topic_distribution = []
    for i in range (0,len(bow_corpus)):
        get_document_topics = lda_model.get_document_topics(bow_corpus[i])
        topic_distribution.append(get_document_topics)

    share = {}
    dominance = {}
    for distribution in topic_distribution:
        max = -10
        indexx = 50
        for tuplee in distribution:
            if tuplee[1]>0.1:
                if tuplee[0] in share.keys():
                    share[tuplee[0]] +=1
                else:
                    share[tuplee[0]] = 1
            if tuplee[1] > max:
                max = tuplee[1]
                indexx = tuplee[0]
        if indexx in dominance.keys():
            dominance[indexx] +=1
        else:
            dominance[indexx] = 1

    for key in share.keys():
        share[key] = (share[key]/len(bow_corpus))*100
        dominance[key] = (dominance[key]/len(bow_corpus))*100

    share_df = pd.DataFrame(share.items(),columns=['Topic','Share']).to_excel('share_molecular.xlsx')
    dominance_df = pd.DataFrame(dominance.items(),columns=['Topic','Popularity']).to_excel('popularity_molecular.xlsx')

    topic_1, topic_2, topic_3, topic_4, topic_5, topic_6, topic_7, = lda_model.show_topics(num_topics=7, num_words=len(lda_model.id2word))
    topic_1_distribution = parse_topic_string(topic_1[1])
    topic_2_distribution = parse_topic_string(topic_2[1])
    topic_3_distribution = parse_topic_string(topic_3[1])
    topic_4_distribution = parse_topic_string(topic_4[1])
    topic_5_distribution = parse_topic_string(topic_5[1])
    topic_6_distribution = parse_topic_string(topic_6[1])
    topic_7_distribution = parse_topic_string(topic_7[1])

    distributions = [topic_1_distribution, topic_2_distribution, topic_3_distribution, topic_4_distribution,
                     topic_5_distribution,
                     topic_6_distribution, topic_7_distribution]
    new_dist = []
    for distribution in distributions:
        to_add = []
        for element in distribution:
            to_add.append(element[1])
        new_dist.append(to_add)

    index = 1
    distances = {}
    for distribution in new_dist:
        dst_list = []
        for distribution2 in new_dist:
            dst = jensenshannon(distribution, distribution2)
            dst_list.append(dst)
        distances['Topic {}'.format(index)] = dst_list
        index+=1

    distances_df = pd.DataFrame(distances)
    distances_df.to_excel('topic_distances_jensen_shannon_molecular.xlsx')

    all_memberships = {0:[],
                       1:[],
                       2:[],
                       3:[],
                       4:[],
                       5:[],
                       6:[],}
    for distro in topic_distribution:
        for tuplee in distro:
            all_memberships[tuplee[0]].append(tuplee[1])

    b = pd.DataFrame(all_memberships)
    b.to_excel('memberships.xlsx')
    # min_topics = 2
    # max_topics = 11
    # step_size = 1
    # topics_range = range(min_topics, max_topics, step_size)  # Alpha parameter
    # alpha = list(np.arange(0.01, 1, 0.3))
    # alpha.append('symmetric')
    # alpha.append('asymmetric')  # Beta parameter
    # beta = list(np.arange(0.01, 1, 0.3))
    # beta.append('symmetric')  # Validation sets
    # num_of_docs = len(bow_corpus)
    # model_results = {
    #                  'Topics': [],
    #                  'Alpha': [],
    #                  'Beta': [],
    #                  'Coherence': []
    #                  }  # Can take a long time to run
    #
    # pbar = tqdm.tqdm(total=270)
    #     # iterate through number of topics
    # for k in topics_range:
    #     # iterate through alpha values
    #     for a in alpha:
    #         # iterare through beta values
    #         for b in beta:
    #             # get the coherence score for the given parameters
    #             cv = compute_coherence_values(corpus=bow_corpus, dictionary=dictionary,
    #                                           k=k, a=a, b=b)
    #             print(cv)
    #             # Save the model results
    #             model_results['Topics'].append(k)
    #             model_results['Alpha'].append(a)
    #             model_results['Beta'].append(b)
    #             model_results['Coherence'].append(cv)
    #             pbar.update(1)
    # pd.DataFrame(model_results).to_excel('lda_tuning_results_molecular_titles_removed_terms.xlsx', index=False)
    # pbar.close()


import boto3
import pdfplumber
from time import sleep
import requests
import os, sys, subprocess

AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_BUCKET_NAME = 'practisebucketaws'
TOPIC_ARN = 'arn:aws:sns:ap-southeast-1:524255913858:audiobook'
region = 'ap-southeast-1'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
                        '(KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36'}

# Extract text from pdf
with pdfplumber.open('The Girl with the Dragon Tattoo.pdf') as pdf:
    all_pages = pdf.pages
    full_text = ''
    for page in all_pages[:20]:
        single_page_text = page.extract_text(x_tolerance=1)
        full_text = full_text + '\n' + single_page_text

# Create a boto3 session
polly_client = boto3.Session(aws_access_key_id=AWS_ACCESS_KEY_ID,
                             aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                             region_name=region).client('polly')

# Request speech synthesis
response = polly_client.start_speech_synthesis_task(VoiceId='Joanna',
                                                    OutputS3BucketName=AWS_BUCKET_NAME,
                                                    OutputFormat='mp3',
                                                    Text=str(full_text),
                                                    SnsTopicArn=TOPIC_ARN,
                                                    Engine='neural')

# Get mp3 file uri from response
mp3_uri = response['SynthesisTask']['OutputUri']

# Wait for speech to be fully synthesised
retries = 0
max_retries = 29
still_try = True
while retries < max_retries and still_try == True:
    if requests.get(mp3_uri, headers=headers).status_code != 200:
        retries += 1
        print(f'mp3 file not ready..')
        sleep(60)
    else:
        print(f'mp3 file is ready..')
        audiobook = requests.get(mp3_uri, headers=headers)
        with open('audiobook.mp3', 'wb') as file:
            file.write(audiobook.content)
        still_try = False

# Play audiobook
if sys.platform == "win32":
    os.startfile('audiobook.mp3')
else:
    opener = "open" if sys.platform == "darwin" else "xdg-open"
    subprocess.call([opener, 'audiobook.mp3'])


# Find Circles Example
#
# This example shows off how to find circles in the image using the Hough
# Transform. https://en.wikipedia.org/wiki/Circle_Hough_Transform
#
# Note that the find_circles() method will only find circles which are completely
# inside of the image. Circles which go outside of the image/roi are ignored...
#初始化
import sensor, image, time , lcd, math ,array
import gc
from modules import ybkey
KEY = ybkey()
from modules import ybrgb
RGB = ybrgb()
gc.enable()
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE) # grayscale is faster
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(True) # must turn this off to prevent image washout...
clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    i=0;
    mid_point_x=0.0;
    mid_point_y=0.0;
    point_list_x=array.array("I")
    point_list_y=array.array("I")
    # Circle objects have four values: x, y, r (radius), and magnitude. The
    # magnitude is the strength of the detection of the circle. Higher is
    # better...

    # `threshold` controls how many circles are found. Increase its value
    # to decrease the number of circles detected...

    # `x_margin`, `y_margin`, and `r_margin` control the merging of similar
    # circles in the x, y, and r (radius) directions.

    # r_min, r_max, and r_step control what radiuses of circles are tested.
    # Shrinking the number of tested circle radiuses yields a big performance boost.
    for c in img.find_circles(threshold = 2500, x_margin = 10, y_margin = 10, r_margin = 10,
            r_min = 4, r_max = 6, r_step = 1):
        img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))
        mid_point_x=mid_point_x+c.x()
        mid_point_y=mid_point_y+c.y()
        print(c)
        i=i+1;
        point_list_x.append(c.x());
        point_list_y.append(c.y());
    img.draw_string(0, 0, "%i" %(i), color=(255, 255, 255), scale=2.0)
    if i==8:
        mid_point_x=mid_point_x/8.0
        mid_point_y=mid_point_y/8.0
        img.draw_circle(int(mid_point_x), int(mid_point_y), 6, color = (255, 255, 255))
        print(mid_point_x)
        print(mid_point_y)
        RGB.set(0,255,0)
    else:
        RGB.set(0,0,0)
    lcd.display(img)
    print("FPS %f" % clock.fps())
    print(i)
    if KEY.is_press() and i==8:
        RGB.set(0,0,0)
        break
#垃圾回收
gc.collect()
import  math
primary=[[217,62],[56,64],[171,86],[80,110],[240,131],[149,155],[104,178],[265,177]]

def change(data):
    x=0
    y=0
    for i in range(len(data)):
        x += data[i][0]
        y += data[i][1]
    x=x/8
    y=y/8
    second=[]
    distance=0
    max=7.7
    for i in range(len(data)):
        second.append([data[i][0]-x,data[i][1]-y])
    x = 0
    y = 0
    flag=0
    mid=second
    for i in range(len(second)):
        if math.sqrt((second[i][0]-x)**2+(second[i][1]-y)**2)>distance:
            distance=math.sqrt((second[i][0]-x)**2+(second[i][1]-y)**2)
            flag=i

    for j in range(1,20):
        if distance<max:
            break
        else:
            for i in range(len(second)):
                second[i][0] =mid[i][0]/j
                second[i][1] =mid[i][1]/j
            distance=math.sqrt((second[flag][0]-x)**2+(second[flag][1]-y)**2)

    for i in range(len(second)):
        second[i][0] = round(second[i][0]+5.5)
        second[i][1] = round(second[i][1]+5.5)
    for i in range(len(second)):
        second[i][1] = 10-second[i][1]
    print(second)
change(primary)


import boto3
import json
import logging
import os

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

logger.info('Loading function, boto3 version: {}'.format(boto3.__version__))

STATEMACHINE_ARN = os.environ['STATEMACHINE_ARN']

c_sfn = boto3.client('stepfunctions')

def lambda_handler(event, context):
    #logger.info("event: {}".format(event))
    logger.info(json.dumps(event, indent=4))

    try:
        logger.info("len: {}".format(len(event['Records'])))
        logger.info("event type: {}".format(event['Records'][0]['dynamodb']['NewImage']['eventType']['S']))

        record = event['Records'][0]['dynamodb']
        logger.info("record: {}".format(record))
        logger.info("event type: {}".format(record['NewImage']['eventType']['S']))

        logger.info(json.dumps(record, indent=2))
        input = json.dumps(record)
        logger.info(input)

        logger.info("STATEMACHINE_ARN: {}".format(STATEMACHINE_ARN))
        response = c_sfn.start_execution(
            stateMachineArn=STATEMACHINE_ARN,
            input=input
        )

        logger.info("response: {}".format(response))

        return record
    except Exception as e:
        logger.error('{}'.format(e))
        return False


from termcolor import colored
from utils import Point
import heapq, math

def d(a, b): return math.sqrt((a.real-b.real)**2+(a.imag-b.imag)**2)

def main(day_input):
    heightmap = {Point(x, y): h for y, row in enumerate(day_input) for x, h in enumerate(row)}

    for k, v in heightmap.items():
        if v == 'S':
            start = k
            heightmap[k] = 'a'
        if v == 'E':
            end = k
            heightmap[k] = 'z'

    xmax, ymax = int(max([m.real for m in heightmap.keys()])), int(max([m.imag for m in heightmap.keys()]))

    arrows = {-1: '<',1: '>',1j: 'v',-1j: '^',0j: 'X'}

    def print_map(path1, path2):
        print()
        def get_char(path, cpos):
            i = path.index(cpos)
            try: diff = path[i+1]-cpos
            except IndexError: diff = end-cpos
            try: return arrows[diff]
            except KeyError: return '#'
        for y in range(ymax+1):
            row=''
            for x in range(xmax+1):
                cpos = Point(x, y)
                if cpos in path1:
                    row += colored(get_char(path1, cpos), 'green')
                elif cpos in path2:
                    row += colored(get_char(path2, cpos), 'red')
                else:
                    row += heightmap[cpos]
            print(row)
        print()

    def walk(current_start):
        q = [(0, d(current_start, end), [current_start])]
        heapq.heapify(q)
        visited = set([])
        while q:
            _, _, path = heapq.heappop(q)

            pos = path[-1]

            if pos == end:
                return path

            for next_pos in [pos+off for off in (-1j, 1, 1j, -1)]:
                if next_pos in heightmap and next_pos not in visited and (ord(heightmap[next_pos])-ord(heightmap[pos])) <= 1:
                    heapq.heappush(q, (len(path)+1, d(next_pos, end), path + [next_pos]))
                    visited.add(next_pos)

    path = walk(start)
    min_path = min([walk(s) for s, h in heightmap.items() if h == 'a'], key=lambda p: len(p) if p else float('inf'))

    # print_map(min_path, path)

    return len(path)-1, len(min_path)-1