import json
import logging
import time
from typing import Optional
from datetime import datetime, date

import requests
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError

from cafe_shtin.delivery.models import Product, Category

logger = logging.getLogger(__name__)

class SbisPresto:

    def __init__(self):
        self.headers = {"X-SBISAccessToken": settings.SBISACCESSTOKEN}
        self.shops = self.__get_shops()
        self.menu = self.__get_menu()

    def __get_shops(self) -> list:
        parameters = {
            'withPhones': 'true',
            'withPrices': 'true',
            'product': 'delivery'
        }
        url = 'https://api.sbis.ru/retail/point/list?'
        response = requests.get(url, params=parameters, headers=self.headers).json()
        shops = [{'id': x['id'], 'name': x['name']} for x in response['salesPoints']]
        return shops

    def __get_menu(self) -> dict:
        parameters = {
            'pointId': self.shops[0]['id'],
            'actualDate': f'{datetime.now().strftime("%Y-%m-%d")}',
        }
        url = 'https://api.sbis.ru/retail/nomenclature/price-list?'
        response = requests.get(url, params=parameters, headers=self.headers).json()['priceLists']
        for menu in response:
            if menu['name'] == 'Доставка':
                return {'id': menu['id'], 'name': menu['name']}
        logger.error(f'Не найденo нужное меню. Взято из {self.shops[0]["name"]}')

    def update_catalog_site(self):
        categories, dishes = self._get_list_dishes(shop_id=self.shops[0]['id'],
                                                   menu_id=self.menu['id'],
                                                   stop_dish='false',
                                                   balance='false')
        logger.debug('Начало сохранения фото блюд')
        dishes = self._save_image(dishes=dishes)
        logger.debug('Фото блюд сохранены успешно')
        logger.debug('Актуализация категорий')
        for category in categories:
            obj, created = Category.objects.update_or_create(id=category['id'],
                                                             defaults={'name': category['name']})
        logger.debug('Актуализация блюд')
        for dish in dishes:
            try:
                obj, created = Product.objects.update_or_create(id=dish['id'],
                                                                defaults={
                                                                    'name': dish['name'],
                                                                    'category_id': Category.objects.get(
                                                                        id=dish['category_id']),
                                                                    'price': dish['cost'],
                                                                    'description': dish['description'],
                                                                    'image': dish['image_url'],
                                                                    'weight': dish['attributes'][
                                                                        'outQuantity'],
                                                                    'uuid': dish['uuid'],
                                                                    'price_list_id': dish['price_list_id']
                                                                }
                                                                )
            except ObjectDoesNotExist:
                logger.warning(f'Неудачная попытка добавить блюдо {dish["name"]}\n.'
                               f'Невозможно добавить блюдо с категорией id={dish["category_id"]}\n'
                               f'Блюдо пропущенно, преход к следующему блюду')
            except IntegrityError:
                logger.warning(f'Неудачная попытка добавить блюдо {dish["name"]}\n.'
                               f'Проверьте правильность внесения блюда в сбис престо!')
            except KeyError:
                logger.warning(f'Неудачная попытка добавить блюдо {dish["name"]}\n.'
                               f'В сбис престо не заполнено какое то поле (скорее всего вес)')
            else:
                logger.info(f'блюдо {dish["name"]} обновлено')

    def _get_list_dishes(self, shop_id: int, menu_id: int, stop_dish: str = 'false', balance: str = 'false'):
        parameters = {
            'pointId': shop_id,
            'priceListId': menu_id,
            'withBalance': balance,
            'noStopList': stop_dish,
        }
        url = 'https://api.sbis.ru/retail/nomenclature/list?'
        response = requests.get(url, params=parameters, headers=self.headers).json()
        categories = [{'id': x['hierarchicalId'], 'name': x['name']} for x in response['nomenclatures'] if
                      x['attributes'] is None]
        if balance == 'true':
            dishes = [{'id': x['id'],
                       'balance': x['balance'],
                       } for x in response['nomenclatures'] if x['attributes'] is not None]
        else:
            dishes = [{'id': x['id'],
                       'name': x['name'],
                       'category_id': x['hierarchicalParent'],
                       'cost': x['cost'],
                       'image_url': x['images'],
                       'description': x['description'],
                       'attributes': x['attributes'],
                       'uuid': x['externalId'],
                       'price_list_id': menu_id
                       } for x in response['nomenclatures'] if x['attributes'] is not None]
        return categories, dishes

    def _save_image(self, dishes: list):
        start = time.time()
        url = 'https://api.sbis.ru/retail/'
        for dish in dishes:
            image = requests.get(f'{url}{dish["image_url"][0]}', headers=self.headers).content
            image_url = f"media/dishes/{dish['name']}.jpg"
            with open(image_url, "wb") as file:
                file.write(image)
            dish["image_url"] = f'/{image_url}'
        logger.debug(f'Загрузка фото блюд заняло {(time.time() - start):0.2f} сек.')
        return dishes

    def update_count_dishes_in_shop(self):
        Product.objects.all().update(available=False)
        for shop in self.shops:
            categories, dishes = self._get_list_dishes(shop_id=shop['id'],
                                                       menu_id=self.menu['id'],
                                                       stop_dish='true',
                                                       balance='true')
            for dish in dishes:
                try:
                    obj, created = Product.objects.update_or_create(
                        dish_id=Product.objects.get(id=dish['id']),
                        defaults={
                            'count': dish['balance'],
                            'available': True})
                except ObjectDoesNotExist:
                    logger.warning(f'Ошибка добавления количества блюд для {dish["id"]}\n'
                                   f'Проверьте правильность shop_id={shop["id"]} и dish_id={dish["id"]}\n'
                                   f'Возможно еще не прошла актуализация каталога блюд на сайте')
                else:
                    logger.info(f'Количество блюд для id = {dish["id"]} обновлено')

class SbisOrder:
    def __init__(self, shop_id, user, nomenclatures, address, payment, is_pickup):
        self.headers = {"X-SBISAccessToken": settings.SBISACCESSTOKEN,
                        'Content-Type': 'application/json'}
        self.shop_id = shop_id
        self.user = user
        self.nomenclatures = nomenclatures
        self.address = address
        self.payment = payment
        self.is_pickup = is_pickup

    def make_order(self):
        url = "https://api.sbis.ru/retail/order/create"
        payload = {
            "product": "delivery",  # Обязательно delivery
            "pointId": self.shop_id,  # Точка продаж shop обязательна
            "comment": "Проба пера",
            "customer": {
                "externalId": self.user.uuid,
                "name": self.user.first_name,  # Обязательно
                "phone": self.user.phone_number  # Обязательно
            },
            "datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),  # Время на которое создается заказ. Обязательно
            "nomenclatures": self.nomenclatures,
            "delivery": {
                "addressFull": "г. Киров, ул. Советская, д. 166",  # Обязательно при доставкеself.address,
                'addressJSON': '{"City": "г. Киров", "Street": "ул. Советская", "HouseNum": "д. 166", "Entrance": "3", "Floor": "87", "AptNum": "47", "Address": "г. Киров, ул. Советская, д. 166, кв. 87"}',
                # Попробывать без него
                "paymentType": self.payment,  # Обязательно, варианты: «card», «online», «cash»
                "persons": 4,
                "isPickup": self.is_pickup  # False - доставка, True - самовызов
            }
        }
        payload_json = json.dumps(payload)
        response = requests.request("POST", url, headers=self.headers, data=payload_json)
        return response.json()

    def _get_orders_user(self):
        pass

    def get_address(self):
        pass

class SbisUser:
    def __init__(self):
        self.headers = {
            "Host": "online.sbis.ru",
            "Content-Type": "application/json-rpc; charset=utf-8",
            "Accept": "application/json-rpc",
        }
        self.sid = self.__login_sbis()

    def __login_sbis(self) -> str:
        return self.__invoke(
            "СБИС.Аутентифицировать",
            {"Параметр": {"Логин": settings.SBIS_LOGIN, "Пароль": settings.SBIS_PASSWORD}},
            None,
        )["result"]

    def __invoke(self, method: str, params: dict, auth_sid) -> dict:
        """
            Вызов метода
            """
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params,
            "protocol": 2,
            "id": 0,
        }

        if auth_sid:
            self.headers["X-SBISSessionID"] = auth_sid
            url = "https://online.sbis.ru/service/"
        else:
            url = "https://online.sbis.ru/auth/service/"

        response = requests.post(url, headers=self.headers, data=json.dumps(payload)).json()
        return response

    def get_user_crm(self, phone: str) -> dict:
        params = {
            "client_data": {
                "d": {
                    'ContactData': {'d': [[phone, 'mobile_phone', None]],
                                    's': [{'n': 'Value', 't': 'Строка'},
                                          {'n': 'Type', 't': 'Строка'},
                                          {'n': 'Priority', 't': 'Строка'}]},
                },
                "s": {
                    'ContactData': 'Выборка',
                },
            },
            "options": None
        }
        user_crm = self.__invoke("CRMClients"
                                 ".GetCustomerByParams", params, self.sid)['result']['d']
        if user_crm:
            return {
                    "is_user":  True,
                    'birthday': user_crm['BirthDay'],
                    'phone': phone,
                    'uuid': user_crm['UUID'],
                    'name': user_crm['FirstName'],
                }
        return {
                    "is_user":  False,
                    'phone': phone,
                }

class CardUser:
    def __init__(self, phone: str, name: Optional[str] = None, birthday: Optional[date] = None,
                 gender: Optional[int] = None):
        self.phone = phone
        self.name = name
        self.birthday = birthday
        self.gender = gender
        self.headers = {'Content-Type': 'application/json',
                        'Cookie': 'CpsUserId=034d5129-2037-4ddb-8af8-63b894d90a5a; s3csu=daab; s3su=00a28c6f-00a2a4ae; s3tok-daab=; sid=00a28c6f-00a2a4ae-000d-1111111111111111'
                        }
        self.card_type_uuid = "16f7b6d9-7908-443e-82f8-d22e45c31508"

    def verify_phone(self) -> dict:
        url = "https://sabyget.ru/discount-cards/service/?x_version=23.5104-16"
        payload = json.dumps({
            "jsonrpc": "2.0",
            "protocol": 6,
            "method": "Questionary.VerifyPhone",
            "params": {
                "CardTypeUUID": self.card_type_uuid,
                "PhoneNumber": self.phone
            },
            "id": 1
        })

        response = requests.request("POST", url, headers=self.headers, data=payload).json()
        uniq_id = response['result']
        return uniq_id

    def get_or_create_user(self, uniq_id: str, code_user: int) -> dict:
        url = "https://sabyget.ru/discount-cards/service/?x_version=23.2155-19"
        payload = json.dumps({
            "jsonrpc": "2.0",
            "protocol": 6,
            "method": "Questionary.CreateCard",
            "params": {
                "CardTypeUUID": self.card_type_uuid,
                "Data": {
                    "d": [
                        "44507f6a-b617-4c5a-a0c4-0ed4a4ad1e58",
                        self.phone,
                        uniq_id,
                        code_user,
                        {
                            "d": [
                                self.name,
                                None,
                                None,
                                None
                            ],
                            "s": [
                                {
                                    "t": "Строка",
                                    "n": "FIO"
                                },
                                {
                                    "t": "Строка",
                                    "n": "Email"
                                },
                                {
                                    "t": "Дата",
                                    "n": "BirthDay"
                                },
                                {
                                    "t": "Число целое",
                                    "n": "Gender"
                                }
                            ],
                            "_type": "record",
                            "f": 1
                        },
                        True,
                        True,
                        "discount-cards.gpay.channel:6990a57a-7459-4db2-b575-0553a0e7dc31",
                        "discount-cards.card-image.channel.d50c3c9d-1c15-4de3-85c8-552137e4f617:10658990",
                        None
                    ],
                    "s": [
                        {
                            "t": "UUID",
                            "n": "CardTypeUUID"
                        },
                        {
                            "t": "Строка",
                            "n": "PhoneNumber"
                        },
                        {
                            "t": "Строка",
                            "n": "SMSTicket"
                        },
                        {
                            "t": "Строка",
                            "n": "SMSCode"
                        },
                        {
                            "t": "Запись",
                            "n": "ClientData"
                        },
                        {
                            "t": "Логическое",
                            "n": "WithWalletQR"
                        },
                        {
                            "t": "Логическое",
                            "n": "WithGPayQR"
                        },
                        {
                            "t": "Строка",
                            "n": "EventChannelGPay"
                        },
                        {
                            "t": "Строка",
                            "n": "EventChannelCardImage"
                        },
                        {
                            "t": "Число целое",
                            "n": "PreferredPass"
                        }
                    ],
                    "_type": "record",
                    "f": 0
                }
            },
            "id": 1
        })
        response = requests.post(url, data=payload, headers=self.headers)


