#!/usr/bin/python3

import argparse
import logging
import os
from pathlib import Path
import re
import shutil
import sys

def is_correct_directory(directory_path):
    """
        Returns True if directory exists else False
    """

    return os.path.isdir(directory_path)

def get_file_extension(filename):
    """
        Returns the extension of the file
    """

    _, file_extension = os.path.splitext(filename)

    return file_extension

def create_root_directory(root_path):
    """
        Creates a root directory for the movie
        if it doesnt exists
    """
    try:
        os.makedirs(root_path)
    except FileExistsError as ex:
        print(f"Folder already exists in {root_path}")

def sanitize_name(name, year_pattern, quality_pattern):
    """
        Returns a sanitized name that will convert this type of names
            28.Weeks.Later.2007.1080p.BluRay.x264-CiNEFiLE
            Absolutely.Anything.2015.1080p.BluRay.x265-RARBG
            2001 A Space Odyssey (1968) [BluRay] [1080p] [YTS.AM]
        into
            28 Weeks Later (2007) [1080p]
            Absolutely Anything (2015) [1080p]
            2001 A Space Odyssey (1968) [1080p]

    regex -- r"(\(?19[0-9]{2}\)?|\(?20[0-9]{2}\)?)"
    """

    movie_name_sanitized = ""
    movie_year = ""
    movie_quality = ""
    common_separators = ['.', '_'] # NOTE - Update this list if the pattern changes

    # Find the movie year with regular expressions
    year_pattern = re.compile(year_pattern)
    movie_year = year_pattern.findall(name)

    if len(movie_year) > 0:
        movie_name_sanitized = name.split(movie_year[-1])[0].strip() # -1 will always take the last item, if only one item, it will take that
        movie_year = movie_year[-1]
        movie_year = movie_year.replace("(", "").replace(")", "")
        movie_year = f" ({movie_year.strip()})" # In case there is only one parenthesis

    # Find the movie quality with regular expressions
    quality_pattern = re.compile(quality_pattern)
    movie_quality_found = quality_pattern.search(name)
    if movie_quality_found:
        movie_quality = movie_quality_found.group(0)
        movie_quality = movie_quality.replace("[", "").replace("]", "")
        movie_quality = f" [{movie_quality.strip()}]"

    # Replace common separators like ['.', '_'] with space, only if it has more than 3 of them
    for separator in common_separators:
        if name.count(separator) > 3:
            # print(f"Found more {separator}")
            movie_name_sanitized = movie_name_sanitized.replace(separator, " ")
            # print(f"Movie sanitized {movie_name_sanitized}")

    return f"{movie_name_sanitized.title()}{movie_year}{movie_quality}"

def remove_rubbish(directory_path, approved_extensions=['.mkv', '.avi', '.mp4']):
    """
        Loops through directories/subdirectories recursively, removing empty directories
        and files that are not video files
    """

    size_cleaned = 0
    video_files = []

    # Get the list of directories in current working directory
    directory_list = [direct for direct in os.listdir(directory_path) if os.path.isdir(os.path.join(directory_path, direct))]

    # Get the list of files in current working directory
    file_list = [file for file in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, file))]

    for file in file_list:
        if get_file_extension(file) not in approved_extensions:
            logging.debug(f'File to remove {os.path.join(directory_path, file)}')
            size_cleaned += Path(os.path.join(directory_path, file)).stat().st_size
            os.remove(os.path.join(directory_path, file))
            # print(f"Removing {os.path.join(directory_path, file)}")

    if len(directory_list) > 0:
        for directory in directory_list:
            if len(os.listdir(os.path.join(directory_path, directory))) == 0:
                logging.debug(f'Directory to remove {os.path.join(directory_path, directory)}')
                os.removedirs(os.path.join(directory_path, directory))
                # print(f"Removing {os.path.join(directory_path, directory)}")

            else: # If directory is not empty, do recursive
                remove_rubbish(os.path.join(directory_path, directory))
    else:
        if len(os.listdir(directory_path)) == 0:
            logging.debug(f'Directory to remove {directory_path}')
            # Remove empty directory
            os.removedirs(directory_path)
            # print(f"Removing {directory_path}")

    return size_cleaned

def main():

    # Setting up logging
    # If you standalone file replace strea=sys.stdout with filename='filename.txt'
    logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s',
                        stream=sys.stdout,
                        level=logging.DEBUG,
                        datefmt='%Y-%m-%d %H:%M:%S')

    # Setting up the argument parser
    parser = argparse.ArgumentParser(description='Process configuration needed')
    parser.add_argument('path', help='Path to the folder', type=str, metavar='path')
    args = parser.parse_args()

    approved_extensions = ['.mkv', '.mp4', '.avi']

    if is_correct_directory(args.path):

        # filter those that are stand alone files
        standalone_movies = [movie for movie in os.listdir(args.path) if movie[-4:] in approved_extensions]
        movie_folder_list = [movie for movie in os.listdir(args.path) if is_correct_directory(os.path.join(args.path, movie))]

    else:
        logging.error(f"Incorrect path {args.path}")
        # print(f"Incorrect path {args.path}")
        exit()

    for standalone_movie in standalone_movies:
        sanitized_name = sanitize_name(standalone_movie,
                                        year_pattern=r"(\(?19[0-9]{2}\)?|\(?20[0-9]{2}\)?)",
                                        quality_pattern=r"(\[?[0-9]+p\]?)")

        create_root_directory(os.path.join(args.path, sanitized_name))

        file_extension = get_file_extension(standalone_movie)
        shutil.move(os.path.join(args.path, standalone_movie), os.path.join(args.path, sanitized_name ,sanitized_name+file_extension))

    for movie in movie_folder_list:
        video_files = []

        for root, dirs, files in os.walk(os.path.join(args.path, movie)):

            for f in files:
                file_extension = get_file_extension(f)
                if file_extension in approved_extensions:
                    video_files.append({
                        "file_name": f,
                        "file_path": os.path.join(root, f),
                        "file_extension": file_extension,
                        "file_size": Path(os.path.join(root, f)).stat().st_size
                        })

        logging.debug(f'Video files found in {movie} #{len(video_files)}')

        sanitized_name = sanitize_name(movie,
                                        year_pattern=r"(\(?19[0-9]{2}\)?|\(?20[0-9]{2}\)?)",
                                        quality_pattern=r"(\[?[0-9]+p\]?)") # Sanitize from Movie folder not video file

        if len(video_files) == 1:

            # print(f"Sanitized name is {sanitized_name}")
            # Rename movie file
            shutil.move(video_files[0]['file_path'], os.path.join(args.path, movie, sanitized_name+video_files[0]['file_extension']))
            # Rename root folder
            shutil.move(os.path.join(args.path, movie), os.path.join(args.path, sanitized_name))

        elif len(video_files) > 1:
            # print("More than 1 video file, checking sizes...")
            video_files.sort(reverse=True, key=lambda video:video['file_size'])
            logging.debug(f'Video files sorted  {video_files}')

            for file_sorted in video_files[1:]:
                logging.debug(f"Removing {file_sorted['file_path']}")
                os.remove(file_sorted['file_path'])

            # Rename movie file
            shutil.move(video_files[0]['file_path'], os.path.join(args.path, movie, sanitized_name+video_files[0]['file_extension']))
            # Rename root folder
            shutil.move(os.path.join(args.path, movie), os.path.join(args.path, sanitized_name))

        remove_rubbish(args.path)

if __name__ == "__main__":
    main()


import sys
import os
import pystache

class Template(object):

    """docstring for Template"""

    def __init__(self, path_template, header, doc, offset=0):
        super(Template, self).__init__()
        if path_template is None:
            path_template = os.path.join(
                sys.path[0], "template", "default_template.html")
        with open(path_template, "r") as template:
            template = template.read()

        renderer = pystache.Renderer()
        self.html = renderer.render(
            template, {"offset": offset, "header": header, "doc": doc})

    def get_html(self):
        return self.html


#!/usr/bin/env python3

import glob
import pdb
import sys
import numpy as np
from statsmodels.stats.contingency_tables import mcnemar

dev = glob.glob(sys.argv[1] + '/*')
sys1 = glob.glob(sys.argv[2] + '/*')
sys2 = glob.glob(sys.argv[3] + '/*')

corrects = []

for f in dev:
    ifile = open(f + '/dev.tsv', 'r')
    lines = ifile.readlines()
    for line in lines:
        line = line.strip().split('\t')
        corr = line[-1]
        if corr != 'label':
            corrects.append(corr)
    ifile.close()

preds1 = []
preds2 = []

for f1, f2 in zip(sys1, sys2):
    ofile1 = open(f1 + '/scores.txt', 'r')
    ofile2 = open(f2 + '/scores.txt', 'r')
    for line1, line2 in zip(ofile1, ofile2):
        # try:
        line1 = line1.strip()
        line1 = line1.split('\t')
        # assert(len(line1) == 2)
        line2 = line2.strip()
        line2 = line2.split('\t')
        # assert(len(line2) == 2)
        if len(line1) > 1 and len(line2) > 1:
            pred1 = line1[1]
            score1 = line1[0]
            preds1.append(pred1)

            pred2 = line2[1]
            score2 = line2[0]
            preds2.append(pred2)
            # except:
                # continue

    ofile1.close()
    ofile2.close()

def correct(system, gold):
    correct = 0
    total = 0
    for l1, l2 in zip(system, gold):
        total += 1
        if l1 == l2:
            correct += 1
    # print("Acc:", correct / total)
    return correct / total

# pdb.set_trace()
print(sys.argv[2] + " acc:", correct(preds1, corrects))
print(sys.argv[3] + " acc:", correct(preds2, corrects))

bothright = 0
YesNo = 0
NoYes = 0
bothwrong = 0
for c1, c2, gold in zip(preds1, preds2, corrects):
    if c1 == gold and c2 == gold:
        bothright += 1
    elif c1 == gold and c2 != gold:
        YesNo += 1
    elif c1 != gold and c2 == gold:
        NoYes += 1
    elif c1 != gold and c2 != gold:
        bothwrong += 1
    else:
        print("Error")
        pdb.set_trace()

print("statsmodels", mcnemar(np.array([[bothright, YesNo], [NoYes, bothwrong]])))
print("statsmodels exact false", mcnemar(np.array([[bothright, YesNo], [NoYes, bothwrong]]), exact=False))
print("statsmodels correction false", mcnemar(np.array([[bothright, YesNo], [NoYes, bothwrong]]), correction=False))
print("statsmodels exact false correction false", mcnemar(np.array([[bothright, YesNo], [NoYes, bothwrong]]), exact=False, correction=False))


"""Main entry point

We setup a custom subclass to interface with the Pi camera better, and then
start it just like the docs.
"""
import asyncio
import logging
import os
import signal
import subprocess

from pyhap.accessory_driver import AccessoryDriver
from pyhap import camera

logging.basicConfig(level=logging.INFO, format="[%(module)s] %(message)s")
logger = logging.getLogger('main')

