import time
import random
import logging
import collections

from puglib import rating

states = {
    "GATHERING_PLAYERS": 0,
    "MAP_VOTING": 1,
    "MAPVOTE_COMPLETED": 2,
    "TEAMS_SHUFFLED": 3,
    "GAME_STARTED": 4,
    "REPLACEMENT_REQUIRED": 5,
    "GAME_OVER": 6
}

MAPVOTE_DURATION = 30 # Time in seconds for map vote duration
AVAILABLE_MAPS = [ "cp_granary", "cp_badlands", "cp_gravelpit",
                   "cp_snakewater_final1", "cp_process_final",
                   "cp_gullywash_final1", "cp_sunshine_rc2",
                   "koth_pro_viaduct_rc4"
                ]
REPLACE_TIMEOUT = 300 # Time in seconds to wait for a replace before ending pug
DISCONNECT_TIMEOUT = 180 # Time in seconds to wait before replacing a disconnect

# Raised when trying to start a map vote when the map has been forced
class MapForcedException(Exception):
    pass

class PlayerStats(dict):
    """
    A simple class to wrap base player stats, and allow for the easy addition
    of new player stats. Since player stats are stored as a JSON string in the
    database, we can just use json.loads() to load the dict, and then pass it
    to this constructor. Any stat set in the database will be restored, and any
    new stats will be initialized. Likewise, stats can be added by other
    objects (such as the parser), and they will be reflected in this object
    without us needing to do anything special.
    """

    # special stats are stats that are not incremented in update_end_stats,
    # they are set to whatever value is in the game stats dict
    SPECIAL_STATS = ("rating", "winstreak")

    def __init__(self, *args, **kwargs):
        # Set the base stats, and then super to restore any stats from the
        # database
        self["games_since_medic"] = 0
        self["games_played"] = 0
        self["rating"] = rating.BASE
        self["kills"] = 0
        self["deaths"] = 0
        self["assists"] = 0
        self["wins"] = 0
        self["losses"] = 0
        self["draws"] = 0
        self["winstreak"] = 0

        super(PlayerStats, self).__init__(*args, **kwargs)

