"""
.. py:module:: environment

This module holds ``Enviroment``-class, an universe where the agents live.
Environment holds methods for inter-agent communication and some utilities that
are usually needed when implementing creative multi-agent systems.

All implementations should subclass ``Environment`` in order to provide basic
functionality for the system to operate.

Environments are used by defining their address at the instantation time, and
adding agents to their container.
"""
import asyncio

import logging
from random import choice, shuffle

from aiomas import Container

from creamas.logging import ObjectLogger
from creamas.util import run_or_coro
from creamas.serializers import get_serializers

__all__ = ['Environment']

class Environment(Container):
    """Base environment class inherited from :py:class:`aiomas.Container`.
    """
    @classmethod
    def create(cls, *args, **kwargs):
        """Create a new environment, see :py:func:`~aiomas.Container.create` for details.

        If ``extra_serializers`` keyword argument is None, serializers returned by
        :func:`~creamas.serializers.get_serializers` are added to it.
        """
        extra_ser = kwargs.pop('extra_serializers', None)
        if extra_ser is None:
            extra_ser = get_serializers()
        kwargs.update({'extra_serializers': extra_ser})
        return super().create(*args, **kwargs)

    def __init__(self, base_url, loop, clock, connect_kwargs):
        super().__init__(base_url, loop, clock, connect_kwargs)
        self._age = 0
        self._logger = None
        self._log_folder = None
        self._artifacts = []
        self._candidates = []
        self._name = base_url

        # Try setting the process name to easily recognize the spawned
        # environments with 'ps -x' or 'top'
        try:
            import setproctitle as spt
            spt.setproctitle('Creamas: {}'.format(str(self)))
        except:
            pass

    @property
    def name(self):
        """Name of the environment."""
        return self._name

    @property
    def artifacts(self):
        """Published artifacts for all agents."""
        return self._artifacts

    @property
    def age(self):
        """Age of the environment.
        """
        return self._age

    @age.setter
    def age(self, a):
        self._age = a

    @property
    def logger(self):
        """Logger for the environment.
        """
        return self._logger

    @property
    def log_folder(self):
        """Logging folder for the environment. If set, will create py:class:`creamas.logging.ObjectLogger` for that
        folder.
        """
        return self._log_folder

    @log_folder.setter
    def log_folder(self, _log_folder):
        assert(type(_log_folder) is str)
        self._log_folder = _log_folder
        self._logger = ObjectLogger(self, _log_folder, add_name=True,
                                    init=True)

    def get_agents(self, addr=True, agent_cls=None, include_manager=False):
        """Get agents in the environment.

        :param bool addr: If ``True``, returns only addresses of the agents.
        :param agent_cls: Optional, if specified returns only agents belonging to that particular class.

        :param bool include_manager:
            If ``True`` includes the environment's manager, i.e. the agent in the address
            ``tcp://environment-host:port/0``, to the returned list if the environment has attribute :attr:`manager`.
            If environment does not have :attr:`manager`, then the parameter does nothing.

        :returns: A list of agents in the environment.
        :rtype: list

        .. note::
            Manager agents are excluded from the returned lists of agents by default.
        """
        agents = list(self.agents.dict.values())
        if hasattr(self, 'manager') and self.manager is not None:
            if not include_manager:
                agents = [a for a in agents if a.addr.rsplit('/', 1)[1] != '0']
        if agent_cls is not None:
            agents = [a for a in agents if type(a) is agent_cls]
        if addr:
            agents = [agent.addr for agent in agents]
        return agents

    def get_agent(self, addr):
        """Get agent in given address.

        :raises ValueError: If given address is not part of this environment
        :raises KeyError: If no such agent in the environment
        """
        base_url, agent_number = addr.rsplit('/', 1)
        base_url += "/"
        if base_url != self._base_url:
            raise ValueError("Given address' base URL ({}) does not match with the environment ({})."
                             .format(base_url, self._base_url))
        agent = self.agents.dict[agent_number]
        return agent

    async def trigger_act(self, *args, addr=None, agent=None, **kwargs):
        """Trigger agent to act.

        If *agent* is None, then looks the agent by the address.

        :raises ValueError: if both *agent* and *addr* are None.
        """
        if agent is None and addr is None:
            raise TypeError("Either addr or agent has to be defined.")
        if agent is None:
            agent = self.get_agent(addr)
        self._log(logging.DEBUG, "Triggering agent in {}".format(agent.addr))
        ret = await agent.act(*args, **kwargs)
        return ret

    async def trigger_all(self, *args, **kwargs):
        """Trigger all agents in the environment to act asynchronously.

        :returns: A list of agents' :meth:`act` return values.

        Given arguments and keyword arguments are passed down to each agent's
        :meth:`creamas.core.agent.CreativeAgent.act`.

        .. note::
            The environment's manager agent, i.e. if the environment has :attr:`manager`, is excluded from acting.
        """
        tasks = []
        for a in self.get_agents(addr=False, include_manager=False):
            task = asyncio.ensure_future(self.trigger_act
                                         (*args, agent=a, **kwargs))
            tasks.append(task)
        rets = await asyncio.gather(*tasks)
        return rets

    def is_ready(self):
        """Check if the environment is fully initialized.

        The function is mainly used by the multiprocessing environment managers
        and distributed environments to ensure that the environment has been
        correctly initialized before any other preparations are done for the
        environments or the simulation is started.

        Override the function in the subclasses which need more time consuming
        initialization routines. The function should return True when the
        environment is ready be used in a simulation, or when any
        cross-environment initialization routines can be run. That is, the
        environment is inherently in a coherent state, and can execute orders
        from managers or simulations.

        :rtype: bool
        :returns: This basic implementation returns always True.
        """
        return True

    def create_random_connections(self, n=5):
        """Create random connections for all agents in the environment.

        :param int n: the number of connections for each agent

        Existing agent connections that would be created by chance are not
        doubled in the agent's :attr:`connections`, but count towards
        connections created.
        """
        if type(n) != int:
            raise TypeError("Argument 'n' must be of type int.")
        if n <= 0:
            raise ValueError("Argument 'n' must be greater than zero.")
        for a in self.get_agents(addr=False):
            others = self.get_agents(addr=False)[:]
            others.remove(a)
            shuffle(others)
            for r_agent in others[:n]:
                a.add_connection(r_agent)

    def create_connections(self, connection_map):
        """Create agent connections from a given connection map.

        :param dict connection_map:
            A map of connections to be created. Dictionary where keys are agent addresses and values are lists of
            (addr, attitude)-tuples suitable for :meth:`~creamas.core.agent.CreativeAgent.add_connections`.

        Only connections for agents in this environment are made.
        """
        agents = self.get_agents(addr=False)
        rets = []
        for a in agents:
            if a.addr in connection_map:
                r = a.add_connections(connection_map[a.addr])
                rets.append(r)
        return rets

    def get_connections(self, data=True):
        """Return connections from all the agents in the environment.

        :param bool data: If ``True`` return also the dictionary associated with each connection

        :returns:
            A list of ``(addr, connections)``-tuples, where ``connections`` is a list of addresses agent in ``addr`` is
            connected to. If ``data`` parameter is ``True``, then the ``connections`` list contains tuples of
            ``(nb_addr, data)``-pairs , where ``data`` is a dictionary.

        :rtype: dict

        .. note::
            Environment's manager agent is excluded from the returned list.
        """
        connections = []
        for a in self.get_agents(addr=False):
            c = (a.addr, a.get_connections(data=data))
            connections.append(c)
        return connections

    def clear_connections(self):
        """Clear all connections from the agents in the environment.
        """
        for a in self.get_agents(addr=False):
            a.clear_connections()

    def get_random_agent(self, agent):
        """Return random agent that is not the same as the agent given as a parameter.

        :param agent: Agent that is not wanted to return
        :type agent: :py:class:`~creamas.core.agent.CreativeAgent`
        :returns: random, non-connected, agent from the environment
        :rtype: :py:class:`~creamas.core.agent.CreativeAgent`
        """
        r_agent = choice(self.get_agents(addr=False))
        while r_agent.addr == agent.addr:
            r_agent = choice(self.get_agents(addr=False))
        return r_agent

    def add_artifact(self, artifact):
        """Add artifact with given framing to the environment.

        :param object artifact: Artifact to be added.
        """
        artifact.env_time = self.age
        self.artifacts.append(artifact)
        self._log(logging.DEBUG, "ARTIFACTS appended: '{}', length={}"
                  .format(artifact, len(self.artifacts)))

    def add_artifacts(self, artifacts):
        """Add artifacts to :attr:`artifacts`.

        :param artifacts: list of :py:class:`~creamas.core.artifact.Artifact` objects
        """
        for artifact in artifacts:
            self.add_artifact(artifact)

    async def get_artifacts(self, agent=None):
        """Return artifacts published to the environment.

        :param agent: If not ``None``, then returns only artifacts created by the agent.

        :returns: All artifacts published (by the agent).
        :rtype: list

        If environment has a :attr:`manager` agent, e.g. it is a slave environment in
        :class:`~creamas.mp.MultiEnvironment`, then the manager's :meth:`~creamas.mp.EnvManager.get_artifacts` is called.
        """
        # TODO: Figure better way for this
        if hasattr(self, 'manager') and self.manager is not None:
            artifacts = await self.manager.get_artifacts()
        else:
            artifacts = self.artifacts
        if agent is not None:
            artifacts = [a for a in artifacts if agent.name == a.creator]
        return artifacts

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

    def save_info(self, folder, *args, **kwargs):
        """Save information accumulated during the environments lifetime.

        Called from :py:meth:`~creamas.core.Environment.destroy`. Override in subclass.

        :param str folder: root folder to save information
        """
        pass

    def destroy(self, folder=None, as_coro=False):
        """Close the environment.

        .. deprecated:: 0.4.0
            Use :func:`close` instead

        """
        DeprecationWarning("{0}.destroy is deprecated, use {0}.close instead.".format(str(self.__class__.__name__)))
        return self.close(folder=folder, as_coro=as_coro)

    def close(self, folder=None, as_coro=False):
        """Close the environment.

        Does the following:

        1. calls :py:meth:`~creamas.core.Environment.save_info`
        2. for each agent: calls :py:meth:`close`
        3. Shuts down its RPC-service.
        """
        async def _close(folder):
            ret = self.save_info(folder)
            for a in self.get_agents(addr=False):
                a.close(folder=folder)
            await self.shutdown(as_coro=True)
            return ret

        return run_or_coro(_close(folder), as_coro)

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

    def __repr__(self):
        return "{}({})".format(self.__class__.__name__, self.name)


import cv2
import numpy as np
import matplotlib.pyplot as plt

# Load the image
img = cv2.imread('opencv_logo.png')
img_contours = img.copy()
# Convert to grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Threshold the image to produce a binary image
ret, thresh = cv2.threshold(img_gray, 150, 255, 0)

