import json
import os

import torch
from pytest import fixture

import inseq
from inseq.data.aggregator import (
    AggregatorPipeline,
    ContiguousSpanAggregator,
    PairAggregator,
    SequenceAttributionAggregator,
    SubwordAggregator,
)
from inseq.models import HuggingfaceDecoderOnlyModel, HuggingfaceEncoderDecoderModel

EXAMPLES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../fixtures/aggregator.json")
EXAMPLES = json.load(open(EXAMPLES_FILE))

@fixture(scope="session")
def saliency_mt_model() -> HuggingfaceEncoderDecoderModel:
    return inseq.load_model("Helsinki-NLP/opus-mt-en-it", "saliency", device="cpu")

@fixture(scope="session")
def saliency_gpt_model() -> HuggingfaceDecoderOnlyModel:
    return inseq.load_model("gpt2", "saliency", device="cpu")

def test_sequence_attribution_aggregator(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute(
        "This is a test.",
        step_scores=["probability"],
        attribute_target=True,
        output_step_attributions=True,
        device="cpu",
        show_progress=False,
    )
    seqattr = out.sequence_attributions[0]
    assert seqattr.source_attributions.shape == (6, 7, 512)
    assert seqattr.target_attributions.shape == (7, 7, 512)
    assert seqattr.step_scores["probability"].shape == (7,)
    for i, step in enumerate(out.step_attributions):
        assert step.source_attributions.shape == (1, 6, 512)
        assert step.target_attributions.shape == (1, i + 1, 512)
    out_agg = seqattr.aggregate()
    assert out_agg.source_attributions.shape == (6, 7)
    assert out_agg.target_attributions.shape == (7, 7)
    assert out_agg.step_scores["probability"].shape == (7,)

def test_continuous_span_aggregator(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute(
        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu", show_progress=False
    )
    seqattr = out.sequence_attributions[0]
    out_agg = seqattr.aggregate(ContiguousSpanAggregator, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
    assert out_agg.source_attributions.shape == (5, 4, 512)
    assert out_agg.target_attributions.shape == (4, 4, 512)
    assert out_agg.step_scores["probability"].shape == (4,)

def test_span_aggregator_with_prefix(saliency_gpt_model: HuggingfaceDecoderOnlyModel):
    out = saliency_gpt_model.attribute("Hello, world! I am,:.", "Hello, world! I am,:.!,. Last")
    aggregated = out.aggregate("subwords", special_symbol=("Ġ", "Ċ")).aggregate()
    assert aggregated[0].target_attributions.shape == (5, 2)
    assert aggregated[0].attr_pos_start == 3
    assert aggregated[0].attr_pos_end == 5

def test_aggregator_pipeline(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute(
        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu", show_progress=False
    )
    seqattr = out.sequence_attributions[0]
    squeezesum = AggregatorPipeline([ContiguousSpanAggregator, SequenceAttributionAggregator])
    out_agg_squeezesum = seqattr.aggregate(squeezesum, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
    assert out_agg_squeezesum.source_attributions.shape == (5, 4)
    assert out_agg_squeezesum.target_attributions.shape == (4, 4)
    assert out_agg_squeezesum.step_scores["probability"].shape == (4,)
    sumsqueeze = AggregatorPipeline([SequenceAttributionAggregator, ContiguousSpanAggregator])
    out_agg_sumsqueeze = seqattr.aggregate(sumsqueeze, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
    assert out_agg_sumsqueeze.source_attributions.shape == (5, 4)
    assert out_agg_sumsqueeze.target_attributions.shape == (4, 4)
    assert out_agg_sumsqueeze.step_scores["probability"].shape == (4,)
    assert not torch.allclose(out_agg_squeezesum.source_attributions, out_agg_sumsqueeze.source_attributions)
    assert not torch.allclose(out_agg_squeezesum.target_attributions, out_agg_sumsqueeze.target_attributions)
    # Named indexing version
    named_squeezesum = ["spans", "scores"]
    named_sumsqueeze = ["scores", "spans"]
    out_agg_squeezesum_named = seqattr.aggregate(named_squeezesum, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
    out_agg_sumsqueeze_named = seqattr.aggregate(named_sumsqueeze, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
    assert out_agg_squeezesum_named.source_attributions.shape == (5, 4)
    assert out_agg_squeezesum_named.target_attributions.shape == (4, 4)
    assert out_agg_squeezesum_named.step_scores["probability"].shape == (4,)
    assert out_agg_sumsqueeze_named.source_attributions.shape == (5, 4)
    assert out_agg_sumsqueeze_named.target_attributions.shape == (4, 4)
    assert out_agg_sumsqueeze_named.step_scores["probability"].shape == (4,)
    assert not torch.allclose(
        out_agg_squeezesum_named.source_attributions, out_agg_sumsqueeze_named.source_attributions
    )
    assert not torch.allclose(
        out_agg_squeezesum_named.target_attributions, out_agg_sumsqueeze_named.target_attributions
    )

def test_subword_aggregator(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute(EXAMPLES["source"], show_progress=False)
    seqattr = out.sequence_attributions[0]
    for idx, token in enumerate(seqattr.source):
        assert token.token == EXAMPLES["source_subwords"][idx]
    for idx, token in enumerate(seqattr.target):
        assert token.token == EXAMPLES["target_subwords"][idx]
    # Full aggregation
    out_agg = seqattr.aggregate(SubwordAggregator)
    for idx, token in enumerate(out_agg.source):
        assert token.token == EXAMPLES["source_merged"][idx]
    for idx, token in enumerate(out_agg.target):
        assert token.token == EXAMPLES["target_merged"][idx]
    # Source-only aggregation
    out_agg = seqattr.aggregate(SubwordAggregator, aggregate_target=False)
    for idx, token in enumerate(out_agg.source):
        assert token.token == EXAMPLES["source_merged"][idx]
    for idx, token in enumerate(out_agg.target):
        assert token.token == EXAMPLES["target_subwords"][idx]
    # Target-only aggregation
    out_agg = seqattr.aggregate(SubwordAggregator, aggregate_source=False)
    for idx, token in enumerate(out_agg.source):
        assert token.token == EXAMPLES["source_subwords"][idx]
    for idx, token in enumerate(out_agg.target):
        assert token.token == EXAMPLES["target_merged"][idx]

def test_pair_aggregator(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute([EXAMPLES["source"], EXAMPLES["alternative_source"]], show_progress=False)
    orig_seqattr = out.sequence_attributions[0].aggregate(["vnorm"])
    alt_seqattr = out.sequence_attributions[1].aggregate(["vnorm"])
    diff_seqattr = orig_seqattr.aggregate(PairAggregator, paired_attr=alt_seqattr)
    for idx, token in enumerate(diff_seqattr.source):
        assert token.token == EXAMPLES["diff_subwords"][idx]
    assert torch.allclose(
        alt_seqattr.source_attributions - orig_seqattr.source_attributions, diff_seqattr.source_attributions
    )
    # Default aggregation with SequenceAttributionAggregator
    orig_seqattr_other = out.sequence_attributions[0].aggregate()
    alt_seqattr_other = out.sequence_attributions[1].aggregate()
    # Aggregate with aggregator name
    diff_seqattr_other = orig_seqattr_other.aggregate("pair", paired_attr=alt_seqattr_other)
    assert torch.allclose(diff_seqattr_other.source_attributions, diff_seqattr.source_attributions)

def test_named_aggregate_fn_aggregation(saliency_mt_model: HuggingfaceEncoderDecoderModel):
    out = saliency_mt_model.attribute(
        [EXAMPLES["source"], EXAMPLES["alternative_source"]],
        show_progress=False,
        attribute_target=True,
        method="attention",
    )
    out_headmean = out.aggregate(aggregator=["mean", "mean"])
    assert out_headmean.sequence_attributions[0].source_attributions.ndim == 2
    assert out_headmean.sequence_attributions[0].target_attributions.ndim == 2
    assert out_headmean.sequence_attributions[1].source_attributions.ndim == 2
    assert out_headmean.sequence_attributions[1].target_attributions.ndim == 2
    out_allmean_subwords = out.aggregate(aggregator=["mean", "mean", "subwords"])

    # Check whether scores aggregation worked correctly
    assert out_allmean_subwords.sequence_attributions[0].source_attributions.ndim == 2
    assert out_allmean_subwords.sequence_attributions[0].target_attributions.ndim == 2
    assert out_allmean_subwords.sequence_attributions[1].source_attributions.ndim == 2
    assert out_allmean_subwords.sequence_attributions[1].target_attributions.ndim == 2

    # Check whether subword aggregation worked correctly
    assert (
        out_allmean_subwords.sequence_attributions[0].source_attributions.shape[0]
        < out.sequence_attributions[0].source_attributions.shape[0]
    )
    assert (
        out_allmean_subwords.sequence_attributions[0].target_attributions.shape[0]
        < out.sequence_attributions[0].target_attributions.shape[0]
    )
    assert (
        out_allmean_subwords.sequence_attributions[1].source_attributions.shape[0]
        < out.sequence_attributions[1].source_attributions.shape[0]
    )
    assert (
        out_allmean_subwords.sequence_attributions[1].target_attributions.shape[0]
        < out.sequence_attributions[1].target_attributions.shape[0]
    )

    out_allmean_subwords_expanded = out.aggregate(
        aggregator=["scores", "scores", "subwords"], aggregate_fn=["mean", "mean", None]
    )
    assert out_allmean_subwords == out_allmean_subwords_expanded


from Helper.RequestContext import RequestContext
from Helper.RoutingEndpoint import RoutingEndpoint
from Handler.LogHandler import LogHandler
import http.client
import json
import datetime

class RequestRedirectManager:

    def __init__(self,log : LogHandler):
        self._log = log

    def RedirectRequest(self,context : RequestContext, endpoint : RoutingEndpoint):
        print("--->In Request Redirect Manager\n Request redirected to http://"+endpoint.Host+":"+str(endpoint.Port)+endpoint.Url)
        client = http.client.HTTPConnection(endpoint.Host,endpoint.Port)
        self._log.LogHttpInfo(endpoint,context.Command)
        payload = None if context.Command == 'GET'  else self.AddPayloadToken(context.RequestMessage.read(int(context.Header['Content-Length'])))
        client.request(context.Command,endpoint.Url,payload,{'Content-type': 'application/json'})
        response = client.getresponse()
        context.SetResponse(response.status,response.reason,response.read())
        client.close()
        return context

    def AddPayloadToken(self,payload):
        payloadJson = json.loads(payload)
        payloadJson['PayLoadToken'] = datetime.datetime.now().timestamp()
        print(payloadJson)
        self._log.DataLogger(payloadJson)
        return json.dumps(payloadJson)


import pytest

from api.models import CelebrationDay, RegistryUser, GiftItem
from faker import Faker

fake = Faker()
TEST_USER_ID = '54321'

@pytest.fixture
def api_client():
   from rest_framework.test import APIClient
   return APIClient()

@pytest.fixture
def user_create(django_user_model):
   def make_user(**kwargs):
       return django_user_model.objects.create(
       sub = 123456789,
       email = 'testuser@testuser.com',
       first_name = 'test',
       last_name = 'user',
       id = TEST_USER_ID)
   return make_user

@pytest.fixture
def non_auth_user_create(django_user_model):
   def make_non_auth_user(**kwargs):
       return django_user_model.objects.create(
       sub = 987654321,
       email = 'non_auth_user@non_auth_user.com',
       first_name = 'non_auth',
       last_name = 'user',
       id = f'{TEST_USER_ID}12345')
   return make_non_auth_user

@pytest.fixture
def api_auth_client(user_create, api_client):
    user = user_create()
    api_client.force_authenticate(user=user)
    yield api_client
    api_client.force_authenticate(user=None)

@pytest.fixture
def create_owned_base_model(user_create):
   user = RegistryUser.objects.get(id=TEST_USER_ID)
   payload={
        'name': fake.name(),
        'owner': user,
        'created_at': fake.date(),
        'updated_at': fake.date(),
    }
   return payload

@pytest.fixture
def create_celebration_day_item(create_owned_base_model):
   payload={
        'date': fake.date(),
    }
   celebration_day = CelebrationDay.objects.create(**payload, **create_owned_base_model)
   return celebration_day

@pytest.fixture
def create_gift_item(create_owned_base_model):
   payload={
        'is_purchased': fake.boolean(),
        'notes': fake.text(),
    }
   gift_item = GiftItem.objects.create(**payload, **create_owned_base_model)
   return gift_item

@pytest.fixture
def create_non_auth_user_gift_item(non_auth_user_create):
   user = non_auth_user_create()
   payload={
        'name': fake.name(),
        'owner': user,
        'created_at': fake.date(),
        'updated_at': fake.date(),
        'is_purchased': fake.boolean(),
        'notes': fake.text(),
    }
   gift_item = GiftItem.objects.create(**payload)
   return gift_item


import itertools

from . import util
from . import calc_stl

ut = util.UTIL()
cs = calc_stl.Calc_STL()

class GEN_STL_ASCII():

    def pt2stl_vec(self, vector):
        return "facet normal " + str(vector[0]) + " " + str(vector[1]) + " " + str(vector[2])

    def pt2stl_pt(self, point):
        return "vertex " + str(point[0]) + " " + str(point[1]) + " " + str(point[2])

    def format_stl(self, meshes):
        formated = []

        header = "solid nameee"
        formated.append(header)

        for flatten in range(len(meshes)):
            formated.append(meshes[flatten])

        footer = "endsolid nameee"
        formated.append(footer)

        return formated

    def stl_3pt(self, pt3):

        stl = []

        ### calc normal vector
        va = cs.face_normal(pt3)

        stl.append(self.pt2stl_vec(va))
        stl.append("outer loop")
        stl.append(self.pt2stl_pt(pt3[0]))
        stl.append(self.pt2stl_pt(pt3[1]))
        stl.append(self.pt2stl_pt(pt3[2]))
        stl.append("endloop")
        stl.append("endfacet")

        return stl

    def gen_stl_ascii(self, pt3_list, export_path):

        meshes = []

        for num in range(len(pt3_list)):

            # print(num)

            m = self.stl_3pt(pt3_list[num])
            meshes.append(m)

        ### Flatten
        meshes = list(itertools.chain.from_iterable(meshes))
        # print(meshes)

        export = self.format_stl(meshes)

        ### Export File
        with open(export_path, mode='w') as f:
            f.write('\n'.join(export))

        print("Export (Ascii) : {}".format(export_path))


import os
import argparse
import cv2

import image_processing
import dataset_handler

overwrite = False

def test():

	mypath = "d:\\Diplomamunka\\CNN-1\\working_dir\\"
	f = []
	for (dirpath, dirnames, filenames) in os.walk(mypath):

		print(dirpath, dirnames)

def main():

	if False:
		parser = argparse.ArgumentParser(description='Recursive normalizer.')
		parser.add_argument('csv_in', metavar='csv_in', type=str)
		#parser.add_argument('dir_out', metavar='dir_out', type=str)

		args = parser.parse_args()

		csv_in = args.csv_in
		#dir_out = args.dir_out
	else:
		csv_in = "d:\\Diplomamunka\\CNN-1\\working_dir\\jura\\11.10\\Bpas-Verdict.csv"
	#print(dir_in, dir_out)

	#if not os.path.isfile(csv_in) or not os.path.isdir(dir_out):
	if not os.path.isfile(csv_in):
		print(csv_in, " does not exist")
		raise AssertionError

	#if dir_in == dir_out:
	#	raise Exception

	#corners_list = []
	input_list = dataset_handler.read_full_input(csv_in, zip_results=True)

	for entry in input_list:
		path, _, corners = entry

		name = os.path.basename(path)
		dir = os.path.dirname(path)

		if len(corners) == 0:
			print(path, " skipped: no corner info")
			continue

		new_name = "normalized_" + name
		new_path = dir + "\\" + new_name

		in_image = cv2.imread(path)
		result = image_processing.normalize_image(in_image, corners)
		if not os.path.exists(new_path) or overwrite:
			cv2.imwrite(new_path, result)
			print(path, "->", new_name , " done")
		else:
			print(new_path, "already exists")

		pass

	return

if __name__ == "__main__":

	try:
		main()
	except AssertionError:
		print("Task failed")


from selenium import webdriver
from .base import FunctionalTest
from .list_page import ListPage
from .my_lists_page import MyListsPage

def quit_if_possible(browser):
    try: browser.quit()
    except: pass

class SharingTest(FunctionalTest):

    def test_can_share_list_with_another_user(self):
        # Carl is a logged-in user
        self.create_pre_authenticated_session('carl@abv.bg')
        carl_browser = self.browser
        self.addCleanup(lambda: quit_if_possible(carl_browser))

        # his friend Lucifer is also hanging out
        luci_browser = webdriver.Firefox()
        self.addCleanup(lambda: quit_if_possible(luci_browser))
        self.browser = luci_browser
        self.create_pre_authenticated_session('luci')

        # carl goes to the home page and starts a list
        self.browser = carl_browser
        self.browser.get(self.live_server_url)
        list_page = ListPage(self).add_list_item('Pray')

        # He notices a share this list button
        share_box = list_page.get_share_box()
        self.assertEqual(
            share_box.get_attribute('placeholder'),
            'your-friend@example.com'
        )

        # the page updates to say that the list has been shared wiwth luci
        list_page.share_list_with('luci')

        # Lucifer goes to the list page
        self.browser = luci_browser
        MyListPage(self).go_to_my_lists_page()

        # He sees Carl's list in there! WTF?
        self.browser.find_element_by_link_text('Pray').click()

        # On the list page, Lucifer can see that it's Carl's list
        self.wait_for(lambda: self.assertEqual(
            list_page.get_list_owner(),
            'carl@abv.bg'
        ))

        # He adds an item to the list
        list_page.add_list_item('To the devil!')

        # When Carl refreshes the page, he sees Lucifer's message
        self.browser = carl_browser
        self.browser.refresh()
        list_page.wait_for_row_in_list_table('To the devil!', 2)


import time
import sys

from six.moves import _thread
from simpbot import envvars
from simpbot import __version__

def ascii(start='#'):
    head = ''
    head += '{0}  ____  _  __    _______  ____   ______________\n'
    head += '{0} / ___|(_)|  \  /   ___ \| __ \ / _ \___   ___/\n'
    head += '{0} | |__ | ||   \/   |___||||__||| / \ |  | |\n'
    head += '{0} \___ \| || |\  /|  ____/| __ || | | |  | |\n'
    head += '{0} ___| || || | \/ | |     ||__||| \_/ |  | |\n'
    head += '{0}/____ /|_|| |    |_|     |____/ \___/   |_|\n'
    head += '{0}    Copyright 2016-2017, Ismael Lugo (kwargs)    v{1}\n'
    return head.format(start, __version__)

def debug(level, daemon=envvars.daemon):
    #kw = {'level': level, 'format': '%(name)s - %(levelname)s: %(message)s'}
    kw = {
        'level': level,
        'format': '%(levelname)s: %(message)s',

        # shut up excepthook!
        'stream': sys.stdout
    }
    if daemon is True:
        kw['filename'] = envvars.logs.join(time.strftime('%d%m%Y.log'))
        kw['filemode'] = 'a'
    import logging
    logging.basicConfig(**kw)

def invalid_section(conf, section, options):
    status = False
    if conf.has_section(section):
        s = 0
        t = len(options)
        for option in options:
            if conf.has_option(section, option):
                s += 1
        if s != t:
            status = True
    else:
        status = True
    return status

def temp(dtime):
    return float('%.2f' % (time.time() - dtime))

def major(dtime, secs):
    return temp(dtime) > secs

def minor(dtime, secs):
    return temp(dtime) < secs

def thread(func):
    def start_thread(*args, **kwargs):
        _thread.start_new(func, args, kwargs)
    return start_thread

_getattr = getattr
def getattr(obj, attr):
    if '.' in attr:
        a, b = attr.split('.', 1)
        obj = _getattr(obj, a)
        return getattr(obj, b)
    return _getattr(obj, attr)


import cv2
import argparse

parse = argparse.ArgumentParser()

parse.add_argument("img_input", help="read one image")
parse.add_argument("img_output", help="save the processed image")

args = vars(parse.parse_args())

img = cv2.imread(args["img_input"])

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cv2.imwrite(args["img_output"], img_gray)

cv2.imshow("original image", img)
cv2.imshow("gray image", img_gray)

cv2.waitKey(0)
cv2.destroyAllWindows()


import logging

import openai

import UsersHandler
from RequestResponseContainer import RequestResponseContainer

class DALLEModule:
    def __init__(self, config: dict, messages: dict, users_handler: UsersHandler.UsersHandler) -> None:
        self.config = config
        self.messages = messages
        self.users_handler = users_handler

        self._enabled = False
        self._restart_attempts = 0
        self._proxy = None

    def initialize(self) -> None:
        """
        Initializes DALL-E official API
        :return:
        """
        try:
            # Set enabled status
            self._enabled = self.config["modules"]["dalle"]
            if not self._enabled:
                logging.warning("DALL-E module disabled in config file!")
                return

            # Set Key
            openai.api_key = self.config["dalle"]["open_ai_api_key"]

            # Proxy for DALL-E
            proxy = self.config["dalle"]["proxy"]
            if proxy and len(proxy) > 1 and proxy.strip().lower() != "auto":
                self._proxy = proxy
                openai.proxy = proxy
            else:
                self._proxy = None

            # Done?
            logging.info("DALL-E module initialized")

        # Error
        except Exception as e:
            logging.error("Error initializing DALL-E module!", exc_info=e)
            self._enabled = False

    def set_proxy(self, proxy: str) -> None:
        """
        Sets new proxy from ProxyAutomation
        self.config["dalle"]["proxy"] must be "auto"
        :param proxy: https proxy but in format http://IP:PORT
        :return:
        """
        if self.config["dalle"]["proxy"].strip().lower() != "auto":
            return

        logging.info("Setting proxy {0} for DALL-E module".format(proxy))
        self._proxy = proxy
        openai.proxy = proxy

    def process_request(self, request_response: RequestResponseContainer) -> None:
        """
        Processes request to DALL-E
        :param request_response: RequestResponseContainer object
        :return:
        """
        # Check if we are initialized
        if not self._enabled:
            logging.error("DALL-E module not initialized!")
            request_response.response = self.messages["response_error"].replace("\\n", "\n") \
                .format("DALL-E module not initialized!")
            request_response.error = True
            return

        try:
            # Increment requests_total for statistics
            request_response.user["requests_total"] += 1
            self.users_handler.save_user(request_response.user)

            # Set Key
            openai.api_key = self.config["dalle"]["open_ai_api_key"]

            # Generate image
            logging.info("Requesting image from DALL-E")
            image_response = openai.Image.create(prompt=request_response.request,
                                                 n=1,
                                                 size=self.config["dalle"]["image_size"])
            response_url = image_response["data"][0]["url"]

            # Check response
            if not response_url or len(response_url) < 1:
                raise Exception("Wrong DALL-E response!")

            # OK?
            logging.info("Response successfully processed for user {0} ({1})"
                         .format(request_response.user["user_name"], request_response.user["user_id"]))
            request_response.response = response_url

        # Exit requested
        except KeyboardInterrupt:
            logging.warning("KeyboardInterrupt @ process_request")
            return

        # DALL-E or other error
        except Exception as e:
            logging.error("Error processing request!", exc_info=e)

            # Try to restart
            self.restart()
            self._restart_attempts += 1

            # Try again 1 time
            if self._restart_attempts < 2:
                self.process_request(request_response)

            # Stop restarting and respond with error
            else:
                request_response.response = self.messages["response_error"].replace("\\n", "\n").format(str(e))
                request_response.error = True
                self._restart_attempts = 0

    def restart(self):
        """
        Restarts module and saves proxy
        :return:
        """
        if not self.config["modules"]["dalle"]:
            return
        logging.info("Restarting DALL-E module")

        # Restart
        self.initialize()

        # Set proxy
        try:
            if self._proxy is not None:
                openai.proxy = self._proxy
        except Exception as e:
            logging.error("Error setting back proxy to DALL-E module!", exc_info=e)


import os

import keras
import numpy as np
from keras.utils import to_categorical

def read_labels_file(file_path: str) -> np.array:
    """Reads the labels from the csv file and returns it as an array

    :param file_path: path to the csv file containing the labels to the files in the dataset
    :return: labels as a numpy array
    """
    with open(file_path, 'r') as f:
        f.readline()
        vals = f.readlines()

    data = np.empty(shape=(len(vals), 1), dtype=np.float32)

    for val in vals:
        val_split = val.split(",")
        data[int(val_split[0])] = int(val_split[1])

    return data

def getmean(max_seq_len):
    mean = np.genfromtxt('mean.csv', delimiter=',')
    if len(mean) < max_seq_len:
        mean = np.array([mean,]*max_seq_len)
    return mean

def getmax(max_seq_len):
    max_arr = np.genfromtxt('max.csv', delimiter=',')
    if len(max_arr) < max_seq_len:
        max_arr = np.array([max_arr,]*max_seq_len)
        max_arr = max_arr.reshape(max_seq_len,102,1)
    return max_arr

def getstddev(max_seq_len):
    stddev = np.genfromtxt('mean.csv', delimiter=',')
    # f = open('stddev.csv', 'r')
    # for line in f:
    #     stddev.append(line)
    # f.close()
    if len(stddev) < max_seq_len:
        stddev = np.array([stddev, ] * max_seq_len)
    return stddev

class DataGenerator(keras.utils.Sequence):
    """Iterator can be used to iterate the dataset given for CS5242

    Attributes
    ----------
        max_seq_len : int
            max length of each sample in the dataset
        batch_size : int
            number of samples in each batch of training
        folder : str
            name of the folder containing the files, all the files are assumed to be in .npy format
        shuffle : bool
            this is to enable shuffle of the indices for each epoch
        file_ids : [int]
            array containing the names of all the files in the dataset excluding the .npy extension
        indexes : [int]
            copy of the file_ids array, but used for shuffling the indexes if shuffle enabled and used for slicing the batch
        labels : np.array(np.float32)
            contains the label for each file with indices corresponding to the file id from the file_ids or indexes list

    Usage
    -----
        train = DatasetGenerator('train/train', 'train_kaggle.csv')

    """

    def __init__(self, data_folder='', labels_file='', batch_size=32, max_seq_len=1000, shuffle=True):
        """Constructor to initialize the iterator

        :param data_folder: folder containing the data files; in our case the path to the folder containing the .npy files
        :param labels_file: path to the csv containing the labels to the training samples
        :param batch_size: number of samples in each batch
        :param max_seq_len: max len of each sample
        :param shuffle: whether to shuffle or not on each epoch
        """
        self.max_seq_len = max_seq_len
        self.batch_size = batch_size
        self.folder = data_folder
        self.shuffle = shuffle
        self.file_ids = np.array([int(file_name.split(".")[0]) for file_name in os.listdir(self.folder)])
        self.indexes = np.copy(self.file_ids)
        self.labels = read_labels_file(labels_file)
        self.on_epoch_end()

    def __len__(self) -> int:
        """Denotes the number of batches per epoch

        :return: batches per epoch
        """
        return int(np.floor(len(self.file_ids) / self.batch_size))

    def __getitem__(self, index: int) -> (np.array, np.array):
        """Returns each batch of samples

        :param index: based on the __len__ function this function is called with the index of the batch of samples to be sent
        :return: tuple of the X and the Y for the batch in the dataset
        """

        indexes = self.indexes[index * self.batch_size:(index + 1) * self.batch_size]

        Xin = np.empty(shape=(self.batch_size, 102, self.max_seq_len))
        X = np.empty(shape=(self.batch_size, self.max_seq_len, 102))
        y = np.zeros(shape=(self.batch_size, 1))
        # y_cat = np.zeros(shape=(self.batch_size, 2))
        mean = getmean(self.max_seq_len)
        stddev = getstddev(self.max_seq_len)
        max_arr = getmax(self.max_seq_len).reshape(self.max_seq_len, 102)

        for idx, id in enumerate(indexes):
            # get X data for each file
            data_x = np.load(os.path.join(self.folder, str(id)+".npy"))
            if len(data_x) < self.max_seq_len:
                X[idx] = (np.append(data_x, np.zeros(shape=(self.max_seq_len - len(data_x), 102)), axis=0)).reshape(self.max_seq_len, 102)
            else:
                X[idx] = data_x.reshape(self.max_seq_len, 102)
            # X[idx] = np.nan_to_num((X[idx]-mean)/stddev)
            # X[idx] = X[idx]/max_arr
            # X[idx] = X[idx].reshape(1000, 102)
            # Xin[idx] = np.transpose(X[idx], (1,0,2))
            # X[idx]= np.transpose(X[idx], (1,0))

            # add y for each file
            y[idx] = (self.labels[id])
            # y_cat += to_categorical(y)
        # X = np.squeeze(X)
        # X[idx] = X[idx].reshape(1000, 102, 1)
        # X = np.transpose(X, axes=(0,2,1,3))

        # print(y_cat)
        return X, y

    def on_epoch_end(self):
        """Called at the end of each epoch to shuffle the elements in the next batch"""
        if self.shuffle:
            np.random.shuffle(self.indexes)

if __name__ == '__main__':
    train = DataGenerator('train/train', 'train_kaggle.csv')
    # print(train[0][1].shape)
#
# def compute_mean_and_stddev():
#     sum_x = np.zeros(102)
#     sum_x2 = np.zeros(102)
#     mean = np.zeros(102)
#     stddev = np.zeros(102)
#     length = 0
#     for id in range(len(os.listdir('train/train'))):
#         data_x = np.load(os.path.join('train/train', str(id) + ".npy"))
#         length = length + len(data_x)
#         for tuple in range(len(data_x)):
#             sum_x = np.add(sum_x, data_x[tuple])
#             sum_x2 = np.add(sum_x2, np.square(tuple))
#         data_x =[]
#
#     mean = np.divide(sum_x, length)
#     stddev = np.sqrt(np.divide(sum_x2, length) - np.square(mean))
#     return mean, stddev
    # print(mean)
    # print(stddev)
    # for j in range (102):
    #     sum_x = sum_x +


from sklearn.datasets import fetch_olivetti_faces
import datetime

# Load the dataset
faces = fetch_olivetti_faces()

# Prove that the dataset was loaded
# print(faces.data.shape)

# Only instance methods can access instance attributes.
# Instance methods are associated with a particular object

class Person:
    # instance attributes
    def __init__(self, name, photo, date_of_birth):
        self.name = name
        self.photo = photo
        self.date_of_birth = date_of_birth

    # instance method
    def get_age(self):
        return int((datetime.datetime.now() - self.date_of_birth).days / 365.25)

    # overriding __str__ built in class method
    def __str__(self):
        return self.name + ', age ' + str(self.get_age())

aPerson = Person("Robert", faces.images[0], datetime.datetime(1998, 10, 21))
print(aPerson.name)

print(str(aPerson.get_age()))

print(str(aPerson))
print(aPerson.__str__())
print(aPerson)

# Inheritance
class MissingPerson(Person):
    def __init__(self, name, photo, date_of_birth, date_missing):
       # construct the base object
       Person.__init__(self, name, photo, date_of_birth)

       # Add missing_date attribute
       self.date_missing = date_missing

    #Add get_years_missing() method
    def get_years_missing(self):
        return int((datetime.datetime.now() - self.date_missing).days / 365.25)

missing_person = MissingPerson('Louis', faces.images[1], datetime.datetime(2000, 5, 7), datetime.datetime(2017, 10, 31))
# print(str(missing_person.date_missing))
# print(str(missing_person.get_years_missing()))
print(missing_person.name + ' has been missing for ' + str(missing_person.get_years_missing()) + ' years')

class MissingSKPerson(MissingPerson):
    def __init__(self, name, photo, date_of_birth, date_missing):
        MissingPerson.__init__(self, name, photo, date_of_birth, date_missing)

    # override the get_age() method
    def get_age(self):
        return super().get_age() + 1

name = 'Jung'
faceP = faces.images[2]
birth = datetime.datetime(1994, 7, 1)
missing = datetime.datetime(2017, 8, 30)

skPerson = MissingSKPerson(name, faceP, birth, missing)
print(skPerson.get_age())

date_birth = datetime.datetime(1990, 9, 16)
date_missing = datetime.datetime(2016, 1, 1)
face = faces.images[0]
name = "Adam"

# Creating Person, MissingPerson & SKMissingPerson objects
aPerson = Person(name, face, date_birth)
print(str(aPerson.get_age()))

aMPerson = MissingPerson(name, face, date_birth, date_missing)
print(str(aPerson.get_age()))

aSKPerson = MissingSKPerson(name, face, date_birth, date_missing)
print(str(aPerson.get_age()))

# Remove an inherited attribute
class AnonymousPerson(Person):
    def __init__(self, photo, date_of_birth):
        Person.__init__(self, '', photo, date_of_birth)
        delattr(self, 'name')

# This cause a runtime error, we can't delete methods
# that are inherited from a base class
# However we can override them and change the way they work
anonymousPerson = AnonymousPerson(faces.images[4], datetime.datetime(1994, 6, 6))
print(str(anonymousPerson))


from typing import List, Tuple, Optional

from collections import defaultdict,deque
from functools import cache
import heapq
from sortedcontainers import SortedDict,SortedList

class Solution:
    def findCrossingTime(self, n: int, k: int, time: List[List[int]]) -> int:
        stLeft, stRight=[],[]
        for i,(l1,p1,l2,p2) in enumerate(time):
            heapq.heappush(stLeft,(-(l1+l2),-i))
        cntRight = 0
        lastTime = 0
        leftWait,rightWait =[],[]
        leftCnt =0
        while cntRight < n :

            while leftWait and leftWait[0][0] <= lastTime:
                a,b,c = heapq.heappop(leftWait)
                heapq.heappush(stLeft,(b,c))
            while rightWait and rightWait[0][0] <= lastTime:
                a,b,c = heapq.heappop(rightWait)
                heapq.heappush(stRight,(b,c))
            if len(stLeft) == len(stRight) == 0:
                if leftWait and rightWait and len(rightWait) + cntRight <n:
                    lastTime = min(leftWait[0][0],rightWait[0][0])
                elif leftWait:
                    lastTime =leftWait[0][0]
                else:
                    lastTime = rightWait[0][0]
            if leftCnt == n and len(stRight) ==0 and len(rightWait)>0:
                lastTime = rightWait[0][0]
            #print(lastTime,stRight,stLeft,leftWait,rightWait,cntRight)
            while leftWait and leftWait[0][0] <= lastTime:
                a,b,c = heapq.heappop(leftWait)
                heapq.heappush(stLeft,(b,c))
            while rightWait and rightWait[0][0] <= lastTime:
                a,b,c = heapq.heappop(rightWait)
                heapq.heappush(stRight,(b,c))
            if stRight:
                b,c = heapq.heappop(stRight)
                cntRight +=1
                lastTime += time[-c][2]
                if leftCnt <n:
                    heapq.heappush(leftWait,(lastTime + time[-c][3],b,c))
            else :
                if leftCnt <n:
                    b,c = heapq.heappop(stLeft)
                    lastTime  += time[-c][0]
                    heapq.heappush(rightWait,(lastTime +time[-c][1],b,c))
                    leftCnt +=1
        return lastTime

#re =Solution().findCrossingTime(n = 3, k = 2, time = [[1,9,1,8],[10,10,10,10]])
#re = Solution().findCrossingTime(10,6,[[2,10,5,8],[3,5,2,2],[5,8,10,10],[7,8,8,5],[5,6,6,10],[6,10,6,2]])
re = Solution().findCrossingTime(9,6,[[2,6,9,4],[4,8,7,5],[4,6,7,6],[2,3,3,7],[9,3,6,8],[2,8,8,4]])
print(re)


import linecache
import os
from time import sleep

this_path = os.path.dirname(__file__)
first_elc_lines = "FF\n02\n5A\nE2\n35\nF5\n04\n"

def get_bv_files() -> list:
    """ Получает список полных путей исходных фафйлов с базой ключей МК2012 из папки <2012> """
    mkf_path = this_path+"/2012/"
    list_2012_dir = os.listdir(mkf_path)
    mkf_lst = []
    for elem in list_2012_dir:
        if os.path.splitext(elem)[-1] == ".mkf":
            mkf_lst.append(mkf_path + elem)

    return mkf_lst

def create_key_dict(bv_path: str) -> dict:
    """ Принимает файл базы ключей MK2012. Возвращает словарь с ключами"""
    key_dict = {}
    key_code = ''
    key_code_last = 'none'
    first_line = 8193
    last_line = first_line + 3

    """
    получаем список ключей.
    сравниваем последний полученный ключ из файла с предпоследним.
    Если они совпадают значит пошли пустые ячейки в памяти
    """
    while key_code != key_code_last:
        key_code_last = key_code
        key_code = ''
        # Перебераем
        while first_line <= last_line:
            ln_read = linecache.getline(bv_path, first_line)
            key_code = key_code + ln_read
            first_line += 1

        key_dict.update({key_code: None})
        # обновляем значения линий для следующего ключа
        first_line = first_line + 4
        last_line = last_line + 8

    return key_dict

if __name__ == "__main__":
    mkf_list = get_bv_files()
    key_dict = {}
    for elem in mkf_list:
        new_dict = create_key_dict(elem)
        key_dict.update(new_dict)

    # КОСТЫЛЬ удаляем пустой ключ
    key_dict.pop("FF\nFF\nFF\nFF\n")

    if len(key_dict) > 5000:
        print(f"Ключей больше чем 5000.\nСоздать файл для ELC5000 невозможно.\n"
              f"Завершение работы программы через 20сек.")
        sleep(20)
        exit()

    print(f"Всего ключей для записи: {len(key_dict)}")

    # ПИШИМ КЛЮЧИ В ФАЙЛ
    writeFile = open('elc-new.mkf', 'w')  # открываем файл на запись
    writeFile.write(first_elc_lines)  # пишем в файл 7 служебных строк ELC5000

    for elem in key_dict:  # пишем в файл список ключей
        writeFile.write('01\n' + elem + '01\n')

    # пишем в файл пустые строки до служебной записи с кол-вом ключей
    ffLn = 30018 - 7 - len(key_dict) * 6
    writeFile.write(ffLn * 'FF\n')

    # ДОБОВЛЯЕМ СЛУЖЕБНУЮ ЗАПИСЬ О КОЛ-ВЕ КЛЮЧЕЙ
    # конвертируем кол-во ключей в шестнадцатеричное число, состоящее из 4-х символов
    key_to_hex = "{0:x}".format(len(key_dict) + 1)  # переводим в 16-ричное //кол-во ключей + 1шт.(так нужно для ELC5000)
    key_len_hex = len(key_to_hex)  # узнаём кол-во символов
    hexList = ['', '000', '00', '0', '']  # список с недостающими символами
    hex4simbol = hexList[key_len_hex] + key_to_hex  # делаем число из 4-х символов
    hex_amount = hex4simbol[0:2] + '\n' + hex4simbol[2:4] + '\n'  # итоговое число для файла
    writeFile.write(hex_amount)  # пишем итоговое число в файл

    writeFile.write('FF\n' * 2748)  # добиваем файл пустотой

    writeFile.close()  # закрываем файл

    print("Создан файл <elc-new.mkf>\n\n")
    print("Записывать через метакомовскую прогу MKA\nНастройки:\n"
          "Модель домофона: Неизвестный домофон\nТип носителя: 24CXX\nОбъём памяти: С256\n\n"
          "Окно автоматически закроется через минуту")
    sleep(60)


from requests_html import HTMLSession
from funcy import print_durations
from selenium import webdriver
import lxml.html
import csv
import os

options = webdriver.ChromeOptions()
options.add_argument(
    'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
    (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36')
options.add_argument('accept=accept: ')
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('--headless')
driver = webdriver.Chrome(
    executable_path=os.path.join('chromedriver', 'chromedriver.exe'),
    options=options
)
driver.set_window_size(1980, 2000)

def get_name_and_city_from_file():  # Open file with company names
    try:
        with open('Sample_Web_Scrapping.csv', 'r', newline='') as csv_read:
            reader = csv.DictReader(csv_read)
            company_name = []
            company_city = []
            for row in reader:
                company_name.append(row['CompanyName'])
                company_city.append(row['CompanyCity'])
            return company_name, company_city
    except Exception as e:
        print(e)
        print("Can't read the file. Try rename it like 'Sample_Web_Scrapping.csv'")

def create_name_for_search_links():  # Change names to insert into a link
    name_list = get_name_and_city_from_file()[0]
    name_list_for_search = []
    for name in name_list:
        if '&' in name:
            name = name.replace('&', '%26')
        if '\'' in name:
            name = name.replace('\'', '%27')
        if ';' in name:
            name = name.replace(';', '')
        if ' ' in name:
            name = name.replace(' ', '%20')
        if ',' in name:
            name = name.replace(',', '%2C')
        name_list_for_search.append(name)
    return name_list_for_search

def create_search_links():  # Create search links :)
    print('==========================')
    print('Creating links for search')
    print('==========================')
    name_list_for_search = create_name_for_search_links()
    links_list = []
    for i in range(len(name_list_for_search)):
        link = f'https://www.dnb.com/business-directory/company-search.html?term={name_list_for_search[i]}&page=1'
        links_list.append(link)
    return links_list

# def save_search_links():  # Save search links into a file (not necessary)
#     try:
#         links_list = create_search_links()
#         with open('search_links_list.csv', 'a', encoding='utf-8', newline='') as links_csv:
#             writer = csv.writer(links_csv)
#             for link in links_list:
#                 writer.writerow([link])
#     except Exception as e:
#         print(e)
#         print('File writing error')

# def save_links_list(company_link):  # Save links list into a file (not necessary)
#     try:
#         with open('links_list.csv', 'a', encoding='utf-8', newline='') as links_csv:
#             writer = csv.writer(links_csv)
#             writer.writerow([company_link])
#     except Exception as e:
#         print(e)
#         print('File writing error')

def save_result(row):
    with open('result.csv', 'a', encoding='utf-8', newline='') as links_csv:
        writer = csv.writer(links_csv, delimiter=';')
        writer.writerow(row)

def parse_company_page_requests(company_link): # Use requests-html and lxml (higher speed)
    session = HTMLSession()
    try:
        r = session.get(company_link)
        r.html.render(sleep=1, keep_page=True)
        tree = lxml.html.document_fromstring(r.text)
        try:
            title = (tree.xpath('//*[@id="content"]/div[2]/div/div[3]/div/div/div[1]/div/div/div/h2/text()')[0]).strip()
        except:
            title = ' '
        try:
            website = (tree.xpath('//*[@id="hero-company-link"]/text()')[0]).strip()
        except:
            website = ' '
        try:
            street_address_1 = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[1]/div/text()')[
                0]).strip()
        except:
            street_address_1 = ' '
        try:
            company_city = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[1]/text()')[
                0]).strip()
        except:
            company_city = ' '
        try:
            company_region = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[2]/text()')[
                0]).strip()
        except:
            company_region = ' '
        try:
            company_postal = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[3]/text()')[
                0]).strip()
        except:
            company_postal = ' '
        try:
            company_country = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[4]/text()')[
                0]).strip()
        except:
            company_country = ' '
        try:
            address = (street_address_1 + ',' + company_city + ',' + company_region + ',' + company_postal + ',' + company_country).strip()
        except:
            address = ' '
        try:
            phone = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[3]/div[2]/div/span/text()')[
                0]).strip()
        except:
            raise Exception
            # phone = ' '
        try:
            description = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[4]/div[2]/div/div/span/text()')[
                0]).strip()
        except:
            description = ' '
        try:
            key_principal = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[5]/div[2]/div/div/span[1]/text()')[
                0]).strip()
        except:
            key_principal = ' '
        try:
            industry = (tree.xpath(
                '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[6]/div[2]/div/span[1]/a/text()')[
                0]).strip()
        except:
            industry = ' '

        save_result([title, website, address, phone, description, key_principal, industry])
    except Exception as e:
        print('phone number not found', e)

