import os
from random import shuffle
import tensorflow as tf
import glob
from config import config

# all functions except init and create_iterators should be empty
class Preprocessing:
    def __init__(self):
        print('preprocessing instance creation started')

        self.dir_name = config['data_dir']
        self.input_len = config['input_len']
        #maybe add later noise augmentation

    def create_iterators(self):
        # get the filenames split into train test validation
        test_files = self.get_files_from_txt('testing_list.txt')
        val_files = self.get_files_from_txt('validation_list.txt')
        filenames = glob.glob(os.path.join(self.dir_name, '*/**.wav'), recursive=True)
        filenames = [filename for filename in filenames if 'background_noise' not in filename]
        train_files = list(set(filenames) - set(val_files) - set(test_files))
        shuffle(train_files)
        # get the commands and some prints
        self.commands = self.get_commands()
        self.num_classes = len(self.commands)
        print('len(train_data)', len(train_files))
        print('prelen(test_data)', len(test_files))
        print('len(val_data)', len(val_files))
        print('commands: ', self.commands)
        print('number of commands: ', len(self.commands))

        # make tf dataset object
        train_dataset = self.make_tf_dataset_from_list(train_files)
        val_dataset = self.make_tf_dataset_from_list(val_files, is_validation = True)
        test_dataset = self.make_tf_dataset_from_list(test_files)
        return train_dataset, val_dataset, test_dataset

    def get_files_from_txt(self, which_txt):
        assert which_txt == 'testing_list.txt' or which_txt == 'validation_list.txt', 'wrong argument'
        path = os.path.join(self.dir_name, which_txt)
        with open(path) as f:
            paths = f.readlines()
        paths = [os.path.join(self.dir_name, path[:len(path) - 1]) for path in paths]
        shuffle(paths)
        return paths

    def get_commands(self):
        dirs = glob.glob(os.path.join(self.dir_name, "*", ""))
        commands = [os.path.split(os.path.split(dir)[0])[1] for dir in dirs if 'background' not in dir]
        return commands

    @staticmethod
    def decode_audio(audio_binary):
        audio, _ = tf.audio.decode_wav(audio_binary)
        return tf.squeeze(audio, axis=-1)

    def get_label(self, file_path):
        parts = tf.strings.split(file_path, os.path.sep)
        label = parts[-2]
        label_id = tf.argmax(label == self.commands)
        label = tf.one_hot(label_id, self.num_classes)
        return label

    def make_tf_dataset_from_list(self, filenames_list, is_validation = False):
        files = tf.data.Dataset.from_tensor_slices(filenames_list)
        dataset = files.map(self.get_waveform_and_label, num_parallel_calls=tf.data.AUTOTUNE)
        dataset = dataset.map(self.pad_map_func, num_parallel_calls=tf.data.AUTOTUNE)
        dataset = dataset.shuffle(buffer_size=5000, reshuffle_each_iteration=True)
        if is_validation:
            dataset = dataset.repeat()
        dataset = dataset.batch(config['train_params']['batch_size']).prefetch(tf.data.AUTOTUNE)
        return dataset

    def get_waveform_and_label(self, file_path):
        label = self.get_label(file_path)
        audio_binary = tf.io.read_file(file_path)
        waveform = self.decode_audio(audio_binary)
        return waveform, label

    def pad_map_func(self, audio, label):
        return [self.add_paddings(audio), label]

    def add_paddings(self, wav):
        len_wav = len(wav)
        if len_wav < self.input_len:
            paddings = tf.zeros((self.input_len - len_wav))
            wav = tf.concat([wav, paddings], axis=0)
        return wav


import numpy as np
import cv2

img = cv2.imread('/Users/macbookair/PycharmProjects/PR/homework2/unpro.jpg')
bg = cv2.imread('/Users/macbookair/PycharmProjects/PR/homework2/back2.png')#---->3750*2500
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (1250,25,2000,2325)
# rect = (1,1,l-2,w-2)
#1250 25 2400 2450

cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
mask2 = cv2.erode(mask2,None,iterations=2)
mask2 = cv2.dilate(mask2,None,iterations=1)
mask_inv = np.where((mask2==0),1,0).astype('uint8')

img1 = img*mask2[:,:,np.newaxis]
img2 = bg*mask_inv[:,:,np.newaxis]
dst=cv2.addWeighted(img1,1,img2,1,0)
cv2.imshow('output',dst)
cv2.imwrite('output.jpg',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()


import pandas as pd
from config import CONFIG_DICT
import networkx as nx
import matplotlib.pyplot as plt
import random
import cv2
import numpy as np
import math
from MplCanvas import MplCanvas

import Equirec2Perspec as E2P
new_min = -100
new_max = 100
lat_min = 40.42524817            ## this is for first 500 in pittsburg need to generalize this for all places
lat_max = 40.44497464
long_min = -80.03468568
long_max = -79.98858816

class DataHelper():

    def __init__(self):

        self.G = nx.Graph()
        self.end_points = []

        # Create canvas for plot rendering:
        self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
        self.bev_graph = MplCanvas(self, width=5, height=4, dpi=100)
        self.xdata = []
        self.ydata = []

        # Set of visited locations.
        self.visited_locations = set()

        self.read_routes(CONFIG_DICT["csv_file"])

    def new_lat_scale(self, x):
        normalized_new_val = ((x - lat_min) / (lat_max - lat_min) * (new_max - new_min)) + new_min
        return normalized_new_val

    def new_long_scale(self, x):
        normalized_new_val = ((x - long_min) / (long_max - long_min) * (new_max - new_min)) + new_min
        return normalized_new_val

    def image_name(self, pos):
        return self.image_names[pos]

    def panorama_split(self, theta, image, resolution = (720, 1080)):
        print("\n")
        print("Showing image: ", image + ".jpg")
        print("Current viewing angle: ", theta)
        print("\n")
        equ = E2P.Equirectangular("data/Pittsburgh/"+image+".jpg")  # Load equirectangular image

        #
        # FOV unit is degree
        # theta is z-axis angle(right direction is positive, left direction is negative)
        # phi is y-axis angle(up direction positive, down direction negative)
        # height and width is output image dimension
        #

        img = equ.GetPerspective(90, -theta, 0, *resolution)  # Specify parameters(FOV, theta, phi, height, width)

        return img

    def build_graph(self, data):
        i = 0
        prev_route = -1
        prev_pos = (-1,-1)
        prev_name = "abc"
        x = []
        y = []
        print("\n")
        print("Building graph. \n")
        for index, row in data.iterrows():
            route_no = row['route_no']
            lat = row['latitude']
            long = row['longitude']
            scaled_lat = self.new_lat_scale(lat)
            scaled_long = self.new_long_scale(long)
            image_name = row['image_name']
            current_node = (scaled_lat,scaled_long)
            if (image_name not in self.G):
                self.G.add_node((scaled_lat,scaled_long),image_name = image_name, latitude = lat, longitude=long, yaw =row['yaw'], )  # saves a node as image name
                #print((scaled_lat,scaled_long), image_name)
                if route_no == prev_route and prev_pos != (-1,-1): # Why is prev_pos only compares to one integer while it is a tuple?
                    # So the edges only connect nodes of the same route?
                    #print("adding edge")
                    x.append(scaled_lat) # What are these x, y lists for? Look at the elif below.
                    y.append(scaled_long)
                    self.G.add_edge(prev_pos, current_node)   # need to add something like a direction on this edge like right left straight...

                elif route_no != prev_route:                                       ## going to a new route
                    plt.plot(x, y, '-o', linewidth=1, markersize=2) # x and y used to plot the previous route.
                    if(prev_pos!= (-1,-1)): # end_points mean the end point of each route.
                        self.end_points.append(prev_pos)
                    x=[]
                    y=[]

            prev_pos = current_node
            prev_route = route_no
        #save the graph as a json?
        self.image_names = nx.get_node_attributes(self.G, 'image_name')
        plt.savefig("filename5.png")

    def read_routes(self, csv_file = "data/pittsburg_500.csv" ):
        data = pd.read_csv(csv_file, keep_default_na=False)
        self.build_graph(data)

    def find_adjacent(self, pos, action = "next"):
        #print("Finding next position based on action/direction and position \n")
        if action == "next":
            #print(self.end_points)
            #print("Current node: \n", pos)
            #print("Adjacent nodes and edges: \n", (self.G.adj[pos])) # Finding adjacent nodes and edges to pos node.
            #adj_nodes_list = [keys for keys,value in self.G.adj[pos].items()]
            #print("Coordinate of the adjacent nodes: \n", adj_nodes_list)

            return list([keys for keys,value in self.G[pos].items()]) # Return list of keys of nodes adjacent to node with key pos.

    def reset(self):
        # reset the position of the agent
        print("Resets the position to a start \n")
        #i = random.choice(range(len(self.end_points)))
        i = 1000
        return self.end_points[i]

    def sample_location(self):

        location_list = [keys for keys, values in self.G.nodes.items()]
        location = random.choice(location_list)

        return location

    # Function to find the distances to adjacent nodes.
    # This is used to check to see if the node found is actually the nearest node.
    def find_distances(self, pos, adj_nodes_list):

        distance_list = []

        for node in adj_nodes_list:
            distance_list.append(np.linalg.norm(np.array(pos) - np.array(node)))

        return distance_list

    def fix_angle(self, angle):

        if angle < 0:
            angle = 360 + angle
        elif angle >= 360:
            angle = angle - 360

        return angle

    # This function should also convert from triangular to abosulute angle?
    def get_angle(self, curr, prev):
        if (curr[0] - prev[0]) != 0 :
            slope = (curr[1] - prev[1]) / (curr[0] - prev[0])
        else:
            return 0
        #print(slope)
        angle = math.degrees(math.atan(slope))
        # The direction is from the second to the fourth quadrant.
        # So angle is negative.
        if (curr[0] > prev[0] and curr[1] < prev[1]):
            angle = 360 + angle
        # Direction: from fourth to second quadrant.
        # Angle is negative.
        elif (curr[0] < prev[0] and curr[1] > prev[1]):
            angle = 180 + angle
        # Direction: from first to third.
        # Angle is positive.
        elif (curr[0] < prev[0] and curr[1] < prev[1]):
            angle = 180 + angle

        #angle = fix_angle(angle)
        return angle

    # Convention we are using: in the angle_range, the first value always represent the right boundary of the cone.
    # While the second value represent the left boundary of the cone.
    # This function return 1 if angle is in range, 0 if not.
    def angle_in_range(self, angle, angle_range):
        # This is the case where the fix_angle adjusted the angle to be only from 0 to 360.
        if angle_range[0] > angle_range[1]:
            if angle < angle_range[1] or angle > angle_range[0]:
                return 1
            else:
                return 0
        # This is the regular case:
        else:
            if angle > angle_range[0] and angle < angle_range[1]:
                return 1
            else:
                return 0

    # Note on the process of finding the nearest node:
    # My speculation:
    # 1. Find the current angle cone of the agent, which is where the agent is looking in absolute angles.
    # 2. Then get the adjacent nodes' absolute angles. Note: adjacent is defined as being connected by an edge.
    # 3. Filter the adjacent nodes by fov cone using the abosolute angles.
    # 4. Move to the nearest node within the cone.
    # Note: Process of graph creation: Dynamic_plot.py called build_graph. Build_graph go through every line
    # of the csv file then add all the nodes. What about edges?

    def find_nearest(self, curr_pos, prev_pos,curr_angle, direction):
        print("\n")

        # This is the view angle.
        center_angle = self.fix_angle(curr_angle)

        # The search angle is based on positions. Independent of viewing angle.
        search_angle = self.get_angle(curr_pos, prev_pos)

        left_bound = self.fix_angle(search_angle+90)
        right_bound = self.fix_angle(search_angle-90)

        # Check the current view angle against the search angle range:
        if direction == "forward":

            if self.angle_in_range(curr_angle, (right_bound, left_bound)) :
                search_angle_range = (right_bound , left_bound)
            else:
                search_angle_range = (left_bound, right_bound)

        elif direction == "backward":

            if self.angle_in_range(curr_angle, (right_bound, left_bound)) :
                search_angle_range = (left_bound , right_bound)
            else:
                search_angle_range = (right_bound, left_bound)

        print("Current center angle: ", center_angle)
        next_pos_list = self.find_adjacent(curr_pos) # This is a list of adjacent nodes to node agents_pos_1
        decision = curr_pos
        image_name = self.image_name(curr_pos)
        print("Current node: ", curr_pos)
        print("Possible next nodes: ", len(next_pos_list))
        print("List of adjacent nodes: ", next_pos_list)
        print("Distances from current node to the adjacent nodes: ", self.find_distances(curr_pos, next_pos_list))
        print("Search angle range: ", search_angle_range)
        filtered_pos_list = []
        # Filtering the adjacent nodes by angle cone.
        for pos in next_pos_list:
            # Getting the angle between the current nodes and all adjacent nodes.
            angle = self.get_angle(pos, curr_pos)
            print("Angle from ", curr_pos,"to ", pos, "is ", angle)

            if self.angle_in_range(angle, search_angle_range):
                filtered_pos_list.append(pos)

        print("Filtered adjacent nodes list: ", filtered_pos_list)

        if (len(filtered_pos_list) == 0):

            print("\n")
            print("No nodes found. Agent standing still.")

        else:

            filtered_distances_list = self.find_distances(curr_pos, filtered_pos_list)
            print("Distances from current node to the filtered adjacent nodes: ", filtered_distances_list)
            print("Index of min value: ", (min(filtered_distances_list)))
            decision = filtered_pos_list[filtered_distances_list.index(min(filtered_distances_list))]
            print("The nearest node within the angle cone is: " , decision)
            print("Found a node within the angle cone. New node position: ", decision)
            image_name = self.image_name(decision)
            print("Showing new node's image: ", image_name)

        self.panorama_split(center_angle, image_name)
        return decision, image_name, center_angle

    # The next two functions help in the render method.
    def draw_angle_cone(self, curr_pos, angle, color = 'm'):

        x = curr_pos[0]
        y = curr_pos[1]

        angle_range = [self.fix_angle(angle - 45), self.fix_angle(angle + 45)]
        line_length = 50

        for angle in angle_range:

            end_y = y + line_length * math.sin(math.radians(angle))
            end_x = x + line_length * math.cos(math.radians(angle))

            self.canvas.axes.plot([x, end_x], [y, end_y], ':' + color)

        self.canvas.draw()

    def update_plot(self, curr_pos, prev_pos, curr_angle):

        y_prev = prev_pos[1]
        x_prev = prev_pos[0]

        y = curr_pos[1]
        x = curr_pos[0]

        self.ydata = self.ydata + [y]
        self.xdata = self.xdata + [x]

        self.canvas.axes.cla()  # Clear the canvas.
        self.canvas.axes.plot(self.xdata, self.ydata, '-ob')

        adj_nodes_list = [keys for keys, values in self.G.adj[(x,y)].items()]
        num_adj_nodes = len(adj_nodes_list)
        adj_nodes_list = np.array( [[x_coor, y_coor] for x_coor, y_coor in adj_nodes_list])

        x_pos_list = np.array([x] * num_adj_nodes)
        y_pos_list = np.array([y] * num_adj_nodes)

        self.canvas.axes.plot([x_pos_list,adj_nodes_list[:,0]], [y_pos_list, adj_nodes_list[:,1]], '--or')
        self.canvas.axes.plot(x, y, color = 'green', marker = 'o')
        self.canvas.axes.text(x, y, '({}, {})'.format(x, y))
        self.canvas.axes.plot(x_prev, y_prev, color = 'purple', marker = 'o')

        # Current view of the agent.
        self.draw_angle_cone(curr_pos, curr_angle, color = 'g')

        self.canvas.axes.set_xlim([new_min, new_max])
        self.canvas.axes.set_ylim([new_min, new_max])

        self.canvas.draw()

        self.canvas.show()

    def bird_eye_view(self, curr_pos, radius):

        adjacent_pos_list = self.find_adjacent(curr_pos)
        distances_list = self.find_distances(curr_pos, adjacent_pos_list)
        in_range_nodes_list = []

        for distance, pos in zip(distances_list, adjacent_pos_list):

            if distance <= radius:

                in_range_nodes_list.append(pos)

        if len(in_range_nodes_list) == 0:

            print("No nodes found in range for bird eye's view.")
            return None

        bird_eye_graph = self.G.subgraph(in_range_nodes_list)

        return bird_eye_graph

    def draw_bird_eye_view(self, curr_pos, radius, graph):

        #self.bev_graph.axes.cla()

        nodes_list = [keys for keys, values in graph.nodes().items()]

        num_nodes = len(nodes_list)

        nodes_list = np.array([[x_coor, y_coor] for x_coor, y_coor in nodes_list])

        x = curr_pos[0]
        y = curr_pos[1]

        x_pos_list = np.array([x] * num_nodes)
        y_pos_list = np.array([y] * num_nodes)

        self.bev_graph.axes.plot([x_pos_list,nodes_list[:,0]], [y_pos_list, nodes_list[:,1]], '--or')
        self.bev_graph.axes.plot(x, y, color = 'green', marker = 'o')
        self.bev_graph.axes.text(x, y, '({}, {})'.format(x, y))
        self.bev_graph.axes.set_xlim([new_min, new_max])
        self.bev_graph.axes.set_ylim([new_min, new_max])

        # Draw a circle to see if the BEV is done correctly.
        draw_circle= plt.Circle(curr_pos, radius = radius, fill = False)
        self.bev_graph.axes.add_artist(draw_circle)

        self.bev_graph.draw()

        self.bev_graph.show()

    def distance_to_goal(self, curr_pos, goal):

        return np.linalg.norm(np.array(curr_pos) - np.array(goal))


from __future__ import division
from __future__ import print_function
from builtins import range
from past.utils import old_div
from numpy import *
from matplotlib.pyplot import *
import sys

def solver(I, a, T, dt, theta):
    """Solve u'=-a*u, u(0)=I, for t in (0,T]; step: dt."""
    dt = float(dt)           # avoid integer division
    N = int(round(old_div(T,dt)))     # no of time intervals
    T = N*dt                 # adjust T to fit time step dt
    u = zeros(N+1)           # array of u[n] values
    t = linspace(0, T, N+1)  # time mesh

    u[0] = I                 # assign initial condition
    for n in range(0, N):    # n=0,1,...,N-1
        u[n+1] = (1 - (1-theta)*a*dt)/(1 + theta*dt*a)*u[n]
    return u, t

def exact_solution(t, I, a):
    return I*exp(-a*t)

def explore(I, a, T, dt, theta=0.5, makeplot=True):
    """
    Run a case with the solver, compute error measure,
    and plot the numerical and exact solutions (if makeplot=True).
    """
    u, t = solver(I, a, T, dt, theta)  # Numerical solution
    u_e = exact_solution(t, I, a)
    e = u_e - u
    E = sqrt(dt*sum(e**2))
    if makeplot:
        figure()                         # create new plot
        t_e = linspace(0, T, 1001)       # very fine mesh for u_e
        u_e = exact_solution(t_e, I, a)
        plot(t,   u,   'r--o')           # red dashes w/circles
        plot(t_e, u_e, 'b-')             # blue line for u_e
        legend(['numerical', 'exact'])
        xlabel('t')
        ylabel('u')
        title('Method: theta-rule, theta=%g, dt=%g' % (theta, dt))
        theta2name = {0: 'FE', 1: 'BE', 0.5: 'CN'}
        savefig('%s_%g.png' % (theta2name[theta], dt))
        show()
    return E

def define_command_line_options():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--I', '--initial_condition', type=float,
                        default=1.0, help='initial condition, u(0)',
                        metavar='I')
    parser.add_argument('--a', type=float,
                        default=1.0, help='coefficient in ODE',
                        metavar='a')
    parser.add_argument('--T', '--stop_time', type=float,
                        default=1.0, help='end time of simulation',
                        metavar='T')
    parser.add_argument('--makeplot', action='store_true',
                        help='display plot or not')
    parser.add_argument('--dt', '--time_step_values', type=float,
                        default=[1.0], help='time step values',
                        metavar='dt', nargs='+', dest='dt_values')
    return parser

