import collections
import uuid
import json
import copy

import ayon_api
import ftrack_api

from ftrack_common import (
    CUST_ATTR_AUTO_SYNC,
    FTRACK_ID_ATTRIB,
    FTRACK_PATH_ATTRIB,
    ServerAction,
    get_service_ftrack_icon_url,
    get_ayon_attr_configs,
    query_custom_attribute_values,
)
from processor.lib import SyncFromFtrack

class PrepareProjectServer(ServerAction):
    """Prepare project attributes in Anatomy."""

    default_preset_name = "__default__"
    identifier = "prepare.project.server"
    label = "AYON Admin"
    variant = "- Prepare Project for AYON"
    description = "Set basic attributes on the project"
    icon = get_service_ftrack_icon_url("AYONAdmin.svg")

    role_list = ["Pypeclub", "Administrator", "Project Manager"]

    settings_key = "prepare_project"

    item_splitter = {"type": "label", "value": "---"}
    _keys_order = (
        "fps",
        "frameStart",
        "frameEnd",
        "handleStart",
        "handleEnd",
        "clipIn",
        "clipOut",
        "resolutionHeight",
        "resolutionWidth",
        "pixelAspect",
        "applications",
        "tools_env",
        "library_project",
    )

    def discover(self, session, entities, event):
        """Show only on project."""
        if (
            len(entities) != 1
            or entities[0].entity_type.lower() != "project"
        ):
            return False

        return self.valid_roles(session, entities, event)

    def _get_list_items(self, attr_name, attr_def, default):
        default = default or []
        title = attr_def["title"] or attr_name
        output = [
            {
                "type": "label",
                "value": "---"
            },
            {
                "type": "label",
                "value": f"Attribute '{title}' selection:"
            }
        ]
        mapping = {}
        for item in attr_def["enum"]:
            value = item["value"]
            name = uuid.uuid4().hex
            mapping[name] = value
            output.append({
                "type": "boolean",
                "label": item["label"],
                "name": name,
                "value": value in default
           })
        output.append({
            "type": "hidden",
            "value": json.dumps(mapping),
            "name": f"attr_list_{attr_name}"
        })
        return output

    def _get_autosync_value(self, session, project_entity):
        custom_attrs, _ = get_ayon_attr_configs(session)
        auto_sync_attr = None
        for attr in custom_attrs:
            if (
                attr["entity_type"] == "show"
                and attr["key"] == CUST_ATTR_AUTO_SYNC
            ):
                auto_sync_attr = attr
                break

        if auto_sync_attr is None:
            return None

        project_id = project_entity["id"]
        attr_id = auto_sync_attr["id"]
        value_items = query_custom_attribute_values(
            session, [attr_id], [project_id]
        )
        for item in value_items:
            value = item["value"]
            if value is not None:
                return value
        return True

    def _first_interface(self, session, project_entity):
        # Inform user that this may take a while
        self.log.debug("Preparing data which will be shown")

        primary_preset = self.default_preset_name
        anatomy_presets = [
            {"label": "Default", "value": self.default_preset_name}
        ]
        for anatomy_preset in ayon_api.get_project_anatomy_presets():
            name = anatomy_preset["name"]
            anatomy_presets.append({"label": name, "value": name})
            if anatomy_preset["primary"]:
                primary_preset = name

        ayon_autosync_value = self._get_autosync_value(
            session, project_entity)
        items = [
            {
                "type": "hidden",
                "name": "in_attribute_set",
                "value": False
            },
            {
                "type": "label",
                "value": "### Choose Anatomy Preset"
            },
            {
                "label": "AYON Anatomy Preset",
                "type": "enumerator",
                "name": "anatomy_preset",
                "data": anatomy_presets,
                "value": primary_preset
            }
        ]
        if ayon_autosync_value is not None:
            items.append({
                "label": "Enable auto-sync",
                "type": "boolean",
                "name": "auto_sync_project",
                "value": ayon_autosync_value
            })
        else:
            items.append({
                "type": "hidden",
                "name": "auto_sync_project",
                "value": False
            })

        return {
            "title": "Choose AYON Anatomy Preset",
            "submit_button_label": "Continue",
            "items": items
        }

    def _attributes_interface(self, event_values):
        anatomy_preset = event_values["anatomy_preset"]
        attribute_items = [
            {
                "type": "hidden",
                "name": "in_attribute_set",
                "value": True
            },
            {
                "type": "hidden",
                "name": "anatomy_preset",
                "value": anatomy_preset
            },
            {
                "type": "hidden",
                "name": "auto_sync_project",
                "value": event_values["auto_sync_project"]
            },
            {
                "type": "label",
                "value": (
                    "<b>You can validate or change your default"
                    " project attributes.</b>"
                )
            }
        ]
        if anatomy_preset == self.default_preset_name:
            anatomy_preset = None
        anatomy_preset_values = ayon_api.get_project_anatomy_preset(
            anatomy_preset)
        anatomy_attribute_values = anatomy_preset_values["attributes"]
        project_attributes = ayon_api.get_attributes_for_type("project")
        unknown_attributes = []
        list_attr_defs = []
        for attr_name, attr_def in project_attributes.items():
            if attr_name in (
                FTRACK_ID_ATTRIB,
                FTRACK_PATH_ATTRIB,
                "startDate",
                "endDate",
                "description",
            ):
                continue
            attr_type = attr_def["type"]
            default = anatomy_attribute_values.get(attr_name)
            if default is None:
                default = attr_def["default"]

            # Not sure how to show this
            if attr_type == "list_of_integers":
                continue

            # List of strings is handled differently
            if attr_type == "list_of_strings":
                list_attr_defs.append((attr_name, attr_def, default))
                continue

            item_base = {
                "name": f"attr_{attr_name}",
                "label": attr_def["title"] or attr_name,
                "value": default
            }
            if attr_type in ("float", "integer",):
                item_base["type"] = "number"

            elif attr_type == "datetime":
                item_base["type"] = "date"

            elif attr_type == "boolean":
                item_base["type"] = "boolean"

            elif attr_type == "string":
                item_base["type"] = "text"

            elif attr_type in ("list_of_strings", "list_of_integers"):
                item_base["type"] = "enumerator"
                item_base["data"] = attr_def["enum"]

            else:
                unknown_attributes.append({
                    "type": "label",
                    "value": f"{attr_name}: {attr_type}"
                })
                self.log.info("Unknown attribute type: {}".format(attr_type))
                continue
            attribute_items.append(item_base)

        for item in list_attr_defs:
            attribute_items.extend(self._get_list_items(*item))

        if unknown_attributes:
            attribute_items.append(
                {"type": "label", "value": "Unknown types"}
            )
            attribute_items.extend(unknown_attributes)

        return {
            "title": "Default project attributes",
            "submit_button_label": "Confirm",
            "items": attribute_items
        }

    def interface(self, session, entities, event):
        event_values = event["data"].get("values")

        project_entity = entities[0]
        project_name = project_entity["full_name"]
        syncer = SyncFromFtrack(session, project_name, self.log)
        if syncer.project_exists_in_ayon():
            return {
                "message": "Project already exists in Ayon.",
                "success": True
            }

        self.show_message(event, "Preparing data... Please wait", True)
        if not event_values:
            return self._first_interface(session, project_entity)

        # Exit interface once attributes are confirmed
        if event_values["in_attribute_set"]:
            return

        # User did not want to modify default attributes
        return self._attributes_interface(event_values)

    def _set_ftrack_attributes(self, session, project_entity, values):
        custom_attrs, hier_custom_attrs = get_ayon_attr_configs(session)
        project_attrs = [
            attr
            for attr in custom_attrs
            if attr["entity_type"] == "show"
        ]
        hier_attrs_by_name = {
            attr["key"]: attr for attr in hier_custom_attrs
        }
        attrs_by_name = {
            attr["key"]: attr for attr in project_attrs
        }

        attr_ids = {
            attr["id"]
            for attr in project_attrs
        } | {
            attr["id"]
            for attr in hier_custom_attrs
        }
        value_items = query_custom_attribute_values(
            session, attr_ids, [project_entity["id"]]
        )
        values_by_attr_id = {}
        for value_item in value_items:
            value = value_item["value"]
            attr_id = value_item["configuration_id"]
            values_by_attr_id[attr_id] = value

        for attr_name, attr_value in values.items():
            attrs = [
                attrs_by_name.get(attr_name),
                hier_attrs_by_name.get(attr_name)
            ]
            for attr in attrs:
                if attr is None:
                    continue
                attr_id = attr["id"]
                is_new = attr_id not in values_by_attr_id
                current_value = values_by_attr_id.get(attr_id)

                entity_key = collections.OrderedDict((
                    ("configuration_id", attr_id),
                    ("entity_id", project_entity["id"])
                ))
                op = None
                if is_new:
                    op = ftrack_api.operation.CreateEntityOperation(
                        "CustomAttributeValue",
                        entity_key,
                        {"value": attr_value}
                    )

                elif current_value != attr_value:
                    op = ftrack_api.operation.UpdateEntityOperation(
                        "CustomAttributeValue",
                        entity_key,
                        "value",
                        current_value,
                        attr_value
                    )

                if op is not None:
                    session.recorded_operations.push(op)

        if session.recorded_operations:
            session.commit()

    def launch(self, session, entities, event):
        event_values = event["data"].get("values")
        if not event_values:
            return

        project_entity = entities[0]
        project_name = project_entity["full_name"]
        syncer = SyncFromFtrack(session, project_name, self.log)
        if syncer.project_exists_in_ayon():
            return {
                "message": "Project already exists in Ayon.",
                "success": True
            }

        attributes = {}
        list_mapping = {}
        for key, value in event_values.items():
            if key.startswith("attr_list_"):
                attr_name = key[10:]
                list_mapping[attr_name] = json.loads(value)
            elif key.startswith("attr_"):
                attributes[key[5:]] = value

        for attr_name, mapping in list_mapping.items():
            final_value = []
            for item_id, value in mapping.items():
                item_value = event_values[item_id]
                if item_value:
                    final_value.append(value)

            attributes[attr_name] = final_value

        anatomy_preset = event_values["anatomy_preset"]
        if anatomy_preset == self.default_preset_name:
            anatomy_preset = None
        syncer.create_project(anatomy_preset, attributes)

        ayon_project = ayon_api.get_project(project_entity["full_name"])
        values = copy.deepcopy(ayon_project["attrib"])
        auto_sync_project = event_values["auto_sync_project"]
        values[CUST_ATTR_AUTO_SYNC] = auto_sync_project
        self._set_ftrack_attributes(session, project_entity, values)

        if not auto_sync_project:
            event_data = {
                "actionIdentifier": "sync.from.ftrack.to.ayon",
                "selection": [{
                    "entityId": project_entity["id"],
                    "entityType": "show"
                }]
            }
            user = session.query(
                "User where username is \"{}\"".format(session.api_user)
            ).one()
            user_data = {
                "username": user["username"],
                "id": user["id"]
            }
            self.trigger_event(
                "ftrack.action.launch",
                event_data=event_data,
                session=session,
                source=user_data,
                event=event,
                on_error="ignore"
            )

        report_items = syncer.report_items
        if report_items:
            self.show_interface(
                report_items,
                title="Prepare Project report",
                event=event
            )
        self.log.info(f"Project '{project_name}' prepared")
        return {
            "message": "Project created in AYON.",
            "success": True
        }

def register(session):
    PrepareProjectServer(session).register()