# Find the contours
contours, heirarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draw the contours
cv2.drawContours(img_contours, contours, -1, (153,153,0), 3)

plt.subplot(2,2,1)
plt.title('original')
plt.imshow(img)

plt.subplot(2,2,2)
plt.title('grayscale')
plt.imshow(img_gray, cmap ='gray')

plt.subplot(2,2,3)
plt.title('binary image')
plt.imshow(thresh, cmap ='gray')

plt.subplot(2,2,4)
plt.title('contours')
plt.imshow(img_contours)

plt.show()


# !/usr/bin/env python
# -*- coding: utf-8 -*-
#--------------------------------------------------------------------------------------------------
# Name          : TieResolver.py
# Author  		: Mark Pooley (mark-pooley@uiowa.edu)
# Link    		: http://www.ppc.uiowa.edu
# Date    		: 2015-01-20 12:39:50
# Version		: $1.0$
# Description	:Takes as input a table of ties and a table of near pologyons.
# Ties are resolved by choosing the provider ZCTA that shares the longest
# common boundary with the recipient ZCTA. If none of the candidate provider
# ZCTAs are adjacent, then the nearest is selected calculating the distance
# between the rec_ZCTA and the prov_ZCTA
# ---------------------------------------------------------------------------

###################################################################################################
#Import python modules
###################################################################################################

import arcpy
from arcpy import env
import math
import csv
import os
from operator import itemgetter
from collections import defaultdict

###################################################################################################
#Input Variable loading and environment declaration
###################################################################################################
tieTable = arcpy.GetParameterAsText(0) #table of recipient provider ties
nbrTable = arcpy.GetParameterAsText(1) #table of polygon neighbors generated from ZCTAs
ZCTAs = arcpy.GetParameterAsText(2) #ZCTAs input
outputLocation = arcpy.GetParameterAsText(3) #location of output file
outFile = arcpy.GetParameterAsText(4) #name of ouput file
#check if '.csv' at end of outFile name, if not add it.
if outFile[:-4] != '.csv':
	outFile = outFile + '.csv'

outFile = os.path.join(outputLocation,outFile) #concantenate path and file name so it gets stored in correct location

env.workspace = arcpy.GetParameterAsText(5)
env.overwriteOutput = True

###################################################################################################
# Defining global functions
###################################################################################################

#define function that will be used to calculate the distance between paired points. Cursor data will be fed into this
def distanceXY(lat1, long1, lat2, long2):

    # Convert latitude and longitude to
    # spherical coordinates in radians.
    degrees_to_radians = math.pi/180.0

    # phi = 90 - latitude
    phi1 = (90.0 - lat1)*degrees_to_radians
    phi2 = (90.0 - lat2)*degrees_to_radians

    # theta = longitude
    theta1 = long1*degrees_to_radians
    theta2 = long2*degrees_to_radians

    cos = (math.sin(phi1)*math.sin(phi2)*math.cos(theta1 - theta2) + math.cos(phi1)*math.cos(phi2))
    arc = math.acos(cos)

    #multiple by 3960 to get miles
    arc = arc *3960
    return arc

###################################################################################################
#Global variables to be used in process
###################################################################################################
tempDict = defaultdict(list) #establish default dictionary to be populated with all csv entries
tieDict = {} #dictionary that will keep just ties
resolvedDict = {} #dictionary to contain resolved/matched ties
nbrTable_FieldList = [f.name for f in arcpy.ListFields(nbrTable)]
ZCTAs_FieldList = [f.name for f in arcpy.ListFields(ZCTAs)]
outList = [] # output list of entries that will be written to output CSV

###################################################################################################
#Pull field variables from field lists
###################################################################################################
src_ZCTA_field = [f for f in nbrTable_FieldList if 'src_' in f][0] #find src field within field list
nbr_ZCTA_field = [f for f in nbrTable_FieldList if 'nbr_' in f][0] #find nbr field within field list
ZCTA_field = [f for f in ZCTAs_FieldList if 'ZCTA' in f or 'ZIP' in f][0] #find ZCTA field within field list
length_Field = [f for f in nbrTable_FieldList if 'LENGTH' in f][0] #find LENGTH field within field list

###################################################################################################
#read in input CSV and create dictionaries of tied Rec ZCTAs
###################################################################################################

#open tieTable csv as reader csv and create a temporary dictionary of rec and prov ZCTAs from rows
with open(tieTable, "rb") as inFile:
	rowCount = 0
	#sniff into 10kb of csv to check dialect create a reader using the identified dialect and
	dialect = csv.Sniffer().sniff(inFile.read(10*1024))
	inFile.seek(0)
	reader = csv.reader(inFile, dialect) #reader object
	header = reader.next() #create header

	for row in reader:
		tempDict[row[0]].append(row[1])
		outList.append(row)
		rowCount +=1

#create new dictionary by iterating through current one and checking for value lists greater than 1
#lists greater than 1 indicate a tie
tieDict = {}
for key,value in tempDict.iteritems():
	if len(value) > 1:
		tieDict[key] = value
arcpy.AddMessage(str(len(tieDict)) + " ties found in data... ")

###################################################################################################
#Find best provider match where providers are
#adjacent/touching recipient ZCTA
###################################################################################################

#main loop to iterate through the ties dictionary and
arcpy.SetProgressor("step","Checking for matching provider ZCTAs adjacent to recipients...",0,len(tieDict),1)
for key,values in tieDict.iteritems():
	srcQuery =  src_ZCTA_field + " = '" + str(key) + "'"
	dyadBorder = 0

	#first check that the rec and prov don't match. If they do, consider the tie resolved by making the provider
	#zcta that of the recipient
	if key in values:
		resolvedDict[key] = values[values.index(key)]

	else:
		#create search cursor that will look through the neighbor table first.
		#in the future look to see if neighbors and shared boreder length can be identified
		#using geomtries instead of a bulky neighbor table
		with arcpy.da.SearchCursor(nbrTable,nbrTable_FieldList,srcQuery) as cursor:
			for row in cursor:
				if row[nbrTable_FieldList.index(nbr_ZCTA_field)] in values:
					if row[nbrTable_FieldList.index(length_Field)] > dyadBorder:
						dyadBorder = row[nbrTable_FieldList.index(length_Field)]
						provZCTA = row[nbrTable_FieldList.index(nbr_ZCTA_field)]
						arcpy.SetProgressorLabel("Match Found!")
						#resolvedDict[key] = provZCTA
		if dyadBorder > 0:
			#create match from the rec and provider sharing the most boundary length
			resolvedDict[key] = provZCTA
	arcpy.SetProgressorPosition() #update progressor positon

arcpy.AddMessage(str(len(resolvedDict)) + " ties resolved by finding martching or adjacent provider ZCTAs..." )

#create set of those where neighbor search is needed because provider ZCTAS
#aren't adjacent.  Use iteritems to iterate through a dictionary correctly.
for key,value in resolvedDict.iteritems():
	if tieDict.has_key(key):
		#if key is in resolved dictionary, pop identified key from tie dictionary and keep none of the values
		tieDict.pop(key,None)

arcpy.AddMessage(str(len(tieDict)) + " remaining ties to be resolved by finding nearest provider ZCTA...")

###################################################################################################
#Find best provider match - being the closest provider to the recipient ZCTA based on the
#distance between recipient and candidate provider centroid
###################################################################################################

#loop through remaining ties to find the nearest provider ZCTA
arcpy.SetProgressor('step','finding nearest provider ZCTAs for remaining ties...',0,len(tieDict),1)
for key,values in tieDict.iteritems():
	tempDict = {} #temporary dictionary to track the best recipient provider match
	recQuery = ZCTA_field + " = '" + str(key) + "'" #query to be used for search cursor
	provDistance = 1e309 #check variable for distance checking. set to infinity for each key value

	#get recipient coordinates using Shape@TRUECENTROID
	with arcpy.da.SearchCursor(ZCTAs,["ZCTA5CE10","SHAPE@TRUECENTROID"],recQuery) as cursor:
		for row in cursor:
			recCoord = row[1]
			recX = recCoord[0] #rec lat/X var
			recY = recCoord[1] #rec lon/Y var

	#-------------------------------------------------------------------------------------------
	#iterate through provider zctas to find coordinates and pass them through the
	#distance function.
	#-------------------------------------------------------------------------------------------
	for value in values:
		provQuery = ZCTA_field + " = '" + str(value) + "'" #queary to be used for search cursor
		with arcpy.da.SearchCursor(ZCTAs,[ZCTA_field,"SHAPE@TRUECENTROID"],provQuery) as cursor:
			for row in cursor:
				provCoord = row[1] #pull coordinate pairs
				provX = provCoord[0] #prov lat/X var
				provY = provCoord[1] #prov long/Y var

				#feed coordinates into distanceXY funcation to calculate distance between the two pairs
				distance = distanceXY(recX,recY,provX,provY)
				if distance < provDistance:
					provDistance = distance # declare newly caluclate distance as the minimum distance
					tempDict[key] = value #reassign recipient and provider paring based on caluclation

	resolvedDict.update(tempDict)#update the resovled dictionary with the best fitting pair
	arcpy.SetProgressorPosition() #update progressor position through each iteration

###################################################################################################
#write final output file to CSV
###################################################################################################

arcpy.SetProgressor("step", "writing new CSV with all ties resolved",0,rowCount,1)

#open tieTable csv as reader csv and create a temporary dictionary of rec and prov ZCTAs from rows
readerFile =  open(tieTable, "rb")
dialect = csv.Sniffer().sniff(readerFile.read(10*1024)) #sniff into 10kb of csv to check dialect create a reader using the identified dialect and
readerFile.seek(0) #not sure what this does, but it's important
reader = csv.reader(readerFile, dialect) #reader object using snieefed dialect
header = reader.next() #create header

outCSV = open(outFile, 'wb') #open writer object
writer = csv.writer(outCSV,dialect) #writer object using the reader dialect
writer.writerow(header) #write header

for row in reader:
	if row[0] not in resolvedDict: #if rec ZCTA is not in the resolved Dictionary, just write the row
		writer.writerow(row)

	elif resolvedDict[row[0]] == row[1]: #if resolved dictionary value for key is equal to prov_ZCTA, write row
		writer.writerow(row)

	else:
		pass #pass, nothing to see hear, not even a slight weapons malfunction

	arcpy.SetProgressorPosition() #udpate progressor position

#close csv files.
outCSV.close()
readerFile.close()

arcpy.AddMessage("Process complete!\n" + "Output csv location: " + str(os.path.realpath(outFile)))


# -*- coding:utf-8 -*-
import subprocess

def excute_shell(command: str, verbose: bool = False):
    params = {"text": True}
    program = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, **params)
    outputs = []
    while program.poll() is None:
        # 当程序退出时，似乎会读取到一个空字符串
        item = program.stdout.readline()
        if verbose:
            print(item, end="")
        outputs.append(item)
    return program.returncode, "".join(outputs)