def read_command_line(use_argparse=True):
    if use_argparse:
        parser = define_command_line_options()
        args = parser.parse_args()
        print('I={}, a={}, makeplot={}, dt_values={}'.format(
            args.I, args.a, args.makeplot, args.dt_values))
        return args.I, args.a, args.T, args.makeplot, args.dt_values
    else:
        if len(sys.argv) < 6:
            print('Usage: %s I a on/off dt1 dt2 dt3 ...' % \
                  sys.argv[0]); sys.exit(1)

        I = float(sys.argv[1])
        a = float(sys.argv[2])
        T = float(sys.argv[3])
        makeplot = sys.argv[4] in ('on', 'True')
        dt_values = [float(arg) for arg in sys.argv[5:]]

        return I, a, T, makeplot, dt_values

def main():
    I, a, T, makeplot, dt_values = read_command_line()
    r = {}
    for theta in 0, 0.5, 1:
        E_values = []
        for dt in dt_values:
            E = explore(I, a, T, dt, theta, makeplot=False)
            E_values.append(E)

        # Compute convergence rates
        m = len(dt_values)
        r[theta] = [old_div(log(old_div(E_values[i-1],E_values[i])),
                    log(old_div(dt_values[i-1],dt_values[i])))
                    for i in range(1, m, 1)]

    for theta in r:
        print('\nPairwise convergence rates for theta=%g:' % theta)
        print(' '.join(['%.2f' % r_ for r_ in r[theta]]))
    return r

def verify_convergence_rate():
    r = main()
    tol = 0.1
    expected_rates = {0: 1, 1: 1, 0.5: 2}
    for theta in r:
        r_final = r[theta][-1]
        diff = abs(expected_rates[theta] - r_final)
        if diff > tol:
            return False
    return True  # all tests passed

if __name__ == '__main__':
    if 'verify_rates' in sys.argv:
        sys.argv.remove('verify_rates')
        if not '--dt' in sys.argv:
            print('Must assign several dt values through the --dt option')
            sys.exit(1)  # abort
        if verify_convergence_rate():
            pass
        else:
            print('Bug in the implementation!')
    else:
        # Perform simulations
        main()


import os
import shutil
import subprocess
import time
import pylab
import imageio
import numpy as np
from tqdm import tqdm
from skimage.io import imread, imsave

def create_options(model, epoch):
    opts_test = {
        "loadSize": 512,
        "fineSize": 512,
        "how_many": 'all',
        "phase": 'test',
        "name": model,
        "checkpoints_dir": './checkpoints',
        "results_dir": '.temp_output',
        "which_epoch": str(epoch),
        "which_direction": 'AtoB',
        "resize_or_crop": '"scale_width"',
    }
    return opts_test

def create_bash_cmd_test(opts_test):
    """constructs bash command to run CycleGAN with the given settings"""
    cmd = []
    cmd.append("DATA_ROOT=.temp_input")
    for opt in opts_test.keys():
        cmd.append(opt + "=" + str(opts_test[opt]))
    cmd += ['th', 'test.lua']
    return(" ".join(cmd))

def check_correct_directory():
    """check if the script is being run from CycleGAN"""
    fpath = os.path.realpath(__file__)
    dirname = os.path.dirname(fpath).split('/')[-1]
    if not dirname == "CycleGAN":
        raise ValueError("Script should be run from CycleGAN base directory.")

def prep_directories():
    """ensures clean temporary directories for CycleGAN"""
    for dir_ in ['.temp_input', '.temp_output']:
        if os.path.exists(dir_):
            shutil.rmtree(dir_)
    for dir_ in ['testA', 'testB']:
        os.makedirs(os.path.join('.temp_input', dir_))
    os.makedirs(os.path.join('.temp_output'))

def grab_epochs(model):
    """
    given a model name or a folder path,
    returns an array of available epochs
    """
    if not os.path.isdir(model):
        model = os.path.join('checkpoints', model)
    assert os.path.isdir(model), model + " not a valid model"

    epochs = []
    for file in os.listdir(model):
        if file.split('.')[-1] == "t7":
            epochs.append(file.split('_')[0])
    epochs = [e for e in epochs if not e == 'latest']

    return list(set(epochs))

def test(img, opts):
    """
    performs a test inference on img, saves to a temp directory
    returns the stylized image
    """
    prep_directories()
    for dir_ in ['testA', 'testB']:
        imsave(os.path.join('.temp_input', dir_, 'img.png'), img)

    # run the bash command for test phase of CycleGAN
    cmd = create_bash_cmd_test(opts)

    start = time.time()
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
    process.wait()
    print("Stylizing complete. Time elapsed:", time.time() - start)

    # read image back into python
    path = os.path.join('.temp_output', opts['name'], str(opts['which_epoch']) + "_test", "images", "fake_B", "img.png")
    stylized_img = imread(path)
    return stylized_img

