from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer

from litex.soc.cores.clock import *
from litex.soc.interconnect.csr import *
from litex.soc.cores.prbs import PRBSTX, PRBSRX
from litex.soc.cores.code_8b10b import Encoder, Decoder

from liteiclink.transceiver.gtx_7series_init import GTXTXInit, GTXRXInit
from liteiclink.transceiver.clock_aligner import BruteforceClockAligner

from liteiclink.transceiver.common import *
from liteiclink.transceiver.prbs import *

class GTXChannelPLL(Module):
    def __init__(self, refclk, refclk_freq, linerate):
        self.refclk = refclk
        self.reset = Signal()
        self.lock = Signal()
        self.config = self.compute_config(refclk_freq, linerate)

    @staticmethod
    def compute_config(refclk_freq, linerate):
        for n1 in 4, 5:
            for n2 in 1, 2, 3, 4, 5:
                for m in 1, 2:
                    vco_freq = refclk_freq*(n1*n2)/m
                    if 1.6e9 <= vco_freq <= 3.3e9:
                        for d in 1, 2, 4, 8, 16:
                            current_linerate = vco_freq*2/d
                            if current_linerate == linerate:
                                return {"n1": n1, "n2": n2, "m": m, "d": d,
                                        "vco_freq": vco_freq,
                                        "clkin": refclk_freq,
                                        "linerate": linerate}
        msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate."
        raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9))

    def __repr__(self):
        r = """
GTXChannelPLL
==============
  overview:
  ---------
       +--------------------------------------------------+
       |                                                  |
       |   +-----+  +---------------------------+ +-----+ |
       |   |     |  | Phase Frequency Detector  | |     | |
CLKIN +----> /M  +-->       Charge Pump         +-> VCO +---> CLKOUT
       |   |     |  |       Loop Filter         | |     | |
       |   +-----+  +---------------------------+ +--+--+ |
       |              ^                              |    |
       |              |    +-------+    +-------+    |    |
       |              +----+  /N2  <----+  /N1  <----+    |
       |                   +-------+    +-------+         |
       +--------------------------------------------------+
                            +-------+
                   CLKOUT +->  2/D  +-> LINERATE
                            +-------+
  config:
  -------
    CLKIN    = {clkin}MHz
    CLKOUT   = CLKIN x (N1 x N2) / M = {clkin}MHz x ({n1} x {n2}) / {m}
             = {vco_freq}GHz
    LINERATE = CLKOUT x 2 / D = {vco_freq}GHz x 2 / {d}
             = {linerate}GHz
""".format(clkin=self.config["clkin"]/1e6,
           n1=self.config["n1"],
           n2=self.config["n2"],
           m=self.config["m"],
           vco_freq=self.config["vco_freq"]/1e9,
           d=self.config["d"],
           linerate=self.config["linerate"]/1e9)
        return r

class GTXQuadPLL(Module):
    def __init__(self, refclk, refclk_freq, linerate):
        self.clk = Signal()
        self.refclk = Signal()
        self.reset = Signal()
        self.lock = Signal()
        self.config = self.compute_config(refclk_freq, linerate)

        # DRP
        self.drp = DRPInterface()

        # # #

        fbdiv_ratios = {
            16:  1,
            20:  1,
            32:  1,
            40:  1,
            64:  1,
            66:  0,
            80:  1,
            100: 1
        }
        fbdivs = {
            16:  0b0000100000,
            20:  0b0000110000,
            32:  0b0001100000,
            40:  0b0010000000,
            64:  0b0011100000,
            66:  0b0101000000,
            80:  0b0100100000,
            100: 0b0101110000
        }

        self.specials += \
            Instance("GTXE2_COMMON",
                p_QPLL_CFG=0x0680181 if self.config["vco_band"] == "upper" else
                           0x06801c1,
                p_QPLL_FBDIV=fbdivs[self.config["n"]],
                p_QPLL_FBDIV_RATIO=fbdiv_ratios[self.config["n"]],
                p_QPLL_REFCLK_DIV=self.config["m"],
                i_GTREFCLK0=refclk,
                i_QPLLRESET=self.reset,

                o_QPLLOUTCLK=self.clk,
                o_QPLLOUTREFCLK=self.refclk,
                i_QPLLLOCKEN=1,
                o_QPLLLOCK=self.lock,
                i_QPLLREFCLKSEL=0b001,

                i_DRPADDR=self.drp.addr,
                i_DRPCLK=self.drp.clk,
                i_DRPDI=self.drp.di,
                o_DRPDO=self.drp.do,
                i_DRPEN=self.drp.en,
                o_DRPRDY=self.drp.rdy,
                i_DRPWE=self.drp.we,
            )

    @staticmethod
    def compute_config(refclk_freq, linerate):
        for n in 16, 20, 32, 40, 64, 66, 80, 100:
            for m in 1, 2, 3, 4:
                vco_freq = refclk_freq*n/m
                if 5.93e9 <= vco_freq <= 8e9:
                    vco_band = "lower"
                elif 9.8e9 <= vco_freq <= 12.5e9:
                    vco_band = "upper"
                else:
                    vco_band = None
                if vco_band is not None:
                    for d in [1, 2, 4, 8, 16]:
                        current_linerate = (vco_freq/2)*2/d
                        if current_linerate == linerate:
                            return {"n": n, "m": m, "d": d,
                                    "vco_freq": vco_freq,
                                    "vco_band": vco_band,
                                    "clkin": refclk_freq,
                                    "clkout": vco_freq/2,
                                    "linerate": linerate}
        msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate."
        raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9))

    def __repr__(self):
        r = """
GTXQuadPLL
===========
  overview:
  ---------
       +-------------------------------------------------------------++
       |                                          +------------+      |
       |   +-----+  +---------------------------+ | Upper Band | +--+ |
       |   |     |  | Phase Frequency Detector  +->    VCO     | |  | |
CLKIN +----> /M  +-->       Charge Pump         | +------------+->/2+--> CLKOUT
       |   |     |  |       Loop Filter         +-> Lower Band | |  | |
       |   +-----+  +---------------------------+ |    VCO     | +--+ |
       |              ^                           +-----+------+      |
       |              |        +-------+                |             |
       |              +--------+  /N   <----------------+             |
       |                       +-------+                              |
       +--------------------------------------------------------------+
                               +-------+
                      CLKOUT +->  2/D  +-> LINERATE
                               +-------+
  config:
  -------
    CLKIN    = {clkin}MHz
    CLKOUT   = CLKIN x N / (2 x M) = {clkin}MHz x {n} / (2 x {m})
             = {clkout}GHz
    VCO      = {vco_freq}GHz ({vco_band})
    LINERATE = CLKOUT x 2 / D = {clkout}GHz x 2 / {d}
             = {linerate}GHz
""".format(clkin=self.config["clkin"]/1e6,
           n=self.config["n"],
           m=self.config["m"],
           clkout=self.config["clkout"]/1e9,
           vco_freq=self.config["vco_freq"]/1e9,
           vco_band=self.config["vco_band"],
           d=self.config["d"],
           linerate=self.config["linerate"]/1e9)
        return r

