import numpy as np
import cv2
import math

class Paint_CV:
    def __init__(self):
        pass

    def CropImage(self, image, coords):
        return image[min(coords[1], coords[3]):max(coords[1], coords[3])+1, min(coords[0], coords[2]):max(coords[0], coords[2])+1]

    def SaveImage(self, filename, image):
        return cv2.imwrite(filename, image)

    def LoadImage(self, filepath):
        return cv2.imread(filepath)

    def ResizeImage(self, image, dim):
        return cv2.resize(image, (dim[0], dim[1]),cv2.INTER_AREA)

    def ConvertColor(self, type, image):
        if type==0:
            return image
        elif type==1:
            return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        elif type==2:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
        elif type==3:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HSV)[:,:,0]
        elif type==4:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HSV)[:,:,1]
        elif type==5:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HSV)[:,:,2]
        elif type==6:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HLS)
        elif type==7:
            return cv2.cvtColor(image, cv2.COLOR_RGB2HLS)[:,:,1]
        elif type == 8:
            return cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
        elif type == 9:
            return cv2.cvtColor(image, cv2.COLOR_RGB2LUV)
        elif type == 10:
            return cv2.cvtColor(image, cv2.COLOR_RGB2YCrCb)
        elif type == 11:
            return cv2.cvtColor(image, cv2.COLOR_RGB2XYZ)

    def OverlayImage(self, image, background, coords):
        top, bottom, left, right = coords[1], coords[1] + image.shape[0], coords[0], coords[0] + image.shape[1]
        if left>background.shape[1] or right<0 or top>background.shape[0] or bottom<0:
            return background
        if left<0:
            image = self.CropImage(image, (abs(left), 0, image.shape[1], image.shape[0]))
            left = 0
        if right>background.shape[1]:
            image = self.CropImage(image, (0, 0, image.shape[1]-(right-background.shape[1])-1, image.shape[0]))
            right = background.shape[1]
        if top<0:
            image = self.CropImage(image, (0, abs(top), image.shape[1], image.shape[0]))
            top = 0
        if bottom>background.shape[0]:
            image = self.CropImage(image, (0, 0, image.shape[1], image.shape[0]-(bottom-background.shape[0])-1))
            bottom = background.shape[0]
        background[top:bottom, left:right] = image
        return background

    def RotateImage(self, image, coords, index):
        # new_coord = (coords[0], coords[1])
        if index < 4:
            ang = 0
            lst = []
            center = (coords[0] + image.shape[1] / 2, coords[1] + image.shape[0] / 2)
            if index == 1:
                ang = -90, 3
            elif index == 2:
                ang = 90, 1
            elif index == 3:
                ang = 180, 2
            M = cv2.getRotationMatrix2D(center, ang[0], 1)
            coordes = np.array([[coords[0], coords[1], 1], [coords[0] + image.shape[1], coords[1], 1], [coords[0] + image.shape[1], coords[1] + image.shape[0], 1], [coords[0], coords[1] + image.shape[0], 1]])
            for coord in coordes:
                lst.append(np.array(np.round(M.dot(coord), 0)).astype(int).tolist())
            coords = (min(lst)[0], min(lst)[1], max(lst)[0],max(lst)[1])
            image = np.rot90(image, ang[1]).copy()
        else:
            if index == 4:
                image = cv2.flip(image, 0)  # flip vertical
            elif index == 5:
                image = cv2.flip(image, 1)  # flip horizontal
        return image, coords

    def drawPrimitive(self, image, coords, type, color=(255,255,255), thick=None):      # dotted square, line, filled-square, square,
        if type == 1:
            color = (150,150,150)
            width = 5
            thick = 1
            LR, UD, dst = self.calcRegion(coords)
            if sum(dst) == 0:
                return
            gap = dst[0] / width
            for i in range(math.ceil(gap / 2)):
                cv2.line(image, (coords[0] + width * 2 * LR * i, coords[1]), (coords[0] + width * 2 * LR * i + width * LR, coords[1]), color, thick, cv2.LINE_AA)
                cv2.line(image, (coords[2] + width * 2 * LR * i * -1, coords[3]), (coords[2] + width * 2 * LR * i * -1 + width * LR * -1, coords[3]), color, thick, cv2.LINE_AA)
            gap = dst[1] / width
            for i in range(math.ceil(gap / 2)):
                cv2.line(image, (coords[0], coords[1] + width * 2 * UD * i), (coords[0], coords[1] + width * 2 * UD * i + width * UD), color, thick, cv2.LINE_AA)
                cv2.line(image, (coords[2], coords[3] + width * 2 * UD * i * -1), (coords[2], coords[3] + width * 2 * UD * i * -1 + width * UD * -1), color, thick, cv2.LINE_AA)
        elif type==2:
            color = (150, 150, 150)
            width = 2
            LR, UD, dst = self.calcRegion(coords)
            gap = dst[0] / width
            for i in range(math.ceil(gap / 2)):
                cv2.line(image, (coords[0] + width * 2 * LR * i, coords[1]), (coords[0] + width * 2 * LR * i + width * LR, coords[1]), color, 1, cv2.LINE_AA)
            gap = dst[1] / width
            for i in range(math.ceil(gap / 2)):
                cv2.line(image, (coords[0], coords[1] + width * 2 * UD * i), (coords[0], coords[1] + width * 2 * UD * i + width * UD), color, 1, cv2.LINE_AA)
        elif type == 3:
            cv2.line(image, (coords[0], coords[1]), (coords[2], coords[3]), color, thick, cv2.LINE_AA)
        elif type == 5:
            cv2.rectangle(image, (coords[0], coords[1]), (coords[2], coords[3]), color, thick, cv2.LINE_AA)
        elif type == 4:
            center, radius = self.recalc_Center_Radius(coords)
            cv2.circle(image, center, max(radius), color, thick, cv2.LINE_AA)
        elif type == 6:
            cv2.polylines(image, [self.Triangle(coords)], True, color, thick, cv2.LINE_AA)
        elif type == 8:
            cv2.fillPoly(image, [self.Triangle(coords)], color)
        elif type == 7:
            cv2.polylines(image, [self.Diamond(coords)], True, color, thick, cv2.LINE_AA)
        elif type == 9:
            cv2.fillPoly(image, [self.Diamond(coords)], color)

    def drawText(self, image, text, coords, fontstyle, scale, color, thick):
        font = None
        if fontstyle == 0:
            font = cv2.FONT_HERSHEY_COMPLEX
        elif fontstyle == 1:
            font = cv2.FONT_HERSHEY_COMPLEX_SMALL
        elif fontstyle == 2:
            font = cv2.FONT_HERSHEY_DUPLEX
        elif fontstyle == 3:
            font = cv2.FONT_HERSHEY_PLAIN
        elif fontstyle == 4:
            font = cv2.FONT_HERSHEY_SCRIPT_COMPLEX
        elif fontstyle == 5:
            font = cv2.FONT_HERSHEY_SCRIPT_SIMPLEX
        elif fontstyle == 6:
            font = cv2.FONT_HERSHEY_TRIPLEX
        elif fontstyle == 7:
            font = cv2.FONT_ITALIC
        cv2.putText(image, text, coords, font, scale, color, thick)

    def recalc_Center_Radius(self, coords):
        LR, UD, dst = self.calcRegion(coords)
        radius = [dst[0]//2, dst[1]//2]
        center = (int(coords[0]+radius[0]*LR), int(coords[1]+radius[1]*UD))
        return center, radius

    def Triangle(self, coords):
        center, radius = self.recalc_Center_Radius(coords)
        c = [center[0], center[1]-radius[1]]
        b = [center[0] +radius[0], center[1]+radius[1]]
        a = [center[0] -radius[0], center[1]+radius[1]]
        return np.array([a,b,c], np.int32)

    def Diamond(self, coords):
        center, radius = self.recalc_Center_Radius(coords)
        return np.array([[center[0]-radius[0], center[1]], [center[0], center[1]-radius[1]], [center[0]+radius[0], center[1]], [center[0], center[1]+radius[1]]], np.int32)

    def ReLocateCoords(self, coords):
        LR, UD, dst = self.calcRegion(coords)
        if LR==-1:
            coords[0] -= dst[0]
            coords[2] += dst[0]
        if UD == -1:
            coords[1] -= dst[1]
            coords[3] += dst[1]
        return coords

    def calcRegion(self, coords):
        LR = UD = 0
        dst = [0, 0]
        x1 = coords[0]
        y1 = coords[1]
        x2 = coords[2]
        y2 = coords[3]
        if x2 < x1:
            LR = -1
            dst[0] = x1 - x2
        elif x2 > x1:
            LR = 1
            dst[0] = x2 - x1
        if y2 < y1:
            UD = -1
            dst[1] = y1 - y2
        elif y2 > y1:
            UD = 1
            dst[1] = y2 - y1
        return LR, UD, dst

    def Color_picker(self, color):
        image = np.zeros((300, 300, 3), np.uint8)
        image[:] = color
        self.drawPrimitive(image, (int(300*.01), int(300*.01), int(300*.99), int(300*.99)), 5, (0,0,0), 10)
        self.drawPrimitive(image, (int(300*.1), int(300*.1), int(300*.9), int(300*.9)), 5, (255,255,255), 20)
        self.SaveImage("TP_assets/color.png", image)


#TITLE: 뱀 (https://www.acmicpc.net/problem/3190)
#LEVEL: G4
#TAG: implementation, simulation, queue
#DATE: 20221006
#AUTHOR: squareyun

from collections import deque

n=int(input())
k=int(input())
graph=[[0] * n for _ in range(n)]
for _ in range(k):
    a,b=map(int,input().split())
    graph[a-1][b-1] = 2 #사과 위치
l=int(input())
logs=[]
for _ in range(l):
    a,b=input().split()
    logs.append([int(a),b])

dx = [0, -1, 0, 1] #동북서남
dy = [1, 0, -1, 0]

def solution():
    cnt = 0
    logIdx = 0
    x, y = 0, 0
    dir = 0
    graph[0][0] = 1
    snake=deque([(0,0)])
    while True:
        cnt += 1
        nx = x + dx[dir]
        ny = y + dy[dir]

        if logIdx < len(logs) and cnt == logs[logIdx][0]:
            if logs[logIdx][1] == 'L':
                dir = (dir + 1) % 4
            else:
                dir = (dir - 1) % 4
            logIdx += 1

        if 0 > nx or nx >= n or 0 > ny or ny >= n: #벽에 부딪힐 때
            return cnt
        elif graph[nx][ny] == 1: #자기자신의 몸과 부딪힐 때
            return cnt
        elif graph[nx][ny] == 2: #사과 만날 때
            graph[nx][ny] = 1
            snake.append((nx,ny))
        else:
            graph[nx][ny] = 1
            snake.append((nx,ny))
            graph[snake[0][0]][snake[0][1]] = 0
            snake.popleft()

        x, y = nx, ny

print(solution())


class Solution(object):
    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        nums = list(range(1, n+1))
        n = len(nums)
        res = []
        # for each valid combination
        for i in range(2**n):
            _res = []
            count = 0
            # check count == k
            for j in range(32):
                count += 1 if i & 1<<j else 0
            # add the nums pos
            if count == k:
                for j in range(32):
                    if i & 1<<j:
                        _res.append(nums[j])

                res.append(_res)

        return res

# dfs
class Solution(object):

    def __init__(self):
        self.res = []
        self.path = []

    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        nums = list(range(1, n + 1))
        n = len(nums)
        self.dfs(nums, 0, n, k)

        return self.res

    def dfs(self, nums, i, n, k):
        if len(self.path) == k:
            self.res.append(copy.deepcopy(self.path))
            return

        if i >= n:
            return

        for j in range(i, n):
            self.path.append(nums[j])
            self.dfs(nums, j + 1, n, k)
            self.path.pop()


import sys
from datetime import datetime

try:
    option = sys.argv[1]
except IndexError:
    option = "help"

if option=='add':
    try:
        with open('todo.txt','a') as todoFile:
            todoFile.write(str(sys.argv[2])+"\n")
            print('Added todo: "{}"'.format(sys.argv[2]))
            todoFile.close()
    except IndexError:
        print('Error: Missing todo string. Nothing added!')

elif option=='ls':
    try:
        with open('todo.txt','r') as todoFile:
            todoItems=list(todoFile)
            if len(todoItems)>0:
                for i in range(len(todoItems),0,-1):
                    print("[{}] {}".format(i,todoItems[i-1]),end="")
            else:
                raise FileNotFoundError()
    except FileNotFoundError:
        print('There are no pending todos!')

elif option=='help':
    help = """Usage :-\n$ ./todo add \"todo item\"  # Add a new todo\n$ ./todo ls               # Show remaining todos\n$ ./todo del NUMBER       # Delete a todo\n$ ./todo done NUMBER      # Complete a todo\n$ ./todo help             # Show usage\n$ ./todo report           # Statistics"""
    print (help)

elif option=='del':
    try:
        index = int(sys.argv[2])
        with open('todo.txt','r') as oldTodo:
            todoItems=list(oldTodo)
            try:
                if index<=0: raise IndexError
                del todoItems[index-1]
                with open('todo.txt','w') as newTodo:
                    for item in todoItems:
                        newTodo.write(item)
                    newTodo.close()
                    print("Deleted todo #{}".format(index))
            except IndexError:
                print('Error: todo #{} does not exist. Nothing deleted.'.format(index))
            oldTodo.close()
    except IndexError:
        print("Error: Missing NUMBER for deleting todo.")
    except FileNotFoundError:
        print('There are no pending todos!')

elif option=='done':
    try:
        index = int(sys.argv[2])
        with open('todo.txt','r') as todoFile:
            todoItems=list(todoFile)
            try:
                if index<=0: raise IndexError
                todo=todoItems[index-1]
                del todoItems[index-1]
                with open('done.txt','a') as doneFile:
                    doneFile.write('x {} {}'.format(datetime.today().strftime('%Y-%m-%d'),todo))
                with open('todo.txt','w') as newTodo:
                    for item in todoItems:
                        newTodo.write(item)
                    newTodo.close()
                print("Marked todo #{} as done.".format(index))

            except IndexError:
                print('Error: todo #{} does not exist.'.format(index))

    except IndexError:
        print('Error: Missing NUMBER for marking todo as done.')
    except FileNotFoundError:
        print('There are no pending todos!')

elif option=='report':
    try:
        with open('todo.txt','r') as pendingTodo:
            pending=len(list(pendingTodo))
        with open('done.txt','r') as completedTodo:
            completed=len(list(completedTodo))
        date=datetime.today().strftime('%Y-%m-%d')
        print("{} Pending : {} Completed : {}".format(date,pending,completed))
    except FileNotFoundError:
        print('There are no pending todos!')


import sys
import math
from dataclasses import dataclass

dirs = {"R": (1, 0), "U": (0, 1), "L": (-1, 0), "D": (0, -1)}

@dataclass
class Knot:
    x: int = 0
    y: int = 0

    def follow(self, r):
        hx, hy = r.pos()
        mx = abs(self.x - hx)
        my = abs(self.y - hy)
        mult = 1
        if my == 2 and mx == 2:
            mult = 2
        if my == 2 and mx == 1:
            self.x = hx
        if my == 1 and mx == 2:
            self.y = hy

        dist = abs(self.x - hx) + abs(self.y - hy)

        if dist > 1:
            angle = math.atan2(self.x - hx, self.y - hy)
            move_by_cos = -math.cos(angle) * mult
            move_by_sin = -math.sin(angle) * mult
            self.move(int(move_by_sin), int(move_by_cos))

    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def pos(self):
        return (self.x, self.y)

def solve(data, times):
    locations = set()
    rope = [Knot() for _ in range(times)]
    for d in data:
        dirt, t = d.split()
        for _ in range(int(t)):
            rope[0].move(*dirs[dirt])
            for i, r in enumerate(rope[1:]):
                r.follow(rope[i])
            locations.add(rope[-1].pos())

    return len(locations)

if __name__ == "__main__":
    d = sys.stdin.read().split("\n")
    print("part 1:", solve(d, 2))
    print("part 2:", solve(d, 10))


# uses python3

import sys
import queue

class Edge:
  def __init__(self, u, v, lower_bound, capacity):
    self.u = u
    self.v = v
    self.lower_bound = lower_bound
    self.capacity = capacity
    self.diff = capacity - lower_bound
    self.flow = 0

class FlowGraph:
  def __init__(self, n):
    self.edges = []
    self.graph = [[] for _ in range(n + 2)]
    self.dv = [0] * (n + 2)
    self.DD = 0

  def add_edge(self, fr, to, lower_bound, capacity):
    forward_edge = Edge(fr, to, lower_bound, capacity)
    backward_edge = Edge(to, fr, 0, 0)
    self.graph[fr].append(len(self.edges))
    self.edges.append(forward_edge)
    self.graph[to].append(len(self.edges))
    self.edges.append(backward_edge)
    self.dv[fr] += lower_bound
    self.dv[to] -= lower_bound

  def construct(self, id, flow):
    self.edges[id].flow += flow
    self.edges[id ^ 1].flow -= flow
    self.edges[id].diff -= flow
    self.edges[id ^ 1].diff += flow

  def get_ids(self, fr):
    return self.graph[fr]

  def size(self):
    return len(self.graph)

  def get_edge(self, id):
    return self.edges[id]

class Circulation:
  def __init__(self):
    graph, n, m = self.read_input()
    flow, flows = self.find_circulation(graph, n, m)
    self.write(flow, flows)

  def read_input(self):
    vertex_count, edge_count = map(int, input().split())
    graph = FlowGraph(vertex_count)
    for _ in range(edge_count):
      u, v, lower_bound, capacity = map(int, input().split())
      graph.add_edge(u-1, v-1, lower_bound, capacity)

    for v in range(vertex_count):
      if graph.dv[v] < 0:
        graph.add_edge(vertex_count, v, 0, -graph.dv[v])
      if graph.dv[v] > 0:
        graph.add_edge(v, vertex_count + 1, 0, graph.dv[v])
        graph.DD += graph.dv[v]

    return graph, vertex_count, edge_count

  def bfs(self, graph, fr, to):
    X = float('inf')
    has_path = False
    n = graph.size()
    dist = [float('inf')] * n
    path = []
    parent = [(None, None)] * n
    q = queue.Queue()
    dist[fr] = 0
    q.put(fr)
    while not q.empty():
      cur_from_node = q.get()
      for id in graph.get_ids(cur_from_node):
        cur_edge = graph.get_edge(id)
        if float('inf') == dist[cur_edge.v] and cur_edge.diff > 0:
          dist[cur_edge.v] = dist[cur_from_node] + 1
          parent[cur_edge.v] = (cur_from_node, id)
          q.put(cur_edge.v)
          if cur_edge.v == to:
            while True:
              path.insert(0, id)
              cur_X = graph.get_edge(id).diff
              X = min(cur_X, X)
              if cur_from_node == fr:
                break
              cur_from_node, id = parent[cur_from_node]
            has_path = True
            return has_path, path, X
    return has_path, path, X

  def max_flow(self, graph, fr, to):
    flow = 0
    while True:
      has_path, path, X = self.bfs(graph, fr, to)
      if not has_path:
        return flow
      for id in path:
        graph.construct(id, X)
      flow += X

    return flow

  def find_circulation(self, graph, n, m):
    flow = self.max_flow(graph, n, n + 1)
    flows = [0] * m
    if flow != graph.DD:
      return False, flows
    else:
      for i in range(m):
        forward_edge = graph.edges[i * 2]
        flows[i] = forward_edge.flow + forward_edge.lower_bound
      return True, flows

  def write(self, flow, flows):
    if not flow:
      print('NO')
    else:
      print('YES')
      print('\n'.join(map(str, flows)))

if __name__ == "__main__":
  Circulation()


import collections
import time

from panda3d.core import *

from realtime import io
from realtime import types
from realtime.notifier import notify

class MessageError(RuntimeError):
    """
    An message director specific runtime error
    """

class Participant(io.NetworkHandler):
    notify = notify.new_category('Participant')

    def __init__(self, *args, **kwargs):
        io.NetworkHandler.__init__(self, *args, **kwargs)

        self._lo_channel = 0
        self._hi_channel = 0

    @property
    def lo_channel(self):
        return self._lo_channel

    @lo_channel.setter
    def lo_channel(self, lo_channel):
        self._lo_channel = lo_channel

    @property
    def hi_channel(self):
        return self._hi_channel

    @hi_channel.setter
    def hi_channel(self, hi_channel):
        self._hi_channel = hi_channel

    def handle_datagram(self, di):
        channels = di.get_uint8()
        if channels == 1:
            self.handle_control_message(di)

    def handle_control_message(self, di):
        channel = di.get_uint64()
        if channel == types.CONTROL_MESSAGE:
            message_type = di.get_uint16()
            sender = di.get_uint64()

            if message_type == types.CONTROL_SET_CHANNEL:
                if not self.channel:
                    self.channel = sender

                self.network.interface.add_participant(sender, self)
            elif message_type == types.CONTROL_REMOVE_CHANNEL:
                self.network.message_interface.flush_post_handles(sender)
                self.network.interface.remove_participant(sender)
            elif message_type == types.CONTROL_SET_CON_NAME:
                pass
            elif message_type == types.CONTROL_SET_CON_URL:
                pass
            elif message_type == types.CONTROL_ADD_RANGE:
                pass
            elif message_type == types.CONTROL_REMOVE_RANGE:
                pass
            elif message_type == types.CONTROL_ADD_POST_REMOVE:
                self.network.message_interface.append_post_handle(sender, io.NetworkDatagram(
                    Datagram(di.get_remaining_bytes())))
            elif message_type == types.CONTROL_CLEAR_POST_REMOVE:
                self.network.message_interface.clear_post_handles(sender)
            else:
                self.notify.warning('Failed to handle unknown datagram with '
                    'message type: %d!' % message_type)
        else:
            self.network.message_interface.append_handle(channel, di.get_uint64(), di.get_uint16(),
                io.NetworkDatagram(Datagram(di.get_remaining_bytes())))

    def handle_disconnected(self):
        self.network.message_interface.flush_post_handles(self.channel)
        self.network.interface.remove_participant(self.channel)
        io.NetworkHandler.handle_disconnected(self)

    def shutdown(self):
        self.allocated_channel = 0
        self.channel = 0
        io.NetworkHandler.shutdown(self)

class ParticipantInterface(object):
    notify = notify.new_category('ParticipantInterface')

    def __init__(self, network):
        self._network = network
        self._participants = {}

    @property
    def participants(self):
        return self._participants

    def has_participant(self, channel):
        return channel in self._participants

    def add_participant(self, channel, participant):
        if self.has_participant(channel):
            self.notify.debug('Failed to add participant with channel: %d, '
                'participant already exists!' % channel)

            return

        self._participants[channel] = participant

    def remove_participant(self, channel):
        if not self.has_participant(channel):
            self.notify.debug('Failed to remove participant with channel: %d, '
                'participant does not exist!' % channel)

            return

        del self._participants[channel]

    def get_participant(self, channel):
        return self._participants.get(channel)

class MessageHandle(object):

    def __init__(self, channel, sender, message_type, datagram, timestamp):
        self._channel = channel
        self._sender = sender
        self._message_type = message_type
        self._datagram = datagram
        self._timestamp = timestamp

    @property
    def channel(self):
        return self._channel

    @property
    def sender(self):
        return self._sender

    @property
    def message_type(self):
        return self._message_type

    @property
    def datagram(self):
        return self._datagram

    @property
    def timestamp(self):
        return self._timestamp

    def destroy(self):
        self._channel = None
        self._sender = None
        self._message_type = None
        self._datagram = None
        self._timestamp = None

class PostMessageHandle(object):

    def __init__(self, channel, datagram):
        self._channel = channel
        self._datagram = datagram

    @property
    def channel(self):
        return self._channel

    @property
    def datagram(self):
        return self._datagram

    def destroy(self):
        self._channel = None
        self._datagram = None

class MessageInterface(object):
    notify = notify.new_category('MessageInterface')

    def __init__(self, network):
        self._network = network
        self._message_timeout = config.GetFloat(
            'messagedirector-message-timeout', 15.0)

        self._messages = collections.deque()
        self._post_messages = {}

    @property
    def messages(self):
        return self._messages

    @property
    def post_messages(self):
        return self._post_messages

    def get_timestamp(self):
        return round(time.time(), 2)

    def append_handle(self, channel, sender, message_type, datagram):
        #if not datagram.get_length():
        #    self.notify.warning('Failed to append messenger handle from sender: '
        #        '%d to channel: %d, invalid datagram!' % (sender, channel))
        #
        #    return

        message_handle = MessageHandle(channel, sender, message_type,
            datagram, self.get_timestamp())

        self._messages.append(message_handle)

    def remove_handle(self, message_handle):
        if not isinstance(message_handle, MessageHandle):
            raise MessageError('Failed to remove message handle of '
                'invalid type: %r!' % message_handle)

        self._messages.remove(message_handle)

    def append_post_handle(self, channel, datagram):
        message_handle = PostMessageHandle(channel, datagram)
        messages = self._post_messages.setdefault(channel, collections.deque())
        messages.append(message_handle)

    def remove_post_handle(self, message_handle):
        if not isinstance(message_handle, PostMessageHandle):
            raise MessageError('Failed to remove post message handle of '
                'invalid type: %r!' % message_handle)

        messages = self._post_messages.get(message_handle.channel)
        if not messages:
            self.notify.debug('Failed to remove post message handle, '
                'unknown channel: %d!' % channel)

            return

        messages.remove(message_handle)

    def clear_post_handles(self, channel):
        messages = self._post_messages.get(channel)
        if not messages:
            self.notify.debug('Failed to flush post message handles, '
                'unknown channel: %d!' % channel)

            return

        del self._post_messages[channel]

    def setup(self):
        self.__flush_task = task_mgr.add(self.__flush,
            self._network.get_unique_name('flush-queue'))

    def __flush(self, task):
        # check to see if we have any available messages in the
        # queue to route...
        if not len(self._messages):
            return task.cont

        for _ in range(len(self._messages)):
            # pull a message handle object off the top of the queue,
            # then attempt to route it to its appropiate channel...
            message_handle = self._messages.popleft()

            # before we can attempt to route this message, we need to check and
            # see if the channel exists on the participant interface...
            if not self._network.interface.has_participant(message_handle.channel):
                # each message has a delay as to when it will be automatically removed.
                # let's just check to make sure we can "re-queue" it again...
                if self.get_timestamp() - message_handle.timestamp > self._message_timeout:
                    continue

                # even though this message's channel couldn't be found,
                # this message is still valid because it is within the message
                # timeout time frame, we will "re-queue" it until it expires...
                self._messages.append(message_handle)
                continue

            # we've successfully found the channel in which this message will be routed to,
            # and have a valid message, now reconstruct the message and send it off...
            participant = self._network.interface.get_participant(
                message_handle.channel)

            if not participant:
                continue

            datagram = io.NetworkDatagram()
            datagram.add_header(message_handle.channel, message_handle.sender,
                message_handle.message_type)

            other_datagram = message_handle.datagram
            datagram.append_data(other_datagram.get_message())
            participant.handle_send_datagram(datagram)

            # destroy the datagram and message handle objects since they are
            # no longer needed in this scope...
            other_datagram.clear()
            datagram.clear()

            del other_datagram
            del datagram

            message_handle.destroy()
            del message_handle

        return task.cont

    def flush_post_handles(self, channel):
        messages = self._post_messages.get(channel)
        if not messages:
            self.notify.debug('Failed to flush post message handles, '
                'unknown channel: %d!' % channel)

            return

        participant = self._network.interface.get_participant(channel)
        if not participant:
            self.notify.debug('Failed to flush post message handles, '
                'unknown participant with channel: %d!' % channel)

            return

        for _ in range(len(messages)):
            message_handle = messages.popleft()

            # in order for us to properly handle post remove messages,
            # we need to unpack and process them like we would normally...
            datagram = message_handle.datagram
            participant.handle_datagram(io.NetworkDatagramIterator(datagram))

            # destroy the datagram and message handle objects since they are
            # no longer needed in this scope...
            datagram.clear()
            del datagram

            message_handle.destroy()
            del message_handle

        # finally clear our channel from the post removes
        # dictionary which held the message handle objects...
        self.clear_post_handles(channel)

    def shutdown(self):
        if self.__flush_task:
            task_mgr.remove(self.__flush_task)
            self.__flush_task = None

class MessageDirector(io.NetworkListener):
    notify = notify.new_category('MessageDirector')

    def __init__(self, address, port):
        io.NetworkListener.__init__(self, address, port, Participant)

        self._interface = ParticipantInterface(self)
        self._message_interface = MessageInterface(self)

    @property
    def interface(self):
        return self._interface

    @property
    def message_interface(self):
        return self._message_interface

    def setup(self):
        self._message_interface.setup()
        io.NetworkListener.setup(self)

    def shutdown(self):
        self._message_interface.shutdown()
        io.NetworkListener.shutdown(self)


import os
import re

import bpy

def getsequences():
    return list(bpy.context.scene.sequence_editor.sequences_all)

def getnearbysequences(clip, range):
    """
    get clips above clip and within time boundaries of clip
    """
    returnlist = []
    clipparent = clip.parent_meta()
    for i in getsequences():
        if i.parent_meta() != clipparent.parent_meta():
            continue
        if (
            i.channel >= (clip.channel - range)
            and i.channel < clip.channel
            and i.frame_start >= clip.frame_start
            and i.frame_final_end <= clip.frame_final_end
        ):
            returnlist.append(i)
            if len(returnlist) >= range:
                break
    returnlist.sort(key=lambda x: x.channel, reverse=True)
    return returnlist

# TODO comment difference between this and getsequences
def gettopsequences():
    return list(bpy.context.scene.sequence_editor.sequences)

# some things don't have a good API so proceditor needs to emulate a user by
# selecting and doing stuff with the clips
# This is needed to restore the selection afterwards
def saveselection():
    returnlist = []
    for i in getsequences():
        if i.select:
            returnlist.append(i)
    return returnlist

# restore clip selection after emulating a user due to lack of good API
def restoreselection(selectlist):
    bpy.ops.sequencer.select(deselect_all=True)
    for i in selectlist:
        i.select = True

def savesequences():
    returnlist = []
    for i in gettopsequences():
        returnlist.append(i.name)
    return returnlist

# return newly added sequences
def getnewsequences(sequencelist):
    returnlist = []
    for i in sequencelist:
        if i not in returnlist:
            returnlist.append(bpy.context.scene.sequence_editor.sequences[i])
    return returnlist

# get sequences witout the compiler marker _c$, optionally filter through regex
def getmarkupsequences(regex="", compiled=False):
    sequences = bpy.context.scene.sequence_editor.sequences
    returnlist = []
    # compiled sequences have a _c at the end but may also have an auto assigned
    # number
    tpattern = re.compile(".*(_c|_c\\.[0-9]*)$")
    if not regex == "":
        fpattern = re.compile(regex)
    for i in sequences:
        if type(i) == bpy.types.TextSequence and (
            not compiled
            and not tpattern.match(i.name)
            or (compiled and tpattern.match(i.name))
        ):
            # with custom search string
            if not regex == "":
                if not fpattern.match(i.text):
                    continue
            returnlist.append(i)
    return returnlist

# get template clip with format template.name
def gettemplate(tname):
    templatename = "template_" + tname
    for i in gettopsequences():
        if i.name.startswith(templatename):
            os.system("echo " + i.name + " >> /tmp/test.txt")
            return i

    return False

# get all sequeces that match the given regex
def getresequences(regex, stype=0):
    retsequences = []
    pattern = re.compile(regex)
    for i in getsequences():
        if pattern.match(i.name):
            if stype == 0:
                retsequences.append(i)
            elif type(i) == stype:
                retsequences.append(i)
    return retsequences

# restore graphical clip highlight
def activateselection():
    for i in getsequences():
        if i.select:
            bpy.context.scene.sequence_editor.active_strip = i
            return

# replace markup clip with matching template
def replacemarkupclip(clip: bpy.types.TextSequence, templatename: str):

    sequences = bpy.context.scene.sequence_editor.sequences
    if not templatename or templatename == "":
        return False

    markupcontent = clip.text
    startframe = clip.frame_final_start
    markupduration = clip.frame_final_duration
    markupchannel = clip.channel
    clipname = clip.name

    removeclip(clip)

    templateclip = gettemplate(templatename)
    templatelength = templateclip.frame_final_duration

    if not templateclip:
        return False

    bpy.ops.sequencer.select_all(action="DESELECT")

    sequences[templateclip.name].select = True

    # maybe replace ops with api
    bpy.ops.sequencer.duplicate_move(
        SEQUENCER_OT_duplicate={},
        TRANSFORM_OT_seq_slide={
            "value": (
                startframe - templateclip.frame_final_start,
                markupchannel - templateclip.channel,
            ),
            "release_confirm": False,
            "use_accurate": False,
        },
    )

    newclip = list(
        filter(
            lambda element: element.select,
            list(bpy.context.scene.sequence_editor.sequences),
        )
    )[0]
    newclip.frame_final_duration = markupduration
    newclip.name = clipname + "_c"
    newclip["pcontent"] = markupcontent
    newclip["templatelength"] = templatelength

    return newclip

def getkeyframes(clipname):
    returnlist = []
    matchpath = 'sequence_editor.sequences_all["' + clipname + '"]'
    for action in bpy.data.actions:
        for curve in list(action.fcurves):
            if curve.data_path.startswith(matchpath):
                returnlist += list(curve.keyframe_points)
    return returnlist

def removeclip(clip):
    bpy.ops.sequencer.select(deselect_all=True)
    clip.select = True
    bpy.ops.sequencer.delete()

# move keyframes at the end of the clip towards the end

def adjustkeyframes(clip, oldduration):
    frames = getkeyframes(clip.name)

    if len(frames) == 0:
        return

    beginframes = []
    endframes = []

    for i in frames:
        frametime = i.co[0]
        if frametime > (clip.frame_final_start + oldduration / 2):
            endframes.append(i)
        else:
            beginframes.append(i)

    if len(endframes) == 0:
        return

    endoffset = clip.frame_final_duration - oldduration
    for i in endframes:
        i.co[0] += endoffset

def gettopchannel(frame):
    channel = 0
    for i in getsequences():
        if i.frame_final_start <= frame and i.frame_final_end >= frame:
            if i.channel > channel:
                channel = i.channel
    return channel + 1


# This code is just done for showing purpouses.
# Summed up, this shows how dictionaries can contain lists and vice versa.

def run():
    list = [1, 'Hello World', 15, 3.14]
    dict = {
        'First Name': 'Cristopher',
        'Last Name': 'Vanegas'
    }

    super_list = [
        {'First Name': 'Cristopher', 'Last Name': 'Vanegas'},
        {'First Name': 'Alondra', 'Last Name': 'Vanegas'},
        {'First Name': 'Damian', 'Last Name': 'Vanegas'}
    ]

    super_dict = {
        'Natural_nums': [1, 2, 3, 4, 5],
        'Integer_nums': [-2, -1, 0, 1, 2],
        'Floating_nums': [1.2, 4.5, 5.5, 7.2, 10.2]
    }

    for key, value in super_dict.items():
        print(key, '-', value)
    print()

    for x in super_list:
        key, value = x.items()
        print(key, '-', value)

if __name__ == '__main__':
    run()


import pandas as pd
import numpy as np
#MISSING VALUES BEGIN
full_mat = np.empty((944,1683)) #table for values
full_mat[:] = np.nan
p = pd.read_table('udata.txt')
df = pd.DataFrame(data=p, columns=['user_id','item_id','rating','timestamp']) #get the data frame
means = df.groupby('user_id').agg('mean')
grouped = df.groupby('user_id').agg({"rating":{"size","mean"}})
df=df.drop('timestamp',axis=1)
print(df.loc[0][0]-1)

for i in range(0,len(df)-1):
        cur_item = df.loc[i][1]
        if (i+1) >len(df): #last item
            next_item = cur_item
        else:
            next_item = df.loc[i+1][1]
        #how many movies are blank between records -> sub = next_item - cur_item
        user = int(df.loc[i][0])
        rating = int(grouped.loc[user][1]) #replace with mean

        full_mat[user][cur_item]=df.loc[i][2]
        if (next_item - cur_item)>1:  #more than 1 empty
            j=1
            while(j<=(next_item - cur_item-1)): #for the middle empty lines
                item = j+cur_item
                full_mat[user][item]=rating
                j+=1
        elif (next_item - cur_item)<0: #until 1683 movie,   <= for last value
            while(cur_item<1682):
                item = cur_item+1
                full_mat[user][item]=rating
                cur_item+=1
            j=1
            while (j<next_item):#empty lines between 1-next_item
                user = int(df.loc[i+1][0]) #next user
                rating = int(grouped.loc[user][1]) #next mean rating
                item=j
                full_mat[user][item]=rating

for i in range(1327,1682):
        user,rating=943,3
        full_mat[user][i]=rating
     #   file.write("%i\t%i\t%i\n" % (user,i,rating))
pd.DataFrame(full_mat).to_csv("C:\\Users\\lefteris\\.spyder-py3\\ml-100k\\data.csv")


f = open('input.txt')

directionsL = ['E', 'N', 'W', 'S']
directionsR = ['E', 'S', 'W', 'N']

facing = 'E'
dict = {
    'N': 0,
    'S': 0,
    'E': 0,
    'W': 0
}
coord = (0, 0)

for x in f:
    instruction = x.strip()
    direction = instruction[0]
    # print(instruction[1:])
    # print(facing)
    if direction == 'F':
        dict[facing] += int(instruction[1:])
    elif direction == 'L':
        currDirection = directionsL.index(facing)
        angle = instruction[1:]
        getIndex = int(angle) * 4 // 360
        facing = directionsL[(currDirection + getIndex) % 4]
    elif direction == 'R':
        currDirection = directionsR.index(facing)
        angle = instruction[1:]
        getIndex = int(angle) * 4 // 360
        print(currDirection, angle, getIndex)
        facing = directionsR[(currDirection + getIndex) % 4]
    else:
        dict[direction] += int(instruction[1:])

print(dict)
print(dict['N'] - dict['S'], dict['E'] - dict['W'])
print(abs(dict['N'] - dict['S']) + abs(dict['E'] - dict['W']))


# -*- coding: utf-8 -*-
"""
Created on Sat Jul  9 12:04:05 2022

@author: sr
"""

# -*- coding: utf-8 -*-
"""
Created on Tue Feb 15 21:19:34 2022

@author: sr
"""

from artiq.experiment import *
import numpy as np
from artiq.language import *
from artiq.coredevice.ad9910 import PHASE_MODE_TRACKING

class Phase_Sync_Test(EnvExperiment):

    def build(self):

        self.setattr_device("core")
        self.setattr_device("urukul0_cpld")
        self.d0 = self.get_device("urukul0_ch0")
        self.d1 = self.get_device("urukul0_ch1")
        self.d2 = self.get_device("urukul0_ch2")
        self.d3 = self.get_device("urukul0_ch3")
        self.ttl7 = self.get_device("ttl7")

        self.setattr_argument("t_pulse",NumberValue(1.0*1e-6,min=0.0*1e-6,max=500.00*1e-6,scale = 1e-6,
                      unit="us"),"Args")

        self.setattr_argument("t_wait",NumberValue(1.0*1e-6,min=0.0*1e-6,max=500.00*1e-6,scale = 1e-6,
                      unit="us"),"Args")

    @kernel
    def run(self):
        self.core.break_realtime()
        self.urukul0_cpld.init()
        self.d0.init()
        self.d1.init()
        self.d2.init()
        self.d3.init()

        delay(2000*us)

        self.d0.set_att(15*dB)
        self.d1.set_att(15*dB)
        self.d2.set_att(15*dB)
        self.d3.set_att(15*dB)

        # self.d0.set(93*MHz)
        # self.d1.set(93*MHz)
        # self.d2.set(93*MHz)
        # self.d3.set(93*MHz)
        # delay(10*us)

        # self.d0.set_phase_mode(PHASE_MODE_ABSOLUTE)
        # self.d1.set_phase_mode(PHASE_MODE_ABSOLUTE)
        # self.d2.set_phase_mode(PHASE_MODE_ABSOLUTE)
        # self.d3.set_phase_mode(PHASE_MODE_ABSOLUTE)

        self.d0.set_phase_mode(PHASE_MODE_TRACKING)
        self.d1.set_phase_mode(PHASE_MODE_TRACKING)
        self.d2.set_phase_mode(PHASE_MODE_TRACKING)
        self.d3.set_phase_mode(PHASE_MODE_TRACKING)

        delay(10*us)

        self.d0.sw.off()
        self.d1.sw.off()
        self.d2.sw.off()
        self.d3.sw.off()
        self.ttl7.off()

        nreps = 100
        for ii in range(nreps):

            ph = ii/nreps

            t = now_mu()
            self.d0.set(93*MHz,phase=0.0, ref_time_mu=t)
            self.d1.set(93*MHz,phase=0.0, ref_time_mu=t)
            self.d2.set(93*MHz,phase=0.0, ref_time_mu=t)
            self.d3.set(93*MHz,phase=0.0, ref_time_mu=t)
            delay(1*ms)

            with parallel:
                #self.ttl7.on()
                self.d0.sw.on()
                self.d1.sw.on()
                self.d2.sw.on()
                self.d3.sw.on()

            with parallel:
                delay(self.t_pulse)
                #self.ttl7.off()

            with parallel:
                self.ttl7.on()
                self.d0.sw.off()
                self.d1.sw.off()
                self.d2.sw.off()
                self.d3.sw.off()

            # with parallel:
            #     if ii%2 ==0:
            #         self.d0.set(93*MHz, phase=0.5, ref_time_mu=t)
            #     else:
            #         self.d0.set(93*MHz, phase=0.0, ref_time_mu=t)
                delay(self.t_wait)

            with parallel:
                self.ttl7.off()
                self.d0.sw.on()
                self.d1.sw.on()
                self.d2.sw.on()
                self.d3.sw.on()

            with parallel:
                delay(self.t_pulse)
                #self.ttl7.off()

            with parallel:
                self.ttl7.on()
                self.d0.sw.off()
                self.d1.sw.off()
                self.d2.sw.off()
                self.d3.sw.off()

            self.ttl7.off()

        self.d0.sw.on()
        self.d1.sw.on()
        self.d2.sw.on()
        self.d3.sw.on()
        self.ttl7.off()


"""
Update manager for ReaCoMa
"""
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW
from pathlib import Path

class Grim(toga.App):

    def startup(self):
        main_box = toga.Box(style=Pack(direction=COLUMN))

        # Row for Directory pointing
        self.find = toga.Button(
            'ReaCoMa location',
            on_press = self.find_reacoma,
            style=Pack(padding=5)
        )
        self.dir_label = toga.TextInput(
            readonly=True,
            style=Pack(padding=5, width=500)
        )
        dir_box = toga.Box(style=Pack(direction=ROW))
        dir_box.add(self.find)
        dir_box.add(self.dir_label)

        # Add things to main box
        main_box.add(dir_box)

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = main_box
        self.main_window.show()

    def get_me(self, btn):
        print(self.rand_label.value)

    def find_reacoma(self, btn):
        """pass the button that was pressed into the function"""
        p = self.main_window.select_folder_dialog('ReaCoMa location')

        if len(p) != 0:
            self.reacoma_dir = Path(p[0]).resolve()
            self.dir_label.value = str(self.reacoma_dir)

def main():
    return Grim()


import matplotlib.pyplot as plt

def show_img(img_hr, img_lr):
    plt.figure(figsize=(14,10))
    plt.subplot(1,2,1)
    plt.xticks([])
    plt.yticks([])
    plt.title("high resolution image")
    plt.imshow(img_hr)
    plt.subplot(1,2,2)
    plt.xticks([])
    plt.yticks([])
    plt.title("low resolution image")
    plt.imshow(img_lr)
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Thu Dec 12 16:18:23 2019

@author: hadjis
"""

# References:
#Lecture notes
#Generating recommendations with Pandas: https://stackabuse.com/creating-asimple-recommender-system-in-python-using-pandas/
#Matrix factorization with Pandas: https://beckernick.github.io/matrix-factorizationrecommender/
#Wes McKinney, Python for Data Analysis, O'Reilly, 2018.
#Flask: https://www.makeuseof.com/tag/python-javascript-communicate-json/
# code taken for css mostly is referenced as much as possible to my best understanding.

from flask import Flask, render_template, redirect, url_for, request, jsonify, g
from hashlib import md5
import sqlite3
import pandas as pd
import numpy as np

app = Flask(__name__)
DATABASE = "database.db"
app.debug = True

def get_db() :
	db = getattr(g, '_database', None)
	if db is None :
		db = g._database = sqlite3.connect(DATABASE)
		db.row_factory = dict_factory
	return db

def dict_factory(cursor, row) :
	d = {}
	for idx, col in enumerate(cursor.description) :
		d[col[0]] = row[idx]
	return d

@app.teardown_appcontext
def close_connection(exception) :
	database = getattr(g, '_database', None)
	if database is not None :
		database.close()

# url_for() is the endpoint name thus url_for('login') returns /login

def get_forename() :
	cur = get_db().execute("SELECT * FROM book_data")
	forename = cur.fetchall()
	return forename

def get_book_table():
    cur = get_db().execute("SELECT * FROM book_data")
    book_data = cur.fetchall()
    book_data_table = pd.DataFrame(book_data).values.tolist()
#    print(book_data_table)
    return book_data_table

def get_user_data_table():
    cur = get_db().execute("SELECT * FROM user_profiles")
    user_data = cur.fetchall()
    print(user_data)
    user_data_table = pd.DataFrame(user_data).values.tolist()
#    print(book_data_table)
    return user_data_table

# get all user book ratings
def get_user_book_ratings():
    cur = get_db().execute("SELECT * FROM ratings")
    user_book_rating = cur.fetchall()
    print(user_book_rating)
    user_data_table = pd.DataFrame(user_book_rating).values.tolist()
#    print(book_data_table)
    return user_data_table

def get_credentials(username):
    query = "SELECT * FROM `user_details` WHERE Name='{}'".format(username)
    print(query)
    cur = get_db().execute(query)
    user_credentials = cur.fetchone()
    if user_credentials is not None:
        user_name = user_credentials['Name']
        print(user_name)
        user_id = user_credentials['user_ID']
        print(user_id)
        return user_id, user_name
    else:
        print('Username does not exist.')

@app.route('/get_user_book_rating', methods=['POST'])
def all_book_ratings():
    a = get_user_book_ratings()
    return jsonify(a)

#************************** Try to get routes from other file ******************************

# check if username is valid
def register_user(user_name):
    cur = get_db().execute("SELECT MAX(user_ID) AS M FROM `user_details`")
    user_id = cur.fetchone()['M']
    new_user_id = int(user_id) + 1
    query = "INSERT INTO user_details (user_ID, Name) VALUES ({},'{}')".format(int(new_user_id), user_name)
    get_db().execute(query)
    get_db().commit()
    print('Successful registration')
    return user_id, user_name

@app.route('/register', methods=['GET', 'POST'])
def register():
    print('Removing any leading or trailing spaces')
    username = request.form.get('username')
    try:
        username = username.strip()
    except AttributeError:
        raise AttributeError("Nonetype object. Please try again")
    print('username:{}'.format(username))
    if username is None or username == "":
        raise Exception('Empty username')

    user_id, user_name = register_user(username)
    string_user_id_for_avatar  = str(user_id)
    # md5 works on bytes and not on string so encode
    digest = md5(string_user_id_for_avatar.lower().encode('utf-8')).hexdigest()
    digest_image = "https://www.gravatar.com/avatar/"+digest+"?d=identicon&s="+'20'

    return render_template('index.html', digest_image = digest_image, user_id=user_id, user_name=user_name)

# check if username is valid
def login_user(id):
    inputed_id = id
    try:
        inputed_id = int(inputed_id)
    except ValueError:
       print("That's not an int!")
       raise ValueError("id must be integer")

    cur = get_db().execute("SELECT user_id,Name FROM `user_details` WHERE user_id={}".format(inputed_id))
    data = cur.fetchone()
    print('data:',data)
    print('eeeeem:',cur)
    try:
        user_id = data['user_ID']
    except TypeError:
        raise TypeError("You chose a wrong ID. If you don't remember your own, create a new account.")
    print('user_id:',user_id)
    user_name =data['Name']
    print('user_name: ',user_name)
    return user_id, user_name

@app.route('/login', methods=['GET', 'POST'])
def login():
    id = request.form.get('username')
    print('id: {} and has type {}'.format(id, type(id)))
    if isinstance(id, int) == False:
        print('ID must be integer.')
    user_id, user_name = login_user(id)
    print('user_id: ' , user_id)
    print('user_name:',user_name)
    string_user_id_for_avatar  = str(user_id)
    # md5 works on bytes and not on string so encode
    digest = md5(string_user_id_for_avatar.lower().encode('utf-8')).hexdigest()
    digest_image = "https://www.gravatar.com/avatar/"+digest+"?d=identicon&s="+'20'

    return render_template('index.html', digest_image = digest_image, user_id=user_id, user_name=user_name)

@app.route('/', methods=['GET','POST'])

@app.route('/index', methods=['GET','POST'])
def index():
    return render_template('login_2.html')

@app.route('/logout')
def logout():
    return redirect(url_for('index'))

def edit_user(user_id,user_name):
    inputed_id = int(user_id)
    get_db().execute("UPDATE user_details SET Name = '{}' WHERE user_ID = {}".format(user_name, inputed_id))
    get_db().commit()
    print('Successful Change of data')
    return user_id, user_name

@app.route('/editUser', methods=['GET', 'POST'])
def editUser():
    new_username = request.form['new_username']
    user_id = request.form['user_id']
    if new_username is None:
        raise Exception('Empty username')
    user_id, user_name = edit_user(user_id, new_username)
    string_user_id_for_avatar  = str(user_id)
    # md5 works on bytes and not on string so encode
    digest = md5(string_user_id_for_avatar.lower().encode('utf-8')).hexdigest()
    digest_image = "https://www.gravatar.com/avatar/"+digest+"?d=identicon&s="+'20'

    return render_template('index.html', digest_image = digest_image, user_id=user_id, user_name=user_name)

def get_ratings_of_user(user_id):
    cur = get_db().execute("SELECT * FROM `book_ratings` WHERE user_ID = {}".format(user_id))
    data = cur.fetchall()
    return data

@app.route('/get_user_ratings', methods=['GET', 'POST'])
def get_user_ratings():
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    data_received = get_ratings_of_user(int_user_id)
    data_to_be_sent = jsonify(data_received)
    print('data_to_be_sent:{}',data_to_be_sent)

    return data_to_be_sent

def user_rated_books(user_id):
    cur = get_db().execute("SELECT book_data.book_title FROM (`book_ratings` INNER JOIN `book_data` ON book_ratings.ISBN = book_data.ISBN) WHERE book_ratings.user_ID ={}".format(user_id))
    data = cur.fetchall()
    return data

@app.route('/get_user_rated_books', methods=['GET', 'POST'])
def get_user_rated_books():
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    rated_books_received = user_rated_books(int_user_id)
    rated_books_sent = jsonify(rated_books_received)
    print('rated_books_sent:{}',rated_books_sent)

    return rated_books_sent

def update_book_rating(user_id, book_title, new_rating):
    inputed_id = int(user_id)
    cur = get_db().execute("SELECT book_data.ISBN FROM (`book_ratings` INNER JOIN `book_data` ON book_ratings.ISBN = book_data.ISBN) WHERE book_ratings.user_ID ={} AND book_data.book_title = '{}'".format(inputed_id, book_title))
    data = cur.fetchone()
    ISBN_chosen = data['ISBN']
    get_db().execute("UPDATE book_ratings SET book_rating = {} WHERE user_ID = {} and ISBN = '{}'".format(new_rating, inputed_id, ISBN_chosen))
    get_db().commit()
    cur = get_db().execute("SELECT * from book_ratings where user_ID = {} and ISBN = '{}'".format(inputed_id,ISBN_chosen))
    data = cur.fetchone()
    return data

@app.route('/update_rating', methods=['GET', 'POST'])
def update_rating():
    print('received from html: {}'.format(request.form))
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    book_title = request.form.get('book_title')
    rating = request.form.get('rating')
    data = update_book_rating(int_user_id, book_title, rating)
    book_rating_verification = data['book_rating']
    ISBN_verification = data['ISBN']

    return 'Successful Update of rating'

def delete_book_rating(user_id, book_title):
    inputed_id = int(user_id)
    cur = get_db().execute("SELECT book_data.ISBN FROM (`book_ratings` INNER JOIN `book_data` ON book_ratings.ISBN = book_data.ISBN) WHERE book_ratings.user_ID ={} AND book_data.book_title = '{}'".format(inputed_id, book_title))
    data = cur.fetchone()
    ISBN_chosen = data['ISBN']
    get_db().execute("DELETE FROM book_ratings WHERE user_ID = {} and ISBN = '{}'".format(inputed_id, ISBN_chosen))
    get_db().commit()
    cur = get_db().execute("SELECT * from book_ratings where user_ID = {} ".format(inputed_id))
    data = cur.fetchone()

@app.route('/delete_rating', methods=['GET', 'POST'])
def delete_rating():
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    book_title = request.form.get('book_title')
    delete_book_rating(int_user_id, book_title)

    return 'Successful Delete of rating'

def user_unrated_books(user_id):
    cur = get_db().execute("SELECT DISTINCT book_data.book_title FROM `book_data` WHERE book_data.book_title NOT IN ( SELECT book_data.book_title FROM (`book_ratings` INNER JOIN `book_data` ON book_ratings.ISBN = book_data.ISBN) WHERE user_ID = {})".format(user_id))
    data = cur.fetchall()
    return data

@app.route('/get_unrated_books', methods=['GET', 'POST'])
def get_unrated_books():
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    unrated_books_received = user_unrated_books(int_user_id)
    unrated_books_sent = jsonify(unrated_books_received)

    return unrated_books_sent

#emina dame

def add_book_rating(user_id, book_title, new_rating):
    inputed_id = int(user_id)

    cur = get_db().execute("SELECT book_data.ISBN FROM `book_data` WHERE book_data.book_title ='{}'".format(book_title))
    data = cur.fetchone()
    ISBN_chosen = data['ISBN']
    get_db().execute("INSERT INTO book_ratings VALUES ({}, '{}', {})".format(inputed_id, ISBN_chosen, new_rating))
    get_db().commit()

    cur = get_db().execute("SELECT * from book_ratings where user_ID = {} and ISBN = '{}'".format(inputed_id,ISBN_chosen))
    data = cur.fetchone()
    return data

@app.route('/add_new_rating', methods=['GET', 'POST'])
def add_new_rating():
    user_id = request.form.get('user_id')
    int_user_id = int(user_id)
    book_title = request.form.get('book_title')
    rating = request.form.get('rating')
    data = add_book_rating(int_user_id, book_title, rating)
    book_rating_verification = data['book_rating']
    ISBN_verification = data['ISBN']

    return 'Successful Addition of rating'

def helper_function(predictions_df, userID, movies_df, original_ratings_df, num_recommendations=5):

    # Get and sort the user's predictions
    user_row_number = userID - 1 # UserID starts at 1, not 0
    try :
        sorted_user_predictions = predictions_df.iloc[user_row_number].sort_values(ascending=False)
    except IndexError:
        raise IndexError('Must have at least one rating to use recommendation system.')

    # Get the user's data and merge in the movie information.
    user_data = original_ratings_df[original_ratings_df.user_ID == (userID)]
    user_full = (user_data.merge(movies_df, how = 'left', left_on = 'ISBN', right_on = 'ISBN').
                     sort_values(['book_rating'], ascending=False)
                 )

    # Recommend the highest predicted rating movies that the user hasn't seen yet.
    recommendations = (movies_df[~movies_df['ISBN'].isin(user_full['ISBN'])].
         merge(pd.DataFrame(sorted_user_predictions).reset_index(), how = 'left',
               left_on = 'ISBN',
               right_on = 'ISBN').
         rename(columns = {user_row_number: 'Predictions'}).
         sort_values('Predictions', ascending = False).
                       iloc[:num_recommendations, :-1]
                      )

    return user_full, recommendations

# get the two tables
def recommend_books(num_recommendations = 2):
    user_id = request.form.get('user_id')
    user_id = int(user_id)

    cur = get_db().execute("SELECT * FROM book_data")
    data_books = cur.fetchall()
    books_df = pd.DataFrame(data_books)
    cur = get_db().execute("SELECT * FROM book_ratings")
    data_ratings = cur.fetchall()
    book_rating_df = pd.DataFrame(data_ratings)

    # perform SVD

    from scipy.sparse.linalg import svds
    R_df = book_rating_df.pivot(index = 'user_ID', columns ='ISBN', values = 'book_rating').fillna(0)
    R = R_df.as_matrix()
    user_ratings_mean = np.mean(R, axis = 1)
    R_demeaned = R - user_ratings_mean.reshape(-1, 1)
    U, sigma, Vt = svds(R_demeaned, k=4)
    # need matrix multiplication for predictions
    sigma = np.diag(sigma)

    all_user_predicted_ratings_df = np.dot(np.dot(U, sigma), Vt) + user_ratings_mean.reshape(-1, 1)
    preds_df = pd.DataFrame(all_user_predicted_ratings_df, columns= R_df.columns)

    already_rated, predictions = helper_function(preds_df, user_id, books_df, book_rating_df, num_recommendations)
    list_to_return_already_rated = []
    for i in already_rated.values.tolist():
        print(i)
        dict1 = {}
        dict1['ISBN'] = i[0]
        dict1['rating'] = i[1]
        dict1['user_ID'] = i[2]
        dict1['book_author'] = i[3]
        dict1['genre'] = i[4]
        dict1['book_title'] = i[5]
        list_to_return_already_rated.append(dict1)

    list_to_return_predictions = []
    for j in predictions.values.tolist():
        print(j)
        dict2 = {}
        dict2['ISBN'] = j[0]
        dict2['book_author'] = j[1]
        dict2['book_genre'] = j[2]
        dict2['book_title'] = j[3]
        list_to_return_predictions.append(dict2)

    return list_to_return_already_rated, list_to_return_predictions

 # recommend only top 2 books if available else, whatever is available in chosen category
@app.route('/get_rec', methods=['GET', 'POST'])
def get_rec():
    return jsonify(recommend_books())

@app.route('/get_genre_rec', methods=['GET','POST'])
def get_gentre_rec():
    return jsonify(recommend_books())

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


import torch
import torch.nn as nn
import copy
from attention import MultiHeadAttention
from feedforward import PositionwiseFeedforward
from embeddings import Embeddings

class Decoder(nn.Module):
  ''' Decodes a target batch using a stack of identical decoder layers '''
  def __init__(self, output_dim, hidden_dim, embedding_layer, decoder_layer, num_layers, dropout):
    super(Decoder, self).__init__()

    self.embed = embedding_layer
    self.layers = nn.ModuleList([copy.deepcopy(decoder_layer) for _ in range(num_layers)])
    self.dropout = nn.Dropout(dropout)
    self.linear = nn.Linear(hidden_dim, output_dim)
    self.log_softmax = nn.LogSoftmax(dim=1)

  def forward(self, target, target_mask, encoded_source, source_mask):
    ''' Applies combined embeddings, decoder layers, linear and softmax layers'''
    target = self.dropout(self.embed(target))

    for layer in self.layers:
      target = layer(target, target_mask, encoded_source, source_mask)

    target_proj = self.linear(target)
    return self.log_softmax(target_proj)

class DecoderLayer(nn.Module):
  ''' Decoder layer consisting of three sequential components:
      masked multi-head self-attention,
      encoder-decoder multi-head attention,
      positionwise feedforward layer'''

  def __init__(self, hidden_dim, num_heads, inner_dim, dropout):
    super(DecoderLayer, self).__init__()

    self.masked_self_att = MultiHeadAttention(hidden_dim, num_heads, dropout)
    self.combined_att = MultiHeadAttention(hidden_dim, num_heads, dropout)
    self.feedforward = PositionwiseFeedforward(hidden_dim, inner_dim, dropout)

    self.masked_self_att_norm = nn.LayerNorm(hidden_dim)
    self.combined_att_norm = nn.LayerNorm(hidden_dim)
    self.feedforward_norm = nn.LayerNorm(hidden_dim)

    self.dropout = nn.Dropout(dropout)

  def forward(self, target, target_mask, encoded_source, source_mask):
    '''
    Args:
      target: tensor [batch_size, target_len, hidden_dim]
      target_mask: tensor [batch_size, 1, target_len, target_len]
      encoded_source: tensor [batch_size, source_len, hidden_dim]
      source_mask: tensor [batch_szie, 1, 1, source_len]
    Returns:
      target_output: tensor [batch_size, target_len, hidden_dim]
    '''

    target_self_att = self.masked_self_att(target, target, target, target_mask)
    new_target = self.masked_self_att_norm(target + self.dropout(target_self_att))

    combined_att = self.combined_att(encoded_source, new_target, encoded_source, source_mask)
    new_target = self.combined_att_norm(new_target + self.dropout(combined_att))

    target_feedforward = self.feedforward(new_target)
    target_output = self.feedforward_norm(new_target + self.dropout(target_feedforward))

    return target_output

if __name__ == '__main__':
    # sanity check for decoder
    batch_size = 64
    hidden_dim = 512
    input_dim = 100
    output_dim = 100
    max_length = 100
    num_heads = 8
    inner_dim = 1024
    dropout = 0.1
    num_layers = 12
    pad_id = 0
    seq_len = 100

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    embedding_layer = Embeddings(input_dim, hidden_dim, max_length, device, static=False)
    decoder_layer = DecoderLayer(hidden_dim, num_heads, inner_dim, dropout)
    decoder = Decoder(output_dim, hidden_dim, embedding_layer, decoder_layer, num_layers, dropout)

    source = torch.LongTensor(batch_size, seq_len).random_(input_dim)
    source_mask = (source != pad_id).unsqueeze(1).unsqueeze(2)

    target = torch.LongTensor(batch_size, seq_len).random_(input_dim)
    target_mask = (target != pad_id).unsqueeze(1).unsqueeze(2)

    encoded_source = torch.rand(batch_size, seq_len, hidden_dim)
    output = decoder(target, target_mask, encoded_source, source_mask)


# Question 13
# Level 2
#
# Question:
# Write a program that accepts a sentence and calculate the number of letters and digits.
# Suppose the following input is supplied to the program:
# hello world! 123
# Then, the output should be:
# LETTERS 10
# DIGITS 3
#
# Hints:
# In case of input data being supplied to the question, it should be assumed to be a console input.

numbers = 0
letters = 0

userInput = input("LETTERS AND NUMBERS CALCULATOR!!\nPlease enter a sentence that also contains numbers: ")
for i in userInput:
    if i.isalpha() is True:
        letters += 1
    if i.isdigit() is True:
        numbers += 1

print("LETTERS: {}\nNUMBERS: {}".format(letters, numbers))


import skimage.io as io
from PIL import Image
import os
def alpha2white(img):
    img = img.convert("RGBA")
    for y in range(img.size[1]):
        for x in range(img.size[0]):
            if img.getpixel((x,y))[3] == 0:
                img.putpixel((x,y),(255,255,255,255))
    return img
def stardardlize(path):
    im = Image.open(path)
    im = alpha2white(im)
    im.convert("L")
    im.save("temp.png")
    # im.show()
    img_io = io.imread("temp.png")
    alpha = img_io[:,:,0]
    alpha = (alpha == 0) * 255
    resolution = [50, 50]
    font_size = 48
    output = Image.fromarray(alpha)
    #output = output.convert("L")
    #output.show()
    scale = font_size / max(output.size[0], output.size[1])
    resize_width = int(output.size[0] * scale)
    resize_height = int(output.size[1] * scale)
    output = output.resize((resize_width, resize_height), Image.Resampling.LANCZOS)
    final_img = Image.new("L", resolution)
    final_img.paste(output, (int((resolution[0] - output.size[0])/2),int((resolution[1] - output.size[1])/2)))
    final_img.save("standardlized/" + path)
paths = ["uni4EBA/", "uni6C34/", "uni7A0B/", "uni7AF9/", "uni7C7D/", "uni7E83/","uni5A0C/","uni5C71/","uni8A00/","uni8DB3/","uni94A0/"]
for path in paths:
    for f in os.listdir(path):
        stardardlize(path+f)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------
# @Date        : 2020/4/6
# @Author      : Zhicheng Qian
# @Version     : 1.0
# @Brief       :
# @Description :
# @Reference   :
# ----------------------------------
import heapq

class MedianNumber:
    """
    获取中位数
    通过heapq构建一个大顶堆, 一个小顶堆, 保证大顶堆中所有元素都小于小顶堆
    中位数即为小顶堆最小值, 或者两个堆顶元素的均值
    """

    def __init__(self):
        self.small_heap = []
        self.big_heap = []
        self.N = 0

    def Insert(self, num):
        # write code here
        if self.N % 2 == 0:
            heapq.heappush(self.big_heap, -num)  # 大顶堆的构建，通过插入值取负，返回值取负，来将小顶堆构建成大顶堆
            heapq.heappush(self.small_heap, -heapq.heappop(self.big_heap))  # 返回值取负
        else:
            heapq.heappush(self.small_heap, num)
            heapq.heappush(self.big_heap, -heapq.heappop(self.small_heap))
        self.N += 1

    def GetMedian(self):
        # write code here
        if self.N % 2 == 1:
            return heapq.heappop(self.small_heap)
        else:
            return 0.5 * (heapq.heappop(self.small_heap) + (-heapq.heappop(self.big_heap)))

if __name__ == '__main__':
    so = MedianNumber()
    [so.Insert(k) for k in [4, 5, 1, 6, 2, 7, 3, 8]]
    print(so.GetMedian())


'''
'''

import numpy as np
import matplotlib.pyplot as plt

from bstate import BState, BStateSum

def make_ansatz(lam, normalize=True,verbose=0) -> object:
    r'''
    Construct the variational ansatz of occupied bfermion states,
    |0_\gamma > \equiv N_\gamma \times
    \prod_q \prod_{p<q} (1+\lambda_pq \xi_{p \tau_p}^\dagger \xi_{\tau_q} q^\dagger) |vac>
    where p and q are molecular orbitals, \tau_p, \tau_q are local spin-ups
    s.t. \xi_{q\tau_q}^\dagger = \cos(\theta_q/2) \xi_{q \up}^\dagger + \sin(\theta_q/2) \xi_{q \down}^\dagger
    and N_\gamma is chosen s.t.
    <0_\gamma |0_\gamma> = 1

    NB we are working IN THE LOCAL SPIN DIRECTION so \tau_q are not created as superpositions

    Args:
    lam, 2d complex-valued array, the variational parameters of the ansatz
    '''
    if(len(lam)!=2): raise NotImplementedError; # <- needs to be tested for dim>2
    dim = len(lam);
    vac = BState(2*dim);
    result = BStateSum([vac]);

    # \prod_q \prod_p<q
    for q in range(dim):
        for p in range(q):
            taup, tauq = 2*p, 2*q; # local ups
            # act with 1 + \lambda_pq \xi_{p \tau_p}^\dagger \xi_{q \tau_q}^\dagger
            effect_pq = result.copy();
            effect_pq.c(tauq);
            effect_pq.c(taup);
            # combine w/ result
            effect_pq.times(lam[p,q]);
            result.add(effect_pq);
            if(verbose):
                print("add =\n"+str(effect_pq));
                print("result =\n"+str(result));
                if(q==dim-1): assert False

    # normalization
    if(normalize):
        Ngamma = 1/np.sqrt( result.inner(result) );
        result.times(Ngamma);

    return result;

def fermion_to_bfermion(beta_q, theta_q, lam, opstring, sites, spins) -> float:
    '''
    Given a (2nd order only for now) exp val of REGULAR fermion ops
    acting on MOLECULAR (ie 2-fermion) sites=[site1, site2,..],
    transform to a sum of bfermion exp vals.

    '''
    if(len(opstring) != len(sites) or len(opstring) != len(spins)): raise ValueError;
    alpha_q = np.sqrt(1-beta_q*beta_q);
    if( abs(np.imag(alpha_q[0])) > 1e-10): raise ValueError # alpha, beta both real
    #assert(len(opstring)==2);

    # ansatz
    nsites = len(beta_q);
    dim = 2*nsites; # number of fermionic orbitals
    ansatz = make_ansatz(lam);
    ket = ansatz.copy();

    # transform from fermions to b-fermions
    # rows are c_up, c_down, c_up^\dagger, c_down^\dagger
    # columns are \xi_\tau, \xi_-\tau, \xi_\tau^\dagger, \xi_-\tau^\dagger
    inv_transform = np.zeros((nsites,4,4),dtype=complex);
    for q in range(nsites):
        th = theta_q[q]# for shorter expressions
        inv_transform[q] = np.array([[ alpha_q[q]*np.cos(th/2),-alpha_q[q]*np.sin(th/2), beta_q[q]*np.sin(th/2), beta_q[q]*np.cos(th/2)],
                                     [ alpha_q[q]*np.sin(th/2), alpha_q[q]*np.cos(th/2),-beta_q[q]*np.cos(th/2), beta_q[q]*np.sin(th/2)],
                                     [ beta_q[q]*np.sin(th/2), beta_q[q]*np.cos(th/2), alpha_q[q]*np.cos(th/2),-alpha_q[q]*np.sin(th/2)],
                                     [-beta_q[q]*np.cos(th/2), beta_q[q]*np.sin(th/2), alpha_q[q]*np.sin(th/2), alpha_q[q]*np.cos(th/2)]]);

    # get the coefs of the b-fermion ops, for the given fermion op
    get_coefs = {"a^":0,"av":1,"c^":2,"cv":3}; # ie we choose which row of c = coefs*xi

    # act with transformed operator
    op_indices = np.array(range(-len(opstring),0))[::-1]; # right to left
    for opi in op_indices:
        bfermion_coefs = inv_transform[sites[opi]][get_coefs[opstring[opi]+spins[opi]]];
        #print(">>> bfermion_coefs at ",get_coefs[opstring[opi]+spins[opi]],"=\n",bfermion_coefs);
        pup, pdown = 2*sites[opi], 2*sites[opi]+1;
        # ket and 3 copies of it to cover 4 operator terms
        ket1, ket2, ket3 = ket.copy(), ket.copy(), ket.copy();
        ket.a(pup);
        ket.times(bfermion_coefs[0]);
        ket1.a(pdown);
        ket1.times(bfermion_coefs[1]);
        ket.add(ket1);
        ket2.c(pup);
        ket2.times(bfermion_coefs[2]);
        ket.add(ket2);
        ket3.c(pdown);
        ket3.times(bfermion_coefs[3]);
        ket.add(ket3);

    ret = ansatz.inner(ket);
    if( abs(np.imag(ret)) > 1e-10):
        #return ret;
        print("ansatz = \n",ansatz)
        print("ket = \n",ket)
        print(np.imag(ret)); raise ValueError;
    return np.real(ret);

#########################################################
#### execute
if(__name__ == "__main__"):

    # system properties
    M = 2; # dimensionality of the space
    lam = np.empty((M,M), dtype=complex); # lambda
    for p in range(M):
        for q in range(M):
            lam[p,q] = (10*p+q)/10 * complex(0,1);
    print("lambda =\n",lam);
    ansatz = make_ansatz(lam);
    print("|0_g> =\n", ansatz);

    #### expectation values ####
    print("\n");
    ops = 'ca';
    spins = [1,1];
    if(ops=='aa'): printstr = "< 0_g | xi_{:.0f} xi_{:.0f} | 0_g > = ";
    elif(ops=='ac'): printstr = "< 0_g | xi_{:.0f} xi_{:.0f}\dagger | 0_g > = ";
    elif(ops=='ca'): printstr = "< 0_g | xi_{:.0f}\dagger xi_{:.0f} | 0_g > = ";
    elif(ops=='cc'): printstr = "< 0_g | xi_{:.0f}\dagger xi_{:.0f}\dagger | 0_g > = ";
    # ansatz expectation of \xi_p \xi_q^\dagger
    for p in range(M):
        for q in range(M):
            pspin, qspin = 2*p+spins[0], 2*q+spins[1];
            bra = ansatz.copy();
            ket = ansatz.copy();
            if(ops=='aa'):
                ket.a(qspin);
                ket.a(pspin);
            elif(ops=='ac'):
                ket.c(qspin);
                ket.a(pspin);
            elif(ops=='ca'):
                ket.a(qspin);
                ket.c(pspin);
            elif(ops=='cc'):
                ket.c(qspin);
                ket.c(pspin);
            else: raise NotImplementedError;
            print(printstr.format(pspin,qspin), bra.inner(ket));


"""server URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path
from django.conf import settings
from django.shortcuts import redirect
from django.contrib.auth import views as auth_views

from . import views

urlpatterns = [
    path('', lambda request: redirect('searchPatient', permanent=False)),
	path('login', auth_views.LoginView.as_view(), {'template_name': 'login.html'}, name='login'),
	path('logout', auth_views.LogoutView.as_view(), name='logout'),
	path('createPatient', views.formPatient, name="createPatient"),
    path('updatePatient/<int:idPersonne>', views.modifierPatient, name="updatePatient"),
    path('searchPatient', views.recherchePatient, name="searchPatient"),
    path('createPersonnel', views.formPersonnel, name="createPersonnel"),
    path('updatePersonnel/<int:idPersonne>', views.modifierPersonnel, name="updatePersonnel"),
    path('searchPersonnel', views.recherchePersonnel, name="searchPersonnel"),
	path('afficheDocuments/<int:pid>', views.afficheDocuments, name="afficheDocs"),
	path('editDocument/<int:did>', views.editDocument, name="editDoc"),
	path('seeDmp/<int:pid>', views.afficheDocuments, name="dmp"),
]


"""
generator -> rodzaj funkcji, która zwraca obiekt zwany iteratorem. Iterator to obiekt po którym możemy iterować (one value at a time)
1) oszczędzanie pamięci
2) używane do sekwencji, które nie mają końca
3) słowo kluczowe yield
"""

def return_next_even():
    for n in range(2, 20, 2):
        yield n

# for item in return_next_even():
#     print(item)

generator_object = return_next_even()
print(generator_object)

for i in range(10):
    print(next(generator_object, None))

y = ('a' * n for n in range(1, 6))  # generator expression - wyrażenie generatorowe
# tworzy generator, który będzie zwracał kolejne wielokrotności stringa 'a' w zakresie od 1 do 5

for i in range(5):  # wypisanie kolejnych wartości zwróconych przez obiekt genratora y
    print(next(y))

# https://www.programiz.com/python-programming/generator


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

import sys
import json
import requests
import argparse

api_key = "fcbb4e77"  # get your own key and put it here if mine doesn't work

def ask_for_title():
    while True:
        t = input("Enter movie title: ")
        if is_title_valid(t):
            return t
        else:
            report_invalid_title(t)

def ask_for_year():
    while True:
        y = input("Enter movie year (optional): ")
        if len(y) == 0:
            return 0
        elif is_year_valid(y):
            return y
        else:
            report_invalid_year(y)

def is_title_valid(t):
    return len(t) > 0

def is_year_valid(y):
    return y.isdigit() and len(str(y)) == 4

def report_invalid_title(t):
    print("Invalid title %s" % t)

def report_invalid_year(y):
    print("Invalid year %s" % y)

parser = argparse.ArgumentParser()
parser.add_argument("-t", "--title", help="Movie's title")
parser.add_argument("-y", "--year", help="Release year. If empty - get movie with the most recent release year")
args = parser.parse_args()

if args.title is not None:
    title = args.title
    if not is_title_valid(title):
        report_invalid_title(title)
        sys.exit(1)
else:
    title = ask_for_title()

if args.year is not None:
    year = args.year
    if not is_year_valid(year):
        report_invalid_year(year)
        sys.exit(1)
else:
    '''
     if title wasn't specified as the argument - user will be asked for it in interactive
     mode, so year should be asked for year in interactive mode as well.
    '''
    if args.title is None:
        year = ask_for_year()
    else:
        year = 0

request_params = dict(
    apikey=api_key,
    t=title)

# if there is no year given OMDB will return movie with most recent release year.
if not year == 0:
    request_params['y'] = year

print("Connecting to OMDB...")

try:
    error_key = "Error"
    ratings_key = "Ratings"
    response_json = requests.get("http://www.omdbapi.com/", request_params).json()
    if error_key in response_json:
        print(response_json[error_key])
    elif ratings_key in response_json:
        title = response_json["Title"]
        release_date = response_json["Released"]
        print("%s (%s)" % (title, release_date))
        ratings = response_json[ratings_key]
        for rating in ratings:
            # reverse elements in list so resource name will be in front of score
            resource_score = list(rating.values())[::-1]
            print(": ".join(resource_score))

except requests.RequestException as error:
    print("Can't connect to OMDB:")
    print(error)


# -*- coding: utf-8 -*-
"""
Created on Tue Apr 17 22:21:46 2018

@author: wattai
"""

# test for Hamiltonian Monte Carlo method.

import numpy as np
import matplotlib.pyplot as plt

def leap_frog(theta, p, h, eps, L):
    for l in range(L):
        p_half = p - eps/2. * h.dpotent(theta)
        theta_next = theta + eps * p_half
        p_next = p_half - eps/2. * h.dpotent(theta_next)
        theta, p = theta_next.copy(), p_next.copy()
    return theta_next, p_next

def Hamiltonian(h, theta, p):
    return h.potent(theta) + np.sum(p**2, axis=0)/2.

class gamma:
    def __init__(self, alpha, lam):
        self.alpha = alpha
        self.lam = lam

    def potent(self, theta):
        return self.lam*theta - (self.alpha - 1.)*np.log(theta)

    def dpotent(self, theta):
        return self.lam - (self.alpha - 1.) / theta

class normal:
    def __init__(self, x):
        self.x = x.copy()
        self.N = self.x.shape[0]

    def potent(self, theta):
        mu = theta[0].copy()  # np.mean(x, axis=0)
        sigma2 = theta[1].copy()  # np.var(x, axis=0)

        out = self.N/2*np.log(sigma2) + 1/(2*sigma2)*np.sum(
                (self.x - mu)**2, axis=0)
        print('potent:', out)
        return out

    def dpotent(self, theta):
        mu = theta[0].copy()  # np.mean(x, axis=0)#
        sigma2 = theta[1].copy()  # np.var(x, axis=0)#

        dmu = -1/sigma2*np.sum(self.x - mu, axis=0)
        dsigma2 = self.N/(2*sigma2) - 1/(2*sigma2**2)*np.sum(
                (self.x - mu)**2, axis=0)
        dtheta = np.array([dmu, dsigma2])
        # print('dpotent:', dtheta)
        return dtheta

class HMC:
    def __init__(self, h, eps, L, T):
        self.n_dim = None

        self.theta = None
        self.p = None
        self.thetas = []
        self.ps = []

        self.h = h
        self.eps = eps
        self.L = L
        self.T = T

    def fit(self, theta):
        self.n_dim = theta.shape[0]
        self.theta = theta
        self.thetas.append(self.theta.copy())
        self.p = np.zeros([self.n_dim])
        self.ps.append(self.p.copy())

        for t in range(T):
            self.p = np.random.randn(n_dim)
            theta_a, p_a = leap_frog(theta=self.theta, p=self.p,
                                     h=self.h, eps=self.eps, L=self.L)
            print('theta_a:', theta_a)
            print('p_a:', p_a)
            H_t = Hamiltonian(h=self.h, theta=self.theta, p=self.p)
            print('H_t:', H_t)
            H_a = Hamiltonian(h=self.h, theta=theta_a, p=p_a)
            print('H_a:', H_a)
            r = np.exp(H_t - H_a)
            print('r:', r)
            update_index = (np.random.uniform(0, 1) <= np.minimum(1, r))
            self.theta[update_index] = theta_a[update_index].copy()

            self.thetas.append(self.theta.copy())
            self.ps.append(self.p.copy())
            print('p:', self.p, 'theta:', self.theta)

    def sample(self):
        return np.array(self.thetas)

    def momentum(self):
        return np.array(self.ps)

if __name__ == '__main__':

    # このデータの平均値と分散をHMC法で推定する.
    x = np.random.normal(170, 7, size=(5000))

    n_dim = 2
    eps = 0.05
    L = 100  # n_iter of Leap-Frog method.
    T = 5000  # n_iter of sample.
    T_burnin = int(0.5*T)  # burn-in period.

    # theta = np.random.uniform(low=0, high=1, size=(n_sample, n_dim))
    theta = 100. * np.ones([n_dim])
    p = np.zeros([n_dim])  # momentum

    # h = gamma(alpha=11, lam=13)
    h = normal(x=x)

    # theta_next, p_next = leap_frog(theta, p, h, eps, L) # Leap-Frog test.
    hmc = HMC(h, eps, L, T)
    hmc.fit(theta)
    thetas = hmc.sample()
    ps = hmc.momentum()

    # plot graphs.
    plt.figure()
    plt.subplot(211)
    plt.plot(thetas)
    plt.xlabel(r'$\tau$')
    plt.ylabel(r'$\theta$')
    plt.grid()

    plt.subplot(212)
    theta_map = []
    for i in range(n_dim):
        y_hist, x_hist = np.histogram(thetas[T_burnin:, i],
                                      int(0.5*T),
                                      normed=False)
        theta_map.append(x_hist[np.argmax(y_hist)])
        plt.bar(x=x_hist[:-1], height=y_hist)
    plt.xlabel(r'$\theta$')
    plt.ylabel('hist.')
    plt.grid()

    plt.tight_layout()
    plt.show()

    # print estimated MAP value.
    theta_map = np.array(theta_map)
    print('theta_map:', theta_map)