import numpy as np

from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec
from matplotlib.backends.backend_agg import FigureCanvasAgg

from sigvisa.plotting.heatmap import Heatmap
from scipy.spatial import KDTree

f = open("papers/product_tree/tco.csv", 'r')
data_dict = {}
lats = set()
lons = set()
for line in f:
    lon, lat, depth, tco = [float(x) for x in line.split(',')]
    lats.add(lat)
    lons.add(lon)
    data_dict[(lon, lat)] = tco

lats = np.array(sorted(list(lats)))
lons = np.array(sorted(list(lons)))

def neighbor(lon, lat):
    idx1 = np.searchsorted(lons, lon)
    idx2 = np.searchsorted(lats, lat)

    try:
        lon2 = lons[idx1-1]
    except IndexError:
        lon2 = lons[idx1]
    try:
        if np.abs(lons[idx1] - lon) < np.abs(lon2-lon):
            lon2 = lons[idx1]
    except IndexError:
        pass

    try:
        lat2 = lats[idx2-1]
    except IndexError:
        lat2 = lats[idx2]
    try:
        if np.abs(lats[idx2] - lat) < np.abs(lat2-lat):
            lat2 = lats[idx2]
    except IndexError:
        pass

    return lon2, lat2

def lookup(lon, lat):
    lon2,lat2 = neighbor(lon, lat)
    tco = data_dict[(lon2, lat2)]
    return tco

hm = Heatmap(f = lookup, left_lon=-179, right_lon=179, top_lat=89.5, bottom_lat=-89.5, n=180)
fig = Figure(figsize=(8, 5), dpi=144)
fig.patch.set_facecolor('white')
axes = fig.add_subplot(111)
hm.init_bmap(axes=axes)
hm.plot_density(smooth=True, nolines=True)
canvas = FigureCanvasAgg(fig)
canvas.print_figure("tco.png")


# O(n)

# first we must decalre a set variable, left pointer and the result
# loop every index
# while current char is in the set: remove the left pointer and increment by 1. Hence, the sliding window
# we need to add current right pointer value to the set
# update the result with right-left+1 length
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        charSet = set()
        l = 0
        res = 0

        for r in range(len(s)):
            while s[r] in charSet:
                charSet.remove(s[l])
                l += 1
            charSet.add(s[r])
            res = max(res, r - l + 1)
        return res

s = "abcabcbb"
print(Solution().lengthOfLongestSubstring(s))


import plotly.express as px
tips = px.data.tips()
fig = px.scatter(
    tips,
    x="total_bill",
    y="tip",
    facet_col="sex",
    width=1000,
    height=500
    # adjust the size of figure
)
fig.update_layout(
    margin=dict(l=20,r=20,t=20,b=20),
    # set margin of left,right,top,bottom
    paper_bgcolor="LightSteelBlue"
)
fig.show(
    config={
        'scrollZoom':True,
        'editable':True
    }
)


from typing import Any, Dict, List, Tuple, Type, Union

from pydantic import BaseModel

__all__ = ["Validator", "Parser", "Filter"]

class Validator:
    delimiter: str
    ordering: Union[bool, List[str]]

    def __init__(self, delimiter: str, ordering: Union[bool, List[str]]):
        self.delimiter = delimiter
        self.ordering = ordering

    def parse(self, model: Type[BaseModel]) -> Type[BaseModel]:
        raise NotImplementedError()

class Filter:
    _value: Any
    _field: Union[str, List[str]]

    def __init__(self, field: str, value: Any, delimiter: str):
        self._value = value

        self._field = [field]
        if delimiter in field:
            self._field = field.split(delimiter)

    def value(self) -> Any:
        return {
            "field": self._field,
            "value": self._value,
            "operation": self.operation(),
        }

    @classmethod
    def operation(cls) -> str:
        raise NotImplementedError()

    def name(self) -> str:
        raise NotImplementedError()

class Parser:
    delimiter: str
    validation_model: Type[BaseModel]
    ignore_unknown_name: bool = True

    def __init__(
        self,
        validation_model: Type[BaseModel],
        delimiter: str,
        ignore_unknown_name: bool = True,
    ):
        self.validation_model = validation_model
        self.delimiter = delimiter
        self.ignore_unknown_name = ignore_unknown_name

    def parse(
        self, raw_qs: str
    ) -> Tuple[Dict[Tuple[str, str], Any], Dict[Tuple[str, str], Type[Filter]]]:
        raise NotImplementedError()


import time

class HashTable:
    def __init__(self):
        self.__max_capacity = 4
        self.__keys = [None] * self.__max_capacity
        self.__values = [None] * self.__max_capacity
        self.__min_index = 0

    def __getitem__(self, key):
        try:
            index = self.__keys.index(key)
            return self.__values[index]
        except ValueError:
            raise KeyError(f"{key} is not a valid key!")

    def __setitem__(self, key, value):
        if key in self.__keys:  # First we check if this key is already created, and if it is we update its value
            index = self.__keys.index(key)
            self.__values[index] = value
            return

        if self.size() == self.__max_capacity:  # Then we check if we have reached the array's capacity
            self.__resize()

        index = self.__calc_index(key)
        index = self.__get_index(index)

        self.__keys[index] = key
        self.__values[index] = value

    def __calc_index(self, key):  # This is our Hash Function, we decide how to hash the data
        return sum(ord(c) for c in key) % self.__max_capacity

    def __get_index(self, index):  # We check if there is a collision
        if index == self.__max_capacity:
            index = self.__min_index

        if self.__keys[index] is None:
            return index

        return self.__get_index(index + 1)

    def __resize(self):
        self.__keys = self.__keys + [None] * self.__max_capacity
        self.__values = self.__values + [None] * self.__max_capacity

        # self.__min_index = self.__max_capacity
        self.__max_capacity *= 2

    def size(self):
        return len([k for k in self.__keys if k is not None])

    def get(self, key, default=None):
        try:
            return self[key]

        except KeyError:
            return default

    def get_representation(self):
        print("{", end="")
        for i in range(self.__max_capacity):
            if self.__keys[i] is not None:
                print(f"{self.__keys[i]}: {self.__values[i]},", end=" ")

        print("}")

    def __len__(self):
        return self.__max_capacity

start_time = time.time()

table = HashTable()

table["name"] = "Peter"
table["age"] = 25
table["last name"] = "Jackson"
table["is_married"] = "No"
table["has_drivers_license"] = "Yes"

print(table["name"])
# print(table["pets"])  # returns KeyError: 'pets is not a valid key!'

# table.get_representation()

print(table)
print(table.get("name"))
print(table.get("n"))  # returns None

print(table["age"])
print(len(table))

time.sleep(1)
end_time = time.time()
execution = end_time - start_time
# print(f"Executed in: {execution * 1000 - 1000:.10f} milliseconds")


import os

import ltp_enums

VTS_LTP_OUTPUT = os.path.join('DATA', 'nativetest', 'ltp')
LTP_RUNTEST_DIR = 'external/ltp/runtest'
# The bp file that contains all binaries of ltp
LTP_GEN_BINARY_BP = 'external/ltp/gen.bp'

LTP_DISABLED_BUILD_TESTS_CONFIG_PATH = 'external/ltp/android/tools/disabled_tests.txt'
# Directory for the template of the test config.
LTP_CONFIG_TEMPLATE_DIR = 'test/vts-testcase/kernel/ltp/testcase/tools/template'
# The file name of the config template file
LTP_CONFIG_TEMPLATE_FILE_NAME = 'template.xml'

# Environment paths for ltp test cases
# string, ltp build root directory on target
LTPDIR = '/data/local/tmp/ltp'
# Directory for environment variable 'TMP' needed by some test cases
TMP = os.path.join(LTPDIR, 'tmp')
# Directory for environment variable 'TMPBASE' needed by some test cases
TMPBASE = os.path.join(TMP, 'tmpbase')
# Directory for environment variable 'LTPTMP' needed by some test cases
LTPTMP = os.path.join(TMP, 'ltptemp')
# Directory for environment variable 'TMPDIR' needed by some test cases
TMPDIR = os.path.join(TMP, 'tmpdir')

# File name suffix for low memory scenario group scripts
LOW_MEMORY_SCENARIO_GROUP_SUFFIX = '_low_mem'

# Requirement to testcase dictionary.
REQUIREMENTS_TO_TESTCASE = {
    ltp_enums.Requirements.LOOP_DEVICE_SUPPORT: [
        'syscalls.mount01',
        'syscalls.fchmod06',
        'syscalls.ftruncate04',
        'syscalls.ftruncate04_64',
        'syscalls.inotify03',
        'syscalls.link08',
        'syscalls.linkat02',
        'syscalls.mkdir03',
        'syscalls.mkdirat02',
        'syscalls.mknod07',
        'syscalls.mknodat02',
        'syscalls.mmap16',
        'syscalls.mount01',
        'syscalls.mount02',
        'syscalls.mount03',
        'syscalls.mount04',
        'syscalls.mount06',
        'syscalls.rename11',
        'syscalls.renameat01',
        'syscalls.rmdir02',
        'syscalls.umount01',
        'syscalls.umount02',
        'syscalls.umount03',
        'syscalls.umount2_01',
        'syscalls.umount2_02',
        'syscalls.umount2_03',
        'syscalls.utime06',
        'syscalls.utimes01',
        'syscalls.mkfs01',
        'fs.quota_remount_test01',
    ],
    ltp_enums.Requirements.BIN_IN_PATH_LDD: ['commands.ldd'],
}

# Requirement for all test cases
REQUIREMENT_FOR_ALL = [ltp_enums.Requirements.LTP_TMP_DIR]

# Requirement to test suite dictionary
REQUIREMENT_TO_TESTSUITE = {}

# List of LTP test suites to run
TEST_SUITES = [
    'can',
    'cap_bounds',
    'commands',
    'connectors',
    'containers',
    'controllers',
    'cpuhotplug',
    'cve',
    'dio',
    'fcntl-locktests_android',
    'filecaps',
    'fs',
    'fs_bind',
    'fs_perms_simple',
    'fsx',
    'hugetlb',
    'hyperthreading',
    'input',
    'io',
    'ipc',
    'kernel_misc',
    'math',
    'mm',
    'nptl',
    'power_management_tests',
    'pty',
    'sched',
    'securebits',
    'syscalls',
    'tracing',
]

