import argparse
import timeit
import resource
from collections import deque
from heapq import heappush, heappop, heapify

class State:
    def __init__(self, state, parent, move, depth, cost, key):

        self.state = state

        self.parent = parent

        self.move = move

        self.depth = depth

        self.cost = cost

        self.key = key

        if self.state:
            self.map = ''.join(str(e) for e in self.state)

    def __eq__(self, other):
        return self.map == other.map

    def __lt__(self, other):
        return self.map < other.map

goal_state = [0, 1, 2, 3, 4, 5, 6, 7, 8]
goal_node = State
initial_state = list()
nodes_expanded = 0
max_search_depth = 0
moves = list()

up_restricted = {0,1,2}
down_restricted = {6,7,8}
left_restricted = {0,3,6}
right_restricted = {2,5,8}

def bfs(initial_state):
    global goal_node, max_search_depth

    frontier = deque([State(initial_state, None, None, 0, 0, 0)])
    start_node = State(initial_state, None, None, 0, 0, 0)
    #frontier_checker = deque()
    #frontier_checker.append(start_node.map)
    explored = set()

    while frontier:
        current_node = frontier.popleft()
        #frontier_checker.popleft()
        explored.add(current_node.map)

        if current_node.state == goal_state:
            goal_node = current_node
            return True

        neighbors = expand(current_node)

        for node in neighbors:
            if node.map not in explored:
                frontier.append(node)
                #frontier_checker.append(node.map)
                explored.add(node.map)

                if node.depth > max_search_depth:
                    max_search_depth = node.depth
    return False

def dfs(initial_state):
    global goal_node, max_search_depth

    stack =  list([State(initial_state, None, None, 0, 0, 0)])
    explored = set()

    while stack:
        current_node = stack.pop()
        explored.add(current_node.map)

        if current_node.state == goal_state:
            goal_node = current_node
            return True

        neighbors = reversed(expand(current_node))

        for node in neighbors:
            if node.map not in explored:
                stack.append(node)
                explored.add(node.map)

                if node.depth > max_search_depth:
                    max_search_depth = node.depth
    return False

def ast(initial_state):
    global goal_node, max_search_depth

    heap = list()
    explored = set()
    heap_checker = {}

    key = h(initial_state)
    start_node = State(initial_state, None, None, 0, 0, 0)
    entry = (key, start_node)

    heappush(heap, entry)
    heap_checker[start_node.map] = entry

    while heap:
        current_node = heappop(heap)
        explored.add(current_node[1].map)

        if current_node[1].state == goal_state:
            goal_node = current_node[1]
            return True

        neighbors = expand(current_node[1])

        for node in neighbors:
            node.key = node.cost + h(node.state)
            entry = (node.key, node)

            if node.map not in explored:
                heappush(heap, entry)
                explored.add(node.map)
                heap_checker[node.map] = entry

                if node.depth > max_search_depth:
                    max_search_depth += 1

            elif node.map in heap_checker and node.key < heap_checker[node.map][1].key:
                heap_index = heap.index((heap_checker[node.map][1].key, heap_checker[node.map][1]))

                #re-insert into heap with new key(cost)
                heap[int(heap_index)] = entry
                heap_checker[node.map] = entry
                heapify(heap)

    return False