def company_search():  # Company search
    company_city = get_name_and_city_from_file()[1]
    company_search_links_list = create_search_links()
    len_of_list = len(company_search_links_list)
    for a in range(len_of_list):
        company_city_match = company_city[a].lower()
        try:
            driver.get(company_search_links_list[a])
            driver.implicitly_wait(10)
            print('Company №', a + 1, 'of', len_of_list)
            results_amount = len(driver.find_elements_by_class_name('search_result'))
            if results_amount == 1:
                city = driver.find_element_by_xpath('//*[@id="company_results"]/ul/li/div[4]/div/span[1]').text
                city = city.lower()
                if city == company_city_match:
                    company_link = driver.find_element_by_xpath(
                        '//*[@id="company_results"]/ul/li/div[1]/div[1]/a').get_attribute('href')
                    parse_company_page_requests(company_link)
            elif results_amount > 1:
                for i in range(1, results_amount):
                    if i == 11 or i == 22:
                        continue
                    else:
                        city = driver.find_element_by_xpath(
                            f'//*[@id="company_results"]/ul/li[{i}]/div[4]/div/span[1]').text
                        city = city.lower()
                        if city == company_city_match:
                            company_link = driver.find_element_by_xpath(
                                f'//*[@id="company_results"]/ul/li[{i}]/div[1]/div[1]/a').get_attribute('href')
                            parse_company_page_requests(company_link)
            else:
                raise Exception
        except Exception as e:
            print('company not found', e)
    driver.close()
    driver.quit()