STREAM_CMD = (
    # Use raspivid, as it can take advantage of the Pi's h264 encoding hardware
    "raspivid -n " # No preview
    "-ih " # Insert PPS, SPS headers - needed for FFMPEG
    "-t 0 " # run forever
    "-ex auto " # auto expose
    "-drc med " # do some dynamic range compression
    "-w {width} -h {height} -fps {fps} " # set width, height, fps
    "-lev 4 -pf {profile} -b {v_max_bitrate} " # setup the h.264 parameters
    "-o - " # Dump to stdout
    # ffmpeg, does all the hairy STRP stuff
    "| ffmpeg -re -i - -c:v copy "
    "-payload_type 99 -ssrc {v_ssrc} -f rtp "
    "-srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params {v_srtp_key} "
    "'srtp://{address}:{v_port}?rtcpport={v_port}&"
    "localrtcpport={v_port}&pkt_size=1378'"
)
'''Template for the command.'''

class PiCamera(camera.Camera):
    """A camera that implements the capture function"""
    def __init__(self, *args, **kwargs):
        super(PiCamera, self).__init__(*args, **kwargs)
        self.logger = logging.getLogger('PiCamera')

    def get_snapshot(self, image_size):
        """Use the raspistill command to capture a snapshot.
        """
        cmd = ["raspistill",
                "-n", # No preview
                "-t", "200", # 200 milliseconds to warm up
                "-ex", "auto", # auto exposure
                "-mm", "average", # metering mode, average
                "-drc", "med", # do some dynamic range compression
                "-w", str(image_size["image-width"]), # width
                "-h", str(image_size["image-height"]), # height
                "-o", "-"] # output to stdout
        self.logger.debug("Executing image capture command: %s", ' '.join(cmd))
        raspistill = subprocess.run(cmd, capture_output=True) # ensure we grab stdout
        output = raspistill.stderr.decode('utf-8').strip()
        if output:
            self.logger.error("Error in still output: %s", output)
        return raspistill.stdout

    async def start_stream(self, session_info, stream_config):
        """Start the stream.

        Overriding this is necessary beecuse we use a shell to pipe data between
        raspivid and ffmpeg, which means we need a process group and
        create_process_shell instead of create_process_exec
        """
        stream_config['v_max_bitrate'] *= 1000 # kbps to bps conversion
        stream_config['profile'] = ('baseline', 'main', 'high')[ord(stream_config['v_profile_id'])]

        self.logger.debug('[%s] Starting stream with the following parameters: %s',
                      session_info['id'], stream_config)

        cmd = self.start_stream_cmd.format(**stream_config)
        self.logger.debug('Executing start stream command: "%s"', cmd)
        try:
            process = await asyncio.create_subprocess_shell(cmd,
                    stdout=asyncio.subprocess.DEVNULL,
                    stderr=asyncio.subprocess.PIPE,
                    limit=1024,
                    start_new_session=True)
        except Exception as e:
            self.logger.error('Failed to start streaming process because of error: %s', e)
            return False

        session_info['process'] = process

        self.logger.info('[%s] Started stream process - PID %d',
                     session_info['id'], process.pid)

        return True

    async def stop_stream(self, session_info):  # pylint: disable=no-self-use
        """Stop the stream for the given ``session_id``.

        We implement this because we need to stop the whole process group, not
        just one process.
        """
        session_id = session_info['id']
        ffmpeg_process = session_info.get('process')
        if ffmpeg_process:
            pgid = os.getpgid(ffmpeg_process.pid)
            self.logger.info('[%s] Stopping stream.', session_id)
            try:
                os.killpg(pgid, signal.SIGTERM)
                _, stderr = await asyncio.wait_for(
                    ffmpeg_process.communicate(), timeout=2.0)
                self.logger.debug('Stream command stderr: %s', stderr.decode('utf-8'))
            except asyncio.TimeoutError:
                self.logger.error('Timeout while waiting for the stream process '
                                  'to terminate. Trying with kill.')
                os.killpg(pgid, signal.SIGKILL)
                await ffmpeg_process.wait()
            self.logger.debug('Stream process stopped.')
        else:
            self.logger.warning('No process for session ID %s', session_id)

# Specify the audio and video configuration that your device can support
# The HAP client will choose from these when negotiating a session.
options = {
    "video": {
        "codec": {
            "profiles": [
                camera.VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["BASELINE"],
                camera.VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["MAIN"],
                camera.VIDEO_CODEC_PARAM_PROFILE_ID_TYPES["HIGH"]
            ],
            "levels": [
                camera.VIDEO_CODEC_PARAM_LEVEL_TYPES['TYPE4_0']
            ],
        },
        "resolutions": [
            # Width, Height, framerate
            [1920, 1080, 25], # 16x9
            [1280, 720, 25],
            [640, 360, 25],
            [480, 270, 25],
            [480, 270, 25],
            [320, 180, 25],
            [1280, 960, 25], # 4:3
            [1024, 768, 25],
            [640, 480, 25],
            [480, 360, 25],
            [320, 240, 25],
        ],
    },
    "audio": { #audio is left blank, because I don't have a mic hooked up.
        "codecs": [ ],
    },
    "srtp": True,
    "address": "172.24.0.30",
    "start_stream_cmd": STREAM_CMD,
}

# Start the accessory on port 51826
driver = AccessoryDriver(port=51826)
acc = PiCamera(options, driver, "Camera")
driver.add_accessory(accessory=acc)

# We want KeyboardInterrupts and SIGTERM (terminate) to be handled by the driver itself,
# so that it can gracefully stop the accessory, server and advertising.
signal.signal(signal.SIGTERM, driver.signal_handler)
# Start it!
driver.start()


from .validators import ValidateAPIKey

class Content(object):
    """Content to be included in your email.

    You must specify at least one mime type in the Contents of your email.
    """

    def __init__(self, type_=None, value=None):
        """Create a Content with the specified MIME type and value.

        :param type_: MIME type of this Content (e.g. "text/plain").
        :type type_: string, optional
        :param value: The actual content.
        :type value: string, optional
        """
        self._type = None
        self._value = None
        self._validator = ValidateAPIKey()

        if type_ is not None:
            self.type = type_

        if value is not None:
            self.value = value

    @property
    def type(self):
        """The MIME type of the content you are including in your email.

        For example, "text/plain" or "text/html".

        :rtype: string
        """
        return self._type

    @type.setter
    def type(self, value):
        self._type = value

    @property
    def value(self):
        """The actual content (of the specified mime type).

        :rtype: string
        """
        return self._value

    @value.setter
    def value(self, value):
        self._validator.validate_message_dict(value)
        self._value = value

    def get(self):
        """
        Get a JSON-ready representation of this Content.

        :returns: This Content, ready for use in a request body.
        :rtype: dict
        """
        content = {}
        if self.type is not None:
            content["type"] = self.type

        if self.value is not None:
            content["value"] = self.value
        return content


from html.parser import HTMLParser
from collections import Counter, deque
from sys import stdin
accepted = deque([], maxlen=9)
failed = []
out = []
out_append = out.append
ac_append = accepted.append
failed_append = failed.append

class MyHTMLParser(HTMLParser):
    def handle_data(self, data):
        k = [bool(x) for x in accepted]
        data = data.strip()
        if data == 'Accepted':
            datas[accepted[-2]] += 1
        elif len(k) == 9 and k[0] and k[1] and k[2] and k[3] and not k[4] and not k[5] and k[6] and k[7] and k[8]:
            failed_append(accepted[1])
        data = data.replace('\n', '')
        ac_append(data)

parser = MyHTMLParser()
datas = Counter()
parser.feed(''.join(stdin))
t = None
for x, y in datas.most_common():
    if t is None:
        t = y
    elif t != y:
        break
    out_append(x)
out.sort()
try:
    print(out[0], t, sep=': ')
except IndexError:
    failed.sort()
    print('{}: 0'.format(failed[0]))


import random
from copy import deepcopy, copy
from typing import Tuple

from libs import ActorPosition, BaseClass, reverse_tuple, add_tuples
from libs.greedy_shortest_path import AStar
from libs.layouts import manhattan_distance

class GhostAgent(BaseClass):
    name: str
    initial_position: ActorPosition
    position: ActorPosition
    scared: bool = False
    dead: bool = False
    previous_action: Tuple[int, int] = (0, 0)
    disable_clip: bool = False
    fleeing_since: int = 0
    key: str

    def __init__(self, position: Tuple[int, int]):
        position = ActorPosition(position, (1, 0))
        self.initial_position = deepcopy(position)
        self.position = position

    def set_respawn(self):
        self.dead = True

    def respawn_tick(self):
        if self.position.coordinates == self.initial_position.coordinates:
            self.dead = False
            self.scared = False
            self.fleeing_since = 0

    def get_action(self, state):
        if self.dead:
            return self.go_to_coords(state, self.initial_position.coordinates)
        if self.scared:
            if self.fleeing_since > 10:
                return self.go_to_coords(state, self.initial_position.coordinates)
            self.fleeing_since += 1
            return self.flee_pacman(state)
        if self.disable_clip:
            return self.previous_action

    def flee_pacman(self, state):
        """
        The ghost should flee from Pacman.
        :param state: the game state
        :return: the action that will move the ghost away from Pacman
        """
        pacman_position = state.pacman.position.coordinates
        ghost_position = self.position.coordinates
        actions = self.get_legal_actions(state)
        distances = []
        for action in actions:
            distances.append(manhattan_distance(add_tuples(ghost_position, action), pacman_position))
        return actions[distances.index(max(distances))]

    def get_legal_actions(self, state):
        """
        A ghost can only move in cardinal directions.
        A ghost cannot move backwards.
        A ghost cannot move through a wall.
        A ghost cannot move through a ghost.
        A ghost can only advance one step at a time.

        :return: list of legal actions
        """
        walls = state.layout.walls
        coordinates = self.position.coordinates
        direction = self.position.direction
        actions = []
        if not (coordinates[0] + 1, coordinates[1]) in walls and direction != (-1, 0):
            actions.append((1, 0))
        if not (coordinates[0] - 1, coordinates[1]) in walls and direction != (1, 0):
            actions.append((-1, 0))
        if not (coordinates[0], coordinates[1] + 1) in walls and direction != (0, -1):
            actions.append((0, 1))
        if not (coordinates[0], coordinates[1] - 1) in walls and direction != (0, 1):
            actions.append((0, -1))
        if len(actions) == 0:
            actions.append((direction[0] * -1, direction[1] * -1))
        return actions

    def go_to_coords(self, state, coords):
        actions = self.get_legal_actions(state)
        maze = deepcopy(state.layout.maze)
        if self.position.coordinates != self.initial_position.coordinates:
            previous_position = (self.position.coordinates[1] - self.position.direction[1], self.position.coordinates[0] - self.position.direction[0])
            try:
                maze[previous_position[0]][previous_position[1]] = 1
            except IndexError:
                pass
        shortest_path_to_target = AStar(maze).search((self.position.coordinates[1], self.position.coordinates[0]), (coords[1], coords[0]))
        try:
            next_position = (shortest_path_to_target[1][1], shortest_path_to_target[1][0])
        except (TypeError, IndexError):
            return random.choice(actions)
        vector = (next_position[0] - self.position.coordinates[0], next_position[1] - self.position.coordinates[1])
        if vector in actions:
            return vector
        else:
            return random.choice(actions)

class RandomGhostAgent(GhostAgent):
    """
    A ghost agent that chooses a legal action uniformly at random.
    """

    def get_action(self, state):
        action = super().get_action(state)
        if action is not None:
            return action
        actions = self.get_legal_actions(state)
        return random.choice(actions)

class BlinkyAgent(GhostAgent):
    """
    Chaser ghost, starts outside the box and chases pacman immediately.
    """

    def get_action(self, state):
        action = super().get_action(state)
        if action is not None:
            return action
        return self.go_to_coords(state, state.pacman.position.coordinates)