import rasterio
from rasterio.plot import show

def show_data(gds, title=""):
    print(f"Metadados: {gds.meta}")
    print(f"Dados: {gds.read()}")

    show(gds, title=title)

def write_data(gds):
    data = gds.read()
    with rasterio.open(fp="../output_data/nepal_lc_2020_new.tif",
        mode="w",
        driver=gds.driver,
        height=gds.height,
        width=gds.width,
        count=gds.count,
        crs=gds.crs,
        transform=gds.transform,
        dtype=data.dtype,
        nodata=gds.nodata
    ) as file:
        file.write(data)

def main():
    gds = rasterio.open("../data/nepal_lc_2020.tif")

    show_data(gds, "Original dataset")
    write_data(gds)

    new_gds = rasterio.open("../output_data/nepal_lc_2020_new.tif")

    show_data(new_gds, "Edited dataset")

if __name__ == "__main__":
    main()


from lxml import etree
import json
from utils import get_page
import datetime

def get_project(name):
    project_page = etree.HTML(get_page('https://www.openhub.net/p/' + name).decode('utf-8'))

    project_name = project_page.xpath(u"//*[@id=\"project_header\"]/div[1]/h1/a")[0].text
    project_tag = project_page.xpath(u"//*[@id=\"project_tags\"]/p")[0].text

    similar_projects = project_page.xpath(u"//*[@id=\"similar_projects\"]")[0].text

    manager = project_page.xpath(u"//*[@id=\"page_contents\"]/div[3]/div[2]/div/dl/dd[5]/a")[0].text

    licenses = project_page.xpath(u"//*[@id=\"page_contents\"]/div[3]/div[2]/div/dl/dd[3]")[0].text

    location_page = etree.HTML(get_page('https://www.openhub.net/p/' + name + '/enlistments').decode('utf-8'))

    location_table = location_page.xpath(u"//table//tbody")[0]
    locations = [c.getchildren()[0].text.strip() for c in location_table.getchildren()]
    code_location = '\t'.join(locations)
    project = {"update_time": datetime.datetime.now().isoformat(), "project_name": project_name, "project_tag": project_tag, "similar_projects": similar_projects, "manager": manager, "licenses": licenses, "code_location": code_location }
    for key in project:
        if project[key] is None:
            project[key] = ''
    return project

# //*[@id="analyses_language_table"]


import requests
from urllib.parse import urljoin
from datetime import datetime

from src.models import Repository

def parse_datetime(datestring: str) -> datetime:
    datestring = datestring.replace("Z", "+00:00")
    return datetime.fromisoformat(datestring)

def load_repository(data: dict) -> Repository:
    return Repository(
        id=data["id"],
        name=data["name"],
        full_name=data["full_name"],
        description=data["description"],
        topics=data["topics"],
        license=data["license"].get("name") if data["license"] else None,
        private=data["private"],
        forked=data["fork"],
        open_issues_count=data["open_issues_count"],
        commits_count=data["size"],
        stargazers_count=data["stargazers_count"],
        watchers_count=data["watchers_count"],
        repository_url=data["html_url"],
        created_at=parse_datetime(data["created_at"]),
        updated_at=parse_datetime(data["updated_at"]),
        showcase_url=data["homepage"] or None,
    )

class Github(requests.Session):
    def __init__(self, username, access_token):
        super(Github, self).__init__()
        self.base_url = "https://api.github.com"
        self.username = username
        self.auth = (username, access_token)
        self.headers = {"Accept": "application/vnd.github.mercy-preview+json"}

    def request(self, method, url, *args, **kwargs):
        url = urljoin(self.base_url, url)
        return super(Github, self).request(method, url, *args, **kwargs)

    def get_my_repositories(self):
        response = self.get(f"/users/{self.username}/repos")
        return [load_repository(repo_data) for repo_data in response.json()]

if __name__ == "__main__":
    from settings import GITHUB_USERNAME, GITHUB_TOKEN

    github = Github(GITHUB_USERNAME, GITHUB_TOKEN)
    repositories = github.get_my_repositories()

    for repository in repositories:
        print(repository)


# https://leetcode.com/problems/wiggle-subsequence/

def wiggleMaxLength(nums: list):
    n = len(nums)
    if n < 2:
        return n

    prevdiff = nums[1] - nums[0]
    ret = (2 if prevdiff != 0 else 1)
    for i in range(2, n):
        diff = nums[i] - nums[i - 1]
        if (diff > 0 and prevdiff <= 0) or (diff < 0 and prevdiff >= 0):
            ret += 1
            prevdiff = diff

    return ret

if __name__ == "__main__":
    nums = [1, 1, 7, 4, 9, 2, 5]
    print(wiggleMaxLength(nums))


from asyncio import sleep
import itertools
from pyboy import WindowEvent
from AISettings.AISettingsInterface import AISettingsInterface, Config

# Macros
DMG_REWARD = 10
FAINT_REWARD = 100
ENCOUNTER_REWARD = 1000
GYM_REWARD = 10000

class GameState():
    def __init__(self, pyboy):
        game_wrapper = pyboy.game_wrapper()
        self.money = game_wrapper.money
        self.badges = game_wrapper.badges
        self.current_poke_hp = game_wrapper.current_poke_hp
        self.current_poke_max_hp = game_wrapper.current_poke_max_hp
        self.current_poke_level = game_wrapper.current_poke_level
        self.opponent_poke_hp = game_wrapper.opponent_poke_hp
        self.opponent_poke_max_hp = game_wrapper.opponent_poke_max_hp
        self.opponent_poke_level = game_wrapper.opponent_poke_level
        self.scene = game_wrapper.scene
        self.low_hp = bool(game_wrapper.low_hp)
        self.player_location = game_wrapper.player_location
        self.textbox = bool(game_wrapper.textbox)

class PokeAI(AISettingsInterface):
	def __init__(self):
		self.realMax = [] #[[1,1, 2500], [1,1, 200]]

	def GetReward(self, prevGameState: GameState, pyboy):
		# timeRespawn = pyboy.get_memory_value(0xFFA6) #Time until respawn from death (set when Mario has fell to the bottom of the screen)
		# if(timeRespawn > 0): # if we cant move return 0 reward otherwise we could be punished for crossing a level
		# 	return 0

		"Get current game state"
		current_state = self.GetGameState(pyboy)

		reward = 0

		if current_state.scene == "overworld":
			#reward += self.ComputeMovementReward(prevGameState, current_state)
			reward += self.ComputeBadgeReward(prevGameState, current_state)
		elif current_state.scene == "wild":
			if prevGameState.scene == "overworld":
				reward += 0.1
			reward += self.ComputeBattleReward(prevGameState, current_state)
		elif current_state.scene == "trainer":
			if prevGameState.scene == "overworld":
				reward += 0.5
			reward += self.ComputeBattleReward(prevGameState, current_state)
		elif current_state.scene == "gym":
			if prevGameState.scene == "overworld":
				reward += 1
			reward += self.ComputeBattleReward(prevGameState, current_state)

		return reward

	def ComputeBattleReward(self, prevGameState: GameState, currentGameState: GameState):
		poke_hp_diff = currentGameState.current_poke_hp - prevGameState.current_poke_hp
		opponent_hp_diff = currentGameState.opponent_poke_hp - prevGameState.opponent_poke_hp
		if opponent_hp_diff < 0:
			opponent_reward = - DMG_REWARD*(opponent_hp_diff/currentGameState.opponent_poke_max_hp)
		else:
			opponent_reward = 0
		low_hp_reward = -0.05 if currentGameState.low_hp else 0
		return DMG_REWARD*(poke_hp_diff/currentGameState.current_poke_max_hp) + opponent_reward + low_hp_reward

	def ComputeBadgeReward(self, prevGameState: GameState, currentGameState: GameState):
		return 1 if currentGameState.badges > prevGameState.badges else 0

	def ComputeMovementReward(self, prevGameState: GameState, currentGameState: GameState):
		if prevGameState.player_location == currentGameState.player_location: #and currentGameState.textbox == False:
			return -0.0001
		else:
			return 0

	def GetActions(self):
		baseActions = [WindowEvent.PRESS_BUTTON_A,
                       WindowEvent.PRESS_BUTTON_B,
                       WindowEvent.PRESS_ARROW_UP,
                       WindowEvent.PRESS_ARROW_DOWN,
                       WindowEvent.PRESS_ARROW_LEFT,
                       WindowEvent.PRESS_ARROW_RIGHT,
                       WindowEvent.PRESS_BUTTON_START
                       ]

		totalActionsWithRepeats = list(itertools.permutations(baseActions, 2))
		withoutRepeats = []

		# for combination in totalActionsWithRepeats:
		# 	reversedCombination = combination[::-1]
		# 	if(reversedCombination not in withoutRepeats):
		# 		withoutRepeats.append(combination)

		filteredActions = [[action] for action in baseActions] + withoutRepeats

		return filteredActions

	def PrintGameState(self, pyboy):
		#gameState = GameState(pyboy)
		game_wrapper = pyboy.game_wrapper()

		print(repr(game_wrapper))

	def GetGameState(self, pyboy):
		return GameState(pyboy)

	def GetHyperParameters(self) -> Config:
		config = Config()
		config.exploration_rate_decay = 0.999
		return config

	def GetLength(self, pyboy):
		return pyboy.game_wrapper().badges


#Нисуев Нису ИУ7-12Б
#Формирование матрицы С путем перемножения элементов матриц А и В
#Поиск суммы элементов всех столбцов

#Блок ввода матриц
n = int(input('Введите количество строк матриц A и B: '))
m = int(input('Введите количество столбцов матриц А и В: '))

while m <= 0 or n <= 0:
	print('В матрицах должно быть больше нуля столбцов и строк')
	n = int(input('Введите количество строк матриц А и В: '))
	m = int(input('Введите количество столбцов матриц А и В: '))

#Ввод матрицы А
a = []
for i in range(n):
	print()
	a.append([])
	for j in range(m):
		a[i].append(float(input(f'Введите {j + 1}-й элемент {i + 1}-й строки матрицы А: ')))

#Вывод матрицы A
print('Mатрица A:')
for i in range(n):
	for j in range(m):
		print('{:10.5g}'.format(a[i][j]),end='')
	print()
print()

#Ввод матрицы В
b = []
for i in range(n):
	print()
	b.append([])
	for j in range(m):
		b[i].append(float(input(f'Введите {j + 1}-й элемент {i + 1}-й строки матрицы B: ')))

#Вывод матрицы B
print('Mатрица B:')
for i in range(n):
	for j in range(m):
		print('{:10.5g}'.format(b[i][j]),end='')
	print()
print()

c = [[0] * m for i in range(n)] #Ввод матрицы С

#Создание матрицы С по правилу
for i in range(n):
	for j in range(m):
		c[i][j] = a[i][j] * b[i][j] #Перемножение соответствующих элементов матриц А и В

#Вывод матрицы C
print('Mатрица C:')
for i in range(n):
	for j in range(m):
		print('{:10.5g}'.format(c[i][j]),end='')
	print()
print()

#Подсчет суммы столбцов
v = [0] * m #Создание списка сумм
for j in range(m):
	sum_el = 0
	for i in range(n):
		sum_el += c[i][j] #Поиск суммы элементов столбца
	v[j] = sum_el

for i in range(m):
	print(f'Сумма элементов {i + 1} столбца матрицы С: ', v[i])


"""
.. py:module:: simulation

Basic simulation implementation where agents in the same environment can be
run in an iterative manner.
"""
import time
import logging
from random import shuffle