def h(state):
    h = 0

    for i in range(1, 9):
        board_i = state.index(i)
        goal_i = goal_state.index(i)
        h += abs(board_i % 3 - goal_i % 3) + abs(board_i // 3 - goal_i // 3)

    return h

def expand(node):
    global nodes_expanded
    nodes_expanded += 1

    neighbors = []
    neighbors.append(State(move(node.state, 1), node, 1, node.depth + 1, node.cost + 1, 0))
    neighbors.append(State(move(node.state, 2), node, 2, node.depth + 1, node.cost + 1, 0))
    neighbors.append(State(move(node.state, 3), node, 3, node.depth + 1, node.cost + 1, 0))
    neighbors.append(State(move(node.state, 4), node, 4, node.depth + 1, node.cost + 1, 0))

    node_list = []

    for node in neighbors:
        if node.state != None:
            node_list.append(node)

    return node_list

def move(state, action):
    global up_restricted, down_restricted, left_restricted, right_restricted

    new_state = state[:]
    key_index = new_state.index(0)
    #up
    if action == 1:
        if key_index not in up_restricted:
            temp = new_state[key_index - 3]
            new_state[key_index-3] = new_state[key_index]
            new_state[key_index] = temp

            return new_state
        else:
            return None

    if action == 2:
        if key_index not in down_restricted:
            temp = new_state[key_index + 3]
            new_state[key_index + 3] = new_state[key_index]
            new_state[key_index] = temp

            return new_state
        else:
            return None

    if action == 3:
        if key_index not in left_restricted:
            temp = new_state[key_index - 1]
            new_state[key_index - 1] = new_state[key_index]
            new_state[key_index] = temp

            return new_state
        else:
            return None

    if action == 4:
        if key_index not in right_restricted:
            temp = new_state[key_index + 1]
            new_state[key_index + 1] = new_state[key_index]
            new_state[key_index] = temp

            return new_state
        else:
            return None

def backtrace():
    current_node = goal_node

    while initial_state != current_node.state:
        if current_node.move == 1:
            movement = 'Up'
        elif current_node.move == 2:
            movement = 'Down'
        elif current_node.move == 3:
            movement = 'Left'
        else:
            movement = 'Right'

        moves.insert(0, movement)
        current_node = current_node.parent

    return moves

def output(time, start_ram):
    global moves
    moves = backtrace()

    file = open('output.txt', 'w')

    file.write("path_to_goal: " + str(moves))
    file.write("\ncost_of_path: " + str(len(moves)))
    file.write("\nnodes_expanded: " + str(nodes_expanded))
    file.write("\nsearch_depth: " + str(goal_node.depth))
    file.write("\nmax_search_depth: " + str(max_search_depth))
    file.write("\nrunning_time: " + format(time, '.8f'))
    file.write("\nmax_ram_usage: " + format((resource.getrusage(resource.RUSAGE_SELF).ru_maxrss - start_ram)/(2**20), '.8f'))
    file.close()

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('algorithm')
    parser.add_argument('board')
    args = parser.parse_args()

    #create list for the intial State
    board = args.board.split(",")

    for element in board:
        initial_state.append(int(element))

    function = function_map[args.algorithm]
    dfs_start_ram = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss

    start = timeit.default_timer()
    frontier = function(initial_state)
    stop = timeit.default_timer()

    output(stop-start, dfs_start_ram)

function_map = {'bfs':bfs, 'dfs':dfs, 'ast':ast}

if __name__ == '__main__':
    main()


from collections import deque

def breadth_first_search(graph : dict, name, searched_element):
    '''
    graph type : dict
    rtype : int
    '''
    search_queue = deque()
    search_queue += graph[name]
    searched = []
    while search_queue:
        person = search_queue.popleft()
        if not person in searched:
            if person == searched_element:
                print(f"Person {person} is mango seller")
                return True
            else:
                search_queue += graph[person]
                searched.append(person)

def create_graph():
    # Created Dict that will store our graph
    graph = {}
    # Creating nodes and edges between them(key: value)
    # This is a directed graph, because we`re pointing from one node to another
    graph["you"] = ["alice", "bob", "claire"]
    graph["bob"] = ["anuj", "peggy"]
    graph["alice"] = ["peggy"]
    graph["claire"] = ["thom", "jonny"]
    graph["anuj"] = []
    graph["peggy"] = []
    graph["thom"] = []
    graph["jonny"] = []
    return graph

def tests():
    graph = create_graph()
    assert breadth_first_search(graph, "you", "anuj") == True

tests()


import os
import django
import sys
import MySQLdb

pro_dir = os.getcwd()
sys.path.append(pro_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BioDesignVer.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

from biosearch.models import LdaResult as LdaResult

connect = MySQLdb.connect(
    host='localhost',
    port=3306,
    user='root',
    passwd='',
    db='wiki'
)
cur = connect.cursor()
id = 1

def updateIds(teamStr):
    teamId = ''
    if teamStr != '':
        teams = teamStr.split('\n')
        print(teams)
        teams = set(teams)
        ids = list()
        for team in teams:
            position = team.find('_')
            print(team[0:position])
            year = int(team[0:position])
            name = team[position+1:]
            print(year, name)
            cur.execute("select * from team where year=%d and team_name='%s'"%(year, name))
            team = cur.fetchone()
            if team:
                print(team[21])
                ids.append(team[21])
        teamId = ','.join(ids)
    return teamId;

def mainFunc():
    start_pos = 198
    step = 100
    end_pos = start_pos + step
    total = LdaResult.objects.count()
    print('process started')
    while total > 0:
        resultList = LdaResult.objects.all()[start_pos:end_pos]
        start_pos += step
        end_pos += step
        total -= step
        for result in resultList:
            print(result.tracks)
            print("team0")
            teamStr = result.teams_0
            teamIds = updateIds(teamStr)
            result.teamIds_0 = teamIds
            print("team1")
            teamStr = result.teams_1
            teamIds = updateIds(teamStr)
            result.teamIds_1 = teamIds
            print("team2")
            teamStr = result.teams_2
            teamIds = updateIds(teamStr)
            result.teamIds_2 = teamIds
            print("team3")
            teamStr = result.teams_3
            teamIds = updateIds(teamStr)
            result.teamIds_3 = teamIds
            print("team4")
            teamStr = result.teams_4
            teamIds = updateIds(teamStr)
            result.teamIds_4 = teamIds
            result.save()

    print('process end')

if __name__ == '__main__':
    django.setup()
    mainFunc()


import json
import logging
import traceback

from nlds.rabbit.consumer import RabbitMQConsumer

logger = logging.getLogger("nlds.root")

class LoggingConsumer(RabbitMQConsumer):
    DEFAULT_QUEUE_NAME = "logging_q"
    DEFAULT_ROUTING_KEY = (f"{RabbitMQConsumer.RK_ROOT}."
                           f"{RabbitMQConsumer.RK_LOG}."
                           f"{RabbitMQConsumer.RK_WILD}")
    DEFAULT_LOGGING_LEVEL = RabbitMQConsumer.RK_LOG_INFO

    _logging_levels = (
        RabbitMQConsumer.RK_LOG_DEBUG,
        RabbitMQConsumer.RK_LOG_INFO,
        RabbitMQConsumer.RK_LOG_WARNING,
        RabbitMQConsumer.RK_LOG_ERROR,
        RabbitMQConsumer.RK_LOG_CRITICAL
    )
    _logging_modes = {
        RabbitMQConsumer.RK_LOG_NONE: 0,
        RabbitMQConsumer.RK_LOG_INFO: 1,
        RabbitMQConsumer.RK_LOG_DEBUG: 2,
    }

    def __init__(self, queue=DEFAULT_QUEUE_NAME, setup_logging_fl=True):
        super().__init__(queue=queue, setup_logging_fl=setup_logging_fl)

    def callback(self, ch, method, properties, body, connection):
        # Convert body from bytes to json for ease of manipulation
        body_json = json.loads(body)

        # Verify routing key is appropriate
        try:
            rk_parts = self.split_routing_key(method.routing_key)
        except ValueError:
            logger.error("Routing key inappropriate format, exiting callback.")
            logger.debug(traceback.format_exc())
            return

        # Print certain outputs to global logger output depending on the stdout
        # log level.
        logger.info(f"Received message with route "
                    f"{body_json[self.MSG_DETAILS][self.MSG_ROUTE]}")

        # Print whole json message if in debug
        logger.debug(json.dumps(body_json, indent=4))

        # The log level should be in the routing key, the logger to use should
        # be in the message body under MSG_DETAILS:MSG_LOG_TARGET
        if rk_parts[2] not in self._logging_levels:
            logger.error(f"Invalid routing key provided, log_level is set to an"
                         f"invalid value ({rk_parts[2]})\n"
                         f"Should be one of {self._logging_levels}.")
            logger.debug(traceback.format_exc())
            return

        # Get target log file from message
        try:
            consumer = body_json[self.MSG_DETAILS][self.MSG_LOG_TARGET]
        except KeyError as e:
            logger.error(f"Invalid message contents, log target should be in "
                         f"the details section of the message body.")
            logger.debug(traceback.format_exc(), exc_info=e)
            return

        # Get curated list of loggers to verify the log_target can actually be used.
        loggers = {name: logging.getLogger(name)
                   for name in logging.root.manager.loggerDict
                   if self.LOGGER_PREFIX == name[:5]}
        try:
            consumer_logger = loggers[consumer]
        except KeyError as e:
            logger.error(f"Invalid log target provided, consumer does not have "
                         f"a valid logger/handler setup ({consumer}) \n"
                         f"Should be one of {list(loggers.keys())}.",
                         exc_info=e)
            logger.debug(traceback.format_exc())
            return
        logging_func = self.get_logging_func(rk_parts[2],
                                             logger_like=consumer_logger)

        # Check message body contains log message, under
        # MSG_DATA:MSG_LOG_MESSAGE
        try:
            log_message = body_json[self.MSG_DATA][self.MSG_LOG_MESSAGE]
        except KeyError as e:
            logger.error(f"Invalid message contents, log message should be in "
                         f"the data section of the message body.",
                         exc_info=e)
            logger.debug(traceback.format_exc())
            return

        exc_info = None
        if self.MSG_ERROR in body_json[self.MSG_DATA]:
            exc_info = body_json[self.MSG_DATA][self.MSG_ERROR]

        # Finally, log the message
        logging_func(log_message, exc_info=exc_info)

        logger.info(f"Callback finished. \n")

    @staticmethod
    def get_logging_func(log_level: str, logger_like: logging.Logger = logger):
        """
        Selects the appropriate logging function, given a logging level, from a
        Logger object or Logger-like object. The global logger is used by
        default (logging.getLogger(__name__)) but anything which has the
        standard logging operations (debug, info, warning etc. ) can be used
        i.e. the logging package

        :param str log_level:       Logging level requested
        :param Logger logger_like:  Logger object to get function from
        :return:                    The logging function to use
        """
        logging_function = {
            RabbitMQConsumer.RK_LOG_DEBUG: logger_like.debug,
            RabbitMQConsumer.RK_LOG_INFO: logger_like.info,
            RabbitMQConsumer.RK_LOG_WARNING: logger_like.warning,
            RabbitMQConsumer.RK_LOG_ERROR: logger_like.error,
            RabbitMQConsumer.RK_LOG_CRITICAL: logger_like.critical
        }
        return logging_function[log_level]

def main():
    consumer = LoggingConsumer()
    consumer.run()

if __name__ == "__main__":
    main()


'''
Hackerrank: https://www.hackerrank.com/challenges/coin-change/problem
this solution will get timeout in many test cases
however, this solution can get all the combination during computation
'''
import sys

from collections import Counter, defaultdict
sys.setrecursionlimit(10000)

memory = defaultdict(list)

def recur_getWays(n, c):
    #print('enter: n='+str(n))
    if n < 0:
        return False, []
    elif n == 0:
        return True, [Counter()]

    if n in memory.keys():
        return True, memory[n]

    all_combs_count = []
    for coin in c:
        #print('choose coin:'+str(coin))
        valid, combs = recur_getWays(n-coin, c)
        if valid:
            for comb in combs:
                comb = comb + Counter({coin:1})
                existed = False
                for existed_comb in all_combs_count:
                    if existed_comb == comb:
                        existed = True
                        break
                if not existed:
                    all_combs_count.append(comb)
    #print('memorize: n='+str(n)+' count:'+str(all_combs_count))
    memory[n] = all_combs_count

    return True, all_combs_count

def getWays(n, c):
    # Complete this function
    valid, combs = recur_getWays(n, c)
    #print(memory)
    return len(combs)

n, m = input().strip().split(' ')
n, m = [int(n), int(m)]
c = list(map(int, input().strip().split(' ')))
# Print the number of ways of making change for 'n' units using coins having the values given by 'c'
ways = getWays(n, c)
print(ways)


import math
import torch.nn as nn

from ..common.utils import make_channels

class Discriminator(nn.Module):
    def __init__(self, resolution):
        super().__init__()
        channels = make_channels(math.log2(resolution / 8)-1)
        self.in_layer = nn.Sequential(
            nn.Conv2d(3, channels[0], 3, 1, 1, bias=False),
            nn.BatchNorm2d(channels[0]),
            nn.LeakyReLU(0.1, inplace=True)
        )
        self.layers = nn.Sequential(*[
            self._build_layer(
                in_c,
                out_c
            ) for in_c, out_c in zip(channels[:-1], channels[1:])
        ])

        self.out_layer = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(channels[-1], 1, 1)
        )

    def _build_layer(self, in_c, out_c):
        return nn.Sequential(
            nn.Conv2d(in_c, in_c, 4, 2, 1, bias=False),
            nn.BatchNorm2d(in_c),
            nn.LeakyReLU(0.1, inplace=True),
            nn.Conv2d(in_c, out_c, 3, 1, 1, bias=False),
            nn.BatchNorm2d(out_c),
            nn.LeakyReLU(0.1, inplace=True)
        )

    def forward(self, x):
        x = self.in_layer(x)
        x = self.layers(x)
        x = self.out_layer(x)
        return x


import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans

def kmeans_cluster_labels():
    label_df = pd.read_csv('data/runtimes/extended_runtime_labels.csv', index_col=0)
    current_label = 'log10_parity_two_label'
    print(label_df.columns.tolist())
    # number of clusters
    k = 3
    new_label_name = f"{k}-means_label_on_{current_label}"
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans_df = pd.DataFrame(label_df[current_label])
    # we have to drop nan's
    kmeans_df.dropna(inplace=True)
    # drop only the 0's
    kmeans_df = kmeans_df[(kmeans_df.log10_parity_two_label != np.log10(0))]
    # execute kmeans and retrieve labels

    kmeans_df[new_label_name] = kmeans.fit_predict(kmeans_df)
    # drop old label column
    kmeans_df = kmeans_df.drop(labels=current_label, axis=1)
    print(kmeans_df)

    # we have to merge due to the drops
    merged_df = label_df.join(kmeans_df, how='left')
    # plot our clusters
    frame = plt.scatter(merged_df[current_label], merged_df.index, c=merged_df[new_label_name])
    frame.axes.get_yaxis().set_visible(False)
    plt.title(f'{k}-Means Clustering of Average Par-2 Time for Labelling')
    plt.xlabel('Average Par-2 Time of Each Instance')
    plt.show()

    return merged_df

def calculate_new_labels():
    # calculate new labels
    runtime_df = pd.read_csv('data/runtimes/extended_solver_runtimes.csv', index_col=0)
    old_runtimes_df = pd.read_csv('data/runtimes/solver_runtimes.csv', index_col=0)
    # a timeout happens at 5000s. parity 2 doubles its weight to punish a timeout
    runtime_df.replace('timeout', 10000, inplace=True)
    runtime_df = runtime_df.apply(pd.to_numeric)
    runtime_df['parity_two_label'] = runtime_df.mean(axis=1)
    runtime_df.sort_index(inplace=True)

    # calculate log of par2
    runtime_df['log10_parity_two_label'] = np.log10(runtime_df['parity_two_label'])

    # drop non-label columns
    runtime_df = runtime_df[['parity_two_label', 'log10_parity_two_label']]

    # merge new and old feature dataframes
    new_feature_df = pd.read_csv('data/measured_data/new_SAT_features.csv', index_col=0)
    new_feature_df.sort_index(inplace=True)
    old_feature_df = pd.read_csv('data/measured_data/SAT_features.csv', index_col=0)
    obsolete_columns = ['MeanEigenvectorCentrality', 'MinEigenvectorCentrality', 'MaxEigenvectorCentrality',
                        'VarEigenvectorCentrality', 'EntropyEigenvectorCentrality']
    old_feature_df.drop(obsolete_columns, axis=1, inplace=True)
    old_feature_df.sort_index(inplace=True)
    feature_df = pd.concat([old_feature_df, new_feature_df]).drop_duplicates()

    # we only want to use instances, for which we have the features AND the runtime
    merged_df = pd.merge(feature_df, runtime_df, left_index=True, right_index=True)

    return merged_df

if __name__ == '__main__':
    # comment out/in the steps you need:

    # load and merge both runtime files
    all_new_runtimes_df = pd.read_csv('data/instances/prepared-anni-seq.csv', index_col=0)
    all_new_runtimes_df.sort_index(inplace=True)
    old_runtimes_df = pd.read_csv('data/runtimes/solver_runtimes.csv', index_col=0)
    old_runtimes_df.sort_index(inplace=True)
    merged_df = all_new_runtimes_df.join(old_runtimes_df, how='outer')

    # remove non-runtime columns
    merged_df.drop(merged_df.iloc[:, 0:4], inplace=True, axis=1)
    merged_df.to_csv('data/runtimes/extended_solver_runtimes.csv')

    # calculate new labels
    merged_df = calculate_new_labels()

    # split into two df's again and save
    runtime_df = merged_df[['parity_two_label', 'log10_parity_two_label']]
    feature_df = merged_df.drop(['parity_two_label', 'log10_parity_two_label'], axis=1)

    # save
    runtime_df.to_csv('data/runtimes/extended_runtime_labels.csv')
    feature_df.to_csv('data/measured_data/extended_SAT_features.csv')

    # k means label
    label_df = kmeans_cluster_labels()
    label_df.to_csv('data/runtimes/extended_runtime_labels.csv')


from collections import deque
#Breadth-First Search (BFS)
def bfs(graph, start):
    """
    Performs breadth-first search on the given graph starting from the given node.
    Returns a list of nodes in the order they were visited.
    """
    visited = {start}
    queue = deque([start])
    order = [start]

    while queue:
        node = queue.popleft()
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
                order.append(neighbor)

    return order
'''
The function takes a graph represented as a dictionary and a starting node as inputs,
and returns a list of nodes in the order they were visited using Breadth-First Search algorithm.
The algorithm visits all nodes at a given level before moving to the next level. It uses a queue data structure to keep track of the nodes to visit.

'''
#Depth-First Search (DFS)
def dfs(graph, start):
    """
    Performs depth-first search on the given graph starting from the given node.
    Returns a list of nodes in the order they were visited.
    """
    visited = set()
    order = []

    def dfs_recursive(node):
        visited.add(node)
        order.append(node)
        for neighbor in graph[node]:
            if neighbor not in visited:
                dfs_recursive(neighbor)

    dfs_recursive(start)
    return order

'''
The function takes a graph represented as a dictionary and a starting node as inputs,
and returns a list of nodes in the order they were visited using Depth-First Search algorithm.
The algorithm explores as far as possible along each branch before backtracking. It uses a recursive function to implement the DFS algorithm.
'''

# Dijkstra's Algorithm:

import heapq

def dijkstra(graph, start):
    """
    Performs Dijkstra's algorithm on the given graph starting from the given node.
    Returns a dictionary of shortest paths to each node from the start node.
    """
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    heap = [(0, start)]
    while heap:
        (dist, node) = heapq.heappop(heap)
        if dist > distances[node]:
            continue
        for neighbor, weight in graph[node].items():
            distance = dist + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(heap, (distance, neighbor))
    return distances
'''
The function takes a weighted graph represented as a dictionary and a starting node as inputs,
and returns a dictionary of shortest paths to each node from the start node using Dijkstra's algorithm.
The algorithm works by maintaining a priority queue of nodes to visit and their current distances from the start node.
It repeatedly extracts the node with the smallest distance from the queue and updates the distances of its neighbors.
It terminates when all nodes have been visited or the shortest path to the destination node has been found.

'''


import os
import random
import json
import pygame
from boardData import *
from findPath import *
from findPathOrder import *
import time

with open("setup.json", "r") as readFile:                                   # implements setup.json values
    setup = json.load(readFile)
FILEDIR = setup["FILE"]
BOARDWIDTH, BOARDHEIGHT = setup["WIDTH"], setup["HEIGHT"]
DEPTH = setup["SEARCHDEPTH"]

DEFAULTWEIGHT = 5                                                           # default weight for movement

STARTDIR = FILEDIR + "/start.txt"
TARGETSDIR = FILEDIR + "/targets.txt"
AVOIDSDIR = FILEDIR + "/avoids.txt"
SCREENWIDTH, SCREENHEIGHT = 800, ((800 / BOARDWIDTH) * BOARDHEIGHT) + 100   # sets up dimensions for graphics

pygame.init()                                                               # initializes graphics
WIN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))                  # initializes window
pygame.display.set_caption("Killdozer")                                     # sets title of application
KILLDOZERIMG = pygame.image.load("./images/killdozer.png")                  # creates killdozer image
KILLDOZER = pygame.transform.scale(KILLDOZERIMG, (SCREENWIDTH / BOARDWIDTH, SCREENWIDTH / BOARDWIDTH))  # scales killdozer image

