# from PIL import Image
from functions import load_data, get_df, get_month, get_day, get_percentage, get_df_pv

import streamlit as st
import plotly.express as px

def main():

    # load data
    df = load_data()
    # obtain objects from data
    cc_names, df_minmax, col_pv = get_df(df)

    # Streamlit web
    st.set_page_config(layout="wide")

    # # Cryptocurrency image
    # row_0_spacer_1, row_0, row_0_spacer_2 = st.columns((0.1,1,0.1))
    # cc_image = Image.open('bitcoin.jpg')
    # with row_0:
    #     st.image(cc_image)
    # #''' image here'''

    # ROW 1: introduction
    row_1_spacer_1, row_1, row_1_spacer_2 = st.columns((0.1, 1, 0.1))

    row_1.title(
        ":currency_exchange:Data Analysis: Historical Price of 23 Crypto-currencies"
    )

    row_1.subheader(
        """This App aims to provide various form of visualization, charts, graphs, and tables for you to analyze 23 crypto-currencies on the market. Some are well known to all, such as Bitcoin and Dogecoin, some are only popular among enthusiasts. Whether you are familiar with crypto-currencies or not, have fun with this simple dashboard!"""
    )

    row_1.markdown(
        """:star2: For all charts, you are able to zoom in/out, and focus on a range of dates of your interest:star2:"""
    )

    row_1.write(
        """:chart: Check the data source [here](https://www.kaggle.com/sudalairajkumar/cryptocurrencypricehistory):chart:"""
    )
    row_1.write(
        """:notebook_with_decorative_cover: Check Data Wrangling Notebook [here](https://nbviewer.org/github/honghusldl/cryptocurrency-dashboard/blob/main/preprocessing/data_wrangling.ipynb):notebook_with_decorative_cover:"""
    )
    # divider
    row_1.markdown("---")

    # ROW 2: Life span table
    row_2_spacer_1, row_2_1, row_2_2, row_2_spacer_2 = st.columns((0.3, 1.7, 1.3, 0.3))

    with row_2_1:
        st.subheader("Life Span")

        st.write(
            ":bar_chart:Each crypto-currency has distinct life span. Here you can discover the life span for each currency"
        )

        fig_bar_lifespan = st.plotly_chart(
            px.bar(
                data_frame=df_minmax,
                x=df_minmax.index,
                y="Duration",
                color=df_minmax.index,
                title="Duration on Market by Currency",
                hover_data=["First Day", "Last Day"],
                height=650,
                width=850,
                labels={"Duration": "Duration on Market in Days"},
                text="Duration",
            )
            .update_traces(textposition="outside")
            .update_layout(showlegend=False)
        )

    with row_2_2:
        st.write("")
        st.dataframe(data=df_minmax, height=1000)
        st.write(":warning:The data source was update on 2021-7-6")

    st.write("---")

    # ROW 3: overview line chart market cap

    row_3_spacer_1, row_3_1, row_3_2, row_3_spacer_2 = st.columns((0.5, 4, 1, 0.5))
    with row_3_2:
        st.subheader(":book:Capitalpedia")
        st.markdown(
            ":ledger:***Market Capitalization*** is the total market value of the shares outstanding of a publicly traded cryptocurrency."
        )
        st.markdown(
            ":ledger:It is equal to **share price** times **number of shares outstanding**."
        )
        st.markdown(
            ":ledger:Market capitalization is one of the metrics to reflect the value of a cryptocurrency. It is even more useful for investors to understand the whole picture of a specific cryptocurrency since it leverages both volume and price. "
        )
        st.markdown(
            ":ledger:Cryptocurrencies are categorized into three classes based on their market capitalization"
        )
        st.markdown(
            ":one:Large-cap cryptocurrencies: with over $10 billion market cap. Lower risks for investors."
        )
        st.markdown(
            ":two:Mid-cap cryptocurrencies: with $1 to $10 billion market cap. Great growth potential but high risks."
        )
        st.markdown(
            ":three:Small-cap cryptocurrencies: with less than $1 billion market cap. High risks due to massive volatility.([Reference](https://www.coinbase.com/learn/crypto-basics/what-is-market-cap))"
        )

    with row_3_1:
        st.subheader("Overview: Market Capitalization")
        fig_line_cap = st.plotly_chart(
            px.line(
                data_frame=df,
                x="Date",
                y="Market_Capitalization",
                color="Name",
                width=1100,
                height=600,
                labels={
                    "Market_Capitalization": "Market Cap in USD",
                    "Volume": "Traded Volume",
                },
                template="seaborn",
            )
            .add_vline(x="2017-01-01", line_width=3, line_dash="dot", line_color="red")
            .add_annotation(
                x="2017-01-01",
                y=max(df["Market_Capitalization"]) * 0.85,
                text="'Cryptocurrency Fever' Began",
            )
            .update_layout(showlegend=False)
        )

        st.markdown(""":bookmark:**PC Component Market**:bookmark:""")
        st.markdown(
            """After cryptocurrency went in vogue in the middle of 2017, well-prepared mining companies and the enthusiasm among the general public causes destructive fluctuation on market.
      People have been forced to pay more than twice amount of money to hunt for a GPU. Majority of PC components rises in price due to shortage in supply. Used mining GPU are placed on market with a unresonable price.
      There are more and more disturbing the PC component market, especially GPU. """
        )

    st.markdown("---")
    row_4_spacer_1, row_4_1, row_4_2, row_4_3, row_4_spacer_2 = st.columns(
        (0.5, 1, 3, 1, 0.5)
    )
    with row_4_1:
        st.markdown(":point_down:Choose Your Day of Interest")
        # get year, month, day for pie chart
        y = list(range(2017, 2022))
        year = st.selectbox("Select Year", options=y)
        m = get_month(year)
        month = st.selectbox("Select Month", options=m)
        d = get_day(year, month)
        day = st.selectbox("Select Day", options=d)

        st.write(":bookmark:Dates range from 2017-1-1 to 2021-7-6.")

    with row_4_2:
        st.write(
            "Due to limit of space, full information about percentages of market cap are showed via table :point_right: "
        )
        st.write(
            "Percentage of Market Capitalization by Currency on a specific date after 2017 when the 'Fever' begun"
        )
        target_date = f"{year}-{month}-{day}"
        fig_pie_cap = st.plotly_chart(
            px.pie(
                data_frame=df.query(f"Date == '{target_date}'"),
                values="Market_Capitalization",
                names="Name",
                height=550,
            ).update_traces(textposition="inside", textinfo="percent+label")
        )

        st.markdown(
            "Higher percentage indicates that a cryptocurrency has higher total market value and stand strong in the crypto market. **However, as the line graph shown, market capitalization of a cryptocurrency could evaporate drastically due to market sentiment, societal responses and even governmental intervention.**"
        )

    with row_4_3:
        df_percentage = df.query(f"Date == '{target_date}'")
        df_cap_percentage = get_percentage(df_percentage)
        st.dataframe(data=df_cap_percentage, height=1000)

    st.write("---")

    row_5_spacer_1, row_5_1, row_5_spacer_2 = st.columns((0.2, 1, 0.2))
    # get df for analyzing price and volume
    df_pv = get_df_pv(df)

    with row_5_1:
        st.subheader("Price & Volume")
        st.write(
            "Price and volume are two important metrics reflecting the value of a cryptocurrency. Compared to market capitalization, they depict a cryptocurrency from different angles."
        )
        st.markdown(
            ":chart_with_upwards_trend:**Explore Opening price, Closing Price, Daily Highest and Lowest Price by selecting name of your interest.**"
        )

    row_6_spacer_1, box1, box2, box3, row_6_spacer_2 = st.columns((0.6, 1, 1, 1, 0.6))
    with box1:
        currency_name = st.selectbox("Select Cryptocurrency", options=cc_names)
    with box2:
        price_type_line = st.selectbox("Select type of price (Line)", options=col_pv)
    with box3:
        price_type_bar = st.selectbox("Select type of price (Bar)", options=col_pv)

    row_7_spacer_1, row_7_1, row_7_spacer_2 = st.columns((0.2, 1, 0.2))
    with row_7_1:
        df_query = df_pv.query("Name == @currency_name")
        fig_line_price = st.plotly_chart(
            px.line(
                data_frame=df_pv.query("Name == @currency_name"),
                x="Date",
                y=price_type_line,
                labels={
                    "High": "Highest Price in USD",
                    "Low": "Lowest Price in USD",
                    "Open": "Opening Price in USD",
                    "Close": "Closing Price in USD",
                },
                height=500,
                width=1100,
            )
            .add_bar(
                x=df_query["Date"], y=df_query[price_type_bar], name=price_type_bar
            )
            .update_layout(showlegend=False)
        )
        st.markdown(
            ":chart_with_upwards_trend:**Explore Volume by specifiying the date.**"
        )

    row_8_spacer_1, box4, box5, box6, row_8_spacer_2 = st.columns((0.6, 1, 1, 1, 0.6))
    with box4:
        y2 = list(range(2017, 2022))
        year2 = st.selectbox("Select Year:", options=y2)
    with box5:
        m2 = get_month(year2)
        month2 = st.selectbox("Select Month:", options=m2)
    with box6:
        d2 = get_day(year2, month2)
        day2 = st.selectbox("Select Day:", options=d2)
    row_8_spacer_1, row_8_1, row_8_2, row_8_spacer_2 = st.columns((0.6, 2, 1, 0.6))
    with row_8_1:
        target_date2 = f"{year2}-{month2}-{day2}"
        fig_bubble_volume = st.plotly_chart(
            px.scatter(
                data_frame=df_pv.query(f"Date == '{target_date2}'"),
                x="Close",
                y="Market_Capitalization",
                labels={
                    "Close": "Closing Price",
                    "Market_Capitalization": "Market Capitalization",
                },
                size="Volume",
                color="Name",
                log_x=True,
                log_y=True,
                width=750,
                height=500,
            )
        )
    with row_8_2:
        st.markdown(
            ":warning:Note: The chart is applied with log transformation on both X and Y axis."
        )
        st.markdown(
            ":books:Volume reflects activity or intensity of a cryptocurrency. In general, large volume indicates large number of participants in trading."
        )
        st.markdown(
            ":books:Since volume reflects activity, it might reveal the characteristics of a cryptocurrency. For instance, Bitcoin requires high-end PC specification to solve math problems in blockchain, which makes Bitcoin finite in amount and time-comsuming. Thus, Bitcoin has higher value and attracts more participants on the market, resulting in larger volume."
        )
        st.markdown(
            ":books:Volume fluctuates at various stages, and it is not necessarily correlated with price."
        )
        st.markdown(
            ":books:As mentioned earlier, volume and price together are able to reveal the market's trend, hotspot and so on. Let's discover more about volume and price below!"
        )

    row_9_spacer_1, row_9_1, row_9_2, row_9_3, row_9_spacer_2 = st.columns(
        (0.6, 1, 1, 1, 0.6)
    )
    with row_9_1:
        st.markdown(
            ":chart_with_upwards_trend:**Explore Closing price and Volume Trend.**"
        )
        currency_name_pv = st.selectbox("Select Cryptocurrency:", options=cc_names)

    row_10_spacer_1, row_10_1, row_10_2, row_10_spacer_2 = st.columns((0.8, 3, 1, 0.8))
    with row_10_1:
        df_query2 = df_pv.query("Name == @currency_name_pv")
        fig_line_volume_price = st.plotly_chart(
            px.line(
                data_frame=df_query2.melt(
                    id_vars=["Name", "Date", "High", "Open", "Low"]
                ),
                x="Date",
                y="value",
                color="variable",
                height=500,
                width=1000,
                log_y=True,
            )
        )