class Pug(object):
    def __init__(self, pid = None, custom_id = None, size = 12, pmap = None,
                 restriction = None):
        self.id = pid
        self.custom_id = custom_id
        self.size = size
        self.state = states["GATHERING_PLAYERS"]
        self._previous_state = self.state
        self.start_time = time.time()

        self.map = pmap

        if pmap is not None:
            self.map_forced = True
        else:
            self.map_forced = False

        self.admin = None
        #players is a dict in the form { cid: "name", ... }
        self._players = {}
        self.player_restriction = restriction # rating restriction

        self.disconnects = []
        # A record of all disconnects that resulted in a replacement
        self.disconnect_record = []
        self.leaver_record = []

        self.player_stats = {} # stats before game
        self.game_stats = {} # stats obtained during this pug
        self.end_stats = {} # stats after game
        self.stats_done = False

        self.player_votes = {}
        self.map_vote_start = -1
        self.map_vote_end = -1
        self.map_vote_duration = MAPVOTE_DURATION
        self.maps = AVAILABLE_MAPS

        self.server = None
        self.server_id = -1

        self.game_start_time = 0
        self.game_over_time = 0

        self.replacement_time = 0
        self.replacement_timeout = 0

        self.teams = {
            "red": set(),
            "blue": set()
        }

        # TODO: Make everything use variable teams, so it is easily extended
        team1, team2 = self.teams.keys()

        self.team_ratings = {
            "red": 0,
            "blue": 0
        }

        self.game_scores = {
            "red": 0,
            "blue": 0
        }

        self.medics = {
            "red": 0,
            "blue": 0
        }

    def add_player(self, player_id, player_name, pstats):
        if self.full:
            return

        if self.player_count == 0:
            self.admin = player_id

        self._players[player_id] = player_name

        self.player_stats[player_id] = pstats
        self._get_game_stats(player_id)

        # If this player is a replacement (i.e. in REPLACEMENT_REQUIRED state),
        # and the pug is now full after this person has joined, go back to the
        # previous state. HOWEVER, if we need MORE than one replacement, do NOT
        # change the state back, keep it in REPLACEMENT_REQUIRED until the pug
        # is full again.
        if self.state == states["REPLACEMENT_REQUIRED"]:
            """
            Decide which team to place the player on. If the teams are uneven,
            then we simply place them on whichever team has the least number of
            players. If the teams are EVEN (i.e. 2 or more people have left),
            we place the player on a team based on the current team ratings and
            the player's rating.
            """
            team1, team2 = self.teams.keys()
            team_lens = {
                            team1: len(self.teams[team1]),
                            team2: len(self.teams[team2])
                        }

            team1_len = team_lens[team1]
            team2_len = team_lens[team2]

            new_team = None

            if team1_len > team2_len: # t1 has more players than t2. add to t2
                new_team = team2

            elif team1_len < team2_len: # opposite, t2 has more players than t1
                new_team = team1

            else:
                # teams are even (i.e. more than 1 replacement), so we add to
                # whichever team has the least rating.
                team1_rating = self.team_ratings[team1]
                team2_rating = self.team_ratings[team2]

                if team1_rating > team2_rating: # add to team2
                    new_team = team2

                elif team1_rating < team2_rating:
                    new_team = team1

                else:
                    # teams are even 100% even... dice roll!
                    new_team = random.choice([ team1, team2 ])

            self._add_to_team(new_team, player_id)

            # If the pug is now full, go back to prev state.
            if self.full:
                self.replacement_time = 0
                self.replacement_timeout = 0
                self.state = self._previous_state

    def remove_player(self, player_id):
        if player_id in self._players:
            # if the game is in progress, we need to change the state to
            # replacement needed. we store the previous state so we can go
            # back to it if we get a replacement.
            if self.state > states["GATHERING_PLAYERS"]:
                # if the current state is already REPLACEMENT_REQUIRED (i.e.
                # this is a second, or more, leaver), do NOT override the
                # previous state.
                ctime = time.time()
                if self.state != states["REPLACEMENT_REQUIRED"]:
                    self._previous_state = self.state

                    # Start a timer for this replacement, so we can end the pug
                    # if it takes too long.
                    self.replacement_time = ctime
                    self.replacement_timeout = ctime + REPLACE_TIMEOUT

                    self.state = states["REPLACEMENT_REQUIRED"]

                # Store the leaver's ID and the time they left for a future
                # record.
                self.leaver_record.append({ "id": player_id, "time": ctime })

                player_team = self.player_team(player_id)
                if player_team is not None:
                    self._remove_from_team(player_team, player_id)

            del self._players[player_id]

            # update the admin to the next person in the pug
            if player_id == self.admin and self.player_count > 0:
                self.admin = self._players.keys()[0]

            # remove this player's stats
            del self.player_stats[player_id]
            del self.game_stats[player_id]

        if player_id in self.player_votes:
            del self.player_votes[player_id]

    def _add_to_team(self, team, player):
        """
        Add a player to the specified team list. Player can also be a list, as
        per __allocate_players. We also increment the team rating here.
        """
        if isinstance(player, list):
            for cid in player:
                self.team_ratings[team] += self.player_stats[cid]["rating"]

            self.teams[team] |= set(player)
        else:
            self.team_ratings[team] += self.player_stats[player]["rating"]

            self.teams[team].add(player)

    def _remove_from_team(self, team, player):
        if isinstance(player, list):
            for cid in player:
                self.team_ratings[team] -= self.player_stats[cid]["rating"]

            self.teams[team] -= set(player)
        else:
            self.team_ratings[team] -= self.player_stats[player]["rating"]

            self.teams[team].discard(player)

    def add_disconnect(self, player_id, reason):
        """
        Add a disconnection so it can be checked for a replacement after
        DISCONNECT_TIMEOUT. Note that when a game first starts, ALL players are
        added to the disconnect list, so that anyone who does not join within
        the given disconnect period is also automatically replaced.
        """
        if player_id in self._players:
            self.disconnects.append({ "id": player_id, "reason": reason,
                                      "time": time.time()
                                    })

    def remove_disconnect(self, player_id):
        """
        Remove a disconnection in the case that a player has rejoined the
        server after disconnecting
        """
        if player_id in self._players:
            for disc in self.disconnects[:]:
                if disc["id"] == player_id:
                    self.disconnects.remove(disc)

    def check_disconnects(self):
        """
        Check the disconnects list. If anyone has been disconnected for longer
        than DISCONNECT_TIMEOUT, remove them from the pug (trigger replacement)

        This includes players who have not connected to the server fast enough.
        If, for whatever reason, we end up removing ALL players, the pug will
        be ended. (i.e. server is dead - no one can actually join)
        """
        ctime = time.time()
        # make a copy, as we are removing from the list at the same time
        for disc in self.disconnects[:]:
            if ctime > disc["time"] + DISCONNECT_TIMEOUT:
                self.remove_player(disc["id"])

                self.disconnects.remove(disc)
                self.disconnect_record.append(disc)

    def begin_map_vote(self):
        if self.state >= states["MAP_VOTING"]:
            return

        if self.map_forced:
            self.state = states["MAPVOTE_COMPLETED"]

        else:
            # we store the map vote start and end times. this way, clients can know
            # when they need to update the pug's status again after a map vote
            self.map_vote_start = time.time()
            self.map_vote_end = self.map_vote_start + MAPVOTE_DURATION

            self.state = states["MAP_VOTING"]

    def end_map_vote(self):
        if self.map_forced:
            self.state = states["MAPVOTE_COMPLETED"]
            return

        if len(self.map_votes) > 0:
            self.map = self.map_votes.most_common(1)[0][0]

        else:
            # no one voted for a map, pick 1 at random
            self.map = random.choice(self.maps)

        self.state = states["MAPVOTE_COMPLETED"]

    def vote_map(self, player_id, map_name):
        if self.state != states["MAP_VOTING"] or map_name not in self.maps:
            return

        if player_id in self.player_votes:
            # ignore votes if they're the same map
            if map_name == self.player_votes[player_id]:
                return
            self.player_votes[player_id] = map_name

        else:
            self.player_votes[player_id] = map_name

    def force_map(self, map_name):
        self.map_forced = True
        self.map = map_name

    def shuffle_teams(self):
        if not self.full or self.teams_done:
            return

        stat_data = self.player_stats

        # To select teams, we have to first select a medic for each team.
        # After that we need to establish a score for each player and sort
        # them by it

        # To select a medic, we loop over the players in the pug, picking
        # whoever has played more games since last playing medic until we have
        # atleast 2 potential medics. then we randomly pick 2 from the list

        potential_medics = []
        threshold = 4
        # need atleast 2 potential medics
        while len(potential_medics) < 2:
            # add players who have played more games (since last playing medic)
            # than the threshold until we have atleast 2 players. If we don't
            # get 2 players on the first run, the threshold is decreased to
            # incorporate more players until eventually the threshold may be 0
            # and every player is a candidate
            for cid in self._players:
                if stat_data[cid]["games_since_medic"] > threshold and cid not in potential_medics:
                    potential_medics.append(cid)

            threshold -= 1

        # now we have our potential medics, so we can just shuffle and select them
        random.shuffle(potential_medics)
        logging.debug("Potential medics shuffled: %s", potential_medics)

        medics = []
        for team in self.teams:
            medic = potential_medics.pop()

            self.medics[team] = medic
            self._add_to_team(team, medic)
            medics.append(medic)

        logging.debug("Medics - Red: %s Blue: %s. Now calculating the rest of team",
                        self.medics["red"], self.medics["blue"])

        # now we can sort by score. we'll get a list of sorted ids out
        # in order of highest score to lowest
        sorted_ids = sorted(stat_data, key = lambda k: stat_data[k]["rating"], reverse = True)

        # remove the medics from the sorted ids, so we don't process them again
        # when allocating the rest of the players
        player_ids = [ x for x in sorted_ids if x not in medics ]

        # now just setup the teams. SIMPLE, RIGHT? WRONG
        self.__allocate_players(player_ids, stat_data)

        self.state = states["TEAMS_SHUFFLED"]

    def __allocate_players(self, ids, stat_data):
        # each team needs to have approximately total_pr/2 skill rating, or
        # as close to this as possible, in order to be considered even.
        # therefore, we need to iterate over possible team combinations
        # until we have the most even

        red = []
        red_score = 0

        blue = []
        blue_score = 0

        # establish base teams, by alternating the assignment
        count = 0
        for pid in ids:
            if (count % 2) == 0:
                red.append(pid)
                red_score += stat_data[pid]["rating"]

            else:
                blue.append(pid)
                blue_score += stat_data[pid]["rating"]

            count += 1

        # each possible team now has (self.size/2 - 1) players in it. now
        # we iterate over both teams and swap if there's an improvement.
        # much like a quicksort
        curr_score_diff = abs(red_score - blue_score)
        i = 0
        j = 0

        # loop over all red players
        while i < len(red):
            pred = red[i] #the current red player being checked

            # loop over all blue players for each red player. if a swap occurs,
            # we break from this inner loop and move to the next red player
            while j < len(blue):
                pblue = blue[j]

                # if we swapped pred and pblue, would the score difference become
                # smaller? if yes, then we should swap them
                new_red_score = red_score - stat_data[pred]["rating"] + stat_data[pblue]["rating"]
                new_blue_score = blue_score + stat_data[pred]["rating"] - stat_data[pblue]["rating"]
                new_diff = abs(new_red_score - new_blue_score)

                if new_diff < curr_score_diff:
                    # swap the players, and go onto the next red player
                    red[i] = pblue
                    blue[j] = pred

                    curr_score_diff = new_diff
                    red_score = new_red_score
                    blue_score = new_blue_score

                    logging.debug("%s swapped with %s. new difference: %s", pblue, pred, new_diff)

                    break

                # Swapping these players wouldn't provide an improvement, so
                # we just move onto the next blue player
                j += 1

            i += 1

        # our teams are now as balanced as we're going to get them, so merge
        # the temp teams with the real teams
        self._add_to_team("red", red)
        self._add_to_team("blue", blue)

        logging.info("Team allocation complete. Red: %s (Score: %s), Blue: %s (Score: %s)",
                        self.teams["red"], red_score, self.teams["blue"], blue_score)

    def setup_connect_timer(self):
        # Add all players to disconnect list so they are replaced if they
        # do not join within a reasonable time (DISCONNECT_TIMEOUT)
        for pid in self._players:
            self.add_disconnect(pid,
                                "Not joining server within DISCONNECT_TIMEOUT"
                            )

    def begin_game(self):
        if not self.game_started:
            self.state = states["GAME_STARTED"]
            self.game_start_time = time.time()

        else:
            pass

    def update_score(self, team, score):
        if not self.game_started:
            return

        try:
            score = int(score)
            self.game_scores[team] = score
        except:
            pass

    def end_game(self):
        self.state = states["GAME_OVER"]

        self.game_over_time = time.time()

    def update_end_stats(self):
        if self.stats_done:
            return

        # merge the game stats with the pre-game stats to get player's new
        # total stats

        # wins, losses, draws, games played. we just set these to 1, and
        # they'll be incremented when we update with previous stats.
        team1, team2 = self.teams.keys()
        opposition = { team1: team2, team2: team1 }
        for cid in self.game_stats:
            player_team = self.player_team(cid)
            if player_team is None:
                logging.error("Player '%s' has no team", cid)
                continue

            team_score = self.game_scores[player_team]
            oppo_score = self.game_scores[opposition[player_team]]

            game_stat = self.game_stats[cid]
            pregame = self.player_stats[cid]

            if team_score > oppo_score: # this player won!
                game_stat["wins"] = 1

                # adjust win streak
                if pregame["winstreak"] < 0:
                    game_stat["winstreak"] = 1
                else:
                    game_stat["winstreak"] = pregame["winstreak"] + 1

            elif team_score < oppo_score: # player lost
                game_stat["losses"] = 1

                if pregame["winstreak"] < 0:
                    game_stat["winstreak"] = pregame["winstreak"] - 1
                else:
                    game_stat["winstreak"] = -1

            else: # draw
                game_stat["draws"] = 1
                game_stat["winstreak"] = 0

            game_stat["games_played"] = 1

            if cid not in self.medics.values():
                game_stat["games_since_medic"] = 1

            # update all other stats
            if cid not in self.player_stats: # don't have player pre-game stats
                self.end_stats[cid] = game_stat
                continue

            else:
                self.end_stats[cid] = PlayerStats()

            endgame = self.end_stats[cid]

            for stat, value in game_stat.iteritems():
                # if the stat existed before the game, just add to it. else,
                # we set it as new
                if stat in PlayerStats.SPECIAL_STATS:
                    endgame[stat] = value

                elif stat in pregame:
                    endgame[stat] = pregame[stat] + value

                else:
                    endgame[stat] = value

        # update games_since_medic for medics (i.e set to 0)
        for medic in self.medics.values():
            if medic in self.end_stats:
                self.end_stats[medic]["games_since_medic"] = 0

        self.stats_done = True

    def has_player(self, player_id):
        return player_id in self._players

    def player_restricted(self, rating):
        """
        Checks whether the given rating is within the allowed range for this
        pug. Restrictions are limits, and set such that a number < 0 means the
        player must have rating below the absolute value of the restriction,
        and a number > 0 means the player must have a rating equal to or above
        the rating.

        If the player is outside of the set range, they are considered to be
        restricted, and we return True.
        """
        if self.player_restriction is None:
            return False

        elif (self.player_restriction < 0
              and rating >= abs(self.player_restriction)):

            return True

        elif (self.player_restriction > 0
              and rating < self.player_restriction):

            return True

        else:
            return False

    def player_list(self):
        return self._players.keys()

    def is_admin(self, pid):
        return self.admin == pid

    def named_teams(self):
        """
        Returns a dictionary containing player names along with role for each
        team instead of just cids
        """
        named = {}
        for team in self.teams:
            named[team] = [ (self.player_name(x), self.player_role(x)) for x in self.teams[team] ]

        return named

    def player_role(self, pid):
        if pid in self.medics.values():
            return "Medic"

        else:
            return None

    def player_name(self, pid):
        if pid in self._players:
            return self._players[pid]

    def player_team(self, pid):
        if pid in self._players:
            for team in self.teams:
                if pid in self.teams[team]:
                    return team

        return None

    def get_state_string(self):
        for name, enum in states.items():
            if enum == self.state:
                return name

    def update_game_stat(self, player_id, statkey, value, increment = True):
        if not self.game_started:
            return

        ps = self._get_game_stats(player_id)

        if (not increment) or (statkey not in ps):
            ps[statkey] = value

        else:
            ps[statkey] += value

    def _get_game_stats(self, player_id):
        if player_id in self.game_stats:
            return self.game_stats[player_id]

        else:
            rating_default = self.player_stats[player_id]["rating"] or rating.BASE

            new = PlayerStats(rating = rating_default)
            self.game_stats[player_id] = new

            return new

    def set_player_rating(self, player_id, rating):
        """
        Used by pug manager when updating ratings to set the player's new
        rating after the game.
        """
        if player_id in self.game_stats:
            self.game_stats[player_id]["rating"] = rating

    @property
    def replacement_timed_out(self):
        if self.state == states["REPLACEMENT_REQUIRED"]:
            return time.time() >= self.replacement_timeout
        else:
            return False

    @property
    def replacement_required(self):
        return self.state == states["REPLACEMENT_REQUIRED"]

    @property
    def has_disconnects(self):
        return len(self.disconnects) > 0

    @staticmethod
    def map_available(map_name):
        return map_name in AVAILABLE_MAPS

    @property
    def teams_done(self):
        return self.state >= states["TEAMS_SHUFFLED"]

    @property
    def full(self):
        return self.size == self.player_count

    @property
    def player_count(self):
        return len(self._players)

    @property
    def game_started(self):
        if self.state == states["REPLACEMENT_REQUIRED"]:
            return self._previous_state >= states["GAME_STARTED"]
        else:
            return self.state >= states["GAME_STARTED"]

    @property
    def game_over(self):
        return self.state == states["GAME_OVER"]

    @property
    def password(self):
        if self.server is None:
            return None
        else:
            return self.server.password

    @property
    def map_votes(self):
        return collections.Counter(self.player_votes.values())


import socket
import queue
import time
import IgluMessage

# ServerCommunication class used to access interprocess communication server
# Programmer: Christian Wagner
# Date Created: 3/11/2020
# Date Modified: 11/02/2020
# Version: 2.0