# List of LTP test suites to run
TEST_SUITES_LOW_MEM = [
    'can',
    'cap_bounds',
    'commands',
    'connectors',
    'containers',
    'cpuhotplug',
    'cve',
    'dio',
    'fcntl-locktests_android',
    'filecaps',
    'fs',
    'fs_bind',
    'fs_perms_simple',
    'fsx',
    'hugetlb',
    'hyperthreading',
    'input',
    'io',
    'ipc',
    'kernel_misc',
    'math',
    'mm',
    'nptl',
    'power_management_tests',
    'pty',
    'sched_low_mem',
    'securebits',
    'syscalls',
    'tracing',
]


# P5_test.py
#
# This file is part of P5.py.
#
# date:    02/17/2017
# author:  Chiayo Lin
# license: GPL 3.0

from P5 import interleaveChars

index = 0
test_file = list(open("P5_text.txt", 'r'))
while index != len(test_file):
    line_1 = test_file[index][:-1]
    line_2 = test_file[index + 1][:-1]
    print(line_1, line_2, interleaveChars(line_1, line_2),
          sep = '\n', end = '\n\n')

    index += 2


import random
import matplotlib.pyplot as mlt
import numpy as nmpi

Elementlist = ["Ted", "Barney", "Marshall", "Lily", "Robin"]

for Breathtaking in range(2):
    print(random.choices(Elementlist))

print(random.randint(0, 9))

print(random.random())

print(random.uniform(9.5, 80.5))

print(round(random.uniform(33.33, 66.66),2))

print(random.SystemRandom().uniform(5, 10))

print(" ")

min_value = int(input("Write the minimum number "))
max_value = int(input("Write the maximum number "))
Guess = int(input("choose one random number between them "))

ypoints1 = []
xpoints = []

def binary_search(Guess, min_value, max_value):
    tries = 0
    found = False

    if max_value < min_value:
        print("Maximum value must be bigger than the minimum value")
    elif Guess < min_value or Guess > max_value:
        print("The number must be between min_value and max_value")
    else:
        while min_value < max_value and not found:
            tries += 1
            xpoints.append(tries)
            mid_value = (min_value + max_value) // 2
            ypoints1.append(mid_value)
            if mid_value == Guess:
                found = True
            else:
                if Guess < mid_value:
                    max_value = mid_value - 1
                else:
                    min_value = mid_value + 1

            print([(min_value, max_value), (mid_value, Guess), tries])

        print("The number is:", str(Guess))
        print("Tries:", str(tries))

print(binary_search(Guess, min_value, max_value))

print(ypoints1)
print(xpoints)

#xnumber = nmpi.array(xpoints)
#ynumber1 = nmpi.array(ypoints1)
#ypoint2 = nmpi.array([Guess])

xnumber=nmpi.array([12,10,20,50])
ynumber1=nmpi.array([18,20,26,57])

print(xnumber)
print(ynumber1)

mlt.plot(xnumber,ynumber1)
mlt.show()

print(" ")

Max_number = 100
Good_number = random.randrange(Max_number)
Guess = int(input("Guess the number"))
number_of_Guesses = 0
while Guess != Good_number:
    if Guess < Good_number:
        print("Higher")
        Guess = int(input("Guess again: "))
        number_of_Guesses += 1
    elif Guess > Good_number:
        print("Lower")
        Guess = int(input("Guess again: "))
        number_of_Guesses += 1
    if Guess == Good_number:
        print("You win")
    if number_of_Guesses == 10:
        print("Game over")

print(" ")

import math

lowest_number = int(input("Enter Lower bound:- "))

highest_number = int(input("Enter Upper bound:- "))

x = random.randint(lowest_number, highest_number)
print("\n\tYou've only ",
      round(math.log(highest_number - lowest_number + 1, 2)),
      " chances to guess the integer!\n")

count = 0

while count < math.log(highest_number - lowest_number + 1, 2):
    count += 1

    guess = int(input("Guess a number:- "))

    if x == guess:
        print("Congratulations you did it in ",
              count, " try")
        break
    elif x > guess:
        print("You guessed too small!")
    elif x < guess:
        print("You Guessed too high!")

if count >= math.log(highest_number - lowest_number + 1, 2):
    print("\nThe number is %d" % x)
    print("\tBetter Luck Next time!")

#Random

import random

Integerslist = []

for Great in range(0, 10):
    Numbers1 = random.randint(30, 50)
    Integerslist.append(Numbers1)

print(Integerslist)

Floatlist = []

for Awesome in range(0, 5):
    Numbers2 = random.uniform(1, 10)
    Floatlist.append(Numbers2)

print(Floatlist)

Gaussianlist = []

for Astounding in range(0, 7):
    Numbers3 = random.gauss(50, 25)
    Gaussianlist.append(Numbers3)

print(Gaussianlist)

Elementlist = ["Ted", "Barney", "Marshall", "Lily", "Robin"]

for Breathtaking in range(2):
    print(random.choices(Elementlist))

#Break

Number = 0

while Number <= 100:
    Number += 1
    print(Number)
    if Number > 49:
        break

#Try and Except

Integer = int(input("Skriv ett number "))
String = str(input("Skriv ett ord "))

try:
    print(Integer, String)
except:
    print("What is wrong with you! You can not add an integer to a string ")
try:
    print(12/0)
except:
    print("A number can not be divided by zero ")


import csv

priorities = {
    "SPECIFIC": 0,
    "STORY": 1,
    "RELEVANT": 2,
    "QUIP": 99
}

npc_dict = {}
dialogues = {}

with open("./list.csv", "r") as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        # Skip the header
        if reader.line_num != 1:
            if row[0] == '':
                break
            npc = row[0].lower()
            timeline = row[1]
            priority = row[2]
            unlocks = row[3].split(",")
            removes = row[4].split(",")
            bubble = True if row[5] == "TRUE" else False

            if npc not in npc_dict:
                npc_dict[npc] = dict()
            npc_dict[npc][timeline] = {
                "id": timeline,
                "priority": priorities[priority],
                "bubble": bubble
            }
            unlocked_ids = []
            removed_ids = []
            for full in unlocks:
                if full == '':
                    break
                split = full.split("-")
                unlocked_ids.append({
                    "dialogue_id": "-".join(split[1:]),
                    "npc_id": split[0]
                })
            for full in removes:
                if full == '':
                    break
                split = full.split("-")
                removed_ids.append({
                    "dialogue_id": "-".join(split[1:]),
                    "npc_id": split[0]
                })
            dialogues[timeline] = {
                "unlocked_ids": unlocked_ids,
                "removed_ids": removed_ids,
            }

for npc_name in npc_dict:
    with open('../%sDialogueFile.tres' % npc_name.title(), 'w') as f:
        text = '''[gd_resource type="Resource" load_steps=%d format=2]

[ext_resource path="res://Scripts/DialogueSystem/classes/DialogueFile.gd" type="Script" id=1]
[ext_resource path="res://Scripts/DialogueSystem/classes/Dialogue.gd" type="Script" id=2]
''' % (3 + len(npc_dict[npc_name]))
        dialogues_text = '''
[resource]
script = ExtResource( 1 )
dialogues = {'''
        count = 1
        for dialogue_name in npc_dict[npc_name]:
            dialogue = npc_dict[npc_name][dialogue_name]
            d_id = "-".join(dialogue_name.split("-")[1:])
            text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 2 )
id = "%s"
priority = %d
bubble = %s
''' % (count, d_id, dialogue["priority"], str(dialogue["bubble"]).lower())
            dialogues_text += '''
"%s": SubResource( %d )%s''' % (d_id, count, ''',''' if count <= len(npc_dict[npc_name]) - 1 else '''
}''')
            count += 1

        f.write(text + dialogues_text)

with open("../UnlockTable.tres", "w") as f:
    sub_resources = {}
    text = '''[gd_resource type="Resource" load_steps=%d format=2]

[ext_resource path="res://Scripts/DialogueSystem/classes/UnlockTable.gd" type="Script" id=1]
[ext_resource path="res://Scripts/DialogueSystem/classes/UnlockTableEntry.gd" type="Script" id=2]
[ext_resource path="res://Scripts/DialogueSystem/classes/DialogueNpcIds.gd" type="Script" id=3]
'''
    count = 1
    with open("./events.csv", "r") as events_file:
        reader = csv.reader(events_file)
        for row in reader:
            if reader.line_num != 1:
                if row[0] == '':
                    break
                timeline = row[0]
                unlocks = row[1].split(",")
                removes = row[2].split(",")

                unlocked_resource_ids = []
                removed_resource_ids = []
                for i in range(len(unlocks)):
                    full = unlocks[i]
                    if full == '':
                        break
                    split = full.split("-")
                    unlocked_resource_ids.append(count + i + 1)
                    text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 3 )
dialogue_id = "%s"
npc_id = "%s"
''' % (count + i + 1, "-".join(split[1:]), split[0])
                for i in range(len(removes)):
                    full = removes[i]
                    if full == '':
                        break
                    split = full.split("-")
                    removed_resource_ids.append(count + i + len(unlocked_resource_ids) + 1)
                    text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 3 )
dialogue_id = "%s"
npc_id = "%s"
''' % (count + i + len(unlocked_resource_ids) + 1, "-".join(split[1:]), split[0])

                text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 2 )
unlocked_ids = [ ''' % count
                for i in range(len(unlocked_resource_ids)):
                    text += "SubResource( %d )%s" % (
                        unlocked_resource_ids[i], ", " if i < len(unlocked_resource_ids) - 1 else "")
                text += ''' ]
removed_ids = [ '''
                for i in range(len(removed_resource_ids)):
                    text += "SubResource( %d )%s" % (
                        removed_resource_ids[i], ", " if i < len(removed_resource_ids) - 1 else "")

                text += ''' ]
                '''
                sub_resources[timeline] = count
                count += 1 + len(unlocked_resource_ids) + len(removed_resource_ids)

    for d in dialogues:
        unlocked_resource_ids = []
        removed_resource_ids = []
        for i in range(len(dialogues[d]["unlocked_ids"])):
            entry = dialogues[d]["unlocked_ids"][i]
            unlocked_resource_ids.append(count + i + 1)
            text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 3 )
dialogue_id = "%s"
npc_id = "%s"
''' % (count + i + 1, entry["dialogue_id"], entry["npc_id"])
        for i in range(len(dialogues[d]["removed_ids"])):
            entry = dialogues[d]["removed_ids"][i]
            removed_resource_ids.append(count + i + len(unlocked_resource_ids) + 1)
            text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource ( 3 )
dialogue_id = "%s"
npc_id = "%s"
''' % (count + i + len(unlocked_resource_ids) + 1, entry["dialogue_id"], entry["npc_id"])

        text += '''
[sub_resource type="Resource" id=%d]
script = ExtResource( 2 )
unlocked_ids = [ ''' % count
        for i in range(len(unlocked_resource_ids)):
            text += "SubResource( %d )%s" % (
                unlocked_resource_ids[i], ", " if i < len(unlocked_resource_ids) - 1 else "")
        text += ''' ]
removed_ids = [ '''
        for i in range(len(removed_resource_ids)):
            text += "SubResource( %d )%s" % (
                removed_resource_ids[i], ", " if i < len(removed_resource_ids) - 1 else "")

        text += ''' ]
'''
        sub_resources["npc-%s" % d] = count
        count += 1 + len(unlocked_resource_ids) + len(removed_resource_ids)

    text += '''
[resource]
script = ExtResource( 1 )
entries = {
'''
    keys = list(sub_resources.keys())
    for resource in range(len(keys)):
        text += '''"%s": SubResource( %d )%s''' % (keys[resource], sub_resources[keys[resource]], ''',
''' if resource < len(keys) - 1 else '''
}''')

    f.write(text % count)