def main():
    if FILEDIR == "random":                                                 # if file is random, create random configuration
        makeRandomInput("random", 15, 60, 1000, 50)
    clock = pygame.time.Clock()                                             # initializes framerate
    run = True                                                              # runs until set false by exiting application
    board = makeBoard()                                                     # initializes matrix

    WIN.fill((200, 200, 200))                                               # fills window with gray
    startBtn = pygame.Rect((SCREENWIDTH / 2) - 50, SCREENWIDTH + 25, 100, 50)   # makes button to press to solve matrix
    pygame.draw.rect(WIN, (180, 180, 180), startBtn)
    font = pygame.font.Font(pygame.font.get_default_font(), 25)
    startText = font.render("Start", True, (0, 0, 0))
    startTextRect = startText.get_rect(center=((SCREENWIDTH / 2), SCREENWIDTH + 50))
    WIN.blit(startText, startTextRect)

    drawScore(0)                                                            # draws text for score

    printBoard(board)                                                       # prints the board on the window
    startPos = open(STARTDIR, "r").read().split(",")                        # gets start position of killdozer
    printKillDozer(int(startPos[0]), int(startPos[1]))                      # renders killdozer at start position
    graph = makeGraph(board, getTargets(board, TARGETSDIR, STARTDIR))       # makes a graph out of the matrix

    # printPath(board, graph, (0,0), (8, 6))
    # printPath(board, graph, (8, 6), (0, 2))
    # for g in graph:
    #     print(f"from {g}:")
    #     for p in graph[g]:
    #         print(f"{p}: {graph[g][p]}")
    while run:                                                              # main application loop
        onStart = False
        clock.tick(60)                                                      # sets framerate to 60fps
        mouse = pygame.mouse.get_pos()
        if (SCREENWIDTH / 2) - 50 <= mouse[0] <= (SCREENWIDTH / 2) + 50\
                and SCREENWIDTH + 25 <= mouse[1] <= SCREENWIDTH + 75:       # checks if mouse is over start button
            onStart = True
        for event in pygame.event.get():
            if event.type == pygame.QUIT:                                   # exit button on top right
                run = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if onStart:                                                 # if mouse clicked while over start button
                    doPath(board, graph, (int(startPos[0]), int(startPos[1])))  # main algorithm for pathfinding
        pygame.display.update()                                             # update appearance of graphics

def doPath(board, graph, start):                                            # using the graph of the matrix, find order
    path = findPathOrder(graph, start, DEPTH)
    score = 0
    for i in range(len(path) - 1):
        score = printPath(board, graph, path[i], path[i+1], score)          # print next movement and update score

def printKillDozer(x, y):                                                   # prints killdozer at location
    tileWidth = SCREENWIDTH / BOARDWIDTH
    WIN.blit(KILLDOZER, (x * tileWidth, y * tileWidth))

def makeBoard():                                                            # creates board object
    board = Board(BOARDHEIGHT, BOARDWIDTH, DEFAULTWEIGHT, targetsDir=TARGETSDIR, avoidsDir=AVOIDSDIR)
    return board

def printBoard(board):                                                      # prints board graphics
    tileWidth = SCREENWIDTH / BOARDWIDTH
    background = pygame.Rect(0, 0, SCREENWIDTH, tileWidth * BOARDHEIGHT)
    pygame.draw.rect(WIN, (100, 100, 100), background)
    borderWidth = tileWidth * 0.02
    drawnWidth = tileWidth - 2 * borderWidth
    matrix = board.matrix
    for i, row in enumerate(matrix):
        for j, tile in enumerate(row):
            drawnTile = pygame.Rect((tileWidth * j) + borderWidth, (tileWidth * i) + borderWidth,  drawnWidth, drawnWidth)
            color = (200, 200, 200)
            printedText = ""
            textColor = (0, 0, 0)
            if tile.status == "TARGET":
                color = (0, 120, 0)
                textColor = (250, 200, 80)
                printedText = str(tile.score)
            elif tile.status == "AVOID":
                color = (120, 0, 0)
                printedText = "-" + str(tile.weight)
                textColor = (255, 200, 200)
            elif tile.status == "PATH":
                color = (0, 0, 120)

            font = pygame.font.Font(pygame.font.get_default_font(), int(tileWidth / 4))
            text = font.render(printedText, True, textColor)
            text_rect = text.get_rect(center=((tileWidth * j) + tileWidth / 2, tileWidth * i + tileWidth / 2))

            pygame.draw.rect(WIN, color, drawnTile)
            WIN.blit(text, text_rect)

def reprint(tile):                                                          # updates only the tiles that were affected
    tileWidth = SCREENWIDTH / BOARDWIDTH
    borderWidth = tileWidth * 0.01
    drawnWidth = tileWidth - 2 * borderWidth
    drawnTile = pygame.Rect((tileWidth * tile.x) + borderWidth, (tileWidth * tile.y) + borderWidth, drawnWidth,
                            drawnWidth)
    color = (200, 200, 200)
    printedText = ""
    textColor = (0, 0, 0)
    if tile.status == "TARGET":
        color = (0, 120, 0)
        textColor = (250, 200, 80)
        printedText = str(tile.score)
    elif tile.status == "AVOID":
        color = (120, 0, 0)
        printedText = "-" + str(tile.weight)
        textColor = (255, 200, 200)
    elif tile.status == "PATH":
        color = (0, 0, 120)

    font = pygame.font.Font(pygame.font.get_default_font(), int(tileWidth / 4))
    text = font.render(printedText, True, textColor)
    text_rect = text.get_rect(center=((tileWidth * tile.x) + tileWidth / 2, tileWidth * tile.y + tileWidth / 2))

    pygame.draw.rect(WIN, color, drawnTile)
    WIN.blit(text, text_rect)

def printPath(board, graph, source, dest, score):
    kdx = 0
    kdy = 0
    printBoard(board)  # refreshes board
    for tilePos in graph[source][dest]["PATH"]:
        tile = board.matrix[tilePos[1]][tilePos[0]]
        score -= tile.weight
        score += tile.score
        tile.score = 0
        drawScore(score)
        if tile.status == "DEFAULT":
            tile.status = "PATH"
        reprint(tile)
        printKillDozer(tilePos[0], tilePos[1])
        pygame.display.update()
        time.sleep(0.3)
        reprint(tile)
        kdx = tile.x
        kdy = tile.y
    printKillDozer(kdx, kdy)
    return score

def drawScore(score):
    scoreText = pygame.Rect(25, SCREENWIDTH + 25, 150, 50)
    pygame.draw.rect(WIN, (180, 180, 180), scoreText)
    font = pygame.font.Font(pygame.font.get_default_font(), 20)
    startText = font.render(f"Score: {score}", True, (0, 0, 0))
    startTextRect = startText.get_rect(center=(0, SCREENWIDTH + 50), left=30)
    WIN.blit(startText, startTextRect)

def makeRandomInput(name, targetCount, avoidCount, maxTarget, maxAvoid):
    if not os.path.exists(name):
        os.mkdir(name)
    places = []
    for i in range(BOARDWIDTH):
        for j in range(BOARDHEIGHT):
            places.append((i, j))
    spots = random.sample(places, targetCount + avoidCount + 1)
    targets = ""
    avoids = ""
    targetPlaces = spots[0:targetCount]
    avoidPlaces = spots[targetCount:-1]
    start = spots[-1]
    # print(targetPlaces)
    # print(avoidPlaces)
    # print(start)
    for t in targetPlaces:
        targets += f"{t[0]},{t[1]},{random.randint(0, maxTarget)}\n"
    for a in avoidPlaces:
        avoids += f"{a[0]},{a[1]},{random.randint(10, maxAvoid)}\n"
    start = f"{start[0]},{start[1]}"
    with open(name + "/targets.txt", "w") as f:
        f.write(targets[:-1])
    with open(name + "/avoids.txt", "w") as f:
        f.write(avoids[:-1])
    with open(name + "/start.txt", "w") as f:
        f.write(start)

if __name__ == "__main__":
    main()


import mars_functions as M
import flask as fl
import pymongo
import time as t

# Let's set up a Flask App
app = fl.Flask(__name__)

#--------/ CONNECT TO MONGO MARS /------------
my_db = 'mission_to_mars'
my_col = 'mars_scrape'
collection = M.mongo_me(my_db,my_col)

#--------/ APP ROUTES /------------

#--------/ INDEX /-----------------
@app.route("/")
def index():

    print('staring index route')

    #--------/ PULLING FROM MARS COLLECTION /------------
    my_mars = M.last_doc(collection)

    return fl.render_template('index.html',latest_scrape=my_mars)

@app.route("/scrape")
def scrape():

    print('starting scrape route')

    M.scrape_mars()

    print('Fresh Scrape!')

    # Redirect back to home page
    return fl.redirect("/", code=302)

#--------/ RUN APP /------------
if __name__ == "__main__":
    app.run(debug=True)


import pytest_check as check
from testinfra.modules.package import RpmPackage

from ..base import (
    get_package_files,
    get_shared_libraries,
    has_missing_shared_libraries,
    is_debuginfo_package,
    is_file_dynamically_linked,
    is_package_empty,
    is_rpath_correct,
    resolve_symlink,
)

def test_package_is_installed(host, package_name, package_version):
    """
    Test that package is installed on the system.

    Parameters
    ----------
    host:               Host
        Host reference
    package_name:       str
        Package name
    package_version:    str
        Package version

    Returns
    -------

    """

    package = host.package(package_name)
    check.is_true(package.is_installed)
    if package_version:
        check.is_in(
            package.version,
            package_version,
            f'Version does not match: required: {package_version}, '
            f'actual: {package.version}',
        )
        if isinstance(package, RpmPackage):
            check.is_in(
                package.release,
                package_version,
                f'Release does not match: required: {package_version}, '
                f'actual: {package.release}',
            )

