import json
import logging
import tornado.gen

from tornado_http_auth import BasicAuthMixin
from pywakeonlan.wakeonlan import send_magic_packet
from server.base import BaseHandler

class DialogFlowHandler(BasicAuthMixin, BaseHandler):
    lastComputer = {}

    def initialize(self, credentials):
        self.credentials = credentials

    def check_xsrf_cookie(self):
        """
        Disable check since DialogFlow logs in via basic HTTP authentication
        """
        return True

    def prepare(self):
        self.get_authenticated_user(check_credentials_func=self.credentials.get, realm='Protected')

    def get(self):
        self.write("This is meant to be a webhook for DialogFlow")

    @tornado.gen.coroutine
    def get_wol_mac(self, userid, computer):
        laptop_mac, desktop_mac = yield self.get_macs(userid)

        if computer.strip().lower() == "laptop":
            return laptop_mac
        else:
            return desktop_mac

    @tornado.gen.coroutine
    def post(self):
        data = json.loads(self.request.body.decode('utf-8'))

        # Skip if already answered, e.g. saying "Hi!" will be fulfilled by "Small Talk"
        if 'fulfillmentText' in data['queryResult']:
            self.write(json.dumps({}))
            self.set_header("Content-type", "application/json")
            return

        # Make sure the user is logged in and provided a valid access token for a signed-up user
        if 'originalDetectIntentRequest' not in data or \
           'payload' not in data['originalDetectIntentRequest'] or \
           'user' not in data['originalDetectIntentRequest']['payload'] or \
           'accessToken' not in data['originalDetectIntentRequest']['payload']['user']:
            self.write(json.dumps({ "fulfillmentText": "You must be logged in." }))
            self.set_header("Content-type", "application/json")
            return

        userid = yield self.getUserIDFromToken(data['originalDetectIntentRequest']['payload']['user']['accessToken'])

        if not userid:
            logging.error("Invalid access token - userid: "+str(userid)+", data:"+str(data))
            self.write(json.dumps({ "fulfillmentText": "Invalid access token." }))
            self.set_header("Content-type", "application/json")
            return

        response = "Sorry, I'm not sure how to answer that."
        longResponse = None

        # Determine command/query and respond appropriately
        try:
            intent = data['queryResult']['intent']['displayName']
            params = data['queryResult']['parameters']

            if intent == "Computer Command":
                command = params['Command']
                computer = params['Computer']
                x = params['X']
                url = params['url']
                number = params['number']

                # Update last computer used
                if computer:
                    self.lastComputer[userid] = computer
                # If no computer specified, use last, if available
                elif userid in self.lastComputer:
                    computer = self.lastComputer[userid]

                # Only command we handle is the WOL packet
                if command == "power on":
                    if computer:
                        mac = yield self.get_wol_mac(userid, computer)

                        if mac:
                            send_magic_packet(mac, port=9)
                            response = "Woke your "+computer
                        else:
                            response = "Your "+computer+" is not set up for wake-on-LAN"
                    else:
                        response = "Please specify which computer you are asking about"
                else:
                    if userid in self.clients and computer in self.clients[userid]:
                        self.clients[userid][computer].write_message(json.dumps({
                            "command": { "command": command, "x": x, "url": url, "number": number }
                        }))
                        response, longResponse = yield self.clients[userid][computer].wait_response()

                        if not response:
                            response = "Command sent to "+computer
                    elif computer:
                        response = "Your "+computer+" is not currently online"
                    else:
                        response = "Please specify which computer you are asking about"

                    # TODO
                    # If this takes too long, then immediately respond "Command sent to laptop"
                    # and then do this: https://productforums.google.com/forum/#!topic/dialogflow/HeXqMLQs6ok;context-place=forum/dialogflow
                    # saving context and later returning response or something
            elif intent == "Computer Query":
                value = params['Value']
                x = params['X']
                computer = params['Computer']

                # Update last computer used
                if computer:
                    self.lastComputer[userid] = computer
                # If no computer specified, use last, if available
                elif userid in self.lastComputer:
                    computer = self.lastComputer[userid]

                # Only query we handle is the "where is my laptop/desktop"
                if value == "where":
                    if computer:
                        if userid in self.clients and computer in self.clients[userid]:
                            ip = self.clients[userid][computer].ip
                            response = "Unknown location for your "+computer

                            if ip:
                                if ip == self.serverIp:
                                    response = "Your "+computer+" is at home"
                                else:
                                    data = self.gi.record_by_addr(ip)

                                    if data and "city" in data and "region_name" in data and "country_name" in data:
                                        city = data["city"]
                                        region = data["region_name"]
                                        country = data["country_name"]
                                        response = "Your "+computer+" is in "+city+", "+region+", "+country+" ("+ip+")"
                        else:
                            response = "Could not find location of your "+computer
                    else:
                        response = "Please specify which computer you are asking about"
                else:
                    if userid in self.clients and computer in self.clients[userid]:
                        self.clients[userid][computer].write_message(json.dumps({
                            "query": { "value": value, "x": x }
                        }))
                        response, longResponse = yield self.clients[userid][computer].wait_response()

                        if not response:
                            response = "Your "+computer+" did not respond"
                    elif computer:
                        response = "Your "+computer+" is not currently online"
                    else:
                        response = "Please specify which computer you are asking about"
        except KeyError:
            pass

        #"source": string,
        #"payload": { },
        #"outputContexts": [ { object(Context) } ],
        #"followupEventInput": { object(EventInput) },
        #"fulfillmentMessages": [ { response } ],

        # If desired, display one thing and say another. This is useful for
        # example when the displayed text is a file name and you only want to
        # read the most relevant part of it.
        if longResponse:
            json_response = json.dumps({
                "fulfillmentMessages": [{
                    "platform": "ACTIONS_ON_GOOGLE",
                    "simpleResponses": {
                        "simpleResponses": [{
                            "textToSpeech": response,
                            "displayText": longResponse
                        }]
                    }
                }]})
        else:
            json_response = json.dumps({ "fulfillmentText": response })

        self.write(json_response)
        self.set_header("Content-type", "application/json")


from types import SimpleNamespace

import torch
from torch import nn
import math

from src.vision.part3_training_utils import get_model_and_optimizer
from src.vision.part1_ppm import PPM
from src.vision.part5_pspnet import PSPNet

def test_get_model_and_optimizer_pspnet():
    """ """
    args = SimpleNamespace(
        **{
            "classes": 11,
            "zoom_factor": 8,
            "layers": 50,
            "ignore_label": 255,
            "arch": "PSPNet",
            "base_lr": 1e-3,
            "momentum": 0.99,
            "weight_decay": 1e-5,
            "pretrained": False,
            "use_ppm": True
        }
    )
    model, optimizer = get_model_and_optimizer(args)
    param_learning_rates = [group["lr"] for group in optimizer.param_groups]
    print(isinstance(model, PSPNet))
    print(isinstance(optimizer, torch.optim.Optimizer))
    print(len(optimizer.param_groups) > 1)
    print(args.base_lr in param_learning_rates)
    print(not all([param_learning_rates == 1e-3]))
    print(type(model))
    print(PSPNet)
    print(type(PSPNet))
    assert isinstance(model, PSPNet)
    assert isinstance(optimizer, torch.optim.Optimizer)

    assert len(optimizer.param_groups) > 1

    # some modules should be trained at this rate
    assert args.base_lr in param_learning_rates
    # should be separate rates
    assert not all([param_learning_rates == 1e-3])

def test_pspnet_output_shapes() -> None:
    """"""
    args = SimpleNamespace(
        **{
            "classes": 11,
            "zoom_factor": 8,
            "layers": 50,
            "ignore_label": 255,
        }
    )

    criterion = nn.CrossEntropyLoss(ignore_index=args.ignore_label)
    model = PSPNet(
        layers=args.layers,
        num_classes=args.classes,
        zoom_factor=args.zoom_factor,
        criterion=criterion,
        use_ppm=True,
        pretrained=False
    )

    # check whether PPM exists
    #print(isinstance(model.ppm, nn.Module))
    #print(isinstance(model.ppm, PPM))
    assert isinstance(model.ppm, nn.Module)
    assert isinstance(model.ppm, PPM)

    batch_size = 5
    H = 201
    W = 201
    x = torch.rand(batch_size,3,H,W).type(torch.float32)
    y = torch.ones(batch_size,H,W).type(torch.int64) * 255

    logits, yhat, main_loss, aux_loss = model(x, y)

    assert logits.shape == (batch_size, args.classes, H, W)

    # make sure that the output shape is correct
    assert yhat.shape == (batch_size, H, W)

    assert isinstance(logits, torch.Tensor)
    assert isinstance(yhat, torch.Tensor)
    assert isinstance(main_loss, torch.Tensor)
    assert isinstance(aux_loss, torch.Tensor)

    # check loss with all ground truth set to ignore index
    # assert torch.allclose(main_loss, torch.Tensor([0.]))
    # assert torch.allclose(aux_loss, torch.Tensor([0.]))

    # check the dilation settings

def test_check_output_shapes_testtime_pspnet():
    """When y is not provided to the model, losses should be None"""
    args = SimpleNamespace(
        **{
            "classes": 11,
            "zoom_factor": 8,
            "layers": 50,
            "ignore_label": 255,
        }
    )

    criterion = nn.CrossEntropyLoss(ignore_index=args.ignore_label)
    model = PSPNet(
        layers=args.layers,
        num_classes=args.classes,
        zoom_factor=args.zoom_factor,
        criterion=criterion,
        use_ppm=True,
        pretrained=False
    )

    batch_size = 5
    H = 201
    W = 201
    x = torch.rand(batch_size,3,H,W).type(torch.float32)
    y = torch.ones(batch_size,H,W).type(torch.int64) * 255

    logits, yhat, main_loss, aux_loss = model(x)

    assert logits.shape == (batch_size, args.classes, H, W)

    # make sure that the output shape is correct
    assert yhat.shape == (batch_size, H, W)

    assert isinstance(logits, torch.Tensor)
    assert isinstance(yhat, torch.Tensor)

    assert main_loss == None
    assert aux_loss == None

