"""Unittests for the collect_stata.read_stata module"""
import pathlib
import unittest
from typing import Dict, List
from unittest.mock import patch

import numpy
import pandas
from deepdiff import DeepDiff

from collect_stata.read_stata import StataDataExtractor
from collect_stata.types import Variable

class MockedStataReader:
    """Implement StataReader functions needed for tests; provide test data."""

    varlist: List[str] = ["variable_name"]
    dtypelist: List[object] = [numpy.int8]

    @staticmethod
    def value_labels() -> Dict[str, Dict[int, str]]:
        """Control what value labels are ingested during a test."""
        return {"variable_name": {-1: "[-1] invalid", 1: "[1] valid"}}

    @staticmethod
    def variable_labels() -> Dict[str, str]:
        """Control what variable labels are ingested during a test."""
        return {"variable_name": "variable_label"}

    lbllist: List[str] = ["variable_name"]

    @staticmethod
    def expected_metadata(dataset_name: str) -> List[Variable]:
        """Give the full metadata set which should be expected as test result."""
        return [
            {
                "name": "variable_name",
                "dataset": dataset_name,
                "label": "variable_label",
                "scale": "cat",
                "categories": {
                    "values": [-1, 1],
                    "labels": ["[-1] invalid", "[1] valid"],
                },
            }
        ]

class TestMetadataFunctions(unittest.TestCase):
    """Test functionality related to Metadata extraction."""

    def test_get_variable_metadata(self) -> None:
        """ Do we get desired metadata from the method?

        get_variable_metadata should return a list with a dictionary for every
        variable accessible through the stata reader.

        The expected keys should be as follow:
            * name: The name of the variable.
            * label: The label of the variable.
            * categories: A dictionary containing:

                + values: All values for the variable,
                          that have labels assigned to them.
                + labels: All labels for the variable values.
                          A label needs to be at the same index position as
                          its corresponding value inside the values list.
        """
        dataset_name = "test"
        dataset_path = pathlib.Path(dataset_name).with_suffix(".dta")
        dataset_path = pathlib.Path("/tmp").joinpath(dataset_path)
        with patch.object(pandas, attribute="read_stata", return_value=MockedStataReader):
            data_extractor = StataDataExtractor(dataset_path)
            result = data_extractor.get_variable_metadata()

        # We deepdiff both structures to ensure, that they contain the same content
        # even in the nested parts of the structure.
        # The diff should be empty, giving a {} that evaluates to False.
        # Otherwise it contains information about the difference which should be
        # usefull in the test output.
        diff = DeepDiff(MockedStataReader.expected_metadata(dataset_name), result)
        self.assertTrue(expr=(not diff), msg=str(diff))


import random
import openai
import os
from dotenv import load_dotenv
load_dotenv()
# Set up OpenAI API key
openai.api_key = os.environ["OPENAI_API_KEY"]

major_arcana = [
    "The Fool",
    "The Magician",
    "The High Priestess",
    "The Empress",
    "The Emperor",
    "The Hierophant",
    "The Lovers",
    "The Chariot",
    "Strength",
    "The Hermit",
    "Wheel of Fortune",
    "Justice",
    "The Hanged Man",
    "Death",
    "Temperance",
    "The Devil",
    "The Tower",
    "The Star",
    "The Moon",
    "The Sun",
    "Judgement",
    "The World"
]

def generate_tarot_reading():
    cards = random.sample(major_arcana, 3)
    reversed_cards = [random.choice([True, False]) for _ in range(3)]

    reading = []
    for i in range(3):
        card = cards[i]
        reversed = reversed_cards[i]
        reading.append({"card": card, "reversed": reversed})

    return reading

def generate_answer(question, reading):
    # Combine question and card reading into prompt
    system_prompt = "You're a psychic who expertise in tarot reading, now the user will ask for the reading and you will reply in a calm, charming and fascinating way and explain as detailed as possible.\n Avoid answering any questions unrelated to tarot reading but do provide the reading if possible"
    prompt = f"Please, I want to know: '{question}'\n\nThe cards drawn were:"
    for card in reading:
        card_name = card["card"]
        reversed = "reversed" if card["reversed"] else "upright"
        prompt += f"\n- {card_name} ({reversed})"

    messages = [{"role": "system", "content": system_prompt},{"role": "user", "content": prompt}]
    # Use OpenAI's GPT-3 to generate an answer
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages,
    )

    return response.choices[0].message.content


import p3
import collections
# listt = []
# for i in range(1, 11):
#     listt.append(i)

def largest(a, b):
    list1 = p3.primefactors(a)
    list2 = p3.primefactors(b)
    a = collections.Counter(list1)
    b = collections.Counter(list2)
    a_keys = list(a.keys())
    a_val = list(a.values())
    b_keys = list(b.keys())
    b_val = list(b.values())
    keys = a_keys + b_keys
    keys = set(keys)
    nww = 1
    for k in keys:
        if k in a_keys:
            ia = a_keys.index(k)
            av = a_val[ia]
        else:
            av = 1
        if k in b_keys:
            ib = b_keys.index(k)
            bv = b_val[ib]
        else:
            bv = 1

        number = max(av, bv)
        nww *= pow(k,number)
    return nww
n = 1
for i in range(2, 21):
    n = largest(n, i)

print(n)


import jsonpickle
import numpy as np
from aioxmpp import PresenceShow
from spade import agent
from spade.behaviour import OneShotBehaviour, CyclicBehaviour
from spade.template import Template

import config
import tools
from config import domain
from data_agent import DataAgent
from database.models import Model
from decision import decision
from job_manager import JobManager
from protocol import give_negative_decision_template, request_model_from_db_template, give_model_template, \
    save_model_to_db_template, give_data_template, reply_historical_data, give_decision_not_available_template
from protocol import request_decision_template, give_positive_decision_template, request_cost_computation
from strategy_worker_agent import StrategyAgentWorker
from tools import make_logger, message_from_template

class StrategyAgent(agent.Agent):
    def __init__(self, jid, password, currency_symbol, verify_security=False):
        super().__init__(jid, password, verify_security)
        self.currency_symbol = currency_symbol
        self.log = make_logger(self.jid)
        self.training_behaviour = None
        self.has_strategy = False
        self.model = None
        self.decision_records = None

    async def setup(self):
        self.log.debug('Starting!')
        self.training_behaviour = self.TrainBehaviour()
        self.add_behaviour(self.PrepareModelBehaviour(), give_model_template)
        self.add_behaviour(self.PrepareDataBehaviour(), reply_historical_data)

    class PrepareModelBehaviour(OneShotBehaviour):

        async def run(self):
            message = message_from_template(request_model_from_db_template,
                                            body=self.agent.currency_symbol,
                                            to='data_agent@127.0.0.1')
            await self.send(message)
            reply = await self.receive(10)
            model = jsonpickle.loads(reply.body)
            if not model:
                self.agent.log.debug("No model found in db")
                self.agent.add_behaviour(self.agent.training_behaviour)
            else:
                self.agent.log.debug("Retrieved model from db")
                self.agent.model = model
                self.agent.has_strategy = True

    class TrainBehaviour(OneShotBehaviour):
        def __init__(self, *args, **kwargs):
            super(StrategyAgent.TrainBehaviour, self).__init__()
            self.workers = []
            self.job_manager = None

        async def on_start(self):
            self.workers = [f'strategy_agent_worker_{self.agent.currency_symbol}_1@{domain}' for _ in range(2)]
            self.job_manager = JobManager(workers=self.workers)
            for worker_jid in self.workers:
                await StrategyAgentWorker(worker_jid, worker_jid, self.agent.currency_symbol).start(auto_register=True)

        async def run(self):
            self.agent.log.debug('Starting training!')

            population_size = 6
            mutation_chance = 0.05
            niterations = 20
            random_genotype = lambda: np.array([np.random.randint(10, 30), np.random.randint(100, 300)])
            repair = lambda genes: np.where(genes < 1, 1, genes)
            _mutate = lambda genes: genes + np.random.randint(-1, 2, size=(2,))
            mutate = lambda genes: repair(_mutate(genes))

            population = [random_genotype() for _ in range(population_size)]
            for i in range(niterations):
                self.agent.log.debug(f'Starting iteration {i}')
                population.extend([
                    mutate(genotype) if np.random.random() > mutation_chance
                    else genotype
                    for genotype in population
                ])
                costs = await self.compute_costs(population)
                population = [genotype for (genotype, cost) in
                              sorted(zip(population, costs), key=lambda x: x[1], reverse=True)]
                population = population[:population_size]

            best = population[0]
            model = Model(currency=self.agent.currency_symbol, short_mean=best[0], long_mean=best[1])
            self.agent.model = model

            message = message_from_template(save_model_to_db_template,
                                            to="data_agent@127.0.0.1",
                                            body=jsonpickle.dumps(model))
            await self.send(message)

            self.agent.has_strategy = True
            self.agent.log.debug('Training done!')

        async def compute_costs(self, population):
            jobs = await self.job_manager.create_jobs(data=population)
            for job in jobs:
                uuid = tools.make_uuid()
                template = Template(thread=uuid)
                self.agent.add_behaviour(StrategyAgent.WorkerConversationBehaviour(job, uuid), template)

            return await self.job_manager.jobs_finished()

    class WorkerConversationBehaviour(OneShotBehaviour):
        ATTEMPTS = 2

        def __init__(self, job, uuid, *args, **kwargs):
            super(StrategyAgent.WorkerConversationBehaviour, self).__init__()
            self.job = job
            self.conversation_id = uuid

        async def on_start(self):
            pass

        async def run(self):
            while True:
                for attempt in range(self.ATTEMPTS):
                    msg = message_from_template(request_cost_computation,
                                                body=jsonpickle.dumps(self.job.data),
                                                to=self.job.worker_id,
                                                thread=self.conversation_id)
                    await self.send(msg)
                    reply = await self.receive(timeout=config.timeout)
                    if reply:
                        self.job.result = jsonpickle.loads(reply.body)
                        self.agent.log.debug('Reply from worker {} arrived: {}'.format(reply.sender, self.job.result))
                        await self.agent.training_behaviour.job_manager.job_done(self.job)
                        return
                else:
                    self.agent.log.error('Reply from worker {} not arrived!'.format(self.job.worker_id))
                    self.job = await self.agent.training_behaviour.job_manager.job_failed(self.job)

    class GiveDecisionBehaviour(CyclicBehaviour):
        async def on_start(self):
            self.presence.set_available(show=PresenceShow.CHAT)

        async def run(self):
            msg = await self.receive(timeout=config.timeout)
            if msg is not None:
                self.agent.log.debug('I got request_decision_template message!')
                if self.agent.has_strategy:
                    # jest wytrenowany model, odsyłamy decyzję
                    if decision(self.agent.model.short_mean, self.agent.model.long_mean, self.agent.decision_records):
                        reply = message_from_template(give_positive_decision_template, to=str(msg.sender))
                        self.agent.log.debug('I sent give_positive_decision_template message!')
                    else:
                        reply = message_from_template(give_negative_decision_template, to=str(msg.sender))
                        self.agent.log.debug('I sent give_negative_decision_template message!')
                    await self.send(reply)
                else:
                    # trwa trening, nie można dać decyzji
                    reply = message_from_template(give_decision_not_available_template, to=str(msg.sender))
                    await self.send(reply)
                    self.agent.log.debug('I sent give_decision_not_available_template message!')

    class PrepareDataBehaviour(OneShotBehaviour):
        async def run(self):
            msg = tools.create_message(to="data_agent@127.0.0.1",
                                       performative="inform", ontology="history",
                                       body=jsonpickle.encode(
                                           value=(self.agent.currency_symbol, 300)))  # jeśli dane z ostatnich dni

            await self.send(msg)
            reply = await self.receive(10)
            records = jsonpickle.loads(reply.body)
            # print(records)
            self.agent.decision_records = list(map(lambda x: x.close, records))
            self.agent.add_behaviour(StrategyAgent.GiveDecisionBehaviour(), request_decision_template)
            # print(self.agent.decision_records)

