import datetime
import logging
import re
from enum import StrEnum, auto
from typing import Self
from xml.etree.ElementTree import XML, Element

from requests import get

SUPPORTED_API_VERSIONS = ["1.2", "1.1", "1.0"]
API_VERSION_PATH = "/user/api"
MENU_PATH = "/user/menu"
VARIABLE_PATH = "/user/var"

TIMESLOT_REGEX_PATTERN = "\\d{2}:\\d{2} - \\d{2}:\\d{2} \\d{1,3}"

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

class EtaObject:
  name: str
  uri: str

  def __init__(self, name: str, uri: str):
    self.name = name
    self.uri = uri

  def __str__(self) -> str:
    return f"{self.name} ({self.uri})"

class VariableType(StrEnum):
  DEFAULT = auto()
  TEXT = auto()
  TIMESLOT = auto()

class Variable(EtaObject):
  adv_text_offset: int
  unit: str
  str_value: str
  scale_factor: int
  dec_places: int
  value: int
  variable_type: VariableType
  writeable: bool

  def __init__(self,
               name: str,
               uri: str,
               variable_type: VariableType = None,
               adv_text_offset: int = 0,
               unit: str = "",
               str_value: str = None,
               scale_factor: int = 1,
               dec_places: int = 0,
               value: int = None):
    super().__init__(name, uri)
    self.adv_text_offset = adv_text_offset
    self.unit = unit
    self.str_value = str_value
    self.scale_factor = scale_factor
    self.dec_places = dec_places
    self.value = value
    self.variable_type = variable_type

    if value is not None and str_value is not None:
      self.last_updated = datetime.datetime.now()
    else:
      self.last_updated = None

  def __str__(self) -> str:
    return (f"{self.name} ({self.uri}): {self.value} (strValue='{self.str_value}', type={self.variable_type}"
            f" unit={self.unit}, scaleFactor={self.scale_factor}, decPlaces={self.dec_places}, advTextOffset={self.adv_text_offset},"
            f" last_updated={self.last_updated})")

  def normalized_value(self) -> float | None:
    """
    Apply scale factor to value.
    :return: The normalized value after applying the scale factor. Or None in case there is no value.
    """
    if self.value is not None:
      return self.value / max(self.scale_factor, 1)
    else:
      return None

class VariableList(EtaObject):
  elements: dict[str, Variable | Self]

  def __init__(self, name: str, uri: str, elements: dict[str, Variable | Self]):
    super().__init__(name, uri)
    self.elements = elements

  def __str__(self) -> str:
    return f"{self.name} ({self.uri}) {self.elements}"

class Eta:
  """
  Represents a connection to you ETA heating system, further communication is done with methods of this class.

  :param host: The dns name or ip of your ETA heating system. Make sure to meet the precondition described in the package README.
  :param hide_io_variables: When enabled, all io interface variables are not included in the api requests. (Defaults to `True`)
  """

  def __init__(self, host: str, hide_io_variables: bool = True):
    self.url = "http://{0}:8080".format(host)
    self.hide_io_variables = hide_io_variables
    self.__check_compatibility()
    logger.info("Initialized ETAtouch REST connection to %s", host)

  def __check_compatibility(self):
    xml = self.__get_version_xml()

    api_element = xml[0]
    if not (api_element.tag.endswith("api") and api_element.attrib["version"] in SUPPORTED_API_VERSIONS):
      logger.error("Error: Not supported api version. Your ETAtouch REST api version is not supported by this library.")
      logger.error("Detected api version: '%s' Supported versions: %s", api_element.attrib["version"], SUPPORTED_API_VERSIONS)
      exit(1)
    logger.info("Detected ETAtouch REST api version: %s", api_element.attrib["version"])

  def get_nodes(self) -> dict[str, VariableList]:
    """
    Retrieves all available device nodes of you ETA heating system.
    The nodes are not filled with data but represent the structure of the available variables.
    :return: A dict with names of the nodes and a node object with nested variables.
    """
    xml = self.__get_menu_xml()
    nodes: dict[str, VariableList] = {}

    node: Element
    for node in xml[0]:
      node_elements = self.__parse_object_list(node)

      nodes[node.attrib["name"]] = VariableList(node.attrib["name"], node.attrib["uri"], node_elements)

    return nodes

  def __parse_object_list(self, root: Element) -> dict[str, Variable | VariableList]:
    elements: dict[str, Variable | VariableList] = {}
    node_object: Element

    uid_blacklist_regexes: list[str] = []

    if self.hide_io_variables:
      uid_blacklist_regexes.append(".*0/0/10...$")

    for node_object in root:

      if len(uid_blacklist_regexes) > 0:
        on_blacklist = False
        for regex in uid_blacklist_regexes:
          if re.search(regex, node_object.attrib["uri"]) is not None:
            on_blacklist = True
            break

        if on_blacklist:
          logger.debug("Skip %s (%s) since on blacklist", node_object.attrib["name"], node_object.attrib["uri"])
          continue

      if len(node_object) > 1:
        elements[node_object.attrib["name"]] = (VariableList(node_object.attrib["name"], node_object.attrib["uri"], self.__parse_object_list(node_object)))
      else:
        elements[node_object.attrib["name"]] = Variable(node_object.attrib["name"], node_object.attrib["uri"])

    return elements

  def update_eta_object(self, element: Variable | VariableList):
    if isinstance(element, Variable):
      logger.debug("Update value of %s (%s)", element.name, element.uri)
      xml = self.__get_variable_xml(element)[0]

      element.adv_text_offset = int(xml.attrib["advTextOffset"])
      element.unit = xml.attrib["unit"]
      element.str_value = xml.attrib["strValue"]
      element.scale_factor = int(xml.attrib["scaleFactor"])
      element.dec_places = int(xml.attrib["decPlaces"])
      element.value = int(float(xml.text))

      if element.adv_text_offset > 0 and len(element.unit) == 0:
        element.variable_type = VariableType.TEXT
      elif re.search(TIMESLOT_REGEX_PATTERN, element.str_value) is not None:
        element.variable_type = VariableType.TIMESLOT
      else:
        element.variable_type = VariableType.DEFAULT

      element.last_updated = datetime.datetime.now()

    elif isinstance(element, VariableList):
      for variable in element.elements.values():
        self.update_eta_object(variable)

  def __get_version_xml(self) -> Element:
    response = get(self.url + API_VERSION_PATH)
    if not response.ok:
      logger.error("Error on communication. (%s, %s) %s", response.status_code, response.url, response.text)
      exit(2)

    return XML(response.text)

  def __get_menu_xml(self) -> Element:
    response = get(self.url + MENU_PATH)
    if not response.ok:
      logger.error("Error on communication. (%s, %s) %s", response.status_code, response.url, response.text)
      exit(2)

    return XML(response.text)

  def __get_variable_xml(self, variable: Variable) -> Element:
    response = get(self.url + VARIABLE_PATH + variable.uri)
    if not response.ok:
      logger.error("Error on communication. (%s, %s) %s", response.status_code, response.url, response.text)
      exit(2)

    return XML(response.text)


from django.shortcuts import render
from django.http import HttpResponse
import random
from django.conf import settings

# Create your views here.
def accueil(request):
	user_gived = ''
	if request.COOKIES.get('my_cookie'):
		user_gived = request.COOKIES['my_cookie']
		response = render(request,'page_accueil.html',{'user_gived' : user_gived})
	else :
		user_gived = random.choice(settings.USER_NAMES)
		response = render(request,'page_accueil.html',{'user_gived' : user_gived})
		response.set_cookie('my_cookie',user_gived,max_age=settings.COOKIE_AGE)
	return(response)
	csrftoken = getCookie('csrftoken')
	console.log(csrftoken)

	# Create your views here.
def inscription(request):
 	response = render(request,'inscription.html')
 	return response

	# Create your views here.
def connexion(request):
	response = render(request,'connexion.html')
	return response


from sys import stdin

def main():
    N, X = map(int, stdin.readline().split())
    *A, = map(int, stdin.readline().split())
    A.sort()

    # if X in A:
    #     print("Yes")
    # else:
    #     print("No")

    def binary_search(x):
        left, right = 0, N-1

        while left <= right:
            mid = (left + right) // 2
            if A[mid] == x:
                return True
            elif A[mid] < x:
                left = mid + 1
            else:
                right = mid - 1
        return False

    print("Yes" if binary_search(X) else "No")

if __name__ == '__main__':
    main()


#!/usr/bin/env python
import roslib

import sys
import rospy
import cv2
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError

import numpy as np

class image_converter:

  def __init__(self):
    cv2.namedWindow("Depth Image", 1)
    self.bridge = CvBridge()
    self.image_sub = rospy.Subscriber("camera/depth_registered/image",Image,self.callback)

  def callback(self,data):
    try:
      depth_image = self.bridge.imgmsg_to_cv2(data, '32FC1')
      depth_array = np.array(depth_image, dtype=np.float32)
      cv2.normalize(depth_array, depth_array, 0, 1, cv2.NORM_MINMAX)
      cv2.imshow("Depth Image",depth_image)
      cv2.imwrite('capture_depth.png',depth_array*255)
    except CvBridgeError as e:
      print(e)

    cv2.waitKey(3)