from creamas.core.agent import CreativeAgent
from creamas.core.environment import Environment
from creamas.logging import ObjectLogger
from creamas import util

__all__ = ['Simulation']

class Simulation:
    """A base class for iterative simulations.

    In each step the simulation calls :py:meth:`~creamas.core.agent.CreativeAgent.act` for each agent in the simulation.

    Functions :py:meth:`~creamas.core.simulation.Simulation.step`,
    :py:meth:`~creamas.core.simulation.Simulation.steps`, :py:meth:`~creamas.core.simulation.Simulation.async_step`
    and :py:meth:`~creamas.core.simulation.Simulation.async_steps` are used to advance the simulation.
    """
    @classmethod
    def create(cls, agent_cls=None, n_agents=10, agent_kwargs={}, env_cls=Environment, env_kwargs={}, callback=None,
               conns=0, log_folder=None):
        """A convenience function to create simple simulations.

        Method first creates an environment, then instantiates agents into it with given arguments, and finally creates
        simulation for the environment.

        :param agent_cls:
            class for agents, or list of classes. If list, then **n_agents** and **agent_kwargs** are expected to be
            lists also.

        :param n_agents:
            amount of agents for simulation, or list of amounts

        :param agent_kwargs:
            keyword arguments passed to agents at creation time, or list of keyword arguments.

        :param env_cls:
            environment class for simulation

        :type env_cls:
            :py:class:`~creamas.core.environment.Environment`

        :param dict env_kwargs:
            keyword arguments passed to environment at creation time

        :param callable callback:
            optional callable to call after each simulation step

        :param conns:
            Create **conns** amount of initial (random) connections for agents in the simulation environment.

        :param str log_folder:
            folder for possible logging. This overwrites *log_folder* keyword argument from **agent_kwargs** and
            **env_kwargs**.
        """
        if not issubclass(env_cls, Environment):
            raise TypeError("Environment class must be derived from ({}"
                            .format(Environment.__class__.__name__))
        if callback is not None and not hasattr(callback, '__call__'):
            raise TypeError("Callback must be callable.")

        if hasattr(agent_cls, '__iter__'):
            for e in agent_cls:
                if not issubclass(e, CreativeAgent):
                    raise TypeError("All agent classes must be derived from {}"
                                    .format(CreativeAgent.__class__.__name__))
        else:
            if not issubclass(agent_cls, CreativeAgent):
                raise TypeError("Agent class must be derived from {}"
                                .format(CreativeAgent.__class__.__name__))

        env = env_cls.create(**env_kwargs)

        agents = []
        if hasattr(agent_cls, '__iter__'):
            for i in range(len(n_agents)):
                agent_kwargs[i]['environment'] = env
                agent_kwargs[i]['log_folder'] = log_folder
                agents = agents + [agent_cls[i](**agent_kwargs[i]) for _ in
                                   range(n_agents[i])]
        else:
            agent_kwargs['environment'] = env
            agent_kwargs['log_folder'] = log_folder
            agents = [agent_cls(**agent_kwargs) for _ in range(n_agents)]

        if conns > 0:
            env.create_random_connections(n=conns)

        return Simulation(env, callback, log_folder)

    def __init__(self, env, callback=None, log_folder=None):
        """Create a simulation for an existing environment.

        :param env: An environment.
        :type env:
            :class:`~creamas.core.environment.Environment`,
            :class:`~creamas.mp.MultiEnvironment` or
            :class:`~creamas.ds.DistributedEnvironment`
        :param callable callback: function to call after each simulation step
        :param str log_folder: folder to log simulation information
        """
        self._env = env
        self._callback = callback
        self._cur_step = 0
        self._order = 'alphabetical'
        self._name = 'sim'
        self._start_time = time.monotonic()
        self._step_start_time = None
        self._step_processing_time = 0.0
        self._processing_time = 0.0
        self._end_time = None

        # List of agents that have not been triggered for current step.
        self._agents_to_act = []

        if type(log_folder) is str:
            self.logger = ObjectLogger(self, log_folder, add_name=False,
                                       init=True)
        else:
            self.logger = None

    @property
    def name(self):
        """Name of the simulation as a string.

        """
        return self._name

    @property
    def env(self):
        """Environment for the simulation.
        """
        return self._env

    @property
    def cur_step(self):
        """The simulation's current step as an integer.
        """
        return self._cur_step

    @property
    def callback(self):
        """Callable to be called after each simulation step for any extra bookkeeping, etc.. Callback should accept one
        parameter: *cur_step* that is the simulation's current step.
        """
        return self._callback

    @property
    def order(self):
        """Order in which agents are run. Order is not enforced for asynchronous executions.

        Possible values:

        * alphabetical: agents are sorted by name
        * random: agents are shuffled

        Changing the order while iteration is unfinished will take place in the next iteration.
        """
        return self._order

    @order.setter
    def order(self, order):
        assert order in ['alphabetical', 'random']
        self._order = order

    def _get_order_agents(self):
        agents = self.env.get_agents(addr=True)
        if self.order == 'alphabetical':
            return sorted(agents)
        shuffle(agents)
        return agents

    def _init_step(self):
        """Initialize next step of simulation to be run.
        """
        self._cur_step += 1
        self.env.age = self.cur_step
        self._log(logging.INFO, "")
        self._log(logging.INFO, "\t***** Step {:0>10} *****". format(self.cur_step))
        self._log(logging.INFO, "")
        self._agents_to_act = self._get_order_agents()
        self._step_processing_time = 0.0
        self._step_start_time = time.monotonic()

    def _finalize_step(self):
        """Finalize simulation step after all agents have acted for the current
        step.
        """
        t = time.time()
        if self._callback is not None:
            self._callback(self.cur_step)
        t2 = time.monotonic()
        self._step_processing_time += t2 - t
        self._log(logging.INFO, "Step {} run in: {:.3f}s ({:.3f}s of "
                  "actual processing time used)"
                  .format(self.cur_step, self._step_processing_time,
                          t2 - self._step_start_time))
        self._processing_time += self._step_processing_time

    def finish_step(self):
        """Progress simulation to the end of the current step.

        .. deprecated:: 0.4.0
            Use :func:`step` instead.
        """
        rets = []
        while len(self._agents_to_act) > 0:
            ret = self.next()
            rets.append(ret)
        return rets

    def step(self):
        """Progress simulation by a single step.
        """
        assert len(self._agents_to_act) == 0
        t = time.monotonic()
        rets = []

        self._init_step()

        while len(self._agents_to_act) > 0:
            addr = self._agents_to_act.pop(0)
            ret = util.run(self.env.trigger_act(addr=addr))
            rets.append(ret)

        self._finalize_step()
        self._step_processing_time = time.monotonic() - t
        return rets

    def steps(self, n):
        """Progress simulation with given amount of steps.

        Can not be called when some of the agents have not acted for the current step.

        :param int n: amount of steps to run
        """
        assert len(self._agents_to_act) == 0
        rets = []
        for _ in range(n):
            ret = self.step()
            rets.append(ret)

        return rets

    def async_step(self):
        """Progress simulation by running all agents asynchronously once.
        """
        assert len(self._agents_to_act) == 0
        self._init_step()
        t = time.time()
        ret = util.run(self.env.trigger_all())
        self._agents_to_act = []
        self._step_processing_time = time.monotonic() - t
        self._finalize_step()
        return ret

    def async_steps(self, n):
        """Progress simulation by running all agents *n* times asynchronously.
        """
        assert len(self._agents_to_act) == 0
        rets = []
        for _ in range(n):
            ret = self.async_step()
            rets.append(ret)

        return rets

    def _log(self, level, msg):
        if self.logger is not None:
            self.logger.log(level, msg)

    def end(self, folder=None):
        """Close the simulation and the current simulation environment.

        .. deprecated:: 0.4.0
            Use func:`close` instead.
        """
        return self.close(folder=folder)

    def close(self, folder=None):
        """Close the simulation and the current simulation environment.
        """
        ret = self.env.close(folder=folder)
        self._end_time = time.time()
        self._log(logging.DEBUG, "{} step simulation completed in {:.3f}s (actual processing time {:.3f}s)."
                  .format(self.cur_step, self._end_time - self._start_time, self._processing_time))
        return ret


#ionization.py - define charge production models
from . import kinematics as kin
import numpy as np

import scipy.integrate as integrate
import scipy.interpolate as interp
import scipy.ndimage as ndi

import os

import matplotlib
matplotlib.rcParams['text.usetex'] = True
import matplotlib.pyplot as plt

#get the gaussian p_n defined in 2004.10709
def get_p_n_Si_gauss(n):
    F_inf = 0.119
    eps_inf = 3.8

    norm = np.sqrt(2*np.pi*n*F_inf)
    std_dev = np.sqrt(n*F_inf)*eps_inf

    def p_n(E):
        num = n*eps_inf - E
        return (1/norm)*np.exp(-0.5*(num/std_dev)**2)

    if(n == 0):
        def p_0(E):
            return 1*np.heaviside(1.2 - E, 1)
        return p_0
    if n == 1:
        def p_1(E):
            E = min(E, 2*eps_inf)
            p_2 = get_p_n_Si_gauss(2)
            p_3 = get_p_n_Si_gauss(3)
            return (1 - p_2(E) - p_3(E))*np.heaviside(E - 1.2, 1)
        return p_1

    return p_n

#for the low energy bins we load the calculations from 2004.10709
def get_p_n_Si(n):
    data_file = os.path.dirname(__file__) + '/../../targets/data/Si/ionization/p0K.dat'

    if(n == 0):
        def p_0(E):
            return 1*np.heaviside(1.2 - E, 1)
        return p_0
    if(n <= 10):
        prob_tab = np.genfromtxt(data_file)
        energies = list(zip(*prob_tab))[0]
        probs = list(zip(*prob_tab))[n]

        p_n = interp.interp1d(energies, probs, bounds_error=False, fill_value=0, kind='quadratic')

        return p_n
    return get_p_n_Si_gauss(n)

#Fano smearing for the binned method
def Fano_smearing(bins, hist, F, nsig = 5):
    N_e_low = bins[0]
    N_e_hi = bins[-1]

    N_e_low_smeared = max(np.floor(N_e_low - nsig*np.sqrt(N_e_low*F)), 0)
    N_e_hi_smeared = np.ceil(N_e_hi + nsig*np.sqrt(N_e_hi*F))

    smeared_bins = np.arange(N_e_low_smeared, N_e_hi_smeared + 1)
    smeared_hist = [0]*len(smeared_bins)

    for (i, n) in enumerate(bins):
        std_dev = np.sqrt(n*F)

        temp_hist = [0]*len(smeared_bins)
        #need to determine the bin index to place the value from the original histogram
        th_index = None
        for j in range(len(smeared_bins)):
            if smeared_bins[j] == n:
                th_index = j

        if(th_index == None):
            print("error in fano smearing")
            exit()

        temp_hist[th_index] = hist[i]

        smear = ndi.gaussian_filter(temp_hist, std_dev, truncate=nsig)
        smeared_hist = np.add(smeared_hist, smear)

    return smeared_bins, smeared_hist