def stylize_image_all_epochs(img_path, output_dir, model):
    """
    processes an image with a model at all available epochs
    """
    imname = os.path.split(img_path)[1].split('.')[0]
    os.makedirs(output_dir, exist_ok=True)

    img = imread(img_path)
    available_epochs = grab_epochs(model)

    for epoch in tqdm(available_epochs):
        opts = create_options(model, epoch)
        stylized_img = test(img, opts)
        imsave(os.path.join(output_dir, imname + "-" + model + "-epoch-" + str(epoch)) + ".png", stylized_img)

def stylize_video(vid_path, out_path, model, epoch):
    """
    stylizes all frames of a video
    """
    video = imageio.get_reader(vid_path, 'mpeg')
    writer = imageio.get_writer(out_path, fps=30)
    opts = create_options(model, epoch)

    # TODO: don't hardcode 30fps downsampling
    for i, frame in enumerate(video):
        if i % 2 == 0:
            frame = test(np.array(frame), opts)
            writer.append_data(frame)
        if i % 10 == 0:
            print(i, "of", len(video), "frames done.")
        if i == len(video) - 10:  # TAKE THIS OUT AFTER DONE TESTING
            break
    writer.close()

def repeat_stylization(img_path, out_dir, n_iter, model, epoch):
    """
    Repeatedly applies a style to an image
    """
    fname = os.path.splitext(img_path)[0].split("/")[-1]
    img = imread(img_path)
    os.makedirs(out_dir, exist_ok=True)
    opts = create_options(model, epoch)

    for i in range(n_iter):
        img = test(img, opts)
        imsave(os.path.join(out_dir, fname + "-" + model + "-" + str(epoch) + "-iter" + i))

def stylize_dir_hacky(input_dir, output_dir):
    """
	this is horrible and last minute
    temporary function to perform stylization
    images: applies 3 available styles at 5 different epochs
    the bean - pop art at all epochs
    northwestern - cubism at all epochs
    video: applies 3 styles to each video
    """
    models = ['cubism_v2', 'impressionism', 'pop_art']
    epochs_img = [50, 100, 150, 200]
    files = os.listdir(input_dir)
    files = [f for f in files if not f[0] == "."]
    os.makedirs(output_dir)

    for file in files:
        filename = file.split(".")[0]
        output_subdir = os.path.join(output_dir, filename + "-stylized")
        os.makedirs(output_subdir, exist_ok=True)

        print("Stylizing", file, "\nSaving to", output_subdir)

        # Videos
        if ".mp4" in file:
            for model in models:
                print("Applying", model, "to", file, ", saving to")
                stylize_video(vid_path=os.path.join(input_dir, file),
                              out_path=os.path.join(output_subdir, file + '-' + model + '.mp4'),
                              model=model,
                              epoch=200)

        # Photos
        else:

            # Images, all epochs, all models
            if file in ['northwestern.jpeg', 'the_bean.jpeg']:
                output_subdir_all_epochs = os.path.join(output_dir, file.split(".")[0] + "-all-epochs")
                os.makedirs(output_subdir_all_epochs, exist_ok=True)
                for model in models:
                    print("Applying", model, "to", file, "all epochs", "\nSaving to", output_subdir_all_epochs)
                    # try:
                    stylize_image_all_epochs(img_path=os.path.join(input_dir, file),
                                             output_dir=output_subdir_all_epochs,
                                             model=model)
                    # except:
                    #     pass

            # Images, only certain styles
            for model in models:
                for epoch in epochs_img:
                    try:
                        img = imread(os.path.join(input_dir, file))
                        opts = create_options(model, epoch)
                        stylized_img = test(img, opts)
                        imsave(os.path.join(output_subdir, filename + "-" + model + "-epoch-" + epoch + ".png"), stylized_img)
                    except:
                        pass

def stylize_image_all_styles(img_path, models):
    pass

if __name__ == "__main__":
    stylize_dir_hacky("input_5-28-17", "output_5-28-17")


#!/usr/bin/env python3

import fnmatch
import os
import re
import ntpath
import sys
import argparse

def get_private_declare(content):
    priv_declared = []

    srch = re.compile('private.*')
    priv_srch_declared = srch.findall(content)
    priv_srch_declared = sorted(set(priv_srch_declared))

    priv_dec_str = ''.join(priv_srch_declared)

    srch = re.compile('(?<![_a-zA-Z0-9])(_[a-zA-Z0-9]*?)[ ,\}\]\)";]')
    priv_split = srch.findall(priv_dec_str)
    priv_split = sorted(set(priv_split))
    priv_declared += priv_split;

    srch = re.compile('params \[.*\]|PARAMS_[0-9].*|EXPLODE_[0-9]_PVT.*|DEFAULT_PARAM.*|KEY_PARAM.*|IGNORE_PRIVATE_WARNING.*')
    priv_srch_declared = srch.findall(content)
    priv_srch_declared = sorted(set(priv_srch_declared))

    priv_dec_str = ''.join(priv_srch_declared)

    srch = re.compile('(?<![_a-zA-Z0-9])(_[a-zA-Z0-9]*?)[ ,\}\]\)";]')
    priv_split = srch.findall(priv_dec_str)
    priv_split = sorted(set(priv_split))

    priv_declared += priv_split;

    srch = re.compile('(?i)[\s]*local[\s]+(_[\w\d]*)[\s]*=.*')
    priv_local = srch.findall(content)
    priv_local_declared = sorted(set(priv_local))

    priv_declared += priv_local_declared;

    return priv_declared

def check_privates(filepath):
    bad_count_file = 0
    def pushClosing(t):
        closingStack.append(closing.expr)
        closing << Literal( closingFor[t[0]] )

    def popClosing():
        closing << closingStack.pop()

    with open(filepath, 'r') as file:
        content = file.read()

        priv_use = []
        priv_use = []

        # Regex search privates
        srch = re.compile('(?<![_a-zA-Z0-9])(_[a-zA-Z0-9]*?)[ =,\^\-\+\/\*\%\}\]\)";]')
        priv_use = srch.findall(content)
        priv_use = sorted(set(priv_use))

        # Private declaration search
        priv_declared = get_private_declare(content)

        if '_this' in priv_declared: priv_declared.remove('_this')
        if '_this' in priv_use: priv_use.remove('_this')

        if '_x' in priv_declared: priv_declared.remove('_x')
        if '_x' in priv_use: priv_use.remove('_x')

        if '_forEachIndex' in priv_declared: priv_declared.remove('_forEachIndex')
        if '_forEachIndex' in priv_use: priv_use.remove('_forEachIndex')
        if '_foreachIndex' in priv_declared: priv_declared.remove('_foreachIndex')
        if '_foreachIndex' in priv_use: priv_use.remove('_foreachIndex')
        if '_foreachindex' in priv_declared: priv_declared.remove('_foreachindex')
        if '_foreachindex' in priv_use: priv_use.remove('_foreachindex')

        missing = []
        for s in priv_use:
            if s.lower() not in map(str.lower,priv_declared):
                if s.lower() not in map(str.lower,missing):
                    missing.append(s)

        if len(missing) > 0:
            print (filepath)

            private_output = 'private[';
            first = True
            for bad_priv in missing:
                if first:
                    first = False
                    private_output = private_output + '"' + bad_priv
                else:
                    private_output = private_output + '", "' + bad_priv

            private_output = private_output + '"];';
            print (private_output)

            for bad_priv in missing:
                print ('\t' + bad_priv)
                bad_count_file = bad_count_file + 1

    return bad_count_file

def main():

    print("#########################")
    print("# Search your Privates  #")
    print("#########################")

    sqf_list = []
    bad_count = 0

    parser = argparse.ArgumentParser()
    parser.add_argument('-m','--module', help='only search specified module addon folder', required=False, default=".")
    args = parser.parse_args()

    for root, dirnames, filenames in os.walk('../addons' + '/' + args.module):
      for filename in fnmatch.filter(filenames, '*.sqf'):
        sqf_list.append(os.path.join(root, filename))

    for filename in sqf_list:
        bad_count = bad_count + check_privates(filename)

    print ("Bad Count {0}".format(bad_count))

if __name__ == "__main__":
    main()


# -*- coding: UTF-8 -*-
# 百度人脸识别：https://ai.baidu.com/ai-doc/FACE/ek37c1qiz#%E4%BA%BA%E8%84%B8%E6%A3%80%E6%B5%8B
from aip import AipFace

from config import BAIDU_ID, BAIDU_KEY, BAIDU_SECRET_KEY

'''
百度人脸识别
优点：可免费使用，个人账户的限制为2QPS,企业账户的限制为10QPS
'''

""" 你的 APPID AK SK """
APP_ID = BAIDU_ID
API_KEY = BAIDU_KEY
SECRET_KEY = BAIDU_SECRET_KEY

client = AipFace(APP_ID, API_KEY, SECRET_KEY)

"""
image = "取决于image_type参数，传入BASE64字符串或URL字符串或FACE_TOKEN字符串"

imageType = "BASE64"

# 调用人脸检测
client.detect(image, imageType)

# 如果有可选参数
options = dict()
options["face_field"] = "age"
options["max_face_num"] = 2
options["face_type"] = "LIVE"
options["liveness_control"] = "LOW"

# 带参数调用人脸检测
client.detect(image, imageType, options)
"""

if __name__ == "__main__":
    url = "https://smartracing.oss-cn-hangzhou.aliyuncs.com/shared/images/profiles/full/1571196895035.jpg"
    options = {
        "face_field": "age,beauty,expression,face_shape,emotion"
    }
    res = client.detect(url, "URL", options)
    face = res['result']['face_list'][0]

    expression = {"none": "不笑", "smile": "微笑", "laugh": "大笑"}
    face_shape = {"square":" 正方形", "triangle": "三角形", "oval": "椭圆", "heart": "心形", "round": "圆形"}
    emotion = {"angry": "愤怒", "disgust": "厌恶", "fear": "恐惧", "happy": "高兴", "sad": "伤心", "surprise": "惊讶", "neutral": "无情绪"}

    print(f"检测年龄：{face['age']},颜值：{face['beauty']},表情：{expression.get(face['expression']['type'])},脸型：{face_shape.get(face['face_shape']['type'])}, 情绪:{emotion.get(face['emotion']['type'])}")


import numpy as np
import matplotlib.pyplot as plt
# data I/O
filename = 'dataset.txt'
file = open(filename, 'r')
data = file.read()
# use set() to count the vacab size
chars = list(set(data))
data_size, vocab_size = len(data), len(chars)
print ('data has %d characters, %d unique.' % (data_size, vocab_size))

# dictionary to convert char to idx, idx to char
char_to_ix = { ch:i for i,ch in enumerate(chars) }
ix_to_char = { i:ch for i,ch in enumerate(chars) }