def main(args):
  ic = image_converter()
  rospy.init_node('image_converter', anonymous=True)
  try:
    rospy.spin()
  except KeyboardInterrupt:
    print("Shutting down")
  cv2.destroyAllWindows()

if __name__ == '__main__':
    main(sys.argv)


from app.models.exports import Kingdom

def test_war_victory_credit(ctx):
    faenoth = Kingdom.query.get(1)
    ecthalion = Kingdom.query.get(2)

    war = faenoth.declare_war_against(ecthalion)

    # test winning as aggressor (auto-win)
    assert faenoth.distribute_war_points(ecthalion, war.aggressor_goal) == True
    assert war.status == war.AGGRESSOR_WON

    # test winning as defender
    war = ecthalion.declare_war_against(faenoth)
    assert faenoth.distribute_war_points(ecthalion, war.defender_goal) == True
    assert war.status == war.DEFENDER_WON


from django.conf.urls import patterns, url
from django.contrib.auth.views import logout
from django.core.urlresolvers import reverse_lazy

from .views import (
    NotificationsListView,
    PortfolioListView,
    TransactionsListView,
    UserDetailView,
    UserProfileCreateView,
    UserProfileDetailView,
    UsersGroupListView,
    UsersListView,
    UserUpdateView,
    login,
)

urlpatterns = patterns('',
    url(r'^login/$', login, name='login'),
    url(r'^logout/$', logout, {'next_page': reverse_lazy('home')}, name='logout'),
    url(r'^create/$', UserProfileCreateView.as_view(), name='create'),
    url(r'^rank/$', UsersListView.as_view(), name='rank'),
    url(r'^groups/(?P<pk>[0-9]+)(/)*$', UsersGroupListView.as_view(), name='groups'),
    url(r'^(?P<pk>[0-9]+)/$', UserDetailView.as_view(), name='user'),  # '/accounts/<pk>/'
    url(r'^(?P<pk>[0-9]+)/zawartoscportfela/$', PortfolioListView.as_view(), name='user_portfolio'),
    url(r'^(?P<pk>[0-9]+)/powiadomieniaowynikach/$', NotificationsListView.as_view(), name='user_notifications'),
    url(r'^(?P<pk>[0-9]+)/historiatransakcji/$', TransactionsListView.as_view(), name='user_transactions'),
    url(r'^user_settings/$', UserUpdateView.as_view(), name='user_settings'),
    url(r'^user_profile/$', UserProfileDetailView.as_view(),
        name='user_profile'),
)


from mock import patch

from iiblib.iib_session import IIBSession

@patch("requests.Session.get")
@patch("requests.Session.post")
@patch("requests.Session.put")
@patch("requests.Session.delete")
def test_iib_session_methods(patched_delete, patched_put, patched_post, patched_get):
    iibs = IIBSession("fake-host")
    iibs.get("fake-end-point")
    iibs.post("fake-end-point")
    iibs.put("fake-end-point")
    iibs.delete("fake-end-point")

    patched_get.assert_called_with(
        "https://fake-host/api/v1/fake-end-point", verify=True
    )
    patched_post.assert_called_with(
        "https://fake-host/api/v1/fake-end-point", verify=True
    )
    patched_put.assert_called_with(
        "https://fake-host/api/v1/fake-end-point", verify=True
    )
    patched_delete.assert_called_with(
        "https://fake-host/api/v1/fake-end-point", verify=True
    )


"""Set up repository."""

import pathlib
from pip.req import parse_requirements
from setuptools import find_packages, setup

REPO_ROOT = pathlib.Path(__file__).parent

with open(REPO_ROOT / "README.md", encoding="utf-8") as f:
    README = f.read()

setup(
    name="data_preparation",
    description="Prepare local electricity usage data for RL simulations",
    long_description=README,
    long_description_content_type="text/markdown",
    author="Flora Charbonnier",
    author_email="flora.charbonnier@eng.ox.ac.uk",
    url="https://github.com/floracharbo/hedge",
    license="GNU Affero General Public License v3.0",
    packages=find_packages(),
    install_requires=parse_requirements('requirements.txt', session='hack'),
    python_requires=">=3.7",
)


import datetime as dt
import warnings
from collections import deque
from datetime import datetime
from logging import getLogger
from time import monotonic, sleep
from typing import Callable

from pydantic import BaseModel
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By

from .browser import Browser, BrowserError
from .humanlike import randsleep, spinner_sleep
from .utils import solve_captcha

class Test(BaseModel):
    """A driving test."""

    date: datetime
    centre: str

class Centre(BaseModel):
    """A centre and optional dates.

    If dates are not supplied, the defaults from the `Driver()` are used.

    Args:
        centre (str): the centre name.
        not_before (datetime): tests must not be before this date. (Default=None)
        not_after (datetime): tests must not be after this date. (Default=None)

    """

    centre: str
    not_before: datetime = None
    not_after: datetime = None

class Driver(BaseModel):
    """A driver seeking a driving test.

    Args:
        licence_number (str): the driver's licence number.
        name (str): the driver's name.
        booking_ref (str): the driver's booking reference.
        centres (list[Centre]): the centres to search.
        not_before (datetime): do not consider tests before this date.
        not_after (datetime): do not consider tests after this date.
        disabled_dates: (list[datetime]): ignore tests on these dates.  (Default=None)
    """

    licence_number: str
    name: str
    booking_ref: str
    centres: list[Centre]
    not_before: datetime
    not_after: datetime
    disabled_dates: list[datetime] = None
    current_test: Test = None
    refresh_urls: dict = None

class ScraperError(Exception):
    pass

class BookingError(ScraperError):
    pass

class LoginError(Exception):
    pass