import tkinter, wikipediaapi
import requests
#Configuring tkinter for size and window
root = tkinter.Tk()
root.geometry('680x420')
root.title("Wikipedia Article gets")

#GLOBALS
article_tab =0
#Configuring wikipedia api\

#configuring language
wiki = wikipediaapi.Wikipedia('en', extract_format=wikipediaapi.ExtractFormat.WIKI)

S = requests.Session()
URL = "https://en.wikipedia.org/w/api.php"

PARAMS = {
    "action":"query",
    "format": "json",
    "generator":"random",
    "grnnamespace":"0",
    "rvprop":"content",
    "grnlimit": "7"
}

#Functions
def get_clicked(val):
    if(not val):
        return
    # print(val)
    for l in root.pack_slaves():
       l.destroy()

    page = wiki.article(val)
    article_tab = tkinter.Toplevel(root)
    article_tab.title(page.title)

    scrollbar = tkinter.Scrollbar(article_tab)
    scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)

    article = tkinter.Text(article_tab, font="Courier 11",  yscrollcommand= scrollbar.set)
    article.insert(tkinter.END, page.text)
    article.pack()

    scrollbar.config(command=article.yview)

def get_random_articles():
    for l in root.pack_slaves():
       l.destroy()
    R = S.get(url=URL,params=PARAMS)
    Data = R.json()['query']['pages']
    for d in Data:
        d =  Data[d]
        btn = tkinter.Button(root , text=d['title'], command=lambda i=d['title']:get_clicked(i))
        btn.pack()

#Labels and buttons
lb1 = tkinter.Label(root,text="Click Button to get random wikipedia article(s)")

lb1.place(x=340,y=230, anchor="center")
lb1.configure(font=("Courier",18))

btn1 = tkinter.Button(root ,command=get_random_articles, text="Click")
btn1.place(x=340, y=260, anchor="center")
root.mainloop()


'''The SuperText class inherits from Tkinter's Text class and provides added
functionality to a standard text widget:

- Option to turn scrollbar on/off
- Right-click pop-up menu
- Two themes included (terminal and typewriter)

Compliant with Python 2.5-2.7

Author: @ifthisthenbreak
'''

from Tkinter import Tk, Frame, Text, Scrollbar, Menu
from tkMessageBox import askokcancel

class SuperText(Text):

    def __init__(self, parent, scrollbar=True, **kw):

        self.parent = parent

        frame = Frame(parent)
        frame.pack(fill='both', expand=True)

        # text widget
        Text.__init__(self, frame, **kw)
        self.pack(side='left', fill='both', expand=True)

        # scrollbar
        if scrollbar:
            scrb = Scrollbar(frame, orient='vertical', command=self.yview)
            self.config(yscrollcommand=scrb.set)
            scrb.pack(side='right', fill='y')

        # pop-up menu
        self.popup = Menu(self, tearoff=0)
        self.popup.add_command(label='Cut', command=self._cut)
        self.popup.add_command(label='Copy', command=self._copy)
        self.popup.add_command(label='Paste', command=self._paste)
        self.popup.add_separator()
        self.popup.add_command(label='Select All', command=self._select_all)
        self.popup.add_command(label='Clear All', command=self._clear_all)
        self.bind('<Button-3>', self._show_popup)

    def apply_theme(self, theme='standard'):
        '''theme=['standard', 'typewriter', 'terminal']'''

        if theme == 'typewriter':
            '''takes all inserted text and inserts it one char every 100ms'''
            text = self.get('1.0', 'end')
            self.delete('1.0', 'end')
            self.char_index = 0
            self._typewriter([char for char in text])

        elif theme == 'terminal':
            '''blocky insert cursor'''
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()

    def _show_popup(self, event):
        '''right-click popup menu'''

        if self.parent.focus_get() != self:
            self.focus_set()

        try:
            self.popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup.grab_release()

    def _cut(self):

        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
            self.delete(*self.tag_ranges('sel'))
        except TypeError:
            pass

    def _copy(self):

        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
        except TypeError:
            pass

    def _paste(self):

        self.insert('insert', self.selection_get(selection='CLIPBOARD'))

    def _select_all(self):
        '''selects all text'''

        self.tag_add('sel', '1.0', 'end-1c')

    def _clear_all(self):
        '''erases all text'''

        isok = askokcancel('Clear All', 'Erase all text?', parent=self,
                           default='ok')
        if isok:
            self.delete('1.0', 'end')

    def _typewriter(self, text): # theme: typewriter
        '''after the theme is applied, this method takes all the inserted text
        and types it out one character every 100ms'''

        self.insert('insert', text[self.char_index])
        self.char_index += 1

        if self.char_index == len(text):
            self.after_cancel(self.typer)
        else:
            self.typer = self.after(100, self._typewriter, text)

    def _place_cursor(self): # theme: terminal
        '''check the position of the cursor against the last known position
        every 15ms and update the cursorblock tag as needed'''

        current_index = self.index('insert')

        if self.cursor != current_index:
            self.cursor = current_index
            self.tag_delete('cursorblock')

            start = self.index('insert')
            end = self.index('insert+1c')

            if start[0] != end[0]:
                self.insert(start, ' ')
                end = self.index('insert')

            self.tag_add('cursorblock', start, end)
            self.mark_set('insert', self.cursor)

        self.after(15, self._place_cursor)

    def _blink_cursor(self): # theme: terminal
        '''alternate the background color of the cursorblock tagged text
        every 600 milliseconds'''

        if self.switch == self.fg:
            self.switch = self.bg
        else:
            self.switch = self.fg

        self.tag_config('cursorblock', background=self.switch)

        self.after(600, self._blink_cursor)

lorem = '''Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'''

def typewriter_sample():

    typewriter = SuperText(root, scrollbar=False, font=('Times', 10, 'bold'))
    typewriter.pack(fill='both', expand=True)

    typewriter.insert(1.0, lorem)
    typewriter.apply_theme(theme='typewriter')

def terminal_sample():

    options = {'bg': 'black', 'fg': 'green', 'font': ('Courier', 10)}

    terminal = SuperText(root, scrollbar=True)
    terminal.pack(fill='both', expand=True)

    terminal.insert(1.0, lorem)
    terminal.config(options)
    terminal.apply_theme(theme='terminal')

if __name__ == '__main__':

    root = Tk()

    typewriter_sample()
    terminal_sample()

    root.mainloop()


#open方法需要指定正确的文件夹，a+为对文件的操作方法，如果文件不存在就创建文件，如果存在就在文件末尾处新增内容
#写入内容的时候，需要通过file=fq为执行操作指定对应的文件名
fq=open('D:/test/text.txt','a+')
print("hello word",file=fq)
fq.close()

fp=open('D:/test/text2.txt','a+')
print('hello word',file=fp)
fp.close()
#在操作文件时，需要记住有始有终，打开一个文件后，操作完成之后要记住关闭该文件


from django.shortcuts import render
from django.conf.urls import url
from eventhub import views
from registration.backends.simple.views import RegistrationView

urlpatterns = [ url(r'^$', views.index, name='index'),
                url(r'about/$', views.about, name='about'),
                url(r'contact/$', views.contact, name='contact'),
                url(r'create_event/$', views.create, name='create'),
                url(r'event/(?P<eventID>[\w\-]+)/$', views.event, name='event'),
                url(r'search/$', views.search, name='search'),
                url(r'category/(?P<cat>[\w\-]+)/$', views.category, name='category'),
                url(r'profile/', views.profile, name='profile'),
                url(r'creator/', views.get_creator, name='get_creator'),
                url(r'recommended/', views.recommended, name='recommended'),
                url(r'post_prefs/', views.post_prefs, name='post_prefs'),
                url(r'removeLike/(?P<eid>[\w\-]+)/$', views.remove_like, name='remove_like'),
                url(r'addLike/(?P<eid>[\w\-]+)/$', views.add_like, name='add_like'),
                url(r'edit/(?P<eid>[\w\-]+)/$', views.edit, name='edit'),
                url(r'delete/(?P<eid>[\w\-]+)/$', views.delete, name='delete'),
            ]


import sys
import tkinter as tk # If this fai

import time

def times():
    current_time = time.strftime("%H : %M : %S")
    clock.config(text=current_time)
    clock.after(200,times)

win = tk.Tk()
win.geometry("500x250")
clock = tk.Label(win,font=("times",50,"bold"),bg="white")
clock.grid(row=2,column=2,pady=25,padx=100)
times()

digi = tk.Label(win,text="Digital Clock",font="times 24 bold")
digi.grid(row=0,column=2)

nota = tk.Label(win,text="Hours   Minutes   Seconds    ",font="times 15 bold")
nota.grid(row=3,column=2)

win.mainloop()


import numpy as np
import pylab as pl

sampling_rate = 8000    # 采样频率为8000Hz
fft_size = 512          # FFT处理的取样长度
t = np.arange(0, 1.0, 1.0/sampling_rate)       # np.arange(起点，终点，间隔)产生1s长的取样时间
x = np.sin(2*np.pi*156.25*t) + 2*np.sin(2*np.pi*234.375*t)        # 两个正弦波叠加，156.25HZ和234.375HZ
# N点FFT进行精确频谱分析的要求是N个取样点包含整数个取样对象的波形。因此N点FFT能够完美计算频谱对取样对象的要求是n*Fs/N（n*采样频率/FFT长度），
# 因此对8KHZ和512点而言，完美采样对象的周期最小要求是8000/512=15.625HZ,所以156.25的n为10,234.375的n为15。
xs = x[:fft_size]   # 从波形数据中取样fft_size个点进行运算
xf = np.fft.rfft(xs)/fft_size   # 利用np.fft.rfft()进行FFT计算，rfft()是为了更方便对实数信号进行变换，由公式可知/fft_size为了正确显示波形能量
# rfft函数的返回值是N/2+1个复数，分别表示从0(Hz)到sampling_rate/2(Hz)的分。
# 于是可以通过下面的np.linspace计算出返回值中每个下标对应的真正的频率：
freqs = np.linspace(0, sampling_rate/2, int(fft_size/2+1))
# np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
# 在指定的间隔内返回均匀间隔的数字
xfp = 20*np.log10(np.clip(np.abs(xf), 1e-20, 1e100))
# 最后我们计算每个频率分量的幅值，并通过 20*np.log10()将其转换为以db单位的值。为了防止0幅值的成分造成log10无法计算，我们调用np.clip对xf的幅值进行上下限处理

# 绘图显示结果
pl.figure(figsize=(8, 4))
pl.subplot(211)
pl.plot(t[:fft_size], xs)
pl.xlabel(u"Time(S)")
pl.title(u"156.25Hz and 234.375Hz WaveForm And Freq")
pl.subplot(212)
pl.plot(freqs, xfp)
pl.xlabel(u"Freq(Hz)")
pl.subplots_adjust(hspace=0.4)
pl.show()

01 信号的频谱图.py


