import random

class ByteKey(bytearray):

    def __init__(self, value=None, buckets=20, prefix=None, rand=None):
        if buckets <= 0:
            raise ValueError('buckets must be > 0: found %d' % buckets)
        if rand is None:
            rand = random.Random()
        if isinstance(value, int):
            buckets = value
            value = None
        if value is None:
            self._init_none(buckets, rand, prefix)
        elif isinstance(value, bytearray):
            self._init_bytearray(value, buckets)
        elif isinstance(value, bytes):
            self._init_bytes(value, buckets, prefix)
        elif isinstance(value, str):
            self._init_str(value, buckets, prefix)
        else:
            super(ByteKey, self).__init__()
            raise TypeError(
                'value must be string or bytearray: found %s' %
                type(value).__name__)
        self._prefix = prefix if prefix else buckets * 8 - 1

    def _init_none(self, buckets, rand, prefix):
        super(ByteKey, self).__init__(buckets)
        for i in range(buckets):
            bits = rand.getrandbits(8)
            if bits and not prefix:
                prefix = i * 8 + ByteKey._bp(bits)
            self[i] = bits

    def _init_bytearray(self, value, buckets):
        ByteKey._assert_length(value, buckets)
        super(ByteKey, self).__init__(value)

    def _init_bytes(self, value, buckets, prefix):
        ByteKey._assert_length(value, buckets, strict=False)
        super(ByteKey, self).__init__(buckets)
        start = buckets - len(value)
        for i in range(buckets):
            if i < start:
                self[i] = 0
            else:
                val = value[i - start]
                if val and not prefix:
                    prefix = i * 8 + ByteKey._bp(val)
                self[i] = val

    def _init_str(self, value, buckets, prefix):
        ByteKey._assert_length(value, buckets, strict=False)
        super(ByteKey, self).__init__(buckets)
        start = buckets - len(value)
        for i in range(buckets):
            if i < start:
                self[i] = 0
            else:
                val = ord(value[i - start])
                if val and not prefix:
                    prefix = i * 8 + ByteKey._bp(val)
                self[i] = val

    def __repr__(self):
        return self.raw

    def __str__(self):
        return self.raw

    def __xor__(self, other):
        ByteKey._assert_length(self, other.buckets)
        i = min(self.prefix, other.prefix) // 4
        ba = bytearray(self.buckets)
        prefix = None
        while i < other.buckets:
            e = other[i]
            val = self[i] ^ e
            if val and not prefix:
                prefix = i * 8 + ByteKey._bp(val)
            ba[i] = val
            i += 1
        key = ByteKey(ba, buckets=self.buckets, prefix=prefix)
        return key

    def rprefix(self, other):
        ByteKey._assert_length(self, other.buckets)
        i = min(self.prefix, other.prefix) // 4
        while i < self.buckets:
            e = other[i]
            val = self[i] ^ e
            if val:
                return i * 8 + ByteKey._bp(val)
            i += 1
        return self.buckets * 8 - 1

    @property
    def raw(self):
        return hex(int(''.join(str(k) for k in self)))

    @property
    def buckets(self):
        return len(self)

    @property
    def prefix(self):
        return self._prefix

    @classmethod
    def _bp(cls, byte):
        if isinstance(byte, str):
            byte = ord(byte)
        if isinstance(byte, bytes):
            byte = byte[0]
        for i in range(8):
            if (byte >> (7 - i)) & 0x1 != 0:
                return i
        return 7

    @classmethod
    def _assert_length(cls, value, buckets, strict=True):
        if (strict and len(value) != buckets) or \
                (not strict and len(value) > buckets):
            raise ValueError(
                'cannot unpack key into %d buckets: %s' %
                (buckets, value))


from concurrent.futures import ThreadPoolExecutor
from socket import create_connection, socket
from threading import Lock, Thread
from time import time

from box.common.resources import address_to_host_port, get_address

class Client():

    LEN_BYTELEN = 8
    BYTEORDER = "big"

    def __init__(self, address, thread_pool_workers=None, max_workers=32) -> None:
        self._address = address_to_host_port(address) if isinstance(address, str) else address
        self._socket = create_connection(self._address)
        self._thread_connection = Thread(target=self._run_connection, name=f"Client Connection")
        self._thread_pool_worker = (
            thread_pool_workers if not thread_pool_workers is None
            else ThreadPoolExecutor(max_workers=max_workers)
        )
        self._func_on_packet = None
        self._running = False

    def _run_connection(self):
        while self._running:
            try:
                _len = int.from_bytes(self._socket.recv(self.LEN_BYTELEN), self.BYTEORDER, signed=False)
                _packet = self._socket.recv(_len)
                if not self._func_on_packet is None:
                    self._thread_pool_worker.submit(self._run_on_packet, self._socket, self._address, _packet)
            except TimeoutError:
                continue
            except Exception as e:
                self._socket.close()
                break

    def _run_on_packet(self, conn, addr, packet):
        _func = self._func_on_packet
        if not _func is None:
            _resp = _func(addr, packet)
            if _resp:
                _len = len(_resp).to_bytes(self.LEN_BYTELEN, self.BYTEORDER, signed=False)
                conn.send(_len + _resp)

    def send(self, bytes):
        _len = len(bytes).to_bytes(self.LEN_BYTELEN, self.BYTEORDER, signed=False)
        self._socket.send(_len + bytes)

    def on_packet(self, func):
        self._func_on_packet = func
        return func

    def start(self):
        self._running = True
        self._thread_connection.start()

    def stop(self):
        self._running = False
        self._socket.close()

class ClientPool():

    LEN_BYTELEN = 8
    BYTEORDER = "big"
    TTL = 10
    LRU = 32
    UPDATE_MAX_WORKERS = 4
    THREAD_POOL_UPDATE = ThreadPoolExecutor(max_workers=UPDATE_MAX_WORKERS)

    def __init__(self, thread_pool_workers=None, max_workers=32, _ttl = None, _lru = None) -> None:
        self._addr2time = {}
        self._addr2conn = {}
        self._addr2thread = {}
        self._lock = Lock()

        self._thread_pool_worker = (
            thread_pool_workers if not thread_pool_workers is None
            else ThreadPoolExecutor(max_workers=max_workers)
        )
        self._func_on_packet = None

        if not _ttl is None:
            self.TTL = _ttl
        if not _lru is None:
            self.LRU = _lru

    def _run_connection(self, conn, addr):
        while self._running:
            try:
                _len = int.from_bytes(conn.recv(self.LEN_BYTELEN), self.BYTEORDER, signed=False)
                _packet = conn.recv(_len)
                if not self._func_on_packet is None:
                    self._thread_pool_worker.submit(self._run_on_packet, conn, addr, _packet)
            except TimeoutError:
                continue
            except Exception as e:
                conn.close()
                break
        self._kill(get_address(*addr))

    def _run_on_packet(self, conn, addr, packet):
        _func = self._func_on_packet
        if not _func is None:
            _resp = _func(addr, packet)
            if _resp:
                _len = len(_resp).to_bytes(self.LEN_BYTELEN, self.BYTEORDER, signed=False)
                conn.send(_len + _resp)

    def _update(self):
        _living = time() - self.TTL
        _queue = self._addr2time.items()
        _idx = max(len(_queue) - self.LRU, 0)
        while _queue[_idx][1] < _living:
            _idx += 1
        _updating = [_queue[_idx][0] for _idx in range(_idx)]
        with self._lock:
            for _addr in _updating:
                if _addr in self._addr2time and self._addr2time[_addr] < _living:
                    _time = self._addr2time.pop(_addr)
                    _conn = self._addr2conn.pop(_addr)
                    _thread = self._addr2thread.pop(_addr)
                    _conn.stop()

    def _access(self, address: str):
        with self._lock:
            self._addr2time.pop(address, None)
            self._addr2time[address] = time()
            _conn = self._addr2conn.get(address, None)
            if _conn is None:
                _conn = create_connection(*address_to_host_port(address))
                _thread = Thread(
                    target=self._run_connection,
                    name=f"Client Connection @{address}",
                    args=(_conn, address_to_host_port(address))
                )
                self._addr2conn[address] = _conn
                self._addr2thread[address] = _thread
                _thread.start()
        ClientPool.THREAD_POOL_UPDATE.submit(self._update)
        return _conn

    def _kill(self, address: str):
        with self._lock:
            _time = self._addr2time.pop(address, None)
            _conn = self._addr2conn.pop(address, None)
            _thread = self._addr2thread.pop(address, None)
            if not _conn is None:
                _conn.stop()

    def send(self, address: str, bytes: bytes):
        _c = self._access(address)
        _len = len(bytes).to_bytes(self.LEN_BYTELEN, self.BYTEORDER, signed=False)
        _c.send(_len + bytes)

    def on_packet(self, func):
        self._func_on_packet = func
        return func

    def start(self):
        self._running = True

    def stop(self):
        self._running = False


import cv2, copy
import numpy as np
def frameToImage(depth, color, ir):
    i_depth = depth.asarray() / 4500.
    i_color = cv2.resize(color.asarray(), (int(1920 / 3), int(1080 / 3)))
    i_ir = ir.asarray() / 65535.
    return i_depth, i_color, i_ir

