# Using numpy for matrix manipulations
import numpy as np

# Check if the numba module is installed (compiled, high-speed functions)
import importlib.util
foundNumba = importlib.util.find_spec("numba") is not None

if foundNumba:
	#Numba is installed, import @jit decorator
	from numba import jit
else:
	# Numba not installed, warn the user and make a blank @jit decorator
	def jit(f):
		'''Numba was not found in the current python environment
		'''
		return f

def timeWarp(a,b,method='DTW',window=0,retMat=True,**kwargs):
	'''This function is the main time warping interface, and acts
	as a convenient wrapper to the other functions.

	Parameters
	----------
		a : list or numpy 1D-array
			First time series, which will be compared against time series b
		b : list or numpy 1D-array
			Second time series (reference)
		method : str
			Time warping method ``{'DTW','ERP'}`` - see below
		window : int
			Time warping window constraint (default = 0)
		retMat : bool
			Whether to include the cost matrices in the returned object
		ERPg :	int
			g-value (for ``method = 'ERP'`` only)

	Returns
	-------
		warpObj : dict
			A timeWarpOB warp object, containing the following items:
		warpObj.backTraceCost : float
			The sum cost of following the backtrace through the cost matrix
		warpObj.backTracePath : list
			List or numpy array of pairs of coordinates in time-space describing the backtrace through
			the cost matrix
		warpObj.cost : float
			Bottom left value on the cost matrix.  With no warping window, this should
			equal warpObj.backTraceCost
		warpObj.costMat : list
			A matrix (list of lists) or numpy array describing the cost matrix between the two time
			series.  For a series of length n, this matrix will be of size n x n.  Only
			output if ``retMat = True`` in the input parameters
		warpObj.distMat : list
			A matrix (list of lists) or numpy array describing the L1-distance matrix between the two
			time series.  For a series of length n, this matrix will be of size n x n.
			Only output if ``retMat = True`` in the input parameters
		warpObj.warpWindow : int
			Returning the warp window parameter used (used by plotting functions)
		warpObj.warpStats : dict
			Warp statistics object, containing:
		warpObj.warpStats.timeAhead : int
			The number of periods that time series a was in sync with time series b.
		warpObj.warpStats.timeAhead : int
			The number of periods that time series a was ahead of time series b.
		warpObj.warpStats.timeBehind : int
			The number of periods that time series a was behind of time series b.
		warpObj.warpStats.amountAhead : int
			The total sum of the number of periods that time series a was leading
			time series b by.
		warpObj.warpStats.amountBehind : int
			The total sum of the number of periods that time series a was lagging
			time series b by.
		warpObj.warpStats.avgAhead : int
			Average amount of periods that a was ahead of b by, i.e.
			amountAhead divided by timeAhead
		warpObj.warpStats.avgAhead : int
			Average amount of periods that a was behind b by, i.e.
			amountBehind divided by timeBehind
		warpObj.warpStats.avgWarp : int
			Average amount of periods that a ahead or behind b by, i.e.
			``(amountAhead - amountBehind) / (timeAhead + timeBehind + timeSync)``
			This will give positive values if a is on average ahead of b and negative
			values if a is on average behind b.

	Notes
	-----
	* If lists are supplied, the output matrices will be in list form.  If numpy arrays are supplied, the output will be as numpy arrays.

	* Numpy arrays will calculate faster, as no internal type conversion is required.

	* Time series should be of equal length.  If they are not, the longer will be clipped from the end.

	* ERP and DTW methods are available.  For information on how they work, see the module documentation.

	* Cost matricies should be returned for use by the plotting functions

	'''

	# Check if a list has been passed or numpy object
	usingList = False
	if type(a) == list:
		usingList = True
		a = np.array(a)

	if type(b) == list:
		usingList = True
		b = np.array(b)

	# Create a warp object to return
	warpObj = {}

	# Clip any longer time series
	minLen = min(len(a),len(b))
	a = a[0:minLen]
	b = b[0:minLen]

	# Get distance matrix
	dist = L1distances(a,b)

	# Get the cost matrix
	if method == 'DTW':
		costMat = DTWwarp(dist,a,b,w=window)
	elif method == 'ERP':
		ERPg = 0
		if 'ERPg' in kwargs:
			ERPg = kwargs['ERPg']
		costMat = ERPwarp(dist,a,b,w=window,g=ERPg)
	else:
		print("timeWarp error - incorrect warp method specified:", method)
		return -1

	# Extract the cost
	cIndex = len(costMat[0]) - 1
	cost = costMat[cIndex,cIndex]

	# Backtrace the warp path
	path, backTraceCost, warpStats = backTrace(costMat,dist)

	# Return the results
	if retMat == True:
		if usingList:
			warpObj["costMat"] = costMat.tolist()
			warpObj["distMat"] = dist.tolist()
		else:
			warpObj["costMat"] = costMat
			warpObj["distMat"] = dist

	warpObj["cost"] = cost
	warpObj["backTraceCost"] = backTraceCost
	warpObj["warpStats"] = warpStats

	if usingList:
		warpObj["backTracePath"] = path.tolist()
	else:
		warpObj["backTracePath"] = path

	if window == 0:
		warpObj["warpWindow"] = len(a)
	else:
		warpObj["warpWindow"] = window

	return warpObj

@jit
def L1distances(a,b):
	'''Calcluates the L1 distance matrix between two time series.

	Parameters
	----------
		a : list
			First time series, which will be compared against time series b
		b : list
			Second time series (reference)

	Returns
	-------
		distance : list
			A matrix (list of lists) describing the L1-distance matrix between the two
			time series.  For a series of length n, this matrix will be of size n x n.
	'''
	n = len(a)
	m = len(b)

	distance = np.zeros((n,m))

	for i in range(n):
		for j in range(m):
			distance[i,j] = abs(a[i] - b[j])

	return distance

@jit
def ERPwarp(dist,x,y,w=0,g=0):
	'''Calcluates the ERP cost matrix between two time series.

	Parameters
	----------
		dist : list
			A matrix (list of lists) describing the L1-distance matrix between two
			time series.  For a time series of length n, this matrix must be of size n x n.
		x : list
			First time series, which will be compared against time series y
		y : list
			Second time series (reference)
		w : int
			Time warping window constraint (default = 0)
		g :	int
			ERP g-value (deafult = 0)

	Returns
	-------
		costMat : list
			A matrix (list of lists) describing the ERP cost matrix between the two time
			series.  For a series of length n, this matrix will be of size n x n.
	'''
	n = len(x)
	m = len(y)

	costMat = np.zeros((n,m))

	costMat[0,0] = dist[0,0]

	# Fill the edges
	for i in range(1, n):
		costMat[0,i] =  costMat[0,i-1] + abs(dist[0,i] - g)

	for i in range(1, n):
		costMat[i,0] = costMat[i-1,0] + abs(dist[i,0] - g)

	# Fill the rest of the matrix
	for i in range(1, n):
		for j in range(1, n):
			OpMatch = costMat[i-1,j-1] + dist[i,j]
			OpIns = costMat[i-1,j] + abs(x[i] - g)
			OpDel = costMat[i,j-1] + abs(y[i] - g)

			costMat[i,j] = min(OpMatch,OpDel,OpIns)

	# Apply warp window
	if w != 0:
		for i in range(0, n):
			for j in range(0, n):
				if abs(i-j) >= w:
					costMat[i,j] = np.inf

	return costMat

@jit
def DTWwarp(dist,x,y,w=0):
	'''Calcluates the ERP cost matrix between two time series.

	Parameters
	----------
		dist : list
			A matrix (list of lists) describing the L1-distance matrix between two
			time series.  For a time series of length n, this matrix must be of size n x n.
		x : list
			First time series, which will be compared against time series y
		y : list
			Second time series (reference)
		w : int
			Time warping window constraint (default = 0)

	Returns
	-------
		costMat : list
			A matrix (list of lists) describing the DTW cost matrix between the two time
			series.  For a series of length n, this matrix will be of size n x n.
	'''
	n = len(x)
	m = len(y)

	costMat = np.zeros((n,m))

	costMat[0,0] = dist[0,0]

	# Fill the edges
	for i in range(1, n):
		costMat[0,i] = dist[0,i] + costMat[0,i-1]

	for i in range(1, n):
		costMat[i,0] = dist[i,0] + costMat[i-1,0]

	# Fill the rest of the matrix
	for i in range(1, n):
		for j in range(1, n):
			minMove = min(costMat[i-1,j-1], costMat[i-1,j], costMat[i,j-1])
			costMat[i,j] = minMove + dist[i,j]

	# Apply warp window
	if w != 0:
		for i in range(0, n):
			for j in range(0, n):
				if abs(i-j) >= w:
					costMat[i,j] = np.inf

	return costMat

def backTrace(costMat,dist):
	'''Finds the optimal warping path by backtracking through the cost matrix.

	Parameters
	----------
		dist : list
			A matrix (list of lists) describing the L1-distance matrix between two
			time series.  For a time series of length n, this matrix must be of size n x n.
		costMat : list
			A matrix (list of lists) describing the time-warped cost matrix between two
			time series.  For a time series of length n, this matrix must be of size n x n.

	Returns
	-------
		path : list
			List of pairs of coordinates in time-space describing the backtrace through
			the cost matrix
		backTraceCost : float
			The sum cost of following the backtrace through the cost matrix
		warpStats : dict
			Warp statistics object, containing:
		warpStats.timeAhead : int
			The number of periods that time series a was in sync with time series b.
		warpStats.timeAhead : int
			The number of periods that time series a was ahead of time series b.
		warpStats.timeBehind : int
			The number of periods that time series a was behind of time series b.
		warpStats.amountAhead : int
			The total sum of the number of periods that time series a was leading
			time series b by.
		warpStats.amountBehind : int
			The total sum of the number of periods that time series a was lagging
			time series b by.
		warpStats.avgAhead : int
			Average amount of periods that a was ahead of a by, i.e.
			amountAhead divided by timeAhead
		warpStats.avgAhead : int
			Average amount of periods that a was behind b by, i.e.
			amountBehind divided by timeBehind
		warpStats.avgWarp : int
			Average amount of periods that a ahead or behind b by, i.e.
			``(amountAhead - amountBehind) / (timeAhead + timeBehind + timeSync)``
			This will give positive values if a is on average ahead of b and negative
			values is a is on average behind b.
	'''

	timeAhead = 0
	timeBehind = 0
	timeSync = 0

	amountAhead = 0
	amountBehind = 0

	i = len(costMat) - 1
	j = len(costMat[0]) - 1
	path = np.array([i,j])

	backTraceCost = dist[i,j]

	while i>0 or j>0:
		if i==0:
			# Edge condition (only one direction)
			j = j - 1
		elif j==0:
			# Edge condition (only one direction)
			i = i - 1
		else:
			minMove = min(costMat[i-1,j-1], costMat[i-1,j], costMat[i,j-1])
			if costMat[i-1,j] == minMove:
				i = i - 1
			elif costMat[i,j-1] == minMove:
				j = j - 1
			else:
				i = i - 1
				j = j - 1

		backTraceCost += dist[i,j]
		path = np.vstack([path,[i,j]])

		if j > i:
			timeAhead += 1
			amountAhead += j - i
		elif i > j:
			timeBehind += 1
			amountBehind += i - j
		else:
			timeSync +=1

	warpStats = {}
	warpStats["timeAhead"] = timeAhead
	warpStats["timeBehind"] = timeBehind
	warpStats["timeSync"] = timeSync
	warpStats["amountAhead"] = amountAhead
	warpStats["amountBehind"] = amountBehind
	warpStats["avgAhead"] = 0
	warpStats["avgBehind"] = 0

	if timeAhead > 0:
		warpStats["avgAhead"] = amountAhead / timeAhead

	if timeBehind > 0:
		warpStats["avgBehind"] = amountBehind / timeBehind

	warpStats["avgWarp"] = (amountBehind - amountAhead) / (timeAhead + timeBehind + timeSync)

	return path, backTraceCost, warpStats


"""Script to get the name of the movie and the link to the pdf of the script from the 'Script PDFs' endpoint
and write it to a file"""
import requests
from bs4 import BeautifulSoup
import re
from .movie import Movie
from .helper_functions import switch_article, get_file_type, get_name_to_compare