if __name__ == '__main__':
    data_agent = DataAgent("data_agent@127.0.0.1", "data_agent")
    data_agent.start(auto_register=False)
    agent = StrategyAgent(f'strategy_agent_worker@{domain}', 'strategy_agent_worker1', "USDT")
    agent.start(auto_register=True)


"""
    This module contains the logger class.
"""
import logging

class Logger:
    def __int__(self):
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.INFO)

        self.formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s')

        self.file_handler = logging.FileHandler('logs.log')
        self.file_handler.setFormatter(self.formatter)

        self.logger.addHandler(self.file_handler)

    def log(self, level, message):
        self.logger.log(level, message)


class Node():
    def __init__(self, value):
        self.prev = None
        self.val = value
        self.next = None
        self.count = 0

class dublyLinkedList():
    def __init__(self):
        self.start = None
        self.end = None
        self.count = 0

    def add(self, value):
        node = Node(value)
        if self.end is None:
            self.start = node
            self.end = node
            self.count += 1
        else:
            self.end.next = node
            node.prev = self.end
            self.end = node
            self.count += 1

    def add_first(self,value):
        node = Node(value)

        temp = self.start
        self.start = node
        self.start.next = temp
        self.count += 1

    def add_last(self,value):
        node = Node(value)

        temp = self.end
        self.end.next = node
        self.end.prev = temp
        self.count += 1

    def replaceByPosition(self,pos1,pos2):
        pos = 0
        posc = 0
        temp1 = None
        temp2 = None
        current = self.start
        while current is not None:
            if pos is pos1:
                temp1 = current
                temp1prev = temp1.prev
                temp1next = temp1.next
                print(temp1prev,"-",temp1.val,"-",temp1next.val)

            if pos is pos2:
                temp2 = current
                temp2prev = temp2.prev
                temp2next = temp2.next
                print(temp2prev.val, "-", temp2.val, "-", temp2next.val)

            pos += 1
            current = current.next

        current2 = self.start
        while current2 is not None:
            if posc is pos1:
                current2.next = temp2next
                current2.val = temp2.val
                current2.prev = temp2prev

            if posc is pos2:
                current2.next = temp1next
                current2.val = temp1.val
                current2.prev = temp1prev

            posc += 1
            current2 = current2.next

    def __str__(self):
        list = []
        node = self.start
        while node is not None:
            list.append(node.val)
            node = node.next
        return f"[{', '.join(str(val) for val in list)}]"

mylist = dublyLinkedList()
mylist.add(1)
mylist.add(3)
mylist.add(5)
mylist.add_first(6)
print(mylist)
mylist.add_last(7)
print(mylist)
print("total element : ", mylist.count)

# pos1, pos2 = list(map(int, input("Enter 2 position that you want to replace : ").split()))
pos1 =1
pos2 =3
print("pos1 ",pos1)
print("pos2 ",pos2)

mylist.replaceByPosition(pos1,pos2)
print(mylist)


__author__ = 'mla'
from model.group import Group
import random
import string

def random_string(prefix, maxlen):
   symbols = string.ascii_letters + string.digits + " "*10 # string.punctuation +
   return prefix + "".join([random.choice(symbols) for i in range(random.randrange(maxlen))]).strip()

#def random_string(maxlen):
#    symbols = string.ascii_letters + string.digits + " " * 10
#    chars = "".join([random.choice(symbols) for i in range(random.randrange(5,maxlen))]).strip()
#    return chars

def test_modify_first_group_name(app, db):
    if len(db.get_contact_list())  == 0:
        app.group.create(Group(name="test"))
    old_groups = db.get_contact_list()
    group = Group(name="New group")
    group.id = old_groups[0].id
    app.group.modify2_first_group(group)
    new_groups = app.group.get_group_list()
    assert len(old_groups) == len(new_groups)
    old_groups[0] = group
    assert sorted(old_groups, key=Group.id_or_max) == sorted(new_groups, key=Group.id_or_max)
    #app.session.logout()

def test_modify_some_group_name(app, db, check_ui):
    if len(db.get_group_list()) == 0:
        app.group.create(Group(name=random_string("name", 10), header=random_string("header", 20), footer=random_string("footer", 20)))
    old_groups = db.get_group_list()
    chosen_group = random.choice(old_groups)
    app.group.modify2_group_by_id(chosen_group.id, Group(name=random_string("name", 10), header=random_string("header", 20), footer=random_string("footer", 20)))
    new_groups = db.get_group_list()
    assert len(old_groups) == len(new_groups)
    #app.session.logout()
    if check_ui:
        assert len(old_groups) == len(app.group.get_group_list())

#def test_modify_group_header(app):
#    if app.group.count() == 0:
#        app.group.create(Group(name="test"))
#    old_groups = app.group.get_group_list()
#    app.group.modify2_first_group(Group(header="New header"))
#    new_groups = app.group.get_group_list()
#    assert len(old_groups) == len(new_groups)
    #app.session.logout()


import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
from torch.utils.data.sampler import SubsetRandomSampler
import sys
sys.path.append('../')
import common.CreditDataSet as CD

epoch = 50

#torch.set_default_tensor_type('torch.DoubleTensor')

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()

        self.fc1 = nn.Linear(24, 200)
        self.dropout = nn.Dropout(0.5)
        self.fc2 = nn.Linear(200, 200)
        self.fc3 = nn.Linear(200, 1)

    def forward(self,x):
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = F.relu(self.fc2(x))
        x = torch.sigmoid(self.fc3(x))
        return x

custdata=CD.CreditDataSet("../data/train.csv")
datalen = len(custdata)
split_pc = 0.2
split_index = int( split_pc * datalen)

indices = list(range(datalen))
np.random.shuffle(indices)

train_indices, test_indices = indices[split_index:], indices[:split_index]
train_sampler = SubsetRandomSampler(train_indices)
test_sampler = SubsetRandomSampler(test_indices)
trainloader = torch.utils.data.DataLoader(custdata, batch_size=4, shuffle=False, sampler=train_sampler )
testset = torch.utils.data.DataLoader(custdata, batch_size=4, shuffle=False, sampler=test_sampler)

net = Net()
criterion = nn.BCELoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)

running_loss = 0.0