if __name__ == "__main__":
    main()


# Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
# Find a group of numbers of any length that returns the largest sum
# max_subarray([-2,1,-3,4,-1,2,1,-5,4]) // 6
# max_subarray([5,4,-1,7,8]) // 23
# max_subarray([1]) // 1
# max_subarray([]) // return null
# max_subarray({}) // return null

def max_subarray(list):
    # set max current and max global as first index
    max_current = list[0]
    max_global = list[0]
    # loop throught list
    # Starting from index of 1
    for i in range(1, len(list)):
    # if the current element is greater than the current element plus max current, set max current to current element else, set it to the current element plus max current
        max_current = max(list[i], list[i] + max_current)
    # if the maxcurrent is greater than max global, set max global to max current
        if max_current > max_global:
            max_global = max_current
    # return max global
    return max_global

# print(max_subarray([5, 4, -1, 7, 8]))
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))
if 15 % 3 == 0:
    print('Fizz')


def ackermann(m,n,identation = None):
    if identation is None:
        identation = 0
    print('%sackermann(%s, %s)' % (' ' * identation, m, n))
    if m == 0:
        return n+1
    elif m>0 and n == 0:
        return ackermann(m-1,1,identation + 1)
    elif m>0 and n >0:
        return ackermann(m-1,ackermann(m-1,1,identation+1),identation+1)
print(ackermann(1,1))


# conding=utf-8
# author = 'pengben 2020-5-26'
import os
import time
import shutil

def mkSubFile(lines, head, srcName, sub):
    [des_filename, extname] = os.path.splitext(srcName)
    filename = des_filename + '_' + str(sub) + extname
    print('make file: %s' % filename)
    fout = open(filename, 'w')
    try:
        fout.writelines([head])
        fout.writelines(lines)
        return sub + 1
    finally:
        fout.close()

def splitByLineCount(filename, count):
    fin = open(filename, 'r')
    try:
        head = fin.readline()
        buf = []
        sub = 1
        for line in fin:
            buf.append(line)
            if len(buf) == count:
                sub = mkSubFile(buf, head, filename, sub)
                buf = []
        if len(buf) != 0:
            sub = mkSubFile(buf, head, filename, sub)
    finally:
        fin.close()

if __name__ == '__main__':
    begin = time.time()
    splitByLineCount('E:\Breakfile\log.htm', 100000)
    end = time.time()
    print('time is %d seconds ' % (end - begin))

def objFileName():
    # list.txt记录截取目标文件列表
    fileNameList = r"E:\Breakfile\list.txt"
    objNameList = []

    for i in open(fileNameList, 'r'):
        objNameList.append(i.replace('\n', ''))
        return objNameList

def copyFile():
    # 指定文件原始路径
    sourcePath = r'E:\Breakfile'

    # 指定文件存放目录
    targetPath = r'E:\rsyncdata'

    for i in objFileName():
        objName = i
        shutil.copy(sourcePath + '/' + objName, targetPath + '/' + objName)

if __name__ == '__main__':
    copyFile()


#Embedded file name: localizationBSD/wrappers\message.py
from . import AuthoringValidationError
from .. import const as localizationBSDConst
from ..util import GetNumericLanguageIDFromLanguageID
import bsdWrappers
import bsd
import dbutil
import re
from localization.const import LOCALE_SHORT_ENGLISH
import utillib as util
import messageText as locMessageText
import wordMetaData as locWordMetaData
import wordType as locWordType