# hyperparameters
hidden_size = 50 # size of hidden layer of neurons
seq_length = 50 # number of steps to unroll the RNN for
learning_rate = 1e-1
Wxh = np.random.randn(hidden_size, vocab_size)*0.01 # input to hidden
Whh = np.random.randn(hidden_size, hidden_size)*0.01 # hidden to hidden
Why = np.random.randn(vocab_size, hidden_size)*0.01 # hidden to output
bh = np.zeros((hidden_size, 1)) # hidden bias
by = np.zeros((vocab_size, 1)) # output bias
def lossFun(inputs, targets, hprev):

  xs, hs, ys, ps = {}, {}, {}, {}
  ## record each hidden state of
  hs[-1] = np.copy(hprev)
  loss = 0
  # forward pass for each training data point
  for t in range(len(inputs)):
    xs[t] = np.zeros((vocab_size, 1)) # encode in 1-of-k representation
    xs[t][inputs[t]] = 1

    ## hidden state, using previous hidden state hs[t-1]
    hs[t] = np.tanh(np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t-1]) + bh)
    ## unnormalized log probabilities for next chars
    ys[t] = np.dot(Why, hs[t]) + by
    ## probabilities for next chars, softmax
    ps[t] = np.exp(ys[t]) / np.sum(np.exp(ys[t]))
    ## softmax (cross-entropy loss)
    loss += -np.log(ps[t][targets[t], 0])

  # backward pass: compute gradients going backwards
  dWxh, dWhh, dWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
  dbh, dby = np.zeros_like(bh), np.zeros_like(by)
  dhnext = np.zeros_like(hs[0])
  for t in reversed(range(len(inputs))):
    ## compute derivative of error w.r.t the output probabilites
    ## dE/dy[j] = y[j] - t[j]
    dy = np.copy(ps[t])
    dy[targets[t]] -= 1 # backprop into y

    ## output layer doesnot use activation function, so no need to compute the derivative of error with regard to the net input
    ## of output layer.
    ## then, we could directly compute the derivative of error with regard to the weight between hidden layer and output layer.
    ## dE/dy[j]*dy[j]/dWhy[j,k] = dE/dy[j] * h[k]
    dWhy += np.dot(dy, hs[t].T)
    dby += dy

    ## backprop into h
    ## derivative of error with regard to the output of hidden layer
    ## derivative of H, come from output layer y and also come from H(t+1), the next time H
    dh = np.dot(Why.T, dy) + dhnext
    ## backprop through tanh nonlinearity
    ## derivative of error with regard to the input of hidden layer
    ## dtanh(x)/dx = 1 - tanh(x) * tanh(x)
    dhraw = (1 - hs[t] * hs[t]) * dh
    dbh += dhraw

    ## derivative of the error with regard to the weight between input layer and hidden layer
    dWxh += np.dot(dhraw, xs[t].T)
    dWhh += np.dot(dhraw, hs[t-1].T)
    ## derivative of the error with regard to H(t+1)
    ## or derivative of the error of H(t-1) with regard to H(t)
    dhnext = np.dot(Whh.T, dhraw)

  for dparam in [dWxh, dWhh, dWhy, dbh, dby]:
    np.clip(dparam, -5, 5, out=dparam) # clip to mitigate exploding gradients

  return loss, dWxh, dWhh, dWhy, dbh, dby, hs[len(inputs)-1]

## given a hidden RNN state, and a input char id, predict the coming n chars
def sample(h, seed_ix, n):

  ## a one-hot vector
  x = np.zeros((vocab_size, 1))
  x[seed_ix] = 1

  ixes = []
  for t in range(n):
    ## self.h = np.tanh(np.dot(self.W_hh, self.h) + np.dot(self.W_xh, x))
    h = np.tanh(np.dot(Wxh, x) + np.dot(Whh, h) + bh)
    ## y = np.dot(self.W_hy, self.h)
    y = np.dot(Why, h) + by
    ## softmax
    p = np.exp(y) / np.sum(np.exp(y))
    ## sample according to probability distribution
    ix = np.random.choice(range(vocab_size), p=p.ravel())

    ## update input x
    ## use the new sampled result as last input, then predict next char again.
    x = np.zeros((vocab_size, 1))
    x[ix] = 1

    ixes.append(ix)

  return ixes

## iterator counter
n = 0
## data pointer
p = 0

mWxh, mWhh, mWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)
mbh, mby = np.zeros_like(bh), np.zeros_like(by) # memory variables for Adagrad
smooth_loss = -np.log(1.0/vocab_size)*seq_length # loss at iteration 0
l=[]
sl=[]
## main loop
while True:
  # prepare inputs (we're sweeping from left to right in steps seq_length long)
  if p + seq_length + 1 >= len(data) or n == 0:
    # reset RNN memory
    ## hprev is the hiddden state of RNN
    hprev = np.zeros((hidden_size, 1))
    # go from start of data
    p = 0

  inputs = [char_to_ix[ch] for ch in data[p : p + seq_length]]
  targets = [char_to_ix[ch] for ch in data[p + 1 : p + seq_length + 1]]

  # sample from the model now and then
  if n % 1000 == 0:
    sample_ix = sample(hprev, inputs[0], 5000)
    txt = ''.join(ix_to_char[ix] for ix in sample_ix)
    print ('---- sample -----')
    print ('----\n %s \n----' % (txt, ))

  # forward seq_length characters through the net and fetch gradient
  loss, dWxh, dWhh, dWhy, dbh, dby, hprev = lossFun(inputs, targets, hprev)
  ## author using Adagrad(a kind of gradient descent)
  smooth_loss = smooth_loss * 0.999 + loss * 0.001
  if n % 1000 == 0:
    print ('iter %d, loss: %f' % (n, smooth_loss)) # print progress
    l.append(n)
    sl.append(smooth_loss)
  for param, dparam, mem in zip([Wxh, Whh, Why, bh, by],
                                [dWxh, dWhh, dWhy, dbh, dby],
                                [mWxh, mWhh, mWhy, mbh, mby]):
    mem += dparam * dparam
    param += -learning_rate * dparam / np.sqrt(mem + 1e-8)

  p += seq_length # move data pointer
  n += 1 # iteration counter

# gradient checking

from random import uniform
def gradCheck(inputs, target, hprev):
  global Wxh, Whh, Why, bh, by
  num_checks, delta = 10, 1e-5
  _, dWxh, dWhh, dWhy, dbh, dby, _ = lossFun(inputs, targets, hprev)
  for param,dparam,name in zip([Wxh, Whh, Why, bh, by], [dWxh, dWhh, dWhy, dbh, dby], ['Wxh', 'Whh', 'Why', 'bh', 'by']):
    s0 = dparam.shape
    s1 = param.shape
    if(s0 == s1):
        print('Error dims dont match: %s and %s.' % (s0, s1))
    print (name)
    for i in range(num_checks):
      ri = int(uniform(0,param.size))

      old_val = param.flat[ri]
      param.flat[ri] = old_val + delta
      cg0, _, _, _, _, _, _ = lossFun(inputs, targets, hprev)
      param.flat[ri] = old_val - delta
      cg1, _, _, _, _, _, _ = lossFun(inputs, targets, hprev)
      param.flat[ri] = old_val
      grad_analytic = dparam.flat[ri]
      grad_numerical = (cg0 - cg1) / ( 2 * delta )
      rel_error = abs(grad_analytic - grad_numerical) / abs(grad_numerical + grad_analytic)
      print ('%f, %f => %e ' % (grad_numerical, grad_analytic, rel_error))

gradCheck(inputs,targets,hprev)

plt.plot(loss,smoothloss,label='Epoch Loss')

plt.xlabel('Epochs')

plt.ylabel('Loss')

plt.title('EPOCH _LOSS PLOT')

plt.legend()

plt.show()


import cv2
import numpy as np
from PIL import Image

# Load the image
img = cv2.imread('ParkingLot.jpg')
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply edge detection
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# Apply Hough line detection
lines = cv2.HoughLines(edges, rho=1, theta=np.pi/180, threshold=100)
# Cluster the detected lines
line_clusters = []
for line in lines:
    rho, theta = line[0]
    if len(line_clusters) == 0:
        line_clusters.append([(rho, theta)])
    else:
        found_cluster = False
        for cluster in line_clusters:
            if abs(cluster[0][0] - rho) < 50 and abs(cluster[0][1] - theta) < np.pi/36:
                cluster.append((rho, theta))
                found_cluster = True
                break
        if not found_cluster:
            line_clusters.append([(rho, theta)])
# Find intersection points
intersections = []
for cluster in line_clusters:
    for i in range(len(cluster)):
        rho1, theta1 = cluster[i]
        for j in range(i+1, len(cluster)):
            rho2, theta2 = cluster[j]
            A = np.array([[np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)]])
            b = np.array([rho1, rho2])
            x, y = np.linalg.solve(A, b)
            if x >= 0 and x < img.shape[1] and y >= 0 and y < img.shape[0]:
                intersections.append((int(x), int(y)))
# Find parking space polygons
polygons = []
for i in range(len(intersections)):
    for j in range(i+1, len(intersections)):
        for k in range(j+1, len(intersections)):
            for l in range(k+1, len(intersections)):
                p1, p2, p3, p4 = intersections[i], intersections[j], intersections[k], intersections[l]
                sides = [cv2.norm(np.array(p1) - np.array(p2)),
                         cv2.norm(np.array(p2) - np.array(p3)),
                         cv2.norm(np.array(p3) - np.array(p4)),
                         cv2.norm(np.array(p4) - np.array(p1))]
                if all(side > 30 for side in sides):
                    area = cv2.contourArea(np.array([p1, p2, p3, p4]))
                    if area > 1000:
                        polygons.append([p1, p2, p3, p4])

# Draw the polygons on the image
for i, parking_space in enumerate(polygons):
    pts = np.array(parking_space, np.int32)
    pts = pts.reshape((-1, 1, 2))
    cv2.polylines(img, [pts], True, (0, 255, 0), thickness=2)

# Display the image with polygons drawn
cv2.imshow('Parking Lot with Polygons', img)
cv2.waitKey(0)
cv2.destroyAllWindows()


import pytest
from collections import Counter
from ottoscript.base import OttoBase, OttoContext
from ottoscript.datatypes import (Number,
                                  String,
                                  Var,
                                  Entity,
                                  List,
                                  Dict,
                                  Target,
                                  Area,
                                  Input)

@pytest.mark.asyncio
async def test_numeric():
    """Verify we correctly parse a number"""

    n = Number().parseString("15")[0]
    output = await n.eval()
    assert output == 15

@pytest.mark.asyncio
async def test_string():
    """Verify we correctly parse a string"""

    n = String().parseString("'foo'")[0]
    output = await n.eval()
    assert output == 'foo'

@pytest.mark.asyncio
async def test_var_no_fetch():
    """Verify we correctly parse a var"""

    n = Var().parseString("@foo")[0]
    assert n.name == '@foo'

@pytest.mark.asyncio
async def test_var_with_attributes():
    """Verify we correctly parse a var with attributes"""

    ctx = OttoContext()
    d_string = "(one=1, two=2)"
    e_string = "ship.crew"
    ctx.update_vars({'@foo_entity': Entity().parseString(e_string)[0]})
    ctx.update_vars({'@foo_dict': Dict().parseString(d_string)[0]})
    OttoBase.set_context(ctx)

    n = Var().parseString("@foo_entity:name")[0]
    r = await n.eval()
    assert r == "ship.crew"

    n = Var().parseString("@foo_entity:brightness")[0]
    r = await n.eval()
    assert r == 1

    r = n.fetch()
    assert r.name == "ship.crew.brightness"

    n = Var().parseString("@foo_entity:number")[0]
    r = await n.eval()
    assert r == 1

    n = Var().parseString("@foo_dict:one")[0]
    r = await n.eval()
    assert r == 1

    n = Var().parseString("@foo_dict:two")[0]
    r = await n.eval()
    assert r == 2

@pytest.mark.asyncio
async def test_entity():
    """Verify we correctly parse an entity"""
    test_list = [('ship.crew', 'ship.crew', 'ship.crew'),
                 ('ship.crew:uniform', 'ship.crew.uniform', 1)
                 ]

    for test in test_list:
        n = Entity().parseString(test[0])[0]
        assert n.name == test[1]
        assert await n.eval() == test[2]

@pytest.mark.asyncio
async def test_list():
    """Verify we correctly parse a list"""

    ctx = OttoContext()
    ctx.update_vars({'@foo': 'foostring'})
    OttoBase.set_context(ctx)

    string = "'test1', 27, ship.crew, @foo"
    expected = [String().parseString('"test1"')[0],
                Number().parseString('27')[0],
                Entity().parseString('ship.crew')[0],
                Var().parseString('@foo')[0]]

    n1 = List().parseString(string)[0]

    assert Counter([type(x) for x in n1.contents]) \
        == Counter([type(x) for x in expected])

    n2 = List().parseString(f"({string})")[0]
    assert Counter([type(x) for x in n2.contents]) \
        == Counter([type(x) for x in expected])

@pytest.mark.asyncio
async def test_list_single():
    """Verify we correctly parse a number"""

    string = "ship.crew"
    expected = list

    n1 = List().parseString(string)[0]

    assert type(n1.contents) == expected

@pytest.mark.asyncio
async def test_dictionary():
    """Verify we correctly parse a dictionary"""

    ctx = OttoContext()
    ctx.update_vars({'@foo': 'foostring'})
    OttoBase.set_context(ctx)

    string = "(first = 1, second = 'foo', third = ship.crew, fourth = @foo)"
    expected = {'first': 1,
                'second': 'foo',
                "third": 'ship.crew',
                "fourth": 'foostring'}

    n1 = Dict().parseString(string)[0]

    result = await n1.eval()
    assert result == expected