for loopidx in range(epoch):
    for i , data in enumerate(trainloader, 0):
        input,label = data

        optimizer.zero_grad()

        output = net(input)
        #print ("label", label)
        #print ("output", output)
        loss = criterion(output, label)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 20 == 19:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (loopidx + 1, i + 1, running_loss / 20))
            running_loss = 0.0

net.train(False)

correct = 0
total = 0
with torch.no_grad():
    for data in testset:
        input,label = data
        output = net(input)

        diff = abs(label - output)
        total += len(diff)
        result = diff < 0.5
        correct += torch.sum(result)

print ("Correct Prediction: ", correct.item(), "\nTotal Samples", total)

x = custdata.getrawinputs()
x=torch.from_numpy(x)

#Saving in both the formats.
torch_output = torch.onnx._export(net, x, "../models/cust_credit.onnx", export_params=True)
torch.save(net.state_dict(), "../models/model.pt")


import csv
import time
import base64
import requests
import numpy as np
import pandas as pd

from typing import *
from io import BytesIO, StringIO
from PIL import Image

Response = Tuple[int, Type[requests.models.Response]]
Method = Literal['GET', 'POST', 'PUT']
Json = Dict
Date = str

class BolAPI:
    """ Super class for bol.com API

    Attributes
    ----------
    client_id : str
        ID from client credentials
    client_secret : str
        Secret from client credentials
    base_url : str
        Initial part of the API URL for all requests
    headers : dict
        API Headers containing:
            - Authentication credentials (Authorization)
            - Expected content type received in response (Accept)
            - Media type of current request body (Content-Type)
    """
    def __init__(self, client_id: str, client_secret: str) -> None:
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = "https://api.bol.com"
        self.valid = None

    def get_access_token(self) -> None:
        """ Obtain access token

        Acquire a token from the authentication service using
        client credentials and set the token as an authorization header
        """
        credentials = base64.b64encode(bytes(f"{self.client_id}:{self.client_secret}", "utf-8")).decode("utf-8")
        credentials_header = {
            'Accept' : 'application/json',
            'Authorization': f'Basic {credentials}'
        }

        request = requests.post('https://login.bol.com/token?grant_type=client_credentials', headers=credentials_header)
        status = request.status_code
        response = request.json()

        if status == 200:
            self.valid = True
            access_token = response['access_token']
            bearer_str = f'Bearer {access_token}'
            self.headers.update({'Authorization' : bearer_str})
            return

        else:
            print(f'ERROR: failed to retrieve access token \n {request}')
            self.valid = False
            return

    def request(self, method: Method, url: str, data: Optional[dict] = None, headers: Optional[dict] = None) -> Response:
        """ Send a request to api.bol.com

        Configures the request and returns its status code with the response body.
        In case the access token has expired, new one will be requested.

        Parameters
        ----------
        method:  str
            The HTTP Method for our request ['GET', 'POST', 'PUT']
        url : str
            Endpoint location, appends to self.base_url
        data : dict
            Optional; Query Parameters (default is None)
        headers : dict
            Optional; Header Parameters (default is self.headers)

        Returns
        -------
        status_code : int
            Status code of request
        request : Any
            Request response
        """
        # Update headers if necessary
        if headers:
            headers_ = self.headers.copy()
            headers_.update(headers)
            headers = headers_
        else:
            headers = self.headers

        # Set the request url
        request_url = f'{self.base_url}/{url}'

        # Make request
        if method == 'GET':
            request = requests.get(request_url, params=data, headers=headers)
        elif method == 'POST':
            request = requests.post(request_url, headers=headers, json=data)
        elif method == 'PUT':
            request = requests.put(request_url, params=data, headers=headers)

        # Check if request has been denied due to token expiration
        status_code = request.status_code
        if status_code == 401:
            print('Token expired, acquiring new one...')
            self.get_access_token()
            return self.request(method, url, data, headers)

        if status_code == 429:
            print('Too many requests, retrying after 1550 seconds')
            time.sleep(1550)
            return  self.request(method, url, data, headers)
        else:
            return status_code, request

    def get(self, url: str, data: Optional[dict] = None, headers: Optional[dict] = None) -> Response:
        status, response = self.request('GET', url, data, headers)
        return status, response

    def post(self, url: str, data: Optional[dict] = None, headers: Optional[dict] = None) -> Response:
        status, response = self.request('POST', url, data, headers)
        return status, response

    def put(self, url: str, data: Optional[dict] = None, headers: Optional[dict] = None) -> Response:
        status, response = self.request('PUT', url, data, headers)
        return status, response

class BolRetailerAPI(BolAPI):
    """ Initializes API connection with bol Retailer API
    """

    def __init__(self, client_id: str, client_secret: str) -> None:
        super().__init__(client_id, client_secret)
        self.headers = {
            'Accept' : 'application/vnd.retailer.v9+json',
            'Content-Type' : 'application/vnd.retailer.v9+json'
        }
        self.get_access_token()

    def request_invoice_specification(self, invoice_id: str) -> pd.DataFrame:
        """ Retrieve invoice specification by invoice ID

        Parameters
        ----------
        invoice_id : str
            ID of the specified invoice

        Returns
        -------
        json
            Json-format dict containing all details in invoice specification
        """
        headers = {
            'Accept' : 'application/vnd.retailer.v10+openxmlformats-officedocument.spreadsheetml.sheet',
            'Content-Type' : 'None'
        }
        endpoint_url = f'retailer/invoices/{invoice_id}/specification'
        status, response = self.get(endpoint_url, headers=headers)

        if status == 200:
            df = pd.read_excel(response.content)
            df.rename(columns=df.iloc[6], inplace=True) # Set row 6 as column headers
            df.drop(np.arange(0,7), inplace=True) # Remove first 7 rows that aren't part of table
            df.reset_index(drop=True, inplace=True) # Reset the indexing
            return df

        else: print(f'ERROR: failed to retrieve invoice specification \n{response.text}')

    def request_all_offers(self) -> csv:
        """ Retrieve information on all offers

        Prepares a offer export CSV file, checks when
        the export is ready and retrieves the file.

        Data contains following columns:
            - offerID
            - ean
            - conditionName
            - conditionCategory
            - conditionComment
            - bundlePricesPrice
            - fulfilmentDeliveryCode
            - stockAmount
            - onHoldByRetailer
            - fulfilmentType
            - mutationDateTime
            - referenceCode
            - correctedStock

        Returns
        -------
        csv
            Decoded csv data containing details of all offers
        """
        # Prepare offer export
        data = {"format": "CSV"}
        endpoint_url = 'retailer/offers/export'

        status, response = self.post(endpoint_url, data=data)

        if status == 202:
            # Check status of offer export
            process_id = response.json()['processStatusId']
            endpoint_url = f'shared/process-status/{process_id}'
            _, process = self.get(endpoint_url)

            while process.json()['status'] == 'PENDING':
                time.sleep(60) # Wait 60 seconds
                _, process = self.get(endpoint_url)

            if process.json()['status'] == 'SUCCESS':
                report_id = process.json()['entityId']
                endpoint_url = f'retailer/offers/export/{report_id}'
                headers = {
                    'Accept' : 'application/vnd.retailer.v9+csv',
                    'Content-Type' : 'application/x-www-form-urlencoded'
                }
                status, response = self.get(endpoint_url, headers=headers)

                if status == 200:
                    return StringIO(response.content.decode('utf-8'))

                else: print(f'ERROR: failed to retrieve offer export \n{response.text}')
            else: print(f'ERROR: failed to process offer export \n{process}')
        else:
            print(f'ERROR: failed to request offer export \n{response.text}')
            return response

    def request_offer(self, offer_id: str) -> Json:
        """ Retrieve an offer by its ID

        Obtains information of listed offer,
        useful for retrieving product title

        Parameters
        ----------
        offer_id : str
            The ID of the offer

        Returns
        -------
        dict
            Json-formatted dictionary containing offer details
        """

        endpoint_url = f'retailer/offers/{offer_id}'
        status, response = self.get(endpoint_url)
        if status == 200:
            return response.json()
        else:
            print(f'ERROR: failed to retrieve offer \n{response.text}')

    def request_offer_forecast(self, offer_id: str, weeks: int) -> Tuple[float, float]:
        """ Retrieve sales forecast of an offer

        Get estimated the sales expectations on the total bol.com platform
        for the requested number of weeks ahead.

        In case product is sold less than 2 times in past 28 days, a range
        will be shown. Otherwise minimum==maximum.

        Parameters
        ----------
        offer_id : str
            The ID of the offer
        weeks : int
            The requested no. weeks ahead

        Returns
        -------
        minimum : float
            The minimum no. expected sales
        maximum : float
            The maximum no. expected sales
        """

        data = {
            'offer-id': offer_id,
            'weeks-ahead': weeks
        }
        endpoint_url = 'retailer/insights/sales-forecast'

        status, response = self.get(endpoint_url, data=data)

        if status == 200:
            minimum = response.json()['total']['minimum']
            maximum = response.json()["total"]["maximum"]

            return minimum, maximum

        else: print(f'ERROR: failed to retrieve offer sales forecast \n{response.text}')

    def request_offer_insights(self, offer_id: str,
                           name: Literal['PRODUCT_VISITS', 'BUY_BOX_PERCENTAGE'],
                           period: Literal['DAY', 'WEEK', 'MONTH'],
                           no_periods: int,
                           country: Optional[Literal['NL', 'BE']] = 'NL') -> Any:
        """ Retrieve offer insights from past

        Get the no. product visits or buy-box percentage of an offer
        within a certain period. Format to two lists for pd.DataTable usage.

        Parameters
        ----------
        offer_id : str
            The ID of the offer
        name : str
            The name of the requested offer insight ['PRODUCT_VISITS', 'BUY_BOX_PERCENTAGE']
        period : str
            The time unit in which the offer insights are grouped ['DAY', 'WEEK', 'MONTH']
        no_periods : int
            The no. periods for which the offer insights are requested back in time.
            Max values are 730, 104 and 24 for DAY, WEEK and MONTH respectively
        country : str
            The country code of requested offer insight ['NL', 'BE']

        Returns
        -------
        dates : list
            List of strings, contains the dates
        values : list
            List of floats, contains measured values
        """

        data = {
            'offer-id' : offer_id,
            'period' : period,
            'number-of-periods' : no_periods,
            'name' : name
        }
        endpoint_url = 'retailer/insights/offer'

        status, response = self.get(endpoint_url, data=data)

        if status == 200:
            response = response.json()

            dates = [] # The dates corresponding to measured value
            values = [] # Measured values per date

            for i in response['offerInsights'][0]['periods']:
                date = i['period']
                countries = i['countries']

                if period == 'DAY':
                    date_str = f"{date['day']}-{date['month']}-{date['year']}"
                elif period == 'MONTH':
                    date_str = f"{date['month']}-{date['year']}"
                elif period == 'YEAR':
                    date_str = f"{date['year']}"

                dates.append(date_str)

                for c in countries:
                    if c['countryCode'] == country:
                        values.append(c['value'])

            if no_periods == 1:
                return values[0]
            else:
                if name == 'PRODUCT_VISITS':
                    return {'Date': dates, 'Visits': values}
                else:
                    return {'Date': dates, 'Buy-Box %': values}

        else: print(f'ERROR: failed to retrieve offer insights \n{response.text}')

    def request_product_image(self, ean: str) -> Image:
        """ Retrieve primary image of product by EAN

        Obtain image url of the primary product image,
        request the image and save into variable

        Parameters
        ----------
        ean : str
            EAN of product

        Returns
        -------
        img : PIL.Image
            Image of product
        """
        endpoint_url = f'retailer/products/{ean}/assets?usage=PRIMARY'
        status, response = self.get(endpoint_url)

        if status == 200:
            img_url = response.json()['assets'][0]['variants'][0]['url']
            img = Image.open(requests.get(img_url, stream=True).raw)

            return img

        else: print(f'ERROR: failed to retrieve product\'s primary image \n{response.text}')

    def request_product_ratings(self, ean: str) -> Dict[int, int]:
        """ Retrieve product ratings by EAN

        Obtain the count of each rating for given product

        Parameters
        ----------
        ean : str
            EAN of product

        Returns
        -------
        dict
            Dictionary containing the ratings and corresponding counts
        """

        dict_data = {
            'Rating' : [],
            'Count' : []
        }

        endpoint_url = f'retailer/products/{ean}/raings'
        status, response = self.get(endpoint_url)

        if status == 200:
            response = response.json()

            for i in response['ratings']:
                dict_data['Rating'].append(i['rating'])
                dict_data['Count'].append(i['count'])

        return dict_data