# def read_links_list_from_file():  # Open file with company links (not necessary)
#     try:
#         with open('links_list.csv', 'r', newline='') as csv_read:
#             reader = csv.reader(csv_read)
#             company_links = []
#             for row in reader:
#                 company_links.append(row)
#             return company_links
#     except Exception as e:
#         print(e)
#         print("Can't read the file 'links_list.csv'")

# def parse_company_page_selenium(): # Use Selenium webdriver (lower speed) (not necessary)
#     links_list = read_links_list_from_file()
#     len_links_list = len(links_list)
#     for i in range(len_links_list):
#         print('Page №', i+1, 'of', len_links_list)
#         try:
#             driver.get(links_list[i][0])
#             driver.implicitly_wait(3)
#             try:
#                 title = driver.find_element_by_class_name('profile_header_title').text
#             except:
#                 title = ' '
#             try:
#                 website = driver.find_element_by_id('hero-company-link').get_attribute('href')
#             except:
#                 website = ' '
#             try:
#                 street_address_1 = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[1]/div').text
#             except:
#                 street_address_1 = ' '
#             try:
#                 company_city = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[1]').text
#             except:
#                 company_city = ' '
#             try:
#                 company_region = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[2]').text
#             except:
#                 company_region = ' '
#             try:
#                 company_postal = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[3]').text
#             except:
#                 company_postal = ' '
#             try:
#                 company_country = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[2]/div/div/span/div[2]/span[4]').text
#             except:
#                 company_country = ' '
#             try:
#                 address = street_address_1 + ',' + company_city + ',' + company_region + ',' + company_postal + ',' + company_country
#             except:
#                 address = ' '
#             try:
#                 phone = driver.find_element_by_class_name('profile-phone-element').text
#             except:
#                 phone = ' '
#             try:
#                 description = driver.find_element_by_xpath(
#                     '/html/body/div[1]/div[3]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[4]/div[2]/div/div/span').text
#             except:
#                 description = ' '
#             try:
#                 key_principal = driver.find_element_by_xpath(
#                     '//*[@id="content"]/div[2]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[5]/div[2]/div/div/span[1]').text
#             except:
#                 key_principal = ' '
#             try:
#                 industry = driver.find_element_by_class_name('profile-industry-item').text
#             except:
#                 industry = ' '
#
#             save_result([title, website, address, phone, description, key_principal, industry])
#         except Exception as e:
#             print(e)
#     driver.close()
#     driver.quit()