#produces the spectrum of electron events in Silicon from a spectrum of ionization energy by chopping the spectrum into bins of 3.8eV
#and applying fano smearing
def Si_electron_spectrum_binned(Eion_spectrum, Y, En, c, A, flux = 1, number_of_bins=20, fano=True):
    ER_el = kin.E_R_elastic(c, A, En)
    e0 = 3.8
    F = 0.119

    E_el_Q = Y(ER_el)*ER_el

    n_e_base = np.floor(E_el_Q/e0)

    first_bin = n_e_base*e0 + 1.2
    last_bin = first_bin + (number_of_bins + 1)*e0

    bins = np.arange(first_bin, last_bin, e0)
    n_e_bins = np.arange(1, number_of_bins + 1, 1, dtype=int)

    hist = []

    for n_e in n_e_bins:
        lower_bound = np.round(bins[n_e - 1], 6)
        upper_bound = np.round(bins[n_e], 6)
        rate = flux*integrate.quad(Eion_spectrum, lower_bound, upper_bound, limit=100, epsrel=1e-4)[0]
        # ~ E_range = np.geomspace(lower_bound, upper_bound, 101)
        # ~ samples = Eion_spectrum(E_range)
        # ~ rate = flux*integrate.trapz(samples, E_range)
        if rate < 1e-12:
            rate = 0
        hist.append(rate)

    if(n_e_base == 0):
        zero_bin = rate = flux*integrate.quad(Eion_spectrum, 0, 1.2, limit=100, epsrel=1e-4)[0]
        hist = [zero_bin] + hist
        n_e_bins = [0] + n_e_bins

    if(fano == True):
        fano_bins, fano_hist = Fano_smearing(n_e_bins, hist, F, nsig = 5)
        return fano_bins, fano_hist

    return n_e_bins, hist

#produces the spectrum of electron events in a noble gas
def noblegas_electron_spectrum_binned(Eion_spectrum, Y, W, F, En, c, A, flux = 1, number_of_bins=20, fano=True):
    ER_el = kin.E_R_elastic(c, A, En)
    e0 = W
    F = F

    E_el_Q = Y(ER_el)*ER_el

    n_e_base = np.floor(E_el_Q/e0)

    first_bin = n_e_base*e0
    last_bin = first_bin + (number_of_bins + 1)*e0

    bins = np.arange(first_bin, last_bin, e0)
    n_e_bins = np.arange(n_e_base, number_of_bins + 1, 1, dtype=int)
    hist = []

    for n_e in n_e_bins:
        # lower_bound = np.round(bins[n_e - 1], 6)
        # upper_bound = np.round(bins[n_e], 6)
        lower_bound = n_e*e0
        upper_bound = (n_e+1)*e0
        rate = flux*integrate.quad(Eion_spectrum, lower_bound, upper_bound, limit=100, epsrel=1e-4)[0]

        if rate < 1e-12:
            rate = 0
        hist.append(rate)

    if(fano == True):
        fano_bins, fano_hist = Fano_smearing(n_e_bins, hist, F, nsig = 5)
        return fano_bins, fano_hist

    return n_e_bins, hist

def noblegas_electron_spectrum_binned_elastic(rate, Y, W, F, En, c, A, flux = 1, number_of_bins=20, fano=True):
    ER_el = kin.E_R_elastic(c, A, En)
    e0 = W
    F = F

    E_el_Q = Y(ER_el)*ER_el

    n_e_base = np.floor(E_el_Q/e0)

    n_e_bins = np.arange(n_e_base, n_e_base + 2, dtype=int)

    hist = []

    hist.append(rate)
    hist.append(0)

    if(fano == True):
        fano_bins, fano_hist = Fano_smearing(n_e_bins, hist, F, nsig = 5)
        return fano_bins, fano_hist

    return n_e_bins, hist

#produces spectrum by integrating against the n electron probabilities from 2004.10709
def Si_electron_spectrum(Eion_spectrum, ER_Q, flux=1, start_bin=0, number_of_bins=20, gaussian=False):
    n_bins = np.arange(start_bin, start_bin + number_of_bins, 1, dtype=int)
    r_bins = []

    for n in n_bins:
        if gaussian==True:
            p_n = get_p_n_Si_gauss(n)
        else:
            p_n = get_p_n_Si(n)

        integrand = lambda E: flux*Eion_spectrum(E)*p_n(E)
        E_range = np.geomspace(1 + ER_Q, 1000 + ER_Q, 201)

        samples = integrand(E_range)

        I = integrate.trapezoid(samples, E_range)

        r_bins.append(I)

    return n_bins, r_bins

def Si_elastic_electron_spectrum_fixed_angle(ER_Q, Elastic_Rate, start_bin=0, number_of_bins=20, gaussian=False):
    n_bins = np.arange(start_bin, start_bin + number_of_bins, 1, dtype=int)
    r_bins = []

    for n in n_bins:
        if gaussian==True:
            p_n = get_p_n_Si_gauss(n)
        else:
            p_n = get_p_n_Si(n)

        rate = Elastic_Rate*p_n(ER_Q) #because the elastic spectrum is a delta function at fixed angle
        if(rate < 1e-10):
            rate = 0

        r_bins.append(rate)

    return n_bins, r_bins


from pokemon import pokemon

def inicio():
  pokemonPlayer = pokemon("Charizard", 100)
  pokemonEnemy = pokemon("Squirtle", 50)

  trocar  = int(input("Antes de iniciarmos a batalha deseja trocar o nome do seu " + pokemonPlayer.nome + "?\n"))
  if trocar == 1:
    nomeNovo = input("Coloque o novo nome do seu pokemon: ")
    pokemonPlayer.nome = nomeNovo
    print("O nome do seu pokemon agora se chama " + pokemonPlayer.nome)
  else:
    print("Tudo bem então, vamos continuar a batalha")
  print("==========================")
  print("Vai " + pokemonPlayer.nome + " eu escolho você")
  print("Acaba com ele " + pokemonPlayer.nome)
  print("==========================")

  while pokemonPlayer.Hp > pokemonEnemy.Hp or pokemonPlayer.Hp < pokemonEnemy.Hp:
    Hud(pokemonPlayer.nome, pokemonPlayer.Hp, pokemonEnemy.nome, pokemonEnemy.Hp)

print("------------------------------------")
print("Bem-vindo ao pokemon battle system.")
print("Deseja jogar?")
jogar = int(input("1 - Sim \n2 - Não\n"))

while jogar == 1:
  inicio()


A = int(input())
X = int(input())

def divide(A, X):
    if X == 1:
        return A

    if X % 2 == 0:
        return (divide(A, X//2)**2) % 1000000007
    else:
        return (divide(A, X//2)**2*A) % 1000000007

print(divide(A, X))

C = int(input())
n = int(input())

def fpow(C, n):
    if n == 1:
        return C
    result = 1
    while n:
        if n & 1:
            result = (result*C) % 1000000007
        C = (C*C) % 1000000007
        n >>= 1
    return result

print(fpow(C, n))


import math
import itertools

# Завдання 1: Обчислення кількості розміщень без повторень
n = 12
r = 6

# Обчислення кількості розміщень без повторень
arrangements = math.perm(n, r)

# Виведення результату
print("Кількість розміщень без повторень:", arrangements)

# Завдання 2: Побудова таблиці для чисел Стірлінга другого роду та числа Белла
i = 9
n = i + 5

# Побудова таблиці для чисел Стірлінга другого роду
stirling_table = []
for k in range(n + 1):
    row = []
    for j in range(i + 1):
        if j == 0 or j > k:
            row.append(0)
        elif j == 1 or j == k:
            row.append(1)
        else:
            row.append(j * stirling_table[k - 1][j] + stirling_table[k - 1][j - 1])
    stirling_table.append(row)

# Обчислення числа Белла
bell_number = sum(stirling_table[n])

# Виведення результатів
print("Таблиця чисел Стірлінга другого роду:")
for row in stirling_table:
    print(row)
print("Число Белла для n =", n, ":", bell_number)


# 抽取网页的模块
import lxml.html
# 之前的版本，cssselect直接在lxml中包含了，但是现在作为一个单独的模块出现了。因此需要单独安装。=

import json
import string
# import cssselect
from classMethod.Downloader import Downloader

import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)

# 测试一下动态提取的功能
#  了解网页是如何加载数据的（这个过程被称为逆向工程）
if __name__ == "__main__":
    # 在爬取动态的网页的时候，没能爬取到当前的动态网页的情况，所以爬取的动态的内容为空
    D = Downloader()
    # 下面下载的是带有AJAX的网页反馈的内容
    # html = D('http://example.webscraping.com/ajax/search.json?page=0&page_size=10&search_term=a')
    # 在这个网页的下载中，使用的是ajax连接的搜索
    # page应该表示的是ajax库里总的页数
    # 搜索的结果还会被分为多个页面
    # 具体的网页的搜索的条件，是根据不同的网页来进行调整的
    # 分为多少页是与page_size的大小有关系
    # ajax响应返回的数据是JSON格式的，可以用
    # python的JSON模块解析成为一个字典
    # final_result = json.load(html)
    # 使用库来结构下载的网页的模型，来提取详细的信息
    # tree = lxml.html.fromstring(html)
    # result = tree.cssselect('div#results a')
    # print(final_result)

    # 动态的搜索动态网页的所有的查询结果
    # 格式化的网页模板 format()的填充方式
    template_url = 'http://example.webscraping.com/ajax/search.json?page={}&page_size=10&search_term={}'
    contries = set()
    # 这个网页，每一个字母就是一个搜索的条件
    for letter in string.ascii_lowercase:
        page = 0
        while True:
            html = D(template_url.format(page, letter))
            try:
                # 下载返回的是JSON格式的数据
                ajax = json.load(html)
            except ValueError as e:
                print(e)
                ajax = None
            else:
                for record in ajax['records']:
                    # 加入字典一下，是为了去掉重复
                    contries.add(record['country'])

            page += 1
            if ajax is None or page >= ajax['num_pages']:
                break

    # 生成的数据进行保存
    open('countries.txt', 'w').write('\n'.join(sorted(contries)))
    # 使用的边界条件，也可以更高效的继续宁查询，像是page_size提高显示的数量，也可以使得下载的次数减少
    # 像是匹配的搜索的条件search_term使用正则表达式进行的搜索条件，可以不用进行循环
    # 看网页的情况而定

    # 也可以按行写入CSV文件中


import argparse
from dcore._dispatcher import MeshReFreq, MeshImFreq, GfReFreq, GfImFreq
from dcore.version import version, print_header
import numpy
import toml

def _set_n_pade(omega_cutoff, beta, n_min, n_max):
    """
    Return (int)n_pade: the number of Matsubara frequencies below the cutoff frequency.
    n_pade is bounded between n_min and n_max
    """
    n_pade = int((beta * omega_cutoff + numpy.pi) / (2.0 * numpy.pi))
    print("n_pade = {} (evaluated from omega_pade)".format(n_pade))
    n_pade = max(n_pade, n_min)
    n_pade = min(n_pade, n_max)
    print("n_pade = {}".format(n_pade))
    return n_pade

def dcore_pade(seedname):
    print("Reading ", seedname + "_anacont.toml...")
    with open(seedname + "_anacont.toml", "r") as f:
        params = toml.load(f)

    print("Reading ", seedname + "_sigma_iw.npz...")
    npz = numpy.load(seedname + "_sigma_iw.npz")

    assert params["omega_min"] < params["omega_max"]
    mesh_w = MeshReFreq(params["omega_min"], params["omega_max"], params["Nomega"])

    n_pade = _set_n_pade(params["pade"]["omega_max"], params['beta'], n_min=params["pade"]["n_min"], n_max=params["pade"]["n_max"])

    data_w = {}

    num_data = numpy.sum([key.startswith("data") for key in npz.keys()])
    for idata in range(num_data):
        key = f"data{idata}"
        data = npz[key]
        mesh_iw = MeshImFreq(params["beta"], "Fermion", data.shape[0]//2)
        sigma_iw = GfImFreq(data=data, beta=params["beta"], mesh=mesh_iw)
        sigma_w = GfReFreq(mesh=mesh_w, target_shape=data.shape[1:])
        sigma_w.set_from_pade(sigma_iw, n_points=n_pade, freq_offset=params["pade"]["eta"])
        data_w[key] = sigma_w.data
    print("Writing to", seedname + "_sigma_w.npz...")
    numpy.savez(seedname + "_sigma_w.npz", **data_w)

def run():

    print_header()

    parser = argparse.ArgumentParser(
        prog='dcore_pade.py',
        description='pre script for dcore.',
        usage='$ dcore_pade input',
        add_help=True,
        formatter_class=argparse.RawTextHelpFormatter,
        #epilog=generate_all_description()
    )
    parser.add_argument('seedname',
                        action='store',
                        default=None,
                        type=str,
                        help="seedname"
                        )
    parser.add_argument('--version', action='version', version='DCore {}'.format(version))

    args = parser.parse_args()

    dcore_pade(args.seedname)


# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")

# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam
from keras.preprocessing.image import img_to_array
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.model_selection import train_test_split
from imutils import paths
import numpy as np
import random
import pickle
import cv2
import os

#************************************************************************************************************************************#
#************************************************************************************************************************************#
######                                                    MODEL TRAINING                                                        ######
#************************************************************************************************************************************#
#************************************************************************************************************************************#

# Initialize the Hyperparameters: --epochs to train for, initial learning rate, batch size, and image dimensions
EPOCHS = 20
INIT_LR = 1e-3
BS = 32
IMAGE_DIMS = (96, 96, 3)

# Det the PATH to the Dataset, pickle file to store label_binarizer values
dataset=r'C:\Users\kusha\Documents\KERAS\MULTICLASS\keras-multi-label\train'
labelbin= r'C:\Users\kusha\Documents\KERAS\MULTICLASS\keras-multi-label\mlb.pickle'

# Randomply shuffle the images:
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(dataset)))
random.seed(42)
random.shuffle(imagePaths)

######################################################################################################################################
######                                                       Data Pre-processing                                                ######
######################################################################################################################################

# initialize the data and labels
data = []
labels = []

# Load all input images
for imagePath in imagePaths:

	# load the image, pre-process it, and store it in the data list
	image = cv2.imread(imagePath)
	image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0]))

    # Convert image to numpy array
	image = img_to_array(image)
	data.append(image)

	# Extract set of class labels from the image path and update the labels list
	l = label = imagePath.split(os.path.sep)[-2].split("_")
	labels.append(l)