def test_pspnet_output_with_zoom_factor():
    args = SimpleNamespace(
        **{
            "classes": 11,
            "layers": 50,
            "ignore_label": 255,
        }
    )

    criterion = nn.CrossEntropyLoss(ignore_index=args.ignore_label)
    model = PSPNet(
        layers=args.layers,
        num_classes=args.classes,
        criterion=criterion,
        use_ppm=True,
        pretrained=False
    )
    batch_size = 5
    H = 201
    W = 201

    for zoom_factor in [1, 2, 4, 8]:
        model.zoom_factor = zoom_factor
        h_scaled = int(math.ceil(H/8 * zoom_factor))
        w_scaled = int(math.ceil(W/8 * zoom_factor))
        x = torch.rand(batch_size,3,H,W).type(torch.float32)
        y = torch.ones(batch_size,h_scaled,w_scaled).type(torch.int64) * 255

        logits, yhat, main_loss, aux_loss = model(x)

        assert logits.shape == (batch_size, args.classes, h_scaled, w_scaled)
        assert yhat.shape == (batch_size, h_scaled, w_scaled)


import pygame;
import random;
import math;
BLACK = (0,0, 0)
WHITE = (255, 255,255)
BLUE = (50, 50, 255)
YELLOW = (255, 255, 0)
GREEN = (50, 255, 50)
pygame.init()

size = (640, 480)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("My window")
done = False;
clock = pygame.time.Clock()

d = 20

ballPosition = [d, d]
batStep = 15
Direction = [1, 1]

batPosition = [20, 200]
ballSpeed = 1

Direction[0] = random.randint(1,5)
Direction[1] = random.randint(1,5)
print("X: "+str(Direction[0]))
print("Y: "+str(Direction[1]))

while not done:

    #--Userinputandcontrols
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            done=True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:

                batPosition[1]=batPosition[1]-batStep
                if (batPosition[1] <= 0):
                    batPosition[1] = 0

            if event.key == pygame.K_DOWN:
                batPosition[1]=batPosition[1]+batStep
                if batPosition[1] >= 380:
                    batPosition[1] = 380

    screen.fill(BLACK)
            #--Drawhere

    #drawing
    pygame.draw.circle(screen,BLUE,(ballPosition[0],ballPosition[1]),15,0)
    pygame.draw.rect(screen,WHITE,(0, batPosition[1], 20,100)) #bat
    pygame.draw.rect(screen,WHITE,(620,0,640,480))
    #--flipdisplaytorevealnewpositionofobjects
    pygame.display.flip()
            #-Theclockticksover

    #ball movement

    ballPosition[0]=ballPosition[0]+Direction[0] #x movement of the ball
    ballPosition[1]=ballPosition[1]+Direction[1] #y movement of the ball

    #collision of the ball and the bat
    if (ballPosition[0] <= batPosition[0]+20) and ((ballPosition[1] > batPosition[1]-15) and (ballPosition[1] < batPosition[1]+100)):
        Direction[0] = (-1)*Direction[0]
        print("Hit the bat!")

    if (ballPosition[0] >= 605):  #Right wall
        #Direction[1] = (-1)*Direction[1]
        Direction[0] = (-1)*Direction[0]
        print("Hit the right wall")

    if (ballPosition[1] >= 465): #bottom wall
        Direction[1] = (-1)*Direction[1]
        print("Hit the bottom wall")

    if (ballPosition[1] <= 15): #top wall
        Direction[1] = (-1)*Direction[1]
        print("Hit the top wall")

    if (ballPosition[0] <= 15): #Left wall
        print("You lost!")
        done = True

    #moving the ball
    ballPosition[0] = ballPosition[0]+int((Direction[0]*ballSpeed)/2)
    ballPosition[1] = ballPosition[1]+int((Direction[1]*ballSpeed)/2)

    clock.tick(60)
#EndWhile-Endofgameloop
pygame.quit()


from flask import request
from importlib_metadata import metadata
from sqlalchemy import Column, Integer, String, create_engine,Table,MetaData,ForeignKey

# Database Constant Variable
SQLITE = 'sqlite'

# Table Constant Variable
BOOKS = 'books'

class BooksDatabase:
    DB_ENGINE = {
        SQLITE: 'sqlite:///books'
    }

    db_engine = None

    def __init__(self,name='', author='', year='',book_type=''):
        engine_url = self.DB_ENGINE[SQLITE]

        self.db_engine = create_engine(engine_url)

        print(self.db_engine)

    def create_db_table(self):
        metadata = MetaData()
        books = Table(BOOKS, metadata,
                        Column('id', Integer, primary_key = True),
                        Column('name', String(50), index = True , nullable = False),
                        Column('author', String(50) , nullable = False),
                        Column('year', Integer() , nullable = False),
                        Column('book_type', Integer(), nullable = False),
                        Column('availability', String(50))

                        )
        try:
            metadata.create_all(self.db_engine)
            print("Table created")
        except Exception as e:
            print("error occured while table creation")
            print(e)

    def execute_query(self, query=''):
        if query == '' : return

        print (query)
        with self.db_engine.connect() as connection:
            try:
                connection.execute(query)
            except Exception as e:
                print(e)

    def addBook(self, name, author, year,book_type):
        query = f"INSERT INTO {BOOKS}(name, author,year,book_type, availability) VALUES ('{name}','{author}',{year},{book_type},'available')"
        self.execute_query(query)

    def removeBook(self, name):
            query = f"DELETE FROM {BOOKS} WHERE name = '{name}'"
            self.execute_query(query)

    def print_all_data(self, table = BOOKS):
        query = f"SELECT * FROM '{table}';"
        print(query)
        res = []
        with self.db_engine.connect() as connection:
            try:
                result = connection.execute(query)
            except Exception as e:
                print(e)
            else:
                for row in result:
                    res.append( row)
                result.close()
        # print("\n")
        return res

    def findBookStatus(self, name):
            query = f"SELECT availability FROM {BOOKS} WHERE name = '{name}'"
            print(query)
            res = []
            with self.db_engine.connect() as connection:
                try:
                    result = connection.execute(query)
                except Exception as e:
                    print(e)
                else:
                    for row in result:
                        res.append( row)
                    result.close()
            ress = res[0]
            ress = str(ress).strip('(').strip(')').strip(',')
            print (ress)
            return ress

    def updateBookStatus(self, name ,availability):
        query = f"UPDATE {BOOKS} SET availability = {availability} WHERE name = {name}"
        self.execute_query(query)


#!/usr/bin/env python3

# See https://github.com/grepcoffee/aws-scripts/blob/master/inspector/ListFindingsBySev/listfindings.py

import boto3,sys

if __name__ == "__main__":
  if len(sys.argv) > 1:
    my_region = sys.argv[1]
  else:
    my_region = "us-east-1"

  c = boto3.client("inspector2",region_name=my_region)

  p = c.get_paginator("list_findings")
  print ("\n== Getting findings ==")
  for f in p.paginate():
    for fi in (f['findings']):
      print("\n====",fi['findingArn'])
      print (fi['description'])


import base64
import json
import cv2

import sqlalchemy as sa
from sqlalchemy.sql import text

from starlette.applications import Starlette
from starlette.responses import JSONResponse, Response, StreamingResponse
from starlette.middleware.gzip import GZipMiddleware
from starlette.concurrency import run_in_threadpool

from frames import DB, LOG
from frames.hashing import ImageHash
from frames.misc import from_dataurl_to_cvimage, IMG_TYPES

from frames.db import (HASHES_T, showsql, RFT,
                       IMAGES_T, USER_T, UserImage,
                       Reference_Frame, Hashes, Images)

app = Starlette(debug=True)
app.add_middleware(GZipMiddleware, minimum_size=500)
# TODO Add auth middlewhere.

def api_response(message='', status='success', data=None, task=None, **kwargs):
    """Skeleton for the api response"""

    if data is None:
        data = []

    output = {"status": status,
              "data": data,
              "message": message
              }

    if status == 'success':
        status_code = 200
    else:
        status_code = 500

    return JSONResponse(output, status_code=status_code, background=task)

@app.on_event("startup")
async def startup():
    await DB.connect()

@app.on_event("shutdown")
async def shutdown():
    await DB.disconnect()

@app.route('/')
async def homepage(request):
    # Add some bootstrap page? See https://github.com/encode/starlette-example for ideas
    return JSONResponse({'hello': 'world'})

@app.route('/api/sql/dump/{name:str}')
async def dump_hashes_table(request):
    """Simple way to dump the tables to json."""
    name = request.path_params['name']

    if name == 'hashes':
        table = HASHES_T.select()

    elif name == 'userimage':
        # We skip the img key as this is the binary data.
        # We dont want to dump this info as they are huge.
        table = sa.select([col for col in USER_T.columns if col.key != 'img'])
    elif name == 'reference_frame':
        table = RFT.select()

    else:
        return api_response(status='error', message='Invalid table')

    async def gen():
        yield '{"status:"success", "message: "", data: ['
        async for row in DB.iterate(table):
            if row:
                yield json.dumps(dict(row))
                yield ','
        yield "]}"
    LOG.debug('dumping table %s to api' % name)
    return StreamingResponse(gen(), media_type="application/json")

@app.route('/api/query/')
async def test_check_if_show_in_db(request):
    """simple proxy for now later we will have our own db"""

    import http3
    q = request.query_params
    client = http3.AsyncClient()

    if q.get('q'):
        url = 'http://api.tvmaze.com/singlesearch/shows?q=%s' % q.get('q')
        result = await client.get(url)

        result = result.json()
        show_ids = result['externals']
        print(show_ids)

        res = await qq(show_ids['thetvdb'], q['season'])
        if isinstance(res, dict):
            return api_response(message=res['message'])
        elif isinstance(res, list):
            return api_response(data=res)
        else:
            return api_response(status='error')

async def qq(tvdbid, season):
    conf = 0.7 # should be a config option?
    # this should probably be changed as we should just remove enogh episodes.
    episode_statement = text("SELECT COUNT(DISTINCT episode) FROM frames.hashes "
                             "WHERE tvdbid = :tvdbid and season = :season").bindparams(tvdbid=tvdbid,
                                                                                season=season)
    # showsql(episode_statement)
    num_epiodes = await DB.fetch_one(episode_statement)
    num_epiodes = num_epiodes[0]
    req_eps = num_epiodes * conf
    LOG.debug('%s season %s got %s episodes' % (tvdbid, season, num_epiodes))

    if num_epiodes < 3: # Be a config option?
        return dict(message="To few episodes in the db")

    statement = text("SELECT hash FROM (SELECT * FROM frames.hashes "
                     "WHERE frames.hashes.tvdbid = :tvdbid "
                     "AND frames.hashes.season = :season "
                     "GROUP by hash, episode) as f "
                     "GROUP by hash "
                     "having count(hash) > :req_eps "
                     ).bindparams(tvdbid=tvdbid,
                                  season=season,
                                  req_eps=req_eps)

    # showsql(statement)

    result = []
    async for row in DB.iterate(statement):
        result.append(row.hash)

    return result