@print_durations()
def main():
    try:
        company_search()  # Run it to get a file with links to company pages
    except Exception as e:
        print('=====================')
        print(e)
        print('=====================')
        print('Something went wrong. Save the message above and contact your programmer.')
        print('=====================')
    finally:
        print('=====================')
        print('The program has completed its work.')
        print('You can check the file "result.csv"')
        print('=====================')

if __name__ == '__main__':
    main()


from collections import defaultdict
from random import randint

LETRAS = ('B', 'I', 'N', 'G', 'O')

def min_max(letra:str) -> tuple[int]:

    intervalo = {"B": (1, 15), "I": (16, 30), "N": (31, 45), "G": (46, 60), "O": (61, 75)}

    # Retorna o número mínimo e máximo de cada letra
    minimo, maximo = intervalo[letra][0], intervalo[letra][1]
    return minimo, maximo

# Passo número 0:
def gerar() -> defaultdict[str, list[int]]:

    cartela = defaultdict(list)

    for letra in LETRAS:

        # Pegando o número mínimo e máximo de cada letra
        minimo, maximo = min_max(letra)

        while len(cartela[letra]) < 5:
            # Gerando os números aleatórios
            num_aleatorio = randint(minimo, maximo)

            # Verificando se o número já existe na lista
            if num_aleatorio in cartela[letra]:
                continue

            # Coloca os números aleatórios na lista
            cartela[letra].append(num_aleatorio)

            # Ordena em ordem crescente
            cartela[letra].sort()

    return cartela