#!/usr/bin/env python3
"""Sets up the Custom Fields needed to support this ParDreamin Demo.

Like all scripts in this project, this script requires that the `config/app.ini`
file has been set up already. Check out the README.md file in this project for
more information on configuration.
"""
import demoFunctions, os.path, sys

# read our configuration
config = demoFunctions.readConfig()

# login to the org
demoFunctions.authenticate(config)

# make sure we haven't previously created fields
if os.path.isfile('config/fields.csv'):
    print('This script has already generated fields in the past. Please delete them first using '\
        + '5-deleteCustomFields.py, then try re-running this script')
    sys.exit(10)

# create the fields to support the Template, which aren't specific to the number of
# listings we want to display
demoFunctions.createCustomField(config,'Count','')
demoFunctions.createCustomField(config,'AgentName','')

# loop through number of listings we can have at most in an email
itemCount = int(config['Field Naming']['listing_count_max'])
print('need to create {lineItemCount} groups of custom fields'\
        .format(lineItemCount = itemCount))

for i in range(1,itemCount+1):
    # loop through all the fields, creating them all
    print('Creating Fields for listing {lineItemNumber}'\
            .format(lineItemNumber = i))

    # fields will be named with the prefix defined in app.ini (for example: PD2021_Listing_XXXXXXXX)
    demoFunctions.createCustomFields(config, ['Price','Bedrooms','Bathrooms','Sqft','Address',
                                                'ListingUrl','ImageUrl'], i)

print('Done creating fields, details stored in config/fields.csv')


import time
from typing import Tuple

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class base_parser:
    """Parent class for parsers of all marketplaces"""
    def __init__(self):
        """Default constructor which created a web driver for selenium parser"""
        options = Options()
        self.driver = webdriver.Chrome(options=options)

    def parse(self, url):
        """Function parses a site via provided url. Should be reimplemented in each dependent class"""
        pass

class ozon_parser(base_parser):
    """Ozon market parser. Extends from base parser class"""
    def parse(self, url: str) -> Tuple[str, int]:
        """
        Reimplementation of parse function for ozon market. Parses price and name of product using provided url.
        :param url: url for the product
        :return: tuple (name, price)
        """
        try:
            self.driver.get(url)

            price = self._parse_price(self.driver.find_element(By.CLASS_NAME, 'k1y').text)
            name = self.driver.find_element(By.CLASS_NAME, 'lm').text

            return name, price

        except Exception as ex:
            print(ex)
            return "-1", -1

        finally:
            self.driver.close()
            self.driver.quit()

    def _parse_price(self, price: str) -> int:
        """
        Parses price from sting to integer.
        :param price: price in string format.
        :return: price in integer format.
        """
        price = price.rsplit(u'\u2009', 1)[0].replace(u'\u2009', '')

        return int(price)

class wildberries_parser(base_parser):
    """Wildberries market parser. Extends from base parser class"""
    def parse(self, url: str) -> Tuple[str, int]:
        """
        Reimplementation of parse function for wildberries market. Parses price and name of product using provided url.
        :param url: url for the product
        :return: tuple (name, price)
        """
        try:
            self.driver.get(url)
            WebDriverWait(self.driver, 60).until(
                EC.element_to_be_clickable((By.CLASS_NAME, 'price-block__final-price')))

            price = self._parse_price(self.driver.find_element(By.CLASS_NAME, 'price-block__final-price').text)
            name = self.driver.find_element(By.CLASS_NAME, 'product-page__header').text

            return name, price

        except Exception as ex:
            print(ex)
            return "-1", -1

        finally:
            self.driver.close()
            self.driver.quit()

    def _parse_price(self, price: str) -> int:
        """
        Parses price from sting to integer.
        :param price: price in string format.
        :return: price in integer format.
        """
        price_parts = price.rsplit(' ', 1)[0]
        merged_price = price_parts.replace(' ', '')

        return int(merged_price)

class sbermegamarket_parser(base_parser):
    """Sbermegamarket parser. Extends from base parser class"""
    def parse(self, url: str) -> Tuple[str, int]:
        """
        Reimplementation of parse function for sbermegamarket. Parses price and name of product using provided url.
        :param url: url for the product
        :return: tuple (name, price)
        """
        try:
            self.driver.get(url=url)
            time.sleep(3)
            try:
                self.driver.find_element(By.CLASS_NAME, 'header-region-selector-view__footer-ok').click()
            except Exception as ex:
                pass
            price_div = self.driver.find_element(By.CLASS_NAME, "pdp-sales-block__price-final")
            price_div_text = price_div.text
            item_price = ''
            for i in price_div_text:
                if i == '.' or i == ',' or i.isdigit():
                    item_price += i
            item_price = item_price.replace(',', '.')
            item_price = float(item_price)
            return ' ', item_price

        except Exception as ex:
            print(ex)
            return "-1", -1

        finally:
            self.driver.close()
            self.driver.quit()

class kazanexpress_parser(base_parser):
    """KazanExpress parser. Extends from base parser class"""
    def parse(self, url: str) -> Tuple[str, float]:
        """
        Reimplementation of parse function for kazanexpress market. Parses price and name of product using provided url.
        :param url: url for the product
        :return: tuple (name, price)
        """
        try:
            self.driver.get(url=url)
            time.sleep(5)
            prod_name = self.driver.find_element(By.XPATH, '//*[@id="product-info"]/div[1]/h1').text
            price_div = self.driver.find_element(By.XPATH, '//*[@id="product-info"]/div[2]/div[4]/div[2]/div[1]/span')
            price_div_text = price_div.text
            item_price = ''
            for i in price_div_text:
                if i == '.' or i == ',' or i.isdigit():
                    item_price += i
            item_price = item_price.replace(',', '.')
            item_price = float(item_price)
            return prod_name, item_price

        except Exception as ex:
            return "-1", -1

        finally:
            self.driver.close()
            self.driver.quit()

class yandex_market_parser(base_parser):
    """Yandex market parser. Extends from base parser class"""
    def parse(self, url: str) -> Tuple[str, float]:
        """
        Reimplementation of parse function for yandex market. Parses price and name of product using provided url.
        :param url: url for the product
        :return: tuple (name, price)
        """
        try:
            self.driver.get(url)
            time.sleep(15)
            xpath_for_name_list = ['/html/body/div[2]/div[2]/main/div[4]/div/div/div[2]/div/div/div[1]/div[1]/h1',
                                   '/html/body/div[2]/div[2]/main/div[3]/div/div/div[2]/div/div/div[1]/div[1]/h1',
                                   '/html/body/div[2]/div[2]/div/div/div[1]/div/div/div/div/div[1]/div[1]/h1']
            prod_name = ''
            for i in range(len(xpath_for_name_list)):
                xpath = xpath_for_name_list[i]
                flag = 0
                try:
                    prod_name = self.driver.find_element(By.XPATH, xpath).text
                except Exception as ex:
                    flag = 1
                if not flag:
                    break

            try:
                price_div = self.driver.find_element(By.XPATH, '//*[@id="cardAddButton"]/div[1]/div/div/div[1]/div/div[4]/div[1]/div/div[1]/div/h3/span[2]')
            except Exception as ex:
                price_div = self.driver.find_element(By.XPATH, '/html/body/div[2]/div[2]/div/div/div[3]/div/div[3]/div[1]/div[1]/div/div/div[3]/div[2]/div/div/div[1]/span/span[1]')
            price_div_text = price_div.text
            item_price = ''
            for i in price_div_text:
                if i == '.' or i == ',' or i.isdigit():
                    item_price += i
            item_price = item_price.replace(',', '.')
            item_price = float(item_price)
            return prod_name, item_price

        except Exception as ex:
            return "-1", -1

        finally:
            self.driver.close()
            self.driver.quit()


#!/usr/bin/python3

import json

f= open("terms.json","r")
j = json.load(f)

f.close()

f=open("queries_training_set.txt","r")
l = f.readlines()
f.close()

o=open("query_terms.txt","w")
for i in range(len(l)):
    a = l[i].split("\n")
    b = a[0].split(" ")
    s=""
    for c in b:
        s+=str(j[c])+","

    o.write(s[:len(s)-1]+"\n")

o.close()


import datetime

time = datetime.datetime.now()
date_time = time.strftime("%m/%d/%Y, %H:%M:%S")
class Operation:
    def __init__(self,balance):
        self.balance = balance
        self.account_change = []
    # main function to deal with credit
    def pullMoney( self, request):
        cash = 0
        papers = [100,50,20,10,5]
        if request <= self.balance :
            if request > 0 :
                for paper in papers:
                    while request >= paper :
                        request -= paper
                        cash += paper
                        self.balance -= paper
            if request < 10 :
                print(f'your request : {request}  \n'
                     f'you must provide more at least 10 $ to preform operation\n')
                cash_request = {
                    "cash":cash,
                    "time":date_time,
                    "balance":self.balance
                }
                self.account_change.append(cash_request)
                print(f'cash : {cash} \nbalance : {self.balance} ')
            else:
                print('can not preform request,pls input at least 10 $')
        else:
            print('sorry u dont have enough credits in you account')
    def show_Changes(self):
        print('your transcripation  details :')
        for operation in self.account_change :
            print(f'your withdraw {operation["cash"]} $ from your account at {operation["time"]}'
                  f' your balance : {operation["balance"]} $')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019-05-14 21:27
# @Author : lmh
# @Software: PyCharm
#

import openpyxl

class exceldata():
    def __init__(self, excelfile, sheetname):
        self.excelfile = excelfile
        self.sheetname = sheetname
        self.wb = openpyxl.load_workbook(self.excelfile)
        self.ws = self.wb[self.sheetname]
        self.rows = self.ws.max_row
        self.cols = self.ws.max_column

    def exceldata_row(self):
        """
        读取excel,每行数据和第一行组成一个字典.返回excel数据列表
        :return:excel数据列表,每个元素是该行和首行对应的字典
        """
        exceldata = []
        # 读取
        for r in range(1, self.rows+1):
            excelline = []
            for c in range(1, self.cols + 1):
                excelline.append(self.ws.cell(row=r, column=c).value)
            exceldata.append(excelline)

        excellist = []
        for i in range(1, len(exceldata)):
            dict1 = dict(zip(exceldata[0], exceldata[i]))
            excellist.append(dict1)
        return excellist

    def getChars(self, length):
        return [self.getChar(index) for index in range(length)]

    def getChar(self, number):
        factor, moder = divmod(number, 26) # 26 字母个数
        modChar = chr(moder + 65)          # 65 -> 'A'
        if factor != 0:
            modChar = self.getChar(factor-1) + modChar # factor - 1 : 商为有效值时起始数为 1 而余数是 0
        return modChar

    def exceldata_col(self):
        """
        读取excel,每列数据和第一列组成一个字典.返回excel数据列表
        :return:excel数据列表,每个元素是该行和首行对应的字典
        """
        # 读取
        exceldata = []
        for c in range(1, self.cols+1):
            excelline = []
            for r in range(1, self.rows + 1):
                excelline.append(self.ws.cell(row=r, column=c).value)
            exceldata.append(excelline)

        excellist = []
        for i in range(1, len(exceldata)):
            dict1 = dict(zip(exceldata[0], exceldata[i]))
            excellist.append(dict1)
        return excellist