@app.route('/api/image/{hash:str}')
async def show_image(request):
    """Show a image to a user using the api."""
    img_hash = request.path_params['hash']
    q = USER_T.select().where(UserImage.hash == img_hash)
    result = await DB.fetch_all(q)

    if result is None:
        return api_response(status='error', message='No images match %s' % img_hash)

    if len(result) > 1:
        LOG.debug('We have more then one one image with this hash picking '
                  'the first one. You should check for duplicates')

    if request.query_params.get('base64', '') in ('true', True):
        # This should probably be a better method
        # to do this but it should be enough for now.
        bs = base64.b64encode(result[0].img)
        # All the images in the db should be stored as
        # png anyway, at least if they are upload using
        # the browser extension.
        img = 'data:image/png;base64,%s' % bs.decode("utf-8")
        return Response(img)

    return Response(result[0].img, media_type="image/png")

@app.route('/api/upload', methods=['POST'])
async def upload(request):
    """
    Upload command for the api.

    the form should contain.
    id, show, episode, season, file and type

    """

    # Lets start with some housekeeping first.
    five_mb = 5242880
    if int(request.headers["content-length"]) > five_mb:
        LOG.debug('File size to big')
        return api_response(status='error', message='The request was to large, try reduzing the image size.')

    form = await request.form()

    if form['file'].content_type not in IMG_TYPES:
        message = 'The file type was %s expected %s' % (form['file'].content_type, IMG_TYPES)
        LOG.debug(message)
        return api_response(status='error', message=message)

    if form.get('type', '') not in ('intro', 'outro'):
        message = 'Missing or invalid type, expected values was intro or outro'
        return api_response(status='error', message=message)

    file_ob = form.get('file')
    content = ''
    if file_ob is None:
        LOG.debug('The user forgot to add the damn file.')
        return api_response(status='error', message='Missing file')
    else:
        content = await file_ob.read()

    # Need to run this in the threadpool
    def tb():
        image = from_dataurl_to_cvimage(content)
        ih = ImageHash(cv2.img_hash.pHash(image))
        return ih

    ih = await run_in_threadpool(tb)
    ih_str = str(ih)

    # Images are stored in binary form.
    query = USER_T.insert().values(hash=ih_str,
                                   tvdbid=form['id'],
                                   img=content,
                                   season=int(form['season']),
                                   episode=int(form['episode']),
                                   show=form['show'],
                                   type=form['type'])
    await DB.execute(query)

    LOG.debug('Added %s %s %s with hash %s to the db', form['show'],
              form['season'], form['episode'], ih_str)

    return api_response(status='success')

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host='0.0.0.0', port=8000)


from collections import OrderedDict

SEPARATOR = ','

class Restaurant():
    WEEKDAYS = [
        'Sun',
        'Mon',
        'Tue',
        'Wed',
        'Thu',
        'Fri',
        'Sat',
    ]

    def __init__(self, *opening_hours):

        # group day with the opening hours
        # [('Mon', '9-17'), ('Tue', '10-15'), ...]
        self.opening_hours = zip(
            self.WEEKDAYS,
            [opening_hour.to_string() for opening_hour in opening_hours]
        )

    def get_opening_hours(self):

        group_days = self._group_days_with_same_opened_hours()
        timetable = self._build_timetable(group_days)
        return timetable

    def _split_group_days_by_consecutive_days(self, seq, sep):
        group = []
        for el in seq:
            if el == sep:
                yield group
                group = []
            group.append(el)
        yield group

    def _group_days_with_same_opened_hours(self):
        group_days = OrderedDict()
        last_day = ''
        for opening_hour in self.opening_hours:
            if opening_hour[1] not in group_days.keys():
                group_days[opening_hour[1]] = (opening_hour[0],)
            else:
                if last_day not in group_days[opening_hour[1]]:
                    group_days[opening_hour[1]] = group_days[opening_hour[1]] + (SEPARATOR,)
                group_days[opening_hour[1]] = group_days[opening_hour[1]] + (opening_hour[0],)
            last_day = opening_hour[0]
        return group_days

    def _build_timetable(self, group_days):
        timetable = ''
        for opening_hour, group_day in group_days.iteritems():
            if len(group_day) > 1:
                if SEPARATOR in group_day:
                    splitted_group_day = self._split_group_days_by_consecutive_days(group_day, SEPARATOR)
                    for split in splitted_group_day:
                        if len(split) > 2:
                            timetable = timetable + split[1] + ' - ' + split[len(split) - 1] + ', '
                        else:
                            if SEPARATOR in split:
                                split.remove(',')
                            timetable = timetable + split[0] + ', '
                    timetable = timetable[:-2]
                    timetable = timetable + ': ' + opening_hour + ', '
                else:
                    timetable = timetable + group_day[0] + ' - ' + group_day[
                        len(group_day) - 1] + ': ' + opening_hour + ', '
            else:
                timetable = timetable + group_day[0] + ': ' + opening_hour + ', '

        if timetable:
            timetable = timetable[:-2]
        return timetable

class OpeningHour():

    def __init__(self, opening_hour, closing_hour):
        self.opening_hour = opening_hour
        self.closing_hour = closing_hour

    def to_string(self):
        return "{}-{}".format(self.opening_hour, self.closing_hour)


import pygame
from pygame.locals import *
import os
from Grid import Grid
from BarsContainer import BarsContainer
from pygame_widgets import Button

class AlgoVisual:
    def __init__(self, display):
        self.DISPLAY = display
        os.environ['SDL_VIDEO_CENTERED'] = '1'
        pygame.init()
        pygame.font.init()
        self.surface = pygame.display.set_mode(self.DISPLAY)
        pygame.display.set_caption("AlgoVisual")
        self.font = pygame.font.SysFont("Copperplate-Light", 35)
        self.buttons = self.generateButtons()
        self.pathfinder = False
        self.sorter = False
        self.bgImg = pygame.image.load("bg.JPG")
        self.bgImg = pygame.transform.scale(self.bgImg, (self.DISPLAY[0],self.DISPLAY[1]))

    def generateButtons(self):
        button = []
        # Create Maze Button
        button.append(Button(
            self.surface, 700, 100, 200, 50, text='VISUALIZE',
            font=self.font,
            inactiveColour=(100,100,100),
            pressedColour=(140, 125, 140),
            textColour=(210,210,210),
            onRelease=self.pathFindingButtonOnClick
        ))

        button.append(Button(
            self.surface, 350, 575, 200, 50, text='VISUALIZE',
            font=self.font,
            inactiveColour=(100,100,100),
            pressedColour=(140, 125, 140),
            textColour=(210,210,210),
            onRelease=self.sortingButtonOnClick

        ))
        return button

    def pathFindingButtonOnClick(self):
        self.grid = Grid(self, 600, 75, 500, 500, 50)
        self.pathfinder = True

    def sortingButtonOnClick(self):
        self.container = BarsContainer(self, 350, 100, 800, 500,50)
        self.sorter = True

    def listen_events(self, events):
        for button in self.buttons:
            button.listen(events)

    def run(self):
        running = True
        clock = pygame.time.Clock()

        while running:
            events = pygame.event.get()
            for event in events:
                if event.type == QUIT:
                    running = False
                    break
                if event.type == pygame.KEYDOWN:
                    if event.key == K_ESCAPE:
                        running = False
                        break
                    if event.key == K_RETURN:
                        for bar in self.container.bars:
                            print("(",bar.x, bar.HEIGHT,")", end="" )
                        print()
                        print("-------------------------------------------")

            if self.sorter:
                self.container.listen_events(events)
            if self.pathfinder:
                self.grid.listen_events(events)
            if not self.sorter and not self.pathfinder:
                self.listen_events(events)

            self.surface.fill((180,210,230))

            self.draw()

            pygame.display.flip()

        pygame.quit()

    def draw(self):
        if self.sorter:
            self.container.draw()
        if self.pathfinder:
            self.grid.draw()
        if not self.sorter and not self.pathfinder:
            self.surface.blit(self.bgImg, (0,0))
            for button in self.buttons:
                button.draw()

if __name__ == "__main__":
    a = AlgoVisual((1200, 700))
    a.run()


import numpy as np
from functools import reduce

def khatrirao(matrices, skip_matrix=None, reverse=False):
    """Khatri-Rao product of a list of matrices

        This can be seen as a column-wise kronecker product.
        (see [1]_ for more details).

    Parameters
    ----------
    :param matrices: ndarray list
        list of matrices with the same number of columns, i.e.::

            for i in len(matrices):
                matrices[i].shape = (n_i, m)

    :param skip_matrix: None or int, optional, default is None
        if not None, index of a matrix to skip

    :param reverse: bool, optional
        if True, the order of the matrices is reversed

    Returns
    -------
    khatri_rao_product: matrix of shape ``(prod(n_i), m)``
        where ``prod(n_i) = prod([m.shape[0] for m in matrices])``
        i.e. the product of the number of rows of all the matrices in the product.
    """

    matrices = list(matrices)

    if skip_matrix is not None:
        if skip_matrix > -1:
            matrices = [matrices[i]
                        for i in range(len(matrices)) if i != skip_matrix]
        else:
            raise ValueError("Wrong skip_matrix: {}".format(skip_matrix))

    if matrices[0].ndim == 1:
        matrices[0] = np.reshape(matrices[0], [1, -1])

    n_columns = matrices[0].shape[1]

    # Optional part, testing whether the matrices have the proper size.

    for i, matrix in enumerate(matrices):
        if matrix.ndim != 2:
            raise ValueError("All the matrices must have exactly 2 dimensions!"
                             "Matrix {} has dimension {} != 2.".format(
                i, matrix.ndim))
        if matrix.shape[1] != n_columns:
            raise ValueError("All matrices must have same number of columns!"
                             "Matrix {} has {} columns != {}.".format(
                i, matrix.shape[1], n_columns))

    n_factors = len(matrices)

    if reverse:
        matrices = matrices[::-1]
        # Note: we do NOT use .reverse() which would reverse matrices
        # even outside this function.

    start = ord("a")
    common_dim = "z"
    target = "".join(chr(start + i) for i in range(n_factors))
    source = ",".join(i + common_dim for i in target)
    operation = source + "->" + target + common_dim

    return np.einsum(operation, *matrices).reshape((-1, n_columns))