# Passo número 1:
def imprime(cartela: dict[str, list[int]]) -> None:
    # Formata a cartela para imprimir na tela

    print("B   I   N   G   O")
    print("-" * 20)

    for linha in range(5):

        # Para cada linha, ele imprime os elementos daquela linha na tela
        lista_str = [str(lista[linha]).zfill(2) for lista in cartela.values()]

        #Formata a string para imprimir
        string = ",".join(lista_str)

        print(string)

# Passo número 2:


from quart import Blueprint, jsonify, request, current_app as app
import json
import secrets

from ..common.users import mass_user_update

from ..enums import UserFlags

from ..utils import str_bool, toggle_flag

from litecord.auth import token_check
from litecord.blueprints.checks import guild_perm_check
from litecord.errors import ManualFormError

bp = Blueprint("science", __name__)

try:
    with open("assets/discovery_categories.json", "r") as f:
        DISCOVERY_CATEGORIES = json.load(f)
except (FileNotFoundError, json.JSONDecodeError, UnicodeDecodeError):
    DISCOVERY_CATEGORIES = {}

@bp.route("/science", methods=["POST"])
@bp.route("/track", methods=["POST"])
@bp.route("/metrics", methods=["POST"])
async def science():
    return "", 204

@bp.route("/applications", methods=["GET"])
@bp.route("/teams", methods=["GET"])
@bp.route("/outbound-promotions", methods=["GET"])
async def applications():
    return jsonify([])