from collections import defaultdict
import sys
sys.setrecursionlimit(10**6)

def solution(nodeinfo):
    num2x = {i+1 : nodeinfo[i][0] for i in range(len(nodeinfo))}
    x2num = {nodeinfo[i][0] : i+1 for i in range(len(nodeinfo))}
    y_cords = set()
    nodelevel = defaultdict(list)
    nodes = [[0] * 2 for _ in range(len(nodeinfo)+1)]

    for info in nodeinfo:
        y_cords.add(info[1])
        nodelevel[info[1]].append(info[0])
    y_cords = sorted(list(y_cords), reverse=True)

    def maketree(num, depth, ll, rl):
        if depth == len(y_cords):
            return

        x = num2x[num]
        for node in nodelevel[y_cords[depth]]:
            if ll <= node <= x:
                nodes[num][0] = x2num[node]
                maketree(x2num[node], depth+1, ll, x)
            elif x <= node <= rl:
                nodes[num][1] = x2num[node]
                maketree(x2num[node], depth+1, x, rl)

    root = x2num[nodelevel[y_cords[0]][0]]
    maketree(root, 1, 0, max(nodeinfo)[0])

    def preorder(n):
        if n == 0:
            return
        pre.append(n)
        preorder(nodes[n][0])
        preorder(nodes[n][1])

    def postorder(n):
        if n == 0:
            return
        postorder(nodes[n][0])
        postorder(nodes[n][1])
        post.append(n)

    pre = []
    post = []
    preorder(root)
    postorder(root)

    return [pre, post]


import pickle
import re

import settings

with open(settings.Model, "rb") as handle:
    model = pickle.load(handle)

def clean_tweet(tweet):
    """
    Clean the tweets before prediction
    :param tweet: Single tweet value
    :return: clean tweet
    """
    tweet = re.sub("RT @[\w]*:", "<user>", tweet)
    tweet = re.sub(r"@\w+", "<user>", tweet)
    tweet = re.sub(r"[-+]?[.\d]*[\d]+[:,.\d]*", "<number>", tweet)
    tweet = re.sub(r"https?:\/\/\S+\b|www\.(\w+\.)+\S*", "<url>", tweet)
    tweet = re.sub("#[\w]*:", "", tweet)
    tweet = re.sub(r"\W", " ", tweet)
    tweet = re.sub("â", "a", tweet)
    tweet = tweet.lower()
    return [tweet]

def predict(tweet):
    """
    predict the Intent of the text.
    :param text: tweet
    :return: Intent label
    """
    tweet = clean_tweet(tweet)
    tweet = model.predict(tweet)
    label = list(map(get_value, tweet))
    return label

# Key: code of intent and value: Intent label.
dict_labels = {
    0: "Disease signs or symptoms",
    1: "Disease transmission",
    2: "Prevention",
    3: "Treatment",
    4: "Deaths reports",
    5: "Affected people",
    6: "Other useful information",
    7: "Not related or irrelevant",
}

def get_value(x):
    """
    maps Intent label based on code.
    :param x: Intent code
    :return: Intent label
    """
    return list(dict_labels.values())[list(dict_labels.keys()).index(x)]


class Node(object):
    def __init__(self, data, parent_node):
        self.data = data
        self.parent_node = parent_node
        self.right_child = None
        self.left_child = None
        self.balance = 0

    def insert(self, data, parent_node):
        if data < self.data:
            if not self.left_child:
                self.left_child = Node(data, parent_node)
            else:
                self.left_child.insert(data, parent_node)
        else:
            if not self.right_child:
                self.right_child = Node(data, parent_node)
            else:
                self.right_child.insert(data, parent_node)
        return parent_node

    def traverse_in_order(self):
        if self.left_child:
            self.left_child.traverse_in_order()
        print(self.data)

        if self.right_child:
            self.right_child.traverse_in_order()
        print(self.data)

    def get_min(self):
        if not self.left_child:
            return self.data
        else:
            return self.left_child.get_min()

    def get_max(self):
        if not self.right_child:
            return self.data
        else:
            return self.right_child.get_max()

class BalanceTree(object):
    def __init__(self):
        self.root_node = None
    def insert(self, data):
        parent_node = self.root_node
        if self.root_node is None:
            parent_node = Node(data, None)
            self.root_node = parent_node
        else:
            parent_node = self.root_node.insert(data, self.root_node)
        self.rebalance_tree(parent_node)

    def rebalance_tree(self, parent_node):
        self.set_balance(parent_node)

    def set_balance(self, node):
        node.balance = (self.height(node.right_child) - self.height)

    def height(self, node):
        if node is None:
            return -1
        else:
            return 1 + max(self.height(node.right_child),
                           self.height(node.left_child))


#Author: Adam Ferrante
#Class: CIT-135-01
#Assignment: Week Eight Practice Problems - Question 2
#Date Assigned: Oct 16 @ 11am
#Due Date and Time: Oct 23 @ 11am
#Description: Allows a shape to be calculated from user input.
###
#Certification of Authenticity:  I certify that this is entirely my own work,
#except where I have given fully-documented references to the work of others.
#I understand the definition and consequences of plagiarism and acknowledge
#that the assessor of this assignment may, for the purpose of assessing
#this assignment: - Reproduce this assignment and provide a copy
#to another member of academic staff; and/or Communicate a copy
#of this assignment to a plagiarism checking service (which may then retain
#a copy of this assignment on its database for the purpose of
#future plagiarism checking)
###

import math

# Defines the functions for all four shapes.
def calc_square():
    side_length = float(input("Please enter the side length for the square: "))
    area = (side_length * side_length)
    area = round(area, 2)
    return area

def calc_rectangle():
    side_length = float(input("Please enter the length of the rectangle: "))
    side_height = float(input("Please enter the height of the rectangle: "))
    area = side_length * side_height
    area = round(area, 2)
    return area

def calc_triangle():
    side_base = float(input("Please enter the base of the triangle: "))
    side_height = float(input("Please enter the height of the triangle: "))
    area = .5 * (side_base * side_height)
    area = round(area, 2)
    return area

def calc_circle():
    radius = float(input("Please enter the radius of the circle: "))
    area = math.pi * (radius * radius)
    area = round(area, 2)
    return area

# Asks the user what shape they would like to input.
shape = int(input("Please input the number a shape below:\n\t1)Square\n\t2)Rectangle\n\t3)Triangle\n\t4)Circle\n> "))

# Determines what shape to use, calls the function, and outputs to the user.
if shape == 1:
    print("The area of a square is", calc_square())
elif shape == 2:
    print("The area of a rectangle is", calc_rectangle())
elif shape == 3:
    print("The area of a triangle is", calc_triangle())
elif shape == 4:
    print("The area of a circle is", calc_circle())


#LISCENSE
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#INTRODUCTION
# This program serves as an interface with the bulk
# uploader program. It allows one to specify a directory
# containing multiple osm files and have them all uploaded at
# once. Please use this program carefully and reach a
# a community consensus before massive imports.
# ~ingalls

#REQUIREMENTS
# Python2
# Python3

import os
import shutil
import sys
import optparse

rootLoc = os.getcwd()
version = "0.2"
fileLoc = ""
comment = ""
num = 0

#print "Enter Source Directory (Press enter for current)"
#fileLoc = raw_input(":")
sourceFiles = "src/"
outputFiles = "upload/"

#print "Enter Changeset Comment"
#comment = raw_input(":")
comment = 'Imported MassGIS Building Structures - %%filename%% - 4th data set';
source = 'Building Structures (2-D, from 2011-2012 Ortho Imagery) - Office of Geographic Information (MassGIS), Commonwealth of Massachusetts, Information Technology Division';

if not os.path.exists(rootLoc + "/" + outputFiles):
    os.makedirs(rootLoc + "/" + outputFiles)

for osmfile in os.listdir(sourceFiles):
    if osmfile.endswith(".osm"):
        fullOsmFile = sourceFiles + osmfile
        smallOutputStatusFile = outputFiles + osmfile[:-4] + "-status.txt"
        largeOutputStatusFile = outputFiles + osmfile[:-4] + "-part0000-status.txt"

        if ( not os.path.exists(smallOutputStatusFile) and not os.path.exists(largeOutputStatusFile) ) :

            print("converting to osc: " + fullOsmFile)
            r = os.system("python3.1 osm2osc.py " + fullOsmFile)
            if ( r ) :
               sys.exit(1)

            fullOSCFile = fullOsmFile[:-4] + ".osc"

            # clean out older OSC files, may have changed maxElements up or down.
            if ( os.path.exists( outputFiles + osmfile[:-4] + ".osc" ) ) :
                os.remove( outputFiles + osmfile[:-4] + ".osc")
                os.remove( outputFiles + osmfile[:-4] + ".comment")
                os.remove( outputFiles + osmfile[:-4] + ".source")

            fileCount = 0
            while ( os.path.exists( outputFiles + osmfile[:-4] + "-part%04d.osc" % (fileCount,) )) :
                os.remove( outputFiles + osmfile[:-4] + "-part%04d.osc" % (fileCount,) )
                os.remove( outputFiles + osmfile[:-4] + "-part%04d.comment" % (fileCount,) )
                os.remove( outputFiles + osmfile[:-4] + "-part%04d.source" % (fileCount,) )
                fileCount += 1

            print("splitting osc: " + fullOSCFile)
            r = os.system("python osmsplit.py --outputDir " + outputFiles + " --maxElements 10000 " + fullOSCFile)
            if ( r ) :
                sys.exit(1)
            os.remove( fullOSCFile)
        else :
            print("already uploaded skipping: " + fullOsmFile)

# write out comment and source files.
for oscfile in os.listdir(outputFiles):
    if oscfile.endswith(".osc"):
        commentFilename = outputFiles + oscfile[:-4] + ".comment"
        if ( not os.path.exists(commentFilename)  ) :
            commentFile = open( commentFilename,"w")
            commentFile.write(comment.replace('%%filename%%',oscfile))
            commentFile.close()

            sourceFilename = outputFiles + oscfile[:-4] + ".source"
            sourceFile = open( sourceFilename,"w")
            sourceFile.write(source)
            sourceFile.close()


import numpy as np

