from cmath import nan
import random
import numpy

class Order:
    """
        a data structure containing all the relevant information for the order request of an agent
    """
    def __init__(self, orderType, buy_currency, sell_currency, amount_of_buying_currency, round, agent, limit_price, expiration_time):
        self.order_type = orderType # OPEN or CLOSE order
        self.buy_currency = buy_currency # currency agent wants to buy
        self.sell_currency = sell_currency # currency agent will sell in order to buy
        self.amount_of_buying_currency = amount_of_buying_currency # amount of buy currency agent wants to own :: DEPEND ON EXCHANGE_RATE
        self.timestep = round
        self.agent = agent
        self.expiration_time = expiration_time
        self.limit_price = limit_price

class Strategy:
    """
        Superclass whose children have different implementations of the four methods
        each children represents a different type of strategy
    """
    def __init__(self, strategy_name, exchange_rates_data):
        self.name = strategy_name
        self.exchange_rates_data = exchange_rates_data
        pass

    def getAmountOfBuyingCurrency(self, exchange_rate, limit_price, max_amount_to_sell):
        if exchange_rate > 1:
            if exchange_rate > limit_price:
                return max_amount_to_sell / limit_price
            else: return max_amount_to_sell / exchange_rate
        else:
            exchange_price = 1 / limit_price
            if exchange_rate > exchange_price:
                return max_amount_to_sell / exchange_price
            else: return max_amount_to_sell / exchange_rate

    def getLimitPrice(self, exchange_rate):
        # https://arxiv.org/pdf/cond-mat/0103600.pdf
        random_gauss_factor = self.getRandomDrawFromGaussian() # to add randomness in limit_prices
        limit_price = 0
        # WHAT AM I DOING HERE ???
        while limit_price <= 0:
            limit_price = exchange_rate * random_gauss_factor
        if limit_price <= 1:
            return 1 / limit_price # makes limit_price always one sided
        return limit_price

    def getRandomDrawFromGaussian(self):
        # For orders: μ = 0.98 / 1.02, σmin = 0.01 and σmax = 0.003.
        mean = 1
        return numpy.random.normal(loc = mean, scale = random.uniform(0.003, 0.01))

    def tryToMakeOpenOrder(self, agent, round):
        """ wishes to exchange X for Y """
        currencies_in_wallet = agent.getCurrenciesInWalletWithPositiveBalance()
        currencies_in_market = random.sample(agent.currency_market.getAvailableCurrencies(), len(agent.currency_market.getAvailableCurrencies()))
        exchanging_currencies = self.findCurrencyPairToInvest(currencies_in_market, currencies_in_wallet, round, agent.risk_level)
        if exchanging_currencies == None:
            return None
        else:
            # creates an ORDER
            buy_currency = exchanging_currencies[0]
            sell_currency = exchanging_currencies[1]
            return self.sendOrderRequest(agent, buy_currency, sell_currency)

    def findCurrencyPairToInvest(self, currencies_in_market, currencies_in_wallet, round, agent_risk_level):
        for possible_selling_currency in currencies_in_wallet:
            possible_selling_currency_symbol = possible_selling_currency.symbol
            for possible_buying_currency in currencies_in_market:
                possible_buying_currency_symbol = possible_buying_currency.symbol
                if possible_selling_currency_symbol == possible_buying_currency_symbol: continue

                exchange_rate_symbol = possible_buying_currency_symbol + "/" + possible_selling_currency_symbol # is this the right way around ?

                if self.shouldAgentOpenOrderWithThisCurrencyPair(round, exchange_rate_symbol, agent_risk_level): # this method is subclass specific !!!
                    return [possible_buying_currency, possible_selling_currency]
        return None

    def sendOrderRequest(self, agent, buy_currency, sell_currency):

        exchange_rate_symbol = buy_currency.symbol + "/" + sell_currency.symbol
        exchange_rate = agent.currency_market.getCurrenciesExchangeRate(exchange_rate_symbol, agent.round)

        limit_price = self.getLimitPrice(exchange_rate)
        amount_of_buying_currency = self.getAmountOfBuyingCurrency(exchange_rate, limit_price, agent.wallet[sell_currency]) # AGENT WANTS TO BUY 10 of currency
        expiration_time = random.choice(range(24, 168)) # 1 step == 1 hour --> 1 day to 7 days

        return Order("OPEN", buy_currency, sell_currency, amount_of_buying_currency, agent.round, agent, limit_price, expiration_time)

    def closingConditionMet(self, agent, round):
        """" Agent's strategy for when to close the position """
        investmentToClose = agent.current_investment

        buy_currency = investmentToClose["sold_currency"] # currency you used to invest
        sell_currency = investmentToClose["bought_currency"] # currency you invested in

        exchange_rate_symbol = buy_currency.symbol + "/" + sell_currency.symbol

        return self.shouldAgentCloseCurrentInvestment(round, exchange_rate_symbol, agent.risk_level)

    def makeCloseOrder(self, agent, round):
        """ wishes to exchange Y for X """

        investment_to_close = agent.current_investment # close current investment // investment is a dictionary object
        buy_currency = investment_to_close["sold_currency"] # currency you used to invest
        sell_currency = investment_to_close["bought_currency"] # currency you invested in
        amount_of_buying_currency = investment_to_close["amount"]

        symbol = buy_currency.symbol + "/" + sell_currency.symbol
        exchange_rate = agent.currency_market.getCurrenciesExchangeRate(symbol, agent.round)
        limit_price = self.getLimitPrice(exchange_rate)

        expiration_time = random.choice(range(2, 24)) # want to close ASAP so willing to change much quicker
        return Order("CLOSE", buy_currency, sell_currency, amount_of_buying_currency, round, agent, limit_price, expiration_time)

class RandomStrategy(Strategy):

    """
        Randomly decides to invest in a currency using a random currency
        Represents people that are in the market without any knowledge (Zero-Intelligence Traders) whose aim is not
        profit maximisation
    """
    def __init__(self, strategy_name, exchange_rates_data):
        super().__init__(strategy_name, exchange_rates_data)

    def tryToMakeOpenOrder(self, agent, round):
        """ wishes to exchange X for Y """
        currenciesInWallet = agent.getCurrenciesInWalletWithPositiveBalance()
        sell_currency = random.choice(currenciesInWallet) # currency agent has in its wallet that he wants to exchange (selling this to buy)

        currencies = agent.currency_market.getAvailableCurrencies() # list of available currencies in the market
        buy_currency = None
        while buy_currency == None:
            potentialCurrency = random.choice(currencies)
            if potentialCurrency != sell_currency:
                buy_currency = potentialCurrency

        exchange_symbol = buy_currency.symbol + "/" + sell_currency.symbol
        exchange_rate = agent.currency_market.getCurrenciesExchangeRate(exchange_symbol, agent.round)

        limit_price = self.getLimitPrice(exchange_rate)

        random_amount = random.randint(10,200)
        amount_of_buying_currency = self.getAmountOfBuyingCurrency(exchange_rate, limit_price, random_amount)

        expiration_time = random.choice(range(4, 24))

        return Order("OPEN", buy_currency, sell_currency, amount_of_buying_currency, round, agent, limit_price, expiration_time) # creates an ORDER

class PivotPointStrategy(Strategy):
    """
        Follows Pivot Point and Support and Resistance indicators
    """
    def __init__(self, strategy_name, exchange_rates_data):
        super().__init__(strategy_name, exchange_rates_data)
        self.exchange_rates_data = exchange_rates_data

    def shouldAgentCloseCurrentInvestment(self, round, symbol, agent_risk_level):
        """" Agent's strategy for when to close the position """
        # get support and the pivot points
        symbol_exchange_rate_data = self.exchange_rates_data[symbol]
        important_points = self.getImportantPoints(symbol_exchange_rate_data, round)
        high = important_points[1]
        low = important_points[2]
        pivot_point = important_points[0]
        support = self.calculateSupport(high, pivot_point)
        second_support = self.calculateSecondSupport(low, high, pivot_point)
        current_exchange_rate_price = symbol_exchange_rate_data[round]

        if agent_risk_level == "averse":
            if self.isMarketTrendDown(pivot_point, current_exchange_rate_price):
                return True
        elif agent_risk_level == "neutral":
            if self.isMarketTrendDown(pivot_point, current_exchange_rate_price):
                if self.hasBrokenSupportLevel(support, current_exchange_rate_price):
                    return True
        elif agent_risk_level == "taker":
              if self.isMarketTrendDown(pivot_point, current_exchange_rate_price):
                if self.hasBrokenSupportLevel(support, current_exchange_rate_price):
                    if self.isCloserToSecondSupportLevelThanPivotPoint(second_support, pivot_point, current_exchange_rate_price):
                        return True
        else: return False

    def shouldAgentOpenOrderWithThisCurrencyPair(self, round, symbol, agent_risk_level):
        symbol_exchange_rate_data = self.exchange_rates_data[symbol]
        important_points = self.getImportantPoints(symbol_exchange_rate_data, round)
        low = important_points[2]
        high = important_points[1]
        pivot_point = important_points[0]
        resistance = self.calculateResistance(low, pivot_point)
        second_resistance = self.calculateSecondResistance(low, high, pivot_point)
        current_exchange_rate_price = symbol_exchange_rate_data[round]

        # a risk taker will only check if we are trading above the pivot point
        if agent_risk_level == "taker":
            if self.isMarketTrendUp(pivot_point, current_exchange_rate_price):
                return True
        # a neutral risk agent will check if marketTrendIsUp and wether the price has broken the resistance level
        elif agent_risk_level == "neutral":
            if self.isMarketTrendUp(pivot_point, current_exchange_rate_price):
                if self.hasBrokenResistanceLevel(resistance, current_exchange_rate_price):
                    return True
        # a risk averse agent will check if marketTrendIsUp, price has broken resistance level and if price going towards second_resistance
        elif agent_risk_level == "averse":
            if self.isMarketTrendUp(pivot_point, current_exchange_rate_price):
                if self.hasBrokenResistanceLevel(resistance, current_exchange_rate_price):
                    if self.isCloserToSecondResistanceLevelThanPivotPoint(second_resistance, pivot_point, current_exchange_rate_price):
                        return True
        else: False
        # does not change performance and makes it more readable ^

    def getImportantPoints(self, exchange_rate_data, round):
        """ formula: pivot_point = (prev_high + prev_low + prev_close) / 3 """
        day_in_hours = 7 * 24
        window = round - day_in_hours # looks a week back
        exchange_rate_data_past_day = exchange_rate_data.iloc[range(window, round)] # window to previous round
        max = exchange_rate_data_past_day.max()
        min = exchange_rate_data_past_day.min()
        close = exchange_rate_data_past_day.iloc[-1] # last value

        pivot_point = (max + min + close) / 3
        return [pivot_point, max, min, close]

    def calculateResistance(self, low, pivot_point):
        """ formula: resistance = 2 * P - L """
        return 2 * pivot_point - low

    def calculateSecondResistance(self, low, high, pivot_point):
        """ formula: R2 = P + (H − L) """
        return pivot_point + high - low

    def isCloserToSecondResistanceLevelThanPivotPoint(self, second_resistance, pivot_point, exchange_rate):
        if abs(second_resistance - exchange_rate) < abs(pivot_point - exchange_rate):
            return True
        return False

    def calculateSupport(self, high, pivot_point):
        """ formula: resistance = 2*P - H """
        return 2 * pivot_point - high

    def calculateSecondSupport(self, low, high, pivot_point):
        """ formula: S2 = P − (H − L) """
        return pivot_point - high + low

    def isCloserToSecondSupportLevelThanPivotPoint(self, second_support, pivot_point, exchange_rate):
        if abs(second_support - exchange_rate) < abs(pivot_point - exchange_rate):
            return True
        return False

    def isMarketTrendUp(self, pivot_point, current_exchange):
        if current_exchange > pivot_point:
            return True
        return False

    def isMarketTrendDown(self, pivot_point, current_exchange):
        if current_exchange < pivot_point:
            return True
        return False

    def hasBrokenResistanceLevel(self, resistance, current_exchange):
        if current_exchange > resistance:
            return True
        return False

    def hasBrokenSupportLevel(self, support, current_exchange):
        if current_exchange < support:
            return True
        return False