class ServerCommunication:
    # Overloaded constructor
    # host -> the name of the host
    # port -> the port number being served on
    # pid -> the process identification number
    def __init__(self,host='localhost',port=8189,pid=0):
        self.__DEBUG_FLAG = True # debug messages flag
        self.__RETRY_CONNECTION_COUNT = 4 # number of times to retry before giving up
        self.__RETRY_CONNECTION_WAIT = 1 # time to wait, in seconds, between retries
        super().__init__() # call to super constructor
        self.__host = host # name of host
        self.__port = port # port number
        self.__pid = pid # process identifcation number
        self.__coordination_port = 18000 # port for communication coordination
        self.__s = 0 # setup socket variable
        self.__connected = False # default connection status

    # getter for process identification number variable
    @property
    def PID(self):
        return self.__pid

    # Connect to server using given host and port parameters
    def connect(self):
        self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # initialize socket object
        self.__s.connect((self.__host, self.__coordination_port)) # establish coordination socket connection

        try:
            tmp = 'test\n'
            self.__s.sendall(tmp.encode('utf-8')) # try sending on connection
            self.__connected = True
        except Exception as e:
            # connection failed, try again
            self.__connected = False

        if(not self.__connected):
            if(self.__DEBUG_FLAG): print('Connection on coordination port failed!')

            self.__s = 0 # clear variable

            # try to make connection again
            for x in range(0, self.__RETRY_CONNECTION_COUNT):
                if(self.__DEBUG_FLAG): print('Retrying connection on coordination port')

                self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # initialize socket object
                self.__s.connect((self.__host, self.__coordination_port)) # establish coordination socket connection

                time.sleep(self.__RETRY_CONNECTION_WAIT) # wait

                try:
                    tmp = 'test\n'
                    self.___s.sendall(tmp.encode('utf-8')) # try sending on connection
                    self.__connected = True # connecion was made
                except:
                    self.__connected = False # connection failed

                if self.__connected:
                    break

                # clear and restart
                self.__s = 0

            if not self.__connected:
                return False

        if(self.__DEBUG_FLAG): print('Connected to coordination port!')

        tmp = str(self.__port) + '\n'
        self.__s.sendall(tmp.encode('utf-8')) # communicate desired port
        check = self.__s.recv(1024) # get server status
        if check == b'a\n':
            self.disconnect()
            self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # initialize socket object
            self.__s.connect((self.__host, self.__port)) # establish socket connection
            ID = 'PID=' + str(self.__pid) + '\n' # create PID query
            self.__s.sendall(ID.encode('utf-8')) # send PID information
            return True
        else:
            if self.__DEBUG_FLAG: print('Coordination failed.')
            if self.__DEBUG_FLAG: print('Selected port is being used.')

            self.disconnect()
            return False

    # Disconnect from the server
    def disconnect(self):
        try:
            self.__s.sendall(b"exit\n") # signal exit
            self.__s.close() # close socket connection
            self.__s = 0 # clear variable
            return True
        except:
            return False

    # Open connection to the server
    def open(self):
        if self.__s != 0:
            try:
                self.__s.sendall(b"test\n") # signal exit
                return True # socket is already open
            except:
                return self.connect()
        else:
            return self.connect()

    # Close connection to the server
    def close(self):
        if self.__s == 0:
            return True # socket is already closed
        else:
            return self.disconnect()

    # Send data to the server for the queue
    # msg -> the data to send
    def WriteQueue(self, msg='NULL'):
        try:
            self.__s.sendall(b'QW\n')
            tmp = msg.get_tx_data() + '\n'
            self.__s.sendall(tmp.encode('utf-8')) # send data from IgluMessage object
            return True
        except:
            return False # socket is not connected

    # Check for items in the queue
    # return -> returns true if items are in the queue, false otherwise
    def CheckQueue(self):
        # method to check queue status
        self.__s.sendall(b'QC\n')
        check = self.__s.recv(1024) # get true/false flag
        if check == b't\n':
            return True # elemenets found
        else:
            return False # queue is empty

    # Reads and returns queue objects from the server
    # returns -> a queue of the elements gathered from the server
    def ReadQueue(self): # read items in queue
        tmpQueue = queue.Queue()
        while(self.CheckQueue()):
            try:
                self.__s.sendall(b'QR\n')
                data = self.__s.recv(1024) # get data
                data = str(data.decode('utf-8'))
                newMsg = IgluMessage.IgluMessage(data)
                tmpQueue.put(newMsg) # add fetched data to queue
            except:
                return tmpQueue
        return tmpQueue # return queue


import pytest

from mysql_client.mysql_client import MysqlConnection
from tests.builder import MysqlBuilder

class TestMysql:
    @pytest.fixture(scope='function', autouse=True)
    def setup(self, mysql_client):
        self.mysql: MysqlConnection = mysql_client
        self.builder = MysqlBuilder(self.mysql)

    def test_create_logs_mysql(self):
        self.builder.add_logs()
        assert len(self.mysql.execute_query('SELECT * FROM access')) > 0


#!/usr/bin/env python
import math
import rospy
import cv2
import ros_numpy
import numpy
from geometry_msgs.msg import PointStamped, Point
from sensor_msgs.msg import Image
from sensor_msgs.msg import PointCloud2
from cv_bridge import CvBridge
from std_msgs.msg import Float32MultiArray

def mouse_callback(event,x,y,flags,param):
    global hsv
    if event == cv2.EVENT_LBUTTONDOWN:
            #cv2.circle(img,(x,y),100,(255,0,0),-1)
            print(hsv[y,x])
def callback_image(msg):
    global hsv
    global pub_ball, use_gui
    bridge = CvBridge()
    img = bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')

    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    bin = cv2.inRange(hsv,(65,162,101),(83,207,255))
    idx =  cv2.findNonZero(bin)
    [cx,cy,var1,var2] = cv2.mean(idx)
    msg_ball = Float32MultiArray()
    msg_ball.data = [cx,cy]
    if [cx,cy]!= [0,0]:
        pub_ball.publish(msg_ball)
    if use_gui:
        cv2.circle(img,(int(cx),int(cy)),100,(255,0,0),10)
        cv2.imshow("Binary", bin)
        cv2.imshow("Image",img)
        cv2.imshow("HSV",hsv)
        cv2.waitKey(10)

def callback_point_cloud(msg):
    global use_gui
    points = ros_numpy.point_cloud2.pointcloud2_to_array(msg)
    rgb_arr = points['rgb'].copy()
    rgb_arr.dtype = numpy.uint32
    r,g,b = ((rgb_arr >> 16) & 255), ((rgb_arr >> 8) & 255), (rgb_arr & 255)
    img = cv2.merge((numpy.asarray(b,dtype='uint8'),numpy.asarray(g,dtype='uint8'),numpy.asarray(r,dtype='uint8')))
    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    bin = cv2.inRange(hsv,(65,162,101),(83,207,255))
    idx =  cv2.findNonZero(bin)
    [cx,cy,var1,var2] = cv2.mean(idx)
    [x,y,z] = [0,0,0]
    counter = 0
    if idx is None:
        return
    for [[c, r]] in idx:
        xt, yt, zt = points[r,c][0], points[r,c][1], points[r,c][2]
        if math.isnan(xt) or math.isnan(yt) or math.isnan(zt):
            continue
        [x,y,z,counter] = [x+xt, y+yt, z+zt, counter+1]
    [x,y,z] = [x/counter, y/counter, z/counter] if counter > 0 else [0,0,0]
    print[x,y,z]

    if use_gui:
        cv2.circle(img,(int(cx),int(cy)),100,(255,0,0),10)
        cv2.imshow("Binary", bin)
        cv2.imshow("Image",img)
        cv2.imshow("HSV",hsv)

def main ():
    global pub_ball, use_gui
    use_gui= False
    print("initializing color segmenter")
    rospy.init_node("color_segmenter")
    if rospy.has_param("~gui"):
        use_gui = rospy.get_param("~gui")
    #rospy.Subscriber("/camera/color/image_raw", Image, callback_image)
    rospy.Subscriber("/camera/depth_registered/points", PointCloud2,callback_point_cloud)
    pub_ball = rospy.Publisher("/ball_position",Float32MultiArray,queue_size=10)
    cv2.namedWindow('HSV')
    cv2.setMouseCallback('HSV',mouse_callback)
    rospy.spin()

if __name__== "__main__":
    main()


from django.urls import path

from . import views

urlpatterns = [
    path('home', views.home.as_view(), name='home'),
    path('invoicedata', views.invoicedata, name='invoicedata'),
    path('generatedinvoice', views.generatedinvoice, name='generatedinvoice'),
    path('charge', views.charge, name='charge'),
    path('emailConsole', views.emailConsole, name='emailConsole'),
    path('dbupdated', views.dbupdated, name='dbupdated'),
    path('clientfilter', views.clientfilter, name='clientfilter'),

]


from turtle import Turtle,Screen
import random

colors = ("red","green","blue","yellow","orange","pink","purple")

MOVE_DISTANCE = 20 # RENAME

RIGHT = 0
UP = 90
LEFT = 180
DOWN = 270

class Snake(Turtle):

    def __init__(self):
        super().__init__()
        self.segments = []
        self.beginner_snake()

    def beginner_snake(self):
        for _ in range(3):
            self.add_part()

        self.head = self.segments[0]

    def add_part(self):
        random_box_size = random.randint(5, 10) / 10

        new_segment = Turtle("square")
        new_segment.color("white") # change later
        new_segment.shapesize(stretch_len=random_box_size, stretch_wid=random_box_size)
        new_segment.pu()

        self.segments.append(new_segment)

    def reset(self):
        for part in self.segments:
            part.goto(1000,1000)

        self.segments.clear()
        self.beginner_snake()

    def move(self):
        for i in range(len(self.segments) - 1, 0, -1):
            x = self.segments[i - 1].xcor()
            y = self.segments[i - 1].ycor()

            self.segments[i].goto(x, y)

        self.head.forward(MOVE_DISTANCE)

    def right(self):
        if self.head.heading() != LEFT:
            self.head.setheading(RIGHT)

    def up(self):
        if self.head.heading() != DOWN:
            self.head.setheading(UP)

    def left(self):
        if self.head.heading() != RIGHT:
            self.head.setheading(LEFT)

    def down(self):
        if self.head.heading() != UP:
            self.head.setheading(DOWN)


def solve():
    N,X = map(int, input().split())
    S = input()
    T = ["T"] # リストがからかどうかを判断するためのもの
    for s in S:
        if s == "U" and T[-1] in "LR":
            T.pop()
        else:
            T.append(s)
        print(T)

    ans = X
    for t in T[1:]:
        if t == 'U':
            ans //= 2
        elif t == "L":
            ans *= 2
        else:
            ans *= 2
            ans += 1
    return ans
print(solve())