def formation_of_bicluster(cluster_gene, gene_data, label_gene, cond_cluster, cond_data, label_cond):
    """
       :param cluster_gene: # no. of gene clusters
       :param gene_data: # the whole data for formation of gene cluster
       :param label_gene:  # list that contain label of gene cluster
       :param cond_cluster: # no. of condition cluster
       :param cond_data:  # the whole data for formation of condition cluster
       :param label_cond: # no. of gene cluster
       :param threshold_value:  # the threshold value of MSR
       :return: a list of bicluster
       """

    pop_gene = [[] for i in range(cluster_gene)]   # list to store all condition clusters that belong to same label
    for i in range(len(label_gene)):
        pop_gene[label_gene[i]].append(gene_data[i])
    #print(pop_gene)
    pop_cond = [[] for i in range(cond_cluster)]   # list to store all gene clusters that belong to same label
    for i in range(len(label_cond)):
        pop_cond[label_cond[i]].append(cond_data[i])
    #print(pop_cond)

    cond_index = [[] for j in range(cond_cluster)]  # store index of condition column that belong to same label
    # for formation of bicluster
    for i in range(len(label_cond)):
        cond_index[label_cond[i]].append(i)
    #print(cond_index)

    arr = []  # store the value of starting location of each condtion cluster in original data in first gene cluster
    arr.append(len(pop_cond[0]))
    for i in range(1, len(pop_cond)):
        arr.append(arr[i - 1] + (len(pop_cond[i])))
    #print("Length of each condition cluster:", arr)
    again = [0]    # store the value of starting location of each condtion cluster in original data in all gene cluster
    new = []  # store length of condition cluster
    again.extend(arr)
    #print(again)
    for i in range(cond_cluster):
        new.append(len(pop_cond[i]))
    #print(new)
    for i in range(1, cluster_gene):
        for j in new:
            flag = again[-1]
            flag += j
            again.append(flag)
    #print(again)

    max = []  # store all gene cluster in transpose manner
    for s in pop_gene:
        for sub in cond_index:
            for i in sub:
                k = np.array(s).T.tolist()
                max.append((k[i]))
    #print(max)

    # to finally select biclusters from max list
    Bicluster = []  # store bicluster of all possible combination of gene and condition cluster
    for i in range(1, len(again)):
        Bicluster.append(max[again[i - 1]:again[i]])
    #print("All biclusters:", Bicluster)
    return Bicluster


import sys
import os
import numpy as np
import pandas as pd
from pathlib import Path
import wandb
import socket
import setproctitle
import torch
from offpolicy.config import get_config
from offpolicy.utils.util import get_cent_act_dim, get_dim_from_space
from offpolicy.envs.predator_prey.stag_hunt import StagHunt
from offpolicy.envs.env_wrappers import ShareDummyVecEnv, ShareSubprocVecEnv

def make_train_env(all_args):
    def get_env_fn(rank):
        def init_env():
            if all_args.env_name == "Predator_prey":
                env = StagHunt(all_args)
            else:
                print("Can not support the " +
                      all_args.env_name + "environment.")
                raise NotImplementedError
            return env
        return init_env
    if all_args.n_rollout_threads == 1:
        return ShareDummyVecEnv([get_env_fn(0)])
    else:
        return ShareSubprocVecEnv([get_env_fn(i) for i in range(all_args.n_rollout_threads)])

def make_eval_env(all_args):
    def get_env_fn(rank):
        def init_env():
            if all_args.env_name == "Predator_prey":
                env = StagHunt(all_args)
            else:
                print("Can not support the " +
                      all_args.env_name + "environment.")
                raise NotImplementedError
            env.seed(all_args.seed * 50000 + rank * 10000)
            return env
        return init_env
    if all_args.n_eval_rollout_threads == 1:
        return ShareDummyVecEnv([get_env_fn(0)])
    else:
        return ShareSubprocVecEnv([get_env_fn(i) for i in range(all_args.n_eval_rollout_threads)])

def parse_args(args, parser):
    parser.add_argument('--use_available_actions', action='store_false',
                        default=True, help="Whether to use available actions")
    parser.add_argument('--use_same_share_obs', action='store_false',
                        default=True, help="Whether to use available actions")
    parser.add_argument('--use_global_all_local_state', action='store_true',
                        default=False, help="Whether to use available actions")
    parser.add_argument("--num_stags", type=int, default=3)
    parser.add_argument("--num_hare", type=int, default=3)
    parser.add_argument('--num_agents', type=int,
                        default=3, help="number of agents")
    parser.add_argument('--toroidal', action='store_true',
                        default=False, help="whether the world is bounded (False) or toroidal (True)")
    parser.add_argument('--world_shape',type=list, default=[10, 10], help="the shape of the grid-world [height, width]")
    parser.add_argument('--agent_obs',type=list, default=[2,2], help="(radius-1) of the agent's observation, e.g., [0, 0] observes only one pixel")
    parser.add_argument('--agent_move_block',type=list, default=[0,1,2], help="by which entities is an agent's move blocked (0=agents, 1=stags, 2=hare)")
    parser.add_argument('--capture_action_conditions',type=list, default=[3,1], help="number of agents that have to simultaneously execute catch action")
    #parser.add_argument('--capture_action_conditions',nargs = '+', help="number of agents that have to simultaneously execute catch action",required=True)
    parser.add_argument('--reward_hare', type=int,
                        default=1, help="reward for capturing a hare")
    parser.add_argument('--reward_stag', type=int,
                        default=10, help="reward for capturing a stag")
    parser.add_argument('--reward_collision', type=float,
                        default=0, help="reward (or punishment) for colliding with other agents")
    parser.add_argument('--reward_time', type=float,
                        default=0, help="reward (or punishment) given at each time step")
    parser.add_argument('--miscapture_punishment', type=float, default=-2)
    parser.add_argument('--capture_action', action='store_false',
                        default=True, help="whether capturing requires an extra action (True) or just capture_conditions (False)")
    parser.add_argument('--capture_terminal', action='store_true',
                        default=False, help="whether capturing any prey ends the episode (i.e. only one prey can be caught)")
    parser.add_argument('--p_stags_rest', type=float, default=0,help="probability that a stag will not move (at each time step)")
    parser.add_argument('--p_hare_rest', type=float, default=0)
    parser.add_argument('--prevent_cannibalism', action='store_false',
                        default=True, help="If set to False, prey can be captured by other prey (witch is rewarding)")
    parser.add_argument('--remove_frozen', action='store_false',
                        default=True, help="whether frozen agents are removed (True) or still present in the world (False)")
    parser.add_argument('--capture_freezes', action='store_false',
                        default=True, help="whether capturing any prey freezes the participating agents (True) or not (False)")
    parser.add_argument('--num_factor', type=int,
                        default=28, help="number of factor")
    parser.add_argument('--highest_orders', type=int,
                        default=3, help="number of agents")
    all_args = parser.parse_known_args(args)[0]

    return all_args

def main(args):
    parser = get_config()
    all_args = parse_args(args, parser)

    # cuda and # threads
    if all_args.cuda and torch.cuda.is_available():
        device = torch.device("cuda:0")
        torch.set_num_threads(all_args.n_training_threads)
        if all_args.cuda_deterministic:
            torch.backends.cudnn.benchmark = False
            torch.backends.cudnn.deterministic = True
    else:
        device = torch.device("cpu")
        torch.set_num_threads(all_args.n_training_threads)

    # setup file to output tensorboard, hyperparameters, and saved models
    run_dir = Path(os.path.split(os.path.dirname(os.path.abspath(__file__)))[
                   0] + "/results") / all_args.env_name / all_args.algorithm_name / all_args.experiment_name
    if not run_dir.exists():
        os.makedirs(str(run_dir))

    if all_args.use_wandb:
        # init wandb
        run = wandb.init(config=all_args,
                         project=all_args.env_name,
                         entity=all_args.user_name,
                         notes=socket.gethostname(),
                         name=str(all_args.algorithm_name) + "_" +
                         str(all_args.experiment_name) +
                         "_seed" + str(all_args.seed),
                         dir=str(run_dir),
                         job_type="training",
                         reinit=False)
    else:
        if not run_dir.exists():
            curr_run = 'run1'
        else:
            exst_run_nums = [int(str(folder.name).split('run')[
                                 1]) for folder in run_dir.iterdir() if str(folder.name).startswith('run')]
            if len(exst_run_nums) == 0:
                curr_run = 'run1'
            else:
                curr_run = 'run%i' % (max(exst_run_nums) + 1)
        run_dir = run_dir / curr_run
        if not run_dir.exists():
            os.makedirs(str(run_dir))

    setproctitle.setproctitle(str(all_args.algorithm_name) + "-" + str(
        all_args.env_name) + "-" + str(all_args.experiment_name) + "@" + str(all_args.user_name))

    # set seeds
    torch.manual_seed(all_args.seed)
    torch.cuda.manual_seed_all(all_args.seed)
    np.random.seed(all_args.seed)

    env = make_train_env(all_args)
    num_agents = all_args.num_agents
    # create policies and mapping fn
    if all_args.share_policy:
        print(env.share_observation_space[0])
        policy_info = {
            'policy_0': {"cent_obs_dim": get_dim_from_space(env.share_observation_space[0]),
                         "cent_act_dim": get_cent_act_dim(env.action_space),
                         "obs_space": env.observation_space[0],
                         "share_obs_space": env.share_observation_space[0],
                         "act_space": env.action_space[0]}
        }

        def policy_mapping_fn(id): return 'policy_0'
    else:
        policy_info = {
            'policy_' + str(agent_id): {"cent_obs_dim": get_dim_from_space(env.share_observation_space[agent_id]),
                                        "cent_act_dim": get_cent_act_dim(env.action_space),
                                        "obs_space": env.observation_space[agent_id],
                                        "share_obs_space": env.share_observation_space[agent_id],
                                        "act_space": env.action_space[agent_id]}
            for agent_id in range(num_agents)
        }

        def policy_mapping_fn(agent_id): return 'policy_' + str(agent_id)

    # choose algo
    if all_args.algorithm_name in ["rmaddpg", "qtran","qmix", "vdn","rddfg_cent_rw","dcg"]:
        from offpolicy.runner.rnn.prey_runner import PREYRunner as Runner
        assert all_args.n_rollout_threads == 1, ("only support 1 env in recurrent version.")
        eval_env = make_train_env(all_args)
    elif all_args.algorithm_name in ["matd3", "maddpg", "masac", "mqmix", "mvdn"]:
        from offpolicy.runner.mlp.smac_runner import SMACRunner as Runner
        eval_env = make_eval_env(all_args)
    else:
        raise NotImplementedError

    adj = torch.zeros((all_args.num_agents,all_args.num_factor),dtype=torch.int64)
    index = 0
    n = 0
    if all_args.use_dyn_graph == False and all_args.equal_vdn == False and all_args.algorithm_name in ["rddfg_cent_rw","dcg"]:
        for i in range(all_args.num_agents-1):
            for j in range(i+1,all_args.num_agents):
                adj[i,index] = 1
                adj[j,index] = 1
                index = index + 1
        for i in range(index,all_args.num_factor):
            adj[n,i] = 1
            n = n + 1

    config = {"args": all_args,
              "policy_info": policy_info,
              "policy_mapping_fn": policy_mapping_fn,
              "env": env,
              "eval_env": eval_env,
              "num_agents": num_agents,
              "device": device,
              "run_dir": run_dir,
              "use_same_share_obs": all_args.use_same_share_obs,
              "use_available_actions": all_args.use_available_actions,
              "adj": adj}

    total_num_steps = 0
    runner = Runner(config=config)

    progress_filename = os.path.join(run_dir,'config.csv')
    df = pd.DataFrame(list(all_args.__dict__.items()),columns=['Name', 'Value'])
    df.to_csv(progress_filename,index=False)

    progress_filename = os.path.join(run_dir,'progress.csv')
    df = pd.DataFrame(columns=['step','reward'])
    df.to_csv(progress_filename,index=False)

    progress_filename = os.path.join(run_dir,'progress_eval.csv')
    df = pd.DataFrame(columns=['step','reward'])
    df.to_csv(progress_filename,index=False)

    progress_filename_train = os.path.join(run_dir,'progress_train.csv')
    df = pd.DataFrame(columns=['step','loss','Q_tot','grad_norm'])
    df.to_csv(progress_filename_train,index=False)

    progress_filename_train = os.path.join(run_dir,'progress_train_adj.csv')
    df = pd.DataFrame(columns=['step','advantage','clamp_ratio','rl_loss','entropy_loss','grad_norm'])
    df.to_csv(progress_filename_train,index=False)
    while total_num_steps < all_args.num_env_steps:
        total_num_steps = runner.run()

    env.close()
    if all_args.use_eval and (eval_env is not env):
        eval_env.close()

    if all_args.use_wandb:
        run.finish()
    else:
        runner.writter.export_scalars_to_json(str(runner.log_dir + '/summary.json'))
        runner.writter.close()