class BolAdvertisingAPI(BolAPI):
    """ Initializes API connection with bol Advertising API v10

    Methods
    -------
    request_campaigns_report(start_date, end_date)
        Obtain performance results of all campaign for requested period
    """

    def __init__(self, client_id: str, client_secret: str):
        super().__init__(client_id, client_secret)
        self.headers = {
            'Accept' : 'application/vnd.advertiser.v10+json',
            'Content-Type' : 'application/vnd.advertiser.v10+json'
        }
        self.get_access_token()

    def request_campaigns_report(self, start_date: str, end_date: str):
        """ Request and retrieve campaign performance report for requested period

        The specified date range should be seven days apart.
        start_date and end_date must be within the past one year from the current
        date with end-date being at least one day after the start-date.

        The following performance metrics are provided:
            - date
            - campaignId
            - campaignName
            - impressions
                no. times sponsored product is shown
            - clicks
                no. times sponsored product is clicked
            - ctr (click-through-rate)
                clicks/impressions
            - conversions
                no. sales through sponsored products
            - conversionRate
                avg conversions per click
            - sales
            - conversionsOtherEan
            - salesOtherEan
            - spent
            - cpc (cost per click)
            - acos (Advertising Cost of Sale)
                advertising costs calculated against revenue in %
            - roas (Return On Ad-Spent)
                revenue generated from ad calculated against advertising costs in %

        Parameters
        ----------
        start_date : str
            The start date for the reporting period.
            Period start date in ISO 8601 standard.
        end_date : str
            The end date for the reporting period.
            This will be one day after the last full day that is included in the reporting.
            Period end date in ISO 8601 standard.

        Returns
        -------
            pd.DataFrame
                DataFrame with performance results of all campaigns for requested period.
        """
        endpoint_url = f'advertiser/sponsored-products/campaign-performance/reports?start-date={start_date}&end-date={end_date}'
        status, response = self.post(endpoint_url)

        if status == 202:
            # Check status of offer export
            process_id = response.json()['processStatusId']
            endpoint_url = f'shared/process-status/{process_id}'
            _, process = self.get(endpoint_url)

            while process.json()['status'] == 'PENDING':
                time.sleep(60) # Wait 60 seconds
                _, process = self.get(endpoint_url)

            if process.json()['status'] == 'SUCCESS':
                report_id = process.json()['entityId']
                endpoint_url = f'advertiser/sponsored-products/campaign-performance/reports/{report_id}'
                status, response = self.get(endpoint_url)
                if status == 200:
                    download_url = response.json()['url']
                    report = requests.get(download_url)

                    return pd.read_csv(StringIO(report.content.decode('utf-8')))

                else: print(f'ERROR: failed to retrieve campaign performance \n{response.text}')

        else:
            print(f'ERROR: failed to request campaign performance export \n{response.text}')

class BolAdvertisingAPIv9(BolAPI):
    def __init__(self, client_id: str, client_secret: str) -> None:
        super().__init__(client_id, client_secret)
        self.headers = {
            'Accept' : 'application/vnd.advertiser.v9+json',
            'Content-Type' : 'application/vnd.advertiser.v9+json'
        }
        self.get_access_token()

    def request_adgroups(self, campaign_id: str):
        endpoint_url = f'advertiser/sponsored-products/ad-groups?campaign-id={campaign_id}'
        status, response = self.get(endpoint_url)

        if status == 200:
            return response.json()
        else: print(f'ERROR: failed to retrieve campaign ad-groups \n{response.text}')

    def request_targetproducts(self, adgroup_id: str):
        endpoint_url = f'advertiser/sponsored-products/target-products?ad-group-id={adgroup_id}'
        status, response = self.get(endpoint_url)

        if status == 200:
            return response.json()
        else: print(f'ERROR: failed to retrieve ad-group target-products \n{response.text}')


import math

def ecuacion_trigonometrica(x):
    return math.sin(x) - 0.5

def derivada_ecuacion(x):
    return math.cos(x)

def newton_raphson(ecuacion, derivada, x0, epsilon, max_iter):
    iteracion = 0
    error = abs(ecuacion(x0))

    while error > epsilon and iteracion < max_iter:
        x1 = x0 - ecuacion(x0) / derivada(x0)
        error = abs(ecuacion(x1))
        x0 = x1
        iteracion += 1

    if error <= epsilon:
        return x0
    else:
        return None

# Ejemplo de uso
x0 = 1.0  # Valor inicial
epsilon = 1e-6  # Tolerancia para el error
max_iter = 100  # Máximo número de iteraciones

solucion = newton_raphson(ecuacion_trigonometrica, derivada_ecuacion, x0, epsilon, max_iter)

if solucion is not None:
    print("La solución aproximada es:", solucion)
else:
    print("No se pudo encontrar una solución.")


"""
Download and unpack use example

from utils import *

url = "https://wintesting.s3.amazonaws.com/testing/packages/adminrouter/adminrouter--19c887e02f1a8325cabd980f039015b70ab19cee.tar.xz"
path = "./tmp/"
if is_downloadable(url):
  archive =  download(url, path)
else:
    print("{} \nis not downloadable!!!".format(url))

print("this is {}".format(archive))
unpack(archive, "./tmp/Arc/")

"""
import os
from pathlib import Path
from pprint import pprint as pp
import random
import subprocess
import tarfile
import tempfile
import time

import requests

from common import logger
from common import exceptions as cm_exc
from typing import Any, Callable

LOG = logger.get_logger(__name__)

def download(url: str, location: Path) -> Path:
    """
    Download from `url` and store in the `location` directory.
    """
    r = requests.get(url, stream=True)
    fd, path = tempfile.mkstemp(dir=str(location))
    try:
        try:
            for chunk in r.iter_content(chunk_size=32 * 1024):
                os.write(fd, chunk)
        finally:
            os.close(fd)
        r.raise_for_status()
    except Exception:
        os.unlink(path)
        raise
    return Path(path)