def depthToPointCloudWithPos(device, depth):
    points = []
    for i in range(depth.height):
        for j in range(depth.width):
            pos = list(device.registration.getPointXYZ(depth, i, j))
            if not np.isnan(pos[0]):
                points.append([pos[0], pos[1], pos[2], i, j])
    return points

def depthToPointCloud(device, depth):
    points = []
    for i in range(depth.height):
        for j in range(depth.width):
            pos = list(device.registration.getPointXYZ(depth, i, j))
            if not np.isnan(pos[0]):
                points.append(pos)
    return points

def depthToPointCloudWithDownSample(device, depth, mask, d):
    points = []
    for i in range(depth.height):
        for j in range(depth.width):
            if mask[i][j] == True and (i + j) % d == 0:
                try:
                    state = True
                    for ii in range(5):
                        for jj in range(5):
                            state = state and mask[i + ii - 2][j + jj - 2]
                    if state:
                        pos = list(device.registration.getPointXYZ(depth, i, j))
                        if (not np.isnan(pos[0])) and (pos[0] ** 2 + pos[1] ** 2 + pos[2] ** 2 <= 2.2):
                            points.append(pos)
                except:
                    pass

    return points

def depthToPointCloudWithDownSampleAndPlane(device, depth, mask, d, plane):
    points = []
    tmp_scale = np.sqrt(plane[0] ** 2 + plane[1] ** 2 + 1)
    for i in range(depth.height):
        for j in range(depth.width):
            if mask[i][j] == True and (i + j) % d == 0:
                try:
                    state = True
                    for ii in range(11):
                        for jj in range(11):
                            state = state and mask[i + ii - 5][j + jj - 5]
                    if state:
                        pos = list(device.registration.getPointXYZ(depth, i, j))
                        if (not np.isnan(pos[0])) and (pos[0] ** 2 + pos[1] ** 2 + pos[2] ** 2 <= 2.2):
                            dist = (pos[0] * plane[0] + pos[1] * plane[1] - (pos[2] - plane[2])) / tmp_scale
                            if abs(dist) > 0.05:
                                points.append(pos)
                except:
                    pass

    return points

def depthToPointCloudWithMask(device, depth, mask):
    points = []
    for i in range(depth.height):
        for j in range(depth.width):
            if mask[i][j] == True:
                pos = list(device.registration.getPointXYZ(depth, i, j))
                if (not np.isnan(pos[0])) and (pos[0] ** 2 + pos[1] ** 2 + pos[2] ** 2 <= 2.2):
                    points.append(pos)
    return points

def depthToPoint(device, depth, x, y):
    min_dist = 2 ** 31
    feature_pos = None
    for i in range(3):
        for j in range(3):
            try:
                pos = list(device.registration.getPointXYZ(depth, x + i, y + j))
                if (j ** 2 + i ** 2 < min_dist) and (not np.isnan(pos[0])):
                    feature_pos = copy.copy(pos)
            except:
                pass
    return feature_pos

def grayToThreeChannels(gray):
    tem = copy.copy(gray)
    tem = np.array([tem])
    tem = np.concatenate((tem, tem, tem), axis = 0)
    return np.moveaxis(tem, 0, -1)


from datasets.utils.make_border_map import MakeBorderMap
from datasets.utils.make_shrink_map import MakeShrinkMap

class TargetCreator:
    def __init__(self, mask_shrinker_cfg, border_creator_cfg):
        self.border_creator = MakeBorderMap(**border_creator_cfg)
        self.mask_shrinker = MakeShrinkMap(**mask_shrinker_cfg)

    def create_target(self, image, word_polygons):
        res = self.mask_shrinker({
            'img': image,
            'text_polys': word_polygons,
            'ignore_tags': [0] * len(word_polygons)
        })

        shrink_map = res['shrink_map']
        shrink_mask = res['shrink_mask']

        res = self.border_creator({
            'img': image,
            'text_polys': word_polygons,
            'ignore_tags': [0] * len(word_polygons)
        })

        threshold_map = res['threshold_map']
        threshold_mask = res['threshold_mask']

        return shrink_map, shrink_mask, threshold_map, threshold_mask


import cv2 as cv
import os
from PIL import Image
import numpy as np
import pickle

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
faces_dir = os.path.join(BASE_DIR, 'Faces')

recognizer = cv.face.LBPHFaceRecognizer_create()

current_id = 0
label_ids = {}
y_lebels = []
x_train = []

for root, dirs, files in os.walk(faces_dir):
    for file in files:
        if file.endswith("png") or file.endswith('jpg'):
            path = os.path.join(root, file)
            label = os.path.basename(root).replace(' ', '-')
            if label not in label_ids:
                label_ids[label] = current_id
                current_id += 1

            id_ = label_ids[label]

            pil_image = Image.open(path)
            final_image = pil_image.resize((550,550), Image.ANTIALIAS)
            image_array = np.array(final_image, 'uint8')
            x_train.append(image_array)
            y_lebels.append(id_)

with open('labels.pickle', 'wb') as f:   # writing bytes = wb
    pickle.dump(label_ids, f)

recognizer.train(x_train, np.array(y_lebels))
recognizer.save('trainner.yml')


#!/usr/bin/env python
#
# Udacity Nanodegree: Fullstack Web Developer
# File: tournament.py -- implementation of a Swiss-system tournament
# Author: Fernando Matarrubia

import psycopg2
import contextlib

@contextlib.contextmanager
def get_cursor():
    """
    Helper function using the context lib to avoid repeating the same code when executing queries
    Reference: Udacity first project review
    Reference: https://docs.python.org/2/library/contextlib.html
    Reference: http://thecodeship.com/patterns/guide-to-python-function-decorators/
    """
    conn = connect()
    cur = conn.cursor()
    try:
        yield cur
    except:
        raise
    else:
        conn.commit()
    finally:
        cur.close()
        conn.close()

def connect():
    """Connect to the PostgreSQL database.  Returns a database connection."""
    return psycopg2.connect("dbname=tournament")

def executeQuery(query, fetchResults, listOfParameters=()):
    """Convenience method to safely execute an sql query"""
    results = None;
    with get_cursor() as cursor:
        # Using this phyton's formatting prevents sql injection attacks
        cursor.execute(query, listOfParameters);
        if (fetchResults):
            results = cursor.fetchall();
    return results;

def deleteMatches():
    """Remove all the match records from the database."""
    query = "TRUNCATE matches CASCADE;";
    executeQuery(query, False);

def deletePlayers():
    """Remove all the player records from the database."""
    query = "TRUNCATE players CASCADE;";
    executeQuery(query, False);

def deleteTournaments():
    """Remove all the tournament records from the database."""
    query = "TRUNCATE tournaments CASCADE;";
    executeQuery(query, False);

def countPlayers():
    """Returns the number of players currently registered."""
    query = "SELECT count(*) as totalPlayers FROM players;";
    result = executeQuery(query, True);
    # Result value should be the first item in the first returned row
    totalPlayers = result[0][0];
    return totalPlayers;

def countTournaments():
    """Returns the number of tournaments currently registered."""
    query = "SELECT count(*) as totalTournaments FROM tournaments;";
    result = executeQuery(query, True);
    # Result value should be the first item in the first returned row
    totalTournaments = result[0][0];
    return totalTournaments;

def registerPlayer(name):
    """Adds a player to the tournament database.

    The database assigns a unique serial id number for the player.  (This
    should be handled by your SQL database schema, not in your Python code.)

    Args:
      name: the player's full name (need not be unique).
    """
    # Sanitizing the input before executing the query
    # This will escape or strip characters making the input safe and preventing sql injection attacks
    query = "INSERT INTO players (name) VALUES (%s);";
    executeQuery(query, False, (name,));

def registerTournament(name):
    """Adds a tournament to the tournament database.

    The database assigns a unique serial id number for the tournament.

    Args:
      name: the tournament's name (it doesn't need to be unique).
    """
    # Sanitizing the input before executing the query
    # This will escape or strip characters making the input safe and preventing sql injection attacks
    query = "INSERT INTO tournaments (name) VALUES (%s);";
    executeQuery(query, False, (name,));

def getTournaments():
    """Returns a list of the existing tournaments.

    The first entry in the list should be the player in first place, or a player
    tied for first place if there is currently a tie.

    Returns:
      A list of tuples, each of which contains (id, name):
        id: the tournament's unique id
        name: the tournaments's name (as registered)
    """
    query = "SELECT * FROM tournaments;";
    result = executeQuery(query, True);
    tournaments = [[row[0], row[1]] for row in result];
    return tournaments;

def playerStandings():
    """Returns a list of the players and their win records, sorted by wins.

    The first entry in the list should be the player in first place, or a player
    tied for first place if there is currently a tie.

    Returns:
      A list of tuples, each of which contains (id, name, wins, matches):
        id: the player's unique id (assigned by the database)
        name: the player's full name (as registered)
        wins: the number of matches the player has won
        matches: the number of matches the player has played
    """
    query = "SELECT id, name, wins, matches FROM playerStandings;";
    playerStandings = executeQuery(query, True);
    return playerStandings;