# Part 2 only, part 1 is very similar though
def part_2():
    """
    Formula:

    x_vel = 1
    y_vel = 1

    result_x = x_vel - step, assuming x_vel is positive
    result_y = y_vel - step

    we want to maximze the y_vel to get the most distance.

    we want x_vel to equal 0 when it is above the x_end_num.
    the x_pos is a decreasing series function that we want to end at 0 in the target.
    So consider it an increasing series function that ends at 0.

    For each x_val in the target, see if we can get an increasing series function that ends at 0.

    Start with brute force <-- brute force works

    """

    def get_input():
        with open('input.txt', 'r') as f:
            line = f.readline().strip().split(' ')
            x_str = line[-2]
            y_str = line[-1]

            x_toks = x_str.split('..')
            x_start_num = int(x_toks[0][2:])
            x_end_num = int(x_toks[1][:-1])

            y_toks = y_str.split('..')
            y_start_num = int(y_toks[0][2:])
            y_end_num = int(y_toks[1])

            return x_start_num, x_end_num, y_start_num, y_end_num

    # Target values
    x_start_num, x_end_num, y_start_num, y_end_num = get_input()

    x_pos = y_pos = 0

    start_x_vel = 6
    start_y_vel = 3

    best_x_vel = 0
    best_y_vel = 0
    i = 0

    highest = 0
    setty = set()

    for a in range(-300,400):
        for b in range(-300,400):
            i += 1
            x_pos = 0
            y_pos = 0
            start_x_vel = a
            start_y_vel = b
            x_vel = a
            y_vel = b

            temp_highest = 0

            while True:
                x_pos += x_vel
                y_pos += y_vel

                temp_highest = max(temp_highest, y_pos)
                if x_start_num <= x_pos <= x_end_num and y_start_num <= y_pos <= y_end_num:
                    found = True
                    # print("Best_x_vel: ", start_x_vel)
                    # print("Best_y_vel: ", start_y_vel)
                    setty.add((start_x_vel, start_y_vel))
                    if start_y_vel > best_y_vel:
                        best_y_vel = start_y_vel
                        best_x_vel = start_x_vel
                        highest = max(temp_highest, highest)

                    break

                if x_pos > x_end_num:
                    # print("x too far")
                    break
                if y_pos < y_start_num:
                    # print("x too far")
                    break

                if x_vel > 0:
                    x_vel -= 1
                elif x_vel < 0:
                    x_vel += 1

                y_vel -= 1

    return best_x_vel, best_y_vel, highest, setty

a, b, c, d = part_2()
print(len(d))


from openerp.osv import fields, orm
from openerp.tools.translate import _
import time

class general_ledger_webkit_wizard(orm.TransientModel):
    _inherit = 'general.ledger.webkit'

    _columns = {
        'filter_partner_ids': fields.many2many('res.partner', 'general_ledger_webkit_res_partner_rel', 'gen_ledger_wzd_id', 'partner_id', 'Filter by Partners'),
        'filter_operating_unit_ids': fields.many2many('operating.unit', 'general_ledger_webkit_operating_unit_rel', 'gen_ledger_wzd_id', 'operating_unit_id', string='Operating Units', required=False),
        # Secundary currency rate options
        'display_curr_columns': fields.boolean('Display columns secundary currency'),
        'curr_rate_option': fields.selection([ ('trans_date', 'Tipo de cambio según fecha de la transacción'),
                                               ('set_date', 'Tipo de cambio según una fecha dada'),
                                               ('set_curr_rate', 'Otro tipo de cambio')], 'Opciones de tipo de cambio', required=True),
        'curr_rate_date': fields.date('Fecha'),
        'curr_rate': fields.float('Tipo de cambio'),
    }

    _defaults = {
        'centralize': False,
        'target_move': 'all',
        'amount_currency': False,
        'display_curr_columns': True,
        'curr_rate_option': 'trans_date',
        'curr_rate_date': time.strftime("%Y-%m-%d")
    }

    def pre_print_report(self, cr, uid, ids, data, context=None):
        data = super(general_ledger_webkit_wizard, self).pre_print_report(
            cr, uid, ids, data, context)
        vals = self.read(cr, uid, ids,
                         ['display_curr_columns','curr_rate_option','curr_rate_date','curr_rate' ],
                         context=context)[0]
        row = self.browse(cr, uid, ids[0])
        filter_partner_ids = []
        filter_partner_names = []
        for partner in row.filter_partner_ids:
            filter_partner_ids.append(partner.id)
            filter_partner_names.append(partner.name)
        vals['filter_partner_ids'] = filter_partner_ids
        vals['filter_partner_names'] = filter_partner_names
        filter_operating_unit_ids = []
        filter_operating_unit_names = []
        for ou in row.filter_operating_unit_ids:
            filter_operating_unit_ids.append(ou.id)
            filter_operating_unit_names.append(ou.name)
        vals['filter_operating_unit_ids'] = filter_operating_unit_ids
        vals['filter_operating_unit_names'] = filter_operating_unit_names
        data['form'].update(vals)
        return data

    def _print_report(self, cr, uid, ids, data, context=None):
        context = context or {}
        data = self.pre_print_report(cr, uid, ids, data, context=context)
        if context.get('xls_export'):
            return {'type': 'ir.actions.report.xml',
                    'report_name': 'account.account_report_general_ledger_xls_ext',
                    'datas': data}
        else:
            return {'type': 'ir.actions.report.xml',
                    'report_name': 'account.account_report_general_ledger_webkit_ext',
                    'datas': data}


from sklearn import preprocessing
import numpy as np

features = np.array([[-100.1, 3240.1],
 [-200.2, -234.1],
 [5000.5, 150.1],
 [6000.6, -125.1],
 [9000.9, -673.1]])
# Create scaler
scaler = preprocessing.StandardScaler()
# Transform the feature
features_standardized = scaler.fit_transform(features)
# Show feature
print(features_standardized)

Preprocessing Data for Neural Networks.py


from django.shortcuts import render, HttpResponse, redirect
from django.urls import reverse
from app01.models import Book

# Create your views here.

def index(request):
    # 方式一：
    # book_obj = Book(title="python_book",state=True,price=101,publish='机械工业出版社',pub_date='2018-08-17')
    # book_obj.save()
    # 方式2：
    book_obj = Book.objects.create(title="浪潮之巅", state=True, price=198, publish="科学出版社", pub_date="2018-12-12")
    print(book_obj.title)
    return HttpResponse('ojbk')

def bookstore(request):
    return HttpResponse('ok')

def addbook(request):
    if request.method == "POST":
        title = request.POST.get("title")
        price = request.POST.get("price")
        date = request.POST.get("date")
        publish = request.POST.get("publish")

        Book.objects.create(title=title, price=price, pub_date=date, publish=publish, state=True)

        return redirect("app01:books")

    return render(request, 'addbook.html')

def books(request):
    booklist = Book.objects.all()

    return render(request, 'books.html', locals())

def delbook(request, id):
    Book.objects.filter(id=id).delete()
    return redirect("app01:books")

def modbook(request, id):
    book_obj = Book.objects.filter(id=id).first()

    if request.method == "POST":
        title = request.POST.get("title")
        price = request.POST.get("price")
        date = request.POST.get("date")
        publish = request.POST.get("publish")

        Book.objects.filter(id=id).update(title=title, price=price, pub_date=date, publish=publish)

        return redirect("app01:books")

    return render(request, "modbook.html", {"book_obj": book_obj})


with open('input', 'r') as f:
    lines = f.readlines()

trees = 0
pos_y = 0

for line in lines:
    pattern_width = len(line.rstrip())

    pos_x = (3*pos_y)%(pattern_width)

    print("Line %d: Checking if pos %d has a tree" % (pos_y,pos_x))

    if line.rstrip()[pos_x] == '#':
        trees += 1

    pos_y += 1

print("Found %d trees" % trees)


# Twilio podruhé
# Stáhni si soubor twlo.csv, který obsahuje informace o vývoji ceny akcie firmy Twilio od začátku roku 2020. Soubor obsahuje informace o otevírací, minimální, maximální a uzavírací ceně za každý den.
#
# Stažení souboru pomocí wget:
#
# import wget
# wget.download("https://raw.githubusercontent.com/pesikj/python-012021/master/zadani/5/twlo.csv")
# #
import pandas
import matplotlib.pyplot as plt
#
twilio = pandas.read_csv("twlo.csv")
print(twilio.info())
print(twilio)

# Výše uvedeným programem načti data o vývoji ceny akcie. Vytvoř čárový graf vývoje zavírací ceny akcie (sloupec Close) v čase.

twilio.plot("Date", "Close")
plt.show()

# Zkus nyní převést sloupec Date na typ datetime příkazem níže a vytvoř stejný graf jako předtím. Porovnej grafy a zjisti, co se změnilo.

twilio["Date"] = pandas.to_datetime(twilio["Date"])
twilio.plot("Date", "Close")
plt.show()

# osa x se zmenila


"""

Settings for the game

"""

WINDOW = {
    'WIDTH': 800,
    'HEIGHT': 800,
    'TITLE': 'SideStep Trainer',
    'BG_COL': (0, 0, 0)  # Black
}

PLAYER = {
    'SPAWN_POS': (WINDOW['WIDTH'] / 2, WINDOW['HEIGHT'] / 2),
    'MOVE_SPEED': 5,
    'RADIUS': 25,
    'COL': (0, 255, 0),  # Green
    'MOVE_TO_RADIUS': 3
}

PROJECTILE = {
    'RADIUS_RANGE': (20, 40),
    'SPEED_RANGE': (20, 35),
    'DEG_OFFSET_RANGE': (-2, 2),  # The smaller the range, the more accurate the projectiles
    'COL': (255, 0, 0)  # Red
}

TARGET = {
    'RADIUS': 10,
    'COL': (255, 255, 0)  # Yellow
}

GAME = {
    'INIT_PROJECTILE_FIRE_FRAME_INTERVAL': 500,
    'MIN_INIT_PROJECTILE_FIRE_FRAME_INTERVAL': 10,
    'FIRE_FRAME_INTERVAL_STEP': 10
}

GUI = {
    'CURSOR_TARGET_SIZE': 20
}


"""Tests."""

from typer.testing import CliRunner

from nb_query.main import app

runner = CliRunner()

EXPECTED_STDOUT = """                                  fname           line  cell  count
0  ./tests/NB_Query_Test_Notebook.ipynb  "Hello World"     0      1"""

def test_app():
    """Tests if it finds the right string."""
    result = runner.invoke(app, ['Hello'])
    assert result.exit_code == 0
    assert EXPECTED_STDOUT in result.stdout