def cpd_initialize(ext_sizes, rank, init_function=None):
    """
    Initialize a CPD decompositions.
    :param ext_sizes:  ndarray
        sizes of external indices
    :param rank:  int
        rank of the CPD decompositions
    :param init_function: func
        function to call for the initialization of each factor.
        Will be passed a single tuple with factor's size.
    Returns
    -------
    lam, factors: vector of factor norms and a tuple with factors
    """

    if init_function is None:
        def init_function(x): return np.random.rand(*x)

    return [init_function((size, rank))
            for size in ext_sizes]

def cpd_normalize(factors, sort=True, merge_lam=False):
    """
    Normalize the columns of factors to unit. The norms
    are returned in as ndarray

    :param factors: ndarray iterable
        factor matrices
    :param sort: bool, optional
        default True
    :param merge_lam: bool, optional, default False
        merge lam and normalized factors into
        a single tuple, as in nCPD format

    Returns
    -------
    lam: ndarray
    factors: ndarray tuple
    """

    lam = np.ones([1, factors[0].shape[1]])
    new_factors = []

    for factor in factors:
        lam_factor = np.linalg.norm(factor, axis=0)
        new_factors.append(factor / lam_factor)
        lam = lam * np.reshape(lam_factor, [1, -1])

    if sort:
        order = np.argsort(lam)[::-1][0]
        lam = lam[:, order]

        for idx, factor in enumerate(new_factors):
            new_factors[idx] = factor[:, order]

    if merge_lam:
        return (lam,) + tuple(new_factors)
    else:
        return lam, tuple(new_factors)

def ncpd_denormalize(factors, sort=True):
    """
    Convert nCPD format to the CPD format. Lambda factors are
    multiplied into factor matrices

    :param factors: ndarray iterable
        factor matrices in ncpd format
    :param sort: bool, if the factors are sorted by norm
        default True

    Returns
    -------
    lam: ndarray
    factors: ndarray tuple
    """

    lam = factors[0]
    new_factors = list(factors[1:])

    if sort:
        order = np.argsort(lam)[::-1][0]
        lam = lam[:, order]

        for idx, factor in enumerate(new_factors):
            new_factors[idx] = factor[:, order]

    lam_factor = np.power(lam, 1. / len(new_factors))

    for idx, factor in enumerate(new_factors):
        new_factors[idx] = np.dot(factor, np.diag(lam_factor[0, :]))

    return new_factors

def ncpd_renormalize(factors, sort=False, positive_lam=False):
    """
    Normalizes the columns of factors in nCPD format, in
    case the normalization was lost due to some operation on
    the original factors.

    :param factors: ndarray iterable
        factor matrices in ncpd format
    :param sort: bool, default False
        if the factors are sorted by norm
    :param positive_lam: bool, default False
        if negative weights lam have to be turned positive

    Returns
    -------
    lam: ndarray
    factors: ndarray tuple
    """

    old_lam = factors[0]
    old_factors = list(factors[1:])

    lam, factors = cpd_normalize(old_factors, sort=False, merge_lam=False)

    new_lam = old_lam * lam

    if sort:
        order = np.argsort(new_lam)[::-1][0]
        new_lam = new_lam[:, order]
    if positive_lam:
        signs = np.sign(new_lam)
        factors = (factors[0] * signs,) + factors[1:]
        new_lam = new_lam * signs

    return (new_lam,) + factors

def ncpd_initialize(ext_sizes, rank, init_function=None):
    """
    Initialize a normalized CPD decompositions.
    :param ext_sizes:  ndarray
        sizes of external indices
    :param rank: int
        rank of the CPD decompositions
    :param init_function: func
        function to call for the initialization of each factor.
        Will be passed a single tuple with factor's size.

    Returns
    -------
    norm_and_factors: ndarray tuple

    """

    lam, factors = cpd_normalize(
        cpd_initialize(ext_sizes, rank,
                       init_function=init_function),
        sort=True)

    return (lam,) + factors

def cpd_rebuild(factors):
    """
    Rebuild full tensor from it's CPD decompositions
    :param factors: iterable with factor matrices

    Returns
    -------
    tensor: ndarray
    """

    N = len(factors)
    tensor_shape = tuple(factor.shape[0] for factor in factors)
    tensor = khatrirao(tuple(factors[ii] for ii in range(
        N - 1)), reverse=False).dot(factors[N - 1].transpose())

    return tensor.reshape(tensor_shape)

def ncpd_rebuild(norm_factors):
    """
    Rebuild full tensor from it's normalized CPD decompositions
    :param norm_factors: iterable with norm and factors. First
                         iterate is the normalization vector lambda,
                         the rest are factor matrices
    """

    lam = norm_factors[0]
    factors = norm_factors[1:]

    N = len(factors)
    tensor_shape = tuple(factor.shape[0] for factor in factors)
    t = khatrirao(tuple(factors[ii] for ii in range(
        N - 1)), reverse=False).dot((lam * factors[N - 1]).transpose())

    return t.reshape(tensor_shape)

def cpd_contract_free_cpd(factors_top, factors_bottom,
                          skip_factor=None, conjugate=False):
    """
    Contract "external" indices of two CPD decomposed tensors
    :param factors_top: iterable with CPD decompositions
                        of the top (left) tensor
    :param factors_bottom: iterable with CPD decompositions
                        of the bottom (right) tensor
    :param conjugate: conjugate the top (left) factor (default: False)
    :param skip_factor: int, default None
              skip the factor number skip_factor
    """

    if skip_factor is not None:
        factors_top = [factors_top[ii]
                       for ii in range(len(factors_top))
                       if ii != skip_factor]
        factors_bottom = [factors_bottom[ii]
                          for ii in range(len(factors_bottom))
                          if ii != skip_factor]

    if conjugate:
        factors_top = [factor.conjugate() for factor in factors_top]

    s = reduce(lambda x, y: x * y,
               map(lambda x: x[0].T.dot(x[1]),
                   zip(factors_top, factors_bottom)))

    return s

def ncpd_contract_free_ncpd(factors_top, factors_bottom,
                            skip_factor=None, conjugate=False):
    """
    Contract "external" indices of two nCPD decomposed tensors
    :param factors_top: iterable with nCPD decompositions
                        of the top(left) tensor
    :param factors_bottom: iterable with nCPD decompositions
                        of the bottom(right) tensor
    :param conjugate: conjugate the top(left) factor(default: False)
    :param skip_factor: int, default None
              skip the factor number skip_factor
    """

    if skip_factor is not None:
        if skip_factor != 0:
            skip_cpd = skip_factor - 1
        else:
            skip_cpd = None
    else:
        skip_cpd = None

    s = cpd_contract_free_cpd(factors_top[1:],
                              factors_bottom[1:],
                              skip_factor=skip_cpd,
                              conjugate=conjugate)

    lam_top = factors_top[0]
    lam_bottom = factors_bottom[0]

    if skip_factor != 0:
        return s * np.dot(lam_top.T, lam_bottom)
    else:
        return s

def cpd_symmetrize(factors, permdict, adjust_scale=True, weights=None):
    """
    Produce a symmetric CPD decompositions.
    :param factors: CPD factors
    :param permdict: dictionary of tuple: tuple pairs.
                     keys are tuples containing the permutation
                     values are tuples of any of('ident', 'neg', 'conj')
                     Identity permutation has to be excluded(added internally)
    :param weights: list, default None
                    weights of the symmetry elements.
                    If set adjust scale will turn off
    :param adjust_scale: bool, default True
                    If factors have to be scaled by the order
                    of the permutation group

    Returns
    -------
    symm_factos: ndarray list, symmetrized CPD factors
    """

    nsym = len(permdict) + 1
    nfactors = len(factors)

    if weights is not None:
        if len(weights) != nsym:
            raise ValueError('len(weights) != len(permdict)+1')
        weights = [pow(w, 1 / nfactors) for w in weights]
        adjust_scale = False
    else:
        weights = [1 for ii in range(len(factors))]

    if adjust_scale:
        scaling_factor = pow(1 / nsym, 1 / nfactors)
    else:
        scaling_factor = 1

    def ident(x):
        return x

    def neg(x):
        return -1 * x

    def conj(x):
        return np.conj(x)

    def make_scaler(weight):
        return lambda x: x * weight

    from functools import reduce

    n_factors = len(factors)

    new_factors = []
    for idx, factor in enumerate(factors):
        new_factor = factor * scaling_factor * weights[0]
        for (perm, operations), weight in zip(permdict.items(), weights[1:]):
            transforms = []
            for operation in operations:
                if operation == "ident":
                    transforms.append(ident)
                elif operation == "neg":
                    if n_factors % 2 == 0 and idx == 0:  # We don't want to negate.
                        transforms.append(ident)  # Even number of times.
                    else:
                        transforms.append(neg)
                elif operation == "conj":
                    transforms.append(conj)
                else:
                    raise ValueError(
                        "Unknown operation: {}".format(
                            operation))
            transforms.append(make_scaler(weight))

            new_factor = np.hstack(
                (new_factor,
                 scaling_factor *
                 reduce((lambda x, y: y(x)), transforms, factors[perm[idx]])))
        new_factors.append(new_factor)

    return new_factors

def ncpd_symmetrize(norm_factors, permdict, weights=None):
    """
    Produce a symmetric nCPD decompositions.
    :param norm_factors: norm and normalized CPD factors
    :param permdict: dictionary of tuple: tuple pairs.
                     keys are tuples containing the permutation
                     values are tuples of any of('ident', 'neg', 'conj')
                     Identity permutation has to be excluded(added internally)
    :param weights: list, default None
                    weights of the symmetry elements.

    Returns
    -------
    symm_norm_factos: ndarray list, symmetrized nCPD factors
    """

    lam = norm_factors[0]
    factors = norm_factors[1:]
    nsym = len(permdict) + 1

    if weights is not None:
        if len(weights) != nsym:
            raise ValueError("len(weights) != len(permdict)+1")
        scaling_factor = 1
    else:
        weights = [1 for item in range(nsym)]
        scaling_factor = 1 / nsym

    new_factors = cpd_symmetrize(factors, permdict, adjust_scale=False, weights=None)
    new_lam = scaling_factor * np.hstack(
        (lam * weight for weight in weights))

    return [new_lam, ] + new_factors