class Scraper:
    instances = []
    DVSA_OPENS = dt.time(6)
    DVSA_CLOSES = dt.time(23, 30)

    def __init__(
        self,
        browser: Browser,
        drivers: list[Driver],
        notify: Callable = None,
        reserve: bool = True,
        short_notice: bool = True,
        error_period: int = 30,
    ):
        self._browser = browser
        self.notify = notify or print
        i = max(self.instances) + 1 if self.instances else 1
        self.instances.append(i)
        self.name = f"Browser-{i}"
        self._logger = getLogger(self.name)
        self.drivers = drivers
        for driver in self.drivers:
            driver.refresh_urls = {}
        self._logged_in = False
        self.reserve = reserve
        self.short_notice = short_notice
        self.period = 5
        self.error_period = error_period
        self._search_counter = 0
        self.running = True
        """A Scraper which finds tests for us.

        Args:
            browser (Browser): the browser we use to do the scraping.

            drivers (list[Driver]): the drivers to find tests for.

            notify (callable): the function to call when we find something.  If
                               unset we use `print`, so you should set this.
                               Receives one argument, a str. (default=None)

            reserve (bool): whether to reserve a test if we find it. (default=True)

            short_notice (bool): whether to consider short notice tests. (default=True)

            error_period (int): time in seconds to sleep when we have an error (default=30).
        """

    def dvsa_disabled(self):
        return datetime.now() < datetime.combine(
            dt.date.today(), self.DVSA_OPENS
        ) or datetime.now() > datetime.combine(dt.date.today(), self.DVSA_CLOSES)

    @staticmethod
    def input_text_box(el, text, click=False):
        if click:
            el.click()
            randsleep(0.2)
        for char in text:
            el.send_keys(char)
            randsleep(0.01)

    @staticmethod
    def parse_timestr(timestr: str) -> datetime:
        return datetime.strptime(timestr, "%A %d %B %Y %I:%M%p")

    def logged_in(self, browser) -> bool:
        return (
            self._logged_in
            and "queue" not in browser.current_url
            and "/login" not in browser.page_source
        )

    def login(self, browser: Chrome, driver: Driver):
        if self.logged_in(browser):
            return

        browser.bypass()
        if "queue" in browser.current_url:
            self._logger.info("Queuing...")
        while "queue" in browser.current_url:
            sleep(2)
        randsleep(3)
        browser.bypass()

        el = browser.find_element(value="driving-licence-number")
        el.click()
        randsleep(1)
        self.input_text_box(el, driver.licence_number)

        el = browser.find_element(value="application-reference-number")
        el.click()
        randsleep(1)
        self.input_text_box(el, driver.booking_ref)

        browser.find_element(value="booking-login").click()
        randsleep(3)

        if "loginError=true" in browser.current_url:
            raise LoginError("Unable to login.")
        self._logged_in = True

    def find_tests(self, browser: Chrome, driver: Driver):
        self.login(browser, driver)
        main = browser.find_element(value="main").get_attribute("innerHTML")
        if "has been cancelled" in main:
            raise ScraperError("Booking Cancelled.")
        elif "has now been exceeded" in main:
            raise ScraperError("Maximum rebookings exceeded.")

        contents_container = browser.find_elements(By.CLASS_NAME, "contents")
        if not contents_container:
            raise ScraperError("Failed to find contents container.")

        current_test_date = self.parse_timestr(
            contents_container[0]
            .find_element(By.XPATH, ".//dd")
            .get_attribute("innerHTML")
        )

        current_centre = (
            contents_container[1]
            .find_element(By.XPATH, ".//dd")
            .get_attribute("innerHTML")
        )

        driver.current_test = Test(date=current_test_date, centre=current_centre)

        self._logger.debug(
            f"Current Booking for {driver.name} is on "
            f"{current_test_date} in {current_centre}"
        )
        for centre in driver.centres:
            self._logger.debug(
                f"Looking for dates for {driver.name} between "
                f"{centre.not_before or driver.not_before} and "
                f"{centre.not_after or driver.not_after}"
            )
            # wait for a bit so we don't look too automated.
            randsleep(1.5)

            # go back until we're at the starting screen.
            depth = self.find_next_available(browser, driver, centre)
            for _ in range(depth):
                randsleep(0.5)
                browser.back()

    def get_centre_url(self, browser, centre):
        browser.find_element(value="test-centre-change").click()
        randsleep(3)
        el = browser.find_element(value="test-centres-input")
        el.clear()
        self.input_text_box(el, centre)
        browser.find_element(value="test-centres-submit").click()
        randsleep(5)
        container = browser.find_element(By.CLASS_NAME, "test-centre-results")
        centre = container.find_element(By.XPATH, ".//a")
        return centre.get_attribute("href")

    def find_next_available(self, browser: Chrome, driver: Driver, centre: Centre):
        # try to avoid hitting search limit for day
        randsleep(18)
        self._search_counter += 1
        self._logger.info(
            f"Search {self._search_counter}: Trying centre {centre.centre}"
        )
        if centre.centre == driver.current_test.centre:
            back = 2
            browser.find_element(value="date-time-change").click()
            randsleep(1)
            browser.find_element(value="test-choice-earliest").click()
            randsleep(1)
            browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            randsleep(1)
            browser.find_element(value="driving-licence-submit").click()
            randsleep(1)
        else:
            back = 3
            refresh_url = driver.refresh_urls.get(
                centre.centre, self.get_centre_url(browser, centre.centre)
            )
            browser.get(refresh_url)
            randsleep(1)

        page = browser.page_source
        if any(
            x in page
            for x in (
                "Oops",
                "in the queue",
                "Incapsula incident",
                "Enter details below",
                "Search limit reached",
            )
        ):
            browser.bypass()  # is this needed now we handle on getting?

        if "no tests that meet your requirements" in page:
            self._logger.info("No tests available.")
            return back

        day, el = self._scan_for_test(browser, driver, centre)
        if not day:
            self._logger.info("No tests in required range.")
            return back

        if self.reserve:
            slot = self._reserve_test(browser, day, centre, el)
            if slot:
                self._logger.info(f"Reserved test: {slot}")
            else:
                self._logger.info("Failed to reserve test...")
        else:
            self.notify(f"Test found at {centre} on {day}")
            input("Deal with test; press enter when done.")
        return back

    @staticmethod
    def days_to_correct_month(browser: Chrome, day: datetime) -> int:
        el = browser.find_element(By.CLASS_NAME, "BookingCalendar-currentMonth")
        month = el.get_attribute("innerHTML")
        el = browser.find_element(By.CLASS_NAME, "BookingCalendar-currentYear")
        year = el.get_attribute("innerHTML")
        showing = datetime.strptime(f"{month} {year}", "%B %Y")
        return (showing - datetime(day.year, day.month, 1)).days

    def _reserve_test(self, browser: Chrome, day: datetime, centre: str, el) -> bool:
        """Reserve a test.  **UNTESTED**"""
        warnings.warn(
            "Attempting to reserve test: code untested.  YMMV!", RuntimeWarning
        )

        # scroll to correct month
        attempts = 0
        while self.days_to_correct_month(browser, day) > 0:
            browser.find_element(By.CLASS_NAME, "BookingCalendar-nav--prev").click()
            attempts += 1
            if attempts > 12:
                raise BookingError("Failed to find correct month by going backwards.")

        attempts = 0
        while self.days_to_correct_month(browser, day) < 0:
            browser.find_element(By.CLASS_NAME, "BookingCalendar-nav--next").click()
            attempts += 1
            if attempts > 12:
                raise BookingError("Failed to find correct month by going forwards.")

        # click on date.
        el.click()
        # get container
        time_container = browser.find_element(By.ID, f"date-{day.strftime('%Y-%m-%d')}")
        label = time_container.find_element(By.XPATH, ".//label")
        # get time
        time_ms = int(label.get_attribute("for").replace("slot-", ""))
        time = datetime.fromtimestamp(time_ms / 1000).time()
        test_slot = datetime.combine(day.date(), time)
        self._logger.info(f"earliest availabe slot is ", test_slot)

        # check if short_notice
        try:
            short_notice = (
                label.get_attribute("for").get_attribute("data-short-notice") == "true"
            )
        except Exception:
            short_notice = False

        # add error handling here if required.
        randsleep(1)
        # click on time box
        first_available_time = time_container.find_element(By.XPATH, "./label")
        randsleep(1)
        first_available_time.click()
        randsleep(1)
        # click on continue button
        continue_button = browser.find_element(By.ID, "slot-chosen-submit")
        randsleep(1)
        continue_button.click()
        # label.click()
        randsleep(1)

        # dismiss warning
        if short_notice:
            if self.short_notice:
                browser.find_element(
                    By.XPATH, "(//button[@id='slot-warning-continue'])[2]"
                ).click()
            else:
                self._logger.info("Skipping test as short notice.")
                return None
        else:
            # click submit button
            slot_warning_continue_button = browser.find_element(
                By.ID, "slot-warning-continue"
            )
            slot_warning_continue_button.click()
        randsleep(5)

        self._logger.info("15 min timer started, releases in about 16.5 min ")
        # this is wrapped in a loop in the original code.  I'm not sure what those multiple attempts are for.

        randsleep(3)
        # we are the candidate
        browser.find_element(By.ID, "i-am-candidate").click()
        randsleep(1)

        # we make no manual attempt to solve the captcha here.  It might be
        # solved for us by the Browser().
        if "no longer available" in browser.page_source:
            self._logger.info("Missed it: someone else got there first...")
            return False
        self.notify(f"A Driving test has been reserved on {test_slot} in {centre}.")

        # start of new hold loop
        # sleep for long time while dvsa release back to pool
        spinner_sleep(950)
        randsleep(15)

        # find and click abandon button
        abandon_button = browser.find_element(By.ID, "abandon")
        randsleep(1)
        abandon_button.click()
        # TODO add explicit wait until clickable, something like
        # element = WebDriverWait(driver, 10).until \
        #     (EC.element_to_be_clickable((By.ID, "test-centre-change")))
        # driver.find_element_by_id("test-centre-change").click()

        randsleep(2)
        # find and click abandon change button
        abandon_changes_button = browser.find_element(By.ID, "abandon-changes")
        randsleep(1)
        abandon_changes_button.click()
        randsleep(1)
        self._logger.info("Released test.")
        randsleep(2)
        return test_slot

    def _scan_for_test(self, browser: Chrome, driver: Driver, centre: Centre):
        cal = browser.find_element(By.CLASS_NAME, "BookingCalendar-datesBody")
        days = cal.find_elements(By.XPATH, ".//td")
        for day in days:
            if "--unavailable" in day.get_attribute("class"):
                continue
            a = day.find_element(By.XPATH, ".//a")
            date = datetime.strptime(a.get_attribute("data-date"), "%Y-%m-%d")

            if driver.disabled_dates and date in driver.disabled_dates:
                continue

            not_before = centre.not_before or driver.not_before
            if date < not_before:
                continue

            # prevent it finding a test before the current test if the current
            # test is in the required window.
            if driver.current_test.date > not_before:

                # We probably don't care to move back test by test on the same day,
                # so we only accept tests on at least the day before.
                if date.date() >= driver.current_test.date.date():
                    continue

            not_after = centre.not_after or driver.not_after
            if date > not_after:
                continue
            return date, a

        return None, None

    def time_to_next_event(self, elapsed: dt.timedelta = None) -> int:
        """Time to sleep between runs.

        Returns:
            time (int): time in seconds.
        """
        subtract = elapsed.seconds if elapsed else 0
        return max(self.period * 60 - subtract, 0)

    def error_callback(self):
        """Run something when we have an error."""
        pass

    def loop_sleep(self, period):
        """Sleep fn for main loop."""
        period = max(period - 5, 0)
        self._logger.debug(f"Sleeping for ~{period}s.")
        if period:
            randsleep(period, period + 45)
        self._logger.debug(f"Sleeping for ~5s to introduce some randomness.")
        randsleep(5)

    def __call__(self):
        while True:
            self._logger.info("Starting search loop")

            if self.dvsa_disabled():
                self._logger.info("Website not currently available; sleeping.")

            while self.dvsa_disabled():
                randsleep(60)  # has spinner

            while not self.running:
                randsleep(60)

            printed = False
            errs = deque([], maxlen=5)
            searched, errored = 0, 0

            try:
                with self._browser as browser:
                    while self.running:
                        for driver in self.drivers:
                            start = datetime.now()
                            self._logger.info(
                                f"Finding tests for driver {driver.name} "
                                f"run {searched +1}, of which {errored} errored."
                            )
                            self.find_tests(browser, driver)
                            end = datetime.now()
                            period = self.time_to_next_event(elapsed=end - start)
                            self.loop_sleep(period)
                            searched += 1
            except Exception as e:
                errored += 1
                errs.append(monotonic())
                self._logger.exception(e)
                self.error_callback()
                randsleep(self.error_period)

            if len(errs) == 5 and errs[-1] - errs[0] < 10 * 60:
                msg = (
                    "Five errors within 10 minutes; "
                    "giving up so this IP doesn't get blacklisted."
                )
                self._logger.error(msg)  # make sure it's displayed, however we handle
                raise ScraperError(msg)