class PinkyAgent(GhostAgent):
    """
    Ghost that tries to get in front of pacman. Starts inside the box but exits immediately.
    """
    start_at_turn = 5

    def get_action(self, state):
        action = super().get_action(state)
        if action is not None:
            return action
        actions = self.get_legal_actions(state)
        if state.turn < self.start_at_turn:
            if self.previous_action == (0, 0):
                self.previous_action = random.choice(actions)
                return self.previous_action
            else:
                self.previous_action = reverse_tuple(self.previous_action)
                return self.previous_action
        way_ahead = state.predict_pacman_position(3)
        return self.go_to_coords(state, way_ahead.pacman.position.coordinates)

class InkyAgent(GhostAgent):
    """
    Ghost setting up ambushes. Starts inside the box and exits after 30 fruit have been eaten.

    Draw a vector from blinky to 2 tiles in front of pacman, then double it. This is the target position for inky.
    """
    needed_food_to_start = 10

    def get_action(self, state):
        action = super().get_action(state)
        if action is not None:
            return action
        actions = self.get_legal_actions(state)
        if state.layout.initial_food_count - len(state.layout.food) < self.needed_food_to_start:
            if self.previous_action == (0, 0):
                self.previous_action = random.choice(actions)
                return self.previous_action
            else:
                self.previous_action = reverse_tuple(self.previous_action)
                return self.previous_action
        return self.go_to_coords(state, state.pacman.position.coordinates)

class ClydeAgent(GhostAgent):
    """
    Hard to predict ghost. Starts inside the box and exits after a third of the fruit have been eaten.

    If clyde is more than 8 tiles away from pacman, he will target him.
    Else, he will flee him
    """

    def get_action(self, state):
        action = super().get_action(state)
        if action is not None:
            return action
        actions = self.get_legal_actions(state)
        if state.layout.initial_food_count - len(state.layout.food) < state.layout.initial_food_count / 3:
            if self.previous_action == (0, 0):
                self.previous_action = random.choice(actions)
                return self.previous_action
            else:
                self.previous_action = reverse_tuple(self.previous_action)
                return self.previous_action
        if manhattan_distance(state.pacman.position.coordinates, self.position.coordinates) > 8:
            return self.go_to_coords(state, state.pacman.position.coordinates)
        else:
            return self.flee_pacman(state)


# Title: Wikipedia Scraper
# Class: CS 361 - Software Engineering I
# Author: Mallory Huston
# Description: A wikipedia scraper microservice that pulls up any information of a
#              category of your choosing.

from tkinter import *
import wikipedia as wiki
import os

root = Tk()
root.title('Game Development Guide - Category Wikipedia')
root.geometry("700x675")

# Clear
def clear():
    my_entry.delete(0, END)
    my_text.delete(0.0, END)

# Search
def search():
    data = wiki.page(my_entry.get())
    # Clear screen
    clear()
    # Output Wikipedia Results to Textbox
    my_text.insert(0.0, data.content)
    print(f"[wiki] Pulling information from {data.title}")

# Write to File
def writeFile():
    save_path = './information'
    file_name = input("Article name: ") + ".txt"
    # Saving .txt file to the /information directory
    completeName = os.path.join(save_path, file_name)
    file = open(completeName, "a+")
    # Output Wikipedia Results to .txt file
    file.write(my_text.get("1.0", 'end-1c') + '\n')
    file.close()

# Create label frame
my_label_frame = LabelFrame(root, text="Search Category")
my_label_frame.pack(pady=20)

# Create entry box
my_entry = Entry(my_label_frame, font=("Helvetica", 18), width=47)
my_entry.pack(pady=20, padx=20)

# Create text box frame
my_frame = Frame(root)
my_frame.pack(pady=5)

# Create vertical scrollbar
text_scroll = Scrollbar(my_frame)
text_scroll.pack(side=RIGHT, fill=Y)

# Create horizontal scrollbar
hor_scroll = Scrollbar(my_frame, orient='horizontal')
hor_scroll.pack(side=BOTTOM, fill=X)

# Create text box
my_text = Text(my_frame, yscrollcommand=text_scroll.set, wrap="none", xscrollcommand=hor_scroll.set)
my_text.pack()

# Configure scrollbars
text_scroll.config(command=my_text.yview)
hor_scroll.config(command=my_text.xview)

# Button Frame
button_frame = Frame(root)
button_frame.pack(pady=10)

# Buttons
search_button = Button(button_frame, text="Lookup", font=("Helvetica", 32), fg="#3a3a3a", command=search)
search_button.grid(row=0, column=0, padx=20)

clear_button = Button(button_frame, text="Clear", font=("Helvetica", 32), fg="#3a3a3a", command=clear)
clear_button.grid(row=0, column=1)

write_button = Button(button_frame, text="Write to File", font=("Helvetica", 32), fg="#3a3a3a", command=writeFile)
write_button.grid(row=0, column=2)

root.mainloop()


import torch
import os
import torch
from torch.optim import optimizer
from tqdm import trange
from typing import List, Dict
import numpy as np
import torch.nn as nn
from tqdm import trange
import argparse
import sys
import json

# relative import hacks (sorry)
import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) # for bash user
os.chdir(parentdir) # for pycharm user

from utils.d5 import get_data_loaders
from utils.log import Logger, Timer, save_model, save_vars
from utils.utils import *
from utils.models import *
import utils.loss_functions as loss_functions

parser = argparse.ArgumentParser(description='cai')

parser.add_argument('--experiment', type=str, default='CAI', metavar='E',
                    help='directory to save the results')
parser.add_argument('-l','--domains', nargs='+', default=['mnistm', 'mnist', 'usps', 'svhn', 'syn'],
                    help='Domains to use for train and evaluation (must choose at least one from mnist, mnistm, usps, svhn, syn)',
                    # required=True
                    )
parser.add_argument('--seed', type=int, default=70, metavar='S',
                    help='random seed (default: 70)')
parser.add_argument('--no-cuda', action='store_true', default=False,
                    help='disable CUDA use')
parser.add_argument('--batch-size', type=int, default=128, metavar='N',
                    help='batch size for data (default: 128)')
parser.add_argument('--data-size', type=int, default=12000, metavar='N',
                    help='amount of data to use from each domains (default: 12000)')
parser.add_argument('--margin', type=float, default=0.001,
                    help='margin for triplet loss: (0.001)')
parser.add_argument('--beta', type=float, default=0.0,
                    help='coefficient for triplet loss: (0.0)')
parser.add_argument('--embed_space', type=int, default=256,
                    help='size of the embedding space: (256)')
parser.add_argument('--model_name', type=str, default='fusion_model',
                    help='model name to use, a class with the given name must exist in models.py')
parser.add_argument('--aux_loss', type=str, default='myTripletLoss',
                    help='auxilary loss to use for domains')

# Add tensor fusion with the trick used in "https://aclanthology.org/D17-1115.pdf"
parser.add_argument('--fusion_mode', type=str, default='concat',
                    help='how to fuse representations with given features',
                    choices=['concat', 'additive', 'multiplicative'])
parser.add_argument('--bn_feats', action='store_true', default=False,
                    help='if True, adds a batch norm layer in input space of given features, default: (False) ')
parser.add_argument('--dropout_feats', action='store_true', default=False,
                    help='if True, adds a dropout layer in the fusion layer, default: (False) ')
parser.add_argument('--lr', type=float, default=0.001,
                    help='learning rate, default: (0.001)')
parser.add_argument('--optim', type=str, default='adam', metavar='M',
                    choices=['adam', 'sgd'],
                    help='optimizer (default: adam) - the sgd option is with momentum of 0.9')
parser.add_argument('--epochs', type=int, default=10, metavar='E',
                    help='number of epochs to train (default: 10)')

args = parser.parse_args()

print(args)