@pytest.mark.asyncio
async def test_target():

    ctx = OttoContext()
    area = Area().parseString('kitchen')[0]
    ctx.update_vars({'@area': area})

    arealist = List(Area()).parseString('kitchen, living_room')[0]
    ctx.update_vars({'@arealist': arealist})

    OttoBase.set_context(ctx)

    tests = [('ship.crew, ship.phasers',
              {'entity_id': ['ship.crew', 'ship.phasers'], 'area_id': []}
              ),

             ('AREA kitchen, living_room',
              {'area_id': ['kitchen', 'living_room'], 'entity_id': []}
              ),

             ('AREA @area',
              {'area_id': ['kitchen'], 'entity_id': []}
              ),

             ('AREA @arealist',
              {'area_id': ['kitchen', 'living_room'], 'entity_id': []}
              )
             ]

    for test in tests:
        n = Target().parseString(test[0])[0]
        result = await n.eval()
        assert result == test[1]

@pytest.mark.asyncio
async def test_input():

    ctx = OttoContext()
    ctx.update_vars({'@foostring': String().parseString("'foostring'")[0],
                     '@foonumber': Number().parseString("30.0")[0]})

    OttoBase.set_context(ctx)

    tests = [{"type": "text",
              "string": "'foostring'",
              "expected": "foostring"},

             {"type": "text",
              "string": "@foostring",
              "expected": "foostring"},

             {"type": "text",
              "string": "foo.string",
              "expected": "foo.string"},

             {"type": "numeric",
              "string": "15",
              "expected": 15.0},

             {"type": "numeric",
             "string": "@foonumber",
              "expected": 30.0},

             {"type": "numeric",
             "string": "foo.number:attr",
              "expected": 1.0},

             {"type": "any",
             "string": "'foostring'",
                      "expected": "foostring"},

             {"type": "any",
              "string": "@foostring",
              "expected": "foostring"},

             {"type": "any",
              "string": "foo.string",
              "expected": "foo.string"},

             {"type": "any",
              "string": "15",
              "expected": 15.0},

             {"type": "any",
              "string": "@foonumber",
              "expected": 30.0}

             ]

    for test in tests:
        n = Input(test["type"]).parseString(test["string"])[0]
        print(test["string"])
        result = await n.eval()
        assert result == test["expected"]


import numpy as np
import torch
import os
from collections import OrderedDict
from torch.autograd import Variable
import itertools
import util.util as util
from util.image_pool import ImagePool
from .base_model import BaseModel
from . import networks
import sys

# TODO (1) remove CycleLoss?
#       We have feat_loss_ArecA, which computes the feature loss between A and recreated A.
#       It's kind of redundant with CycleLoss, which computes the pixelwise L1 loss between those two.
#       But then again, we might want to keep both, so that we keep both similar
#       in terms of "style" and "pixelwise resemblence".

# TODO use MSELoss of Pytorch?
def mse_loss(input, target):
    return torch.sum((input - target)**2) / input.data.nelement()

def printnorm(self, input, output):
    # input is a tuple of packed inputs
    # output is a Variable. output.data is the Tensor we are interested
    print('')
    print('Inside ' + self.__class__.__name__ + ' forward')
    # print('input: ', type(input))
    # print('input[0]: ', type(input[0]))
    # print('output: ', type(output))
    # print('')
    # print('input size:', input[0].size())
    # print('output size:', output.data.size())
    print('output norm:', output.data.norm())

def printgradnorm(self, grad_input, grad_output):
    print('Inside ' + self.__class__.__name__ + ' backward')
    #print('Inside class:' + self.__class__.__name__)
    # print('grad_input: ', type(grad_input))
    # print('grad_input[0]: ', type(grad_input[0]))
    # print('grad_output: ', type(grad_output))
    # print('grad_output[0]: ', type(grad_output[0]))
    # print('')
    # print('grad_input size:', grad_input[0].size())
    # print('grad_output size:', grad_output[0].size())
    print('grad_input norm:', grad_input[0].data.norm())