def unfold(tensor, mode=0):
    """Returns the mode-`mode` unfolding of `tensor`
    with modes starting at `0`.

    Parameters
    ----------
    tensor : ndarray
    mode : int, default is 0
           indexing starts at 0, therefore mode is in
           ``range(0, tensor.ndim)``. If -1 is passed, then
           `tensor` is flattened

    Returns
    -------
    ndarray
        unfold_tensor of shape ``(tensor.shape[mode], -1)``
    """

    if mode > -1:
        return np.moveaxis(tensor, mode, 0).reshape((tensor.shape[mode], -1))
    elif mode == -1:
        return tensor.reshape([1, -1])
    else:
        raise ValueError("Wrong mode: {}".format(mode))

def fold(unfolded_tensor, mode, shape):
    """Refolds the mode-`mode` unfolding into a tensor of shape `shape`

        In other words, refolds the n-mode unfolded tensor
        into the original tensor of the specified shape.

    Parameters
    ----------
    unfolded_tensor : ndarray
        unfolded tensor of shape
        ``(shape[mode], -1)``
    mode : int
        the mode of the unfolding
    shape : tuple
        shape of the original tensor before unfolding

    Returns
    -------
    ndarray
        folded_tensor of shape `shape`
    """

    if mode > -1:
        full_shape = list(shape)
        mode_dim = full_shape.pop(mode)
        full_shape.insert(0, mode_dim)
        return np.moveaxis(unfolded_tensor.reshape(full_shape), 0, mode)
    elif mode == -1:
        return unfolded_tensor.reshape(shape)
    else:
        raise ValueError("Wrong mode: {}".format(mode))

def als_contract_cpd(factors_top, tensor_cpd,
                     skip_factor, conjugate=False,
                     tensor_format='cpd'):
    """
    Performs the first part of the ALS step on an (already CPD decomposed)
    tensor, which is to contract "external" indices of the tensor with all
    CPD factors of the decompositions except of one, denoted by skip_factor
    :param factors_top: iterable with CPD decompositions
               of the top (left) tensor
    :param tensor_cpd: iterable with CPD decompositions
               of the bottom (right) tensor
    :param skip_factor: int
               skip the factor number skip_factor
    :param conjugate: bool, default: False
               conjugate the top (left) factors
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd') for both
               tensor_cpd and factors_top
    Returns
    -------
           matrix
    """

    if tensor_format == "cpd":
        contractor = cpd_contract_free_cpd
    elif tensor_format == "ncpd":
        contractor = ncpd_contract_free_ncpd
    else:
        raise ValueError("Unknown tensor_format: {}".format(tensor_format))

    s = contractor(factors_top, tensor_cpd, skip_factor=skip_factor, conjugate=conjugate)

    return np.dot(tensor_cpd[skip_factor], s.T)

def als_contract_dense(factors_top, tensor, skip_factor, conjugate=False, tensor_format="cpd"):
    """
    Performs the first part of the ALS step on a dense
    tensor, which is to contract "external" indices of the tensor with all
    nCPD factors of the decompositions except of one, denoted by skip_factor
    :param factors_top: iterable with CPD decompositions
               of the top (left) tensor
    :param tensor: tensor to contract with
    :param skip_factor: int
              skip the factor number skip_factor
    :param conjugate: bool, default: False
               conjugate the top (left) factors
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd')
    Returns
    -------
        matrix
    """

    if conjugate:
        factors_top = [factor.conjugate() for factor in factors_top]

    if tensor_format == "cpd":
        mode = skip_factor
    elif tensor_format == "ncpd":
        mode = skip_factor - 1
    else:
        raise ValueError("Unknown tensor_format: {}".format(tensor_format))

    return np.dot(unfold(tensor, mode=mode),
                  khatrirao(factors_top, skip_matrix=skip_factor))

def als_pseudo_inverse(factors_top, factors_bottom, skip_factor, conjugate=False, thresh=1e-10):
    """
    Calculates the pseudo inverse needed in the ALS algorithm.

    :param factors_top: iterable with CPD decompositions
               of the top (left) tensor
    :param factors_bottom: iterable with CPD decompositions
               of the bottom (right) tensor
    :param skip_factor: int
              skip the factor number skip_factor
    :param conjugate: bool, default: False
               conjugate the top (left) factors
    :param thresh: float, default: 1e-10
               threshold used to calculate pseudo inverse
    Returns
    -------
          matrix
    """

    rank1 = factors_top[0].shape[1]
    rank2 = factors_bottom[0].shape[1]

    if conjugate:
        factors_top = [factor.conjugate() for factor in factors_top]

    pseudo_inverse = np.ones((rank1, rank2))
    for ii, (factor1, factor2) in enumerate(zip(factors_top, factors_bottom)):
        if ii != skip_factor:
            pseudo_inverse *= np.dot(factor1.T, factor2)

    return np.linalg.pinv(pseudo_inverse, thresh)

def als_step_cpd(factors_top, tensor_cpd, skip_factor, conjugate=False, tensor_format='cpd'):
    """
    Performs one ALS update of the factor skip_factor
    for a CPD decomposed tensor
    :param factors_top: iterable with CPD decompositions
               of the top (left) tensor
    :param tensor_cpd: iterable with CPD decompositions
               of the bottom (right) tensor
    :param skip_factor: int
               skip the factor number skip_factor
    :param conjugate: bool, default: False
               conjugate the top (left) factors
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd')

    Returns
    -------
          matrix - updated factor skip_factor
    """

    r = als_contract_cpd(factors_top, tensor_cpd, skip_factor, conjugate=conjugate, tensor_format=tensor_format)
    s = als_pseudo_inverse(factors_top, factors_top, skip_factor, conjugate=conjugate, thresh=1e-10)

    return np.dot(r, s)

def als_step_dense(factors_top, tensor, skip_factor, conjugate=False, tensor_format='cpd'):
    """
    Performs one ALS update of the factor skip_factor
    for a full tensor
    :param factors_top: iterable with CPD decompositions
               of the top (left) tensor
    :param tensor: ndarray, tensor to decompose
    :param skip_factor: int
               skip the factor number skip_factor
    :param conjugate: bool, default: False
               conjugate CPD factors (needed for complex CPD)
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd')
    Returns
    -------
          matrix - updated factor skip_factor
    """

    r = als_contract_dense(factors_top, tensor, skip_factor, conjugate=conjugate, tensor_format=tensor_format)
    s = als_pseudo_inverse(factors_top, factors_top, skip_factor, conjugate=conjugate, thresh=1e-10)

    return np.dot(r, s)

def als_cpd(guess, tensor_cpd, complex_cpd=False, max_cycle=100, tensor_format='cpd'):
    """
    Run an ALS algorithm on the CPD decomposed tensor
    :param guess: iterable with initial guess for CPD decompositions
    :param tensor_cpd: iterable with CPD decompositions
                       of the target tensor
    :param complex_cpd: bool, default: False
               if complex decompositions is done
               (guess should also be complex, or this will not be enforced)
    :param max_cycle: maximal number of iterations
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd')

    Returns
    -------
    Iterable with CPD decompositions
    """

    factors = [factor for factor in guess]

    for iteration in range(max_cycle):
        for idx in range(len(factors)):
            factor = als_step_cpd(factors, tensor_cpd,
                                  skip_factor=idx,
                                  conjugate=complex_cpd,
                                  tensor_format=tensor_format)
            factors[idx] = factor

        if tensor_format == "ncpd":
            factors = list(ncpd_renormalize(factors, sort=False, positive_lam=True))

    return factors

def als_dense(guess, tensor, complex_cpd=False, max_cycle=100, tensor_format="cpd"):
    """
    Run an ALS algorithm on a dense tensor

    :param guess: iterable with initial guess for CPD decompositions
    :param tensor: ndarray, target tensor
    :param complex_cpd: bool, default: False
               if complex decompositions is done
               (guess should also be complex, or this will not be enforced)
    :param max_cycle: maximal number of iterations
    :param tensor_format: str, default 'cpd'
               Format of the decompositions ('cpd' or 'ncpd')

    Returns
    -------
    Iterable with CPD decompositions
    """
    factors = [factor for factor in guess]  # copy the guess

    for iteration in range(max_cycle):
        for idx in range(len(factors)):
            factor = als_step_dense(factors, tensor,
                                    skip_factor=idx,
                                    conjugate=complex_cpd,
                                    tensor_format=tensor_format)
            factors[idx] = factor
        if tensor_format == "ncpd":
            # Turning off sorting is important, otherwise no convergence
            # Normalization improves convergence of lam. Also, lams may become
            # negative if not forced positive at each iteration - not sure
            # what this means.
            factors = list(ncpd_renormalize(factors, sort=False, positive_lam=True))

    return factors

def _demonstration_symmetry_rank():
    """
    1. This function demonstrates that a symmetrized
    tensor has a rank which is larger than the
    rank of its unsymmetric part. If we set the rank of the
    unsymmetric part to R1, the errors in the CPD decompositions
    of the symmetrized tensor with a guess having rank R1 are not small,
    thus the rank of symmetrized tensor may be larger than
    the rank of the unsymmetric part.

    2. There is no difference between decomposing full tensor
    or its CPD decompositions, although there should be
    a large gain in speed for decomposed tensors.

    3. Symmetrized factors, which produce symmetrized tensor
    exactly, preserve all their weights during nCPD ALS if
    used as an inital guess. This means that ALS procedure
    does not break symmetry.
    However, a random initial guess can have different weights
    and yield an exact decompositions. This also shows that the form
    of CPD may not be unique if factors are not independent, as is
    in the case of symmetrized factors. Otherwise CPD is unique.

    4. The minimal rank of the symmetrized tensor may be smaller than
    the rank of its CPD done with symmetrized factors as an inital guess.
    For example, a symmetrized
    CPD can be rank 6 and yield the symmetrized tensor exactly, but
    there may exist an exact CPD of rank 4 of the same tensor.
    """

    # Initialize unsymmetric cpd, unsymmetric tensor and symmetric tensor.
    a = cpd_initialize([3, 3, 4], 3)
    t1 = cpd_rebuild(a)
    ts = 1 / 2 * (t1 - t1.transpose([1, 0, 2]))

    # Symmetrize cpd.
    k = cpd_symmetrize(a, {(1, 0, 2): ("neg",)})

    # Check symmetrized CPD yeilds symmetrized tensor.
    z0 = ts - cpd_rebuild(k)

    # Initialize unsymmetric ncpd and its symmetrized version.
    an = cpd_normalize(a, sort=True, merge_lam=True)
    kn = cpd_normalize(k, sort=True, merge_lam=True)

    # Check symmetrized ncpd yeilds symmetric tensor
    z1 = ts - ncpd_rebuild(kn)

    # Calculate cpd of the same tensor in dense and CPD forms
    # with original unsymmetric factors as inital guess.
    n = als_cpd(an, kn, max_cycle=10000, tensor_format="ncpd")
    m = als_dense(an, ts, max_cycle=10000, tensor_format="ncpd")

    # Check that the rank of symmetrized tensor may be bigger.
    z2 = ts - ncpd_rebuild(n)
    z3 = ts - ncpd_rebuild(m)

    # Check that ALS preserves weights.
    l = als_dense(kn, ts, max_cycle=10000, tensor_format="ncpd")
    z4 = ts - ncpd_rebuild(l)

    # Check that there may exist an unsymmetric tensor with smaller
    # rank which decomposes symmetric tensor.
    kp = ncpd_initialize([3, 3, 4], 5)
    o = als_dense(kp, ts, max_cycle=10000, tensor_format="ncpd")
    z5 = ts - ncpd_rebuild(o)

    # print("Symm tensor - symm CPD: {}".format(np.linalg.norm(z0.ravel())))
    # print("Symm tensor - symm nCPD: {}".format(np.linalg.norm(z1.ravel())))
    # print("Symm nCPD - optimized original nCPD: {}".format(np.linalg.norm(z2.ravel())))
    # print("Symm tensor - optimized original nCPD: {}".format(np.linalg.norm(z3.ravel())))
    # print("Symm tensor - optimized symm nCPD: {}".format(np.linalg.norm(z4.ravel())))
    # print("Symm tensor - optimized nCPD of lower rank: {}".format(np.linalg.norm(z5.ravel())))