def get_movies_script_pdf(URL: str) -> list[Movie]:
    """Function to get the name of the movie and the link to the pdf of the script from the 'Script PDFs' endpoint

    Args:
        URL (str): URL of the 'Script PDFs' endpoint
    """
    movies = []
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
    re_year = re.compile(r"\(\d{4}\)")

    try:
        home_page_html = requests.get(URL, headers=headers)
        home_page_data = BeautifulSoup(home_page_html.text, "html.parser")
    except:
        with open("error_log.txt", "a", encoding="utf-8") as outfile:
            outfile.write("The URL did not work for 'Script PDFs'\n")
        return

    sections = home_page_data.find("div", class_="entry-content").find_all("ul")
    del sections[-1]

    for section in sections:
        li_tags = section.find_all("li")
        for li_tag in li_tags:
            movie_title = li_tag.find("a").text
            script_url = li_tag.find("a").get("href")

            try:
                movie_year = re.findall(re_year, movie_title)[0][1:-1]
                movie_title = re.sub(re_year, "", movie_title).strip()
            except IndexError:
                movie_year = None

            if (
                movie_title.endswith(", The")
                or movie_title.endswith(", A")
                or movie_title.endswith(", An")
            ):
                movie_title = switch_article(movie_title.split(" ")[-1], movie_title)

            filetype = get_file_type(script_url)
            name_to_compare = get_name_to_compare(movie_title)

            movies.append(
                Movie(
                    title=movie_title,
                    script_url=script_url,
                    movie_year=movie_year,
                    file_type=filetype,
                    name_to_compare=name_to_compare,
                )
            )

    print(f"Script PDFs: {len(movies)} movies found")

    return movies


import sqlalchemy
import sqlalchemy.orm
import pandas as pd
from sqlalchemy.ext.declarative import declarative_base
import datetime

Base = declarative_base()

class Mysqlprocess():
    def __init__(self):
        self.engine = self.createDB()
        self.DB_Session = self.createSession(engine = self.engine)

    def packageData(self, Dates, Open, High, Low, Close, Object):
        item = {'Dates': Dates, 'Open': Open, 'High': High, 'Low': Low, 'Close': Close}
        if Object == 'ESA_index':
            u = ESA_index(Dates = item['Dates'], Data_Open = item['Open'], Data_Close = item['Close'], Data_High =
            item['High'], Data_Low = item['Low'])
        elif Object == 'AUDUSD_Curncy':
            u = AUDUSD_Curncy(Dates = item['Dates'], Data_Open = item['Open'], Data_Close = item['Close'], Data_High =
            item['High'], Data_Low = item['Low'])
        return u

    def addData(self, u):
        with self.DB_Session() as session:
            session.add(u)
            session.commit()

    def createDB(self):
        DB_CONNECT_STRING = 'mysql+pymysql://allanchan339:33715882aAB@localhost/data'
        engine = sqlalchemy.create_engine(DB_CONNECT_STRING, echo = False)
        return engine

    def createSession(self, engine):
        DB_Session = sqlalchemy.orm.sessionmaker(bind = engine)
        Base.metadata.create_all(engine)
        return DB_Session

    def insertData(self, items, tablename):
        with self.DB_Session() as session:
            for item in items:
                session.execute(f"""
                INSERT INTO {tablename} value (%s,%s,%s,%s,%s)""",
                                (
                                        item['Dates'],
                                        item['Open'],
                                        item['High'],
                                        item['Low'],
                                        item['Close']
                                        ))

class ESA_index(Base):
    __tablename__ = 'ESA_index'
    # id = sqlalchemy.Column('Id', sqlalchemy.Integer, primary_key = True, autoincrement = True)
    Dates = sqlalchemy.Column(sqlalchemy.DateTime(timezone = True), primary_key = True)
    Data_Open = sqlalchemy.Column('Data_Open', sqlalchemy.Float)
    Data_Close = sqlalchemy.Column('Data_Close', sqlalchemy.Float)
    Data_High = sqlalchemy.Column('Data_High', sqlalchemy.Float)
    Data_Low = sqlalchemy.Column('Data_Low', sqlalchemy.Float)

class AUDUSD_Curncy(Base):
    __tablename__ = 'AUDUSD_Curncy'
    # id = sqlalchemy.Column('Id', sqlalchemy.Integer, primary_key = True, autoincrement = True)
    Dates = sqlalchemy.Column(sqlalchemy.DateTime(timezone = True), primary_key = True)
    Data_Open = sqlalchemy.Column('Data_Open', sqlalchemy.FLOAT)
    Data_Close = sqlalchemy.Column('Data_Close', sqlalchemy.FLOAT)
    Data_High = sqlalchemy.Column('Data_High', sqlalchemy.FLOAT)
    Data_Low = sqlalchemy.Column('Data_Low', sqlalchemy.FLOAT)

class Excelprocess():
    def __init__(self):
        pass

    def readfile(self, filename):
        self.df = pd.read_excel(filename, skiprows = 3, sheet_name = None)
        self.xlsx = pd.ExcelFile(filename)
        return self.df, self.xlsx
    def readNews(self, filename):
        self.df = pd.read_excel(filename, sheet_name = None)
        self.xlsx = pd.ExcelFile(filename)
        return self.df, self.xlsx

def main():
    dataframe, xlsx = Excelprocess().readfile('Data.xlsx')
    print(xlsx.sheet_names)
    dataframe_sh1 = dataframe.get('Sheet1')
    dataframe_sh2 = dataframe.get('Sheet2')
    print(dataframe_sh1)
    print(dataframe_sh2)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from keras.models import load_model
import numpy as np
from DatasetManager import DatasetManager
from jungle import Jungle
from train_lstm import CharacterTable

jungle = Jungle()

model = load_model('jungle_lstm.h5')

word = "jetaimedilu"
encrypted_word = jungle.encode(word)

dm = DatasetManager(max_len_word = 10)

expected, questions = dm.readDataset("datasets/dataset.csv")

x_train = questions
y_train = expected

MAXLEN = dm.getMaxLen(questions)
print("MAXLEN = "+str(MAXLEN))
word = word + " "*(MAXLEN-len(word))

# All the numbers, plus sign and space for padding.
chars = dm.getDic(x_train)
chars = chars + [c for c in dm.getDic(y_train) if c not in chars]
#print(chars)
ctable = CharacterTable(chars)
#print(ctable.encode("hello", MAXLEN))

x_test = ctable.encode(encrypted_word, MAXLEN)
y_test = ctable.encode(word, MAXLEN)

#print("Input word : "+encrypted_word)
#print("Output word : "+word)

#print("Input vec : " + str(x_test))
#print("Expected output vec : "+str(y_test))

preds = model.predict_classes(np.array([x_test]), verbose=0)
q = ctable.decode(x_test)
correct = ctable.decode(y_test)
guess = ctable.decode(preds[0], calc_argmax=False)
print(preds[0])
print("encrypted_word : "+encrypted_word)
print("word : "+word)
print("AI RESULT : "+guess)


#!/usr/bin/env python
# An IRC tweet -> Slack bot in python
#
# Grant Hernandez <grant.h.hernandez@gmail.com>
# Based off of IRC example by
#   Joel Rosdahl <joel@rosdahl.net>

import irc.bot
import irc.strings
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr

from server import SlackServer, SlackPost

import re
import json
import datetime
from ttp import ttp  # twitter text parsing

# From http://tools.medialab.sciences-po.fr/iwanthue/index.php
# Sorted by their color difference
COLORS = ["#6a0032", "#01cf49", "#604bf7", "#74c200", "#8900b2",
          "#b3dc3d", "#00179a", "#e2cf4a", "#ff53f4", "#008c43",
          "#e6008a", "#5d8200", "#4b7cff", "#936d00", "#0264ce",
          "#ac1c00", "#0192f7", "#ff5259", "#00aeb1", "#c30038",
          "#019abe", "#940034", "#94d7f4", "#7f3400", "#ed97ff",
          "#232e00", "#c1b9ff", "#00664b", "#ff7d8e", "#002172",
          "#c1d693", "#5a005b", "#bdd2cc", "#2a1632", "#fcbfb8",
          "#005053", "#ff99bf", "#00556d"]

class TbSlack(irc.bot.SingleServerIRCBot):

    def __init__(
            self,
            channel,
            nickname,
            server,
            port,
            slackServers,
            accepted_nick,
            testing=False):
        recon = irc.bot.ExponentialBackoff(min_interval=0.01)
        irc.bot.SingleServerIRCBot.__init__(
            self, [(server, port)], nickname, nickname, recon=recon)
        self.channel = channel
        self.colormap = {}
        self.colormapIter = 0
        self.testing = testing
        self.accepted_nick = accepted_nick

        self.slack = slackServers
        self.ttp = ttp.Parser(include_spans=True)

        print(
            "TbSlack connecting to {}:{} as {}".format(
                server, port, nickname))
        print("Listening to IRC messages from {}".format(self.accepted_nick))

        if self.testing:
            print("** TESTING MODE ACTIVE")

        for i in slackServers:
            print("- Broadcasting to {}".format(i))

    def on_nicknameinuse(self, c, e):
        print("WARNING: nickname in use...")
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        print("Now joining {}".format(self.channel))
        c.join(self.channel)

    def on_disconnect(self, c, e):
        print("WARNING: disconnected from server...")

    def on_join(self, c, e):
        print("Joined {}".format(self.channel))

    # strips IRC colors as per the spec. Probably doesnt work for strange cases
    def strip_colors(self, msg):
        return re.sub("\x03([0-9]{1,2})?(,[0-9]{1,2})?", "", msg)

    def on_pubmsg(self, c, e):
        src = e.source.nick
        msg = e.arguments[0]

        # strip color control characters
        msg = self.strip_colors(msg)

        if src == self.accepted_nick:
            self.process_tb(e, msg)
        else:
            print("PUB_MSG: <{}> {}".format(src, msg.encode("utf-8")))

    def on_privmsg(self, c, e):
        src = e.source.nick
        msg = e.arguments[0]

        # strip color control characters
        msg = self.strip_colors(msg)

        print("PRIVMSG: <{}> {}".format(src, msg.encode("utf-8")))

        if self.testing:
            self.process_tb(e, msg)

    def process_tb(self, e, tweet):
        print("[{}] Tweet: {}".format(
            str(datetime.datetime.today()), tweet.encode("utf-8")))

        tokens = tweet.split(" ")

        if len(tokens) < 1:
            print("Malformed tweet (no tokens)")
            return

        tweeter = tokens[0]
        tokens = tokens[1:]
        final_msg = ""
        header = ""

        if re.match("^<.+>$", tweeter) is None:
            print("Malformed tweet (invalid tweeter)")
            return

        tweeter = re.findall("^<(.+)>$", tweeter)[0]

        if len(tokens) < 1:
            print("Malformed tweet (blank tweet)")
            return

        is_rt = tokens[0] == "RT"

        def mklink(target, text=""):
            if text == "":
                return u"<{}>".format(target)
            else:
                return u"<{}|{}>".format(target, text)

        def mkat(t):
            return mklink(u"https://twitter.com/{}".format(t),
                          u"@{}".format(t))

        def mkhash(t):
            return mklink(u"https://twitter.com/hashtag/{}".format(t),
                          u"#{}".format(t))

        if is_rt:
            target = tokens[1]
            tokens = tokens[2:]

            if re.match("^@.+:$", target) is None:
                print("Malformed retweet (bad target)")
                return

            target = re.findall("^@(.+):$", target)[0]

            header = "{} :repeat: {}".format(mkat(tweeter), mkat(target))
        else:
            header = "{} tweeted".format(mkat(tweeter))

        if len(tokens) < 1:
            print("Malformed tweet (missing body after header)")
            return

        # we are limited to one color in Slack. Base it off of the tweeter
        color = ""

        if tweeter in self.colormap:
            color = self.colormap[tweeter]
        else:
            c = COLORS[self.colormapIter]
            self.colormapIter = (self.colormapIter + 1) % len(COLORS)

            self.colormap[tweeter] = c
            color = c

        body = " ".join(tokens)
        res = self.ttp.parse(body)
        users = set([r[0] for r in res.users])
        tags = set([r[0] for r in res.tags])

        for i in users:
            body = body.replace(u"@" + i, mkat(i))

        for i in tags:
            body = body.replace(u"#" + i, mkhash(i))

        final_msg += header + ": " + body

        # print final_msg

        if len(self.slack):
            for i in self.slack:
                i.postRich(header, body, color, tweet)
        else:
            if self.testing:
                post = SlackPost()
                post.addAttachment(header, body, color, tweet)

                print("Test send: " + str(post))

