# -*- coding: utf-8 -*-
# @Time    : 2022/8/27 20:23
# @Author  : CMM
# @Site    :
# @File    : trainer.py
# @Software: PyCharm
import torchvision.utils as vutils
import torchvision.datasets as dset
from gans.base_trainer import BaseTrainer
from gans.wgan.wgan import Generator, Discriminator
import torchvision.transforms as transforms
import torch
import config

class Trainer(BaseTrainer):
    def train(self):
        for epoch in range(config.N_EPOCH):
            for i, (imgs, _) in enumerate(self.dataloader):
                real_imgs = imgs.to(self.device)
                batch_size = real_imgs.size(0)
                ############################
                # (1) Update D network: maximize D(x) - D(G(z)))
                ###########################
                self.optimizer_D.zero_grad()
                noise = torch.randn(batch_size, config.N_Z, device=self.device)
                fake_image = self.net_G(noise)
                fake_output = self.net_D(fake_image.detach())
                real_output = self.net_D(real_imgs)
                loss_D = -torch.mean(real_output) + torch.mean(fake_output)
                loss_D.backward()
                self.optimizer_D.step()

                # Clip weights of discriminator
                for p in self.net_D.parameters():
                    p.data.clamp_(-config.CLIP_VALUE, config.CLIP_VALUE)

                ############################
                # (2) Update G network: maximize D(G(z)))
                ###########################
                if i % config.N_CRITIC == 0:
                    self.optimizer_G.zero_grad()
                    loss_G = -torch.mean(self.net_D(fake_image))
                    loss_G.backward()
                    self.optimizer_G.step()
                    print('[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f'
                          % (epoch, config.N_EPOCH, i, len(self.dataloader),
                             loss_D.item(), loss_G.item()))

                if i % 100 == 0:
                    fake = self.net_G(self.fixed_noise)
                    self.summary_image(fake, epoch * (int(len(self.dataloader) / 100) * 100) + i, one_channel=True)
                    vutils.save_image(real_imgs,
                                      '%s/sample/real_samples.png' % config.OUT_PATH,
                                      normalize=True)
                    vutils.save_image(fake.detach(),
                                      '%s/sample/fake_samples_epoch_%03d.png' % (config.OUT_PATH, epoch),
                                      normalize=True)
                if config.DRY_RUN:
                    break
            # do checkpointing
            torch.save(self.net_G.state_dict(), '%s/checkpoint/netG_epoch_%d.pth' % (config.OUT_PATH, epoch))
            torch.save(self.net_D.state_dict(), '%s/checkpoint/netD_epoch_%d.pth' % (config.OUT_PATH, epoch))

    def setup(self):
        # Initialize dataset
        self.dataset, self.dataloader, self.classes = self.get_dataset(config.DATASET)

        # Initialize generator and discriminator
        self.net_G = Generator().to(self.device)
        self.net_D = Discriminator().to(self.device)
        if config.NET_G != '':
            self.net_G.load_state_dict(torch.load(config.NET_G))
        print(self.net_G)
        if config.NET_D != '':
            self.net_D.load_state_dict(torch.load(config.NET_D))
        print(self.net_D)

        # Optimizers
        self.optimizer_G = torch.optim.RMSprop(self.net_G.parameters(), config.LR)
        self.optimizer_D = torch.optim.RMSprop(self.net_D.parameters(), config.LR)

        self.fixed_noise = torch.randn(config.BATCH_SIZE, config.N_Z, device=self.device)

        if config.DRY_RUN:
            config.N_EPOCH = 1

        # 检查模型
        self.summary_graph(self.net_G, self.fixed_noise)
        fake = self.net_G(self.fixed_noise)
        self.summary_graph(self.net_D, fake.detach())
        # 查看数据
        self.summary_embedding(self.dataset, self.classes)

    def __init__(self, name='wgan', config=config):
        super(Trainer, self).__init__(name=name, config=config)

        self.classes = None
        self.dataloader = None
        self.dataset = None
        self.fixed_noise = None
        self.optimizer_G = None
        self.optimizer_D = None
        self.net_D = None
        self.net_G = None
        self.setup()

if __name__ == '__main__':
    trainer = Trainer()
    trainer.train()


import cv2 #importando o OPenCV
import os
import numpy as np
import math
cap = cv2.VideoCapture(0)