class MovingAverageStrategy(Strategy):
    """
        Follows Moving average indicators
    """
    def __init__(self, strategy_name, exchange_rates_data):
        super().__init__(strategy_name, exchange_rates_data)
        self.exchange_rates_data = exchange_rates_data

    def shouldAgentCloseCurrentInvestment(self, round, symbol, agent_risk_level):
        """" Agent's strategy for when to close the position depends on risk_level the lower the tolerance the most likely it closes """
        if agent_risk_level == "averse": # will close if it sees sign weak or strong
            if self.isPriceMovementShowingStrongSell(symbol, round, 5) or self.isPriceMovementShowingWeakSell(symbol, round, 5):
                return True
            elif self.isComparingMovingAveragesShowingStrongSell(symbol, round) or self.isComparingMovingAveragesShowingWeakSell(symbol, round):
                return True
        elif agent_risk_level == "neutral": # closes if strong sell
            if self.isPriceMovementShowingStrongSell(symbol, round, 5):
                return True
            if self.isComparingMovingAveragesShowingStrongSell(symbol, round):
                return True
        elif agent_risk_level == "taker": # closes if strong sell for SMA and EMA
            if self.isPriceMovementShowingStrongSell(symbol, round, 5) and self.isPriceMovementShowingStrongSellEMA(symbol, round, 9):
                return True
            elif self.isComparingMovingAveragesShowingStrongSell(symbol, round) and self.isComparingEMAShowingStrongSell(symbol, round):
                return True

        return False

    def shouldAgentOpenOrderWithThisCurrencyPair(self, round, symbol, agent_risk_level):
        """ should an open position be made  """
        # risk taker will invest even if weak or strong buy
        if agent_risk_level == "taker":
            if self.isPriceMovementShowingStrongBuy(symbol, round, 5) or self.isPriceMovementShowingWeakBuy(symbol, round, 5):
                return True
            elif self.isComparingMovingAveragesShowingStrongBuy(symbol, round) or self.isComparingMovingAveragesShowingWeakBuy(symbol, round):
                return True

        # risk neutral will only invest if strong buy
        elif agent_risk_level == "neutral":
            if self.isPriceMovementShowingStrongBuy(symbol, round, 5):
                return True
            elif self.isComparingMovingAveragesShowingStrongBuy(symbol, round):
                return True

        # risk averse strong buy SMA and EMA
        elif agent_risk_level == "averse":
            if self.isPriceMovementShowingStrongBuy(symbol, round, 5) and self.isPriceMovementShowingStrongBuyEMA(symbol, round, 9):
                return True
            elif self.isComparingMovingAveragesShowingStrongBuy(symbol, round) and self.isComparingEMAShowingStrongBuy(symbol, round):
                return True

        return False

    def isPriceMovementShowingStrongBuy(self, symbol, round, time_considered_in_days):
        X_days_in_hours = time_considered_in_days * 24
        if self.isXDayMovingAverageRising(round, X_days_in_hours, symbol) and self.hasPriceCrossedFromBelowXDayMovingAverage(round, X_days_in_hours, symbol):
            return True
        return False

    def isPriceMovementShowingStrongBuyEMA(self, symbol, round, time_considered_in_days):
        # must keep the time in days to obtain correct data in exchange rates dataframe passing 9, 12 or 26
        if self.isXDayEMARising(round, time_considered_in_days, symbol) and self.hasPriceCrossedFromBelowXDayEMA(round, time_considered_in_days, symbol):
            return True
        return False

    def isPriceMovementShowingWeakBuy(self, symbol, round, time_considered_in_days):
        """ if current price crosses from below a falling moving average curve than it signals a weak buy """
        X_days_in_hours = time_considered_in_days * 24
        if self.isXDayMovingAverageFalling(round, X_days_in_hours, symbol) and self.hasPriceCrossedFromBelowXDayMovingAverage(round, X_days_in_hours, symbol):
            return True
        return False

    def isPriceMovementShowingWeakSell(self, symbol, round, time_considered_in_days):
        """  a weak sell if falling current price is crossed by a rising longer period curve. """
        X_days_in_hours = time_considered_in_days * 24
        if self.isXDayMovingAverageRising(round, X_days_in_hours, symbol) and self.hasPriceCrossedFromAboveXDayMovingAverage(round, X_days_in_hours, symbol):
            return True
        return False

    def hasPriceCrossedFromBelowXDayMovingAverage(self, round, range, symbol):
        current_price = self.exchange_rates_data[symbol][round]
        previous_price = self.exchange_rates_data[symbol][round - 1]
        current_moving_average = self.getXDayMovingAverage(round, range, symbol)
        previous_moving_average = self.getXDayMovingAverage(round - 1, range, symbol)

        if previous_price < previous_moving_average and current_price > current_moving_average:
            return True
        return False

    def hasPriceCrossedFromBelowXDayEMA(self, round, time_range, symbol):
        # time_range: 9, 12, 26
        current_price = self.exchange_rates_data[symbol][round]
        previous_price = self.exchange_rates_data[symbol][round - 1]
        current_ema = self.getXDayExponentialMovingAverage(round, time_range, symbol)
        previous_ema = self.getXDayExponentialMovingAverage(round - 1, time_range, symbol)

        if previous_price < previous_ema and current_price > current_ema:
            return True
        return False

    def isXDayMovingAverageRising(self, round, range, symbol):
        """ rising if current round moving avg higher than previous round """
        current_moving_average_X_day = self.getXDayMovingAverage(round, range, symbol)
        previous_moving_average_X_day = self.getXDayMovingAverage(round - 1, range, symbol)
        if current_moving_average_X_day > previous_moving_average_X_day:
            return True
        return False

    def isXDayEMARising(self, round, time_range, symbol):
        # time_range 9, 12, 26
        current_ema_X_day = self.getXDayExponentialMovingAverage(round, time_range, symbol)
        previous_ema_X_day = self.getXDayExponentialMovingAverage(round - 1, time_range, symbol)
        if current_ema_X_day > previous_ema_X_day:
            return True
        return False

    def isComparingMovingAveragesShowingStrongBuy(self, symbol, round):
        shorter_period = 5 * 24
        longer_period = 20 * 24
        if (self.isXDayMovingAverageRising(round, shorter_period, symbol) and self.isXDayMovingAverageRising(round, longer_period, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromBelow(round, shorter_period, longer_period, symbol) ):
            return True

    def isComparingEMAShowingStrongBuy(self, symbol, round):
        shorter_period_in_days = 9 # replaced by params
        longer_period_in_days = 26 # replaced by params
        if (self.isXDayEMARising(round, shorter_period_in_days, symbol) and self.isXDayEMARising(round, longer_period_in_days, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromBelowEMA(round, shorter_period_in_days, longer_period_in_days, symbol) ):
            return True

    def isComparingMovingAveragesShowingWeakBuy(self, symbol, round):
        """  if a rising lower period curve crosses from below another falling longer period curve than weak buy is indicated """
        shorter_period = 5 * 24
        longer_period = 20 * 24
        if (self.isXDayMovingAverageRising(round, shorter_period, symbol) and self.isXDayMovingAverageFalling(round, longer_period, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromBelow(round, shorter_period, longer_period, symbol) ):
            return True
        return False

    def isComparingMovingAveragesShowingWeakSell(self, symbol, round):
        shorter_period = 5 * 24
        longer_period = 20 * 24
        if (self.isXDayMovingAverageFalling(round, shorter_period, symbol) and self.isXDayMovingAverageRising(round, longer_period, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromAbove(round, shorter_period, longer_period, symbol) ):
            return True
        return False

    def hasShorterPeriodCrossedLongerPeriodFromBelow(self, round, shorter_period, longer_period, symbol):
        previous_short_period_day_moving_average = self.getXDayMovingAverage(round - 1, shorter_period, symbol)
        current_short_period_day_moving_average = self.getXDayMovingAverage(round, shorter_period, symbol)

        previous_long_period_day_moving_average = self.getXDayMovingAverage(round - 1, longer_period, symbol)
        current_long_period_day_moving_average = self.getXDayMovingAverage(round, longer_period, symbol)

        if previous_short_period_day_moving_average < previous_long_period_day_moving_average and current_short_period_day_moving_average > current_long_period_day_moving_average:
            return True
        return False

    def hasShorterPeriodCrossedLongerPeriodFromBelowEMA(self, round, shorter_period, longer_period, symbol):
        previous_short_period_day_moving_average = self.getXDayExponentialMovingAverage(round - 1, shorter_period, symbol)
        current_short_period_day_moving_average = self.getXDayExponentialMovingAverage(round, shorter_period, symbol)

        previous_long_period_day_moving_average = self.getXDayExponentialMovingAverage(round - 1, longer_period, symbol)
        current_long_period_day_moving_average = self.getXDayExponentialMovingAverage(round, longer_period, symbol)

        if previous_short_period_day_moving_average < previous_long_period_day_moving_average and current_short_period_day_moving_average > current_long_period_day_moving_average:
            return True
        return False

    def hasShorterPeriodCrossedLongerPeriodFromBelowEMA(self, round, shorter_period, longer_period, symbol):
        previous_short_period_day_moving_average = self.getXDayExponentialMovingAverage(round - 1, shorter_period, symbol)
        current_short_period_day_moving_average = self.getXDayExponentialMovingAverage(round, shorter_period, symbol)

        previous_long_period_day_moving_average = self.getXDayExponentialMovingAverage(round - 1, longer_period, symbol)
        current_long_period_day_moving_average = self.getXDayExponentialMovingAverage(round, longer_period, symbol)

        if previous_short_period_day_moving_average > previous_long_period_day_moving_average and current_short_period_day_moving_average < current_long_period_day_moving_average:
            return True
        return False

    def getXDayMovingAverage(self, round, period, symbol):
        if round < period:
            period = round
        total = 0
        for i in range(period):
            total += self.exchange_rates_data[symbol][round - i]
        return total / period

    def getXDayExponentialMovingAverage(self, round, period, symbol):
        """ using pandas ewm formula -- returns a pandas column """
        """ 9_ema_BNB/BTC, 12_ema_BNB/BTC, 26_ema_BNB/BTC """
        column_name = str(period) + "_ema_" + symbol
        return self.exchange_rates_data[column_name].iloc[round]

    def isPriceMovementShowingStrongSell(self, symbol, round, time_frame):
        _5_days_in_hours = time_frame * 24
        if self.isXDayMovingAverageFalling(round, _5_days_in_hours, symbol) and self.hasPriceCrossedFromAboveXDayMovingAverage(round, _5_days_in_hours, symbol):
            return True
        return False

    def isPriceMovementShowingStrongSellEMA(self, symbol, round, time_frame):
        if self.isXDayEMARising(round, time_frame, symbol) and self.hasPriceCrossedFromAboveXDayEMA(round, time_frame, symbol):
            return True
        return False

    def hasPriceCrossedFromAboveXDayEMA(self, round, time_range, symbol):
        # time_range: 9, 12, 26
        current_price = self.exchange_rates_data[symbol][round]
        previous_price = self.exchange_rates_data[symbol][round - 1]
        current_ema = self.getXDayExponentialMovingAverage(round, time_range, symbol)
        previous_ema = self.getXDayExponentialMovingAverage(round - 1, time_range, symbol)

        if previous_price > previous_ema and current_price < current_ema:
            return True
        return False

    def isXDayMovingAverageFalling(self, round, range, symbol):
        current_moving_average_X_day = self.getXDayMovingAverage(round, range, symbol)
        previous_moving_average_X_day = self.getXDayMovingAverage(round - 1, range, symbol)
        if current_moving_average_X_day < previous_moving_average_X_day:
            return True
        return False

    def isXDayEMAFalling(self, round, range, symbol):
        current_moving_average_X_day = self.getXDayExponentialMovingAverage(round, range, symbol)
        previous_moving_average_X_day = self.getXDayExponentialMovingAverage(round - 1, range, symbol)
        if current_moving_average_X_day < previous_moving_average_X_day:
            return True
        return False

    def hasPriceCrossedFromAboveXDayMovingAverage(self, round, range, symbol):
        current_price = self.exchange_rates_data[symbol][round]
        previous_price = self.exchange_rates_data[symbol][round - 1]
        current_moving_average = self.getXDayMovingAverage(round, range, symbol)
        previous_moving_average = self.getXDayMovingAverage(round - 1, range, symbol)

        if previous_price > previous_moving_average and current_price < current_moving_average:
            return True
        return False

    def isComparingMovingAveragesShowingStrongSell(self, symbol, round):
        shorter_period = 5 * 24
        longer_period = 20 * 24
        if (self.isXDayMovingAverageFalling(round, shorter_period, symbol) and self.isXDayMovingAverageFalling(round, longer_period, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromAbove(round, shorter_period, longer_period, symbol) ):
            return True
        return False

    def isComparingEMAShowingStrongSell(self, symbol, round):
        shorter_period = 9
        longer_period = 26
        if (self.isXDayEMAFalling(round, shorter_period, symbol) and self.isXDayEMAFalling(round, longer_period, symbol)
            and self.hasShorterPeriodCrossedLongerPeriodFromAbove(round, shorter_period, longer_period, symbol) ):
            return True
        return False

    def hasShorterPeriodCrossedLongerPeriodFromAbove(self, round, shorter_period, longer_period, symbol):
        previous_short_period_day_moving_average = self.getXDayMovingAverage(round - 1, shorter_period, symbol)
        current_short_period_day_moving_average = self.getXDayMovingAverage(round, shorter_period, symbol)

        previous_long_period_day_moving_average = self.getXDayMovingAverage(round - 1, longer_period, symbol)
        current_long_period_day_moving_average = self.getXDayMovingAverage(round, longer_period, symbol)

        if previous_short_period_day_moving_average > previous_long_period_day_moving_average and current_short_period_day_moving_average < current_long_period_day_moving_average:
            return True
        return False

class MACDStrategy(Strategy):
    """
        Follows MACD indicator
    """
    def __init__(self, strategy_name, exchange_rates_data):
        super().__init__(strategy_name, exchange_rates_data)
        self.exchange_rates_data = exchange_rates_data

    def shouldAgentCloseCurrentInvestment(self, round, symbol, agent_risk_level):
        """" Agent's strategy for when to close the position """
        # get support and the pivot points
        if agent_risk_level == "averse":
            if self.hasCrossedSignalLineFromAbove(symbol, round) or self.hasCrossedOverXAxisFromAbove(symbol, round) or self.IsThereConvergenceBetweenMACDAndPriceDownward(symbol, round):
                return True
        elif agent_risk_level == "neutral":
            if self.hasCrossedSignalLineFromAbove(symbol, round) or self.hasCrossedOverXAxisFromAbove(symbol, round):
                if self.IsThereConvergenceBetweenMACDAndPriceDownward(symbol, round):
                    return True
        elif agent_risk_level == "taker":
            if self.hasCrossedSignalLineFromAbove(symbol, round) and self.hasMACDLineHasCrossedSignalLineFromAbove and self.IsThereConvergenceBetweenMACDAndPriceDownward(symbol, round):
                return True
        return False

    def shouldAgentOpenOrderWithThisCurrencyPair(self, round, symbol, agent_risk_level):
        """
            MACD line crosses the Signal line. If it does so from below then bullish trend is indicated
            If the MACD line becomes positive (crosses from below), it is usually a bullish signal.
            A convergence pattern occurs when the MACD line's trend is the same as the price movement.
        """
        # a risk taker will
        if agent_risk_level == "taker":
            if self.hasCrossedSignalLineFromBelow(symbol, round) or self.hasCrossedOverXAxisFromBelow(symbol, round) or self.IsThereConvergenceBetweenMACDAndPriceUpward(symbol,round):
                return True
        # risk neutral will
        elif agent_risk_level == "neutral":
            if self.hasCrossedSignalLineFromBelow(symbol, round) or self.hasCrossedOverXAxisFromBelow(symbol, round):
                if self.IsThereConvergenceBetweenMACDAndPriceUpward(symbol,round):
                    return True
        # risk averse will
        elif agent_risk_level == "averse":
            if self.hasCrossedSignalLineFromBelow(symbol, round) and self.hasCrossedOverXAxisFromBelow(symbol, round) and self.IsThereConvergenceBetweenMACDAndPriceUpward(symbol,round):
                    return True
        return False

    def getXDayExponentialMovingAverage(self, round, period, symbol):
        """ using pandas ewm formula -- returns a pandas column """
        column_name = str(period) + "_ema_" + symbol
        return self.exchange_rates_data[column_name].iloc[round]

    def getMACDLine(self, symbol, round):
        EMA_12_days = self.getXDayExponentialMovingAverage(round, 12, symbol)
        EMA_26_days = self.getXDayExponentialMovingAverage(round, 26, symbol)
        return EMA_12_days - EMA_26_days

    def getSignalLine(self, symbol, round):
        return self.getXDayExponentialMovingAverage(round, 9, symbol)

    def IsThereConvergenceBetweenMACDAndPriceUpward(self, symbol, round):
        """ convergence upwards if both are rising """
        if self.isMACDLineRising(symbol, round) and self.isExchangeRateRising(symbol, round):
            return True
        return False

    def IsThereConvergenceBetweenMACDAndPriceDownward(self, symbol, round):
        """ convergence upwards if both are rising """
        if self.isMACDLineFalling(symbol, round) and self.isExchangeRateFalling(symbol, round):
            return True
        return False

    def isExchangeRateRising(self, symbol, round):
        previous_exchange_rate = self.exchange_rates_data[symbol].iloc[round - 1]
        current_exchange_rate = self.exchange_rates_data[symbol].iloc[round]
        if previous_exchange_rate < current_exchange_rate:
            return True
        return False

    def isExchangeRateFalling(self, symbol, round):
        previous_exchange_rate = self.exchange_rates_data[symbol].iloc[round - 1]
        current_exchange_rate = self.exchange_rates_data[symbol].iloc[round]
        if previous_exchange_rate > current_exchange_rate:
            return True
        return False

    def hasCrossedSignalLineFromBelow(self, symbol, round):
        if self.isMACDLineRising(symbol, round) and self.hasMACDLineHasCrossedSignalLineFromBelow(symbol, round):
            return True
        return False

    def hasCrossedSignalLineFromAbove(self, symbol, round):
        if self.isMACDLineFalling(symbol, round) and self.hasMACDLineHasCrossedSignalLineFromAbove(symbol, round):
            return True
        return False

    def isMACDLineRising(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)
        if current_MACD_line > previous_MACD_line:
            return True
        return False

    def isMACDLineFalling(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)
        if current_MACD_line < previous_MACD_line:
            return True
        return False

    def hasCrossedOverXAxisFromBelow(self, symbol, round):
        if self.isMACDLineRising(symbol, round) and self.hasMACDLineHasCrossedXAxisFromBelow(symbol, round):
            return True
        return False

    def hasCrossedOverXAxisFromAbove(self, symbol, round):
        if self.isMACDLineFalling(symbol, round) and self.hasMACDLineHasCrossedXAxisFromAbove(symbol, round):
            return True
        return False

    def hasMACDLineHasCrossedXAxisFromBelow(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)

        if previous_MACD_line < 0 and current_MACD_line > 0:
            return True
        return False

    def hasMACDLineHasCrossedXAxisFromAbove(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)

        if previous_MACD_line > 0 and current_MACD_line < 0:
            return True
        return False

    def hasMACDLineHasCrossedSignalLineFromBelow(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)
        previous_signal_line = self.getSignalLine(symbol, round - 1)
        current_signal_line = self.getSignalLine(symbol, round)

        if previous_MACD_line < previous_signal_line and current_MACD_line > current_signal_line:
            return True
        return False

    def hasMACDLineHasCrossedSignalLineFromAbove(self, symbol, round):
        previous_MACD_line = self.getMACDLine(symbol, round - 1)
        current_MACD_line = self.getMACDLine(symbol, round)
        previous_signal_line = self.getSignalLine(symbol, round - 1)
        current_signal_line = self.getSignalLine(symbol, round)

        if previous_MACD_line > previous_signal_line and current_MACD_line < current_signal_line:
            return True
        return False

class RSIStrategy(Strategy):
    """
        This use the Relative strength index as the indicator for entry and exit of the market
    """

    def __init__(self, strategy_name, exchange_rates_data):
        super().__init__(strategy_name, exchange_rates_data)
        self.exchange_rates_data = exchange_rates_data

    def shouldAgentCloseCurrentInvestment(self, round, symbol, agent_risk_level):
        """" Agent's strategy for when to close the position """

        if agent_risk_level == "averse":
            if self.hasRSICrossedOverboughtSignal(round, symbol, 40) or self.hasUpwardWeakness(round, symbol):
                return True
        elif agent_risk_level == "neutral":
            if self.hasRSICrossedOverboughtSignal(round, symbol, 30) or self.hasUpwardWeakness(round, symbol):
                return True
        elif agent_risk_level == "taker":
            if self.hasRSICrossedOverboughtSignal(round, symbol, 30):
                return True
        return False

    def shouldAgentOpenOrderWithThisCurrencyPair(self, round, symbol, agent_risk_level):
        # a risk taker will use 40-60 as threshold or look if there is downward weakness
        if agent_risk_level == "taker":
            if self.hasRSICrossedOversoldSignal(round, symbol, 40) or self.hasDownwardWeakness(round, symbol):
                return True
        # risk neutral will use 30 - 70 - TRUE and Downward weakness
        elif agent_risk_level == "neutral":
            if self.hasRSICrossedOversoldSignal(round, symbol, 30) or self.hasDownwardWeakness(round, symbol):
                return True
        # risk averse will use 30-70 and only invest if below 30
        elif agent_risk_level == "averse":
            if self.hasRSICrossedOversoldSignal(round, symbol, 30):
                return True
        return False

    def hasDownwardWeakness(self, round, symbol):
        """
            If exchange rate reaches 10 (X) day low but indicator does not
            If the price falls to a new low, but the indicator does not, that may be a sign of the downtrend weakness.
        """
        current_exchange_rate = self.exchange_rates_data[symbol].iloc[round]
        _10_days_in_hours = 10 * 24
        min_exchange_rate_past_10_days = self.exchange_rates_data[symbol].iloc[round - _10_days_in_hours:round+1].min()
        if current_exchange_rate == min_exchange_rate_past_10_days:
            current_rsi = self.getRelativeStrengthIndex(round, symbol)
            column_name = "rsi_" + symbol
            min_rsi_past_10_days = self.exchange_rates_data[column_name].iloc[round - _10_days_in_hours:round+1].min()
            if current_rsi == min_rsi_past_10_days:
                return True
        return False

    def hasRSICrossedOversoldSignal(self, round, symbol, threshold):
        """ oversold signal is indication to BUY """
        current_rsi = self.getRelativeStrengthIndex(round, symbol)
        if current_rsi == None: return False
        elif current_rsi < threshold:
            return True
        return False

    def hasUpwardWeakness(self, round, symbol):
        """
            If exchange rate reaches 10 (X) day low but indicator does not
            If the price falls to a new low, but the indicator does not, that may be a sign of the downtrend weakness.
        """
        current_exchange_rate = self.exchange_rates_data[symbol].iloc[round]
        _10_days_in_hours = 10 * 24
        max_exchange_rate_past_10_days = self.exchange_rates_data[symbol].iloc[round - _10_days_in_hours:round+1].max()
        if current_exchange_rate == max_exchange_rate_past_10_days:
            current_rsi = self.getRelativeStrengthIndex(round, symbol)
            column_name = "rsi_" + symbol
            max_rsi_past_10_days = self.exchange_rates_data[column_name].iloc[round - _10_days_in_hours:round+1].max()
            if current_rsi == max_rsi_past_10_days:
                return True
        return False

    def hasRSICrossedOverboughtSignal(self, round, symbol, threshold):
        """ overbought signal is indication to SELL """
        current_rsi = self.getRelativeStrengthIndex(round, symbol)
        if current_rsi == None: return False
        elif current_rsi > threshold:
            return True
        return False

    def getRelativeStrengthIndex(self, round, symbol):
        column_name = "rsi_" + symbol
        rsi = self.exchange_rates_data[column_name].iloc[round]
        if rsi != nan:
            return rsi
        return None


from __future__ import print_function

from builtins import str
from builtins import input
from builtins import object
from menu import Menu

from datetime import datetime

from adapter.adapter import Functions

class CLI():
    def __init__(self):
        self.db = Functions()

        self.delete_options = [
            ("delete words", self.delete_words),
            ("Quit", Menu.CLOSE)
        ]
        self.update_options = [
            ("Update all words", self.update_words),
            ("Update english word", self.update_words, {'lang': 'eng'}),
            ("Update russian word", self.update_words, {'lang': 'rus'}),
            ("Update chinese word", self.update_words, {'lang': 'cn'}),
            ("quit", Menu.CLOSE)
        ]
        self.delete_menu = Menu(
            options=self.delete_options,
            title='Delete words',
            message='',
            prompt='>',
        )
        self.update_menu = Menu(
            options=self.update_options,
            title='Update words',
            message='',
            prompt='>',
        )
        self.main_options = [
            ("Add words", self.add_words),
            ("Delete words", self.delete_menu.open),
            ("Update words", self.update_menu.open),
            ("Show dict", self.show_dictionary),
            ("Quit", Menu.CLOSE)
        ]
        self.main_menu = Menu(
            options=self.main_options,
            title='Main menu',
            message='',
            prompt='> ',
            auto_clear=True
        )

    def add_words(self):
        while True:
            eng = input("english text: ")
            if eng == 'quit':
                return
            try:
                rus = input("russian text: ")
                cn = input("chinese text: ")
                self.db.add_words(eng, rus, cn)
                return
            except Exception as err:
                print("CLI add word ERROR: " + str(err))
                input()

    def delete_words(self):
        while True:
            try:
                dictionary = self.db.get_full_dict()
                for el in dictionary:
                    print(el)
                word_id = input("input word id: ")
                if word_id == 'quit':
                    return
                word = self.db.get_words(word_id)
                self.db.delete_words(word_id)
                print('word {} deleted'.format(word))
                input()
            except Exception as err:
                print('CLI delete word ERROR: ' + str(err))
                input()

    def update_words(self, lang='all'):
        while True:
            try:
                dictionary = self.db.get_full_dict()
                for el in dictionary:
                    print(el)

                word_id = input('input word id: ')
                if word_id == 'quit':
                    return
                word = self.db.get_words(word_id)

                if not isinstance(word, dict):
                    print("there is no word with that id")
                    input()
                    return

                if lang == 'all':
                    eng = input("updated english text: ")
                    rus = input("updated russian text: ")
                    cn = input("updated chinese text: ")
                    self.db.update_words(word_id, eng, rus, cn)
                elif lang == 'eng':
                    upd_text = input("updated english text: ")
                    self.db.update_words(word_id, eng=upd_text)
                elif lang == 'rus':
                    upd_text = input("updated russian text: ")
                    self.db.update_words(word_id, rus=upd_text)
                elif lang == 'cn':
                    upd_text  = input("updated chinese text: ")
                    self.db.update_words(word_id, cn=upd_text)

                upd_word = self.db.get_words(word_id)

                word = word['word_eng'] + " " + word['word_rus'] + " " + word['word_cn']
                upd_word = upd_word['word_eng'] + " " + upd_word['word_rus'] + " " + upd_word['word_cn']

                print('\n {} \n changed to \n{}'.format(word, upd_word))
                input()
            except Exception as err:
                print('CLI update word ERROR: ' + str(err))
                input()

    def show_dictionary(self, lang='all'):
        while True:
            try:
                dictionary = self.db.get_full_dict()
                for el in dictionary:
                    print(el['word_eng'], " ", el['word_rus'], " ", el['word_cn'])

                input()
                return
            except Exception as err:
                print("CLI show dictionary Error: " + str(err))
                input()

    def run(self):
        self.main_menu.open()


# CDDL HEADER START
#
# Copyright 2016-2017 Intelerad Medical Systems Incorporated.  All
# rights reserved.
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License").  You may not use this file except in compliance
# with the License.
#
# The full text of the License is in LICENSE.txt.  See the License
# for the specific language governing permissions and limitations
# under the License.
#
# When distributing Covered Software, include this CDDL HEADER in
# each file and include LICENSE.txt.  If applicable, add the
# following below this CDDL HEADER, with the fields enclosed by
# brackets "[]" replaced with your own identifying information:
# Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END

from flarelint import rule
from flarelint import flarenode
import os

_ACCEPTED_FORMATS = ['.png', '.jpg', '.jpeg']

rule.Error(
    extensions = rule.TOPICS_AND_SNIPPETS,

    match = flarenode.whenself('img'),

    test = lambda n: os.path.splitext(n.attribute('src'))[1].lower() in _ACCEPTED_FORMATS,

    message = """Unsupported graphics format. To fix, convert this file to an
    accepted format (""" + ", ".join(["`{0}`".format(s) for s in _ACCEPTED_FORMATS]) + """),
    revise the link to the new graphics file, and delete the
    unsupported file."""
)


import os
import json
import logging
import typing
from logging import Logger
from datetime import datetime

class LogBase:
    def __init__(self, log_name:str, file_share:str, identity:str = None):
        self.file_share = file_share
        self.log_name = log_name
        self.identity = identity

    def get_logger(self) -> Logger:
        return LoggingUtils.get_logger(self.file_share, self.log_name, self.identity)

class ActivityLog:
    ACTIVITY_BASE = "activity"

    def __init__(self, file_share:str, activity_name:str, identity:str = None):
        # Set up base logger

        self.file_share = file_share
        self.activity_name = activity_name

        if identity is not None:
            if identity is not None:
                self.activity_file = "{}-{}.log".format(self.activity_name,identity)
        else:
            timestamp = datetime.now().strftime('%m%d%y')
            self.activity_file = "{}-{}.log".format(self.activity_name,timestamp)

        self.log_path = os.path.join(self.file_share, ActivityLog.ACTIVITY_BASE)
        self.activity_log_path = os.path.join(self.log_path, self.activity_file)

        self._buffer:typing.List[str] = []

    def add_activity(self, *args):
        now = datetime.utcnow()
        stamp = now.strftime("%m-%d-%Y, %H:%M:%S,%f : ")
        for arg in args:
            content = arg
            if isinstance(arg, dict) or isinstance(arg, list):
                content = json.dumps(arg, indent=4)

            self._buffer.append("{} {}".format(stamp, content))

    def dump(self):
        if not os.path.exists(self.log_path):
            os.makedirs(self.log_path)

        with open(self.activity_log_path, "w") as log:
            for activity in self._buffer:
                log.writelines("{}\n".format(activity))

class LoggingUtils:
    LOG_UTILS:typing.Dict[str, Logger] = {}
    ACTIVE_LOG_FILE = None
    LOG_BASE = "output"

    @staticmethod
    def get_logger(file_share:str, log_name:str, identity:str = None) -> Logger:

        if log_name in LoggingUtils.LOG_UTILS:
            return LoggingUtils.LOG_UTILS[log_name]

        # Set up base logger
        timestamp = datetime.now().strftime('%m%d%y')
        LOG_FILE_NAME = "dataloader-{}.log".format(timestamp)
        if identity is not None:
            LOG_FILE_NAME = "dataloader-{}.log".format(identity)

        working_directory = file_share
        if not working_directory:
            working_directory = os.getcwd()

        LOG_FILE_PATH = os.path.join(
            working_directory,
            LoggingUtils.LOG_BASE,
            LOG_FILE_NAME
        )
        LoggingUtils.ACTIVE_LOG_FILE = LOG_FILE_PATH

        os.makedirs(os.path.dirname(LOG_FILE_PATH), exist_ok=True)

        handler = logging.FileHandler(LOG_FILE_PATH)
        handler.setFormatter(logging.Formatter(
            "%(asctime)s [%(name)-14.14s] [%(levelname)-7.7s]  %(message)s"))

        logger = logging.getLogger(log_name)

        try:
            level = logging.getLevelName(os.environ.get('LOG_LEVEL', 'info').upper())
            logger.setLevel(level)
        except ValueError:
            print('Valid Log Levels are DEBUG, INFO, WARN and ERROR')
            exit(1)

        logger.addHandler(handler)

        LoggingUtils.LOG_UTILS[log_name] = logger

        return LoggingUtils.LOG_UTILS[log_name]


import json
import os
from typing import Dict
from typing import List
from typing import Optional

from git import Repo

# Global Configuration
GIT_REPO_BASE_PATH = "./repo"
AUTHOR_LICENSE_FILE = "./config/author-licenses.txt"
PSEUDONYMS_FILE = "./config/pseudonyms.txt"
EXCLUDE_DIRS = [".git"]

def _load_pseudonyms(path: str):
    cache = {}
    if os.path.exists(path):
        with open(path) as f:
            for line in f:
                module, author, email, license = line.strip().split("|")
                cache[module] = {
                    "author": author,
                    "email": email,
                    "license": license,
                }
    return cache

def _load_author_licenses(path: str):
    cache = {}
    if os.path.exists(path):
        with open(path) as f:
            for line in f:
                author, license = line.strip().split("|")
                cache[author] = license
    return cache

def _get_git_repo_path(base_path: str):
    _root, dirs, _files = next(os.walk(base_path))
    return os.path.join(base_path, dirs[0])

# Internal Configuration
_GIT_REPO_PATH = _get_git_repo_path(GIT_REPO_BASE_PATH)
_BUILT_PATH = "./build"
_BUILT_BLAME_FILE = f"{_BUILT_PATH}/blame.json"
_BUILT_HTML_FILE = f"{_BUILT_PATH}/authorship.html"
_PSEUDONYMS_CACHE = _load_pseudonyms(PSEUDONYMS_FILE)
_AUTHOR_LICENSE_CACHE = _load_author_licenses(AUTHOR_LICENSE_FILE)

repo = Repo(_GIT_REPO_PATH)

def file_blame(path: str):
    blame = repo.blame("HEAD", path, rev_opts=["-M", "-C", "-C", "-C"])
    return (
        [
            [(commit.author.name, commit.author.email), len(lines)]
            for commit, lines in blame
        ]
        if blame
        else []
    )

def folder_blame(path: str) -> Dict:
    print(f"Blaming {path}")
    root, dirs, files = next(os.walk(path))
    return {
        "files": {
            file_name: file_blame(
                os.path.join(root, file_name)[len(_GIT_REPO_PATH) + 1 :]
            )
            for file_name in files
        },
        "dirs": {
            dir_name: folder_blame(os.path.join(root, dir_name))
            for dir_name in dirs
            if dir_name not in EXCLUDE_DIRS
        },
    }

def repo_blame():
    from pathlib import Path

    if os.path.exists(_BUILT_BLAME_FILE):
        with open(_BUILT_BLAME_FILE) as f:
            return json.load(f)
    else:
        blame = folder_blame(_GIT_REPO_PATH)
        Path(_BUILT_PATH).mkdir(parents=True, exist_ok=True)
        with open(_BUILT_BLAME_FILE, "w") as f:
            json.dump(blame, f)
    return blame

#####################################

class ModuleAnalyzer:
    name: str
    parent: str
    blame: List
    submodules: List["ModuleAnalyzer"]

    def __init__(
        self, name: str, parent: str, submodules: List["ModuleAnalyzer"] = None
    ):
        self.name = name
        self.parent = parent
        self.submodules = submodules or []

    def with_blame(self, blame) -> "ModuleAnalyzer":
        self.blame = blame
        return self

    def authorship(self):
        authors = {}
        for submodule in self.submodules:
            for author, lines in submodule.authorship().items():
                authors[author] = authors.get(author, 0) + lines
        return authors

    def licensing(self):
        licenses = {}
        for submodule in self.submodules:
            for license, lines in submodule.licensing().items():
                licenses[license] = licenses.get(license, 0) + lines
        return licenses

    def flatten(self):
        flat = [self]
        for submodule in self.submodules:
            flat += submodule.flatten()
        return flat

class FileModuleAnalyzer(ModuleAnalyzer):
    def authorship(self):
        NAME = 0  # list idx
        authors = {}
        for author, lines in self.blame:
            name = self.__author_override() or author[NAME]
            authors[name] = authors.get(name, 0) + lines
        return authors

    def __author_override(self) -> Optional[str]:
        for override_path, override in _PSEUDONYMS_CACHE.items():
            if override_path in self.name:
                return override["author"]
        return None

    def licensing(self):
        NAME = 0  # list idx
        licenses = {}
        for author, lines in self.blame:
            license = self.__license_override() or _AUTHOR_LICENSE_CACHE.get(
                author[NAME], "???"
            )
            licenses[license] = licenses.get(license, 0) + lines
        return licenses

    def __license_override(self) -> Optional[str]:
        # Note, uses the first matching entry.
        # Consider using the longest matching entry instead.
        for override_path, override in _PSEUDONYMS_CACHE.items():
            if override_path in self.name:
                return override["license"]
        return None

def raw_blame_to_module_analyzer(
    module_name: str, parent_name: str, raw_blame: Dict[str, Dict]
) -> ModuleAnalyzer:
    return ModuleAnalyzer(
        module_name,
        parent_name,
        [
            *[
                FileModuleAnalyzer(
                    f"{module_name}/{file_name}", module_name
                ).with_blame(blame)
                for file_name, blame in raw_blame["files"].items()
            ],
            *[
                raw_blame_to_module_analyzer(
                    f"{module_name}/{dirname}", module_name, dirblame
                )
                for dirname, dirblame in raw_blame["dirs"].items()
            ],
        ],
    )

#####################################

blame = repo_blame()
analyzer = raw_blame_to_module_analyzer(_GIT_REPO_PATH, "", blame)
stats = analyzer.authorship()
print(stats)

#####################################

import plotly.graph_objects as go

modules = analyzer.flatten()
ids = [module.name for module in modules]
labels = [i.split("/")[-1] for i in ids]
parents = [module.parent for module in modules]
values = [sum(module.authorship().values()) for module in modules]

def authorship_str(module: ModuleAnalyzer) -> str:
    authors = module.authorship()
    return "
Authors:
 - " + "
 - ".join(
        f"{author}: {lines}" for author, lines in authors.items()
    )

def licensing_str(module: ModuleAnalyzer) -> str:
    licenses = module.licensing()
    return "
Licenses:
 - " + "
 - ".join(
        f"{license}: {lines}" for license, lines in licenses.items()
    )

def info_str(module: ModuleAnalyzer) -> str:
    return f"{authorship_str(module)}
{licensing_str(module)}"

fig = go.Figure(
    go.Treemap(
        ids=ids,
        labels=labels,
        parents=parents,
        values=values,
        maxdepth=3,
        branchvalues="total",
        text=[info_str(module) for module in modules],
        hovertemplate="%{label}

%{value} lines
%{text}",
        root_color="lightgrey",
    )
)

fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))
fig.write_html(_BUILT_HTML_FILE)


from six.moves.urllib.parse import urljoin, urlsplit, urlunsplit

from pywb.rewrite.wburl import WbUrl
from pywb.rewrite.cookie_rewriter import get_cookie_rewriter

#=================================================================
class UrlRewriter(object):
    """
    Main pywb UrlRewriter which rewrites absolute and relative urls
    to be relative to the current page, as specified via a WbUrl
    instance and an optional full path prefix
    """

    NO_REWRITE_URI_PREFIX = ('#', 'javascript:', 'data:',
                             'mailto:', 'about:', 'file:', '{')

    PROTOCOLS = ('http:', 'https:', 'ftp:', 'mms:', 'rtsp:', 'wais:')

    REL_SCHEME = ('//', r'\/\/', r'\\/\\/')

    PARENT_PATH = '../'
    REL_PATH = '/'

    def __init__(self, wburl, prefix='', full_prefix=None, rel_prefix=None,
                 root_path=None, cookie_scope=None, rewrite_opts=None, pywb_static_prefix=None):
        self.wburl = wburl if isinstance(wburl, WbUrl) else WbUrl(wburl)
        self.prefix = prefix
        self.full_prefix = full_prefix or prefix
        self.rel_prefix = rel_prefix or prefix
        self.root_path = root_path or '/'
        if self.full_prefix and self.full_prefix.startswith(self.PROTOCOLS):
            self.prefix_scheme = self.full_prefix.split(':')[0]
        else:
            self.prefix_scheme = None
        self.prefix_abs = self.prefix and self.prefix.startswith(self.PROTOCOLS)
        self.cookie_scope = cookie_scope
        self.rewrite_opts = rewrite_opts or {}
        self._pywb_static_prefix = pywb_static_prefix

        if self.rewrite_opts.get('punycode_links'):
            self.wburl._do_percent_encode = False

    @property
    def pywb_static_prefix(self):
        """Returns the static path URL
        :rtype: str
        """
        if self._pywb_static_prefix is None:
            return ''
        if self._pywb_static_prefix.startswith(self.PROTOCOLS):
            return self._pywb_static_prefix
        return self.urljoin(self.full_prefix, self._pywb_static_prefix)

    def rewrite(self, url, mod=None, force_abs=False):
        # if special protocol, no rewriting at all
        if url.startswith(self.NO_REWRITE_URI_PREFIX):
            return url

        if (self.prefix and
             self.prefix != '/' and
             url.startswith(self.prefix)):
            return url

        if (self.full_prefix and
             self.full_prefix != self.prefix and
             url.startswith(self.full_prefix)):
            return url

        wburl = self.wburl

        is_abs = url.startswith(self.PROTOCOLS)

        scheme_rel = False
        if url.startswith(self.REL_SCHEME):
            is_abs = True
            scheme_rel = True
        elif (not force_abs and not is_abs and
              not url.startswith(self.REL_PATH) and
              self.PARENT_PATH not in url):
            return url

            # if prefix starts with a scheme
            #if self.prefix_scheme:
            #    url = self.prefix_scheme + ':' + url
            #url = 'http:' + url

        # optimize: join if not absolute url, otherwise just use as is
        if not is_abs:
            new_url = self.urljoin(wburl.url, url)
        else:
            new_url = url

        if mod is None:
            mod = wburl.mod

        final_url = self.prefix + wburl.to_str(mod=mod, url=new_url)

        if not is_abs and self.prefix_abs and not self.rewrite_opts.get('no_match_rel'):
            parts = final_url.split('/', 3)
            final_url = '/'
            if len(parts) == 4:
                final_url += parts[3]

        # experiment for setting scheme rel url
        elif scheme_rel and self.prefix_abs:
            final_url = final_url.split(':', 1)[1]

        return final_url

    def get_new_url(self, **kwargs):
        return self.prefix + self.wburl.to_str(**kwargs)

    def rebase_rewriter(self, base_url):
        if not base_url.startswith(self.PROTOCOLS):
            base_url = self.urljoin(self.wburl.url, base_url)

        new_wburl_str = self.wburl.to_str(url=base_url)
        new_wburl = WbUrl(new_wburl_str)

        return self._create_rebased_rewriter(new_wburl, self.prefix)

    def _create_rebased_rewriter(self, new_wburl, prefix):
        return UrlRewriter(new_wburl, prefix)

    def get_cookie_rewriter(self, scope=None):
        # collection scope overrides rule scope?
        if self.cookie_scope:
            scope = self.cookie_scope

        cls = get_cookie_rewriter(scope)
        return cls(self)

    def deprefix_url(self):
        return self.wburl.deprefix_url(self.full_prefix)

    def __repr__(self):
        return "UrlRewriter('{0}', '{1}')".format(self.wburl, self.prefix)

    @staticmethod
    def urljoin(orig_url, url):  # pragma: no cover
        new_url = urljoin(orig_url, url)
        if '../' not in new_url:
            return new_url

        # only needed in py2 as py3 urljoin resolves '../'
        parts = urlsplit(new_url)
        scheme, netloc, path, query, frag = parts

        path_parts = path.split('/')
        i = 0
        n = len(path_parts) - 1
        while i < n:
            if path_parts[i] == '..':
                del path_parts[i]
                n -= 1
                if i > 0:
                    del path_parts[i - 1]
                    n -= 1
                    i -= 1
            else:
                i += 1

        if path_parts == ['']:
            path = '/'
        else:
            path = '/'.join(path_parts)

        parts = (scheme, netloc, path, query, frag)

        new_url = urlunsplit(parts)
        return new_url

#=================================================================
class IdentityUrlRewriter(UrlRewriter):
    """
    No rewriting performed, return original url
    """
    def rewrite(self, url, mod=None, force_abs=False):
        return url

    def get_new_url(self, **kwargs):
        return kwargs.get('url', self.wburl.url)

    def rebase_rewriter(self, new_url):
        return self

    def get_cookie_rewriter(self, scope=None):
        return None

    def deprefix_url(self):
        return self.wburl.url

#=================================================================
class SchemeOnlyUrlRewriter(IdentityUrlRewriter):
    """
    A url rewriter which ensures that any urls have the same
    scheme (http or https) as the base url.
    Other urls/input is unchanged.
    """

    def __init__(self, *args, **kwargs):
        super(SchemeOnlyUrlRewriter, self).__init__(*args, **kwargs)
        self.url_scheme = self.wburl.url.split(':')[0]
        if self.url_scheme == 'https':
            self.opposite_scheme = 'http'
        else:
            self.opposite_scheme = 'https'

    def rewrite(self, url, mod=None, force_abs=False):
        if url.startswith(self.opposite_scheme + '://'):
            url = self.url_scheme + url[len(self.opposite_scheme):]

        return url


# -*- coding: utf-8 -*-
"""
Created on Thu Jan 13 12:26:21 2022

@author: annas

This script identifies the number and name of genes with
all gene expressions equal to 0 in the data set GSE80655.
The gene names are written to a file called genes_zero_expression.txt"""

def identify_zeros(infile):
    gene_names = []
    num_genes = 0
    for line in infile: #Read lines in file
        line_split = line.rstrip().split('\t')
        not_zero = True
        first_element = True
        #Check each element in the line and investigate if all elements are equal to 0
        for el in line_split:
            if first_element:
                first_element = False
                gene_name = el
                continue
            if float(el) != 0:
                not_zero = True
                break
            else:
                not_zero = False
        #If all elements in the line are 0, register this gene
        if not_zero == False:
            num_genes += 1
            gene_names.append(gene_name)

    print("Number of genes with all expression values equal to", 0, "is", num_genes)

    return gene_names

if __name__ == '__main__':
    #Open files
    infile1 = open("almost_CSD_bipolar_disorder_GSE80655.txt") #open file
    infile2 = open("almost_CSD_control_GSE80655.txt") #open file
    next(infile1) #skip header
    next(infile2) #skip header

    #Identify genes with all gene expression values equal to 0
    gene_names1 = set(identify_zeros(infile1))
    gene_names2 = set(identify_zeros(infile2))

    #Find total number of genes were all gene expression values are equal to 0 in at least one condition
    common_genes = gene_names1.union(gene_names2)

    #Display the findings
    for el in common_genes:
        print(el)

    print("Total number of genes where all expression values are 0:", len(common_genes))

	#Close the files
    infile1.close()
    infile2.close()

    #Write the gene names to file
    outfile = open("genes_zero_expression_GSE80655.txt", 'w')
    for gene in common_genes:
        outfile.write(gene + "\n")

    outfile.close()


# -*- coding: utf-8 -*-
#!/usr/bin/env python3
'''
Created on Wed Jan 16 17:50:59 CST 2019
@Mail: minnglee@163.com
@Author: Ming Li
'''

import sys,os,logging,click

logging.basicConfig(filename=os.path.basename(__file__).replace('.py','.log'),
                    format='%(asctime)s: %(name)s: %(levelname)s: %(message)s',level=logging.DEBUG,filemode='w')
logging.info(f"The command line is:\n\tpython3 {' '.join(sys.argv)}")

def Rename(name):
    return f'{name.split(":")[0]}#{name.split(":")[1].replace("-","#")}'
def LoadFasta(File):
    Dict = {}
    seq = ''
    for line in File:
        line = line.strip()
        if line[0] == '>':
            if len(seq) > 0:
                Dict[name] = seq
            name = Rename(line.split()[0][1:])
            seq = ''
        else: seq += line
    Dict[name] = seq
    return Dict
@click.command()
@click.option('-i','--input',type=click.File('r'),help='The input file',required=True)
@click.option('-l','--length',type=int,help='the min length of seqence',default=500)
@click.option('-o','--output',type=click.File('w'),help='The output file',required=True)
def main(input,length,output):
    FaDict = LoadFasta(input)
    for key,value in FaDict.items():
        Gap = value.upper().count('N')
        if len(value) - Gap < length : continue
        while value[0].upper() == "N": value = value[1:]
        while value[-1].upper() == "N": value = value[:-1]
        output.write(f'>{key}\n{value}\n')
if __name__ == '__main__':
    main()


import pyrealsense2 as rs

def main():
    # Inicializa el dispositivo RealSense
    pipeline = rs.pipeline()
    config = rs.config()
    config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
    config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
    pipeline.start(config)

    # Obtiene la profundidad y la imagen RGB
    depth_frame = pipeline.wait_for_frames().get_depth_frame()
    color_frame = pipeline.wait_for_frames().get_color_frame()

    # Ajusta la densidad de puntos al máximo
    config.depth_points_density = rs.config.DepthPointsDensity.MAXIMUM

    # Transmite la imagen de profundidad en tiempo real
    depth_image = np.asanyarray(depth_frame.get_data())
    cv2.imshow("Depth", depth_image)
    cv2.waitKey(1)

    # Transmite la imagen RGB en tiempo real
    color_image = np.asanyarray(color_frame.get_data())
    cv2.imshow("Color", color_image)
    cv2.waitKey(1)

    # Detiene el dispositivo RealSense
    pipeline.stop()

if __name__ == "__main__":
    main()


# 正規方程式
import numpy as np
import matplotlib.pyplot as plt

# 架空のデータセットの用意
# データは正規分布に従って生成
N = 100
mean1 = [1, 3]  # クラス1の平均
mean2 = [3, 1]  # クラス2の平均
cov = [[2.0,0.0], [0.0, 0.1]]  # 共分散行列（2クラス共通)
class_1 = np.random.multivariate_normal(mean1, cov, N//2)
class_2 = np.random.multivariate_normal(mean2, cov, N//2)
bias_x = np.ones((N, 1))
t_1 = np.ones(N//2)
t_2 = np.ones(N//2) * (-1)

# はじめてのパターン認識(P75)通りに変数を指定, 正規方程式からパラメータwを計算
X = np.concatenate((class_1, class_2))
X = np.concatenate((bias_x, X), axis=1)
t = np.concatenate((t_1, t_2)).reshape(N, 1)
w = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), t)

# 求めたパラメータから直線を引く
w0, w1, w2 = w[0], w[1], w[2]
x = np.arange(start=-4, stop=10)
y = (((-1) * w1)/w2)*x + ((-1) * w0)/w2

plt.scatter(class_1[:, 0], class_1[:, 1], marker='o', color='red')
plt.scatter(class_2[:, 0], class_2[:, 1], marker='o', color='blue')
plt.plot(x, y)
plt.show()


from gensim import corpora, models
from glob import glob
from operator import itemgetter
from scipy.sparse.csgraph import connected_components
from statistics import mean
import fasttext
import hdbscan
import collections
import umap
import os
import sys
import csv
import string
import codecs
import re
import time
import MeCab
import pandas as pd
import numpy as np

#MeCab tokenizer
def mecab_tokenizer(tx, sw):
    token_list = []
    tagger = MeCab.Tagger('/usr/local/lib/mecab/dic/mecab-ipadic-neologd')

    tagger.parse('')
    node = tagger.parseToNode(tx)
    while node:
        if not node.surface in sw:
            pos = node.feature.split(",")
            if not pos[0] in ["記号"]:
                token_list.append(node.surface)
        node = node.next
    return list(token_list)

#Feature-word extractor
def fword_extractor(num, docs):
    fword = docs[0][0]
    for c in range(num+1):
        if not c == 0:
            fword = fword + '|' + docs[c][0]
    return fword

#FastText vectorizer
def ft_vectorizer(tx, bsn):
    model_path = "02_models/cc.ja.300.bin"
    if not os.path.exists(model_path):
        model_txt_path = "02_models/" + bsn + "_ft_corpus" + ".txt"
        model_alt_path = "02_models/" + bsn + "_ft_corpus" + ".bin"
        with open(model_txt_path, 'w', encoding="utf_8") as f:
            text_corpus = ""
            for t in tx:
                text_corpus = " ".join(map(str, t))
                f.write(text_corpus+"\n")
        print("New FastText model was created at " + model_alt_path)
        model = fasttext.train_unsupervised(model_txt_path, model='cbow', dim=300)
        #model.save_model(model_alt_path)
    else:
        print("Pre-trained model " + model_path + " is used.")
        model = fasttext.load_model(model_path)

    ft_vec = np.zeros((df.shape[0], 300))
    #Prepairing an empty list for the model coverage rate
    coverage = []
    #Caluculating the average value of the vector of words by a document
    for i,doc in enumerate(tx):
        feature_vec = np.zeros(300) #Initializing the 300-dimension vector data to 0
        num_words = 0
        no_count = 0
        for word in doc:
            try:
                feature_vec += model[str(word)]
                num_words += 1
            except:
                no_count += 1
        feature_vec = feature_vec / num_words
        ft_vec[i] = feature_vec
        #Caluculating the word coverage rate of the model by each document
        cover_rate = num_words / (num_words + no_count)
        coverage.append(cover_rate)
    #Print overall word coverage rate of the model
    mean_coverage = round(mean(coverage)*100, 2)
    print("Word cover-rate: " + str(mean_coverage) + "%")
    return ft_vec

os.makedirs("01_dataset", exist_ok=True)
os.makedirs("02_models", exist_ok=True)
os.makedirs("03_processing", exist_ok=True)

#Open the input-data and store it into DataFrame
docs_file = input('Input a document-list file (.csv) in 01_dataset >> ')
docs_path = "01_dataset/" + str(docs_file)
if os.path.exists(docs_path):
    with codecs.open(docs_path, 'r', 'utf-8', 'ignore') as f:
        #df = pd.read_csv(f, delimiter='\t')
        df = pd.read_csv(f)
    base_name = os.path.splitext(os.path.basename(docs_file))[0] #The file name without the extension
else:
    print('Processing was cancelled due to an invalid input. Please enter a correct file name')
    sys.exit()

#Open stopword list
stops_file = input('Input a stopword-list file (.txt) in 02_models >> ')
stops_path = "02_models/" + str(stops_file)
if os.path.exists(stops_path):
    with codecs.open(stops_path, 'r', 'utf-8', 'ignore') as f:
        stopwords = f.read().splitlines()
else:
    print('The stopword file is not found. This process continues without stopwords.')
    stopwords = []

#Target column
df['text'] = df['description'].astype(str)
#Tokenizer
text_tokenizer = mecab_tokenizer

print("Input data size : " + str(len(df)))

#Remove https-links
df['text_clean'] = df.text.map(lambda x: re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+', "", x))
#Remove numerals
df['text_clean'] = df.text_clean.map(lambda x: re.sub(r'\d+', '', x))
#Remove symbols
df['text_clean'] = df.text_clean.map(lambda x: re.sub(r'[「」。、,（）%#\$&\?\(\)~\.=\+\-\[\]\{\}\|\*]+', '', x))
#Remove specific noises (optional)
df['text_clean'] = df.text_clean.map(lambda x: re.sub(r'○.{0,20}　', ' ', x))
#Creating DataFrame for Token-list
df['text_tokens'] = df.text_clean.map(lambda x: text_tokenizer(x, stopwords))

#Creating dictionary and corpus
texts = df['text_tokens'].values
dictionary = corpora.Dictionary(texts)
dictionary.filter_extremes(no_below=3, no_above=0.4)
corpus = [dictionary.doc2bow(text) for text in texts]

#Feature words extraction by tf-idf (option: min_df, max_df)
tfidf_model = models.TfidfModel(corpus, id2word=dictionary.token2id, normalize=False)
tfidf_corpus = list(tfidf_model[corpus])

method_name = "FT" #For the output file name
doc_vec = ft_vectorizer(df['text_tokens'], base_name)

tfidf_texts = []
for doc in tfidf_corpus:
    tfidf_text = []
    for word in doc:
        tfidf_text.append([dictionary[word[0]], word[1]])
        tfidf_text_sort = sorted(tfidf_text, reverse=True, key=itemgetter(1))
    tfidf_texts.append(tfidf_text_sort)

num_fword = 4 #Set the number of displayed feature words
fword_list = []
for i in range(len(tfidf_texts)):
    if len(tfidf_texts[i]) > num_fword-1:
        fword = fword_extractor(num_fword-1, tfidf_texts[i])
    else:
        fword = fword_extractor(len(tfidf_texts[i])-1, tfidf_texts[i])
    fword_list.append(fword)

#Storing in DataFrame
embedding_u = umap.UMAP(min_dist=0.1, n_neighbors=50, metric='euclidean', spread=1.0, init='spectral').fit_transform(doc_vec)
embedding = pd.DataFrame(embedding_u, columns=['x', 'y'])
embedding['uid'] = df['ID']
embedding['keywords'] = fword_list
embedding['size'] = df['size']
embedding['title'] = df['title']
embedding['date'] = df['date']
embedding['author'] = df['author']
embedding['affiliation'] = df['affiliation']
embedding['description'] = df['description']

x_coord = embedding_u[:, 0]
y_coord = embedding_u[:, 1]

#Clustering
clst_input = input('Input the number for min-size of a cluster (default=100) >> ')
try:
    clusters = int(clst_input)
except:
    clusters = 100 #set default value
    print("The number of cluster was set to 100, due to an invalid input")

type_input = input('Input type of clustering - eom:1 or leaf:2 >> ')
if type_input == "1":
    type_c = 'eom'
elif type_input == "2":
    type_c = 'leaf'
else:
    type_c = 'leaf'
    print("Type of the clustering is set to leaf due to an invalid input.")

clustering = hdbscan.HDBSCAN(cluster_selection_method=type_c, min_cluster_size=clusters, min_samples=10) #The lower the value, the less noise you’ll get
log_method = "HDBSCAN (minimum size of clusters: " + str(clusters) + " )"

log_list = []
label_list = []
log_list.append(log_method)

#Extract only XY coordinates from DataFrame for the clustering calculation
df_xy = embedding.loc[:, ['x', 'y']]

#Convert XY coordicates into numpy array
X = df_xy.to_numpy()
log_doc = "Documents : " + str(X.shape[0])
log_list.append(log_doc)
print(log_doc)

#Execution of clustering (using scikit-learn based modules)
clustering.fit(X)

#Store the label data
labels = clustering.labels_
num_labels = len(set(labels)) - (1 if -1 in labels else 0)
outliers = list(labels).count(-1)
log_label = "labels : " + str(num_labels) + ", outliers : " + str(outliers)
log_list.append(log_label)
print(log_label)

#Create DataFrame of ID and Label No
embedding_L1 = pd.DataFrame()
embedding_L1["id"] = df['ID']
embedding_L1["keywords"] = fword_list
embedding_L1["X"] = x_coord
embedding_L1["Y"] = y_coord
embedding_L1["label"] = labels

#Feature words extraction
num = 0
log_head = "area_id" + '\t' + "documents" + '\t' + "keywords" + '\t' + "X" + '\t' + "Y" + '\t' + "label"
log_list.append(log_head)
label_list.append(log_head)
while num < num_labels:
    f_list = []
    embedding_L2 = embedding_L1.query("label == @num")
    fwords = np.array(embedding_L2['keywords'])
    s = fwords.T

    for i in s:
        try:
            l = [x.strip() for x in i.split('|')]
            f_list.extend(l)
        except:
            pass

    c = collections.Counter(f_list)
    top_c = c.most_common(40)[0:39]
    doc_n = len(embedding_L2)
    x_mean = embedding_L2["X"].mean()
    y_mean = embedding_L2["Y"].mean()

    try:
        l_key1 = top_c[0][0] + "/" + top_c[1][0] + "/" + top_c[2][0]
        l_key2 = [k for k, v in top_c[3:] if v / doc_n > 0.4 and v / doc_n < 0.65]
        if len(l_key2) > 0:
            l_keys = l_key1 + "/" + l_key2[0]
        else:
            l_keys = l_key1
    except:
        l_keys = "-"

    log_fwords = str(num) + "\t" + str(doc_n) + "\t" + str(top_c) + "\t" + str(round(x_mean, 4)) + "\t" + str(round(y_mean, 4)) + "\t" + str(l_keys) #log the feature words of areas
    log_list.append(log_fwords)
    label_list.append(log_fwords)
    print(log_fwords)
    num += 1

#export the result
embedding.to_csv("03_processing/" + base_name + "_by" + method_name + ".csv", encoding="utf_8", index=False)

log_file = "log_" + str(num_labels) + ".txt"
with open("03_processing/" + base_name + "_by" + method_name + "_" + log_file, 'w', encoding="utf_8") as t:
    t.write("\n".join(log_list))

label_name = "label_" + str(num_labels) + ".tsv"
with open("03_processing/" + base_name + "_by" + method_name + "_" + label_name, 'w', encoding="utf_8") as t:
    t.write("\n".join(label_list))

print("Completed.")


import torch

import numpy
import pprint
import matplotlib.pyplot as plt

if __name__ == "__main__":
    checkpoint = torch.load("loss_log_original_3x.pt")

    x=checkpoint.numpy()

    epochs=[]
    loss=[]
    rows=x.shape[0]
    columns=x.shape[1]
    print(x.shape)
    for i in range(rows):
        for j in range(columns):

            epochs.insert(i,i)
            loss.insert(i,x[i][j])

    checkpoint1 = torch.load("loss_log_2_blocks_customized_3x.pt")
    print("enter")
    x1=checkpoint1.numpy()

    epochs1=[]
    loss1=[]
    rows1=x1.shape[0]
    columns1=x1.shape[1]
    for l in range(rows):
        for m in range(columns):

            epochs1.insert(l,l)
            loss1.insert(l,x1[l][m])

    plt.plot(epochs,loss,label = "original 3x",linestyle="-")
    plt.plot(epochs1,loss1,label = "model 7 3x " ,linestyle="-.")
    plt.title('Loss curves')
    plt.xlabel('epochs')
    plt.ylabel('loss')
    plt.legend()
    plt.show()


import re
import os
import pytesseract
from PIL import Image
from tqdm import tqdm

pytesseract.pytesseract.tesseract_cmd = (
    r"/usr/local/Cellar/tesseract/5.1.0/bin/tesseract"
)
directory = ""

def preprocess_text(text):
    text = text.lower().strip()
    text = re.sub(re.escape("\n"), " ", text)
    return text

def main():
    print("Loading images...")
    file_strings = dict()
    images_paths = [os.path.join(directory, file) for file in os.listdir(directory) if os.fsdecode(file).endswith(".png")]
    for file_path in tqdm(images_paths):
            file_string = pytesseract.image_to_string(file_path)
            file_string = preprocess_text(file_string)
            file_strings[file_path] = file_string
    print("Images loaded.")
    print()

    while True:
        print("Introduce phrase:")
        text = input()
        print("")
        print("searching...")
        text = preprocess_text(text)
        files = [
            file_path
            for file_path, image_text in file_strings.items()
            if text in image_text
        ]
        for file in files:
            img = Image.open(file)
            img.show()
        print("DONE")
        print("")

if __name__ == "__main__":
    main()


import numpy as np

# 游戏环境
from gridworld import GridworldEnv

class policy_iteration:
    def __init__(self, env, theta=0.01, discount_factor=.8, policy=None):
        self.env = env
        self.theta = theta
        self.discount_factor = discount_factor

        if policy:
            self.policy = policy
        else:
            self.policy = self.__random_policy__()

    def __random_policy__(self):
        policy = np.zeros((self.env.nS, self.env.nA))
        for s in range(self.env.nS):
            random_action = np.random.randint(0, self.env.nA)
            policy[s, random_action] = 1.0
        return policy

    def evalue_policy(self):
        '''
        !!! Policy Evaluation !!! 从policy得到state value function
        :return: state value function
        '''
        V = np.zeros(self.env.nS)
        while True:
            # delta = 0
            pre_v = np.copy(V)
            for s in range(self.env.nS):
                res = 0
                for a in range(self.env.nA):
                    for prob, next_state, reward, done in self.env.P[s][a]:
                        res += self.policy[s][a] * prob * (reward + self.discount_factor * V[next_state])
                V[s] = res
            if np.sum(np.fabs(pre_v - V)) < self.theta:
                return V

    def __calc_q_table__(self, V):
        '''
        从state value function 中得到q table
        :param V:
        :return:
        '''
        q_table = np.zeros((self.env.nS, self.env.nA))

        for s in range(self.env.nS):
            for a in range(self.env.nA):
                res = 0
                for prob, next_state, reward, done in env.P[s][a]:
                    res += prob * (reward + self.discount_factor * V[next_state])
                q_table[s][a] = res

        return q_table

    def update_policy(self, V):
        '''
        得到最优的policy
        :param V:
        :return:
        '''
        changed = False  # policy是否发生变化
        q_table = self.__calc_q_table__(V)

        for s in range(self.env.nS):
            best_action = np.argmax(q_table[s][:])

            # 原先的action
            old_action = np.argmax(self.policy[s][:])
            self.policy[s, old_action] = 0
            self.policy[s, best_action] = 1

            if old_action != best_action:
                changed = True

        return changed

    def get_best_policy(self):
        '''
        寻找最优的policy
        :return:
        '''
        max_iteration = 20000
        for ite in range(max_iteration):
            V = self.evalue_policy()
            changed = self.update_policy(V)
            if not changed:
                print("converged at {} steps".format(ite))
                return self.policy
        return self.policy

env = GridworldEnv()
pi = policy_iteration(env)

policy = pi.get_best_policy()

print("Policy Probability Distribution:")
print(policy)
print("")

print("Reshaped Grid Policy (0=up, 1=right, 2=down, 3=left):")
print(np.reshape(np.argmax(policy, axis=1), env.shape))
print("")


from typing import Optional
from fastapi import APIRouter, Depends, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession

from .dao import LandmarkDAO
from .service import DatabaseManager
from .schemas import LandmarkCreate, LandmarkBase, Landmark, LandmarkId
from ..database import get_async_session

router = APIRouter()

@router.post("/create_landmark/", response_model=Landmark)
async def create_landmark(
    request: Request,
    landmark_data: LandmarkCreate,
    token: str,
    db: AsyncSession = Depends(get_async_session),
) -> Landmark:
    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    if token:
        return await landmark_crud.create_landmark(token=token, request=request, landmark=landmark_data)

@router.post("/get_landmark/", response_model=Landmark)
async def get_landmark(
    landmark_data: LandmarkId,
    db: AsyncSession = Depends(get_async_session),
) -> Landmark:
    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    return await landmark_crud.get_existing_landmark(id=landmark_data.id)

# Получение списка всех пользователей
@router.get("/read_all_landmarks")
async def get_all_landmarks(
    offset: int = 0,
    limit: int = 10,
    db: AsyncSession = Depends(get_async_session),
):
    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    return await landmark_crud.get_all_landmarks(offset=offset, limit=limit)

@router.delete("/delete_landmark")
async def delete_landmark(
    id: str = None,
    title: str = None,
    address: str = None,
    db: AsyncSession = Depends(get_async_session),
):

    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    await landmark_crud.delete_landmark(id=id, title=title, address=address)

    return {"message": "Deleting successful"}

@router.post("/add_to_favorite")
async def add_to_favorite(
    request: Request,
    landmark_id: LandmarkId,
    token: str,
    db: AsyncSession = Depends(get_async_session),
):

    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    return await landmark_crud.add_to_favorite(token=token, request=request, landmark_data=landmark_id.id)

@router.post("/remove_from_favorite")
async def remove_from_favorite(
    request: Request,
    landmark_id: LandmarkId,
    token: str,
    db: AsyncSession = Depends(get_async_session),
):

    db_manager = DatabaseManager(db)
    landmark_crud = db_manager.landmark_crud

    return await landmark_crud.remove_from_favorite(token=token, request=request, landmark_data=landmark_id.id)


a=int(input())
b=list(map(int,input().split()))
b.append(b[-1])
c=[b[0]]

for i in range(1,a):
    c.append(min(b[i],b[i-1]))

ans=sum(c)
print(ans)


"""Resources related with fractals.

Refs:
 - https://realpython.com/mandelbrot-set-python/
"""

from dataclasses import dataclass
import math
from typing import Union

import numpy as np
import matplotlib.pyplot as plt

def mandelbrot_sequence(c):
    """Returns generator of the Mandelbrot sequence given C"""
    z = 0
    while True:
        yield z
        z = z**2 + c

def julia_sequence(c, z=0):
    """Returns generator of a Julia sequence given C and Z!=0

    Note: if Z=0 then Julia_seq==Mandelbrot_seq
    """
    while True:
        yield z
        z = z**2 + c

def mandelbrot_sequence_index(n, c):
    """Returns the n-th value of the Mandelbrot sequence given C"""
    if n == 0:
        return 0
    else:
        return mandelbrot_sequence_index(n - 1, c) ** 2 + c

def pixel_matrix(pixel_density, xmin=-2, xmax=0.5, ymin=-1.5, ymax=1.5):
    """Generate a matrix for plotting Mandelbrot/Julia sets.

    Args:
     - pixel_density: Number of pixels per unit
    """
    re = np.linspace(xmin, xmax, int((xmax - xmin) * pixel_density))
    im = np.linspace(ymin, ymax, int((ymax - ymin) * pixel_density))
    return re[np.newaxis, :] + im[:, np.newaxis] * 1j

def is_mandelbrot_elem(c, num_iterations):
    """Returns if a value is stable (relatively small) and is element of Mandelbrot set"""
    z = 0
    for _ in range(num_iterations):
        z = z**2 + c
    return abs(z) <= 2

def mask_pixel_matrix(c, num_iterations):
    """Return pixel_matrix with bool elements indicating if pixel is Mandelbrot elem"""
    mask = is_mandelbrot_elem(c, num_iterations)
    return c[mask]

def plot_mandelbrot_ori(pixel_density=21):
    """Plot replica of first ever visualization of Mandelbrot set"""

    c = pixel_matrix(pixel_density=pixel_density)
    members = mask_pixel_matrix(c, num_iterations=20)

    plt.scatter(members.real, members.imag, color="black", marker=",", s=1)
    plt.gca().set_aspect("equal")
    plt.axis("off")
    plt.tight_layout()
    plt.show()

def plot_mandelbrot(pixel_density=512):
    """Plot Mandelbrot set"""
    c = pixel_matrix(pixel_density=pixel_density)

    plt.imshow(is_mandelbrot_elem(c, num_iterations=20), cmap="binary")
    plt.gca().set_aspect("equal")
    plt.axis("off")
    plt.tight_layout()
    plt.show()

@dataclass
class MandelbrotSet:
    """Encapsulates the logic to compute if a value is element of Mandelbrot set.

    Optionally return a value between 0 and 1 if the approximation is not enough.
    """

    max_iterations: int
    escape_radius: float = 2.0

    def __contains__(self, c: complex) -> bool:
        return self.stability(c) == 1

    def stability(self, c: complex, smooth=False, clamp=True) -> float:
        value = self.escape_count(c, smooth) / self.max_iterations
        return max(0.0, min(value, 1.0)) if clamp else value

    def escape_count(self, c: complex, smooth=False) -> Union[int, float]:
        z = 0
        for iteration in range(self.max_iterations):
            z = z**2 + c
            if abs(z) > self.escape_radius:
                if smooth:
                    return iteration + 1 - math.log(math.log(abs(z))) / math.log(2)
                return iteration
        return self.max_iterations


def bubble_sort(a):
    '''
    Complexity O(n^2) in all cases
    '''
    n = len(a) - 1
    for i in range(n):
        for j in range(0, n - i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]

if __name__ == "__main__":
    a = [8,5,3,1,9,6,0,7,4,2,5]
    print('unsorted:', a)
    bubble_sort(a)
    print('sorted:', a)


from tkinter import *

# CONSTANTS
CANVAS_PADDING = 10

# VARIABLES
current_input = ""
full_calculation = []

# NUMBER TYPING
def number_clicked(number):
    global current_input
    current_input += str(number)
    update_display()

# CLEAR INPUTS
def handle_ac_button():
    global current_input, full_calculation
    current_input = ""
    full_calculation = []
    last_calc_canvas.delete("all")
    update_display()

# OPERATIONS

# PLUS BUTTON
def handle_plus_button():
    global current_input, full_calculation
    full_calculation.append(current_input)
    full_calculation.append("+")
    current_input = ""
    update_display()

# MINUS BUTTON
def handle_minus_button():
    global current_input, full_calculation
    full_calculation.append(current_input)
    full_calculation.append("-")
    current_input = ""
    update_display()

# MULTIPLY BUTTON
def handle_mul_button():
    global current_input, full_calculation
    full_calculation.append(current_input)
    full_calculation.append("*")
    current_input = ""
    update_display()

# DIVISION BUTTON
def handle_div_button():
    global current_input, full_calculation
    full_calculation.append(current_input)
    full_calculation.append("/")
    current_input = ""
    update_display()

# MODULUS BUTTON
def handle_mod_button():
    global current_input, full_calculation
    full_calculation.append(current_input)
    full_calculation.append("%")
    current_input = ""
    update_display()

# DECIMAL BUTTON
def handle_dec_button():
    global current_input

    if "." not in current_input:
        current_input += "."
        update_display()

# POSITIVE/NEGATIVE BUTTON
def handle_pos_neg_button():
    global current_input

    if not current_input:
        return

    if current_input[0] == "-":
        current_input = current_input[1:]
    else:
        current_input = "-" + current_input

    update_display()

# CALCULATE/EQUAL BUTTON FUNCTIONS
def handle_equal_button():
    global current_input, full_calculation

    full_calculation.append(current_input)

    calculation_str = "".join(full_calculation)
    calculation_str = calculation_str.replace("x", "*")

    try:
        result = eval(calculation_str)
        if isinstance(result, float):
            if result.is_integer():
                result = int(result)
            else:
                result = round(result, 10)
    except Exception as e:
        result = "Error"

    last_calc_display = calculation_str.replace("*", "x")
    last_calc_canvas.delete("all")
    last_calc_canvas.create_text(
        200 - CANVAS_PADDING,
        75 - CANVAS_PADDING,
        text=last_calc_display,
        anchor="se",
        font=("TkDefaultFont", 14),
        fill="white",
    )

    full_calculation = []
    current_input = str(result)

    update_display()

# UPDATE DISPLAY
def update_display():
    global current_input, full_calculation
    display_text = "".join(full_calculation) + current_input
    display_text = display_text.replace("*", "x")
    font_size = dynamic_font_size(display_text)
    result_canvas.delete("all")
    result_canvas.create_text(
        200 - CANVAS_PADDING,
        75 - CANVAS_PADDING,
        text=display_text,
        anchor="se",
        font=("TkDefaultFont", font_size),
        fill="white",
    )

# ADJUST FONT SIZES DYNAMICALLY
def dynamic_font_size(display_text):
    size_mapping = {7: 32, 8: 28, 9: 24, 10: 20, 11: 18, 12: 16, 13: 14}
    default_size = 10

    for length, size in size_mapping.items():
        if len(display_text) <= length:
            return size
    return default_size

# UI SETUP
# Layout inspired by Maciej on Dribbble:
# https://dribbble.com/shots/17536429-Calculator-DailyUI

window = Tk()
window.title("EasyCalc")
window.config(padx=25, pady=25, bg="#7f8c8d")

# CANVAS AREAS
last_calc_canvas = Canvas(width=200, height=75, highlightthickness=0, bg="#34495e")
last_calc_canvas.create_text(
    200 - CANVAS_PADDING,
    75 - CANVAS_PADDING,
    text="",
    anchor="se",
    font=("TkDefaultFont", 14),
    fill="white",
)
last_calc_canvas.grid(column=0, row=0, columnspan=4, rowspan=2)

result_canvas = Canvas(width=200, height=75, highlightthickness=0, bg="#2c3e50")
result_canvas.create_text(
    200 - CANVAS_PADDING,
    75 - CANVAS_PADDING,
    text="",
    anchor="se",
    font=("TkDefaultFont", 32),
    fill="white",
)
result_canvas.grid(column=0, row=2, columnspan=4, rowspan=2)

# OPERATION/SPECIAL BUTTONS
ac_button = Button(
    text="AC", width=2, command=handle_ac_button, bg="#2980b9", borderwidth=0
)
ac_button.grid(column=0, row=5, sticky="EW")

pos_neg_button = Button(
    text="±", width=2, command=handle_pos_neg_button, bg="#2980b9", borderwidth=0
)
pos_neg_button.grid(column=1, row=5, sticky="EW")

mod_button = Button(
    text="%", width=2, command=handle_mod_button, bg="#2980b9", borderwidth=0
)
mod_button.grid(column=2, row=5, sticky="EW")

div_button = Button(
    text="÷", width=2, command=handle_div_button, bg="#3498db", borderwidth=0
)
div_button.grid(column=3, row=5, sticky="EW")

mul_button = Button(text="x", command=handle_mul_button, bg="#3498db", borderwidth=0)
mul_button.grid(column=3, row=6, sticky="EW")

minus_button = Button(
    text="-", command=handle_minus_button, bg="#3498db", borderwidth=0
)
minus_button.grid(column=3, row=7, sticky="EW")

plus_button = Button(text="+", command=handle_plus_button, bg="#3498db", borderwidth=0)
plus_button.grid(column=3, row=8, sticky="EW")

dec_button = Button(text=".", command=handle_dec_button, bg="#2980b9", borderwidth=0)
dec_button.grid(column=1, row=9, sticky="EW")

equal_button = Button(
    text="=", command=handle_equal_button, bg="#9b59b6", borderwidth=0
)
equal_button.grid(column=2, row=9, columnspan=2, sticky="EW")

# NUMBER BUTTONS
zero_button = Button(
    text="0", command=lambda: number_clicked(0), bg="#bdc3c7", borderwidth=0
)
zero_button.grid(column=0, row=9, sticky="EW")

one_button = Button(
    text="1", command=lambda: number_clicked(1), bg="#bdc3c7", borderwidth=0
)
one_button.grid(column=0, row=8, sticky="EW")

two_button = Button(
    text="2", command=lambda: number_clicked(2), bg="#bdc3c7", borderwidth=0
)
two_button.grid(column=1, row=8, sticky="EW")

three_button = Button(
    text="3", command=lambda: number_clicked(3), bg="#bdc3c7", borderwidth=0
)
three_button.grid(column=2, row=8, sticky="EW")

four_button = Button(
    text="4", command=lambda: number_clicked(4), bg="#bdc3c7", borderwidth=0
)
four_button.grid(column=0, row=7, sticky="EW")

five_button = Button(
    text="5", command=lambda: number_clicked(5), bg="#bdc3c7", borderwidth=0
)
five_button.grid(column=1, row=7, sticky="EW")

six_button = Button(
    text="6", command=lambda: number_clicked(6), bg="#bdc3c7", borderwidth=0
)
six_button.grid(column=2, row=7, sticky="EW")

seven_button = Button(
    text="7", command=lambda: number_clicked(7), bg="#bdc3c7", borderwidth=0
)
seven_button.grid(column=0, row=6, sticky="EW")

eight_button = Button(
    text="8", command=lambda: number_clicked(8), bg="#bdc3c7", borderwidth=0
)
eight_button.grid(column=1, row=6, sticky="EW")

nine_button = Button(
    text="9", command=lambda: number_clicked(9), bg="#bdc3c7", borderwidth=0
)
nine_button.grid(column=2, row=6, sticky="EW")

window.mainloop()


import heapq as hq
# é criada a lista de prioridade, com o indice de prioridade e o valor
list_func = [(4, 'F(N) = 2 ^ N'), (1, 'H(N) = Nlog(N)'), (3, 'S(N) = N ^ log(N)'), (2, 'G(N) = N ^ 3/2')]
# heapify transforma a lista em uma lista de prioridade, ordenando ela conforme o indice de cada elemento
hq.heapify(list_func)

print('The order of presentation is: ')
# a lista é impressa na ordem de prioridade
for i in list_func:
    print(i[0], ':', i[1])