def playerStandingsInTournament(tournamentId):
    """Returns a list of the players and their win records, sorted by wins and filtered by tournamentId

    The first entry in the list should be the player in first place, or a player
    tied for first place if there is currently a tie.

    Returns:
      A list of tuples, each of which contains (id, name, tournament_id, wins, matches):
        id: the player's unique id (assigned by the database)
        name: the player's full name (as registered)
        tournament_id: the tournament's unique id
        wins: the number of matches the player has won
        matches: the number of matches the player has played
    """
    query = "SELECT * FROM playerStandings WHERE tournament_id = (%s)";
    playerStandings = executeQuery(query, True, (tournamentId,));
    return playerStandings;

def reportMatch(winner, loser, tournament=-1, comments=""):
    """Records the outcome of a single match between two players.

    Args:
      winner:  the id number of the player who won
      loser:  the id number of the player who lost
      tournament:  the id number of the tournament where the match took place in.
                    If -1 the first tournament int he database will be use as default.
      comments: string containing comments about the match
    """
    # This code will use the first tournament in the database as the default tournament
    # when reporting a match with an invalid tournament id
    if(tournament == -1):
        tournaments = getTournaments()
        if (len(tournaments) == 0):
            raise ValueError("Cannot report a match if there are no tournaments in the databse")
            return
        else:
            tournament = tournaments[0][0];

    query = "INSERT INTO matches VALUES ((%s), (%s), (%s), (%s));";
    executeQuery(query, False, (tournament, winner, loser, comments, ));

def createPairs(list):
    """Generator function to return a list of pairs given an existing list

        Reference: https://www.jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
    """
    listIterator = iter(list)
    # Yields on two values at a time and returns a tuple containing both of them
    while True:
        yield(listIterator.next(), listIterator.next())

def swissPairings(tournamentId = -1):
    """Returns a list of pairs of players for the next round of a match. A tournamentId is optional.

    Assuming that there are an even number of players registered, each player
    appears exactly once in the pairings.  Each player is paired with another
    player with an equal or nearly-equal win record, that is, a player adjacent
    to him or her in the standings.

    If a tournament Id is specified, the pairing will be done between players with matches on a given tournament.
    If no index is specified, the pairing will be done using all existing player standings, that is, taking in account
    results of all players in all tournaments

    Returns:
      A list of tuples, each of which contains (id1, name1, id2, name2)
        id1: the first player's unique id
        name1: the first player's name
        id2: the second player's unique id
        name2: the second player's name
    """
    # Depending on the tournamentId we need to fetch the standings in a given way
    playerStandingsList = playerStandings() if (tournamentId == -1) else playerStandingsInTournament(tournamentId);
    # Then, we create the pairs using a generator function
    standingPairs = createPairs(playerStandingsList);
    # Finally we build the result with the required structure and return them
    result = [[pair[0][0], str(pair[0][1]), pair[1][0], str(pair[1][1])] for pair in standingPairs];
    return result


from django.shortcuts import render
from ask.models import Question,Answer
from django.apps import apps
from django.forms import ModelForm

t = 'freezyTemplate/'

class FreezyAdmin:
    templates = {}

    def __init__(self,title):
        self.title = title
        self.models = []

    def __str__(self):
        return self.title

    def register_model(self,**item):
        print(item)
        for k,v in item.items():
            for i in v:
                model = apps.get_model(k,i)
                objects = model.objects.all()
                self.models.append({'name':model.__name__,'label':model._meta.app_label,'model':model,'objects':objects})
        return self.models

    #def register_template(self)

def overviewPage(request):
    template = t+'overview.html'
    freezy = FreezyAdmin('Curious')
    models = freezy.register_model(ask=['Question','Answer'],auth=['User','Group'])
    print(models)
    context = dict(models=models)
    return render(request,template,context)

def detailviewPage(request,name,label):
    mod = apps.get_model(label,name)
    subject_items = mod.objects.all()
    template = t + 'detail.html'
    context = dict(subject=name,subject_items=subject_items,label=label)
    return render(request,template,context)

def itemDetail(request,id,label,model):
    mod = apps.get_model(label,model)
    item = mod.objects.get(id=id)
    get_fields = item._meta.get_fields()
    fields = [{'name':i.name,'value':getattr(item,i.name)} for i in get_fields]
    template = t + 'itemdetail.html'
    context = dict(item=item,fields=fields)
    return render(request,template, context)


from numpy import product
import BST
import node
import pandas as pd

df = pd.read_csv("foodDataCleaned.csv")

# hard coded test nodes
test1 = node.Node(
    product="Banana Chips Sweetened (Whole)",
    energy=2243.0,
    fat=28.57,
    carbs=64.29,
    proteins=3.57,
    ingredients="Bananas, vegetable oil (coconut oil, corn oil and/or palm oil) sugar, natural banana flavor."
)

test2 = node.Node(
    product="Peanuts",
    energy=1941.0,
    fat=17.86,
    carbs=60.71,
    proteins=17.86,
    ingredients="Peanuts, wheat flour, sugar, rice flour, tapioca starch, salt, leavening (ammonium bicarbonate, baking soda), soy sauce (water, soybeans, wheat, salt), potato starch."
)

test3 = node.Node(
    product="Organic Salted Nut Mix",
    energy=2540.0,
    fat=57.14,
    carbs=17.86,
    proteins=17.86,
    ingredients="Organic hazelnuts, organic cashews, organic walnuts almonds, organic sunflower oil, sea salt."
)

test4 = node.Node(
    product="Organic Polenta",
    energy=1552.0,
    fat=1.43,
    carbs=77.14,
    proteins=8.57,
    ingredients="Organic polenta"
)

# uncomment this for testing the node class
print("- starting node tests...\n")

testArr = []

for i in range(4):
    n = node.Node(
        df["product_name"][i],
        df["energy_100g"][i],
        df["fat_100g"][i],
        df["carbohydrates_100g"][i],
        df["proteins_100g"][i],
        df["ingredients_text"][i]
    )
    testArr.append(n)

# assertions
print("testing first 4 nodes from csv sheet vs. hard coded nodes...")
assert node.isSame(test1, testArr[0]), "test 1 failed"
assert node.isSame(test2, testArr[1]), "test 2 failed"
assert node.isSame(test3, testArr[2]), "test 3 failed"
assert node.isSame(test4, testArr[3]), "test 4 failed"
print("Node tests passed\n")

# uncomment this to test BST methods
print("- starting BST tests...\n")
bstSoln = BST.BST(test3)

# sorting by product name
test3.right = test2
test2.parent = test3

test3.left = test1
test1.parent = test3

# bstSoln.printInOrder(bstSoln.getRoot())

test1BST = node.Node(
    product="Banana Chips Sweetened (Whole)",
    energy=2243.0,
    fat=28.57,
    carbs=64.29,
    proteins=3.57,
    ingredients="Bananas, vegetable oil (coconut oil, corn oil and/or palm oil) sugar, natural banana flavor."
)

test2BST = node.Node(
    product="Peanuts",
    energy=1941.0,
    fat=17.86,
    carbs=60.71,
    proteins=17.86,
    ingredients="Peanuts, wheat flour, sugar, rice flour, tapioca starch, salt, leavening (ammonium bicarbonate, baking soda), soy sauce (water, soybeans, wheat, salt), potato starch."
)

test3BST = node.Node(
    product="Organic Salted Nut Mix",
    energy=2540.0,
    fat=57.14,
    carbs=17.86,
    proteins=17.86,
    ingredients="Organic hazelnuts, organic cashews, organic walnuts almonds, organic sunflower oil, sea salt."
)

bstTest = BST.BST(test3BST)
bstTest.insertNode(test2BST, bstTest.getRoot())
bstTest.insertNode(test1BST, bstTest.getRoot())

try:
    bstTest.insertNode(test3BST, bstTest.getRoot())
    print("duplicate test failed, did you forget to uncomment the value error in BST.py?")
    raise AssertionError
except ValueError:
    print("duplicate test passed")

# bstTest.printInOrder(bstTest.getRoot())

# assertions
print("testing BST insertNode using first 3 nodes from csv sheet vs. hard coded nodes...")
assert node.isSame(bstSoln.getRoot(), bstTest.getRoot()), "test 1 failed"
assert node.isSame(bstSoln.getRoot().left, bstTest.getRoot().left), "test 2 failed"
assert node.isSame(bstSoln.getRoot().right, bstTest.getRoot().right), "test 3 failed"

assert bstSoln.getRoot().parent == bstTest.getRoot().parent, "test 4 failed"
assert node.isSame(bstSoln.getRoot().left.parent, bstTest.getRoot().left.parent), "test 5 failed"
assert node.isSame(bstSoln.getRoot().right.parent, bstTest.getRoot().right.parent), "test 6 failed"

print("testing BST searchNode (node)...")
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot(), bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot(), bstTest.getRoot())), "test 7 failed"
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot().left, bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot().left, bstTest.getRoot())), "test 8 failed"
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot().right, bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot().right, bstTest.getRoot())), "test 9 failed"
assert bstTest.searchNode(test4, bstTest.getRoot()) is None, "test 10 failed"