from collections import Counter

import matplotlib.pyplot as plt

def main():
    with open('priorities.txt') as file:
        priorities = file.read().strip().split('\n')
        priorities = list(map(int, priorities))
    n = len(priorities)
    t = [(n-i, v) for i, v in enumerate(priorities)]
    diffs = [actual-expected for actual, expected in t]
    c = Counter(diffs)
    x, y = [], []
    for k, v in c.items():
        x.append(k)
        y.append(v)

    fig, ax = plt.subplots()
    ax.bar(x, y)
    plt.show()

if __name__ == '__main__':
    main()


from flask import Flask,request, jsonify

app = Flask(__name__)

def predict_price(lotarea):
    # Load a machine learning model
    # pass the features
    # get the prediction using the .predict Attribute return that prediction
    # for now create a mock model
    #  y = B + B1x
    return 50000 + 200*int(lotarea)

@app.route('/getprice/', methods=['GET'])
def respond():
    # Retrieve the name from url parameter
    lotarea = request.args.get("LotArea", None)

    # For debugging
    print(f"got LotArea {lotarea}")

    response = {}

    # Check if user sent a name at all
    if not lotarea:
        return "
 Lot Area value not found enter LotArea value
"
    # Check if the user entered a number not a string
    elif not str(lotarea).isdigit():
        return "
 Lot Area can't be non Numeric
"
    # Now the user entered a valid name
    else:
        return "
 Predicted price of house is {0}
".format(predict_price(lotarea))

@app.route('/')
def index():
    return '
Hello world welcome to python flask app and impriving it
'

if __name__ == '__main__':
    app.run(threaded=True,port=5000)


import sys
import time
import argparse
import matplotlib.pyplot

from concurrent import concurrent_solution
from sequential import sequential_solution
from utils import *

def get_sample(n_process, file, max_threads):
    x = []
    y = []
    for n_thread in range(1, max_threads + 1):
        start = time.time()
        sys.argv = ["python", file, str(n_process), str(n_thread), "False"]
        concurrent_solution()
        end = time.time()
        x.append(n_thread)
        y.append(end - start)

    return x[:], y[:]

def graph():
    parser = argparse.ArgumentParser(add_help=True, description='Gráfico do speedup')

    parser.add_argument('-f', '--file-name', action='store', type=valid_file, required=True, help='O nome do arquivo com as solucoes a serem validadas')
    parser.add_argument('-p', '--max-process', action='store', type=pos_int, required=True, help='O numero máximo de processos trabalhadores')
    parser.add_argument('-t', '--max-threads', action='store', type=pos_int, required=True, help='O numero máximo de threads de correcao a serem utilizadas por cada processo trabalhador')

    try:
        args = parser.parse_args()
    except Exception as e:
        print(e)
        exit(1)

    start = time.time()
    sys.argv = ["python", args.file_name, "False"]
    sequential_solution()
    end = time.time()
    sequential_time = end - start

    sudokus = len(read_sudokus(args.file_name))

    print(f"Número de sudokus {sudokus}")
    print("Tempo de referência T(1): ", sequential_time)

    matplotlib.pyplot.title(f'Gráfico speedup (número de sudokus {sudokus})')
    matplotlib.pyplot.xlabel('n_threads')
    matplotlib.pyplot.ylabel('speedup')
    for n_process in range(1, args.max_process + 1):
        x, y = get_sample(n_process, args.file_name, args.max_threads)
        for n_thread, t in zip(x, y):
            print(f"Tempo T({n_process}, {n_thread}): ", t)
        y = [sequential_time / t for t in y]
        matplotlib.pyplot.plot(x, y, label=f'Processos: {n_process}')

    matplotlib.pyplot.legend()
    matplotlib.pyplot.show()

if __name__ == "__main__":
    graph()

Projeto 2 - Validador de Sudokus/graph.py


def largestRectangle(h):
    stack = [] # indices where the height increases
    area = 0
    i = 0
    while i < len(h):
        height = h[i]
        if not stack or h[stack[-1]] < height:
            stack.append(i)
            i += 1
        elif h[stack[-1]] == height:
            i += 1
        elif h[stack[-1]] > height:
            begin = stack.pop()
            area = max(area, h[begin] * (i - begin))
    # there are consective heights in increasing order left
    while stack:
        begin = stack.pop()
        area = max(area, h[begin] * (len(h) - begin))

    return area

print(largestRectangle([11,11,10,10,10]))


from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework import status

from django.http import HttpResponse
from django.conf import settings
from django.core.cache import cache

import time
import requests
from datetime import datetime

from .serializers import SynonymsSerializer, AntonymsSerializer, ShopSerializer, TemplateSerializer, SubscribeSerializer, ExportSerializer
from .models import Shop, Subscribe, Word

from openpyxl import Workbook
from openpyxl.drawing.image import Image

from rest_framework_tracking.mixins import LoggingMixin

class SynonymsView(LoggingMixin, GenericAPIView):

    def get(self, request, format=None):
        """
        Return words with synonyms
        """
        data = {}
        data['synonyms'] = []
        tags = request.GET.get('tags', '')
        for tag in tags.split(','):
            result = requests.get('https://wordsapiv1.p.mashape.com/words/{0}/synonyms'.format(tag),
                                  headers={
                "X-Mashape-Key": settings.MASHAPE,
                "Accept": "application/json",
            })
            if 'synonyms' in result.json():
                data['synonyms'] += result.json()['synonyms']
        return Response(data)

class AntonymsView(LoggingMixin, GenericAPIView):

    def get(self, request, format=None):
        """
        Return words with antonyms
        """
        data = {}
        data['antonyms'] = []
        tags = request.GET.get('tags', '')
        for tag in tags.split(','):
            result = requests.get('https://wordsapiv1.p.mashape.com/words/{0}/antonyms'.format(tag),
                                  headers={
                "X-Mashape-Key": settings.MASHAPE,
                "Accept": "application/json",
            })
            if 'antonyms' in result.json():
                data['antonyms'] += result.json()['antonyms']
        return Response(data)

class KeywordToolView(LoggingMixin, GenericAPIView):

    def get(self, request, format=None):
        """
        Return result from keywordtool
        """
        keywords = request.GET.get('tags', '')
        result = {
            'keywords': []
        }

        if keywords != '':
            for word in keywords.split(','):
                payload = {
                    'apikey': settings.KEYWORDTOOL,
                    'keyword': '[{0}]'.format(word),
                    'output': 'json',
                    'country': 'us',
                    'language': 'en',
                    'metrics': 'true',
                    'metrics_location': '2840',
                    'metrics_language': 'en'
                }
                word = word.lower()

                word_result = Word.objects.filter(name=word).first()

                if word_result:
                    data = word_result.results
                else:
                    try:
                        data_keywordtool = requests.get('http://api.keywordtool.io/v2/search/suggestions/amazon', params=payload)
                        results = data_keywordtool.json()
                        created_word = Word.objects.create(name=word, results=results)
                        data = created_word.results
                    except Exception as e:
                        data = False

                if data:
                    for item in data['results']:
                        for sub_item in data['results'][item]:
                            if 'volume' in sub_item and 'string' in sub_item:
                                result['keywords'].append({'name': sub_item['string'], 'volume': sub_item['volume']})

        return Response(result)