class Message(bsdWrappers.BaseWrapper):
    """
    A wrapper object for messages, where a message is composed of a label identifier, and one or more strings (one string per supported language).
    This class also handles operations on Metadata.
    """
    __primaryTable__ = bsdWrappers.RegisterTable(localizationBSDConst.MESSAGES_TABLE)
    _messageTextTable = None
    _propertyTable = None
    _bsdSvc = None
    _APPEND_NEW = '(new)'

    def GetLabelPath(self, projectID = None):
        """
        Generate path to this label as it'll appear in export/pickle file(s).
        NOTE: This is primarily used in UI/Content Browser to show the user how the paths would look like.
              This function doesnt actually care whether this message was tagged with the projectID or not.
        parameters:
            projectID - optional parameter. When specified will use Project's working directory when rendering
                        final path string
        returns:
            a path string, of the form: u'/UI/Generic/Buttons/Cancel'
        """
        from messageGroup import MessageGroup
        labelPath = '' if self.label is None else self.label
        if self.groupID is not None:
            folderPath = MessageGroup.Get(self.groupID).GetFolderPath(projectID=projectID)
            if folderPath and labelPath:
                labelPath = '/'.join((folderPath, labelPath))
            elif folderPath:
                labelPath = folderPath
        return labelPath

    def GetOpenedBy(self):
        """
        Aggregates bsd state information across all components of a message (label, texts for each language, and metadata for each language),
        and returns it in human-readable form.
        """
        openedBy = [self._GetOpenedBy(self)]
        for messageText in locMessageText.MessageText.GetWithFilter(messageID=self.messageID):
            openedBy += [self._GetOpenedBy(messageText)]

        for metadata in locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID):
            openedBy += [self._GetOpenedBy(metadata)]

        openedBy = '\n'.join([ text for text in openedBy if text ])
        return openedBy

    def _GetOpenedBy(self, bsdWrapper):
        """
        Get a nicely formatted message describing who is editing any rows that make up this wrapper.
        Because a message is composed of multiple wrappers, we create a fancier string including the wrapper name.
        """
        openedBy = ''
        openedByUserIDs = bsdWrapper.GetOpenedByUserIDs()
        bsdState = bsdWrapper.GetState()
        if bsdState & dbutil.BSDSTATE_OPENFORADD != 0:
            openedBy += bsdWrapper.__class__.__name__ + ' added by '
        elif bsdState & dbutil.BSDSTATE_OPENFORDELETE != 0:
            openedBy += bsdWrapper.__class__.__name__ + ' marked for delete by '
        elif bsdState & dbutil.BSDSTATE_OPENFOREDIT != 0:
            openedBy += bsdWrapper.__class__.__name__ + ' opened for edit by '
        elif openedByUserIDs:
            openedBy += bsdWrapper.__class__.__name__ + ' opened in unknown state by '
        if not openedBy:
            return openedBy
        openedBy += ', '.join((bsdWrapper.cache.Row(const.cacheStaticUsers, userID).userName for userID in openedByUserIDs))
        return openedBy

    def Copy(self, groupID, newLabel = None):
        """
        Copy the current message into groupID with the new Label. All metadata will be copied as well.
        parameters:
            groupID  - destination group. The message label needs to be unique in the destination group.
                       The group's wordType also needs to be the same as the message wordTypeID.
            newLabel - if set, the message's label will be changed to this new label
        pre-req:
            This method must not be ran within Transaction
        exceptions:
            Will throw various exceptions on unsuccessful Copy.
        returns:
            New row of the copied message
        """
        Message._ErrorIfInTransaction('Message Copy will not run within Transaction.')
        copyLabel = newLabel or self.label
        if not Message.CheckIfLabelUnique(copyLabel, groupID):
            raise AuthoringValidationError('Label (%s) is not unique.' % copyLabel)
        messageCopy = Message.Create(copyLabel, groupID, text=self.GetTextEntry(LOCALE_SHORT_ENGLISH).text, context=self.context)
        englishText = messageCopy.GetTextEntry(LOCALE_SHORT_ENGLISH)
        originalEnglishText = self.GetTextEntry(LOCALE_SHORT_ENGLISH)
        originalTexts = self.messageTextTable.GetRows(messageID=self.messageID, _getDeleted=False)
        for aText in originalTexts:
            if aText.numericLanguageID != localizationBSDConst.LOCALE_ID_ENGLISH:
                newSourceDataID = englishText.dataID if originalEnglishText.dataID == aText.sourceDataID else None
                self.messageTextTable.AddRow(messageCopy.messageID, aText.numericLanguageID, sourceDataID=newSourceDataID, text=aText.text, statusID=aText.statusID)

        locWordMetaData.WordMetaData._CopyAllMetaDataToNewMessage(sourceMessageID=self.messageID, destMessageID=messageCopy.messageID, destinationWordTypeID=messageCopy.wordTypeID)
        return messageCopy

    def ResetWordType(self):
        """
        Change the wordTypeID of this message to None. This operation will remove all metadata belonging to
        this message.
        NOTE: This code is bsd transaction friendly.
        """
        if self.wordTypeID is not None:
            with bsd.BsdTransaction():
                self._DeleteMetaData()
                bsdWrappers.BaseWrapper.__setattr__(self, 'wordTypeID', None)

    def GetAllMetaDataEntries(self, languageID):
        """
        Return all metadata entries for this language
        returns:
            list of metadata row objects
        """
        metaDataForLanguage = []
        dbLanguageID = GetNumericLanguageIDFromLanguageID(languageID)
        propertyTable = self.__class__._propertyTable
        allMetaData = locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID)
        for metaEntry in allMetaData:
            propertyRow = propertyTable.GetRowByKey(metaEntry.wordPropertyID)
            if propertyRow and propertyRow.numericLanguageID == dbLanguageID:
                metaDataForLanguage.append(metaEntry)

        return metaDataForLanguage

    def GetMetaDataEntry(self, wordPropertyID):
        """
        Return metadata for the specified property.
        returns:
            metadata row object if found, None if property or metadata isnt found
        """
        metaDataRows = locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID, wordPropertyID=wordPropertyID)
        if metaDataRows and len(metaDataRows):
            return metaDataRows[0]
        else:
            return None

    def GetMetaDataEntryByName(self, propertyName, languageID):
        """
        Return metadata for the specified property / language.
        returns:
            metadata row object if found, None if property or metadata isnt found
        """
        propertyRows = self.__class__._propertyTable.GetRows(wordTypeID=self.wordTypeID, propertyName=propertyName, numericLanguageID=GetNumericLanguageIDFromLanguageID(languageID), _getDeleted=False)
        if propertyRows and len(propertyRows) != 1:
            return None
        else:
            metaDataRows = locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID, wordPropertyID=propertyRows[0].wordPropertyID)
            if metaDataRows and len(metaDataRows):
                return metaDataRows[0]
            return None

    def AddMetaDataEntry(self, wordPropertyID, metaDataValue, transactionBundle = None):
        """
        Add new metadata entry to this message. Will throw an error if the metadata entry already exists.
        NOTE: This code is bsd transaction friendly.
        parameters:
            wordPropertyID    - unique identifier for the property
            metaDataValue     - metadata string
            transactionBundle - cache containing entries of messages to be added within transaction.
                                It is required for validations within transactions. See CreateMessageDataBundle()
        """
        if self.wordTypeID == None:
            raise AuthoringValidationError('Before adding metadata, the wordType needs to be set on this messageID (%s).' % str(self.messageID))
        with bsd.BsdTransaction():
            locWordMetaData.WordMetaData.TransactionAwareCreate(wordPropertyID, self.messageID, metaDataValue, transactionBundle=transactionBundle)

    def AddMetaDataEntryByName(self, propertyName, languageID, metaDataValue, transactionBundle = None):
        """
        Add new metadata entry to this message. Will throw an error if the metadata entry already exists.
        NOTE: This code is bsd transaction friendly.
        parameters:
            propertyName      - name of the property
            languageID        - id for the language. For example "en-us"
            metaDataValue     - metadata string
            transactionBundle - cache containing entries of messages to be added within transaction.
                                It is required for validations within transactions. See CreateMessageDataBundle()
        """
        if self.wordTypeID == None:
            raise AuthoringValidationError('Before adding metadata, the wordType needs to be set on this messageID (%s).' % str(self.messageID))
        typeRow = locWordType.WordType.Get(self.wordTypeID)
        if typeRow == None:
            raise AuthoringValidationError('WordTypeID (%s), of this message, does not exist.' % self.wordTypeID)
        typeName = typeRow.typeName
        with bsd.BsdTransaction():
            locWordMetaData.WordMetaData.TransactionAwareCreateFromPropertyName(typeName, propertyName, languageID, self.messageID, metaDataValue, transactionBundle)

    def GetTextEntry(self, languageID):
        """
        Returns text row for the language specified
        returns:
            text row or None if none found
        """
        return locMessageText.MessageText.Get(self.messageID, languageID)

    def AddTextEntry(self, languageID, text):
        """
        Add text entry for the language, if one doesnt exist
        NOTE: This code is bsd transaction friendly.
        """
        textRow = locMessageText.MessageText.Get(self.messageID, languageID)
        if textRow == None:
            locMessageText.MessageText.Create(self.messageID, languageID, text=text)
        else:
            raise AuthoringValidationError('Can not add duplicate text entry. messageID,languageID : (%s, %s)' % (str(self.messageID), languageID))

    def GetState(self):
        """
        Aggregates bsd state information across all components of a message (label, texts for each language, and metadata for each language)
        """
        bsdState = super(Message, self).GetState()
        for messageText in locMessageText.MessageText.GetWithFilter(messageID=self.messageID):
            bsdState |= messageText.GetState()

        for metadata in locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID):
            bsdState |= metadata.GetState()

        return bsdState

    def GetWordCount(self, languageID = 'en-us', includeMetadata = True):
        """
        Does a naive word count of the message text in the given language (splitting on spaces).
        By default, includes the number of words in all metadata entries, where present.
        """
        textEntry = self.GetTextEntry(languageID)
        if not textEntry:
            return 0
        count = len([ part for part in re.findall('\\w*', textEntry.text or '') if part ])
        if includeMetadata:
            metadataEntries = self.GetAllMetaDataEntries(languageID)
            for metadata in metadataEntries:
                if metadata.metaDataValue:
                    count += len([ part for part in re.findall('\\w*', metadata.metaDataValue or '') if part ])

        return count

    def __init__(self, row):
        bsdWrappers.BaseWrapper.__init__(self, row)
        self.__class__.CheckAndSetCache()
        self.messageTextTable = self.__class__._messageTextTable

    def __setattr__(self, key, value):
        if key == localizationBSDConst.COLUMN_LABEL:
            if not Message.CheckIfLabelUnique(value, self.groupID):
                raise AuthoringValidationError('Label can not be set to non-unique name (%s).' % str(value))
        if key == localizationBSDConst.COLUMN_TYPE_ID:
            if self.wordTypeID is not None:
                raise AuthoringValidationError('Not allowed to edit wordTypeID on the message that may contain metadata. Use ResetWordType().')
            elif locWordType.WordType.Get(value) is None:
                raise AuthoringValidationError('WordTypeID (%s) does not exist.' % str(value))
        bsdWrappers.BaseWrapper.__setattr__(self, key, value)

    def _DeleteChildren(self):
        with bsd.BsdTransaction('Deleting message: %s' % self.label):
            self._DeleteText()
            self._DeleteMetaData()
        return True

    def _DeleteText(self):
        for messageText in locMessageText.MessageText.GetMessageTextsByMessageID(self.messageID):
            if not messageText.Delete():
                raise AuthoringValidationError('Message (%s) wrapper was unable to delete text entry.' % self.messageID)

    def _DeleteMetaData(self):
        for metaData in locWordMetaData.WordMetaData.GetWithFilter(messageID=self.messageID):
            if not metaData.Delete():
                raise AuthoringValidationError('Message (%s) wrapper was unable to metadata entry.' % self.messageID)

    @classmethod
    def Get(cls, messageID):
        return bsdWrappers._TryGetObjByKey(cls, messageID, _getDeleted=False)

    @classmethod
    def CheckAndSetCache(cls):
        """
        Reset cache on the class.
        """
        if cls._messageTextTable is None or cls._propertyTable is None:
            bsdTableSvc = sm.GetService('bsdTable')
            cls._messageTextTable = bsdTableSvc.GetTable(localizationBSDConst.MESSAGE_TEXTS_TABLE)
            cls._propertyTable = bsdTableSvc.GetTable(localizationBSDConst.WORD_PROPERTIES_TABLE)
            cls._bsdSvc = sm.GetService('BSD')

    @classmethod
    def Create(cls, label, groupID = None, text = '', context = None):
        """
        Creates a new message label, and a blank English string by default.
        parameters:
            label      - label of the message. Must be unique
            groupID    - destination group. Must match the wordType of this message
            text       - english text
            context    - description for this message entry
        pre-req:
            this MUST NOT be called within nested Transactions. This not what this method for.
        exceptions:
            throws various exceptions on failures
        returns:
            row of the message that we just added
        """
        cls._ErrorIfInTransaction('Message Create will not run within Transaction. Use TransactionAwareCreate.')
        with bsd.BsdTransaction('Creating new message: %s' % label) as bsdTransaction:
            cls._TransactionAwareCreate(label, groupID, LOCALE_SHORT_ENGLISH, text, context, wordTypeID=None, transactionBundle=None)
        resultList = bsdTransaction.GetTransactionResult()
        return cls.Get(resultList[0][1].messageID)

    @classmethod
    def TransactionAwareCreate(cls, label, groupID = None, text = '', context = None, transactionBundle = None):
        """
        This is the transaction-aware portion of the create code. It is split up from Create() on purpose; in order to
        allow other Wrappers to include these operations as port of their transaction as well.
        Purpose: Creates a new message label, and a blank English string by default.
        parameters:
            label      - label of the message. Must be unique
            groupID    - destination group. Must match the wordType of this message
            text       - english text
            context    - description for this message entry
            wordTypeID - type of the message
            transactionBundle - cache containing entries of messages to be added within transaction.
                                It is required for validations within transactions. See CreateMessageDataBundle()
        pre-req:
            this IS meant to be called within nested Transactions.
        Returns:  reserved actionID dictionary for the message, that will be added when transaction is done.
                  The return is formated as:
                      {"reservedMessageID": INTEGER}
                  Notice: when things in base fail, this may return None
        """
        cls._ErrorIfNotInTransaction('Message TransactionAwareCreate will not run within Transaction. Use Create.')
        with bsd.BsdTransaction('Creating new message: %s' % label):
            actionIDsResult = cls._TransactionAwareCreate(label, groupID, LOCALE_SHORT_ENGLISH, text, context, wordTypeID=None, transactionBundle=transactionBundle)
        return actionIDsResult

    @classmethod
    def _GetGroupRecord(cls, groupID, transactionBundle = None):
        """
        get the group entry, to resolve issue between actionIDs + bundles and live data
        """
        from messageGroup import MessageGroup
        if transactionBundle and type(groupID) != int:
            currentGroup = transactionBundle.get(localizationBSDConst.BUNDLE_GROUP, {}).get(groupID, None)
        else:
            currentGroup = MessageGroup.Get(groupID)
        return currentGroup

    @classmethod
    def _GetWordTypeID(cls, groupID, transactionBundle = None):
        """
        Resolving two required pieces of data for message creation.
        """
        wordTypeID = None
        if groupID is not None:
            parentGroup = cls._GetGroupRecord(groupID, transactionBundle=transactionBundle)
            if parentGroup:
                wordTypeID = parentGroup.wordTypeID
        return wordTypeID

    @classmethod
    def _ValidateCreationOfMessage(cls, label, groupID, wordTypeID, transactionBundle = None):
        """
        validate various things before allowing this entry to be created
        the function is expected to interrupt this execution if things are wrong
        """
        if not cls.CheckIfLabelUnique(label, groupID, transactionBundle=transactionBundle):
            raise AuthoringValidationError('Label (%s) in groupID (%s) is not unique.' % (label, str(groupID)))
        if groupID != None:
            parentGroup = cls._GetGroupRecord(groupID, transactionBundle=transactionBundle)
            if parentGroup:
                if wordTypeID != parentGroup.wordTypeID:
                    raise AuthoringValidationError('Group type doesnt match message type (%s,%s).' % (wordTypeID, parentGroup.wordTypeID))
            else:
                raise AuthoringValidationError("Parent group (%s) wasn't found." % str(groupID))
        if wordTypeID != None:
            typeRow = locWordType.WordType.Get(wordTypeID)
            if typeRow == None:
                raise AuthoringValidationError("Type (%s) wasn't found." % wordTypeID)
        return True

    @classmethod
    def _TransactionAwareCreate(cls, label, groupID, languageID, text, context, wordTypeID = None, transactionBundle = None):
        """
        Worker function for transaction-aware portion of the create code.
        parameters:
            label      - label of the message. Must be unique
            groupID    - destination group. Must match the wordType of this message
            languageID - id for text entry
            text       - text entry
            context    - description for this message entry
            wordTypeID - type of the message
            transactionBundle - cache containing entries of messages to be added within transaction.
                                It is required for validations within transactions. See CreateMessageDataBundle()
        Returns:  reserved actionID dictionary for the message, that will be added when transaction is done.
                  The return is formated as:
                      {"reservedMessageID": INTEGER}
        pre-req:
            always meant to run in transaction
        """
        inheritedWordTypeID = Message._GetWordTypeID(groupID)
        if wordTypeID is None:
            wordTypeID = inheritedWordTypeID
        Message._ValidateCreationOfMessage(label, groupID, wordTypeID, transactionBundle=transactionBundle)
        dbLocaleID = GetNumericLanguageIDFromLanguageID(languageID)
        if dbLocaleID is None:
            raise AuthoringValidationError('Didnt find language (%s).' % languageID)
        reservedActionID = bsdWrappers.BaseWrapper._Create(cls, label=label, groupID=groupID, context=context, wordTypeID=wordTypeID)
        if transactionBundle:
            tupleActionID = (reservedActionID, 'messageID')
            transactionBundle[localizationBSDConst.BUNDLE_MESSAGE][tupleActionID] = util.KeyVal({'label': label,
             'groupID': groupID,
             'context': context,
             'wordTypeID': wordTypeID})
        messageTextTable = bsdWrappers.GetTable(locMessageText.MessageText.__primaryTable__)
        messageTextTable.AddRow((reservedActionID, 'messageID'), dbLocaleID, text=text)
        if type(reservedActionID) == int:
            return {'reservedMessageID': reservedActionID}
        raise AuthoringValidationError('Unexpected error. Possibly incorrect use of transactions. Expected actionID but instead got : %s ' % str(reservedActionID))

    @classmethod
    def _ErrorIfInTransaction(cls, errorMessage):
        cls.CheckAndSetCache()
        if cls._bsdSvc.TransactionOngoing():
            raise AuthoringValidationError(errorMessage)

    @classmethod
    def _ErrorIfNotInTransaction(cls, errorMessage):
        cls.CheckAndSetCache()
        if not cls._bsdSvc.TransactionOngoing():
            raise AuthoringValidationError(errorMessage)

    @staticmethod
    def CheckIfLabelUnique(originalLabel, groupID, transactionBundle = None, _appendWord = None):
        """
        Check against data in DB of label is unique
        parameters:
            groupID           - parent group
            transactionBundle - see CreateMessageDataBundle()
        return:
            True or False
        """
        isUnique, label = Message._CheckLabelUniqueness(originalLabel, groupID, transactionBundle=transactionBundle, returnUnique=False, _appendWord=_appendWord)
        return isUnique

    @staticmethod
    def GetUniqueLabel(originalLabel, groupID, transactionBundle = None, _appendWord = None):
        """
        Generate unique label against data in DB.
        parameters:
            groupID           - parent group
            transactionBundle - see CreateMessageDataBundle()
        return:
            unique label
        """
        isUnique, label = Message._CheckLabelUniqueness(originalLabel, groupID, transactionBundle=transactionBundle, returnUnique=True, _appendWord=_appendWord)
        return label

    @staticmethod
    def GetMessageByID(messageID):
        primaryTable = bsdWrappers.GetTable(Message.__primaryTable__)
        return primaryTable.GetRowByKey(_wrapperClass=Message, keyId1=messageID, _getDeleted=False)

    @staticmethod
    def GetMessagesByGroupID(groupID, projectID = None):
        """
        Returns all messages directly beneath the parent group.
        If ProjectID is specified then return all messages under this group, tagged for this project.
        """
        return Message.GetWithFilter(groupID=groupID)

    @staticmethod
    def _CheckLabelUniqueness(originalLabel, groupID, transactionBundle = None, returnUnique = False, _appendWord = None):
        """
        Check or get unique label (if returnUnique is set to True)
        return:
            tuple: (if label is unique, unique label string)
        """
        isOriginalLabelUnique = True
        if originalLabel is None:
            return (isOriginalLabelUnique, None)
        primaryTable = bsdWrappers.GetTable(Message.__primaryTable__)
        newLabel = originalLabel
        while True:
            labels = primaryTable.GetRows(label=newLabel, groupID=groupID, _getDeleted=True)
            atLeastOneMatch = False
            if transactionBundle:
                for key, aLabel in transactionBundle[localizationBSDConst.BUNDLE_MESSAGE].iteritems():
                    if aLabel.label == newLabel and aLabel.groupID == groupID:
                        atLeastOneMatch = True
                        break

            if labels and len(labels) or atLeastOneMatch:
                isOriginalLabelUnique = False
                if returnUnique:
                    newLabel = newLabel + (Message._APPEND_NEW if not _appendWord else _appendWord)
                else:
                    break
            else:
                break

        if returnUnique:
            return (isOriginalLabelUnique, newLabel)
        else:
            return (isOriginalLabelUnique, None)


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