class Exp:
    def __init__(self, use_gpu: bool = True) -> None:
        self.lr: float
        self.full_dataloaders: Dict[str, DataLoader]
        self.opt: nn.Module
        self.model: nn.Module
        self.use_gpu = use_gpu

        self.triplet_loss: myTripletLoss
        # seeds
        rand_seed = 11
        torch.manual_seed(rand_seed)
        torch.cuda.manual_seed(rand_seed)

        self.device = torch.device("cuda:0" if torch.cuda.is_available() and self.use_gpu else "cpu")

        self.img_path = 'imgs'
        self.exp_name = 'default'
        self.path_save_model = 'models'

    def set_env(self, margin: float,
                 embed_space: int, beta: float,
                 model_name: str,
                 fusion_mode: str,
                 bn_on_features: bool,
                 dropout: bool,
                 lr: float,
                 exp_dir: str,
                 full_dataloaders: Dict[str, DataLoader], optimzier_str: str = 'sgd'):
        """
        margin: passed on to tripletloss, margin for triplet loss
        embed_space: passed on to model, embed_space for outputs of image encoder which is the input of triplet loss
        beta: coeff that multiplies the triplet loss and sums up with CE
        model_name: str,
        fusion_mode: passed on to model, how to fuse given input features with embeddings produced by image encoder
        """
        self.lr = lr
        self.full_dataloaders = full_dataloaders
        self.margin = margin
        self.embed_space = embed_space
        self.beta = beta

        ### set model
        if model_name == 'fusion_model':
            self.model = fusion_model(fusion_mode, image_embedding_space=embed_space, do_bn_on_features=bn_on_features, dropout=dropout)
            self.model_name = model_name
            self.model = self.model.to(self.device)

        else:
            print('invalid model name.')

        print(self.model)

        ### set optimizer
        if optimzier_str == 'sgd':
            self.opt = torch.optim.SGD(self.model.parameters(), lr=self.lr, momentum=0.9)
        elif optimzier_str == 'adam':
            self.opt = torch.optim.Adam(self.model.parameters(), lr=self.lr)

        ### set CE loss for digits
        self.ce_loss = nn.NLLLoss()

        ### set auxilary loss
        # 0.2 for mnist
        lossC = getattr(loss_functions, args.aux_loss)
        self.triplet_loss = lossC(self.device, margin)

        self.exp_name = f'opti_{optimzier_str}-fusion_mode_{fusion_mode}-beta_{beta}-margin_{margin}-bn_on_features_{bn_on_features}-dropout_{dropout}-embed_space_{embed_space}-model_name_{model_name}-lr_{lr}'
        self.img_path = f'{exp_dir}/imgs/{self.exp_name}'
        self.path_save_model = f'{exp_dir}/models/{self.exp_name}'

    def train(self, num_epochs: int, beta2: float = 1.0):
        print('training...')
        print('exp ', self.exp_name)

        self.acc_history = {'train': [], 'test': [], 'test_missing': []}
        self.loss_history = {'train': [], 'test': [], 'test_missing': []}
        self.triplet_loss_history = {'train': [], 'test': [], 'test_missing': []}
        self.ce_loss_history = {'train': [], 'test': [], 'test_missing': []}

        for epoch in trange(num_epochs):

            for phase in ['train', 'test', 'test_missing']:
                running_loss = 0.0
                running_loss_CE = 0.0
                running_loss_T = 0.0
                running_corrects = 0
                epoch_features = []
                epoch_labels = []
                epoch_domain_labels = []

                if phase == 'train': self.model.train()
                else: self.model.eval()

                for batch_indx, (inputs, features, domain_labels, digit_labels) in enumerate(self.full_dataloaders[phase]):
                    # _, freqs = torch.unique(domain_labels, return_counts=True)
                    # print(freqs)

                    self.opt.zero_grad()

                    with torch.set_grad_enabled(phase == 'train'):
                        inputs = inputs.to(self.device)
                        features = features.to(self.device)
                        domain_labels = domain_labels.to(self.device)
                        digit_labels = digit_labels.to(self.device)

                        embeddings, deep_feats, outputs = self.model(inputs, features)
                        _, preds = torch.max(outputs, dim=1)

                        # triplet loss on domains
                        t_loss = self.triplet_loss(embeddings, domain_labels)
                        c_loss = self.ce_loss(outputs, digit_labels)

                        loss = self.beta * t_loss + beta2 * c_loss

                        if phase == 'train':
                            loss.backward()
                            self.opt.step()

                    running_loss += loss.item()
                    running_loss_CE += c_loss.item()
                    running_loss_T += t_loss.item()
                    running_corrects += torch.sum(preds == digit_labels)

                    epoch_features.append(deep_feats.cpu().detach().numpy())
                    epoch_labels.append(digit_labels.cpu().detach().numpy())
                    epoch_domain_labels.append(domain_labels.cpu().detach().numpy())

                epoch_loss    = (running_loss / self.full_dataloaders[f'{phase}_size'])
                epoch_loss_CE = (running_loss_CE / self.full_dataloaders[f'{phase}_size'])
                epoch_loss_T  = (running_loss_T / self.full_dataloaders[f'{phase}_size'])
                epoch_loss /= (batch_indx+1)
                epoch_loss_CE /= (batch_indx+1)
                epoch_loss_T /= (batch_indx+1)

                self.loss_history[phase].append(epoch_loss)
                self.ce_loss_history[phase].append(epoch_loss_CE)
                self.triplet_loss_history[phase].append(epoch_loss_T)

                epoch_acc = (running_corrects.double() / self.full_dataloaders[f'{phase}_size']).cpu().numpy()
                self.acc_history[phase].append(epoch_acc)

                print(f'{phase} total loss: {epoch_loss}, CE loss: {epoch_loss_CE}, triplet_loss: {epoch_loss_T}, acc: {epoch_acc}')

                epoch_features = np.concatenate(epoch_features)
                epoch_labels = np.concatenate(epoch_labels)
                epoch_domain_labels = np.concatenate(epoch_domain_labels)

                plot_feats = False
                if plot_feats:
                    # plot labels based on the true labels
                    if beta2 != 0.0:
                        custom_plot_features(features=epoch_features, labels=epoch_labels,
                                            path = f'{self.img_path}/feats',
                                            title=f'phase_{phase}-epoch_{epoch}-deep_{self.exp_name}')
                    else:
                        custom_plot_features(features=epoch_features, labels=epoch_domain_labels,
                                            path = f'{self.img_path}/feats',
                                            title=f'phase_{phase}-epoch_{epoch}-deep_feats{self.exp_name}')

        plot_loss = True
        plot_acc = True
        if plot_loss and plot_acc:
            custom_plot_training_stats(self.acc_history, self.loss_history, ['train', 'test', 'test_missing'], title=f'{self.exp_name}', dir=self.img_path)
            custpm_plot_loss(self.ce_loss_history, ['train', 'test', 'test_missing'], loss_name='cross entropy loss', title=f'{self.exp_name}', dir=self.img_path)
            custpm_plot_loss(self.triplet_loss_history, ['train', 'test', 'test_missing'], loss_name='triplet loss', title=f'{self.exp_name}', dir=self.img_path)

        save_model = True
        if save_model:
            mkdir(self.path_save_model)
            torch.save(self.model, f'{self.path_save_model}/{self.exp_name}.pt')

    def load_model(self, model_name_to_load: str):
        if model_name_to_load is None:
            self.model = torch.load(f'{self.path_save_model}/{self.exp_name}.pt')
        else:
            self.model = torch.load(f'{self.path_save_model}/{model_name_to_load}.pt')

        self.model = self.model.to(self.device)

# Reproducibility
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
torch.manual_seed(args.seed)
np.random.seed(args.seed)
random.seed(args.seed)

# Save outputs
runPath = args.experiment
mkdir(runPath)
sys.stdout = Logger('{}/run.log'.format(runPath))
print('Expt:', runPath)
command_line_args = sys.argv
command = ' '.join(command_line_args)
print(f"The command that ran this script: {command}")

# save args to run
with open('{}/args.json'.format(runPath), 'w') as fp:
    json.dump(args.__dict__, fp)
torch.save(args, '{}/args.rar'.format(runPath))

if __name__ == '__main__':
    with Timer('CAI-Final-project') as t:
        full_dataloaders, num_domains = get_data_loaders(sorted(args.domains), batch_size= args.batch_size, size=args.data_size)
        exp = Exp(True if torch.cuda.is_available() and not args.no_cuda else False)

        exp.set_env(margin=args.margin, beta=args.beta, embed_space=args.embed_space,
            model_name=args.model_name, fusion_mode=args.fusion_mode,
            bn_on_features=args.bn_feats, dropout=args.dropout_feats, lr=args.lr,
            full_dataloaders=full_dataloaders, optimzier_str=args.optim,
            exp_dir=args.experiment)
        exp.train(args.epochs)

Final-Project: Triplet Loss and fusion/main.py


from matplotlib import colors
import matplotlib.pyplot as plt

days = [1,2,3,4,5]

sleeping =  [7,8,6,11,7]
eating =    [2,3,4,3,2]
working =   [7,8,7,2,2]
playing =   [8,5,7,8,13]

slices = [7,2,2,13]
activities = ['sleeping','eating','working','playing']
cols = ['c','m','r','b']

# Create pie chart that starts at 90 degress, has one section exploaded out, and percent values
plt.pie(slices,
        labels=activities,
        colors=cols,
        startangle=90,
        shadow=True,
        explode=(0,0.1,0,0),
        autopct='%1.1f%%')

plt.title('Graph')
plt.show()


import numpy as np
import tensorflow as tf
from collections import OrderedDict

import tensorflow_train
from tensorflow_train.utils.tensorflow_util import create_placeholders
import utils.io.image
import utils.io.landmark
import utils.io.text
from tensorflow_train.data_generator import DataGenerator
from tensorflow_train.train_loop import MainLoopBase
from tensorflow_train.utils.data_format import get_batch_channel_image_size
from tensorflow_train.utils.heatmap_image_generator import generate_heatmap_target
from transformations.intensity.np.shift_scale_clamp import ShiftScaleClamp
from utils.landmark.heatmap_test import HeatmapTest
from utils.landmark.landmark_statistics import LandmarkStatistics
from utils.image_tiler import ImageTiler, LandmarkTiler
from tensorflow_train.utils.summary_handler import create_summary_placeholder

from dataset import Dataset
from network import network_scn, network_unet