# TODO: Needs refactoring
def unpack(tarpath: Path, location: str) -> str:
    """
    unpacks tar.xz to  location
    """

    _location = os.path.abspath(location)

    if not os.path.exists(_location):
        print("no Directory exist creating...\n{}".format(_location))
        os.mkdir(_location)

    with tarfile.open(str(tarpath)) as tar:
        tar.extractall(_location)
        print("extracted to {}".format(_location))
        pp({tarinfo.name: tarinfo.size for tarinfo in tar})
    return _location

def rmdir(path: str, recursive: bool = False) -> None:
    """Remove a directory.

    :param path:      str, target directory path. It must be a direct directory
                      path. Symlinks won't be processed.
    :param recursive: bool, perform recursive removal, if True. Otherwise fail,
                      if a nested directory encountered.
    """
    path_ = Path(str(path))
    if not path_.is_absolute():
        path_ = Path(Path('.').resolve(), path_)

    LOG.debug(f'rmdir(): Target path: {path_}')

    if path_.exists():
        if path_.is_symlink():
            raise OSError(f'Symlink conflict: {path_}')
        if path_.is_reserved():
            raise OSError(f'Reserved name conflict: {path_}')
        elif not path_.is_dir():
            raise OSError(f'Not a directory: {path_}')
        else:
            # Remove content of a directory
            for sub_path in path_.iterdir():
                if sub_path.is_dir():
                    if recursive is True:
                        rmdir(str(path_.joinpath(sub_path)), recursive=True)
                    else:
                        raise RuntimeError(f'Nested directory: {sub_path}')
                else:
                    sub_path.unlink()
                    LOG.debug(f'rmdir(): Remove file: {sub_path}')
            # Remove a directory itself
            path_.rmdir()
            LOG.debug(f'rmdir(): Remove directory: {path_}')
    else:
        LOG.debug(f'rmdir(): Path not found: {path_}')

def run_external_command(cl_elements: str, timeout: float = 30) -> subprocess.CompletedProcess:
    """Run external command.

    :param cl_elements: str|list, string, representing a whole command line, or
                        list of individual elements of command line, beginning
                        with executable name
    :param timeout:     int|float, forcibly terminate execution, if this number
                        of seconds passed since execution was started
    :return:            subprocess.CompletedProcess, results of sub-process
                        execution
    """
    try:
        subproc_run = subprocess.run(
            cl_elements, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            timeout=timeout, check=True, universal_newlines=True
        )
    except subprocess.CalledProcessError as e:
        raise cm_exc.ExternalCommandError(
            '{}: {}: Exit code [{}]: {}'.format(
                cl_elements, type(e).__name__, e.returncode,
                e.stderr.replace('\n', ' ')
            )
        ) from e
    except subprocess.SubprocessError as e:
        raise cm_exc.ExternalCommandError(
            '{}: {}: {}'.format(cl_elements, type(e).__name__, e)
        ) from e
    except (OSError, ValueError) as e:
        raise cm_exc.ExternalCommandError(
            f'{cl_elements}: {type(e).__name__}: {e}'
        ) from e

    return subproc_run

def get_retry_interval(attempt: int, retry_interval_base: float,
                       retry_interval_cap: float) -> float:
    """Calculate interval before the next retry of an operation put into
    retrying loop.

    :param attempt:             int, attempt number
    :param retry_interval_base: float, lower limit of the retry interval
    :param retry_interval_cap:  float, upper limit of the retry interval

    :return:                    float, retry interval in seconds
    """
    # Implementation of the 'Exponential Backoff' with 'Full Jitter'.
    # Ref: http://www.awsarchitectureblog.com/2015/03/backoff.html
    return random.uniform(
        retry_interval_base,
        min(retry_interval_cap, pow(2, attempt) * retry_interval_base)
    )

def retry_on_exc(exceptions: Any = (Exception,), max_attempts: int = 1,
                 retry_interval_base: float = 0.5,
                 retry_interval_cap: float = 5.0) -> Callable:
    """Apply retrying logic to a function/method being decorated.
    """
    def decorator(func: Callable) -> Callable:
        """"""
        def call_proxy(*args: Any, **kwargs: Any) -> Any:
            """"""
            exc_ = None
            result = None

            op_name = func.__name__

            for attempt in range(1, max_attempts + 1):
                try:
                    result = func(*args, **kwargs)
                except exceptions as e:
                    exc_ = e
                    retry_interval = get_retry_interval(
                        attempt, retry_interval_base, retry_interval_cap
                    )
                    LOG.debug(f'Retrying {op_name}: ERROR: attempt[{attempt}]'
                              f' cause[{type(e).__name__}: {e}]'
                              f' next_attempt_in[{retry_interval}]')
                    time.sleep(retry_interval)
                else:
                    LOG.debug(f'Retrying {op_name}: OK:'
                              f' attempts_spent[{attempt}]')
                    exc_ = None
                    break

            if exc_:
                LOG.error(f'Retrying {op_name}: FAILED:'
                          f' attempts_spent[{max_attempts}]')
                raise exc_
            else:
                return result

        return call_proxy

    return decorator

def transfer_files(src: str, dst: str) -> None:
    """
    Transfer files from one directory to another on the same partition.
    """
    for name in os.listdir(src):
        src_path = os.path.join(src, name)
        if os.path.isdir(src_path):
            dstdir = os.path.join(dst, name)
            if not os.path.isdir(dstdir):
                os.mkdir(dstdir)
            transfer_files(src_path, dstdir)
        else:
            os.link(src_path, os.path.join(dst, name))


from django.urls import include, path
from . import views
urlpatterns=[

    path('login',views.login_v,name="login_v"),
    path('login_validate',views.login_validate,name="login_validate"),
    path('logout',views.logout_user,name="logout_user"),
    path('register',views.register,name="logout_user"),
    path('',views.login_v,name="login_v"),

]


import sys, pygame
import time
from pygame.locals import*

width=400
height=400
Color_screen= "#06273a"
Color_line= "#797e66"
Color_snake = "#461815"
Color_frog = "#4f772d"
Cell_size = 20
X_Cell = 10
Y_Cell = 10
X_Tail_Cell = -1
Y_Tail_Cell = -1

GAME_ON = True
SNAKE_FACE_DIRECTION = None
GAME_BOARD = [0]*400

screen=pygame.display.set_mode((width,height))

def draw_sanke():
    global X_Tail_Cell, Y_Tail_Cell
    if X_Cell>19 or X_Cell<0 or Y_Cell>19 or Y_Cell<0:
        return False
    pygame.draw.rect(screen, Color_snake, pygame.Rect((Cell_size*X_Cell)+1, (Cell_size*Y_Cell)+1, Cell_size-1, Cell_size-1))
    if X_Tail_Cell != -1:
        pygame.draw.rect(screen, Color_screen, pygame.Rect((Cell_size*X_Tail_Cell)+1, (Cell_size*Y_Tail_Cell)+1, Cell_size-1, Cell_size-1))
    X_Tail_Cell = X_Cell
    Y_Tail_Cell = Y_Cell
    pygame.display.flip()
    return True

def snake_speed(direction):
    global X_Cell, Y_Cell
    if direction == "down":
        Y_Cell += 1
        if not draw_sanke():
            Y_Cell -= 1
    elif direction == "up":
        Y_Cell -= 1
        if not draw_sanke():
            Y_Cell += 1
    elif direction == "right":
        X_Cell += 1
        if not draw_sanke():
            X_Cell -= 1
    elif direction == "left":
        X_Cell -= 1
        if not draw_sanke():
            X_Cell += 1

def main():
    global Y_Cell, X_Cell, SNAKE_FACE_DIRECTION
    screen.fill(Color_screen)
    for times in range(1, 20):
        changer = Cell_size * times
        pygame.draw.line(screen, Color_line, (changer,0), (changer,400))
        pygame.draw.line(screen, Color_line, (0,changer), (400, changer))
    draw_sanke()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            elif event.type == KEYDOWN:
                key_pressed = pygame.key.name(event.key)
                if key_pressed == "down":
                    SNAKE_FACE_DIRECTION = "down"
                elif key_pressed == "up":
                    SNAKE_FACE_DIRECTION = "up"
                elif key_pressed == "right":
                    SNAKE_FACE_DIRECTION = "right"
                elif key_pressed == "left":
                    SNAKE_FACE_DIRECTION = "left"
        snake_speed(SNAKE_FACE_DIRECTION)
        time.sleep(0.40)
main()


elements = input().split(" ")
needed_products = input().split(" ")
bakery = {}

for i in range(0,len(elements),2):
    element = elements[i]
    key = int(elements[i+1])
    bakery[element] = key

for product in needed_products:
    if product in bakery:
        print(f"We have {bakery[product]} of {product} left")
    else:
        print(f"Sorry, we don't have {product}")


"""Code Kata: Grouped by Commas in CodeWars, level 6."""