@bp.route("/experiments", methods=["GET"])
async def experiments():
    ret = {"assignments": await app.storage.get_experiments()}

    user_id = await token_check(False)
    if not user_id and not request.headers.get("X-Fingerprint"):
        ret[
            "fingerprint"
        ] = f"{app.winter_factory.snowflake()}.{secrets.token_urlsafe(32)}"

    if request.args.get("with_guild_experiments", type=str_bool):
        ret["guild_experiments"] = await app.storage.get_guild_experiments()

    return jsonify(ret)

@bp.route("/discovery/categories", methods=["GET"])
async def get_discovery_categories():
    """Get discovery categories"""
    primary_only = request.args.get("primary_only", False, type=str_bool)
    if primary_only:
        return jsonify([cat for cat in DISCOVERY_CATEGORIES if cat["is_primary"]])
    return jsonify(DISCOVERY_CATEGORIES)

@bp.route("/partners/<int:guild_id>/requirements", methods=["GET"])
async def get_partner_requirements(guild_id: int):
    """Get the requirements for a guild to be a partner."""
    user_id = await token_check()
    await guild_perm_check(user_id, guild_id, "manage_guild")

    data = await app.db.fetchrow(
        """
    SELECT rules_channel_id, mfa_level
    FROM guilds
    WHERE id = $1
    """,
        guild_id,
    )

    # Currently we just always say that a guild is partnerable
    data = {
        "guild_id": str(guild_id),
        "safe_enviroment": True,
        "healthy": True,
        "health_score_pending": False,
        "size": True,
        "nsfw_properties": {},
        "protected": bool(data["mfa_level"]),
        "sufficient": True,
        "sufficient_without_grace_period": True,
        "valid_rules_channel": bool(data["rules_channel_id"]),
        "retention_healthy": True,
        "engagement_healthy": True,
        "age": True,
        "minimum_age": 7,
        "health_score": {
            "avg_nonnew_participators": None,
            "avg_nonnew_communicators": None,
            "num_intentful_joiners": None,
            "perc_ret_w1_intentful": None,
        },
        "minimum_size": 1,
    }
    return jsonify(data)