def banner():
    print("TbSlack by Grant")
    print("")

def usage():
    import sys
    global EXENAME

    print("usage: " + EXENAME + " config.json")
    sys.exit(1)

def main(args):
    banner()

    slackServers = []
    configFp = None

    try:
        configName = args[0] if len(args) else "config.json"
        configFp = open(configName, "r")
    except IOError:
        usage()

    config = json.load(configFp)
    configFp.close()

    # load slack servers
    for i in config["servers"]:
        slackServers.append(
            SlackServer(
                i["url"],
                i["name"],
                i["username"],
                i["channel"],
                (i["batch_time"],
                 i["batch_amount"])))

    # load irc info
    server = config["irc_server"]
    port = config["irc_port"]
    channel = config["irc_channel"]
    nickname = config["irc_nick"]
    accepted_nick = config["accepted_nick"]
    testing = config["testing"]

    bot = TbSlack(channel, nickname, server,
                  port, slackServers, accepted_nick, testing)

    try:
        bot.start()
    except KeyboardInterrupt:
        print("Disconnecting on user Ctrl-C")
        bot.disconnect()

if __name__ == "__main__":
    import sys

    global EXENAME
    EXENAME = sys.argv[0]

    main(sys.argv[1:])


#%%
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread('baboon.jpg')
# plt.imshow(img)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
plt.hist(gray.ravel(), 256, [0,256])
plt.show()

#%% Histogram equalization is the mapping of one distribution to another distribution.
cv.imshow('Gray',gray)
img_histogram = cv.equalizeHist(gray)
cv.imshow('Histogram',img_histogram)
cv.waitKey()
# How you re-map the distribution for the image

# %%
cv.destroyAllWindows()


"""weight_initialization.py
---------------------------
This program shows how weight_initialization affects training.
"""
import json
import random
import sys

import matplotlib
# matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

import mnist_loader
import network2

def main(filename, n, eta):
    run_network(filename, n, eta)
    make_plots(filename)

def run_network(filename, n, eta):
    """
    Train the network using both the default and the large starting weights.
    Store the results in the file with name 'filename', where they can later be used by 'make_plots'.
    'n' is the neuron number of the hidden layer.
    'eta' is learning rate.
    """
    # Make results more easily reproducible
    random.seed(12345678)
    np.random.seed(12345678)
    training_data, validation_data, test_data = mnist_loader.load_data_wrapper()
    net = network2.Network([784, 100, 10], cost=network2.CrossEntropyCost())
    print("Train the network with the default starting weights.")
    default_vc, default_va, default_tc, default_ta = net.SGD(training_data,
            30, 10, eta, evaluation_data=validation_data, lmbda=5.0,
            monitor_evaluation_accuracy=True)
    print("Train the network with the large starting weights.")
    net.large_weight_initializer()
    large_vc, large_va, large_tc, large_ta = net.SGD(training_data,
            30, 10, eta, evaluation_data=validation_data, lmbda=5.0,
            monitor_evaluation_accuracy=True)
    with open(filename, "w") as f:
        json.dump({"default_weight_initialization":
                   [default_vc, default_va, default_tc, default_ta],
                   "large_weight_initialization":
                   [large_vc, large_va, large_tc, large_ta]}, f)

def make_plots(filename):
    """
    Load the results from 'filename', and generate the corresponding plots.
    """
    with open(filename, "r") as f:
        results = json.load(f)
    default_vc, default_va, default_tc, default_ta = results["default_weight_initialization"]
    large_vc, large_va, large_tc, large_ta = results["large_weight_initialization"]
    #  Convert raw classification numbers to percentages, for ploting
    default_va = [x / 100.0 for x in default_va]
    large_va = [x / 100.0 for x in large_va]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(np.arange(0, 30, 1), large_va, color='r', label='large weight initialization')
    ax.plot(np.arange(0, 30, 1), default_va, color='b', label='default weight initialization')
    ax.grid(True)
    ax.set_xlim([0, 30])
    ax.set_xlabel('Epoch')
    ax.set_ylim([85, 100])
    ax.set_title("Classification accuracy")
    plt.legend(loc='lower right')
    plt.savefig('./figs/weight_init.png')
    plt.show()

if __name__ == '__main__':
    main("monitor_weights.json", 100, 0.1)


from scipy.interpolate import CubicSpline
import numpy as np
import matplotlib.pyplot as plt
import PySimpleGUI as sg

#initial values y
y01 = 50
y02 = 100
y03 = -50

#3 points
x = [-1, 1, 3]
y = (y01, y02, y03)

#cubic spline
f = CubicSpline(x, y, bc_type='natural')
x_new = np.linspace(x[0], x[2], 100)
y_new = f(x_new)

x_val_01 = x[0]
x_val_02 = x[2]

#creating tangent at edge points
def create_line(x_val_num, f):
    x_new_num = np.linspace(x_val_num-0.5, x_val_num+0.5, 20)
    y_new_num = f(x_new_num)

    slope = np.gradient(y_new_num, x_new_num)

    ind_min = (np.abs(x_new_num - x_val_num)).argmin()

    if x_val_num == x_new_num[ind_min]:
        y_val_01, slope_Val = y_new_num[ind_min], slope[ind_min]
    else:
        if x_val_num < x_new_num[ind_min]:
            ind_min, ind2 = ind_min-1, ind_min
        else:
            ind_min, ind2 = ind_min, ind_min+1
        y_val_01 = y_new_num[ind_min] + (y_new_num[ind2]-y_new_num[ind_min]) * (x_val_num-x_new_num[ind_min]) / (x_new_num[ind2]-x_new_num[ind_min])
        slope_Val = slope[ind_min] + (slope[ind2]-slope[ind_min]) * (x_val_num-x_new_num[ind_min]) / (x_new_num[ind2]-x_new_num[ind_min])
    intercVal = y_val_01 - slope_Val * x_val_num

    plt.plot([x_new_num.min(), x_new_num.max()], [slope_Val*x_new_num.min()+intercVal, slope_Val*x_new_num.max()+intercVal], linestyle = '-.', linewidth = 1, color = 'orange')

def draw():
    create_line(x_val_01, f)
    create_line(x_val_02, f)
    plt.plot(x_new, y_new, 'g')
    plt.plot(x, y, '-o', color='red', linewidth = 1)
    plt.title('_KG_LAB_07_')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

def rebuild(f):
    f = CubicSpline(x, y, bc_type='natural')
    x_new = np.linspace(x[0], x[2], 100)
    y_new = f(x_new)
    create_line(x_val_01, f)
    create_line(x_val_02, f)
    plt.plot(x_new, y_new, 'g')
    plt.plot(x, y, '-o', color='red')
    plt.title('_KG_LAB_07_')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

layout = [
    [sg.Text('Y1 = '), sg.Slider(orientation ='horizontal', key='slider1', range=(-100,100))],
    [sg.Text('Y2 = '), sg.Slider(orientation ='horizontal', key='slider2', range=(-100,100))],
    [sg.Text('Y3 = '), sg.Slider(orientation ='horizontal', key='slider3', range=(-100,100))],
    [sg.Button('Plot'), sg.Button('Exit'), sg.Button('Enter')]]

window = sg.Window('___Setting window___', layout)

while True:
    event, values = window.read()
    if event in (sg.WIN_CLOSED, 'Exit'):
        break
    elif event == 'Plot':
        draw()
    elif event == 'Enter':
        y1 = int(values['slider1'])
        y2 = int(values['slider2'])
        y3 = int(values['slider3'])
        y = (y1, y2, y3)
        rebuild(f)
        y = (y01, y02, y03)

window.close()


import random
import sqlite3
import cv2
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader, IterableDataset
from functools import partial
import torchvision
from typing import Iterator
import numpy as np
import torch.nn.functional as F
import sys

DEVICE=torch.device('cuda')
CPU_DEVICE = torch.device('cpu')

BATCH_SIZE=64

BatchNorm2d = partial(nn.BatchNorm2d, eps=0.001, momentum=0.01)