def recompress_ncpd_tensor(tensor_ncpd, new_rank, max_cycle=100, return_fit=True, tensor_format="ncpd"):
    """
    Given a tensor in the nCPD format and a new rank, calculate the
    best nCPD approximation to the given tensor.

    :param tensor_ncpd: iterable with the tensor in the nCPD format
    :param new_rank: int, new value of the rank
    :param max_cycle: int, default 100, number of cycles to calculate
                      the new CPD decompositions
    :param return_fit: bool, default True, if the Frobenius norm of
                      the difference tensor is returned
    """

    sizes = None
    guess = None
    tensor_full = None
    tensor_full_new = None

    if tensor_format == "ncpd":
        sizes = [factor.shape[0] for factor in tensor_ncpd[1:]]
    elif tensor_format == "cpd":
        sizes = [factor.shape[0] for factor in tensor_ncpd[:]]

    is_complex = any([np.iscomplex(factor).any() for factor in tensor_ncpd])

    if tensor_format == "ncpd":
        guess = ncpd_initialize(sizes, new_rank)
    elif tensor_format == "cpd":
        guess = cpd_initialize(sizes, new_rank)

    new_tensor = als_cpd(guess, tensor_ncpd, complex_cpd=is_complex, max_cycle=max_cycle, tensor_format=tensor_format)
    result = new_tensor

    if return_fit:
        if tensor_format == "ncpd":
            tensor_full = ncpd_rebuild(tensor_ncpd)
            tensor_full_new = ncpd_rebuild(new_tensor)
        elif tensor_format == "cpd":
            tensor_full = cpd_rebuild(tensor_ncpd)
            tensor_full_new = cpd_rebuild(new_tensor)

        fit = np.linalg.norm((tensor_full - tensor_full_new).flatten()) / np.linalg.norm(tensor_full.flatten())
        result = (result, fit)

    return result


"""
Creates plots for SVD-MCMC section.
"""
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path

from uq4pk_src import model_grids
from ..plot_params import CW
from .parameters import TIMES, QLIST, ERRORS

# Use consistent style.
plt.style.use("src/uq4pk.mplstyle")

plot_name = "SVD.png"

def plot_svd_mcmc(src: Path, out: Path):
    """
    Creates figure A.1 in the paper (influence of latent dimension on SVD-MCMC).
    """
    fig = plt.figure(figsize=(CW, CW))
    ax_top = plt.subplot2grid(shape=(2, 2), loc=(0, 0), colspan=2)
    ax_left = plt.subplot2grid(shape=(2, 2), loc=(1, 0))
    ax_right = plt.subplot2grid(shape=(2, 2), loc=(1, 1))

    ssps = model_grids.MilesSSP(lmd_min=5000, lmd_max=5500)
    light_weighted_ssps = ssps.X / np.sum(ssps.X, 0)
    U, S, VT = np.linalg.svd(light_weighted_ssps)
    ax_top.semilogy(S)
    ax_top.axvline(15, ls=':', color='k')
    ax_top.set_xlabel('q')
    ax_top.set_ylabel('Singular value')
    ax_top.set_title('SVD of MILES templates')

    # First, get relevant data.
    q_list = QLIST
    times = np.load(str(src / TIMES))
    errors = np.load(str(src / ERRORS))
    # extract MC error
    mc_error = errors[-1]
    # Complement q_list
    q_list = np.append(q_list, [636])

    # If dimensions do not match, just make up q_list (this happens in test_mode).
    if q_list.size != times.size:
        print("WARNING: Size of q_list is wrong. Are you in test mode?")
        q_list = range(times.size)

    # First plot is error, measured in mean Jaccard distance.
    ax_left.semilogx(q_list, errors)
    ax_left.set_xlabel("q")
    ax_left.set_ylabel("Mean Jaccard distance")
    ymax = 1.1 * errors.max()
    ymax = max(ymax, mc_error)
    # Mark the q15-line.
    ax_left.axvline(15, ls=':', color='k')
    ax_left.text(18, 0.75, 'q=15', rotation=0, transform=ax_left.get_xaxis_text1_transform(0)[0], size="small")
    ax_left.set_ylim(0, ymax)

    # Second plot is times.
    ax_right.semilogx(q_list[:-1], times[:-1])
    ax_right.set_xlabel("q")
    ax_right.set_ylabel("Computation time [s]")
    # Enforce scientific notation on y-axis.
    ax_right.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
    # Horizontal line for computation time of full MCMC.
    ax_right.axhline(times[-1], ls="--", color="b", lw=1)
    ymax = 1.1 * times.max()
    ax_right.axvline(15, ls=':', color='k')
    ax_right.text(18, 0.75, 'q=15', rotation=0, transform=ax_right.get_xaxis_text1_transform(0)[0], size="small")
    ax_right.set_ylim(0, ymax)

    # Save figure.
    fig.tight_layout()
    fig.savefig(str(out / plot_name), bbox_inches="tight")


import pytest

from colortool import Color
from colortool import Gradient

@pytest.fixture
def gradient():
    _colors = [0x845EC2, 0xD65DB1, 0xFF6F91, 0xFF9671, 0xFFC75F, 0xF9F871]
    return Gradient([Color(c) for c in _colors])

@pytest.mark.parametrize(
    ('color', 'expected'), [
        (0.0, 0x845EC2),
        (0.2, 0xD65DB1),
        (0.4, 0xFF6F91),
        (0.6, 0xFF9671),
        (0.8, 0xFFC75F),
        (0.9, 0xFCDF68),
        (1.0, 0xF9F871),
    ],
)
def test_gradient(gradient, color, expected):
    assert gradient(color) == Color(expected)


"""
module that counts the words from tweets
"""

import re
import langid
import sqlite3
from collections import Counter
import tconfig
import sys

def fetch(config):
    """ function that fetches the tweets """
    conn = sqlite3.connect(config['dbclean'])
    cur = conn.cursor()
    cur.execute('SELECT text FROM Tweets')
    rows = cur.fetchall()
    return rows

def countwords(rows):
    """ function that puts all the tweets in one string and counts words """
    text = ''
    for row in rows:
        text += row[0]
    return Counter(text.split())

def write2js(counts):
    """ this function is made by dr Chuck """
    x = sorted(counts, key=counts.get, reverse=True)
    highest = None
    lowest = None
    for k in x[:100]:
        if highest is None or highest < counts[k] :
            highest = counts[k]
        if lowest is None or lowest > counts[k] :
            lowest = counts[k]
    print('Range of counts:',highest,lowest)

    # Spread the font sizes across 20-100 based on the count
    bigsize = 80
    smallsize = 20

    fhand = open('tword.js','w')
    fhand.write("tword = [")
    first = True
    for k in x[:100]:
        if not first: fhand.write( ",\n")
        first = False
        size = counts[k]
        size = (size - lowest) / float(highest - lowest)
        size = int((size * bigsize) + smallsize)
        fhand.write("{text: '"+k+"', size: "+str(size)+"}")
    fhand.write( "\n];\n")
    fhand.close()

def main():
    """ main function """
    config = tconfig.get_config()
    rows = fetch(config)
    counts = countwords(rows)
    write2js(counts)

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


from pygame.locals import *
import pygame
import random

class Snake():
    x = None
    y = None
    width = 20
    height = 20
    speed = 20
    direction = None
    head_color = (255, 0, 0)
    body_color = (180, 0, 0)

    #The following function block and the update function allow the snake to continue movement until another button is pressed.
    def move_right(self):
        self.direction = "right"
    def move_left(self):
        self.direction = "left"
    def move_up(self):
        self.direction = "up"
    def move_down(self):
        self.direction = "down"

    def update(self):
        if self.direction == "right":
            self.x += self.speed
        if self.direction == "left":
            self.x -= self.speed
        if self.direction == "up":
            self.y -= self.speed
        if self.direction == "down":
            self.y += self.speed