# First try
class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        def subtree_has_one(node):
            if not node: return False
            if node.val: return True
            return subtree_has_one(node.left) or subtree_has_one(node.right)

        def dfs(node):
            if not node: return

            if not subtree_has_one(node.left):
                node.left = None
            else:
                dfs(node.left)

            if not subtree_has_one(node.right):
                node.right = None
            else:
                dfs(node.right)

        dfs(root)
        return root

# This solution is more clear
class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        if not root: return root
        root.left = self.pruneTree(root.left)
        root.right = self.pruneTree(root.right)
        return root if root.val or root.left or root.right else None


import re
text_input = input().split()
scanner = ""
for i in text_input:
    scanner += ",".join(re.findall(r"^_[a-zA-Z0-9]+\b", i))
scanner = scanner.split("_")
del scanner[0]
print(",".join(scanner))

Python-Fundamentals/Regular Expressions - Exercise/02. Find Variable Names in Sentences.py


from typing import List
from fastapi import WebSocket
from app.schemas.chat import Chat

class ConnectionManager:
    def __init__(self) -> None:
        self.active_connections: List[(WebSocket, str)] = []
        self.neew_help_conn: List[(WebSocket, str)] = []

    async def connect(self, websocket: WebSocket, nickname: str) -> None:
        await websocket.accept()
        self.active_connections.append((websocket, nickname))
        self.neew_help_conn.append((websocket, nickname))

    def disconnect(self, websocket: WebSocket, nickname: str) -> None:
        self.active_connections.remove((websocket, nickname))

    async def send_personal_message(self, message: str, websocket: WebSocket) -> None:
        await websocket.send_text(message)

    async def broadcast(self, message: str) -> None:
        for connection in self.active_connections:
            await connection[0].send_text(message)

    async def get_chats_with_promlem(self):
        chats: List[Chat] = []
        for chat in self.neew_help_conn:
            chats.append(Chat(name=str(chat[1]), status=chat[0].client_state.name))
        return chats


# Crie um programa que declare uma matriz de dimensão 3×3 e preencha com valores
# lidos pelo teclado.
# No final, mostre a matriz na tela, com a formatação correta.

matriz = [[], [], []]
for i in range(0, 3):
    for j in range(0, 3):
        valor = int(input(f'Digite o valor para [{i},{j}]: '))
        matriz[i].append(valor)
print(matriz)
print()

for i in range(0, 3):
    for j in range(0, 3):
        print(f'[ {matriz[i][j]} ]', end='')
    print()


class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        buy = prices[0] # 首次买入价格
        m = 0   # 当前最大收益
        for p in prices[1:]:
            # 每次获取最小买入价格
            buy = min([buy, p])
            # 每次获取最大收益
            m = max([p-buy, m])
        return m


from base.method import *
import unittest
from page.openS import *
from utils.excel_data import excel_data as e
class test_role(unittest.TestCase):
    def setUp(self):
        self.obj=method()
        self.excel_data =e()
        #获取实际结果列数
        self.r_col=self.excel_data.get_result_col()
        #获取响应时间列数
        self.t_col=self.excel_data.get_time_col()
        self.f = "public_url.json"
        self.f1="requestData_role.json"
        self.f2="data_role.xls"
    def write2excel(self,r,col,f):
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.json()["status"], 200)
        writeResult(col, self.r_col, "pass",f)
        writeResult(col, self.t_col, r.elapsed.total_seconds(),f)
    def tearDown(self):
        pass

    # 登陆接口
    def test_001(self):
        r = self.obj.post(1, self.f, self.f2)
        writeToken(r.json()["data"]["token"])
        # r=self.obj.post_token(2)
        self.write2excel(r, 1, self.f2)
    def test_002(self):
        #查询角色列表
        r=self.obj.get_t(2,self.f1,self.f2)
        self.write2excel(r,2,self.f2)
        #添加角色
        r=self.obj.post_t(3,self.f1,self.f2)
        self.write2excel(r,3,self.f2)
        #编辑角色
        level=r.json()["data"]["level"]
        name=r.json()["data"]["name"]
        tenantId=r.json()["data"]["tenantId"]
        id=r.json()["data"]["id"]
        l=[]
        li=[]
        l.append("level")
        li.append(level)
        l.append("name")
        li.append(name)
        l.append("tenantId")
        li.append(tenantId)
        l.append("id")
        li.append(id)
        r=self.obj.post_c(9,self.f1,self.f2,l,li)
        self.write2excel(r,9,self.f2)
        #角色授权加载自定义菜单树
        r=self.obj.get_v(4,id,self.f1,self.f2)
        self.write2excel(r,4,self.f2)
        #角色授权菜单保存
        l=[]
        li=[]
        l.append("roleId")
        li.append(id)
        r=self.obj.post_c(5,self.f1,self.f2,l,li)
        self.write2excel(r,5,self.f2)
        #通过角色id查询数据看板范围树
        r=self.obj.get_v(6,id,self.f1,self.f2)
        self.write2excel(r,6,self.f2)
        #角色授权数据看板保存
        l=[]
        li=[]
        l.append("roleId")
        li.append(id)
        r=self.obj.post_c(7,self.f1,self.f2,l,li)
        self.write2excel(r,7,self.f2)
        #删除角色
        r=self.obj.get_v(8,id,self.f1,self.f2)
        self.write2excel(r,8,self.f2)
if __name__ == '__main__':
    unittest.main()


#124 나라의 숫자
#https://programmers.co.kr/learn/courses/30/lessons/12899

def solution(n):
    answer = ''
    order = [4, 1, 2]
    while n > 0:
        answer += str(order[n%3])
        n = n//3 if n%3 != 0 else n//3-1
    return "".join(reversed(answer))

#다른 사람의 풀이 ( if를 쓰지않고 n-=1로 해결 )
#  while n > 0:
#         n -= 1
#         answer = num[n % 3] + answer
#         n //= 3


import pickle

from PyDictionary import PyDictionary
from gensim.models import KeyedVectors
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet
from pyinflect import getInflection
from pattern.text.en import superlative, pluralize, comparative
from complexity_prediction.complexity_prediction import predict

def create_model(path, limit):
    """
    Store a gensim object of the current word2vec embeddings using pickle; the file will be named word2vec_model.sav

    Parameters:
    path (str): path to the word2vec pre-trained model
    limit (int): the number of embeddings to be saved in the gensim model
    """
    model = KeyedVectors.load_word2vec_format(path, limit=limit)
    pickle.dump(model, open("word2vec_model.sav", "wb"))

def tagConversion(tag):
    """
    Convert a complex nltk POS tag to a simpler wornet POS tag

    Parameters:
    tag (str): a nltk POS tag

    Returns:
    str: a corresponding wordnet POS tag
    """
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV

def debug_print(msg, debug=False):
    """
    Prints a debug message

    Parameters:
    msg (str): a message to be displayed
    debug (boolean): if the debug mode is enabled or not
    """
    if debug:
        print("[SYNONYMS GENERATION] " + msg)

def get_synonyms(word, nltk_pos, path, debug=False):
    """
    Get a list of synonyms for a given word and its corresponding POS

    The function selects only those synonyms that have a cosine similarity above the average similarity of all
    found synonyms; also, the function performs morphological changes to the words to preserve gramatical corectness.

    Parameters:
    word (str): the word for which the synonyms must be found
    nltk_pos (str): the nltk POS tag for the word given
    path (str): path to the word2vec saved model
    debug (boolean) (default:False): if the debug mode is enabled or not

    Returns:
    list: a list of touples formed by the synonym and its cosine similarity to the original word
    """
    dictionary = PyDictionary()
    model = pickle.load(open(path, "rb"))

    lemmatizer = WordNetLemmatizer()
    word = lemmatizer.lemmatize(word, pos=tagConversion(nltk_pos))

    synonyms = dictionary.synonym(word)

    if synonyms == None:
        return []

    # loop through the synonyms and compute the cosine similarities
    selected_synonyms = []
    average_similarity = 0
    for syn in synonyms:
        if syn in model.key_to_index and word in model.key_to_index:
            similarity = model.similarity(word, syn)
            debug_print("Similarity between " + word + " and " + syn + " is " + str(similarity), debug=debug)
            selected_synonyms.append((syn, similarity))
            average_similarity += similarity
        else:
            debug_print("Similarity between " + word + " and " + syn + " is unknown", debug=debug)

    if word not in model.key_to_index:
        for syn in synonyms:
            selected_synonyms.append((syn, 0))

    if len(selected_synonyms) == 0:
        return []

    average_similarity /= len(selected_synonyms)
    selected_synonyms = list(filter(lambda x: x[1] >= average_similarity, selected_synonyms))

    # do morphological changes to the synonyms
    for i in range(len(selected_synonyms)):
        if nltk_pos in ["VBD", "VBP", "VBZ", "VBG", "VBN"]:
            inflection = getInflection(selected_synonyms[i][0], nltk_pos)
            if inflection != None:
                selected_synonyms[i] = (inflection[0], selected_synonyms[i][1])
        elif nltk_pos in ["JJS", "RBS"]:
            selected_synonyms[i] = (superlative(selected_synonyms[i][0]), selected_synonyms[i][1])
        elif nltk_pos in ["NNS"]:
            selected_synonyms[i] = (pluralize(selected_synonyms[i][0]), selected_synonyms[i][1])
        elif nltk_pos in ["JJR", "RBR"]:
            selected_synonyms[i] = (comparative(selected_synonyms[i][0]), selected_synonyms[i][1])

    return selected_synonyms