import math
import itertools
import numpy as NP

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

def read_case(f):
    N = read_int(f)
    E = read_arr(f, N-1)
    return N, E

def size_aux(n, s, d, i, j):
    res = 1
    for k in n[j]:
        if k == i:
            continue
        res += size(n, s, d, j, k)
    return res

def delete_aux(n, s, d, i, j):
    best = None
    for k in n[j]:
        if k == i:
            continue
        for l in n[j]:
            if l in [i, k]:
                continue
            b = delete(n, s, d, j, k) + delete(n, s, d, j, l) - size(n, s, d, j, k) - size(n, s, d, j, l)
            if best == None or best > b:
                best = b
    if best is None:
        if len(n[j] - {i}) == 1:
            best = size(n, s, d, j, (n[j] - {i}).pop())
        else:
            best = 0
    else:
        best += sum(size(n, s, d, j, k) for k in n[j] if k != i)
    return best

def size(n, s, d, i, j):
    if (i, j) not in s:
        s[i, j] = size_aux(n, s, d, i, j)
    return s[i, j]

def delete(n, s, d, i, j):
    if (i, j) not in d:
        d[i, j] = delete_aux(n, s, d, i, j)
    return d[i, j]

def solve_small(case):
    N, E = case
    n = {}
    for (x, y) in E:
        n.setdefault(x, set()).add(y)
        n.setdefault(y, set()).add(x)
    s = {}
    d = {}
    for i in range(1, N+1):
        for j in n[i]:
            s[i, j] = size(n, s, d, i, j)
            d[i, j] = delete(n, s, d, i, j)
    best = None
    for i in range(1, N+1):
        b = delete_aux(n, s, d, None, i)
        if best == None or best > b:
            best = b
    return best

def solve_large(case):
    return solve_small(case)

def write_case(f, i, res):
    f.write('Case #%d: '%i)
    f.write('%s'%res)
    f.write('\n')

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

def read_word(f):
    return next(f).strip()

def read_int(f, b=10):
    return int(read_word(f), b)

def read_letters(f):
    return list(read_word(f))

def read_digits(f, b=10):
    return [int(x, b) for x in read_letters(f)]

def read_words(f, d=' '):
    return read_word(f).split(d)

def read_ints(f, b=10, d=' '):
    return [int(x, b) for x in read_words(f, d)]

def read_floats(f, d=' '):
    return [float(x) for x in read_words(f, d)]

def read_arr(f, R, reader=read_ints, *args, **kwargs):
    return [reader(f, *args, **kwargs) for i in range(R)]

def solve(solver, fn, out_fn=None):
    in_fn = fn + '.in'
    if out_fn is None:
        out_fn = fn + '.out'
    with open(in_fn, 'r') as fi:
        with open(out_fn, 'w') as fo:
            T = read_int(fi)
            for i in range(T):
                case = read_case(fi)
                res = solver(case)
                write_case(fo, i, res)

DEBUG = 'i'

from run import *


import sys
import heapq
input = sys.stdin.readline

n, m, k = map(int, input().rstrip().split())
s, d = map(int, input().rstrip().split())
graph = [{} for _ in range(n+1)]
for _ in range(m):
    a, b, w = map(int, input().rstrip().split())
    if graph[a].get(b): graph[a][b] = min(graph[a][b], w)
    else: graph[a][b] = w
    if graph[b].get(a): graph[b][a] = min(graph[b][a], w)
    else: graph[b][a] = w

# 도시별로, 1000개 배열을 생성 ( 1000번 도로를 건너서 도착했음을 의미, [지금까지의 거리, 도로 개수] )
# d 에서 세금 올릴때마다 1000개 배열 탐색하면서 보면

dp = [[float('inf') for _ in range(n+1)] for _ in range(n+1)]
# dp[i][j] = i 번째 도시까지 j 개 도로를 건넜을 때의 최소 거리

def dijkstra():
    dp[s][0] = 0
    queue = []
    visited = [0 for _ in range(n+1)]
    heapq.heappush(queue, (0, s, 0))

    while queue:
        current_distance, current_destination, current_road = heapq.heappop(queue)
        done = 0
        for i in range(current_road):
            if dp[current_destination][i] < current_distance:
                done = 1
                break

        if done == 1 or current_destination == d: continue

        for next_destination, next_distance in graph[current_destination].items():
            if current_distance + next_distance < dp[next_destination][current_road+1]:
                dp[next_destination][current_road+1] = current_distance + next_distance
                heapq.heappush(queue, (current_distance + next_distance, next_destination, current_road + 1))

    return

dijkstra()
#for di in dp: print(di)
print(min(dp[d]))

for _ in range(k):
    p = int(input().rstrip())
    for i in range(n+1):
        if dp[d][i] == float('inf'): continue
        dp[d][i] += p * i
    print(min(dp[d]))


import numpy as np
import matplotlib.pyplot as plt

# Funzione da integrare
def f(x, y):
    return x**2 + y**2

# Definizione dei limiti di integrazione
x_lower = -1
x_upper = 1
y_lower = -1
y_upper = 1

# Calcolo dell'integrale doppio
integral = 0
n = 100  # Numero di divisioni
dx = (x_upper - x_lower) / n
dy = (y_upper - y_lower) / n

for i in range(n):
    for j in range(n):
        x = x_lower + i * dx
        y = y_lower + j * dy
        integral += f(x, y) * dx * dy

print("Integrale doppio:", integral)

# Creazione del grafico dell'integrale doppio
x = np.linspace(x_lower, x_upper, n)
y = np.linspace(y_lower, y_upper, n)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.title('Integrale doppio')

plt.show()

# Calcolo dell'integrale di linea
t = np.linspace(0, 2*np.pi, 100)  # Parametro t per la curva
integral_line = 0

for i in range(len(t) - 1):
    x1 = np.cos(t[i])
    y1 = np.sin(t[i])
    x2 = np.cos(t[i + 1])
    y2 = np.sin(t[i + 1])
    arc_length = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)
    integral_line += f(x2, y2) * arc_length

print("Integrale di linea:", integral_line)

# Creazione del grafico dell'integrale di linea
fig, ax = plt.subplots()
ax.plot(np.cos(t), np.sin(t), 'r', label='Curva')
ax.set_aspect('equal', 'box')
plt.title('Integrale di linea')
plt.legend()
plt.show()


from readinput import readfile_and_split

sand = (500, -1)
blocked = set()

max_y = 0

for path in [
    [tuple(int(i) for i in m.split(",")) for m in p] for p in readfile_and_split(" -> ")
]:
    prev_x, prev_y = path[0]
    blocked.add((prev_x, prev_y))
    for x, y in path:

        # Find max y
        max_y = max(max_y, y)

        # Build map
        if x > prev_x:
            for x_ in range(prev_x + 1, x + 1):
                blocked.add((x_, y))
        elif x < prev_x:
            for x_ in range(prev_x - 1, x - 1, -1):
                blocked.add((x_, y))
        elif y > prev_y:
            for y_ in range(prev_y + 1, y + 1):
                blocked.add((x, y_))
        elif y < prev_y:
            for y_ in range(prev_y - 1, y - 1, -1):
                blocked.add((x, y_))

        # Update prev
        prev_x = x
        prev_y = y

assert sand not in blocked
count = 0
while True:
    pos = sand
    done = False
    while True:
        a = (pos[0], pos[1] + 1)
        b = (pos[0] - 1, pos[1] + 1)
        c = (pos[0] + 1, pos[1] + 1)
        if a not in blocked and a[1] < max_y + 2:
            pos = a
        elif b not in blocked and a[1] < max_y + 2:
            pos = b
        elif c not in blocked and a[1] < max_y + 2:
            pos = c
        else:
            blocked.add(pos)
            if pos == (500, 0):
                done = True
            break
    if done:
        count += 1
        break
    count += 1
print(count)


qte = int(input())
lista = {}
for i in range(qte):
	v = int(input())
	if(v in lista):
		lista[v] += 1
	else:
		lista[v] = 1

chaves = lista.keys()
chaves = sorted(chaves)

for k in chaves:
	print("%d aparece %d vez(es)" %(k,lista[k]))


import os
import glob
import numpy as np
import matplotlib.pyplot as plt
# import xml.etree.ElementTree as ET
import csv
# plt.rcParams.update({'font.size': 22})
# cwd = os.getcwd()
import glob
import os
import pandas as pd
from scipy import interpolate
import json
import math
import sys