class Game():
    display_width = 1000
    display_height = 1000
    display_color = (0, 0, 0)
    window = pygame.display.set_mode((display_width, display_height))
    food_x = random.randrange(0, display_width, 20)
    food_y = random.randrange(0, display_height, 20)
    food_color = (0, 255, 0)
    food_points = 0
    snake = Snake()
    snake.x = display_width / 2
    snake.y = display_height / 2
    snake.body = []
    snake.body_length = 0
    running = True

    #When main() is called, this initializes required PyGame modules, draws the map, and draws the snake at its starting point.
    def setup(self):
        pygame.init()
        pygame.display.set_caption("Snake!")
        self.window.fill(self.display_color)
        pygame.draw.rect(self.window, (self.snake.head_color), (self.snake.x, self.snake.y, self.snake.width, self.snake.height))
        pygame.display.update()
        self.food_sound = pygame.mixer.Sound("Food.ogg")

    #This updates the screen to display the current location of all objects.
    def refresh(self, window):
        self.window.fill(self.display_color)

        for i in self.snake.body:
            for snake_x, snake_y in i.items():
                pygame.draw.rect(self.window, self.snake.body_color, (snake_x, snake_y, self.snake.width, self.snake.height))

        pygame.draw.rect(self.window, self.food_color, (self.food_x, self.food_y, self.snake.width, self.snake.height))
        pygame.draw.rect(self.window, self.snake.head_color, (self.snake.x, self.snake.y, self.snake.width, self.snake.height))

        pygame.display.update()

    #Generates a new random location for the food.
    def food_eaten(self):
        self.food_sound.play(0)
        self.food_x = random.randrange(0, self.display_width, 20)
        self.food_y = random.randrange(0, self.display_height, 20)
        self.food_points += 1

        #while self.food_x and self.food_y in self.
    #This needs to increase the length of the snake by 2 when food is eaten. This will be 2 elements inserted into a list, the elements will be the previous snake coordinates.
    def control_body(self):
        self.snake.body.insert(0, {self.snake.x: self.snake.y})

        while len(self.snake.body) > self.snake.body_length:
            del self.snake.body[self.snake.body_length]

    #This displays the game over text and resets snake direction and coordinates.
    #This also sets and plays the proper sound queues.
    def game_over(self):

        #The Following block sets up three different text overlays.
        self.window.fill(self.display_color)
        display_score_text = pygame.font.Font('pixel_font.ttf', 24).render(f"You scored {self.food_points} points and achieved a length of {len(self.snake.body) + 1} blocks!", False, (255, 0, 0))
        display_score_surface = display_score_text.get_rect()
        display_score_surface.center = (self.display_width / 2, 50)
        game_over_text = pygame.font.Font('pixel_font.ttf', 64).render("Game over!", False, (255, 0, 0))
        game_over_surface = game_over_text.get_rect()
        game_over_surface.center = (self.display_width / 2, (self.display_height / 2) - 25)
        play_again_text = pygame.font.Font('pixel_font.ttf', 32).render("Press Space to play again.", False, (255, 0, 0))
        play_again_surface = play_again_text.get_rect()
        play_again_surface.center = (self.display_width / 2, (self.display_height / 2) + 25)

        #If the player dies, plays the death sound and resets all neccesary variables to their default state.
        self.death_sound = pygame.mixer.music
        self.death_sound.load("Snake_death.ogg")
        self.death_sound.set_volume(1)
        self.death_sound.play(0)
        self.snake.y = self.display_height / 2
        self.snake.x = self.display_width / 2
        self.food_points = 0
        self.snake.body = []
        self.snake.body_length = 0
        self.snake.direction = None
        self.play_again = False

        self.window.blits(blit_sequence=((display_score_text, display_score_surface), (game_over_text, game_over_surface), (play_again_text, play_again_surface)))
        pygame.display.update()

        while not self.play_again:
            pygame.time.delay(100)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()

                if event.type == pygame.KEYDOWN and event.key ==  pygame.K_SPACE:
                    self.play_again = True

    #This contains the core functionality of the game, including the main game loop. Pressing Escape or the Exit button will close the PyGame window.
    def main(self):
        self.setup()
        keys = pygame.key.get_pressed()

        while self.running:
            #This causes the player to lose if they go out of bounds.

            #Game now restarts when space button is pressed, need to add text informing the player.
            if self.snake.x >= self.display_width or self.snake.x < 0 or self.snake.y >= self.display_width or self.snake.y < 0:
                self.game_over()

            for index in self.snake.body:
                for snake_x, snake_y in index.items():
                    if self.snake.x == snake_x and self.snake.y == snake_y:
                        self.game_over()

            #The following code closes the game of the X button is clicked and controls movements for the snake when the arrow keys are pressed.
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False
                    pygame.quit()

                #Determines which direction key is pressed. If the player is not traveling in the opposite direction, moves the player in the direction that the key indicates.
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT and self.snake.direction != "left":
                        self.snake.move_right()
                    if event.key == pygame.K_LEFT and self.snake.direction != "right":
                        self.snake.move_left()
                    if event.key == pygame.K_UP and self.snake.direction != "down":
                        self.snake.move_up()
                    if event.key == pygame.K_DOWN and self.snake.direction != "up":
                        self.snake.move_down()

                    if event.key == pygame.K_ESCAPE:
                        self.running = False

            #If the player eats the food, this will increase the snake's length.
            if self.snake.x == self.food_x and self.snake.y == self.food_y:
                self.snake.body_length += 3
                self.food_eaten()

            self.control_body()
            self.snake.update()
            self.refresh(self.window)
            pygame.time.delay(75)

        pygame.quit()

play_game = Game()
play_game.main()

'''
Chomp sound takes too long to activate.

During play, add a counter to the top to display the score of the player.

Player should not be able to reverse direction into themselves and cause an instant loss, this can still occer if directions are changed very quickly.

Experiment with making the background into a grid and the try giving the snake blocks a thin black outline.
'''


import unittest
from unittest import TestCase
import os
import sys

d = os.path.dirname
ubbr_location = d(d(d(d(d((os.path.abspath(__file__)))))))
print(ubbr_location)
sys.path.append(ubbr_location)

from ubbr.engine.core import Ubbr
from ubbr.engine.graders.graders import StringInputGrader, IntegerInputGrader, DecimalInputGrader, ExpressionInputGrader

import json

class UbbrTest(TestCase):

    def setUp(self):
        fixtures_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),'fixtures')
        with open(os.path.join(fixtures_path,'testcases.json')) as tc_file:
            self.testcases = json.load(tc_file)

    def test_string_grader(self):
        cases = [case for case in self.testcases if case['test']=='string_grader']
        for tc in cases:
            u = Ubbr(tc['source'])
            data = u.get_context()[1]
            for r in data:
                grader = StringInputGrader()
                for answer in tc['correct']:
                    self.assertEqual(grader.grade(answer,r)['score'],grader.grade(answer,r)['max_score'])
                for answer in tc['incorrect']:
                    self.assertEqual(grader.grade(answer,r)['score'],int(0))

    def test_integer_grader(self):
        cases = [case for case in self.testcases if case['test']=='integer_grader']
        for tc in cases:
            u = Ubbr(tc['source'])
            data = u.get_context()[1]
            for r in data:
                grader = IntegerInputGrader()
                for answer in tc['correct']:
                    self.assertEqual(grader.grade(answer,r)['score'],grader.grade(answer,r)['max_score'])
                for answer in tc['incorrect']:
                    self.assertEqual(grader.grade(answer,r)['score'],int(0))

    def est_decimal_input_precision(self):
        tcs = [c  for c in self.testcases if c['test']=='DecimalInput Precision']
        for case in tcs:
            u = Ubbr(case['source'])
            data = u.get_context()[1]
            for r in data:
                grader = DecimalInputGrader()
                for answer in case['correct']:
                    self.assertEqual(grader.grade(answer,r)['score'],grader.grade(answer,r)['max_score'])
                for answer in case['incorrect']:
                    self.assertEqual(grader.grade(answer,r)['score'],int(0))

    def est_sage_expression_input(self):
        tcs = [c  for c in self.testcases if c['test']=='ExpressionInput']
        for case in tcs:
            u = Ubbr(case['source'])
            data = u.get_context()[1]
            for r in data:
                grader = ExpressionInputGrader()
                for answer in case['correct']:
                    print(r)
                    print(answer)
                    self.assertEqual(grader.grade(answer,r)['score'],grader.grade(answer,r)['max_score'])
                for answer in case['incorrect']:
                    print(answer)
                    self.assertEqual(grader.grade(answer,r)['score'],int(0))

    def test_sage_expression_input_grader(self):
        tcs = [c  for c in self.testcases if c['test']=='ExpressionInputGrader']
        for case in tcs:
            data = case['data']
            grader = ExpressionInputGrader()
            for answer in case['correct']:
                print(data)
                print(answer)
                self.assertEqual(grader.grade(answer,data)['score'],grader.grade(answer,data)['max_score'])
            for answer in case['incorrect']:
                print(answer)
                self.assertEqual(grader.grade(answer,data)['score'],int(0))

if __name__=="__main__":
    unittest.main()


from __future__ import division
from configparser import ConfigParser
import argparse
from model import AELikeModel
from preprocessing import split_train

def main(args):
    # parser config
    # see train.cfg for parameters

    cp = ConfigParser()
    cp.read(args.train)
    cp.read(args.augmentation)
    cp.read(args.test)
    image_size = cp["TRAIN"].getint("image_size")
    alpha = cp["TRAIN"].getfloat("alpha")

    # takes unified x at "source folder", y "target folder" and splits into training/ testing batches at "split output dir/test /train"
    if split:

        split_train(cp["SPLIT"].get("source_folder"), cp["SPLIT"].get("target_folder"), cp["SPLIT"].get("split_output_dir") )

    if train:
        cp.read(args.train)
        x_train_folder= cp["TRAIN"].get("source_folder")
        y_train_folder = cp["TRAIN"].get("target_folder")

        # use_trained_model = cp["TRAIN"].getboolean("use_trained_model")
        epochs = cp["TRAIN"].getint("epochs")
        train_steps = cp["TRAIN"].getint("train_steps")
        learning_rate = cp["TRAIN"].getfloat("learning_rate")
        epochs_to_reduce_lr = cp["TRAIN"].getint("epochs_to_reduce_lr")
        reduce_lr = cp["TRAIN"].getfloat("reduce_lr")
        output_model = cp["TRAIN"].get("output_model")
        output_log = cp["TRAIN"].get("output_log")
        batch_size = cp["TRAIN"].getint("batch_size")
        verbose = cp["TRAIN"].getboolean("verbose")

        model = AELikeModel(image_size, alpha, AE = True, verbose=True, trained_model = None)
        model.train(x_train_folder, y_train_folder, epochs, train_steps, learning_rate, epochs_to_reduce_lr, reduce_lr, output_model, output_log, batch_size)

        # loads previously trained model
        # AE = True uses Autoencoder architecuture
    elif test:
        cp.read(args.test)
        ModelPath = cp["TEST"].get("output_model")
        model = AELikeModel(image_size, alpha, AE = True, verbose=True, trained_model = ModelPath)

    if test:
        x_test_folder = cp["TEST"].get("source_folder")
        y_test_folder = cp["TEST"].get("target_folder")
        cp.read(args.test)
        print(y_test_folder)
        results = model.test(x_test_folder,y_test_folder,y_test_folder+"/results/")
        print("Mean Squared Error"+ str(results["MSE"]))
        # print("Average SSIM",results["SSIM"])
        # print("combined", results["cost"])

    # Parse arguments

    # # Training
    # trained_model = None
    # if use_trained_model:
    #     trained_model = cp["TRAIN"].get("trained_model")
    # print('into the model')
    # model = AELikeModel(image_size, alpha, AE = False, verbose, trained_model)
    # model.train(source_folder, target_folder, epochs, train_steps, learning_rate, epochs_to_reduce_lr, reduce_lr, output_model, output_log, batch_size)