def get_synonyms_transformers(word, nltk_pos, model, dictionary_unigrams, total, debug=False):
    """
    Get a list of synonyms for a given word and its corresponding POS

    This function shall be used in the transformer pipeline to determine which synonyms remain as candidates
    for the sentence ranking stage. This function will select only those synonyms that are predicted by the
    complexity prediction model as being easy words

    Parameters:
    word (str): the word for which the synonyms must be found
    nltk_pos (str): the nltk POS tag for the word given
    model (scikit-learn): the complexity prediction model to be used
    dictionary_unigrams (dict): a dictionary of unigrams from a language model
    total (int): the total number of words in the language model
    debug (bool): weather or not to print informations to stdout

    Returns:
    list: a list of touples formed by the synonym and the value 0 (the second value is for compatibility purposes and shall be ignored)
    """
    dictionary = PyDictionary()

    lemmatizer = WordNetLemmatizer()
    word = lemmatizer.lemmatize(word, pos=tagConversion(nltk_pos))

    synonyms = dictionary.synonym(word)

    if synonyms == None:
        return []

    selected_synonyms = []
    for syn in synonyms:
        tokens = syn.split(" ")
        simple = True
        for token in tokens:
            if predict(model, dictionary_unigrams, total, token) == 1:
                simple = False
                break
        if simple:
            debug_print("Synonym " + syn + " is a simple word", debug=debug)
            selected_synonyms.append((syn, 0))
        else:
            debug_print("Synonym " + syn + " is not a simple word", debug=debug)

    for i in range(len(selected_synonyms)):
        if nltk_pos in ["VBD", "VBP", "VBZ", "VBG", "VBN"]:
            inflection = getInflection(selected_synonyms[i][0], nltk_pos)
            if inflection != None:
                selected_synonyms[i] = (inflection[0], selected_synonyms[i][1])
        elif nltk_pos in ["JJS", "RBS"]:
            selected_synonyms[i] = (superlative(selected_synonyms[i][0]), selected_synonyms[i][1])
        elif nltk_pos in ["NNS"]:
            selected_synonyms[i] = (pluralize(selected_synonyms[i][0]), selected_synonyms[i][1])
        elif nltk_pos in ["JJR", "RBR"]:
            selected_synonyms[i] = (comparative(selected_synonyms[i][0]), selected_synonyms[i][1])

    return selected_synonyms


import scipy.io
import os
import Utils.OneHot
import pandas as pd

'''
    TFName represents name of TFs
    DataSetName represents name of Datasets
'''
def seq2kmer(seq):
    """
    Convert original sequence to kmers

    Arguments:
    seq -- str, original sequence.
    k -- int, kmer of length k specified.

    Returns:
    kmers -- str, kmers separated by space

    """
    kmer = [seq[x:x + 3] for x in range(len(seq) + 1 - 3)]
    kmers = " ".join(kmer)
    return kmers

def DataReader(TFName, DataSetName, type):
    FeatureMatrix = []
    DenseLabels = []
    if DataSetName == 'ChIP-exo':
        '''
            AR -> labels
            GR -> label
        '''
        DenseLabels = scipy.io.loadmat(os.path.dirname(__file__) + '/ChIP-exo/' + TFName + '/label.mat')['labels']
        with open(os.path.dirname(__file__) + '/ChIP-exo/' + TFName + '/sequence.txt', 'r') as SReader:
            for line in SReader.readlines():
                FeatureMatrix.append(list(map(str, line.rstrip('\n'))))
        FeatureMatrix = Utils.OneHot.OneHot(sequence=FeatureMatrix, number=len(FeatureMatrix), nucleotide=4,
                                            length=DenseLabels.shape[1])
    else:
        with open(os.path.dirname(__file__) + '/ChIP-seq/' + TFName + '/baseline/seq_' + type + '.txt', 'r') as SReader, open(
                  os.path.dirname(__file__) + '/ChIP-seq/' + TFName + '/baseline/lab_' + type + '.txt', 'r') as LReader:
            for SRLine, LRLine in zip(SReader.readlines(), LReader.readlines()):
                FeatureMatrix.append(SRLine.rstrip('\n'))
                DenseLabels.append(list(map(int, [label for label in LRLine.rstrip('\n')])))
        FeatureMatrix = Utils.OneHot.OneHot(sequence=FeatureMatrix, number=len(FeatureMatrix), nucleotide=4,
                                            length=len(DenseLabels[1]))
    return FeatureMatrix, DenseLabels

def DataReaderPrecit(path):

    Dataset = pd.read_csv(path, header=None)
    Sequence = Dataset[0].tolist()
    FeatureMatrix = Utils.OneHot.OneHot(sequence=Sequence, number=len(Sequence), nucleotide=4,
                                        length=100)
    return FeatureMatrix

def DataReaderBERT(TFName, DataSetName, KMER):

    trainDataset = pd.read_csv('../Dataset/' + DataSetName + '/' + TFName + '/' + str(KMER) + '-mer/train.txt', sep='\t')

    TrainSequence = trainDataset['sequence'].tolist()
    TrainDenseLabels = []
    TrainLabels = trainDataset['label'].tolist()

    for row in trainDataset['denseLabel']:
        TrainDenseLabels.append(list(map(int, [label for label in row])))

    testDataset = pd.read_csv('../Dataset/' + DataSetName + '/' + TFName + '/' + str(KMER) + '-mer/test.txt', sep='\t')

    TestSequence = testDataset['sequence'].tolist()
    TestDenseLabels = []
    TestLabels = testDataset['label'].tolist()

    for row in testDataset['denseLabel']:
        TestDenseLabels.append(list(map(int, [label for label in row])))

    return TrainSequence, TrainDenseLabels, TrainLabels, TestSequence, TestDenseLabels, TestLabels

def DataReaderSequence(TFName, DataSetName, KMER):

    trainDataset = pd.read_csv('../Dataset/' + DataSetName + '/' + TFName + '/' + str(KMER) + '-mer/train.txt', sep='\t')

    TrainSequence = trainDataset['sequence'].tolist()
    TrainLabels = trainDataset['label'].tolist()

    testDataset = pd.read_csv('../Dataset/' + DataSetName + '/' + TFName + '/' + str(KMER) + '-mer/test.txt', sep='\t')

    TestSequence = testDataset['sequence'].tolist()
    TestLabels = testDataset['label'].tolist()

    return TrainSequence, TrainLabels, TestSequence, TestLabels

def DataReaderPrecitBERT(path):

    Dataset = pd.read_csv(path, header=None)
    Sequence = Dataset[0].tolist()
    Sequence = list(map(seq2kmer, Sequence))

    return Sequence


#!/usr/bin/python3
import pandas as pd
import sys
import os
import json
import matplotlib.pyplot as plt
from texttable import Texttable

def toDf(item_path, dropCols=None):
    pf_list = []
    counter = 0
    for chunk in chunks(item_path):
        if dropCols is not None:
            chunk = chunk.drop(labels=dropCols, axis='columns')
        pf_list.append(chunk)
        counter += len(chunk.index)
        print('read %d of %s' % (counter, item_path))
    return pd.concat(pf_list)

def chunks(item_path):
    chunkSize = 1000000
    return pd.read_csv(item_path, header=0, chunksize=chunkSize)

def min_watch_of_topN(dataset_path, ratings):
    ur = ratings.pivot_table(index=['userId'], values=['movieId'], aggfunc='count').rename(columns={'movieId': 'movies'})
    ur = ur.sort_values(('movies'), ascending=False)
    total_users = len(ur.index)
    percentage_list = []
    min_watched = []
    for i in range(1, 101):
        percent_i_idx = int(round((i * total_users)/100))-1
        if percent_i_idx < 0:
            percent_i_idx = 0
        if percent_i_idx > (total_users-1):
            percent_i_idx = total_users-1
        percent_i_record = ur.iloc[percent_i_idx]
        # print('index percent %d is %d' % (i, percent_i_idx))
        percentage_list.append(i)
        min_watched.append(percent_i_record['movies'].item())
    top_watchs = pd.DataFrame({'top N % of user': percentage_list, 'Minimal watched': min_watched})
    # print(top_watchs)
    top_watchs.plot(x='top N % of user', y='Minimal watched', title='Minimal movies watched / top N percent users', grid=True)
    plt.show()

def min_watched_of_topN(dataset_path, ratings):
    ur = ratings.pivot_table(index=['movieId'], values=['userId'], aggfunc='count').rename(columns={'userId': 'users'})
    ur = ur.sort_values(('users'), ascending=False)
    total_users = len(ur.index)
    percentage_list = []
    min_watched = []
    for i in range(1, 101):
        if (i % 5) != 0 or (i < 5):
            continue
        percent_i_idx = int(round((i * total_users)/100))-1
        if percent_i_idx < 0:
            percent_i_idx = 0
        if percent_i_idx > (total_users-1):
            percent_i_idx = total_users-1
        percent_i_record = ur.iloc[percent_i_idx]
        # print('index percent %d is %d' % (i, percent_i_idx))
        percentage_list.append(i)
        min_watched.append(percent_i_record['users'].item())
    top_watchs = pd.DataFrame({'top N % of movies': percentage_list, 'Minimal watchers': min_watched})
    print(top_watchs.head())
    # print(top_watchs)
    top_watchs.plot(x='top N % of movies', y='Minimal watchers', title='Minimal watchers / top N percent movies', grid=True)
    plt.show()

def group_by_hour(dataset_path, ratings):
    rating_times = pd.to_datetime(ratings['timestamp'], unit='s')
    print(rating_times.min())
    print(rating_times.max())
    ratings['rating_hour'] = rating_times.dt.hour
    ratings['rating_time'] = rating_times
    start = pd.to_datetime('2000/01/01', format='%Y/%m/%d')
    end = pd.to_datetime('2018/01/01', format='%Y/%m/%d')
    period = (end - start).days
    print('period = %d days' % period)
    filtered = ratings[(ratings['rating_time'] >= start) & (ratings['rating_time'] < end)]
    ur = filtered.pivot_table(index=['rating_hour'], values=['userId'], aggfunc='count').rename(columns={'userId': 'watch_times'})
    ur['average watch in hour'] = ur['watch_times']/period
    ur.plot(y='average watch in hour', title='Watched movies time-distributed', grid=True)
    plt.show()
    # print(ur.head(n=24))
    # times = pd.DatetimeIndex(ratings.timestamp)
    # grp_by_hr = ratings.groupby([times.hour])
    # print(grp_by_hr.head())