@bp.route("/partners/apply", methods=["POST"])
async def partners_apply():
    user_id = await token_check()

    try:
        guild_id = int((await request.get_json())["guild_id"])
    except (KeyError, ValueError):
        raise ManualFormError(
            guild_id={
                "code": "BASE_TYPE_REQUIRED",
                "message": "This field is required.",
            }
        )

    await guild_perm_check(user_id, guild_id, "manage_guild")

    features = await app.storage.guild_features(guild_id) or []
    if "PARTNERED" in features:
        return "", 204

    owner_id = await app.db.fetchval(
        """
    SELECT owner_id
    FROM guilds
    WHERE id = $1
    """,
        guild_id,
    )
    user = await app.storage.get_user(owner_id)
    flags = UserFlags.from_int(user["flags"])
    toggle_flag(flags, UserFlags.partner, True)

    await app.db.execute(
        """
    UPDATE users
    SET flags = $1
    WHERE id = $2
    """,
        flags.value,
        user_id,
    )
    await mass_user_update(user_id)

    features.append("PARTNERED")
    features.append("VANITY_URL")
    features.append("INVITE_SPLASH")
    features.append("ANIMATED_ICON")
    features.append("BANNER")

    await app.db.execute(
        """
    UPDATE guilds
    SET features = $1
    WHERE id = $2
    """,
        features,
        guild_id,
    )

    guild = await app.storage.get_guild_full(guild_id, user_id)
    await app.dispatcher.guild.dispatch(guild_id, ("GUILD_UPDATE", guild))

    return "", 204