class SqueezeExcite(nn.Module):
    def __init__(
        self,
        channels,
        channelsize
    ):
        super(SqueezeExcite, self).__init__()
        self.block = nn.Sequential(
            nn.AvgPool2d(channelsize),
            nn.Flatten(),
            nn.Linear(channels, channels//4),
            nn.LeakyReLU(0.3, True),
            nn.Linear(channels//4, channels),
            nn.Sigmoid(),
            nn.Unflatten(1, (channels, 1, 1))
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return x * self.block(x)

class Block(nn.Module):
    def __init__(
        self,
        input_channels: int,
        expanded_channels: int,
        channel_size,
        output_channels: int,
        kernel_size: int = 3,
        padding: int = 1
    ):
        super(Block, self).__init__()
        expander = nn.Conv2d(in_channels=input_channels, out_channels=expanded_channels, kernel_size=1)
        depthwise = nn.Conv2d(in_channels=expanded_channels, out_channels=expanded_channels, kernel_size=kernel_size, stride=2, padding=padding, groups=expanded_channels)
        unexpander = nn.Conv2d(in_channels=expanded_channels, out_channels=output_channels, kernel_size=1)

        self.block = nn.Sequential(
            expander,
            BatchNorm2d(num_features=expanded_channels),
            nn.LeakyReLU(0.3, True),
            depthwise,
            BatchNorm2d(num_features=expanded_channels),
            nn.LeakyReLU(0.3, True),
            SqueezeExcite(expanded_channels, channel_size//2),
            unexpander,
            BatchNorm2d(num_features=output_channels),
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.block(x)

class CourseProgressClassifier(nn.Module):
    def __init__(self):
        super(CourseProgressClassifier, self).__init__()
        C = 64

        self.layer_1 = Block(3, 3*C, 16, C-1, 3, 1)

        self.block = nn.Sequential(
            Block(C, 3*C, 8, C, 3, 1),
            Block(C, 6*C, 4, 2*C, 3, 1),
            nn.Conv2d(2*C, 4*C, 2),
            nn.Flatten(),
            nn.LeakyReLU(0.3, True),
            nn.Dropout(0.25, True),
            nn.Linear(4*C, 4*C),
            nn.LeakyReLU(0.3, True),
            nn.Linear(4*C, 11),
            nn.LogSoftmax(dim=1)
        )

    def forward(self, x: torch.Tensor, side: torch.Tensor) -> torch.Tensor:
        return self.block(
            torch.cat(
                (
                    self.layer_1(x),
                    side,
                ),
                dim=1
            )
        )

print("selected camera:", sys.argv[1])

cap = cv2.VideoCapture(int(sys.argv[1]))

classifier = CourseProgressClassifier().to(device=DEVICE)
classifier.load_state_dict(
    torch.load('2.pytorch')['model']
)
classifier = classifier.train(False)

side_r = torch.tensor([1], dtype=torch.float, device=DEVICE).expand((1, 1, 8, 8))
side_l = torch.tensor([-1], dtype=torch.float, device=DEVICE).expand((1, 1, 8, 8))
sides = torch.cat((side_l, side_r))

classifier = torch.jit.script(
    classifier,
    example_inputs=[(torch.ones((2, 3, 16, 16), device=DEVICE, dtype=torch.float), sides)]
)

normalize = torchvision.transforms.Normalize(
    (0.5, 0.5, 0.5), (0.5, 0.5, 0.5)
)

TABLE_NAME = 'auto_labeled14'

# with sqlite3.connect('frames.sqlite3') as db:
#     db.execute(f'CREATE TABLE IF NOT EXISTS {TABLE_NAME} (label INT, image BLOB NOT NULL);')
if True:
    # loop over
    while True:
        # read frames from stream
        #frame = stream.read()
        ret, vidframe = cap.read()
        if not ret:
            break

        # check for frame if Nonetype
        # if frame is None:
        #     break

        # {do something with the frame here}
        frame = vidframe[80:96, 580:596]

        img = normalize(
            torch.from_numpy(
                np.transpose(
                    frame[:, :, ::-1],
                    (2, 0, 1)
                ).copy()
            ).float().__div__(255.0)
        )[None,...]

        cv2.imshow('Frame', frame)
        output = classifier(torch.cat((img, img)).to(device=DEVICE), sides)
        [_, values] = torch.max(output, dim=1)#.to(device=CPU_DEVICE)
        values = values.to(device=CPU_DEVICE)
        [l, r] = values
        l, r = l.item(), r.item()
        print('_' if l == 10 else l, '_' if r == 10 else r, sep='')

        label = -1 if r == 10 else ((0 if l == 10 else l)*10 + r)

        # db.execute(
        #     f'INSERT INTO {TABLE_NAME} (image, label) VALUES(?, ?)',
        #     (
        #         bytes(cv2.imencode('.png', frame, [cv2.IMWRITE_PNG_COMPRESSION, 0])[1]),
        #         label
        #     )
        # )

        # check for 'q' key if pressed
        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break


from numpy import exp, array, zeros, ones, dot, set_printoptions, log10, argmax, clip, sqrt
from collections import Counter
from scipy.sparse import load_npz, lil_matrix, csr_matrix, csc_matrix
import shelve
from numpy.random import choice
set_printoptions(precision=2, edgeitems = 10, linewidth=200)
import warnings
from bytepair import bpstr
warnings.filterwarnings("ignore", message="Changing the sparsity structure of a csr_matrix is expensive.")

def sigmoid(v):
    try:
        return 1./(1.+exp(-v))
    except:
        print(v)

def softmax(v):
    if type(v) is lil_matrix:
        v = v.toarray()
    v = v-v.mean() # to avoid overflow errors
    es = exp(v)
    output = es/(es.sum()+0.00000001)
    return output

def sparsemax(v):
    if type(v) is lil_matrix:
        v = v.toarray()
    z = v.copy()
    z.sort()
    K = z.shape[1]
    z = z[0,::-1]
    k = 1
    total = z[0, 0]
    try:
        while k < z.shape[1] and 1 + k * z[0, k] > total:
            total += z[0, k]
            k += 1
    except Exception as e:
        print(z.shape, total.shape)
        print (e)
        exit()
    tau = (total-1)/k
    p = v-tau
    p[p<0] = 0.0
    return p

class SP():

    CowanBufferLength = 4
    MillerBufferLength = 7
    HoneyHassonBufferLength = 20
    KintschBufferLength = 150
    epsilon = 0.00000000001
    lidstone = 0.000001

    def __init__(self, corpus, constraints="X BX AX XB XA ABX XBA CX MX HX KX CI MI HI KI"):
        self.corpus = corpus
        self.constraints = set(constraints.split())  # which parameters to change when learning
        self.lam = 0.0001
        self.vocab = [w.strip() for w in open(corpus+"/vocab", encoding='utf-8').readlines()]
        self.V = len(self.vocab)
        self.I = dict([(w.strip(), i) for i, w in enumerate(self.vocab)])
        self.bigramvocab = [w.strip() for w in open(self.corpus+"/bigramvocab", encoding='utf-8').readlines()]
        self.bigramV = len(self.bigramvocab)
        self.bigramI = dict([(w.strip(), i) for i, w in enumerate(self.bigramvocab)])
        self.CountsLoaded = False
        self.initParams()
        self.loadParams()

        # init net input variables

        self.netBX = None
        self.netAX = None
        self.netXA = None
        self.netXB = None
        self.netABX = None
        self.netXBA = None
        self.netX = None
        self.netCX = None
        self.netMX = None
        self.netHX = None
        self.netKX = None
        self.netCI = None
        self.netMI = None
        self.netHI = None
        self.netKI = None

    def loadCounts(self):
        self.BX = load_npz(self.corpus+f"/BX.npz") * 1000000000
        self.X = self.BX.sum(axis=0)
        self.AX = load_npz(self.corpus+f"/AX.npz") * 1000000000
        self.ABX = load_npz(self.corpus+f"/ABX.npz") * 1000000000
        self.XBA = load_npz(self.corpus+f"/XBA.npz") * 1000000000
        self.CX = load_npz(self.corpus+f"/CX.npz") * 1000000000
        self.MX = load_npz(self.corpus+f"/MX.npz") * 1000000000
        self.HX = load_npz(self.corpus+f"/HX.npz") * 1000000000
        self.KX = load_npz(self.corpus+f"/KX.npz") * 1000000000

        self.BX.data = log10(self.BX.data+1.0)
        self.X = log10(self.X+1.0)
        self.AX.data = log10(self.AX.data+1.0)
        self.ABX.data = log10(self.ABX.data+1.0)
        self.XBA.data = log10(self.XBA.data+1.0)
        self.CX.data = log10(self.CX.data+1.0)
        self.MX.data = log10(self.MX.data+1.0)
        self.HX.data = log10(self.HX.data+1.0)
        self.KX.data = log10(self.KX.data+1.0)

        #self.BX = log10(self.BX.todense()+SP.lidstone)
        #self.X = log10(self.X+SP.lidstone)
        #self.AX = log10(self.AX.todense()+SP.lidstone)
        #self.ABX = log10(self.ABX.todense()+SP.lidstone)
        #self.XBA = log10(self.XBA.todense()+SP.lidstone)
        #self.CX = log10(self.CX.todense()+SP.lidstone)
        #self.MX = log10(self.MX.todense()+SP.lidstone)
        #self.HX = log10(self.HX.todense()+SP.lidstone)
        #self.KX = log10(self.KX.todense()+SP.lidstone)
        self.CountsLoaded = True

    def initParams(self):
        self.Gax = 1.0
        self.Gbx = 1.0
        self.Gxa = 1.0
        self.Gxb = 1.0
        self.Gci = -1.0 # Cowan scale inhibition
        self.Gmi = -1.0 # Miller scale inhibition
        self.Ghi = -1.0 # Honey Hasson scale inhibition
        self.Gki = -1.0 # Kintsch scale inhibition
        self.Gx = -1.0
        self.Gabx = 1.0
        self.Gxba = 1.0
        #self.Gcx = ones((self.V, 1)) / self.CowanBufferLength
        #self.Gmx = ones((self.V, 1)) / self.MillerBufferLength
        #self.Ghx = ones((self.V, 1)) / self.HoneyHassonBufferLength
        #self.Gkx = ones((self.V, 1)) / self.KintschBufferLength
        self.Gcx = 1.0
        self.Gmx = 1.0
        self.Ghx = 1.0
        self.Gkx = 1.0

    def strVec(self, v, NumToReport=14, NoZeros = False):

      if type(v) is lil_matrix or type(v) is csr_matrix or type(v) is csc_matrix:
          v = v.toarray()
      v = array(v)
      v2 = v.flatten()
      c = Counter(dict(enumerate(v2[0:len(self.vocab)])))
      res = ""
      for i,n in c.most_common(int(NumToReport/2)):
          if n != 0 or not NoZeros:
              res += "{0} {1:1.3f} ".format(self.vocab[i], n)
      res += " ... "
      for i,n in c.most_common()[:-int(NumToReport/2)-1:-1][::-1]:
          if n != 0 or not NoZeros:
              res += "{0} {1:1.3f} ".format(self.vocab[i], n)
      return res

    def saveParams(self):

        params = shelve.open(self.corpus+"/params")
        params["Gbx"] = self.Gbx
        params["Gax"] = self.Gax
        params["Gxb"] = self.Gxb
        params["Gxa"] = self.Gxa
        params["Gabx"] = self.Gabx
        params["Gxba"] = self.Gxba
        params["Gcx"] = self.Gcx
        params["Gmx"] = self.Gmx
        params["Ghx"] = self.Ghx
        params["Gkx"] = self.Gkx
        params["Gci"] = self.Gci
        params["Gmi"] = self.Gmi
        params["Ghi"] = self.Ghi
        params["Gki"] = self.Gki
        params["Gx"] = self.Gx
        params.close()

    def loadParams(self):

        params = shelve.open(self.corpus+"/params")
        if "Gax" in params.keys():
            self.Gax = params["Gax"]
        if "Gbx" in params.keys():
            self.Gbx = params["Gbx"]
        if "Gxa" in params.keys():
            self.Gxa = params["Gxa"]
        if "Gxb" in params.keys():
            self.Gxb = params["Gxb"]
        if "Gx" in params.keys():
            self.Gx = params["Gx"]
        if "Gabx" in params.keys():
            self.Gabx = params["Gabx"]
        if "Gxba" in params.keys():
            self.Gxba = params["Gxba"]
        if "Gcx" in params.keys():
            self.Gcx = params["Gcx"]
        if "Gmx" in params.keys():
            self.Gmx = params["Gmx"]
        if "Gci" in params.keys():
            self.Gci = params["Gci"]
        if "Gmi" in params.keys():
            self.Gmi = params["Gmi"]
        if "Ghi" in params.keys():
            self.Ghi = params["Ghi"]
        if "Gki" in params.keys():
            self.Gki = params["Gki"]
        if "Ghx" in params.keys():
            self.Ghx = params["Ghx"]
        if "Gkx" in params.keys():
            self.Gkx = params["Gkx"]
        params.close()
        if "X" not in self.constraints: self.Gx = 0.0
        if "BX" not in self.constraints: self.Gbx = 0.0
        if "AX" not in self.constraints: self.Gax = 0.0
        if "ABX" not in self.constraints: self.Gabx = 0.0
        if "XB" not in self.constraints: self.Gxb = 0.0
        if "XA" not in self.constraints: self.Gxa = 0.0
        if "XBA" not in self.constraints: self.Gxba = 0.0
        if "CX" not in self.constraints: self.Gcx = 0.0
        if "MX" not in self.constraints: self.Gmx = 0.0
        if "HX" not in self.constraints: self.Ghx = 0.0
        if "KX" not in self.constraints: self.Gkx = 0.0
        if "CI" not in self.constraints: self.Gci = 0.0
        if "MI" not in self.constraints: self.Gmi = 0.0
        if "HI" not in self.constraints: self.Ghi = 0.0
        if "KI" not in self.constraints: self.Gki = 0.0

    def strParams(self, NumToReport=15):
        result =  f"Gabx = {self.Gabx:1.3f} Gxba = {self.Gxba:1.3f} Gax = {self.Gax:1.3f} Gbx = {self.Gbx:1.3f} Gxa = {self.Gxa:1.3f} Gxb = {self.Gxb:1.3f} Gx = {self.Gx:1.3f}\n"
        result += f"Gci = {self.Gci:1.3f} Gmi = {self.Gmi:1.3f} Ghi = {self.Ghi:1.3f} Gki = {self.Gki:1.3f}\n"
        result +=  f"Gcx = {self.Gcx:1.3f} Gmx = {self.Gmx:1.3f} Ghx = {self.Ghx:1.3f} Gkx = {self.Gkx:1.3f}\n"
        return result

    def strNets(self, cowan, miller, honeyhasson, kintsch):
        t = zeros((1,self.V)) # temporary storage of attention weights
        result = "Weighted Nets:\n"
        result += f"all: {self.strVec(self.net)}\n\n"
        result += f"X({self.Gx:1.3f}): {self.strVec(self.Gx * self.netX, NoZeros = True)}\n"
        result += f"BX({self.Gbx:1.3f}): {self.strVec(self.Gbx * self.netBX)}\n"
        if self.netXB is not None:
            result += f"XB({self.Gxb:1.3f}): {self.strVec(self.Gxb * self.netXB)}\n"
        result += f"AX({self.Gax:1.3f}): {self.strVec(self.Gax * self.netAX)}\n"
        if self.netXA is not None:
            result += f"XA({self.Gxa:1.3f}): {self.strVec(self.Gxa * self.netXA)}\n"
        if self.netABX is not None:
            result += f"ABX({self.Gabx:1.3f}): {self.strVec(self.Gabx * self.netABX)}\n"
        if self.netXBA is not None:
            result += f"XBA({self.Gxba:1.3f}): {self.strVec(self.Gxba * self.netXBA)}\n"
        result += "\n"
        result += f"CX({self.Gcx:1.3f}): {self.strVec(self.Gcx * self.netCX)}\n"
        result += f"MX({self.Gmx:1.3f}): {self.strVec(self.Gmx * self.netMX)}\n"
        result += f"HX({self.Ghx:1.3f}): {self.strVec(self.Ghx * self.netHX)}\n"
        result += f"KX({self.Gkx:1.3f}): {self.strVec(self.Gkx * self.netKX)}\n"

        result += "\n"
        result += f"CI({self.Gci:1.3f}): {self.strVec(self.Gci * self.netCI, NoZeros = True)}\n"
        result += f"MI({self.Gmi:1.3f}): {self.strVec(self.Gmi * self.netMI, NoZeros = True)}\n"
        result += f"HI({self.Ghi:1.3f}): {self.strVec(self.Ghi * self.netHI, NoZeros = True)}\n"
        result += f"KI({self.Gki:1.3f}): {self.strVec(self.Gki * self.netKI, NoZeros = True)}\n"

        # attention weights
        result += "\n"
        result += "Attention Weights:\n"

        if len(cowan) > 0:
            attention = (sparsemax(-self.X[:, cowan]))
            t[:,:] = 0.0
            t[:, cowan] = attention
            result += "Cowan: " + self.strVec(t, NoZeros = True) + "\n"
        if len(miller) > 0:
            attention = (sparsemax(-self.X[:, miller]))
            t[:,:] = 0.0
            t[:, miller] = attention
            result += "Miller: " + self.strVec(t, NoZeros = True) + "\n"
        if len(honeyhasson) > 0:
            attention = (sparsemax(-self.X[:, honeyhasson]))
            t[:,:] = 0.0
            t[:, honeyhasson] = attention
            result += "HoneyHasson: " + self.strVec(t, NoZeros = True) + "\n"
        if len(kintsch) > 0:
            attention = (sparsemax(-self.X[:, kintsch]))
            t[:,:] = 0.0
            t[:, kintsch] = attention
            result += "Kintsch: " + self.strVec(t, NoZeros = True) + "\n"
        return result

    def select(self, words, vec):
        if type(vec) == csr_matrix:
            vec = vec.todense()
        wordvec = zeros((1,self.V))
        wordvec[0, words] = vec[0,words]
        return wordvec

    def trace(self, words, cowan, miller, honeyhasson, kintsch):
        result = "Weighted Nets:\n"
        result += f"all: {self.strVec(self.select(words, self.net), NoZeros=True)}\n\n"
        result += f"X({self.Gx:1.3f}): {self.strVec(self.select(words, self.Gx * self.netX), NoZeros = True)}\n"
        result += f"BX({self.Gbx:1.3f}): {self.strVec(self.select(words, self.Gbx * self.netBX), NoZeros=True)}\n"
        if self.netXB is not None:
            result += f"XB({self.Gxb:1.3f}): {self.strVec(self.select(words, self.Gxb * self.netXB), NoZeros=True)}\n"
        result += f"AX({self.Gax:1.3f}): {self.strVec(self.select(words, self.Gax * self.netAX), NoZeros=True)}\n"
        if self.netXA is not None:
            result += f"XA({self.Gxa:1.3f}): {self.strVec(self.select(words, self.Gxa * self.netXA), NoZeros=True)}\n"
        if self.netABX is not None:
            result += f"ABX({self.Gabx:1.3f}): {self.strVec(self.select(words, self.Gabx * self.netABX), NoZeros=True)}\n"
        if self.netXBA is not None:
            result += f"XBA({self.Gxba:1.3f}): {sel.strVec(self.select(words, self.Gxba * self.netXBA), NoZeros=True)}\n"
        result += "\n"
        result += f"CX({self.Gcx:1.3f}): {self.strVec(self.select(words, self.Gcx * self.netCX), NoZeros=True)}\n"
        result += f"MX({self.Gmx:1.3f}): {self.strVec(self.select(words, self.Gmx * self.netMX), NoZeros=True)}\n"
        result += f"HX({self.Ghx:1.3f}): {self.strVec(self.select(words, self.Ghx * self.netHX), NoZeros=True)}\n"
        result += f"KX({self.Gkx:1.3f}): {self.strVec(self.select(words, self.Gkx * self.netKX), NoZeros=True)}\n"

        result += "\n"
        result += f"CI({self.Gci:1.3f}): {self.strVec(self.select(words, self.Gci * self.netCI), NoZeros = True)}\n"
        result += f"MI({self.Gmi:1.3f}): {self.strVec(self.select(words, self.Gmi * self.netMI), NoZeros = True)}\n"
        result += f"HI({self.Ghi:1.3f}): {self.strVec(self.select(words, self.Ghi * self.netHI), NoZeros = True)}\n"
        result += f"KI({self.Gki:1.3f}): {self.strVec(self.select(words, self.Gki * self.netKI), NoZeros = True)}\n"

        # attention weights

        t = zeros((1,self.V)) # temporary storage of attention weights
        result += "\n"
        result += "Attention Weights:\n"

        if len(cowan) > 0:
            attention = (sparsemax(-self.X[:, cowan]))
            t[:,:] = 0.0
            t[:, cowan] = attention
            result += "Cowan: " + self.strVec(t, NoZeros = True) + "\n"
        if len(miller) > 0:
            attention = (sparsemax(-self.X[:, miller]))
            t[:,:] = 0.0
            t[:, miller] = attention
            result += "Miller: " + self.strVec(t, NoZeros = True) + "\n"
        if len(honeyhasson) > 0:
            attention = (sparsemax(-self.X[:, honeyhasson]))
            t[:,:] = 0.0
            t[:, honeyhasson] = attention
            result += "HoneyHasson: " + self.strVec(t, NoZeros = True) + "\n"
        if len(kintsch) > 0:
            attention = (sparsemax(-self.X[:, kintsch]))
            t[:,:] = 0.0
            t[:, kintsch] = attention
            result += "Kintsch: " + self.strVec(t, NoZeros = True) + "\n"
        return result

    def prob(self, a, b, bafter, aafter, cowan, miller, honeyhasson, kintsch):

        # lazy load counts and do log transform
        if not self.CountsLoaded:
            self.loadCounts()

        abkey = self.vocab[a]+"_"+self.vocab[b]
        if abkey in self.bigramI:
            ab = self.bigramI[abkey]
        else:
            ab = -1
        if bafter != -1 and aafter != -1:
            bakey = self.vocab[bafter]+"_"+self.vocab[aafter]
            if bakey in self.bigramI:
                baafter = self.bigramI[bakey]
            else:
                baafter = -1
        else:
            baafter = -1

        self.netAX = self.AX[a,:]
        self.netBX = self.BX[b,:]
        if aafter != -1:
            self.netXA = self.AX.T[aafter,:]
        if bafter != -1:
            self.netXB = self.BX.T[bafter,:]
        if ab != -1:
            self.netABX = self.ABX[ab,:]
        if baafter != -1:
            self.netXBA = self.XBA[baafter,:]
        self.netX = self.X

        if len(cowan) > 0:
            attention = (sparsemax(-self.X[:, cowan]))
            self.netCX = attention * self.CX[cowan,:]
        else:
            self.netCX = zeros((1,self.V))
        if len(miller) > 0:
            attention = (sparsemax(-self.X[:, miller]))
            self.netMX = attention * self.MX[miller,:]
        else:
            self.netMX = zeros((1,self.V))
        if len(honeyhasson) > 0:
            attention = (sparsemax(-self.X[:, honeyhasson]))
            self.netHX = attention * self.HX[honeyhasson,:]
        else:
            self.netHX = zeros((1,self.V))
        if len(kintsch) > 0:
            attention = (sparsemax(-self.X[:, kintsch]))
            self.netKX = attention * self.KX[kintsch,:]
        else:
            self.netKX = zeros((1,self.V))
        #self.netMX = self.MX[miller,:]
        #self.netHX = self.HX[honeyhasson,:]
        #self.netKX = self.KX[kintsch,:]

        self.netCI = csr_matrix((1, self.V))
        self.netMI = csr_matrix((1, self.V))
        self.netHI = csr_matrix((1, self.V))
        self.netKI = csr_matrix((1, self.V))
        self.netCI[0, cowan] = 1.
        self.netMI[0, miller] = 1.
        self.netHI[0, honeyhasson] = 1.
        self.netKI[0, kintsch] = 1.

        self.net = self.Gax * self.netAX
        self.net += self.Gbx * self.netBX
        self.net += self.Gx * self.netX
        self.net += self.Gcx * self.netCX
        self.net += self.Gci * self.netCI
        self.net += self.Gmx * self.netMX
        self.net += self.Gmi * self.netMI
        self.net += self.Ghx * self.netHX
        self.net += self.Ghi * self.netHI
        #if len(honeyhasson) > 0:
        #    v = zeros((1, self.V))
        #    attention = (sparsemax(-self.X[:, honeyhasson]))
        #    for j in range(len(honeyhasson)):
        #        v[0, honeyhasson[j]] += attention[0, j]
        #    print (self.strVec(v))
        self.net += self.Gkx * self.netKX
        #if len(kintsch) > 0:
        #    v = zeros((1, self.V))
        #    attention = (sparsemax(-self.X[:, kintsch]))
        #    for j in range(len(kintsch)):
        #        v[0, kintsch[j]] += attention[0, j]
        #    print (self.strVec(v))
        self.net += self.Gki * self.netKI
        if ab != -1:
            self.net += self.Gabx * self.netABX
        if aafter != -1:
            self.net += self.Gxa * self.netXA
        if bafter != -1:
            self.net += self.Gxb * self.netXB
        if baafter != -1:
            self.net +=  self.Gxba * self.netXBA

        s = sparsemax(self.net)
        return s

    def samplerGibbs(self, prefix, BufferLength = 8, Threshold = 6, stopSampler = 1000):
        buffer = ones(BufferLength, int) * -1
        bufferprobs = zeros(BufferLength)
        for i in range(len(prefix)):
            buffer[i] = self.I[prefix[i]]
        counts = Counter()
        iteration = 0
        while len(counts) == 0 or counts.most_common(1)[0][1] < Threshold and iteration < stopSampler:
            for j in range(len(prefix), len(buffer)):
                cowan = buffer[max(0, j - SP.CowanBufferLength):j]
                miller = buffer[max(0, j - SP.MillerBufferLength):j]
                honeyhasson = buffer[max(0, j - SP.HoneyHassonBufferLength):j]
                kintsch = buffer[max(0, j - SP.KintschBufferLength):j]
                if j == len(buffer)-2:
                    ps = array(self.prob(buffer[j-2], buffer[j-1], buffer[j+1], -1, cowan, miller, honeyhasson, kintsch))
                elif j == len(buffer)-1:
                    ps = array(self.prob(buffer[j-2], buffer[j-1], -1, -1, cowan, miller, honeyhasson, kintsch))
                else:
                    ps = array(self.prob(buffer[j-2], buffer[j-1], buffer[j+1], buffer[j+2], cowan, miller, honeyhasson, kintsch))
                c = choice(range(self.V), 1, p=ps.ravel())[0]
                buffer[j] = c
                bufferprobs[j] = ps[0, c]
            key = " ".join(self.vocab[w] for w in buffer)
            print (" ".join(bpstr([self.vocab[buffer[k]]]) if k < len(prefix) else f"{bpstr([self.vocab[buffer[k]]])} ({bufferprobs[k]:1.2f})" for k in range(len(buffer))))
            counts[key] += 1
            iteration += 1
        if iteration >= stopSampler:
            return None
        else:
            return counts.most_common(1)[0][0]

    def sampler(self, prefix, BufferLength = 8):
        buffer = ones(BufferLength, int) * -1
        bufferprobs = zeros(BufferLength)
        for i in range(len(prefix)):
            buffer[i] = self.I[prefix[i]]
        for j in range(len(prefix), len(buffer)):
            cowan = buffer[max(0, j - SP.CowanBufferLength):j]
            miller = buffer[max(0, j - SP.MillerBufferLength):j]
            honeyhasson = buffer[max(0, j - SP.HoneyHassonBufferLength):j]
            kintsch = buffer[max(0, j - SP.KintschBufferLength):j]
            if j == len(buffer)-2:
                ps = array(self.prob(buffer[j-2], buffer[j-1], buffer[j+1], -1, cowan, miller, honeyhasson, kintsch))
            elif j == len(buffer)-1:
                ps = array(self.prob(buffer[j-2], buffer[j-1], -1, -1, cowan, miller, honeyhasson, kintsch))
            else:
                ps = array(self.prob(buffer[j-2], buffer[j-1], buffer[j+1], buffer[j+2], cowan, miller, honeyhasson, kintsch))
            c = argmax(ps.ravel())
            buffer[j] = c
            #bufferprobs[j] = ps[0, c]
            #key = " ".join(self.vocab[w] for w in buffer)
            #print (" ".join(bpstr([self.vocab[buffer[k]]]) if k < len(prefix) else f"{bpstr([self.vocab[buffer[k]]])} ({bufferprobs[k]:1.2f})" for k in range(len(buffer))))
        return buffer

    def learnOnePass (self, changeweights = True, verbose=False, regularise=False):
        se = 0.0
        sa = 0.0
        count = 0
        correct = 0
        for i in range(len(self.words)-4):
            cowan = self.words[max(0, i - SP.CowanBufferLength):i]
            miller = self.words[max(0, i - SP.MillerBufferLength):i]
            honeyhasson = self.words[max(0, i - SP.HoneyHassonBufferLength):i]
            kintsch = self.words[max(0, i - SP.KintschBufferLength):i]
            output = self.prob(self.words[i], self.words[i+1], self.words[i+3], self.words[i+4], cowan, miller, honeyhasson, kintsch)
            c = self.words[i+2]

            delta = -output
            delta [0,c] += 1
            se += dot(delta, delta.T)[0,0]
            sa += dot(output, output.T)[0,0]
            if argmax(output) == c:
                correct += 1
            count += 1
            if verbose:
                print (f"{dot(delta, delta.T)[0,0]:1.3f} {self.vocab[self.words[i+2]]}: {self.strVec(output, NoZeros=True)}")

            if changeweights:
                delta = csr_matrix(delta)
                if "BX" in self.constraints:
                    self.Gbx += self.lam * dot(delta, self.netBX.T)[0,0]
                    if regularise: self.Gbx -= self.lam * self.Gbx
                if "AX" in self.constraints:
                    self.Gax += self.lam * dot(delta, self.netAX.T)[0,0]
                    if regularise: self.Gax -= self.lam * self.Gax
                if "XA" in self.constraints:
                    self.Gxa += self.lam * dot(delta, self.netXA.T)[0,0]
                    if regularise: self.Gxa -= self.lam * self.Gxa
                if "XB" in self.constraints:
                    self.Gxb += self.lam * dot(delta, self.netXB.T)[0,0]
                    if regularise: self.Gxb -= self.lam * self.Gxb
                if self.netABX is not None:
                    if "ABX" in self.constraints:
                        self.Gabx += self.lam * dot(delta, self.netABX.T)[0,0]
                        if regularise: self.Gabx -= self.lam * self.Gabx
                if self.netXBA is not None:
                    if "XBA" in self.constraints:
                        self.Gxba += self.lam * dot(delta, self.netXBA.T)[0,0]
                        if regularise: self.Gxba -= self.lam * self.Gxba
                if len(cowan) > 0:
                    if "CX" in self.constraints:
                        self.Gcx += self.lam * dot(self.netCX, delta.T.todense())[0,0]
                        if regularise: self.Gcx -= self.lam * self.Gcx
                    if "CI" in self.constraints:
                        self.Gci += self.lam * dot(self.netCI, delta.T)[0,0]
                        if regularise: self.Gci -= self.lam * self.Gci
                if len(miller) > 0:
                    if "MX" in self.constraints:
                        self.Gmx += self.lam * dot(self.netMX, delta.T.todense())[0,0]
                        if regularise: self.Gmx -= self.lam * self.Gmx
                    if "MI" in self.constraints:
                        self.Gmi += self.lam * dot(self.netMI, delta.T)[0,0]
                        if regularise: self.Gmi -= self.lam * self.Gmi
                if len(honeyhasson) > 0:
                    if "HX" in self.constraints:
                        self.Ghx += self.lam * dot(self.netHX, delta.T.todense())[0,0]
                        if regularise: self.Gkx -= self.lam * self.Gkx
                    if "HI" in self.constraints:
                        self.Ghi += self.lam * dot(self.netHI, delta.T)[0,0]
                        if regularise: self.Ghi -= self.lam * self.Ghi
                if len(kintsch) > 0:
                    if "KX" in self.constraints:
                        self.Gkx += self.lam * dot(self.netKX, delta.T.todense())[0,0]
                        if regularise: self.Gkx -= self.lam * self.Gkx
                    if "KI" in self.constraints:
                        self.Gki += self.lam * dot(self.netKI, delta.T)[0,0]
                        if regularise: self.Gki -= self.lam * self.Gki

                if "X" in self.constraints:
                    self.Gx += self.lam * (delta * self.netX.T)[0,0]
                    if regularise: self.Gx -= self.lam * self.Gxa

        return sqrt(se/count), sqrt(sa/count), correct/count

    def learn(self, NumberOfIterations, CorpusSize):

        self.words = []
        with open(self.corpus+"/corpus.tok", encoding='ascii') as f:
            for line in f:
                self.words += [self.I[w] for w in line.lower().split()]
                if len(self.words) >= CorpusSize:
                    break
        self.words = self.words[0:CorpusSize]

        for iteration in range(NumberOfIterations):
            rmse, rmsa, correct = self.learnOnePass()
            print (f"{iteration+1}/{NumberOfIterations}: rmse: {rmse:1.4f} rmsa: {rmsa:1.4f} correct: {correct:1.2f} {self.strParams()}", flush=True)
            self.saveParams()

    def test(self, size=None, verbose=False):

        with open(self.corpus+"/corpus.tok", encoding='ascii') as f:
            self.words = [self.I[w] for w in f.read().lower().split()]

        if size:
            self.words = self.words[0:size]
        rmse, rmsa, correct = self.learnOnePass(changeweights = False, verbose=verbose)
        print (self.strParams())
        print (f"rmse: {rmse:1.4f} rmsa:{rmsa:1.4f} correct:{correct:1.2f}")

if __name__ == "__main__":
    s = SP("small")
    a = s.I["australia"]
    b = s.I["is"]
    aafter = -1
    bafter = -1
    cowan = [s.I[w] for w in "australia is".split()]
    miller = cowan
    honeyhasson = cowan
    kintsch = cowan
    ps = s.prob(a, b, bafter, aafter, cowan, miller, honeyhasson, kintsch)
    print (s.strVec(ps))


import pandas as pd
import numpy as np

# Import and format data sets

# Aubert 2012 Data

AubertData = pd.read_csv(r'~/Path/to/Data')  # Add path to Aubert Data

AubertData_gran_base = pd.DataFrame(AubertData, columns=['Granulo']).to_numpy()[:, 0]
AubertData_age_base = pd.DataFrame(AubertData, columns=['age']).to_numpy()[:, 0]

AubertData_age = np.delete(AubertData_age_base, np.argwhere(np.isnan(AubertData_gran_base)))
AubertData_gran = np.delete(AubertData_gran_base, np.argwhere(np.isnan(AubertData_gran_base)))

# Andreu 2022 Data

AndreuData = pd.read_csv(r'~/Path/to/Data')  # Add path to Andreu Data

AndreuData_age_base = AndreuData.iloc[:, 1].to_numpy()[8:]
AndreuData_gran_base = AndreuData.iloc[:, 14].to_numpy()[8:]

AndreuData_age = np.delete(AndreuData_age_base, np.argwhere(AndreuData_gran_base == "-"))
AndreuData_gran = np.delete(AndreuData_gran_base, np.argwhere(AndreuData_gran_base == "-"))

AndreuData_gran = AndreuData_gran.astype("float64")
AndreuData_age = AndreuData_age.astype("float64")

# Alder 2018 Data
AlderData_gran = np.array(
    [])

AlderData_age = np.array(
    [])

AlderData_age = np.delete(AlderData_age, np.argwhere(AlderData_gran == None))
AlderData_gran = np.delete(AlderData_gran, np.argwhere(AlderData_gran == None))
AlderData_age = AlderData_age.astype('float64')
AlderData_gran = AlderData_gran.astype('float64')


import urllib
import pandas as pd
import numpy as np
from glob import glob
import argparse
import csv
import opponents

def ParseArgs():
    """Setup command-line interface"""
    parser = argparse.ArgumentParser(description='Get all available AUDL data with minor enhancements and regularization from UltiAnalytics.')
    parser.add_argument('--updatecurrent', dest='updatecurrent', action='store_true',
                        default=False,
                        help='Only get latest year.')
    return  parser.parse_args()

def CSV2DataFrame(filename):
    """Read CSV as Pandas DataFrame but deal with inconsistent use of commas in CSV"""
    teamlog = []
    with open(filename, 'r') as csvfile:
        reader = csv.reader(csvfile, delimiter=',', quotechar='|')
        header = next(reader)
        teamlog = list(reader)
    # Deal with sticky situation of rows with more or less CSV's than the header
    ncols = len(header)
    teamlog = [e[:ncols] if len(e) > ncols else e+['']*(ncols-len(e)) for e in teamlog]

    return pd.DataFrame(teamlog,columns=header)

def AddExtraCols(df_in, teamname, year):
    """Add extra useful columns"""
    df_in['Teamname'] = teamname
    df_in['Tournament'] = year
    df_in = df_in.drop('Tournamemnt',axis=1) # Remove misspelled, useless column

    return df_in

def MakeGameOverLine(df_in):
    gameoverline = df_in.copy()
    gameoverline['Action'] = 'GameOver'
    gameoverline['Event Type'] = 'Cessation'
    gameoverline['Passer'] = ''
    gameoverline['Receiver'] = ''
    gameoverline['Defender'] = ''
    gameoverline['Hang Time (secs)'] = np.nan
    gameoverline['Begin Area']              =np.nan
    gameoverline['Begin X']                 =np.nan
    gameoverline['Begin Y']                 =np.nan
    gameoverline['End Area']                =np.nan
    gameoverline['End X']                   =np.nan
    gameoverline['End Y']                   =np.nan
    gameoverline['Distance Unit of Measure']=np.nan
    gameoverline['Absolute Distance']       =np.nan
    gameoverline['Lateral Distance']        =np.nan
    gameoverline['Toward Our Goal Distance']=np.nan
    return gameoverline.to_frame().T

def FixGameOvers(df_in):
    """Fix missed and redundant GameOver entries"""

    # Remove double GameOvers: Consecutive Action's can't both be GameOver
    df_in = df_in[ (~df_in.Action.eq(df_in.Action.shift(-1))) | (df_in.Action!='GameOver') ].reset_index(drop=True)

    # Add missing GameOvers: Date/Time changes require GameOver, Get indicies where previous Action should be GameOver but isn't
    idx = df_in[ ~(df_in['Date/Time'].eq(df_in['Date/Time'].shift())) & (df_in.Action.shift()!='GameOver') & (df_in.index>0)].index.values

    if len(idx)>0:
        dflist = []
        previ=0
        #iterate through indicies, create gameover instance using previous row as template, append previous rows then gameover row to a list
        for i in idx:
            dflist.append( df_in.iloc[previ:i] )
            dflist.append( MakeGameOverLine(df_in.iloc[i-1]) )

            previ=i
        dflist.append( df_in.iloc[i:] )

        df_in = pd.concat(dflist).reset_index(drop=True)

    # Add missing GameOver to last line
    if df_in.iloc[-1].Action!='GameOver':
        df_in = pd.concat( [df_in, MakeGameOverLine(df_in.iloc[-1]) ] ).reset_index(drop=True)

    return df_in

def RemoveTestGames(df_in):
    """Remove test games from log"""
    return df_in[~(df_in.Opponent=='Test')]

def TimeEventSort(df_in):
    """Sort by Date/Time and orignal index"""
    df_in['OrigIndex'] = df_in.index
    df_in = df_in.sort_values(['Date/Time','OrigIndex'])
    return df_in.drop('OrigIndex',axis=1).reset_index(drop=True)

def InsertPlayerNames(df_in):
    """Insert player names by replacing usernames,
       given the Tournament and Teamname"""
    upr = pd.read_csv('player-names/11_username_playername_relation.csv',encoding = "ISO-8859-1")
    upr['PlayerName'] = upr['PlayerName'].fillna(upr.Username)

    numbered_player_fields = [f'Player {i}' for i in range(0,28)]
    player_fields = ['Passer', 'Receiver', 'Defender'] + numbered_player_fields

    for p_field in player_fields:
        df_in[p_field] = pd.merge(df_in[['Tournament','Teamname',p_field]],upr,
                                         left_on=['Tournament','Teamname',p_field],
                                         right_on=['Tournament','Teamname','Username'],
                                         how='left')['PlayerName'].values

    df_in['Lineup'] = df_in.fillna('').apply( lambda x : ', '.join([ x[i] for i in numbered_player_fields if x[i] !='']), axis=1).values

    return df_in

def AddGameplayIDs(df_in):
    """Add IDs for each Game and its Points and Possessions"""
    df_in['GameID'] = pd.factorize(df_in['Date/Time'].astype(str)
                                 +df_in['Opponent'].astype(str))[0] +1

    df_in.loc[df_in.Action=='EndOfFirstQuarter','QuarterID'] = 1
    df_in.loc[df_in.Action=='Halftime','QuarterID'] = 2
    df_in.loc[df_in.Action=='EndOfThirdQuarter','QuarterID'] = 3
    df_in.loc[df_in.Action=='EndOfFourthQuarter','QuarterID'] = 4
    df_in.loc[df_in.Action=='GameOver','QuarterID'] = 4
    ot_games = df_in[df_in.Action.isin(['EndOfFourthQuarter','EndOfOvertime'])].GameID.unique()
    df_in.loc[(df_in.Action=='GameOver')&(df_in.GameID.isin(ot_games)),'QuarterID'] = 5
    df_in['QuarterID'] = df_in.QuarterID.bfill().astype(int)

    point_groups = df_in.groupby(['GameID']).apply(lambda x : pd.factorize( x['Our Score - End of Point'].astype(str)
                                                                             +x['Their Score - End of Point'].astype(str)
                                                                             +x['Line']
                                                                             +x['Point Elapsed Seconds'].astype(str))[0] + 1).values
    df_in['PointID'] =  [j for i in point_groups for j in i]

    poss_change_list=['Goal',
                        'Throwaway',
                        'D',
                        'Drop',
                        'EndOfThirdQuarter',
                        'GameOver',
                        'EndOfFirstQuarter',
                        'Halftime',
                        'Stall',
                        'Callahan',
                        'EndOfFourthQuarter',
                        'EndOfOvertime']

    poss_groups =df_in.groupby(['GameID','PointID']).apply(lambda x : range(1,len(x[x.Action.isin(poss_change_list)])+1 ) )
    df_in.loc[df_in.Action.isin(poss_change_list),'PossessionID']= [j for i in poss_groups for j in i]
    df_in['PossessionID'] = df_in['PossessionID'].bfill()

    return df_in

def main():

    args = ParseArgs()

    allfiles = sorted(glob('data/teams*.csv'))
    filestoget = allfiles if not args.updatecurrent else [allfiles[-1]]

    for f in filestoget:

        df_filepaths =pd.read_csv(f).sort_values(['year','teams'])

        for i,row in df_filepaths.iterrows():

            teamno = row['teams-href'].split("/")[5]
            year = row['year']
            teamname = row['teams']
            print(year,teamname)

            url = 'http://www.ultianalytics.com/rest/view/team/{}/stats/export'.format(teamno)
            outfn = "output/{}_{}.csv".format(year,teamname).replace(' ','')
            urllib.request.urlretrieve(url, outfn)

            df_teamdata = CSV2DataFrame(outfn)
            df_teamdata = AddExtraCols(df_teamdata, teamname, year)
            df_teamdata = FixGameOvers(df_teamdata)
            if len(df_teamdata[~(df_teamdata['Date/Time'].eq(df_teamdata['Date/Time'].shift(-1))) &(df_teamdata.Action!='GameOver')]) > 0:
                print('Missing GameOvers')
            if len(df_teamdata[ (df_teamdata.Action.eq(df_teamdata.Action.shift())) & (df_teamdata.Action.shift()=='GameOver') ]) > 0:
                print('Double GameOvers')

            df_teamdata = RemoveTestGames(df_teamdata)
            df_teamdata = opponents.Standardize(df_teamdata)
            df_teamdata = TimeEventSort(df_teamdata)
            df_teamdata = InsertPlayerNames(df_teamdata)
            df_teamdata = AddGameplayIDs(df_teamdata)

            df_teamdata.to_csv(outfn,sep=',')

main()


class Solution(object):
    def fairCandySwap(self, A, B):
        """
        :type A: List[int]
        :type B: List[int]
        :rtype: List[int]
        """
        sum_a = sum(A)
        sum_b = sum(B)
        target = (sum_a + sum_b) / 2
        diff = target - sum_b
        set_a = set(A)
        for b in B:
            if b + diff in set_a:
                return [b + diff, b]


def gcd(ar):
    res = 0
    for i in range(1, ar[0]+ar[1]):
        if ar[0] % i == 0 and ar[1] % i == 0:
            res = i
    return res

if __name__ == '__main__':
    input_lst = [int(x) for x in input().split()]
    print(gcd(input_lst))


import argparse
import time

import numpy as np
import scipy.sparse as sp
import torch
from torch import optim
from transformers.utils import logging

from model import GCNModelVAE, KMeansModel
from optimizer import gae_loss_function, k_means_loss_function
from options import args
from utils import load_graph, preprocess_graph
from evaluate import single_text_rouge

def main():
    features, srcs, adjs, tgt = load_graph(args.multi_news)
    summaries = []
    rouge1_list = []
    rouge2_list = []
    rougel_list = []
    for i in range(len(features)):
        feature = torch.FloatTensor(features[i])
        n_nodes, feat_dim = feature.shape
        # model输入
        adj = adjs[i]
        adj_norm = preprocess_graph(adj)
        src = srcs[i]
        # loss所需参数
        pos_weight = torch.Tensor([float(adj.shape[0] * adj.shape[0] - adj.sum()) / adj.sum()])
        norm = adj.shape[0] * adj.shape[0] / float((adj.shape[0] * adj.shape[0] - adj.sum()) * 2)
        adj_label = adj + sp.eye(adj.shape[0])
        adj_label = torch.FloatTensor(adj_label.toarray())

        gae_model = GCNModelVAE(feat_dim, args.hidden1, args.hidden2, args.dropout)
        k_means_model = KMeansModel(args.n_clusters)
        optimizer = optim.Adam(gae_model.parameters(), lr=args.lr)

        for epoch in range(args.epochs):
            t = time.time()
            gae_model.train()
            optimizer.zero_grad()
            recovered, mu, logvar = gae_model(feature, adj_norm)
            gae_loss = gae_loss_function(preds=recovered, labels=adj_label,
                                         mu=mu, logvar=logvar, n_nodes=n_nodes,
                                         norm=norm, pos_weight=pos_weight)
            cluster_centers, sentence_feat, sentence_index = k_means_model(recovered.detach().numpy().tolist())
            k_means_loss = k_means_loss_function(cluster_centers, sentence_feat)
            loss = gae_loss + args.gama * k_means_loss
            loss.backward()
            optimizer.step()
            # cur_loss = loss.item()
            #
            # print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(cur_loss),
            #       "time=", "{:.5f}".format(time.time() - t)
            #       )
        summary_index = [src[ind] for ind in sentence_index]
        summary = '.'.join(summary_index)
        # print(summary, "\t", tgt[i])
        summaries.append(summary)
        res = single_text_rouge(summary, tgt[i])
        rouge1 = res[0]["rouge-1"]['f']
        rouge1_list.append(rouge1)
        rouge2 = res[0]["rouge-2"]['f']
        rouge2_list.append(rouge2)
        rougel = res[0]["rouge-l"]['f']
        rougel_list.append(rougel)
        print("sentence {}\t".format(i), "rouge-1=", "{:.5f}".format(rouge1), "rouge-2=", "{:.5f}".format(rouge2),
              "rouge-l=", "{:.5f}".format(rougel))
    print("total\n", "rouge-1=", "{:.5f}".format(np.mean(rouge1_list)), "rouge-2=",
          "{:.5f}".format(np.mean(rouge2_list)), "rouge-l=",
          "{:.5f}".format(np.mean(rougel_list)))

if __name__ == '__main__':
    logging.set_verbosity_error()
    main()


""" Write a python script to create a to print the above user account
object using operator overloading (hint __str__ method) """

class UserAccount:
    def __init__(self,id,blnc):
        self.userid=id
        self.balance=blnc
    def __str__(self):
        return str(print("UserID =",self.userid,"\nBalance =",self.balance))
U1=UserAccount(101,10000)
U2=UserAccount(102,20000)
U3=UserAccount(103,30000)
print(U1)
print(U2)
print(U3)


"""Custom Agent"""

from pysc2.agents import base_agent
from pysc2.env import sc2_env, run_loop
from pysc2.lib import actions, features, units
from absl import app
import random
import numpy as np

class RawAgent(base_agent.BaseAgent):
    def __init__(self):
        super(RawAgent, self).__init__()
        self.base_top_left = None

    def get_my_units_by_type(self, obs, unit_type):
        return [unit for unit in obs.observation.raw_units if unit.unit_type == unit_type and unit.alliance == features.PlayerRelative.SELF]

    def get_my_completed_units_by_type(self, obs, unit_type):
        return [unit for unit in obs.observation.raw_units if unit.unit_type == unit_type and unit.build_progress == 100 and unit.alliance == features.PlayerRelative.SELF]

    def get_distances(self, obs, units, xy):
        units_xy = [(unit.x, unit.y) for unit in units]
        return np.linalg.norm(np.array(units_xy) - np.array(xy), axis=1)

    def step(self, obs):
        super(RawAgent, self).step(obs)

        if obs.first():
            command_center = self.get_my_units_by_type(obs, units.Terran.CommandCenter)[0]
            self.base_top_left = (command_center.x < 32)

        depots = self.get_my_units_by_type(obs, units.Terran.SupplyDepot)
        completed_depots = self.get_my_completed_units_by_type(obs, units.Terran.SupplyDepot)

        barracks = self.get_my_units_by_type(obs, units.Terran.Barracks)
        completed_barracks = self.get_my_completed_units_by_type(obs, units.Terran.Barracks)

        free_supply = (obs.observation.player.food_cap - obs.observation.player.food_used)

        marines = self.get_my_units_by_type(obs, units.Terran.Marine)

        if len(depots) == 0 and obs.observation.player.minerals >= 100:
            scvs = self.get_my_units_by_type(obs, units.Terran.SCV)
            if len(scvs) > 0:
                SupplyDepot_xy = (22, 20) if self.base_top_left else (35, 42)
                distances = self.get_distances(obs, scvs, SupplyDepot_xy)
                SCV = scvs[np.argmin(distances)]
                return actions.RAW_FUNCTIONS.Build_SupplyDepot_pt("now", SCV.tag, SupplyDepot_xy)

        if (len(completed_depots) > 0 and len(barracks) == 0 and obs.observation.player.minerals >= 150):
            scvs = self.get_my_units_by_type(obs, units.Terran.SCV)
            if len(scvs) > 0:
                Barracks_xy = (22, 24) if self.base_top_left else (35, 45)
                distances = self.get_distances(obs, scvs, Barracks_xy)
                SCV = scvs[np.argmin(distances)]
                return actions.RAW_FUNCTIONS.Build_Barracks_pt("now", SCV.tag, Barracks_xy)

        if (len(completed_barracks) > 0 and obs.observation.player.minerals >= 100 and free_supply >= 2):
            Barracks = barracks[0]
            if Barracks.order_length < 5:
                return actions.RAW_FUNCTIONS.Train_Marine_quick("now", Barracks.tag)

        if free_supply < 2 and len(marines) > 0:
            attack_xy = (38, 44) if self.base_top_left else (19, 23)
            distances = self.get_distances(obs, marines, attack_xy)
            Marine = marines[np.argmax(distances)]
            x_offset = random.randint(-4, 4)
            y_offset = random.randint(-4, 4)
            return actions.RAW_FUNCTIONS.Attack_pt("now", Marine.tag, (attack_xy[0] + x_offset, attack_xy[1] + y_offset))
        return actions.RAW_FUNCTIONS.no_op()

def main(unused_argv):
    agent = RawAgent()
    try:
        while True:
            with sc2_env.SC2Env(
                map_name = "Simple64",
                players = [sc2_env.Agent(sc2_env.Race.terran), sc2_env.Bot(sc2_env.Race.protoss, sc2_env.Difficulty.very_easy)],
                agent_interface_format = features.AgentInterfaceFormat(action_space=actions.ActionSpace.RAW, use_raw_units=True, raw_resolution=64),
            ) as env:
                run_loop.run_loop([agent], env)
    except KeyboardInterrupt:
        pass
if __name__ == "__main__":
    app.run(main)


# I know how to use help class but I like hardcoding it so stfu.
from setting import *

@client.command(aliases=['h'])
async def help(ctx, command_help: str):

    # Ping
    if command_help == 'ping':
        embed = discord.Embed(title=f"Ping help command",
                              description=f"This will tell you the ping of bot!", color=0x00f2ff)
        await ctx.send(embed=embed)

    # Kick
    elif command_help == 'kick':
        embed = discord.Embed(title=f"kick help command",
                              description=f"This will kick user", color=0x00f2ff)
        embed.add_field(
            name=f"Example", value=f"{prefix}kick {ctx.author.mention}", inline=False)
        await ctx.send(embed=embed)

    # Ban
    elif command_help == 'ban':
        embed = discord.Embed(title=f"Ban help command",
                              description=f"This will ban user", color=0x00f2ff)
        embed.add_field(
            name=f"Example", value=f"{prefix}ban {ctx.author.mention}", inline=False)
        await ctx.send(embed=embed)

    # Unban
    elif command_help == 'unban':
        embed = discord.Embed(title=f"Unban help command",
                              description=f"This will unban user", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}unban {ctx.author}", inline=False)
        await ctx.send(embed=embed)

    # Confess
    elif command_help == 'confess':
        embed = discord.Embed(title=f"Confess help command",
                              description=f"You can write anything then your message will be displayed as this bot and your original message will be deleted!", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}confess example", inline=False)
        await ctx.send(embed=embed)

    # Clear
    elif command_help == 'clear' or command_help == "purge":
        embed = discord.Embed(title=f"Clear help command",
                              description=f"This will clear the message in the channe", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}clear 5", inline=False)
        embed.add_field(name=f"Aliases", value=f"`purge`", inline=False)
        await ctx.send(embed=embed)

    # PP
    elif command_help == 'pp':
        await ctx.send(embed=discord.Embed(title=f"PP command",
                                           description=f"This will tell you your (or the person you mention) pp size", color=0x00f2ff))

    # Slowmode
    elif command_help == 'slowmode' or command_help == "sm":
        embed = discord.Embed(title=f"Slowmode help command",
                              description=f"This slow down the chat!", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}slowmode 5[s, m, h]", inline=False)
        embed.add_field(name=f"Aliases", value=f"`sm`", inline=False)
        await ctx.send(embed=embed)

    # Calculate
    elif command_help == 'calculate' or command_help == "calc":
        embed = discord.Embed(title=f"Calculate help command",
                              description=f"This slow down the chat!", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}calc 5 + 5", inline=False)
        embed.add_field(name=f"Aliases", value=f"`calc`", inline=False)
        await ctx.send(embed=embed)

    # Info
    elif command_help == "info":
        embed = discord.Embed(title=f"Info help command",
                              description=f"This shows the server info!", color=0x00f2ff)
        await ctx.send(embed=embed)

    # Create Text Channel
    elif command_help == "createtextchannel" or command_help=="ctc":
        embed = discord.Embed(title=f"Create Text Channel help command",
                              description=f"This create a new text channel in the category in which this command has been executed ", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}createtextchannel this is a test channel", inline=False)
        embed.add_field(name=f"Aliases", value=f"`ctc`", inline=False)
        await ctx.send(embed=embed)

    # Create Voice Channel
    elif command_help == "createvoicechannel" or command_help=="cvc":
        embed = discord.Embed(title=f"Create Voice Channel help command",
                              description=f"This create a new voice channel in the category in which this command has been executed!", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}createvoicechannel 5 this is a example channel", inline=False)
        embed.add_field(name=f"Aliases", value=f"`cvc`", inline=False)
        embed.set_footer(text="Use 0 as limit to set no limit!")
        await ctx.send(embed=embed)

    # Nickname
    elif command_help == "nickname" or command_help == "nick":
        embed = discord.Embed(title=f"Nichname help command",
                              description=f"This change the nickname of mentioned user!", color=0x00f2ff)
        embed.add_field(name=f"Example",
                        value=f"{prefix}nickname {ctx.author.mention} Exmaple", inline=False)
        embed.add_field(name=f"Aliases", value=f"`nick`", inline=False)
        embed.set_footer(text="Please use character limit of 32 or lower")
        await ctx.send(embed=embed)

    # None
    else:
        embed = discord.Embed(title=f"Command does not exist",
                              description=f"Help for this command dosent exist, please check if the command is correct and present!", color=0x00f2ff)
        await ctx.send(embed=embed)

# Error(s)
@help.error
async def help_error(ctx, error):
    if isinstance(error, commands.MissingRequiredArgument):

        # Variable
        description = '**<:invite:822410792804417567> [ Invite](https://top.gg/bot/709984874924081174/)** | **<:support:822410788773691392> [ Support Server](https://bigbeastishank.com/discord)** |  **<:sourecode:822410789122080768> [ Source Code](https://github.com/BIGBEASTISHANK/discord.py)** | **<:vote:826728613663342642> [ Vote](https://top.gg/bot/709984874924081174/vote)**'

        # Header
        embed = discord.Embed(
            title=f"Guild Prefix: `{prefix}`", color=0x00f2ff, description=description, timestamp=datetime.utcnow())
        embed.set_author(name='BIG Beast Help', url='',
                         icon_url="https://images.discordapp.net/avatars/709984874924081174/dcb255eea70abcc9d6014aac2564e7a0.png?size=128")
        embed.set_thumbnail(
            url="https://images.discordapp.net/avatars/709984874924081174/dcb255eea70abcc9d6014aac2564e7a0.png?size=128")

        # Commands
        embed.add_field(name='❯ General',
                        value='`confess`', inline=False)
        embed.add_field(
            name='❯ Moderation', value='`kick` | `ban` | `unban` | `clear` | `slowmode` | `createtextchannel` | `createvoicechannel` | `nickname`', inline=False)
        embed.add_field(name='❯ Fun', value='`pp` | `calculate`', inline=False)
        embed.add_field(name='❯ Utility', value='`ping` | `info`', inline=False)

        # Footer
        embed.set_footer(
            text=f"Help for specific command use {prefix}help [command]")

        await ctx.send(embed=embed)
        return

    # Unknown error
    else:
        await unknown_error(ctx, error)


import torch
from torch import nn

def ChamferDistance(x, y):  # for example, x = batch,2025,3 y = batch,2048,3
    #   compute chamfer distance between tow point clouds x and y

    x_size = x.size()
    y_size = y.size()
    assert (x_size[0] == y_size[0])
    assert (x_size[2] == y_size[2])
    x = torch.unsqueeze(x, 1)  # x = batch,1,2025,3
    y = torch.unsqueeze(y, 2)  # y = batch,2048,1,3

    x = x.repeat(1, y_size[1], 1, 1)  # x = batch,2048,2025,3
    y = y.repeat(1, 1, x_size[1], 1)  # y = batch,2048,2025,3

    x_y = x - y
    x_y = torch.pow(x_y, 2)  # x_y = batch,2048,2025,3
    x_y = torch.sum(x_y, 3, keepdim=True)  # x_y = batch,2048,2025,1
    x_y = torch.squeeze(x_y, 3)  # x_y = batch,2048,2025
    x_y_row, _ = torch.min(x_y, 1, keepdim=True)  # x_y_row = batch,1,2025
    x_y_col, _ = torch.min(x_y, 2, keepdim=True)  # x_y_col = batch,2048,1

    x_y_row = torch.mean(x_y_row, 2, keepdim=True)  # x_y_row = batch,1,1
    x_y_col = torch.mean(x_y_col, 1, keepdim=True)  # batch,1,1
    x_y_row_col = torch.cat((x_y_row, x_y_col), 2)  # batch,1,2
    chamfer_distance, _ = torch.max(x_y_row_col, 2, keepdim=True)  # batch,1,1
    # chamfer_distance = torch.reshape(chamfer_distance,(x_size[0],-1))  #batch,1
    # chamfer_distance = torch.squeeze(chamfer_distance,1)    # batch
    chamfer_distance = torch.mean(chamfer_distance)
    return chamfer_distance

class ChamferLoss1(nn.Module):
    # chamfer distance loss
    def __init__(self):
        super(ChamferLoss1, self).__init__()

    def forward(self, x, y):
        return ChamferDistance(x, y)


"""
Author: passa-
Problem: Parentheses ครบคู่ไหมนะ
Student Code: 6510503310
Branch: Computer Engineering
"""

class py_solution:
    def __init__(self,paren):
        self.paren = paren

    def is_valid_parentheses(self):
        stack = []
        o_bracket = ["(","[","{"]
        c_bracket = [")","]","}"]

        if len(self.paren) == 1: return False

        for i in range(len(self.paren)):
            if len(stack) == 0:
                stack.append(self.paren[i])
            elif self.paren[i] in o_bracket:
                stack.append(self.paren[i])
            elif self.paren[i] in c_bracket:
                if c_bracket.index(self.paren[i]) == o_bracket.index(stack[-1]):
                    stack.pop()
                else:
                    return False
        return True

## main ##

paren = py_solution(input("input: "))

if paren.is_valid_parentheses():
    print("valid parentheses")
else:
    print("invalid parentheses")


def txt2array(text_var):
	txt_var=text_var.split()
	return txt_var

def array2txt(txt_var,join_by=" "):
	 output_a2t =join_by.join(txt_var)
	 return output_a2t

def array2dic(array_1,array_2):
	dic={}
	for i in array_1:
		for j in array_2 :
			dic[i]=j
			array_2.remove(j)
			break
	return dic

def dic2array(dictionary):
	get=list(dictionary.items())
	list_key=list(dictionary.keys())
	list_value=list(dictionary.values())
	return list_key,list_value , get

def wordcounter(txt_var,word=" "):
	if word == " ":
		output = len(txt_var.split())
	else:
		output=word.count(txt_var)
	return output

def get_txt_between(text_var,parse_1,parse_2):
	try:
		if parse_1 ==" ":
	    		text_var=text_var.split(parse_2)[0]
		elif parse_2 == " ":
				text_var=text_var.split(parse_1)[1]
		else:
			text_var=text_var.split(parse_1)[1]
			text_var=text_var.split(parse_2)[0]

		return text_var
	except IndexError:
		pass
def add_txt_between(text_var,string_var,parse_1,parse_2):
	try:
		if text_var =="none":
			pass
		elif parse_1 == " ":
				text1=text_var.split(parse_2)[0]
				text_var=string_var+string_var
		elif parse_2 == " ":
				text1=text_var.split(parse_1)[1]
				text_var=text1+string_var
		else:
			text1=text_var.split(parse_1)[0]
			text2=text_var.split(parse_2)[1]
			text_var=text1+string_var+text2

		return text_var
	except IndexError:
		pass

def average(lis):
	l=0
	a=len(lis)
	for i in lis:
            l=l+i
	rtn= l/a
	return rtn


"""
定义一个函数，接受三个参数，分别为字符串s、数值a1、数值a2，将字符串s从下标a1开始的a2个字符删除，并把结果返回
"""

def cut_str(s, a1, a2):
    """
    功能：把字符串s中，下标a1开始的a2字符删除，返回剩下的内容
    """
    s1 = s[:a1]
    s2 = s[a1+a2:]
    return s1 + s2

res = cut_str('123456789', 2, 4)
print(res)

res = cut_str('123456789', 4, 2)
print(res)

"""
定义一个函数
- 接收参数 num 和 command
- command 为 True 则返回0-n(包含n)以内的偶数组成的列表
- command 为 False 则返回0-n(包含n)以内的奇数组成的列表
"""

def get_list(num, command):
    ret = []
    i = 0

    while i <= num:
        if command:
            # 生成0-num之间偶数组成的列表
            if i % 2 == 0:
                ret.append(i)
        else:
            # 生成0-num之间奇数组成的列表
            if i % 2 != 0:
                ret.append(i)

        i += 1

    return ret

res = get_list(10, True)
print(res)

res = get_list(10, False)
print(res)

00-昨日作业扩展题.py


# -*- coding: utf-8 -*-
# Copyright (c) 2011-2013 RelationWare. All rights reserved.
# See also LICENSE.txt

import AccessControl

#from Products.SilvaExternalSources import install
from zope.interface import Interface
from silva.core.conf.installer import DefaultInstaller

from silva.core import conf as silvaconf

from Products.SilvaPhotoGallery.configuration import cs_container, dft_id, dft_title

_extensionName = "SilvaPhotoGallery"
silvaconf.extensionName(_extensionName)
silvaconf.extensionTitle('Silva Photo Gallery')
silvaconf.extensionDepends(["SilvaExternalSources"])

class IExtension(Interface):
    '''
    SilvaPhotoGallery Extension
    '''

class GalleryInstaller(DefaultInstaller):
    def install_custom(self, root):
        folder = getattr(root, cs_container, root)
        if hasattr(folder.aq_inner.aq_explicit, dft_id):
            return
        constructor = getattr(folder.manage_addProduct['SilvaPhotoGallery'], 'manage_addPhotoGallery')
        if constructor:
            constructor(dft_id, dft_title)

    def uninstall_custom(self, root):
        folder = getattr(root, cs_container, root)
        folder.manage_delObjects(dft_id)

install = GalleryInstaller(_extensionName, IExtension)