def top_100_rated_movies(dataset_path):
    ratings = toDf(os.path.join(dataset_path, 'ratings.csv'), dropCols=['timestamp', 'userId'])
    movies = toDf(os.path.join(dataset_path, 'movies.csv'), dropCols=['genres'])
    average_rating = ratings.groupby(by='movieId').mean()
    rating_count = ratings.groupby(by='movieId').count().rename(columns={'rating': 'rating_count'})
    movie_stat = average_rating.merge(rating_count, left_index=True, right_index=True).sort_values(by='rating_count', ascending=False).reset_index()
    movie_stat = movie_stat.merge(movies, left_on='movieId', right_on='movieId')
    total_movies_rated = len(movie_stat.index)
    print(total_movies_rated)
    # print(average_rating.head())
    # print(rating_count.head())
    theMiddle = int(total_movies_rated * 0.2)
    middle100 = movie_stat.iloc[theMiddle-100:theMiddle].drop(columns=['movieId'])
    print('From %d to %d, the mean rate is %f' % (theMiddle-100, theMiddle, middle100['rating'].mean()))
    middle100.plot(y=['rating'], title='Rating of Not so hot movies', grid=True)
    plt.show()
    hot100 = movie_stat.iloc[0:100].drop(columns=['movieId'])
    print('From 0 to 99, the mean rate is %f' % hot100['rating'].mean())
    # print(movie_stat.head())
    tb = Texttable()
    tb.set_cols_align(['l', 'r', 'r'])
    tb.set_cols_dtype(['f', 'i', 't'])
    tb.header(hot100.columns.get_values())
    tb.add_rows(hot100.values, header=False)
    with open('hot_100.txt', 'w') as ofile:
        ofile.write(tb.draw().encode('utf8'))
    hot100.plot(y=['rating'], title='Rating of Hot 100 movies', grid=True)
    hot_sucks = hot100[hot100['rating'] < 3.2]
    tb.reset()
    tb.header(hot_sucks.columns.get_values())
    tb.add_rows(hot_sucks.values, header=False)
    with open('hot_sucks.txt', 'w') as ofile:
        ofile.write(tb.draw().encode('utf8'))
    # print(hot100.mean())
    # print(cool100.mean())
    plt.show()

def test(dataset_path):
    tags = toDf(os.path.join(dataset_path, 'tags.csv'), dropCols=['timestamp', 'userId'])
    toy_story_tags = tags[tags['movieId'] == 1]
    print(toy_story_tags.head())

def main():
    dataset_path = sys.argv[1]
    test(dataset_path)
    # ratings = toDf(os.path.join(dataset_path, 'ratings.csv'), dropCols=['rating'])
    # min_watch_of_topN(dataset_path, ratings)
    # min_watched_of_topN(dataset_path, ratings)
    # group_by_hour(dataset_path, ratings)
    # top_100_rated_movies(dataset_path)

if __name__ == '__main__':
    main()


"""
Name: 13f_search.py
Author: Ryder Rhoads
Company: Wedbush Secruities
Summary: The goal of this program is to find all institutional clients which hold the given tickers. With the goal of creating business at the firm.
Requires: https://pandas.pydata.org/ & https://sec-api.io/
"""
from sec_api import QueryApi
import pandas as pd
from datetime import datetime, timedelta

def main():
    """
    Main purpose of th
    """
    queryApi = QueryApi(api_key="your_key_here")
    sheet = []  # Create an empty list to store data from each iteration

    latest_date = datetime.strptime("2023-02-27", "%Y-%m-%d")
    current_date = datetime.strptime("2023-05-28", "%Y-%m-%d")
    date = datetime.strptime("2023-02-28", "%Y-%m-%d")
    formatted_latest_date = latest_date.strftime("%Y-%m-%d")
    formatted_current_date = current_date.strftime("%Y-%m-%d")
    formatted_date = date.strftime("%Y-%m-%d")

    while date <= current_date:
        formatted_latest_date = latest_date.strftime("%Y-%m-%d")
        formatted_current_date = current_date.strftime("%Y-%m-%d")
        formatted_date = date.strftime("%Y-%m-%d")
        for tikr in BIOTECH_COMPANIES:
            query = {
                "query": {
                    "query_string": {
                        "query": f"formType:\"13F\" AND holdings.ticker:{tikr} AND filedAt:[{formatted_latest_date} TO {formatted_date}]"
                    }
                },
                "from": "0",
                "sort": [{"filedAt": {"order": "desc"}}]
            }
            print(f"Query pulled FROM {formatted_latest_date} TO {formatted_date} FOR {tikr}")
            filings = queryApi.get_filings(query)  # Retrieve filings for the current ticker
            filings_data = get_filings(filings)  # Process filings data into a list
            sheet.extend(filings_data)  # Append the filings data to the 'sheet' list

        latest_date += timedelta(days=1)  # Increment the date by 1 day
        date += timedelta(days=1)  # Increment the date by 1 day

    # Convert 'sheet' list into a pandas DataFrame
    df = pd.DataFrame(sheet, columns=["Company Name", "Total Value", "Position Value", "Position Percentage"])

    # Save the DataFrame as an Excel file
    df.to_excel("13FSearch/output.xlsx", index=False)

def get_filings(filings):
    i = 0
    sheet=[]
    for f in filings.items():
        if i == 2:
            if len(f[1]) ==200:
                print("OVER LIMIT QUERIES")
                print(f[1])
            for i in f[1]:
                tot = 0
                positionVal = 0
                info = [i['companyName']]
                for holding in i["holdings"]:
                    tot += holding["value"]
                    try:
                        if holding["ticker"] in BIOTECH_COMPANIES and holding["shrsOrPrnAmt"]['sshPrnamtType'] == "SH":
                            positionVal += holding["value"]
                    except KeyError:
                        continue
                info.append(tot)
                info.append(positionVal)
                info.append(float(positionVal / tot))
                sheet.append(info)
            break
        i+=1
    return sheet

main()


import time
import json
from pyfiglet import figlet_format
import pyautogui as pyg
import os
import sys
import subprocess

subprocess.call(["pip3", "install" ,"-r" ,"requirements.txt"])

# save urls.json do a variable
f = open("urls.json")
global urls
urls = json.load(f)
f.close()

# save data.json to a variable
f = open("data.json")
global data
data = json.load(f)
f.close()

# save all data

def save():
    f = open("data.json", 'w')
    json.dump(data, f)
    f.close()
    f = open("urls.json", 'w')
    json.dump(urls, f)
    f.close()
    print("Data saved")

# wait x seconds and restart

def wait_and_reset(amount=data["waittime"]):
    time.sleep(amount)
    clear()
    start()

def params(command, *args):
    print("Invalid params for:", command)
    for value in args:
        print("[{}]".format(value))
    wait_and_reset()

def clear():
    os.system("clear")

if data["clear_on_start"] == "True":
    clear()

def error():
    print("Someting went wrong")
    wait_and_reset()

# operation select function

def operation_select():
    operation = (input("Input operation (open or run)> ")).split(" ")
    # prime opening function
    if operation[0] == "open":
        run("open", "N/A", "N/A")
    # prime spam function
    elif operation[0] == "run":
        operation = "run"
    # extra commands
    # change loadtime
    elif operation[0] == "lt":
        try:
            data["loadtime"] = int(operation[1])
        except ValueError:
            print("Value must be an integer")
            wait_and_reset()
        except IndexError:
            params("lt(load time)", "length")
        save()
        wait_and_reset()
    # change wait time
    elif operation[0] == "wt":
        try:
            data["waittime"] = int(operation[1])
        except ValueError:
            print("Value must be an integer")
            wait_and_reset()
        except IndexError:
            params("wt(wait time)", "length")
        save()
        wait_and_reset()
    # change 'clear on start' status
    elif operation[0] == "cos":
        try:
            if operation[1] == "t":
                data["clear_on_start"] = "True"
            if operation[1] == "f":
                data["clear_on_start"] = "False"
            else:
                params("cos(clear on start)", "t(True) or f(False")
        except IndexError:
            params("cos(clear on start)", "t(True) or f(False")
        save()
        wait_and_reset()

    # add url fucntion
    elif operation[0] == "url":
        try:
            if operation[1] == "r":
                for key, values in urls.items():
                    print("{}: {}".format(key, values))
                try:
                    inp = int(input("Select url to remove> "))
                    del urls[str(inp)]
                    save()
                    wait_and_reset()
                except ValueError:
                    print("Value must be an integer")
                    wait_and_reset()

            elif operation[1] == "a":
                try:
                    i = len(urls.keys())
                    urls[str(i+1)] = operation[2]
                    print("Url added")
                    save()
                    wait_and_reset()
                except IndexError:
                    params("url", "r(remove)", "a(add) [url]")
            else:
                params("url", "r(remove)", "a(add) [url]")
        except IndexError:
            params("url", "r(remove)", "a(add) [url]")
    # save data
    elif operation[0] == "s":
        save()
        print("All data saved")
        wait_and_reset()
    # else
    else:
        print("Invalid operation")
        wait_and_reset()
    return operation

# runtime select function

def length_select():
    try:
        length = int(input("Input desired runtime (seconds)> "))
    except ValueError:
        print("Invalid length")
        time.sleep(data["waittime"])
        length_select()
    return length

# message select function

def message_select():
    message = input("Input message> ")
    return message

# countdown function

def countdown(amount):
    for i in range(0, amount):
        print(amount-i)
        time.sleep(1)

# main function (opens sites / or run spam)

def run(operation, message, runtime):
    # open urls
    if operation == 'open':
        if input("Enter 'r' when ready> ") == "r":
            print("Have browser open in:")
            countdown(data["loadtime"])
            for key, value in urls.items():
                pyg.keyDown("alt")
                pyg.press("d")
                pyg.keyUp("alt")
                pyg.typewrite(value)
                time.sleep(0.5)
                pyg.press("enter")
                time.sleep(1)
                pyg.keyDown("ctrl")
                pyg.press("t")
                pyg.keyUp("ctrl")
            pyg.keyDown("ctrl")
            pyg.press("w")
            pyg.keyUp("ctrl")
            inp = input("Would you like to run program> ")
            if inp == "yes":
                run("run", message_select(), length_select())
            elif inp == "no":
                print("Ok")
                save()
                exit()
            else:
                print("Invalid input")
                save()
                save()
                exit()
        else:
            print("Invalid input")
            time.sleep(data["waittime"])
            run(open, message, runtime)

    # start spam
    if operation == 'run':
        print("Open browser in:")
        countdown(data["loadtime"])
        t_end = time.time() + 60 * runtime
        while time.time() < t_end:
            time.sleep(1)
            pyg.typewrite(message)
            time.sleep(0.1)
            pyg.press("ENTER")
            pyg.keyDown("CTRL")
            pyg.press("TAB")
            pyg.keyUp("CTRL")
        print("Process finished")
        save()
        exit()

# define main loop

def start():
    print(figlet_format("DarkSGC", font="graffiti") + "Version 1.1\n")
    operation = operation_select()
    message = message_select()
    length = length_select()
    run(operation, message, length)

# start main loop
start()


#!/usr/bin/env python
"""
Assignments from ROS for Beginners:
Author: Anis Koubaa
Modifications: Pranav.S (spranav1911@gmail.com)
Date of modification: 05-06-2022

"""
import numpy as np
import cv2

def filter_color(rgb_image, lower_bound_color, upper_bound_color):
    #convert the image into the HSV color space
    hsv_image = cv2.cvtColor(rgb_image, cv2.COLOR_BGR2HSV)
    #cv2.imshow("hsv image",hsv_image)

    #find the upper and lower bounds of the yellow color (tennis ball)
    yellowLower =(30, 150, 100)
    yellowUpper = (50, 255, 255)

    #define a mask using the lower and upper bounds of the yellow color
    mask = cv2.inRange(hsv_image, lower_bound_color, upper_bound_color)

    return mask