import argparse
import os
import exifread
from shutil import copy

############# general auxiliary methods #############

"""
Checks if the given file_path leads to a valid file type.

@param String file_path
@return a boolean value	-	True if the file_path is valid
						-	False if it isn't
"""
def validate_file(file_path):
	if os.path.isfile(file_path):
		if file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.cr2')): #Figure out if the user should specify the extensions
			return True
	return False

"""
Defines how command-line arguments should be parsed and creates the desired parser.
@return ArgumentParser parser
"""
def create_parser():
	parser = argparse.ArgumentParser()
	sub_parsers = parser.add_subparsers()
	rename_parser = sub_parsers.add_parser('rn')
	rename_parser.set_defaults(which='rn')
	organization_parser = sub_parsers.add_parser('org')
	organization_parser.set_defaults(which='org')

	rename_parser.add_argument('-d', metavar='directory', type=str, action='store', default=os.getcwd(),
									help='Desired directory. If no directory is given, the current directory is used.')
	rename_parser.add_argument('-p', metavar='prefix', type=str, action='store', default='',
									help='Desired prefix.')
	rename_parser.add_argument('-v', metavar='value', type=str, action='store', default='0',
									help='The desired starting value.')

	organization_parser.add_argument('-d', metavar='directory', type=str, action='store', default=os.getcwd(),
											help='Desired directory. If no directory is given, the current directory is used.')
	organization_parser.add_argument('-f', metavar='folder', type=str, action='store',
											help='Name of the main folder where the organized folders will be stored. \
												If no name is provided then the default name will be \'organized_by<organization method>\'')
	organization_parser.add_argument('organization_method', type=str, action='store', choices=['day', 'month', 'year', 'shutter_speed', 'lens', 'aperture', 'ISO', 'focal_length'],
											help='Organize the content by one of the following parameters.')

	return parser

"""
Validates the given arguments.
@param ArgumentParser args
"""
def parse_args(args):
	if args.d:
		if not os.path.isdir(args.d):
			print("Invalid directory - " + args.d)
			exit(1)
		if not args.d.lower().endswith('/'):
			args.d += '/'

	if args.which == 'rn' and args.p:
		try:
			if '/' in args.p:
				raise Exception('Invalid prefix - ' + args.p + '\nThe prefix can\'t contain the following character: \'/\'')
		except Exception as e:
			print(e)
			exit(1)

#####################################################

############# rn - rename related methods #############

"""
Renames the files in the given directory args.d
@param ArgumentParser args
"""
def rename(args):
	i = args.v
	for file in os.listdir(args.d):
		file_path = args.d + file
		if not validate_file(file_path):
			continue
		extension = os.path.splitext(file)[1] #There might be a better way to do this
		new_file_name = args.d + args.p + i + extension
		i = next_value(i)
		try:
			os.rename(file_path, new_file_name)
		except FileExistsError:
			print('A file with the name ' + new_file_name + ' already exists.')

"""
@param String/int value
@return The correspondent adjacent value to value.
"""
def next_value(value):
	if value[0] >= '0' and value[0] <= '9':
		value = int(value) + 1
		return str(value)
	elif value[0] >= 'A' and value[0] <= 'Z':
		return aux(value, ['A', 'Z'])
	else:
		return aux(value, ['a', 'z'])

"""
Auxiliary method to next_value, if the given value is a String
Returns the correspondent adjacent value to value.
@param String value
@param List<String> limit => [lower_limit, upper_limit]
"""
def aux(value, limit):
	if value == '':
		return limit[0]
	if value[-1] == limit[1]:
		return aux(value[:-1], limit) + limit[0]
	else:
		return value[:-1] + chr(ord(value[-1]) + 1)

#######################################################

###########  org - organize related methods  ##########

"""
Specifies which processing method is used depending on the organization method.
@param ArgumentParser args
"""
def organize_data(args):
	if args.organization_method == 'year':
		organize(args, ['DateTimeOriginal', 'EXIF DateTimeOriginal', 1], process_date_time_data)
	elif args.organization_method == 'month':
		organize(args, ['DateTimeOriginal', 'EXIF DateTimeOriginal', 2], process_date_time_data)
	elif args.organization_method == 'day':
		organize(args, ['DateTimeOriginal', 'EXIF DateTimeOriginal', 3], process_date_time_data)
	elif args.organization_method == 'shutter_speed':
		organize(args, ['ExposureTime', 'EXIF ExposureTime'], process_shutter_speed_data)
	elif args.organization_method == 'lens':
		organize(args, ['LensModel', 'EXIF LensModel'], process_lens_model_data)
	elif args.organization_method == 'aperture':
		organize(args, ['FNumber', 'EXIF FNumber'], process_aperture_data)
	elif args.organization_method == 'ISO':
		organize(args, ['ISOSpeedRatings', 'EXIF ISOSpeedRatings'], process_ISO_data)
	elif args.organization_method == 'focal_length':
		organize(args, ['FocalLength', 'EXIF FocalLength'], process_focal_length_data)

"""
@param ArgumentParser args
@param List data_info
@param method process_data
"""
def organize(args, data_info, process_data):
	if not args.f:
		organization_folder = 'organized_by_' + args.organization_method + '/'
	else:
		if not args.f.endswith('/'):
			organization_folder = args.f + '/'
		else:
			organization_folder = args.f

	try:
		os.mkdir(args.d + organization_folder)
	except FileExistsError:
		print('The given file name ' + args.d + organization_folder + ' already exists.')

	for file in os.listdir(args.d):
		file_path = args.d + file
		if not validate_file(file_path):
			continue

		data = get_image_data(file_path, data_info[0], data_info[1])
		if data:
			data = process_data(data, data_info)
		else:
			data = 'Unknown'

		path = args.d + organization_folder + data
		if not os.path.isdir(path):
			os.mkdir(path)

		copy(file_path, path)

"""
Processes the image at the given path.
@param String image_path
@param String stop_tag
@param String data_field
@return String Data from the correspondent data_field
		OR None if the field doesn't exist
"""
def get_image_data(image_path, stop_tag, data_field):
	with open(image_path, 'rb') as image:
		tags = exifread.process_file(image, stop_tag=stop_tag, details=False)
		try:
			return str(tags[data_field])
		#Some images don't contain the desired metadata
		except KeyError:
			return None

def process_date_time_data(data, data_info):
	return '-'.join(data.replace(' ', ':').split(':')[:data_info[2]])

def process_shutter_speed_data(data, data_info):
	return '-'.join(data.split('/')) + 's'

def process_lens_model_data(data, data_info):
	return '-'.join(data.split('/'))

def process_ISO_data(data, data_info):
	return data

def process_focal_length_data(data, data_info):
	return data + 'mm'

def process_aperture_data(data, data_info):
	data = data.split('/')
	if len(data) == 2:
		return str(float(data[0]) / float(data[1]))

	return data[0]

#######################################################

def main():
	parser = create_parser()
	args = parser.parse_args()
	parse_args(args)

	if args.which == 'rn':
		rename(args)
	else:
		organize_data(args)

if __name__ == "__main__":
	main()