while(1):

    try:  #um erro ocorre se não encontrar nada na janela, pois não
        #pode encontrar o contorno da área máxima #portanto, esta instrução de erro try

        ret, frame = cap.read()
        frame=cv2.flip(frame,1)
        kernel = np.ones((3,3),np.uint8)

        #Define a região de interesse - máscara de análise do objeto
        roi=frame[100:300, 100:300] #tamanho da máscara

        cv2.rectangle(frame,(100,100),(300,300),(0,255,0),0)  #leitura da máscara
        hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) #conversão do padrão RGB para HSV

    # definir gama de cor da pele em HSV
        lower_skin = np.array([0,20,70], dtype=np.uint8)
        upper_skin = np.array([20,255,255], dtype=np.uint8)

     ##extrair imagem do contorno da pele em relação ao fundo do objeto
        mask = cv2.inRange(hsv, lower_skin, upper_skin)

    #dilatação na mão para preencher manchas escuras dentro
        mask = cv2.dilate(mask,kernel,iterations = 4)

    #preencher mão com blur "borrar" na imagem
        mask = cv2.GaussianBlur(mask,(5,5),100)

    #Encontrando os contornos

        contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

   #Encontre o contorno máximo da mão
        cnt = max(contours, key = lambda x: cv2.contourArea(x))
        #função aplicada para detectar o contorno do objeto binarizado

    #aproximação do contorno ao objeto
        epsilon = 0.0005*cv2.arcLength(cnt,True)
        approx= cv2.approxPolyDP(cnt,epsilon,True)

    #fazer um objeto convexo ao redor da mão
        hull = cv2.convexHull(cnt)

     #define area of hull
        areahull = cv2.contourArea(hull)
        areacnt = cv2.contourArea(cnt)

    #define área do objeto e área da mão
        arearatio=((areahull-areacnt)/areacnt)*100

     #encontre os defeitos no objeto convexo em relação à mão
        hull = cv2.convexHull(approx, returnPoints=False)
        defects = cv2.convexityDefects(approx, hull)

    # l = sem defeitos
        l=0

    #definindo a região de interesse
        for i in range(defects.shape[0]):
            s,e,f,d = defects[i,0]
            start = tuple(approx[s][0])
            end = tuple(approx[e][0])
            far = tuple(approx[f][0])
            pt= (100,180)

            # encontrar o comprimento de todos os lados do triângulo
            a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
            b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
            c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)
            s = (a+b+c)/2
            ar = math.sqrt(s*(s-a)*(s-b)*(s-c))

            #calculo do perimetro do objeto

            #distância entre o ponto e o casco convexo
            d=(2*ar)/a

            # distância entre o ponto e o objeto convexo
            angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57

            # ignore ângulos > 90 e ignore pontos muito próximos ao objeto convexo (geralmente vêm devido ao ruído)
            if angle <= 90 and d>30:
                l += 1
                cv2.circle(roi, far, 3, [255,0,0], -1)

            #desenhar linhas ao redor da mão
            cv2.line(roi,start, end, [0,255,0], 2)
            #o ROI define uma região de interesse

        l+=1

        #imprimir gestos correspondentes que estão em seus intervalos
        font = cv2.FONT_HERSHEY_SIMPLEX
        if l==1:

            if areacnt<2000: #significa que não existe objeto na região
                cv2.putText(frame,'Esperando dados',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
            else:
                executado = False
                if arearatio<12 and not executado:
                    cv2.putText(frame,'0 = Navegador',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                    #os.system("start Chrome.exe --window-size=800,600")
                    executado = True
                    #break

                elif arearatio<17.5:
                    cv2.putText(frame,'',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                    #os.system("start Arduino IDE.exe")

                else:
                    cv2.putText(frame,'1 = Word',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                    #os.system("start WINWORD.EXE --window-size=600,400")
                    #break

        elif l==2:
            cv2.putText(frame,'2 = Excel',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
          #os.system("start Excel.exe --window-size=600,400")
            #break

        elif l==3:

              if arearatio<27:
                    cv2.putText(frame,'3 = Power Point',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
                    #os.system("start POWERPNT.EXE --window-size=600,400")

              else:
                    cv2.putText(frame,'ok',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)

        elif l==4:
            cv2.putText(frame,'',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
            #os.system("start firefox.exe")

        elif l==5:
            cv2.putText(frame,'',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
            #os.system("start Spyder.launch.pyw")

        elif l==6:
            cv2.putText(frame,'reposition',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)

        else :
            cv2.putText(frame,'reposition',(10,50), font, 2, (0,0,255), 3, cv2.LINE_AA)

        #show the windows
        cv2.imshow('mask',mask)
        cv2.imshow('frame',frame)
    except:
        pass

    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()
cap.release()


from numpy import ndarray, array, isnan, where, nan
from numpy.random import geometric
from ast import literal_eval
from copy import deepcopy
from ..base.Set import Set
from ..base.Model import Model, PCTMC_ID
from sympy import sympify

class Parametric_Model(Model):
	"""
	Abstract class that represents parametric models.
	Is inherited by PCTMC.
	Should not be instantiated itself!
	"""
	def __init__(self, matrix: ndarray, labelling: list,
				 transition_expr: list, parameter_values: dict,
				 parameter_indexes: list, parameter_str: list,
				 name: str) -> None:
		"""
		Creates an abstract model for PMC or PCTMC.

		Parameters
		----------
		matrix : ndarray
			Represents the transition matrix.
			matrix[i,j] is the index, in `transition_expr`, of the symbolic
			representation of the transition from `i` to `j`.
		labelling: list of str
			A list of N observations (with N the nb of states).
			If `labelling[s] == o` then state of ID `s` is labelled by `o`.
			Each state has exactly one label.
		transition_expr: list of str
			Contains the symbolic representation for each transition.
		parameter_values: list of float
			Contains the value for each parameter.
			`parameter_values[i]` is the instantiation for parameter `i`.
			If the ith parameter is not instantiated, `parameter_values[i] == numpy.nan`.
		parameter_indexes: list of ndarray
			Contains the indexes of each transition using each parameter.
			`parameter_indexes[i] = array([[0,1],[2,1]])` means that parameter `i`
			is used by the transition from state 0 to state 1 and from state 2 to state 1.
		parameter_str: list
			Contains the name of each parameter.
			`parameter_str[i]` is the name of parameter `i`.
			Parameter `i` doesn't have a name if `parameter_str[i]==None`.
		name : str, optional
			Name of the model.
		"""
		self.labelling = labelling
		self.alphabet = list(set(labelling))
		self.nb_states = len(matrix)

		if not 'init' in self.labelling:
			msg = "No initial state given: at least one"
			msg += " state should be labelled by 'init'."
			raise ValueError(msg)
		initial_state = [1.0/self.labelling.count("init") if i=='init' else 0.0 for i in self.labelling]

		if len(parameter_indexes) != len(parameter_str):
			raise ValueError("Length of parameter_indexes and parameter_str must be equal.")
		self.nb_parameters = len(parameter_indexes)
		if max(matrix.flatten()) >= len(transition_expr):
			msg = "Transition "+str(max(matrix.flatten()))+" found in matrix while length "
			msg+= "of transition_expr is "+str(len(transition_expr))
			raise ValueError(msg)
		if min(matrix.flatten()) < 0:
			raise ValueError("Transition "+str(min(matrix.flatten()))+" found in matrix")

		if len(self.labelling) != self.nb_states:
			msg = "The length of labelling ("+str(len(labelling))+") is not equal "
			msg+= "to the number of states("+str(self.nb_states)+")"
			raise ValueError(msg)

		self.transition_expr = transition_expr
		k = list(parameter_values.keys())
		for i in k:
			if isnan(parameter_values[i]):
				del parameter_values[i]
		self.parameter_values = parameter_values
		self.parameter_indexes= parameter_indexes
		self.parameter_str = parameter_str

		super().__init__(matrix,initial_state,name)

	def isInstantiated(self,state1:int = None, state2:int = None, param:str =None) -> bool:
		"""
		If nothing is set, checks if all the parameters are instantiated.
		If `state1` is set, checks if all the transitions leaving this state
		are instantiated.
		If `state1` and `state2` are set, checks if the transitions from
		`state1` to `state2` is instantiated.
		If `param` is set, checks if the parameter `param` is instantiated.

		Parameters
		----------
		state1 : int, optional.
			state ID.

		state2 : int, optional.
			state ID.

		param : str, optional
			Parameter name.

		Returns
		-------
		bool
			True if all the requested entity(ies) is/are instantiated.
			See above.
		"""
		if type(param) == str:
			return param in self.parameter_values
		elif type(state1) == type(None):
			return len(set(self.parameter_str)-set(self.parameter_values.keys())) == 0
		else:
			self._checkStateIndex(state1)
			if type(state2) == type(None):
				parameters = self.involvedParameters(state1)
			else:
				parameters = self.involvedParameters(state1,state2)
			for i in parameters:
				if not self.isInstantiated(param=i):
					return False
			return True

	def transitionValue(self,i:int,j:int):
		"""
		Returns the value of the transition from state `i` to `j`.
		If at least one of the paramater in this transition is not
		instantiated, returns the symbolic representation of the transition.

		Parameters
		----------
		i : int
			source state ID.
		j : int
			destination state ID.

		Returns
		-------
		float or symbolic representation
			The value of the transition from state `i` to `j`.
			If at least one of the paramater in this transition is not
			instantiated, returns the symbolic representation of the
			transition.
		"""
		return self.transition_expr[self.matrix[i,j]].evalf(subs=self.parameter_values)

	def transitionExpression(self,i:int,j:int):
		"""
		Returns the symbolic representation of the transition.

		Parameters
		----------
		i : int
			source state ID.
		j : int
			destination state ID.

		Returns
		-------
		symbolic representation
			The symbolic representation of the transition.
		"""
		return self.transition_expr[self.matrix[i,j]]

	def parameterValue(self, p:str)-> float:
		"""
		Returns the value of the parameter `p`.
		If `p` is not instantiated, returns numpy.nan.
		If the model doesn't have any parameter `p`, returns numpy.nan.

		Parameters
		----------
		p : str
			parameter name.

		Returns
		-------
		float
			The value of `p` if `p` is instantiated, numpy.nan otherwise.
			If the model doesn't have any parameter `p`, returns numpy.nan.
		"""
		if not p in self.parameter_values:
			return nan
		return self.parameter_values[p]

	def parameterIndexes(self, p:str) -> list:
		"""
		Returns the list of all transitions involving `p`.
		If the model doesn't have any parameter `p`, returns an empty list.

		Parameters
		----------
		p : str
			parameter name.

		Returns
		-------
		list
			The list of all transitions involving `p`.
			If the model doesn't have any parameter `p`, returns an empty list.

		Examples
		--------
		>>> m.parameterIndexes('x')
		[[4,0],[2,3]]
		>>> # the transitions from state 4 to 0 and from 2 to 3 involve 'x'.
		>>> m.transitionExpression(4,0)
		3*x
		"""
		if not p in self.parameter_str:
			return []
		return self.parameter_indexes[self.parameter_str.index(p)]

	def instantiate(self,parameters: list, values: list) -> ndarray:
		"""
		Returns a copy of the `self.parameter_values` dict, where all the
		parameters in `parameters` to the values `values`.

		Parameters
		----------
		parameters : list of string
			List of all parameters to set. This list must contain parameter
			names.
		values : list of float
			List of values. `parameters[i]` will be set to `values[i]`.

		Returns
		-------
		numpy.ndarray
			A copy of the `self.parameter_values` dict, where all the
			parameters in `parameters` to the values `values`.

		Remark
		------
		The output numpy.ndarray will be used by the inherited class to check
		if this instantiation is valid. If so, the `self.parameter_values` dict
		is updated.
		"""
		new_values = deepcopy(self.parameter_values)
		for s,v in zip(parameters,values):
			new_values[s] = v
		return new_values

	#def evaluateString(self,string:str,parameter_values=None):
	#	if parameter_values == None:
	#		parameter_values = self.parameter_values
	#	return sympify(string).evalf(subs=parameter_values)

	def evaluateTransition(self,i:int,j:int, parameter_values: dict = None):
		"""
		Returns the value of the transition from state `i` to `j`.
		If `parameter_values` is given, the parameters are instantiated by
		`parameter_values`, otherwise by `self.parameter_values`.
		If at least one of the paramater in this transition is not
		instantiated, returns the symbolic representation of the transition.

		Parameters
		----------
		i : int
			source state ID.
		j : int
			destination state ID.
		parameter_values: dict, optional
			dictionary with the instantiation of the parameters.
			The keys are the parameter names (str).

		Returns
		-------
		float or symbolic representation
			The value of the transition from state `i` to `j`.
			If at least one of the paramater this transition is not
			instantiated, returns the symbolic representation of the
			transition.
		"""
		if parameter_values == None:
			parameter_values = self.parameter_values
		v =  self.transitionExpression(i,j).evalf(subs=parameter_values)
		try:
			v = float(v)
		except TypeError:
			pass
		return v

	def involvedParameters(self,i: int,j: int = -1) -> list:
		"""
		Returns the parameters involved in the transition from `i` to `j`.
		If `j` is not set, it returns the parameters involved in all the
		transitions leaving `i`.

		Parameters
		----------
		i : int
			source state ID.
		j : int, optional
			destination state ID.

		Returns
		-------
		list of str
			list of parameter names.
		"""
		if j == -1:
			j = range(self.nb_states)
		else:
			j =  [j]
		res = set()
		for jj in j:
			res = res.union(self.transitionExpression(i,jj).free_symbols)
		res = list(res)
		res = [i.name for i in res]
		return res

	def getLabel(self,state: int) -> str:
		"""
		Returns the label of `state`.

		Parameters
		----------
		state : int
			a state ID

		Returns
		-------
		str
			a label

		Example
		-------
		>>> model.getLabel(2)
		'Label-of-state-2'
		"""
		self._checkStateIndex(state)
		return self.labelling[state]

	def getAlphabet(self) -> list:
		"""
		Returns the alphabet of this model.

		Returns
		-------
		list of str
			The alphabet of this model

		Example
		-------
		>>> model.getAlphabet()
		['a','b','c','d','done']
		"""
		return self.alphabet

	def __str__(self) -> str:
		res = "Name: "+self.name+'\n'
		for i in self.parameter_values.keys():
			if not isnan(self.parameter_values[i]):
				res += i+' = '+str(round(self.parameter_values[i],5))+'\n'
		res += '\n'
		if 1.0 in self.initial_state:
			res += "Initial state: s"+str(where(self.initial_state==1.0)[0][0])+'\n'
		else:
			res += "Initial state: "
			for i in range(len(self.matrix)):
				if self.initial_state[i] >= 0.001:
					res += 's'+str(i)+': '+str(round(self.initial_state[i],3))+', '
			res = res[:-2]+'\n'
		for i in range(self.nb_states):
			res += self._stateToString(i)+'\n'
		res += '\n'
		return res

	def generateSet(self, set_size: int, param, distribution=None, min_size=None, timed: bool=False) -> Set:
		"""
		Generates a set (training set / test set) containing ``set_size`` traces.

		Parameters
		----------
		set_size: int
			number of traces in the output set.
		param: a list, an int or a float.
			the parameter(s) for the distribution. See "distribution".
		distribution: str, optional
			If ``distribution=='geo'`` then the sequence length will be
			distributed by a geometric law such that the expected length is
			``min_size+(1/param)``.
			If distribution==None param can be an int, in this case all the
			seq will have the same length (``param``), or ``param`` can be a
			list of int.
			Default is None.
		min_size: int, optional
			see "distribution". Default is None.
		timed: bool, optional
			Only for timed model. Generate timed or non-timed traces.
			Default is False.

		Returns
		-------
		output: Set
			a set (training set / test set).

		Examples
		--------
		>>> set1 = model.generateSet(100,10)
		>>> # set1 contains 100 traces of length 10
		>>> set2 = model.generate(100, 1/4, "geo", min_size=6)
		>>> # set2 contains 100 traces. The length of the traces is distributed following
		>>> # a geometric distribution with parameter 1/4. All the traces contains at
		>>> # least 6 observations, hence the average length of a trace is 6+(1/4)**(-1) = 10.
		"""
		seq = []
		val = []
		for i in range(set_size):
			if distribution == 'geo':
				curr_size = min_size + int(geometric(param))
			else:
				if type(param) == list:
					curr_size = param[i]
				elif type(param) == int:
					curr_size = param

			if timed:
				trace = self.run(curr_size,timed)
			else:
				trace = self.run(curr_size)

			if not trace in seq:
				seq.append(trace)
				val.append(1)
			else:
				val[seq.index(trace)] += 1

		return Set(seq,val)

	def _save(self, f) -> None:
		f.write(self.name)
		f.write('\n')
		f.write(str(self.matrix.tolist()))
		f.write('\n')
		f.write(str(self.labelling))
		f.write('\n')
		f.write(str(self.parameter_values))
		f.write('\n')
		f.write(str(self.parameter_indexes))
		f.write('\n')
		f.write(str(self.parameter_str))
		f.write('\n')
		f.write(str([str(i) for i in self.transition_expr]))
		f.write('\n')
		f.close()

	def _checkStateIndex(self,s:int) -> None:
		try:
			s = int(s)
		except TypeError:
			raise TypeError('The parameter must be a valid state ID')
		if s < 0:
			raise IndexError('The parameter must be a valid state ID')
		elif s >= self.nb_states:
			raise IndexError('This model contains only '+str(self.nb_states)+' states')

def loadParametricModel(f):
	"""
	Used by the inherited classes.
	Should not be used directly!
	"""
	name = f.readline()[:-1]
	matrix = array(literal_eval(f.readline()[:-1]))
	labelling = literal_eval(f.readline()[:-1])
	parameter_values = literal_eval(f.readline()[:-1])
	parameter_indexes = literal_eval(f.readline()[:-1])
	parameter_str = literal_eval(f.readline()[:-1])
	transition_expr = literal_eval(f.readline()[:-1])
	transition_expr = [sympify(i) for i in transition_expr]
	return matrix,labelling,parameter_values,parameter_indexes,parameter_str,transition_expr,name


#!/Users/elijahsutton/opt/anaconda3/envs/wod_collector/bin/python
import requests
from bs4 import BeautifulSoup
import pandas as pd

URL = 'https://www.wordnik.com/word-of-the-day' # URL which to scrape for WoD data
WoD_FNAME = '/Users/elijahsutton/Google-Drive/Professional/Portfolio/Word-of-the-Day-Collector/wod_data.txt' # file where WoD data is stored

def scrape_url(url):
    """
    This funtion takes a URL as a string to scrape for word-of-the-day data element
    and returns the data elements (word, part of speech, definiton, and example)
    as a dictionary.

    Parameters
    ----------
    url : string which is a URL to scrape

    Returns
    -------
    res : dictionary of data elements scraped
    """
    # Send HTTP request to specified URL and save response from server
    r = requests.get(url)

    # Create BeautifulSoup object from raw HTML with HTML parser
    soup = BeautifulSoup(r.content, 'html.parser')

    # Get word, part of speech, definition and example
    word = soup.find(name='h1').text
    pos = soup.find(name='abbr').text
    def_ = soup.find(name='div', attrs={'class':'guts active'}).li.contents[-1].strip()
    eg = soup.find(name='p', attrs={'class':'text'}).text

    # Store scraped data elements as a dictionary
    res = {'word' : word,
           'part_of_speech' : pos,
           'definition' : def_,
           'example' : eg}
    return res

def display_word_data(word_dict):
    """
    This function takes in a dictionary containing data elements of a word and
    displays each of the key-value pairs.

    Parameters
    ----------
    word_dict : tuple which contains four data elements of a word

    Returns
    -------
    None.

    """
    for k,v in word_dict.items():
        print('{key} : {value}\n'.format(key=k.upper(), value=v))
    return

def get_wod_df():
    """
    This functions reads in the Word of the Day TXT file from the provided path,
    where previous WoD data is stored, into a DataFrame and returns it.

    Parameters
    ----------
    fname : string which is the filename of file where previous WoD data is stored

    Returns
    -------
    df : pandas DataFrame of word of the day data

    """
    df = pd.read_csv(WoD_FNAME, sep='\t')
    return df

def update_wod_df(df, wod):
    """
    This function takes the WoD DataFrame (df) and the day's WoD (wod) as input
    and appends wod to df if the wod does not already exist in df.

    Parameters
    ----------
    df : pandas DataFrame containing all WoD data
    wod : dict containing today's WoD data

    Returns
    -------
    None.

    """
    # Check for presence of wod in df
    if wod['word'] in df['word'].values:
        # Print that the word has already by captured
        print('"{}" has already be captured.'.format(wod['word']))
    else:
        # Append new WoD to DataFrame
        df = df.append(wod, ignore_index=True)

        # Save DataFrame to file
        df.to_csv(WoD_FNAME, index=False, sep='\t')

        print('{} updated successfully.'.format(WoD_FNAME))
    return

def main():

    # Scrape URL
    word_dict = scrape_url(URL)

    # Display all elements of word_tuple
    display_word_data(word_dict)

    # Read in Word of the Day file to be updated as a DataFrame
    words_df = get_wod_df()

    # Append new word (word_dict) to DataFrame (words_df) and write back to file
    update_wod_df(words_df, word_dict)
    return

main()


from datetime import datetime
import itertools
import os

from trac.api import ISystemInfoProvider
from trac.cache import cached
from trac.config import BoolOption, IntOption, ListOption, PathOption, Option
from trac.core import Component, TracError, implements
from trac.util.datefmt import FixedOffset, to_timestamp, format_datetime
from trac.util.html import Markup, tag
from trac.util.text import exception_to_unicode, shorten_line, to_unicode
from trac.util.translation import _
from trac.versioncontrol.api import Changeset, Node, Repository, \
                                    IRepositoryConnector, InvalidRepository,\
                                    NoSuchChangeset, NoSuchNode, \
                                    RepositoryManager, IRepositoryProvider
from trac.versioncontrol.cache import CACHE_YOUNGEST_REV, CachedRepository, \
                                      CachedChangeset
from trac.versioncontrol.web_ui import IPropertyRenderer
from trac.web.chrome import Chrome
from trac.wiki import IWikiSyntaxProvider

from tracopt.versioncontrol.git import PyGIT

class GitCachedRepository(CachedRepository):
    """Git-specific cached repository."""

    def display_rev(self, rev):
        return self.short_rev(rev)

    def short_rev(self, path):
        return self.repos.short_rev(path)

    def normalize_rev(self, rev):
        if not rev:
            return self.get_youngest_rev()
        normrev = self.repos.git.verifyrev(rev)
        if normrev is None:
            raise NoSuchChangeset(rev)
        return normrev

    def get_youngest_rev(self):
        # return None if repository is empty
        return CachedRepository.get_youngest_rev(self) or None

    def child_revs(self, rev):
        return self.repos.child_revs(rev)

    def get_changesets(self, start, stop):
        for key, csets in itertools.groupby(
                CachedRepository.get_changesets(self, start, stop),
                key=lambda cset: cset.date):
            csets = list(csets)
            if len(csets) == 1:
                yield csets[0]
                continue
            rev_csets = {cset.rev: cset for cset in csets}
            while rev_csets:
                revs = [rev for rev in rev_csets
                            if not any(r in rev_csets
                                       for r in self.repos.child_revs(rev))]
                for rev in sorted(revs):
                    yield rev_csets.pop(rev)

    def get_changeset(self, rev):
        return GitCachedChangeset(self, self.normalize_rev(rev), self.env)

    def sync(self, feedback=None, clean=False):
        if clean:
            self.remove_cache()

        metadata = self.metadata
        self.save_metadata(metadata)
        meta_youngest = metadata.get(CACHE_YOUNGEST_REV, '')
        repos = self.repos

        def is_synced(rev):
            for count, in self.env.db_query("""
                    SELECT COUNT(*) FROM revision WHERE repos=%s AND rev=%s
                    """, (self.id, rev)):
                return count > 0
            return False

        def needs_sync():
            max_holders = 999
            revs = sorted(set(rev for refname, rev in repos.git.get_refs()))
            step = max_holders - 1
            for idx in range(0, len(revs), step):
                revs_ = revs[idx:idx + step]
                holders = ','.join(('%s',) * len(revs_))
                args = [self.id]
                args.extend(revs_)
                query = """SELECT COUNT(*) FROM revision
                           WHERE repos=%%s AND rev IN (%s)""" % holders
                for count, in self.env.db_query(query, args):
                    if count < len(revs_):
                        return True
            return False

        def traverse(rev, seen):
            revs = []
            merge_revs = []
            while True:
                if rev in seen:
                    break
                seen.add(rev)
                if is_synced(rev):
                    break
                revs.append(rev)
                parent_revs = repos.parent_revs(rev)
                if not parent_revs:  # root commit?
                    break
                rev = parent_revs[0]
                if len(parent_revs) > 1:
                    merge_revs.append((len(revs), parent_revs[1:]))
            for idx, parent_revs in reversed(merge_revs):
                for rev in parent_revs:
                    revs[idx:idx] = traverse(rev, seen)
            return revs

        def sync_revs():
            updated = False
            seen = set()

            for rev in repos.git.all_revs():
                if repos.child_revs(rev):
                    continue
                revs = traverse(rev, seen)  # topology ordered
                while revs:
                    # sync revision from older revision to newer revision
                    rev = revs.pop()
                    self.log.info("Trying to sync revision [%s]", rev)
                    cset = repos.get_changeset(rev)
                    try:
                        self.insert_changeset(rev, cset)
                        updated = True
                    except self.env.db_exc.IntegrityError as e:
                        self.log.info('Revision %s already cached: %r', rev, e)
                        continue
                    if feedback:
                        feedback(rev)

            return updated

        with self.env.db_query:
            while True:
                repos.sync()
                if needs_sync() and sync_revs():
                    continue  # sync again
                repos_youngest = repos.youngest_rev or ''
                if meta_youngest != repos_youngest:
                    with self.env.db_transaction as db:
                        db("""
                            UPDATE repository SET value=%s
                            WHERE id=%s AND name=%s
                            """, (repos_youngest, self.id, CACHE_YOUNGEST_REV))
                        del self.metadata
                return

class GitCachedChangeset(CachedChangeset):
    """Git-specific cached changeset."""

    def get_branches(self):
        _rev = self.rev

        return [(k, v == _rev) for k, v in
                 self.repos.repos.git.get_branch_contains(_rev, resolve=True)]

    def get_tags(self):
        return self.repos.repos.git.get_tags(self.rev)

def _last_iterable(iterable):
    """helper for detecting last iteration in for-loop"""
    i = iter(iterable)
    try:
        v = next(i)
    except StopIteration:
        return
    for nextv in i:
        yield False, v
        v = nextv
    yield True, v

def intersperse(sep, iterable):
    """The 'intersperse' generator takes an element and an iterable and
    intersperses that element between the elements of the iterable.

    inspired by Haskell's ``Data.List.intersperse``
    """

    for i, item in enumerate(iterable):
        if i: yield sep
        yield item

# helper
def _parse_user_time(s):
    """Parse author or committer attribute lines and return
    corresponding ``(user, timestamp)`` pair.
    """

    user, time, tz_str = s.rsplit(None, 2)
    tz = FixedOffset((int(tz_str) * 6) // 10, tz_str)
    time = datetime.fromtimestamp(float(time), tz)
    return user, time

_file_type_mask = 0o170000

def _is_dir(mode):
    if mode is None:
        return False
    return (mode & _file_type_mask) in (0o040000, 0o160000)

def _is_submodule(mode):
    if mode is None:
        return False
    return (mode & _file_type_mask) == 0o160000

class GitConnector(Component):

    implements(IRepositoryConnector, ISystemInfoProvider, IWikiSyntaxProvider)

    def __init__(self):
        self._version = None

        try:
            self._version = PyGIT.Storage.git_version(git_bin=self.git_bin)
        except PyGIT.GitError as e:
            self.log.error("GitError: %s", e)

        if self._version:
            self.log.info("detected GIT version %s", self._version['v_str'])
            if not self._version['v_compatible']:
                self.log.error("GIT version %s installed not compatible"
                               "(need >= %s)", self._version['v_str'],
                               self._version['v_min_str'])

    # ISystemInfoProvider methods

    def get_system_info(self):
        if self._version:
            yield 'GIT', self._version['v_str']

    # IWikiSyntaxProvider methods

    def _format_sha_link(self, formatter, sha, label):
        # FIXME: this function needs serious rethinking...

        reponame = ''

        context = formatter.context
        while context:
            if context.resource.realm in ('source', 'changeset'):
                reponame = context.resource.parent.id
                break
            context = context.parent

        try:
            repos = RepositoryManager(self.env).get_repository(reponame)

            if not repos:
                raise Exception("Repository '%s' not found" % reponame)

            sha = repos.normalize_rev(sha) # in case it was abbreviated
            changeset = repos.get_changeset(sha)
            return tag.a(label, class_='changeset',
                         title=shorten_line(changeset.message),
                         href=formatter.href.changeset(sha, repos.reponame))
        except Exception as e:
            return tag.a(label, class_='missing changeset',
                         title=to_unicode(e), rel='nofollow')

    def get_wiki_syntax(self):
        yield (r'(?:\b|!)r?[0-9a-fA-F]{%d,40}\b' % self.wiki_shortrev_len,
               lambda fmt, sha, match:
                    self._format_sha_link(fmt, sha.startswith('r')
                                          and sha[1:] or sha, sha))

    def get_link_resolvers(self):
        yield ('sha', lambda fmt, _, sha, label, match=None:
                        self._format_sha_link(fmt, sha, label))

    # IRepositoryConnector methods

    persistent_cache = BoolOption('git', 'persistent_cache', 'false',
        """Enable persistent caching of commit tree.""")

    cached_repository = BoolOption('git', 'cached_repository', 'false',
        """Wrap `GitRepository` in `CachedRepository`.""")

    shortrev_len = IntOption('git', 'shortrev_len', 7,
        """The length at which a sha1 is abbreviated (must be >= 4
        and <= 40).
        """)

    wiki_shortrev_len = IntOption('git', 'wikishortrev_len', 40,
        """The minimum length at which a hex-string in wiki content
        is formatted as a changeset TracLink (must be >= 4 and <= 40).
        """)

    trac_user_rlookup = BoolOption('git', 'trac_user_rlookup', 'false',
        """Enable reverse mapping of git email addresses to trac user ids.
        Performance will be reduced if there are many users and the
        `cached_repository` option is `disabled`.

        A repository resync is required after changing the value of this
        option.
        """)

    use_committer_id = BoolOption('git', 'use_committer_id', 'true',
        """Use git-committer id instead of git-author id for the
        changeset ''Author'' field.
        """)

    use_committer_time = BoolOption('git', 'use_committer_time', 'true',
        """Use git-committer timestamp instead of git-author timestamp
        for the changeset ''Timestamp'' field.
        """)

    git_fs_encoding = Option('git', 'git_fs_encoding', 'utf-8',
        """Define charset encoding of paths within git repositories.""")

    git_bin = Option('git', 'git_bin', 'git',
        """Path to the git executable.""")

    def get_supported_types(self):
        yield ('git', 8)

    def get_repository(self, type, dir, params):
        """GitRepository factory method"""
        assert type == 'git'

        if not (4 <= self.shortrev_len <= 40):
            raise TracError(_("%(option)s must be in the range [4..40]",
                              option="[git] shortrev_len"))

        if not (4 <= self.wiki_shortrev_len <= 40):
            raise TracError(_("%(option)s must be in the range [4..40]",
                              option="[git] wikishortrev_len"))

        if not self._version:
            raise TracError(_("GIT backend not available"))
        elif not self._version['v_compatible']:
            raise TracError(_("GIT version %(hasver)s installed not "
                              "compatible (need >= %(needsver)s)",
                              hasver=self._version['v_str'],
                              needsver=self._version['v_min_str']))

        if self.trac_user_rlookup:
            def rlookup_uid(email):
                """Reverse map 'real name <user@domain.tld>' addresses to trac
                user ids.

                :return: `None` if lookup failed
                """

                try:
                    _, email = email.rsplit('<', 1)
                    email, _ = email.split('>', 1)
                    email = email.lower()
                except Exception:
                    return None

                for _uid, _name, _email in self.env.get_known_users():
                    try:
                        if email == _email.lower():
                            return _uid
                    except Exception:
                        continue

        else:
            def rlookup_uid(_):
                return None

        repos = GitRepository(self.env, dir, params, self.log,
                              persistent_cache=self.persistent_cache,
                              git_bin=self.git_bin,
                              git_fs_encoding=self.git_fs_encoding,
                              shortrev_len=self.shortrev_len,
                              rlookup_uid=rlookup_uid,
                              use_committer_id=self.use_committer_id,
                              use_committer_time=self.use_committer_time,
                              )

        if self.cached_repository:
            repos = GitCachedRepository(self.env, repos, self.log)
            self.log.debug("enabled CachedRepository for '%s'", dir)
        else:
            self.log.debug("disabled CachedRepository for '%s'", dir)

        return repos

class CsetPropertyRenderer(Component):

    implements(IPropertyRenderer)

    # relied upon by GitChangeset
    def match_property(self, name, mode):
        # default renderer has priority 1
        return (name in ('Parents',
                         'Children',
                         'Branches',
                         'git-committer',
                         'git-author',
                         ) and mode == 'revprop') and 4 or 0

    def render_property(self, name, mode, context, props):

        def sha_link(sha, label=None):
            # sha is assumed to be a non-abbreviated 40-chars sha id
            try:
                reponame = context.resource.parent.id
                repos = RepositoryManager(self.env).get_repository(reponame)
                cset = repos.get_changeset(sha)
                if label is None:
                    label = repos.display_rev(sha)

                return tag.a(label, class_='changeset',
                             title=shorten_line(cset.message),
                             href=context.href.changeset(sha, repos.reponame))

            except Exception as e:
                return tag.a(sha, class_='missing changeset',
                             title=to_unicode(e), rel='nofollow')

        if name == 'Branches':
            branches = props[name]

            # simple non-merge commit
            return tag(*intersperse(', ', (sha_link(rev, label)
                                           for label, rev in branches)))

        elif name in ('Parents', 'Children'):
            revs = props[name] # list of commit ids

            if name == 'Parents' and len(revs) > 1:
                # we got a merge...
                current_sha = context.resource.id
                reponame = context.resource.parent.id

                parent_links = intersperse(', ',
                                           ((sha_link(rev),
                      ' (',
                      tag.a(_("diff"),
                            title=_("Diff against this parent (show the "
                                    "changes merged from the other parents)"),
                            href=context.href.changeset(current_sha, reponame,
                                                        old=rev)),
                      ')')
                     for rev in revs))

                return tag(list(parent_links),
                           tag.br(),
                           tag.span(Markup(_("Note: this is a merge"
                                             " changeset, the "
                                             "changes displayed below "
                                             "correspond to the merge "
                                             "itself.")),
                                    class_='hint'),
                           tag.br(),
                           tag.span(Markup(_("Use the (diff) "
                                             "links above to see all the "
                                             "changes relative to each "
                                             "parent.")),
                                    class_='hint'))

            # simple non-merge commit
            return tag(*intersperse(', ', map(sha_link, revs)))

        elif name in ('git-committer', 'git-author'):
            user_, time_ = props[name]
            _str = "%s (%s)" % (
                Chrome(self.env).format_author(context.req, user_),
                format_datetime(time_, tzinfo=context.req.tz))
            return str(_str)

        raise TracError(_("Internal error"))

class GitRepository(Repository):
    """Git repository"""

    def __init__(self, env, path, params, log,
                 persistent_cache=False,
                 git_bin='git',
                 git_fs_encoding='utf-8',
                 shortrev_len=7,
                 rlookup_uid=lambda _: None,
                 use_committer_id=False,
                 use_committer_time=False,
                 ):

        self.env = env
        self.logger = log
        self.gitrepo = path
        self.params = params
        self.persistent_cache = persistent_cache
        self.shortrev_len = max(4, min(shortrev_len, 40))
        self.rlookup_uid = rlookup_uid
        self.use_committer_time = use_committer_time
        self.use_committer_id = use_committer_id

        try:
            factory = PyGIT.StorageFactory(path, log, not persistent_cache,
                                           git_bin=git_bin,
                                           git_fs_encoding=git_fs_encoding)
            self._git = factory.getInstance()
        except PyGIT.GitError as e:
            log.error(exception_to_unicode(e))
            raise InvalidRepository(
                _('"%(name)s" is not readable or not a Git repository.',
                  name=params.get('name') or '(default)'))

        Repository.__init__(self, 'git:' + path, self.params, log)
        self._cached_git_id = str(self.id)

    def close(self):
        self._git = None

    @property
    def git(self):
        if self.persistent_cache:
            return self._cached_git
        else:
            return self._git

    @cached('_cached_git_id')
    def _cached_git(self):
        self._git.invalidate_rev_cache()
        return self._git

    def get_youngest_rev(self):
        return self.git.youngest_rev()

    def get_path_history(self, path, rev=None, limit=None):
        raise TracError(_("Unsupported \"Show only adds and deletes\""))

    def get_oldest_rev(self):
        return self.git.oldest_rev()

    def normalize_path(self, path):
        return path and path.strip('/') or '/'

    def normalize_rev(self, rev):
        if not rev:
            return self.get_youngest_rev()
        normrev = self.git.verifyrev(rev)
        if normrev is None:
            raise NoSuchChangeset(rev)
        return normrev

    def display_rev(self, rev):
        return self.short_rev(rev)

    def short_rev(self, rev):
        return self.git.shortrev(self.normalize_rev(rev),
                                 min_len=self.shortrev_len)

    def get_node(self, path, rev=None):
        return self._get_node(path, rev)

    def _get_node(self, path, rev, ls_tree_info=None, historian=None):
        return GitNode(self, path, rev, self.log, ls_tree_info, historian)

    def get_quickjump_entries(self, rev):
        for bname, bsha in self.git.get_branches():
            yield 'branches', bname, '/', bsha
        for t in self.git.get_tags():
            yield 'tags', t, '/', t

    def get_path_url(self, path, rev):
        return self.params.get('url')

    def get_changesets(self, start, stop):
        for rev in self.git.history_timerange(to_timestamp(start),
                                              to_timestamp(stop)):
            yield self.get_changeset(rev)

    def get_changeset(self, rev):
        """GitChangeset factory method"""
        return GitChangeset(self, rev)

    def get_changeset_uid(self, rev):
        return self.normalize_rev(rev)

    def get_changes(self, old_path, old_rev, new_path, new_rev,
                    ignore_ancestry=0):
        # TODO: handle renames/copies, ignore_ancestry
        old_path = self.normalize_path(old_path)
        new_path = self.normalize_path(new_path)
        if old_path != new_path:
            raise TracError(_("Not supported in git_fs"))

        old_rev = self.normalize_rev(old_rev)
        new_rev = self.normalize_rev(new_rev)
        if old_rev == new_rev:
            return

        def get_tree(rev):
            results = self.git.ls_tree(rev, target_path, recursive=True)
            return {result[4]: result for result in results}

        target_path = old_path.strip('/')
        old_tree = get_tree(old_rev)
        new_tree = get_tree(new_rev)

        with self.git.get_historian(old_rev, target_path) as old_historian:
            with self.git.get_historian(new_rev, target_path) as new_historian:
                for chg in self.git.diff_tree(old_rev, new_rev, target_path):
                    mode1, mode2, obj1, obj2, action, path, path2 = chg
                    kind = Node.DIRECTORY \
                           if _is_dir(mode2) or _is_dir(mode1) \
                           else Node.FILE

                    change = GitChangeset.action_map[action]
                    old_node = self._get_node(path, old_rev,
                                              old_tree.get(path, False),
                                              old_historian) \
                               if change != Changeset.ADD else None
                    new_node = self._get_node(path, new_rev,
                                              new_tree.get(path, False),
                                              new_historian) \
                               if change != Changeset.DELETE else None

                    yield old_node, new_node, kind, change

    def next_rev(self, rev, path=''):
        return self.git.hist_next_revision(rev)

    def previous_rev(self, rev, path=''):
        return self.git.hist_prev_revision(rev)

    def parent_revs(self, rev):
        return self.git.parents(rev)

    def child_revs(self, rev):
        return self.git.children(rev)

    def rev_older_than(self, rev1, rev2):
        return self.git.rev_is_anchestor_of(self.normalize_rev(rev1),
                                            self.normalize_rev(rev2))

    # def clear(self, youngest_rev=None):
    #     self.youngest = None
    #     if youngest_rev is not None:
    #         self.youngest = self.normalize_rev(youngest_rev)
    #     self.oldest = None

    def clear(self, youngest_rev=None):
        self.sync()

    def sync(self, rev_callback=None, clean=None):
        if rev_callback:
            revs = set(self.git.all_revs())

        if self.persistent_cache:
            del self._cached_git  # invalidate persistent cache
        if not self.git.sync():
            return None # nothing expected to change

        if rev_callback:
            revs = set(self.git.all_revs()) - revs
            for rev in revs:
                rev_callback(rev)

class GitNode(Node):

    def __init__(self, repos, path, rev, log, ls_tree_info=None,
                 historian=None):
        self.log = log
        self.repos = repos
        self.fs_sha = None # points to either tree or blobs
        self.fs_perm = None
        self.fs_type = None
        self.fs_size = None
        if rev:
            rev = repos.normalize_rev(to_unicode(rev))
        else:
            rev = repos.youngest_rev
        created_rev = rev

        kind = Node.DIRECTORY
        p = path.strip('/')
        if p:  # ie. not the root-tree
            if not rev:
                raise NoSuchNode(path, rev)
            if ls_tree_info is None:
                ls_tree_info = repos.git.ls_tree(rev, p)
                if ls_tree_info:
                    ls_tree_info = ls_tree_info[0]
            if not ls_tree_info:
                raise NoSuchNode(path, rev)
            self.fs_perm, self.fs_type, self.fs_sha, self.fs_size, fname = \
                ls_tree_info

            # fix-up to the last commit-rev that touched this node
            created_rev = repos.git.last_change(rev, p, historian)

            if self.fs_type == 'tree':
                kind = Node.DIRECTORY
            elif self.fs_type == 'blob':
                kind = Node.FILE
            elif _is_submodule(self.fs_perm):
                # FIXME: this is a workaround for missing git submodule
                #        support in the plugin
                kind = Node.DIRECTORY
            else:
                self.log.warning('Got unexpected object %r', ls_tree_info)
                raise TracError(_("Internal error (got unexpected object "
                                  "kind '%(kind)s')", kind=self.fs_type))

        self.created_path = path
        self.created_rev = created_rev

        Node.__init__(self, repos, path, rev, kind)

    def __git_path(self):
        """return path as expected by PyGIT"""
        p = self.path.strip('/')
        if self.isfile:
            assert p
            return p
        if self.isdir:
            return p and (p + '/')

        raise TracError(_("Internal error"))

    def get_content(self):
        if not self.isfile:
            return None
        return self.repos.git.get_file(self.fs_sha)

    def get_properties(self):
        if self.fs_perm is None:
            return {}
        props = {'mode': '%06o' % self.fs_perm}
        if _is_submodule(self.fs_perm):
            props['commit'] = self.fs_sha
        return props

    def get_annotations(self):
        if not self.isfile:
            return

        return [rev for rev, lineno in
                self.repos.git.blame(self.rev,self.__git_path())]

    def get_entries(self):
        if not self.rev:  # if empty repository
            return
        if not self.isdir:
            return
        if _is_submodule(self.fs_perm):
            return

        with self.repos.git.get_historian(self.rev,
                                          self.path.strip('/')) as historian:
            for ent in self.repos.git.ls_tree(self.rev, self.__git_path()):
                yield GitNode(self.repos, ent[-1], self.rev, self.log, ent,
                              historian)

    def get_content_type(self):
        if self.isdir:
            return None

        return ''

    def get_content_length(self):
        if not self.isfile:
            return None

        if self.fs_size is None:
            self.fs_size = self.repos.git.get_obj_size(self.fs_sha)

        return self.fs_size

    def get_history(self, limit=None):
        if not self.rev:  # if empty repository
            return
        # TODO: find a way to follow renames/copies
        for is_last, rev in _last_iterable(self.repos.git.history(self.rev,
                                                self.__git_path(), limit)):
            yield (self.path, rev, Changeset.EDIT if not is_last else
                                   Changeset.ADD)

    def get_last_modified(self):
        if not self.isfile:
            return None

        try:
            msg, props = self.repos.git.read_commit(self.rev)
            user, ts = _parse_user_time(props['committer'][0])
        except:
            self.log.error("internal error (could not get timestamp from "
                           "commit '%s')", self.rev)
            return None

        return ts

class GitChangeset(Changeset):
    """A Git changeset in the Git repository.

    Corresponds to a Git commit blob.
    """

    action_map = { # see also git-diff-tree(1) --diff-filter
        'A': Changeset.ADD,
        'M': Changeset.EDIT, # modified
        'T': Changeset.EDIT, # file type (mode) change
        'D': Changeset.DELETE,
        'R': Changeset.MOVE, # renamed
        'C': Changeset.COPY
        } # TODO: U, X, B

    def __init__(self, repos, sha):
        if sha is None:
            raise NoSuchChangeset(sha)

        try:
            msg, props = repos.git.read_commit(sha)
        except PyGIT.GitErrorSha:
            raise NoSuchChangeset(sha)

        self.props = props

        assert 'children' not in props
        _children = list(repos.git.children(sha))
        if _children:
            props['children'] = _children

        committer, author = self._get_committer_and_author()
        # use 1st author/committer as changeset owner/timestamp
        c_user = a_user = c_time = a_time = None
        if committer:
            c_user, c_time = _parse_user_time(committer)
        if author:
            a_user, a_time = _parse_user_time(author)

        if repos.use_committer_time:
            time = c_time or a_time
        else:
            time = a_time or c_time

        if repos.use_committer_id:
            user = c_user or a_user
        else:
            user = a_user or c_user

        # try to resolve email address to trac uid
        user = repos.rlookup_uid(user) or user

        Changeset.__init__(self, repos, rev=sha, message=msg, author=user,
                           date=time)

    def _get_committer_and_author(self):
        committer = author = None
        if 'committer' in self.props:
            committer = self.props['committer'][0]
        if 'author' in self.props:
            author = self.props['author'][0]
        return committer, author

    def get_properties(self):
        properties = {}

        if 'parent' in self.props:
            properties['Parents'] = self.props['parent']

        if 'children' in self.props:
            properties['Children'] = self.props['children']

        committer, author = self._get_committer_and_author()
        if author != committer:
            properties['git-committer'] = _parse_user_time(committer)
            properties['git-author'] = _parse_user_time(author)

        branches = list(self.repos.git.get_branch_contains(self.rev,
                                                           resolve=True))
        if branches:
            properties['Branches'] = branches

        return properties

    def get_changes(self):
        # Returns the differences against the first parent
        parent = self.props.get('parent')
        parent = parent[0] if parent else None

        changes = self.repos.git.get_changes(parent, self.rev)
        for mode1, mode2, obj1, obj2, action, path1, path2 in changes:
            path = path2 or path1
            p_path, p_rev = path1, parent

            kind = Node.DIRECTORY \
                   if _is_dir(mode2) or _is_dir(mode1) else \
                   Node.FILE

            action = GitChangeset.action_map[action]

            if action == Changeset.ADD:
                p_path = p_rev = None

            yield path, kind, action, p_path, p_rev

    def get_branches(self):
        _rev = self.rev

        return [(k, v == _rev)
                for k, v in self.repos.git.get_branch_contains(_rev,
                                                               resolve=True)]

    def get_tags(self):
        return self.repos.git.get_tags(self.rev)

class GitwebProjectsRepositoryProvider(Component):

    implements(IRepositoryProvider)

    projects_list = PathOption('gitweb-repositories', 'projects_list', doc=
        """Path to a gitweb-formatted projects.list""")

    projects_base = PathOption('gitweb-repositories', 'projects_base', doc=
        """Path to the base of your git projects""")

    projects_url = Option('gitweb-repositories', 'projects_url', doc=
        """Template for project URLs. `%s` will be replaced with the repo
        name""")

    sync_per_request = ListOption('gitweb-repositories',
        'sync_per_request', '', doc="""Repositories to sync on every request
        (not recommended).""")

    def get_repositories(self):
        """Retrieve repositories specified in a `projects_list` file."""
        if not self.projects_list:
            return

        if not os.path.exists(self.projects_list):
            self.log.warning("The [git] projects_list file was not found at "
                             "'%s'", self.projects_list)
            return

        with open(self.projects_list, 'r', encoding='utf-8') as fp:
            for line in fp:
                entries = line.strip().split()
                if entries:
                    name = entries[0]
                    reponame = name.rstrip('.git')
                    info = {
                        'dir': os.path.join(self.projects_base, name),
                        'sync_per_request': reponame in self.sync_per_request,
                        'type': 'git',
                    }
                    description_path = \
                        os.path.join(info['dir'], 'description')
                    if os.path.exists(description_path):
                        with open(description_path, 'r',
                                  encoding='utf-8') as fd:
                            info['description'] = fd.read().strip()
                    if self.projects_url:
                        info['url'] = self.projects_url % reponame
                    yield reponame, info


import numpy as np

from pylatex import Document, Section, Subsection, Tabular, Math, TikZ, Axis, \
    Plot, Figure, Package, Matrix
from pylatex.utils import italic
import os

if __name__ == '__main__':
    item="XT-500"
    platforms=["NSC","WMEH","FRC"]
    device = {
    'XTL-5000': ['NSC'],
    'RT-300': ['WMEH','NSC'],
    'AN/AP-213':['WHEC','FRC','NSC']
    }
    image_filename = os.path.join(os.path.dirname(__file__), 'kitten.jpg')

    doc = Document()
    doc.packages.append(Package('geometry', options=['tmargin=1cm',
                                                     'lmargin=10cm']))

    with doc.create(Section('Hessam has created this!')):
        doc.append('Some regular text and some')
        doc.append(italic('italic text. '))
        doc.append('\nAlso some crazy characters: $&#{}')
        with doc.create(Subsection('Math that is incorrect')):
            doc.append(Math(data=['2*3', '=', 9]))

        with doc.create(Subsection('Table of something')):
            with doc.create(Tabular('rc|cl')) as table:
                table.add_hline()
                table.add_row((1, 2, 3, device['XTL-5000']))
                table.add_hline()
                table.add_row((-1, 'ss', 3, 4))
                table.add_hline(1, 2)
                table.add_empty_row()
                table.add_row((4, 5, 6, 7))

    a = np.array([[100, 10, 20]]).T
    M = np.matrix([[2, 3, 4],
                   [0, 0, 1],
                   [0, 0, 2]])

    with doc.create(Section('The fancy stuff')):
        with doc.create(Subsection('Correct matrix equations')):
            doc.append(Math(data=[Matrix(M), Matrix(a), '=', Matrix(M * a)]))

        with doc.create(Subsection('Beautiful graphs')):
            with doc.create(TikZ()):
                plot_options = 'height=6cm, width=6cm, grid=major'
                with doc.create(Axis(options=plot_options)) as plot:
                    plot.append(Plot(name='model', func='-x^5 - 242'))

                    coordinates = [
                        (-4.77778, 2027.60977),
                        (-3.55556, 347.84069),
                        (-2.33333, 22.58953),
                        (-1.11111, -493.50066),
                        (0.11111, 46.66082),
                        (1.33333, -205.56286),
                        (2.55556, -341.40638),
                        (3.77778, -1169.24780),
                        (5.00000, -3269.56775),
                    ]

                    plot.append(Plot(name='estimate', coordinates=coordinates))

        with doc.create(Subsection('Cute kitten pictures')):
            with doc.create(Figure(position='h!')) as kitten_pic:
                kitten_pic.add_image(image_filename, width='120px')
                kitten_pic.add_caption('Look it\'s on its back')

    doc.generate_pdf('full')


from osgeo import gdal, osr

def float2int(src_raster, dst_raster):
    """
    Converts Float number pixels of a GeoTiff raster in Integer numbers
    WARNING: FUNCTION NOT YET FULLY TESTED - MAY NOT WORK UNDER ALL CIRCUMSTANCES
    :param src_raster: STR of full directory for the source raster (TIFF)
    :param dst_raster:STR of full directory for the output raster (TIFF)
    :return: None
    """
    # Open existing dataset
    src_ds = gdal.Open(src_raster)

    # Open output format driver, see gdal_translate --formats for list
    format = "GTiff"
    driver = gdal.GetDriverByName(format)
    srs = osr.SpatialReference()
    srs.ImportFromWkt(src_ds.GetProjection())

    # Output to new format
    ds = gdal.Translate(dst_raster, src_raster, projWin=src_ds.GetProjection())

    # Properly close the datasets to flush to disk
    ds = None
    src_ds = None


'''
    构建B-树提供单词查找，输入单词返回单词的倒排记录
'''
import operator
from RetrivalSys import DictBuild
from functools import cmp_to_key

class BTree(object):
    """具有插入、搜索、打印的B树。"""

    class Node(object):
        """B树的节点"""

        def __init__(self, t):
            self.keys = []
            self.children = []
            # 是否为叶子节点
            self.leaf = True
            # t是树的度，节点的最大关键字数量是2t-1
            self._t = t

        def split(self, parent, payload):
            """分裂节点，调整key与children"""
            new_node = self.__class__(self._t)
            # _class_获得已有当前对象的类

            mid_point = self.size // 2
            # " / "表示 浮点数除法，返回浮点结果;" // "表示整数除法
            split_value = self.keys[mid_point]
            parent.add_key(split_value)

            # 将key与孩子节点添加到合适的节点
            new_node.children = self.children[mid_point + 1:]
            self.children = self.children[:mid_point + 1]
            # 将中间点之后的所有孩子节点赋给新的节点,[a:]表示将列表里a之后元素，[:a]表示列表里a之前的元素，包括a
            # 将中间点之前的所有孩子节点留给原节点
            new_node.keys = self.keys[mid_point + 1:]
            self.keys = self.keys[:mid_point]

            # 新节点有孩子，将它设为内节点
            if len(new_node.children) > 0:
                new_node.leaf = False

            parent.children = parent.add_child(new_node)
            # 将key与提升的关键字比较，决定返回关键字应该插入的分支
            if cmp_precode(payload, split_value) is -1:
                return self
            else:
                return new_node

        @property
        def _is_full(self):
            return self.size == 2 * self._t - 1

        @property
        def size(self):
            return len(self.keys)

        def add_key(self, value):
            """
            将key的值为value添加keys列表
            """
            self.keys.append(value)
            self.keys.sort(key=cmp_to_key(cmp_precode), reverse=False)  # 对keys重新排序

        def add_child(self, new_node):
            """
            给节点添加一个孩子. 对节点的孩子节点重新排序. allowing for children
            to be ordered even after middle nodes are split.
            返回: 一个有序的孩子节点列表
            """
            i = len(self.children) - 1
            while i >= 0 and cmp_precode(self.children[i].keys[0], new_node.keys[0]) is 1:
                i -= 1
            return self.children[:i + 1] + [new_node] + self.children[i + 1:]

    def __init__(self, t):
        """
        Create the B-tree. t是树的度.（算法导论里的定义，度为内节点最少的孩子数目，所以每个节点最少有t个孩子，最少有t-1个key
        最多有2t个孩子，2t-1个key）Tree 刚建立时没有key
        允许重复的key
        """
        self._t = t
        if self._t <= 1:
            raise ValueError("B-Tree must have a degree of 2 or more.")
        self.root = self.Node(t)

    def insert(self, payload):
        """在B-Tree中插入值为payload的关键字"""
        node = self.root
        # 根节点比较特殊，需要单独定义
        if node._is_full:
            # 根节点满，生成一个节点作为新的根节点，将原有根节点分裂为两个节点，作为孩子放入新的根节点孩子列表
            new_root = self.Node(self._t)
            new_root.children.append(self.root)
            new_root.leaf = False

            node = node.split(new_root, payload)
            self.root = new_root
        while not node.leaf:
            i = node.size - 1
            while i > 0 and cmp_precode(payload, node.keys[i]) is -1:  # 找到key在当前node哪个key之间
                i -= 1
            if cmp_precode(payload, node.keys[i]) is 1:  # 在当前key的右分支
                i += 1

            next = node.children[i]
            if next._is_full:
                node = next.split(node, payload)
            else:
                node = next
        # 将路径上的所有满的节点都分裂，就可以轻松地插入key.
        node.add_key(payload)

    def search(self, value, node=None):
        """如果B树包含查询的key，返回node"""
        if node is None:
            node = self.root
        if node is not None:
            h = node.size
            i = 0
            while i < h:
                w = cmp_key(value, node.keys[i])
                if w is not -1 and w is not -2:
                    return w
                elif w is -2:
                    i += 1
                elif w is -1:
                    break
            if node.leaf:
                return False
            return self.search(value, node.children[i])

    def print_order(self):
        """按每层打印B树."""
        this_level = [self.root]
        while this_level:
            next_level = []
            output = ""
            for node in this_level:
                if node.children:
                    next_level.extend(node.children)
                output += str(node.keys) + " "
            print(output)
            this_level = next_level

# 比较压缩词典行precode1和precode2的关系
def cmp_precode(precode1, precode2):
    """前缀编码比较函数"""
    pre1 = precode1.split('*')[0]
    pre2 = precode2.split('*')[0]
    if pre1 == '':
        pre1 = DictBuild.LineDecompress(precode1)[0][0]
    if pre2 == '':
        pre2 = DictBuild.LineDecompress(precode2)[0][0]
    mlen = min(len(pre1), len(pre2))
    pre1 = pre1[0:mlen]
    pre2 = pre2[0:mlen]
    if operator.lt(pre1, pre2):
        return -1
    elif operator.gt(pre1, pre2):
        return 1

    elif operator.eq(pre1, pre2):
        word1 = DictBuild.LineDecompress(precode1)[0][0]
        word2 = DictBuild.LineDecompress(precode2)[0][0]
        if operator.lt(word1, word2):
            return -1
        elif operator.gt(word1, word2):
            return 1
        elif operator.eq(word1, word2):
            return 0

# 单词比当前前缀小时，返回-1
# 单词比当前前缀大时，返回-2
# 找到时，返回偏移量
def cmp_key(key, precode):
    """key与前缀编码的比较函数"""
    pre = precode.split('*')[0]
    decode, offset = DictBuild.LineDecompress(precode)
    if pre == '':
        pre = decode[0]
    mlen = min(len(key), len(pre))
    prekey = key[0:mlen]
    pre = pre[0:mlen]
    if operator.lt(prekey, pre):
        if operator.ge(key, decode[0]):
            juge = find(decode, key)
            if juge is not -1:
                return offset[juge]
        return -1
    # key的前缀小于编码的前缀，key小于前缀
    elif operator.gt(prekey, pre):
        if operator.le(key, decode[len(decode) - 1]):
            juge = find(decode, key)
            if juge is not -1:
                return offset[juge]
        return -2
    elif operator.eq(pre, prekey):
        juge = find(decode, key)
        if juge is not -1:
            return offset[juge]
        elif operator.gt(key, decode[len(decode) - 1]):
            return -2
        elif operator.lt(key, decode[0]):
            return -1

def find(decode, key):
    """解码后，在块中二分查找"""
    low = 0
    high = len(decode) - 1
    while low <= high:
        mid = (low + high) // 2
        if operator.eq(decode[mid], key):
            return mid
        elif operator.gt(decode[mid], key):
            high = mid - 1
        elif operator.lt(decode[mid], key):
            low = mid + 1
    return -1

def FindWord(tree, word):
    return tree.search(word)

# 构建B-树
def createTree(args, key=2.5):
    cpn_path = args.cpn_dir
    dict_path = cpn_path + 'CompressedDict.txt'
    c = BTree(key)
    dict_file = open(dict_path, "r", encoding="utf-8")
    for line in dict_file:
        line = line.strip('\n')
        c.insert(line)
    dict_file.close()
    return c


# -*- coding: utf-8 -*-
import os

import tensorflow as tf
from keras import backend as K
from tensorflow.python.tools import freeze_graph
from tensorflow.python.tools import optimize_for_inference_lib

def export_model(saver: tf.train.Saver, input_names: list, output_name: str, model_name: str):
    """
    You can find node names by using debugger: just connect it right after model is created and look for nodes in the inspec
    :param saver:
    :param input_names:
    :param output_name:
    :param model_name:
    :return:
    """
    os.makedirs("./out", exist_ok=True)
    tf.train.write_graph(K.get_session().graph_def, 'out',
                         model_name + '_graph.pbtxt')

    saver.save(K.get_session(), 'out/' + model_name + '.chkp')

    # pbtxt is human readable representation of the graph
    freeze_graph.freeze_graph('out/' + model_name + '_graph.pbtxt', None,
                              False, 'out/' + model_name + '.chkp', output_name,
                              "save/restore_all", "save/Const:0",
                              'out/frozen_' + model_name + '.pb', True, "")

    input_graph_def = tf.GraphDef()
    with tf.gfile.Open('out/frozen_' + model_name + '.pb', "rb") as f:
        input_graph_def.ParseFromString(f.read())

    # optimization of the graph so we can use it in the android app
    output_graph_def = optimize_for_inference_lib.optimize_for_inference(
        input_graph_def, input_names, [output_name],
        tf.float32.as_datatype_enum)

    # This is archived optimal graph in the protobuf format we'll use in our android App.
    with tf.gfile.FastGFile('out/opt_' + model_name + '.pb', "wb") as f:
        f.write(output_graph_def.SerializeToString())

    print("graph saved!")


# Created by: Gavin Zhou
# Created on: Dec 2017
# Created for: ICS3U

from enum import Enum

# 1. about street
street_type = Enum('Avenue', 'Boulevard', 'Crescent', 'Lane', 'Road')

# 2. about provinces
provinces = Enum('AB', 'BC', 'MB', 'NB', 'NL', 'NT', 'NS', 'NU', 'ON', 'PE', 'QC', 'SK', 'YT')

class Address():
    def __init__(self, name, street_number, street_name, street_type, province, city, postal_code):
        self.name = name
        self.street_number = street_number
        self.street_name = street_name
        self.street_type = street_type
        self.province = province
        self.city = city
        self.postal_code = postal_code

user_name = raw_input("Enter your name: ")

user_street_number = raw_input("Enter your street number: ")

user_street_name = raw_input("Enter your street name: ")

print("Choose your street type: Street, Boulevard, Road, Avenue, Crescent")
user_street_type = raw_input("Enter your street type: ")
if user_street_type in street_type:
    print('Valid street type')

    print("Enter the abbreviation of the province in this list: AB (Alberta), BC (British Columbia), MB (Manitoba), NB (New Brunswick), NL (Newfoundland and Labrador), NT (Northwest Territories), NS (Nova Scotia), NU (Nunavut), ON (Ontario), PE (Prince Edward Island), QC (Quebec), SK (Saskatchewan)")
user_province= raw_input("Enter your province(abbreviation): ")
if user_province in provinces:
        print('Valid province')

user_city = raw_input("Enter your city: ")

user_postal_code = raw_input("Enter your postal code: ")

user_input = Address(user_name, user_street_number, user_street_name, user_street_type, user_city, user_province, user_postal_code)
print(user_input.name + '\n' + user_input.street_number + ' ' + user_input.street_name + ' ' +  user_input.street_type + '\n' +  ' ' + user_input.province + ' ' + user_input.city + ' ' + user_input.postal_code)


from abc import abstractmethod, ABCMeta
from typing import List, Union
from app.dto.permission_dto import *
from app.models import Permission, Person, Role

class PermissionRepository(metaclass=ABCMeta):
    @abstractmethod
    def create_permission(self, model: CreatePermissionDto):
        """Create Permission Object"""
        raise NotImplementedError

    @abstractmethod
    def edit_permission(self, permission_id: int, model: EditPermissionDto):
        """Edit Permission Object"""
        raise NotImplementedError

    @abstractmethod
    def list_permission(self) -> List[ListPermissionDto]:
        """List Permission Objects"""
        raise NotImplementedError

    @abstractmethod
    def get_permission(self, permission_id: int) -> GetPermissionDto:
        """Get Permission Object"""
        raise NotImplementedError

    @abstractmethod
    def assign_permission_to_role(self, model: AssignPermissionToRoleDto):
        """Assign Permission to Role"""
        raise NotImplementedError

    @abstractmethod
    def assign_permission_to_person(self, model: AssignPermissionToUserDto):
        """Assign Permission to Person"""
        raise NotImplementedError

class DjangoORMPermissionRepository(PermissionRepository):
    def create_permission(self, model: CreatePermissionDto):
        permission = Permission()
        permission.id = model.id
        permission.name = model.name
        permission.description = model.description
        permission.save()

    def edit_permission(self, permission_id: int, model: EditPermissionDto):
        try:
            permission = Permission.objects.get(id=permission_id)
            permission.name = model.name
            permission.description = model.description
            permission.save()
        except Permission.DoesNotExist as e:
            return e

    def list_permission(self) -> List[ListPermissionDto]:
        permissions = Permission.objects.all()
        result: List[ListPermissionDto] = []

        for permission in permissions:
            item = ListPermissionDto()
            item.name = permission.name
            result.append(item)
        return result

    def get_permission(self, permission_id: int) -> GetPermissionDto:
        permission = Permission.objects.get(id=permission_id)
        item = GetPermissionDto()
        item.id = permission.id
        item.name = permission.name
        item.description = permission.description
        return item

    def assign_permission_to_person(self, model: AssignPermissionToUserDto):
        try:
            permission = Permission.objects.get(id=model.permission_id)
            Person.objects.get(id=model.person_id).permission.add(permission)
        except Exception as e:
            return e

    def assign_permission_to_role(self, model: AssignPermissionToRoleDto):
        try:
            permission = Permission.objects.get(id=model.permission_id)
            Role.objects.get(id=model.role_id).permission.add(permission)
        except Exception as e:
            return e


"""
This module is responsible for processing the data.  Each function in this module will take a list of reviews,
process it and return the desired result.
"""

"""
Task 16 - 20: Write suitable functions to process the data.

Each of the functions below should follow the pattern:
- Take a list of reviews (where each review is a list of data values) as a parameter.
- Process the list of reviews appropriately.  You may use the module 'tui' to retrieve any additional information
required from the user to complete the processing.
- Return a suitable result

The required functions are as follows:
- Retrieve the total number of reviews that have been loaded.
- Retrieve the reviews for a hotel where the hotel name is specified by the user.
- Retrieve the reviews for the dates specified by the user.
- Retrieve all the reviews grouped by the reviewer’s nationality.
- Retrieve a summary of all the reviews. This should include the following information for each date in ascending order:
    - the total number of negative reviews on that date
    - the total number of positive reviews on that date
    - the average rating on that date
"""

# TODO: Your code here

from typing import List
from tui import hotel_name, review_dates
from main import read_csv
import csv

filename = 'data/hotel_reviews.csv'
reviews_data = []

def get_total_reviews(reviews: List[List[str]]) -> int:
    """
    Task 16: Retrieve the total number of reviews that have been loaded.

    :param reviews: A list of reviews
    :return: The total number of reviews
    """
    read_csv()
    total_reviews_index = read_csv.header.index('Total_Reviews_By_Reviewer')
    total_reviews_sum = 0

    # Iterate over each row in the CSV file
    for i, row in enumerate(read_csv.csv_reader):
        # Add the value from the "Total_Reviews_By_Reviewer" column to the sum
        total_reviews_sum += int(row[total_reviews_index])

        # Append the entire row to the reviews_data list
        reviews_data.append(row)

        # Print the total sum of the "Total_Reviews_By_Reviewer" column
        print("Total reviews:", total_reviews_sum)

    return len(reviews)

def get_reviews_by_hotel(reviews: List[List[str]]) -> List[List[str]]:
    """
    Task 17: Retrieve the reviews for a hotel where the hotel name is specified by the user.

    :param reviews: A list of reviews
    :return: The reviews for the specified hotel
    """
    hotel_name = hotel_name()
    return [review for review in reviews if review[1] == hotel_name]

def get_reviews_by_dates(reviews: List[List[str]]) -> List[List[str]]:
    """
    Task 18: Retrieve the reviews for the dates specified by the user.

    :param reviews: A list of reviews
    :return: The reviews for the specified dates
    """
    review_dates = review_dates()
    return [review for review in reviews if review[0] in review_dates]

def group_reviews_by_nationality(reviews: List[List[str]]) -> dict:
    """
    Task 19: Retrieve all the reviews grouped by the reviewer's nationality.

    :param reviews: A list of reviews
    :return: A dictionary where the keys are nationalities and the values are lists of reviews for each nationality
    """
    grouped_reviews = {}
    for review in reviews:
        nationality = review[2]
        if nationality in grouped_reviews:
            grouped_reviews[nationality].append(review)
        else:
            grouped_reviews[nationality] = [review]
    return grouped_reviews

def summarize_reviews(reviews: List[List[str]]) -> List[dict]:
    """
    Task 20: Retrieve a summary of all the reviews.

    :param reviews: A list of reviews
    :return: A list of dictionaries containing the summary information for each date
    """
    summary = []
    dates = set(review[0] for review in reviews)
    for date in sorted(dates):
        positive_reviews = 0
        negative_reviews = 0
        total_rating = 0
        num_reviews = 0
        for review in reviews:
            if review[0] == date:
                rating = float(review[5])
                total_rating += rating
                num_reviews += 1
                if rating >= 3.0:
                    positive_reviews += 1
                else:
                    negative_reviews += 1
        average_rating = total_rating / num_reviews if num_reviews > 0 else 0
        summary.append({
            'date': date,
            'positive_reviews': positive_reviews,
            'negative_reviews': negative_reviews,
            'average_rating': average_rating
        })
    return summary


# -*- coding: utf-8 -*-
"""
Created on Wed Nov 14 18:11:12 2018

@author: Kathrine
"""
import numpy as np
import matplotlib.pyplot as plt

N=25               #Число игроков
Coins = 100             #Число монеток
times = 10000
Players=[]               #Число итераций
CoinsOfPlayers=[]           #Массив монеток у игроков
Remain=[]
Taken=[]                  #Сколько монеток взяли у игрока
Transfer=[]

def DrawThis(Array, a): #Рисуем всякую графику
    dpi = 80
    plt.figure(dpi = dpi, figsize = (512 / dpi, 384 / dpi) )
    plt.title('здесь могла быть ваша реклама')
    ax = plt.axes()
    ax.set_ylim( min(range(1)), max(range(350)) )
    plt.bar([x  for x in Players], Array,
        width = 0.3, color = 'red',
        zorder = 2)
    plt.savefig('zbars%d.png' % a)
    ax.clear()
    plt.close()

for i in range(N):
    CoinsOfPlayers.append(Coins)
    Players.append(i)

t=0
while t < times :
    for i in range(N):
        #xi= rnd.uniform(0.2 ,0.5)    #Генерируем случайную величину
        #xi = rnd.gauss(0,1)
        xi= np.abs(np.random.normal(0,0.27))
        #print(xi)
        Taken.append(CoinsOfPlayers[i]*xi)
        Remain.append( CoinsOfPlayers[i] - ( CoinsOfPlayers[i] * xi ))

    sum=0
    for i in range(N):
        if i != 0:
            Transfer.append(Remain[i]+Taken[i-1])
        else:
            Transfer.append(Remain[i]+Taken[N-1])
        sum=Transfer[i]+sum
    CoinsOfPlayers.clear()
    CoinsOfPlayers=Transfer[:]
    DrawThis(CoinsOfPlayers, t)
    Remain.clear()
    Taken.clear()
    Transfer.clear()
    #ax.clear()
    #print("Итерации" + str(t))
    t+=1

#print(Transfer)
#print(CoinsOfPlayers)
#print(Taken)
#print(Remain)


import heapq
from typing import List
from math import floor

class Solution:
    def minStoneSum(self, piles: List[int], k: int) -> int:
        heap = [-pile for pile in piles]
        heapq.heapify(heap)

        for _ in range(k):
            heapq.heappush(heap, floor(heapq.heappop(heap) / 2))

        return -sum(heap)


import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
from pdb import set_trace
import pickle

# import prettyjson file from parent dir
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import prettyjson as prettyjson

outdir = os.getcwd()+'/Plots'

fname = 'median_Mtt_Mthad.json'
median_dict = prettyjson.loads(open(fname).read())

mtt_ranges_to_centers = {
	'M($t\\overline{t}$) 200-350' : 275, 'M($t\\overline{t}$) 350-400' : 375, 'M($t\\overline{t}$) 400-500' : 450,
	'M($t\\overline{t}$) 500-700' : 600, 'M($t\\overline{t}$) 700-1000' : 850, 'M($t\\overline{t}$) $\geq$1000' : 1200
}
mthad_ranges_to_centers = {
	'M($t_{h}$) 0.9-1.1' : 1.0, 'M($t_{h}$) 1.1-1.3' : 1.2, 'M($t_{h}$) 1.3-1.5' : 1.4, 'M($t_{h}$) 1.5-1.7' : 1.6,
	'M($t_{h}$) 1.7-1.9' : 1.8, 'M($t_{h}$) 1.9-2.1' : 2.0, 'M($t_{h}$) 2.1-2.3' : 2.2, 'M($t_{h}$) 2.3-2.5' : 2.4
}

mttbar_ranges = [ 'Mttbar200to350', 'Mttbar350to400', 'Mttbar400to500', 'Mttbar500to700', 'Mttbar700to1000', 'Mttbar1000toInf']

mthad_bin_edges = np.arange(0.9, 2.7, 0.2).tolist()
mttbar_bin_edges = [200, 350, 400, 500, 700, 1000]
alpha_bin_edges = [0.5, 1.0, 1.5, 2.0, 2.5, 3.0]

colors = ['green', 'red', 'black', 'blue', 'orange', 'magenta', 'cyan', 'yellow']

### create grid of ( x = 173.1/Mthad, y = mttbar, z = medians )

x = np.array([1.0 , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4]) # 173.1/mthad vals
y = np.array([275, 375, 450, 600, 850, 1200]) # mttbar bins

for alpha_key in median_dict.keys():
	z = np.array([median_dict[alpha_key][mtt_range]['medians'] for mtt_range in mttbar_ranges]) # median alpha values

	f = interpolate.interp2d(x, y, z, kind='cubic')

		## save interpolation function for each alpha
	with open('%s/Alpha_%s_Interpolation.pkl' % (outdir, alpha_key), 'wb') as pkl_file:
		pickle.dump(f, pkl_file)

	#interp_loaded = 0
	#with open('%s/Alpha_%s_Interpolation.pkl' % (outdir, alpha_key), 'rb') as interpolate:
	#	interp_loaded = pickle.load(interpolate)

	xnew = np.linspace(0.9,3.0, 500)
	z500 = f(xnew, 500) ## estimate new alphas for mttbar = 500
	z350 = f(xnew, 350) ## estimate new alphas for mttbar = 350

	## make alpha vs 173.1/MTHad plots
	fig, ax = plt.subplots()
	for i in range(len(y)):
		leg_label = [ k for k,v in mtt_ranges_to_centers.items() if v == y[i] ][0]
		plt.plot(x, z[i,:], linestyle='None', color=colors[i], marker='.', label=leg_label)

	plt.plot(xnew, z500, linestyle='-', color='cyan', label='M($t\\overline{t}$)=500 Est.')
	plt.plot(xnew, z350, linestyle='-', color='black', label='M($t\\overline{t}$)=350 Est.')

	ax.set_xticks(mthad_bin_edges)
	ax.xaxis.grid(True, which='major')
	ax.set_yticks(alpha_bin_edges)
	ax.yaxis.grid(True, which='major')
	plt.xlabel('173.1/Reco M($t_{h}$)')
	if alpha_key == 'THad_E':
		plt.ylabel('$\\alpha_{E}$ = Gen E($t_{h}$)/Reco E($t_{h}$)')
	elif alpha_key == 'THad_P':
	    plt.ylabel('$\\alpha_{P}$ = Gen P($t_{h}$)/Reco P($t_{h}$)')
	else: # 'THad_M'
	    plt.ylabel('$\\alpha_{M}$ = Gen M($t_{h}$)/Reco M($t_{h}$)')

	plt.ylim(0.5, 3.0)
	plt.legend(loc='upper left',fontsize=8, numpoints=1)
	fig.savefig('%s/Alpha_%s_vs_MTHad.png' % (outdir, alpha_key) )
	#set_trace()
	#plt.show()

	ynew = np.linspace(200, 1300, 1100)
	z1p3 = f(1.3, ynew) ## estimate new alphas for mthad = 1.3
	z2p1 = f(2.1, ynew) ## estimate new alphas for mthad = 2.1
	## make alpha vs /Mttbar plots
	fig, ax = plt.subplots()
	for i in range(len(x)):
		leg_label = [ k for k,v in mthad_ranges_to_centers.items() if v == x[i] ][0]
		plt.plot(y, z[:,i], linestyle='None', color=colors[i], marker='.', label=leg_label)

	plt.plot(ynew, z1p3, linestyle='-', color='green', label='M($t_{h}$)=1.3 Est.')
	plt.plot(ynew, z2p1, linestyle='-', color='red', label='M($t_{h}$)=2.1 Est.')

	ax.set_xticks(mttbar_bin_edges)
	ax.xaxis.grid(True, which='major')
	ax.set_yticks(alpha_bin_edges)
	ax.yaxis.grid(True, which='major')
	plt.xlabel('M($t\\overline{t}$)')
	if alpha_key == 'THad_E':
		plt.ylabel('$\\alpha_{E}$ = Gen E($t_{h}$)/Reco E($t_{h}$)')
	elif alpha_key == 'THad_P':
	    plt.ylabel('$\\alpha_{P}$ = Gen P($t_{h}$)/Reco P($t_{h}$)')
	else: # 'THad_M'
	    plt.ylabel('$\\alpha_{M}$ = Gen M($t_{h}$)/Reco M($t_{h}$)')

	plt.ylim(0.5, 3.0)
	plt.legend(loc='upper right',fontsize=8, numpoints=1)
	fig.savefig('%s/Alpha_%s_vs_MTTBar.png' % (outdir, alpha_key) )
	#set_trace()


def main():
    import numpy as np
    import numpy.random as rnd
    import matplotlib.pyplot as plt

    import gncpy.plotting as gplot
    from gncpy.filters import KalmanFilter
    from gncpy.filters import InteractingMultipleModel
    from gncpy.dynamics.basic import CoordinatedTurnKnown

    # set measurement and process noise values
    m_noise = 0.002
    p_noise = 0.004

    dt = 0.01
    t0, t1 = 0, 9.5 + dt
    rng = rnd.default_rng(69)

    dyn_obj1 = CoordinatedTurnKnown(turn_rate=0)
    dyn_obj2 = CoordinatedTurnKnown(turn_rate=5 * np.pi / 180)

    in_filt1 = KalmanFilter()
    in_filt1.set_state_model(dyn_obj=dyn_obj1)
    m_mat = np.array([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 1]])
    in_filt1.set_measurement_model(meas_mat=m_mat)
    in_filt1.cov = np.diag([0.25, 0.25, 3.0, 3.0, 0.25])
    gamma = np.array([0, 0, 1, 1, 0]).reshape((5, 1))
    # in_filt1.proc_noise = gamma @ np.array([[p_noise ** 2]]) @ gamma.T
    in_filt1.proc_noise = np.eye(5) * np.array([[p_noise ** 2]])
    in_filt1.meas_noise = m_noise ** 2 * np.eye(m_mat.shape[0])

    in_filt2 = KalmanFilter()
    in_filt2.set_state_model(dyn_obj=dyn_obj2)
    in_filt2.set_measurement_model(meas_mat=m_mat)
    in_filt2.cov = np.diag([0.25, 0.25, 3.0, 3.0, 0.25])
    in_filt2.proc_noise = np.eye(5) * np.array([[p_noise ** 2]])
    # in_filt2.proc_noise = gamma @ np.array([[p_noise ** 2]]) @ gamma.T
    in_filt2.meas_noise = m_noise ** 2 * np.eye(m_mat.shape[0])

    # vx0 = 2
    # vy0 = 1
    v = np.sqrt(2 ** 2 + 1 ** 2)
    angle = 60 * np.pi / 180
    vx0 = v * np.cos(angle)
    vy0 = v * np.sin(angle)

    filt_list = [in_filt1, in_filt2]

    model_trans = np.array([[1 - 1 / 200, 1 / 200], [1 / 200, 1 - 1 / 200]])

    init_means = np.array([[0, 0, vx0, vy0, 0], [0, 0, vx0, vy0, 0]]).T
    init_covs = np.array([in_filt1.cov, in_filt2.cov])

    filt = InteractingMultipleModel()
    filt.set_models(
        filt_list, model_trans, init_means, init_covs, init_weights=[0.5, 0.5]
    )

    time = np.arange(t0, t1, dt)
    states = np.nan * np.ones((time.size, 5))
    stds = np.nan * np.ones(states.shape)
    pre_stds = stds.copy()
    states[0, :] = np.array([0, 0, vx0, vy0, 0])
    stds[0, :] = np.sqrt(np.diag(filt.cov))
    pre_stds[0, :] = stds[0, :]

    t_states = states.copy()

    for kk, t in enumerate(time[:-1]):
        states[kk + 1, :] = filt.predict(t, state_mat_args=(dt,)).flatten()
        if t < 5:
            t_states[kk + 1, :] = dyn_obj1.propagate_state(
                t, t_states[kk, :].reshape((5, 1)), state_args=(dt,)
            ).flatten()
        else:
            t_states[kk + 1, :] = dyn_obj2.propagate_state(
                t, t_states[kk, :].reshape((5, 1)), state_args=(dt,)
            ).flatten()
        pre_stds[kk + 1, :] = np.sqrt(np.diag(filt.cov))

        n_state = m_mat @ (
            t_states[kk + 1, :].reshape((5, 1))
            + gamma * p_noise * rng.standard_normal(1)
        )

        meas = (
            n_state + m_noise * rng.standard_normal(n_state.size).reshape(n_state.shape)
        ).reshape((-1, 1))

        states[kk + 1, :] = filt.correct(t, meas)[0].flatten()
        stds[kk + 1, :] = np.sqrt(np.diag(filt.cov))
    errs = states - t_states

# plot states
    fig = plt.figure()
    for ii, s in enumerate(CoordinatedTurnKnown().state_names):
        fig.add_subplot(5, 1, ii + 1)
        fig.axes[ii].plot(time, states[:, ii], color="b")
        fig.axes[ii].plot(time, t_states[:, ii], color="r")
        fig.axes[ii].grid(True)
        fig.axes[ii].set_ylabel(s)
    fig.axes[-1].set_xlabel("time (s)")
    fig.suptitle("States (mat)")
    fig.tight_layout()

    # # plot stds
    # fig2 = plt.figure()
    # for ii, s in enumerate(CoordinatedTurnKnown().state_names):
    #     fig2.add_subplot(5, 1, ii + 1)
    #     fig2.axes[ii].plot(time, stds[:, ii], color="b")
    #     fig2.axes[ii].plot(time, np.abs(errs[:, ii]), color="r")
    #     # fig.axes[ii].plot(time, pre_stds[:, ii], color="g")
    #     fig2.axes[ii].grid(True)
    #     fig2.axes[ii].set_ylabel(s + " std")
    # fig2.axes[-1].set_xlabel("time (s)")
    # fig2.suptitle("Filter standard deviations (mat)")
    # fig2.tight_layout()
    return fig

def run():
    import os

    print("Generating KF examples")

    fout = os.path.join(
        os.path.dirname(__file__), "{}.png".format(os.path.basename(__file__)[:-3])
    )
    if not os.path.isfile(fout):
        fig = main()
        fig.savefig(fout)

if __name__ == "__main__":
    import matplotlib.pyplot as plt

    plt.close("all")

    run()

    plt.show()


from .invoke import astr, arepr, Func, Table, Scope, Nothing, callfunc, S
from .visitor import fixtags, flattenbody
from .parse import parseFile
from .serialize import serialize

def isle_serialize(stack, callstack, arg):
    return serialize(arg[1])

def isle_apply(stack, callstack, arg):
    assert isinstance(arg[2], Table)
    callfunc(arg[1], arg[2], stack, callstack)
    return Nothing

def isle_puts(stack, callstack, arg):
    n = 1
    while n in arg:
        print(astr(arg[n]))
        n += 1

def isle_show(stack, callstack, arg):
    print(', '.join(arepr(x) for x in _iter_args(arg)))

def isle_assert(stack, callstack, arg):
    assert arg[1] is not None

def isle_assert_error(stack, callstack, arg):
    callstack.append(Scope(arg[1], 0, Table()))
    #something something error handling

def isle_replace_closure(stack, callstack, arg):
    assert(isinstance(arg[1], Func))
    assert(isinstance(arg[2], Table))
    new_closure = tuple(_iter_args(arg[2]))
    for env in new_closure:
        assert(isinstance(env, Table))
    return Func(body=arg[1].body, closure=new_closure)

def isle_get_closure(stack, callstack, arg):
    assert(isinstance(arg[1], Func))
    closure = Table()
    for i, v in enumerate(arg[1].closure):
        closure[i + 1] = v
    return closure

def _iter_args(t, start=1):
    n = start
    while n in t:
        yield t[n]
        n += 1

def next_item(stack, callstack, arg):
    try:
        return Table({S.func: next_item, 1: arg[1](stack, callstack, arg), S.arg: Table([(1, arg[1])])})
    except StopIteration:
        return None

def isle_args(stack, callstack, arg):
    it = _iter_args(arg[1], start=arg.get(S.start, 1))
    return next_item(stack, callstack, arg={1:lambda s,c,a:next(it)})

def isle_chars(stack, callstack, arg):
    assert isinstance(arg[1], str)
    it = iter(arg[1])
    return next_item(stack, callstack, arg={1:lambda s,c,a:next(it)})

def isle_range(stack, callstack, arg):
    start = arg[S.start] if S.start in arg else arg[1] if 2 in arg else 1
    stop = arg[S.stop] if S.stop in arg else arg[2] if 2 in arg else arg[1]
    step = arg.get(S.step, 1)
    if start <= stop:
        return Table({S.func: isle_range, 1: start, S.arg: Table({S.start: start + step, S.step: step, S.stop: stop})})

def isle_require(stack, callstack, arg):
    env = Table()
    useenv = arg.get(S.useret) is None
    callstack.append(Scope(Func(fixtags(flattenbody(parseFile(arg[1]), droplast=useenv)), ()), 0, env))
    return env if useenv else Nothing

def isle_slice(stack, callstack, arg):
    string = arg[1]
    start = arg[2]
    if start < 0:
        start = len(string) + start + 1
    end = arg.get(3, start)
    if end < 0:
        end = len(string) + end + 1
    assert 1 <= start <= len(string)
    assert start <= end <= len(string)
    return string[start - 1:end]

def isle_delkey(stack, callstack, arg):
    table = arg[1]
    key = arg[2]
    if key in table:
        del table[key]

def stdlib():
    lib = Table()
    for key, value in globals().items():
        if key.startswith('isle_'):
            lib[S[key[5:]]] = value
    return lib

stdlib = stdlib()


import sys
from itertools import chain, combinations

def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))

mask = ''
addrs = []
vdict = {}
for line in sys.stdin:
    line = line.rstrip()
    if line.startswith('mask'):
        mask = line.split(' ')[2]
    else:
        addr = int(line.split('[')[1].split(']')[0])
        val = int(line.split(' ')[2])
        binval = '{:036b}'.format(addr)
        newval = ''
        i=0
        while i<36:
            if mask[i]=='0':
                newval += binval[i]
            elif mask[i]=='1':
                newval += '1'
            else:
                newval += 'X'
            i+=1
        addrs.append(newval)
        vdict.update({newval: val})

ndict = {}
sum = 0
for val in addrs:
    toset = vdict[val]
    nval = ''
    x = []
    i=0
    while i<36:
        if val[i]=='X':
            tv = 2**(35-i)
            x.append(tv)
            nval += '0'
        else:
            nval += val[i]
        i+=1
    base_sum = int(nval, 2)
    for subset in all_subsets(x):
        bval = base_sum
        for elem in subset:
            bval += elem
        ndict.update({bval: toset})

for key in ndict.keys():
    sum+=ndict[key]
print(sum)