class MainLoop(MainLoopBase):
    def __init__(self, cv, network_id):
        super().__init__()
        self.cv = cv
        self.network_id = network_id
        self.output_folder = network_id
        if cv != -1:
            self.output_folder += '_cv{}'.format(cv)
        self.output_folder += '/' + self.output_folder_timestamp()
        self.batch_size = 1
        learning_rates = {'scn': 0.00000005,
                          'unet': 0.000000005}
        max_iters = {'scn': 40000,
                     'unet': 80000}
        self.learning_rate = learning_rates[self.network_id]
        self.max_iter = max_iters[self.network_id]
        self.test_iter = 2500
        self.disp_iter = 100
        self.snapshot_iter = self.test_iter
        self.test_initialization = False
        self.current_iter = 0
        self.reg_constant = 0.0005
        self.sigma_regularization = 100
        self.sigma_scale = 1000
        self.invert_transformation = False
        self.num_landmarks = 26
        self.image_size = [96, 96, 192]
        self.image_spacing = [2, 2, 2]
        self.heatmap_size = self.image_size
        self.image_channels = 1
        self.heatmap_sigma = 4
        self.data_format = 'channels_first'
        self.save_debug_images = False
        self.base_folder = 'spine_localization_dataset'
        self.generate_landmarks = True
        self.cropped_training = True
        self.cropped_inc = [0, 64, 0, 0]
        if self.cropped_training:
            dataset = Dataset(self.image_size,
                              self.image_spacing,
                              self.heatmap_sigma,
                              self.num_landmarks,
                              self.base_folder,
                              self.cv,
                              self.data_format,
                              self.save_debug_images,
                              generate_heatmaps=not self.generate_landmarks,
                              generate_landmarks=self.generate_landmarks)
            self.dataset_train = dataset.dataset_train()
            dataset = Dataset(self.image_size,
                              self.image_spacing,
                              self.heatmap_sigma,
                              self.num_landmarks,
                              self.base_folder,
                              self.cv,
                              self.data_format,
                              self.save_debug_images,
                              generate_heatmaps=not self.generate_landmarks,
                              generate_landmarks=self.generate_landmarks)
            self.dataset_val = dataset.dataset_val()
        else:
            dataset = Dataset(self.image_size,
                              self.image_spacing,
                              self.heatmap_sigma,
                              self.num_landmarks,
                              self.base_folder,
                              self.cv,
                              self.data_format,
                              self.save_debug_images,
                              generate_heatmaps=not self.generate_landmarks,
                              generate_landmarks=self.generate_landmarks,
                              translate_by_random_factor=False)
            self.dataset_train = dataset.dataset_train()
            self.dataset_val = dataset.dataset_val()

        networks = {'scn': network_scn,
                    'unet': network_unet}
        self.network = networks[self.network_id]

        self.point_statistics_names = ['pe_mean', 'pe_stdev', 'pe_median', 'num_correct']
        self.additional_summaries_placeholders_val = dict([(name, create_summary_placeholder(name)) for name in self.point_statistics_names])

    def loss_function(self, pred, target):
        batch_size, _, _ = get_batch_channel_image_size(pred, self.data_format)
        return tf.nn.l2_loss(pred - target) / batch_size

    def initNetworks(self):
        net = tf.make_template('scn', self.network)

        if self.data_format == 'channels_first':
            if self.generate_landmarks:
                data_generator_entries = OrderedDict([('image', [self.image_channels] + list(reversed(self.image_size))),
                                                      ('landmarks', [self.num_landmarks, 4])])
            else:
                data_generator_entries = OrderedDict([('image', [self.image_channels] + list(reversed(self.image_size))),
                                                      ('heatmaps', [self.num_landmarks] + list(reversed(self.heatmap_size)))])
        else:
            if self.generate_landmarks:
                data_generator_entries = OrderedDict([('image', list(reversed(self.image_size)) + [self.image_channels]),
                                                      ('landmarks', [self.num_landmarks, 4])])
            else:
                data_generator_entries = OrderedDict([('image', list(reversed(self.image_size)) + [self.image_channels]),
                                                      ('heatmaps', list(reversed(self.heatmap_size)) + [self.num_landmarks])])

        sigmas = tf.get_variable('sigmas', [self.num_landmarks], initializer=tf.constant_initializer(self.heatmap_sigma))
        mean_sigmas = tf.reduce_mean(sigmas)
        self.train_queue = DataGenerator(self.dataset_train, self.coord, data_generator_entries, batch_size=self.batch_size)
        #self.train_queue = DataGeneratorDataset(self.dataset_train, data_generator_entries, batch_size=self.batch_size)
        placeholders = self.train_queue.dequeue()
        image = placeholders[0]

        if self.generate_landmarks:
            target_landmarks = placeholders[1]
            target_heatmaps = generate_heatmap_target(list(reversed(self.heatmap_size)), target_landmarks, sigmas, scale=self.sigma_scale, normalize=True, data_format=self.data_format)
            loss_sigmas = self.sigma_regularization * tf.nn.l2_loss(sigmas * target_landmarks[0, :, 0])
        else:
            target_heatmaps = placeholders[1]
            loss_sigmas = self.sigma_regularization * tf.nn.l2_loss(sigmas)
        heatmaps, _, _ = net(image, num_heatmaps=self.num_landmarks, is_training=True, data_format=self.data_format)
        self.loss_net = self.loss_function(heatmaps, target_heatmaps)

        with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
            if self.reg_constant > 0:
                reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
                self.loss_reg = self.reg_constant * tf.add_n(reg_losses)
                self.loss = self.loss_net + self.loss_reg + loss_sigmas
            else:
                self.loss = self.loss_net + loss_sigmas

        self.train_losses = OrderedDict([('loss', self.loss_net), ('loss_reg', self.loss_reg), ('loss_sigmas', loss_sigmas), ('mean_sigmas', mean_sigmas)])
        # self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.loss)
        self.optimizer = tf.train.MomentumOptimizer(learning_rate=self.learning_rate, momentum=0.99, use_nesterov=True).minimize(self.loss)

        # build val graph
        val_placeholders = create_placeholders(data_generator_entries, shape_prefix=[1])
        self.image_val = val_placeholders['image']
        if self.generate_landmarks:
            self.target_landmarks_val = val_placeholders['landmarks']
            self.target_heatmaps_val = generate_heatmap_target(list(reversed(self.heatmap_size)), self.target_landmarks_val, sigmas, scale=self.sigma_scale, normalize=True, data_format=self.data_format)
            loss_sigmas_val = self.sigma_regularization * tf.nn.l2_loss(sigmas * self.target_landmarks_val[0, :, 0])
        else:
            self.target_heatmaps_val = val_placeholders['heatmaps']
            loss_sigmas_val = self.sigma_regularization * tf.nn.l2_loss(sigmas)
        self.heatmaps_val, self.heatmals_local_val, self.heatmaps_global_val = net(self.image_val, num_heatmaps=self.num_landmarks, is_training=False, data_format=self.data_format)

        # losses
        self.loss_val = self.loss_function(self.heatmaps_val, self.target_heatmaps_val)
        self.val_losses = OrderedDict([('loss', self.loss_val), ('loss_reg', self.loss_reg), ('loss_sigmas', loss_sigmas_val), ('mean_sigmas', mean_sigmas)])

    def test_full_image(self, dataset_entry):
        generators = dataset_entry['generators']
        transformations = dataset_entry['transformations']
        heatmap_transform = transformations['image']
        feed_dict = {self.image_val: np.expand_dims(generators['image'], axis=0)}
        if self.generate_landmarks:
            feed_dict[self.target_landmarks_val] = np.expand_dims(generators['landmarks'], axis=0)
        else:
            feed_dict[self.target_heatmaps_val] = np.expand_dims(generators['heatmaps'], axis=0)

        # run loss and update loss accumulators
        run_tuple = self.sess.run((self.heatmaps_val, self.target_heatmaps_val, self.loss_val) + self.val_loss_aggregator.get_update_ops(), feed_dict)
        heatmaps = np.squeeze(run_tuple[0], axis=0)
        image = generators['image']

        return image, heatmaps, heatmap_transform

    def test_cropped_image(self, dataset_entry):
        generators = dataset_entry['generators']
        transformations = dataset_entry['transformations']
        heatmap_transform = transformations['image']

        image_size_np = [1] + list(reversed(self.image_size))
        heatmap_size_np = [self.num_landmarks] + list(reversed(self.image_size))
        full_image = generators['image']
        landmarks = generators['landmarks']
        image_tiler = ImageTiler(full_image.shape, image_size_np, self.cropped_inc, True, -1)
        landmark_tiler = LandmarkTiler(full_image.shape, image_size_np, self.cropped_inc)
        heatmap_tiler = ImageTiler((self.num_landmarks,) + full_image.shape[1:], heatmap_size_np, self.cropped_inc, True, 0)

        for image_tiler, landmark_tiler, heatmap_tiler in zip(image_tiler, landmark_tiler, heatmap_tiler):
            current_image = image_tiler.get_current_data(full_image)
            current_landmarks = landmark_tiler.get_current_data(landmarks)
            feed_dict = {self.image_val: np.expand_dims(current_image, axis=0),
                         self.target_landmarks_val: np.expand_dims(current_landmarks, axis=0)}
            run_tuple = self.sess.run((self.heatmaps_val, self.target_heatmaps_val, self.loss_val) + self.val_loss_aggregator.get_update_ops(), feed_dict)
            prediction = np.squeeze(run_tuple[0], axis=0)
            image_tiler.set_current_data(current_image)
            heatmap_tiler.set_current_data(prediction)

        return image_tiler.output_image, heatmap_tiler.output_image, heatmap_transform

    def test(self):
        print('Testing...')
        if self.data_format == 'channels_first':
            np_channel_index = 0
        else:
            np_channel_index = 3
        heatmap_maxima = HeatmapTest(np_channel_index, False)
        landmark_statistics = LandmarkStatistics()
        landmarks = {}
        for i in range(self.dataset_val.num_entries()):
            dataset_entry = self.dataset_val.get_next()
            current_id = dataset_entry['id']['image_id']
            datasources = dataset_entry['datasources']
            image_datasource = datasources['image_datasource']
            landmarks_datasource = datasources['landmarks_datasource']

            if not self.cropped_training:
                image, heatmaps, heatmap_transform = self.test_full_image(dataset_entry)
            else:
                image, heatmaps, heatmap_transform = self.test_cropped_image(dataset_entry)

            utils.io.image.write_np(ShiftScaleClamp(scale=255, clamp_min=0, clamp_max=255)(heatmaps).astype(np.uint8),
                                    self.output_file_for_current_iteration(current_id + '_heatmaps.mha'))
            utils.io.image.write_np(image, self.output_file_for_current_iteration(current_id + '_image.mha'))

            predicted_landmarks = heatmap_maxima.get_landmarks(heatmaps, image_datasource, self.image_spacing, heatmap_transform)
            landmarks[current_id] = predicted_landmarks
            landmark_statistics.add_landmarks(current_id, predicted_landmarks, landmarks_datasource)

            tensorflow_train.utils.tensorflow_util.print_progress_bar(i, self.dataset_val.num_entries(), prefix='Testing ', suffix=' complete')

        tensorflow_train.utils.tensorflow_util.print_progress_bar(self.dataset_val.num_entries(), self.dataset_val.num_entries(), prefix='Testing ', suffix=' complete')
        print(landmark_statistics.get_pe_overview_string())
        print(landmark_statistics.get_correct_id_string(20.0))
        summary_values = OrderedDict(zip(self.point_statistics_names, list(landmark_statistics.get_pe_statistics()) + [landmark_statistics.get_num_correct_id(20)]))

        # finalize loss values
        self.val_loss_aggregator.finalize(self.current_iter, summary_values)
        utils.io.landmark.save_points_csv(landmarks, self.output_file_for_current_iteration('points.csv'))
        overview_string = landmark_statistics.get_overview_string([2, 2.5, 3, 4, 10, 20], 10, 20.0)
        utils.io.text.save_string_txt(overview_string, self.output_file_for_current_iteration('eval.txt'))

if __name__ == '__main__':
    # TODO: if the loss gets 'nan', either restart the network training or reduce the learning rate
    # change networks
    networks = ['scn', 'unet']
    for network in networks:
        # cv 0, 1 for cross validation
        # cv -1 for training on full training set and testing on test set
        for cv in [-1, 0, 1]:
            loop = MainLoop(cv, network)
            loop.run()


from random import randint
from typing import Any, Dict

from sqlalchemy.orm import Session

from app.choices.cost_unit import COST_UNIT_TYPES
from app.db_models.item import Item
from app.tests.factory.base import Base

class ItemFactory(Base):
    def __init__(self, shop_id: str, owner_id: int) -> None:
        self.id = None
        self.name = self.random_lower_string()
        self.cost = self.random_integer()
        self.cost_unit = COST_UNIT_TYPES[randint(0, len(COST_UNIT_TYPES) - 1)][0]
        self.shop_id = shop_id
        self.owner_id = owner_id
        self.item_available = None

    def create(self, db: Session):
        item = Item(
            name=self.name,
            cost=self.cost,
            cost_unit=self.cost_unit,
            shop_id=self.shop_id,
            owner_id=self.owner_id,
        )
        db.add(item)
        db.commit()
        db.refresh(item)
        self.id = item.id
        self.item_available = item.item_available

    def update(self, db: Session, values: Dict[str, Any]):
        item: Item = db.query(Item).filter_by(id=self.id).first()
        for key in values:
            setattr(item, key, values[key])
        db.add(item)
        db.commit()
        db.refresh(item)
        for key in values:
            setattr(self, key, getattr(item, key))


# CHAPTER 5: In Depth: k-Means Clustering
# =======================================

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()    # plot formatting

from sklearn.cluster import KMeans
from sklearn.cluster import SpectralClustering
from sklearn.cluster import MiniBatchKMeans
from sklearn.manifold import TSNE

from sklearn.metrics import pairwise_distances_argmin
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix

from scipy.stats import mode

from sklearn.datasets import make_blobs
from sklearn.datasets import make_moons
from sklearn.datasets import load_digits
from sklearn.datasets import load_sample_image

# -------------------------------------------------------------

# Clustering algorithms
#   seek to learn, from the properties of the data,
#   an optimal division or discrete labeling of groups of points

# Many clustering algorithms are available in Scikit-Learn and elsewhere,
# perhaps the simplest to understand is an algorithm known as k-means clustering,
#   which is implemented in sklearn.cluster.KMeans

#region Introducing k-Means
# k-means algorithm
#   searches for a predetermined number of clusters
#   within an unlabeled multidimensional dataset

# accomplishes this using a simple conception of what the optimal clustering looks like:
# • The “cluster center”
#       is the arithmetic mean of all the points belonging to the cluster.
# • Each point is closer to its own cluster center than to other cluster centers

# Those two assumptions are the basis of the k-means model

# e.g.
# generate a two-dimensional dataset containing four distinct blobs
# To emphasize that this is an unsupervised algorithm, leave the labels out of the visualization

# from sklearn.datasets import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
plt.scatter(X[:, 0], X[:, 1], s=50); plt.show()

# By eye, it is relatively easy to pick out the four clusters
# k-means algorithm does this automatically
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=4)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)

# visualize the results by plotting the data colored by these labels
# also plot the cluster centers as determined by the k-means estimator
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)
plt.show()

# how this algorithm finds these clusters so quickly!
# typical approach to k-means involves
#   an intuitive iterative approach known as expectation–maximization

#endregion

#region k-Means Algorithm: Expectation–Maximization
# expectation–maximization approach consists of the following procedure:
# 1. Guess some cluster centers
# 2. Repeat until converged
#   a. E-Step: assign points to the nearest cluster center
#   b. M-Step: set the cluster centers to the mean

# “E-step” or “Expectation step”
#   involves updating our expectation of which cluster each point belongs to