print("testing BST searchNode (string)...")
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot().getProduct(), bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot().getProduct(), bstTest.getRoot())), "test 11 failed"
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot().left.getProduct(), bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot().left.getProduct(), bstTest.getRoot())), "test 12 failed"
assert node.isSame(bstSoln.searchNode(bstSoln.getRoot().right.getProduct(), bstSoln.getRoot()), bstTest.searchNode(bstTest.getRoot().right.getProduct(), bstTest.getRoot())), "test 13 failed"
assert bstTest.searchNode(test4.getProduct(), bstTest.getRoot()) is None, "test 14 failed"

print("BST tests passed\n")


import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import cv2
import pdb

from mpl_toolkits.mplot3d import proj3d

def axisEqual3D(ax):
    extents = np.array([getattr(ax, 'get_{}lim'.format(dim))() for dim in 'xyz'])
    sz = extents[:,1] - extents[:,0]
    centers = np.mean(extents, axis=1)
    maxsize = max(abs(sz))
    r = maxsize/2
    for ctr, dim in zip(centers, 'xyz'):
        getattr(ax, 'set_{}lim'.format(dim))(ctr - r, ctr + r)

# CameraSize: half of the camera body length
# CameraEdge: line width of the camera body
# CameraColor: 3-vector RGB color of the camera
def Func_cameraDisplay(rot_cam, trans_cam, cam_size, cam_edge, cam_color, ax):
    r = cam_size
    t = trans_cam
    R = rot_cam

    # Corners of the camera in the camera coordinate system
    X1 = np.asarray([[r,-r,-2*r]]).T
    X2 = np.asarray([[r,r,-2*r]]).T
    X3 = np.asarray([[-r,-r,-2*r]]).T
    X4 = np.asarray([[-r,r,-2*r]]).T

    X5 = np.asarray([[r,-r,2*r]]).T
    X6 = np.asarray([[r,r,2*r]]).T
    X7 = np.asarray([[-r,-r,2*r]]).T
    X8 = np.asarray([[-r,r,2*r]]).T

    X9 = np.asarray([[1.5*r,-1.5*r,3*r]]).T
    X10 = np.asarray([[1.5*r,1.5*r,3*r]]).T
    X11 = np.asarray([[-1.5*r,-1.5*r,3*r]]).T
    X12 = np.asarray([[-1.5*r,1.5*r,3*r]]).T

    X13 = np.asarray([[0, 0, 0]]).T
    X14 = np.asarray([[0, 0, 2*r]]).T
    X15 = np.asarray([[0, 2*r, 0]]).T
    X16 = np.asarray([[2*r, 0, 0]]).T

    # Corners of the camera in the world coordinate system
    X1 = np.matmul(R,X1) + t
    X2 = np.matmul(R,X2) + t
    X3 = np.matmul(R,X3) + t
    X4 = np.matmul(R,X4) + t
    X5 = np.matmul(R,X5) + t
    X6 = np.matmul(R,X6) + t
    X7 = np.matmul(R,X7) + t
    X8 = np.matmul(R,X8) + t
    X9 = np.matmul(R,X9) + t
    X10 = np.matmul(R,X10) + t
    X11 = np.matmul(R,X11) + t
    X12 = np.matmul(R,X12) + t
    X13 = np.matmul(R,X13) + t
    X14 = np.matmul(R,X14) + t
    X15 = np.matmul(R,X15) + t
    X16 = np.matmul(R,X16) + t

    #plot

    ax.plot([X1[0][0], X2[0][0]], [X1[1][0], X2[1][0]],zs=[X1[2][0], X2[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X1[0][0], X3[0][0]], [X1[1][0], X3[1][0]],zs=[X1[2][0], X3[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X4[0][0], X3[0][0]], [X4[1][0], X3[1][0]],zs=[X4[2][0], X4[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X2[0][0], X4[0][0]], [X2[1][0], X4[1][0]],zs=[X2[2][0], X4[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)

    ax.plot([X5[0][0], X6[0][0]], [X5[1][0], X6[1][0]],zs=[X5[2][0], X6[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X5[0][0], X7[0][0]], [X5[1][0], X7[1][0]],zs=[X5[2][0], X7[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X8[0][0], X7[0][0]], [X8[1][0], X7[1][0]],zs=[X8[2][0], X7[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X6[0][0], X8[0][0]], [X6[1][0], X8[1][0]],zs=[X6[2][0], X8[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)

    ax.plot([X1[0][0], X5[0][0]], [X1[1][0], X5[1][0]],zs=[X1[2][0], X5[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X2[0][0], X6[0][0]], [X2[1][0], X6[1][0]],zs=[X2[2][0], X6[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X3[0][0], X7[0][0]], [X3[1][0], X7[1][0]],zs=[X3[2][0], X7[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X4[0][0], X8[0][0]], [X4[1][0], X8[1][0]],zs=[X4[2][0], X8[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)

    ax.plot([X9[0][0], X10[0][0]], [X9[1][0], X10[1][0]],zs=[X9[2][0], X10[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X9[0][0], X11[0][0]], [X9[1][0], X11[1][0]],zs=[X9[2][0], X11[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X12[0][0], X11[0][0]], [X12[1][0], X11[1][0]],zs=[X12[2][0], X11[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X10[0][0], X12[0][0]], [X10[1][0], X12[1][0]],zs=[X10[2][0], X12[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)

    ax.plot([X5[0][0], X9[0][0]], [X5[1][0], X9[1][0]],zs=[X5[2][0], X9[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X6[0][0], X10[0][0]], [X6[1][0], X10[1][0]],zs=[X6[2][0], X10[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X7[0][0], X11[0][0]], [X7[1][0], X11[1][0]],zs=[X7[2][0], X11[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)
    ax.plot([X8[0][0], X12[0][0]], [X8[1][0], X8[1][0]],zs=[X8[2][0], X12[2][0]], color = (cam_color[0],cam_color[1],cam_color[2]), linewidth=cam_edge)

    ax.plot([X13[0][0], X14[0][0]], [X13[1][0], X14[1][0]],zs=[X13[2][0], X14[2][0]], color = (1.0,0.0,0.0), linewidth=cam_edge)
    ax.plot([X13[0][0], X15[0][0]], [X13[1][0], X15[1][0]],zs=[X13[2][0], X15[2][0]], color = (0.0,1.0,0.0), linewidth=cam_edge)
    ax.plot([X13[0][0], X16[0][0]], [X13[1][0], X16[1][0]],zs=[X13[2][0], X16[2][0]], color = (0.0,0.0,1.0), linewidth=cam_edge)

#!!!! This display code assumes a single camera group remain at the end the calibration process
# 1. path to calibration results
#path_root = "/home/francois/Documents/CppProject/Stereo_Calibration/Images_Synth_4cam_8boards_4groups_NonOverlap/"
#path_root = "/disk/francois/Projets/Calibration_toolbox/Data/Real_Images/2021-07-12-15-09-53/"
#path_root = "/disk/francois/Projets/Calibration_toolbox/Data/Real_Images/stereo_cube/"
path_root = "/disk/francois/Projets/Calibration_toolbox/Data/Real_Images/2021-07-12-15-09-53/"
path_calib_results = path_root + "calibrated_cameras_data.yml"
cam_size = 3
cam_edge = 2
cam_color = [0.0, 0.0, 0.0]
# 2. Open the file
fs = cv2.FileStorage(path_calib_results, cv2.FILE_STORAGE_READ)
Nb_Camera = fs.getNode("nb_camera").real()
Nb_Camera = int(Nb_Camera)

#2. declare figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_proj_type('ortho')
ax.set_title('Calibration Result')

# 3. Read the data for all the cameras
for i in range(0,Nb_Camera):
    cam_id = "camera_" + str(i)
    cam_mat = fs.getNode(cam_id).getNode("camera_matrix").mat()
    cam_pose = fs.getNode(cam_id).getNode("camera_pose_matrix").mat()
    #cam_pose = np.linalg.inv(cam_pose)
    t = np.asarray([cam_pose[0:3,3]]).T
    R = cam_pose[0:3,0:3]
    Func_cameraDisplay(R, t, cam_size, cam_edge, cam_color,ax)
    print(cam_pose)

#ax.axis('equal')
#ax.set_aspect('equal', 'box')
#fig.tight_layout()
#ax.view_init(20, 90)
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
axisEqual3D(ax)
#ax.set_xlim3d(-5, 3)
#ax.set_ylim3d(1, -12)
#ax.set_zlim3d(-1.5, 1.5)
ax.set_xlabel('x (cm)',fontsize=20)
ax.set_ylabel('y (cm)',fontsize=20)
ax.set_zlabel('z (cm)',fontsize=20)
plt.show()

# 2. Display the cameras


#!/usr/bin/env python3

"""
NB THIS IS CURRENTLY WRONG
Author: Ian
Purpose: Coding challenge as per https://www.hackerrank.com/challenges/magic-square-forming/problem
Input: A 3*3 matrix of ints ranged 1 to 9 inclusive
Output: int, the minimum error correction to make the matrix a magic square
"""

import math
import pdb

def formingMagicSquare(s):
	"""Input: 3x3 matix of ints range 1 through 9
	Output: positive int"""
	# 1. Choose magic_num
	cols = []
	for ind,row in enumerate(s):
		col = [x[ind] for x in s]
		cols.append(col)
	fwd_diag = [s[x][x] for x in range(0, len(s))]
	rev_diag = [s[::-1][x][x] for x in range(0, len(s))]
	row_sums = [sum(x) for x in s]
	col_sums = [sum(x) for x in cols]
	diag_sums = [sum(x) for x in [rev_diag, fwd_diag]]
	mean = sum(row_sums + col_sums + diag_sums)/8
	magic_num = int(round(mean))

	# 2. Func to find MEC for given magic_num
	# collate all the triplets that are < magicnum
	# find the intersections of these, add one
	# repeat until none
	# rows = {}
	# cols = {}
	# for i in range(0,len(s)):
	# 	rows[i] = [(i,x) for x in range(0,len(s))]
	# 	cols[i] = [(x,i) for x in range(0,len(s))]
	rows = []
	cols = []
	for i in range(0,len(s)):
		rows.append([(i,x) for x in range(0,len(s))])
		cols.append([(x,i) for x in range(0,len(s))])
	diag_one = [(0,0), (1,1), (2,2)]
	diag_two = [(0,2), (1,1), (2,0)]
	all_triples = rows + cols + [diag_one] + [diag_two]

	# iterate through triples, find those less than magic
	less_than = [x for x in all_triples if sum_from_mat(x,s) < magic_num]
	more_than = [x for x in all_triples if sum_from_mat(x,s) > magic_num]
	score = 0
	while any(less_than + more_than):
		if less_than:
			intersect, move_on = find_intersect(less_than, fwd_diag, rev_diag)
			if move_on:
				lessers = less_than[:]
				less_than = []
			else:
				s[intersect[0]][intersect[1]] += 1
				score += 1
				less_than = [x for x in all_triples if sum_from_mat(x,s) < magic_num]
		else:
			intersect, move_on = find_intersect(more_than, fwd_diag, rev_diag)
			if move_on:
				morers = more_than[:]
				more_than = []
			else:
				s[intersect[0]][intersect[1]] -= 1
				score += 1
				more_than = [x for x in all_triples if sum_from_mat(x,s) > magic_num]

	# For each entry in morers and for each in the lessers, add 2 to score
	pdb.set_trace()

	# pdb.set_trace()
	# rows = {i: [(0,x) for x in range(0,len(s))], for i in range(0,len(s))}
	# row_a = [(0,x) for x in range(0,len(s))]
	# row_b = [(1,x) for x in range(0,len(s))]
	# row_c = [(2,x) for x in range(0,len(s))]
	# for

	# 3. Repeat for magic nums within possible realm of beating ans
	return score

def sum_from_mat(index_list, s):
	nums = [s[x[0]][x[1]] for x in index_list]
	return sum(nums)

def find_intersect(triples, fwd_diag, rev_diag):
	""" Find the position most common among a list of triple"""
	spilled_positions = [item for sublist in triples for item in sublist]
	intersects = sorted(spilled_positions, key=spilled_positions.count, reverse=True)
	intersect = intersects[0]
	counts = intersects.count(intersect)
	pdb.set_trace()
	# Alert if the intersect would change a working triple
	move_on = False
	if counts >= 3:
		move_on = False
	elif counts == 2 and ((intersect in fwd_diag) or (intersect in rev_diag)):
		move_on = False
	else:
		move_on = True
	return intersect, move_on
	# pdb.set_trace()
# def mec_matrix_to_magic_square (mat, magic_num):

if __name__ == "__main__":
	mat = [[4, 9, 2], [3, 5, 7], [8, 1, 5]] # ans 1
	mat = [[4, 8, 2], [4, 5, 7], [6, 1, 6]]  # ans 4
	ans = formingMagicSquare(mat)
	print(ans)

# def formingMagicSquare(s):
# 	# First get the average sum of the rows and cols
# 	cols = []
# 	for i in range(0, len(s)):
# 		cols.append([x[i] for x in s])
# 	rows = s
# 	rows_n_cols = rows + cols

# 	sums = [sum(x) for x in rows_n_cols]
# 	mean_sum = sum(sums) / len(sums)
# 	mean_sum = int(round(mean_sum))
# 	magic_num = mean_sum

# 	# Assuming magic_num is the mean, but need to check alternatives too
# 	current_ans = dist_to_magic_square(rows, cols, magic_num)

# 	# Make list of possible magic nums - all ints within float mean +/- min ans
# 	possible_magic_nums = []
# 	rows_sums = [sum(x) for x in rows] # redundantly written below but who's checking
# 	cols_sums =	[sum(x) for x in cols]
# 	lower_comparator = math.floor(sum(min(rows_sums, cols_sums)) / 3)
# 	higher_comparator = math.ceil(sum(max(rows_sums, cols_sums)) / 3)
# 	possible_magic_nums = list(range((lower_comparator - current_ans), (higher_comparator + current_ans) + 1))
# 	possible_magic_nums.remove(magic_num)

# 	for magic_number in possible_magic_nums:
# 		tmp_ans = dist_to_magic_square(rows, cols, magic_number)
# 		if tmp_ans < current_ans:
# 			current_ans = tmp_ans
# 	return current_ans

# def dist_to_magic_square(rows, cols, magic_num):
# 	# Hypoth - cost of single change is 1 if synergy, else 2
# 	rows_sums = [sum(x) for x in rows]
# 	cols_sums =	[sum(x) for x in cols]
# 	row_deltas = [(magic_num - x) for x in rows_sums]
# 	col_deltas = [(magic_num - x) for x in cols_sums]
# 	row_deltas_abs = [abs(magic_num - x) for x in rows_sums]
# 	col_deltas_abs = [abs(magic_num - x) for x in cols_sums]
# 	rows_total_delta = sum(row_deltas_abs)
# 	cols_total_delta = sum(col_deltas_abs)

# 	cost = 0
# 	neg_row_deltas = [x for x in row_deltas if x < 0]
# 	neg_col_deltas = [x for x in col_deltas if x < 0]
# 	pos_row_deltas = [x for x in row_deltas if x > 0]
# 	pos_col_deltas = [x for x in col_deltas if x > 0]
# 	sum_row_neg = sum(neg_row_deltas)
# 	sum_col_neg = sum(neg_col_deltas)
# 	sum_row_pos = sum(pos_row_deltas)
# 	sum_col_pos = sum(pos_col_deltas)

# 	if rows_total_delta >= cols_total_delta:
# 		adders = 2 * abs(sum_row_neg)
# 		adders -= min(abs(sum_row_neg), abs(sum_col_neg))
# 		cost += adders

# 		subtractors = 2 * (abs(sum_row_pos))
# 		subtractors -= min(abs(sum_row_pos), abs(sum_col_pos))
# 		cost += subtractors
# 	else:
# 		adders = 2 * abs(sum_col_neg)
# 		adders -= min(abs(sum_col_neg), abs(sum_row_neg))
# 		cost += adders

# 		subtractors = 2 * (abs(sum_col_pos))
# 		subtractors -= min(abs(sum_col_pos), abs(sum_row_pos))
# 		cost += subtractors

# 	return cost


from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import csv

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
browser = None

def main():
    for i in range(7,10):
        getPageData(i)

def getPageData(pageindex):
    global browser
    browser = webdriver.Chrome(options=chrome_options)
    # browser = webdriver.Chrome()
    url = f'https://hub.docker.com/search?type=image&page={pageindex}'
    print(url)
    browser.get(url)
    now_handle = browser.current_window_handle
    browser.implicitly_wait(20)  # 智能等待20秒
    itemElements = browser.find_elements_by_xpath(r"//div[@id='searchResults']/div/a")

    imageList = []

    for itemElement in itemElements:
        browser.switch_to.window(now_handle)  # 切换到原来的窗口
        nameElement = itemElement.find_element_by_xpath(r"div/div[3]/div/div/div[1]")
        nameStr = nameElement.text #image名称
        # //div[@id='searchResults']/div/a/div/div[2]/div[3]/div[2]/span[1]
        try:
            starElement = itemElement.find_element_by_xpath(r"div/div[2]/div[3]/div[2]/span[1]")

        except:
            starElement = itemElement.find_element_by_xpath(r"div/div[2]/div[3]/div/span[1]")
        starStr = starElement.text  # image star
        dockerPullCmd,versionList = dealitemElement(itemElement,nameStr) # image pull command , version dockerfile link list
        imageDict = {"nameStr":nameStr,"starStr":starStr,"dockerPullCmd":dockerPullCmd,"versionList":versionList}
        print(imageDict)
        imageList.append(imageDict)
    SaveOnePageDataToCsv(imageList)

    browser.quit()

def SaveOnePageDataToCsv(imageList):
    for imageDict in imageList:
        printCsvImage("docker_hub",imageDict)

def printCsvTitle(filename):
    path = "./csv/"
    isExists=os.path.exists(path)
    if not isExists:
        os.makedirs(path)
    with open("./csv/"+filename+".csv",'w',newline='',encoding='utf8') as f:
        row_title = ['name','star','pull command','version','dockerfilelink']
        write=csv.writer(f)
        write.writerow(row_title)

def printCsvImage(filename,imageDict):
    # 不存在路径，创建路径
    path = "./csv/"
    isExists = os.path.exists(path)
    if not isExists:
        os.makedirs(path)
    # 不存在文件则创建文件，添加文件头
    path = "./csv/" + filename + ".csv"
    isExists = os.path.exists(path)
    if not isExists:
        printCsvTitle(filename)

    if imageDict['versionList'] == None:
        with open("./csv/" + filename + ".csv", 'a', newline='', encoding='utf8') as f:
            row = [imageDict['nameStr'], imageDict['starStr'], imageDict['dockerPullCmd'],"",""]
            write = csv.writer(f)
            write.writerow(row)
    else:
        for version in imageDict['versionList']:
            with open("./csv/" + filename + ".csv", 'a', newline='', encoding='utf8') as f:
                row = [imageDict['nameStr'], imageDict['starStr'], imageDict['dockerPullCmd'],version['version'],version['link']]
                write = csv.writer(f)
                write.writerow(row)

def dealitemElement(itemElement,nameStr):
    imagePageUrl = itemElement.get_attribute("href")
    js = f'window.open("{imagePageUrl}");'
    browser.execute_script(js)

    browser.implicitly_wait(20)  # 智能等待20秒

    originHandle = browser.current_window_handle
    handles = browser.window_handles
    imageHandle = None
    for handle in handles:
        if handle != originHandle:
            imageHandle = handle

    browser.switch_to.window(imageHandle)
    try:
        dockerPullCmd = browser.find_element_by_xpath(r"/html/body/div[1]/div[1]/div/div[2]/div/div/div/div[2]/div/div[1]/div[2]/div/div[2]/div/div[2]/input")\
            .get_attribute("value")
    except:
        dockerPullCmd = None
    try:
        versionUlElement = browser.find_element_by_xpath(
        r"/html/body/div[1]/div[1]/div/div[2]/div/div/div/div[3]/div/div[1]/div/div/div/div/div/ul[2]")
        versionList = getVersionAndDockerfileLink(versionUlElement)
    except:
        versionList = None
    browser.close()
    return dockerPullCmd,versionList

def getVersionAndDockerfileLink(versionUlElement):
    versionElements = versionUlElement.find_elements_by_xpath("li/a")
    versionList = []
    for versionElement in versionElements:
        dockerfileLinkStr = versionElement.get_attribute("href")
        version = versionElement.text
        versionList.append({"link" : dockerfileLinkStr, "version" : version})
    return versionList

if __name__ == '__main__':
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Remove all temporary files in a project's folder.

Scan the current directory for the file build_rules.py and look for
the function ``clean`` and call it.

Full documentation on the operation of [``cleanme`` is here](cleanme_man.md).

See Also:
    main, makeprojects.buildme, makeprojects.rebuildme

@package makeprojects.cleanme
"""

# pylint: disable=useless-object-inheritance
# pylint: disable=consider-using-f-string

from __future__ import absolute_import, print_function, unicode_literals

import os
import sys
import argparse
from operator import attrgetter
from burger import convert_to_array, import_py_script, norm_paths
from .config import BUILD_RULES_PY, save_default, _XCODEPROJECT_FILE, \
    _XCODEPROJ_MATCH
from .__init__ import __version__
from .util import get_build_rules, getattr_build_rules_list, was_processed, \
    fixup_args, clear_build_rules_cache, getattr_build_rules
from .build_objects import BuildError
from .modules import MODULES
from .python import create_clean_rules_objects, BuildPythonFile

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

def create_parser():
    """
    Create the parser to process the command line for buildme

    The returned object has these member variables

    - version boolean if version is requested
    - recursive boolean for directory recursion
    - verbose boolean for verbose output
    - preview boolean for previewing the clean process
    - generate_build_rules boolean create build rules and exit
    - rules_file string override build_rules.py
    - fatal boolean abort if error occurs in processing
    - directories string array of directories to process
    - files string array of project files to process
    - configurations string array of configurations to process
    - args string array of unknown parameters

    Returns:
        argparse.ArgumentParser() object
    """

    # Parse the command line
    parser = argparse.ArgumentParser(
        description="Remove project output files. "
        "Copyright by Rebecca Ann Heineman")

    parser.add_argument("--version", action="version",
                        version="%(prog)s " + __version__)

    parser.add_argument("-r", "-all", dest="recursive", action="store_true",
                        default=False, help="Perform a recursive clean")

    parser.add_argument("-n", "-preview", dest="preview", action="store_true",
                        default=False, help="Preview clean commands.")

    parser.add_argument("-v", "-verbose", dest="verbose", action="store_true",
                        default=False, help="Verbose output.")

    parser.add_argument("--generate-rules", dest="generate_build_rules",
                        action="store_true", default=False,
                        help="Generate a sample configuration file and exit.")

    parser.add_argument(
        "--rules-file",
        dest="rules_file",
        metavar="<file>",
        default=BUILD_RULES_PY,
        help="Specify a configuration file.")

    parser.add_argument("-q", dest="fatal", action="store_true",
                        default=False, help="Quit immediately on any error.")

    parser.add_argument("-f", dest="files", action="append",
                        metavar="<filename>",
                        help="Project file to process.")

    parser.add_argument("-d", dest="directories", action="append",
                        metavar="<directory>", default=[],
                        help="List of directories to clean.")

    parser.add_argument("-c", dest="configurations", action="append",
                        metavar="<configuration>",
                        help="Configuration to process.")

    parser.add_argument("args", nargs=argparse.REMAINDER,
                        help="project filenames")

    return parser

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

def add_clean_rules(projects, working_directory,
                    file_name, args, build_rules=None):
    """
    Add a build_rules.py to the clean list.

    Given a build_rules.py to parse, check for the function "clean"
    and use that for scanning for functions to call.

    All valid entries will be appended to the projects list.

    Args:
        projects: List of projects to clean.
        working_directory: Directory to perform actions on
        file_name: Pathname to the build_rules.py file.
        args: Args for determining verbosity for output.
        build_rules: Preloaded build_rules.py object.
    See Also:
        add_project
    """

    # Was the build_rules already loaded?
    if not build_rules:
        build_rules = import_py_script(file_name)

    dependencies = []

    # Was a build_rules.py file found?
    if build_rules:
        if args.verbose:
            print("Using configuration file {}".format(file_name))

        # Test for functions and append all that are found
        if working_directory is None:
            working_directory = os.path.dirname(file_name)
        parms = {
            "working_directory": working_directory}

        # Get the dependency list, if any
        dependencies = getattr_build_rules(
            build_rules, ("CLEANME_DEPENDENCIES", "DEPENDENCIES"), None)[0]

        if dependencies:
            # Ensure all paths are normalized
            dependencies = norm_paths(
                working_directory,
                convert_to_array(dependencies))
        else:
            dependencies = []

        # Add build object found in the build_rules.py file
        projects.extend(
            create_clean_rules_objects(
                file_name,
                build_rules,
                parms,
                args.verbose))
    return dependencies

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

def add_project(projects, processed, file_name, args):
    """
    Detect the project type and add it to the list.

    Args:
        projects: List of projects to build.
        processed: List of directories already processed.
        file_name: Pathname to the build_rules.py file.
        args: Args for determining verbosity for output.
    Returns:
        True if the file was buildable, False if not.
    """

    # pylint: disable=too-many-return-statements
    # pylint: disable=too-many-branches

    # Check if the file is accepted by a build module
    for module in MODULES:

        # Match the file?
        if module.match(file_name):

            # Test for recursion
            if was_processed(processed, file_name, args.verbose):
                return True

            # Create the build objects
            projects.extend(
                module.create_clean_object(
                    file_name,
                    configurations=args.configurations,
                    verbose=args.verbose))
            return True

    return False

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

def process_projects(results, projects, args):
    """
    Process a list of projects

    Sort the projects by priority and build all of them.
    """
    # Sort the list by priority (The third parameter is priority from 1-99)
    error = 0
    projects = sorted(projects, key=attrgetter("priority"))

    # If in preview mode, just show the generated build objects
    # and exit
    if args.preview:
        for project in projects:
            print(project)
        return False

    # Clean all the projects
    # Note, python objects are a special case, if any return a
    # non "None" error code, don't call any others

    python_none = False
    for project in projects:

        # Skip all python clean objects if a numeric error code
        # was already obtained
        if isinstance(project, BuildPythonFile) and python_none:
            continue

        berror = project.clean()
        error = 0
        if berror is not None:
            results.append(berror)
            error = berror.error

            # Check the error code, was it None?
            if error is not None:
                if isinstance(project, BuildPythonFile):
                    # Don't parse any more python "clean" scripts
                    python_none = True

        # Abort on error?
        if error and args.fatal:
            return True
    return False

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

def process_files(results, processed, files, args):
    """
    Process a list of files.
    """
    projects = []
    for item in files:
        base_name = os.path.basename(item)
        if base_name == args.rules_file:
            if not was_processed(processed, item, args.verbose):
                process_dependencies(
                    results, processed, add_clean_rules(
                        projects, None, item, args), args)
        elif not add_project(projects, processed, item, args):
            print("\"{}\" is not supported.".format(item))
            return True
    return process_projects(results, projects, args)

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

def process_directories(results, processed, directories, args):
    """
    Process a list of directories.

    Args:
        results: list object to append BuildError objects
        processed: List of directories already processed.
        directories: iterable list of directories to process
        args: parsed argument list for verbosity
    Returns:
        True if processing should abort, False if not.
    """

    # pylint: disable=too-many-branches
    # pylint: disable=too-many-nested-blocks

    # Process the directory list
    for working_directory in directories:

        # Was this directory already processed?
        if was_processed(processed, working_directory, args.verbose):
            # Technically not an error to abort processing, so skip
            continue

        # Only process directories
        if not os.path.isdir(working_directory):
            msg = "{} is not a directory.".format(working_directory)
            results.append(BuildError(10, working_directory, msg=msg))
            if args.fatal:
                return True
            continue

        # Are there build rules in this directory?
        build_rules_list = get_build_rules(
            working_directory, args.verbose, args.rules_file, "CLEANME")

        # Is recursion allowed?
        allow_recursion = not getattr_build_rules_list(
            build_rules_list, ("CLEANME_NO_RECURSE", "NO_RECURSE"), False)

        allow_files = getattr_build_rules_list(
            build_rules_list, ("CLEANME_PROCESS_PROJECT_FILES", "PROCESS_PROJECT_FILES"), True)

        # Pass one, create a list of all projects to build
        projects = []

        # Process all of the dependencies first, then this folder
        for build_rules in build_rules_list:
            process_dependencies(
                results,
                processed,
                add_clean_rules(
                    projects,
                    working_directory,
                    build_rules.__file__,
                    args,
                    build_rules),
                args)

        # Iterate over the directory to find all the other files
        if allow_files or (args.recursive and allow_recursion):
            for entry in os.listdir(working_directory):

                full_name = os.path.join(working_directory, entry)

                # If it's a directory, check for recursion
                if os.path.isdir(full_name):

                    # Special case for xcode, if it's a *.xcodeproj
                    if allow_files and _XCODEPROJ_MATCH.match(entry):

                        # Check if it's an xcode project file, if so, add it
                        if not add_project(projects, processed, os.path.join(
                                full_name, _XCODEPROJECT_FILE), args):
                            print(
                                ("\"{}\" is not supported on this platform.")
                                .format(full_name))
                            return True
                        continue

                    if args.recursive and allow_recursion:
                        # Process the directory first
                        if process_directories(
                                results, processed, [full_name],
                                args):
                            # Abort?
                            return True
                    continue

                # It's a file, process it, if possible
                # Don't double process the rules file
                if (args.rules_file != entry) and allow_files:
                    add_project(projects, processed, full_name, args)

        # The list is ready, process it in priority order
        # and then loop to the next directory to process
        temp = process_projects(results, projects, args)
        if temp:
            return temp
    return False

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

def process_dependencies(results, processed, dependencies, args):
    """
    Process a mixed string list of both directories and files.

    Iterate over the dependencies list and test each object if it's a directory,
    and if so, dispatch to the directory handler, otherwise, process as a file.

    Args:
        results: list object to append BuildError objects
        processed: List of directories already processed.
        dependencies: iterable list of files/directories to process
        args: parsed argument list for verbosity
    Returns:
        True if processing should abort, False if not.
    """

    # Test, in case it is None
    if dependencies:
        for item in dependencies:
            if os.path.isdir(item):
                error = process_directories(results, processed, (item,), args)
            elif os.path.isfile(item):
                error = process_files(results, processed, (item,), args)
            else:
                error = 0
            if error:
                return error
    return 0

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

def main(working_directory=None, args=None):
    """
    Command line shell for ``cleanme``.

    Entry point for the program ``cleanme``, this function
    will either get the parameters from sys.argv or the paramater ``args``.

    - ``--version``, show version.
    - ``-r``, Perform a recursive clean.
    - ``-v``, Verbose output.
    - ``-n``, Preview clean commands
    - ``--generate-rules``, Create build_rules.py and exit.
    - ``--rules-file``, Override the configruration file.
    - ``-q``, Quit after the first error
    - ``-f``, List of files to build.
    - ``-d``, List of directories to clean.
    - ``-c``, List of configurations to build
    - Additional terms are considered specific files or configurations to clean.

    Args:
        working_directory: Directory to operate on, or None for os.getcwd()
        args: Command line to use instead of sys.argv
    Returns:
        Zero on no error, non-zero on error
    """

    # Make sure working_directory is properly set
    if working_directory is None:
        working_directory = os.getcwd()

    # Create the parser
    parser = create_parser()

    # Parse everything
    args = parser.parse_args(args=args)

    # Output default configuration
    if args.generate_build_rules:
        if args.verbose:
            print(
                "Saving {}".format(
                    os.path.join(
                        working_directory,
                        args.rules_file)))
        return save_default(working_directory, destinationfile=args.rules_file)

    # Handle extra arguments
    fixup_args(args)

    # Get lists of files/directories to build
    files = args.files
    directories = args.directories

    # If there are no entries, use the working directory
    if not directories and not files:
        directories = [working_directory]

    # List of errors created during building
    results = []
    processed = set()

    # Try building all individual files first
    if not process_files(results, processed, files, args):

        # If successful, process all directories
        process_directories(results, processed, directories, args)

    # Was there a build error?
    error = 0
    for item in results:
        if item.error:
            print("Errors detected in clean.")
            error = item.error
            break
    else:
        if args.verbose:
            print("Clean is successful!")

    # Dump the error log if requested or an error
    if args.verbose or error:
        for item in results:
            if args.verbose or item.error:
                print(item)

    # In case clean is being called from a function,
    # clear the build_rules.py cache
    clear_build_rules_cache()
    return error

# If called as a function and not a class,
# call my main

if __name__ == "__main__":
    sys.exit(main())


import pygame
from random import randint
pygame.mixer.init()
pygame.mixer.music.load("on000003.mp3")
pygame.mixer.music.play()
x= 410#265 555
y= 130
posx=260
posy=800
posya=800
posyb=800
velocidade=20

velocidade_foguetes= 15
fundo= pygame.image.load("fundo.PNG")
foguete= pygame.image.load("fog.PNG")
foguete2= pygame.image.load("fog2.PNG") #vermelho
foguete3= pygame.image.load("fog3.PNG") #azul
foguete4= pygame.image.load("fog4.PNG") #amarelo

janela = pygame.display.set_mode((888,500))
pygame.display.set_caption("JOGO DO TEMPO EM CRIACAO")

janela_aberta = True
while janela_aberta:
    pygame.time.delay(50)

    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            janela_aberta= False
    comandos = pygame.key.get_pressed()

    if comandos[pygame.K_RIGHT] and x<=555:
        x += velocidade
    if comandos[pygame.K_LEFT] and x>=265:
        x -= velocidade

    if posy<=-180 and posya <=-180 and posyb <=-180:
        posy= randint(800,2000)
        posya=randint(800,2000)
        posyb=randint(800,2000)

    posy -=velocidade_foguetes+8
    posya -=velocidade_foguetes +10
    posyb -=velocidade_foguetes +5

    janela.blit(fundo, (0,0))
    janela.blit(foguete, (x,y))
    janela.blit(foguete2,(posx, posy))
    janela.blit(foguete3,(posx+300, posya))
    janela.blit(foguete4,(posx+150, posyb))

    pygame.display.update()
pygame.quit()


from . import ast, parser

_lexer = parser.TQLLexer()
_parser = parser.TQLParser()

def compile(expr: str) -> ast.Node:
    comp = ast.Document(_parser.parse(_lexer.tokenize(expr)))
    comp.validate(ast.Mode.DEPTH)
    return comp


'''
프로그래머스
모의고사

1. 1번 수포자: 순서대로 1~5 / 12345
2. 2번 수포자: 홀수는 2, 짝수는 1,3,4,5 / 21232425
3. 3번 수포자: 3,1,2,4,5 각 2번씩 / 3311224455
'''
def solution(answers):
    stu1 = [1,2,3,4,5]
    stu2 = [2,1,2,3,2,4,2,5]
    stu3 = [3,3,1,1,2,2,4,4,5,5]
    answer = []
    cnt = [0, 0, 0]

    for i in range(len(answers)):
        if answers[i] == stu1[i%5]:
            cnt[0] += 1

        if answers[i] == stu2[i%8]:
            cnt[1] += 1

        if answers[i] == stu3[i%10]:
            cnt[2] += 1

    maximum = max(cnt)
    if cnt[0] == maximum:
        answer.append(1)
    if cnt[1] == maximum:
        answer.append(2)
    if cnt[2] == maximum:
        answer.append(3)
    return answer

print(solution([1,2,3,4,5]))

# 다른 사람의 풀이
# 패턴을 제너레이터로 처리하여 공간복잡도를 고려함

from itertools import cycle

def solution(answers):
    giveups = [
        cycle([1,2,3,4,5]),
        cycle([2,1,2,3,2,4,2,5]),
        cycle([3,3,1,1,2,2,4,4,5,5]),
    ]
    scores = [0, 0, 0]
    for num in answers:
        for i in range(3):
            if next(giveups[i]) == num:
                scores[i] += 1
    highest = max(scores)

    return [i + 1 for i, v in enumerate(scores) if v == highest]


# External modules
from colorama import init, Fore
import time
import os
# Local modules
import crud

def clear():
    os.system("cls")

init(autoreset= True)

def validation(msg, a, b):
    while True:
        clear()
        try:
            logo()
            print("\n" + msg + "\n")
            opc = int(input("Ingrese una opcion: "))
            if opc >= a and opc <= b:
                return opc
            else:
                clear()
                print(Fore.RED + "[ X ] Oops!, Opcion invalida... Intente de nuevo.")
                time.sleep(2)
                clear()

        except ValueError:
            clear()
            print(Fore.RED + "[ X ] Oops!, Opcion invalida... Intente de nuevo.")
            time.sleep(2)
            clear()

def logo():
    print("\t\t" + "#"*65, end="\n\t\t#" + " "*63 + "#\n")
    print("\t\t#\t" + Fore.RED             + " /$$   /$$  /$$$$$$  /$$   /$$  /$$$$$$  /$$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.BLUE            + "| $$  | $$ /$$__  $$| $$$ | $$ /$$__  $$| $$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.YELLOW          + "| $$  | $$| $$  \ $$| $$$$| $$| $$  \ $$| $$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.MAGENTA         + "| $$  | $$| $$$$$$$$| $$ $$ $$| $$$$$$$$| $$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.CYAN            + "| $$  | $$| $$__  $$| $$  $$$$| $$__  $$| $$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.GREEN           + "| $$  | $$| $$  | $$| $$\  $$$| $$  | $$| $$       " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.WHITE           + "|  $$$$$$/| $$  | $$| $$ \  $$| $$  | $$| $$$$$$$$ " + Fore.RESET +"\t#")
    print("\t\t#\t" + Fore.LIGHTMAGENTA_EX + " \______/ |__/  |__/|__/  \__/|__/  |__/|________/ " + Fore.RESET +"\t#", end="\n\t\t#" + " "*63 + "#\n")
    print("\t\t" + "#"*65)

def menu():
    msg = "[ 1 ] Crear\n[ 2 ] Mostrar\n[ 3 ] Modificar\n[ 4 ] Eliminar\n[ 5 ] Salir"

    opc = validation(msg, 1, 5)

    if opc == 1:
        crear()
    elif opc == 2:
        mostrar()
    elif opc == 3:
        modificar()
    elif opc == 4:
        eliminar()
    else:
        exit()

    return opc

def salir_regresar(funcion):
    opc = int(input("\n[1] Regresar\t[2] Salir\n\nSeleccione una opcion: "))
    if opc == 1:
        funcion()
    else:
        exit()

def crear():
    msg = "[ 1 ] Registrar Alumno\n[ 2 ] Registrar Trabajador\n[ 3 ] Dar de alta un profesor\n[ 4 ] Regresar"
    opc = validation(msg, 1, 4)

    clear()
    if opc == 1:
        app.CrearAlumno()
        time.sleep(1)
    elif opc == 2:
        app.CrearTrabajador()
    elif opc == 3:
        app.crearProfesor()
    else:
        menu()

    salir_regresar(crear)

def mostrar():
    msg = "[ 1 ] Mostrar Alumnos\n[ 2 ] Mostrar todos los trabajadores\n[ 3 ] Mostrar Profesores\n[ 4 ] Mostrar Facultades\n[ 5 ] Regresar"
    opc = validation(msg, 1, 6)

    clear()
    if opc == 1:
        print("Mostrando tabla de Alumnos...\n\n")
        time.sleep(2)
        app.mostrarAlumnos()
    elif opc == 2:
        print("Mostrando tabla de Trabajadores...\n\n")
        time.sleep(2)
        app.mostrarTrabajadores()
    elif opc == 3:
        print("Mostrando tabla de Profesores...\n\n")
        time.sleep(2)
        app.mostrarProfesor()
    elif opc == 4:
        print("Mostrando tabla de Facultades...\n\n")
        time.sleep(2)
        app.mostrarFacultades()
    else:
        menu()

    salir_regresar(mostrar)

def modificar():
    msg = "[ 1 ] Modificar datos de alumno\n[ 2 ] Modificar datos de trabajador\n[ 3 ] Regresar"
    opc = validation(msg, 1, 4)

    if opc == 1:
        pass
    elif opc == 2:
        pass
    else:
        modificar()

    salir_regresar(modificar)

def eliminar():
    msg = "[ 1 ] Eliminar un alumno\n[ 2 ] Eliminar trabajador\n[ 4 ] Regresar"
    opc = validation(msg, 1, 4)

    if opc == 1:
        pass
    elif opc == 2:
        pass
    else:
        eliminar()

    salir_regresar(eliminar)

if __name__ == '__main__':

    # Inicializar Crud
    app = crud.db()

    menu()

    app.close_connection()


import os
from flask import Flask, flash, request, redirect, url_for, render_template
from werkzeug.utils import secure_filename
import colorgram
import webcolors

app = Flask(__name__)
UPLOAD_FOLDER = 'static/images/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
MAX_COLOURS = 500

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

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

@app.route('/', methods=['POST'])
def upload_image():
    if 'file' not in request.files:
        flash('No file part')
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        flash('No image selected for uploading')
        return redirect(request.url)
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        flash('Image successfully uploaded and displayed below')
        colors = image_colors(filename)
        return render_template('upload_image.html', filename=filename, colors=colors, color_count=0)
    else:
        flash('Allowed image types are -> png, jpg, jpeg, gif')
        return redirect(request.url)

@app.route('/display/<filename>')
def display_image(filename):
    return redirect(url_for('static', filename='images/' + filename), code=301)

def closest_colour(requested_colour):
    min_colours = {}
    for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
        r_c, g_c, b_c = webcolors.hex_to_rgb(key)
        rd = (r_c - requested_colour[0]) ** 2
        gd = (g_c - requested_colour[1]) ** 2
        bd = (b_c - requested_colour[2]) ** 2
        min_colours[(rd + gd + bd)] = name
    return min_colours[min(min_colours.keys())]

def image_colors(filename):
    rgb_colors = colorgram.extract('static/images/'+filename, MAX_COLOURS)
    colors = {}
    for color in rgb_colors:
        rgb_color = (color.rgb.r, color.rgb.b, color.rgb.b)
        try:
            colors[webcolors.rgb_to_name(rgb_color, spec='css3')] = webcolors.rgb_to_hex(rgb_color)
        except ValueError:
            colors[closest_colour(rgb_color)] = webcolors.rgb_to_hex(rgb_color)
    # print(colors)
    return colors

if __name__ == "__main__":
    app.run(debug=True)


n,m,q=[int(x) for x in input().split()]
num=[]
for i in range(m):
	li,ri=[int(x) for x in input().split()]
	num.append((li,ri))

howmany=[{} for x in range(n+1)]
for i in range(1,n+1):
	for li,ri in num:
		if li>=i:
			if ri not in howmany[i]:
				howmany[i][ri]=1
			else:
				howmany[i][ri]+=1

for i in range(q):
	pi,qi=[int(x) for x in input().split()]
	ans=0
	for ri in howmany[pi]:
		if ri<=qi:
			ans+=howmany[pi][ri]
	print(ans)


'''
This module addresses problems from 5.1.2.
'''

import datetime

def main():

    # The user is prompted to enter date and time with specific format.
    ui = input('Enter a datetime with the following format: YYYY-mm-dd  hh:mm:ss:ffffff  ')

    # Here, user info is output to screen.
    d = datetime.datetime.strptime(ui, '%Y-%m-%d %H:%M:%S:%f')
    print(d)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author:任向民
# datetime:2019/4/3 15:56
# software: PyCharm

TESTER_CYCLE = 20
GETTER_CYCLE = 20
TESTER_ENABLED = True
GETTER_ENABLED = True
API_ENABLED = True
API_HOST = '127.0.0.1'
API_PORT = 5555

from multiprocessing import Process
from ip_io import app
from save_run import Getter
from Test import Tester
import time

class Scheduler():
    def schedule_tester(self, cycle = TESTER_CYCLE):
        tester = Tester()
        while True:
            print('开始测试')
            tester.run()
            time.sleep(cycle)

    def schedule_getter(self, cycle=GETTER_CYCLE):

        getter = Getter()
        while True:
            print('开始抓取代理')
            getter.run()
            time.sleep(cycle)

    def schedule_api(self):
        app.run(API_HOST, API_PORT)

    def run(self):
        print('运行代理池')
        if TESTER_ENABLED:
            tester_process = Process(target=self.schedule_tester)
            tester_process.start()

        if GETTER_ENABLED:
            getter_process = Process(target=self.schedule_getter)
            getter_process.start()

        if API_ENABLED:
            api_process = Process(target=self.schedule_api)
            api_process.start()