def commas(num):
    """Add commas after every three-number group to create decimal represenation.

    input = integer
    output = string with comma separations
    ex. input = 10, output = 10
    ex. input = 1000, output = 1,000
    """
    str_num = str(num)
    res = [str_num[0]]
    for idx in range(1, len(str_num)):
        if (len(str_num) - idx) % 3 == 0:
            res.append(',')
        res.append(str_num[idx])
    return ''.join(res)


from pydub import AudioSegment
from tkinter.filedialog import askdirectory
from pytube import YouTube
from flask import Flask, render_template, request, flash
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'd24018a781de2dce4645ed646c6729328e9e71c0942a8eaa'

def getYTObjectWithItag(choice, yt):
    if choice=="mp4":
        return yt.streams.get_by_itag('22')
    else:
        return yt.streams.get_by_itag('251')

def getTitle(ytobject):
    return ytobject.streams[0].title

def getYTExtension(choice):
    if choice == "mp3":
        return "webm"
    else:
        return "mp4"

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/download/', methods=('GET', 'POST'))
def download():
    link = request.form['yt_link']
    choice = request.form['option']
    if not link:
            flash('Veuillez entrer un lien pour continuer.')

    elif request.method == 'POST':
        # recuperation de l'input du formulaire
        link = request.form['yt_link']
        choice = request.form['option']
        yt = YouTube(link)
        ys = getYTObjectWithItag(choice, yt)
        title = getTitle(yt)
        yt_extension = getYTExtension(choice)

        # selection du dossier dans lequel enregistrer la vidéo
        path = askdirectory(title='Selectionnez un dossier pour enregistrer le fichier :')
        if choice == "mp3":
            ys.download()
            song = AudioSegment.from_file(title + "." + yt_extension, "webm")
            song.export(path+"/"+title + "."+choice, format="mp3")
            os.remove(title +"."+ yt_extension)
        else:
            ys.download(path)

    return render_template('ytdownload.html')


"""
jqueue Server
-------------

The job of the server is, when given a list of files, it will save each of those
files as jobs, and then wait for all the results of those jobs to come back, and
store those in files beside the originals.
"""
from functools import singledispatch
import logging
import socket
import threading
import time

from jqueue import protocol, reactor, utils

LOGGER = logging.getLogger('jqueue.server')

# Messages shouldn't be too large, to ensure that transfer overhead isn't
# an issue
RECV_SIZE = 1024 * 1024

# Clients must be able to Ping us every 30 seconds, as the *worst case*
TTL_LIMIT = 30

# How long to offset the timeout, to let the other end download the message
# (Assumes at least 250 kilobytes per second)
DOWNLOAD_OFFSET_BYTESPERSEC = (1 / (250 * 1024))

class JobDispatcher:
    """
    This keeps track of which jobs are available, and those which are currently
    being worked on. This class's primary responsibility is to ensure that jobs
    which are 'abandoned' (that is, their ping time expires) are returned to the
    list of inactive jobs so they can be picked up by another client.
    """
    def __init__(self, jobs):
        self.inactive_jobs = jobs
        self.active_job_timeouts = {}
        self.active_job_ttls = {}

    def time_until_next_timeout(self):
        """
        Returns the number of seconds until the next timeout transpires.
        """
        # If no jobs are running, then we don't care how long we wait, since
        # this function will never have to run
        if not self.active_job_timeouts:
            return None

        nearest_timeout = min(self.active_job_timeouts.values())
        LOGGER.info('Waiting for %d seconds', nearest_timeout - time.time())
        return nearest_timeout - time.time()

    def handle_job_ping(self, job):
        """
        Handles a ping on a job, increasing its timeout by the TTL originally
        marked on the job.
        """
        if job not in self.active_job_timeouts:
            raise ValueError('The job {} is not active'.format(job))

        LOGGER.info('Updated timeout for job %s', job)
        self.active_job_timeouts[job] = time.time() + self.active_job_ttls[job]

    def handle_job_completion(self, job):
        """
        Handles the completion of a job, by removing its associated data.
        """
        if job not in self.active_job_timeouts:
            raise ValueError('The job {} is not active'.format(job))

        del self.active_job_timeouts[job]
        del self.active_job_ttls[job]

    def handle_job_timeouts(self):
        """
        Removes any active jobs which have timed out.
        """
        now = time.time()

        dead_jobs = set()
        for job, timeout in self.active_job_timeouts.items():
            if timeout < now:
                dead_jobs.add(job)

        for dead_job in dead_jobs:
            LOGGER.info('Job %s timed out', dead_job)
            del self.active_job_timeouts[dead_job]
            del self.active_job_ttls[dead_job]

            self.inactive_jobs.append(dead_job)

    def get_job(self, ttl):
        """
        Gets the next job, producing a ``protocol.Job`` to send to the client,
        or ``None``.
        """
        if not self.inactive_jobs:
            return None

        job_filename = self.inactive_jobs.pop()
        with open(job_filename, 'rb') as job_file_stream:
            job_content = job_file_stream.read()

        content_size = len(job_content)
        file_size_adjustment = int(DOWNLOAD_OFFSET_BYTESPERSEC * content_size)
        LOGGER.info('Adjusting timeout for job %s by %d seconds',
            job_filename, file_size_adjustment)

        self.active_job_timeouts[job_filename] = ttl + time.time() + file_size_adjustment
        self.active_job_ttls[job_filename] = ttl
        return protocol.Job(job_filename, job_content)

    def has_jobs(self, active=True):
        """
        Returns ``True`` if there are jobs that need doing, or ``False``
        otherwise.

        Note that, if ``active`` is ``False``, then only inactive jobs are
        checked.
        """
        if active:
            return bool(self.inactive_jobs) or bool(self.active_job_timeouts)
        else:
            return bool(self.inactive_jobs)

class Server:
    """
    Waits for client requests and then handles them.
    """
    def __init__(self):
        self.server_launched = threading.Event()
        self.clients = {}
        self.client_buffers = {}
        self.send_buffers = {}

    def queue_unsent_data(self, sock, data):
        """
        Queues up data which needs to be sent to a particular socket, and
        registers the sending function to ensure that it gets sent.
        """
        self.send_buffers[sock.fileno()] = data
        self.my_reactor.bind(sock, reactor.WRITABLE, self.handle_unsent_data)

    def handle_error(self, fd_event):
        """
        Handles errors on a socket.
        """
        fd, event = fd_event
        LOGGER.info('Error on FD %d', fd)
        if fd in self.clients:
            self.close_client(self.clients[fd])
        else:
            self.close()

    def handle_connect(self, _):
        """
        Handles a connection to the server socket, establishing a new client
        to get a command from.
        """
        client_sock, _ = self.server_sock.accept()
        LOGGER.info('Connection from %s', _)

        self.clients[client_sock.fileno()] = client_sock
        self.client_buffers[client_sock.fileno()] = b''
        self.my_reactor.bind(client_sock, reactor.READABLE, self.handle_data)
        self.my_reactor.bind(client_sock, reactor.ERROR, self.handle_error)

    def handle_unsent_data(self, fd_event):
        """
        Sends any unsent data across a socket, closing the socket if all the
        data has been sent.
        """
        fd, event = fd_event
        sock = self.clients[fd]
        buffer = self.send_buffers[fd]

        sent = sock.send(buffer)
        if len(buffer) == sent:
            # When finished, close the socket, since this server allows only
            # one request per connection (and thus, we can only send one
            # response per connection)
            self.close_client(sock)
            del self.send_buffers[fd]
        else:
            self.send_buffers[fd] = buffer[sent:]

    def handle_data(self, fd_event):
        """
        Handles incoming data from a client, chunking it into messages and
        passing them onto the message handler.
        """
        fd, event = fd_event
        client_sock = self.clients[fd]
        client_buff = self.client_buffers[fd]

        data = client_sock.recv(RECV_SIZE)
        if not data:
            self.close_client(client_sock)
        else:
            client_buff += data
            try:
                while True:
                    message, client_buff = protocol.message_from_bytes(client_buff)
                    if message is not None:
                        LOGGER.info('Got message %s from client', type(message))
                        self.handle_message(message, client_sock)
                    else:
                        break

                if fd in self.client_buffers:
                    # It may be that the socket is closed now, since they are
                    # discarded after a single request
                    LOGGER.info('%d bytes unprocessed', len(self.client_buffers[fd]))
                    self.client_buffers[fd] = client_buff
            except ValueError as exn:
                # If we get any malformed data, kill the connection
                LOGGER.exception(exn)
                self.close_client(client_sock)

    @utils.dispatchmethod
    def handle_message(self, message, client):
        """
        The fallback handler simply sends out a DO_NOT_UNDERSTAND error
        to messages the server is not prepared to handle.
        """
        LOGGER.info('Unknown message: %s', message)
        raw_message = protocol.serialize(
            protocol.Error(protocol.Errors.DO_NOT_UNDERSTAND))
        self.queue_unsent_data(client, raw_message)

    @handle_message.register(protocol.RequestJob)
    def _(self, message, client):
        """
        Job requests can be handled in three ways:

        1. A job is available, and it is sent back
        2. The TTL is too high, and an error is generated
        3. No jobs are available, and an errors is generated
        """
        LOGGER.info('Got job request: %s', message)

        if message.ttl > TTL_LIMIT:
            LOGGER.info('|| TTL too high')
            raw_message = protocol.serialize(
                protocol.Error(protocol.Errors.TTL_TOO_HIGH))
        elif not self.job_dispatcher.has_jobs(active=False):
            LOGGER.info('|| No jobs')
            raw_message = protocol.serialize(
                protocol.Error(protocol.Errors.NO_JOB_AVAIL))
        else:
            job = self.job_dispatcher.get_job(message.ttl)
            LOGGER.info('|| Got job %s of %d bytes', job.id, len(job.data))
            raw_message = protocol.serialize(job)

        self.queue_unsent_data(client, raw_message)

    @handle_message.register(protocol.Ping)
    def _(self, message, client):
        """
        Pings can either succeed and update the job's timeout, or fail and
        produce an error.
        """
        LOGGER.info('Got ping: %s', message)

        try:
            self.job_dispatcher.handle_job_ping(message.id)
            raw_message = protocol.serialize(protocol.Ok())
            LOGGER.info('|| Ping successful')
        except ValueError:
            LOGGER.info('|| No such job')
            raw_message = protocol.serialize(
                protocol.Error(protocol.Errors.NOT_RESERVED))

        self.queue_unsent_data(client, raw_message)

    @handle_message.register(protocol.SubmitResult)
    def _(self, message, client):
        """
        Results can either be ignored, or accepted and written to the result
        file.
        """
        LOGGER.info('Got result for %s with %d bytes', message.id, len(message.data))

        try:
            self.job_dispatcher.handle_job_completion(message.id)
            with open(message.id + b'.result', 'wb') as response_stream:
                response_stream.write(message.data)
            raw_message = protocol.serialize(protocol.Ok())
            LOGGER.info('|| Job completion successful')
        except ValueError:
            LOGGER.info('|| No such job')
            raw_message = protocol.serialize(
                protocol.Error(protocol.Errors.NOT_RESERVED))

        self.queue_unsent_data(client, raw_message)

    def open(self, port):
        """
        Opens the server socket used by the server
        """
        self.server_sock = socket.socket()
        self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_sock.bind(('0.0.0.0', port))
        self.server_sock.listen(5)
        self.server_sock.setblocking(False)

    def close_client(self, client):
        """
        Closes a single client.
        """
        fd = client.fileno()
        self.my_reactor.unbind(client)
        client.close()

        del self.clients[fd]
        del self.client_buffers[fd]

    def close(self):
        """
        Closes the sockets used by the server.
        """
        for client in list(self.clients.values()):
            client.close()

        self.server_sock.close()

    def run(self, file_list, port=2267):
        """
        Runs the server, on the given port, until no jobs remain.
        """
        self.open(port)

        self.my_reactor = reactor.Reactor()
        self.my_reactor.bind(self.server_sock, reactor.ERROR, self.handle_error)
        self.my_reactor.bind(self.server_sock, reactor.READABLE, self.handle_connect)

        self.job_dispatcher = JobDispatcher(file_list)
        self.my_reactor.add_step_callback(self.job_dispatcher.handle_job_timeouts)

        self.server_launched.set()
        while self.job_dispatcher.has_jobs():
            timeout = self.job_dispatcher.time_until_next_timeout()
            self.my_reactor.poll(timeout)

            if not self.job_dispatcher.has_jobs():
                break

        self.close()