# “M-step” or “Maximization step”
#   involves maximizing some fitness function that defines the location of the cluster centers—
#   in this case, that maximization is accomplished by taking a simple mean of the data in each cluster

# under typical circumstances,
#   each repetition of the E-step and M-step
#   will always result in a better estimate of the cluster characteristics

# k-means algorithm is simple enough that we can write it in a few lines of code.
# The following is a very basic implementation
from sklearn.metrics import pairwise_distances_argmin

def find_clusters(X, n_clusters, rseed=2):
    # 1. Randomly choose clusters
    rng = np.random.RandomState(rseed)
    i = rng.permutation(X.shape[0])[:n_clusters]
    centers = X[i]

    while True:
        # 2a. Assign labels based on closest center
        labels = pairwise_distances_argmin(X, centers)

        # 2b. Find new centers from means of points
        new_centers = np.array([X[labels == i].mean(0) for i in range(n_clusters)])

        # 2c. Check for convergence
        if np.all(centers == new_centers):
            break
        centers = new_centers

    return centers, labels

centers, labels = find_clusters(X, 4)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis'); plt.show()

# Most well-tested implementations will do a bit more than this under the hood,
#   but the preceding function gives the gist of the expectation–maximization approach

#region Caveats of expectation–maximization
# few issues to be aware of when using the expectation–maximization algorithm

# ---------------------------

# 1.
# globally optimal result may not be achieved
#   although the E–M procedure is guaranteed to improve the result in each step,
#   there is no assurance that it will lead to the global best solution

# e.g.
# if we use a different random seed in our simple procedure,
#   the particular starting guesses lead to poor results
centers, labels = find_clusters(X, 4, rseed=0)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis'); plt.show()

# Here the E–M approach has converged,
#   but has not converged to a globally optimal configuration

# For this reason, it is common for the algorithm to be run for multiple starting guesses,
#   as indeed Scikit-Learn does by default
#   (set by the n_init parameter, which defaults to 10)

# ---------------------------

# 2,
# The number of clusters must be selected beforehand
#   must tell it how many clusters you expect:
#   it cannot learn the number of clusters from the data

# e.g.
# if we ask the algorithm to identify six clusters,
#   it will happily proceed and find the best six clusters
labels = KMeans(6, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis'); plt.show()

# Whether the result is meaningful is a question that is difficult to answer definitively

# one approach that is rather intuitive is called silhouette analysis

# Alternatively, you might use a more complicated clustering algorithm
#   which has a better quantitative measure of the fitness per number of clusters
#       (e.g., Gaussian mixture models)
#   or which can choose a suitable number of clusters
#       (e.g., DBSCAN, mean-shift, or affinity propagation,
#       all available in the sklearn.cluster submodule)

# ---------------------------

# 3.
# k-means is limited to linear cluster boundaries
# The fundamental model assumptions of k-means
#   (points will be closer to their own cluster center than to others)
# means that the algorithm will often be ineffective
#   if the clusters have complicated geometries

# e.g.
# following data, along with the cluster labels found by the typical k-means approach
from sklearn.datasets import make_moons
X, y = make_moons(200, noise=.05, random_state=0)

labels = KMeans(2, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis'); plt.show()

# use a kernel transformation
#   to project the data into a higher dimension
#   where a linear separation is possible

# One version of this kernelized k-means is implemented in Scikit-Learn within the
#   SpectralClustering estimator
# uses the graph of nearest neighbors to compute a higher-dimensional representation of the data,
#   and then assigns labels using a k-means algorithm

from sklearn.cluster import SpectralClustering
model = SpectralClustering(n_clusters=2, affinity='nearest_neighbors', assign_labels='kmeans')
labels = model.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis'); plt.show()

# see that with this kernel transform approach,
#   the kernelized k-means is able to find the more complicated nonlinear boundaries between clusters

# ---------------------------

# 4.
# k-means can be slow for large numbers of samples
# Because each iteration of k-means must access every point in the dataset,
#   the algorithm can be relatively slow as the number of samples grows

# might wonder if this requirement to use all data at each iteration can be relaxed
# e.g.
#   might just use a subset of the data to update the cluster centers at each step

# This is the idea behind batch-based k-means algorithms,
#   one form of which is implemented in sklearn.cluster.MiniBatchKMeans
# interface for this is the same as for standard KMeans

#endregion

#endregion

#region Examples
# Being careful about these limitations of the algorithm,
#   can use k-means to our advantage in a wide variety of situations

#region Example 1: k-Means on digits
# will attempt to use k-means to try to identify similar digits
# without using the original label information;
#   this might be similar to a first step
#   in extracting meaning from a new dataset
#   about which you don’t have any a priori label information

from sklearn.datasets import load_digits
digits = load_digits()
digits.data.shape

kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits.data)
kmeans.cluster_centers_.shape

# result is 10 clusters in 64 dimensions
# cluster centers themselves are 64-dimensional points,
#   and can themselves be interpreted as the “typical” digit within the cluster

fig, ax = plt.subplots(2, 5, figsize=(8, 3))
centers = kmeans.cluster_centers_.reshape(10, 8, 8)
for axi, center in zip(ax.flat, centers):
    axi.set(xticks=[],yticks=[])
    axi.imshow(center, interpolation='nearest', cmap=plt.cm.binary)
plt.show()

# even without the labels,
#   KMeans is able to find clusters whose centers are recognizable digits,
#   with perhaps the exception of 1 and 8

# Because k-means knows nothing about the identity of the cluster,
#   the 0–9 labels may be permuted
# can fix this
#   by matching each learned cluster label
#   with the true labels found in them

from scipy.stats import mode

labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

# check how accurate our unsupervised clustering was in finding similar digits within the data

from sklearn.metrics import accuracy_score
accuracy_score(digits.target, labels)

# With just a simple k-means algorithm,
#   we discovered the correct grouping for 80% of the input digits!
# check the confusion matrix for this
from sklearn.metrics import confusion_matrix
mat = confusion_matrix(digits.target, labels)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=digits.target_names,
            yticklabels=digits.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label')
plt.show()

# As we might expect from the cluster centers we visualized before,
#   the main point of confusion is between the eights and ones
# But this still shows that using k-means,
#   we can essentially build a digit classifier
#   without reference to any known labels!

# can use the t-distributed stochastic neighbor embedding (t-SNE) algorithm
#   to preprocess the data before performing k-means
# t-SNE is a non‐linear embedding algorithm
#   that is particularly adept at preserving points within clusters
from sklearn.manifold import TSNE

# Project the data: this step will take several seconds
tsne =TSNE(n_components=2, init='pca', random_state=0)
digits_proj = tsne.fit_transform(digits.data)

# Compute the clusters
kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits_proj)

# Permute the labels
labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

# Compute the accuracy
accuracy_score(digits.target, labels)

# That’s nearly 94% classification accuracy without using the labels
# This is the power of unsupervised learning when used carefully:
#   it can extract information from the data‐set
#   that it might be difficult to do by hand or by eye

#endregion

#region Example 2: k-means for color compression
# One interesting application of clustering is in color compression within images

# e.g.
# image with millions of colors.
# In most images,
#   a large number of the colors will be unused,
#   and many of the pixels in the image will have similar or even identical colors

# e.g.
# Note: this requires the pillow package to be installed
from sklearn.datasets import load_sample_image
china = load_sample_image('china.jpg')
ax = plt.axes(xticks=[], yticks=[])
ax.imshow(china)
plt.show()

# image itself is stored in a three-dimensional array of size (height, width, RGB),
#   containing red/blue/green contributions as integers from 0 to 255
china.shape

# One way we can view this set of pixels
#   is as a cloud of points in a three-dimensional color space
# will reshape the data to [n_samples x n_features],
#   and rescale the colors so that they lie between 0 and 1

data = china / 255.0    # use 0...1 scale
data = data.reshape(427 * 640, 3)
data.shape

# visualize these pixels in this color space,
#   using a subset of 10,000 pixels for efficiency
def plot_pixels(data, title, colors=None, N=10000):
    if colors is None:
        colors = data

    # choose a random subset
    rng = np.random.RandomState(0)
    i = rng.permutation(data.shape[0])[:N]
    colors = colors[i]
    R, G, B = data[i].T

    fig, ax = plt.subplots(1, 2, figsize=(16, 6))
    ax[0].scatter(R, G, color=colors, marker='.')
    ax[0].set(xlabel='Red', ylabel='Green', xlim=(0, 1), ylim=(0, 1))

    ax[1].scatter(R, B, color = colors, marker='.')
    ax[1].set(xlabel='Red', ylabel='Blue', xlim=(0, 1), ylim=(0, 1))

    fig.suptitle(title, size=20)

plot_pixels(data, title='Input color space: 16 million possible colors'); plt.show()

# let’s reduce these 16 million colors to just 16 colors,
#   using a k-means clustering across the pixel space
# Because we are dealing with a very large dataset,
#   we will use the mini batch k-means,
#       which operates on subsets of the data
#       to compute the result much more quickly than the standard k-means algorithm

from sklearn.cluster import MiniBatchKMeans
kmeans = MiniBatchKMeans(16)
kmeans.fit(data)
new_colors = kmeans.cluster_centers_[kmeans.predict(data)]

plot_pixels(data, colors=new_colors, title='Reduced color space: 16 colors'); plt.show()

# result is a recoloring of the original pixels,
#   where each pixel is assigned the color of its closest cluster center
# Plotting these new colors in the image space
#   rather than the pixel space
#   shows us the effect of this
china_recolored = new_colors.reshape(china.shape)

fig, ax = plt.subplots(1, 2, figsize=(16, 6), subplot_kw=dict(xticks=[], yticks=[]))
fig.subplots_adjust(wspace=0.05)
ax[0].imshow(china)
ax[0].set_title('Original Image', size=16)
ax[1].imshow(china_recolored)
ax[1].set_title('16-color Image', size=16)
plt.show()

# Some detail is certainly lost in the rightmost panel,
#   but the overall image is still easily recognizable
# This image on the right achieves a compression factor of around 1 million!
# While this is an interesting application of k-means,
#   there are certainly better way to compress information in images

#endregion

#endregion


from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.generic import ListView, UpdateView

from .forms import CustomUserForm
from django.contrib.auth.decorators import login_required, permission_required
from .models import ViewHabitaciones, Habitacion, TipoHabitacion, EstadoHabitacion, ViewEmpleados, Empleados, \
    TipoEmpleado, EstadoEmpleado

# Create your views here.

# Usuario
@login_required
def homeadmin(request):
    return render(request, "baseadmin.html")

@login_required
def adminusuario(request):
    data = {
        'form': CustomUserForm()

    }

    if request.method == 'POST':
        formulario = CustomUserForm(request)

    return render(request, 'usuario/Admin_Usuario.html', data)

@login_required
def listausuario(request):
    return render(request, 'usuario/Listado_Usuario.html')

# Habitacion
@login_required
def adminhabit(request):
    tiposhab = TipoHabitacion.objects.all()
    estadohab = EstadoHabitacion.objects.all()
    variables = {
        'tiposhab': tiposhab,
        'estadohab': estadohab
    }
    if request.method == 'POST':
        hab_tam = request.POST["txtTam"]
        hab_prec = request.POST["txtPrecio"]
        hab_banno = request.POST["cbobano"]
        hab_estado = request.POST["cboestado"]
        hab_tipo = request.POST["cbotipo"]
        habitacion = Habitacion(tamanno_hab=hab_tam, banno_privado=hab_banno, precio_hab=hab_prec,
                                id_estado_habitacion=hab_estado, id_tipohabitacion=hab_tipo)
        habitacion.save()
    return render(request, 'habitacion/addhab.html', variables)