"""
Leetcode 199 : Binary tree right side view

Here the first idea that came to my mind was traverse to right of the tree, if no right node, take left node and go on.
This should give the right most path in the tree.

But this is not enough. If there are paths that has more edges than right most path, that will be seen from right view as well.
So we need to start with right most path and progress to left most path. While doing it, if there is any path that has more edges than right most
path, then add the extra to the right most path and update it.

So I took the code for getting all the paths from GoG and put my logic in the end of path. The original code first gives the left most path in the tree,
and move to right. One clever thing I've done here was, I changed the order of traversal such that, I get the right most path, first.

"""

from typing import Optional, List

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:

    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:

        def find_all_paths(stack, root):

            if root is None:
                return

            stack.append(root.val)
            if root.left == None and root.right == None:
                if self.result == None:
                    self.result = stack[:]
                else:
                    if len(stack) > len(self.result):
                        tmp = stack[:]
                        self.result += tmp[len(self.result):]
            find_all_paths(stack, root.right)
            find_all_paths(stack, root.left)
            stack.pop()
            return

        if root is None:
            return []

        self.result = None
        stack = []
        find_all_paths(stack, root)

        return self.result


import collections
from openpype_modules.ftrack.lib import BaseEvent

class NextTaskUpdate(BaseEvent):
    """Change status on following Task.

    Handler cares about changes of status id on Task entities. When new status
    has state "Done" it will try to find following task and change it's status.
    It is expected following task should be marked as "Ready to work on".

    By default all tasks with same task type must have state "Done" to do any
    changes. And when all tasks with same task type are "done" it will change
    statuses on all tasks with next task type.

    # Enable
    Handler is based on settings, handler can be turned on/off with "enabled"
    key.
    ```
    "enabled": True
    ```

    # Status mappings
    Must have set mappings of new statuses:
    ```
    "mapping": {
        # From -> To
        "Not Ready": "Ready",
        ...
    }
    ```

    If current status name is not found then status change is skipped.

    # Ignored statuses
    These status names are skipping as they would be in "Done" state. Best
    example is status "Omitted" which in most of cases is "Blocked" state but
    it will never change.
    ```
    "ignored_statuses": [
        "Omitted",
        ...
    ]
    ```

    # Change statuses sorted by task type and by name
    Change behaviour of task type batching. Statuses are not checked and set
    by batches of tasks by Task type but one by one. Tasks are sorted by
    Task type and then by name if all previous tasks are "Done" the following
    will change status.
    ```
    "name_sorting": True
    ```
    """
    settings_key = "next_task_update"

    def launch(self, session, event):
        '''Propagates status from version to task when changed'''

        filtered_entities_info = self.filter_entities_info(event)
        if not filtered_entities_info:
            return

        for project_id, entities_info in filtered_entities_info.items():
            self.process_by_project(session, event, project_id, entities_info)

    def filter_entities_info(self, event):
        # Filter if event contain relevant data
        entities_info = event["data"].get("entities")
        if not entities_info:
            return

        filtered_entities_info = collections.defaultdict(list)
        for entity_info in entities_info:
            # Care only about Task `entity_type`
            if entity_info.get("entity_type") != "Task":
                continue

            # Care only about changes of status
            changes = entity_info.get("changes") or {}
            statusid_changes = changes.get("statusid") or {}
            if (
                statusid_changes.get("new") is None
                or statusid_changes.get("old") is None
            ):
                continue

            project_id = None
            for parent_info in reversed(entity_info["parents"]):
                if parent_info["entityType"] == "show":
                    project_id = parent_info["entityId"]
                    break

            if project_id:
                filtered_entities_info[project_id].append(entity_info)
        return filtered_entities_info

    def process_by_project(self, session, event, project_id, _entities_info):
        project_name = self.get_project_name_from_event(
            session, event, project_id
        )
        # Load settings
        project_settings = self.get_project_settings_from_event(
            event, project_name
        )

        # Load status mapping from presets
        event_settings = (
            project_settings["ftrack"]["events"][self.settings_key]
        )
        if not event_settings["enabled"]:
            self.log.debug("Project \"{}\" has disabled {}.".format(
                project_name, self.__class__.__name__
            ))
            return

        statuses = session.query("Status").all()

        entities_info = self.filter_by_status_state(_entities_info, statuses)
        if not entities_info:
            return

        parent_ids = set()
        event_task_ids_by_parent_id = collections.defaultdict(list)
        for entity_info in entities_info:
            parent_id = entity_info["parentId"]
            entity_id = entity_info["entityId"]
            parent_ids.add(parent_id)
            event_task_ids_by_parent_id[parent_id].append(entity_id)

        # From now it doesn't matter what was in event data
        task_entities = session.query(
            (
                "select id, type_id, status_id, parent_id, link from Task"
                " where parent_id in ({})"
            ).format(self.join_query_keys(parent_ids))
        ).all()

        tasks_by_parent_id = collections.defaultdict(list)
        for task_entity in task_entities:
            tasks_by_parent_id[task_entity["parent_id"]].append(task_entity)

        project_entity = session.get("Project", project_id)
        self.set_next_task_statuses(
            session,
            tasks_by_parent_id,
            event_task_ids_by_parent_id,
            statuses,
            project_entity,
            event_settings
        )

    def filter_by_status_state(self, entities_info, statuses):
        statuses_by_id = {
            status["id"]: status
            for status in statuses
        }

        # Care only about tasks having status with state `Done`
        filtered_entities_info = []
        for entity_info in entities_info:
            status_id = entity_info["changes"]["statusid"]["new"]
            status_entity = statuses_by_id[status_id]
            if status_entity["state"]["name"].lower() == "done":
                filtered_entities_info.append(entity_info)
        return filtered_entities_info

    def set_next_task_statuses(
        self,
        session,
        tasks_by_parent_id,
        event_task_ids_by_parent_id,
        statuses,
        project_entity,
        event_settings
    ):
        statuses_by_id = {
            status["id"]: status
            for status in statuses
        }

        # Lower ignored statuses
        ignored_statuses = set(
            status_name.lower()
            for status_name in event_settings["ignored_statuses"]
        )
        # Lower both key and value of mapped statuses
        mapping = {
            status_from.lower(): status_to.lower()
            for status_from, status_to in event_settings["mapping"].items()
        }
        # Should use name sorting or not
        name_sorting = event_settings["name_sorting"]

        # Collect task type ids from changed entities
        task_type_ids = set()
        for task_entities in tasks_by_parent_id.values():
            for task_entity in task_entities:
                task_type_ids.add(task_entity["type_id"])

        statusese_by_obj_id = self.statuses_for_tasks(
            task_type_ids, project_entity
        )

        sorted_task_type_ids = self.get_sorted_task_type_ids(session)

        for parent_id, _task_entities in tasks_by_parent_id.items():
            task_entities_by_type_id = collections.defaultdict(list)
            for _task_entity in _task_entities:
                type_id = _task_entity["type_id"]
                task_entities_by_type_id[type_id].append(_task_entity)

            event_ids = set(event_task_ids_by_parent_id[parent_id])
            if name_sorting:
                # Sort entities by name
                self.sort_by_name_task_entities_by_type(
                    task_entities_by_type_id
                )
                # Sort entities by type id
                sorted_task_entities = []
                for type_id in sorted_task_type_ids:
                    task_entities = task_entities_by_type_id.get(type_id)
                    if task_entities:
                        sorted_task_entities.extend(task_entities)

                next_tasks = self.next_tasks_with_name_sorting(
                    sorted_task_entities,
                    event_ids,
                    statuses_by_id,
                    ignored_statuses
                )

            else:
                next_tasks = self.next_tasks_with_type_sorting(
                    task_entities_by_type_id,
                    sorted_task_type_ids,
                    event_ids,
                    statuses_by_id,
                    ignored_statuses
                )

        for task_entity in next_tasks:
            if task_entity["status"]["state"]["name"].lower() == "done":
                continue

            task_status = statuses_by_id[task_entity["status_id"]]
            old_status_name = task_status["name"].lower()
            if old_status_name in ignored_statuses:
                continue

            new_task_name = mapping.get(old_status_name)
            if not new_task_name:
                self.log.debug(
                    "Didn't found mapping for status \"{}\".".format(
                        task_status["name"]
                    )
                )
                continue

            ent_path = "/".join(
                [ent["name"] for ent in task_entity["link"]]
            )
            type_id = task_entity["type_id"]
            new_status = statusese_by_obj_id[type_id].get(new_task_name)
            if new_status is None:
                self.log.warning((
                    "\"{}\" does not have available status name \"{}\""
                ).format(ent_path, new_task_name))
                continue

            try:
                task_entity["status_id"] = new_status["id"]
                session.commit()
                self.log.info(
                    "\"{}\" updated status to \"{}\"".format(
                        ent_path, new_status["name"]
                    )
                )
            except Exception:
                session.rollback()
                self.log.warning(
                    "\"{}\" status couldn't be set to \"{}\"".format(
                        ent_path, new_status["name"]
                    ),
                    exc_info=True
                )

    def next_tasks_with_name_sorting(
        self,
        sorted_task_entities,
        event_ids,
        statuses_by_id,
        ignored_statuses,
    ):
        # Pre sort task entities by name
        use_next_task = False
        next_tasks = []
        for task_entity in sorted_task_entities:
            if task_entity["id"] in event_ids:
                event_ids.remove(task_entity["id"])
                use_next_task = True
                continue

            if not use_next_task:
                continue

            task_status = statuses_by_id[task_entity["status_id"]]
            low_status_name = task_status["name"].lower()
            if low_status_name in ignored_statuses:
                continue

            next_tasks.append(task_entity)
            use_next_task = False
            if not event_ids:
                break

        return next_tasks

    def check_statuses_done(
        self, task_entities, ignored_statuses, statuses_by_id
    ):
        all_are_done = True
        for task_entity in task_entities:
            task_status = statuses_by_id[task_entity["status_id"]]
            low_status_name = task_status["name"].lower()
            if low_status_name in ignored_statuses:
                continue

            low_state_name = task_status["state"]["name"].lower()
            if low_state_name != "done":
                all_are_done = False
                break
        return all_are_done

    def next_tasks_with_type_sorting(
        self,
        task_entities_by_type_id,
        sorted_task_type_ids,
        event_ids,
        statuses_by_id,
        ignored_statuses
    ):
        # `use_next_task` is used only if `name_sorting` is enabled!
        next_tasks = []
        use_next_tasks = False
        for type_id in sorted_task_type_ids:
            if type_id not in task_entities_by_type_id:
                continue

            task_entities = task_entities_by_type_id[type_id]

            # Check if any task was in event
            event_id_in_tasks = False
            for task_entity in task_entities:
                task_id = task_entity["id"]
                if task_id in event_ids:
                    event_ids.remove(task_id)
                    event_id_in_tasks = True

            if use_next_tasks:
                # Check if next tasks are not done already
                all_in_type_done = self.check_statuses_done(
                    task_entities, ignored_statuses, statuses_by_id
                )
                if all_in_type_done:
                    continue

                next_tasks.extend(task_entities)
                use_next_tasks = False
                if not event_ids:
                    break

            if not event_id_in_tasks:
                continue

            all_in_type_done = self.check_statuses_done(
                task_entities, ignored_statuses, statuses_by_id
            )
            use_next_tasks = all_in_type_done
            if all_in_type_done:
                continue

            if not event_ids:
                break

            use_next_tasks = False

        return next_tasks

    def statuses_for_tasks(self, task_type_ids, project_entity):
        project_schema = project_entity["project_schema"]
        output = {}
        for task_type_id in task_type_ids:
            statuses = project_schema.get_statuses("Task", task_type_id)
            output[task_type_id] = {
                status["name"].lower(): status
                for status in statuses
            }

        return output

    def get_sorted_task_type_ids(self, session):
        types_by_order = collections.defaultdict(list)
        for _type in session.query("Type").all():
            sort_oder = _type.get("sort")
            if sort_oder is not None:
                types_by_order[sort_oder].append(_type["id"])

        types = []
        for sort_oder in sorted(types_by_order.keys()):
            types.extend(types_by_order[sort_oder])
        return types

    @staticmethod
    def sort_by_name_task_entities_by_type(task_entities_by_type_id):
        _task_entities_by_type_id = {}
        for type_id, task_entities in task_entities_by_type_id.items():
            # Store tasks by name
            task_entities_by_name = {}
            for task_entity in task_entities:
                task_name = task_entity["name"]
                task_entities_by_name[task_name] = task_entity

            # Store task entities by sorted names
            sorted_task_entities = []
            for task_name in sorted(task_entities_by_name.keys()):
                task_entity = task_entities_by_name[task_name]
                sorted_task_entities.append(task_entity)
            # Store result to temp dictionary
            _task_entities_by_type_id[type_id] = sorted_task_entities

        # Override values in source object
        for type_id, value in _task_entities_by_type_id.items():
            task_entities_by_type_id[type_id] = value