import json
from datetime import datetime

PARTITION_PU = {
    '0': ([1, 1],     [1, 1]),      # 2N X 2N
    '1': ([1, 0.5],   [1, 0.5]),    # 2N X N
    '2': ([0.5, 1],   [0.5, 1]),    # N X 2N
    '3': ([0.5, 0.5], [0.5, 0.5]),  # N X N
    '4': ([1, 0.75],  [1, 0.25]),   # 2N x nU
    '5': ([1, 0.25],  [1, 0.75]),   # 2N x nD
    '6': ([0.25, 1],  [0.75, 1]),   # nL x 2N
    '7': ([0.75, 1],  [0.25, 1])    # nR x 2N
}

INITIAL_CU_SHIFT = {
    '0': ([0, 0],   [0, 0]),      # 2N X 2N
    '1': ([0, 0],   [0, 0.5]),    # 2N X N
    '2': ([0, 0],   [0.5, 0]),    # N X 2N
    '3': ([0, 0],   [0.5, 0],
          [0, 0.5], [0.5, 0.5]),  # N X N
    '4': ([0, 0],   [0, 0.75]),   # 2N x nU
    '5': ([0, 0],   [0, 0.25]),   # 2N x nD
    '6': ([0, 0],   [0.25, 0]),   # nL x 2N
    '7': ([0, 0],   [0.75, 0])    # nR x 2N
}

with open('tz_cand_list.json', 'r') as fp:
    TZ_CAND_LIST = json.load(fp)

class TraceProcessor(object):
    def __init__(self):
        self.current_frame = str()
        self.ref_frame = str()

        self.cu_position = (int(), int())
        self.cu_size = int()

        self.current_ctu_postion = (int(), int())
        self.first_ctu = True

        self.first_search_shift = (int(), int())

        self.width = int()
        self.height = int()

        self.dispatcher = {
            "I ": self.start_frame,
            "L ": self.start_ctu,
            "U ": self.process_cu,
            "P ": self.process_pu,
            "C ": self.process_block,
            "F ": self.process_first_search,
            "CE": self.process_block_sequence
        }

    def set_resolution(self, width, height):
        self.width = width
        self.height = height

    def process_trace(self, trace_path):
        with open(trace_path) as trace:
            for line in trace:
                key = line[0:2]

                if key in self.dispatcher:
                    yield self.dispatcher[key](line)

    def start_frame(self, line):
        # I <curr_frame_id>
        _, self.current_frame = line.split()
        print(f"[{datetime.now():%H:%M:%S}] Processing frame {self.current_frame}.")

        return list()

    def start_ctu(self, line):
        if self.first_ctu:
            self.first_ctu = False
        else:
            x_pos, y_pos = self.current_ctu_postion

            # Write 64x64 block starting at (x_pos, y_pos)
            for x in range(int(x_pos), int(x_pos) + 64):
                for y in range(int(y_pos), int(y_pos) + 64):
                    yield f"W {x} {y} {self.current_frame}"

        # L <xCTU> <yCTU>
        _, x, y = line.split()

        self.current_ctu_postion = (x, y)

        return list()

    def process_cu(self, line):
        # U <xCU> <yCU> <size>
        _, x, y, cu_size = line.split()

        self.cu_size = int(cu_size)
        self.cu_position = (int(x), int(y))

        return list()

    def process_pu(self, line):
        # P <sizePU> <idPart> <ref_frame_id>
        _, size_pu, id_part, ref_frame = line.split()

        self.ref_frame = ref_frame

        partition_hor, partition_ver = PARTITION_PU[size_pu][int(id_part)]

        self.current_cu_width = int(partition_hor * self.cu_size)
        self.current_cu_height = int(partition_ver * self.cu_size)

        self.shift_cu_position(size_pu, id_part)

        return list()

    def process_block(self, line):
        # C <xCand> <yCand>
        _, x, y = line.split()

        initial_x, initial_y = self.set_initial_pos(int(x), int(y))
        final_x, final_y = self.set_final_pos(initial_x, initial_y)

        for i in range(initial_y, final_y):
            for j in range(initial_x, final_x):
                yield f"R {i} {j} {self.ref_frame}"

    def set_initial_pos(self, x, y):
        center_x, center_y = self.cu_position

        # Initial position can't be nagative
        initial_x = x + int(center_x)
        initial_x = initial_x if initial_x >= 0 else 0

        initial_y = y + int(center_y)
        initial_y = initial_y if initial_y >= 0 else 0

        return initial_x, initial_y

    def set_final_pos(self, initial_x, initial_y):
        # Final position can't be higher than video resolution
        final_x = initial_x + self.current_cu_width
        final_x = final_x if final_x <= self.width else self.width

        final_y = initial_y + self.current_cu_height
        final_y = final_y if final_y <= self.height else self.height

        return final_x, final_y

    def process_first_search(self, line):
        # F <itID>
        _, it_id = line.split()

        lines = (TZ_CAND_LIST[it_id].split("\n"))

        center_x, center_y = self.cu_position
        shift_x, shift_y = self.first_search_shift

        # Shift CU position to First Search
        self.cu_position = (center_x + shift_x, center_y + shift_y)

        for line in lines:
            self.process_block(line)

        # Shift CU postion back to original
        self.cu_position = (center_x, center_y)

        return list()

    def process_block_sequence(self, line):
        # CE <xStart> <yStart>
        _, x, y = line.split()

        self.first_search_shift = (int(x), int(y))

        return list()

    def shift_cu_position(self, size_pu, id_part):
        x, y = self.cu_position

        x_shift, y_shift = INITIAL_CU_SHIFT[size_pu][int(id_part)]

        x = x + int(x_shift) * self.cu_size
        y = y + int(y_shift) * self.cu_size

        self.cu_position = (int(x), int(y))

        return list()

if __name__ == "__main__":
    trace_processor = TraceProcessor()
    trace_processor.set_resolution(1920, 1080)

    generator = trace_processor.process_trace("samples/mem_trace.txt")

    for operations in generator:
        for operation in operations:
            print(operation)