def test_all_package_files_exist(host, package_name):
    """
    Check that all files from the package are present on the filesystem.

    Parameters
    ----------
    host:               Host
        Host reference
    package_name:       str
        Package name

    Returns
    -------

    """

    package = host.package(package_name)
    if is_package_empty(package):
        return
    if is_debuginfo_package(package):
        return

    for file_ in get_package_files(package):
        # .build-id/$something files can be safely skipped,
        # they are never in the package (except for debuginfo)
        # and even if they are there we do not care.
        if '.build-id' in file_:
            continue
        file_obj = host.file(file_)
        check.is_true(
            file_obj.exists,
            f'File is absent on the file system: {file_}',
        )
        # Check all symlinks point to existing files
        if file_obj.is_symlink:
            resolved = resolve_symlink(host, file_obj)
            check.is_not_none(
                resolved,
                f'Symlink cannot be resolved: {file_}',
            )
            file_obj = host.file(resolved)
            check.is_true(
                file_obj.exists,
                f'Symlink is broken: {file_}',
            )

def test_binaries_have_all_dependencies(host, package_name):
    """
    Check that all binaries have corresponding shared libraries.

    Parameters
    ----------
    host:               Host
        Host reference
    package_name:       str
        Package name

    Returns
    -------

    """

    package = host.package(package_name)
    if is_package_empty(package):
        return
    if is_debuginfo_package(package):
        return

    for file_path in get_package_files(package):
        # .build-id/$something files can be safely skipped,
        # they are never in the package (except for debuginfo)
        # and even if they are there we do not care.
        if '.build-id' in file_path:
            continue
        file_ = host.file(file_path)
        if file_.is_symlink:
            try:
                file_ = host.file(resolve_symlink(host, file_))
            except ValueError:
                pass
        if is_file_dynamically_linked(file_):
            check_result = has_missing_shared_libraries(file_)
            check.is_false(check_result.missing, check_result.output)

def test_check_rpath_is_correct(host, package_name):
    """
    Check that RPATH does not have errors in definition
    (for example, ':' in the end).

    Parameters
    ----------
    host:           Host
        Host reference
    package_name:   str
        Package name

    Returns
    -------

    """
    package = host.package(package_name)
    if is_package_empty(package):
        return
    if is_debuginfo_package(package):
        return

    for library in get_shared_libraries(package):
        check.is_true(
            is_rpath_correct(host.file(library)),
            f'RPATH is broken in {library}',
        )


import pygame
import reactor_colors as color