# Standardize the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)

print("[INFO] data matrix: {} images ({:.2f}MB)".format(
	len(imagePaths), data.nbytes / (1024 * 1000.0)))

# Binarize the labels using scikit-learn's multi-labelbinarizer implementation
print("[INFO] class labels:")
mlb = MultiLabelBinarizer()
labels = mlb.fit_transform(labels)

# partition the data into training and testing splits using 80% of
# the data for training and the remaining 20% for testing
(trainX, testX, trainY, testY) = train_test_split(data,
	labels, test_size=0.2, random_state=42)

# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1,
	height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
	horizontal_flip=True, fill_mode="nearest")

######################################################################################################################################
######                                                      TRAINING THE MODEL                                                  ######
######################################################################################################################################

print("[INFO] compiling model...")

import time
from tensorflow.keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.layers.normalization import BatchNormalization
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dropout
from keras.layers.core import Dense
from keras import backend as K
# from tensorflow.keras.callbacks import TensorBoard
# import time
NAME = "cats&Dogs_{}".format( int(time.time()))

print(NAME)
tensorboard = TensorBoard(log_dir=r"C:\Users\kusha\Documents\KERAS\MULTICLASS\keras-multi-label\logs\{}".format(NAME))

# model = SmallerVGGNet.build(
# 	width=IMAGE_DIMS[1], height=IMAGE_DIMS[0],
# 	depth=IMAGE_DIMS[2], classes=len(mlb.classes_),
# 	)

width=IMAGE_DIMS[1]
height=IMAGE_DIMS[0]
depth=IMAGE_DIMS[2]
classes=len(mlb.classes_)

model = Sequential()

inputShape = (height, width, depth)
chanDim = -1

# if we are using "channels first", update the input shape
# and channels dimension
if K.image_data_format() == "channels_first":
	inputShape = (depth, height, width)
	chanDim = 1

# CONV => RELU => POOL
model.add(Conv2D(32, (3, 3), padding="same",
	input_shape=inputShape))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(3, 3)))
model.add(Dropout(0.25))

# (CONV => RELU) * 2 => POOL
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

# (CONV => RELU) * 2 => POOL
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

# first (and only) set of FC => RELU layers
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.5))

# softmax classifier
model.add(Dense(classes))
model.add(Activation("softmax"))

# initialize the optimizer
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)

model.compile(loss="binary_crossentropy", optimizer=opt,
	metrics=["accuracy"])

# train the network
print("[INFO] training network...")
H = model.fit_generator(
	aug.flow(trainX, trainY, batch_size=BS),
	validation_data=(testX, testY),
	steps_per_epoch=len(trainX) // BS,
	epochs=EPOCHS, verbose=1, callbacks=[tensorboard])

# save the model to disk
print("[INFO] serializing network...")
model.save('cats_dogs.model')

# save the multi-label binarizer to disk
print("[INFO] serializing label binarizer...")
f = open(labelbin, "wb")
f.write(pickle.dumps(mlb))
f.close()


from django.http import Http404

from urlparse import urlparse

from mydashboard.models import Microsite

def saved_searches(employer, company, candidate):
    """
    Function that gets employer's companies and those companies microsites.
    Will pull the domain out of the employer_microsites. Gathers the
    candidate's saved search urls and then will pull those urls
    out. Lastly, check to see if employer domains match up with
    candidate domains and return a list of urls.

    inputs:
    :employer:	The employer that is looking at candidate's page
    :candidate:	The job seeker that shows up in employer's activitiy feed

    outputs:
                A list of candidate urls.
    """
    if employer in company.admins.all():
        employer_company = company
    else:
        raise Http404
    employer_microsites = Microsite.objects.filter(
        company=employer_company).values_list('url', flat=True)
    employer_domains = [urlparse(url).netloc for url in employer_microsites]
    candidate_urls = candidate.savedsearch_set.values_list('url', flat=True)
    return [url for url in candidate_urls
            if urlparse(url).netloc in employer_domains]


from __future__ import absolute_import
import gast

from tangent import annotations as anno
from tangent import ast as ast_
from tangent import quoting
from tangent import transformers
from tangent import utils

class CleanStack(transformers.TreeTransformer):
  """Remove stack pushes of variables that are never defined."""

  def visit(self, node):
    # Remove all AD-generated pushes of unused variables.
    if anno.hasanno(node, 'push_var') and anno.hasanno(
        node, 'pop') and anno.hasanno(node, 'gen_push'):
      defs = frozenset(id_
                       for id_, node in anno.getanno(node, 'definitions_in'))
      if ast_.get_name(anno.getanno(node, 'push_var')) not in defs:
        self.remove(node)
        self.remove(anno.getanno(node, 'pop'))
    return super(CleanStack, self).visit(node)

class FixStack(transformers.TreeTransformer):
  """Explicitly defines variables that might not be defined."""

  def visit(self, node):
    if anno.hasanno(node, 'push_var'):
      varname = ast_.get_name(anno.getanno(node, 'push_var'))
      if varname not in anno.getanno(node, 'defined_in'):
        self.insert_top(quoting.quote('{} = None'.format(varname)))
    return super(FixStack, self).visit(node)

class CleanGrad(gast.NodeTransformer):
  """Replace `dx = dx + partial` with `dx = partial` if `dx` undefined."""

  def visit_Assign(self, node):
    if isinstance(node.value, gast.Call) and anno.hasanno(node.value.func,
                                                          'add_grad'):
      defs = frozenset(id_ for id_, node in anno.getanno(node,
                                                         'definitions_in'))
      if ast_.get_name(node.targets[0]) not in defs:
        node.value = node.value.args[1]
    return node

class FixGrad(transformers.TreeTransformer):
  """Explicitly initialize gradient to zero if needed."""

  def __init__(self):
    super(FixGrad, self).__init__()
    self.added = set()

  def _init(self, node):
    gradname = ast_.get_name(node)
    if anno.hasanno(node, 'adjoint_var'):
      var = anno.getanno(node, 'adjoint_var')
    else:
      var = anno.getanno(node, 'temp_adjoint_var')
    return gast.Assign(
        targets=[gast.Name(id=gradname, ctx=gast.Store(), annotation=None)],
        value=gast.Call(func=utils.INIT_GRAD, args=[var], keywords=[]))

  def prepend_uninitialized_grads(self, node):
    if anno.hasanno(node, 'defined_in'):
      uses = (succ for succ in gast.walk(node) if
              isinstance(succ, gast.Name) and
              isinstance(succ.ctx, gast.Load))
      for use in uses:
        if ((anno.hasanno(use, 'adjoint_var') or
             anno.hasanno(use, 'temp_adjoint_var')) and
            use.id not in anno.getanno(node, 'defined_in') and
            use.id not in self.added):
          self.added.add(use.id)
          self.insert_top(self._init(use))
    return node

  def visit_Assign(self, node):
    node = self.prepend_uninitialized_grads(node)
    return node

  def visit_AugAssign(self, node):
    node = self.prepend_uninitialized_grads(node)
    return node

  def visit_Expr(self, node):
    node = self.prepend_uninitialized_grads(node)
    return node

  def visit_Return(self, node):
    node = self.prepend_uninitialized_grads(node)
    return node


from os import path, mkdir, scandir
from json import dumps, loads
from global_constants import COLOR
from lookup import items, levelInfo
saveDir = "saves/"
saveExt = "_save.json"
worldDir = "worlds/"
worldExt = "_world.py"
modDir = "mods/"
modExt = "_mod.json"
if not path.exists(saveDir):
    mkdir(saveDir)
if not path.exists(worldDir):
    mkdir(worldDir)
if not path.exists(modDir):
    mkdir(modDir)

def newSave(name: str) -> int:
    saveName = saveDir + name + saveExt
    if path.exists(saveName):
        while True:
            selection = input(COLOR["red"] + f"Save data with this name ({name}) already exists, do you want to overwrite it (y/n): " + COLOR["reset"]).lower().strip(' ')
            if selection == "y":
                break
            elif selection == "n":
                return 1

    saveDict = {
        "name": name,
        "health": 20,
        "weapon": items["Stick"],
        "armor": items["Fabric"],
        "inventory": [],
        "exp": 0,
        "lv": levelInfo[0],
        "curloc": {
            "name": "unassigned",
            "SUID": "64:0000-0000-0000-0000"
        }
    }

    data = dumps(saveDict, indent=2)
    with open(saveName, "w") as save:
        save.write(data)
    return 0

def savePlayerData(p: dict) -> int:
    saveName = saveDir + p.name + saveExt
    saveDict = {
        "name": p.name,
        "health": p.health,
        "weapon": p.weapon,
        "armor": p.armor,
        "inventory": p.inventory,
        "exp": p.exp,
        "lv": p.level,
        "curloc": p.curloc
    }

    data = dumps(saveDict, indent=2)
    with open(saveName, "w") as save:
        save.write(data)
    return 0