class ExcelView(LoggingMixin, GenericAPIView):
    serializer_class = ExportSerializer

    def post(self, request, format=None):
        """
        Return excel file
        """
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            wb = Workbook()
            ws = wb.active
            ws['A1'] = 'TEE SHIRT DESIGN'
            if serializer.data['photo']:
                img = Image('{0}{1}'.format(settings.MEDIA_ROOT[:-6], serializer.data['xls_photo']))
                ws.add_image(img, 'A2')
            ws['B1'] = 'PRODUCT TITLE'
            ws['B2'] = serializer.data['product_name']
            ws['C1'] = 'BULLET POINT ONE'
            ws['C2'] = serializer.data['first_description']
            ws['D1'] = 'BULET POINT TWO'
            ws['D2'] = serializer.data['second_description']
            ws['E1'] = 'SELECTED KEYWORDS FROM WC'
            ws['E2'] = serializer.data['keywords']

            ws.column_dimensions["A"].width = 60
            ws.column_dimensions["B"].width = 60
            ws.column_dimensions["C"].width = 60
            ws.column_dimensions["D"].width = 60
            ws.column_dimensions["E"].width = 60
            ws.row_dimensions[2].height = 100

            timestamp = int(time.time())
            wb.save('{0}/exel/{1}.xlsx'.format(settings.MEDIA_ROOT, timestamp))
            result = {
                'file': '{0}{1}exel/{2}.xlsx'.format(settings.WEBSITE, settings.MEDIA_URL, timestamp),
                'data': serializer.data
            }
            return Response(result, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class ShopList(LoggingMixin, GenericAPIView):
    serializer_class = ShopSerializer

    def get(self, request, format=None):
        """
        Return list of shops
        """
        shops = Shop.objects.all()
        serializer = self.serializer_class(shops, many=True)
        return Response(serializer.data)

class SubscribeView(LoggingMixin, GenericAPIView):
    serializer_class = SubscribeSerializer

    def post(self, request, format=None):
        """
        Return add email to subscribe
        """
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


#Author
#Lakshmi Praveena Rangavajhula
#Varun Suresh Parashar - vxp171830

from sklearn import tree
import pandas as pd
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
import numpy as np
from sklearn.metrics import accuracy_score
import graphviz
import sys

train_file_path = sys.argv[1]
test_file_path = sys.argv[2]
#Please chafnge the file path as required.
train_data = pd.read_csv(train_file_path)
test_data = pd.read_csv(test_file_path)

#Dropping the null values
train_data = train_data.dropna()
test_data = test_data.dropna()

train_data.rename(columns={'V6': 'v6', 'V5': 'v5','V4': 'v4', 'V3': 'v3','V2': 'v2', 'V1': 'v1','V7': 'v7'}, inplace=True)
test_data.rename(columns={'V6': 'v6', 'V5': 'v5','V4': 'v4', 'V3': 'v3','V2': 'v2', 'V1': 'v1','V7': 'v7'}, inplace=True)

#Replace the String with numeric values
train_data['v1'].replace('low',0, inplace=True)
train_data['v1'].replace('med',1, inplace=True)
train_data['v1'].replace('high',2, inplace=True)
train_data['v1'].replace('vhigh',3, inplace=True)
train_data['v2'].replace('low',0, inplace=True)
train_data['v2'].replace('med',1, inplace=True)
train_data['v2'].replace('high',2, inplace=True)
train_data['v2'].replace('vhigh',3, inplace=True)
train_data['v3'].replace('5more',5, inplace=True)
train_data['v4'].replace('more',5, inplace=True)
train_data['v5'].replace('small',0, inplace=True)
train_data['v5'].replace('med',1, inplace=True)
train_data['v5'].replace('big',2, inplace=True)
train_data['v6'].replace('low',0, inplace=True)
train_data['v6'].replace('med',1, inplace=True)
train_data['v6'].replace('high',2, inplace=True)
train_data['v7'].replace('unacc',0, inplace=True)
train_data['v7'].replace('acc',1, inplace=True)
train_data['v7'].replace('good',2, inplace=True)
train_data['v7'].replace('vgood',3, inplace=True)

#Rename the Dataset
train_dataset=train_data

#Replace the String with numeric values
test_data['v1'].replace('low',0, inplace=True)
test_data['v1'].replace('med',1, inplace=True)
test_data['v1'].replace('high',2, inplace=True)
test_data['v1'].replace('vhigh',3, inplace=True)
test_data['v2'].replace('low',0, inplace=True)
test_data['v2'].replace('med',1, inplace=True)
test_data['v2'].replace('high',2, inplace=True)
test_data['v2'].replace('vhigh',3, inplace=True)
test_data['v3'].replace('5more',5, inplace=True)
test_data['v4'].replace('more',5, inplace=True)
test_data['v5'].replace('small',0, inplace=True)
test_data['v5'].replace('med',1, inplace=True)
test_data['v5'].replace('big',2, inplace=True)
test_data['v6'].replace('low',0, inplace=True)
test_data['v6'].replace('med',1, inplace=True)
test_data['v6'].replace('high',2, inplace=True)
test_data['v7'].replace('unacc',0, inplace=True)
test_data['v7'].replace('acc',1, inplace=True)
test_data['v7'].replace('good',2, inplace=True)
test_data['v7'].replace('vgood',3, inplace=True)

test_dataset = test_data

# Splitting the input columns
X_train = train_dataset.drop('v7',axis=1)
y_train = train_dataset['v7']
X_test= test_dataset.drop('v7',axis=1)
y_test= test_dataset['v7']

#To run with the same file uncomment below
#X_train, X_test, y_train, y_test = train_test_split( X_train, y_train, test_size = 0.25,random_state=100)
clf = tree.DecisionTreeClassifier(criterion = "gini")
clf = clf.fit(X_train, y_train)

# To generate the decision tree
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
dot_data = tree.export_graphviz(clf, out_file=None,
                         feature_names=X_train.columns,
                         class_names=['unacc','acc','good','vgood'],
                         filled=True, rounded=True,
                         special_characters=True)
graph = graphviz.Source(dot_data)
graph

# Predicting the output for test dataset
y_pred = clf.predict(X_test)

#Printing the result.
print("Accuracy ")
print(accuracy_score(y_test,y_pred)*100)
print(" Confusion matrix ")
print( confusion_matrix(y_test, y_pred))


# Description: Given an array of integers, return indices of the two numbers such that they add up to a specific target.

class Solution:
    def twoSum(self, num, target):
        prevMap = {} # val : index

        for i, n in enumerate(num):
            diff = target - n

            if diff in prevMap:
                return [prevMap[diff], i]
            prevMap[n] = i
        return

newSolution = Solution()
arr = [2, 7, 11, 15]
target = 13

print(newSolution.twoSum(arr, target))


print('Bem vindo ao compras online!\n')

import os

lista_compras = []

while True:

    print('Selecione uma opção:')
    inserir_apagar_listar = input('[i]nserir [a]pagar [l]istar: ' ).lower()

    if len(inserir_apagar_listar) > 1:
        os.system('cls')
        print(f'Digite o valor dentro dos [], se referindo à ação que deseja realizar!\n')
        continue

    if inserir_apagar_listar == 'i':
        os.system('cls')
        valor = input('Valor: ')
        lista_compras.append(valor)

        for indice, nome in enumerate(lista_compras):
            print(f'\n \t{indice} {nome}\n')
        continue

    elif inserir_apagar_listar == 'a':
        os.system('cls')
        apagar_indice = input('Escolha um índice para apagar: ')

        try:
            apagar_indice_int = int(apagar_indice)

            try:
                del lista_compras[apagar_indice_int]

                for indice, nome in enumerate(lista_compras):
                    print(f'\n \t{indice} {nome}\n')

            except IndexError:
                print(f'Esse índice não existe!\n')

        except ValueError:
            print(f'Não foi possível apagar esse índice!\n')

    elif inserir_apagar_listar == 'l':
        os.system('cls')
        if lista_compras == []:
            print(f'Não existe uma lista para ser listada!\n')

        for indice, nome in enumerate(lista_compras):
            print(f'\n \t{indice} {nome}\n')

    else:
        os.system('cls')
        print('Digita o valor correto cara!')


from pytest import mark

from utils.tis_log import LOG
from keywords import vm_helper
from consts.stx import METADATA_SERVER

@mark.sanity
def test_vm_meta_data_retrieval(stx_openstack_required):
    """
    VM meta-data retrieval

    Test Steps:
        - Launch a boot-from-image vm
        - Retrieve vm meta_data within vm from metadata server
        - Ensure vm uuid from metadata server is the same as nova show

    Test Teardown:
        - Delete created vm and flavor
    """
    LOG.tc_step("Launch a boot-from-image vm")
    vm_id = vm_helper.boot_vm(source='image', cleanup='function')[1]
    vm_helper.wait_for_vm_pingable_from_natbox(vm_id, fail_ok=False)

    LOG.tc_step('Retrieve vm meta_data within vm from metadata server')
    # retrieve meta instance id by ssh to VM from natbox and wget to remote
    # server
    _access_metadata_server_from_vm(vm_id=vm_id)

def _access_metadata_server_from_vm(vm_id):
    with vm_helper.ssh_to_vm_from_natbox(vm_id) as vm_ssh:
        vm_ssh.exec_cmd('ip route')
        command = 'wget http://{}/openstack/latest/meta_data.json'.format(
            METADATA_SERVER)
        vm_ssh.exec_cmd(command, fail_ok=False)
        metadata = vm_ssh.exec_cmd('more meta_data.json', fail_ok=False)[1]

    LOG.tc_step("Ensure vm uuid from metadata server is the same as nova show")
    metadata = metadata.replace('\n', '')
    LOG.info(metadata)
    metadata_uuid = eval(metadata)['uuid']

    assert vm_id == metadata_uuid, "VM UUID retrieved from metadata server " \
                                   "is not the same as nova show"


from scipy.interpolate import interp1d
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

st.set_page_config(layout="wide")
plotCol, dataCol = st.columns([2,1])

importExp=st.sidebar.expander('Import Option')
skip=importExp.checkbox("First row is a string")
fileName = importExp.file_uploader("Import spectra",accept_multiple_files=False)
delimiter= importExp.selectbox('Delimiter:',('\t',';',','))

if fileName is not None:
    row=0
    if skip is True:
        row=1
    arr = np.loadtxt(fileName,delimiter=delimiter,skiprows=row)
    x=arr[:,0]
    xmin=np.min(arr[:,0])
    step=x[1]-x[0]
    firstWave=dataCol.number_input("Insert the first wavelenght of the spectra", min_value=float(100), max_value= xmin, step=step, value= xmin)
    xfull=x
    n=arr[:,1]
    k=arr[:,2]

    if firstWave!= xmin:
        xless=np.arange(firstWave, xmin,step)
        xfull = np.concatenate((xless,x),axis=0)
        k2 = [0 for i in range(int(( xmin-firstWave)/step))]
        n2 = [0 for i in range(int(( xmin-firstWave)/step))]
        k = np.concatenate((k2,k),axis=0)
        n= np.concatenate((n2,n),axis=0)

    xnew=np.arange(np.min(xfull),np.max(arr[:,0])+1,1)

    nfit=interp1d(xfull, n, kind='cubic')
    kfit=interp1d(xfull, k, kind='cubic')

    specraPlot=plotCol.expander('Dispersion curves')
    fig=plt.figure(1)
    plt.plot(xfull, n, '.', xfull, k, '.', xnew, nfit(xnew), '-',xnew, kfit (xnew), '-')
    plt.legend(['n_data','k_data', 'n_fit', 'k_fit'], loc='best')
    plt.xlabel("Wavelenght [nm]")
    plt.ylabel("n,k")
    specraPlot.pyplot(fig)

    plotData=dataCol.expander('fitted data',True)
    plotDataFrame=pd.DataFrame(np.vstack((xnew,nfit(xnew),kfit(xnew))).transpose(),columns = ['wavelenght','n','k'])
    plotData.dataframe(plotDataFrame)
    plotData.download_button('Download current spectra data',plotDataFrame.to_csv(header=False,index=False,sep ='\t').encode('utf-8'),'fittedspectra.txt')


"""Utility functions used by this codebase."""

from datetime import datetime, timedelta
import h5py
import numpy as np
import pytz
from spacepy import pycdf

import lib_dasilva2022

def read_omniweb_files(omniweb_files, silent=False):
    """Read OMNIWeb files into a single dictionary.

    Args
      omniweb_files: string path to cdf files
    Returns
      dictionary mapping parameters to file
    """
    # Read OMNIWeb Data
    # ------------------------------------------------------------------------------------
    t_items = []
    Bx_items = []
    By_items = []
    Bz_items = []
    n_items = []

    for omniweb_file in sorted(omniweb_files):
        # Open file
        if not silent:
            print(f'Loading {omniweb_file}')
        omniweb_cdf = pycdf.CDF(omniweb_file)

        # Read the data
        t_items.append(np.array([time.replace(tzinfo=pytz.utc)
                           for time in omniweb_cdf['Epoch'][:]]))

        Bx_items.append(omniweb_cdf['BX_GSE'][:])
        By_items.append(omniweb_cdf['BY_GSM'][:])
        Bz_items.append(omniweb_cdf['BZ_GSM'][:])
        n_items.append(omniweb_cdf['proton_density'][:])

        # Close file
        omniweb_cdf.close()

    # Merge arrays list of items
    omniweb_fh = {}
    omniweb_fh['t'] = np.concatenate(t_items)
    omniweb_fh['Bx'] = np.concatenate(Bx_items)
    omniweb_fh['By'] = np.concatenate(By_items)
    omniweb_fh['Bz'] = np.concatenate(Bz_items)
    omniweb_fh['n'] = np.concatenate(n_items)

    return omniweb_fh

def read_dmsp_flux_file(dmsp_flux_filename):
    """Read DMSP Flux hdf or cdf file and load variables into a dictionary.

    Args
      dmsp_flux_filename: string path to hdf or cdf file
    Returns
      dictionary mapping parameters to file
    """
    # Read DMSP Data in HDF5 Format
    # ------------------------------------------------------------------------------------
    if dmsp_flux_filename.endswith(('.hdf5', '.hdf', '.h5')):
        # Open file
        hdf = h5py.File(dmsp_flux_filename, 'r')

        # Populate file handle dictionary
        dmsp_flux_fh = {}
        dmsp_flux_fh['t'] = np.array(
            [datetime(1970, 1, 1, tzinfo=pytz.utc) + timedelta(seconds=i)
             for i in hdf['Data']['Array Layout']['timestamps'][:]]
        )
        dmsp_flux_fh['ch_energy'] = hdf['Data']['Array Layout']['ch_energy'][:]
        dmsp_flux_fh['mlat'] = hdf['Data']['Array Layout']['1D Parameters']['mlat'][:]
        dmsp_flux_fh['mlt'] = hdf['Data']['Array Layout']['1D Parameters']['mlt'][:]
        dmsp_flux_fh['el_d_ener'] = hdf['Data']['Array Layout']['2D Parameters']['el_d_ener'][:]
        dmsp_flux_fh['ion_d_ener'] = hdf['Data']['Array Layout']['2D Parameters']['ion_d_ener'][:]

        # Close file
        hdf.close()

    # Read DMSP Data in CDF Format
    # ------------------------------------------------------------------------------------
    elif dmsp_flux_filename.endswith('cdf'):

        # Open file
        cdf = pycdf.CDF(dmsp_flux_filename)

        dmsp_flux_fh = {}
        dmsp_flux_fh['t'] = np.array([t.replace(tzinfo=pytz.utc) for t in cdf['Epoch'][:]])
        dmsp_flux_fh['ch_energy'] = cdf['CHANNEL_ENERGIES'][:][::-1]
        dmsp_flux_fh['mlat'] = cdf['SC_AACGM_LAT'][:]
        dmsp_flux_fh['mlt'] = cdf['SC_AACGM_LTIME'][:]
        dmsp_flux_fh['el_d_ener'] = cdf['ELE_DIFF_ENERGY_FLUX'][:].T
        dmsp_flux_fh['ion_d_ener'] = cdf['ION_DIFF_ENERGY_FLUX'][:].T

        # Close file
        cdf.close()

    # Crash for any other format
    # ------------------------------------------------------------------------------------
    else:
        raise RuntimeError(f'Invalid file format for {dmsp_flux_filename}')

    # Compute (simple) derived variables
    # ------------------------------------------------------------------------------------
    # Ion and Electron Average Flux
    ch_i = dmsp_flux_fh['ch_energy'].searchsorted(lib_dasilva2022.MIN_ION_VALID_ENERGY)
    ch_j = dmsp_flux_fh['ch_energy'].searchsorted(lib_dasilva2022.MAX_SHEATH_ENERGY)

    dmsp_flux_fh['iflux_avg_sheath'] = np.mean(
        dmsp_flux_fh['ion_d_ener'][ch_i:ch_j, :], axis=0
    )
    dmsp_flux_fh['eflux_avg_sheath'] = np.mean(
        dmsp_flux_fh['el_d_ener'][:ch_j, :], axis=0
    )
    # Ion and Electron Peak Flux in Sheath
    dmsp_flux_fh['iflux_peak_sheath'] = np.max(
        dmsp_flux_fh['ion_d_ener'][ch_i:ch_j, :], axis=0
    )
    dmsp_flux_fh['eflux_peak_sheath'] = np.max(
        dmsp_flux_fh['el_d_ener'][:ch_j, :], axis=0
    )

    return dmsp_flux_fh

def find_moving_average(a, window_size) :
    """Smooth array `a` using moving average with window size `n`.

    This code was adapted from an example found on stack overflow.

    Args
      a: numeric numpy array
      window_size: integer window size
    Returns
      smoothed array using moving average.
    """
    return np.convolve(a, np.ones((window_size,))/window_size, mode='same')


# -*- coding:utf-8 -*-
# @Time    : 2021/2/4 15:59
# @Author  : zengln
# @File    : x 的平方根.py

# 实现 int sqrt(int x) 函数。
#
#  计算并返回 x 的平方根，其中 x 是非负整数。
#
#  由于返回类型是整数，结果只保留整数的部分，小数部分将被舍去。
#
#  示例 1:
#
#  输入: 4
# 输出: 2
#
#
#  示例 2:
#
#  输入: 8
# 输出: 2
# 说明: 8 的平方根是 2.82842...,
#      由于返回类型是整数，小数部分将被舍去。
#

class Solution:
    def mySqrt(self, x: int) -> int:
        left, right = 0, x
        while left < right:
            mid = (left + right + 1) // 2
            #[left, mid-1] [mid, right]
            if mid * mid == x:
                return mid
            elif mid * mid > x:
                right = mid - 1
            elif mid * mid < x:
                left = mid

        return left

二分查找/x 的平方根.py


import math
from stdutils import prettyFunction, inputAsDict

vals = inputAsDict(('degree','minute','second','arc'))

vals['de'] = vals['degree'] + (vals['minute']/60) + (vals['second']/3600)
vals['ra'] = vals['de']/180
vals['rap'] = vals['ra']*math.pi
vals['len'] = vals['arc']/vals['ra']
vals['lenp'] = vals['arc']/vals['rap']

print('')
print(prettyFunction("{degree}{degree}{minute}\"{second}\' = {de}{degree} = {ra}{pi}", vals))
print(prettyFunction("Radius = {arc}/{ra}{pi} = {len}/{pi}", vals))
print(prettyFunction("{len}/{pi} {approx} {lenp}", vals))


#
# @lc app=leetcode id=92 lang=python
#
# [92] Reverse Linked List II
#
# https://leetcode.com/problems/reverse-linked-list-ii/description/
#
# algorithms
# Medium (36.41%)
# Likes:    1560
# Dislikes: 108
# Total Accepted:    223.9K
# Total Submissions: 613.9K
# Testcase Example:  '[1,2,3,4,5]\n2\n4'
#
# Reverse a linked list from position m to n. Do it in one-pass.
#
# Note: 1 ≤ m ≤ n ≤ length of list.
#
# Example:
#
#
# Input: 1->2->3->4->5->NULL, m = 2, n = 4
# Output: 1->4->3->2->5->NULL
#
#
#

# @lc code=start
# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        # if m == n:
        #     return head

        # dummy = ListNode(0)
        # dummy.next = head

        # count = 0
        # l1 = ListNode(None)
        # l2 = ListNode(None)
        # pre = dummy

        # while head:
        #     count += 1
        #     if count == m:
        #         l1 = pre
        #         l2 = head
        #     if count > m and count < n:
        #         temp = head.next
        #         head.next = pre
        #         pre = head
        #         head = temp
        #         continue
        #     if count == n:
        #         l2.next = head.next
        #         head.next = pre
        #         l1.next = head
        #         break

        #     head = head.next
        #     pre = pre.next
        # return dummy.next

        if m == n:
            return head
        dummy = ListNode(0)
        dummy.next = head
        pre = dummy

        for _ in range(m-1):
            pre = pre.next

        reverse = None
        cur = pre.next
        for i in range(n-m+1):
            nex = cur.next
            cur.next = reverse
            reverse = cur
            cur = nex
        pre.next.next = cur
        pre.next = reverse

        return dummy.next

# @lc code=end


import math
from typing import Sequence, Tuple

import torch
from torch import nn
from torch.nn import functional as F
from tensorfn.config import config_model
from pydantic import StrictInt, StrictFloat

from .layer import DropPath, tuple2, PositionwiseFeedForward

LayerNorm = lambda x: nn.LayerNorm(x, eps=1e-6)

def patchify(input, size):
    batch, height, width, dim = input.shape

    return (
        input.view(batch, height // size, size, width // size, size, dim)
        .permute(0, 1, 3, 2, 4, 5)
        .reshape(batch, height // size, width // size, -1)
    )

class PositionalEncodingGenerator(nn.Module):
    def __init__(self, dim):
        super().__init__()

        self.proj = nn.Conv2d(dim, dim, 3, padding=1, bias=False, groups=dim)

    def forward(self, input):
        out = input.permute(0, 3, 1, 2)
        out = self.proj(out) + out
        out = out.permute(0, 2, 3, 1)

        return out

class MultiHeadedAttention(nn.Module):
    def __init__(self, dim, n_head, reduction=1, dropout=0):
        super().__init__()

        self.dim_head = dim // n_head
        self.n_head = n_head

        self.linear_q = nn.Linear(dim, dim, bias=False)
        self.linear_kv = nn.Linear(dim, dim * 2, bias=False)

        self.linear = nn.Linear(dim, dim)
        self.dropout = dropout
        self.reduction = reduction

        if self.reduction > 1:
            self.reduce_conv = nn.Conv2d(
                dim, dim, self.reduction, stride=self.reduction
            )

    def forward(self, input):
        batch_size, height, width, _ = input.shape

        def reshape(input):
            return input.reshape(batch_size, -1, self.n_head, self.dim_head).transpose(
                1, 2
            )

        query = reshape(self.linear_q(input))

        if self.reduction > 1:
            dim = input.shape[-1]
            reduc = input.transpose(1, 2).reshape(batch_size, dim, height, width)
            reduc = self.reduce_conv(reduc).reshape(batch_size, dim, -1).transpose(1, 2)
            kv = reduc

        else:
            kv = input

        key, value = self.linear_kv(kv).chunk(2, dim=2)
        key = reshape(key).transpose(2, 3)
        value = reshape(value)

        score = query @ key / math.sqrt(self.dim_head)

        attn = F.softmax(score, 3)
        attn = F.dropout(attn, self.dropout, training=self.training)

        out = attn @ value

        out = out.transpose(1, 2).reshape(
            batch_size, height, width, self.dim_head * self.n_head
        )
        out = self.linear(out)

        return out

class MultiHeadedLocalAttention(nn.Module):
    def __init__(self, dim, n_head, dim_head, window_size, dropout=0):
        super().__init__()

        self.dim_head = dim_head
        self.n_head = n_head

        self.weight = nn.Linear(dim, n_head * dim_head * 3, bias=True)
        self.linear = nn.Linear(n_head * dim_head, dim)

        self.window_size = window_size
        self.dropout = dropout

    def forward(self, input):
        batch, height, width, dim = input.shape
        h_stride = height // self.window_size
        w_stride = width // self.window_size
        window = self.window_size

        def reshape(input):
            return (
                input.reshape(
                    batch,
                    h_stride,
                    window,
                    w_stride,
                    window,
                    self.n_head,
                    self.dim_head,
                )
                .permute(0, 1, 3, 5, 2, 4, 6)
                .reshape(batch, -1, self.n_head, window * window, self.dim_head)
            )

        query, key, value = self.weight(input).chunk(3, dim=-1)  # B, S, H, W^2, D

        query = reshape(query)
        key = reshape(key).transpose(-2, -1)
        value = reshape(value)

        score = query @ key / math.sqrt(self.dim_head)  # B, S, H, W^2, W^2

        attn = F.softmax(score, -1)
        attn = F.dropout(attn, self.dropout, training=self.training)

        out = attn @ value  # B, S, H, W^2, D

        out = (
            out.view(
                batch, h_stride, w_stride, self.n_head, window, window, self.dim_head
            )
            .permute(0, 1, 4, 2, 5, 3, 6)
            .reshape(batch, height, width, self.n_head * self.dim_head)
        )
        out = self.linear(out)

        return out

class TransformerLayer(nn.Module):
    def __init__(
        self,
        dim,
        n_head,
        dim_head,
        dim_ff,
        window_size,
        activation=nn.SiLU,
        drop_ff=0,
        drop_attn=0,
        drop_path=0,
    ):
        super().__init__()

        self.norm_attn_local = LayerNorm(dim)
        self.attn_local = MultiHeadedLocalAttention(
            dim, n_head, dim_head, window_size, drop_attn
        )
        self.norm_ff_local = LayerNorm(dim)
        self.ff_local = PositionwiseFeedForward(
            dim, dim_ff, activation=activation, dropout=drop_ff
        )

        self.norm_attn_global = LayerNorm(dim)
        self.attn_global = MultiHeadedAttention(dim, n_head, window_size, drop_attn)
        self.norm_ff_global = LayerNorm(dim)
        self.ff_global = PositionwiseFeedForward(
            dim, dim_ff, activation=activation, dropout=drop_ff
        )

        self.drop_path = DropPath(drop_path)

    def set_drop_path(self, p):
        self.drop_path.p = p

    def forward(self, input):
        out = input + self.drop_path(self.attn_local(self.norm_attn_local(input)))
        out = out + self.drop_path(self.ff_local(self.norm_ff_local(out)))
        out = out + self.drop_path(self.attn_global(self.norm_attn_global(out)))
        out = out + self.drop_path(self.ff_global(self.norm_ff_global(out)))

        return out

class PatchEmbedding(nn.Module):
    def __init__(self, in_dim, out_dim, window_size):
        super().__init__()

        self.window_size = window_size
        self.linear = nn.Linear(in_dim * window_size * window_size, out_dim)
        self.norm = nn.LayerNorm(out_dim)

    def forward(self, input):
        out = patchify(input, self.window_size)
        out = self.linear(out)
        out = self.norm(out)

        return out

def reduce_size(size, reduction):
    return (size[0] // reduction, size[1] // reduction)

@config_model(name="twins_svt", namespace="model", use_type=True)
class TwinsSVT(nn.Module):
    def __init__(
        self,
        n_class: StrictInt,
        depths: Tuple[StrictInt, StrictInt, StrictInt, StrictInt],
        dims: Tuple[StrictInt, StrictInt, StrictInt, StrictInt],
        dim_head: StrictInt,
        n_heads: Tuple[StrictInt, StrictInt, StrictInt, StrictInt],
        dim_ffs: Tuple[StrictInt, StrictInt, StrictInt, StrictInt],
        window_size: StrictInt,
        drop_ff: StrictFloat = 0.0,
        drop_attn: StrictFloat = 0.0,
        drop_path: StrictFloat = 0.0,
    ):
        super().__init__()

        self.depths = depths

        def make_block(i, in_dim, reduction):
            return self.make_block(
                depths[i],
                in_dim,
                dims[i],
                n_heads[i],
                dim_head,
                dim_ffs[i],
                window_size,
                reduction,
                drop_ff,
                drop_attn,
            )

        self.block1 = make_block(0, 3, 4)
        self.block2 = make_block(1, dims[0], 2)
        self.block3 = make_block(2, dims[1], 2)
        self.block4 = make_block(3, dims[2], 2)

        self.final_linear = nn.Sequential(nn.LayerNorm(dims[-1]))
        linear = nn.Linear(dims[-1], n_class)
        nn.init.normal_(linear.weight, std=0.02)
        nn.init.zeros_(linear.bias)
        self.classifier = nn.Sequential(nn.AdaptiveAvgPool2d(1), nn.Flatten(1), linear)

        self.apply(self.init_weights)
        self.set_dropout(None, drop_path)

    def set_dropout(self, dropout, drop_path):
        n_blocks = sum(self.depths)
        dp_rate = [drop_path * float(i) / n_blocks for i in range(n_blocks)]

        i = 0
        for block in self.block1:
            try:
                block.set_drop_path(dp_rate[i])
                i += 1

            except:
                continue

        for block in self.block2:
            try:
                block.set_drop_path(dp_rate[i])
                i += 1

            except:
                continue

        for block in self.block3:
            try:
                block.set_drop_path(dp_rate[i])
                i += 1

            except:
                continue

        for block in self.block4:
            try:
                block.set_drop_path(dp_rate[i])
                i += 1

            except:
                continue

    def init_weights(self, module):
        if isinstance(module, nn.Linear):
            nn.init.normal_(module.weight, std=0.02)

            if module.bias is not None:
                nn.init.zeros_(module.bias)

        elif isinstance(module, nn.LayerNorm):
            nn.init.ones_(module.weight)
            nn.init.zeros_(module.bias)

    def make_block(
        self,
        depth,
        in_dim,
        dim,
        n_head,
        dim_head,
        dim_ff,
        window_size,
        reduction,
        drop_ff,
        drop_attn,
    ):
        block = [PatchEmbedding(in_dim, dim, reduction)]

        for i in range(depth):
            block.append(
                TransformerLayer(
                    dim,
                    n_head,
                    dim_head,
                    dim_ff,
                    window_size,
                    drop_ff=drop_ff,
                    drop_attn=drop_attn,
                )
            )

            if i == 0:
                block.append(PositionalEncodingGenerator(dim))

        return nn.Sequential(*block)

    def forward(self, input):
        out = self.block1(input.permute(0, 2, 3, 1))
        out = self.block2(out)
        out = self.block3(out)
        out = self.block4(out)
        out = self.final_linear(out).permute(0, 3, 1, 2)
        out = self.classifier(out)

        return out


'''
Simplification routines for CAS.
'''

from parser import Operator, MinusOp, Number, ParseTree
from operator import add, sub, mul, truediv, pow
from fractions import Fraction

class NonNumericExpr(Exception):
    '''
    This is an exception needed by reduce_numeric_expr
    '''
    def __init__(self, error_msg=''):
        Exception.__init__(self, error_msg)

def reduce(expr):
    '''
    Cleans up expr, reducing any easily-computed numeric expressions.
    '''
    if not isinstance(expr, ParseTree):
        return expr
    else:
        if expr.right:
            return minimal_simplify(ParseTree([expr.root,
                                               reduce(expr.left),
                                               reduce(expr.right)]))
        else:
            return minimal_simplify(ParseTree([expr.root, reduce(expr.left)]))

def minimal_simplify(expr):
    if isinstance(expr.root, Operator):
        return op_table[expr.root.value](expr)
    else:
        return expr

def reduce_numeric_expr(expr, op):
    '''
    Reduces a numeric expression (e.g., [+, 2, 2]); raises NonNumericExpr if
    expr has only one child, or if expr is not a numeric expression.
    '''
    if False not in [isinstance(x, Number) for x in expr.children]:
        left, right = expr.left.value, expr.right.value
        return Number(op(left, right))
    else:
        raise NonNumericExpr

def reduce_add_sub(expr):
    '''
    Reduction cases for addition, subtraction, or negation expressions
    '''
    # we need two operations, since this function handles both addition and
    # subtraction
    ops = {'+':add, '-':sub}

    # if the operands are both numeric, evaluate the expression
    try:
        return reduce_numeric_expr(expr, ops[expr.root.value])
    except NonNumericExpr:
        # now we move on to simplifications we can make for subtraction expressions
        if expr.root.value == '-':
            if expr.left.value == 0:
                if not expr.right:
                    return Number(0)
                else:
                    return ParseTree([MinusOp('-'), expr.right])
            elif expr.right and expr.right.value == 0:
                return expr.left
        # simplifying addition expressions
        elif expr.root.value == '+':
            if expr.left.value == 0:
                return expr.right
            elif expr.right.value == 0:
                return expr.left

        return expr

def reduce_mul(expr):
    '''
    Reduction case for multiplication expressions.
    '''
    try:
        return reduce_numeric_expr(expr, mul)
    except NonNumericExpr:
        if 0 in [x.value for x in expr.children]:
            return Number(0)
        elif expr.left.value == 1:
            return expr.right
        elif expr.right.value == 1.0:
            return expr.left
        else:
            return expr

def reduce_div(expr):
    '''
    Reduction case for division expressions.
    '''
    # for stylistic reasons, I do not want to convert fractions to decimals;
    # thus, I won't use reduce_numeric_expr right away.
    if False not in [isinstance(x, Number) for x in expr.children] and \
            (float not in [type(x.value) for x in expr.children]):
        return Number(Fraction(expr.left.value, expr.right.value))
    else:
        try:
            reduce_numeric_expr(expr, truediv)
        except NonNumericExpr:
            if expr.right.value == 1:
                return expr.left
            elif expr.right.value == 0:
                raise ZeroDivisionError
            else:
                return expr

def reduce_pow(expr):
    '''
    Reduction case for exponentiation expressions
    '''
    try:
        return reduce_numeric_expr(expr, pow)
    except:
        if expr.right.value == 1:
            return expr.left
        elif expr.right.value == 0:
            return Number(1)
        else:
            return expr
## -----------------------------------------------------------------------------
## The operator table
## -----------------------------------------------------------------------------
op_table = {'+':reduce_add_sub,
            '-':reduce_add_sub,
            '*':reduce_mul,
            '/':reduce_div,
            '^':reduce_pow}
## END -------------------------------------------------------------------------