def register(session):
    NextTaskUpdate(session).register()


# DEPRECATED

import os
import shutil

from jinja2 import Environment, PackageLoader, FileSystemLoader
from jinja2.exceptions import TemplateNotFound

from papier import helper

class NoStaticFilesWarning(RuntimeWarning):
    """ Warning for no static files """

class StaticFileExistWarning(RuntimeWarning):
    """ Warning for no static files """

class Renderer(object):
    def __init__(self):
        self._default_src = helper.path('template')
        self._default_env = Environment(loader = PackageLoader('papier', 'template'))
        self._basepath    = None
        self._environment = None
        print(self._default_src)

    def set_basepath(self, basepath):
        self._basepath    = basepath
        self._environment = Environment(loader = FileSystemLoader(self._basepath))

    def template(self, path):
        if self._environment:
            return self._environment.get_template(path)

        return self._default_env.get_template(path)

    def copy_static_files(self, destination_path):
        src_static_path = os.path.join(self._basepath or self._default_src)

        if not os.path.exists(src_static_path):
            raise NoStaticFilesWarning(src_static_path)

        if os.path.exists(destination_path):
            raise StaticFileExistWarning(destination_path)

        shutil.copytree(src_static_path, destination_path)


# -*- coding: utf-8 -*-
"""
 Evaluation functions
"""
import logging
import numpy as np
from sklearn.cluster import AgglomerativeClustering, KMeans
from .datasets.similarity import fetch_MEN, fetch_WS353, fetch_SimLex999, fetch_MTurk, fetch_RG65, fetch_RW, fetch_TR9856
from .datasets.categorization import fetch_AP, fetch_battig, fetch_BLESS, fetch_ESSLI_1a, fetch_ESSLI_2b, \
    fetch_ESSLI_2c
from web.analogy import *
from six import iteritems
from web.embedding import Embedding

logger = logging.getLogger(__name__)

def calculate_purity(y_true, y_pred):
    """
    Calculate purity for given true and predicted cluster labels.

    Parameters
    ----------
    y_true: array, shape: (n_samples, 1)
      True cluster labels

    y_pred: array, shape: (n_samples, 1)
      Cluster assingment.

    Returns
    -------
    purity: float
      Calculated purity.
    """
    assert len(y_true) == len(y_pred)
    true_clusters = np.zeros(shape=(len(set(y_true)), len(y_true)))
    pred_clusters = np.zeros_like(true_clusters)
    for id, cl in enumerate(set(y_true)):
        true_clusters[id] = (y_true == cl).astype("int")
    for id, cl in enumerate(set(y_pred)):
        pred_clusters[id] = (y_pred == cl).astype("int")

    M = pred_clusters.dot(true_clusters.T)
    return 1. / len(y_true) * np.sum(np.max(M, axis=1))

def evaluate_categorization(w, X, y, method="all", seed=None):
    """
    Evaluate embeddings on categorization task.

    Parameters
    ----------
    w: Embedding or dict
      Embedding to test.

    X: vector, shape: (n_samples, )
      Vector of words.

    y: vector, shape: (n_samples, )
      Vector of cluster assignments.

    method: string, default: "all"
      What method to use. Possible values are "agglomerative", "kmeans", "all.
      If "agglomerative" is passed, method will fit AgglomerativeClustering (with very crude
      hyperparameter tuning to avoid overfitting).
      If "kmeans" is passed, method will fit KMeans.
      In both cases number of clusters is preset to the correct value.

    seed: int, default: None
      Seed passed to KMeans.

    Returns
    -------
    purity: float
      Purity of the best obtained clustering.

    Notes
    -----
    KMedoids method was excluded as empirically didn't improve over KMeans (for categorization
    tasks available in the package).
    """

    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    assert method in ["all", "kmeans", "agglomerative"], "Uncrecognized method"

    mean_vector = np.mean(w.vectors, axis=0, keepdims=True)
    words = np.vstack(w.get(word, mean_vector) for word in X.flatten())
    ids = np.random.RandomState(seed).choice(range(len(X)), len(X), replace=False)

    # Evaluate clustering on several hyperparameters of AgglomerativeClustering and
    # KMeans
    best_purity = 0

    if method == "all" or method == "agglomerative":
        best_purity = calculate_purity(y[ids], AgglomerativeClustering(n_clusters=len(set(y)),
                                                                       affinity="euclidean",
                                                                       linkage="ward").fit_predict(words[ids]))
        logger.debug("Purity={:.3f} using affinity={} linkage={}".format(best_purity, 'euclidean', 'ward'))
        for affinity in ["cosine", "euclidean"]:
            for linkage in ["average", "complete"]:
                purity = calculate_purity(y[ids], AgglomerativeClustering(n_clusters=len(set(y)),
                                                                          affinity=affinity,
                                                                          linkage=linkage).fit_predict(words[ids]))
                logger.debug("Purity={:.3f} using affinity={} linkage={}".format(purity, affinity, linkage))
                best_purity = max(best_purity, purity)

    if method == "all" or method == "kmeans":
        purity = calculate_purity(y[ids], KMeans(random_state=seed, n_init=10, n_clusters=len(set(y))).
                                  fit_predict(words[ids]))
        logger.debug("Purity={:.3f} using KMeans".format(purity))
        best_purity = max(purity, best_purity)

    return best_purity

def evaluate_on_semeval_2012_2(w):
    """
    Simple method to score embedding using SimpleAnalogySolver

    Parameters
    ----------
    w : Embedding or dict
      Embedding or dict instance.

    Returns
    -------
    result: pandas.DataFrame
      Results with spearman correlation per broad category with special key "all" for summary
      spearman correlation
    """
    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    data = fetch_semeval_2012_2()
    mean_vector = np.mean(w.vectors, axis=0, keepdims=True)
    categories = data.y.keys()
    results = defaultdict(list)
    for c in categories:
        # Get mean of left and right vector
        prototypes = data.X_prot[c]
        prot_left = np.mean(np.vstack(w.get(word, mean_vector) for word in prototypes[:, 0]), axis=0)
        prot_right = np.mean(np.vstack(w.get(word, mean_vector) for word in prototypes[:, 1]), axis=0)

        questions = data.X[c]
        question_left, question_right = np.vstack(w.get(word, mean_vector) for word in questions[:, 0]), \
                                        np.vstack(w.get(word, mean_vector) for word in questions[:, 1])

        scores = np.dot(prot_left - prot_right, (question_left - question_right).T)

        c_name = data.categories_names[c].split("_")[0]
        # NaN happens when there are only 0s, which might happen for very rare words or
        # very insufficient word vocabulary
        cor = scipy.stats.spearmanr(scores, data.y[c]).correlation
        results[c_name].append(0 if np.isnan(cor) else cor)

    final_results = OrderedDict()
    final_results['all'] = sum(sum(v) for v in results.values()) / len(categories)
    for k in results:
        final_results[k] = sum(results[k]) / len(results[k])
    return pd.Series(final_results)

def evaluate_analogy(w, X, y, method="add", k=None, category=None, batch_size=100):
    """
    Simple method to score embedding using SimpleAnalogySolver

    Parameters
    ----------
    w : Embedding or dict
      Embedding or dict instance.

    method : {"add", "mul"}
      Method to use when finding analogy answer, see "Improving Distributional Similarity
      with Lessons Learned from Word Embeddings"

    X : array-like, shape (n_samples, 3)
      Analogy questions.

    y : array-like, shape (n_samples, )
      Analogy answers.

    k : int, default: None
      If not None will select k top most frequent words from embedding

    batch_size : int, default: 100
      Increase to increase memory consumption and decrease running time

    category : list, default: None
      Category of each example, if passed function returns accuracy per category
      in addition to the overall performance.
      Analogy datasets have "category" field that can be supplied here.

    Returns
    -------
    result: dict
      Results, where each key is for given category and special empty key "" stores
      summarized accuracy across categories
    """
    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    assert category is None or len(category) == y.shape[0], "Passed incorrect category list"

    solver = SimpleAnalogySolver(w=w, method=method, batch_size=batch_size, k=k)
    y_pred = solver.predict(X)

    if category is not None:
        results = OrderedDict({"all": np.mean(y_pred == y)})
        count = OrderedDict({"all": len(y_pred)})
        correct = OrderedDict({"all": np.sum(y_pred == y)})
        for cat in set(category):
            results[cat] = np.mean(y_pred[category == cat] == y[category == cat])
            count[cat] = np.sum(category == cat)
            correct[cat] = np.sum(y_pred[category == cat] == y[category == cat])

        return pd.concat([pd.Series(results, name="accuracy"),
                          pd.Series(correct, name="correct"),
                          pd.Series(count, name="count")],
                         axis=1)
    else:
        return np.mean(y_pred == y)

def evaluate_on_WordRep(w, max_pairs=1000, solver_kwargs={}):
    """
    Evaluate on WordRep dataset

    Parameters
    ----------
    w : Embedding or dict
      Embedding or dict instance.

    max_pairs: int, default: 1000
      Each category will be constrained to maximum of max_pairs pairs
      (which results in max_pair * (max_pairs - 1) examples)

    solver_kwargs: dict, default: {}
      Arguments passed to SimpleAnalogySolver. It is suggested to limit number of words
      in the dictionary.

    References
    ----------
    Bin Gao, Jiang Bian, Tie-Yan Liu (2015)
     "WordRep: A Benchmark for Research on Learning Word Representations"
    """
    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    data = fetch_wordrep()
    categories = set(data.category)

    accuracy = {}
    correct = {}
    count = {}
    for cat in categories:
        X_cat = data.X[data.category == cat]
        X_cat = X_cat[0:max_pairs]

        logger.info("Processing {} with {} pairs, {} questions".format(cat, X_cat.shape[0]
                                                                       , X_cat.shape[0] * (X_cat.shape[0] - 1)))

        # For each category construct question-answer pairs
        size = X_cat.shape[0] * (X_cat.shape[0] - 1)
        X = np.zeros(shape=(size, 3), dtype="object")
        y = np.zeros(shape=(size,), dtype="object")
        id = 0
        for left, right in product(X_cat, X_cat):
            if not np.array_equal(left, right):
                X[id, 0:2] = left
                X[id, 2] = right[0]
                y[id] = right[1]
                id += 1

        # Run solver
        solver = SimpleAnalogySolver(w=w, **solver_kwargs)
        y_pred = solver.predict(X)
        correct[cat] = float(np.sum(y_pred == y))
        count[cat] = size
        accuracy[cat] = float(np.sum(y_pred == y)) / size

    # Add summary results
    correct['wikipedia'] = sum(correct[c] for c in categories if c in data.wikipedia_categories)
    correct['all'] = sum(correct[c] for c in categories)
    correct['wordnet'] = sum(correct[c] for c in categories if c in data.wordnet_categories)

    count['wikipedia'] = sum(count[c] for c in categories if c in data.wikipedia_categories)
    count['all'] = sum(count[c] for c in categories)
    count['wordnet'] = sum(count[c] for c in categories if c in data.wordnet_categories)

    accuracy['wikipedia'] = correct['wikipedia'] / count['wikipedia']
    accuracy['all'] = correct['all'] / count['all']
    accuracy['wordnet'] = correct['wordnet'] / count['wordnet']

    return pd.concat([pd.Series(accuracy, name="accuracy"),
                      pd.Series(correct, name="correct"),
                      pd.Series(count, name="count")], axis=1)