class ViewListHabitacion(ListView):
    model = ViewHabitaciones
    template_name = 'habitacion/Listado_Habitacion.html'

    def post(self, request, *args, **kwargs):
        data = {}
        hab = Habitacion.objects.get(id_habitacion=request.POST['id'])
        hab.id_estado_habitacion = 3
        hab.save()
        data['Estado'] = hab.id_estado_habitacion
        return JsonResponse(data)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['habitaciones'] = ViewHabitaciones.objects.all()
        return context

@login_required
def updatehabit(request, id):
    tiposhab = TipoHabitacion.objects.all()
    estadohab = EstadoHabitacion.objects.all()
    habi = Habitacion.objects.get(id_habitacion=id)
    variables = {
        'tiposhab': tiposhab,
        'estadohab': estadohab,
        'habi': habi
    }
    if request.method == 'POST':
        habi.tamanno_hab = request.POST["txtTam"]
        habi.precio_hab = request.POST["txtPrecio"]
        habi.banno_privado = request.POST["cbobano"]
        habi.id_estado_habitacion = request.POST["cboestado"]
        habi.id_tipohabitacion = request.POST["cbotipo"]
        habi.save()
    return render(request, 'habitacion/updatehab.html', variables)

# Empleado
@login_required
def adminempleado(request):
    tiposemp = TipoEmpleado.objects.all()
    estadoemp = EstadoEmpleado.objects.all()
    variables = {
        'tiposemp': tiposemp,
        'estadoemp': estadoemp
    }
    if request.method == 'POST':
        emp = Empleados()
        emp.rut_emp = request.POST['rut_emp']
        emp.id_tipoempleado = request.POST["cbotipo"]
        emp.id_estadoempleado = request.POST["cboestado"]
        emp.nombres_emp = request.POST["primernombre"] + " " + request.POST["segundonombre"]
        emp.apellidos_emp = request.POST["primerapellido"] + " " + request.POST["segundoapellido"]
        emp.fono_emp = request.POST['fono_emp']
        emp.email_emp = request.POST['email_emp']
        emp.fechanac_emp = request.POST['fechanac']
        emp.save()
    return render(request, 'empleados/addemp.html', variables)

class ViewListaEmpleado(ListView):
    model = ViewEmpleados
    template_name = 'empleados/Listado_Empleado.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['empleados'] = ViewEmpleados.objects.all()
        return context

    def post(self, request, *args, **kwargs):
        data = {}
        emp = Empleados.objects.get(rut_emp=request.POST['rut'])
        emp.id_estadoempleado = 3
        emp.save()
        data['Estado emp'] = emp.id_estadoempleado
        return JsonResponse(data)

@login_required
def updateempleado(request, id):
    tiposemp = TipoEmpleado.objects.all()
    estadoemp = EstadoEmpleado.objects.all()
    emp = Empleados.objects.get(id_empleado=id)
    variables = {
        'tiposemp': tiposemp,
        'estadoemp': estadoemp,
        'emp': emp
    }
    if request.method == 'POST':
        emp.rut_emp = request.POST['rut_emp']
        emp.id_tipoempleado = request.POST["cbotipo"]
        emp.id_estadoempleado = request.POST["cboestado"]
        emp.nombres_emp = request.POST["nombres_emp"]
        emp.apellidos_emp = request.POST["apellidos_emp"]
        emp.fono_emp = request.POST['fono_emp']
        emp.email_emp = request.POST['email_emp']
        emp.fechanac_emp = request.POST['fechanac']
        emp.save(force_update=True)
    return render(request, 'empleados/updemp.html', variables)

@login_required
def pedidos(request):
    return render(request, 'informes/InformePedido.html')

def productos(request):
    return render(request, 'informes/InformeProductos.html')


import sys
import glob
from datetime import datetime, timedelta
from expressions import ExpressionSolver, ExpressionTree, InfixToPostfix

class Loader:
	def __init__(self, message):
		self.message = message

	def __enter__(self):
		print('Loading {}... '.format(self.message), end='')

	def __exit__(self, type, value, traceback):
		print('Done!')

words = {}

units = [
	"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
	"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
	"sixteen", "seventeen", "eighteen", "nineteen",
]
tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
scales = ["hundred", "thousand", "million", "billion", "trillion"]

words["and"] = (1, 0)
words["a"] = (1, 2)
words["few"] = (1, 2)
for i, word in enumerate(units): words[word] = (1, i)
for i, word in enumerate(tens): words[word] = (1, i * 10)
for i, word in enumerate(scales): words[word] = (10 ** (i * 3 or 2), 0)

def textToInt(text):
	text = text.replace('-', ' ')

	current = result = 0
	for word in text.split():
		if word not in words:
			return None
		scale, increment = words[word]
		current = current * scale + increment
		if scale > 100:
			result += current
			current = 0

	return result + current

times = {'noon': 12, 'afternoon': 15, 'midnight': 0, 'sunrise': 6, 'sunset': 18, 'dawn': 6, 'dusk': 18}
dayOffsets = {'today': 0, 'tomorrow': 1, 'next week': 7, 'next month': 31, 'next year': 365}

def getDate(date=None):
	if date == None:
		date = datetime.now()
	return date.replace(microsecond=0)

def convertDate(date):
	return date.strftime('%A, %b %d, %Y at %H:%M:%S %p')

def dateFromNow(amount, units):
	try:
		amount = int(amount)
	except:
		amount = textToInt(amount)
	if units[-1] != 's':
		units += 's'
	return getDate() + timedelta(**{ units: amount })

def dateWithOffset(h, m, s, ampm, timeOfDay, offset):
	h = int(h) if h else 0
	m = int(m) if m else 0
	s = int(s) if s else 0
	if timeOfDay:
		date = getDate().replace(hour=times[timeOfDay], minute=0, second=0)
	else:
		date = getDate().replace(hour=h, minute=m, second=s)
		if ampm and ampm == 'pm':
			date += timedelta(hours=12)
	if offset:
		date += timedelta(days=dayOffsets[offset])
	return date

def checkDatabase(info, chatId, public, type):
	db = glob.db
	addChatUser = False
	if (chatId, type) not in glob.chats:
		print('Adding Chat: ' + str(chatId))
		addChatUser = True
		db.addChat(chatId, type, public)
		glob.chats[(chatId, type)] = True
	if (info['id'], type) not in glob.users:
		print('Adding User: ' + str(info['id']))
		addChatUser = True
		db.addUser(info['id'], info['first_name'], info['last_name'], info['username'], type)
		glob.users[(info['id'], type)] = True
		glob.messageAdmins('New {} User: {} {}: {} ({})'.format(glob.PLATFORMS[type], info['first_name'], info['last_name'], info['username'], chatId))
	if addChatUser:
		print('Adding Chat User:', chatId, ',', info['id'])
		db.addChatUser(db.getChat(chatId, type)['id'], db.getUser(info['id'], type)['id'])
	return (db.getUser(info['id'], type), db.getChat(chatId, type))

def hash(s):
	ans = 1125899906842597
	for c in s:
		ans = ans * 31 + ord(c)
	return (ans & 0xFFFFFFFFFFFFFFF) ^ ((ans & (0xFFFFFFFFFFFFFFF << 32)) >> 32)

def getInfix(exp):
	i = InfixToPostfix(exp)
	try:
		return i.genPostfix()
	except:
		return None

def getPostfix(exp):
	try:
		e = ExpressionTree(exp)
		return e.eval()
	except:
		return None

def calculate(exp):
	exp = exp.replace('times', '*').replace('minus', '-').replace('to the', '^').replace('power', '').replace('divided by', '/').replace('plus', '+').replace('th', '')
	try:
		e = ExpressionSolver(exp)
		return e.solve()
	except:
		return None


import subprocess

def install_libraries(libraries):
    for library in libraries:
        try:
            __import__(library)
        except ImportError:
            print(f"{library} is not installed. Installing now...")
            subprocess.check_call(["pip", "install", library])
required_libraries = ["pyautogui", "mysql.connector", "tqdm", "colorama"]
install_libraries(required_libraries)

from pyautogui import *
import pyautogui
import mysql.connector
from tqdm import tqdm
from datetime import datetime
import time
import keyboard
import win32api, win32con
import mouse
import math
import os
import uuid
from dateutil.relativedelta import relativedelta
import colorama
from colorama import Fore, Back, Style

print(Fore.YELLOW +'''
  /$$$$$$  /$$$$$$$$ /$$$$$$        /$$    /$$       /$$                           /$$
 /$$__  $$|__  $$__//$$__  $$      | $$   | $$      | $$                          | $$
| $$  \__/   | $$  | $$  \ $$      | $$   | $$      | $$$$$$$  /$$   /$$ /$$$$$$$ | $$   /$$ /$$   /$$
| $$ /$$$$   | $$  | $$$$$$$$      |  $$ / $$/      | $$__  $$| $$  | $$| $$__  $$| $$  /$$/| $$  | $$
| $$|_  $$   | $$  | $$__  $$       \  $$ $$/       | $$  \ $$| $$  | $$| $$  \ $$| $$$$$$/ | $$  | $$
| $$  \ $$   | $$  | $$  | $$        \  $$$/        | $$  | $$| $$  | $$| $$  | $$| $$_  $$ | $$  | $$
|  $$$$$$/   | $$  | $$  | $$         \  $/         | $$$$$$$/|  $$$$$$/| $$  | $$| $$ \  $$|  $$$$$$$
 \______/    |__/  |__/  |__/          \_/          |_______/  \______/ |__/  |__/|__/  \__/ \____  $$
                                                                                /$$  | $$
                                                                                |  $$$$$$/
                                                                                \______/

                                                                                GTAV Automatic Bunker Research bot by arkis0

'''+ Style.RESET_ALL)

mydb = mysql.connector.connect(
    host="",
    user="",
    password="",
    database=""
    )
mycursor = mydb.cursor()

mac_address = uuid.UUID(int=uuid.getnode()).hex[-12:]

now = datetime.now()
current_date_str = now.strftime('%Y-%m-%d %H:%M:%S')
current_date = datetime.strptime(current_date_str, '%Y-%m-%d %H:%M:%S')

sql = "SELECT * FROM license_keys WHERE mac_address = %s AND valid = 1"
mycursor.execute(sql, (mac_address,))

# Get info if license key is valid
myresult = mycursor.fetchone()

if myresult is not None:
    if myresult[2] != '':
        if myresult[4] > current_date:
            print("License key is valid!")
        else:
            print("License key has expired.")
            validation_update_sql = "UPDATE license_keys SET valid = 0 WHERE mac_address = %s"
            mycursor.execute(validation_update_sql, (mac_address,))
            mydb.commit()
            exit()
    else:
        print("License key is empty.")