class GTX(Module, AutoCSR):
    def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, data_width=20,
                 tx_buffer_enable=False, rx_buffer_enable=False, clock_aligner=True,
                 tx_polarity=0, rx_polarity=0,
                 pll_master=True):
        assert (data_width == 20) or (data_width == 40)

        # TX controls
        self.tx_restart = Signal()
        self.tx_disable = Signal()
        self.tx_produce_square_wave = Signal()
        self.tx_prbs_config = Signal(2)

        # RX controls
        self.rx_ready = Signal()
        self.rx_restart = Signal()
        self.rx_prbs_config = Signal(2)
        self.rx_prbs_errors = Signal(32)

        # DRP
        self.drp = DRPInterface()

        # Loopback
        self.loopback = Signal(3)

        # # #

        nwords = data_width//10

        self.submodules.encoder = ClockDomainsRenamer("tx")(
            Encoder(nwords, True))
        self.decoders = [ClockDomainsRenamer("rx")(
            Decoder(True)) for _ in range(nwords)]
        self.submodules += self.decoders

        # transceiver direct clock outputs
        # useful to specify clock constraints in a way palatable to Vivado
        self.txoutclk = Signal()
        self.rxoutclk = Signal()

        self.tx_clk_freq = pll.config["linerate"]/data_width
        self.rx_clk_freq = pll.config["linerate"]/data_width

        # control/status cdc
        tx_produce_square_wave = Signal()
        tx_prbs_config = Signal(2)

        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        self.specials += [
            MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"),
            MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"),
        ]

        self.specials += [
            MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME
        ]

        # # #

        use_cpll = isinstance(pll, GTXChannelPLL)
        use_qpll = isinstance(pll, GTXQuadPLL)

        # TX generates TX clock, init must be in system domain
        self.submodules.tx_init = tx_init = GTXTXInit(sys_clk_freq, buffer_enable=tx_buffer_enable)
        self.comb += tx_init.restart.eq(self.tx_restart)
        # RX receives restart commands from TX domain
        self.submodules.rx_init = rx_init = ClockDomainsRenamer("tx")(
            GTXRXInit(self.tx_clk_freq, buffer_enable=rx_buffer_enable))
        self.comb += [
            tx_init.plllock.eq(pll.lock),
            rx_init.plllock.eq(pll.lock)
        ]
        if pll_master:
            self.comb += pll.reset.eq(tx_init.pllreset)

        # DRP mux
        self.submodules.drp_mux = drp_mux = DRPMux()
        drp_mux.add_interface(self.drp)

        rxcdr_cfgs = {
            1 : 0x03000023ff10400020,
            2 : 0x03000023ff10200020,
            4 : 0x03000023ff10100020,
            8 : 0x03000023ff10080020,
           16 : 0x03000023ff10080020,
        }

        txdata = Signal(data_width)
        rxdata = Signal(data_width)

        self.gtx_params = dict(
            # Simulation-Only Attributes
            p_SIM_RECEIVER_DETECT_PASS   ="TRUE",
            p_SIM_TX_EIDLE_DRIVE_LEVEL   ="X",
            p_SIM_RESET_SPEEDUP          ="FALSE",
            p_SIM_CPLLREFCLK_SEL         ="FALSE",
            p_SIM_VERSION                ="4.0",

            # RX Byte and Word Alignment Attributes
            p_ALIGN_COMMA_DOUBLE                     ="FALSE",
            p_ALIGN_COMMA_ENABLE                     =0b1111111111,
            p_ALIGN_COMMA_WORD                       =2 if data_width == 20 else 4,
            p_ALIGN_MCOMMA_DET                       ="TRUE",
            p_ALIGN_MCOMMA_VALUE                     =0b1010000011,
            p_ALIGN_PCOMMA_DET                       ="TRUE",
            p_ALIGN_PCOMMA_VALUE                     =0b0101111100,
            p_SHOW_REALIGN_COMMA                     ="TRUE",
            p_RXSLIDE_AUTO_WAIT                      =7,
            p_RXSLIDE_MODE                           ="OFF" if rx_buffer_enable else "PCS",
            p_RX_SIG_VALID_DLY                       =10,

            # RX 8B/10B Decoder Attributes
            p_RX_DISPERR_SEQ_MATCH                   ="TRUE",
            p_DEC_MCOMMA_DETECT                      ="TRUE",
            p_DEC_PCOMMA_DETECT                      ="TRUE",
            p_DEC_VALID_COMMA_ONLY                   ="TRUE",

            # RX Clock Correction Attributes
            p_CBCC_DATA_SOURCE_SEL                   ="DECODED",
            p_CLK_COR_SEQ_2_USE                      ="FALSE",
            p_CLK_COR_KEEP_IDLE                      ="FALSE",
            p_CLK_COR_MAX_LAT                        =9 if data_width == 20 else 20,
            p_CLK_COR_MIN_LAT                        =7 if data_width == 20 else 16,
            p_CLK_COR_PRECEDENCE                     ="TRUE",
            p_CLK_COR_REPEAT_WAIT                    =0,
            p_CLK_COR_SEQ_LEN                        =1,
            p_CLK_COR_SEQ_1_ENABLE                   =0b1111,
            p_CLK_COR_SEQ_1_1                        =0b0100000000,
            p_CLK_COR_SEQ_1_2                        =0b0000000000,
            p_CLK_COR_SEQ_1_3                        =0b0000000000,
            p_CLK_COR_SEQ_1_4                        =0b0000000000,
            p_CLK_CORRECT_USE                        ="FALSE",
            p_CLK_COR_SEQ_2_ENABLE                   =0b1111,
            p_CLK_COR_SEQ_2_1                        =0b0100000000,
            p_CLK_COR_SEQ_2_2                        =0b0000000000,
            p_CLK_COR_SEQ_2_3                        =0b0000000000,
            p_CLK_COR_SEQ_2_4                        =0b0000000000,

            # RX Channel Bonding Attributes
            p_CHAN_BOND_KEEP_ALIGN                   ="FALSE",
            p_CHAN_BOND_MAX_SKEW                     =1,
            p_CHAN_BOND_SEQ_LEN                      =1,
            p_CHAN_BOND_SEQ_1_1                      =0b0000000000,
            p_CHAN_BOND_SEQ_1_2                      =0b0000000000,
            p_CHAN_BOND_SEQ_1_3                      =0b0000000000,
            p_CHAN_BOND_SEQ_1_4                      =0b0000000000,
            p_CHAN_BOND_SEQ_1_ENABLE                 =0b1111,
            p_CHAN_BOND_SEQ_2_1                      =0b0000000000,
            p_CHAN_BOND_SEQ_2_2                      =0b0000000000,
            p_CHAN_BOND_SEQ_2_3                      =0b0000000000,
            p_CHAN_BOND_SEQ_2_4                      =0b0000000000,
            p_CHAN_BOND_SEQ_2_ENABLE                 =0b1111,
            p_CHAN_BOND_SEQ_2_USE                    ="FALSE",
            p_FTS_DESKEW_SEQ_ENABLE                  =0b1111,
            p_FTS_LANE_DESKEW_CFG                    =0b1111,
            p_FTS_LANE_DESKEW_EN                     ="FALSE",

            # RX Margin Analysis Attributes
            p_ES_CONTROL                             =0b000000,
            p_ES_ERRDET_EN                           ="FALSE",
            p_ES_EYE_SCAN_EN                         ="TRUE",
            p_ES_HORZ_OFFSET                         =0x000,
            p_ES_PMA_CFG                             =0b0000000000,
            p_ES_PRESCALE                            =0b00000,
            p_ES_QUALIFIER                           =0x00000000000000000000,
            p_ES_QUAL_MASK                           =0x00000000000000000000,
            p_ES_SDATA_MASK                          =0x00000000000000000000,
            p_ES_VERT_OFFSET                         =0b000000000,

            # FPGA RX Interface Attributes
            p_RX_DATA_WIDTH                          =data_width,

            # PMA Attributes
            p_OUTREFCLK_SEL_INV                      =0b11,
            p_PMA_RSV                                =0x001e7080,
            p_PMA_RSV2                               =0x2050,
            p_PMA_RSV3                               =0b00,
            p_PMA_RSV4                               =0x00000000,
            p_RX_BIAS_CFG                            =0b000000000100,
            p_DMONITOR_CFG                           =0x000A00,
            p_RX_CM_SEL                              =0b11,
            p_RX_CM_TRIM                             =0b010,
            p_RX_DEBUG_CFG                           =0b000000000000,
            p_RX_OS_CFG                              =0b0000010000000,
            p_TERM_RCAL_CFG                          =0b10000,
            p_TERM_RCAL_OVRD                         =0b0,
            p_TST_RSV                                =0x00000000,
            p_RX_CLK25_DIV                           =5,
            p_TX_CLK25_DIV                           =5,
            p_UCODEER_CLR                            =0b0,

            # PCI Express Attributes
            p_PCS_PCIE_EN                            ="FALSE",

            # PCS Attributes
            p_PCS_RSVD_ATTR                          =0x000000000000,

            # RX Buffer Attributes
            p_RXBUF_ADDR_MODE                        ="FAST",
            p_RXBUF_EIDLE_HI_CNT                     =0b1000,
            p_RXBUF_EIDLE_LO_CNT                     =0b0000,
            p_RXBUF_EN                               ="TRUE" if rx_buffer_enable else "FALSE",
            p_RX_BUFFER_CFG                          =0b000000,
            p_RXBUF_RESET_ON_CB_CHANGE               ="TRUE",
            p_RXBUF_RESET_ON_COMMAALIGN              ="FALSE",
            p_RXBUF_RESET_ON_EIDLE                   ="FALSE",
            p_RXBUF_RESET_ON_RATE_CHANGE             ="TRUE",
            p_RXBUFRESET_TIME                        =0b00001,
            p_RXBUF_THRESH_OVFLW                     =61,
            p_RXBUF_THRESH_OVRD                      ="FALSE",
            p_RXBUF_THRESH_UNDFLW                    =4,
            p_RXDLY_CFG                              =0x001F,
            p_RXDLY_LCFG                             =0x030,
            p_RXDLY_TAP_CFG                          =0x0000,
            p_RXPH_CFG                               =0x000000,
            p_RXPHDLY_CFG                            =0x084020,
            p_RXPH_MONITOR_SEL                       =0b00000,
            p_RX_XCLK_SEL                            ="RXREC" if rx_buffer_enable else "RXUSR",
            p_RX_DDI_SEL                             =0b000000,
            p_RX_DEFER_RESET_BUF_EN                  ="TRUE",

            # CDR Attributes
            p_RXCDR_CFG                              =rxcdr_cfgs[pll.config["d"]],
            p_RXCDR_FR_RESET_ON_EIDLE                =0b0,
            p_RXCDR_HOLD_DURING_EIDLE                =0b0,
            p_RXCDR_PH_RESET_ON_EIDLE                =0b0,
            p_RXCDR_LOCK_CFG                         =0b010101,

            # RX Initialization and Reset Attributes
            p_RXCDRFREQRESET_TIME                    =0b00001,
            p_RXCDRPHRESET_TIME                      =0b00001,
            p_RXISCANRESET_TIME                      =0b00001,
            p_RXPCSRESET_TIME                        =0b00001,
            p_RXPMARESET_TIME                        =0b00011,

            # RX OOB Signaling Attributes
            p_RXOOB_CFG                              =0b0000110,

            # RX Gearbox Attributes
            p_RXGEARBOX_EN                           ="FALSE",
            p_GEARBOX_MODE                           =0b000,

            # PRBS Detection Attribute
            p_RXPRBS_ERR_LOOPBACK                    =0b0,

            # Power-Down Attributes
            p_PD_TRANS_TIME_FROM_P2                  =0x03c,
            p_PD_TRANS_TIME_NONE_P2                  =0x3c,
            p_PD_TRANS_TIME_TO_P2                    =0x64,

            # RX OOB Signaling Attributes
            p_SAS_MAX_COM                            =64,
            p_SAS_MIN_COM                            =36,
            p_SATA_BURST_SEQ_LEN                     =0b0101,
            p_SATA_BURST_VAL                         =0b100,
            p_SATA_EIDLE_VAL                         =0b100,
            p_SATA_MAX_BURST                         =8,
            p_SATA_MAX_INIT                          =21,
            p_SATA_MAX_WAKE                          =7,
            p_SATA_MIN_BURST                         =4,
            p_SATA_MIN_INIT                          =12,
            p_SATA_MIN_WAKE                          =4,

            # RX Fabric Clock Output Control Attributes
            p_TRANS_TIME_RATE                        =0x0E,

            # TX Buffer Attributes
            p_TXBUF_EN                               ="TRUE" if tx_buffer_enable else "FALSE",
            p_TXBUF_RESET_ON_RATE_CHANGE             ="TRUE",
            p_TXDLY_CFG                              =0x001F,
            p_TXDLY_LCFG                             =0x030,
            p_TXDLY_TAP_CFG                          =0x0000,
            p_TXPH_CFG                               =0x0780,
            p_TXPHDLY_CFG                            =0x084020,
            p_TXPH_MONITOR_SEL                       =0b00000,
            p_TX_XCLK_SEL                            ="TXOUT" if tx_buffer_enable else "TXUSR",

            # FPGA TX Interface Attributes
            p_TX_DATA_WIDTH                          =data_width,

            # TX Configurable Driver Attributes
            p_TX_DEEMPH0                             =0b00000,
            p_TX_DEEMPH1                             =0b00000,
            p_TX_EIDLE_ASSERT_DELAY                  =0b110,
            p_TX_EIDLE_DEASSERT_DELAY                =0b100,
            p_TX_LOOPBACK_DRIVE_HIZ                  ="FALSE",
            p_TX_MAINCURSOR_SEL                      =0b0,
            p_TX_DRIVE_MODE                          ="DIRECT",
            p_TX_MARGIN_FULL_0                       =0b1001110,
            p_TX_MARGIN_FULL_1                       =0b1001001,
            p_TX_MARGIN_FULL_2                       =0b1000101,
            p_TX_MARGIN_FULL_3                       =0b1000010,
            p_TX_MARGIN_FULL_4                       =0b1000000,
            p_TX_MARGIN_LOW_0                        =0b1000110,
            p_TX_MARGIN_LOW_1                        =0b1000100,
            p_TX_MARGIN_LOW_2                        =0b1000010,
            p_TX_MARGIN_LOW_3                        =0b1000000,
            p_TX_MARGIN_LOW_4                        =0b1000000,

            # TX Gearbox Attributes
            p_TXGEARBOX_EN                           ="FALSE",

            # TX Initialization and Reset Attributes
            p_TXPCSRESET_TIME                        =0b00001,
            p_TXPMARESET_TIME                        =0b00001,

            # TX Receiver Detection Attributes
            p_TX_RXDETECT_CFG                        =0x1832,
            p_TX_RXDETECT_REF                        =0b100,

            # CPLL Attributes
            p_CPLL_CFG                               =0xBC07DC,
            p_CPLL_FBDIV                             =1 if use_qpll else pll.config["n2"],
            p_CPLL_FBDIV_45                          =4 if use_qpll else pll.config["n1"],
            p_CPLL_INIT_CFG                          =0x00001E,
            p_CPLL_LOCK_CFG                          =0x01E8,
            p_CPLL_REFCLK_DIV                        =1 if use_qpll else pll.config["m"],
            p_RXOUT_DIV                              =pll.config["d"],
            p_TXOUT_DIV                              =pll.config["d"],
            p_SATA_CPLL_CFG                          ="VCO_3000MHZ",

            # RX Initialization and Reset Attributes
            p_RXDFELPMRESET_TIME                     =0b0001111,

            # RX Equalizer Attributes
            p_RXLPM_HF_CFG                           =0b00000011110000,
            p_RXLPM_LF_CFG                           =0b00000011110000,
            p_RX_DFE_GAIN_CFG                        =0x020FEA,
            p_RX_DFE_H2_CFG                          =0b000000000000,
            p_RX_DFE_H3_CFG                          =0b000001000000,
            p_RX_DFE_H4_CFG                          =0b00011110000,
            p_RX_DFE_H5_CFG                          =0b00011100000,
            p_RX_DFE_KL_CFG                          =0b0000011111110,
            p_RX_DFE_LPM_CFG                         =0x0954,
            p_RX_DFE_LPM_HOLD_DURING_EIDLE           =0b0,
            p_RX_DFE_UT_CFG                          =0b10001111000000000,
            p_RX_DFE_VP_CFG                          =0b00011111100000011,

            # Power-Down Attributes
            p_RX_CLKMUX_PD                           =0b1,
            p_TX_CLKMUX_PD                           =0b1,

            # FPGA RX Interface Attribute
            p_RX_INT_DATAWIDTH                       =data_width == 40,

            # FPGA TX Interface Attribute
            p_TX_INT_DATAWIDTH                       =data_width == 40,

            # TX Configurable Driver Attributes
            p_TX_QPI_STATUS_EN                       =0b0,

            # RX Equalizer Attributes
            p_RX_DFE_KL_CFG2                         =0x301148AC,
            p_RX_DFE_XYD_CFG                         =0b0000000000000,

            # TX Configurable Driver Attributes
            p_TX_PREDRIVER_MODE                      =0b0
        )
        self.gtx_params.update(
            # CPLL Ports
            #o_CPLLFBCLKLOST                  =,
            o_CPLLLOCK                       =Signal() if use_qpll else pll.lock,
            i_CPLLLOCKDETCLK                 =ClockSignal(),
            i_CPLLLOCKEN                     =1,
            i_CPLLPD                         =0,
            #o_CPLLREFCLKLOST                 =,
            i_CPLLREFCLKSEL                  =0b001,
            i_CPLLRESET                      =0 if use_qpll else pll.reset,
            i_GTRSVD                         =0b0000000000000000,
            i_PCSRSVDIN                      =0b0000000000000000,
            i_PCSRSVDIN2                     =0b00000,
            i_PMARSVDIN                      =0b00000,
            i_PMARSVDIN2                     =0b00000,
            i_TSTIN                          =0b11111111111111111111,
            #o_TSTOUT                         =,

            # Channel
            i_CLKRSVD                        =0b0000,

            # Channel - Clocking Ports
            i_GTGREFCLK                      =0,
            i_GTNORTHREFCLK0                 =0,
            i_GTNORTHREFCLK1                 =0,
            i_GTREFCLK0                      =0 if use_qpll else pll.refclk,
            i_GTREFCLK1                      =0,
            i_GTSOUTHREFCLK0                 =0,
            i_GTSOUTHREFCLK1                 =0,

            # Channel - DRP Ports
            i_DRPADDR                        =drp_mux.addr,
            i_DRPCLK                         =drp_mux.clk,
            i_DRPDI                          =drp_mux.di,
            o_DRPDO                          =drp_mux.do,
            i_DRPEN                          =drp_mux.en,
            o_DRPRDY                         =drp_mux.rdy,
            i_DRPWE                          =drp_mux.we,

            # Clocking Ports
            #o_GTREFCLKMONITOR                =,
            i_QPLLCLK                        =0 if use_cpll else pll.clk,
            i_QPLLREFCLK                     =0 if use_cpll else pll.refclk,
            i_RXSYSCLKSEL                    =0b11 if use_qpll else 0b00,
            i_TXSYSCLKSEL                    =0b11 if use_qpll else 0b00,

            # Digital Monitor Ports
            #o_DMONITOROUT                    =,

            # FPGA TX Interface Datapath Configuration
            i_TX8B10BEN                      =0,

            # Loopback Ports
            i_LOOPBACK                       =self.loopback,

            # PCI Express Ports
            #o_PHYSTATUS                      =,
            i_RXRATE                         =0b000,
            #o_RXVALID                        =,

            # Power-Down Ports
            i_RXPD                           =Cat(rx_init.gtXxpd, rx_init.gtXxpd),
            i_TXPD                           =0b00,

            # RX 8B/10B Decoder Ports
            i_SETERRSTATUS                   =0,

            # RX Initialization and Reset Ports
            i_EYESCANRESET                   =0,
            i_RXUSERRDY                      =rx_init.Xxuserrdy,

            # RX Margin Analysis Ports
            #o_EYESCANDATAERROR               =,
            i_EYESCANMODE                    =0,
            i_EYESCANTRIGGER                 =0,

            # Receive Ports - CDR Ports
            i_RXCDRFREQRESET                 =0,
            i_RXCDRHOLD                      =0,
            #o_RXCDRLOCK                      =,
            i_RXCDROVRDEN                    =0,
            i_RXCDRRESET                     =0,
            i_RXCDRRESETRSV                  =0,

            # Receive Ports - Clock Correction Ports
            #o_RXCLKCORCNT                    =,

            # Receive Ports - FPGA RX Interface Datapath Configuration
            i_RX8B10BEN                      =0,

            # Receive Ports - FPGA RX Interface Ports
            i_RXUSRCLK                       =ClockSignal("rx"),
            i_RXUSRCLK2                      =ClockSignal("rx"),

            # Receive Ports - FPGA RX interface Ports
            o_RXDATA                         =Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]),

            # Receive Ports - Pattern Checker Ports
            #o_RXPRBSERR                      =,
            i_RXPRBSSEL                      =0b000,

            # Receive Ports - Pattern Checker ports
            i_RXPRBSCNTRESET                 =0,

            # Receive Ports - RX  Equalizer Ports
            i_RXDFEXYDEN                     =1,
            i_RXDFEXYDHOLD                   =0,
            i_RXDFEXYDOVRDEN                 =0,

            # Receive Ports - RX 8B/10B Decoder Ports
            i_RXDISPERR                      =Cat(*[rxdata[10*i+9] for i in range(nwords)]),
            #o_RXNOTINTABLE                   =,

            # Receive Ports - RX AFE
            i_GTXRXP                         =rx_pads.p,
            i_GTXRXN                         =rx_pads.n,

            # Receive Ports - RX Buffer Bypass Ports
            i_RXBUFRESET                     =0,
            #o_RXBUFSTATUS                    =,
            i_RXDDIEN                        =0 if rx_buffer_enable else 1,
            i_RXDLYBYPASS                    =1 if rx_buffer_enable else 0,
            i_RXDLYEN                        =0,
            i_RXDLYOVRDEN                    =0,
            i_RXDLYSRESET                    =rx_init.Xxdlysreset,
            o_RXDLYSRESETDONE                =rx_init.Xxdlysresetdone,
            i_RXPHALIGN                      =0,
            o_RXPHALIGNDONE                  =rx_init.Xxphaligndone,
            i_RXPHALIGNEN                    =0,
            i_RXPHDLYPD                      =0,
            i_RXPHDLYRESET                   =0,
            #o_RXPHMONITOR                    =,
            i_RXPHOVRDEN                     =0,
            #o_RXPHSLIPMONITOR                =,
            #o_RXSTATUS                       =,

            # Receive Ports - RX Byte and Word Alignment Ports
            #o_RXBYTEISALIGNED                =,
            #o_RXBYTEREALIGN                  =,
            #o_RXCOMMADET                     =,
            i_RXCOMMADETEN                   =1,
            i_RXMCOMMAALIGNEN                =(rx_prbs_config == 0b00) if rx_buffer_enable else 0,
            i_RXPCOMMAALIGNEN                =(rx_prbs_config == 0b00) if rx_buffer_enable else 0,

            # Receive Ports - RX Channel Bonding Ports
            #o_RXCHANBONDSEQ                  =,
            i_RXCHBONDEN                     =0,
            i_RXCHBONDLEVEL                  =0b000,
            i_RXCHBONDMASTER                 =0,
            #o_RXCHBONDO                      =,
            i_RXCHBONDSLAVE                  =0,

            # Receive Ports - RX Channel Bonding Ports
            #o_RXCHANISALIGNED                =,
            #o_RXCHANREALIGN                  =,

            # Receive Ports - RX Equailizer Ports
            i_RXLPMHFHOLD                    =0,
            i_RXLPMHFOVRDEN                  =0,
            i_RXLPMLFHOLD                    =0,

            # Receive Ports - RX Equalizer Ports
            i_RXDFEAGCHOLD                   =0,
            i_RXDFEAGCOVRDEN                 =0,
            i_RXDFECM1EN                     =0,
            i_RXDFELFHOLD                    =0,
            i_RXDFELFOVRDEN                  =1,
            i_RXDFELPMRESET                  =0,
            i_RXDFETAP2HOLD                  =0,
            i_RXDFETAP2OVRDEN                =0,
            i_RXDFETAP3HOLD                  =0,
            i_RXDFETAP3OVRDEN                =0,
            i_RXDFETAP4HOLD                  =0,
            i_RXDFETAP4OVRDEN                =0,
            i_RXDFETAP5HOLD                  =0,
            i_RXDFETAP5OVRDEN                =0,
            i_RXDFEUTHOLD                    =0,
            i_RXDFEUTOVRDEN                  =0,
            i_RXDFEVPHOLD                    =0,
            i_RXDFEVPOVRDEN                  =0,
            i_RXDFEVSEN                      =0,
            i_RXLPMLFKLOVRDEN                =0,
            #o_RXMONITOROUT                   =
            i_RXMONITORSEL                   =0,
            i_RXOSHOLD                       =0,
            i_RXOSOVRDEN                     =0,

            # Receive Ports - RX Fabric ClocK Output Control Ports
            #o_RXRATEDONE                     =,

            # Receive Ports - RX Fabric Output Control Ports
            o_RXOUTCLK                       =self.rxoutclk,
            #o_RXOUTCLKFABRIC                 =,
            #o_RXOUTCLKPCS                    =,
            i_RXOUTCLKSEL                    =0b010,

            # Receive Ports - RX Gearbox Ports
            #o_RXDATAVALID                    =,
            #o_RXHEADER                       =,
            #o_RXHEADERVALID                  =,
            #o_RXSTARTOFSEQ                   =,

            # Receive Ports - RX Gearbox Ports
            i_RXGEARBOXSLIP                  =0,

            # Receive Ports - RX Initialization and Reset Ports
            i_GTRXRESET                      =rx_init.gtXxreset,
            i_RXOOBRESET                     =0,
            i_RXPCSRESET                     =0,
            i_RXPMARESET                     =0,

            # Receive Ports - RX Margin Analysis ports
            i_RXLPMEN                        =0,

            # Receive Ports - RX OOB Signaling ports
            #o_RXCOMSASDET                    =,
            #o_RXCOMWAKEDET                   =,

            # Receive Ports - RX OOB Signaling ports
            #o_RXCOMINITDET                   =,

            # Receive Ports - RX OOB signalling Ports
            #o_RXELECIDLE                     =,
            i_RXELECIDLEMODE                 =0b11,

            # Receive Ports - RX Polarity Control Ports
            i_RXPOLARITY                     =rx_polarity,

            # Receive Ports - RX gearbox ports
            i_RXSLIDE                        =0,

            # Receive Ports - RX8B/10B Decoder Ports
            #o_RXCHARISCOMMA                  =,
            o_RXCHARISK                      =Cat(*[rxdata[10*i+8] for i in range(nwords)]),

            # Receive Ports - Rx Channel Bonding Ports
            i_RXCHBONDI                      =0b00000,

            # Receive Ports -RX Initialization and Reset Ports
            o_RXRESETDONE                    =rx_init.Xxresetdone,

            # Rx AFE Ports
            i_RXQPIEN                        =0,
            #o_RXQPISENN                      =,
            #o_RXQPISENP                      =,

            # TX Buffer Bypass Ports
            i_TXPHDLYTSTCLK                  =0,

            # TX Configurable Driver Ports
            i_TXPOSTCURSOR                   =0b00000,
            i_TXPOSTCURSORINV                =0,
            i_TXPRECURSOR                    =0b00000,
            i_TXPRECURSORINV                 =0,
            i_TXQPIBIASEN                    =0,
            i_TXQPISTRONGPDOWN               =0,
            i_TXQPIWEAKPUP                   =0,

            # TX Initialization and Reset Ports
            i_CFGRESET                       =0,
            i_GTTXRESET                      =tx_init.gtXxreset,
            #o_PCSRSVDOUT                     =,
            i_TXUSERRDY                      =tx_init.Xxuserrdy,

            # Transceiver Reset Mode Operation
            i_GTRESETSEL                     =0,
            i_RESETOVRD                      =0,

            # Transmit Ports - 8b10b Encoder Control Ports
            i_TXCHARDISPMODE                 =Cat(*[txdata[10*i+9] for i in range(nwords)]),
            i_TXCHARDISPVAL                  =Cat(*[txdata[10*i+8] for i in range(nwords)]),

            # Transmit Ports - FPGA TX Interface Ports
            i_TXUSRCLK                       =ClockSignal("tx"),
            i_TXUSRCLK2                      =ClockSignal("tx"),

            # Transmit Ports - PCI Express Ports
            i_TXELECIDLE                     =0,
            i_TXMARGIN                       =0b000,
            i_TXRATE                         =0b000,
            i_TXSWING                        =0,

            # Transmit Ports - Pattern Generator Ports
            i_TXPRBSFORCEERR                 =0,

            # Transmit Ports - TX Buffer Bypass Ports
            i_TXDLYBYPASS                    =1 if tx_buffer_enable else 0,
            i_TXDLYEN                        =0,
            i_TXDLYHOLD                      =0,
            i_TXDLYOVRDEN                    =0,
            i_TXDLYSRESET                    =tx_init.Xxdlysreset,
            o_TXDLYSRESETDONE                =tx_init.Xxdlysresetdone,
            i_TXDLYUPDOWN                    =0,
            i_TXPHALIGN                      =0,
            o_TXPHALIGNDONE                  =tx_init.Xxphaligndone,
            i_TXPHALIGNEN                    =0,
            i_TXPHDLYPD                      =0,
            i_TXPHDLYRESET                   =0,
            i_TXPHINIT                       =0,
            #o_TXPHINITDONE                   =,
            i_TXPHOVRDEN                     =0,

            # Transmit Ports - TX Buffer Ports
            #o_TXBUFSTATUS                    =,

            # Transmit Ports - TX Configurable Driver Ports
            i_TXBUFDIFFCTRL                  =0b100,
            i_TXDEEMPH                       =0,
            i_TXDIFFCTRL                     =0b1000,
            i_TXDIFFPD                       =0,
            i_TXINHIBIT                      =self.tx_disable,
            i_TXMAINCURSOR                   =0b0000000,
            i_TXPISOPD                       =0,

            # Transmit Ports - TX Data Path interface
            i_TXDATA                         =Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]),

            # Transmit Ports - TX Driver and OOB signaling
            o_GTXTXN                         =tx_pads.n,
            o_GTXTXP                         =tx_pads.p,

            # Transmit Ports - TX Fabric Clock Output Control Ports
            o_TXOUTCLK                       =self.txoutclk,
            #o_TXOUTCLKFABRIC                 =,
            #o_TXOUTCLKPCS                    =,
            i_TXOUTCLKSEL                    =0b010 if tx_buffer_enable else 0b011,
            #o_TXRATEDONE                     =,

            # Transmit Ports - TX Gearbox Ports
            i_TXCHARISK                      =0b00000000,
            #o_TXGEARBOXREADY                 =,
            i_TXHEADER                       =0b000,
            i_TXSEQUENCE                     =0b0000000,
            i_TXSTARTSEQ                     =0,

            # Transmit Ports - TX Initialization and Reset Ports
            i_TXPCSRESET                     =0,
            i_TXPMARESET                     =0,
            o_TXRESETDONE                    =tx_init.Xxresetdone,

            # Transmit Ports - TX OOB signaling Ports
            #o_TXCOMFINISH                    =,
            i_TXCOMINIT                      =0,
            i_TXCOMSAS                       =0,
            i_TXCOMWAKE                      =0,
            i_TXPDELECIDLEMODE               =0,

            # Transmit Ports - TX Polarity Control Ports
            i_TXPOLARITY                     =tx_polarity,

            # Transmit Ports - TX Receiver Detection Ports
            i_TXDETECTRX                     =0,

            # Transmit Ports - TX8b/10b Encoder Ports
            i_TX8B10BBYPASS                  =0b00000000,

            # Transmit Ports - pattern Generator Ports
            i_TXPRBSSEL                      =0b000,

            # Tx Configurable Driver  Ports
            #o_TXQPISENN                      =,
            #o_TXQPISENP                      =,
            )

        # tx clocking
        tx_reset_deglitched = Signal()
        tx_reset_deglitched.attr.add("no_retiming")
        self.sync += tx_reset_deglitched.eq(~tx_init.done)
        self.clock_domains.cd_tx = ClockDomain()

        txoutclk_bufg = Signal()
        self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg)

        if not tx_buffer_enable:
            txoutclk_div = pll.config["clkin"]/self.tx_clk_freq
        else:
            txoutclk_div = 1
        # Use txoutclk_bufg when divider is 1
        if txoutclk_div == 1:
            self.comb += self.cd_tx.clk.eq(txoutclk_bufg)
            self.specials += AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched)
        # Use a BUFR when integer divider (with BUFR_DIVIDE)
        elif txoutclk_div == int(txoutclk_div):
            txoutclk_bufr = Signal()
            self.specials += [
                Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr,
                    i_CE=1, p_BUFR_DIVIDE=str(int(txoutclk_div))),
                Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_tx.clk),
                AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched)
            ]
        # Use a PLL when non-integer divider
        else:
            txoutclk_pll = S7PLL()
            self.comb += txoutclk_pll.reset.eq(tx_reset_deglitched)
            self.submodules += txoutclk_pll
            txoutclk_pll.register_clkin(txoutclk_bufg, pll.config["clkin"])
            txoutclk_pll.create_clkout(self.cd_tx, self.tx_clk_freq)

        # rx clocking
        rx_reset_deglitched = Signal()
        rx_reset_deglitched.attr.add("no_retiming")
        self.sync.tx += rx_reset_deglitched.eq(~rx_init.done)
        self.clock_domains.cd_rx = ClockDomain()
        self.specials += [
            Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rx.clk),
            AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched)
        ]

        # tx data and prbs
        self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX(data_width, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.comb += [
            self.tx_prbs.i.eq(Cat(*[self.encoder.output[i] for i in range(nwords)])),
            If(tx_produce_square_wave,
                # square wave @ linerate/data_width for scope observation
                txdata.eq(Signal(data_width, reset=1<<(data_width//2)-1))
            ).Else(
                txdata.eq(self.tx_prbs.o)
            )
        ]

        # rx data and prbs
        self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX(data_width, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        for i in range(nwords):
            self.comb += self.decoders[i].input.eq(rxdata[10*i:10*(i+1)])
        self.comb += self.rx_prbs.i.eq(rxdata)

        # clock alignment
        if clock_aligner:
            clock_aligner = BruteforceClockAligner(0b0101111100, self.tx_clk_freq)
            self.submodules.clock_aligner = clock_aligner
            self.comb += [
                clock_aligner.rxdata.eq(rxdata),
                rx_init.restart.eq(clock_aligner.restart | self.rx_restart),
                self.rx_ready.eq(clock_aligner.ready)
            ]
        else:
            self.comb += self.rx_ready.eq(rx_init.done)

    def add_base_control(self):
        if hasattr(self, "clock_aligner"):
            self._clock_aligner_disable  = CSRStorage()
        self._tx_restart             = CSR()
        self._tx_disable             = CSRStorage(reset=0b0)
        self._tx_produce_square_wave = CSRStorage(reset=0b0)
        self._rx_ready               = CSRStatus()
        self._rx_restart             = CSR()
        if hasattr(self, "clock_aligner"):
            self.comb += self.clock_aligner.disable.eq(self._clock_aligner_disable.storage)
        self.comb += [
            self.tx_restart.eq(self._tx_restart.re),
            self.tx_disable.eq(self._tx_disable.storage),
            self.tx_produce_square_wave.eq(self._tx_produce_square_wave.storage),
            self._rx_ready.status.eq(self.rx_ready),
            self.rx_restart.eq(self._rx_restart.re)
        ]

    def add_prbs_control(self):
        self._tx_prbs_config = CSRStorage(2, reset=0b00)
        self._rx_prbs_config = CSRStorage(2, reset=0b00)
        self._rx_prbs_errors = CSRStatus(32)
        self.comb += [
            self.tx_prbs_config.eq(self._tx_prbs_config.storage),
            self.rx_prbs_config.eq(self._rx_prbs_config.storage),
            self._rx_prbs_errors.status.eq(self.rx_prbs_errors)
        ]

    def add_loopback_control(self):
        self._loopback = CSRStorage(3)
        self.comb += self.loopback.eq(self._loopback.storage)

    def add_polarity_control(self):
        self._tx_polarity  = CSRStorage()
        self._rx_polarity  = CSRStorage()
        self.gtx_params.update(
            i_TXPOLARITY = self._tx_polarity.storage,
            i_RXPOLARITY = self._rx_polarity.storage
        )

    def add_electrical_control(self):
        self._tx_diffctrl       = CSRStorage(4, reset=0b1111)
        self._tx_postcursor     = CSRStorage(5, reset=0b00000)
        self._tx_postcursor_inv = CSRStorage(1, reset=0b0)
        self._tx_precursor      = CSRStorage(5, reset=0b00000)
        self._tx_precursor_inv  = CSRStorage(1, reset=0b0)
        self.gtx_params.update(
            i_TXDIFFCTRL      = self._tx_diffctrl.storage,
            i_TXPOSTCURSOR    = self._tx_postcursor.storage,
            i_TXPOSTCURSORINV = self._tx_postcursor_inv.storage,
            i_TXPRECURSOR     = self._tx_precursor.storage,
            i_TXPRECURSORINV  = self._tx_precursor_inv.storage,
        )

    def add_controls(self):
        self.add_base_control()
        self.add_prbs_control()
        self.add_loopback_control()
        self.add_polarity_control()
        self.add_electrical_control()

    def do_finalize(self):
        self.specials += Instance("GTXE2_CHANNEL", **self.gtx_params)


"""
This script is written to do analysis on GA study
"""

# import libraries
import re
import tsfresh
import numpy as np
import pandas as pd
from pandas import ExcelWriter
from sklearn.preprocessing import LabelBinarizer
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("darkgrid")
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedShuffleSplit, train_test_split
from ml_models.LinearRegression import LinearRegressionCalculator
from ml_models.DecisionTreeRegression import DecisionTreeRegressionCalculator
from ml_models.RandomForestRegression import RandomForestRegressionCalculator

# import methods from other scripts / packages
from storage.DataLoader import data_loader
from feature_extraction.FFT import fft_extractor
from feature_extraction.abs_energy import AbsoluteEnergyCalculator

# Constant declarations
col_names = ['Time_sec', 'Sens_L1', 'Sens_L2', 'Sens_L3', 'Sens_L4', 'Sens_L5', 'Sens_L6', 'Sens_L7', 'Sens_L8',
             'Sens_R1', 'Sens_R2', 'Sens_R3', 'Sens_R4', 'Sens_R5', 'Sens_R6', 'Sens_R7', 'Sens_R8', 'TF_L', 'TF_R']

"""
Main Controller
"""
def study_ga_controller(demographics_data):
    group_1_data, group_2_data = split_group_data(demographics_data)
    group_1_analysis(group_1_data, group_2_data)
    # group_2_analysis(group_2_data)

def split_group_data(demographics_data):
    group_1_data = demographics_data[demographics_data['Group'] == 1]
    group_2_data = demographics_data[demographics_data['Group'] == 2]
    return group_1_data, group_2_data

def print_newline():
    print("")

def print_seperator():
    print("--------------------------")

# ----------------------------------------------------- GROUP 1 ------------------------------------------------------ #

def group_1_analysis(group_1_data, group_2_data):
    print_newline()
    print("#####################################")
    print("Group 1 Analysis:")
    print("#####################################")

    # Create Empty Dataframe
    all_patient_dataframe = pd.DataFrame(
        columns=['ID', 'Patient_Number', 'Study', 'Patient_Type', 'Foot', 'file_number', 'Median', 'Max', 'Min', 'Skewness', 'Std', 'Variance', 'Abs_Energy',
                 'coeff_1', 'coeff_2', 'coeff_3', 'coeff_4'])

    df1 = pd.DataFrame([[np.nan] * len(all_patient_dataframe.columns)], columns=all_patient_dataframe.columns)

    patient_data_loader = data_loader()
    patient_data_file_paths = patient_data_loader.get_patient_file_paths()

    group_1_2_data = group_1_data[['ID', 'Gender', 'HoehnYahr']].append(group_2_data[['ID', 'Gender', 'HoehnYahr']])

    # all_patient_dataframe = GenerateAllPatientDataframe(patient_data_loader, patient_data_file_paths, all_patient_dataframe, df1)

    # all_patient_dataframe = pd.merge(all_patient_dataframe, group_1_2_data, how='left', on=['ID'])

    # writer = ExcelWriter('Study_Ga_df.xlsx')
    # all_patient_dataframe.to_excel(writer, 'Sheet1')
    # writer.save()

    all_patient_dataframe = pd.read_excel('Study_Ga_df.xlsx', sheet_name="Sheet1")

    split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
    for train_index, test_index in split.split(all_patient_dataframe, all_patient_dataframe["HoehnYahr"]):
        strat_train_set = all_patient_dataframe.loc[train_index]
        strat_test_set = all_patient_dataframe.loc[test_index]

    '''
    print("Train Set:")
    print_newline()
    print(strat_train_set)

    print_newline()

    print("Test Set:")
    print_newline()
    print(strat_test_set)
    '''

    train_models(strat_train_set, strat_test_set)

def GenerateAllPatientDataframe(patient_data_loader, patient_data_file_paths, all_patient_dataframe, df1):

    for patient_file_path in patient_data_file_paths:
        # Read patient data
        patient_data = patient_data_loader.read_patient_data(patient_file_path)

        filename_fields = extract_fields_from_filename(patient_data_loader, patient_file_path)

        study_name = filename_fields.group(1)
        patient_type = filename_fields.group(2)
        patient_number = filename_fields.group(3)
        data_file_number = filename_fields.group(4)

        # plot_patient_data(patient_data, 'Time_sec', 'TF_L', "Total force on left foot for patient: Group 1 " + study_name + patient_number)
        # plot_zoomed_patient_data(patient_data, 'Time_sec', 'TF_L', "Total force on left foot for patient: Group 1 " + study_name + patient_number)

        # add empty row entry
        all_patient_dataframe = df1.append(all_patient_dataframe, ignore_index=True)
        all_patient_dataframe = add_patient_data(all_patient_dataframe, patient_data, patient_number, study_name, patient_type, 'left', data_file_number)

        all_patient_dataframe = df1.append(all_patient_dataframe, ignore_index=True)
        all_patient_dataframe = add_patient_data(all_patient_dataframe, patient_data, patient_number, study_name, patient_type, 'right', data_file_number)

    return all_patient_dataframe

def extract_fields_from_filename(patient_data_loader, patient_file_path):
    patient_filename = patient_data_loader.extract_file_name(patient_file_path)

    pattern = "([A-Z][a-z])([A-Z][a-z])([\d]+)_([\d]+)"
    fields_from_filename = re.match(pattern, patient_filename)
    return fields_from_filename

def add_patient_data(all_patient_dataframe, patient_data, patient_number, patient_study, patient_type, foot, data_file_number):
    all_patient_dataframe.loc[0, 'ID'] = patient_study + patient_type + patient_number
    all_patient_dataframe.loc[0, 'Patient_Number'] = patient_number
    all_patient_dataframe.loc[0, 'Study'] = patient_study
    all_patient_dataframe.loc[0, 'Patient_Type'] = patient_type
    all_patient_dataframe.loc[0, 'Foot'] = foot
    all_patient_dataframe.loc[0, 'file_number'] = data_file_number

    fft = fft_extractor()
    abs_en = AbsoluteEnergyCalculator()
    all_patient_dataframe = extract_features(all_patient_dataframe, patient_data, foot, fft, abs_en)
    return all_patient_dataframe

def train_models(strat_train_set, strat_test_set):
    strat_train_set, strat_train_labels, strat_test_set, strat_test_labels = clean_sets(strat_train_set, strat_test_set)

    print(strat_test_labels.describe())

    print_seperator()
    print("Linear Regression:")
    lr_calculator = LinearRegressionCalculator()
    lr_calculator.train_model(strat_train_set, strat_train_labels, strat_test_set, strat_test_labels)
    print_seperator()

    print_seperator()
    print("Decision Tree Regression:")
    tree_calculator = DecisionTreeRegressionCalculator()
    tree_calculator.train_model(strat_train_set, strat_train_labels, strat_test_set, strat_test_labels)
    print_seperator()

    print_seperator()
    print("Random Forest Regression:")
    rf_calculator = RandomForestRegressionCalculator()
    rf_calculator.train_model(strat_train_set, strat_train_labels, strat_test_set, strat_test_labels)
    print_seperator()

def clean_sets(strat_train_set, strat_test_set):
    data_col = ['Patient_Type', 'Foot', 'file_number', 'Median', 'Max', 'Min', 'Skewness', 'Std', 'Variance', 'Abs_Energy',
                 'coeff_1', 'coeff_2', 'coeff_3', 'coeff_4', 'Gender']

    strat_train_set['Foot'] = strat_train_set['Foot'].apply(lambda x: '0' if x == 'left' else '1')
    strat_train_set['Foot'] = strat_train_set['Foot'].astype(int)
    strat_test_set['Foot'] = strat_test_set['Foot'].apply(lambda x: '0' if x == 'left' else '1')
    strat_test_set['Foot'] = strat_test_set['Foot'].astype(int)

    strat_train_set['Patient_Type'] = strat_train_set['Patient_Type'].apply(lambda x: '0' if x == 'Co' else '1')
    strat_train_set['Patient_Type'] = strat_train_set['Patient_Type'].astype(int)
    strat_test_set['Patient_Type'] = strat_test_set['Patient_Type'].apply(lambda x: '0' if x == 'Co' else '1')
    strat_test_set['Patient_Type'] = strat_test_set['Patient_Type'].astype(int)

    strat_train_labels = strat_train_set.loc[:, 'HoehnYahr']
    strat_train_set = strat_train_set[data_col]
    strat_test_labels = strat_test_set.loc[:, 'HoehnYahr']
    strat_test_set = strat_test_set[data_col]
    return strat_train_set, strat_train_labels, strat_test_set, strat_test_labels

# ----------------------------------------------------- GROUP 2 ------------------------------------------------------ #

def group_2_analysis(group_2_data):
    print_newline()
    print("#####################################")
    print("Group 2 Analysis:")
    print("#####################################")

    # group_2_study_ga()
    # group_2_study_ju()
    # group_2_study_si()

# ------------------------------------------ FEATURE EXTREACTION METHODS --------------------------------------------- #

def find_gait_cycle(patient_data):
    '''
    gait_cycle = pd.DataFrame(patient_data[(patient_data['Sens_L1'] == 0) & (patient_data['Sens_L2'] == 0) &
                                           (patient_data['Sens_L3'] == 0) & (patient_data['Sens_L4'] == 0) &
                                           (patient_data['Sens_L5'] == 0) & (patient_data['Sens_L6'] == 0) &
                                           (patient_data['Sens_L7'] == 0) & (patient_data['Sens_L8'] == 0)]['Time_sec'])
    '''
    gait_cycle = pd.DataFrame(patient_data[(patient_data['TF_L'] == 0)]['Time_sec'])
    gait_cycle['Time_sec'] = gait_cycle['Time_sec'].astype(int)
    gait_cycle = gait_cycle['Time_sec'].unique()

    print_newline()
    print_seperator()
    print("Values with zero VGRF:\n")
    print(gait_cycle)
    print_seperator()

def extract_features(all_patient_dataframe, patient_data, foot, fft, abs_en):
    if foot == "left":
        all_patient_dataframe = add_foot_coeffs(all_patient_dataframe, fft, patient_data, 'left')
        all_patient_dataframe.loc[0, 'Abs_Energy'] = abs_en.calculate_abs_energy(patient_data[['Time_sec', 'TF_L']], 'TF_L')
        all_patient_dataframe = extract_eda_features(patient_data[['Time_sec', 'TF_L']], 'TF_L', all_patient_dataframe)
    elif foot == "right":
        all_patient_dataframe = add_foot_coeffs(all_patient_dataframe, fft, patient_data, 'right')
        all_patient_dataframe.loc[0, 'Abs_Energy'] = abs_en.calculate_abs_energy(patient_data[['Time_sec', 'TF_R']], 'TF_R')
        all_patient_dataframe = extract_eda_features(patient_data[['Time_sec', 'TF_R']], 'TF_R', all_patient_dataframe)
    return all_patient_dataframe

def add_foot_coeffs(all_patient_dataframe, fft, patient_data, feet_type):
    if feet_type == 'left':
        foot_coeff = fft.calculate_fft_coeff(patient_data[['Time_sec', 'TF_L']], 'TF_L')
    elif feet_type == 'right':
        foot_coeff = fft.calculate_fft_coeff(patient_data[['Time_sec', 'TF_R']], 'TF_R')
    else:
        raise ValueError("add_foot_coeffs() : Wrong value supplied")

    all_patient_dataframe.loc[0, 'coeff_1'] = foot_coeff['coeff_1__attr_"real"']
    all_patient_dataframe.loc[0, 'coeff_2'] = foot_coeff['coeff_2__attr_"real"']
    all_patient_dataframe.loc[0, 'coeff_3'] = foot_coeff['coeff_3__attr_"real"']
    all_patient_dataframe.loc[0, 'coeff_4'] = foot_coeff['coeff_4__attr_"real"']
    return all_patient_dataframe

def extract_eda_features(patient_data, col_name, all_patient_dataframe):
    all_patient_dataframe.loc[0, 'Median'] = tsfresh.feature_extraction.feature_calculators.median(patient_data[col_name])
    all_patient_dataframe.loc[0, 'Max'] = tsfresh.feature_extraction.feature_calculators.maximum(patient_data[col_name])
    all_patient_dataframe.loc[0, 'Min'] = tsfresh.feature_extraction.feature_calculators.minimum(patient_data[col_name])
    all_patient_dataframe.loc[0, 'Skewness'] = tsfresh.feature_extraction.feature_calculators.skewness(patient_data[col_name])
    all_patient_dataframe.loc[0, 'Std'] = tsfresh.feature_extraction.feature_calculators.standard_deviation(patient_data[col_name])
    all_patient_dataframe.loc[0, 'Variance'] = tsfresh.feature_extraction.feature_calculators.variance(patient_data[col_name])

    return all_patient_dataframe

# -------------------------------------------------- PLOTTING METHODS ------------------------------------------------ #

def plot_patient_data(patient_df, x_col_name, y_col_name, plot_title):
    ax = sns.lineplot(x=x_col_name, y=y_col_name, data=patient_df)
    ax.set_title(plot_title)
    plt.show()

def plot_zoomed_patient_data(patient_df, x_col_name, y_col_name, plot_title):
    zoomed_time_data = patient_df[patient_df[x_col_name] < 20]
    ax = sns.lineplot(x=x_col_name, y=y_col_name, data=zoomed_time_data)
    ax.set_title(plot_title)
    plt.show()

def plot_sensor_data(patient_df, x_col_name, y_col_name, sensor_name):
    ax = sns.lineplot(x=x_col_name, y=y_col_name, data=patient_df)
    ax.set_title(sensor_name + "reading over time")
    plt.show()


import numpy as np
import pandas as pd
import matplotlib
import metrics
import sklearn
import xgboost
from sklearn import metrics
from decimal import *
import graphviz

'''
新細明體：PMingLiU
細明體：MingLiU
標楷體：DFKai-SB
黑体：SimHei
宋体：SimSun
新宋体：NSimSun
仿宋：FangSong
楷体：KaiTi
仿宋_GB2312：FangSong_GB2312
楷体_GB2312：KaiTi_GB2312
微軟正黑體：Microsoft JhengHei
微软雅黑体：Microsoft YaHei
————————————————

metrics.confusion_matrix(y_true, y_pred, labels=None, sample_weight=None)
metrics.accuracy_score(y_true,y_pred)
metrics.average_precision_score(y_true, y_score, average='macro', sample_weight=None)
metrics.precision_score(y_true, y_pred, labels=None, pos_label=1, average='binary',)
metrics.recall_score(y_true, y_pred, labels=None, pos_label=1, average='binary', sample_weight=None)
metrics.f1_score(y_true, y_pred, labels=None, pos_label=1, average='binary', sample_weight=None)
precision,recall,thresholds=metrics.precision_recall_curve(y_true,y_pred)
>>> plt.plot(recall, precision)
fpr,tpr,thresholds = metrics.roc_curve(y_true, y_ pred, pos_label=None, sample_weight=None, drop_intermediate=True)
>>> plt.plot(fpr,tpr)

metrics.roc_auc_score(y_true, y_pred, average='macro', sample_weight=None)
metrics.auc(fpr, tpr)

metrics.mean_absolute_error(y_true, y_pred, sample_weight=none, multioutput='uniform_average')
metrics.mean_squared_error(y_true, y_pred, sample_weight=None, multioutput='uniform_average')
metrics.r2_score(y_true, y_pred, sample_weight=None, multioutput='uniform_average')

用于多分类，只有两个属性可以选择 ‘macro’ 和 ‘weighted’
' macro '：计算每个标签的指标，并计算它们的未加权平均值。不考虑样本类别是否平衡。
' weighted '：计算每个标签的指标，并找到它们的平均值，对(每个标签的真实实例的数量)进行加权。
'micro':整体计算TP、FN、FP，然后根据公式计算得分。
'''

def classificationModel(y_true,y_pred):
    nameValueDict={}
    #混淆矩阵
    confusionMatrix = metrics.confusion_matrix(y_true, y_pred)
    #准确率
    accuracyScore = metrics.accuracy_score(y_true, y_pred)
    #精确率
    precisionScore = metrics.precision_score(y_true, y_pred,average=None)
    #召回率
    recallScore = metrics.recall_score(y_true, y_pred,average=None)
    #f1 只对2分类问题有效
    # None, 'micro', 'macro', 'weighted'
    f1Score = metrics.f1_score(y_true, y_pred,average=None)

    nameValueDict.update({})
    #pr曲线
    precision,recall,thresholds = metrics.precision_recall_curve(y_true,y_pred)

    matplotlib.plt.plot(recall, precision)
    fpr, tpr, thresholds = metrics.roc_curve(y_true, y_pred,drop_intermediate = True)
    # >> > plt.plot(fpr, tpr)

    rocAucScore = metrics.roc_auc_score(y_true, y_pred)
    aucArea = metrics.auc(fpr, tpr)

    nameValueDict.update({'accuracyScore':accuracyScore})
    nameValueDict.update({'precisionScore':precisionScore})
    nameValueDict.update({'recallScore':recallScore})
    # nameValueDict.update({'f1Score':f1Score})
    nameValueDict.update({'auc':metrics.auc(fpr, tpr)})
    nameValueDict.update({'accuracyScore':accuracyScore})
    nameValueDict.update({'aucArea':aucArea})

    return nameValueDict

def regressionModel(y_true,y_pred):

    nameValueDict = {}
    MAE = metrics.mean_absolute_error(y_true, y_pred)
    MSE = metrics.mean_squared_error(y_true, y_pred)
    r2 = metrics.r2_score(y_true, y_pred)

    nameValueDict.update({'MAE':MAE})
    nameValueDict.update({'MSE':MSE})
    nameValueDict.update({'r2':r2})
    return nameValueDict

def entU(u):

    return [np.sum([p * np.log2(1 / p) for p in ct / np.sum(ct)]) for ct in [np.unique(u, return_counts=True)[1]]][0]

#条件熵
def uConditionV(u,v):

    entu = [np.sum([p * np.log2(1 / p) for p in ct / np.sum(ct)]) for ct in [np.unique(u, return_counts=True)[1]]][0]
    entv = [np.sum([p * np.log2(1 / p) for p in ct / np.sum(ct)]) for ct in [np.unique(v, return_counts=True)[1]]][0]

    # v 解释变量
    vid, vct = np.unique(v, return_counts=True)

    # 条件信息
    vidEntropy = [np.sum([p * np.log2(1 / p) for p in ct / np.sum(ct)]) for ct in [np.unique(u[v == i], return_counts=True)[1] for i in vid]]

    #条件熵
    entUconditonV= np.sum(np.array(vidEntropy) * (vct / np.sum(vct)))

    return entUconditonV

#信息增益
def gainuv(u,v):

    return entU(u) - uConditionV(u,v)

def gainRatio(u, v):
    return gainuv(u,v) / entU((v))

def display_version():
    print('np.version : ',np.__version__)
    print('pd.version : ',pd.__version__)
    print('matplotlib.version : ',matplotlib.__version__)
    print('sklearn.version : ',sklearn.__version__)
    print('xgboost.version : ',xgboost.__version__)
    print('graphviz.version',graphviz.__version__)

display_version()

#数据查看tool
def overview(data):

    print('\n======================= data overview =======================\n')

    print('\n重复行数 : ',data.duplicated().sum(axis=0))
    print('重复记录为：')
    print(data[data.duplicated()])

    print('\n数据总体缺失情况 : ')
    print('总记录数 : ',data.shape[0])
    print('\n各列没有缺失的样本数量：')
    print(data.notnull().sum())
    print('\n各列缺失的样本数量：')
    print(data.isnull().sum())
    print('\n各列缺失比例')
    print(data.isnull().mean())

    print('\n缺失行\n')
    print(data.loc[data.isnull().sum(axis=1)>0,:])
    print('\n缺失列\n')
    print(data.loc[:,data.isnull().sum(axis=0)>0])
    print('\n缺失区域【缺失行+缺失列】\n')
    print(data.loc[data.isnull().sum(axis=1) > 0, data.isnull().sum(axis=0) > 0])

    print('\n\n')
    print('\n所在列及缺失的行索引号\n')
    for i in data.columns:
        print(i,' : ',list(np.where(pd.isna(data[i]))[0]))
    print('\n\n')

def basicOperate(data):
    print('\n\n')
    print('\n删除重复行\n')
    data.drop_duplicates(inplace=True)
    print('\n\n')
    print('\n\n')
    print('\n\n')

def dropRank(data,thresh):
    threshold = thresh
    print('显示空值个数大于 {} 的行,这些行，予以删除'.format(data.shape[1] - threshold))
    print(data.loc[data.isnull().sum(axis=1) > data.shape[1] - threshold])
    print('=======================================')
    print(data.loc[data.isnull().sum(axis=1) == data.shape[1] - threshold])
    print('=======================================')
    print('显示非空个数大于等于 {} 的行，这些行，予以保留'.format(threshold))
    print(data.dropna(thresh=threshold))
    data.dropna(thresh=threshold,inplace=True)

# 离散型 gini系数 x是自变量，y是flag
def giniC(x, y):
    x_id, x_ct = np.unique(x, return_counts=True)
    p_x = [ct / sum(ct) for ct in [np.unique(x, return_counts=True)[1]]]
    gini = [1 - np.sum(p ** 2) for p in
            [ct / sum(ct) for ct in [np.unique(y[x == i], return_counts=True)[1] for i in x_id]]]

    return np.sum(np.array(p_x) * np.array(gini))

# 连续型 gini系数 x是自变量，y是flag
def giniS(y, x):
    # 将离散数据转成float
    x.astype(float)
    # 对离散数据排序
    sorted_x = np.sort(x)
    split_point_list = []
    split_point_gini = []
    # 求分界点
    for i in range(0, len(sorted_x) - 1, 1):
        split_point_list.append(np.mean([sorted_x[i], sorted_x[i + 1]]))

    # 依次计算每个分界点分割后的gini系数
    for i in split_point_list:
        # 分界后，就是二分类了
        xi = pd.Series.copy(x)
        xi[xi <= i] = 0
        xi[xi > i] = 1

        # 根据新分界点，计算权重（频数、概率）
        w_i = [[p for p in ct / np.sum(ct)] for ct in [np.unique(xi, return_counts=True)[1]]]

        # 分类
        x_id, x_ct = np.unique(xi, return_counts=True)

        # 每个分界点分类的gini
        gini_x_id = [np.sum([(p - p ** 2) for p in ct / np.sum(ct)]) for ct in
                     [np.unique(y[xi == i], return_counts=True)[1] for i in x_id]]

        # 计算每个分界点的gini
        gini = Decimal(str(np.sum(w_i * np.array(gini_x_id)))).quantize(Decimal('0.0000'),ROUND_HALF_UP)
        split_point_gini.append(gini)

    # 封装成字典
    split_point_gini_dict = dict(zip(split_point_list, split_point_gini))

    return split_point_gini_dict


# -*- coding: utf-8 -*-
# @Time    : 2020/6/1 16:16
# @Author  : piguanghua
# @FileName: binary_search.py
# @Software: PyCharm

#titile:binary-search
#Number:704

class Solution:
    #def search(self, nums: List[int], target: int) -> int:
    def search(self, nums, target):
        start = 0
        end = len(nums) - 1

        while start + 1 < end: # 邻近or相等跳出循环
            #mid = int( ( start + end) / 2  )
            mid = start + (end - start) // 2
            if nums[mid] == target:
                start = mid
            elif nums[mid] > target:
                end = mid
            else:
                start = mid

        if nums[start] == target:
            return start
        elif nums[end] == target:
            return end
        else:
            return -1

if __name__ == '__main__':
    nums, target = [1, 3, 5, 6], 7
    print(Solution().search(nums, target))


"""
46. Faça um programa que leia um número inteiro positivo de três digitos (de 100 a 999),
Gere outro número formado pelos dígitos invertidos do número lido
"""
try:
    valor = int(input('Insira um três digitos inteiros (de 100 a 999):  '))
    if (valor >= 100) and (valor <= 999):
        x = str(valor)
        print(x[::-1])
    else:
        print('ERRO!!! Você não digitou os digitos inteiros (de 100 a 999)')
except ValueError:
    print('ERRO!!! o valor digitado tem que ser inteiro')

Variáveis e Tipos de Dados em Python/Exercicio46.py


from fastapi import APIRouter, Depends, status
from sqlalchemy.ext.asyncio import AsyncSession
from src.authentication import AuthModel, get_token_user
from src.core.exceptions import UnprocessableEntityException
from src.db.postgres import get_db

from .dependencies import get_token_parent
from .parents.crud import parent_crud
from .parents.models import ParentModel
from .parents.schemes import ResponseParentScheme, UpdateParentScheme

router = APIRouter()

@router.get(
    path="/me",
    summary="View a personal profile",
    response_model=ResponseParentScheme,
)
async def watch_me(
    parent: ParentModel = Depends(get_token_parent),
):
    return parent

@router.patch(
    path="/me",
    summary="Update a personal profile",
    response_description="Successful Response returns only status code 200",
)
async def update_me(
    *,
    db: AsyncSession = Depends(get_db),
    parent: ParentModel = Depends(get_token_parent),
    update_data: UpdateParentScheme,
):
    update_data = update_data.dict(exclude_none=True)
    if not update_data:
        return None

    _, err = await parent_crud.update(db, parent, update_data)
    if err is not None:
        raise UnprocessableEntityException(detail=err)

    return None

@router.delete(
    path="/me",
    summary="Delete a personal profile",
    status_code=status.HTTP_204_NO_CONTENT,
    response_description="Successful Response returns only status code 204",
)
async def delete_me(
    db: AsyncSession = Depends(get_db),
    auth_user: AuthModel = Depends(get_token_user),
):
    await parent_crud.delete_auth(db, auth_user.email)
    return None


# -*- coding: utf-8 -*-
# @Project : selenium_event
# @File    : test_alert.py
# @Software: PyCharm
# @Author  : Lizhipeng
# @Email   : 1907878011@qq.com
# @Time    : 2021/9/26 17:16
from selenium.webdriver import ActionChains

from seleium_study.selenium_js.base import Base

class TestAlert(Base):
    def test_alert(self):
        self.driver.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
        # 切换frame
        self.driver.switch_to.frame('iframeResult')
        top = self.driver.find_element_by_xpath('//*[@id="draggable"]')
        end = self.driver.find_element_by_xpath('//*[@id="droppable"]')
        # 拖拽元素top到元素end
        action = ActionChains(self.driver)
        action.drag_and_drop(top, end).perform()
        # 焦点切换到弹出框上,点击弹出框上的确定
        self.driver.switch_to.alert.accept()
        # 切换回默认的frame
        self.driver.switch_to.default_content()
        self.driver.find_element_by_xpath('//*[@id="submitBTN"]').click()


from threading import Thread

from flask import Flask, request, redirect, session, render_template, send_file, Response, flash
from flask_session import Session
import os, json

from bs4 import BeautifulSoup, SoupStrainer
import requests, lxml, cchardet

app = Flask('')
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)

from requests_oauthlib import OAuth2Session
import getpass
import random, string, asyncio

import os
import shutil

app.config['GITHUB_CLIENT_ID'] = os.environ['GITHUB_CLIENT_ID']
app.config['GITHUB_CLIENT_SECRET'] = os.environ['GITHUB_CLIENT_SECRET']

# Disable SSL requirement
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

# Settings for your app
base_discord_api_url = 'https://discordapp.com/api'
client_id = os.environ['DISCORD_CLIENT_ID'] # Get from https://discordapp.com/developers/applications
client_id.encode('unicode_escape')
client_secret = os.environ['DISCORD_CLIENT_SECRET']
redirect_uri='https://DataPak.coolcodersj.repl.co/oauth_callback'
scope = ['identify', 'email', 'connections', 'guilds', 'applications.builds.read']
token_url = 'https://discord.com/api/oauth2/token'
authorize_url = 'https://discord.com/api/oauth2/authorize'

app = Flask(__name__)
app.secret_key = os.environ['APP_SECRET_KEY'].encode('utf-8')

@app.route("/")
def home():
	if 'discord_token' not in session.keys():
		disc = ""
	else:
		discord = OAuth2Session(client_id, token=session['discord_token'])
		response = discord.get(base_discord_api_url + '/users/@me')
		disc = response.json()['username'] + "#" + response.json()['discriminator']
	if not "gh_token" in session.keys():
		gh = ""
	else:
		r = requests.get("https://api.github.com/user", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		gh = r.json()['login']

	if not "spotify_token" in session.keys():
		spotify = ""
	else:
		r = requests.get("https://api.spotify.com/v1/me", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		if "error" in r.json() and r.json()['error']['message'] == "The access token expired":
				spotify_client_id, spotify_client_secret = os.environ['SPOTIFY_CLIENT_ID'], os.environ['SPOTIFY_CLIENT_SECRET']
				r = requests.post("https://accounts.spotify.com/api/token", data={
					"grant_type": "refresh_token",
					"refresh_token": session['spotify_refresh_token'],
					"redirect_uri": "https://datapak.coolcodersj.repl.co/spotify/callback",
					'client_id': spotify_client_id,
					"client_secret": spotify_client_secret
				})
				session['spotify_token'] = r.json()['access_token']
				if "refresh_token" in r.json():
					session['spotify_refresh_token'] = r.json()['refresh_token']
		r = requests.get("https://api.spotify.com/v1/me", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		spotify = r.json()['display_name']

	return render_template("index.html", replitusername=request.headers['X-Replit-User-Name'], discordusername=disc, gh=gh, spotify=spotify)

@app.route('/discord')
def discord():
	oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scope)
	login_url, state = oauth.authorization_url(authorize_url)
	session['state'] = state
	return redirect(login_url)

@app.route("/oauth_callback")
def oauth_callback():
	print(type(client_id))
	discord = OAuth2Session(client_id, redirect_uri=redirect_uri, state=session['state'], scope=scope)
	token = discord.fetch_token(
		token_url,
		client_secret=client_secret,
		authorization_response=request.url,
	)
	session['discord_token'] = token
	return redirect("/")

@app.route("/discord/generate")
def gendisc():
	if not 'discord_token' in session:
		disc = ""
		return redirect("/")
	else:
		discord = OAuth2Session(client_id, token=session['discord_token'])
		response1 = discord.get(base_discord_api_url + '/users/@me')
		response2 = discord.get(base_discord_api_url + '/users/@me/connections')
		response3 = discord.get(base_discord_api_url + '/users/@me/guilds')
		disc = {"account": response1.json(), "connections": response2.json(), "guilds": response3.json()}
		resp = Response(json.dumps(disc))
		resp.headers['Content-Type'] = 'application/json'
		return resp

@app.route('/discord/info')
def discordinfo():
	return render_template("discordinfo.html")

@app.route('/replit/info')
def replitinfo():
	return render_template("replitinfo.html")

@app.route("/replit/generate")
def replit():
	try:
		username = request.headers['X-Replit-User-Name']
		os.remove(f'DataPak{username}.zip')
	except:
		pass
	globals()['replurls'] = []
	def findrepls(r):
		global replurls
		if r.status_code == 200:
			soup = BeautifulSoup(r.content, "lxml")
			btn = soup.find_all('a', class_='jsx-688104393')
			repls = soup.find_all("a", class_='repl-item-wrapper')
			for g in repls:
				globals()['replurls'].append(str(g['href']))
			if btn != []:
				r = requests.get(f"https://replit.com{btn[0]['href']}")
				findrepls(r)
			else:
				return
	r = requests.get(f"https://replit.com/@{request.headers['X-Replit-User-Name']}")
	findrepls(r)
	username = request.headers['X-Replit-User-Name']
	os.mkdir(f"DataPak{username}")
	for repl in replurls:
		r = requests.get(f'https://replit.com{repl}.zip')
		f = open(f'DataPak{username}/{repl.split("/")[-1]}.zip', "w+")
		print(r.content, file=f)
		f.close()
	r = requests.get(f"https://replit.com/data/profiles/{request.headers['X-Replit-User-Name']}").json()
	f = open(f'DataPak{username}/account.json', "a")
	del r['repls']
	print(r, file=f)
	f.close()
	shutil.make_archive(f'DataPak{username}', 'zip', f'DataPak{username}/')
	shutil.rmtree(f'DataPak{username}/')
	return send_file(f'DataPak{username}.zip', mimetype="application/zip", as_attachment=True)

@app.route('/spotify/info')
def spotinfo():
	return render_template('spotifyinfo.html')

@app.route('/spotify')
def spot():
	client_id, client_secret = os.environ['SPOTIFY_CLIENT_ID'], os.environ['SPOTIFY_CLIENT_SECRET']
	scopes = [
	'user-read-recently-played',
    'user-top-read',
    'user-read-playback-position',
	'user-read-playback-state',
    'user-read-currently-playing',
	'playlist-read-private',
    'playlist-read-collaborative',
	'user-follow-read',
	'user-follow-modify',
	'user-library-read',
	'user-read-email',
    'user-read-private',
	]
	scopes = " ".join(scopes)
	if not "spotify_token" in session.keys():
		return redirect(f"https://accounts.spotify.com/authorize?response_type=code&client_id={client_id}&scope={scopes}&redirect_uri=https://datapak.coolcodersj.repl.co/spotify/callback")
	else:
		artists = requests.get("https://api.spotify.com/v1/me/following?type=artist", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})

		if artists.text == "":
			artists = {"None": "None"}
		else:
			if "message" in artists.json() and artists.json()['message'] == "The access token expired":
				client_id, client_secret = os.environ['SPOTIFY_CLIENT_ID'], os.environ['SPOTIFY_CLIENT_SECRET']
				r = requests.post("https://accounts.spotify.com/api/token", data={
					"grant_type": "refresh_token",
					"refresh_token": session['spotify_refresh_token'],
					"redirect_uri": "https://datapak.coolcodersj.repl.co/spotify/callback",
					'client_id': client_id,
					"client_secret": client_secret
				})
				session['spotify_token'] = r.json()['access_token']
				if "refresh_token" in r.json():
					session['spotify_refresh_token'] = r.json()['refresh_token']
				artists = requests.get("https://api.spotify.com/v1/me/following?type=artist", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
				})
			artists = artists.json()['artists']['items']

		albums = []
		album_req = requests.get("https://api.spotify.com/v1/me/albums", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in album_req.json()['items']:
			albums.append(item)
		while "next" in album_req.json() and album_req.json()['next'] != None:
			album_req = requests.get(album_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in album_req.json()['items']:
				albums.append(item)

		playlists = []
		playlist_req = requests.get("https://api.spotify.com/v1/me/playlists", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in playlist_req.json()['items']:
			playlists.append(item)
		while "next" in playlist_req.json() and playlist_req.json()['next'] != None:
			playlist_req = requests.get(playlist_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in playlist_req.json()['items']:
				playlists.append(item)

		liked_songs = []
		track_req = requests.get("https://api.spotify.com/v1/me/tracks", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in track_req.json()['items']:
			liked_songs.append(item)
		while "next" in track_req.json() and track_req.json()['next'] != None:
			track_req = requests.get(track_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in track_req.json()['items']:
				liked_songs.append(item)

		liked_episodes = []
		episode_req = requests.get("https://api.spotify.com/v1/me/episodes", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in episode_req.json()['items']:
			liked_episodes.append(item)
		while "next" in episode_req.json() and episode_req.json()['next'] != None:
			episode_req = requests.get(episode_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in episode_req.json()['items']:
				liked_episodes.append(item)

		shows = []
		show_req = requests.get("https://api.spotify.com/v1/me/shows", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in show_req.json()['items']:
			shows.append(item)
		while "next" in show_req.json() and show_req.json()['next'] != None:
			show_req = requests.get(show_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in show_req.json()['items']:
				shows.append(item)

		top_tracks = []
		track_req = requests.get("https://api.spotify.com/v1/me/top/tracks", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in track_req.json()['items']:
			top_tracks.append(item)
		while "next" in track_req.json() and track_req.json()['next'] != None:
			track_req = requests.get(track_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in track_req.json()['items']:
				top_tracks.append(item)

		top_artists = []
		artist_req = requests.get("https://api.spotify.com/v1/me/top/tracks", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in artist_req.json()['items']:
			top_artists.append(item)
		while "next" in artist_req.json() and artist_req.json()['next'] != None:
			artist_req = requests.get(artist_req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in artist_req.json()['items']:
				top_artists.append(item)

		current_playback = requests.get("https://api.spotify.com/v1/me/player", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		if current_playback.text == '':
			current_playback = {"error": "Nothing was playing while backing up."}
		else:
			current_playback = current_playback.json()

		devices = requests.get("https://api.spotify.com/v1/me/player/devices", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})

		if devices.text == '':
			devices = {"error": "No devices available."}
		else:
			devices = devices.json()

		recently_played = []
		req = requests.get("https://api.spotify.com/v1/me/player/recently-played", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})
		for item in req.json()['items']:
			recently_played.append(item)
		while "next" in req.json() and req.json()['next'] != None:
			req = requests.get(req.json()['next'], headers={
			"Authorization": f"Bearer {session['spotify_token']}"
			})
			for item in req.json()['items']:
				recently_played.append(item)

		profile = requests.get("https://api.spotify.com/v1/me", headers={
			"Authorization": f"Bearer {session['spotify_token']}"
		})

		username = profile.json()['display_name']
		os.mkdir(f"DataPak{username}/")

		f = open(f"DataPak{username}/library.json", "w")
		print({"artists": artists, "albums": albums, "playlists": playlists, "liked_songs": liked_songs, "liked_episodes": liked_episodes, "shows": shows, "top_tracks": top_tracks, "top_artists": top_artists}, file=f)
		f.close()

		f = open(f"DataPak{username}/playback.json", "w")
		print({"current_playback": current_playback, "devices": devices, "recently_played": recently_played}, file=f)
		f.close()

		f = open(f"DataPak{username}/profile.json", "w")
		print(profile.json(), file=f)
		f.close()

		shutil.make_archive(f'DataPak{username}', 'zip', f'DataPak{username}/')
		shutil.rmtree(f'DataPak{username}/')
		return send_file(f'DataPak{username}.zip', mimetype="application/zip", as_attachment=True)

@app.route('/spotify/callback')
def spotcallback():
	code = request.args.get("code")
	client_id, client_secret = os.environ['SPOTIFY_CLIENT_ID'], os.environ['SPOTIFY_CLIENT_SECRET']
	r = requests.post("https://accounts.spotify.com/api/token", data={
		"grant_type": "authorization_code",
		"type": "authorization_code",
		"code": code,
		"redirect_uri": "https://datapak.coolcodersj.repl.co/spotify/callback",
		'client_id': client_id,
		"client_secret": client_secret
	})
	session['spotify_token'] = r.json()['access_token']
	session['spotify_refresh_token'] = r.json()['refresh_token']
	return redirect('/')

@app.route('/github/info')
def ghinfo():
	return render_template("ghinfo.html")

@app.route('/github')
def github():
	if not "gh_token" in session:
		state = "irajfvnqehrtdfwbejktrbnvfbiwkjetrnfgcwkjenrsflwejkbtnfjbrethvbw3urskejg"
		session['state'] = state
		return redirect(f"https://github.com/login/oauth/authorize?state={state}&client_id={os.environ['GITHUB_CLIENT_ID']}&scope=repo read:repo_hook read:org read:public_key gist user read:discussion read:packages read:gpg_key&redirect_uri=https://DataPak.coolcodersj.repl.co/github/callback")
	else:
		r = requests.get("https://api.github.com/user", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		account = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/followers", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		followers = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/following", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		following = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/gists", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		gists = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/starred", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		starred = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/subscriptions", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		watchlist = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/orgs", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		organizations = r.json()
		r = requests.get(f"https://api.github.com/users/{account['login']}/repo", headers={
			"Authorization": f"token {session['gh_token']}"
		})
		repos = r.json()
		os.mkdir(f"DataPak{account['login']}/")
		print(account, file=open(f"DataPak{account['login']}/account.json", "w"))
		print(followers, file=open(f"DataPak{account['login']}/followers.json", "w"))
		print(following, file=open(f"DataPak{account['login']}/following.json", "w"))
		print(gists, file=open(f"DataPak{account['login']}/gists.json", "w"))
		print(starred, file=open(f"DataPak{account['login']}/starred.json", "w"))
		print(watchlist, file=open(f"DataPak{account['login']}/watchlist.json", "w"))
		print(organizations, file=open(f"DataPak{account['login']}/orgs.json", "w"))
		print(repos, file=open(f"DataPak{account['login']}/repos.json", "w"))

		username = account['login']

		for repo in repos:
			name = repo['name']
			branch = repo['default_branch']
			r = requests.get(f'https://github.com/{username}/{name}/archive/refs/heads/{branch}.zip')
			f = open(f'DataPak{username}/{name}.zip', "w+")
			print(r.content, file=f)
			f.close()

		shutil.make_archive(f'DataPak{username}', 'zip', f'DataPak{username}/')
		shutil.rmtree(f'DataPak{username}/')
		return send_file(f'DataPak{username}.zip', mimetype="application/zip", as_attachment=True)

@app.route('/github/callback')
def authorized():
	code = request.args.get("code")
	r = requests.post("https://github.com/login/oauth/access_token", data={
		"client_id": os.environ['GITHUB_CLIENT_ID'],
		"client_secret": os.environ['GITHUB_CLIENT_SECRET'],
		"code": code,
		"state": session['state']
	},
	headers={
		"Accept": "application/json"
	})
	session['gh_token'] = r.json()['access_token']
	return redirect("/")

app.run(host="0.0.0.0", port=8080)


def printGrid(grid):
    for row in grid:
        print("".join([str(i) for i in row]))

def copyGrid(grid):
    return [row.copy() for row in grid]

def isInRange(grid, r, c):
    return r >= 0 and r < len(grid) and c >= 0 and c < len(grid[0])

def flash(grid, alreadyFlashed, r, c):
    if grid[r][c] <= 9 or (r, c) in alreadyFlashed:
        return
    # print("Flash: " + str((r,c)))
    alreadyFlashed.add((r, c))
    for i in range(r-1, r+2):
        for j in range(c-1, c+2):
            if isInRange(grid, i, j):
                grid[i][j] += 1
                flash(grid, alreadyFlashed, i, j)

def isSynced(grid):
    for i in range(len(grid)):
        for j in range(len(grid[0])):
            if grid[i][j] != 0:
                return False
    return True
def simulate(grid, numSteps):
    flashCount = 0
    flashed = set()
    sync = False
    step = 0
    while not sync:
        step += 1
        # increase every energy level
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                grid[i][j] += 1
        # flash
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                flash(grid, flashed, i, j)

        # any octupus that flashed should be set to 0
        for r, c in flashed:
            grid[r][c] = 0
        flashCount += len(flashed)
        flashed = set()
        sync = isSynced(grid)

    return step

def solve(file):
    grid = [[int(s) for s in list(l.strip())] for l in open(file).readlines()]
    step = simulate(grid, 100)
    print(step)

solve("inputs/11/full.txt")


import mlflow
import dvc.api
import pandas as pd

def yield_artifacts(run_id, path=None):
    """Yield all artifacts in the specified run"""
    client = mlflow.tracking.MlflowClient()
    for item in client.list_artifacts(run_id, path):
        if item.is_dir:
            yield from yield_artifacts(run_id, item.path)
        else:
            yield item.path

def fetch_logged_data(run_id):
    """Fetch params, metrics, tags, and artifacts in the specified run"""
    client = mlflow.tracking.MlflowClient()
    data = client.get_run(run_id).data
    # Exclude system tags: https://www.mlflow.org/docs/latest/tracking.html#system-tags
    tags = {k: v for k, v in data.tags.items() if not k.startswith("mlflow.")}
    artifacts = list(yield_artifacts(run_id))
    return {
        "params": data.params,
        "metrics": data.metrics,
        "tags": tags,
        "artifacts": artifacts,
    }

def dvc_open(path, url, branch):
    with dvc.api.open(
        path = path,  ## 데이터 경로
        repo = url,  ## github repo 경로,
        rev =  branch ## 현재는 branch 기준
    ) as f:
        return pd.read_csv(f, sep=",")

def find_experiment_id(experiment_name):
    current_experiment = dict(mlflow.get_experiment_by_name(experiment_name))
    return current_experiment["experiment_id"]


import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from numpy import *
import sys

file_name = sys.argv[1]
data1 = loadtxt("./" + file_name)
NUM=data1[:,0]  #
TIME=data1[:,1]  #

fig = plt.figure() #
top = fig.add_subplot(111) # 1 riga, 1 colonna, figura 1

top.set_title('BRUTE FORCE')
top.grid()
top.set_xlabel('n')
top.set_ylabel('time')
top.plot(NUM, TIME)
#top.text(200,35,"Steps: "+str(int(STEPS)))

plt.savefig('fatt-brute-force.pdf')
#plt.show()


a=["Arun","Sri","Kavi"]
b=["male","female","female"]
c=["married","married","single"]
for i in range(0,len(a)):
    if(b[i]=="male"):
        print("mr:",a[i])
    elif(c[i]=="single"):
        print("Ms:",a[i])
    else:
        print("Mrs:",a[i])


def fun(*args):
    res = sum(args)
    return res

def my_range(*args):
    if len(args) == 1:
        start = 0
        stop = args[0]
        step = 1
    elif len(args) == 2:
        start = args[0]
        stop = args[1]
        step = 1
    elif len(args) == 3:
        start = args[0]
        stop = args[1]
        step = args[2]

args = (1, 2, 4, 7)

val = fun(1, 2, 2, 1, 100, 20)
print(val)


#!/usr/bin/env python
# coding: utf-8

# # Pandas Lab Exercise
#
#
# ## Part - 1
# We shall now test your skills in using Pandas package. We will be using the [games Dataset](https://www.kaggle.com/gutsyrobot/games-data/data) from Kaggle.
#
# Answer each question asked below wrt the games dataset.

# ** Import pandas as pd.**

# In[1]:

import pandas as pd

# ** Read games.csv as a dataframe called games.**

# In[2]:

games = pd.read_csv("games.csv")

# ** Check the head of the DataFrame. **

# In[3]:

games.head()

# ** Use .info() method to find out total number of entries in dataset**

# In[4]:

games.info()

# **What is the mean playin time for all games put together ?**

# In[6]:

games['playingtime'].mean()

# ** What is the highest number of comments received for a game? **

# In[7]:

games['total_comments'].max()

# ** What is the name of the game with id 1500?  **

# In[8]:

games[games['id']==1500]['name']

# ** And which year was it published? **

# In[9]:

games[games['id']==1500]['yearpublished']

# ** Which game has received highest number of comments? **

# In[10]:

games[games['total_comments']==games['total_comments'].max()]

# ** Which games have received least number of comments? **

# In[11]:

games[games['total_comments']==games['total_comments'].min()]

# ** What was the average minage of all games per game "type"? (boardgame & boardgameexpansion)**

# In[13]:

games.groupby('type').mean()['minage']

# ** How many unique games are there in the dataset? **

# In[14]:

games['id'].nunique()

# ** How many boardgames and boardgameexpansions are there in the dataset?  **

# In[15]:

games['type'].value_counts()

# ** Is there a correlation between playing time and total comments for the games? - Use the .corr() function **

# In[18]:

games[['playingtime','total_comments']].corr()

# In[ ]:


from math import trunc

a = 159 # Key 1
b = 580 # Key 2
n = 26 # Alphabet size
plaintext = 'no' # Plaintext

def encrypt(a,b,n,plaintext):
    alphabet = None
    ciphertext = ''
    p = 0
    if(n == 26):
        alphabet = 'abcdefghijklmnopqrstuvwxyz'
    elif(n == 45):
        alphabet = 'abdefghijklmnopqrstuvwxyz!£$%^&*()0123456789'
    elif(n == 122):
        alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
    alphabet = list(alphabet)
    plaintext = list(plaintext)

    x = alphabet.index(plaintext[0])
    y = alphabet.index(plaintext[1])
    p = x*n + y
    n2 = n*n
    p = (a*p+b) % n2
    x = trunc(p / n)
    y = trunc(p % n)
    ciphertext = ciphertext + alphabet[x]
    ciphertext = ciphertext + alphabet[y]
    print(ciphertext)

encrypt(a,b,n,plaintext)

Ciphers/Classical */Affine Cipher */Strengthened Affine */Encrypt.py