# -*- coding: utf-8 -*-

import scrapy
from bs4 import BeautifulSoup
import re
import traceback
from pokemons.items import PokemonsItem

class pokemonsSpider(scrapy.Spider):
    '''
    定义一个继承自 scrapy.Spider 的类，用于爬虫
    '''
    # 用于在 terminal 中执行 scrapy 爬虫命令的标示
    name = 'pokemons'

    # 爬取的链接
    start_urls = [
        'https://wiki.52poke.com/wiki/宝可梦列表（按全国图鉴编号）/简单版'
    ]

    # scrapy 输出设置
    custom_settings = {
        'LOG_LEVEL': 'ERROR' # 只显示错误信息
    }

    # 解析网页
    def parse(self, response):
        '''
        解析初始网页
        '''
        # 爬虫获取到的 url 为相对链接
        # 因此定义一个 domain name
        domain = 'https://wiki.52poke.com'
        # 此处的 response 是 start_urls 中返回的数据
        soup = BeautifulSoup(response.body, 'html.parser')
        tags = soup.find_all(class_='mw-redirect',
                             href=re.compile(r'/wiki/\w.*'))
        for tag in tags:
            # 每个 Pokemon 详情界面的 url
            url = (domain+tag.get('href'))
            yield scrapy.Request(url, callback=self.parse_details)

    def parse_details(self, response):
        '''
        解析详情网页
        '''
        # 此处的 response 是 Pokemon 详情界面返回的数据
        soup = BeautifulSoup(response.body, 'html.parser')
        # 返回一个 ResultSet（list）
        base_info_tables = soup.find_all('table',
                                        class_=re.compile('roundy a-r at-c'))
        # 获取 ResultSet 中的第一个元素
        base_info_table = base_info_tables[0]
        # 获取所有 tr 节点
        base_info_trs = base_info_table.find_all('tr')

        # 获取 Pokemon 的种族值信息
        stats_info_table = soup.find_all('table',
                            class_=re.compile('roundy alignt-center'))[0]
        stats_info_trs = stats_info_table.find_all('tr')

        # 获取 Pokemon 的属性相克信息
        against_info_table = soup.find_all(class_="bgwhite bw-1 bd-变化")[0].parent
        against_info_tds = against_info_table.find_all('td')

        try:
            # 获取 Pokemon 中文名字
            chinese_name = self.extract_chinese_name(base_info_trs)
            if chinese_name is None:
                raise Exception('Pokemon Chinese name not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 英文名字
            english_name = self.extract_english_name(base_info_trs)
            if english_name is None:
                raise Exception('Pokemon English name not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 序号
            pokdex = self.extract_pokdex(base_info_trs, soup)
            if pokdex is None:
                raise Exception('Pokemon index not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 属性
            type_1, type_2 = self.extract_types(base_info_trs)
            if type_1 is None:
                raise Exception('Pokemon Type 1 not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 分类
            category = self.extract_category(base_info_trs)
            if category is None:
                raise Exception('Pokemon category not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 特性
            ability_1, ability_2 = self.extract_abilities(base_info_trs)
            if ability_1 is None:
                raise Exception('Pokemon Ability 1 not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 100级时的经验值
            exp_100 = self.extract_exp_100(base_info_trs)
            if exp_100 is None:
                raise Exception('Pokemon Experience not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 身高
            height_m = self.extract_height(base_info_trs)
            if height_m is None:
                raise Exception('Pokemon Height not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 100级时的经验值
            weight_kg = self.extract_weight(base_info_trs)
            if weight_kg is None:
                raise Exception('Pokemon Weight not found for {}'\
                    .format(response.url))

            # 获取 普通的精灵球在 Pokemon 满体力下的捕获率
            catch_rate = self.extract_catch_rate(base_info_trs)
            if catch_rate is None:
                raise Exception('Pokemon Catch Rate not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 是 male 的比例
            male_ratio = self.extract_male_ratio(base_info_trs)
            if male_ratio is None:
                raise Exception('Pokemon Male Ratio not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 孵化步数
            hatch_time = self.extract_hatch_time(base_info_trs)
            if hatch_time is None:
                raise Exception('Pokemon Hatch Time not found for {}'\
                    .format(response.url))

            # 获取 Pokemon HP
            hp = self.extract_hp(stats_info_trs)
            if hp is None:
                raise Exception('Pokemon HP not found for {}'\
                    .format(response.url))

            # 获取 Pokemon attack
            atk = self.extract_atk(stats_info_trs)
            if atk is None:
                raise Exception('Pokemon Attack not found for {}'\
                    .format(response.url))

            # 获取 Pokemon HP
            defense = self.extract_def(stats_info_trs)
            if defense is None:
                raise Exception('Pokemon Defense not found for {}'\
                    .format(response.url))

            # 获取 Pokemon special attack
            spatk = self.extract_spatk(stats_info_trs)
            if spatk is None:
                raise Exception('Pokemon Special Attack not found for {}'\
                    .format(response.url))

            # 获取 Pokemon special defense
            spdef = self.extract_spdef(stats_info_trs)
            if spdef is None:
                raise Exception('Pokemon Special Defense not found for {}'\
                    .format(response.url))

            # 获取 Pokemon Speed
            speed = self.extract_speed(stats_info_trs)
            if speed is None:
                raise Exception('Pokemon Speed not found for {}'\
                    .format(response.url))

            # 获取 Pokemon total
            total = self.extract_total(stats_info_trs)
            if total is None:
                raise Exception('Pokemon Total not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 世代
            generation = self.extract_generation(soup)
            if generation is None:
                raise Exception('Pokemon Generation not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 图片链接
            image_url = self.extract_image_url(base_info_trs)
            image_urls = []
            image_urls.append(image_url)
            if image_url is None:
                raise Exception('Pokemon Image URL not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 一般 属性的抗性
            against_normal = self.extract_against_norml(against_info_tds, soup)
            if against_normal is None:
                raise Exception('Pokemon Against Normal not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 格斗 属性的抗性
            against_fight = self.extract_against_fight(against_info_tds)
            if against_fight is None:
                raise Exception('Pokemon Against Fight not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 飞行 属性的抗性
            against_flying = self.extract_against_flying(against_info_tds)
            if against_flying is None:
                raise Exception('Pokemon Against Flying not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 毒 属性的抗性
            against_poison = self.extract_against_poison(against_info_tds)
            if against_poison is None:
                raise Exception('Pokemon Against Poison not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 地面 属性的抗性
            against_ground = self.extract_against_ground(against_info_tds)
            if against_ground is None:
                raise Exception('Pokemon Against Ground not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 岩石 属性的抗性
            against_rock = self.extract_against_rock(against_info_tds)
            if against_rock is None:
                raise Exception('Pokemon Against Rock not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 虫 属性的抗性
            against_bug = self.extract_against_bug(against_info_tds)
            if against_bug is None:
                raise Exception('Pokemon Against Bug not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 幽灵 属性的抗性
            against_ghost = self.extract_against_ghost(against_info_tds)
            if against_ghost is None:
                raise Exception('Pokemon Against Ghost not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 钢 属性的抗性
            against_steel = self.extract_against_steel(against_info_tds)
            if against_steel is None:
                raise Exception('Pokemon Against Steel not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 火 属性的抗性
            against_fire = self.extract_against_fire(against_info_tds)
            if against_fire is None:
                raise Exception('Pokemon Against Fire not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 水 属性的抗性
            against_water = self.extract_against_water(against_info_tds)
            if against_water is None:
                raise Exception('Pokemon Against Water not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 草 属性的抗性
            against_grass = self.extract_against_grass(against_info_tds)
            if against_grass is None:
                raise Exception('Pokemon Against Grass not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 电 属性的抗性
            against_electric = self.extract_against_electric(against_info_tds)
            if against_electric is None:
                raise Exception('Pokemon Against Electric not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 超能力 属性的抗性
            against_psychic = self.extract_against_psychic(against_info_tds)
            if against_psychic is None:
                raise Exception('Pokemon Against Psychic not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 冰 属性的抗性
            against_ice = self.extract_against_ice(against_info_tds)
            if against_ice is None:
                raise Exception('Pokemon Against Ice not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 龙 属性的抗性
            against_dragon = self.extract_against_dragon(against_info_tds)
            if against_dragon is None:
                raise Exception('Pokemon Against Dragon not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 恶 属性的抗性
            against_dark = self.extract_against_dark(against_info_tds)
            if against_dark is None:
                raise Exception('Pokemon Against Dark not found for {}'\
                    .format(response.url))

            # 获取 Pokemon 对 妖精 属性的抗性
            against_fairy = self.extract_against_fairy(against_info_tds)
            if against_fairy is None:
                raise Exception('Pokemon Against Fairy not found for {}'\
                    .format(response.url))

            # 保存成 item 以存储至 mongodb
            pokemon_item = PokemonsItem(_id=pokdex, chinese_name=chinese_name,
                                        english_name=english_name,
                                        type_1=type_1, type_2=type_2,
                                        category=category,
                                        ability_1=ability_1, ability_2=ability_2,
                                        exp_100=exp_100, height_m=height_m,
                                        weight_kg=weight_kg,
                                        catch_rate=catch_rate,
                                        male_ratio=male_ratio,
                                        hatch_time=hatch_time, hp=hp, atk=atk,
                                        defense=defense,  spatk=spatk,
                                        spdef=spdef, speed=speed,
                                        total=total, generation=generation,
                                        image_urls=image_urls,
                                        against_normal=against_normal,
                                        against_fight=against_fight,
                                        against_flying=against_flying,
                                        against_poison=against_poison,
                                        against_ground=against_ground,
                                        against_rock=against_rock,
                                        against_bug=against_bug,
                                        against_ghost=against_ghost,
                                        against_steel=against_steel,
                                        against_fire=against_fire,
                                        against_water=against_water,
                                        against_grass=against_grass,
                                        against_electric=against_electric,
                                        against_psychic=against_psychic,
                                        against_ice=against_ice,
                                        against_dragon=against_dragon,
                                        against_dark=against_dark,
                                        against_fairy=against_fairy)

            yield pokemon_item

        except Exception as err:
            self.logger.error(str(err))
            self.logger.error(traceback.format_exc())

    @staticmethod
    def extract_chinese_name(trs):
        '''
        提取 Pokemon 中文名字
        '''
        return trs[0].find_all('b')[0].text

    @staticmethod
    def extract_english_name(trs):
        '''
        提取 Pokemon 英文名字
        '''
        return trs[0].find_all('b')[-1].text

    @staticmethod
    def extract_pokdex(trs, soup):
        '''
        提取 Pokemon 序号
        '''
        return re.findall(r'\d{3}', trs[0].text)[0]

    @staticmethod
    def extract_types(trs):
        '''
        提取 Pokemon 属性
        '''
        types = types = trs[6].text.strip().split('\xa0\xa0')
        if len(types) == 2: # 如果该 Pokemon 有两种属性
            # 返回两种属性
            return types[0], types[1]
        else:
            # 返回一种属性
            return types[0], None

    @staticmethod
    def extract_category(trs):
        '''
        提取 Pokemon 类别
        '''
        if len(trs) == 62: # 基格尔德
            return trs[9].text.strip()
        return trs[8].text.strip()

    @staticmethod
    def extract_abilities(trs):
        '''
        提取 Pokemon 特性
        '''
        abilities = trs[11].text.strip().replace('\xa0', ' ').split('\n\n')
        if len(abilities) == 2: # 如果该 Pokemon 有两种特性
            # 返回两种特性
            return abilities[0], abilities[1]
        else:
            # 返回一种特性
            return abilities[0], None

    @staticmethod
    def extract_exp_100(trs):
        '''
        提取 Pokemon 100级时的经验值
        '''
        if len(trs) == 60:
            return trs[13].text.strip()
        elif len(trs) == 62: # 基格尔德
            return trs[15].text.strip()
        return trs[14].text.strip()

    @staticmethod
    def extract_height(trs):
        '''
        提取 Pokemon 身高（m）
        '''
        if len(trs) == 60:
            return re.findall(r'\d.\d', trs[31].text.strip())[0]
        if len(trs) == 62: # 基格尔德
            return 0
        return re.findall(r'\d.\d', trs[32].text.strip())[0]

    @staticmethod
    def extract_weight(trs):
        '''
        提取 Pokemon 体重（kg）
        '''
        if len(trs) == 60:
            return re.findall(r'\d.\d', trs[33].text.strip())[0]
        if len(trs) == 62: # 基格尔德
            return 0
        return re.findall(r'\d.\d', trs[34].text.strip())[0]

    @staticmethod
    def extract_catch_rate(trs):
        '''
        提取 普通的精灵球在 Pokemon 满体力下的捕获率
        '''
        if len(trs) == 60:
            return trs[43].find('span').text
        return trs[44].find('span').text

    @staticmethod
    def extract_male_ratio(trs):
        '''
        提取 Pokemon 是 male 的比例
        '''
        if len(trs) == 60:
            if trs[48].find('span'):
                return re.findall(r'[\d.\d]*%', trs[48].find('span').text)[0]
            else:
                return trs[48].text.strip()
        elif len(trs) == 61:
            if trs[49].find('span'):
                return re.findall(r'[\d.\d]*%', trs[49].find('span').text)[0]
            else:
                return trs[49].text.strip()
        else: # 基格尔德
            return trs[50].text.strip()

    @staticmethod
    def extract_hatch_time(trs):
        '''
        提取 Pokemon 的孵化步数
        '''
        if len(trs) == 60:
            return re.findall(r'[\d]*步', trs[51].find_all('td')[-1].text)[0]
        return re.findall(r'[\d]*步', trs[52].find_all('td')[-1].text)[0]

    @staticmethod
    def extract_hp(trs):
        '''
        提取 Pokemon hp
        '''
        return trs[3].find_all('th', class_='bgl-HP')[-1].text.strip()

    @staticmethod
    def extract_atk(trs):
        '''
        提取 Pokemon attack
        '''
        return trs[5].find_all('th', class_='bgl-攻击')[-1].text.strip()

    @staticmethod
    def extract_def(trs):
        '''
        提取 Pokemon defense
        '''
        return trs[7].find_all('th', class_='bgl-防御')[-1].text.strip()

    @staticmethod
    def extract_spatk(trs):
        '''
        提取 Pokemon special attack
        '''
        return trs[9].find_all('th', class_='bgl-特攻')[-1].text.strip()

    @staticmethod
    def extract_spdef(trs):
        '''
        提取 Pokemon special defense
        '''
        return trs[11].find_all('th', class_='bgl-特防')[-1].text.strip()

    @staticmethod
    def extract_speed(trs):
        '''
        提取 Pokemon speed
        '''
        return trs[13].find_all('th', class_='bgl-速度')[-1].text.strip()

    @staticmethod
    def extract_total(trs):
        '''
        提取 Pokemon 种族值总值
        '''
        return re.findall(r'\d{3}', trs[15].text)[0].strip()

    @staticmethod
    def extract_generation(soup):
        '''
        提取 Pokemon 世代
        '''
        catlinks = soup.find(class_='mw-normal-catlinks')
        return re.search(r'第[\u4e00-\u9fa5]世代寶可夢', catlinks.text)[0]

    @staticmethod
    def extract_image_url(trs):
        '''
        提取 Pokemon 图片链接
        '''
        domain = 'https://'
        try:
            relative_url = re.findall(r'media.*png', trs[3]\
                .find('img').get('data-srcset').split(',')[-1])[0]
        except:
            relative_url = trs[3].find('img').get('data-url')

        img_url = domain + relative_url
        # self.img_urls.append(img_url)
        return img_url

    @staticmethod
    def extract_against_norml(tds, soup):
        '''
        提取 Pokemon 对 一般 属性的抗性
        '''
        if tds[3]:
            return tds[3].text.strip()

    @staticmethod
    def extract_against_fight(tds):
        '''
        提取 Pokemon 对 格斗 属性的抗性
        '''
        if tds[4]:
            return tds[4].text.strip()

    @staticmethod
    def extract_against_flying(tds):
        '''
        提取 Pokemon 对 飞行 属性的抗性
        '''
        if tds[5]:
            return tds[5].text.strip()

    @staticmethod
    def extract_against_poison(tds):
        '''
        提取 Pokemon 对 毒 属性的抗性
        '''
        if tds[6]:
            return tds[6].text.strip()

    @staticmethod
    def extract_against_ground(tds):
        '''
        提取 Pokemon 对 地面 属性的抗性
        '''
        if tds[7]:
            return tds[7].text.strip()

    @staticmethod
    def extract_against_rock(tds):
        '''
        提取 Pokemon 对 岩石 属性的抗性
        '''
        if tds[8]:
            return tds[8].text.strip()

    @staticmethod
    def extract_against_bug(tds):
        '''
        提取 Pokemon 对 虫 属性的抗性
        '''
        if tds[9]:
            return tds[9].text.strip()

    @staticmethod
    def extract_against_ghost(tds):
        '''
        提取 Pokemon 对 幽灵 属性的抗性
        '''
        if tds[10]:
            return tds[10].text.strip()

    @staticmethod
    def extract_against_steel(tds):
        '''
        提取 Pokemon 对 钢 属性的抗性
        '''
        if tds[11]:
            return tds[11].text.strip()

    @staticmethod
    def extract_against_fire(tds):
        '''
        提取 Pokemon 对 火 属性的抗性
        '''
        if tds[12]:
            return tds[12].text.strip()

    @staticmethod
    def extract_against_water(tds):
        '''
        提取 Pokemon 对 水 属性的抗性
        '''
        if tds[13]:
            return tds[13].text.strip()

    @staticmethod
    def extract_against_grass(tds):
        '''
        提取 Pokemon 对 草 属性的抗性
        '''
        if tds[14]:
            return tds[14].text.strip()

    @staticmethod
    def extract_against_electric(tds):
        '''
        提取 Pokemon 对 电 属性的抗性
        '''
        if tds[15]:
            return tds[15].text.strip()

    @staticmethod
    def extract_against_psychic(tds):
        '''
        提取 Pokemon 对 超能力 属性的抗性
        '''
        if tds[16]:
            return tds[16].text.strip()

    @staticmethod
    def extract_against_ice(tds):
        '''
        提取 Pokemon 对 冰 属性的抗性
        '''
        if tds[17]:
            return tds[17].text.strip()

    @staticmethod
    def extract_against_dragon(tds):
        '''
        提取 Pokemon 对 龙 属性的抗性
        '''
        if tds[18]:
            return tds[18].text.strip()

    @staticmethod
    def extract_against_dark(tds):
        '''
        提取 Pokemon 对 恶 属性的抗性
        '''
        if tds[19]:
            return tds[19].text.strip()

    @staticmethod
    def extract_against_fairy(tds):
        '''
        提取 Pokemon 对 妖精 属性的抗性
        '''
        if tds[20]:
            return tds[20].text.strip()


import os
import sys
import stat
import torch
import numpy as np
from sklearn.metrics import classification_report

def rename(path):
    '''
    outputs of ais_bench end with "_0.txt",
    it would cause outputs files can not match label files,
    rename and remove "_0" could fix it.
    '''
    file_names = os.listdir(path)
    for file_name in file_names:
        if not file_name.endswith('.txt'):
            continue
        idx = file_name.split('_')[0]
        src_path = os.path.join(path, file_name)
        dist_path = os.path.join(path, idx + '.txt')
        os.rename(src_path, dist_path)

def load_output_to_results(path):
    file_names = os.listdir(path)
    results = []
    for file_name in file_names:
        if not file_name.endswith('.txt'):
            continue
        file_name = os.path.join(path, file_name)
        with open(file_name) as f:
            for l in f:
                data = list(map(float, l.strip().split()))
                pred = torch.tensor(data).argmax(axis=-1).cpu().numpy()
                results.append(int(pred))

    return results

def load_labels(path):
    file_names = os.listdir(path)
    labels = []
    for file_name in file_names:
        file_name = os.path.join(path, file_name)
        with open(file_name) as f:
            for l in f:
                data = l.strip()
                labels.append(int(data))

    return labels

if __name__ == '__main__':
    output_path, label_path = sys.argv[1], sys.argv[2]
    rename(output_path)
    preds = load_output_to_results(output_path)
    true_labels = load_labels(label_path)
    eval_result = classification_report(true_labels,
                                        preds,
                                        digits=4)
    print(f'Results: {eval_result}')
    flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
    modes = stat.S_IWUSR | stat.S_IRUSR
    with os.fdopen(os.open('result.txt', flags, modes), 'w') as main_f:
        main_f.write(eval_result)


from datetime import datetime
import json
from time import sleep
from typing import Dict, List, Optional, Tuple, Union
from threading import Event, Thread
from argparse import ArgumentParser

import asyncio
import auraxium
from auraxium import ps2
import random

from constants import Team, Classes, MetagameEventType, MetagameEventState, Faction, Vehicles, VEHICLE_WEAPONS, World
from dataclass import OutfitwarsInstance, Outfit, Teams
from events import MetagameEvent, DeathEvent, FacilityControlEvent, VehicleDestroyEvent
from service import get_rabbit, RabbitConnection, RabbitService, Logger
from state import NexusMap
from replay import MetagameReplayEvent, FacilityControlReplayEvent, DeathReplayEvent, VehicleDestroyReplayEvent

logger = Logger.getLogger("Match")

#BLUE_OUTFIT = 37571208657592881 # [HMRD]
#RED_OUTFIT = 37570391403474491  # [UN17]
MAX_CAPTURES = 20

VS_WEAPON = 80   # Orion
NC_WEAPON = 7169 # GD-7F
TR_WEAPON = 7254 # MSW-R
NSO_WEAPON = 6009899 # XMG-100

weapons = {
    Faction.VS: VS_WEAPON,
    Faction.NC: NC_WEAPON,
    Faction.TR: TR_WEAPON,
    Faction.NSO: NSO_WEAPON
}

tiebreaker_points = { Team.RED: 0, Team.BLUE: 0 }
tbpool = 500

def tiebreaker_worker(interval: float, nexus: NexusMap) -> Tuple[Thread, Event]:
    stop = Event()
    def work():
        global tiebreaker_points, tbpool
        while not stop.wait(interval):
            for team in tiebreaker_points:
                points = nexus.count(team) * 2
                if points > tbpool:
                    points = tbpool
                tiebreaker_points[team] += points
                tbpool -= points
    thread = Thread(target=work)
    return thread, stop

def vehicle_destroy_worker(
        interval: float,
        event: OutfitwarsInstance,
        players: Dict[int, List[int]] = {
            37571208657592881: [5428085259783352737],
            37570391403474491: [5428297992006446465, 5428985062301123025]
        },
        delay: float = 0
    ) -> Tuple[Thread, Event]:
    stop = Event()
    def work():
        global weapons
        sleep(delay)
        vehicle_destroy_queue = f'aggregator-outfitwars-{event.world}-{event.zone}-{event.censusInstanceId}-VehicleDestroy'
        thread_rabbit = RabbitService(RabbitConnection())
        while not stop.wait(interval):
            attackerOutfitId = random.choice(list(players.keys()))
            victimOutfitId = random.choice(list(players.keys()))
            i = 0
            while attackerOutfitId == victimOutfitId and i < 5: # 0.5^5 == 3.125% tk rate
                victimOutfitId = random.choice(list(players.keys()))
                i += 1
            attackerOutfit = event.teams.red if event.teams.red.id == attackerOutfitId else event.teams.blue
            attacker = random.choice(players[attackerOutfitId])
            attackerVehicle = random.choice([0, *Vehicles.by_faction(attackerOutfit.faction)])
            if attackerVehicle != 0:
                attackerWeapon = VEHICLE_WEAPONS[attackerVehicle][attackerOutfit.faction]
            else:
                attackerWeapon = weapons[attackerOutfit.faction]
            victimOutfit = event.teams.red if event.teams.red.id == victimOutfitId else event.teams.blue
            victim = random.choice(players[victimOutfitId])
            victimVehicle = random.choice(Vehicles.by_faction(victimOutfit.faction))
            vehicleDestroy = VehicleDestroyEvent(
                world_id=str(int(event.world)),
                attacker_character_id=str(attacker),
                attacker_loadout_id=str(int(random.choice(Classes.by_faction(attackerOutfit.faction)))),
                attacker_team_id='2' if attackerOutfitId == event.teams.blue.id else '3',
                attacker_vehicle_id=str(attackerVehicle),
                attacker_weapon_id=str(attackerWeapon),
                character_id=str(victim),
                faction_id=str(int(victimOutfit.faction)),
                team_id='2' if victimOutfitId == event.teams.blue.id else '3',
                vehicle_id=str(victimVehicle),
                zone_id=(int(event.zoneInstanceId) << 16) | int(event.zone),
            )
            thread_rabbit.send(vehicleDestroy, vehicle_destroy_queue)
    thread = Thread(target=work)
    return thread, stop

def death_worker(
        interval: float,
        event: OutfitwarsInstance,
        players: Dict[int, List[int]] = {
            37571208657592881: [5428085259783352737],
            37570391403474491: [5428297992006446465, 5428985062301123025]
        },
        delay: float = 0
    ) -> Tuple[Thread, Event]:
    stop = Event()
    def work():
        global weapons
        sleep(delay)
        death_queue = f'aggregator-outfitwars-{event.world}-{event.zone}-{event.censusInstanceId}-Death'
        thread_rabbit = RabbitService(RabbitConnection())
        #players = [BLUE_PLAYER, RED_PLAYER, NSO_RED_PLAYER]
        while not stop.wait(interval):
            attackerOutfitId = random.choice(list(players.keys()))
            victimOutfitId = random.choice(list(players.keys()))
            i = 0
            while attackerOutfitId == victimOutfitId and i < 5: # 0.5^5 == 3.125% tk rate
                victimOutfitId = random.choice(list(players.keys()))
                i += 1
            attackerOutfit = event.teams.red if event.teams.red.id == attackerOutfitId else event.teams.blue
            attacker = random.choice(players[attackerOutfitId])
            victimOutfit = event.teams.red if event.teams.red.id == victimOutfitId else event.teams.blue
            victim = random.choice(players[victimOutfitId])
            death = DeathEvent(
                attacker_character_id=str(attacker),
                attacker_loadout_id=str(int(random.choice(Classes.by_faction(attackerOutfit.faction)))),
                attacker_weapon_id=str(weapons[attackerOutfit.faction]),
                attacker_team_id='2' if attackerOutfitId == event.teams.blue.id else '3',
                character_id=str(victim),
                character_loadout_id=str(int(random.choice(Classes.by_faction(victimOutfit.faction)))),
                is_headshot=str(1 if random.random() < 0.25 and attacker != victim else 0),
                team_id='2' if victimOutfitId == event.teams.blue.id else '3',
                world_id=str(event.world),
                zone_id=(int(event.zoneInstanceId) << 16) | int(event.zone)
            )
            thread_rabbit.send(death, death_queue)
    thread = Thread(target=work)
    return thread, stop

def nexus_alert(
    world: int,
    instance: int,
    teams: Teams = Teams(
        Outfit(37570391403474491, name="Un1ty", faction=Faction.TR, alias="UN17"),
        Outfit(37571208657592881, name="Drunk Division", faction=Faction.TR, alias="HMRD")
    ),
    members: Dict[int, List[int]] = {
        37570391403474491: [5428297992006446465, 5428985062301123025],
        37571208657592881: [5428085259783352737]
    },
    capture_rate: int = 5,
    death_rate: float = 0.5,
    first_death_delay: float = 0.0,
    vehicle_destroy_rate: float = 30.0,
    vehicle_destroy_delay: float = 0.0) -> Optional[Tuple[Team, Dict[Team, int]]]:

    metagame_event_queue = f'aggregator-{world}-MetagameEvent'

    zone_id = (instance << 16) | 10
    event = OutfitwarsInstance(
        censusInstanceId=random.randint(1, 65535),
        zoneInstanceId=str(instance),
        world=world,
        zone=10,
        timeStarted=datetime.now(),
        phase=random.randint(1, 3),
        round=random.randint(1, 7),
        teams=teams
    )

    participant_count = len(members[event.teams.blue.id]) + len(members[event.teams.red.id])
    faction_blue = int((len(members[event.teams.blue.id]) / participant_count) * 100)
    faction_red = 100 - faction_blue

    metagame_event = MetagameEvent(
        instance_id=str(event.censusInstanceId),
        metagame_event_id=str(int(MetagameEventType.NEXUS_OUTFIT_WAR)),
        metagame_event_state=str(int(MetagameEventState.STARTED)),
        metagame_event_state_name="started",
        world_id=str(int(event.world)),
        zone_id=(int(event.zoneInstanceId) << 16) | event.zone,
        faction_vs='0',
        faction_nc=str(faction_blue),
        faction_tr=str(faction_red),
    )
    rabbit = get_rabbit()
    rabbit.send(metagame_event, metagame_event_queue)
    death_thread, death_stop_event = None, None
    vehicle_destroy_thread, vehicle_destroy_stop_event = None, None
    tb_thread, tb_stop_event = None, None
    nexus = None
    try:
        nexus = NexusMap(zone_id & 0xFFFF)
        to_capture = 0
        captures = MAX_CAPTURES
        fac_control_queue = f'aggregator-outfitwars-{int(event.world)}-{int(event.zone)}-{event.censusInstanceId}-FacilityControl'
        death_thread, death_stop_event = death_worker(death_rate, event, members, first_death_delay)
        vehicle_destroy_thread, vehicle_destroy_stop_event = vehicle_destroy_worker(vehicle_destroy_rate, event, members, vehicle_destroy_delay)
        tb_thread, tb_stop_event = tiebreaker_worker(60, nexus)
        tb_thread.start()
        death_thread.start()
        vehicle_destroy_thread.start()
        while to_capture not in ['310610', '310600'] and captures > 0:
            sleep(capture_rate)
            team = random.choice([Team.BLUE, Team.RED])
            to_capture = random.choice(nexus.get_capturable(team))
            old_faction = nexus.get_region(to_capture).faction
            nexus.capture(to_capture, team)
            # it appears from the PTS match that outfits might not get credit for captures.
            # Now that we have team id, we can compensate for that on our side ^.^
            if team == Team.BLUE and event.teams.blue.faction == Team.BLUE:
                outfit_id = str(event.teams.blue.id)
            elif team == Team.RED and event.teams.red.faction == Team.RED:
                outfit_id = str(event.teams.red.id)
            else:
                outfit_id = "0"
            facility_control = FacilityControlEvent(
                facility_id=str(to_capture),
                zone_id=str(zone_id),
                world_id=str(int(event.world)),
                old_faction_id=str(int(old_faction)),
                new_faction_id=str(int(team)),
                outfit_id=outfit_id,
            )
            rabbit.send(facility_control, fac_control_queue)
            captures -= 1

        if to_capture in ['310610', '310600']:
            tiebreaker_points[team] += tbpool
            tbpool = 0
    finally:
        metagame_end_event = MetagameEvent(
            instance_id=str(event.censusInstanceId),
            metagame_event_id=str(int(MetagameEventType.NEXUS_OUTFIT_WAR)),
            metagame_event_state=str(int(MetagameEventState.FINISHED)),
            metagame_event_state_name="ended",
            world_id=str(int(event.world)),
            zone_id=(int(event.zoneInstanceId) << 16) | event.zone,
            faction_vs='0',
            faction_nc=str(faction_blue),
            faction_tr=str(faction_red),
        )
        if death_stop_event and death_thread:
            death_stop_event.set()
            if death_thread.is_alive():
                death_thread.join()

        if vehicle_destroy_stop_event and vehicle_destroy_thread:
            vehicle_destroy_stop_event.set()
            if vehicle_destroy_thread.is_alive():
                vehicle_destroy_thread.join()

        if tb_stop_event and tb_thread:
            tb_stop_event.set()
            if tb_thread.is_alive():
                tb_thread.join()

        rabbit.send(metagame_end_event, metagame_event_queue)
        if nexus:
            points = {
                Team.RED: tiebreaker_points[Team.RED],
                Team.BLUE: tiebreaker_points[Team.BLUE]
            }
            winner = Team.RED if nexus.territory(Team.RED) > nexus.territory(Team.BLUE) else Team.BLUE
            return winner, points

def replay_vehicle_destroy_worker(
        event: OutfitwarsInstance,
        vehicle_destroys: List[VehicleDestroyReplayEvent]
    ) -> Thread:
    def work():
        global weapons
        vehicle_destroy_queue = f'aggregator-outfitwars-{event.world}-{event.zone}-{event.censusInstanceId}-VehicleDestroy'
        thread_rabbit = RabbitService(RabbitConnection())
        index = 0
        interval = (datetime.fromtimestamp(int(vehicle_destroys[0].timestamp)) - event.timeStarted).total_seconds()
        while index < len(vehicle_destroys):
            replay_event = vehicle_destroys[index]
            sleep(interval)
            print('Next Vehicle Destroy event in: '+str(interval)+' seconds...')
            vehicleDestroy = VehicleDestroyEvent(
                world_id=str(int(event.world)),
                attacker_character_id=replay_event.attacker_character_id,
                attacker_loadout_id=replay_event.attacker_loadout_id,
                attacker_team_id=replay_event.attacker_team_id,
                attacker_vehicle_id=replay_event.attacker_vehicle_id,
                attacker_weapon_id=replay_event.attacker_weapon_id,
                character_id=replay_event.character_id,
                faction_id=replay_event.faction_id,
                team_id=replay_event.team_id,
                vehicle_id=replay_event.vehicle_definition_id,
                zone_id=replay_event.zone_id,
                timestamp=replay_event.timestamp
            )
            thread_rabbit.send(vehicleDestroy, vehicle_destroy_queue)
            if index + 1 < len(vehicle_destroys):
                interval = (datetime.fromtimestamp(int(vehicle_destroys[index + 1].timestamp)) - datetime.fromtimestamp(int(vehicle_destroys[index].timestamp))).total_seconds()
            index += 1
    thread = Thread(target=work)
    return thread

def replay_death_worker(
        event: OutfitwarsInstance,
        death_replay_events: List[DeathReplayEvent]
    ) -> Thread:
    def work():
        death_queue = f'aggregator-outfitwars-{event.world}-{event.zone}-{event.censusInstanceId}-Death'
        thread_rabbit = RabbitService(RabbitConnection())
        index = 0
        interval = (datetime.fromtimestamp(int(death_replay_events[0].timestamp)) - event.timeStarted).total_seconds()
        #players = [BLUE_PLAYER, RED_PLAYER, NSO_RED_PLAYER]
        while index < len(death_replay_events):
            replay_event = death_replay_events[index]
            print('Next Death event in: '+str(interval)+' seconds...')
            sleep(interval)
            death = DeathEvent(
                attacker_character_id=replay_event.attacker_character_id,
                attacker_loadout_id=replay_event.attacker_loadout_id,
                attacker_weapon_id=replay_event.attacker_weapon_id,
                attacker_team_id=replay_event.attacker_team_id,
                character_id=replay_event.character_id,
                character_loadout_id=replay_event.character_loadout_id,
                is_headshot=replay_event.is_headshot,
                team_id=replay_event.team_id,
                world_id=replay_event.world_id,
                zone_id=replay_event.zone_id,
                timestamp=replay_event.timestamp
            )
            thread_rabbit.send(death, death_queue)
            if index + 1 < len(death_replay_events):
                interval = (datetime.fromtimestamp(int(death_replay_events[index + 1].timestamp)) - datetime.fromtimestamp(int(death_replay_events[index].timestamp))).total_seconds()
            index += 1
    thread = Thread(target=work)
    return thread

def replay_facility_control_worker(
    event: OutfitwarsInstance,
    facility_events: List[FacilityControlReplayEvent]
) -> Thread:
    def work():
        fac_control_queue = f'aggregator-{event.instanceId}-FacilityControl'
        thread_rabbit = RabbitService(RabbitConnection())
        index = 0
        interval = (datetime.fromtimestamp(int(facility_events[0].timestamp)) - event.timeStarted).total_seconds()
        while index < len(facility_events):
            replay_event = facility_events[index]
            print(replay_event)
            print('Next Facility event in: '+str(interval)+' seconds...')
            sleep(interval)
            facility_control = FacilityControlEvent(
                facility_id=replay_event.facility_id,
                zone_id=replay_event.zone_id,
                world_id=replay_event.world_id,
                old_faction_id=replay_event.faction_old,
                new_faction_id=replay_event.faction_new,
                outfit_id=replay_event.outfit_id,
                timestamp=replay_event.timestamp,
                duration_held=replay_event.duration_held
            )
            print('Sending FacilityControl message to queue ' + fac_control_queue)
            print(facility_control)
            thread_rabbit = RabbitService(RabbitConnection())
            thread_rabbit.send(facility_control, fac_control_queue)
            thread_rabbit.close()
            if index + 1 < len(facility_events):
                interval = (datetime.fromtimestamp(int(facility_events[index + 1].timestamp)) - datetime.fromtimestamp(int(facility_events[index].timestamp))).total_seconds()
            index += 1
    thread = Thread(target=work)
    return thread

def replay(
    metagame_replay_event: MetagameReplayEvent,
    metagame_replay_end_event: MetagameReplayEvent,
    facility_events: List[FacilityControlReplayEvent],
    death_events: List[DeathReplayEvent],
    vehicle_destroy_events: List[VehicleDestroyReplayEvent]
):
    world = World(int(metagame_replay_event.world_id))
    censusInstance = int(metagame_replay_event.instance_id)
    metagame_event_queue = f'aggregator-{world.value}-MetagameEvent'

    zone_id = int(metagame_replay_event.zone_id)
    event = OutfitwarsInstance(
        censusInstanceId=censusInstance,
        zoneInstanceId=((zone_id >> 16) & 0xFFFF),
        world=world,
        zone=zone_id & 0xFFFF,
        timeStarted=datetime.fromtimestamp(int(metagame_replay_event.timestamp)),
        phase=1,
        round=2, #really doesn't matter for a replay
        teams=None
    )

    metagame_event = MetagameEvent(
        instance_id=metagame_replay_event.instance_id,
        metagame_event_id=metagame_replay_event.metagame_event_id,
        metagame_event_state=metagame_replay_event.metagame_event_state,
        metagame_event_state_name=metagame_replay_event.metagame_event_state_name,
        world_id=metagame_replay_event.world_id,
        zone_id=metagame_replay_event.zone_id,
        faction_vs=metagame_replay_event.faction_vs,
        faction_nc=metagame_replay_event.faction_nc,
        faction_tr=metagame_replay_event.faction_tr,
    )
    rabbit = get_rabbit()
    rabbit.send(metagame_event, metagame_event_queue)
    death_thread = None
    vehicle_destroy_thread = None
    try:
        death_thread = replay_death_worker(event, death_events)
        vehicle_destroy_thread = replay_vehicle_destroy_worker(event, vehicle_destroy_events)
        facility_control_thread = replay_facility_control_worker(event, facility_events)
        death_thread.start()
        vehicle_destroy_thread.start()
        facility_control_thread.start()
        death_thread.join()
        vehicle_destroy_thread.join()
        facility_control_thread.join()
    finally:
        metagame_replay_end_event
        metagame_end_event = MetagameEvent(
            instance_id=metagame_replay_end_event.instance_id,
            metagame_event_id=metagame_replay_end_event.metagame_event_id,
            metagame_event_state=metagame_replay_end_event.metagame_event_state,
            metagame_event_state_name=metagame_replay_end_event.metagame_event_state_name,
            world_id=metagame_replay_end_event.world_id,
            zone_id=metagame_replay_end_event.zone_id,
            faction_vs=metagame_replay_end_event.faction_vs,
            faction_nc=metagame_replay_end_event.faction_nc,
            faction_tr=metagame_replay_end_event.faction_tr,
            timestamp=metagame_replay_end_event.timestamp
        )
        rabbit.send(metagame_end_event, metagame_event_queue)

async def build_outfit_data(service_id: str, red_outfit_id: int, blue_outfit_id: int):
    if not service_id.startswith("s:"):
        service_id = f"s:{service_id}"
    async with auraxium.Client(service_id=service_id) as client:
        logger.info("Retrieving outfit data...")
        red_outfit, blue_outfit = await asyncio.gather(
            client.get_by_id(ps2.Outfit, red_outfit_id),
            client.get_by_id(ps2.Outfit, blue_outfit_id)
        )
        if red_outfit is None or blue_outfit is None:
            raise ValueError(f"{'Both' if red_outfit is None and blue_outfit is None else ('Red' if red_outfit is None else 'Blue')} outfit(s) do(es) not exist!")

        (red_leader, #standing by
         blue_leader, red_members, blue_members) = await asyncio.gather(
            red_outfit.leader(),
            blue_outfit.leader(),
            red_outfit.members(),
            blue_outfit.members()
        )
        red_leader.character()

        (red_leader_character, blue_leader_character) = await asyncio.gather(
            red_leader.character(),
            blue_leader.character()
        )

        red_outfit_data = Outfit(red_outfit.id, red_outfit.name, red_leader_character.faction_id, red_outfit.alias)
        blue_outfit_data = Outfit(blue_outfit.id, blue_outfit.name, blue_leader_character.faction_id, blue_outfit.alias)
        character_ids = {
            red_outfit.id: [member.id for member in red_members[:48]],
            blue_outfit.id: [member.id for member in blue_members[:48]],
        }

    return Teams(red_outfit_data, blue_outfit_data), character_ids

def start_alert(teams: Teams, members: Dict[int, List], world: int, instance: int, capture_rate: int, death_rate: float, death_delay: float, vehicle_destroy_rate: float, vehicle_destroy_delay: float):

    logger.info(f"Starting alert on world {world}, zone instance {instance}")
    result = nexus_alert(world, instance, teams, members, capture_rate, death_rate, death_delay, vehicle_destroy_rate, vehicle_destroy_delay)
    logger.info(f"Finished alert on world {world}, zone instance {instance}")
    if result is not None:
        logger.info(f"Winner was team {result[0].name.capitalize()}")
    return instance, result

# Simulator that fakes an alert on Nexus with a bunch of random (possible) captures
#   Basically intended to test out various scenarios that could happen with outfit wars
def main():
    global logger
    parser = ArgumentParser(description="A tool that can fake a single outfit wars match between two outfits")

    subparsers = parser.add_subparsers(dest="subparser_name", required=True)
    fake_match_parser = subparsers.add_parser("fake", help="Fake an outfitwars match for testing")
    fake_match_parser.add_argument("service_id", type=str, help="The PS2 Census service id used for querying outfit (member) data")
    fake_match_parser.add_argument("--red-outfit-id", "-r", type=int, default=37570391403474491, help="The outfit id for the red team")
    fake_match_parser.add_argument("--blue-outfit-id", "-b", type=int, default=37571208657592881, help="The outfit id for the blue team")
    fake_match_parser.add_argument("--world", "-w", type=int, choices=[1, 10, 13, 17], default=1, help="The world having the outfit war")
    fake_match_parser.add_argument("--capture-rate", "-c", type=int, default=5, help="The number of seconds between base captures")
    fake_match_parser.add_argument("--death-rate", "-d", type=float, default=1.0, help="The number of seconds between deaths (can be a decimal)")
    fake_match_parser.add_argument("--death-delay", "-l", type=float, default=0.0, help="The decimal number of seconds to delay the first death by")

    replay_parser = subparsers.add_parser("replay", help="Replay an outfitwars match to fix failed matches")
    replay_parser.add_argument("metagame_events_file", type=str)
    replay_parser.add_argument("facility_events_file", type=str)
    replay_parser.add_argument("death_events_file", type=str)
    replay_parser.add_argument("vehicle_destroy_events_file", type=str)
    args = parser.parse_args()

    if args.subparser_name == "fake":
        try:
            teams, members = asyncio.get_event_loop().run_until_complete(build_outfit_data(args.service_id, args.red_outfit_id, args.blue_outfit_id))
        except ValueError as e:
            logger.error(str(e))
            exit(1)
        start_alert(teams, members, args.world, random.randint(0, 0xFFFF), args.capture_rate, args.death_rate, args.death_delay, 5, 5)
    else:
        with open(args.metagame_events_file) as f:
            metagame_events = json.load(f)
        assert len(metagame_events) == 2, "Should have only a start and end event for a single alert!"
        with open(args.facility_events_file) as f:
            facility_events_data = json.load(f)
        with open(args.death_events_file) as f:
            death_events_data = json.load(f)
        with open(args.vehicle_destroy_events_file) as f:
            vehicle_destroy_events_data = json.load(f)

        logger.info("Building replay event objects...")
        metagame_start_event = MetagameReplayEvent.from_json(metagame_events[0])
        metagame_end_event = MetagameReplayEvent.from_json(metagame_events[1])

        facility_events = [FacilityControlReplayEvent.from_json(event) for event in facility_events_data]
        death_events = [DeathReplayEvent.from_json(event) for event in death_events_data]
        vehicle_destroy_events = [VehicleDestroyReplayEvent.from_json(event) for event in vehicle_destroy_events_data]
        logger.info("Built replay event objects")
        logger.info("Starting replay")

        replay(metagame_start_event, metagame_end_event, facility_events, death_events, vehicle_destroy_events)

if __name__ == "__main__":
    main()


from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from scipy.special import expit

def generate_dataset():
    iris = datasets.load_iris()
    # petal length, petal width
    X = iris['data'][:, [2, 3]]
    # 1 if Iris-Virginica, else 0
    y = (iris['target'] == 2).astype(np.int)
    return X, y

def plot_countours(X, y):
    ax = plt.gca()
    x0_min = 2.9
    x0_max = 7
    x1_min = 0.8
    x1_max = 2.7
    x0, x1 = np.meshgrid(
        np.linspace(x0_min, x0_max, 500)[:, np.newaxis],
        np.linspace(x1_min, x1_max, 200)[:, np.newaxis],
    )

    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_proba = log_reg.predict_proba(X_new)

    # plot samples on {x0, x1} grid
    ax.plot(X[y == 0, 0], X[y == 0, 1], 'bs')
    ax.plot(X[y == 1, 0], X[y == 1, 1], 'g^')

    # plot probability countour plots of 1 class on {x0, x1} grid
    p1 = y_proba[:, 1].reshape(x0.shape)
    contour = ax.contour(x0, x1, p1, cmap=plt.cm.brg)
    ax.clabel(contour, inline=1, fontsize=12)

    # plot the learned params
    left_right = np.array([x0_min, x0_max])
    boundary = -(log_reg.coef_[0][0] * left_right + log_reg.intercept_[0]) / log_reg.coef_[0][1]
    ax.plot(left_right, boundary, 'k--', linewidth=3)

    ax.text(3.5, 1.5, 'Not Iris-Virginica', fontsize=14, color='b', ha='center')
    ax.text(6.5, 2.3, 'Iris-Virginica', fontsize=14, color='g', ha='center')
    ax.set_xlabel('Petal length', fontsize=14)
    ax.set_ylabel('Petal width', fontsize=14)
    ax.set_xlim(x0_min, x0_max)
    ax.set_ylim(x1_min, x1_max)

    plt.show()

def cost_function(X, y):
    m = y.shape[0]
    theta_min = -10
    theta_max = 10

    theta = np.arange(theta_min, theta_max, 0.5)
    theta1, theta2 = np.meshgrid(theta, theta)
    theta = np.hstack((theta[:, np.newaxis], theta[:, np.newaxis]))
    c = np.zeros(theta1.shape)

    for i in range(m):
        p = expit(X[i].dot(theta.T))
        c += -(np.log(p) * y[i] + np.log(1 - p) * (1 - y[i]))
    c = c / m

    ax = plt.gca(projection='3d')
    ax.plot_surface(theta1, theta2, c)
    plt.show()

X, y = generate_dataset()
log_reg = LogisticRegression(C=10 ** 10, random_state=42)
log_reg.fit(X, y)

# cost_function(X, y)
plot_countours(X, y)


#!/usr/bin/env python3

'''
A URI Scheme for Denoting Hosts
'''

import logging
import urllib.parse
import re

class MoWN:

    '''
    Man o' War Notation. An arn compatible way to reference and store hosts in a system.
    '''

    _flavor_map = {"default" : {}}

    _notetype = "mown"

    def __init__(self, **kwargs):

        '''
        Vanilla Initiation
        '''

        self.logger = logging.getLogger("saltcell.mown.MoWN")

        self.partition = kwargs.get("partition", "")
        self.service = kwargs.get("service", "")
        self.region = kwargs.get("region", "")
        self.accountid = kwargs.get("accountid", "")
        self.resource_meta = {"resource" : kwargs.get("resource", "")}
        self.path = ""
        self.arguments = kwargs.get("arguments", {})

        if kwargs.get("uri", None) is not None:
            # Parse given uri and use that
            self.parse_uri(kwargs.get("uri"))

        self.uri = self.gen_uri(aws=kwargs.get("aws", False))

        self.logger.debug("New Object Generated URI of : {}".format(self.uri))

    def __str__(self):

        return str(self.gen_uri())

    def __repr__(self):

        return ("MoWN(partition={}, service={}, region={}, accountid={}, resource_meta={})".format(self.partition,
                                                                                self.service,
                                                                                self.region,
                                                                                self.accountid,
                                                                                self.gen_resource()))

    def to_dict(self, noargs=False, v2_compat=True):

        '''
        Returns a Dictionary Representation of the data in this thing
        '''

        return_dict = {}

        return_dict["resource"] = self.resource_meta["resource"]
        return_dict["partition"] = self.partition
        return_dict["service"] = self.service
        return_dict["region"] = self.region
        return_dict["accountid"] = self.accountid
        return_dict["mown_base"] = self.gen_uri(baseonly=True)
        return_dict["mown_full"] = self.gen_uri()

        if v2_compat is True:
            return_dict["uber_id"] = self.arguments.get("uber_id", None)
            return_dict["collection_hostname"] = self.resource_meta["resource"]
            return_dict["pop"] = self.region
            return_dict["srvtype"] = self.service
            return_dict["status"] = self.arguments.get("status", "unspecified")

        if noargs is False:
            return_dict["arguments"] = self.arguments

        return return_dict

    def parse_uri(self, given_mown):

        '''
        # Parsing the Given URI
        '''

        self.logger.debug("Parsing in URI of : {}".format(given_mown))

        parsed_uri = urllib.parse.urlparse(given_mown)

        netloc_flavor = parsed_uri.netloc
        path_flavor = parsed_uri.path

        # Let's deal with ARN Path's as a thing
        if len(parsed_uri.path) > 0:
            # I have a path starting at 1 get's rid of preceeding "/"
            broken_paths = parsed_uri.path[1:].split("/")

            # Always grab the first two as resource and resource qualifier (if they exist)
            # Because I join if I just have one entry it will come in as /resource
            # And if I have two as /resource/qualifier
            netloc_flavor = parsed_uri.netloc + "/{}".format("/".join(broken_paths[0:2]))

            path_flavor = ""
            if len(broken_paths) >= 3:
                # Grab additional items as path items
                path_flavor = "/{}".format("/".join(broken_paths[2:]))

        # Now I load the damn thing into my object's variables (Done by netloc_parse which calls
        # parse_resource_meta too
        self.netloc_parse(netloc_flavor)

        # Store my path as my path
        self.path = path_flavor

        # Store any given arguments
        self.arguments = {**self.arguments, **dict(urllib.parse.parse_qsl(parsed_uri.query))}

        # Record Source of Scheme as an Arg
        if parsed_uri.scheme != "mown":
            self.arguments["source_scheme"] = str(parsed_uri.scheme)

        return parsed_uri

    def gen_uri(self, baseonly=False, **kwargs):

        '''
        Generates a mown:// uri scheme to represent this asset.
        '''

        mown_uri = False

        # Arguments Given
        query = ""
        if baseonly is False:
            query = urllib.parse.urlencode(self.arguments, doseq=False)

        # if kwargs("otherintegration", False) is True
        #   Other Baked in Integrations Here.

        if mown_uri is False:

            # Try Default Pull from Args (Config)
            mown_uri = urllib.parse.urlunparse((self._notetype,
                                                self.netloc_create(),
                                                self.path,
                                                kwargs.get("params", ""),
                                                query,
                                                kwargs.get("fragment", "")))

        return mown_uri

    def netloc_create(self):

        '''
        Assembles the bits
        '''

        netloc = "{}:{}:{}:{}:{}".format((self.partition or ""),
                                         (self.service or ""),
                                         (self.region or ""),
                                         (self.accountid or ""),
                                         self.gen_resource())

        return netloc

    def netloc_parse(self, netloc):

        '''
        Netloc Parser

        Parses thenetloc and loads the bits
        '''
        split_netloc = re.split("[:/]", netloc)

        if len(split_netloc) < 5:
            raise ValueError("Unknown or uncompatible Format on Given URI.")

        # First part is simple
        self.partition, self.service, self.region, self.accountid = split_netloc[0:4]

        resource_string = ":{}".format(":".join(split_netloc[4:]))

        self.resource_meta = self.parse_resource_meta(resource_string)

        return (self.partition, self.service, self.region, self.accountid, self.resource_meta)

    def parse_resource_meta(self, given_resource_string):

        '''
        Take a Resource String and turn it into the appropriate dictionary
        '''

        # Splits the bits into their components based on the existence of / or : followed by text and shit
        seperated_functions = re.findall(r"([/:][\_\-\.\d\w]+)", given_resource_string)

        resource_meta = dict()

        # I swear this isn't as ugly as it looks
        if len(seperated_functions) == 1:
            # I only have a resource so store it a :resource
            resource_meta["rrsep"] = ":"
            resource_meta["resource"] = seperated_functions[0][1:]
        elif len(seperated_functions) == 2:
            # I have a resourcetype and a ressource so store it at :resourcetype[:/]resource
            resource_meta["resourcetype"] = seperated_functions[0][1:]
            resource_meta["rrsep"] = seperated_functions[1][0]
            resource_meta["resource"] = seperated_functions[1][1:]
        elif len(seperated_functions) >= 3:
            # I have a resourcetype, resource and a resource qualifier so store it as:
            # :resourcetype[:/]resource[:/]qualifier

            resource_meta["resourcetype"] = "".join(seperated_functions[0][1:])
            resource_meta["rrsep"] = seperated_functions[1][0]
            resource_meta["resource"] = seperated_functions[1][1:]
            resource_meta["rqsep"] = seperated_functions[2][0]
            resource_meta["qualifier"] = "".join(seperated_functions[2:])[1:]

        return resource_meta

    def gen_resource(self):

        '''
        Generate a Resource from my resource_meta
        '''

        if "resourcetype" not in self.resource_meta.keys() and "qualifier" not in self.resource_meta.keys():
            # Most Common Output
            resource_string = self.resource_meta["resource"]
        elif "qualifier" not in self.resource_meta.keys():
            # Must have resourcetype in this instance
            resource_string = "{}{}{}".format(self.resource_meta["resourcetype"],
                                              self.resource_meta.get("rrsep", "/"),
                                              self.resource_meta["resource"])
        else:
            # I have all three and seperator
            resource_string = "{}{}{}{}{}".format(self.resource_meta["resourcetype"],
                                                  self.resource_meta.get("rrsep", "/"),
                                                  self.resource_meta["resource"],
                                                  self.resource_meta.get("rqsep", ":"),
                                                  self.resource_meta["qualifier"])

        return resource_string


import torch

from .base import EnergyFunction

class ActivityNeuron(EnergyFunction):
    """
    Activity regularisation at the neuron level to avoid quiescent neurons as in Zenke (2021).
    """
    def __init__(self, lamda=None, nu=None):
        super().__init__()
        self.lamda = lamda
        self.nu = nu

    def forward(self, output, target, meta_model, state):
        if all(key in meta_model.meta_learner for key in ["activity_neuron_lambda", "activity_neuron_nu"]):
            loss = [
                l * torch.relu(nu - torch.sum(s, dim=1))**2
                for s, l, nu in zip(
                    state["spiking"],
                    meta_model.meta_learner["activity_neuron_lambda"],
                    meta_model.meta_learner["activity_neuron_nu"])
            ]
        else:
            loss = [
                self.lamda * torch.relu(self.nu - torch.sum(s, dim=1))**2
                for s in state["spiking"]
            ]

        return torch.mean(torch.cat(loss))

class ActivityPopulation(EnergyFunction):
    """
    Activity regularisation at the population level to limit average activity as in Zenke (2021).
    """
    def __init__(self, l_p=2, lamda=None, nu=None):
        """
        Args:
            l_p: order of regularisation used (usually L1 or L2)
        """
        super().__init__()
        self.l_p = l_p
        self.lamda = lamda
        self.nu = nu

        self.lamda_key = "activity_population_lambda_l{}".format(str(l_p))
        self.nu_key = "activity_population_nu_l{}".format(str(l_p))

    def forward(self, output, target, meta_model, state):
        if all(key in meta_model.meta_learner for key in [self.lamda_key, self.nu_key]):
            loss = [
                l * torch.relu(torch.mean(torch.sum(s, dim=1), dim=1) - nu)**self.l_p
                for s, l, nu in zip(
                    state["spiking"],
                    meta_model.meta_learner[self.lamda_key],
                    meta_model.meta_learner[self.nu_key])
            ]
        else:
            loss = [
                self.lamda * torch.relu(torch.mean(torch.sum(s, dim=1), dim=1) - self.nu)**self.l_p
                for s in state["spiking"]
            ]

        return torch.mean(torch.cat(loss))

class MeanFiringRate(EnergyFunction):
    """
    Activity regularisation at the population level as in Bellec (2018).
    """
    def __init__(self, target, strength):
        super().__init__()
        self.target = target
        self.strength = strength

    def forward(self, output, target, meta_model, state):
        loss = [
            (self.strength * (torch.mean(s) - self.target)**2).view(-1)
            for s in state["spiking"]
        ]

        return torch.mean(torch.cat(loss))

class ElasticRegularizer(EnergyFunction):
    def __init__(self, l2_strength=None):
        super().__init__()
        self.l2_strength = l2_strength

    def forward(self, output, target, meta_model, state):
        if "l2_strength" in meta_model.meta_learner:
            loss = [
                (torch.exp(lamda) * (omega - p)**2).view(-1)
                for p, lamda, omega in zip(
                    meta_model.base_parameters(),
                    meta_model.meta_learner["l2_strength"].parameters(),
                    meta_model.meta_learner["omega"].parameters()
                )
            ]
        else:
            loss = [
                (self.l2_strength * (omega - p)**2).view(-1)
                for p, omega in zip(
                    meta_model.base_parameters(),
                    meta_model.meta_learner["omega"].parameters()
                )
            ]

        return torch.sum(torch.cat(loss))

class L2Regularizer(EnergyFunction):
    def __init__(self, l2=None):
        super().__init__()
        self.l2 = l2

    def forward(self, output, target, meta_model, state):
        if "l2" in meta_model.meta_learner:
            # If hyperparams contain l2 strengths, use them
            loss = [
                (l2 * p**2).view(-1)
                for p, l2 in zip(meta_model.base_parameters(), meta_model.meta_learner["l2"])
            ]
        else:
            # Otherwise use default l2 strength defined upon init
            loss = [
                (self.l2 * p**2).view(-1)
                for p in meta_model.base_parameters()
            ]

        return torch.sum(torch.cat(loss))

class L1Spikes(EnergyFunction):
    """
    L1 loss on total number of spikes.
    """
    def forward(self, output, target, meta_model, state):
        loss = [
            l1 * torch.mean(torch.sum(s, dim=(1, 2)))
            for s, l1 in zip(state["spiking"], meta_model.meta_learner["l1_spike"])
        ]

        return torch.mean(torch.stack(loss))

class L2Spikes(EnergyFunction):
    """
    L2 loss on spikes per neuron.
    """
    def forward(self, output, target, meta_model, state):
        loss = [
            l2 * torch.mean(torch.sum(s, dim=1)**2)
            for s, l2 in zip(state["spiking"], meta_model.meta_learner["l2_spike"].parameters())
        ]

        return torch.mean(torch.stack(loss))


import pandas as pd
from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import grangercausalitytests
from statsmodels.tsa.stattools import adfuller
import numpy as np
from statsmodels.tsa.api import VAR
from statsmodels.tools.eval_measures import aic
from sklearn.metrics import mean_absolute_error, mean_squared_error
from math import sqrt

electricity_df = pd.read_csv("IE2111 Project - Electricity Tariffs, Monthly.csv") #Read CSV into DataFrame Object
electricity_df['Month'] = pd.to_datetime(electricity_df['Month']) #Convert 'Month' into a Datetime Object
electricity_df = electricity_df.iloc[::3]
electricity_df.index = pd.DatetimeIndex(electricity_df['Month']) #Set 'Month' as a Pandas DatetimeIndex
print(electricity_df)

seasonal_decompose(electricity_df['Electricity_Tariff'], model='additive').plot() #Decompose the Time Series into Trend, Seasonality & Random Noise
plt.show() #Plot the Decomposed Time Series in the Console

energy_df = pd.read_csv("IE2111 Project - Average USEP, Monthly.csv") #Read CSV into DataFrame Object
energy_df['Month'] = pd.to_datetime(energy_df['Month'], dayfirst=True) #Convert 'Month' into a Datetime Object
energy_df.index = pd.DatetimeIndex(energy_df['Month']) #Set 'Month' as a Pandas DatetimeIndex
print(energy_df)

data_df = pd.merge(electricity_df['Electricity_Tariff'], energy_df['Energy_Price'], left_index=True, right_index=True) #Merge the 2 Time Series based on Month Index
data_df.reset_index(level=0, inplace=True)
print(data_df)

plt.plot(data_df['Month'], data_df['Electricity_Tariff'], label="Electricity_Tariff") #Plot Electricity_Tariff & Nat_Gas_Price Together
plt.plot(data_df['Month'], data_df['Energy_Price'], label="Energy_Price")
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
plt.title('Energy Price VS Electricity Tariff Over Time')
plt.show()

print(grangercausalitytests(data_df[['Electricity_Tariff', 'Energy_Price']], maxlag=12, addconst=True, verbose=True))

adfuller_test = {'Electricity_Tariff': adfuller(data_df['Electricity_Tariff'])[1], 'Energy_Price': adfuller(data_df['Energy_Price'])[1]}

differenced_df, differenced = data_df, 0
while not max(adfuller_test.values()) < 0.05: #Difference DataFrame until both Time Series are Stationary as determined by the Adfuller Test
    differenced_df = differenced_df.diff().dropna()
    for series in adfuller_test:
        adfuller_test[series] = adfuller(differenced_df[series])[1]
    differenced += 1 #Count the Number of Differences
print(differenced_df)

data_array = np.array(data_df[['Electricity_Tariff', 'Energy_Price']].dropna())
differenced_array = np.array(differenced_df[['Electricity_Tariff', 'Energy_Price']].dropna())

n_obs = 8
df_train, df_test = differenced_array[:-n_obs], data_array[-n_obs:]

model = VAR(endog=df_train)
print(model.select_order(maxlags=12).summary())
model_fit = model.fit(ic='aic')
print(model_fit.summary())

lag_order = model_fit.k_ar
model_predict = model_fit.forecast(df_train[-lag_order:], n_obs)
predict_differenced = pd.DataFrame(model_predict, index=data_df.index[-n_obs:], columns=data_df[['Electricity_Tariff', 'Energy_Price']].columns + '_Predicted')
predict_df = predict_differenced.cumsum() + df_test

master_df = pd.merge(data_df, predict_df, left_index=True, right_index=True) #Merge the 2 Time Series based on Month Index
master_df.reset_index(level=0, inplace=True)
print(master_df)

plt.plot(master_df['Month'], master_df['Electricity_Tariff'], label="Actual") #Plot Electricity_Tariff & Electricity_Tariff_Predicted Together
plt.plot(master_df['Month'], master_df['Electricity_Tariff_Predicted'], label="Predicted")
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
plt.title('Predicted VS Actual Electricity Tariffs')
plt.show()

df_actual = [df_test[i][0] for i in range(len(df_test))]
forecast_errors = [df_actual[i] - predict_df.Electricity_Tariff_Predicted[i+53] for i in range(len(df_actual))]
bias = sum(forecast_errors) * 1.0/len(df_actual)
mae = mean_absolute_error(df_actual, predict_df.Electricity_Tariff_Predicted)
mse = mean_squared_error(df_actual, predict_df.Electricity_Tariff_Predicted)
rmse = sqrt(mse)

df_forecast = differenced_array[-n_obs:]
model_forecast = model_fit.forecast(df_forecast[-lag_order:], n_obs)
forecast_differenced = pd.DataFrame(model_forecast, columns=data_df[['Electricity_Tariff', 'Energy_Price']].columns + '_Forecast')
forecast_df = forecast_differenced.cumsum() + [23.0, 88.64]
print(forecast_df)


import json
import logging
import os
from typing import Dict, Optional, Iterable

import jsonschema
import yaml

from .artifact import ArtifactDefinition, make_artifact
from .variables import KnowledgeBase
from .definitions import OS_TYPES

LOGGER = logging.getLogger(__name__)

class Registry:

    def __init__(self):
        self.artifacts: Dict[str, ArtifactDefinition] = {}
        self.artifact_schema = None

        self._load_schema()

    def read_folder(self, folder: str, os_filter: Optional[Iterable[str]] = None) -> None:
        """
        Reads all artifact definition files in a local folder and adds them to the registry.
        Search is not recursive
        """
        input_files = [f for f in os.listdir(folder) if f.endswith('.yaml')]
        LOGGER.debug("Reading files from %s: %s", folder, input_files)
        for input_file in input_files:
            self.read_file(os.path.join(folder, input_file), os_filter)

    def read_file(self, file: str, os_filter: Optional[Iterable[str]] = None) -> None:
        """ Reads a single YAML file and adds the contained artifacts to the registry """
        if not os_filter:
            os_filter = OS_TYPES
        with open(file, 'r') as definition_file:
            try:
                artifacts = list(yaml.safe_load_all(definition_file))
            except yaml.YAMLError as err:
                LOGGER.error("Could not load %s: %s", file, err)
                return
        for artifact_dict in artifacts:
            if self.verify_structure(artifact_dict):
                artifact = make_artifact(artifact_dict)
                if artifact:
                    if artifact.supported_os and not any(os_name in os_filter for os_name in artifact.supported_os):
                        continue
                    self.artifacts[artifact.name] = artifact

            else:
                LOGGER.error("Not adding %s due to validation error", artifact_dict.get('name', '!ERR_NO_NAME'))

    def get_knowledge_base(self) -> KnowledgeBase:
        return KnowledgeBase(self.artifacts)

    def verify_structure(self, artifact_dict: dict) -> bool:
        """ Checks if an artifact definition is valid can be parsed into a definition object """
        try:
            jsonschema.validate(artifact_dict, self.artifact_schema)
            return True
        except jsonschema.exceptions.ValidationError as err:
            LOGGER.error("Artifact is not valid: %s", err)
            return False

    def get_artifact(self, title: str) -> Optional[ArtifactDefinition]:
        """ Return the artifact with the supplied name, if present in the registry """
        return self.artifacts.get(title, None)

    def _load_schema(self):
        my_path = os.path.dirname(os.path.realpath(__file__))
        my_schema = os.path.join(my_path, 'artifact_schema.json')
        with open(my_schema, 'r') as schema:
            self.artifact_schema = json.load(schema)


import logging
from ucloud.core import exc
from ucloud.client import Client
import json

logger = logging.getLogger("ucloud")
logger.setLevel(logging.WARN)
import re
import requests
# 从config文件导入public_key 和private_key
from config import *
from loguru import logger

# 不需要备份的DBId
exclude_DBId_list = [
    # "udbv-hfhtjegj",#"backend_1",
    # "udbhhjarfegion",#"backend_data_v1",
    # "udbfs-glblqh0rq",#backend-dev
]

def get_every_preject(public_key, private_key):
    client = Client({
        "public_key": public_key,
        "private_key": private_key,
        "base_url": "https://api.ucloud.cn"
    })

    try:
        resp = client.uaccount().get_project_list({
        })
    except exc.UCloudException as e:
        print(e)

    projects = resp.get("ProjectSet")
    for project in projects:
        project = project.get("ProjectId")
        yield project

def get_udb_id(project_id):
    client = Client({
        "region": "cn-bj2",
        "public_key": public_key,
        "private_key": private_key,
        "project_id": project_id,
        "base_url": "https://api.ucloud.cn"
    })
    try:
        resp = client.udb().describe_udb_instance({
            "ClassType": "SQL",
            "Offset": 0,
            "Limit": 30
        })
    except exc.UCloudException as e:
        print(e)
    else:
        # print(resp)
        DBId_dict_list = resp.get("DataSet")
        for DBId_dict in DBId_dict_list:
            DBId = DBId_dict.get("DBId")
            DBName = DBId_dict.get("Name")
            yield DBId, DBName

def get_udb_BackupId(project_id, DBId):
    client = Client({
        "region": "cn-bj2",
        "public_key": public_key,
        "private_key": private_key,
        "project_id": project_id,
        "base_url": "https://api.ucloud.cn"
    })

    try:
        resp = client.udb().describe_udb_backup({
            "Offset": 0,
            "Limit": 30,
            "DBId": DBId,

        })
    except exc.UCloudException as e:
        print(e)
    else:
        # print(resp)
        BackupId = resp.get("DataSet")[0].get("BackupId")
        # logger.info(BackupId)
        return BackupId

def get_udb_backup_url(ProjectId, DBId, BackupId):
    client = Client({
        "region": "cn-bj2",
        "public_key": public_key,
        "private_key": private_key,
        "project_id": ProjectId,
        "base_url": "https://api.ucloud.cn"
    })

    try:
        resp = client.udb().describe_udb_instance_backup_url({
            "DBId": DBId,
            "BackupId": BackupId,

        })
    except exc.UCloudException as e:
        print(e)
    else:
        # print(resp)
        BackupURL = resp.get("BackupPath")
        InnerBackupPath = resp.get("InnerBackupPath")
        # logger.info(InnerBackupPath)
        # logger.info(BackupURL)
        return InnerBackupPath, BackupURL

if __name__ == '__main__':
    # 获得所有的项目ID
    p_id = get_every_preject(public_key, private_key)
    for project_id in p_id:
        logger.info(project_id)
        # 获得该项目下的所有 DBId和DBName
        DBId_Name_list = get_udb_id(project_id)
        for DBId, DBName in DBId_Name_list:
            if DBId not in exclude_DBId_list:  # 排除本次不需要备份的udb_id
                # 根据DBId获得BackupId
                BackupId = get_udb_BackupId(project_id, DBId)
                # 根据DBId、BackupId得到 backup_url(外网)
                backup_url = get_udb_backup_url(project_id, DBId, BackupId)[0]  # 内网
                # backup_url = get_udb_backup_url(project_id,DBId,BackupId)[1] #外网
                pattern = r'(http|https)://(.*?)/(.*?)/(.*?)\?'
                name_re = re.match(pattern, backup_url)
                # logger.info(name_re)
                filename = path + project_id + "." + DBName + "." + name_re.group(4)
                logger.info(filename)
                r = requests.get(backup_url, stream=True)
                with open(filename, "wb") as f:
                    count = 0
                    for chunk in r.iter_content(chunk_size=102400):  # 1024 bytes
                        if chunk:
                            count += 1
                            print(count)
                            f.write(chunk)
            else:
                logger.warning("该DB在不备份列表中，不需要备份")


__author__ = 'Michael Maeder'
__date__ = "04.10.2021"
__version__ = "1.1"
__email__ = "michael.maeder@hefr.ch"
__userid__ = "michael.maeder"

import cv2
import numpy as np
import urllib.request

URL = 'https://assets.pokemon.com/assets/cms2/img/pokedex/detail/'

def download_image(img_nbr: int, path: str, verbose_print: bool = False):
    """
    Downloads a specific pokemon image in PNG format. The function gets a index number and downloads the corresponding
    image. The PNG-converted image will be written to the given filesystem path

    :argument
        img_nbr         -- the number of the image (1 .. 898)
        path            -- the path where the image will be written to
        verbose_print   -- selector if some debugging information should be printed or not

    :exception
        urllib.error.HTTPError  -- will be raised by the request library. The exception will be forwarded to the caller
    """

    try:
        # creation of the request object with the given URL
        req = urllib.request.Request(URL + '{:03d}'.format(img_nbr) + '.png')
        response = urllib.request.urlopen(req)                          # response contains the raw response data
        raw_image_data = response.read()                                # get the bytes of the image
        image = np.asarray(bytearray(raw_image_data), dtype="uint8")    # convert it to an array of uint8s
        image = cv2.imdecode(image, cv2.IMREAD_UNCHANGED)               # the code the array as an image
        cv2.imwrite(path + "/" + '{:03d}'.format(img_nbr) + ".png", image)  # finally write the PNG to the given path
        if verbose_print:
            print("Saved " + '{:03d}'.format(img_nbr) + ".png")
    except Exception as e:
        print("Error occured for Pokemon " + '{:03d}'.format(img_nbr))
        raise e                                                         # forward the exception to the caller


from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np
import imutils
import pickle
import cv2
import os
image = cv2.imread("examples/madhavi.jpeg")
print(image)
output = imutils.resize(image,width=400)
print (output)
image = cv2.resize(image, (96, 96))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
print("[INFO] loading network...")
model = load_model("Teeth")
mlb = pickle.loads(open("mlb.pickle", "rb").read())
print("[INFO] classifying image...")
proba = model.predict(image)[0]
idxs = np.argsort(proba)[::-1][:2]
for (i, j) in enumerate(idxs):
	label = "{}: {:.2f}%".format(mlb.classes_[j], proba[j] * 100)
	a= proba[j] * 100
	cv2.putText(output, label, (10, (i * 30) + 25),
		cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow("Output", output)
cv2.waitKey(0)


import cv2  # cvzone==1.5.6
import os
from pathlib import Path
from ffpyplayer.player import MediaPlayer

def find_the_video(file_name, directory_name):
    files_found = []
    for path, subdirs, files in os.walk(directory_name):
        for name in files:
            if(file_name == name):
                file_path = os.path.join(path, name)
                files_found.append(file_path)
    print(files_found)
    return files_found[0]

video_name = input("Nome do arquivo que quer tocar:\n")
# luciano.mp4

video_directory_guess = input("Diretório que contém o arquivo:\n")
# C:\Workspace\Python\EasyVideoPlayer

video_path = find_the_video(video_name, video_directory_guess)
print(f"Video Path: {video_path}")

# Initialize the path of the image file

video_directory = Path(find_the_video(video_name, video_directory_guess))

# Initialize the parent directory of the image path

new_working_directory = video_directory.parent

# Change the working directory of the script

os.chdir(new_working_directory)

def play_video(video_path):
    video = cv2.VideoCapture(video_path)
    player = MediaPlayer(video_path)
    while True:
        grabbed, frame = video.read()
        audio_frame, val = player.get_frame()
        if not grabbed:
            print("End of video")
            break
        if cv2.waitKey(28) & 0XFF == ord("q"):
            break

        cv2.imshow("Video", frame)

        if val != 'eof' and audio_frame is not None:
            img, t = audio_frame

    video.release()
    cv2.destroyAllWindows()

play_video(video_path)


import backtrader as bt

class SmaCross(bt.Strategy):
    params = dict(
        pfast=10,  # period for the fast moving average
        pslow=30   # period for the slow moving average
    )

    def __init__(self):
        sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
        sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
        self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal

    def next(self):
        if not self.position:  # not in the market
            if self.crossover > 0:  # if fast crosses slow to the upside
                self.buy()  # enter long

        elif self.crossover < 0:  # in the market & cross to the downside
            self.close()  # close long position


import torch.nn as nn
# Init NN model
class BasicClassifier(nn.Module):
    def __init__(self,input_dim,output_dim):
        super(BasicClassifier, self).__init__()
        self.input_layer    = nn.Linear(input_dim,128)
        self.hidden_layer1  = nn.Linear(128,64)
        self.output_layer   = nn.Linear(64,output_dim)
        self.relu = nn.ReLU()

    def forward(self,x):
        print(x.shape)
        out =  self.relu(self.input_layer(x))
        out =  self.relu(self.hidden_layer1(out))
        out =  self.output_layer(out)
        return out


from django.shortcuts import render,get_object_or_404
from webmash.models import Category,AboutUs,Post,PostTags,Writer
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from random import shuffle
from django.http import HttpResponse,JsonResponse
from webmash import serializers

def main(request):
	query=Post.objects.all().order_by('heading')
	main_post=query[:4]
	remaining_post=query
	writer=Writer.objects.all()
	latest=Post.objects.all().order_by('post_date')[:4]
	query2=list(Post.objects.all()[:4])

	shuffle(query2)
	print(query2)
	popular=query2
	aboutus=AboutUs.objects.all()
	tag=PostTags.objects.all().order_by('text')
	catt=Category.objects.all().order_by('text')
	page = request.GET.get('page', 1)
	paginator = Paginator(remaining_post, 1)
	try:
		users = paginator.page(page)
	except PageNotAnInteger:
		users = paginator.page(1)
	except EmptyPage:
		users = paginator.page(paginator.num_pages)
	return render(request,'main.html',{'mainp':main_post,'writer':writer,
		'latest':latest,'popular':popular,'tag':tag,'catt':catt,'cat':users,'a':aboutus})

def category(request):
	query=Category.objects.all().order_by('text').distinct()
	aboutus=AboutUs.objects.all()
	return render(request,'category.html',{'cat':query,'a':aboutus})

def posttags(request):
	query=PostTags.objects.all().order_by('text').distinct()
	aboutus=AboutUs.objects.all()
	return render(request,'posttags.html',{'cat':query,'a':aboutus})

def catdetail(request,arg):
	test=get_object_or_404(Category,text=arg)
	querys=Post.objects.filter(Category__text=arg)
	aboutus=AboutUs.objects.all()
	page = request.GET.get('page', 1)
	paginator = Paginator(querys, 2)
	try:
		users = paginator.page(page)
	except PageNotAnInteger:
		users = paginator.page(1)
	except EmptyPage:
		users = paginator.page(paginator.num_pages)
	return render(request,'category_detail.html',{'cat':users,'a':aboutus,'arg':arg
		})

def api_category_detail(request,cat):
	test=get_object_or_404(Category,id=cat)
	querys=Post.objects.filter(Category__id=cat).prefetch_related('writer')
	return JsonResponse({'category':test.text ,'posts':serializers.NewPostSerializers(querys)})

def api_tagdetail(request,tag):
	test=get_object_or_404(PostTags,id=tag)
	querys=Post.objects.filter(posttags__id=tag).prefetch_related('writer')
	return JsonResponse({'tag':test.text,'posts':serializers.NewPostSerializers(querys)})

def postdetail(request,pkid):
	query=get_object_or_404(Post,id=pkid)
	past=Post.objects.none()
	nextt=Post.objects.none()
	if Post.objects.filter(id=pkid-1).exists():
		past=Post.objects.get(id=pkid-1)
	if Post.objects.filter(id=pkid+1).exists():
		nextt=Post.objects.get(id=pkid+1)
	aboutus=AboutUs.objects.all()
	return render(request,'postdetail.html',{'cat':query,'a':aboutus,'p':past,'n':nextt})

def api_writer(request):
	query=Writer.objects.all()
	res={
	'id':query[0].id,
	'name':query[0].name,
	'bio':query[0].bio,
	'pic':query[0].ProfilePic.url
	}
	return JsonResponse({'writer':res})

def api_mainpost(request,pkid):
	query=get_object_or_404(Post,id=pkid)
	past=Post.objects.none()
	nextt=Post.objects.none()
	pastpost={}
	if Post.objects.filter(id=pkid-1).exists():
		past=Post.objects.get(id=pkid-1)
		pastpost['id']=past.id
		pastpost['headline']=past.heading
	nextpost={}
	if Post.objects.filter(id=pkid+1).exists():
		nextt=Post.objects.get(id=pkid+1)
		nextpost['id']=nextt.id
		nextpost['headline']=nextt.heading
	lol=Post.objects.filter(id=pkid).prefetch_related('posttags','writer')
	return JsonResponse({
		"post":serializers.APIPostSerializer(lol),
		"prev":pastpost,
		"next":nextpost
		})

def tagdetail(request,arg):
	test=get_object_or_404(PostTags,text=arg)
	querys=Post.objects.filter(posttags__text=arg)
	aboutus=AboutUs.objects.all()
	page = request.GET.get('page', 1)
	paginator = Paginator(querys, 4)
	try:
		users = paginator.page(page)
	except PageNotAnInteger:
		users = paginator.page(1)
	except EmptyPage:
		users = paginator.page(paginator.num_pages)
	return render(request,'post_detail.html',{'cat':users,'a':aboutus,'arg':arg
		})

def search(request):
	if request.method=="POST":
		p,c,t=GetSearchResults(request.POST['search_input'])
		return render(request,'search.html',{'p':p,'c':c,'t':t})
	else:
		return HttpResponse("Invalid Action!!!")

def GetSearchResults(query):
	post_result=Post.objects.filter(heading__icontains=query)
	category_result=Category.objects.filter(text__icontains=query)
	tag_result=PostTags.objects.filter(text__icontains=query)
	return post_result,category_result,tag_result

def api_main(request):
	remaining_post=Post.objects.all().order_by('heading')
	page = request.GET.get('page', 1)
	paginator = Paginator(remaining_post, 1)
	try:
		users = paginator.page(page)
	except PageNotAnInteger:
		users = paginator.page(1)
	except EmptyPage:
		users = paginator.page(paginator.num_pages)
	return JsonResponse({
		'main_post':serializers.PostSerializers(users.object_list),
		'pages':paginator.num_pages
		})
def api_categories(request):
	query=Category.objects.all().order_by('text').distinct()
	return JsonResponse({'categories':serializers.CategorySerializer(query)})

def api_posttags(request):
	query=PostTags.objects.all().order_by('text').distinct()
	return JsonResponse({'posttags':serializers.PostTagsSerializer(query)})


import logging
from django.db.models import Q
from app_public.models import Doctor, Patient, Speciality, DoctorGroup, WorkPlace, Location
from app_public.app.Configuration import FILE_HANDLER

logger = logging.getLogger("django")
logger.setLevel(logging.INFO)

def search_doctor_by_name(search_text):
    q_req = Q()
    for word in search_text.split(' '):
        q_req = q_req | Q(user__first_name__icontains=word)
        q_req = q_req | Q(user__last_name__icontains=word)

    users = Doctor.objects.filter(q_req).order_by('user__last_name', 'user__first_name')

    return users

def search_patient_by_name(search_text):
    q_req = Q()
    for word in search_text.split(' '):
        q_req = q_req | Q(user__first_name__icontains=word)
        q_req = q_req | Q(user__last_name__icontains=word)

    users = Patient.objects.filter(q_req).order_by('user__last_name', 'user__first_name')

    return users

def search_doctor_by_distance(longitude, latitude, speciality):
    lon = str(longitude)
    lat = str(latitude)
    formula = "address__longitude - {} + address__latitude - {}".format(lon, lat)
    query = speciality.doctors.extra(select={'distance': formula}).order_by('-distance')
    return None

def search_speciality_by_name(search_text):
    q_req = Q()
    for word in search_text.split(' '):
        q_req = q_req | Q(name__icontains=word)

    query = Speciality.objects.filter(Q(validated=True) & q_req)

    return query

def search_group_by_name(search_text):
    q_req = Q()
    for word in search_text.split(' '):
        q_req = q_req | Q(name__icontains=word)

    query = DoctorGroup.objects.filter(q_req)

    return query


import argparse
import time
import os
import requests
import json
import xlsxwriter
from requests_toolbelt.multipart.encoder import MultipartEncoder

parser = argparse.ArgumentParser(description='scan through all apks and produce excel output')
parser.add_argument("-p", required=True, type=str, help="Path to the APK folder")
parser.add_argument("-api", required=True, type=str, help="Mobsf API key")
parser.add_argument("-url", required=True, type=str, help="Mobsf URL e.g. localhost:8000")

args = parser.parse_args()
path = args.p
api_key = args.api
mobsf_server = args.url

# compile list of apk paths
files = []
# r=root, d=directories, f = files
for r, d, f in os.walk(path):
    for file in f:
        if '.apk' in file:
            files.append(os.path.join(r, file))

# create excel file
workbook = xlsxwriter.Workbook("output.xlsx")
result_worksheet = workbook.add_worksheet("result")
cell_format = workbook.add_format({"text_wrap": True, "valign": 'vcenter'})

# for every apk path, send to mobsf
row = 0
col = 0
result_worksheet.write(row, col, "filename")
result_worksheet.write(row, col+1, "Permissions")
result_worksheet.write(row, col+2, "Manifest Analysis")
row+=1

for f in files:
	apk_name = f[f.rfind("/")+1:]
	print("Uploading", apk_name)
	multipart_data = MultipartEncoder(fields={'file': (f, open(f, 'rb'), 'application/octet-stream')})
	headers = {"Content-Type": multipart_data.content_type, "Authorization": api_key}
	response = requests.post(mobsf_server + '/api/v1/upload', data=multipart_data, headers=headers)
	resp_dict = json.loads(response.text)
	print("Uploaded", apk_name)

	# scan apk
	print("Scanning", apk_name)
	resp_dict["re_scan"] = 1 # enable rescan of apk
	headers = {'Authorization': api_key}
	response = requests.post(mobsf_server + '/api/v1/scan', data=resp_dict, headers=headers)
	print("Scanned", apk_name)
	scan_dict = json.loads(response.text)

	if "file_name" in scan_dict.keys():
		# if scan passes, write to excel
		result_worksheet.write(row, col, scan_dict["file_name"])

		permissions_output = ""
		for key, val in scan_dict["permissions"].items():
			permissions_output += key + " \n"
			for title, content in val.items():
				permissions_output += title + ": " + content + " \n"
			permissions_output += "\n"
		result_worksheet.write(row, col+1, permissions_output, cell_format)

		manifest_analysis = ""
		for item in scan_dict["manifest_analysis"]:
			manifest_analysis += "name: " + item["name"] + "\n"
			manifest_analysis += "stat: " + item["stat"] + "\n"
			manifest_analysis += "desc: " + item["desc"] + "\n"
			manifest_analysis += "\n"
		result_worksheet.write(row, col+2, manifest_analysis, cell_format)
		result_worksheet.set_row(row, 20+(len(scan_dict["manifest_analysis"])*5))
	else:
		# fail output name and that it failed
		result_worksheet.write(row, col, apk_name)
		result_worksheet.write(row, col+1, "scan failed")

	row += 1
	time.sleep(1) # needed to prevent connection reset by peer

result_worksheet.set_column(col+1, col+1, 40)
result_worksheet.set_column(col+2, col+2, 100)
workbook.close()


import os
import argparse
import time

import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import argrelextrema

parser = argparse.ArgumentParser('Extract mp4 key frame and extract smiley face feature')

parser.add_argument('--video_path', required=False, type=str, default='./video5.mp4',
                    help='Video path of the source file.')
parser.add_argument('--window_length', required=False, type=int, default=50)

args = parser.parse_args()

# Directory to store the processed frames
output_dir = os.path.splitext(args.video_path)[0]

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

def smooth(x, window_len=13, window='blackman'):
    """ smooth the data using a window with requested size.

    This method is based on the convolution of a scaled window with the signal.
    The signal is prepared by introducing reflected copies of the signal
    (with the window size) in both ends so that transient parts are minimized
    in the begining and end part of the output signal.

    Args:
        x: the input signal.
        window_len: the dimension of the smoothing window.
        window: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'.
            flat window will produce a moving average smoothing.
    Returns:
        the smoothed signal

    example:
    import numpy as np
    t = np.linspace(-2,2,0.1)
    x = np.sin(t)+np.random.randn(len(t))*0.1
    y = smooth(x)

    see also:

    numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve
    scipy.signal.lfilter
    """
    # print(len(x), window_len)

    s = np.r_[2 * x[0] - x[window_len:1:-1],
              x, 2 * x[-1] - x[-1:-window_len:-1]]

    if window == 'flat':  # moving average
        w = np.ones(window_len, 'd')
    else:
        w = getattr(np, window)(window_len)
    y = np.convolve(w / w.sum(), s, mode='same')
    return y[window_len - 1:-window_len + 1]

class Frame:
    """class to hold information about each frame

    """

    def __init__(self, video_id, pic_diff):
        self.id = video_id
        self.different = pic_diff

    def __lt__(self, other):
        if self.id == other.id:
            return self.id < other.id
        return self.id < other.id

    def __gt__(self, other):
        return other.__lt__(self)

    def __eq__(self, other):
        return self.id == other.id and self.id == other.id

    def __ne__(self, other):
        return not self.__eq__(other)

def rel_change(a, b):
    return (b - a) / max(a, b)

def main():
    # load example1 and compute diff between frames
    cap = cv2.VideoCapture(str(args.video_path))
    prev_frame = None
    frame_diffs = []
    frames = []
    success, frame = cap.read()
    i = 0
    while success:
        luv = cv2.cvtColor(frame, cv2.COLOR_BGR2LUV)
        curr_frame = luv
        if curr_frame is not None and prev_frame is not None:
            # logic here
            diff = cv2.absdiff(curr_frame, prev_frame)
            diff_sum = np.sum(diff)
            diff_sum_mean = diff_sum / (diff.shape[0] * diff.shape[1])
            frame_diffs.append(diff_sum_mean)
            frame = Frame(i, diff_sum_mean)
            frames.append(frame)
        prev_frame = curr_frame
        i = i + 1
        success, frame = cap.read()
    cap.release()

    # compute keyframe
    keyframe_id_set = set()

    diff_array = np.array(frame_diffs)
    sm_diff_array = smooth(diff_array, args.window_length)
    frame_indexes = np.asarray(argrelextrema(sm_diff_array, np.greater))[0]
    for i in frame_indexes:
        keyframe_id_set.add(frames[i - 1].id)

    plt.figure(figsize=(40, 20))
    plt.locator_params()
    plt.stem(sm_diff_array, use_line_collection=True)

    # save all keyframes as image
    cap = cv2.VideoCapture(str(args.video_path))
    success, frame = cap.read()
    idx = 0
    while success:
        if idx in keyframe_id_set:
            name = str(idx) + ".png"
            img_save_path = os.path.join(output_dir, name)
            cv2.imwrite(img_save_path, frame)
            keyframe_id_set.remove(idx)
        idx = idx + 1
        success, frame = cap.read()
    cap.release()

if __name__ == "__main__":
    start = time.time()
    main()
    print(f'Done! Times: {time.time() - start:.4f} s.')