else:
    print("No valid license key found for this device.")
    print("Do you have a license key? (y/n)")
    answer = input()
    if answer == 'y' or answer == 'Y':
        print("Enter license key:")
        license_key = input()
        key_sql = "SELECT * FROM license_keys WHERE license_key = %s AND valid = 1"
        mycursor.execute(key_sql, (license_key,))

        # Get info if license key is valid
        myresult_key = mycursor.fetchone()
        if myresult_key is None:
            print("License key is not valid.")
            exit()
        elif myresult_key[1] is not None:
            print("License key is already assigned to another device.")
            exit()
        if myresult_key[6] != 0:
            expiration_date = current_date + relativedelta(months=myresult_key[6])
        elif myresult_key[6] == 0:
            expiration_date = datetime.strptime('9999-12-31 23:59:59', '%Y-%m-%d %H:%M:%S')

        sql = "UPDATE license_keys SET mac_address = %s, registration_date = %s, expiration_date = %s WHERE license_key = %s"

        mycursor.execute(sql, (mac_address, current_date, expiration_date, license_key))
        mydb.commit()
        print("License key was assigned to your device! Your key will expire on:", expiration_date)
    if answer == 'n' or answer == 'N':
        print("You can buy license key from owner by contacting him on discord: .arkis / arkis#0001")
        exit()

begin_position = False

def click(x,y):
    win32api.SetCursorPos((x,y))
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
    time.sleep(0.5)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)

def buy_resources():
    time.sleep(2)
    click(458, 494) #zakładka odnawiania
    time.sleep(2)
    click(967, 791) #przycisk kup zasoby
    time.sleep(2)
    click(1070, 620) #potwierdź zakup
    time.sleep(2)
    keyboard.press_and_release('esc') #powrót na home screen
    keyboard.press_and_release('esc') #swobodny widok
    print("Resources were ordered!")

def check_progress_of_research():

    print("Checking progress of research...")
    mydb = mysql.connector.connect(
    host="",
    user="",
    password="",
    database=""
    )
    mycursor = mydb.cursor()

    x = 993
    y = 329
    matching_pixels_research = 0
    total_pixels = 597
    step_size = 4

    for i in tqdm(range(0, total_pixels, step_size)):
        if pyautogui.pixelMatchesColor(x + i, y, (46,135,46)):
            matching_pixels_research += 4

    research_level = math.ceil((matching_pixels_research / total_pixels) * 100)

    print("You have around", research_level, "% of completion on research")

    sql = "INSERT INTO research (research_level) VALUES (%s)"
    mycursor.execute(sql, (research_level,))

    mydb.commit()

def screenshot_of_current_project():
    mydb = mysql.connector.connect(
    host="",
    user="",
    password="",
    database=""
    )
    mycursor = mydb.cursor()
    #? Usuń ostatni rekord z bazy danych
    sql = "DELETE FROM research_screenshots ORDER BY id DESC LIMIT 1"
    mycursor.execute(sql)
    mydb.commit()

    print("Taking screenshot of current project...")
    click(468, 559)
    sleep(1)
    screenshot = pyautogui.screenshot(region=(1233, 468, 360, 360))
    screenshot.save("screenshot.png")
    print("Sending image to database...")

    command = 'curl -X POST -F "image=@screenshot.png" https://r-dev.pl/save_screenshot.php'
    result = subprocess.run(command, shell=True, capture_output=True, text=True)

    if os.path.exists("screenshot.png"):
        os.remove("screenshot.png")

    if result.returncode == 0:
        print("Screenshot was saved to database")
    else:
        print("Error saving screenshot to database")
    keyboard.press_and_release('esc') #powrót na home screen

def check_amount_of_resources():
    print("Checking amount of resources...")
    mydb = mysql.connector.connect(
    host="",
    user="",
    password="",
    database=""
    )
    mycursor = mydb.cursor()
    x = 993
    y = 380
    matching_pixels_resources = 0
    total_pixels = 597

    step_size = 4
    for i in tqdm(range(0, total_pixels, step_size)):
        if pyautogui.pixelMatchesColor(x + i, y, (179, 57, 9)):
            matching_pixels_resources += 4

    resource_amount = math.ceil((matching_pixels_resources / total_pixels) * 100)

    print("You have around", resource_amount, "% of resources")
    if(resource_amount <= 30):
        print("You need to order more resources")
        buy_resources()
    else:
        print("You have sufficient amount of resources")
        keyboard.press_and_release('esc')

    sql = "INSERT INTO resources (resources_amount) VALUES (%s)"
    mycursor.execute(sql, (resource_amount,))
    mydb.commit()

time.sleep(2)

starting_setup = False
last_buy_time = 0
print("Bot won't start until you enter laptop home screen!")
while keyboard.is_pressed('q') == False:
    while starting_setup == False:
        if pyautogui.locateOnScreen('laptop_home_screen_logo.png', region=(0, 0, 1919, 1079), grayscale=True, confidence=0.8) != None:
            print("Laptop home screen detected! Bot is starting")
            starting_setup = True
            time.sleep(0.5)
            click(941, 645)

    check_progress_of_research()
    screenshot_of_current_project()
    check_amount_of_resources()
    time_of_check = time.time()
    print("Anti-kick started working! Next resource check in 15 minutes. Message from: ", time.ctime())
    while time.time() - time_of_check <= 900:
        if pyautogui.locateOnScreen('kick_time.png', region=(0, 0, 820, 1079), grayscale=True, confidence=0.8) != None:
            print("Kick message detected. Proceeding with activity")
            mouse.drag(0, 630, 1919, 630, absolute=True, duration=2)
            mouse.drag(1919, 630, 0, 630, absolute=True, duration=2)
            activity_detected = False
            while activity_detected == False:
                if pyautogui.locateOnScreen('kick_time.png', region=(0, 0, 820, 1079), grayscale=True, confidence=0.8) == None:
                    print("Activity was detected by game")
                    activity_detected = True

                else:
                    print("Activity was not detected by game! Retrying")
                    mouse.drag(0, 630, 1919, 630, absolute=True, duration=2)
                    mouse.drag(1919, 630, 0, 630, absolute=True, duration=2)
    keyboard.press_and_release('enter')
    time.sleep(3)
    if pyautogui.locateOnScreen('laptop_home_screen_logo.png', region=(0, 0, 1919, 1079), grayscale=True, confidence=0.8) != None:
            print("Laptop home screen detected!")
            time.sleep(0.5)
            click(941, 645)


import numpy as np
from scipy.special import binom

class PiecewiseFunction:
    """
    Implements a one-dimensional piecewise function consisting of arbitrarily many intervals.

    When called with an array of function arguments, each array element will be assigned to its appropriate interval
    using a sorted search, where it is evaluated using the corresponding callable defining the local piece of the
    function.
    """

    def __call__(self, X):
        """
        Returns the function values for a given set of input values.

        Parameters
        ----------
        X : float or 1-D array of size M
            Input(s) to the function.

        Returns
        -------
        out : 1-D or 2-D array, shape: (D,) or (M, D)
            Array containing the function values for the given inputs.
        """
        # treat input always as array
        X = np.atleast_1d(X)

        # assert that all inputs lie in the defined interval range
        # if self.assign_right:
        #     assert np.all(self.grid[0] <= X) and np.all(X < self.grid[-1])
        # else:
        #     assert np.all(self.grid[0] < X) and np.all(X <= self.grid[-1])

        # create array to store the function values
        y = np.zeros((X.size, self.dims))

        # assign all inputs to their corresponding intervals
        if self.assign_right:
            inds = np.minimum(np.searchsorted(self.grid, X, side='right'), len(self.grid)) - 1
        else:
            inds = np.maximum(np.searchsorted(self.grid, X), 0) - 1
        inds = np.clip(inds, 0, np.size(self.grid)-2)

        # evaluate inputs one by one
        for i, (x, ind) in enumerate(zip(X, inds)):
            y[i] = self.funs[ind](x)

        # if input was a single number, convert output to 1-D array
        if X.size == 1:
            y = y[0]

        # return function values
        return y

    def __init__(self, grid, funs, assign_right=False, dims=None):
        """
        Creates a new piecewise function f:R->R^D consisting of N pieces.

        Parameters
        ----------
        grid : 1-D array, shape: (N+1,)
            Sorted array defining the interval boundaries of the piecewise function.

        funs : list of length N containing callables
            Defines the N pieces of the function.

        assign_right : boolean
            Defines whether input values that coincide with the grid points are assigned to the left or right interval.

        dims : optional, int
            Dimension D of the function's codomain. If not provided, it will be inferred by calling the first callable.
        """
        assert np.all(np.diff(grid) > 0)  # assert that the grid is sorted and contains unique values
        assert np.size(grid) == len(funs) + 1  # assert that there are as many functions as intervals
        self.grid = np.array(grid)
        self.funs = funs
        self.assign_right = assign_right
        self.dims = dims if dims is not None else np.size(funs[0](grid[0]))

def transpose_callable(f):
    """Returns a callable whose output is the transposed of the input callable."""
    def transposed(x):
        return f(x).T
    return transposed

def fixed_sum_tuples(length, sum_value):
    """
    Generates all integer tuples of a given length whose entries sum to a certain value.

    Parameters
    ----------
    length : int
        Length of the tuples.

    sum_value : int
        Sum of the entries of each tuple.

    Yields
    ------
    out : tuple
        The next integer tuple.
    """
    if length == 1:
        yield (sum_value,)
        return
    for i in range(sum_value + 1):
        for t in fixed_sum_tuples(length - 1, sum_value - i):
            yield (i,) + t

def n_fixed_sum_tuples(length, sum_value):
    """
    Computes the number of possible integer tuples of a given length whose entries sum to a certain value.

    Parameters
    ----------
    length : int
        Length of the tuples.

    sum_value : int
        Sum of the entries of each tuple.

    Yields
    ------
    out : int
        Number of tuples.
    """
    return int(binom(length + sum_value - 1, length - 1))

def _to_tuple(x):
    """
    Converts an object into a tuple. If the object is not iterable, creates a one-element tuple containing the object.

    Parameters
    ----------
    x : object

    Returns
    -------
    out : tuple
        Tuple representing the object.
    """
    try:
        return tuple(x)
    except TypeError:
        return x,


from typing import NamedTuple, Optional, Tuple
from uuid import UUID

from pyminehub.mcpe.command.const import CommandPermission, CommandOriginDataType

__all__ = [
    'CommandEnum',
    'CommandParameter',
    'CommandData',
    'CommandSpec',
    'CommandOriginData'
]

CommandEnum = NamedTuple('CommandEnum', [
    ('name', str),
    ('index', Tuple[int, ...])
])

CommandParameter = NamedTuple('CommandParameter', [
    ('name', str),
    ('type', int),
    ('is_optional', bool)
])

CommandData = NamedTuple('CommandData', [
    ('name', str),
    ('description', str),
    ('flags', int),
    ('permission', int),
    ('aliases', int),
    ('overloads', Tuple[Tuple[CommandParameter, ...], ...])
])

CommandSpec = NamedTuple('CommandSpec', [
    ('enum_values', Tuple[str, ...]),
    ('postfixes', Tuple[str, ...]),
    ('enums', Tuple[CommandEnum, ...]),
    ('command_data', Tuple[CommandData, ...]),
    ('permission', CommandPermission)
])

CommandOriginData = NamedTuple('CommandOriginData', [
    ('type', CommandOriginDataType),
    ('uuid', UUID),
    ('request_id', str),
    ('long1', Optional[int])
])


#!/usr/bin/env python3

import json,sys

data=json.load(sys.stdin)

if len(data) == 0:
    print("No data")
else:
    for issue in data:
        fileName = ".git/issues/{0}".format(issue["number"])
        f = open(fileName, "w")
        f.write(issue["title"])
        f.close()