def generate_ppm_axis(size, lower_bound, upper_bound):
    ppm_axis = []
    total_range = upper_bound - lower_bound
    step = total_range / size
    curr_index_value = lower_bound
    for i in range(size):
        ppm_axis.append(curr_index_value)
        curr_index_value = curr_index_value + step
    return ppm_axis

def extend_ppm(ppm_vals, vals, boundaries):
    window = ppm_vals[len(ppm_vals) - 1] - ppm_vals[0]
    step = window / (len(ppm_vals) - 1)
    start_point = ppm_vals[0]
    end_point = ppm_vals[len(ppm_vals) - 1]
    pointer = start_point

    front_ppm_extension = []
    front_val_extension = []
    while (pointer > boundaries[0]):
        pointer = pointer - step
        front_ppm_extension.append(pointer)
        front_val_extension.append(0)

    front_ppm_extension.reverse()

    ppm_vals = front_ppm_extension + ppm_vals
    vals = front_val_extension + vals

    pointer = end_point
    while pointer < boundaries[1]:
        pointer = pointer + step
        ppm_vals.append(pointer)
        vals.append(0)

    if len(ppm_vals) != len(vals):
        print("ERROR: extend_ppm failed")
        sys.exit(1)
    return ppm_vals, vals

def resizer(ppm, val, num, newppmtuple):
    f = interpolate.interp1d(ppm, val)
    new_ppm = np.linspace(newppmtuple[0], newppmtuple[1], num)
    new_vals = f(new_ppm)
    return new_ppm, new_vals

def get_peaks(input_mixture, num_peaks):
    peaks_indexes = []
    threshold = .02
    for i in range(len(input_mixture)):
        if i != 1 and i != len(input_mixture) - 2 and i != 0 and i != len(input_mixture) - 1 and input_mixture[
            i] > threshold and input_mixture[i - 1] < input_mixture[i] and input_mixture[i + 1] < input_mixture[i] and \
                input_mixture[i - 2] <= input_mixture[i - 1] and input_mixture[i + 2] <= input_mixture[i + 1]:
            peaks_indexes.append(i)
    return peaks_indexes

def resize(mixture, newsize, showGraphs=False):
    # original_time_domain_mixture = np.fft.ifft(mixture)
    # original_length = len(original_time_domain_mixture)
    time_domain_resize = np.fft.ihfft(mixture)
    # resize_time_domain_size = len(time_domain_resize)
    # print(type(time_domain_resize))
    frequency_domain_resize = np.fft.hfft(time_domain_resize, newsize)
    if showGraphs:
        plt.plot(mixture)
        plt.title("Original")
        plt.show()
        plt.plot(frequency_domain_resize)
        plt.title("Resized")
        plt.show()
    return frequency_domain_resize

def locate_index(list_, value):
    for i in range(len(list_)):
        if i != 0 and list_[i - 1] <= value <= list_[i]:
            return i

def trim_spectrum(ppm_list, value_list, lower_bound, upper_bound):
    if len(ppm_list) != len(value_list):
        print("PPM List and Value List are not the same size")
        exit()
    lower_index = locate_index(ppm_list, lower_bound)
    upper_index = locate_index(ppm_list, upper_bound)
    new_value_list = value_list[lower_index:upper_index]
    return new_value_list

def mixture_template_size_synchronization(template_names, template_ppms_list, template_values_list, mixture_values):
    OFFSET = 12.78661
    SWP = 16.0252988219442
    mixture_ppms = generate_ppm_axis(len(mixture_values), OFFSET - SWP, OFFSET)
    # ***** PRE CHECKS ******
    if len(mixture_ppms) == 0:
        print("[mixture_template_size_synchronization] ERROR: Mixture ppms are empty")
        sys.exit()
    if len(template_ppms_list) == 0:
        print("[mixture_template_size_synchronization] ERROR: No template ppms were passed")
        sys.exit()
    if len(template_values_list) == 0:
        print("[mixture_template_size_synchronization] ERROR: No template values were passed")
        sys.exit()
    if len(template_names) != len(template_values_list):
        print("[mixture_template_size_synchronization] ERROR: Names size is not equal to template values size")
        sys.exit()
    if len(template_ppms_list) != len(template_values_list):
        print(
            "[mixture_template_size_synchronization] ERROR: template_ppms_list length does not equal template_values_list")
        sys.exit()
    if len(mixture_ppms) != len(mixture_values):
        print("[mixture_template_size_synchronization] ERROR: mixture_ppms length does not equal mixture_values length")
        sys.exit()
    # ********************

    # Cycle through template names
    for t in range(len(template_names)):
        template_ppms_list[t], template_values_list[t] = extend_ppm(template_ppms_list[t], template_values_list[t], (
        mixture_ppms[0], mixture_ppms[len(mixture_ppms) - 1]))
        # Resize metabolites
        template_ppms_list[t], template_values_list[t] = resizer(template_ppms_list[t], template_values_list[t],
                                                                 len(mixture_values), (template_ppms_list[t][0],
                                                                                template_ppms_list[t][len(
                                                                                template_ppms_list[t]) - 1]))

    # ****** POST CHECKS *********
    if len(template_ppms_list[0]) != len(mixture_ppms):
        print("[mixture_template_size_synchronization] ERROR: template size not the same as the mixture size")
        sys.exit()
    # First template ppm serves as the benchmark for the rest of the templates to be equivalent to
    first_template_ppm_length = len(template_ppms_list[0])
    for i in range(len(template_ppms_list)):
        if len(template_ppms_list[i]) != first_template_ppm_length:
            print("[mixture_template_size_synchronization] ERROR: template with index " + str(i) + " and name " +
                  template_names[i] + " has ppms that do not equal the first template's ppm length")
            sys.exit()
        if len(template_ppms_list[i]) != len(template_values_list[i]):
            print("[mixture_template_size_synchronization] ERROR: template with index " + str(i) + " and name " +
                  template_names[i] + " has ppm length that does not equal the values list")
            sys.exit()
    # *****************************

    return template_ppms_list, template_values_list

# OFFSET:  12.78661
# SWP:  16.0252988219442
def test():
    names = []
    template_ppms_list = []
    template_values_list = []
    for file in glob.glob("nan_templates/*.csv"):
        if file == "nan_templates/mixture.csv":
            print("READ MIXTURE")
            mixture_values = list(pd.read_csv(file)["values"])
        else:
            names.append(file[14:-4])
            template_ppms_list.append(list(pd.read_csv(file)["ppm"]))
            template_values_list.append(list(pd.read_csv(file)["values"]))

    print(names)
    # print(template_ppms_list)
    # print(template_values_list)

    template_ppms_list, template_values_list = mixture_template_size_synchronization(names, template_ppms_list,
                                                                                template_values_list,
                                                                                mixture_values)

test()


import math
from datetime import datetime
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

### Run this file after "Position_id.py"

# There are some abnormalities in the data of some addresses, such as holding positions for too long.
# Abnormal positions provide very low liquidity, so remove individual abnormal positions for clear images.
# Manually remove the exception when necessary, see the comments in the code.

pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)