class CycleWGANModel(BaseModel):
    def name(self):
        return 'CycleWGANModel'

    def initialize(self, opt):
        BaseModel.initialize(self, opt)

        self.one = self.Tensor([1])
        self.mone = self.one * -1

        if opt.which_model_netD != 'dcgan':
            self.ones = torch.ones(1, 19, 19) # FIXME compute size from input and architecture of netD
            self.ones = self.ones.type(new_type=self.Tensor)

        # init G related losses to 0 to print in the first few iterations
        self.loss_G_A = Variable(self.Tensor([0]))
        self.loss_G_B = Variable(self.Tensor([0]))
        self.loss_idt_A = Variable(self.Tensor([0]))
        self.loss_idt_B = Variable(self.Tensor([0]))
        self.loss_cycle_A = Variable(self.Tensor([0]))
        self.loss_cycle_B = Variable(self.Tensor([0]))
        self.feat_loss_AfB = Variable(self.Tensor([0]))
        self.feat_loss_BfA = Variable(self.Tensor([0]))
        self.feat_loss_fArecB = Variable(self.Tensor([0]))
        self.feat_loss_fBrecA = Variable(self.Tensor([0]))
        self.feat_loss_ArecA = Variable(self.Tensor([0]))
        self.feat_loss_BrecB = Variable(self.Tensor([0]))
        self.feat_loss = Variable(self.Tensor([0]))
        #self.disp_sumGA = self.loss_G_A.clone() + self.loss_cycle_A.clone()
        #self.disp_sumGB = self.loss_G_B.clone() + self.loss_cycle_B.clone()
        self.loss_sumGA = Variable(self.Tensor([0]))
        self.loss_sumGB = Variable(self.Tensor([0]))
        self.rec_A = None
        self.rec_B = None
        # ----------------------------------------------------------------

        nb = opt.batchSize
        size = opt.fineSize
        self.input_A = self.Tensor(nb, opt.input_nc, size, size)
        self.input_B = self.Tensor(nb, opt.output_nc, size, size)

        # load/define networks
        # The naming conversion is different from those used in the paper
        # Code (paper): G_A (G), G_B (F), D_A (D_Y), D_B (D_X)

        self.netG_A = networks.define_G(opt.input_nc, opt.output_nc,
                                        opt.ngf, opt.which_model_netG, opt.norm, not opt.no_dropout, self.gpu_ids)
        self.netG_B = networks.define_G(opt.output_nc, opt.input_nc,
                                        opt.ngf, opt.which_model_netG, opt.norm, not opt.no_dropout, self.gpu_ids)

        if self.isTrain:
            use_sigmoid = opt.no_lsgan
            self.netD_A = networks.define_D(opt.output_nc, opt.ndf,
                                            opt.which_model_netD,
                                            opt.n_layers_D, opt.norm, use_sigmoid, self.gpu_ids)
            self.netD_B = networks.define_D(opt.input_nc, opt.ndf,
                                            opt.which_model_netD,
                                            opt.n_layers_D, opt.norm, use_sigmoid, self.gpu_ids)
            if (self.opt.lambda_feat > 0):
                self.netFeat = networks.define_feature_network(opt.which_model_feat, self.gpu_ids)

            #self.netD_A.model[11].register_forward_hook(printnorm)
            #self.netD_A.model[11].register_backward_hook(printgradnorm)
            #self.netG_A.register_forward_hook(printnorm)
            #self.netG_A.register_backward_hook(printgradnorm)
            #self.netD_B.model[11].register_forward_hook(printnorm)
            #self.netD_B.model[11].register_backward_hook(printgradnorm)

        if not self.isTrain or opt.continue_train:
            which_epoch = opt.which_epoch
            self.load_network(self.netG_A, 'G_A', which_epoch)
            self.load_network(self.netG_B, 'G_B', which_epoch)
            if self.isTrain:
                self.load_network(self.netD_A, 'D_A', which_epoch)
                self.load_network(self.netD_B, 'D_B', which_epoch)

        if self.isTrain:
            self.old_lr = opt.lr

            # create pools of fake images, if pool size > 0
            if opt.pool_size > 0:
                self.fake_A_pool = ImagePool(opt.pool_size)
                self.fake_B_pool = ImagePool(opt.pool_size)
                self.fake_A = None
                self.fake_B = None
            else:
                self.fake_A_pool = None
                self.fake_B_pool = None

            # define loss functions
            # Note: use WGAN loss for cases where we use D_A or D_B, otherwise use default loss functions
            self.criterionCycle = torch.nn.L1Loss()
            self.criterionIdt = torch.nn.L1Loss()
            self.criterionFeat = mse_loss
            self.criterionWGAN = networks.WGANLoss()
            # initialize optimizers
            if opt.adam:
                self.optimizer_G = torch.optim.Adam(itertools.chain(self.netG_A.parameters(), self.netG_B.parameters()),
                                                lr=opt.lr, betas=(opt.beta1, 0.999))
                self.optimizer_D_A = torch.optim.Adam(self.netD_A.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
                self.optimizer_D_B = torch.optim.Adam(self.netD_B.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
            else:
                # in https://github.com/martinarjovsky/WassersteinGAN, only LR is provided to RMSProp
                self.optimizer_G = torch.optim.RMSprop(itertools.chain(self.netG_A.parameters(), self.netG_B.parameters()),
                                                lr=opt.lr)
                self.optimizer_D_A = torch.optim.RMSprop(self.netD_A.parameters(), lr=opt.lr)
                self.optimizer_D_B = torch.optim.RMSprop(self.netD_B.parameters(), lr=opt.lr)

            # manage lambdas for perceptual loss
            if (self.opt.lambda_feat > 0):
                print("sets all lambda_feat* to lambda_feat")
                self.opt.lambda_feat_AfB = self.opt.lambda_feat
                self.opt.lambda_feat_BfA = self.opt.lambda_feat
                self.opt.lambda_feat_fArecB = self.opt.lambda_feat
                self.opt.lambda_feat_fBrecA = self.opt.lambda_feat
                self.opt.lambda_feat_ArecA = self.opt.lambda_feat
                self.opt.lambda_feat_BrecB = self.opt.lambda_feat

        print('---------- Networks initialized -------------')
        networks.print_network(self.netG_A)
        networks.print_network(self.netG_B)
        if self.isTrain:
            networks.print_network(self.netD_A)
            networks.print_network(self.netD_B)
        print('-----------------------------------------------')

    def set_input(self, input):
        AtoB = self.opt.which_direction == 'AtoB'
        input_A = input['A' if AtoB else 'B']
        input_B = input['B' if AtoB else 'A']
        self.input_A.resize_(input_A.size()).copy_(input_A)
        self.input_B.resize_(input_B.size()).copy_(input_B)
        self.image_paths = input['A_paths' if AtoB else 'B_paths']

    def forward(self):
        self.real_A = Variable(self.input_A)
        self.real_B = Variable(self.input_B)

    def test(self):
        self.real_A = Variable(self.input_A, volatile=True)
        self.fake_B = self.netG_A.forward(self.real_A)
        self.rec_A = self.netG_B.forward(self.fake_B)

        self.real_B = Variable(self.input_B, volatile=True)
        self.fake_A = self.netG_B.forward(self.real_B)
        self.rec_B = self.netG_A.forward(self.fake_A)

    def freeze_discriminators(self, freeze=True):
        for p in self.netD_A.parameters():
            p.requires_grad = not freeze
        for p in self.netD_B.parameters():
            p.requires_grad = not freeze

    def freeze_generators(self, freeze=True):
        for p in self.netG_A.parameters():
            p.requires_grad = not freeze
        for p in self.netG_B.parameters():
            p.requires_grad = not freeze

    # get image paths
    def get_image_paths(self):
        return self.image_paths

    def backward_D_basic(self, netD, real, fake):
        # compute outputs for real and fake images
        outD_real = netD(real)
        outD_fake = netD(fake.detach())
        #self.disp_outD_real = outD_real.mean()
        #self.disp_outD_fake = outD_fake.mean()
        wloss = self.criterionWGAN(fake=outD_fake, real=outD_real)
        # import pdb; pdb.set_trace()
        if self.opt.which_model_netD == 'dcgan':
            wloss.backward()
        else:
            wloss.backward(self.ones)

        return outD_real.mean(), outD_fake.mean()

    def backward_D_A(self):
        #if self.fake_B_pool is None or self.fake_B is None:
            self.fake_B = self.netG_A(self.real_A.detach()) # generate a fake image
            self.loss_D_A_real, self.loss_D_A_fake = self.backward_D_basic(self.netD_A, self.real_B, self.fake_B)
            #self.loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, self.fake_B)
        #else:
        #    fake_B = self.fake_B_pool.query(self.fake_B)
        #    self.loss_D_A_real, self.loss_D_A_fake = self.backward_D_basic(self.netD_A, self.real_B, fake_B)
            #self.loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, fake_B)

    def backward_D_B(self):
        #if self.fake_A_pool is None or self.fake_A is None:
            self.fake_A = self.netG_B(self.real_B.detach())
            self.loss_D_B_real, self.loss_D_B_fake = self.backward_D_basic(self.netD_B, self.real_A, self.fake_A)
            #self.loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, self.fake_A)
        #else:
        #    fake_A = self.fake_A_pool.query(self.fake_A)
        #    self.loss_D_B_real, self.loss_D_B_fake = self.backward_D_basic(self.netD_B, self.real_A, fake_A)
            #self.loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, fake_A)

    def backward_G(self):

        # Identity loss
        if self.opt.identity > 0:
            # G_A should be identity if real_B is fed.
            self.idt_A = self.netG_A(self.real_B)
            self.loss_idt_A = self.criterionIdt(self.idt_A, self.real_B) * self.opt.lambda_B * self.opt.identity
            #self.loss_idt_A = self.criterionWGAN(fake=self.idt_A, real=self.real_B) * lambda_B * lambda_idt
            #self.loss_idt_A = self.criterionWGAN(fake=self.idt_A, real=self.real_B) * lambda_idt
            # G_B should be identity if real_A is fed.
            self.idt_B = self.netG_B(self.real_A)
            self.loss_idt_B = self.criterionIdt(self.idt_B, self.real_A) * self.opt.lambda_A * self.opt.identity
            #self.loss_idt_B = self.criterionWGAN(fake=self.idt_B, real=self.real_A) * lambda_A * lambda_idt
            #self.loss_idt_B = self.criterionWGAN(fake=self.idt_B, real=self.real_A) * lambda_idt
        else:
            self.loss_idt_A = 0
            self.loss_idt_B = 0

        # Freeze discriminators so that they are NOT updated
        self.freeze_discriminators(True)

        # WGAN loss
        # D_A(G_A(A))
        self.fake_B = self.netG_A(self.real_A)
        outD_A_fake = self.netD_A(self.fake_B)
        self.loss_G_A = self.criterionWGAN(real=outD_A_fake) # we give as it was a true sample
        #self.loss_G_A.backward(retain_graph=True)

        # FIXME: Api docs says not to use retain_graph and this can be done efficiently in other ways

        # D_B(G_B(B))
        self.fake_A = self.netG_B(self.real_B)
        outD_B_fake = self.netD_B(self.fake_A)
        self.loss_G_B = self.criterionWGAN(real=outD_B_fake)
        #self.loss_G_B.backward(retain_graph=True)

        # Forward cycle loss
        if self.opt.lambda_A != 0:
            self.rec_A = self.netG_B(self.fake_B)
            self.loss_cycle_A = self.criterionCycle(self.rec_A, self.real_A) * self.opt.lambda_A
            #self.loss_cycle_A = self.criterionWGAN(fake=self.netD_B(self.rec_A), real=self.netD_B(self.real_A)) * lambda_A
        else:
            self.loss_cycle_A = 0

        # Backward cycle loss
        if self.opt.lambda_B != 0:
            self.rec_B = self.netG_A(self.fake_A)
            self.loss_cycle_B = self.criterionCycle(self.rec_B, self.real_B) * self.opt.lambda_B
            #self.loss_cycle_B = self.criterionWGAN(fake=self.netD_A(self.rec_B), real=self.netD_A(self.real_B)) * lambda_B
        else:
            self.loss_cycle_B = 0

        self.loss_sumGA = self.loss_G_A + self.loss_cycle_A + self.loss_idt_A
        self.loss_sumGB = self.loss_G_B + self.loss_cycle_B + self.loss_idt_B

        #self.disp_sumGA = self.loss_G_A.clone() + self.loss_cycle_A.clone()
        #self.disp_sumGB = self.loss_G_B.clone() + self.loss_cycle_B.clone()

        # Perceptual losses:
        if (self.opt.lambda_feat_AfB > 0 and self.opt.lambda_feat_BfA > 0):
            self.feat_loss_AfB = self.criterionFeat(self.netFeat(self.real_A), self.netFeat(self.fake_B)) * self.opt.lambda_feat_AfB
            self.feat_loss_BfA = self.criterionFeat(self.netFeat(self.real_B), self.netFeat(self.fake_A)) * self.opt.lambda_feat_BfA
            # self.feat_loss_AfB = self.criterionWGAN(real=self.netFeat(self.real_A), fake=self.netFeat(self.fake_B)) * lambda_feat_AfB
            # self.feat_loss_BfA = self.criterionWGAN(real=self.netFeat(self.real_B), fake=self.netFeat(self.fake_A)) * lambda_feat_BfA
        else:
            self.feat_loss_AfB = 0
            self.feat_loss_BfA = 0

        if (self.opt.lambda_feat_fArecB > 0 and self.opt.lambda_feat_fBrecA > 0):
            self.feat_loss_fArecB = self.criterionFeat(self.netFeat(self.fake_A), self.netFeat(self.rec_B)) * self.opt.lambda_feat_fArecB
            self.feat_loss_fBrecA = self.criterionFeat(self.netFeat(self.fake_B), self.netFeat(self.rec_A)) * self.opt.lambda_feat_fBrecA
            # self.feat_loss_fArecB = self.criterionWGAN(self.netFeat(self.fake_A), self.netFeat(self.rec_B)) * lambda_feat_fArecB
            # self.feat_loss_fBrecA = self.criterionWGAN(self.netFeat(self.fake_B), self.netFeat(self.rec_A)) * lambda_feat_fBrecA
        else:
            self.feat_loss_fArecB = 0
            self.feat_loss_fBrecA = 0

        if (self.opt.lambda_feat_ArecA > 0 and self.opt.lambda_feat_BrecB > 0):
            self.feat_loss_ArecA = self.criterionFeat(self.netFeat(self.real_A), self.netFeat(self.rec_A)) * self.opt.lambda_feat_ArecA
            self.feat_loss_BrecB = self.criterionFeat(self.netFeat(self.real_B), self.netFeat(self.rec_B)) * self.opt.lambda_feat_BrecB
            # self.feat_loss_ArecA = self.criterionWGAN(real=self.netFeat(self.real_A), fake=self.netFeat(self.rec_A)) * lambda_feat_ArecA
            # self.feat_loss_BrecB = self.criterionWGAN(real=self.netFeat(self.real_B), fake=self.netFeat(self.rec_B)) * lambda_feat_BrecB
        else:
            self.feat_loss_ArecA = 0
            self.feat_loss_BrecB = 0

        # first sum the feat losses
        self.feat_loss = self.feat_loss_AfB + self.feat_loss_BfA + self.feat_loss_fArecB \
                        + self.feat_loss_fBrecA + self.feat_loss_ArecA + self.feat_loss_BrecB

        haveFeatLoss =  not (type(self.feat_loss) is int)

        # then backprop OTHER losses, with or without retaining the graph
        if self.opt.which_model_netD == 'dcgan':
            self.loss_sumGA.backward(retain_graph=haveFeatLoss)
            self.loss_sumGB.backward(retain_graph=haveFeatLoss)
        else:
            self.loss_sumGA.backward(self.ones, retain_graph=haveFeatLoss)
            self.loss_sumGB.backward(self.ones, retain_graph=haveFeatLoss)

        if haveFeatLoss:
            self.feat_loss.backward()

        # Unfreeze them for the next iteration of optimize_parameters_D()
        self.freeze_discriminators(False)

    def optimize_parameters_D(self):
        # call self.forward outside!

        # D_A
        self.optimizer_D_A.zero_grad()
        self.backward_D_A() # generates the first fake_B for the iteration
        self.optimizer_D_A.step()

        # D_B
        self.optimizer_D_B.zero_grad()
        self.backward_D_B() # generates fake_A for the iteration
        self.optimizer_D_B.step()

        # clip weights for both discriminators
        for p in self.netD_A.parameters():
            p.data.clamp_(self.opt.clip_lower, self.opt.clip_upper)

        for p in self.netD_B.parameters():
            p.data.clamp_(self.opt.clip_lower, self.opt.clip_upper)

    def optimize_parameters_G(self):
        # call self.forward outside!

        # G_A and G_B
        self.optimizer_G.zero_grad()
        self.backward_G()
#        print("GRADS A  : First conv (mean: %.8f) Last Deconv: (mean: %.8f)" % (self.netG_A.model.model[0].weight.grad.mean(), self.netG_A.model.model[3].weight.grad.mean()))
#        print("GRADS B  : First conv (mean: %.8f) Last Deconv: (mean: %.8f)" % (self.netG_B.model.model[0].weight.grad.mean(), self.netG_B.model.model[3].weight.grad.mean()))
        self.optimizer_G.step()
#        print("WEIGHTS A: First conv (mean: %.8f) Last Deconv: (mean: %.8f)" % (self.netG_A.model.model[0].weight.mean(), self.netG_A.model.model[3].weight.mean()))
#        print("WEIGHTS B: First conv (mean: %.8f) Last Deconv: (mean: %.8f)" % (self.netG_B.model.model[0].weight.mean(), self.netG_B.model.model[3].weight.mean()))
        #print("mean(G_A_LastConvLayer): %.9f mean(G_B_LastConvLayer): %.9f" % (self.netG_A.model[26].weight.mean(), self.netG_B.model[26].weight.mean()))

    def get_current_errors(self):
        #D_A = self.loss_D_A.data[0]
        #D_B = self.loss_D_B.data[0]
        G_A = self.loss_G_A.data[0]
        G_B = self.loss_G_B.data[0]

        if self.opt.which_model_netD != 'dcgan' and type(G_A) == self.Tensor:
            G_A = G_A.mean()
            G_B = G_B.mean()

        D_A_real, D_A_fake = self.loss_D_A_real.data[0], self.loss_D_A_fake.data[0]
        D_B_real, D_B_fake = self.loss_D_B_real.data[0], self.loss_D_B_fake.data[0]
        #sumGA = self.loss_sumGA.data[0]
        #sumGB = self.loss_sumGB.data[0]

        #currentErrors = OrderedDict([('D_A', D_A), ('D_B', D_B), ('sumGA', sumGA), ('sumGB', sumGB)])
        currentErrors = OrderedDict([('D_A_real', D_A_real), ('D_A_fake', D_A_fake), ('D_B_real', D_B_real), ('D_B_fake', D_B_fake),
                                     ('G_A', G_A), ('G_B', G_B)])

        if self.loss_cycle_A is not 0:
            Cyc_A = self.loss_cycle_A.data[0]
            # this is relevant only we use WGAN for CycleLoss
            if self.opt.which_model_netD != 'dcgan' and type(Cyc_A) == self.Tensor:
                Cyc_A = Cyc_A.mean()
            currentErrors['Cyc_A'] = Cyc_A

        if self.loss_cycle_B is not 0:
            Cyc_B = self.loss_cycle_B.data[0]
            # this is relevant only we use WGAN for CycleLoss
            if self.opt.which_model_netD != 'dcgan' and type(Cyc_B) == self.Tensor:
                Cyc_B = Cyc_B.mean()
            currentErrors['Cyc_B'] = Cyc_B

        if self.opt.identity > 0.0:
            idt_A = self.loss_idt_A.data[0]
            idt_B = self.loss_idt_B.data[0]

            currentErrors['idt_A'] = idt_A
            currentErrors['idt_B'] = idt_B

        # feat_AfB = self.feat_loss_AfB.data[0]
        # feat_BfA = self.feat_loss_BfA.data[0]
        #feat_fArecB = self.feat_loss_fArecB.data[0]
        #feat_fBrecA = self.feat_loss_fBrecA.data[0]
        #feat_ArecA = self.feat_loss_ArecA.data[0]
        #feat_BrecB = self.feat_loss_BrecB.data[0]
        featL = self.feat_loss.data[0]
        if featL > 0.0:
            currentErrors['featL'] = featL

        return currentErrors

    def get_current_visuals(self):
        real_A = util.tensor2im(self.real_A.data)
        fake_B = util.tensor2im(self.fake_B.data)
        real_B = util.tensor2im(self.real_B.data)
        fake_A = util.tensor2im(self.fake_A.data)

        currentVisuals = OrderedDict([('real_A', real_A), ('fake_B', fake_B), ('real_B', real_B), ('fake_A', fake_A)])

        if self.rec_A is not None:
            rec_A = util.tensor2im(self.rec_A.data)
            currentVisuals['rec_A'] = rec_A
        if self.rec_B is not None:
            rec_B = util.tensor2im(self.rec_B.data)
            currentVisuals['rec_B'] = rec_B

        if self.opt.identity > 0.0:
            idt_A = util.tensor2im(self.idt_A.data)
            idt_B = util.tensor2im(self.idt_B.data)
            currentVisuals['idt_B'] = idt_B
            currentVisuals['idt_A'] = idt_A

        return currentVisuals

    def save(self, label):
        self.save_network(self.netG_A, 'G_A', label, self.gpu_ids)
        self.save_network(self.netD_A, 'D_A', label, self.gpu_ids)
        self.save_network(self.netG_B, 'G_B', label, self.gpu_ids)
        self.save_network(self.netD_B, 'D_B', label, self.gpu_ids)

    def update_learning_rate(self):
        lrd = self.opt.lr / self.opt.nepoch_decay
        lr = self.old_lr - lrd
        for param_group in self.optimizer_D_A.param_groups:
            param_group['lr'] = lr
        for param_group in self.optimizer_D_B.param_groups:
            param_group['lr'] = lr
        for param_group in self.optimizer_G.param_groups:
            param_group['lr'] = lr

        print('update learning rate: %f -> %f' % (self.old_lr, lr))
        self.old_lr = lr


"""Provides functional layers for the model"""
import numpy as np
import torch
import torch.nn.functional as F
from common_types import Tensor, Union, _float, _int
from torch.types import Device, _size

_opt_arg = Union[_int, _size]
_opt_tensor = Union[Tensor, None]

def conv2d(x: Tensor,
           weight: Tensor,
           bias: _opt_tensor = None,
           device: Device = 'cpu',
           stride: _opt_arg = 1,
           padding: _opt_arg = 0,
           dilation: _opt_arg = 1,
           groups: _int = 1) -> Tensor:

  return F.conv2d(x, weight.to(device), bias.to(device), stride, padding,
                  dilation, groups)

def batchnorm(x: Tensor,
              weight: Tensor = None,
              bias: _opt_tensor = None,
              device: Device = 'cpu',
              running_mean: _opt_tensor = None,
              running_var: _opt_tensor = None,
              training: bool = True,
              eps: _float = 1e-5,
              momentum: _float = 0.1) -> Tensor:
  ''' momentum = 1 restricts stats to the current mini-batch '''
  # This hack only works when momentum is 1 and avoids needing to track
  # running stats by substuting dummy variables
  running_mean = torch.zeros(np.prod(np.array(x.data.size()[1]))).to(device)
  running_var = torch.ones(np.prod(np.array(x.data.size()[1]))).to(device)
  return F.batch_norm(x, running_mean, running_var, weight, bias, training,
                      momentum, eps)

def leaky_relu(x: Tensor, negative_slope: _float = 0.01) -> Tensor:
  return F.leaky_relu(x, negative_slope, True)

def pixel_shuffle(x: Tensor, scale: _int):
  return F.pixel_shuffle(x, scale)


from django.conf.urls import url
from .views import Discount_view, Category_view, Product_view, Product_detail_view, Category_detail_view

#These two added for viewsets
# from django.conf.urls import include
from rest_framework.routers import DefaultRouter
from django.urls import path, include
from django.contrib import admin
from . import views

router = DefaultRouter()
urlpatterns = [
    path('api/discounts', Discount_view, name='discount'),
    path('api/categories', Category_view, name='category api'),
    path('api/categories/<int:category_id>', Category_detail_view, name='category detail'),
    path('api/products', Product_view, name='product'),
    path('api/products/<int:product_id>', Product_detail_view, name='product detail api'),
    path('', views.homepage, name='home'),
    path('categories', views.categories, name='category'),
    path('categories/<int:category_id>/products', views.products, name='products'),
    path('categories/<int:category_id>/products/<int:product_id>', views.product_detail, name='product detail'),
    path('products/register', views.product_regi, name="product register"),
    path('cart/', views.cart, name='cart'),
    path('about/', views.about, name='about'),
    path('support/', views.support, name='support'),
    path('signin/', views.signin, name='signin'),
    path('register/', views.register, name='register'),
    path('signout/', views.signout, name='signout'),
    path('account/', views.account, name='account'),
    path('payment/', views.payment, name='payment'),
    path('shipping/', views.shipping, name='shipping'),
    path('application/', views.application, name='application'),
    path('order/', views.order, name='order')
]


import argparse
import subprocess
import os.path
import math

def dispatch(out_file, err_file, cmd, go, num_cores=1, num_nodes=1, max_hours=1, memory_in_gb=16):
    """
    Populates 'runscript.sh' file to run 'dqn_original.py' file
    on cluster's GPU partition for 'max_hours' hours with 1 node, 1 core, and 32GB memory
    """
    with open('runscript.sh', 'w+') as f:
        f.write(
            f"""#!/bin/bash
#SBATCH -n {num_cores}                 # Number of cores
#SBATCH -N {num_nodes}                 # Ensure that all cores are on one machine
#SBATCH -t {format_time(max_hours)}           # Runtime in D-HH:MM, minimum of 10 minutes
#SBATCH -p gpu               # Partition to submit to
#SBATCH --gres=gpu           # number of GPUs (here 1; see also --gres=gpu:n)
#SBATCH --mem={gb_to_mb(memory_in_gb)}          # Memory pool for all cores (see also --mem-per-cpu)
#SBATCH -o {out_file}  # File to which STDOUT will be written, %j inserts jobid
#SBATCH -e {err_file}  # File to which STDERR will be written, %j inserts jobid
module load Anaconda3/5.0.1-fasrc01  # Load modules
module load cudnn/7.6.5.32_cuda10.1-fasrc01
module load cuda/10.0.130-fasrc01
source activate gpt2  # Switch to correct conda environment
{cmd}  # Run code
"""
        )
    if go:
        subprocess.call(['sbatch', 'runscript.sh'])

def format_time(total_hours):
    '''Converts hours to D-HH:MM format.'''
    days = total_hours // 24
    frac_hour, hours = math.modf(total_hours % 24)
    minutes = math.ceil(frac_hour * 60.0)
    if minutes == 60:
        hours += 1
        minutes = 0
    if hours == 24:
        hours = 0
        days += 1
    return f'{int(days)}-{int(hours):02d}:{int(minutes):02d}'

def gb_to_mb(gb):
    '''Converts gb to mb'''
    mb = int(gb * 1000)
    return mb

def print_red(string):
    print('\033[1;31;40m' + string + '\033[0;37;40m')

def print_yellow(string):
    print('\033[1;33;40m' + string + '\033[0;37;40m')

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('run_name', type=str,
                        help="""
                        (str) Base name for output and error files to which SLURM writes results,
                        and ID for storing checkpoints and samples.
                        """)
    parser.add_argument('dataset', type=str,
                        help='(str) Path to dataset for training')
    parser.add_argument('restore_from', type=str,
                        help='(str) Either "latest", "fresh", or a path to a checkpoint file')
    parser.add_argument('--sample_every', default=100, type=int,
                        help='(int) How often to generate samples (every N steps)')
    parser.add_argument('--save_every', default=1000, type=int,
                        help='(int) How often to create model checkpoint (every N steps)')
    parser.add_argument('--go', action='store_true',
                        help='(flag) Submits jobs to cluster if present. Default disabled')
    parser.add_argument('--num_cores', default=1, type=int,
                        help='(int) Number of cores to run on')
    parser.add_argument('--num_nodes', default=1, type=int,
                        help='(int) Number of nodes to run on')
    parser.add_argument('--hours', default=1., type=float,
                        help='(float) Wall clock time to request on SLURM')
    parser.add_argument('--gb_memory', default=16., type=float,
                        help='(float) Memory (in GB) to request')
    args = parser.parse_args()

    basename = args.run_name
    out_file = basename + '.txt'
    err_file = basename + '.err.txt'
    cmd = f'python3 train.py --dataset {args.dataset} --restore_from {args.restore_from} --run_name {args.run_name}\
    --sample_every {args.sample_every} --save_every {args.save_every}'

    # If file for a configuration exists, skip over that configuration
    if os.path.exists(out_file) or os.path.exists(err_file):
        print_red(f'{basename} (already exists; skipping)')

    else:
        # Otherwise, generate and run script on cluster
        # Populates 'runscript.sh' file to run specified file
        # on cluster's GPU partition with specified number of nodes, cores, and memory
        # Dispatches 'runscript.sh' to SLURM if '--go' flag was specified in CLI
        print(basename)
        dispatch(out_file=out_file,
                 err_file=err_file,
                 cmd=cmd,
                 go=args.go,
                 num_cores=args.num_cores,
                 num_nodes=args.num_nodes,
                 max_hours=args.hours,
                 memory_in_gb=args.gb_memory)

    if not args.go:
        print_yellow('''
*** This was just a test! No jobs were actually dispatched.
*** If the output looks correct, re-run with the "--go" argument.''')
        print(flush=True)

if __name__ == '__main__':
    main()


import bpy
import csv
import os
from bpy import context
import builtins as __builtin__

def console_print(*args, **kwargs):
    for a in context.screen.areas:
        if a.type == 'CONSOLE':
            c = {}
            c['area'] = a
            c['space_data'] = a.spaces.active
            c['region'] = a.regions[-1]
            c['window'] = context.window
            c['screen'] = context.screen
            s = " ".join([str(arg) for arg in args])
            for line in s.split("\n"):
                bpy.ops.console.scrollback_append(c, text=line)

def print(*args, **kwargs):
    """Console print() function."""

    console_print(*args, **kwargs) # to py consoles
    __builtin__.print(*args, **kwargs) # to system console

def importLogos():
    for i in range(1,22):
        image_name = "Team{}.Logo1".format(i)
        file_name = image_name + ".png"
        bpy.ops.import_image.to_plane(files=[{"name":file_name, "name":file_name}], directory="Users/hyungsoobae/Desktop/K-League/image/")
        models[image_name].location= (0,position1[i-1],1)
        bpy.ops.object.editmode_toggle()
        bpy.ops.transform.translate(value=(0,0,0.5), constraint_axis=(False,False,True), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
        bpy.ops.object.editmode_toggle()

models = bpy.data.objects
scn = bpy.context.scene
data_file_path = "/Users/hyungsoobae/Desktop/K-League/data"
position1 = [0.0, 1.1, 2.2, 3.3000000000000003, 4.4, 5.5, 6.6000000000000005, 7.700000000000001, 8.8, 9.9, 11.0, 12.100000000000001, 13.200000000000001, 14.3, 15.400000000000002, 16.5, 17.6, 18.700000000000003, 19.8, 20.900000000000002, 22.0, 23.1]
tposition1 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]

outlier = 27

def reset():
    scn.frame_set(0)

    for model in models:
        if 'Year' in model.name:
            continue
        if 'Team' in model.name and 'Name' in model.name:
            index = []
            for i,action in enumerate(model.animation_data.action.fcurves):
                if action.data_path == 'location':
                    index.append(i)
            for i in range(len(index)):
                print (index)
                model.animation_data.action.fcurves.remove(model.animation_data.action.fcurves[index[i]])
                index = list(map(lambda x: x-1, index))
                print (index)
            continue

        model.animation_data_clear()
        model.data.animation_data_clear()

    for i in range(1,23):
        #print (models['Team{}'.format(i)].location)
        models['Team{}'.format(i)].location[1] = position1[i-1]
        models['Team{}'.format(i)].scale[2] = 0
        models['Team{}.Point'.format(i)].location[0] = 0.4
        models['Team{}.Point'.format(i)].location[1] = position1[i-1]
        models['Team{}.Point'.format(i)].location[2] = 0.4
        models['Team{}.Point'.format(i)].data.text_counter_props.ifAnimated=True
        models['Team{}.Point'.format(i)].data.text_counter_props.counter = 0

        for j in range(1,6):
            try:
                models['Team{}.Name{}'.format(i,j)].location[1] = position1[i-1]
                models['Team{}.Name{}'.format(i,j)].location[2] = 2.1
                models['Team{}.Name{}'.format(i,j)].rotation_euler[1] = -0.872665
                models['Team{}.Name{}'.format(i,j)].data.size = 0.3
            except:
                pass

        for j in range(1,8):
            try:
                models['Team{}.Logo{}'.format(i, j)].location[1] = position1[i-1]
                models['Team{}.Logo{}'.format(i, j)].location[2] = 1.0
            except:
                pass

def get_current_teams(frame=0):
    result = []
    scn.frame_set(frame)
    for model in models:
        if 'Team' in model.name and '.' not in model.name:
            if (model.location[1]) < outlier:
                result.append(model)
    result.sort(key=lambda x : x.location[1])
    result = list(map(lambda x: x.name, result))
    return result

def setNameLocation(ffrom, frame, teamName, value):
    for i in range(1,6):
        try:
            scn.frame_set(ffrom)
            models['{}.Name{}'.format(teamName,i)].keyframe_insert(data_path='location')

            scn.frame_set(ffrom+frame)
            models['{}.Name{}'.format(teamName, i)].location[1] = value
            models['{}.Name{}'.format(teamName, i)].location[2] = models[teamName].scale[2] * 2 + 2.1
            models['{}.Name{}'.format(teamName, i)].keyframe_insert(data_path='location')
        except:
            pass

def setLogoLocation(ffrom, frame, teamName, value):
    for i in range(1,8):
        try:
            scn.frame_set(ffrom)
            models['{}.Logo{}'.format(teamName,i)].keyframe_insert(data_path='location')

            scn.frame_set(ffrom+frame)
            models['{}.Logo{}'.format(teamName, i)].location[1] = value
            models['{}.Logo{}'.format(teamName, i)].location[2] = models[teamName].scale[2] * 2 + 1.0
            models['{}.Logo{}'.format(teamName, i)].keyframe_insert(data_path='location')
        except:
            pass

def setPointLocation(ffrom, frame, teamName, value, point=None):
        scn.frame_set(ffrom)
        models['{}.Point'.format(teamName)].keyframe_insert(data_path='location')

        if point is not None:
            models['{}.Point'.format(teamName)].data.keyframe_insert(data_path='text_counter_props.counter')

        scn.frame_set(ffrom+frame)
        models['{}.Point'.format(teamName)].location[1] = value
        if models[teamName].scale[2] > 0:
            models['{}.Point'.format(teamName)].location[2] = models[teamName].scale[2] * 2 + 0.4
        else:
            models['{}.Point'.format(teamName)].location[2] = 0.4

        if point is not None:
            models['{}.Point'.format(teamName)].data.text_counter_props.counter = point
            models['{}.Point'.format(teamName)].data.keyframe_insert(data_path='text_counter_props.counter')

        models['{}.Point'.format(teamName)].keyframe_insert(data_path='location')

def transition(year, ffrom, frame):
    new_teams = []
    new_teams_set = set()

    fp = data_file_path + "/" + year + ".csv"
    with open(fp, 'r', encoding="utf-8") as csvfile:
        rdr = csv.reader(csvfile)
        for i,v in enumerate(rdr):
            new_teams.append((i,v[2],int(v[1])))
            new_teams_set.add(v[2])

    current_teams = get_current_teams(ffrom)
    print (current_teams)

    #Remove all non participitating teams from the table
    np_teams = set(current_teams) - new_teams_set

    for team in np_teams:
        #print (team)
        scn.frame_set(ffrom)
        models[team].keyframe_insert(data_path='location')
        models[team].keyframe_insert(data_path='scale')

        scn.frame_set(ffrom+frame)
        models[team].location[1] = outlier
        models[team].scale[2] = 0
        models[team].keyframe_insert(data_path='location')
        models[team].keyframe_insert(data_path='scale')

        setNameLocation(ffrom, frame, team, outlier)
        setLogoLocation(ffrom, frame, team, outlier)
        setPointLocation(ffrom, frame, team, outlier, 0)

    #Move the old teams in order
    current_teams = list(filter(lambda x: x not in np_teams, current_teams))
    current_number = len(current_teams)
    for i,team in enumerate(current_teams):
        scn.frame_set(ffrom)
        models[team].keyframe_insert(data_path='location')

        scn.frame_set(ffrom+frame)
        models[team].location[1] = position1[i]
        models[team].keyframe_insert(data_path='location')

        setNameLocation(ffrom, frame, team, position1[i])
        setLogoLocation(ffrom, frame, team, position1[i])
        setPointLocation(ffrom, frame, team, position1[i])

    #Add new teams
    new_teams_set = new_teams_set - set(current_teams)
    for i,team in enumerate(new_teams_set):
        scn.frame_set(ffrom)
        models[team].keyframe_insert(data_path='location')

        scn.frame_set(ffrom+frame)
        models[team].location[1] = position1[current_number+i]
        models[team].keyframe_insert(data_path='location')

        setNameLocation(ffrom, frame, team, position1[current_number+i])
        setLogoLocation(ffrom, frame, team, position1[current_number+i])
        setPointLocation(ffrom, frame, team, position1[current_number+i])

def league_type_1(year, ffrom, frame, scale=10):
    new_teams = []
    new_teams_set = set()

    fp = data_file_path + "/" + year + ".csv"
    with open(fp, 'r', encoding="utf-8") as csvfile:
        rdr = csv.reader(csvfile)
        for i,v in enumerate(rdr):
            new_teams.append((i,v[2],int(v[1])))
            new_teams_set.add(v[2])
    #print (new_teams)

    for team in new_teams:
        scn.frame_set(ffrom)
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        scn.frame_set(ffrom+frame)
        models[team[1]].location[1] = position1[team[0]]
        models[team[1]].scale[2] = team[2] / scale
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        setNameLocation(ffrom, frame, team[1], position1[team[0]])
        setLogoLocation(ffrom, frame, team[1], position1[team[0]])
        setPointLocation(ffrom, frame, team[1], position1[team[0]], team[2])

def league_type_3(year, ffrom, frame, scale):
    league_type_1(year,ffrom,frame, scale)

def league_type_4(year, ffrom, frame, scale):
    league_type_1(year,ffrom,frame, scale)

def post_season(year, ffrom, frame, scale):
    league_type_1(year+'p',ffrom,frame, scale)

def league_type_5(year, ffrom, frame, scale):
    league_type_1(year,ffrom,frame, scale)

def split(year, ffrom, frame, gap=2, scale=10):
    new_teams = []
    new_teams_set = set()

    #GROUP A
    fp = data_file_path + "/" + year + "a.csv"
    with open(fp, 'r', encoding="utf-8") as csvfile:
        rdr = csv.reader(csvfile)
        for i,v in enumerate(rdr):
            new_teams.append((i,v[2],int(v[1])))
            new_teams_set.add(v[2])

    length = len(new_teams)

    for team in new_teams:
        scn.frame_set(ffrom)
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        scn.frame_set(ffrom+frame)
        models[team[1]].location[1] = position1[team[0]]
        models[team[1]].scale[2] = team[2] / scale
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        setNameLocation(ffrom, frame, team[1], position1[team[0]])
        setLogoLocation(ffrom, frame, team[1], position1[team[0]])
        setPointLocation(ffrom, frame, team[1], position1[team[0]], team[2])

    #GROUP B
    new_teams = []
    new_teams_set = set()

    fp = data_file_path + "/" + year + "b.csv"
    with open(fp, 'r', encoding="utf-8") as csvfile:
        rdr = csv.reader(csvfile)
        for i,v in enumerate(rdr):
            new_teams.append((i,v[2],int(v[1])))
            new_teams_set.add(v[2])

    length = len(new_teams)

    for team in new_teams:
        scn.frame_set(ffrom)
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        scn.frame_set(ffrom+frame)
        models[team[1]].location[1] = position1[length-1+gap+team[0]]
        models[team[1]].scale[2] = team[2] / scale
        models[team[1]].keyframe_insert(data_path='location')
        models[team[1]].keyframe_insert(data_path='scale')

        setNameLocation(ffrom, frame, team[1],position1[length-1+gap+team[0]])
        setLogoLocation(ffrom, frame, team[1],position1[length-1+gap+team[0]])
        setPointLocation(ffrom, frame, team[1],position1[length-1+gap+team[0]], team[2])

'''
reset()

transition("1983", 0, 5)
league_type_1("1983", 5, 50, 40)

transition("1984a", 105, 15)
league_type_1("1984a", 120, 50, 40)
league_type_1("1984b", 195, 50, 40)
league_type_1("1984c", 270, 25, 40)

transition("1985", 345, 15)
league_type_1("1985", 360, 50, 40)

transition("1986a", 460, 15)
league_type_1("1986a", 475, 50, 40)
league_type_1("1986b", 550, 50, 40)
league_type_1("1986c", 625, 25, 40)

transition("1987", 700, 15)
league_type_1("1987", 715, 50, 40)

transition("1988", 815, 15)
league_type_1("1988", 830, 50, 40)

transition("1989", 930, 15)
league_type_1("1989", 945, 50, 40)

transition("1990", 1045, 15)
league_type_1("1990", 1060, 50, 40)

transition("1991", 1160, 15)
league_type_1("1991", 1175, 50, 40)

transition("1992", 1275, 15)
league_type_1("1992", 1290, 50, 40)

transition("1993", 1390, 15)
league_type_1("1993", 1405, 50, 40)

transition("1994", 1505, 15)
league_type_1("1994", 1520, 50, 40)

transition("1995a", 1620, 15)
league_type_1("1995a", 1635, 50, 40)
league_type_1("1995b", 1710, 50, 40)
league_type_1("1995c", 1785, 25, 40)

transition("1996a", 1860, 15)
league_type_1("1996a", 1875, 50, 40)
league_type_1("1996b", 1950, 50, 40)
league_type_1("1996c", 2025, 25, 40)

transition("1997", 2100, 15)
league_type_1("1997", 2115, 50, 40)

transition("1998", 2215, 15)
league_type_1("1998", 2230, 50, 40)
post_season("1998", 2305, 25, 40)

transition("1999", 2380, 15)
league_type_1("1999", 2395, 50, 40)
post_season("1999", 2470, 25, 40)

transition("2000", 2545, 15)
league_type_1("2000", 2560, 50, 40)
post_season("2000", 2635, 25, 40)

transition("2001", 2710, 15)
league_type_1("2001", 2725, 50, 40)

transition("2002", 2825, 15)
league_type_1("2002", 2840, 50, 40)

transition("2003", 2940, 15)
league_type_1("2003", 2955, 50, 40)

transition("2004a", 3055, 15)
league_type_1("2004a", 3070, 50, 40)
league_type_1("2004b", 3145, 50, 40)
league_type_1("2004c", 3220, 40, 40)
league_type_1("2004d", 3285, 25, 40)

transition("2005a", 3360, 15)
league_type_1("2005a", 3375, 50, 40)
league_type_1("2005b", 3450, 50, 40)
league_type_1("2005c", 3525, 40, 40)
league_type_1("2005d", 3590, 25, 40)

transition("2006a", 3665, 15)
league_type_1("2006a", 3680, 50, 40)
league_type_1("2006b", 3680+50+25, 50, 40)
league_type_1("2006c", 3680+50+25+50+25, 40, 40)
league_type_1("2006d", 3695+50+25+50+25+25+25, 25, 40)

transition("2007a", 3970, 15)
league_type_1("2007a", 3985, 50, 40)
league_type_1("2007b", 3985+50+25, 25, 40)

transition("2008a", 4135, 15)
league_type_1("2008a", 4150, 50, 40)
league_type_1("2008b", 4150+50+25, 25, 40)

transition("2009a", 4300, 15)
league_type_1("2009a", 4315, 50, 40)
league_type_1("2009b", 4315+50+25, 25, 40)

transition("2010a", 4465, 15)
league_type_1("2010a", 4480, 50, 40)
league_type_1("2010b", 4480+50+25, 25, 40)

transition("2011a", 4630, 15)
league_type_1("2011a", 4645, 50, 40)
league_type_1("2011b", 4645+50+25, 25, 40)

transition("2012", 4795, 15)
league_type_1("2012", 4810, 50, 40)
split("2012", 4885, 40, 2, 40)

transition("2013", 4975, 15)
league_type_1("2013", 4990, 50, 40)
split("2013", 4990+50+25, 40, 2, 40)

transition("2014", 5155, 15)
league_type_1("2014", 5170, 50, 40)
split("2014", 5245, 40, 2, 40)

transition("2015", 5335, 15)
league_type_1("2015", 5350, 50, 40)
split("2015", 5350+50+25, 40, 2, 40)

transition("2016", 5515, 15)
league_type_1("2016", 5530, 50, 40)
split("2016", 5530+50+25, 40, 2, 40)

transition("2017", 5700, 15)
league_type_1("2017", 5715, 50, 40)
split("2017", 5715+50+25, 40, 2, 40)

transition("2018", 5880, 15)
league_type_1("2018", 5910-15, 50, 40)
split("2018", 5910+50+25-15, 40, 2, 40)
'''