def getContours(binary_image):
    #_, contours, hierarchy = cv2.findContours(binary_image,
    #                                          cv2.RETR_TREE,
    #                                           cv2.CHAIN_APPROX_SIMPLE)
    contours, hierarchy = cv2.findContours(binary_image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    return contours

def draw_ball_contour(binary_image, rgb_image, contours):
    black_image = np.zeros([binary_image.shape[0], binary_image.shape[1],3],'uint8')

    for c in contours:
        area = cv2.contourArea(c)
        perimeter= cv2.arcLength(c, True)
        ((x, y), radius) = cv2.minEnclosingCircle(c)
        if (area>100):
            cv2.drawContours(rgb_image, [c], -1, (150,250,150), 1)
            cv2.drawContours(black_image, [c], -1, (150,250,150), 1)
            cx, cy = get_contour_center(c)
            cv2.circle(rgb_image, (cx,cy),(int)(radius),(0,0,255),1)
            cv2.circle(black_image, (cx,cy),(int)(radius),(0,0,255),1)
            cv2.circle(black_image, (cx,cy),5,(150,150,255),-1)
            print ("Area: {}, Perimeter: {}".format(area, perimeter))
    print ("number of contours: {}".format(len(contours)))
    #cv2.imshow("RGB Image Contours",rgb_image)
    cv2.imshow("Black Image Contours",black_image)
    return black_image

def get_contour_center(contour):
    M = cv2.moments(contour)
    cx=-1
    cy=-1
    if (M['m00']!=0):
        cx= int(M['m10']/M['m00'])
        cy= int(M['m01']/M['m00'])
    return cx, cy

def main(image):
    #read_video.capture()
    #image_name = "images/copy/tennis_ball_detection"+str(i)+".jpg"
    yellowLower =(30, 150, 100)
    yellowUpper = (50, 255, 255)
    #rgb_image = read_rgb_image(image_name, False)
    binary_image_mask = filter_color(image, yellowLower, yellowUpper)
    contours = getContours(binary_image_mask)
    b_image = draw_ball_contour(binary_image_mask, image,contours)
    #cv2.imwrite("images/black/tennis_ball_detection"+str(i)+".jpg",b_image)
    cv2.waitKey()
    cv2.destroyAllWindows()


"""
Given an integer array nums, find the contiguous subarray (containing at least one number)
which has the largest sum and return its sum.

Follow up: If you have figured out the O(n) solution, try coding another solution
using the divide and conquer approach, which is more subtle.

Example 1:

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
"""

"""
Greedy search

用 res 保存全局连续最大值，cur_sum 保存局部连续最大值
从左向右遍历，比较 cur_sum + num 和 num 的大小，若cur_sum + num < num，则舍弃之前的 cur_sum
使得 cur_sum = num
"""
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        res, cur_sum = float('-inf'), 0

        for num in nums:
            cur_sum = max(cur_sum + num, num)
            res = max(res, cur_sum)

        return res

    # 动态规划
    def maxSubArray2(self, nums: List[int]) -> int:
        res = nums[0]
        for i in range(1, len(nums)):
            nums[i] = max(nums[i] + nums[i-1], nums[i])
            res = max(res, nums[i])

        return res


# -*- coding: utf-8 -*-

# Imports
from scipy.optimize import linear_sum_assignment
from itertools import permutations
from copy import copy

import numpy as np

# Algoritmo
def branch_bound(n, D, F):
    """
    Implementação do Dual-Procedure Branch and Bound

    :param n: Número de dependências
    :param D: Matriz de custo de deslocamento entre dependências
    :param F: Matriz de fator de risco
    :return: Matriz de escolha com rota ótima
    """

    # Matrix C N^4 para C_bb N² por N²
    # '-> i = dependencia de origem
    # '-> j = dependencia de destino
    # '-> k = posição da rota de origem
    # '-> p = posição da rota de destino
    # '-> C_bb[i][k][j][p] = C[i][j][k][p]
    # Uma vez que esse método considera apenas números inteiros, o custo é multiplicado
    # por um fator de forma a permitir que casas decimais suficientes sejam consideradas.
    C_bb = np.zeros((n, n, n, n))
    for i in range(n):
        for j in range(n):
            for k in range(n):
                for p in range(n):
                    C_bb[i][k][j][p] = int(D[i][j] * F[i][j][k][p] * 1000)

    C_linha, menor_custo = hgb(n, C_bb)
    X, _ = branch(n, C_linha, menor_custo)
    return X

def branch(n, C_bb, menor_custo):
    """
    Função de ramificação do Dual-Procedure Branch and Bound

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :param menor_custo: Menor custo encontrado até o momento
    :return: Matriz de escolha com rota ótima e seu custo
    """

    # Caso especial: final da árvore
    if n == 1:
        return [1], C_bb[0][0][0][0]

    # BRANCH: Fixa uma dependência em uma posição e gera um problema N-1
    # '-> Fazendo C_bb[i][k] = 1, os demais C_bb[i][*] e C_bb[*][k] são forçados a 0
    X = None
    for i in range(n):
        for k in range(n):

            # Formulando custo do problema N-1 fixando C[i][k][i][k]
            # '-> C do branch = C_branch = C_bb[ic][kc] para ic,kc de 0 a N-1, ic != i, kc != k
            # '-> C_branch[ic][kc] = C[ic][kc][jc][pc] para jc,pc de 0 a N-1, jc != i, pc != k
            # '-> C_branch_final = C_branch[ic][kc][jc][kc] + C_bb[i][k][jc][kc] + C_bb[ic][kc][i][k]
            i_branch = [ic for ic in range(n) if ic != i]
            k_branch = [kc for kc in range(n) if kc != k]
            j_branch = [jc for jc in range(n) if jc != i]
            p_branch = [pc for pc in range(n) if pc != k]
            C_branch = [[[[C_bb[ic][kc][jc][pc] + C_bb[i][k][ic][kc]
                           for pc in p_branch]
                          for jc in j_branch]
                         for kc in k_branch]
                        for ic in i_branch]

            # BOUND: Checando bounds do problema
            C_branch, lb = hgb(n - 1, C_branch)

            if menor_custo is not None:
                if lb > menor_custo:
                    continue
            menor_custo = C_bb[i][k][i][k] + lb
            for ic in i_branch:
                for kc in k_branch:
                    menor_custo += C_bb[i][k][i][k]

            # Branching recursivo
            X_branch, custo_branch = branch(n-1, C_branch, menor_custo)
            if X_branch is None:
                continue

            # Atualiza solucao com menor custo
            X = np.zeros((n, n))
            X[i][k] = 1
            X_aux = [x.item() for x in np.nditer(X_branch)]
            for ic in i_branch:
                for kc in k_branch:
                    X[ic][kc] = X_aux.pop(0)

    return X, menor_custo

def hgb(n, C_bb):
    """
    Primeiro passo do algoritmo de Hahn-Grant Bound para calculo do limite inferior
    Junta os elementos complementares da matriz e resolve a LAP das submatrizes.

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :return: Matriz de custo C' no término do algoritmo :method:hungarian e o limite inferior
    """

    if n == 1:
        return C_bb, C_bb[0][0][0][0]

    # (1) Coletando elementos complementares
    C_bb = junta_elementos_complementares(n, C_bb)

    # (1) Resolve cada submatriz (LAP)
    for i in range(n):
        for k in range(n):
            C_bb = resolve_lap_submatriz(n, C_bb, i, k)

    return hgb_passo_2(n, C_bb, 0)

def hgb_passo_2(n, C_bb, R_linha):
    """
    Segundo passo do algoritmo de Hahn-Grant Bound para calculo do limite inferior.
    Roda o algoritmo húngaro na matriz de líderes e define o que deve ser feito:
    * (1) Confere se a solução foi encontrada, returnando ela caso positivo
    * (2) Se solução não encontrada, confere se teve um aumento de R' e roda o passo 3
    * (3) Se a solução não foi encontrada e não teve aumento de R', retorna o limite inferior encontrado

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :param R_linha: Fator de redução R' (limite inferior) encontrado até o momento
    :return: Matriz de custo reduzida e o limite inferior
    """
    while True:
        C_leader = np.zeros((n, n))
        for i in range(n):
            for k in range(n):
                C_leader[i][k] = C_bb[i][k][i][k]

        # (2) Hungarian Algorithm na matriz de lideres
        C_leader, reducao = hungarian(n, C_leader)
        R_linha += reducao
        for i in range(n):
            for k in range(n):
                C_bb[i][k][i][k] = C_leader[i][k]

        # (2) Primeiro caso: solução foi encontrada
        C_test = np.zeros((n, n))
        _, num_linhas = hungarian_linhas(n, C_leader)
        if num_linhas >= n:
            for i in range(n):
                for k in range(n):
                    if C_leader[i][k] == 0:
                        C_test[i][k] = 1

            # Testa as possiveis solucoes
            ic = []
            kc = []
            while True:
                size = len(ic) + len(kc)
                for i in [i for i in range(n) if i not in ic]:
                    if sum(C_test[i]) == 1:
                        for k in [k for k in range(n) if k not in kc]:
                            ic += [i]
                            kc += [k]
                for k in [k for k in range(n) if k not in kc]:
                    if sum(C_test[:][k]) == 1:
                        for i in [i for i in range(n) if i not in ic]:
                            ic += [i]
                            kc += [k]
                if size == len(ic) + len(kc):
                    break

            # Gera matrizes de permutação de possiveis soluções
            permutacao = [np.array(perm) for perm in permutations(np.identity(n))]
            for x in range(len(ic)):
                permutacao = [perm for perm in permutacao if perm[ic[x]][kc[x]] == 1]
            for X in permutacao:
                solucao_confirmada = True
                jc, pc = linear_sum_assignment(X, True)
                for x in range(n):
                    for y in range(n):
                        if C_bb[jc[x]][pc[x]][jc[y]][pc[y]] != 0:
                            solucao_confirmada = False
                            break
                    if not solucao_confirmada: break

                # Solução realmente confirmada!
                if solucao_confirmada:
                    return C_bb, R_linha

        # (2) Segundo caso: aumento do R'
        # Executa proximos passos antes de tentar novamente
        if reducao > 0:
            C_bb, R_linha = hgb_passo_3(n, C_bb, C_leader, R_linha)

        # (2) Terceiro caso: Sem solução. R' é uma borda inferior
        else:
            return C_bb, R_linha

def hgb_passo_3(n, C_bb, C_leader, R_linha):
    """
    Terceiro passo do algoritmo de Hahn-Grant Bound para calculo do limite inferior.
    Se todos os líderes forem zero, retorna o limite inferior.
    Caso contrário, redistribui uniformimente o valor dos lideres em suas submatrizes respectivas

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :param R_linha: Fator de redução R' (limite inferior) encontrado até o momento
    :return: Matriz de custo com valor dos lideres e o limite inferior e o limite inferior
    """

    # (3) Se todos os lideres forem zero
    if C_leader.sum() == 0:
        return C_bb, R_linha

    # (3) Caso contrário, para cada lider que não seja 0, distribuir uniformimente o valor em sua submatriz
    # Lembrando que os valores precisam ser inteiros
    for i in range(n):
        for k in range(n):
            if C_leader[i][k] != 0:
                base = int(C_leader[i][k]) // (n - 1)
                resto = int(C_leader[i][k]) % (n - 1) * (n - 1)
                incr_matriz = np.zeros((n, n))
                for j in [j for j in range(n) if j != i]:
                    for p in [p for p in range(n) if p != k]:
                        if resto == 0:
                            incr_matriz[j][p] = base
                        else:
                            incr_matriz[j][p] = base + 1
                            resto -= 1
                C_bb[i][k] = [list(map(sum, zip(*t))) for t in zip(C_bb[i][k], incr_matriz)]
                C_bb[i][k][i][k] -= C_leader[i][k]

    C_bb = junta_elementos_complementares(n, C_bb)

    return hgb_passo_4(n, C_bb, C_leader, R_linha)

def hgb_passo_4(n, C_bb, C_leader, R_linha):
    """
    Quarto passo do algoritmo de Hahn-Grant Bound para calculo do limite inferior.
    Resolve a LAP das submatrizes, primeiros das que tinham líder zero e depois as demais

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :param C_leader: Matriz de custo dos líderes
    :param R_linha: Fator de redução R' (limite inferior) encontrado até o momento
    :return: Matriz de custo reduzida e o limite inferior
    """
    # (4) Roda novamente o algoritmo nas submatrizes cujos lideres foram zero no passo 2
    for i in range(n):
        for k in range(n):
            if C_leader[i][k] == 0:
                C_bb = resolve_lap_submatriz(n, C_bb, i, k)
    for i in range(n):
        for k in range(n):
            if C_leader[i][k] != 0:
                C_bb = resolve_lap_submatriz(n, C_bb, i, k)
    return C_bb, R_linha

def junta_elementos_complementares(n, C_bb):
    """
    Junta os elementos complementares na matriz de custo

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :return: Matriz de custo com os elementos complementares somados e concentrados nos indices superiores
    """
    for i in range(n):
        for k in range(n):
            j_branch = [jc for jc in range(n) if jc != i]
            p_branch = [pc for pc in range(n) if pc != k]
            for j in j_branch:
                for p in p_branch:
                    if j < i:
                        C_bb[i][k][j][p] = 0
                    else:
                        C_bb[i][k][j][p] += C_bb[j][p][i][k]
    return C_bb

def resolve_lap_submatriz(n, C_bb, i, k):
    """
    Resolve o Linear Assignment Problem da submatriz C_bb[i][k]

    :param n: Número de dependências
    :param C_bb: Matriz de custo N² por N²
    :param i: Índice da dependência escolhida
    :param k: Índice da posição em que a dependência escolhida está
    :return: Matriz de custo reduzida presente no término do algoritmo :method:hungarian
    """
    j_branch = [jc for jc in range(n) if jc != i]
    p_branch = [pc for pc in range(n) if pc != k]
    C_branch = np.array([[C_bb[i][k][j][p] for p in p_branch] for j in j_branch])

    # (1) Move custo dos elementos complementares das submatrizes acima
    if i > 0:
        C_move = [[C_bb[j][p][i][k] for p in p_branch] for j in range(i)]
        for j in range(i):
            for p in range(n - 1):
                C_branch[j][p] = C_move[j][p]
            for p in p_branch:
                C_bb[j][p][i][k] = 0

    # Roda algoritmo hungaro
    C_branch, custo_branch = hungarian(n - 1, C_branch)

    # (1) Adicionando custo no lider da submatriz
    C_bb[i][k][i][k] += custo_branch
    C_aux = [c.item() for c in np.nditer(C_branch)]
    for j in j_branch:
        for p in p_branch:
            C_bb[i][k][j][p] = C_aux.pop(0)

    # (1) Destroca elementos complementares
    if i > 0:
        C_move = np.array([[C_branch[j][p] for p in range(n - 1)] for j in range(i)])
        C_move = [c.item() for c in np.nditer(C_move)]
        for j in range(i):
            for p in p_branch:
                C_bb[j][p][i][k] = C_move.pop(0)

    # Garante elementos complementares nas submatrizes em baixo estão zerados
    for i in range(n):
        for k in range(n):
            j_branch = [jc for jc in range(n) if jc != i]
            p_branch = [pc for pc in range(n) if pc != k]
            for j in j_branch:
                for p in p_branch:
                    if j < i:
                        C_bb[i][k][j][p] = 0
    return C_bb

def hungarian(n, C):
    """
    Hungarian Algorithm para resolver LAPs

    :param n: Número de dependências
    :param C: Matriz de custos
    :return: Matriz de custo reduzida e custo encontrado
    """
    C_ha = np.array(copy(C))

    # Para cada linha, subtrai todos os elementos pelo menos valor
    for j in range(n):
        menor_elemento = min(C_ha[j])
        for p in range(n):
            C_ha[j][p] -= menor_elemento

    # Para cada coluna, subtrai todos os elementos pelo menos valor
    for p in range(n):
        menor_elemento = min(C_ha[:, p])
        for j in range(n):
            C_ha[j][p] -= menor_elemento

    # Enquanto não tiver pelo menos n linhas com mais de 1 zero
    while True:

        linhas_zero, num_linhas = hungarian_linhas(n, C_ha)
        if num_linhas >= n:
            break

        # Caso contrário:
        else:

            # Identifica celula não marcadas com menor valor
            nao_marcados = []
            for j in range(n):
                for p in range(n):
                    if linhas_zero[j][p] == 0:
                        nao_marcados += [C_ha[j][p]]
            menor_nao_marcado = min(nao_marcados)

            # Subtrai menor valor não marcado nas linhas sem cruzamento
            for j in range(n):
                if sum(linhas_zero[j]) < n:
                    for p in range(n):
                        C_ha[j][p] -= menor_nao_marcado

            # Adiciona menor valor não marcado nas colunas com cruzamento
            for p in range(n):
                if sum(linhas_zero[:, p]) == n:
                    for j in range(n):
                        C_ha[j][p] += menor_nao_marcado

    # Calcula custo da solução encontrada
    js, ps = linear_sum_assignment(C_ha)
    menor_custo = 0
    for x in range(n):
        menor_custo += C[js[x]][ps[x]]

    # Retorna a matriz final e valor da solução
    return C_ha, menor_custo

def hungarian_linhas(n, C_ha):
    """
    Traça as linhas de zeros para resolução do algoritmo hungaro

    :param n: Número de dependências
    :param C_ha: Matriz de custos sendo editado pelo algoritmo hungaro
    :return: Matriz de linhas de zeros e número de linhas
    """
    # Assinala zeros
    assinala_zero = np.array([[None] * n for x in range(n)])
    for j in range(n):
        for p in range(n):
            if C_ha[j][p] == 0 and assinala_zero[j][p] is None:
                assinala_zero[j] = [0] * n
                assinala_zero[:, p] = [0] * n
                assinala_zero[j][p] = 1
                break

    # Marca linhas e colunas
    marca_linha = np.zeros(n)
    marca_coluna = np.zeros(n)
    nova_linha = np.zeros(n)
    nova_coluna = np.zeros(n)
    for j in range(n):
        if 1 not in assinala_zero[j]:
            marca_linha[j] = 1
            nova_linha[j] = 1
    while True:
        if sum(nova_linha) == 0:
            break
        else:
            for j in range(n):
                if nova_linha[j]:
                    for p in range(n):
                        if marca_coluna[p] == 0 and C_ha[j, p] == 0:
                            marca_coluna[p] = 1
                            nova_coluna[p] = 1
                    nova_linha[j] = 0
        if sum(nova_coluna) == 0:
            break
        else:
            for p in range(n):
                if nova_coluna[p]:
                    for j in range(n):
                        if marca_linha[j] == 0 and assinala_zero[j][p] == 1:
                            marca_linha[j] = 1
                            nova_linha[j] = 1
                    nova_coluna[p] = 0

    # Gera minimo conjunto de linhas
    linhas_zero = np.zeros((n, n))
    num_linhas = 0
    for j in range(n):
        if marca_linha[j] == 0:
            linhas_zero[j] = [1] * n
            num_linhas += 1
    for p in range(n):
        if marca_coluna[p]:
            linhas_zero[:, p] = [1] * n
            num_linhas += 1

    # Retorna linhas encontradas
    return linhas_zero, num_linhas

def test_vector():
    """
    Vetor de testes do artigo usado de base pro desenvolvimento do HGB

    '-> HAHN, P.; GRANT, T.; Lower Bounds For The Quadratic Assignment Problem Based Upon A Dual Formulation

    :return: Vetor de teste com 4 dependências
    """
    return [[[[105, 0, 0, 0],
              [0, 60, 120, 30],
              [0, 70, 140, 35],
              [0, 20, 40, 10]],

             [[0, 105, 0, 0],
              [108, 0, 54, 24],
              [126, 0, 63, 28],
              [36, 0, 18, 8]],

             [[0, 0, 105, 0],
              [30, 36, 0, 48],
              [35, 42, 0, 56],
              [10, 12, 0, 16]],

             [[0, 0, 0, 105],
              [48, 0, 90, 0],
              [56, 0, 105, 0],
              [16, 0, 30, 0]]],

            [[[0, 60, 120, 30],
              [90, 0, 0, 0, 0],
              [0, 50, 100, 25],
              [0, 60, 120, 30]],

             [[108, 0, 54, 24],
              [0, 90, 0, 0],
              [90, 0, 45, 20],
              [108, 0, 54, 24]],

             [[30, 36, 0, 48],
              [0, 0, 90, 0],
              [25, 30, 0, 40],
              [30, 36, 0, 48]],

             [[48, 0, 90, 0],
              [0, 0, 0, 90],
              [40, 0, 75, 0],
              [48, 0, 90, 0]]],

            [[[0, 70, 140, 35],
              [0, 50, 100, 25],
              [105, 0, 0, 0],
              [0, 10, 20, 5]],

             [[126, 0, 63, 28],
              [90, 0, 45, 20],
              [0, 105, 0, 0],
              [18, 0, 9, 4]],

             [[35, 42, 0, 56],
              [25, 30, 0, 40],
              [0, 0, 105, 0],
              [5, 6, 0, 8]],

             [[56, 0, 105, 0],
              [40, 0, 75, 0],
              [0, 0, 0, 105],
              [8, 0, 15, 0]]],

            [[[0, 20, 40, 10],
              [0, 60, 120, 30],
              [0, 10, 20, 5],
              [90, 0, 0, 0]],

             [[36, 0, 18, 8],
              [108, 0, 54, 24],
              [18, 0, 9, 4],
              [0, 90, 0, 0]],

             [[10, 12, 0, 16],
              [30, 36, 0, 48],
              [5, 6, 0, 8],
              [0, 0, 90, 0]],

             [[16, 0, 30, 0],
              [48, 0, 90, 0],
              [8, 0, 15, 0],
              [0, 0, 0, 90]]]]

# print(hgb_passo_1(4,test_vector()))


def extract_info(book_list):

    result = []

    for i in range(len(book_list)):
        if i%2==0:
            goodsTxtInfo = book_list[i].find("td", {"class" : "goodsTxtInfo"})
            aupu = goodsTxtInfo.find("div", {"class" : "aupu"}).find_all("a")
            p_list = goodsTxtInfo.find_all("p")

            title = p_list[0].find("a").string
            price = p_list[1].find("span", {"class" : "priceB"}).string
            img_src = book_list[i].find("div", {"class" : "goodsImgW"}).find("a").find("img")["src"]

            if len(aupu)==1:
                author = "편집부"
                publisher = aupu[0].string
            else:
                author = aupu[0].string
                publisher = aupu[1].string
        else:
            try:
                summary = book_list[i].find("p", {"class" : "read"}).string.strip()
            except:
                summary = "내용 없음"

            book_info = {
                "title" : title,
                "img_src" : img_src,
                "author" : author,
                "publisher" : publisher,
                "price" : price,
                "summary" : summary
            }
            result.append(book_info)

    return result