if __name__ == "__main__":
    main(sys.argv[1:])


import re
import warnings

import numpy as np
from astropy.coordinates.sky_coordinate import SkyCoord
from bs4 import BeautifulSoup

from lcc.db_tier.base_query import LightCurvesDb
from lcc.entities.exceptions import QueryInputError
from lcc.entities.star import Star
from lcc.utils.commons import ProxyRotatingSession

class OgleII(LightCurvesDb):
    """
    Connector to OGLEII. It is divided into two subdatabases - "phot" and "bvi".
    The first one contains light curves and metadata about coordinates, identifiers
    and V magnitude. The second one also contains information about V and I.

    Identifier of the stars in OgleII db are: field, starid and target.

    In case of cone search (if coordinates are provided), "nearest" key can
    be used. If it is True just nearest star to the target point is returned.

    Example:
    --------
    que1 = {"ra": 5.549147 * 15,
       "dec": -70.55792, "delta": 5, "nearest": True}
    que2 = {"field":"LMC_SC1","starid":"152248"}

    client = StarsProvider().getProvider(
        obtain_method="OgleII", obtain_params=[que1, que2])
    stars = client.getStarsWithCurves()
    """

    ROOT = "http://ogledb.astrouw.edu.pl/~ogle/photdb"

    BVI_TARGETS = ["lmc", "smc", "bul"]
    PHOT_TARGETS = ["lmc", "smc", "bul", "car"]

    QUERY_TYPES = ["bvi", "phot"]

    MAX_TIMEOUT = 60

    LC_META = {"xlabel": "hjd",
               "xlabel_unit": "days",
               "ylabel": "magnitude",
               "ylabel_unit": "mag",
               "color": "V",
               "origin": "OgleII"}

    COL_MAP = {"Field": "field",
               "StarID": "starid",
               "RA": "ra",
               "Decl": "dec",
               "V": "v_mag",
               "I": "i_mag",
               "B": "b_mag"}

    QUERY_OPTIONS = ["ra", "dec", "delta", "nearest", "field", "field_num", "starid", "target"]

    def __init__(self, queries, multiproc=False):
        """
        Parameters
        ----------
        queries : list, dict, iterable
            Query is list of dictionaries of query parameters or single
            dictionary

        multiproc : bool, int
            If True task will be distributed into threads by using all cores. If it is number,
            just that number of cores are used
        """
        if isinstance(queries, dict):
            queries = [queries]
        self.queries = self._parseQueries(queries)
        self.multiproc = multiproc

    def getStar(self, query, load_lc=True):
        """
        Query `Star` object

        Parameters
        ----------
        load_lc : bool
            Append light curves to star objects

        Returns
        -------
        list
            List of `Star` objects
        """
        if "starid" in query and query["starid"] < 1:
            raise ValueError("Starid has to be greater then 0")

        stars = self.postQuery(query, load_lc)
        if "ra" in query and "dec" in query and "delta" in query:
            stars = self.coneSearch(SkyCoord(float(query["ra"]), float(query["dec"]), unit="deg"),
                                    stars, float(query["delta"] / 3600.),
                                    nearest=query.get("nearest", False))
        return stars

    def postQuery(self, query, load_lc):
        PAGE_LEN = int(1e10)
        valmin_ra, valmax_ra, valmin_dec, valmax_dec = self._getRanges(query.get("ra"),
                                                                       query.get(
                                                                           "dec"),
                                                                       query.get("delta"))
        if valmax_ra and valmax_ra:
            valmax_ra = valmax_ra / 15.
            valmin_ra = valmin_ra / 15.

        params = {
            "db_target": query.get("target"),
            "dbtyp": "dia2",
            "sort": "field",
            "use_field": "field" in query,
            "val_field": query.get("field"),
            "use_starid": "starid" in query,
            "val_starid": query.get("starid"),
            "disp_starcat": "off",
            "use_starcat": "off",
            "disp_ra": "on",
            "use_ra": valmin_ra != "",
            "valmin_ra": valmin_ra,
            "valmax_ra": valmax_ra,
            "disp_decl": "on",
            "use_decl": valmin_dec != "",
            "valmin_decl": valmin_dec,
            "valmax_decl": valmax_dec,
            "disp_imean": "on",
            "use_imean": "mag_i_min" in query,
            "valmin_imean": query.get("mag_i_min"),
            "valmax_imean": query.get("mag_i_max"),
            "disp_pgood": "off",
            "disp_bmean": "on",
            "disp_vmean": "on",
            "disp_imed": "off",
            "disp_bsig": "off",
            "disp_vsig": "off",
            "disp_isig": "off",
            "disp_imederr": "off",
            "disp_ndetect": "off",
            "disp_v_i": "off",
            "disp_b_v": "off",
            "sorting": "ASC",
            "pagelen": PAGE_LEN,
        }
        # Delete unneeded parameters
        cparams = dict()
        for key, value in params.items():
            if value and value != "off":
                cparams[key] = value
        # Url for query
        url = "%s/query.php?qtype=%s&first=1" % (self.ROOT, query.get("db"))
        result = ProxyRotatingSession().post(url, cparams)
        return self._parseResult(result, lc=load_lc)

    def _parseQueries(self, queries):
        todel_queries = []
        new_queries = []
        for i, query in enumerate(queries):
            if "db" not in query:
                query["db"] = self.QUERY_TYPES[0]

            if "coo" in query and isinstance(query["coo"], SkyCoord) and "delta" in query:
                todel_queries.append(i)
                coo = query["coo"]
                query["ra"] = coo.ra.degree
                query["dec"] = coo.dec.degree

            if "ra" in query and "dec" in query and "target" not in query:
                todel_queries.append(i)

                if query["db"] == "phot":
                    targets = self.PHOT_TARGETS
                else:
                    targets = self.BVI_TARGETS

                for target in targets:
                    z = query.copy()
                    z["target"] = target
                    new_queries.append(z)

            elif "starid" in query:
                if "field" in query:
                    query["target"] = query["field"][:3].lower()
                elif "field_num" in query and "target" in query:
                    query["field"] = query[
                        "target"].upper() + "_SC" + str(query["field_num"])
                else:
                    raise QueryInputError("Unresolved target")

            if query["db"] not in self.QUERY_TYPES:
                raise QueryInputError(
                    "Invalid db. Available OgleII databases: %s" % self.QUERY_TYPES)

        return [item for i, item in enumerate(
            queries) if i not in todel_queries] + new_queries

    def _parseResult(self, result, lc=False):
        START_TABLE = "
<table"
        END_TABLE = "