def account_create(surface, surface_width, surface_height, margin, margin_color,
                 disc_pulse_value, disc_pulse_direction,
                 scaler, clock, fps):

    blinker_on = True
    blinker_count = 0
    blinker_speed = 3
    # user_account = "benny"

    def draw_background_disc(dissolve, disc_pulse_up):

        if disc_pulse_up:
            dissolve += .5
        else:
            dissolve -= .5

        if dissolve <= 0:
            disc_pulse_up = True
        elif dissolve >= 25:
            disc_pulse_up = False

        pygame.draw.circle(
            surface,
            (color.background[0] - int(dissolve),
             color.background[1] - int(dissolve),
             color.background[2] - int(dissolve)),
            (surface_width // 2, surface_height // 2),
            (surface_width // 2) - margin,
            int(100 * scaler))

        return dissolve, disc_pulse_up

    def start_text_blinker(count, status):

        count += 1
        if count == blinker_speed:
            count = 0
            if status:
                status = False
            else:
                status = True

        return count, status

    def draw_margin():

        pygame.draw.rect(surface, margin_color, (0, 0, surface_width, surface_height), margin)

    def mouse_coord():
        mx, my = pygame.mouse.get_pos()
        return mx, my

    def text_board():

        row_space = 50 * scaler
        board_text = "darkforest.ttf"

        instructions = pygame.font.Font(f"{board_text}", int(30 * scaler))
        alphabet = pygame.font.Font(f"{board_text}", int(50 * scaler))

        instructions_text = "please enter your account name"
        keyboard_1 = "q w e r t y u i o p"
        keyboard_2 = "a s d f g h j k l"
        keyboard_3 = "z x c v b n m"
        keyboard_4 = "adv rub end"

        biggest_let = "m"
        biggest_let_rect = alphabet.render(biggest_let, True, color.title_color).get_rect()
        let_x_size = abs(biggest_let_rect.left - biggest_let_rect.right)
        let_y_size = abs(biggest_let_rect.top - biggest_let_rect.bottom)

        row1_x_start = (surface_width - (len(keyboard_1) * let_x_size)) // 2
        row2_x_start = (surface_width - (len(keyboard_2) * let_x_size)) // 2
        row3_x_start = (surface_width - (len(keyboard_3) * let_x_size)) // 2
        row4_x_start = (surface_width - (len(keyboard_4) * let_x_size)) // 2

        instructions_surface = instructions.render(instructions_text, True, color.title_color)
        alphabet_1_surfaces = [alphabet.render(let, True, color.title_color) for let in keyboard_1]
        alphabet_2_surfaces = [alphabet.render(let, True, color.title_color) for let in keyboard_2]
        alphabet_3_surfaces = [alphabet.render(let, True, color.title_color) for let in keyboard_3]
        alphabet_4_surfaces = [alphabet.render(let, True, color.title_color) for let in keyboard_4]

        instructions_rect = instructions_surface.get_rect()
        alphabet_1_rects = [surf.get_rect() for surf in alphabet_1_surfaces]
        alphabet_2_rects = [surf.get_rect() for surf in alphabet_2_surfaces]
        alphabet_3_rects = [surf.get_rect() for surf in alphabet_3_surfaces]
        alphabet_4_rects = [surf.get_rect() for surf in alphabet_4_surfaces]

        instructions_rect_pos = (instructions_position, surface_height // 4 + row_space)

        alphabet_1_rects_pos = [(row1_x_start + (let_x_size * idx), surface_height // 4 + row_space * 2)
                                for idx, rect in enumerate(alphabet_1_rects)]
        alphabet_2_rects_pos = [(row2_x_start + (let_x_size * idx), surface_height // 4 + row_space * 3) for idx, rect
                                in enumerate(alphabet_2_rects)]
        alphabet_3_rects_pos = [(row3_x_start + (let_x_size * idx), surface_height // 4 + row_space * 4) for idx, rect
                                in enumerate(alphabet_3_rects)]
        alphabet_4_rects_pos = [(row4_x_start + (let_x_size * idx), surface_height // 4 + row_space * 5) for idx, rect
                                in enumerate(alphabet_4_rects)]

        all_keyboard_pos = alphabet_1_rects_pos + alphabet_2_rects_pos + alphabet_3_rects_pos + alphabet_4_rects_pos

        instructions_rect.center = instructions_rect_pos
        surface.blit(instructions_surface, instructions_rect)
        if not instructions_font_animating:
            for idx, pos in enumerate(alphabet_1_rects_pos):
                alphabet_1_rects[idx].topleft = pos
                surface.blit(alphabet_1_surfaces[idx], alphabet_1_rects[idx])
            for idx, pos in enumerate(alphabet_2_rects_pos):
                alphabet_2_rects[idx].topleft = pos
                surface.blit(alphabet_2_surfaces[idx], alphabet_2_rects[idx])
            for idx, pos in enumerate(alphabet_3_rects_pos):
                alphabet_3_rects[idx].topleft = pos
                surface.blit(alphabet_3_surfaces[idx], alphabet_3_rects[idx])
            for idx, pos in enumerate(alphabet_4_rects_pos):
                alphabet_4_rects[idx].topleft = pos
                surface.blit(alphabet_4_surfaces[idx], alphabet_4_rects[idx])

        return all_keyboard_pos, (let_x_size, let_y_size)

    def highlight_text(coord, k_pos, letter):

        x = coord[0]
        y = coord[1]
        letters = "q w e r t y u i o pa s d f g h j k lz x c v b n madv rub end"
        highlighted, highlighted_pos = None, None
        output_letter = None

        for idx, pos in enumerate(k_pos):

            if idx < 49:  # 0 - 48 represents all letters and spaces between them
                if pos[0] <= x < pos[0] + letter[0]:
                    if pos[-1] <= y < pos[-1] + letter[-1]:
                        if letters[idx] != " ":
                            highlighted, highlighted_pos = idx, pos
                            output_letter = idx

            elif idx >= 49:
                if pos[0] <= x < pos[0] + letter[0]:
                    if pos[-1] <= y < pos[-1] + letter[-1]:
                        if letters[idx] != " ":
                            if 49 <= idx <= 51:
                                highlighted, highlighted_pos = [49, 50, 51], [k_pos[49], k_pos[50], k_pos[51]]
                                output_letter = 49
                            elif 53 <= idx <= 55:
                                highlighted, highlighted_pos = [53, 54, 55], [k_pos[53], k_pos[54], k_pos[55]]
                                output_letter = 53
                            elif 57 <= idx <= 59:
                                highlighted, highlighted_pos = [57, 58, 59], [k_pos[57], k_pos[58], k_pos[59]]
                                output_letter = 57

        if highlighted is not None and highlighted_pos is not None:

            board_text = "darkforest.ttf"
            alphabet = pygame.font.Font(f"./{board_text}", int(50 * scaler))

            if not instructions_font_animating:
                if isinstance(highlighted, int):
                    hovered_let_surface = alphabet.render(letters[highlighted], True, color.alert_red, color.background)
                    hovered_let_rect = hovered_let_surface.get_rect()
                    hovered_let_rect.topleft = highlighted_pos
                    surface.blit(hovered_let_surface, hovered_let_rect)

                else:
                    for l_idx, idx in enumerate(highlighted):
                        hovered_let_surface = alphabet.render(letters[idx], True, color.alert_red, color.background)
                        hovered_let_rect = hovered_let_surface.get_rect()
                        hovered_let_rect.topleft = highlighted_pos[l_idx]
                        surface.blit(hovered_let_surface, hovered_let_rect)

        return output_letter

    def print_name(timer, command, user_name, key_positions, letter_size, keyboard):

        name_complete = False
        letters = "q w e r t y u i o pa s d f g h j k lz x c v b n madv rub end"
        if command == 49:
            action = "adv"
        elif command == 53:
            action = "rub"
        elif command == 57:
            action = "end"
        elif command is None:
            pass
        else:
            action = letters[command]

        if command is not None:
            if not keyboard:
                if command < 49:
                    if timer >= 10:
                        if pygame.mouse.get_pressed(num_buttons=3) == (1, 0, 0):
                            timer = 0
                            if timer == 0:
                                if len(user_name) < 12:
                                    user_name += letters[command]

                elif command == 49:
                    if timer >= 10:
                        if pygame.mouse.get_pressed(num_buttons=3) == (1, 0, 0):
                            timer = 0
                            if timer == 0:
                                if len(user_name) < 12:
                                    user_name += "_"
                elif command == 53:
                    if timer >= 10:
                        if pygame.mouse.get_pressed(num_buttons=3) == (1, 0, 0):
                            timer = 0
                            if timer == 0:
                                user_name = user_name[:-1]
                elif command == 57:
                    if timer >= 10:
                        if pygame.mouse.get_pressed(num_buttons=3) == (1, 0, 0):
                            timer = 0
                            if timer == 0:
                                name_complete = True
                                return timer, user_name, name_complete

            else:
                if command < 49:
                    timer = 0
                    if timer == 0:
                        if len(user_name) < 12:
                            user_name += letters[command]
                elif command == 49:
                    timer = 0
                    if timer == 0:
                        if len(user_name) < 12:
                            user_name += "_"
                elif command == 53:
                    timer = 0
                    if timer == 0:
                        user_name = user_name[:-1]
                elif command == 57:
                    timer = 0
                    if timer == 0:
                        name_complete = True
                        return timer, user_name, name_complete

        timer += 1

        board_text = "SF Square Head Bold.ttf"
        name_text = pygame.font.Font(f"{board_text}", int(70 * scaler))

        row_x_start = (surface_width // 2)
        name_surface = name_text.render(user_name, True, color.sky_blue)
        name_rect = name_surface.get_rect()
        name_rect_pos = (row_x_start, surface_height - surface_height // 3)
        name_rect.center = name_rect_pos
        surface.blit(name_surface, name_rect)

        return timer, user_name, name_complete

    def instructions_animation(title_start, count, position):

        if title_start:
            position += instructions_font_speed
            position = position % (surface_width * 2)
            count += 1
            if count == 25:
                title_start = False
                position = (surface_width // 2) % (surface_width * 2)

        return title_start, count, position

    instructions_position = 0
    instructions_font_speed = 500 * scaler
    instructions_font_animating = True
    instructions_font_open_count = 0

    keys = [pygame.K_q, " ", pygame.K_w, " ", pygame.K_e, " ", pygame.K_r, " ", pygame.K_t, " ", pygame.K_y, " ",
            pygame.K_u, " ", pygame.K_i, " ", pygame.K_o, " ", pygame.K_p, pygame.K_a, " ", pygame.K_s, " ", pygame.K_d,
            " ", pygame.K_f, " ", pygame.K_g, " ", pygame.K_h, " ", pygame.K_j, " ", pygame.K_k, " ", pygame.K_l,
            pygame.K_z, " ", pygame.K_x, " ", pygame.K_c, " ", pygame.K_v, " ", pygame.K_b, " ", pygame.K_n, " ",
            pygame.K_m, pygame.K_SPACE, " ", " ", " ", pygame.K_BACKSPACE, " ", " ", " ", pygame.K_RETURN]
    keyboard_pressed = False

    mouse_timer = 0
    account_name = ""
    complete = False
    while not complete:

        surface.fill(color.background)

        draw_margin()
        disc_pulse_value, disc_pulse_direction = draw_background_disc(disc_pulse_value, disc_pulse_direction)

        instructions_font_animating, instructions_font_open_count, instructions_position = \
            instructions_animation(instructions_font_animating, instructions_font_open_count, instructions_position)

        blinker_count, blinker_on = start_text_blinker(blinker_count, blinker_on)

        all_pos, let_size = text_board()
        mouse_xy = mouse_coord()
        hovered_letter = highlight_text(mouse_xy, all_pos, let_size)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    complete = True
                for idx, pressed in enumerate(keys):
                    if event.key == keys[idx]:
                        keyboard_pressed = True
                        hovered_letter = idx

        mouse_timer, account_name, complete = \
            print_name(mouse_timer, hovered_letter, account_name, all_pos, let_size, keyboard_pressed)
        keyboard_pressed = False

        pygame.display.update()

    if not account_name:
        account_name = "default"
    return account_name


from keras.models import load_model
import numpy as np
import os

class LossLandscapeVisualizer:
	def __init__(self, model_path, x_path, y_path, min_v=-1.5, max_v=1.5, num=10):
		print("SAVED MODEL AT: '{}'".format(model_path))
		self.nn_model = load_model(model_path)
		self.x_test = np.load(x_path)
		self.y_test = np.load(y_path)

		self.min_v = min_v
		self.max_v = max_v
		self.num = num

	def flatten_weights(self, weights):
		flatten = list()
		for layer_weights in weights:
			flatten.append(layer_weights.flatten())

		return np.concatenate(flatten)

	def get_random_unit_vector(self, length):
		vector = np.random.normal(size=length)
		# vector = np.random.rand(length)
		magnitude = np.linalg.norm(vector)
		unit_vector = np.divide(vector, magnitude)
		return unit_vector

	def get_step_vectors(self, range1, range2, num1, num2):
		v1 = np.linspace(range1[0], range1[1], num1)
		v2 = np.linspace(range2[0], range2[1], num2)

		return v1, v2

	def get_sets_of_weights(self, unit_vector_1, unit_vector_2, steps1, steps2, weights_origin):
		v1 = unit_vector_1.reshape(unit_vector_1.shape[0], 1)
		steps_1 = steps1.reshape((1, steps1.shape[0]))

		v2 = unit_vector_2.reshape(unit_vector_2.shape[0], 1)
		steps_2 = steps2.reshape((1, steps2.shape[0]))

		v1 = np.matmul(v1, steps_1).T
		v2 = np.matmul(v2, steps_2).T

		v1_idx = np.arange(0, v1.shape[0], 1)
		v2_idx = np.arange(0, v2.shape[0], 1)

		V1_idx, V2_idx = np.meshgrid(v1_idx, v2_idx)

		V1 = np.ndarray(shape=(V1_idx.shape[0], V1_idx.shape[1], v1.shape[1]), dtype=np.float)
		for i in range(V1_idx.shape[0]):
			for j in range(V1_idx.shape[1]):
				idx = V1_idx[i, j]
				temp = v1[idx]
				V1[i, j] = temp

		V2 = np.ndarray(shape=(V2_idx.shape[0], V2_idx.shape[1], v2.shape[1]), dtype=np.float)
		for i in range(V2_idx.shape[0]):
			for j in range(V2_idx.shape[1]):
				idx = V2_idx[i, j]
				temp = v2[idx]
				V2[i, j] = temp

		result_vectors = V1 + V2
		sets_of_weights = weights_origin + result_vectors

		return sets_of_weights

	def set_weights(self, weights_vector):
		new_weights = list()
		for weights_layer in self.nn_model.get_weights():
			number_of_weights = np.prod(weights_layer.shape)

			weights_to_set = weights_vector[:number_of_weights].reshape(weights_layer.shape)
			weights_vector = weights_vector[number_of_weights:]
			new_weights.append(weights_to_set)

		self.nn_model.set_weights(new_weights)

	def evaluate_model(self, weights):
		self.set_weights(weights)
		result = self.nn_model.evaluate(self.x_test, self.y_test, verbose=0)
		return result[0]

	def get_plot_data(self, weights, s1, s2):
		X, Y = np.meshgrid(s1, s2)
		Z = np.ndarray(shape=X.shape, dtype=np.float)
		for i in range(s2.shape[0]):
			for j in range(s1.shape[0]):
				Z[i][j] = self.evaluate_model(weights[i][j])

		return X, Y, Z

	def convert_to_string(self, data):
		string = '['
		for i in range(data.shape[0]):
			arr = '['
			for j in range(data.shape[1]):
				arr += str(data[i, j]) + ','
			arr = arr[:-1] + '],'
			string += arr
		string = string[:-1] + '];'
		return string

	def process(self):
		f = self.flatten_weights(self.nn_model.get_weights())
		v1 = self.get_random_unit_vector(len(f))
		v2 = self.get_random_unit_vector(len(f))
		s1, s2 = self.get_step_vectors((self.min_v, self.max_v), (self.min_v, self.max_v), self.num, self.num)

		weights = self.get_sets_of_weights(v1, v2, s1, s2, f)
		X, Y, Z = self.get_plot_data(weights, s1, s2)

		x_string = self.convert_to_string(X)
		y_string = self.convert_to_string(Y)
		z_string = self.convert_to_string(Z)

		return {'x': x_string, 'y': y_string, 'z': z_string}

if __name__ == '__main__':

	# path = os.path.join('../', '/media/models/model_joIeLZT.h5')
	print(os.listdir('../media/models'))
	path = '..' + '/media/models/model_joIeLZT.h5'
	model = load_model(path)


### Rename all series belonging to single patient into folders
# By Ashkan Pakzad (ashkan.pakzad.13 at ucl.ac.uk)
# also rewindows CT images
#Folder Structure:
#|_PatientName
#   |
#   |_Series1
#       |_Dicomfiles....
#   |
#   |_Series2
#       |_Dicomfiles....
#   |
#   |_Series3
#       |_Dicomfiles....
#   |
#   |_Other
#       |_misc....

import os
import pydicom
import copy
from pathlib import Path
from argparse import ArgumentParser

if __name__ == "__main__":
    parser = ArgumentParser(description="Process raw unorganised dicom files for single patient in dicom series. Also anonymises DOB and changes default CT window.")
    parser.add_argument('Inputfilepath', nargs='+' ,type=str,
                        help='Input folder that directly contains all patient dicom files without subdirectories. e.g. ''dicoms'' ')
    parser.add_argument('--Outputfilepath','-o', nargs='+', type=str,
                        help='Output file to save processed dicom files to. defaults to ''./dicoms-processed/'' where dicoms is the input folder name')
    parser.add_argument('--CTwindow','-w',nargs='+',default=[-600, 1500],
                        type=int, help='Set default DICOM metadata CT window for data, [center, width]. set to pulmonary by default, [-600, 1500]. ')

    args = parser.parse_args()

    CTwindow = args.CTwindow
    # paths to data and save location
    filepath = Path(str(args.Inputfilepath[0])) # directory containing all dicom series of single patient

    # directory to save new metadata fields
    if args.Outputfilepath == None:
        newdir = filepath+'-processed'
    else:
        newdir = Path(str(args.Outputfilepath[0]))
    os.mkdir(newdir)

    # Create list of files in folder
    filenames = []
    for names in os.listdir(filepath):
        if not names.startswith('.'):
            filenames.append(names)

    # Read first file for patient name
    ds = pydicom.filereader.dcmread(str(filepath.joinpath(filenames[0])))
    patientname = str(ds.data_element('PatientName').value)
    print(patientname)
    os.mkdir(newdir.joinpath(patientname))
    newpatient_dir = newdir.joinpath(patientname)
    print('patient name: '+ patientname)

    series_names = []

    # Find all series names
    for dcm in filenames:
        ds = pydicom.filereader.dcmread(str(filepath.joinpath(dcm)))
        print(dcm)
        try:
            current_series = str(ds.data_element('SeriesDescription').value)
        except KeyError: # incase there is no series SeriesDescription tag.
            current_series = 'other'
        if current_series not in series_names:
            series_names.append(current_series)
            os.mkdir(newpatient_dir.joinpath(current_series))
            print('New image series: '+current_series)

    ## for all files
    error_number = 0
    for dcm in filenames:
        # load new dicom metadata
        ds = pydicom.filereader.dcmread(str(filepath.joinpath(dcm)))
        try:
            current_series = str(ds.data_element('SeriesDescription').value)
        except KeyError:
            current_series = 'other'
        # Set patient's DOB to anonymise
        try:
            ds.data_element('PatientBirthDate').value = '19000101'
        except KeyError:
            pass
        try:
            filenumber = ds.data_element('InstanceNumber').value
        except KeyError:
            # incase no instance number
            error_number = error_number + 1
            filenumber = error_number
        # Change default CT window to pulmonary
        try:
            ds.data_element('WindowCenter').value = CTwindow[0]
            ds.data_element('WindowWidth').value = CTwindow[1]
        except KeyError:
            pass
        newfile = 'IM_%04d.dcm' %filenumber
        ## write the dcm file to new file
        print('New file: '+ str(newpatient_dir.joinpath(current_series).joinpath(newfile)))
        ds.save_as(str(newpatient_dir.joinpath(current_series).joinpath(newfile)))

    print('COMPLETE')


from django.shortcuts import render
from django.http.response import HttpResponse

from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.views import Response
import pika
import json

from .models import PendingStore, Store, Product, Tag
from django.core import serializers

# Create your views here.
from .serializers import ProductSerializer, StoreSerializer, PendingStoreSerializer, TagSerializer

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def list(self, request, *args, **kwargs):
        request_data = request.query_params
        search = request_data.get("q")
        if search:
            self.queryset = Product.objects.filter(name__contains=search)

        return super().list(request, *args, **kwargs)

class StoreViewSet(viewsets.ModelViewSet):
    queryset = Store.objects.all()
    serializer_class = StoreSerializer

    def list(self, request, *args, **kwargs):
        request_data = request.query_params
        search = request_data.get("q")
        if search:
            self.queryset = Store.objects.filter(name__contains=search)

        return super().list(request, *args, **kwargs)

class PendingStoreViewSet(viewsets.ModelViewSet):
    queryset = PendingStore.objects.all()
    serializer_class = PendingStoreSerializer

    def list(self, request, *args, **kwargs):
        request_data = request.query_params
        search = request_data.get("q")
        if search:
            self.queryset = PendingStore.objects.filter(name__contains=search)

        return super().list(request, *args, **kwargs)

class TagViewSet(viewsets.ModelViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer

    def list(self, request, *args, **kwargs):
        request_data = request.query_params
        search = request_data.get("q")
        if search:
            self.queryset = Tag.objects.filter(name__contains=search)

        return super().list(request, *args, **kwargs)

@api_view(['POST'])
def propose(request):
    string = request.body.decode("utf-8")
    objectJson = json.loads(string)
    url = "https://{}.myshopify.com".format(objectJson['name'])
    try:
        store = PendingStore.objects.get(url=url)
        if store is not None:
            return Response({"message": "This store exists", "success": False})
    except PendingStore.DoesNotExist:
        connection = pika.BlockingConnection(pika.URLParameters('amqp://rabbitmq:rabbitmq@rabbit:5672/'))
        channel = connection.channel()
        channel.exchange_declare(exchange='store', exchange_type='direct', durable=False, auto_delete=False)
        result = channel.queue_declare(queue='propose', durable=False, exclusive=False, auto_delete=False)
        queue_name = result.method.queue
        channel.queue_bind(exchange='store', queue=queue_name, routing_key='propose')
        body = request.body
        channel.basic_publish(exchange='store', routing_key='propose', body=body)
        channel.close()
        return Response({"message": "Done", "success": True})

@api_view(['POST'])
def add(request):
    string = request.body.decode("utf-8")
    objectJson = json.loads(string)
    name = objectJson['name']
    url = "https://{}.myshopify.com".format(name)
    try:
        pendingStore = PendingStore.objects.get(url=url)
        if pendingStore.status != "approved":
            pendingStore.status = "approved"
            pendingStore.save()
    except PendingStore.DoesNotExist:
        print("continue")

    try:
        store = Store.objects.get(url=url)
        return Response({"message": "This store exists", "success": False})
    except Store.DoesNotExist:
        store = Store(url=url, name=name, status="pending")
        store.save()
        connection = pika.BlockingConnection(pika.URLParameters('amqp://rabbitmq:rabbitmq@rabbit:5672/'))
        channel = connection.channel()
        channel.exchange_declare(exchange='store', exchange_type='direct', durable=False, auto_delete=False)
        result = channel.queue_declare(queue='add', durable=False, exclusive=False, auto_delete=False)
        queue_name = result.method.queue
        channel.queue_bind(exchange='store', queue=queue_name, routing_key='add')
        body = json.dumps({"id": store.id, "url": store.url}).encode("utf-8")
        channel.basic_publish(exchange='store', routing_key='add', body=body)
        channel.close()
        return Response({"message": "Done", "success": True})


'''
Problem Solving Baekjoon 7562
Author: Injun Son
Date: September 22, 2020
'''
import sys
import copy
from itertools import combinations
from collections import deque

dx = [1, 2, 2, 1, -1, -2, -2, -1]
dy = [2, 1, -1, -2, -2, -1, 1, 2]

def bfs(y, x, ty, tx):
    q = deque()
    check = dict()
    check[(y,x)] = 1
    q.append((y,x, 0))
    while q:
        y, x, cnt = q.popleft()
        if (y, x) == (ty, tx):
            return cnt
        else:
            for i in range(len(dx)):
                ny, nx = y+dy[i], x+dx[i]
                if ny<0 or ny>=N or nx<0 or nx>=N or (ny, nx) in check:
                    continue
                else:
                    check[(ny, nx)] = 1
                    q.append((ny, nx, cnt+1))

T = int(input())
for _ in range(T):
    N = int(input())
    cur_y, cur_x = map(int, input().split())
    tar_y, tar_x = map(int, input().split())
    # graph = [[0]*N for _ in range(N)]
    print(bfs(cur_y, cur_x, tar_y, tar_x))


from mltoolkit.mlmo.layers import Ffnn, MuSigmaFfnn, Attention, OutEmbds
from mltoolkit.mlmo.layers.encoders import GruEncoder
from mltoolkit.mlmo.layers.decoders import PointerGenNetwork, GruPointerDecoder
from torch.nn import Module, Embedding, Tanh, Sequential, Softmax, \
    Sigmoid, Parameter, Linear, init, functional, ReLU, LayerNorm, Dropout
from mltoolkit.mlmo.utils.helpers.pytorch.computation import comp_seq_log_prob, \
    re_parameterize, kld_gauss, kld_normal, masked_softmax, wasserstein_gauss, init_wassers_weight, init_rev_weight
from collections import OrderedDict
import torch as T
from wassos.utils.helpers.modelling import group_att_over_input, group_att_over_input_for_decode
from mltoolkit.mlmo.utils.tools import DecState
from mltoolkit.mlmo.layers.wass import Wass, Rev,Weight, Linear_logit
from transformer.Models import Decoder
from pre_train_transformer import load_parameter
from wassos.utils.hparams import ModelHP, RunHP
from .tools import BridgeRNN, BridgeMLP

run_hp = RunHP()

EPS = 1e-12

class WassOS(Module):
    """
    CopyCat summarizer variational summarizer based on hierarchical latent
    representations of data. Specifically, it represents both review groups
    and reviews as separate latent code types.
    """

    def __init__(self, args,vocab, tag_vocab, max_rev_per_group, vocab_size, ext_vocab_size, ext_tag_size,tag_size, emb_dim, enc_hidden_dim,
                 c_dim, z_dim, att_hidden_dim, states_sc_hidden=150,
                 cgate_hidden_dim=None, word_padding_idx=0, dec_layers =1, dec_hidden_size= 200, heads =8,
                 ff_size=3072, strategy='T_center'):
        """
        :param vocab_size: the number of words by the generator.
        :param ext_vocab_size: the extended number of words that is accessible
            by the copy mechanism.
        :param emb_dim: the number of dimensions in word embeddings.
        :param enc_hidden_dim: GRU encoder's hidden dimension.
        :param c_dim: dimension of the group representation.
        :param z_dim: dimension of the review representation.
        :param att_hidden_dim: hidden dimension of hidden dimension of
            feed-forward networks.
        :param states_sc_hidden: hidden dimension of the score function used
            for production of the group representation c.
        :param cgate_hidden_dim: copy gate hidden dimension.
        """
        assert vocab_size <= ext_vocab_size

        super(WassOS, self).__init__()

        self.strategy = strategy

        self.max_rev_per_group = max_rev_per_group

        self.args = args

        self.z_dim = z_dim

        self._embds = Embedding(ext_vocab_size, emb_dim)

        self._embds_tag = Embedding(ext_tag_size, emb_dim)

        self._encoder = GruEncoder(input_dim=emb_dim, hidden_dim=enc_hidden_dim)

        self.enc_hidden_dim = enc_hidden_dim

        # POINTER-GENERATOR NETWORK #

        #   generation network - computes generation distribution over words
        dec_inp_dim = z_dim + enc_hidden_dim
        gen_network = Sequential()
        gen_network.add_module("lin_proj", Linear(dec_inp_dim, emb_dim))
        gen_network.add_module("out_embds", OutEmbds(self._embds, vocab_size))
        gen_network.add_module("softmax", Softmax(dim=-1))

        #   copy gate - computes probability of copying a word
        c_ffnn = Ffnn(z_dim + enc_hidden_dim + emb_dim,
                      hidden_dim=cgate_hidden_dim,
                      non_linearity=Tanh(), output_dim=1)
        copy_gate = Sequential()
        copy_gate.add_module("ffnn", c_ffnn)
        copy_gate.add_module("sigmoid", Sigmoid())

        pgn = PointerGenNetwork(gen=gen_network, copy_gate=copy_gate,
                                ext_vocab_size=ext_vocab_size)

        # COMPLETE DECODER (GRU + ATTENTION + COPY-GEN) #

        #   attention for decoder over encoder's hidden states
        dec_att = Attention(query_dim=z_dim, hidden_dim=att_hidden_dim,
                            value_dim=enc_hidden_dim,
                            non_linearity=Tanh())
        self._keys_creator = dec_att.create_keys

        self.tgt_embedding = Embedding(ext_vocab_size, 768, word_padding_idx)

        self.load_decoder = Decoder(self.tgt_embedding, dec_layers, heads, d_k=96, d_v=96,
                                    d_model=dec_hidden_size, d_inner=ff_size, n_position=200, dropout=0.1,
                                    scale_emb=False)
        self.transformer_decoder = load_parameter(self.load_decoder)
        # self.transformer_decoder = self.load_decoder

        self.logit = Linear_logit(int(z_dim/2), ext_vocab_size)

        self._decoder = GruPointerDecoder(input_dim=emb_dim + z_dim,
                                          hidden_dim=z_dim,
                                          contxt_dim=enc_hidden_dim,
                                          att_module=dec_att,
                                          pointer_gen_module=pgn,
                                          transformer_decoder=self.transformer_decoder,
                                          word_padding_idx=0,
                                          cat_contx_to_inp=True,
                                          pass_extra_feat_to_pg=False,
                                          logit_fun=self.logit)

        # NETWORKS THAT PRODUCES LATENT VARIABLES' MUS AND SIGMAS #

        # z inference network
        self._z_inf_network_sem = MuSigmaFfnn(
                                          # input_dim=enc_hidden_dim,
                                          input_dim=int(enc_hidden_dim / 2),
                                          non_linearity=Tanh(),
                                          output_dim=int(z_dim/2))
        self._z_inf_network_syn = MuSigmaFfnn(
                                          # input_dim=enc_hidden_dim,
                                          input_dim=int(enc_hidden_dim / 2),
                                          non_linearity=Tanh(),
                                          output_dim=int(z_dim / 2))

        # z prior network
        self._z_prior_network = MuSigmaFfnn(input_dim=c_dim, output_dim=z_dim)

        # c inference network
        #   scores each state to obtain group context vector
        if self.strategy == 'T_center':
            states_dim = enc_hidden_dim + emb_dim
        else:
            states_dim = enc_hidden_dim
        self._c_states_scoring = Ffnn(input_dim=states_dim,
                                      hidden_dim=states_sc_hidden,
                                      output_dim=1, non_linearity=Tanh())

        self._c_inf_network_sem = MuSigmaFfnn(input_dim=int(states_dim/2),
                                          output_dim=int(c_dim/2))

        self._c_inf_network_syn = MuSigmaFfnn(input_dim=int(states_dim / 2),
                                          output_dim=int(c_dim / 2))

        self.context_linear = Linear((enc_hidden_dim + emb_dim), states_dim)

        self.wassers_weight_sem = Wass(int(z_dim/2), 1)
        self.wassers_weight_syn = Wass(int(z_dim/2), 1)

        if self.strategy == 'T_center':
            dim = emb_dim + enc_hidden_dim
        else:
            dim = enc_hidden_dim
        self.rev_weight = Rev(dim, 1)

        # encode of multi-task
        self.task_enc_dim = int(enc_hidden_dim/2)
        self.task_dec_dim = int(enc_hidden_dim/2)
        self.args = args
        self.vocab = vocab
        self.tag_vocab = tag_vocab

        # multi-task loss =====================
        self.sup_syn = GruPointerDecoder(input_dim=emb_dim + int(z_dim/2),
                                          hidden_dim=int(z_dim/2),
                                          contxt_dim=enc_hidden_dim,
                                          att_module=dec_att,
                                          pointer_gen_module=pgn,
                                          transformer_decoder=self.transformer_decoder,
                                          word_padding_idx=0,
                                          cat_contx_to_inp=True,
                                          pass_extra_feat_to_pg=False,
                                          logit_fun=self.logit)

        self.sup_sem = BridgeMLP(
            args=self.args,
            vocab=self.vocab,
            enc_dim=self.task_enc_dim,
            dec_hidden=self.task_dec_dim
        )

        # z_syn predicts the sentence
        self.syn_infer = GruPointerDecoder(input_dim=emb_dim + int(z_dim/2),
                                          hidden_dim=int(z_dim/2),
                                          contxt_dim=enc_hidden_dim,
                                          att_module=dec_att,
                                          pointer_gen_module=pgn,
                                          transformer_decoder=self.transformer_decoder,
                                          word_padding_idx=0,
                                          cat_contx_to_inp=True,
                                          pass_extra_feat_to_pg=False,
                                          logit_fun=self.logit)

        # z_sem predicts the sentence
        self.sem_infer = GruPointerDecoder(input_dim=emb_dim + int(z_dim/2),
                                          hidden_dim=int(z_dim/2),
                                          contxt_dim=enc_hidden_dim,
                                          att_module=dec_att,
                                          pointer_gen_module=pgn,
                                          transformer_decoder=self.transformer_decoder,
                                          word_padding_idx=0,
                                          cat_contx_to_inp=True,
                                          pass_extra_feat_to_pg=False,
                                          logit_fun=self.logit)

        self.syn_adv = GruPointerDecoder(input_dim=emb_dim + int(z_dim/2),
                                          hidden_dim=int(z_dim/2),
                                          contxt_dim=enc_hidden_dim,
                                          att_module=dec_att,
                                          pointer_gen_module=pgn,
                                          transformer_decoder=self.transformer_decoder,
                                          word_padding_idx=0,
                                          cat_contx_to_inp=True,
                                          pass_extra_feat_to_pg=False,
                                          logit_fun=self.logit)
        # syn predicts bag of words
        self.sem_adv = BridgeMLP(
            args=self.args,
            vocab=self.vocab,
            enc_dim=self.task_enc_dim,
            dec_hidden=self.task_dec_dim
        )

    def forward(self, rev, rev_len,rev_tag, rev_mask,rev_tag_mask,
                group_rev_indxs, group_rev_indxs_mask,
                rev_to_group_indx, other_rev_indxs, other_rev_indxs_mask,
                other_rev_comp_states, other_rev_comp_states_mask,
                c_lambd=0., z_lambd=0.):
        """
        :param rev: review word ids.
            [batch_size, rev_seq_len]
        :param rev_len: review lengths.
            [batch_size]
        :param rev_mask: float mask where 0. is set to padded words.
            [batch_size, rev_seq_len]
        :param rev_to_group_indx: mapping from reviews to their corresponding
            groups.
            [batch_size]
        :param group_rev_indxs: indxs of reviews that belong to same groups.
            [group_count, max_rev_count]
        :param group_rev_indxs_mask: float mask where 0. is set to padded
            review indxs.
            [group_count, max_rev_count]
        :param other_rev_indxs: indxs of leave-one-out reviews.
            [batch_size, max_rev_count]
        :param other_rev_indxs_mask: float mask for leave-one-out reviews.
        :param other_rev_comp_states: indxs of (hidden) states of leave-one-out
            reviews. Used as an optimization to avoid attending over padded
            positions.
            [batch_size, cat_rev_len]
        :param other_rev_comp_states_mask: masking of states for leave-one-out
            reviews.
            [batch_size, cat_rev_len]
        :param c_lambd: annealing constant for c representations.
        :param z_lambd: annealing constant for z representations.

        :return loss: scalar loss corresponding to the mean ELBO over batches.
        :return metrs: additional statistics that are used for analytics and
            debugging.
        """
        bs = rev.size(0)
        device = rev.device
        group_count = group_rev_indxs.size(0)
        loss = 0.
        metrs = OrderedDict()

        # used for cross_entropy loss
        target = T.zeros_like(rev)
        target[:-1] = rev[1:]
        target[-1] = rev[0]
        # target = rev
        rev_length = rev.size()[1]
        target_list = list(T.chunk(target, rev_length, 1))

        # used for syntactic parse
        target_tag = T.zeros_like(rev_tag)
        target_tag[:-1] = rev_tag[1:]
        target_tag[-1] = rev_tag[0]
        rev_tag_length = rev_tag.size()[1]
        target_tag_list = list(T.chunk(target_tag, rev_tag_length, 1))

        rev_word_embds = self._embds(rev)
        rev_tag_embds = self._embds_tag(rev_tag)

        rev_encs, rev_hiddens = self.encode(rev_word_embds, rev_len)

        att_keys = self.create_att_keys(rev_hiddens)
        contxt_states = self.get_contxt_states(rev_hiddens, rev_word_embds)

        # running the c inference network for the whole group
        # calculate w1*c1 + w2*c2 + ....

        c_mu_q_sem, \
        c_sigma_q_sem, \
        c_mu_q_syn, \
        c_sigma_q_syn, \
        scor_wts = self.get_q_c_mu_sigma(contxt_states, rev_mask,
                                         group_rev_indxs, group_rev_indxs_mask)

        # running the z inference network for each review,
        # separate rev_enc into half
        rev_enc_hid = rev_encs.view(bs, 2, -1)
        rev_enc_sem = rev_enc_hid[:, 0, :].squeeze(1)
        rev_enc_syn = rev_enc_hid[:, 1, :].squeeze(1)

        z_mu_q_sem, z_sigma_q_sem, z_mu_q_syn, z_sigma_q_syn = self.get_q_z_mu_sigma(rev_enc_sem, rev_enc_syn)
        z_sem = re_parameterize(z_mu_q_sem, z_sigma_q_sem)
        z_syn = re_parameterize(z_mu_q_syn, z_sigma_q_sem)
        z = T.cat((z_syn, z_sem), dim=-1)

        # PERFORMING REVIEWS RECONSTRUCTION ================================================#

        rev_att_keys, \
        rev_att_vals, \
        rev_att_mask = group_att_over_input_for_decode(inp_att_keys=att_keys,
                                            inp_att_vals=rev_hiddens,
                                            inp_att_mask=rev_mask,
                                            att_indxs=other_rev_indxs,
                                            att_indxs_mask=other_rev_indxs_mask)

        rev_att_word_ids = rev[other_rev_indxs].view(bs, -1)

        # optimizing the attention targets by making more compact tensors
        # with less padded entries
        sel = T.arange(bs, device=device).unsqueeze(-1)
        rev_att_keys = rev_att_keys[sel, other_rev_comp_states]
        rev_att_vals = rev_att_vals[sel, other_rev_comp_states]
        rev_att_mask = other_rev_comp_states_mask
        rev_att_word_ids = rev_att_word_ids[sel, other_rev_comp_states]

        # creating an extra feature that is passe
        extra_feat = z.unsqueeze(1).repeat(1, rev_word_embds.size(1), 1)

        log_probs, rev_att_wts, \
        hidden, cont, \
        copy_probs = self._decode(embds=rev_word_embds, mask=rev_mask,
                                          extra_feat=extra_feat,
                                          review_word_id=rev,
                                          hidden=z, att_keys=rev_att_keys,
                                          att_values=rev_att_vals,
                                          att_mask=rev_att_mask,
                                          att_word_ids=rev_att_word_ids)

        rec_term = comp_seq_log_prob(log_probs[:, :-1], seqs=rev[:, 1:],
                                     seqs_mask=rev_mask[:, 1:])

        avg_rec_term = rec_term.mean(dim=0)

        # loss for E

        loss += -avg_rec_term

        syntax_hidden, semantic_hidden = self.latent_for_init(z_sem, z_syn)

        syn_loss, sem_loss = self.get_mul_loss(z_syn, semantic_hidden, target_tag_list, rev, rev_tag_embds, rev_tag_mask)
        mul_loss = self.args.mul_syn * syn_loss + self.args.mul_sem * sem_loss
        loss += mul_loss

        if self.training:
            with T.no_grad():
                dis_syn_loss, dis_sem_loss = self.get_dis_loss(z_syn,z_sem, target_list, rev_word_embds, rev_mask)
                syn_adv, sem_adv = self.get_adv(syntax_hidden, z_sem, target_tag_list, rev, rev_tag_embds, rev_tag_mask)
                if self.args.infer_weight > 0.:
                    adv_syn = self.args.adv_syn * syn_adv + self.args.infer_weight * self.args.inf_sem * dis_sem_loss
                    adv_sem = self.args.adv_sem * sem_adv + self.args.infer_weight * self.args.inf_syn * dis_syn_loss
                else:
                    adv_syn = self.args.adv_syn * syn_adv
                    adv_sem = self.args.adv_sem * sem_adv
        else:
            dis_syn_loss, dis_sem_loss = self.get_dis_loss(z_syn, z_sem, target_list, rev_word_embds, rev_mask)
            syn_adv, sem_adv = self.get_adv(syntax_hidden, z_sem, target_tag_list, rev, rev_tag_embds, rev_tag_mask)
            if self.args.infer_weight > 0.:
                adv_syn = self.args.adv_syn * syn_adv + self.args.infer_weight * self.args.inf_sem * dis_sem_loss
                adv_sem = self.args.adv_sem * sem_adv + self.args.infer_weight * self.args.inf_syn * dis_syn_loss
            else:
                adv_syn = self.args.adv_syn * syn_adv
                adv_sem = self.args.adv_sem * sem_adv

        loss += -(adv_syn + adv_sem)

        # WASSERSTEIN DISTANCE #

        # wassers_distance size [batch_size, max_rev_per_group]

        if self.strategy == 'T_center':
            wassers_distance_sem = wasserstein_gauss(z_mu_q_sem, z_sigma_q_sem, c_mu_q_sem, c_sigma_q_sem,
                                                     group_rev_indxs, self.max_rev_per_group)
            wassers_distance_syn = wasserstein_gauss(z_mu_q_syn, z_sigma_q_syn, c_mu_q_syn, c_sigma_q_syn, group_rev_indxs, self.max_rev_per_group)

            w_sem = self.wassers_weight_sem(z_sem, group_rev_indxs)
            w_syn = self.wassers_weight_syn(z_syn, group_rev_indxs)

            wassers_sem = wassers_distance_sem.unsqueeze(-1)
            inf_sem = T.sum(T.sum(w_sem * wassers_sem, dim=-1), dim=-1)
            loss_inf_sem = inf_sem.mean() * 2.0

            wassers_syn = wassers_distance_syn.unsqueeze(-1)
            inf_syn = T.sum(T.sum(w_syn * wassers_syn, dim=-1), dim=-1)
            loss_inf_syn = inf_syn.mean() * 2.0
            loss += (loss_inf_sem + loss_inf_syn) / 4.0
        else:
            wassers_distance_sem = wasserstein_gauss(z_mu_q_sem, z_sigma_q_sem, c_mu_q_sem, c_sigma_q_sem,
                                                     group_rev_indxs, self.max_rev_per_group)

            w_sem = self.wassers_weight_sem(z_sem, group_rev_indxs)

            wassers_sem = wassers_distance_sem.unsqueeze(-1)
            inf_sem = T.sum(T.sum(w_sem * wassers_sem, dim=-1), dim=-1)
            loss_inf_sem = inf_sem.mean() * 2.0
            loss += loss_inf_sem

        # KULLBACK-LEIBLER TERMS #

        # z kld
        z_kl_term_sem = kld_normal(z_mu_q_sem, z_sigma_q_sem)
        avg_z_kl_term_sem = z_kl_term_sem.mean(dim=0)
        kl_zem = z_lambd * avg_z_kl_term_sem * self.args.sem_weight

        z_kl_term_syn = kld_normal(z_mu_q_syn, z_sigma_q_syn)
        avg_z_kl_term_syn = z_kl_term_syn.mean(dim=0)
        kl_syn = z_lambd * avg_z_kl_term_syn * self.args.syn_weight
        kl_loss = (kl_syn + kl_zem)/(self.args.sem_weight + self.args.syn_weight)
        loss += kl_loss

        # log_var_p_z = T.log(z_sigma_p).sum(-1)

        rev_att_wts = rev_att_wts[:, :-1] * rev_mask[:, 1:].unsqueeze(
            -1)
        copy_probs = copy_probs[:, :-1] * rev_mask[:, 1:]

        # computing maximums over attention weights
        rev_att_max = rev_att_wts.max(-1)[0]

        # computing maximums over steps of copy probs
        max_copy_probs = copy_probs.max(-1)[0]

        # averaging over batches different statistics for logging
        avg_att_max = rev_att_max.mean()
        avg_max_copy_prob = max_copy_probs.mean(0)
        avg_copy_prob = (copy_probs.sum(-1) / rev_len.float()).mean(0)

        metrs['avg_rec'] = avg_rec_term.item()
        metrs['avg_z_kl_term_sem'] = avg_z_kl_term_sem.item()
        metrs['avg_z_kl_term_syn'] = avg_z_kl_term_syn.item()
        metrs['wass_sem'] = loss_inf_sem.item()

        metrs['loss'] = loss.item()
        metrs['mul_loss'] = mul_loss.item()

        metrs['avg_att_max'] = avg_att_max.item()
        metrs['avg_max_copy_prob'] = avg_max_copy_prob.item()
        metrs['avg_copy_prob'] = avg_copy_prob.item()

        metrs['c_lambd'] = c_lambd
        metrs['z_lambd'] = z_lambd

        return loss, metrs

    def get_p_z_mu_sigma(self, c):
        """Computes z prior's parameters (mu, sigma)."""
        mu_p, sigma_p = self._z_prior_network(c)
        return mu_p, sigma_p

    def get_q_z_mu_sigma(self, encs_sem, encs_syn):
        """
        Runs the inference network and computes mu and sigmas for review latent
        codes (z).
        """
        mu_q_sem, sigma_q_sem = self._z_inf_network_sem(encs_sem)
        mu_q_syn, sigma_q_syn = self._z_inf_network_syn(encs_syn)

        return mu_q_sem, sigma_q_sem, mu_q_syn, sigma_q_syn

    def get_q_c_mu_sigma(self, states, states_mask, group_indxs,
                         group_indxs_mask):
        """Computes c approximate posterior's parameters (mu, sigma).

        :param states: [batch_size, seq_len1, dim]
                        representations of review steps, e.g. hidden + embd.
        :param states_mask: [batch_size, seq_len1]
        :param group_indxs: [batch_size2, seq_len2]
                      indxs of reviews belonging to the same product
                      [batch_size2, seq_len2(max_rev_per_group)]
        :param group_indxs_mask: [batch_size2, seq_len2]
        """

        grouped_states, \
        grouped_mask = group_att_over_input(inp_att_vals=states,
                                            inp_att_mask=states_mask,
                                            att_indxs=group_indxs,
                                            att_indxs_mask=group_indxs_mask)

        ws_state, \
        score_weights = self._compute_ws_state(states=grouped_states,
                                               states_mask=grouped_mask)

        group = ws_state.size()[0]
        state_hid = ws_state.view(group, 2, -1)
        state_sem = state_hid[:, 0, :].squeeze(1)
        state_syn = state_hid[:, 1, :].squeeze(1)

        mu_sem, sigma_sem = self._c_inf_network_sem(state_sem)
        if self.strategy == 'T_center':
            mu_syn, sigma_syn = self._c_inf_network_syn(state_syn)
        else:
            mu_syn, sigma_syn = self._z_inf_network_syn(state_syn)

        return mu_sem, sigma_sem, mu_syn, sigma_syn, score_weights

    def encode(self, embds, mask_or_lens):
        return self._encoder(embds, mask_or_lens)

    def decode_beam(self, seqs, hidden, att_word_ids, init_z=None, **kwargs):
        """Function to be used in the beam search process.

        :param seqs: [batch_size, 1]
        :param hidden: [batch_size, hidden_dim]
        :param att_word_ids: [batch_size, cat_rev_len]
        :param init_z: [batch_size, z_dim]
        """
        embds = self._embds(seqs)
        mask = T.ones_like(seqs, dtype=T.float32)

        if init_z is None:
            init_z = hidden

        word_log_probs, att_wts, \
        hidden, cont, ptr_probs= self._decode(embds=embds, mask=mask,
                                               extra_feat=init_z.unsqueeze(1),
                                               hidden=hidden,
                                               att_word_ids=att_word_ids,
                                               # review_word_id=seqs,
                                               **kwargs)
        out = DecState(word_scores=word_log_probs,
                       rec_vals={"hidden": hidden, "cont": cont,
                                 "init_z": init_z},
                       coll_vals={'copy_probs': ptr_probs.squeeze(-1),
                                  'att_wts': att_wts.squeeze(1),
                                  "att_word_ids": att_word_ids})
        return out

    def _decode(self, embds, mask, hidden, cont=None, review_word_id=None, eps=EPS,
                **dec_kwargs):

        """Teacher forcing decoding of sequences.

        :param embds: [batch_size, seq_len, dim]
        :param mask: [batch_size, seq_len]
        :param att_word_ids: [batch_size, inp_seq_len]
        :param copy_prob: a fixed probability of copying words.
        :param hidden: [batch_size, hidden_dim]
        """
        word_probs, copy_probs, \
        att_weights, prev_hidden, \
        prev_cont= self._decoder(embds, mask, init_hidden=hidden,
                                          init_cont=cont, review_word_id=review_word_id, **dec_kwargs)
        #     self._decoder(embds, mask, init_hidden=hidden,
        #                           init_cont=cont, **dec_kwargs)

        word_log_probs = T.log(word_probs + eps)

        return word_log_probs, att_weights, prev_hidden, prev_cont, copy_probs

    def _compute_ws_state(self, states, states_mask):
        """Computes weighted state by scoring each state."""

        state_scores = self._c_states_scoring(states)
        grouped_state_weights = masked_softmax(state_scores, states_mask, dim=2)

        # compute the weight of word in each reviews, and put them together
        # the size of group_context is[batch_size, rev_num_per_group, dim]
        group_context = (states * grouped_state_weights).sum(dim=2)
        review_weight = self.rev_weight(group_context)
        goup_rev = T.sum(review_weight * group_context, dim=1)

        return goup_rev, grouped_state_weights

    def create_att_keys(self, hiddens):
        """
        Creates the attention keys that are used in the decoder.
        Performs projection that is required by the attention mechanism, allows
        for a speed-up by not performing this operation every time attention is
         called (at each decoding step).

        :param hiddens: [batch_size, seq_len, hidden_dim]
        """
        att_keys = self._keys_creator(hiddens)
        return att_keys

    def get_contxt_states(self, hiddens, embds):
        context = T.cat((hiddens, embds), dim=-1)
        new_context = self.context_linear(context)
        return new_context
        # return T.cat((hiddens, embds), dim=-1)

    def get_mul_loss(self, syntax_hidden, semantic_hidden, syn_tgt, sem_tgt, tag_emb, tag_mask, cont=None, **dec_kwargs):

        extra_feat = syntax_hidden.unsqueeze(1).repeat(1, tag_emb.size(1), 1)

        logits = self.sup_syn(tag_emb, tag_mask, init_hidden=syntax_hidden,
                                           init_cont=cont, extra_feat=extra_feat,mode='syn', **dec_kwargs)

        rev_tag_length = len(syn_tgt)
        syn_loss = 0

        for targ, logit in zip(syn_tgt, logits):
            # print(type(targ), type(logit), "type is what")
            targ = T.squeeze(targ)

            ptloss = T.nn.CrossEntropyLoss()
            sub_loss = ptloss(logit, targ)
            syn_loss += sub_loss
        syn_loss = T.div(syn_loss, rev_tag_length)

        sem_loss = self.sup_sem.forward(hidden=semantic_hidden, tgt_var=sem_tgt)

        return syn_loss, sem_loss

    # z_sem and z_syn  predict sentence
    def get_dis_loss(self, syntax_hidden, semantic_hidden, sem_tgt, sem_emb, sem_mask, cont=None, **dec_kwargs):
        extra_feat_sem = semantic_hidden.unsqueeze(1).repeat(1, sem_emb.size(1), 1)
        extra_feat_syn = syntax_hidden.unsqueeze(1).repeat(1, sem_emb.size(1), 1)

        logits_syn = self.syn_infer(sem_emb, sem_mask, init_hidden=syntax_hidden,
                                          init_cont=cont, extra_feat=extra_feat_syn,mode='sentence', **dec_kwargs)
        logits_sem = self.sem_infer(sem_emb, sem_mask, init_hidden=semantic_hidden,
                                           init_cont=cont, extra_feat=extra_feat_sem, mode='sentence', **dec_kwargs)

        rev_length = len(sem_tgt)
        dis_syn_inf = 0
        dis_sem_inf = 0

        for targ, logit in zip(sem_tgt, logits_syn):
            # print(type(targ), type(logit), "type is what")
            targ = T.squeeze(targ)

            ptloss = T.nn.CrossEntropyLoss()
            dis_syn_inf = ptloss(logit, targ)
            dis_syn_inf += dis_syn_inf
        dis_syn_loss = T.div(dis_syn_inf, rev_length)

        for targ, logit in zip(sem_tgt, logits_sem):
            # print(type(targ), type(logit), "type is what")
            targ = T.squeeze(targ)

            ptloss = T.nn.CrossEntropyLoss()
            dis_sem_inf = ptloss(logit, targ)
            dis_sem_inf += dis_sem_inf
        dis_sem_loss = T.div(dis_sem_inf, rev_length)

        return dis_syn_loss, dis_sem_loss

    def get_adv(self, syntax_hidden, semantic_hidden, syn_tgt, sem_tgt, tag_emb, tag_mask, cont=None, **dec_kwargs):

        extra_feat = semantic_hidden.unsqueeze(1).repeat(1, tag_emb.size(1), 1)
        logits = self.syn_adv(tag_emb, tag_mask, init_hidden=semantic_hidden,
                                          init_cont=cont, extra_feat=extra_feat, mode='syn', **dec_kwargs)

        rev_tag_length = len(syn_tgt)
        syn_adv = 0

        for targ, logit in zip(syn_tgt, logits):
            # print(type(targ), type(logit), "type is what")
            targ = T.squeeze(targ)

            ptloss = T.nn.CrossEntropyLoss()
            syn_adv = ptloss(logit, targ)
            syn_adv += syn_adv
        syn_adv = T.div(syn_adv, rev_tag_length)

        sem_adv = self.sem_adv.forward(hidden=syntax_hidden, tgt_var=sem_tgt)

        return syn_adv, sem_adv

    def latent_for_init(self, z_sem, z_syn):
        '''
        this method for the shape of z, because DSS-VAE needs it
        :param z_separate:
        :return:
        '''
        def reshape(xx_hidden):
            xx_hidden = xx_hidden.view(batch_size, 1, int(self.enc_hidden_dim / 2))
            xx_hidden = xx_hidden.permute(1, 0, 2)
            return xx_hidden

        # syntax_latent = z_syn
        semantic_latent = z_sem
        batch_size = semantic_latent.size(0)

        syntax_hidden = reshape(z_syn)
        semantic_hidden = reshape(z_sem)

        return syntax_hidden, semantic_hidden