import pickle
import numpy as np

import torch
from torch.utils.data import Dataset, DataLoader

import torchvision
from torchvision import transforms
from train_and_test_utils import test
from torchsummary import summary

from PIL import Image
from model import MyModel

from utils import score, load_checkpoint, reset, count_parameters

test_data_path = 'val.pkl'

with open(test_data_path, 'rb') as file:
    test_data = pickle.load(file)

device = 'cuda' if torch.cuda.is_available() else 'cpu'
batch_size = 256

class TestDataset(Dataset):
    def __init__(self, data, transform=None):
        self.data = data
        self.transform = transform

    def __len__(self):
        return len(self.data['path'])

    def __getitem__(self, idx):

        sample = dict()

        img_path = self.data['path'][idx]

        image = Image.open(img_path)

        if self.transform:
            image = self.transform(image)

        sample['img'] = image
        sample['id'] = self.data['id'][idx]
        sample['label'] = self.data['label'][idx]

        return sample

test_transforms = transforms.Compose([

    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])

test_dataset = TestDataset(test_data, transform=test_transforms)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=8)

reset(0)

def test(model, sample):
    model.eval()

    with torch.no_grad():

        img = sample['img'].to(device)
        label = sample['id'].to(device)
        pred = model(img)
        num_correct = torch.sum(torch.argmax(pred, dim=-1) == label)

    return num_correct.item()

model = load_checkpoint('checkpoint.pth', device)
#model = MyModel()
#summary(model, (3, 256,256))

num_params = count_parameters(model)
print('Number of parameters: {}'.format(num_params))
if num_params > 20000000:
    raise ValueError("Cannot have more than 20 million parameters!")

avg_te_correct = 0
for sample in test_loader:
    te_correct = test(model, sample)
    avg_te_correct += te_correct / len(test_dataset)

print('Your accuracy: {:.02f}%'.format(avg_te_correct*100))
print('Your score: {:.02f} out of 100'.format(score(avg_te_correct*100)))

2023 Fall Semester/AI Toolkits/course projects/project2/food classification/test.py


print("What's good!")

first_name = 'Adrian'
middle_name = 'Scott'
last_name = 'Dean'
full_name = first_name +' '+ middle_name +' '+ last_name
print('Watashiwa '+full_name)

age = 12
age += 5
print("I'm currently "+str(age)+" years old!")

height = 420.69
print("My heighth is: "+str(height)+"in")

a_skinny_man = True
print("Are you a skinny man: "+str(a_skinny_man))


#
# CSCS-USI SummerSchool miniapp ported to Python
#
#   A small benchmark app that solves the 2D fisher equation using second-order
#   finite differences.
#
#   Originally developed in C++ by Ben Cumming, CSCS
#   Ported to Python by Vasileios Karakasis, CSCS

import collections
import matplotlib
import numba
import numpy as np
import os
import sys
from datetime import datetime

import linalg
import operators

Discretization = collections.namedtuple(
    'Discretization', ['nx', 'ny', 'N', 'nt', 'dt', 'dx', 'alpha']
)

Boundary = collections.namedtuple(
    'Boundary', ['north', 'south', 'east', 'west']
)

NewtonStatus = collections.namedtuple(
    'NewtonStatus', ['solution', 'converged', 'timestep',
                     'iters_newton', 'iters_cg', 'status_cg']
)

def usage():
    print(f'Usage: {sys.argv[0]} nx ny nt t', file=sys.stderr)
    print(f'  nx  number of gridpoints in x-direction', file=sys.stderr)
    print(f'  ny  number of gridpoints in y-direction', file=sys.stderr)
    print(f'  nt  number of timesteps', file=sys.stderr)
    print(f'  t   total simulated time', file=sys.stderr)

def parse_arg(v, argname, fn):
    try:
        v = fn(v)
    except ValueError as e:
        print(f'{sys.argv[0]}: could not parse argument {argname}: {e}')
        usage()
        sys.exit(1)

    return v

@numba.njit(cache=True)
def timeloop(x, boundary, options, max_cg_iters, max_newton_iters, tolerance):
    # main timeloop

    nx, ny = options.nx, options.ny

    # initialize fields
    b = np.zeros(nx*ny)
    deltax = np.zeros(nx*ny)

    nt = options.nt
    iters_newton = 0
    iters_cg = 0

    for timestep in range(1, nt+1):
        x_old = np.copy(x)
        converged = False
        for it in range(max_newton_iters):
            operators.diffusion(x, b, x_old, boundary, options)
            residual = np.sqrt(b @ b)
            if residual < tolerance:
                converged = True
                break

            cg_status = linalg.cg(
                deltax, x_old, b, boundary, options,
                tolerance, max_cg_iters
            )

            iters_cg += cg_status.iters
            if not cg_status.converged:
                break

            x -= deltax

        iters_newton += it + 1
        if not converged:
            break

    return NewtonStatus(x, converged, timestep,
                        iters_newton, iters_cg, cg_status)

def main():
    if len(sys.argv) < 5:
        print(f'{sys.argv[0]}: too few arguments', file=sys.stderr)
        usage()
        sys.exit(1)

    nx, ny, nt, t, *_ = sys.argv[1:]

    def is_positive(x):
        if x <= 0:
            raise ValueError(f'value must be positive: {x}')

        return x

    nx = parse_arg(nx, 'nx', lambda x: is_positive(int(x)))
    ny = parse_arg(ny, 'ny', lambda x: is_positive(int(x)))
    nt = parse_arg(nt, 'nt', lambda x: is_positive(int(x)))
    t  = parse_arg(t,  't',  lambda x: is_positive(float(x)))

    # calculate timestep
    dt = t / nt

    # compute the distance between grid points
    # assume that x dimension has length 1.0
    dx = 1. / (nx - 1)

    # set alpha, assume diffusion coefficient D is 1
    alpha = (dx*dx) / dt

    options = Discretization(nx, ny, nx*ny, nt, dt, dx, alpha)

    # set iteration parameters
    max_cg_iters = 200
    max_newton_iters = 50
    tolerance = 1.e-6

    print(f'========================================================================')
    print(f'                      Welcome to mini-stencil!')
    print(f'version   :: Python')
    print(f'mesh      :: {nx} * {ny} dx = {dx}')
    print(f'time      :: {nt} time steps from 0 .. {nt*dt}')
    print(f'iteration :: CG {max_cg_iters}, Newton {max_newton_iters}, '
          f'tolerance {tolerance}')
    print(f'========================================================================')

    # Solution field
    x = np.zeros(nx*ny)

    # set dirichlet boundary conditions to 0 all around
    bndN  = np.zeros(nx)
    bndS  = np.zeros(nx)
    bndE  = np.zeros(ny)
    bndW  = np.zeros(ny)
    boundary = Boundary(bndN, bndS, bndE, bndW)

    # set the initial condition
    # a circle of concentration 0.1 centred at (xdim/4, ydim/4) with radius
    # no larger than 1/8 of both xdim and ydim
    xspace = np.linspace(0, 1, nx)
    yspace = np.linspace(0, 1, ny)
    X, Y = np.meshgrid(xspace, yspace, indexing='ij')

    xc = 1.0 / 4.0
    yc = (ny - 1) * dx / 4
    radius = min(xc, yc) / 2.0
    x = x.reshape((nx, ny))
    x[(X - xc) ** 2 + (Y - yc) ** 2 < radius * radius] = 0.1

    # restore x_new's shape
    x = x.flatten()

    flops_bc = 0
    flops_diff = 0
    flops_blas1 = 0
    iters_cg = 0
    iters_newton = 0
    timespent = datetime.now()

    status = timeloop(
        x, boundary, options, max_cg_iters, max_newton_iters, tolerance
    )
    if not status.converged:
        cg_status = status.status_cg
        if not cg_status.converged:
            print(f'ERROR: CG failed to converge after {cg_status.iters} '
                  f'iterations, with residual {cg_status.residual}',
                  file=sys.stderr)

        print(f'step {status.timestep} '
              f'ERROR : nonlinear iterations failed to converge',
              file=sys.stderr)

    # get times
    timespent = (datetime.now() - timespent).total_seconds()
    print('----------------------------------------'
          '----------------------------------------')
    print(f'simulation took {timespent} seconds')
    print(f'{status.iters_cg} conjugate gradient iterations, at rate of '
          f'{status.iters_cg/timespent} iters/second')
    print(f'{status.iters_newton} newton iterations')
    print(f'Goodbye!')

    if 'DISPLAY' not in os.environ:
        matplotlib.use('Agg')

    import matplotlib.pyplot as plt

    # number of contours we wish to see
    V = [-0.01, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.01]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    outfile = f'output_{nx}x{ny}_t={t}_steps={nt}.png'

    print(f'generating solution figure in "{outfile}" ...')
    ax.contourf(X, Y, x.reshape((nx, ny)), V, alpha=.75, cmap='jet')
    ax.axes.set_aspect('equal')
    fig.savefig(outfile, dpi=72)

    if 'DISPLAY' in os.environ:
        plt.show()

if __name__ == '__main__':
    main()