def loadPlayerData(name: str) -> dict:
    saveName = saveDir + name + saveExt
    try:
        with open(saveName, "r") as save:
            saveDict = loads(' '.join(save.readlines()).replace("\n", ""))
    except FileNotFoundError:
        print(COLOR["red"] + "There is not a save file with this name!" + COLOR["reset"])
    except:
        print(COLOR["red"] + "This save file is not valid!" + COLOR["reset"])
    return saveDict

def showSaves() -> None:
    print("Listed below are all your saves:")
    numOfValidSaves = 0
    for path in scandir(saveDir):
        if path.is_file() and path.name.endswith(saveExt):
            numOfValidSaves += 1
            print(COLOR["blue"] + path.name.rstrip(saveExt) + COLOR["reset"])
    if numOfValidSaves == 0:
        print(COLOR["red"]+"No saves found!"+COLOR["reset"])

def showWorlds() -> None:
    print("Listed below are all your installed worlds:")
    numofValidWorlds = 0
    for path in scandir(worldDir):
        if path.is_file() and path.name.endswith(worldExt):
            numofValidWorlds += 1
            print(COLOR["blue"] + path.name.rstrip(worldExt) + COLOR["reset"])
    if numofValidWorlds == 0:
        print(COLOR["red"]+"No worlds found!"+COLOR["reset"])

def showMods() -> None:
    numofValidMods = 0
    modNames = []
    for path in scandir(modDir):
        if path.is_file() and path.name.endswith(modExt):
            numofValidMods += 1
            modNames.append(COLOR["blue"] + path.name.rstrip(modExt) + COLOR["reset"])
    if numofValidMods == 0:
        print(COLOR["red"] + "No mods are installed!\n" + COLOR["reset"])
        return 0
    print("Listed below are all your installed mods:")
    for modName in modNames:
        print(modName)
    print()

def modLoader() -> tuple:
    for path in scandir(modDir):
        if path.is_file() and path.name.endswith(modExt):
            try:
                with open(modDir + path.name, "r") as modFile:
                    modDict = loads(' '.join(modFile.readlines()).replace("\n", ""))
            except:
                return(1, "Couldn't access mod file: %s" % path.name)

            modItems = loads(dumps(modDict["items"]))
            print(modItems)
            for modItem in modItems.items():
                modItem = ''.join(map(str, modItem))
                for i in range(len(modItem)):
                    if modItem[i] == '{':
                        modItem = modItem[i:]
                        break
                modItemDict = loads(modItem.replace('\'', '"'))
                print(type(modItem), "\n", modItem)
                try:
                    items[modItemDict["Name"]] = modItemDict
                except:
                    return(1, "Couldn't add mod items to global lookup")

    modItemOutput = open("mods/itemsLog.txt", "w")
    modItemOutput.write(dumps(items, indent=2))
    modItemOutput.close()

    return(0, "")


from pyspark import SparkConf
from pyspark.sql import SparkSession

def initialize_spark(args):
    # Set spark config with storage account names/keys and the session timezone so that datetimes are displayed consistently (in UTC)
    spark_conf = SparkConf(loadDefaults=True) \
        .set('fs.azure.account.key.{0}.dfs.core.windows.net'.format(args.data_storage_account_name), args.data_storage_account_key) \
        .set("spark.sql.session.timeZone", "UTC") \
        .set("spark.databricks.io.cache.enabled", "True")

    return SparkSession \
        .builder\
        .config(conf=spark_conf)\
        .getOrCreate()

# COMMAND ----------

p = configargparse.ArgParser(description='Green Energy Hub Tempory aggregation triggger', formatter_class=configargparse.ArgumentDefaultsHelpFormatter)
p.add('--data-storage-account-name', type=str, required=True,
      help='Azure Storage account name holding time series data')
p.add('--data-storage-account-key', type=str, required=True,
      help='Azure Storage key for storage', env_var='GEH_INPUT_STORAGE_KEY')
p.add('--data-storage-container-name', type=str, required=False, default='data',
      help='Azure Storage container name for input storage')
p.add('--time-series-path', type=str, required=False, default="delta/time_series_test_data/",
      help='Path to time series data storage location (deltalake) relative to root container')
p.add('--beginning-date-time', type=str, required=True,
      help='The timezone aware date-time representing the beginning of the time period of aggregation (ex: 2020-01-03T00:00:00Z %Y-%m-%dT%H:%M:%S%z)')
p.add('--end-date-time', type=str, required=True,
      help='The timezone aware date-time representing the end of the time period of aggregation (ex: 2020-01-03T00:00:00Z %Y-%m-%dT%H:%M:%S%z)')
p.add('--telemetry-instrumentation-key', type=str, required=True,
      help='Instrumentation key used for telemetry')
p.add('--grid-area', type=str, required=False,
      help='Run aggregation for specific grid areas format is { "areas": ["123","234"]}. If none is specifed. All grid areas are calculated')
p.add('--process-type', type=str, required=True,
      help='D03 (Aggregation) or D04 (Balance fixing) '),
p.add('--result-url', type=str, required=True, help="The target url to post result json"),
p.add('--result-id', type=str, required=True, help="Postback id that will be added to header"),
p.add('--persist-source-dataframe', type=bool, required=False, default=False)
p.add('--persist-source-dataframe-location', type=str, required=False, default="delta/basis-data/")
p.add('--snapshot-url', type=str, required=True, help="The target url to post result json")
p.add('--cosmos-account-endpoint', type=str, required=True, help="Cosmos account endpoint")
p.add('--cosmos-account-key', type=str, required=True, help="Cosmos account key")
p.add('--cosmos-database', type=str, required=True, help="Cosmos database name")
p.add('--cosmos-container-metering-points', type=str, required=True, help="Cosmos container for metering points input data")
p.add('--cosmos-container-market-roles', type=str, required=True, help="Cosmos container for market roles input data")
p.add('--cosmos-container-grid-loss-sys-corr', type=str, required=True, help="Cosmos container for grid loss and system correction")
p.add('--cosmos-container-es-brp-relations', type=str, required=True, help="Cosmos container for relations between energy supplier and balance responsible")
p.add('--resolution', type=str, required=True, help="Time window resolution eg. 1 hour, 15 minutes etc.")
args, unknown_args = p.parse_known_args()

areas = []

if args.grid_area:
    areasParsed = json.loads(args.grid_area)
    areas = areasParsed["areas"]
if unknown_args:
    print("Unknown args: {0}".format(args))

spark = initialize_spark(args)

# COMMAND ----------

from pyspark.sql.types import StringType, TimestampType, StructType, StructField, IntegerType,DecimalType
from pyspark.sql.functions import col, date_format
from pyspark.sql import SparkSession

# COMMAND ----------

def load_aggregation_data(cosmos_container_name, schema, args, spark):
    config = {
        "spark.cosmos.accountEndpoint": args.cosmos_account_endpoint,
        "spark.cosmos.accountKey": args.cosmos_account_key,
        "spark.cosmos.database": args.cosmos_database,
        "spark.cosmos.container": cosmos_container_name,
        "spark.cosmos.read.inferSchema.forceNullableProperties": False
    }
    return spark.read.schema(schema).format("cosmos.oltp").options(**config).load()

# COMMAND ----------

metering_point_schema = StructType([
      StructField("metering_point_id", StringType(), False),
      StructField("metering_point_type", StringType(), False),
      StructField("settlement_method", StringType()),
      StructField("grid_area", StringType(), False),
      StructField("connection_state", StringType(), False),
      StructField("resolution", StringType(), False),
      StructField("in_grid_area", StringType()),
      StructField("out_grid_area", StringType()),
      StructField("metering_method", StringType(), False),
      StructField("net_settlement_group", StringType()),
      StructField("parent_metering_point_id", StringType()),
      StructField("unit", StringType(), False),
      StructField("product", StringType()),
      StructField("from_date", TimestampType(), False),
      StructField("to_date", TimestampType(), False)
])

def load_metering_points(args, spark):
    return load_aggregation_data(args.cosmos_container_metering_points, metering_point_schema, args, spark)

# COMMAND ----------

from pyspark.sql import DataFrame
from datetime import datetime

def filter_time_period(df: DataFrame, from_time: datetime, to_time: datetime):
    return df \
        .filter(col('time') >= from_time) \
        .filter(col('time') <= to_time)

# COMMAND ----------

import dateutil.parser

def load_time_series(args, areas, spark):
    beginning_date_time = dateutil.parser.parse(args.beginning_date_time)
    end_date_time = dateutil.parser.parse(args.end_date_time)

    TIME_SERIES_STORAGE_PATH = "abfss://{0}@{1}.dfs.core.windows.net/{2}".format(
        args.data_storage_container_name, args.data_storage_account_name, args.time_series_path
    )

    # Create input and output storage paths
    TIME_SERIES_STORAGE_PATH = "abfss://{0}@{1}.dfs.core.windows.net/{2}".format(
        args.data_storage_container_name, args.data_storage_account_name, args.time_series_path
    )

    print("Time series storage url:", TIME_SERIES_STORAGE_PATH)

    beginning_condition = f"Year >= {beginning_date_time.year} AND Month >= {beginning_date_time.month} AND Day >= {beginning_date_time.day}"
    end_condition = f"Year <= {end_date_time.year} AND Month <= {end_date_time.month} AND Day <= {end_date_time.day}"

    # Read in time series data (delta doesn't support user specified schema)
    timeseries_df = spark \
        .read \
        .format("delta") \
        .load(TIME_SERIES_STORAGE_PATH) \
        .where(f"{beginning_condition} AND {end_condition}")
    # Filter out time series data that is not in the specified time period
    valid_time_period_df = filter_time_period(timeseries_df, beginning_date_time, end_date_time)
    # Filter out time series data that do not belong to the specified grid areas
    if areas:
        valid_time_period_df = valid_time_period_df \
            .filter(col("grid_area").isin(areas))

    return valid_time_period_df

# COMMAND ----------

def get_time_series_dataframe(args, areas, spark):
    time_series_df = load_time_series(args, areas, spark)
    metering_point_df = load_metering_points(args, spark)

    print("time_series_df = " + str(time_series_df.count()))

    metering_point_join_conditions = \
        [
            time_series_df.metering_point_id == metering_point_df.metering_point_id,
            time_series_df.time >= metering_point_df.from_date,
            time_series_df.time < metering_point_df.to_date
        ]

    time_series_with_metering_point = time_series_df \
        .join(metering_point_df, metering_point_join_conditions) \
        .drop(metering_point_df.metering_point_id) \
        .drop(metering_point_df.from_date) \
        .drop(metering_point_df.to_date)

    return time_series_with_metering_point

# COMMAND ----------

the_df = get_time_series_dataframe(args, areas, spark)
the_df.display()


s = input("Enter a String:\n")
s = s.split()       #splits by keeping delimiter as a space...
d = {}
#now each word of the given string is treated as an individual element
for i in s:         #scans the string for words
    if i not in d:      #scans the dictionary...if not found then make the value 1
        d[i] = 1
    else:               #if found then increases the value by 1
        d[i] += 1

print(d)


import logging

from api.twitter_tools.api import Api
from api.twitter_tools.response_handler import ResponseHandler