eth = pd.read_csv('eth.csv', sep=',', index_col=[0], dtype=object, header=0)
eth[['block_timestamp']] = eth[['block_timestamp']].astype(str)
eth[['price', '0']] = eth[['price', '0']].astype(float)
ro = 10
eth.loc[:, 'price2'] = eth.loc[:, 'price'].rolling(ro).mean()
eth.loc[0:ro, 'price2'] = eth.loc[0:ro, 'price']
# eth.loc[1,'price2'] = eth.loc[1,'price']
eth.loc[:, 'price_up'] = eth.loc[:, 'price2'] * 1.1
eth.loc[:, 'price_low'] = eth.loc[:, 'price2'] * 0.9
eth.loc[:, "block_timestamp"] = eth.loc[:, "block_timestamp"].apply(lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S"))

info = pd.read_csv('info.csv', sep=',', index_col=[], dtype=object, header=0)
info.index = info['name']

# print(info.index)
# for name in ['polycat']:
for name in info.index:
# for name in ['Popsicle','Unipilot','dHEDGE', 'polycat', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9']:

    receipt = info.loc[name, 'receipt']
    print(name)
    if info.loc[name, 'type'] == 'fund':
        path = '01_init/' + name + '.csv'
        path_result = '01_init/' + receipt + "." + name + '.result.csv'
    else:
        path = '01_init/' + name + '.csv'
        path_result = '01_init/' + receipt + '.result.csv'

    action = pd.read_csv(path, sep=',', index_col=[], dtype=object, header=0)
    action = action[action.tx_type != 'COLLECT']
    action.loc[:, "block_timestamp"] = action.loc[:, "block_timestamp"].apply(
        lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S"))
    action = action[action.block_timestamp >= datetime.strptime('2022-01-01 00:00:00', "%Y-%m-%d %H:%M:%S")]
    action.loc[:, "block_timestamp"] = action.loc[:, "block_timestamp"].apply(lambda x: x.strftime("%Y-%m-%d %H:%M"))
    action = action.sort_values(['block_timestamp', 'tx_type'], ascending=[True, False])
    action[['price_lower', 'price_upper', 'liquidity']] = action[['price_lower', 'price_upper', 'liquidity']].astype(
        float)

    result = pd.read_csv(path_result, sep=',', index_col=[], dtype=object, header=0)
    result.rename(columns={'Unnamed: 0': 'block_timestamp'}, inplace=True)
    result.loc[:, "block_timestamp"] = result.loc[:, "block_timestamp"].apply(
        lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S"))
    result = result[result.block_timestamp > '2022-01-01']
    result[['liquidity']] = result[['liquidity']].astype(float)
    result["log_lq"] = result["liquidity"].apply(lambda x: math.log((x + 1), 10))

    fig, axs = plt.subplots(3, 1, sharex=True, height_ratios=[0.7, 0.15, 0.15], figsize=(20, 10))
    fig.subplots_adjust(hspace=0)
    fig.suptitle(name + ' action', size=30)
    axs[0].set_ylabel('price')
    eth_temp = eth[(eth.block_timestamp >= result['block_timestamp'].min()) & (
                eth.block_timestamp <= result['block_timestamp'].max())]
    axs[0].plot(eth_temp['block_timestamp'], eth_temp['price2'], label='ETH Price', alpha=0.5)

    if (name != 'a2') & (name != 'polycat'):
        axs[0].plot(eth_temp['block_timestamp'], eth_temp['price_low'], label='10% range', color='darkgrey', alpha=.25)
        axs[0].plot(eth_temp['block_timestamp'], eth_temp['price_up'], label='10% range', color='darkgrey', alpha=.25)
        axs[0].legend()

    action_id = action.groupby('tick_id')
    for id, df in action_id:
        print()
        if (id == '349660-349980-0') & (name == 'a8'):
            continue
        elif (id == '202470-202880') & (name == 'a8'):
            continue
        elif (id == '200940-200950-0') & (name == 'polycat'):
            continue
        # elif (id == '202440-202640-0') & (name == 'a8'):
        #     continue
        # if id == '201790.0-205240.0':
        #     continue

        a = 0
        try:
            idx = df[df.tx_type == "MINT"].index[0]
            start_hour = action.loc[idx, 'block_timestamp']
        except:
            print(name, id, "no mint")
            start_hour = result['block_timestamp'].min()

        try:
            idx = df[df.tx_type == "BURN"].index[0]
            end_hour = action.loc[idx, 'block_timestamp']
        except:
            print(name, id, "no burn")
            end_hour = result['block_timestamp'].max()
            # end_hour = '2022-12-31 23:59'

        try:
            price_up = df.loc[df[df.tx_type == "MINT"].index[0], 'price_upper']
            price_low = df.loc[df[df.tx_type == "MINT"].index[0], 'price_lower']
        except:
            price_up = df.loc[df[df.tx_type == "BURN"].index[0], 'price_upper']
            price_low = df.loc[df[df.tx_type == "BURN"].index[0], 'price_lower']

        dates = pd.date_range(start_hour, end_hour, freq='1T').to_list()
        num = len(dates)

        # if price_up > 24000:
        #     up_array = np.repeat(24000,num)
        if price_up > 5000:
            up_array = np.repeat(5000, num)
            print(name, id, price_up, "out of range")
        else:
            up_array = np.repeat(price_up, num)
        low_array = np.repeat(price_low, num)

        print(dates[0], dates[-1], price_up, price_low)
        # for positions with a small market making range and short time period.
        if len(up_array) == 1:
            axs[0].vlines(dates, low_array, up_array, linewidth=3, colors='r', alpha=1)
        elif (price_up - price_low) <= 2:
            axs[0].hlines(np.array([price_up, price_low]), dates[0], dates[-1], linewidth=5, colors='r', alpha=1)
        else:
            axs[0].fill_between(dates, up_array, low_array, interpolate=True, step='mid', alpha=.25)

    axs[1].plot(eth_temp['block_timestamp'], eth_temp['0'])
    axs[1].set_ylabel('fluctuation')
    axs[1].set_xlabel('time')

    axs[2].plot(result['block_timestamp'], result['log_lq'])
    axs[2].set_ylabel('log liquidity')
    axs[2].set_xlabel('time')

    plt.xticks(rotation=30)

    plt.savefig('strategy plot/' + name + ' strategy.png', bbox_inches='tight')
    # plt.show()


import warnings

import numpy as np
import numpy.typing as npt
import scipy.interpolate

from ECM.model.ecm import Thevenin1RC

class BaseSolver:
    def __init__(self, ECM_obj: Thevenin1RC, isothermal: bool, t_app: npt.ArrayLike, i_app: npt.ArrayLike):
        if isinstance(ECM_obj, Thevenin1RC):
            self.ECM_obj = ECM_obj
        else:
            raise TypeError("ECM_obj must be an instance of Thevenin1RC class.")
        if isinstance(isothermal, bool):
            self.isothermal = isothermal
        else:
            raise TypeError("isothermal must be a boolean (True or False).")
        # Ensure the t_app and i_app are numpy arrays of equal length. Furthermore, they should be vectors.
        if isinstance(t_app, np.ndarray):
            if t_app.ndim == 1:
                self.t_app = t_app
            else:
                raise TypeError("t_app must be a vector.")
        else:
            raise TypeError("t_app must be a numpy array.")
        if isinstance(i_app, np.ndarray):
            if len(i_app) == len(t_app):
                self.i_app = i_app
            else:
                raise TypeError("i_app and t_app must be of the same length.")
        else:
            raise TypeError("i_app needs to be numpy object and of the same length as t_app.")

    @staticmethod
    def match_sim_actual_array(t_sim_array: npt.ArrayLike,
                               t_actual_array: npt.ArrayLike,
                               sim_array: npt.ArrayLike,
                               method: str = 'equal') -> npt.ArrayLike:
        """
        This method identifies the gaps in the actual/experimental data and remove them so that
        the lengths of the prediction and actual arrays match.
        :param t_sim_array: (Numpy Array)
        :param t_actual_array: (Numpy Array)
        :param sim_array: (Numpy Array)
        :param method: (string) can be 'equal' or 'interpolation'
        :return: (Numpy Array) The array of simulated values corresponding to the experimental values.
        """
        result_array = np.array([])  # array to be outputted.
        if method == 'equal':
            for k, time in enumerate(t_sim_array):
                if time in t_actual_array:
                    # if condition is true, add the simulated value at this index to result array
                    result_array = np.append(result_array, sim_array[k])
            if result_array.shape[0] == 0:
                warnings.warn("No match between the t_sim_array and t_actual_array.")
        elif method == 'interpolation':
            sim_array_interp = scipy.interpolate.interp1d(t_sim_array, sim_array)
            result_array = sim_array_interp(t_actual_array)
        return result_array


from __future__ import unicode_literals
import datetime
import hashlib

from django.contrib import messages
from django.contrib.auth import login as auth_login, authenticate, get_user_model
from django.db import IntegrityError
from django.shortcuts import redirect, render
from django.views.generic import View
from six import text_type

try:
    from django.urls import reverse
except ImportError:
    from django.core.urlresolvers import reverse

from . import signals
from .forms import PostSocialSignupForm
from .models import SocialAccount
from .providers import registry
from .settings import SIMPLE_SOCIALAUTH_LOGIN_SUCCESS_REDIRECT_URL, SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL, \
    SIMPLE_SOCIALAUTH_GENERATE_USERNAME

class BaseView(View):
    http_method_names = ['get']

    def dispatch(self, request, *args, **kwargs):
        provider_type = kwargs.get('provider_type', '')
        provider = registry.get(provider_type)

        if not provider:
            return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)

        kwargs['provider'] = provider

        return super(BaseView, self).dispatch(request, *args, **kwargs)

class LoginView(BaseView):
    def get(self, request, provider_type, provider, *args, **kwargs):
        kw = {}
        if 'force' in request.GET:
            kw['force'] = True

        next_url = request.GET.get('next', '')
        if next_url:
            request.session['simple_socialauth:next_url'] = next_url

        # get the auth url and redirect the user to it to accept/decline
        return redirect(provider.connect(**kw))

class CallbackView(BaseView):
    def get(self, request, provider_type, provider, *args, **kwargs):
        error = request.GET.get('error')
        if error:
            if error == 'access_denied':
                # user clicked cancel on the facebook dialog
                messages.warning(request,
                                 "You declined the {0} authentication request. Shame!".format(provider_type.title()))
            else:
                messages.warning(request,
                                 "Something went wrong with the {0} authentication request. Perhaps try again?".format(
                                     provider_type.title()))

            return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)

        # process the callback information into a token (the current
        # provider session is auto updated to use the token data)
        try:
            token_data = provider.callback(request.build_absolute_uri())
        except Exception as e:
            # this can fail due to the user denying it; some oauth providers
            # don't pass back the spec-required parameters expected by the
            # oauth lib we use, it blows up - so catch the error and fall back
            # to 'not' authorized.
            token_data = None

        if token_data:
            # List of the possible fields we might get from the various social providers;
            # uid = username = email = name = first_name = last_name = timezone = gender = language = ''

            user_info = provider.get_social_user_info()
            if user_info and 'uid' in user_info:
                user_info['provider'] = provider_type

                # Do we already have a user matching the social provider user id? if so, log in the
                # corresponding Django user.
                try:
                    account = SocialAccount.objects.select_related('user').get(
                        provider=provider_type,
                        uid=user_info.get('uid')
                    )
                except SocialAccount.DoesNotExist:
                    account = None

                if account:
                    if request.user.is_authenticated:
                        if request.user.id != account.user_id:
                            messages.error(request, "This {0} account is associated with another user.".format(
                                provider.display_name()))
                            return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)
                    else:
                        user = authenticate(pk=account.user_id, social=True)
                        if not user:
                            # `user` will be None if the user is not allowed by `authenticate()` above
                            messages.error(request, "Unable to log in.")
                            return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)

                        auth_login(request, user)
                elif provider_type == 'google' and 'refresh_token' not in token_data:
                    # special case for google auth - we need to force a re-auth to ensure we get a refresh_token
                    return redirect(reverse('simple_socialauth-login', args=(provider_type,)) + '?force=1')

                if not request.user.is_authenticated:
                    # we need to redirect the user to another page in order to complete
                    # some signup details - save the social user info to the session
                    # for later use
                    request.session['simple_socialauth:user_info'] = user_info
                    request.session['simple_socialauth:token_data'] = token_data
                    return redirect(reverse('simple_socialauth-login_complete', args=(provider_type,)))

                account, created = SocialAccount.create_or_update(request.user, user_info, token_data)

                signals.login.send(
                    SocialAccount,
                    request=request,
                    account=account,
                    user_info=user_info,
                    created=created
                )
                next_url = request.session.pop('simple_socialauth:next_url', '') or SIMPLE_SOCIALAUTH_LOGIN_SUCCESS_REDIRECT_URL
                return redirect(next_url)

        return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)