def evaluate_similarity(w, X, y):
    """
    Calculate Spearman correlation between cosine similarity of the model
    and human rated similarity of word pairs

    Parameters
    ----------
    w : Embedding or dict
      Embedding or dict instance.

    X: array, shape: (n_samples, 2)
      Word pairs

    y: vector, shape: (n_samples,)
      Human ratings

    Returns
    -------
    cor: float
      Spearman correlation
    """
    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    missing_words = 0
    words = w.vocabulary.word_id
    for query in X:
        for query_word in query:
            if query_word not in words:
                missing_words += 1
    if missing_words > 0:
        logger.warning("Missing {} words. Will replace them with mean vector".format(missing_words))

    mean_vector = np.mean(w.vectors, axis=0, keepdims=True)
    A = np.vstack(w.get(word, mean_vector) for word in X[:, 0])
    B = np.vstack(w.get(word, mean_vector) for word in X[:, 1])
    scores = np.array([v1.dot(v2.T)/(np.linalg.norm(v1)*np.linalg.norm(v2)) for v1, v2 in zip(A, B)])
    return scipy.stats.spearmanr(scores, y).correlation

def evaluate_on_all(w):
    """
    Evaluate Embedding on all fast-running benchmarks

    Parameters
    ----------
    w: Embedding or dict
      Embedding to evaluate.

    Returns
    -------
    results: pandas.DataFrame
      DataFrame with results, one per column.
    """
    if isinstance(w, dict):
        w = Embedding.from_dict(w)

    # Calculate results on similarity
    logger.info("Calculating similarity benchmarks")
    similarity_tasks = {
        "MEN": fetch_MEN(),
        "WS353": fetch_WS353(),
        "WS353R": fetch_WS353(which="relatedness"),
        "WS353S": fetch_WS353(which="similarity"),
        "SimLex999": fetch_SimLex999(),
        "RW": fetch_RW(),
        "RG65": fetch_RG65(),
        "MTurk": fetch_MTurk(),
    }

    similarity_results = {}

    for name, data in iteritems(similarity_tasks):
        similarity_results[name] = evaluate_similarity(w, data.X, data.y)
        logger.info("Spearman correlation of scores on {} {}".format(name, similarity_results[name]))

    # Calculate results on analogy
    logger.info("Calculating analogy benchmarks")
    analogy_tasks = {
        "Google": fetch_google_analogy(),
        "MSR": fetch_msr_analogy()
    }

    analogy_results = {}

    for name, data in iteritems(analogy_tasks):
        analogy_results[name] = evaluate_analogy(w, data.X, data.y)
        logger.info("Analogy prediction accuracy on {} {}".format(name, analogy_results[name]))

    analogy_results["SemEval2012_2"] = evaluate_on_semeval_2012_2(w)['all']
    logger.info("Analogy prediction accuracy on {} {}".format("SemEval2012", analogy_results["SemEval2012_2"]))

    # Calculate results on categorization
    logger.info("Calculating categorization benchmarks")
    categorization_tasks = {
        "AP": fetch_AP(),
        "BLESS": fetch_BLESS(),
        "Battig": fetch_battig(),
        "ESSLI_2c": fetch_ESSLI_2c(),
        "ESSLI_2b": fetch_ESSLI_2b(),
        "ESSLI_1a": fetch_ESSLI_1a()
    }

    categorization_results = {}

    # Calculate results using helper function
    for name, data in iteritems(categorization_tasks):
        categorization_results[name] = evaluate_categorization(w, data.X, data.y)
        logger.info("Cluster purity on {} {}".format(name, categorization_results[name]))

    # Construct pd table
    cat = pd.DataFrame([categorization_results])
    analogy = pd.DataFrame([analogy_results])
    sim = pd.DataFrame([similarity_results])
    results = cat.join(sim).join(analogy)

    return results


import configparser
from datetime import datetime
import os
from pyspark.sql import SparkSession
from pyspark.sql.functions import udf, col
from pyspark.sql.functions import year, month, dayofmonth, hour, weekofyear, date_format
from pyspark.sql.types import StructType as Stt, StructField as Sfd, DoubleType as Dbl, StringType as Str, IntegerType as Int, TimestampType as Tst

config = configparser.ConfigParser()
config.read('dl.cfg')

os.environ['AWS_ACCESS_KEY_ID']=config['Default']['AWS_ACCESS_KEY_ID']
os.environ['AWS_SECRET_ACCESS_KEY']=config['Default']['AWS_SECRET_ACCESS_KEY']

def create_spark_session():
    """
    Initializes a Spark session or retrieves one if already present
    """
    spark = SparkSession \
        .builder \
        .config("spark.jars.packages", "org.apache.hadoop:hadoop-aws:2.7.0") \
        .getOrCreate()
    return spark

def process_song_data(spark, input_data, output_data):
    """
    Loads the song_data JSONs from the given S3, processes them by extracting the data into
    song and artist tables in parquet format in the target output folder

    Paramters
    spark: spark session
    input_data: path to location of target json files
    output_data: path to S3 bucket where processed data will be stored
    """
    # get filepath to song data file
    song_data = os.path.join(input_data, "song_data/*/*/*/*.json")

    song_schema = Stt([
        Sfd("artist_id", Str()),
        Sfd("artist_latitude", Dbl()),
        Sfd("artist_location", Str()),
        Sfd("artist_longitude", Dbl()),
        Sfd("artist_name", Str()),
        Sfd("duration", Dbl()),
        Sfd("num_songs", Int()),
        Sfd("title", Str()),
        Sfd("year", Int())
    ])

    # read song data file
    df = spark.read.json(song_data, schema = song_schema)

    # extract columns to create songs table
    songs_cols = ["title", "artist_id", "year", "duration"]
    songs_table = df.select(songs_cols).dropDuplicates().withColumn("song_id", monotonically_increasing_id())

    # write songs table to parquet files partitioned by year and artist
    songs_table.write.partitionBy("year", "artist_id").parquet(output_data + "songs")

    # extract columns to create artists table
    artists_cols = ["artist_id", "artist_name", "artist_location", "artist_latitude", "artist_longitude"]
    artists_table = df.selectExpr(artists_cols).dropDuplicates()

    # write artists table to parquet files
    artists_table.write.parquet(output_data + "artists")

def process_log_data(spark, input_data, output_data):
    """
    Loads the log_data JSONs from the given S3, processes them by extracting the data into
    users, songplays and times tables in parquet format in the target output folder

    Paramters
    spark: spark session
    input_data: path to location of target json files
    output_data: path to S3 bucket where processed data will be stored
    """
    # get filepath to log data file
    log_data = os.path.join(input_data, "log_data/*/*/*.json")

    # read log data file
    logs_df = spark.read.json(log_data)

    # filter by actions for song plays
    logs_df = logs_df.filter(logs_df.page == "NextSong")

    # extract columns for users table
    users_cols = ["userId as user_id", "firstName as first_name", "lastName as last_name", "gender", "level"]
    users_table = logs_df.selectExpr(users_cols).dropDuplicates()

    # write users table to parquet files
    users_table.write.parquet(output_data + "users")

    # create timestamp column from original timestamp column
    get_timestamp = udf(lambda x: x / 1000, Tst())
    logs_df = logs_df.withColumn("timestamp", get_timestamp(logs_df.timestamp))

    # create datetime column from original timestamp column
    get_datetime = udf(lambda x: datetime.fromtimestamp(x), Tst())
    logs_df = logs_df.withColumn("start_time", get_datetime(logs_df.timestamp))

    # extract columns to create time table
    times_table = logs_df.withColumn("hour", hour("start_time")) \
                         .withColumn("day", dayofmonth("start_time")) \
                         .withColumn("week", weekofyear("start_time")) \
                         .withColumn("month", month("start_time")) \
                         .withColumn("year", year("start_time")) \
                         .withColumn("weekday", dayofweek("start_time")) \

    times_table = times_table.select("start_time", "hour", "day", "week", "month", "year", "weekday")

    # write time table to parquet files partitioned by year and month
    times_table.write.partitionBy("year", "month").parquet(output_data + "times")

    # read in song data to use for songplays table
    songs_df = spark.read.parquet(output_data + "songs/*/*/*")
    artists_df = spark.read.parquet(output_data + "artists")

    songs_logs = logs_df.join(songs_df, (logs_df.song == songs_df.title))
    artists_songs_logs = songs_logs.join(artists_df, (songs_logs.artist == artists_df.artist_name))

    # extract columns from joined song and log datasets to create songplays table
    songplays_table = artists_songs_logs.join(
                      times_table, artists_songs_logs.timestamp == times_table.start_time, "left"
                      ).drop(artists_songs_logs.year)

    songplays_table = songplays_table.select(
        col("start_time"),
        col("userId").alias("user_id"),
        col("level"),
        col("song_id"),
        col("artist_id"),
        col("sessionId").alias("session_id"),
        col("location"),
        col("userAgent").alias("user_agent"),
        col("year"),
        col("month")
    ).repartition("year", "month")

    # write songplays table to parquet files partitioned by year and month
    songplays_table.write.partitionBy("year", "month").parquet(output_data + "songplays")

def main():
    spark = create_spark_session()
    input_data = "s3a://udacity-dend/"
    output_data = ""

    process_song_data(spark, input_data, output_data)
    process_log_data(spark, input_data, output_data)

if __name__ == "__main__":
    main()


'''faca um programa que receba o salario base de um funcionario, calcule e mostre o salario a receber, sabendo que esse funcionario
tem gratificacao de 50,00 e paga imposto de 10% sobre o salario base'''

salariob=0.0
salariof=0.0
imposto=0.0

salariob=float(input("Informe o salario base: "))
imposto=salariob*10/100
salariof=salariob-imposto+50

print(f"O salario a receber é: {salariof}")


from csv import DictWriter
from copy import deepcopy
from collections import Counter