"

        if result.status_code != 200:
            warnings.warn("Website has not returned 200 status")
            return []

        lc_tmp = None
        raw_table = ""
        skip = True
        for line in result.iter_lines():
            line = line.decode()
            if skip:
                if line.strip().startswith(START_TABLE):
                    raw_table += line[len("
"):]
                    skip = False
                if lc and line.strip().startswith("<input type='hidden'"):
                    tmpdir_pattern = re.compile(
                        "<input type='hidden' name='tmpdir' value='(.*)'>")
                    tmpdir = tmpdir_pattern.match(line)
                    if tmpdir:
                        lc_tmp = tmpdir.group(1)

            else:
                if line.strip().startswith(END_TABLE):
                    break
                raw_table += line

        if not raw_table:
            return []

        soup = BeautifulSoup(raw_table, "lxml")
        table = soup.find('table')
        rows = table.findAll('tr')

        res_rows = []
        for tr in rows[1:]:
            cols = tr.findAll('td')
            res_cols = []
            for td in cols:
                res_cols.append(td.find(text=True))
            res_rows.append(res_cols)

        header = [th.find(text=True) for th in table.findAll("th")]
        return self._createStars(header, res_rows, lc_tmp)

    def _createStars(self, header, rows, lc_tmp):
        # [u'No', u'Field', u'StarID', u'RA', u'Decl', u'V', u'I', u'B']
        # [u'No', u'Field', u'StarID', u'RA', u'Decl', u'I']

        cols_map = self._parseHeader(header)
        stars = []
        for row in rows:
            field = str(row[cols_map.get("field")])
            starid = int(row[cols_map.get("starid")])
            ra = float(row[cols_map.get("ra")])
            dec = float(row[cols_map.get("dec")])

            colors = ["i_mag", "b_mag", "v_mag"]
            more = {}
            for col in colors:
                if cols_map.get(col) and cols_map.get(col):
                    try:
                        more[col] = float(row[cols_map.get(col)])
                    except:
                        pass

            name = field + "_" + str(starid)
            coo = (ra * 15, dec, "deg")

            ident = {"OgleII": {"name": name,
                                "db_ident": {"field": field,
                                             "starid": starid}}}

            st = Star(ident, name, coo, more)

            if lc_tmp:
                lc = self._getLc(field, starid, lc_tmp)
                if lc and len(lc) != 0:
                    st.putLightCurve(np.array(lc), meta=self.LC_META)

            stars.append(st)
        return stars

    def _parseHeader(self, header):
        cols_map = {}
        for i, col in enumerate(header):
            if col in list(self.COL_MAP.keys()):
                cols_map[self.COL_MAP[col]] = i
        return cols_map

    def _getLc(self, field, starid, lc_tmp):
        params = {
            "field": field,
            "starid": starid,
            "tmpdir": lc_tmp,
            "db": "DIA",
            "points": "good",
        }

        _url = "%s/getobj.php" % self.ROOT
        ProxyRotatingSession().post(_url, params)

        url = "%s/data/%s/%s_i_%s.dat" % (self.ROOT,
                                          lc_tmp, field.lower(), starid)
        try:
            result = ProxyRotatingSession().get(url)

            if result.status_code == 200:
                star_curve = []
                # TODO: Can be loaded with pandas
                for line in result.iter_lines():
                    line = line.decode()
                    parts = line.strip().split(" ")
                    star_curve.append(
                        [round(float(parts[0]), 4), round(float(parts[1]), 3), round(float(parts[2]), 3)])
                return star_curve

        # TODO
        except:
            raise


import adivinhacao
import forca
def escolhe_jogo():
    print("Qual jogo deseja joga?")
    print("1 - adivinhacao  //  2 - forca")

    jogo = int(input("Digite o jogo que deseja: "))

    if(jogo == 1):
        print("Inicializando adivinhacao")
        adivinhacao.joga_adivinhacao()
    elif(jogo == 2):
        print("Inicializando forca")
        forca.joga_forca()

if(__name__== "__main__"):
    escolhe_jogo()


class OneOnly:

    _singleton = None

    def __new__(cls, *args, **kwargs):

        if not cls._singleton:
        # THEN
            cls._singleton = super(OneOnly, cls).__new__(cls, *args, **kwargs)
        # ENDIF;

        return cls._singleton

    # END __new__

# END OneOnly.

print("Only one created:")
s1 = OneOnly()
print(id(s1))
s2 = OneOnly()
print(id(s2))

class MoreThanOne:
    None
# END MoreThanOne.

print("More than one created:")
s3 = MoreThanOne()
print(id(s3))
s4 = MoreThanOne()
print(id(s4))


class Solution(object):
    def maxSubArray(self, nums):
        """
        定义状态 dp[i] 表示以第 i 个数结尾的「连续子数组的最大和」
        要求答案就是 max(dp[i])  0≤i≤n−1

        可以考虑 nums[i] 单独成为一段还是加入 dp[i-1] 对应的那一段
        :type nums: List[int]
        :rtype: int
        """

        dp = [0] * len(nums)

        for i, num in enumerate(nums):
            dp[i] = max(dp[i-1]+num, num)

        return max(dp)


import mock
import testtools

from dashboard import web

class TestWebUtils(testtools.TestCase):
    def setUp(self):
        super(TestWebUtils, self).setUp()

    def test_make_commit_message(self):
        message = '''
During finish_migration the manager calls initialize_connection but doesn't
update the block_device_mapping with the potentially new connection_info
returned.

Fixes bug 1076801
Change-Id: Ie49ccd2138905e178843b375a9b16c3fe572d1db'''

        module = 'test'

        record = {
            'message': message,
            'module': module,
        }

        expected = '''\
During finish_migration the manager calls initialize_connection but doesn't \
update the block_device_mapping with the potentially new connection_info \
returned.
Fixes bug \
1076801
''' + ('Change-Id: '
       'Ie49ccd2138905e178843b375a9b16c3fe572d1db')

        observed = web.make_commit_message(record)

        self.assertEqual(expected, observed,
                         'Commit message should be processed correctly')

    def test_make_commit_message_blueprint_link(self):
        message = '''
Implemented new driver for Cinder <:
Implements Blueprint super-driver
Change-Id: Ie49ccd2138905e178843b375a9b16c3fe572d1db'''

        module = 'cinder'

        record = {
            'message': message,
            'module': module,
        }

        expected = '''\
Implemented new driver for Cinder <:
Implements Blueprint ''' + (
            'super-driver' + '\n' +
            'Change-Id: '
            'Ie49ccd2138905e178843b375a9b16c3fe572d1db')

        observed = web.make_commit_message(record)

        self.assertEqual(expected, observed,
                         'Commit message should be processed correctly')

    @mock.patch('dashboard.web.get_vault')
    @mock.patch('dashboard.web.get_user_from_runtime_storage')
    def test_make_page_title(self, user_patch, vault_patch):
        memory_storage_mock = mock.Mock()
        memory_storage_mock.get_original_company_name = mock.Mock(
            return_value='Mirantis'
        )
        vault_patch.return_value = {'memory_storage': memory_storage_mock}
        user_patch.return_value = {'user_name': 'John Doe'}

        self.assertEqual('OpenStack community contribution in all releases',
                         web.make_page_title('', '', '', 'all'))
        self.assertEqual('OpenStack community contribution in Havana release',
                         web.make_page_title('', '', '', 'Havana'))
        self.assertEqual('Mirantis contribution in Havana release',
                         web.make_page_title('Mirantis', '', '', 'Havana'))
        self.assertEqual('John Doe contribution in Havana release',
                         web.make_page_title('', 'john_doe', '', 'Havana'))
        self.assertEqual(
            'John Doe (Mirantis) contribution to neutron in Havana release',
            web.make_page_title('Mirantis', 'John Doe', 'neutron', 'Havana'))


import argparse
import tomli

def get_args():
    parser = argparse.ArgumentParser(description="Process .txt and .md files to .html")
    parser.add_argument(
        "path", nargs="?",
        help="path to the file or folder to be processed"
    )
    parser.add_argument(
        "--version", "-v", action="store_true",
        help="print the tool's name and version"
    )
    parser.add_argument(
        "--output",
        "-o",
        default="./html/examples",
        help="Specify a different output directory",
    )
    parser.add_argument(
        "--lang",
        "-l",
        default="en-CA",
        help="Specify the language for the lang attribute in the HTML document",
    )
    parser.add_argument(
        "--config", "-c",
        help="Specify a different config file"
    )

    args = parser.parse_args()

    # Handle TOML config logic
    if args.config:
        try:
            with open(args.config, "rb") as f:
                default_values = {
                    "path": None,
                    "output": "./html/examples",
                    "lang": "en-CA",
                    "version": False,
                }

                toml_dict = tomli.load(f)

                # Convert the dict to a Namespace object
                args = argparse.Namespace(**toml_dict)

                # Set any missing args to their default values
                for key, value in default_values.items():
                    setattr(args, key, getattr(args, key, value))
        except tomli.TOMLDecodeError:
            print(f"Error: {args.config} is not a valid config TOML file.")
            return None
        except FileNotFoundError:
            print(f"Error: {args.config} does not exist.")
            return None
        except IsADirectoryError:
            print(
                f"Error: {args.config} is a directory. Must provide path to config file."
            )
            return None

    return args


n = list(map(int, input().strip().split()))
while n != [0, 0]:
    new = []
    line = input()
    for letter in line:
        new.append(letter)
    for i in range(1, n[0]):
        line = input()
        j = 0
        while j < len(line):
            new[j] += line[j]
            j += 1
    new = sorted(new, key=lambda s: s.lower())
    for i in range(0, n[0]):
        s = ""
        for j in range(0, n[1]):
            s += new[j][i]
        print(s)
    n = list(map(int, input().strip().split()))
    if n != [0, 0]:
        print()


#!/usr/bin/env python3

def merge(lst1, lst2):

    results = []
    i = 0
    j = 0

    while i < len(lst1) and j < len(lst2):

        if lst1[i] <= lst2[j]:
            results.append(lst1[i])
            i += 1
        else:
            results.append(lst2[j])
            j += 1

    # append remaining values of lst1 or lst2
    while i < len(lst1):
        results.append(lst1[i])
        i += 1

    while j < len(lst2):
        results.append(lst2[j])
        j += 1

    return results

def merge_sort(lst):

    if len(lst) <= 1:
        return lst

    # split list in two parts until base condition is met
    mid = len(lst) // 2
    left = merge_sort(lst[:mid])
    right = merge_sort(lst[mid:])

    # merge sorted lists
    return merge(left, right)

print(merge_sort([10, 25, 76, 73, 72, 1, 8]))  # [1, 8, 10, 25, 72, 73, 76]


num = int(input())
ba = num
a = list(map(int, input().split(",")))

def trans(a):
    b = []
    for i in range(len(a) - 1):
        b.append(a[i] - a[i+1])
    return b

while num > 0:
    a = trans(a)
    num -= 1

for i in range(len(a)):
    if i < len(a) - 1:
        print(a[i], end=",")
    else:
        print(a[i])


import json
from requests import Session
from requests import exceptions
from requests.auth import HTTPBasicAuth
import os.path as osp

from .utils import DataikuException

from .fm.tenant import FMCloudCredentials, FMCloudTags
from .fm.virtualnetworks import (
    FMVirtualNetwork,
    FMAWSVirtualNetworkCreator,
    FMAzureVirtualNetworkCreator,
    FMGCPVirtualNetworkCreator,
    FMAWSVirtualNetwork,
    FMAzureVirtualNetwork,
    FMGCPVirtualNetwork
)
from .fm.instances import (
    FMInstance,
    FMInstanceEncryptionMode,
    FMAWSInstanceCreator,
    FMAzureInstanceCreator,
    FMGCPInstanceCreator,
    FMAWSInstance,
    FMAzureInstance,
    FMGCPInstance
)
from .fm.instancesettingstemplates import (
    FMInstanceSettingsTemplate,
    FMAWSInstanceSettingsTemplateCreator,
    FMAzureInstanceSettingsTemplateCreator,
    FMGCPInstanceSettingsTemplateCreator
)

import sys

if sys.version_info > (3, 4):
    from enum import Enum
else:

    class Enum(object):
        pass

class FMClient(object):
    def __init__(
        self,
        host,
        api_key_id,
        api_key_secret,
        tenant_id="main",
        extra_headers=None,
    ):
        """
        Base class for the different FM Clients
        Do not create this class, instead use :class:`dataikuapi.FMClientAWS`, :class:`dataikuapi.FMClientAzure` or :class:`dataikuapi.FMClientGCP`
        """
        if self.cloud == None:
            raise NotImplementedError(
                "Do not use FMClient directly, instead use FMClientAWS, FMClientAzure or FMClientGCP"
            )
        self.api_key_id = api_key_id
        self.api_key_secret = api_key_secret
        self.host = host
        self.__tenant_id = tenant_id
        self._session = Session()

        if self.api_key_id is not None and self.api_key_secret is not None:
            self._session.auth = HTTPBasicAuth(self.api_key_id, self.api_key_secret)
        else:
            raise ValueError("API Key ID and API Key secret are required")

        if extra_headers is not None:
            self._session.headers.update(extra_headers)

    ########################################################
    # Tenant
    ########################################################

    def get_cloud_credentials(self):
        """
        Get the cloud credentials

        :return: cloud credentials
        :rtype: :class:`dataikuapi.fm.tenant.FMCloudCredentials`
        """
        creds = self._perform_tenant_json("GET", "/cloud-credentials")
        return FMCloudCredentials(self, creds)

    def get_cloud_tags(self):
        """
        Get the tenant's cloud tags

        :return: tenant's cloud tags
        :rtype: :class:`dataikuapi.fm.tenant.FMCloudTags`
        """
        tags = self._perform_tenant_json("GET", "/cloud-tags")
        return FMCloudTags(self, tags)

    ########################################################
    # VirtualNetwork
    ########################################################

    def _make_virtual_network(self, vn):
        if self.cloud == "AWS":
            return FMAWSVirtualNetwork(self, vn)
        elif self.cloud == "Azure":
            return FMAzureVirtualNetwork(self, vn)
        elif self.cloud == "GCP":
            return FMGCPVirtualNetwork(self, vn)
        else:
            raise Exception("Unknown cloud type %s" % self.cloud)

    def list_virtual_networks(self):
        """
        List all virtual networks

        :return: list of virtual networks
        :rtype: list of :class:`dataikuapi.fm.virtualnetworks.FMVirtualNetwork`
        """
        vns = self._perform_tenant_json("GET", "/virtual-networks")
        return [self._make_virtual_network(x) for x in vns]

    def get_virtual_network(self, virtual_network_id):
        """
        Get a virtual network by its id

        :param str virtual_network_id: the id of the network to retrieve

        :return: the requested virtual network
        :rtype: :class:`dataikuapi.fm.virtualnetworks.FMVirtualNetwork`
        """
        vn = self._perform_tenant_json(
            "GET", "/virtual-networks/%s" % virtual_network_id
        )
        return self._make_virtual_network(vn)

    ########################################################
    # Instance settings template
    ########################################################

    def list_instance_templates(self):
        """
        List all instance settings templates

        :return: list of instance settings template
        :rtype: list of :class:`dataikuapi.fm.tenant.FMInstanceSettingsTemplate`
        """
        templates = self._perform_tenant_json("GET", "/instance-settings-templates")
        return [FMInstanceSettingsTemplate(self, x) for x in templates]

    def get_instance_template(self, template_id):
        """
        Get an instance setting template template by its id

        :param str template_id: the id of the template to retrieve

        :return: the requested instance settings template
        :rtype: :class:`dataikuapi.fm.instancesettingstemplates.FMInstanceSettingsTemplate`
        """
        template = self._perform_tenant_json(
            "GET", "/instance-settings-templates/%s" % template_id
        )
        return FMInstanceSettingsTemplate(self, template)

    ########################################################
    # Instance
    ########################################################

    def _make_instance(self, i):
        if self.cloud == "AWS":
            return FMAWSInstance(self, i)
        elif self.cloud == "Azure":
            return FMAzureInstance(self, i)
        elif self.cloud == "GCP":
            return FMGCPInstance(self, i)
        else:
            raise Exception("Unknown cloud type %s" % self.cloud)

    def list_instances(self):
        """
        List all DSS instances

        :return: list of instances
        :rtype: list of :class:`dataikuapi.fm.instances.FMInstance`
        """
        instances = self._perform_tenant_json("GET", "/instances")
        return [self._make_instance(x) for x in instances]

    def get_instance(self, instance_id):
        """
        Get a DSS instance by its id

        :param str instance_id: the id of the instance to retrieve

        :return: the requested instance if any
        :rtype: :class:`dataikuapi.fm.instances.FMInstance`
        """
        instance = self._perform_tenant_json("GET", "/instances/%s" % instance_id)
        return self._make_instance(instance)

    def list_instance_images(self):
        """
        List all available images to create new instances

        :return: list of images, as a pair of id and label
        """
        return self._perform_tenant_json("GET", "/images")

    ########################################################
    # Internal Request handling
    ########################################################

    def _perform_http(
        self,
        method,
        path,
        params=None,
        body=None,
        stream=False,
        files=None,
        raw_body=None,
    ):
        if body is not None:
            body = json.dumps(body)
        if raw_body is not None:
            body = raw_body
        try:
            http_res = self._session.request(
                method,
                "%s/api/public%s" % (self.host, path),
                params=params,
                data=body,
                files=files,
                stream=stream,
            )
            http_res.raise_for_status()
            return http_res
        except exceptions.HTTPError:
            try:
                ex = http_res.json()
            except ValueError:
                ex = {"message": http_res.text}
            raise DataikuException(
                "%s: %s"
                % (
                    ex.get("errorType", "Unknown error"),
                    ex.get("message", "No message"),
                )
            )

    def _perform_empty(
        self, method, path, params=None, body=None, files=None, raw_body=None
    ):
        self._perform_http(
            method,
            path,
            params=params,
            body=body,
            files=files,
            stream=False,
            raw_body=raw_body,
        )

    def _perform_json(
        self, method, path, params=None, body=None, files=None, raw_body=None
    ):
        return self._perform_http(
            method,
            path,
            params=params,
            body=body,
            files=files,
            stream=False,
            raw_body=raw_body,
        ).json()

    def _perform_tenant_json(
        self, method, path, params=None, body=None, files=None, raw_body=None
    ):
        return self._perform_json(
            method,
            "/tenants/%s%s" % (self.__tenant_id, path),
            params=params,
            body=body,
            files=files,
            raw_body=raw_body,
        )

    def _perform_tenant_empty(
        self, method, path, params=None, body=None, files=None, raw_body=None
    ):
        self._perform_empty(
            method,
            "/tenants/%s%s" % (self.__tenant_id, path),
            params=params,
            body=body,
            files=files,
            raw_body=raw_body,
        )

class FMClientAWS(FMClient):
    def __init__(
        self,
        host,
        api_key_id,
        api_key_secret,
        tenant_id="main",
        extra_headers=None,
    ):
        """
        AWS Only - Instantiate a new FM API client on the given host with the given API key.

        The API key will define which operations are allowed for the client.

        :param str host: Full url of the FM

        """
        self.cloud = "AWS"
        super(FMClientAWS, self).__init__(
            host, api_key_id, api_key_secret, tenant_id, extra_headers
        )

    def new_virtual_network_creator(self, label):
        """
        Instantiate a new virtual network creator

        :param str label: The label of the network
        :rtype: :class:`dataikuapi.fm.virtualnetworks.FMAWSVirtualNetworkCreator`
        """
        return FMAWSVirtualNetworkCreator(self, label)

    def new_instance_template_creator(self, label):
        """
        Instantiate a new instance template creator

        :param str label: The label of the instance
        :rtype: :class:`dataikuapi.fm.instancesettingstemplates.FMAWSInstanceSettingsTemplateCreator`
        """
        return FMAWSInstanceSettingsTemplateCreator(self, label)

    def new_instance_creator(
        self, label, instance_settings_template_id, virtual_network_id, image_id
    ):
        """
        Instantiate a new instance creator

        :param str label: The label of the instance
        :param str instance_settings_template: The instance settings template id this instance should be based on
        :param str virtual_network: The virtual network where the instance should be spawned
        :param str image_id: The ID of the DSS runtime image (ex: dss-9.0.3-default)
        :rtype: :class:`dataikuapi.fm.instances.FMAWSInstanceCreator`
        """
        return FMAWSInstanceCreator(
            self, label, instance_settings_template_id, virtual_network_id, image_id
        )

class FMClientAzure(FMClient):
    def __init__(
        self,
        host,
        api_key_id,
        api_key_secret,
        tenant_id="main",
        extra_headers=None,
    ):
        """
        Azure Only - Instantiate a new FM API client on the given host with the given API key.

        The API key will define which operations are allowed for the client.

        :param str host: Full url of the FM
        """
        self.cloud = "Azure"
        super(FMClientAzure, self).__init__(
            host, api_key_id, api_key_secret, tenant_id, extra_headers
        )

    def new_virtual_network_creator(self, label):
        """
        Instantiate a new virtual network creator

        :param str label: The label of the network
        :rtype: :class:`dataikuapi.fm.virtualnetworks.FMAzureVirtualNetworkCreator`
        """
        return FMAzureVirtualNetworkCreator(self, label)

    def new_instance_template_creator(self, label):
        """
        Instantiate a new instance template creator

        :param str label: The label of the instance
        :rtype: :class:`dataikuapi.fm.instancesettingstemplates.FMAzureInstanceSettingsTemplateCreator`
        """
        return FMAzureInstanceSettingsTemplateCreator(self, label)

    def new_instance_creator(
        self, label, instance_settings_template_id, virtual_network_id, image_id
    ):
        """
        Instantiate a new instance creator

        :param str label: The label of the instance
        :param str instance_settings_template: The instance settings template id this instance should be based on
        :param str virtual_network: The virtual network where the instance should be spawned
        :param str image_id: The ID of the DSS runtime image (ex: dss-9.0.3-default)
        :rtype: :class:`dataikuapi.fm.instances.FMAzureInstanceCreator`
        """
        return FMAzureInstanceCreator(
            self, label, instance_settings_template_id, virtual_network_id, image_id
        )

class FMClientGCP(FMClient):
    def __init__(
        self,
        host,
        api_key_id,
        api_key_secret,
        tenant_id="main",
        extra_headers=None,
    ):
        """
        GCP Only - Instantiate a new FM API client on the given host with the given API key.

        The API key will define which operations are allowed for the client.

        :param str host: Full url of the FM
        """
        self.cloud = "GCP"
        super(FMClientGCP, self).__init__(
            host, api_key_id, api_key_secret, tenant_id, extra_headers
        )

    def new_virtual_network_creator(self, label):
        """
        Instantiate a new virtual network creator

        :param str label: The label of the network
        :rtype: :class:`dataikuapi.fm.virtualnetworks.FMGCPVirtualNetworkCreator`
        """
        return FMGCPVirtualNetworkCreator(self, label)

    def new_instance_template_creator(self, label):
        """
        Instantiate a new instance template creator

        :param str label: The label of the instance
        :rtype: :class:`dataikuapi.fm.instancesettingstemplates.FMGCPInstanceSettingsTemplateCreator`
        """
        return FMGCPInstanceSettingsTemplateCreator(self, label)

    def new_instance_creator(
        self, label, instance_settings_template_id, virtual_network_id, image_id
    ):
        """
        Instantiate a new instance creator

        :param str label: The label of the instance
        :param str instance_settings_template: The instance settings template id this instance should be based on
        :param str virtual_network: The virtual network where the instance should be spawned
        :param str image_id: The ID of the DSS runtime image (ex: dss-9.0.3-default)
        :rtype: :class:`dataikuapi.fm.instances.FMGCPInstanceCreator`
        """
        return FMGCPInstanceCreator(
            self, label, instance_settings_template_id, virtual_network_id, image_id
        )