class CompleteView(BaseView):
    http_method_names = ['get', 'post']
    form_class = PostSocialSignupForm

    def get(self, *args, **kwargs):
        return self._handler(*args, **kwargs)

    def post(self, *args, **kwargs):
        return self._handler(*args, **kwargs)

    def _handler(self, request, provider_type, provider, *args, **kwargs):
        user_info = request.session.get('simple_socialauth:user_info', {})

        email = user_info.get('email', '').lower().strip()
        username = user_info.get('username', '').strip()

        # we can't legitimately be here if:
        # - we're logged in or
        # - don't have have user_info
        if not user_info or request.user.is_authenticated:
            return redirect(SIMPLE_SOCIALAUTH_LOGIN_ERROR_REDIRECT_URL)

        kw = {
            'username': username,
            'email': email
        }

        if request.method == 'GET':
            # first try to save a new user with their username and email
            # from the social provider; if it fails is_valid() below
            # it probably means data is missing or a matching user already
            # exists for email or username
            form = self.form_class(kw)
        else:
            form = self.form_class(request.POST, initial=kw)

        if form.is_valid():
            user = form.save(commit=False)

            if hasattr(user, 'first_name'):
                user.first_name = user_info.get('first_name') or ''
            if hasattr(user, 'last_name'):
                user.last_name = user_info.get('last_name') or ''
            user.set_unusable_password()

            needs_username = hasattr(user, 'username')
            # loop to allow for race condition induced IntegrityErrors
            # (ie. unique username/email are taken before .save() is
            # called
            while True:
                if needs_username and not user.username and SIMPLE_SOCIALAUTH_GENERATE_USERNAME:
                    h = hashlib.sha256()
                    h.update(text_type(user_info.get('uid', '')).encode('utf8'))
                    h.update(provider_type.encode('utf8'))
                    h.update(email.encode('utf8'))
                    h.update(text_type(datetime.datetime.now()).encode('utf8'))
                    user.username = h.hexdigest()[:user._meta.get_field('username').max_length]

                try:
                    user.save()
                    break
                except IntegrityError:
                    if not needs_username or not user.__class__.objects.filter(username=user.username).exists():
                        # if there isn't a matching user with the same username
                        # already, then it's an IntegrityError for something other
                        # than the the username field - re-raise as we won't handle it.
                        raise
                    user.username = ''

            # clean up the session
            request.session.pop('simple_socialauth:user_info', {})
            token_data = request.session.pop('simple_socialauth:token_data', {})

            user = authenticate(pk=user.pk, social=True)
            auth_login(request, user)

            account, created = SocialAccount.create_or_update(user, user_info, token_data)

            signals.connect.send(
                SocialAccount,
                request=request,
                account=account,
                user_info=user_info,
                created=created
            )

            return redirect(
                request.session.pop('simple_socialauth:next_url', '') or SIMPLE_SOCIALAUTH_LOGIN_SUCCESS_REDIRECT_URL
            )

        context = {
            'form': form
        }

        return render(request, 'simple_socialauth/login_complete.html', context)


from diagrama import Mago,Tank,Assassino

class SimpleCLI:
    def __init__(self):
        self.commands = {}

    def add_command(self, name, function):
        self.commands[name] = function

    def remove_command(self, name):
        if name in self.commands:
            del self.commands[name]
            print(f"Comando '{name}' removido, não é possivel criar mais personagens.")
        else:
            print(f"Command '{name}' not found.")

    def run(self):
        while True:
            command = input("Enter a command: ")
            if command == "quit":
                print("Goodbye!")
                break
            elif command in self.commands:
                self.commands[command]()
            else:
                print("Invalid command. Try again.")

class personagemCLI(SimpleCLI):
    def __init__(self, personagemDAO):
        super().__init__()
        self.personagemDAO = personagemDAO
        self.add_command("create", self.create_personagem)
        self.add_command("read", self.read_personagem)
        self.add_command("update", self.update_personagem)
        self.add_command("delete", self.delete_personagem)

    def create_personagem(self):
        classe = input("Escolha a Classe: Mago,Tank,Assassino: ")
        while True:
            if classe == "Mago":
                personagem = Mago(input("nome do personagem: "))
                self.remove_command("create")
                break
            elif classe == "Tank":
                personagem = Tank(input("nome do personagem: "))
                self.remove_command("create")
                break
            elif classe == "Assassino":
                personagem = Assassino(input("nome do personagem: "))
                self.remove_command("create")
                break
            else:
                print("Classe invalida")
            classe = input("Escolha a Classe: Mago,Tank,Assassino")

        self.personagemDAO.create_personagem(personagem)

    def read_personagem(self):
        try:
            id = input("Enter the id: ")
            personagem = self.personagemDAO.read_personagem(id)
            if personagem:
                print(f"Nome do Personagem: {personagem['nome']} | DanoAP: {personagem['danoAP']} | DanoAD: {personagem['danoAD']} | Vida: {personagem['vida']} | Saldo: {personagem['saldo']}  | Inventario: {personagem['inventario']}")
        except:
            pass

    def update_personagem(self):
        id = input("Entre com o id do personagem para edita-lo: ")
        self.personagemDAO.update_personagem(id)

    def delete_personagem(self):
        id = input("Entre com o id do personagem para exclui-lo: ")
        self.personagemDAO.delete_personagem(id)

    def run(self):
        print("Bem vindo a criação de personagem!")
        print("Comando disponiveis: create, read, update, delete, quit")
        super().run()


from copy import copy

with open("day10.in") as f:
    ADAPTERS = set([int(line.strip()) for line in f.readlines()])

# print(len(ADAPTERS))

used = [0]
diffs = []
def try_all_adapters(used, diffs, available):
    if len(available) == 0:
        print(diffs.count(1) * (diffs.count(3) + 1))
        return

    l = used[-1]
    for a in available:
        diff = a - l
        if diff > 0 and diff <= 3:
            used.append(a)
            diffs.append(diff)
            available.remove(a)
            try_all_adapters(used, diffs, available)
            if len(available) == 0:
                break
            diffs.pop()
            available.add(used.pop())

try_all_adapters(used, diffs, copy(ADAPTERS))

counts = {}
def count_combinations(adapters, first, last):
    if (first, last) in counts:
        return counts[(first, last)]

    if last == first:
        counts[(first, last)] = 1
        return 1

    if last - first == 1:
        counts[(first, last)] = 1
        return 1

    if last - first == 2:
        count = 1
        if first + 1 in adapters:
            count += 1
        counts[(first, last)] = count
        return count

    count = 0
    for i in range(1, 4):
        if first + i in adapters:
            count += count_combinations(adapters, first + i, last)

    counts[(first, last)] = count
    return count

print(count_combinations(ADAPTERS.union([0]), 0, max(ADAPTERS)))


from PyQt5.QtWidgets import (
    QApplication,
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QCheckBox,
    QLineEdit,
    QFormLayout,
    QPushButton,
    QFileDialog
)
from PyQt5.QtGui import QIntValidator
from PyQt5.QtCore import Qt

from process_img import process

# basic GUI setup
app = QApplication(['Advanced Image Processing Project'])
window = QWidget()
window.setFixedSize(500, 200)
layout = QVBoxLayout()
flo = QFormLayout()
bottom = QHBoxLayout()
layout.addLayout(flo)
layout.addLayout(bottom)