# 25000 tweets a month. 800 tweets a day. 33 tweets an hour.
# 250 requests a month. 8 requests a day. 0.33 requests an hour.
class TweetSeeker:
    def __init__(self, token):
        self.token = token

    def run(self, hashtag: str):
        """
        Main application logic for gathering tweets
        args: string like '#yeg'
        """
        api = Api(self.token)
        response_dict = api.daily_search(hashtag)
        for hour in response_dict:
            handler = ResponseHandler(response_dict[hour])
            handler.parse_tweets()

        return 0


# 14466번 소가 길을 건너간 이유 6
# https://www.acmicpc.net/problem/14466

"""
N * N 의 목초지가 격자로 이루어져 있다.
인접한 목초지 사이는 일반적으로 자유롭게 건너갈 수 있지만, 일부는 길을 건너야 한다.
이때 2번째 줄부터 R개의 줄만큼 길에 대한 정보가 주어진다.
2 2 2 3 => (2, 2)~(2, 3)은 길로 연결되어 있다.

0 0 0
0 1-1
0 0 0

이때 배열의 좌표로 생각한다면 (1, 1) ~ (1, 2)가 길로 연결되어 있다는 뜻이다.
길이 없다면 인접한 배열 간에는 자유롭게 이동할 수 있으므로,
(1, 1)과 (1, 2)에 소가 존재한다고 가정하면
위와 같은 길만 존재한다면 다른 길로 돌아서 해당 좌표에 닿을 수 있다.
즉, 길을 이용하지 않더라도 만날 수 있다는 뜻이다.

"""
from collections import deque

N, K, R = map(int, input().split())

# 길에 대한 정보 입력 - 길로는 이동할 수 없다고 생각하자
edges = [[[] for _ in range(N)] for _ in range(N)]
for _ in range(R):
    ay, ax, by, bx = map(lambda x: int(x)-1, input().split())
    edges[ay][ax].append([by, bx])
    edges[by][bx].append([ay, ax])

cows = []
for _ in range(K):
    cy, cx = map(lambda x: int(x)-1, input().split())
    cows.append([cy, cx])

# 모든 소에 대해 bfs 탐색
delta = [[1, 0], [-1, 0], [0, 1], [0, -1]]
result = 0
for idx in range(K):
    q = deque()
    cy, cx = cows[idx]
    graph = [[0 for _ in range(N)] for _ in range(N)]
    graph[cy][cx] = 1
    q.append([cy, cx])

    while q:
        ny, nx = q.popleft()
        for dy, dx in delta:
            ey = ny + dy
            ex = nx + dx
            if 0 <= ey < N and 0 <= ex < N:
                # 길에 해당한다면 패스
                if [ey, ex] in edges[ny][nx]:
                    continue
                # 이미 방문했다면 패스
                if graph[ey][ex]:
                    continue
                graph[ey][ex] = 1
                q.append([ey, ex])

    cnt = K
    for fy, fx in cows:
        # 해당 좌표에 값을 가진다는 뜻은 길을 통하지 않고도 만날 수 있다는 뜻이다.
        # 자기 자신은 무조건 값을 가지고 있다.
        if graph[fy][fx]:
            cnt -= 1
    result += cnt