CODE_TO_NAME = {
    "1.1": "Alluvial_Fan",
    "1.2": "Fluvial_Channel",
    "1.3": "Fluvial_Point_Bar",
    "1.4": "Levee",
    "1.5": "Crevasse_Splay",
    "1.6": "Fluvial_Floodplain",
    "2.1": "Progradational_Lacustrine_Delta",
    "2.2": "Lacustrine_Fan_Delta",
    "2.3": "Progradational_Lacustrine_Shoreface",
    "2.4": "Transgressive_Lacustrine_Shoreface",
    "2.5": "Aggradational_Lacustrine_Shoreface",
    "2.6": "Lacustrine_Offshore_Transition",
    "2.7": "Lacustrine_Shelf",
    "3.1": "Proximal_Sub-Lacustrine_Fan",
    "3.2": "Distal_Sub-Lacustrine_Fan",
    "3.3": "Lacustrine_Turbidite",
    "3.4": "Distal_Lacustrine_Turbidites",
    "3.5": "Lacustrine_Deepwater",
    "4.1": "Marine_Delta",
    "4.2": "Marine_Fan_Delta",
    "4.3": "Tidal_Channel_And_Sand_Flat",
    "4.4": "Sandy_Tidal_Flat",
    "4.5": "Mixed_Tidal_Flat",
    "4.6": "Muddy_Tidal_Flat",
    "4.7": "Lagoon",
    "5.1": "Progradational_Marine_Shoreface",
    "5.2": "Transgressive_Marine_Shoreface",
    "5.3": "Aggradational_Marine_Shoreface",
    "5.4": "Marine_Offshore_Transition",
    "5.5": "Marine_Shelf",
    "6.1": "Proximal_Submarine_Fan",
    "6.2": "Distal_Submarine_Fan",
    "6.3": "Marine_Turbidite",
    "6.4": "Distal_Marine_Turbidites",
    "6.5": "Marine_Deepwater"
}

GROUP_TO_FACIES = {
    "Fluvial": ["1.1", "1.2", "1.3", "1.4", "1.5", "1.6"],
    "Shallow_Lacustrine": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7"],
    "Deep_Lacustrine": ["3.1", "3.2", "3.3", "3.4", "3.5"],
    "Marginal_Marine": ["4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7"],
    "Shallow_Marine": ["5.1", "5.2", "5.3", "5.4", "5.5"],
    "Deep_Marine": ["6.1", "6.2", "6.3", "6.4", "6.5"]
}

NAMES = [
    "Alluvial_Fan",
    "Fluvial_Channel",
    "Fluvial_Point_Bar",
    "Levee",
    "Crevasse_Splay",
    "Fluvial_Floodplain",
    "Progradational_Lacustrine_Delta",
    "Lacustrine_Fan_Delta",
    "Progradational_Lacustrine_Shoreface",
    "Transgressive_Lacustrine_Shoreface",
    "Aggradational_Lacustrine_Shoreface",
    "Lacustrine_Offshore_Transition",
    "Lacustrine_Shelf",
    "Proximal_Sub-Lacustrine_Fan",
    "Distal_Sub-Lacustrine_Fan",
    "Lacustrine_Turbidite",
    "Distal_Lacustrine_Turbidites",
    "Lacustrine_Deepwater",
    "Marine_Delta",
    "Marine_Fan_Delta",
    "Tidal_Channel_And_Sand_Flat",
    "Sandy_Tidal_Flat",
    "Mixed_Tidal_Flat",
    "Muddy_Tidal_Flat",
    "Lagoon",
    "Progradational_Marine_Shoreface",
    "Transgressive_Marine_Shoreface",
    "Aggradational_Marine_Shoreface",
    "Marine_Offshore_Transition",
    "Marine_Shelf",
    "Proximal_Submarine_Fan",
    "Distal_Submarine_Fan",
    "Marine_Turbidite",
    "Distal_Marine_Turbidites",
    "Marine_Deepwater"
]

OUTPUT = [
    "Most_likely_facies",
    "Most_Prob",
    "Second_most_likely_facies",
    "Second_Most_Prob",
    "Third_most_likely_facies",
    "Third_Most_Prob",
    "Uncertainty_flag",

]

OUTPUT_NUMPY_FORMAT = [
    "Lithofacies_major",
    "GR_shape_code",
    "Stacking_pattern",
]

OUTPUT.extend(NAMES)

GROUPS = [
    "Fluvial",
    "Shallow_Lacustrine",
    "Deep_Lacustrine",
    "Marginal_Marine",
    "Shallow_Marine",
    "Deep_Marine"
]

UNDEFINED = -1

def convert_name_to_number(data):
    tmp = deepcopy(CODE_TO_NAME)
    tmp.update({"0": "unknown"})
    for row in data:
        for key, value in row.items():
            if value in tmp.values():
                code = list(tmp.keys())[list(tmp.values()).index(value)]
                row.update({key: code})

def remove_duplicate(arr):
    arr.sort()
    i = 0
    while i < len(arr) - 1:
        if arr[i] == arr[i + 1]:
            arr.pop(i)
            i -= 1
        i += 1
    return arr

def map_core_depofacies_code_to_name(code):
    try:
        return CODE_TO_NAME[str(code)]
    except KeyError:
        return None

def get_group_depofacies(name):
    try:
        return GROUP_TO_FACIES[name]
    except KeyError:
        return None

def get_group_name(facy_name):
    facy_code = None
    for key, item in CODE_TO_NAME.items():
        if item == facy_name:
            facy_code = key

    for key, item in GROUP_TO_FACIES.items():
        if facy_code in item:
            return key

def get_max_by_key(key, data):
    lst = []
    max_value = 0
    for item in data:
        if int(item[key]) > max_value:
            max_value = item[key]
    for item in data:
        if int(item[key]) == max_value:
            lst.append(item)
    return lst

def update_row_group(group_name, row, point):
    for depofacy in get_group_depofacies(group_name):
        name = map_core_depofacies_code_to_name(depofacy)
        if int(row[name]) > 0:
            if point == "x":
                row.update({name: 0})
            else:
                row.update({name: handle_addition(int(row[name]) + point)})

def get_key(lst, i):
    return [key for key in lst[i].keys()][0]

def parse_slash(str):
    if "/" in str:
        return str.split("/")[0]
    return str

def calculate_uncertainty(row):
    if len(row["Special_lithology"]) > 0:
        return 4

    if int(row["Sum"]) == 0:
        return 3

    if row["Most_likely_facies"] and row[parse_slash(row["Most_likely_facies"])] < 0.3:
        return 1

    if row["Second_most_likely_facies"] and row[parse_slash(row["Most_likely_facies"])] - row[
        parse_slash(row["Second_most_likely_facies"])] < 0.1:
        return 2

    return 0

def update_name(lst):
    names = []

    if len(lst) == 1:
        for i in range(3):
            names.append({"curve": lst[0]["name"], "prob": lst[0]["point"]})

    elif len(lst) == 2:
        if lst[0]["point"] > lst[1]["point"]:
            for i in range(2):
                names.append({"curve": lst[0]["name"], "prob": lst[0]["point"]})
            names.append({"curve": lst[1]["name"], "prob": lst[1]["point"]})

        else:
            for i in range(3):
                names.append({"curve": lst[0]["name"] + "/" + lst[1]["name"], "prob": lst[0]["point"]})

    elif len(lst) >= 3:
        i = 0
        while i < len(lst):
            prob = 0
            tmp = 0
            res = ""
            while i + tmp < len(lst) - 1 and lst[i + tmp]["point"] == lst[i + tmp + 1]["point"]:
                tmp += 1
            for j in range(i, i + tmp + 1):
                res += lst[j]["name"]
                if j < i + tmp:
                    res += "/"
                prob = lst[j]["point"]
            if tmp == 0:
                names.append({"curve": lst[i]["name"], "prob": prob})
            else:
                for t in range(tmp + 1):
                    names.append({"curve": res, "prob": prob})
            i += tmp + 1
    return names

def convert_data(data):
    curve = ["Most_likely_facies", "Second_most_likely_facies", "Third_most_likely_facies"]
    prob = ["Most_Prob", "Second_Most_Prob", "Third_Most_Prob"]

    for row in data:
        total = 0
        for key, value in CODE_TO_NAME.items():
            total += int(row[value])
        row.update({"Sum": total})

    for row in data:
        for key, value in CODE_TO_NAME.items():
            if int(row["Sum"]) != 0:
                row.update({value: row[value] / row["Sum"]})

    for row in data:
        lst = []
        for key, value in CODE_TO_NAME.items():
            if row[value] != 0:
                lst.append({"name": value, "point": row[value]})
        lst = sorted(lst, key=lambda it: it["point"], reverse=True)
        lst = update_name(lst)

        for i in range(len(curve)):
            if len(lst) > i:
                if len(row["Special_lithology"]) > 0:
                    row.update({curve[i]: "", prob[i]: ""})
                else:
                    row.update({curve[i]: lst[i]["curve"], prob[i]: lst[i]["prob"]})
            else:
                row.update({curve[i]: "Indeterminate", prob[i]: 0})

    for row in data:
        row.update({"Uncertainty_flag": calculate_uncertainty(row)})

    # convert_name_to_number(data)

def convert_sample_by_sample(data, initial_data):
    final = []
    for row in initial_data:
        for key in data[row["Unit_index"]].keys():
            if key in OUTPUT_NUMPY_FORMAT or key in ["Unit_index"]:
                row.update({key: int(data[row["Unit_index"]][key])})
            elif key in OUTPUT:
                row.update({key: data[row["Unit_index"]][key]})
            elif key == "Boundary_flag":
                row.update({key: int(row[key])})

        final.append(row)
    return final

def export_to_csv(data, filename):
    headers = []
    for row in data:
        for key in row.keys():
            if key not in headers:
                headers.append(key)
    with open(filename, "w") as o_file:
        csv_writer = DictWriter(o_file, fieldnames=headers)
        csv_writer.writeheader()
        for row in data:
            csv_writer.writerow(row)

def pick_most(data):
    if len(data) == 0:
        return UNDEFINED
    return sorted(data, key=Counter(data).get, reverse=True)[0]

def handle_addition(point):
    return point if int(point) >= 0 else 0

def simplify_data(data):
    core_depofacies = []
    biostrats = []
    reliabilities = []
    laterals = []
    special_lithologies = []
    mls = []

    simplified_data = []

    for row in data:
        if row["Core_depofacies"] != UNDEFINED:
            core_depofacies.append(row["Core_depofacies"])

        if row["Reliability"] != UNDEFINED:
            reliabilities.append(row["Reliability"])

        if row["Biostratigraphy"] != UNDEFINED:
            biostrats.append(row["Biostratigraphy"])

        if row["Special_lithology"] != UNDEFINED:
            special_lithologies.append(row["Special_lithology"])

        if row["Lateral_proximity"] != UNDEFINED:
            laterals.append(row["Lateral_proximity"])

        if row["ML"] != UNDEFINED:
            mls.append(row["ML"])

        if row["Boundary_flag"] == 1:
            depo = pick_most(core_depofacies)
            biostrat = pick_most(biostrats)
            reliability = pick_most(reliabilities)
            lateral = pick_most(laterals)
            lithos = remove_duplicate(deepcopy(special_lithologies))
            ml = pick_most(mls)

            row.update({"Special_lithology": lithos})

            row.update({"Core_depofacies": depo})

            row.update({"Biostratigraphy": biostrat})

            row.update({"Reliability": reliability})

            row.update({"Lateral_proximity": lateral})

            row.update({"ML": ml})

            simplified_data.append(deepcopy(row))

            core_depofacies.clear()
            special_lithologies.clear()
            biostrats.clear()
            laterals.clear()
            reliabilities.clear()
            mls.clear()

    return simplified_data


#program to print fibonacci series using while loop
n=int(input("Enter the limit:"))
f1=0
f2=1
if n==1:
	print(f1)
elif n==2:
	print(f1,f2)
elif n<=0:
	print("No Series")
else:
	print(f1,end=" ")
	print(f2,end =" ")
	i=2
	while n>i:
		f3=f1+f2
		print(f3,end=" ")
		f1=f2
		f2=f3
		i=i+1