if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='Bone Suppression Testing')

    split = False
    augment = False
    train = False
    test = True

    parser.add_argument('--train', default='config/train.cfg', type=str, help='train config file')
    parser.add_argument('--augmentation', default='config/data_preprocessing.cfg', type=str, help='augment config file')
    parser.add_argument('--test', default='config/test.cfg', type=str, help='test config file')

    # if  split:

    #     parser.add_argument('--train', default='config/train.cfg', type=str, help='train config file')

    # if augment:
    #     parser = argparse.ArgumentParser(description='bakerco - BoneSuppression v1 - Training')
    #     parser.add_argument('--augmentation', default='config/data_preprocessing.cfg', type=str, help='augment config file')

    # if train:
    #     parser = argparse.ArgumentParser(description='bakerco - BoneSuppression v1 - Training')
    #     parser.add_argument('--train', default='config/train.cfg', type=str, help='train config file')

    # if test:
    #     parser = argparse.ArgumentParser(description='bakerco - BoneSuppression v1 - Training')
    #     parser.add_argument('--test', default='config/test.cfg', type=str, help='test config file')

    args = parser.parse_args()
    main(args)


import base64
import json
from odoo import fields, models
from datetime import datetime, timedelta, date

class AuthToken(models.Model):
  _name = "auth.token"
  _description = "JWT auth token"

  user_id = fields.Many2one(string="Utilisateur", comodel_name="res.users")
  token = fields.Text(string="Token")

  _sql_constraints = [
        ('unique_id_user', 'unique(user_id)', 'This id_user is already in used.'),
    ]

  @staticmethod
  def decode(input):
    return json.loads(base64.urlsafe_b64decode(input+'==').decode('utf-8').replace('=',''))

  @staticmethod
  def encode(input):
    stringAsBytes = input.encode('ascii')
    stringAsBase64 = base64.urlsafe_b64encode(stringAsBytes).decode('utf-8').replace('=','')
    return stringAsBase64

  @staticmethod
  def jwt_creator(user_id, uid, session_id):
    payload = {"expired": (datetime.now() + timedelta(days=15)).strftime("%d-%m-%y"), "user_id": user_id, "uid": uid, "session_id": session_id}
    return str(AuthToken.encode(json.dumps(payload)))

  def has_expired(self):
    for token in self:
      return datetime.strptime(AuthToken.decode(token.token)["expired"], "%d-%m-%y").date() < date.today()

  def to_map(self):
    for token in self:
      return {
        "id": token.id,
        "user_id": token.user_id.id,
        "token": token.token,
      }


import json

class Processor:

    def __init__(self, records):
        """
        (1) No need for duplication (data, loaded)
        """
        self.records = records

    def filter_by_key(self, key):
        """
        (2) A basic filter by key.
        (3) Can reuse already set records
        (4) Make it clearer, that we check for existence (a set would be even clearer, but may distort the output)
        """
        result = []
        for record in self.records:
            if any(key in record for record in result):
                continue
            result.append(record)
        return result

    def run(self):
        for record in self.filter_by_key('a'):
            print(record)

# (5) Loading becomes a bit more independent (could be from any format).
data = '[{"a": 1}, {"b": 2}, {"c": 3}, {"a": 4}, {"b": 5}]'
records = json.loads(data)
processor = Processor(records=records)
for record in processor.filter_by_key('a'):
    print(record)


import os
import sys
import WebScraper
from Indexer import process_query
import PySimpleGUI as sg
import Indexer
from Indexer import data_point
from Indexer import inverted_index
from PIL import Image
import io
import requests
import WebScraper

processing = False
file_types = [("JPEG (*.jpg)", "*.jpg"),
              ("All files (*.*)", "*.*")]
query_str = ""

def make_display():
    global processing, file_types, query_str
    sg.theme('DarkAmber')
    rlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    layout = [[sg.Text("Enter Query")],
              [sg.Input(key="Query")],
              [sg.Text("Filter Options")],
              [sg.Checkbox('Single player', key='Single player')], [sg.Checkbox('Online', key='Online')],
              [sg.Listbox(rlist, key='Show', visible=False, enable_events=True)],
              [sg.Button('Submit')],
              [sg.Multiline("No query being processed yet", key='Process', enable_events=True)]]

    window = sg.Window('Window that stays open', layout)

    while not processing:  # The Event Loop
        event, values = window.read()
        if event == sg.WIN_CLOSED or event == 'Exit':
            break
        elif event == 'Submit':
            if not processing:
                print("returned values are : ", values)
                processing = True
                window['Process'].update('Processing query')
                query_string = values['Query']
                if values['Single player']:
                    query_string += " Singleplayer"
                if values['Online']:
                    query_string += " Online"
                print("Query is : ", query_string)
                query_str = query_string
                break
        elif event == 'Show':
            processing = False
            print(values['Show'])

    window.close()

def show_result_fail():
    sg.theme('DarkAmber')
    layout = [[sg.Text("The query entered did not make any sense, please try again")]]
    window1 = sg.Window('Window that shows that no result was obtained', layout)
    while True:
        event, values = window1.read()
        if event == sg.WIN_CLOSED or event == 'Exit':
            break
    window1.close()

def show_result_success():
    print("Success")

def Reset_Processing_State():
    global processing
    processing = False

def show_Correct_Response(url):
    index = 0
    current_process = False
    elements = [
        [sg.Image(key="-IMAGE-")],
        [sg.Multiline("Image url", key='url', enable_events=True)],
        [sg.Multiline("Reviews", key='review', enable_events=True)],
        [sg.Multiline("Price", key='price', enable_events=True)],
        [sg.Button('load Data')],
        [sg.Button('next')],
        [sg.Button('previous')],
        [sg.Multiline("Description yet to be loaded", key='desc', enable_events=True)]
    ]
    window = sg.Window("Image Viewer", elements)
    while True:
        event, values = window.read()
        if event == "Exit" or event == sg.WIN_CLOSED:
            break
        if event == "load Data" or "next" or "previous":
            if not current_process:
                current_process = True
                if event == "next":
                    if index < len(url) - 1:
                        index += 1
                    else:
                        index = 0
                if event == "previous":
                    if index == 0:
                        index = len(url) - 1
                    else:
                        index -= 1
                img_url = WebScraper.get_image(url[index])
                curr_url = url[index]
                window['url'].update(curr_url)
                desc = WebScraper.get_description(url[index])
                window['desc'].update(desc)
                review = WebScraper.get_review_status(url[index])
                window['review'].update(review)
                item_price = WebScraper.get_price(url[index])
                window['price'].update(item_price)
                image = Image.open(requests.get(img_url, stream=True).raw)
                image.thumbnail((400, 400))
                bio = io.BytesIO()
                image.save(bio, format="PNG")
                window["-IMAGE-"].update(data=bio.getvalue())
                current_process = False
    window.close()

if __name__ == '__main__':
    # get_image('https://store.steampowered.com/app/1097150/Fall_Guys_Ultimate_Knockout/?snr=1_7_7_230_150_1')
    response_list = []
    while not processing:
        make_display()
        print("Query string is : ", query_str)
        if query_str:
            response_list = Indexer.process_query_reduced(query_str, True)
            show_Correct_Response(response_list)
        elif query_str is None:
            show_result_fail()
        if len(response_list) == 0:
            show_result_fail()
        Reset_Processing_State()


from flask import Flask, render_template, request, redirect, url_for, flash,jsonify
import os
from os.path import join, dirname, realpath
import pickle
import pandas as pd
#from sklearn.externals import joblib
import joblib

app = Flask(__name__)
#model = pickle.load(open('SG_finalized_model.pkl', 'rb'))

# enable debugging mode
app.config["DEBUG"] = True

# Upload folder
#UPLOAD_FOLDER = 'static/files'
UPLOAD_FOLDER = 'static/files'
app.config['UPLOAD_FOLDER'] =  UPLOAD_FOLDER

# Root URL
@app.route('/')
def index():
     # Set The upload HTML template '\templates\index.html'
    return render_template('index.html')

# Get the uploaded files
# @app.route("/", methods=['post'])
def uploadfiles():
      # get the uploaded file
      uploaded_file = request.files['file']
      if uploaded_file.filename != '':
           file_path = os.path.join(app.config['UPLOAD_FOLDER'], uploaded_file.filename)
          # set the file path
           uploaded_file.save(file_path)
          # save the file
      return redirect(url_for('index'))

#@app.route("/", methods=['post'])
@app.route('/',methods=['POST'])
def predict():
    #a = uploadfiles()
    # get the uploaded file
    # uploaded_file = request.files['file']
    # if uploaded_file.filename != '':
    #     file_path = os.path.join(app.config['UPLOAD_FOLDER'], uploaded_file.filename)
    #     # set the file path
    #     uploaded_file.save(file_path)
    # #return redirect(url_for('index'))
    uploaded_file = request.files['file']
    if uploaded_file.filename != '':
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], uploaded_file.filename)
        uploaded_file.save(file_path)

    os.chdir("static/files")
    filename = 'vikas_model.pkl'
    RFE_columns = pd.read_csv('RFE_features_1.csv').columns
    # load the model from disk
    loaded_model = pickle.load(open(filename, 'rb'))
    #
    # Load the test set
    df_test = pd.read_csv('sample.csv')

    ## just take the required columns requied for predicting on it

    RFE_columns = [col for col in RFE_columns if col not in 'QuoteConversion_Flag']  # Test wont have the label column
    df_test = df_test[RFE_columns]
    df_test.drop(columns=['Original_Quote_Date', 'SalesField8'], axis=1, inplace=True)

    # Predict on it using the GBM2 pipeline . Here pipe line has made a task easy as we do not have to store features
    #    y_test = GBM2.predict_proba(df_test)
    y_test = loaded_model.predict_proba(df_test)

    print(y_test)
    print(y_test[:, 1])

    output = round(y_test[:, 1][0], 0)
    print(output)

    #clf = joblib.load('SG_finalized_model.pkl')

    if output>0.5:
        prediction = "Positive"
    else:
        prediction = "Negative"

    return jsonify({'prediction': prediction})
    return redirect(url_for('index'))

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