# 1번 소와 2번 소가 만나지 못한다면, 1번 소의 입장에서도, 2번 소의 입장에서도 각각 카운트 되기 때문에 나누기!
print(result // 2)


from django import forms
from django.forms import ModelForm

from vitrineapp.models import CategoriaModel

class CategoriaForm(ModelForm):
    desc_categoria = forms.CharField(max_length=100)

    def save(self, commit=True):
        categoria = super(CategoriaForm, self).save(commit=False)
        if commit:
            categoria.save()

    class Meta:
        model = CategoriaModel
        exclude = ()


#This is key generator of DES algorithm.
from random import randrange
# We have 2**56 or 72,057,594,037,927,936 permutations for valid key.
key_number=randrange(0,72057594037927936)
print("The number of key:%i"%key_number)

binary_mode=bin(key_number)[2:]
print("The binary form of the key:\n%s"%binary_mode)

binary_mode_length=len(binary_mode)
print("The length of binary form:",binary_mode_length)

if binary_mode_length != 56:
    binary_mode = binary_mode+(56-binary_mode_length)*'0'

print("The binary form of the key after zero padding:\n%s"%binary_mode)

print("The length of binary form of the key after zero padding:",len(binary_mode))

array_mode=[]

for i in range(8):
    array_mode.append(binary_mode[i*7:(i*7)+7])

for j in range(8):
    if array_mode[j].count('1')%2==0:
        array_mode[j]=array_mode[j]+'1'
    else:
        array_mode[j]=array_mode[j]+'0'
print("The string form:\n",*array_mode,sep='')
print("The table form:")

for k in array_mode:
    print(*k,sep='  ')


# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   File Name：     setting
   Description :
   Author :       ZWZ
   date：          18-6-6
-------------------------------------------------
   Change Activity:
                   18-6-6:
-------------------------------------------------
"""
__author__ = 'ZWZ'

BOT_NAME = 'bidinfo'
SPIDER_MODULES = ['bidinfo.spiders']
NEWSPIDER_MODULE = 'bidinfo.spiders'
LOG_LEVEL = 'INFO'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'bidinfo (+http://www.yourdomain.com)'

# Obey robots.txt rules
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 1

ITEM_PIPELINES = {
    'bidinfo.pipelines.BidinfoPipeline': 300,
}


"""
Given an array nums containing n + 1 integers where each integer
is between 1 and n (inclusive). Find duplicate number
Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array,
but it could be repeated more than once.
"""

# can't modify the array so can't change the number nums[nums[i]]
# to negative and wait for overlap
# so using the below method based on binary search

class Solution(object):
    def findDuplicate(self, nums):
        low = 1
        high = len(nums)-1

        while low < high:
            mid = (high+low)/2
            count = len([i for i in nums if i <= mid])
            if count <= mid:
                low = mid+1
            else:
                high = mid
        return low

"""
If we're allowed to modify the array then this works

class Solution(object):
    def findDuplicate(self, nums):
        for i in range(len(nums) - 1):
            while nums[i] != i + 1:
                val = nums[i]

                if val == nums[val - 1]:
                    return val

                nums[i], nums[val - 1] = nums[val - 1], nums[i]

        return nums[-1]
"""


def split(arr_list: list) -> list:
    """

    :param arr_list: input list
    :return: splits the input list in two halves
    Used for loop instead of split function to reduce time complexity.O(logn)
    split function increases time complexity to O(kn)
    """
    left_half = []
    right_half = []
    size = len(arr_list)
    midpoint = size // 2
    for i in range(midpoint):
        left_half.append(arr_list[i])
    for midpoint in range(midpoint, size):
        right_half.append(arr_list[midpoint])
    return left_half, right_half

def merge(left: list, right: list) -> list:
    """

    :param left:
    :param right:
    :return:
    takes O(n)
    """
    sorted_merged = []
    l = 0
    r = 0
    while l < len(left) and r < len(right):
        if left[l] < right[r]:
            sorted_merged.append(left[l])
            l += 1
        else:
            sorted_merged.append(right[r])
            r += 1
    while l < len(left):
        sorted_merged.append(left[l])
        l += 1
    while r < len(right):
        sorted_merged.append(right[r])
        r += 1
    return sorted_merged

def merge_sort(arr_list: list) -> list:
    """

    :param arr_list:
    :return:
    O(nlogn)
    """
    if len(arr_list) <= 1:
        return arr_list
    left_half, right_half = split(arr_list)

    left_sorted = merge_sort(left_half)
    right_sorted = merge_sort(right_half)
    return merge(left_sorted, right_sorted)

input_list = [55, 27, 32]
print(merge_sort(input_list))


from typing import List, Optional, Tuple
from pydantic import BaseModel
from strenum import StrEnum
from lxml import etree
from pathlib import Path
import sys
sys.path.append(str(Path(__file__).parent.parent.parent))
from config import ANALYSIS as cfg

# Using lxml instead of xml.etree.ElementTree because it has full XPath support
# xml.etree.ElementTree only supports basic XPath syntax
import os
import pandas as pd

chan_to_part = {}  # index mapping channel to participant per meeting
part_to_chan = {}  # index mapping participant to channel per meeting

# Dataframes containing different types of segments - one per row
laugh_only_df = pd.DataFrame()
invalid_df = pd.DataFrame()
noise_df = pd.DataFrame()
speech_df = pd.DataFrame()

# Dataframe containing total length and audio_path of each channel
info_df = pd.DataFrame()

class SegmentType(StrEnum):
    '''
    Describes the type of data that was transcribed in this segment.
    For detailed information: https://www1.icsi.berkeley.edu/Speech/mr/icsimc_doc/trans_guide.txt
    '''
    INVALID = 'invalid'  # e.g. laughter segments occurring next to speech or other noise
    SPEECH = 'speech'
    LAUGH = 'laugh'
    OTHER_VOCAL = 'other_vocal'  # segments containing a single VocalSound that's not laughter
    NON_VOCAL = 'non_vocal' # segments containing a single NonVocalSound (e.g. 'mic noise')
    MIXED = 'mixed'  # contains some mixture of speech / noise and silence (but no laughter)

class Segment(BaseModel):
    """Represent a Transcription segment from ICSI transcripts"""

    meeting_id: str
    part_id: str
    chan_id: str
    start: float
    end: float
    length: float
    type: SegmentType
    laugh_type: Optional[str]

def parse_preambles(path):
    global chan_to_part, part_to_chan
    """
    Creates 2 id mappings
    1) Dict: (meeting_id) -> (dict(chan_id -> participant_id))
    2) Dict: (meeting_id) -> (dict(participant_id -> chan_id))
    """
    dirname = os.path.dirname(__file__)
    preambles_path = os.path.join(dirname, path)
    chan_to_part = {}
    tree = etree.parse(preambles_path)
    meetings = tree.xpath("//Meeting")
    for meeting in meetings:
        id = meeting.get("Session")
        part_map = {}
        # Make sure that both Name and Channel attributes exist
        for part in meeting.xpath(
            "./Preamble/Participants/Participant[@Name and @Channel]"
        ):
            part_map[part.get("Channel")] = part.get("Name")

        chan_to_part[id] = part_map

    part_to_chan = {}
    for meeting_id in chan_to_part.keys():
        part_to_chan[meeting_id] = {
            part_id: chan_id for (chan_id, part_id) in chan_to_part[meeting_id].items()
        }

def xml_to_segment(xml_seg, meeting_id: str) -> Optional[Segment]:
    """
    Input: xml laughter segment as etree Element, meeting id
    Output: list of features representing this laughter segment:
        - Format: [meeting_id, part_id, chan_id, start, end, length, l_type]
        - returns [] if no valid part_id was found
    """
    part_id = xml_seg.get("Participant")
    # If participant doesn't have a corresponding audio channel
    # discard this segment
    if part_id not in part_to_chan[meeting_id].keys():
        return None

    chan_id = part_to_chan[meeting_id][part_id]
    start = float(xml_seg.get("StartTime"))
    end = float(xml_seg.get("EndTime"))
    length = end - start

    seg_type, laugh_type = _get_segment_type(xml_seg)

    new_seg = Segment(
        meeting_id=meeting_id,
        part_id=part_id,
        chan_id=chan_id,
        start=start,
        end=end,
        length=length,
        type=seg_type,
        laugh_type=laugh_type,
    )
    return new_seg

def _get_segment_type(xml_seg) -> Tuple[SegmentType, str]:
    """
    Determine the segment type of passed xml-segment - if laughter also return type of laughter
    Input: xml-segment of the shape of ICSI transcript segments
    Output: [segment_type, laugh_type]
    """
    children = xml_seg.getchildren()
    laugh_type  = None
    seg_type = SegmentType.MIXED

    if len(children) == 0:
        seg_type = SegmentType.SPEECH
    elif len(children) == 1:
        child = children[0]
        if child.tag == "VocalSound":
            if "laugh" in child.get("Description"):
                # Check that there is no text in any sub-element of this tag
                # which meant speech occurring next to laughter
                if "".join(xml_seg.itertext()).strip() == "":
                    seg_type = SegmentType.LAUGH
                    laugh_type = child.get("Description")
                else:
                    seg_type = SegmentType.INVALID

            else:
                seg_type = SegmentType.OTHER_VOCAL

        elif child.tag == "NonVocalSound":
            seg_type = SegmentType.NON_VOCAL

        else:
            # This is because there are also tags like <Comment>
            seg_type = SegmentType.SPEECH
    else:
        # Track laughter next to speech or noise to discard these segments from evaluation
        # If laughter occurs next to speech we can properly track it but it's still laughter
        # Thus a prediction on such a segment shouldn't be considered wrong but just be ignored.
        laughs = xml_seg.xpath("./VocalSound[contains(@Description, 'laugh')]")

        # If one of VocalSound or NonVocalSound tags appear, classify as mixed
        tag_types = list(map(lambda x: x.tag, children))
        if laughs != []:
            seg_type = SegmentType.INVALID
        elif "NonVocalSound" in tag_types or "VocalSound" in tag_types:
            seg_type = SegmentType.MIXED
        else:
            seg_type = SegmentType.SPEECH

    return (seg_type, laugh_type)

def get_segment_list(filename, meeting_id):
    """
    Returns four lists of Segment objects represented as dict:
        1) List containing segments laughter only (no text or other sounds surrounding it)
        2) List containing invalid segments (e.g. laughter surrounding by other sounds)
        3) List containing speech segments
        4) List containing noise segments
    """
    # Comment shows which types of segments each list will hold
    invalid_list: List[Segment] = []  # INVALID
    laugh_only_list: List[Segment] = []  # LAUGH
    speech_list: List[Segment] = []  # SPEECH
    noise_list: List[Segment] = []  # MIXED, NON_VOCAL, OTHER_VOCAL

    # Get all segments that contain some kind of laughter (e.g. 'laugh', 'breath-laugh')
    # xpath_exp = "//Segment[VocalSound[contains(@Description,'laugh')]]"
    tree = etree.parse(filename)
    # laugh_segs = tree.xpath(xpath_exp)
    all_segs = tree.xpath("//Segment")

    # For each laughter segment classify it as laugh only or mixed laugh
    # mixed laugh means that the laugh occurred next to speech or any other sound
    for xml_seg in all_segs:
        seg = xml_to_segment(xml_seg, meeting_id)
        if (seg==None): # Skip segment without audio chan
            continue
        if seg.type == SegmentType.LAUGH:
            laugh_only_list.append(seg.dict())
        elif seg.type == SegmentType.SPEECH:
            speech_list.append(seg.dict())
        elif seg.type == SegmentType.INVALID:
            invalid_list.append(seg.dict())
        else:
            noise_list.append(seg.dict())

    return invalid_list, speech_list, laugh_only_list, noise_list

def general_info_to_list(filename, meeting_id):
    general_info_list = []
    tree = etree.parse(filename)
    # Get End-Timestamp of last transcription of the meeting
    meeting_len = tree.find("//Transcript").get("EndTime")
    for chan_id, part_id in chan_to_part[meeting_id].items():
        path = os.path.join(meeting_id, f"{chan_id}.sph")
        general_info_list.append([meeting_id, part_id, chan_id, meeting_len, path])

    return general_info_list

def get_transcripts(path):
    """
    Parse meeting transcripts and store laughs in laugh_df
    """

    files = []
    # If a directory is given take all .mrt files
    # otherwise only take given file
    dirname = os.path.dirname(__file__)
    path = os.path.join(dirname, path)

    # Match particular file or all .mrt files
    if os.path.isdir(path):
        for filename in os.listdir(path):
            # All icsi meetings have a 6 letter ID (-> split strips the .mrt extension)
            if filename.endswith(".mrt") and len(filename.split(".")[0]) == 6:
                files.append(filename)
    else:
        if path.endswith(".mrt"):
            files.append(path)

    return files

def create_dfs(file_dir, files):
    """
    Creates four segment-dataframes and one info-dataframe:
        1) laugh_only_df: dataframe containing laughter only snippets
        2) invalid_df: containing snippets with laughter next to speech (discarded from evaluation)
        3) speech_df: contains speech
        4) noise_df: containing all other segments
            - NOTE: this doesn't include silence as silence happens mostly BETWEEN transcription segments

        5) general_info_df: dataframe containing total length and audio_path of each channel

    segment_dataframes columns: ['meeting_id', 'part_id', 'chan_id', 'start', 'end', 'length', 'type', 'laugh_type']

    info_df columns: ['meeting_id', 'part_id', 'chan_id', 'length', 'path']

    """
    global laugh_only_df, invalid_df, info_df, noise_df, speech_df

    # Define lists holding all the rows for those dataframes
    tot_invalid_segs = []
    tot_speech_segs= []
    tot_laugh_only_segs = []
    tot_noise_segs = []

    general_info_list = []
    # Iterate over all .mrt files
    for filename in files:
        # Get meeting id by getting the basename and stripping the extension
        basename = os.path.basename(filename)
        meeting_id = os.path.splitext(basename)[0]
        full_path = os.path.join(file_dir, filename)

        general_info_sublist = general_info_to_list(full_path, meeting_id)
        general_info_list += general_info_sublist

        invalid, speech, laugh_only, noise = get_segment_list(full_path, meeting_id)
        tot_invalid_segs += invalid
        tot_speech_segs += speech
        tot_laugh_only_segs += laugh_only
        tot_noise_segs += noise

    laugh_only_df = pd.DataFrame(tot_laugh_only_segs)
    invalid_df = pd.DataFrame(tot_invalid_segs )
    speech_df = pd.DataFrame(tot_speech_segs)
    noise_df = pd.DataFrame(tot_noise_segs)

    # Create info_df with specified columns and dtypes
    info_dtypes = {"length": "float"}
    info_cols = ["meeting_id", "part_id", "chan_id", "length", "path"]
    info_df = pd.DataFrame(general_info_list, columns=info_cols)
    info_df = info_df.astype(dtype=info_dtypes)

def parse_transcripts(path):
    """
    Function executed on import of this module.
    Parses transcripts (including preamble.mrt) and creates:
        - chan_to_part: index mapping channel to participant per meeting
        - part_to_chan: index mapping participant to channel per meeting
        - laugh_only_df: dataframe containing transcribed laugh only events
        - invalid_df: dataframe containing invalid segments (e.g. mixed laugh and speech)
    """
    parse_preambles(os.path.join(path, "preambles.mrt"))

    transc_files = get_transcripts(path)
    create_dfs(path, transc_files)

def _print_stats(df):
    """
    Print stats of laugh_df - for information/debugging only
    """
    print(df)
    if df.size == 0:
        print("Empty DataFrame")
        return
    print("avg-snippet-length: {:.2f}s".format(df["length"].mean()))
    print("Number of snippets: {}".format(df.shape[0]))
    tot_dur = df["length"].sum()
    print(
        "Accumulated segment duration in three formats: \n- {:.2f}h \n- {:.2f}min \n- {:.2f}s".format(
            (tot_dur / 3600), (tot_dur / 60), tot_dur
        )
    )

def main():
    """
    Main executed when file is called directly
    NOT on import
    """
    file_path = os.path.join(os.path.dirname(__file__), "data")
    parse_transcripts(file_path)

    print("\n----INALID SEGMENTS-----")
    _print_stats(invalid_df)

    print("\n----SPEECH SEGMENTS-----")
    _print_stats(speech_df)

    print("\n----LAUGHTER ONLY-----")
    _print_stats(laugh_only_df)

    print("\n----NOISE SEGMENTS-----")
    _print_stats(noise_df)

    print("\n----INFO DF-----")
    print(info_df)

if __name__ == "__main__":
    main()

#############################################
# EXECUTED ON IMPORT
#############################################
# Parse transcripts on import
parse_transcripts(cfg['transcript_dir'])


import csv
import os
import shutil
from del_directory import delete_file

def del_fun(path):
    if os.path.exists(path):
        delete_file(path)
    os.mkdir(path)

train_path = 'E:/taidi/DataEnhance/train/'
test_path = 'E:/taidi/DataEnhance/test/'
dataset_train = 'E:/taidi/DataEnhance/dataset/train/'
dataset_test = 'E:/taidi/DataEnhance/dataset/test/'
origin_path = train_path
goal_path = dataset_train
# origin_path = test_path
# goal_path = dataset_test

# del_fun(train_path)
with open('rock_label_1.csv', 'r') as f:

    reader = csv.reader(f)
    # Dark gray mudstone
    dgm = []
    # Light gray fine sandstone
    lgfs = []
    # Grey fine sandstone
    gfs = []
    # Dark gray silty mudstone
    dgsm = []
    # Grey argillaceous siltstone
    gas = []
    # Gray-black mudstone
    g_bm = []
    # Black coal
    bc = []
    for row in reader:
        if row[2] == 'Dark gray mudstone':
            dgm.append(row[0])
        elif row[2] == 'Light gray fine sandstone':
            lgfs.append(row[0])
        elif row[2] == 'Grey fine sandstone':
            gfs.append(row[0])
        elif row[2] == 'Dark gray silty mudstone':
            dgsm.append(row[0])
        elif row[2] == 'Grey argillaceous siltstone':
            gas.append(row[0])
        elif row[2] == 'Gray-black mudstone':
            g_bm.append(row[0])
        else:
            bc.append(row[0])

    del_fun(goal_path+'Dark gray mudstone')
    del_fun(goal_path+'Light gray fine sandstone')
    del_fun(goal_path+'Grey fine sandstone')
    del_fun(goal_path+'Dark gray silty mudstone')
    del_fun(goal_path+'Grey argillaceous siltstone')
    del_fun(goal_path+'Gray-black mudstone')
    del_fun(goal_path+'Black coal')

    for root, dirs, files in os.walk(origin_path):
        for i in range(len(dirs)):
            child_dir = dirs[i]
            temp = child_dir.split("-")[0]
            for root_child, dirs_child, files_child in os.walk(origin_path + child_dir):
                if temp in dgm:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Dark gray mudstone'
                        shutil.move(list[k], des_path)
                elif temp in lgfs:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Light gray fine sandstone'
                        shutil.move(list[k], des_path)
                elif temp in dgsm:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Dark gray silty mudstone'
                        shutil.move(list[k], des_path)
                elif temp in gfs:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Grey fine sandstone'
                        shutil.move(list[k], des_path)
                elif temp in gas:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Grey argillaceous siltstone'
                        shutil.move(list[k], des_path)
                elif temp in g_bm:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Gray-black mudstone'
                        shutil.move(list[k], des_path)
                else:
                    list = []
                    for i in range(len(files_child)):
                        list.append(root_child + '/' + files_child[i])
                    for k in range(len(list)):
                        des_path = goal_path + 'Black coal'
                        shutil.move(list[k], des_path)