# setup flags
segmentCharacters = False
segmentLines = True
segmentParagraphs = True

# setup parameter inputs
lineCloseKernelWidth = 40
paragraphCloseKernelHeight = 10

def lckwChanged(val):
    if val != '':
        global lineCloseKernelWidth
        lineCloseKernelWidth = int(val)

def pckwChanged(val):
    if val != '':
        global paragraphCloseKernelHeight
        paragraphCloseKernelHeight = int(val)

def flagChanged(flag):
    checked = lambda state: state == Qt.Checked
    if flag == 'characters':
        def f(state):
            global segmentCharacters
            segmentCharacters = checked(state)
        return f
    if flag == 'lines':
        def f(state):
            global segmentLines
            segmentLines = checked(state)
        return f
    if flag == 'paragraphs':
        def f(state):
            global segmentParagraphs
            segmentParagraphs = checked(state)
        return f

c1 = QCheckBox()
c1.setChecked(segmentCharacters)
c1.stateChanged.connect(flagChanged('characters'))
c2 = QCheckBox()
c2.setChecked(segmentLines)
c2.stateChanged.connect(flagChanged('lines'))
c3 = QCheckBox()
c3.setChecked(segmentParagraphs)
c3.stateChanged.connect(flagChanged('paragraphs'))

e1 = QLineEdit()
e1.setValidator(QIntValidator(1, 100))
e1.setText('40')
e1.textChanged.connect(lckwChanged)
e2 = QLineEdit()
e2.setValidator(QIntValidator(1, 50))
e2.setText('10')
e2.textChanged.connect(pckwChanged)

flo.addRow('Segment characters', c1)
flo.addRow('Segment lines', c2)
flo.addRow('Segment paragraphs', c3)
flo.addRow('Kernel height for joining paragraphs', e2)
flo.addRow('Kernel width for joining lines', e1)

# setup open image button
def selectImage():
    path = QFileDialog.getOpenFileName()[0]
    if path != '':
        flags = {
            'characters': segmentCharacters,
            'lines': segmentLines,
            'paragraphs': segmentParagraphs
        }
        process(path, flags, lineCloseKernelWidth, paragraphCloseKernelHeight)

bottom.addWidget(QLabel('Select an image to process!'))

openFileButton = QPushButton('Open an image')
openFileButton.clicked.connect(selectImage)
bottom.addWidget(openFileButton)

# run the GUI
window.setLayout(layout)
window.show()

app.exec_()


from func_utils import read_file_array

shapes = (((0, 0), (0, 1), (0, 2), (0, 3)),
          ((0, 1), (1, 0), (1, 1), (1, 2), (2, 1)),
          ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2)),
          ((0, 0), (1, 0), (2, 0), (3, 0)),
          ((0, 0), (0, 1), (1, 0), (1, 1)))
move_action_steps = ""

def check_node(floor_shape, x, y):
    return x > 0 and 0 <= y < 7 and (x, y) not in floor_shape

def check_shape(floor_shape, current_shape, x, y):
    return all(check_node(floor_shape, x + x1, y + y1) for x1, y1 in shapes[current_shape])

def move_shape(floor_shape, idx_move_str, idx_shape, max_x):
    global move_action_steps
    current_x = max_x + 5
    current_y = 2
    while check_shape(floor_shape, idx_shape, current_x - 1, current_y):
        # move down
        current_x -= 1
        # move left
        if move_action_steps[idx_move_str] == '<' \
                and check_shape(floor_shape, idx_shape, current_x, current_y - 1):
            current_y -= 1
        # move right
        if move_action_steps[idx_move_str] == '>' \
                and check_shape(floor_shape, idx_shape, current_x, current_y + 1):
            current_y += 1
        # next action step, repeat when current step greater than string length
        idx_move_str = (idx_move_str + 1) % len(move_action_steps)

    fix_shape = [(current_x + sharp_x, current_y + sharp_y) for sharp_x, sharp_y in shapes[idx_shape]]
    floor_shape.update(fix_shape)
    return idx_move_str, (idx_shape + 1) % len(shapes), max(max_x, max(x for x, y in fix_shape))

def find_repeat_block(floor_shape, max_x):
    result_nodes = set()
    # block not filled node in 7*7 block
    for x in range(7):
        for y in range(7):
            if not check_node(floor_shape, max_x - x, y):
                result_nodes.add((x, y))
    return tuple(result_nodes)

def run(run_times, input_string):
    global move_action_steps
    move_action_steps = input_string
    floor_shape = set()
    idx_shape = 0
    idx_move_str = 0
    max_x = 0
    repeat_max_x = 0
    repeat_bocks = dict()
    repeat_processed_flag = False
    while run_times > 0:
        idx_move_str, idx_shape, max_x = move_shape(floor_shape, idx_move_str, idx_shape, max_x)
        run_times -= 1
        if not repeat_processed_flag:
            repeat_bock = find_repeat_block(floor_shape, max_x)
            if (idx_move_str, idx_shape, repeat_bock) in repeat_bocks:
                (old_max_x, old_run_times) = repeat_bocks[idx_move_str, idx_shape, repeat_bock]
                print("finding!!!", (run_times, old_run_times, max_x, old_max_x, idx_move_str, idx_shape))
                repeat_times = run_times // (old_run_times - run_times)
                remain_times = run_times % (old_run_times - run_times)
                repeat_height = max_x - old_max_x
                repeat_max_x += repeat_height * repeat_times
                run_times = remain_times
                repeat_processed_flag = True
            repeat_bocks[idx_move_str, idx_shape, repeat_bock] = (max_x, run_times)
    return max_x + repeat_max_x

if __name__ == '__main__':
    # P1
    print("p1 sample")
    tmp_list_1_s = read_file_array("day17_1_s.txt")
    p1_s = run(2022, tmp_list_1_s[0])
    print("pass" if p1_s == 3068 else "failed")

    print("p1")
    tmp_list_1 = read_file_array("day17.txt")
    p1 = run(2022, tmp_list_1[0])
    print(p1)

    # P2
    print("p2")
    tmp_list_1 = read_file_array("day17.txt")
    p2 = run(1000000000000, tmp_list_1[0])
    print(p2)


import random

import requests
from lxml import etree
import re
from multiprocessing.dummy import Pool
#需求：爬取梨视频的视频数据
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
}
#原则：线程池处理的是阻塞且较为耗时的操作

#对下述url发起请求解析出视频详情页的url和视频的名称
url = 'https://www.pearvideo.com/category_5'
page_text = requests.get(url=url,headers=headers).text

tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="listvideoListUl"]/li')
urls = [] #存储所有视频的链接and名字
for li in li_list:
    detail_url = 'https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
    name = li.xpath('./div/a/div[2]/text()')[0]+'.mp4'
    #对详情页的url发起请求
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    #从详情页中解析出视频的地址（url）  地址是动态加载出来的，此处无法获取到url地址
    # ex = 'srcUrl="(.*?)",vdoUrl'
    # video_url = re.findall(ex,detail_page_text)[0]

    # 需要调用ajax请求获取视频地址
    ajax_url = 'https://www.pearvideo.com/videoStatus.jsp?'
    # 此处请求的第一个参数是视频的id，需要截取出来
    id_ = str(li.xpath('./div/a/@href')[0]).split('_')[1]
    param = {
        'contId': id_,
        'mrd': str(random.Random)
    }

    # 改请求返回的是一个json数据
    # 如果不加Referer,会提示视频已经下线；此处加入防盗链
    headers['Referer'] = 'https://www.pearvideo.com/video_' + id_
    dic_obj = requests.get(url=ajax_url, params=param, headers=headers).json()
    # print(dic_obj)
    video_url = dic_obj['videoInfo']['videos']['srcUrl']
    # 此处视频地址做了加密，ajax返回的地址无法直接获取到视频，需要将一段数据替换为cont-id
    # https://video.pearvideo.com/mp4/third/20210921/1632314538137-15316010-153415-hd.mp4
    # https://video.pearvideo.com/mp4/third/20210921/cont-1742184-15316010-153415-hd.mp4
    # 通过正则替换
    video_url = re.sub(r'/\d+-', '/cont-' + id_ + '-', video_url)
    # print(video_url, name)
    dic = {
        'name': name,
        'url': video_url
    }
    urls.append(dic)
#对视频链接发起请求获取视频的二进制数据，然后将视频数据进行返回
def get_video_data(dic):
    url = dic['url']
    print(dic['name'],'正在下载......')
    data = requests.get(url=url,headers=headers).content
    #持久化存储操作
    with open(dic['name'],'wb') as fp:
        fp.write(data)
        print(dic['name'],'下载成功！')
#使用线程池对视频数据进行请求（较为耗时的阻塞操作）
pool = Pool(4)
pool.map(get_video_data,urls)
# 关闭线程池
pool.close()
# 阻塞   等待子线程结束
pool.join()

第六章：高性能异步爬虫/3.线程池在爬虫案例中的应用.py

3.线程池在爬虫案例中的应用.py