"""
░░░░░░░░░░░██╗░░░░░░░██╗██╗░░░██╗██████╗░██████╗░███████╗░░░░░░██████╗░░█████╗░██████╗░██████╗░░░░░░░░░░░░
░░░░░░░░░░░██║░░██╗░░██║██║░░░██║██╔══██╗██╔══██╗╚════██║░░░░░░██╔══██╗██╔══██╗██╔══██╗██╔══██╗░░░░░░░░░░░
░░░░░░░░░░░╚██╗████╗██╔╝██║░░░██║██║░░██║██║░░██║░░███╔═╝█████╗██║░░██║███████║██████╔╝██████╔╝░░░░░░░░░░░
░░░░░░░░░░░░████╔═████║░██║░░░██║██║░░██║██║░░██║██╔══╝░░╚════╝██║░░██║██╔══██║██╔═══╝░██╔═══╝░░░░░░░░░░░░
░░░░░░░░░░░░╚██╔╝░╚██╔╝░╚██████╔╝██████╔╝██████╔╝███████╗░░░░░░██████╔╝██║░░██║██║░░░░░██║░░░░░░░░░░░░░░░░
░░░░░░░░░░░░░╚═╝░░░╚═╝░░░╚═════╝░╚═════╝░╚═════╝░╚══════╝░░░░░░╚═════╝░╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░░░░░░░░░░░░

 [*]Descr:     ERC20 DAPP, CREATE ACCOUNTS, GET ALL TOKEN BALANCES & USD VALUE FOR AN ACCOUNT/WALLET,
               MAKE TRANSACTIONS, INTERACT SMART CONTRACTS, SWAP ERC20 TOKENS, GET CURRENT CRYPTO PRICES,
               AUTHENTICATE TO EXCHANGE ACCOUNT VIA API, CONVERT CRYPTO TO CRYPTO VALUE AND BASE64 DECODER
 [*]Coder:     Wuddz_Devs
 [*]Email:     wuddz_devs@protonmail.com
 [*]Github:    https://github.com/wuddz-devs
 [*]Reddit:    https://reddit.com/users/wuddz-devs
 [*]Twitter:   https://twitter.com/wuddz_devs
 [*]Telegram:  https://t.me/wuddz_devs
 [*]Videos:    https://mega.nz/folder/IWVAXTqS#FoZAje2NukIcIrEXXKTo0w
 [*]Youtube:   https://youtube.com/@wuddz-devs
 [*]Donation:
    BTC   ->   bc1qa7ssx0e4l6lytqawrnceu6hf5990x4r2uwuead
    ERC20 ->   0xbF4d5309Bc633d95B6a8fe60E6AF490F11ed2Dd1
    LTC   ->   LdbcFiQVUMTfc9eJdc5Gw2nZgyo6WjKCj7
    TRON  ->   TY6e3dWGpqyn2wUgnA5q63c88PJzfDmQAD
    DOGE  ->   DFwLwtcam7n2JreSpq1r2rtkA48Vos5Hgm

 [*]Menu:
    1     =>   Create A New Ethereum Account
    2     =>   Check Account Balance(s)
    3     =>   Send/Deposit To An Account
    4     =>   Get Account Address & Balance(s) From Private Key Or Mnemonic Seed
    5     =>   Get Transaction Hash Attributes
    6     =>   Compile & Deploy Smart Contract To Blockchain
    7     =>   Interact, Read & Execute Smart Contract Functions
    8     =>   Verify Deployed Smart Contract On Etherscan/Polygonscan
    9     =>   Swap/Purchase ERC20 Tokens Using 0x Api
    x     =>   Interact With Exchange Account (Authentication ApiKey, ApiSecret, ApiPassword etc...)
    d     =>   Decode Base64 String
    p     =>   Crypto Price & Conversion
    n     =>   Choose Blockchain Network
    e     =>   Exit Program
"""

import docs, re, sys, json, base64, requests, warnings
from secrets import choice
from platform import system as _ps
from importlib.machinery import SourceFileLoader
from shutil import copy as Cp
from pycoingecko import CoinGeckoAPI
from time import sleep
from pathlib import Path
from web3 import Web3, EthereumTesterProvider
from subprocess import call
from os import system, _exit
warnings.simplefilter(action='ignore', category=FutureWarning)
system('')

class Dapp:
    def __init__(self):
        """Connect & Interact With Various Ethereum Blockchains Using Specified Testnet/Mainnet Networks."""
        self.da=''
        self.pk=''
        self.nw=None
        self.node_url=''
        self.name=_ps()
        self.cg=CoinGeckoAPI()
        self.bt={
                'celo': 'CELO', 'starknet': 'STRK',
                'aurora': 'AURORA', 'near': 'NEAR',
                'avalanche': 'AVAX', 'palm': 'PALM',
                'arbitrum': 'ARB', 'optimism': 'OP',
                'polygon': 'MATIC', 'bsc': 'BNB'
                }
        self.ss='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        self.sw='https://{}api.0x.org/swap/v1/quote?buyToken={}&sellToken={}&{}Amount={}&slippagePercentage={}&takerAddress={}'
        self.hs='\n\033[1;34;40m{}\nTx_Hash: {}\033[0m'
        self.ns='\n\033[1;34;40m    current network: {} | connected: {}\n'
        self.nh='\n\033[1;34;40mTransaction Completed Successfully\nTx_Hash: {}\033[0m'
        self.at='\n\033[1;32;40mDo You Approve Transaction?\nInput y or n=> '
        pkg=str(Path.home().expanduser().joinpath('Desktop','DAPP'))
        if not Path(pkg).exists:Path(pkg).mkdir(parents=True, exist_ok=True)
        self.dp=Path(pkg).joinpath('config.py')
        self.cf=Path(pkg).joinpath('contract_info.txt')
        self.kf=Path(pkg).joinpath('key_file.txt')
        self.kd=Path(pkg).joinpath('key_data.txt')
        self.tr=Path(pkg).joinpath('tx_receipts.txt')
        self.lf=Path(pkg).joinpath('trade-log.txt')
        self.to=Path(pkg).joinpath('trade_output.txt')
        self.dc=(Path(__file__).absolute().parent).joinpath('dapp_config.py')
        if not Path(self.dp).exists():Cp(self.dc, self.dp)
        self.dcfg=self.config_import()
        self.web3=Web3(EthereumTesterProvider)
        self.web3.eth.account.enable_unaudited_hdwallet_features()

    def _fwrite(self, fn: str, data):
        """
        Writes Data To Specified File.
        :param fn: File To Write Data To
        :param data: Data To Write To File
        """
        with open(fn, 'a', encoding='utf-8') as fw:
            fw.write(data)

    def _fread(self, fn: str):
        """
        Returns Data Read From Specified File.
        :param fn: File To Read Data From
        """
        with open(fn, 'r', encoding='utf-8') as fr:
            return fr.read()

    def nw_status(self) -> bool:
        """Returns Web3 Connection Status True Or False."""
        try:
            return self.web3.is_connected()
        except:return False

    def config_import(self):
        """Returns `config.py` Module Imported From Wuddz-Dapp Output Folder."""
        mn='config'
        sp=SourceFileLoader(mn, str(self.dp))
        cm=sp.load_module()
        return cm

    def pexit(self):
        """Clear CLI Screen & Exit Program."""
        self.clear_screen()
        _exit(0)

    def get_menu(self, m: str='', c: bool=True):
        """
        Print Output To Screen & Wait For User Input.
        :param m: Optional String To Print To Screen, If String Is `e` Prints `*Error Occurred*`
        :param c: Optional Bool To Clear CLI Screen Or Not Defaults To True
        """
        if c:self.clear_screen()
        if m:
            a='\033[1;32;40m[*]OUTPUT:\n\n'
            if m=='e':m='\033[1;31;40m*Error Occurred*'
            m=a+m
        input(m+'\n\n\033[1;32;40m...Hit Enter|Return Key To Continue....\033[0m\n')

    def slow_print(self, doc: str, sp: float=0.0005):
        """
        Print String By Speed In Seconds Less Is Faster.
        :param doc: String To Be Printed
        :param sp:  Speed To Print String `e.g 0.0001 or 0.0005 used`
        """
        for d in doc:
            sys.stdout.write(f"\033[1;32;40m{d}")
            sleep(sp)

    def clear_screen(self):
        """Clear Command Line Screen."""
        if self.name=='Linux':system('clear')
        elif self.name=='Windows':system('cls')
        elif self.name=='Darwin':system("printf '\\33c\\e[3J'")

    def decode_bsf(self, s: str):
        """
        Prints Decoded Base64 String To Screen.
        :param s: Encoded Base64 String e.g `3R1ZGVudCBub2l=`
        """
        self.get_menu('\033[1;34;40m'+str(base64.b64decode(s).decode('utf-8')))

    def func_menu(self, c: str, i: str, n: str=None, f: str=None):
        """
        Loads Menu To Return Input.
        :param c: Menu Banner Type Docstring
        :param i: String Specifying Menu Input
        :param n: String To Specify Network Choice In Menu Defaults To None
        :param f: String Specifying Method To Execute Defaults To None
        """
        while True:
            try:
                self.clear_screen()
                d=f'\033[1;32;40m{c}\n\033[0mInput {i}=> '
                if n:d=f'\033[1;32;40m{c}{self.ns.format(self.nw,self.nw_status())}\n\033[0mInput {i}=> '
                a=input(d) or None
                if a=='b':break
                elif a=='e':self.pexit()
                elif n and a=='n':self.block_network()
                elif a and f:eval(f'self.{f}(a)')
                elif a:return a
            except Exception as e:self.get_menu(f'\033[1;31;40m{e}')

    def get_price(self, i: str='ethereum'):
        """
        Return Price Of Token In Usd Using CoinGecko API Token ID.
        :param i: Coingecko Token Id To Get Usd Value Defaults To BTC e.g `ethereum`
        """
        return self.cg.get_price(i,'usd')[i]['usd']

    def js_resp(self, u: str, h: dict={}):
        """
        Returns Url Request Response
        :param u: Url To Call
        :param h: Headers As Type Dictionary
        """
        return requests.get(u, headers=h, verify=None)

    def account_auth(self):
        """Loads Menu To Return Eth Account Object & Private Key From Input, Mnemonic String Or File."""
        try:
            pp=self.func_menu(docs.aa, 'Authentication', 'n')
            if not pp:return 'b',None
            if len(pp) in [64,66] or ' ' in pp:pk=pp
            elif len(pp)==44:pk=self.pkey_file(pp)
            da=self.account_key(pk, x='d')
            return da, pk
        except:pass

    def account_key(self, s: str, x: str=None):
        """
        Returns Address Or Prints Address Balance To Screen.
        :param s: Mnemonic String Or Private Key
        :param x: String To Specify Print Balance To Screen If Specified
        """
        if ' ' in s:acct=self.mnemonic_str(s)
        else:acct=self.pkey_str(s)
        if x:return acct
        bal=self.bal_main(acct.address)

    def mnemonic_str(self, m: str):
        """
        Returns Web3 Eth Account Object From Mnemonic String.
        :param m: Mnemonic String Of Account
        """
        return self.web3.eth.account.from_mnemonic(m)

    def pkey_str(self, k: str):
        """
        Returns Web3 Eth Account Object From Private Key.
        :param k: Private Key Of Account
        """
        return self.web3.eth.account.from_key(k)

    def account_create(self):
        """Creates A Web3 Eth Account, Writes Encrypted Data & Base64 Encoded Info To Output Files & Prints Address To Screen."""
        psd=''.join(choice(self.ss) for i in range(32))
        pd=base64.urlsafe_b64encode(bytes(psd, 'utf-8'))
        acct, mnemonic=self.eth_wallet()
        encrypted=self.web3.eth.account.encrypt(acct.key, psd)
        pk=base64.urlsafe_b64encode(bytes(self.web3.to_hex(acct.key), 'utf-8'))
        mn=base64.urlsafe_b64encode(bytes(mnemonic, 'utf-8'))
        self._fwrite(self.kf, f'{pd[:14]} {json.dumps(encrypted)}\n')
        self._fwrite(self.kd, f'Account: {acct.address}\nPrivate_Key: {pk}\nPrivate_Key_Password: {pd}\nMnemonic: {mn}\n\n')
        self.get_menu(f'\033[1;34;40mAccount_Created=> {acct.address}')

    def pkey_file(self, p: str):
        """
        Returns Private Key From File Containing Encrypted Account Data Using Password.
        :param p: Password To Decrypt Account Data
        """
        psd=str(base64.b64decode(p).decode('utf-8'))
        line=re.search("b'"+p[:14]+"' (.*)",self._fread(self.kf)).group(1)
        return self.web3.to_hex(self.web3.eth.account.decrypt(line, psd))

    def crypto_price(self):
        """Loads Menu To Get Crypto Price & Conversion Using CoinGecko API."""
        while True:
            try:
                self.clear_screen()
                cc=self.func_menu(docs.cp, 'Choice')
                if not cc:break
                ccl=cc.split()
                cd=self.cg.get_coin_by_id(ccl[1])
                cpa=self.cg.get_price(cd['id'],'usd')[str(cd['id'])]['usd']
                crp="${:,.2f}".format(float(ccl[0])*float(cpa))
                syma=cd['symbol'].upper()
                if len(ccl)==2:self.get_menu(f"\033[1;34;40m{cc.replace(ccl[1],syma)} => {crp} USD")
                elif len(cc.split())==3:
                    cb=self.cg.get_coin_by_id(ccl[2])
                    symb=cb['symbol'].upper()
                    cpb=self.cg.get_price(ccl[2],'usd')[str(ccl[2])]['usd']
                    cvv=float(ccl[0])*(float(cpa)/float(cpb))
                    self.get_menu(f"\033[1;34;40m{ccl[0]} {syma} => {cvv} {symb}\nTotal Value => {crp} USD")
            except requests.exceptions.ConnectionError:
                self.get_menu(f'\033[1;31;40mNo Connection Error!!')
            except:self.get_menu(f'\033[1;31;40m{cc} Not Valid!!')

    def eth_value(self, a: str):
        """
        Returns Balance Of Address In Ether Denomination.
        :param a: Address To Get Balance For
        """
        b=self.web3.eth.get_balance(self.web3.to_checksum_address(a))
        return self.web3.from_wei(b, 'ether')

    def ens_addr(self, a: str) -> str:
        """
        Return Ens Name Or Address For Specified Ens Name.
        :param a: Ens Name Or Address e.g `vitalik.eth | 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`
        """
        try:
            f='name'
            if '.eth' in a:f='address'
            adr=eval(f'self.web3.ens.{f}("{a}")')
            if f=='name':adr=re.search('\S+.eth',adr).group()
            return adr
        except:return a

    def tkn_address(self, s: str, n: str='mainnet') -> str:
        """
        Returns Token Contract Address From Dapp_Config Token Info If Available.
        :param s: Symbol Of Token To Retrieve Contract Address e.g `BNB`
        :param e: First Letter Of Token To Retrieve Contract Address e.g `BNB`
        """
        if n not in ['mainnet', 'polygon', 'goerli', 'sepolia', 'mumbai']:return
        return self.dcfg.tcd[n][[i for i in list(self.dcfg.tcd[n].keys()) if i==s.upper()][0]]

    def bal_main(self, a: str):
        """
        Prints Address Balance(s) To Screen From API Or Contract Call.
        :param a: Address To Get Balance(s) For
        """
        enn=''
        tca=''
        ttt=self.bt.get(self.nw)
        if not ttt:ttt='ETH'
        try:
            l=a.split()
            if len(l)==1:addr=l[0]
            elif len(l)==2:
                addr=l[0]
                if len(l[1])==42:tca=l[1]
                else:
                    tca=self.tkn_address(l[1], n=self.nw)
                    assert self.web3.to_checksum_address(tca)
            addr=self.ens_addr(l[0])
            if '.eth' in addr:
                enn=addr
                addr=l[0]
            elif '.eth' in a:enn=a
            base=self.eth_value(addr)
            if self.nw not in ['goerli','mumbai','sepolia','ganache','bsctestnet','development']:
                tot=0
                bs=''
                nw=self.nw[0].upper()+self.nw[1:]
                url=f'https://api.ethplorer.io/getAddressInfo/{addr}?showTxsCount=true&apiKey=freekey'
                if tca:url=f'https://api.ethplorer.io/getAddressInfo/{addr}?token={tca}&showETHTotals=false&showTxsCount=true&apiKey=freekey'
                bjs=self.js_resp(url).json()
                prc=bjs['ETH']['price']['rate']
                ethv=bjs['ETH']['balance']
                txc=bjs['countTxs']
                if bjs.get('tokens'):tot,bs=self.bal_sub(bjs)
                eus=float(prc)*float(ethv)
                usdt="${:,.2f}".format(tot+eus)
                eusd="${:,.2f}".format(eus)
                j=f'\033[1;34;40mAccount: {addr}\nEthereum: {ethv} ETH \033[1;32;40m({eusd} USD)\n'
                if ttt!='ETH':j=f'\033[1;34;40mAccount: {addr}\n{nw}: {base} {ttt}\nEthereum: {ethv} ETH \033[1;32;40m({eusd} USD)\n'
                if enn:j=j+f'\033[1;34;40mEnsName: {enn}\n'
                self.get_menu(bs+j+f'\033[1;34;40mTotal Value: \033[1;32;40m{usdt} USD\n\033[1;34;40mTotal Transactions: {txc}')
            else:
                if tca:c,ethv,ttt,tkn,d=self.contract_info(str(tca), chk=addr)
                self.get_menu(f'\033[1;34;40mAccount: {addr}\nBalance: {base} {ttt}')
        except:self.get_menu('e')

    def bal_sub(self, d: dict) -> int:
        """
        Returns Total USD Value Of All Tokens API Dictionary Response & Prints Each Iterated Token & Balance To Screen.
        :param d: Ethplorer API Response As Json Dictionary
        """
        tot=[]
        bl=''
        for i in range(len(d['tokens'])+1):
            usdc='0'
            try:
                nam=d['tokens'][i]['tokenInfo']['name']
                sym=d['tokens'][i]['tokenInfo']['symbol']
                dec=d['tokens'][i]['tokenInfo']['decimals']
                rbal=d['tokens'][i]['rawBalance']
                bal=rbal
                if str(dec).isdigit():bal=int(rbal)/10**int(dec)
                if d['tokens'][i]['tokenInfo']['price']:
                    pri=d['tokens'][i]['tokenInfo']['price']['rate']
                    usd=float(pri)*int(bal)
                    tot.append(usd)
                    usdc="{:,.2f}".format(usd)
                bl+=f'\033[1;34;40m{nam}: {bal} \033[1;32;40m(${usdc} USD) \033[1;34;40m{sym}\033[0m\n\n'
            except:pass
        return sum(tot),bl

    def bal_fkey(self):
        """Loads Menu To Print Balance & Address Of Token From Authentication."""
        while True:
            try:
                a,k=self.account_auth()
                if a=='b':break
                self.bal_main(a.address)
            except:self.get_menu('e')

    def trx_hash(self, h: str, o=None):
        """
        Prints OR Writes Transaction Hash Info To Screen/Output File.
        :param h: Transaction Hash
        :param o: String To Specify Write Transaction Info To File Defaults To None
        """
        txr=dict(self.web3.eth.get_transaction(h))
        txr['gas']=format(self.web3.from_wei(txr['gas'], 'ether'),'f')
        txr['gasPrice']=format(self.web3.from_wei(txr['gasPrice'], 'ether'),'f')
        txr['value']=self.web3.from_wei(txr['value'], 'ether')
        txr['blockHash']=self.web3.to_hex(txr['blockHash'])
        txr['hash']=self.web3.to_hex(txr['hash'])
        txr['r']=self.web3.to_hex(txr['r'])
        txr['s']=self.web3.to_hex(txr['s'])
        if o:self._fwrite(self.tr, f'{self.node_url}\n{json.dumps(txr, indent=4, default=str)}\n\n')
        else:self.get_menu('\033[1;34;40m'+json.dumps(txr, indent=4, default=str))

    def block_network(self, nc: str=None):
        """
        Sets Or Loads Menu To Select & Set Specified Blockchain Network.
        :param nc: String To Specify Blockchain Network e.g `mainnet | goerli`
        """
        d={'1':'mainnet','2':'sepolia','3':'goerli',
           '4':'linea','5':'celo','6':'starknet',
           '7':'aurora','8':'near','9':'avalanche',
           '10':'palm','11':'arbitrum', '12':'optimism',
           '13':'polygon', '14':'mumbai', '15':'bsc',
		   '16':'bsctestnet', 'g':'ganache', 'd':'development'}
        try:
            if not nc:nc=self.func_menu(docs.nwl, 'Network Choice')
            if d.get(nc):self.nw=str(d[nc])
            else:self.nw='mainnet'
            self.node_url=eval(f'self.dcfg.{self.nw}')
            self.web3=Web3(Web3.HTTPProvider(self.node_url))
        except:pass

    def account_deposit(self):
        """Loads Menu To Create, Approve & Sign Deposit Transaction."""
        while True:
            try:
                ttt='ETH'
                acc, pk=self.account_auth()
                if acc=='b':break
                nonce=self.web3.eth.get_transaction_count(acc.address)
                dtx=self.func_menu(docs.der, 'Transfer Format', n='n')
                if not dtx:break
                dpa,amnt,tca=dtx.split()
                if tca.lower()!='eth':
                   if len(tca)!=42:
                       tca=self.tkn_address(tca, n=self.nw)
                       assert self.web3.to_checksum_address(tca)
                   c,b,ttt,n,dec=self.contract_info(tca)
                   amt=float(amnt)*(10**int(dec))
                else:amt=self.web3.to_wei(amnt, 'ether')
                assert self.web3.to_checksum_address(dpa)
                if ttt=='ETH':tx=self.transfer_eth(dpa, amt, nonce)
                else:tx=self.transfer_tkn(contract, dpa, amt, nonce)
                tc='\n\033[1;32;40mTransaction:\033[1;34;40m\n{}\n{}\n'
                td='Deposit Amount: {} {}\nFrom: {}\nTo: {}'.format(str(amnt), ttt, acc.address, dpa)
                at=tc.format(json.dumps(tx, indent=2, default=str),td)
                ap=input(f'{at}{self.at}') or 'n'
                if ap=='y':self.sign_tx(tx,pk)
            except:self.get_menu('e')

    def sign_tx(self, tx: dict, k: str, hs: str=None, cd: str=None):
        """
        Signs Transaction With Provided Private Key, Returns Or Prints To Screen & Writes Tx Hash & Receipt To Output File.
        :param tx: Unsigned Transaction As Type Dictionary
        :param k:  Private Key To Sign Transaction
        :param hs: Optional String If Specified Prints Transaction Hash To Screen Defaults To None
        :param cd: Optional String If Specified Returns Transaction Receipt & Hash Defaults To None
        """
        signed_tx=self.web3.eth.account.sign_tx(tx, k)
        tx_hash=self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
        tx_receipt=self.web3.eth.wait_for_transaction_receipt(tx_hash)
        th=self.web3.to_hex(tx_receipt.transactionHash)
        if cd:return tx_receipt,th
        elif hs:print(self.hs.format(hs,th))
        else:self.get_menu(self.nh.format(th))
        self.trx_hash(th,'t')

    def get_contract(self, abi: list, ca: str=None, bc: str=None):
        """
        Returns Web3 Contract Instance For Specified Contract Address.
        :param abi: ABI List For Specified Contract `ca`
        :param ca:  Contract Address Defaults To None
        :param bc:  Contract ByteCode Defaults To None
        """
        if ca:return self.web3.eth.contract(abi=abi, address=ca)
        return self.web3.eth.contract(abi=abi, bytecode=bc)

    def contract_info(self, tca: str, chk: str=None):
        """
        Returns Web3 Contract Instance, Balance Of Contract Name For Address If Specified, Symbol, Name & Decimal Number For Contract Address.
        :param tca: Contract Address
        :param chk: Address To Get Balance Of Contract Address For Defaults To None
        """
        ethv=''
        contract=self.get_contract(self.dcfg.abi, ca=tca)
        if chk:ethv=contract.functions.balanceOf(str(chk)).call()
        dec=contract.functions.decimals().call()
        sym=contract.functions.symbol().call()
        nam=contract.functions.name().call()
        if str(dec)!='0' and chk:ethv=ethv/10**dec
        return contract,ethv,sym,nam,dec

    def contract_rw(self, addr: str):
        """
        Loads Menu To Interact, Call & Execute Contract Functions & Print Results.
        :param addr: Verified Smart Contract Address
        """
        abi=''
        if self.nw=='ganache':abi=self.local_abi()
        else:abi=self.remote_abi(addr, n=self.nw)
        if abi:
            contract=self.get_contract(abi, ca=addr)
            cfs=[(str(c).split('>')[0]).split(' ')[1] for c in contract.all_functions()]
            if cfs:
                dec=''
                if 'decimals()' in str(cfs):dec=contract.functions.decimals().call()
                while True:
                    self.clear_screen()
                    print(f'\n\033[1;32;40m [*]ALL CONTRACT FUNCTIONS FOR => {addr}:\033[0m\n')
                    for c in cfs:
                        if '()' in c:c=self.contract_call(contract,c,dec=dec)
                        print(f'\033[1;34;40m{c}\033[0m')
                    fnc=input(f'\n\033[1;32;40m{docs.crw}\033[0m\nInput Choice=> ')
                    if fnc=='b':break
                    elif fnc=='c':self.convert_value()
                    elif f'{fnc}(' in str(cfs):
                        v=[c for c in cfs if f'{fnc}(' in c][0]
                        self.contract_sub(v,contract,dec)
            else:self.get_menu('\033[1;31;40m*Contract Not Valid*')
        else:self.get_menu('\033[1;31;40m*Contract Abi Not Found*')

    def contract_sub(self, fnc: str, contract, dec: str):
        """
        Execute Private Contract Function.
        :param fnc: Function To Be Executed e.g `balanceOf`
        :param contract: Contract Instance To Execute Functions
        :param dec: Decimal Number For Contract
        """
        if '()' in fnc:self.get_menu(self.contract_call(contract,fnc,dec=dec))
        else:
            et=''
            fnc=fnc.split('(')[0]
            fd,et=self.contract_data(fnc,contract.abi)
            fo=f'{fnc}('
            for k,v in fd.items():
                if v:
                    if 'uint' in str(k):fo+=f'int("{v}"),'
                    else:fo+=f'"{v}",'
            if fo[-1]!='(':
                fp=f'{fo[:-1]})'
                if str(et) not in ['pure', 'view']:
                    acc, pk=self.account_auth()
                    if acc=='b':return
                    nonce=self.web3.eth.get_transaction_count(acc.address)
                    gas=eval(fp).estimate_gas()
                    tx=eval(fp).build_transaction({'nonce': nonce, 'gas': gas, 'gasPrice': self.web3.eth.gas_price})
                    self.sign_tx(tx,pk)
                else:self.get_menu(self.contract_call(contract,fp,dec=dec))
            else:self.get_menu('e')

    def contract_deploy(self, cn: str):
        """
        Verifies & Deploys Smart Contract To Current Blockchain Network & Prints Transaction Results To Screen.
        :param cn: Name Of Contract To Be Deployed
        """
        fd=list(Path(self.dcfg.scdir).rglob(f'{cn}.json'))
        if fd:fd=fd[0]
        else:call(['truffle', 'compile'], cwd=self.dcfg.scdir)
        ci=json.loads(self._fread(fd))
        abi=ci['abi']
        bc=ci['bytecode']
        acc,pk=self.account_auth()
        contract=self.get_contract(abi=abi, bc=bc)
        tx=contract.constructor().build_transaction(
              {
               'nonce': self.web3.eth.get_transaction_count(acc.address),
               'gasPrice': self.web3.eth.gas_price
              }
           )
        txr,txh=self.sign_tx(tx,pk,cd='cd')
        ca=txr.contractAddress
        cna=f'{cn}@{ca}'
        self._fwrite(self.cf, f'name: {cn}.json\nabi: {abi}\naddress: {ca}\nnetwork: {self.node_url}\n\n')
        if self.nw!='ganache':call(['truffle', 'run', 'verify', cna, '--network', self.nw], cwd=self.dcfg.scdir)
        self.trx_hash(txh,'t')
        self.get_menu(f'\n\033[1;34;40mSmart_Contract_Address: {ca}')

    def contract_call(self, contract, cf: str, dec: str=None):
        """
        Prints Contract Function Call & Result To Screen If Valid.
        :param contract: Contract Instance To Call Functions With
        :param cf:  Contract Function To Call e.g `balanceOf`
        :param dec: Decimal Number For Token Contract Defaults To None
        """
        try:
            fnc=eval(f'contract.functions.{cf}.call()')
            if dec and len(str(fnc))>int(dec):fnc=fnc/(10**int(dec))
            return f'\033[1;34;40m{cf} = {fnc}\033[0m'
        except:return 'e'

    def convert_value(self):
        """Loads Menu To Convert To/From Wei."""
        while True:
            try:
                self.clear_screen()
                cv=input(f'\n\033[1;32;40m{docs.cwd}\n\033[0mInput Parameters=> ')
                if cv=='b':break
                cv=cv.split()
                if cv[2]=='w':
                    cs="\033[1;34;40m{} => {}"
                    if cv[1]=='t':self.get_menu(cs.format('Wei', self.web3.to_wei(float(cv[0]), 'ether')))
                    elif cv[1]=='f':self.get_menu(cs.format('Eth', self.web3.to_wei(float(cv[0]), 'ether')))
                elif str(cv[2]).isdigit():
                    if cv[1]=='t':val=float(cv[0])*10**int(cv[2])
                    else:val=float(cv[0])/10**int(cv[2])
                    self.get_menu(f"\033[1;34;40mValue => {val}")
            except:pass

    def remote_abi(self, a: str, n: str='mainnet'):
        """
        Returns ABI Of Verified Contract Address Using Etherscan API.
        :param a: Verified Contract Address
        :param n: Network Verified Contract Address Is Deployed On e.g `goerli`
        """
        abi=''
        try:
            cn=''
            ed={'User-Agent': 'Mozilla/5.0', 'Host':'api.etherscan.io'}
            hd={'User-Agent': 'Mozilla/5.0', 'Host':f'api-{n}.etherscan.io'}
            md={'User-Agent': 'Mozilla/5.0', 'Host':'api-testnet.polygonscan.com'}
            pd={'User-Agent': 'Mozilla/5.0', 'Host':'api.polygonscan.com'}
            if n=='mainnet':
                cn=requests.get(f'https://api.etherscan.io/api?module=contract&action=getabi&address={a}', headers=ed).text
            elif n=='mumbai':
                cn=requests.get(f'https://api-testnet.polygonscan.com/api?module=contract&action=getabi&address={a}', headers=md).text
            elif n=='polygon':
                cn=requests.get(f'https://api.polygonscan.com/api?module=contract&action=getabi&address={a}', headers=pd).text
            elif n!='ganache':
                cn=requests.get(f'https://api-{n}.etherscan.io/api?module=contract&action=getabi&address={a}', headers=hd).text
            abi=json.loads(cn)['result']
        except requests.exceptions.ConnectionError:
            print(f'\033[1;31;40mNo Connection Error!!\033[0m')
        return abi

    def local_abi(self):
        """Loads Prompt To Return ABI Of Locally Stored Contract."""
        abi=''
        cnt=input('\nInput Contract Name Or Pass=> ')
        if cnt:
            ci=json.loads(self._fread(Path(self.dcfg.scdir).joinpath('build','contracts',f'{cnt}.json')))
            abi=ci['abi']
        return abi

    def token_id(self):
        """Loads Menu To Search For Token Id Using CoinGecko API."""
        while True:
            try:
                st=self.func_menu(docs.st, 'String')
                if not st:break
                sd=self.cg.search(st)['coins']
                print('')
                for i in range(len(sd)):
                    print("Id: {},  Name: {},  Symbol: {}".format(sd[i]['id'], sd[i]['name'], sd[i]['api_symbol']))
                input('\n\n\033[1;32;40m...Hit Enter|Return Key To Continue....\033[0m\n') or None
            except:pass

    def eth_wallet(self):
        """Returns Tuple Containing Eth Account Object & Mnemonic String For Newly Created Account."""
        return self.web3.eth.account.create_with_mnemonic()

    def token_swap(self):
        """Loads Menu To Swap Tokens On Blockchain Of Choice."""
        while True:
            try:
                acc, pk=self.account_auth()
                if acc=='b':break
                td={'1': '','2': 'goerli.',
                    '3': 'polygon.','4': 'mumbai.',
                    '5': 'bsc.','6': 'optimism.',
                    '7': 'fantom.','8': 'celo.',
                    '9': 'avalanche.','10': 'arbitrum.',
                    '11': 'base.'
                    }
                self.clear_screen()
                chain=input(f'\n\033[1;32;40m{docs.tsn}\033[0m\nInput Number=> ') or '1'
                self.clear_screen()
                ld={
                    '1  ->  BuyToken        [e.g DAI Or Token Smart Contract Address]':'',
                    '2  ->  Slippage        [e.g 0.01 = 1% slippage]':'0.01',
                    '3  ->  SellToken       [e.g ETH Or Token Smart Contract Address]':'ETH',
                    '4  ->  SellAmount      [e.g Sell Specified Amount Of Sell Token]':'',
                    '5  ->  BuyAmount       [e.g Buy Specified Amount Of Buy Token]':'',
                    '6  ->  TakerAddress    [e.g Address]':acc.address
                   }
                kd={f'{k.split()[0]} ':k for k in ld.keys()}
                hd=self.function_dict(ld,kd,docs.tsa,st='s',zx=td[chain][:-1])
                bt=[x for x in (v for k,v in hd.items())]
                dt=[d for d in bt if d]
                bs='Buy'
                if bt[3]:bs='Sell'
                ff=self.web3.to_checksum_address(dt[4])
                api=self.js_resp(self.sw.format(td[str(chain)],dt[0],dt[2],bs.lower(),dt[3],dt[1],ff), h=self.dcfg.zerox).json()
                ps=dict(api)
                del(ps['data'])
                del(ps['sources'])
                apr=input(f'\n\033[1;34;40m{json.dumps(ps, indent=4)}{self.at}') or 'n'
                if apr.lower()=='y':
                    self.token_approve(api['sellTokenAddress'],acc.address,pk,api['sellAmount'],n=str(td[chain])[:-1])
                    nonce=self.web3.eth.get_transaction_count(acc.address)
                    tx={
                        'nonce': nonce,
                        'from':acc.address,
                        'to': self.web3.to_checksum_address(api['to']),
                        'data': api['data'],
                        'value': int(api['value']),
                        'gas': int(api['gas']),
                        'gasPrice': int(api['gasPrice']),
                        'chainId': api['chainId']
                        }
                    self.sign_tx(tx,pk)
            except requests.exceptions.ConnectionError:
                self.get_menu(f'\033[1;31;40mConnection Error!!')
            except Exception as e:self.get_menu(f'\033[1;31;40m{e}')

    def token_approve(self, t: str, o: str, k: str, a: str, n: str='mainnet'):
        """
        Creates & Signs Swap Approval Transaction.
        :param t: Token Contract Address
        :param o: Owner Address Containing Token To Swap
        :param k: Private Key Of Owner Address
        :param a: Amount Of Token To Be Swapped
        :param n: Network To Make Swap On Defaults To Ethereum Mainnet e.g `polygon | mainnet`
        """
        da=self.dcfg.exp[n]
        contract=self.web3.eth.contract(address=self.web3.to_checksum_address(t), abi=self.dcfg.abi)
        spender=self.web3.to_checksum_address(da)
        tx=contract.functions.approve(spender, int(a)).build_transaction({
            'from': o,
            'nonce': self.web3.eth.get_transaction_count(o),
        })
        self.sign_tx(tx,k,hs='Transaction Approved')

    def contract_data(self, fnc: str, abi: list):
        """
        Returns Contract Function Parameters As Dictionary & Function Type As String.
        :param fnc: Name Of Contract Function e.g `balanceOf`
        :param abi: ABI Of Contract Type List
        """
        doc=f" [*]{fnc}() FUNCTION PARAMETERS:"
        ld={}
        hd={}
        ex=''
        for i in range(len(abi)):
            if abi[i].get('type')=='function' and abi[i].get('name')==fnc:
                ex=abi[i]['stateMutability']
                lst=abi[i]['inputs']
                for n in range(len(lst)):
                    la=f'{n+1} -> {lst[n]["type"]} ({lst[n]["name"]})'
                    ld[la]=''
                    hd[f'{n+1} ']=la
        ld=self.function_dict(ld,hd,doc)
        return ld,ex

    def function_dict(self, ld: dict, hd: dict, sd: str, st: str=None, zx: str=None) -> dict:
        """
        Loads Menu To Set & Return Function Arguments & Values As Dictionary.
        :param ld: Arguments Dictionary
        :param hd: Arguments Key Dictionary
        :param sd: Banner String
        :param st: String To Specify Swap Token Menu Banner Defaults To None
        :param zx: 0x Swap Network As String Defaults To None e.g `celo`
        """
        od=dict(ld)
        while True:
            try:
                fs='Function'
                self.clear_screen()
                if st:
                    fs='Swap'
                    doc=docs.fdi+docs.fdt+self.ns.format(self.nw,self.nw_status())+f'\nSwap Network: {zx}'
                else:doc=docs.fdi+self.ns.format(self.nw,self.nw_status())
                bs=f'\n\033[1;32;40m{sd}\n{doc}\n\033[1;34;40m{fs} Parameters: {json.dumps(ld, indent=2)}'
                lda=input(f'{bs}\n\n\033[0mInput Choice=> ')
                if lda=='b':break
                elif lda=='e':self.pexit()
                elif lda=='n':self.block_network()
                elif lda=='c':self.convert_value()
                elif lda=='d':ld.update(od)
                elif len(lda)>1:
                    if lda[0]=='t' and st:
                        s=lda[2:]
                        tca=self.tkn_address(s, n=zx)
                        if not tca:
                            self.get_menu(f'\033[1;31;40m*{s} Not Found In Dapp_Config*')
                            continue
                        c,v,t,n,d=self.contract_info(tca)
                        self.get_menu(f'\033[1;34;40mAddress: {tca}\nName: {n}\nSymbol: {t}\nDecimals: {d}\nNetwork: {self.nw}')
                    elif hd.get(lda[:2]):
                        k,v=lda[:2],lda[2:]
                        ld[hd[k]]=v
            except:self.get_menu('e')
        return ld

    def contract_verify(self, s: str):
        """
        Verify Contract On Blockchain.
        :param s: String With Contract Name & Contract Address e.g `FeeCollector 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045`
        """
        cn,adr=s.split()
        if adr and cn:
            cna=f'{cn}@{adr}'
            call(['truffle', 'run', 'verify', cna, '--network', self.nw], cwd=self.dcfg.scdir)
            self.get_menu(c=False)

    def transfer_eth(self, d: str, a: str, n: str) -> dict:
        """
        Returns Unsigned Transaction Dictionary For Transferral Of Ethereum.
        :param d: Deposit Address
        :param a: Exact Amount To Transfer (Converted To Wei/Decimal)
        :param n: Nonce (Amount Of Transactions Made By Address)
        """
        gas=self.web3.eth.estimate_gas({'to': d, 'value': a})
        tx={
            'nonce': n,
            'to': d,
            'value': a,
            'gas': gas,
            'gasPrice': self.web3.eth.gas_price
           }
        return tx

    def transfer_tkn(self, c, d: str, a: str, n: str) -> dict:
        """
        Returns Unsigned Transaction Dictionary For Transferral Of Contract Address Token.
        :param c: Eth Contract Object To Execute Token Smart Contract Functions
        :param d: Deposit Address
        :param a: Exact Amount To Transfer (Converted To Wei/Decimal)
        :param n: Nonce (Amount Of Transactions Made By Address)
        """
        gas=c.functions.transfer(d, a).estimate_gas()
        tx=c.functions.transfer(d, a).build_transaction({
            'nonce': n,
            'gas': gas,
            'gasPrice': self.web3.eth.gas_price
            })
        return tx

    def main(self):
        """Loads Wuddz_Dapp Main Menu."""
        while True:
            try:
                self.clear_screen()
                self.slow_print(__doc__)
                etht=input("\033[0m\nInput Choice=> ")
                if etht=='e':break
                elif etht=='d':self.func_menu(docs.ds, 'String', f='decode_bsf')
                elif etht=='p':self.crypto_price()
                elif etht=='n':self.block_network()
                elif etht=='x':
                    import exchange_api as _eapi
                    _eapi.Exchange().main()
                elif etht=='1':self.account_create()
                elif etht=='2':self.func_menu(docs.gb, 'Balance Format', n='n', f='bal_main')
                elif etht=='3':self.account_deposit()
                elif etht=='4':self.bal_fkey()
                elif etht=='5':self.func_menu(docs.ts, 'Hash', n='n', f='trx_hash')
                elif etht=='6':self.func_menu(docs.cnf, 'Contract Name', n='n', f='contract_deploy')
                elif etht=='7':self.func_menu(docs.sca, 'Contract Address', n='n', f='contract_rw')
                elif etht=='8':self.func_menu(docs.cnv, 'Verify Format', n='n', f='contract_verify')
                elif etht=='9':self.token_swap()
            except KeyboardInterrupt:break
        self.clear_screen()

def cli_main():
    """Wuddz_Dapp Entry Point Launches Wuddz_Dapp Main Menu."""
    Dapp().main()


import os
import pandas as pd
from tqdm import tqdm

from geopy.geocoders import Nominatim

loc_app = Nominatim(user_agent="tutorial")
data_load_path = os.path.join('..', '..', 'data', 'train.csv')
data_dump_path = os.path.join('..', '..', 'data', 'df_for_plot_on_map.csv')

def recognize_location(location: str):
    try:
        return loc_app.geocode(location).raw
    except:
        return None

def prepare_df_for_plot_on_map(dataset: pd.DataFrame) -> pd.DataFrame:
    df = dataset.copy()
    df = df[df['location'].notna()]

    if 'size' not in df.columns:
        df['target'] = df['target'].map({0: 'fake', 1: 'real'})
        df['size'] = 1

    right_locations = []
    for _, row in tqdm(df.iterrows(), total=len(df)):
        right_locations.append(recognize_location(row['location']))

    df['lat'] = [el['lat'] if isinstance(el, dict) else None for el in right_locations]
    df['lon'] = [el['lon'] if isinstance(el, dict) else None for el in right_locations]

    df = df.dropna(subset=['location', 'lat', 'lon'])
    return df

if __name__ == '__main__':
    df = pd.read_csv(data_load_path)
    print(f"DF SHAPE: {df.shape}")

    df = prepare_df_for_plot_on_map(df)
    print(f"PREPARED DF SHAPE: {df.shape}")
    df.to_csv(data_dump_path, index=False)


# Importing Module
from pygame import mixer
import customtkinter, tkinter
from PIL import Image
import eyed3
import os

mixer.init()

# Variables
sList = []
musicFolder = "/home/bir/Music/"
current = ''
start = False
fname = "assets/notfound.jpg"

# Functions
def changeThumb():
    global fname, playImg, mImg
    audio_file = eyed3.load(musicFolder+current)

    image = audio_file.tag.images[0]
    fname = f"assets/song.png"
    image_file = open(fname, "wb")
    image_file.write(image.image_data)
    image_file.close()

    playImg.configure(light_image=Image.open(fname))

    os.remove(fname)

def play():
    global start, current
    if current == '':
        current = sList[0]

    i = sList.index(current)
    changeThumb()

    if start:
        mixer.music.unpause()
    else:
        mixer.music.load(musicFolder+current)
        mixer.music.play()
        mixer.music.queue(musicFolder+current)
        start = True

def pause():
    mixer.music.pause()

def resume():
    mixer.music.unpause()

def next():
    global current, start
    length = len(sList)-1
    i = sList.index(current)

    if i < length:
        current = sList[i+1]
    else:
        current = sList[0]

    changeThumb()
    start = False
    play()

def prev():
    global current, start
    length = len(sList)-1
    i = sList.index(current)

    if i != length:
        current = sList[i-1]
    else:
        current = sList[0]

    changeThumb()
    start = False
    play()

def lsSongs():
    for f in os.listdir(musicFolder):
        if '.mp3' in f or '.wav' in f:
            sList.append(f)

def addsongs():
    global current, musicFolder,sList
    songs = list(tkinter.filedialog.askopenfilenames(initialdir=musicFolder,title="Choose a song", filetypes=(("mp3 Files","*.mp3"),)))
    if len(songs) != 0:
        sList = songs
        current = sList[0]
        print(current)
        musicFolder = ''
        next()

# Main GUI Code
root = customtkinter.CTk()
root.geometry("840x545")
root.minsize(840, 545)
root.maxsize(840, 545)
root.title("Music Player")

# Fonts
bg = customtkinter.CTkFont(family="Helevetica", size=35, weight = 'bold')
md = customtkinter.CTkFont(family="Helevetica", size=18, weight='bold')
sm = customtkinter.CTkFont(family="Helevetica", size=15)

lsSongs()

# Menu Bar
mainmenu = customtkinter.CTkFrame(root, height=30, width=830)
mainmenu.grid(row=0, column=0,padx=5, pady=5, sticky="nw")

addSongs = customtkinter.CTkButton(mainmenu, text="Add Songs", width=50, height=20, font=md, corner_radius=0, command=addsongs, fg_color="transparent")
addSongs.grid(padx=5,ipadx=5,ipady=5,sticky="w")

# Music Thumbnail
mThumb = customtkinter.CTkFrame(master=root, width=835, height=370, fg_color="transparent")
mThumb.grid(row=1, column=0, padx=5, pady=5)
playImg = customtkinter.CTkImage(light_image=Image.open(fname), size=(835,370))
mImg = customtkinter.CTkLabel(mThumb, image=playImg, text="")
mImg.grid(padx=0)

# Music Player Options
mPlay = customtkinter.CTkFrame(master=root, width=835, height=110, fg_color='transparent')
mPlay.grid(row=2, columnspan=2, column=0, padx=5, pady=15)

nextBtn = customtkinter.CTkButton(mPlay, text="Prev", width=75, height=75, corner_radius=75, font=md, border_spacing=0, command=prev)
nextBtn.pack(side='left', padx=7)

playBtn = customtkinter.CTkButton(mPlay, text="Play", width=75, height=75, corner_radius=75, font=md, border_spacing=0, command=play)
playBtn.pack(side='left', padx=7)

pauseBtn = customtkinter.CTkButton(mPlay, text="Pause", width=75, height=75, corner_radius=75, font=md, border_spacing=0, command=pause)
pauseBtn.pack(side='left', padx=7)

nextBtn = customtkinter.CTkButton(mPlay, text="Next", width=75, height=75, corner_radius=75, font=md, border_spacing=0, command=next)
nextBtn.pack(side='left', padx=7)

root.mainloop()


import json
import pickle
import time
from hashlib import sha256
# Block class
# Block is a class that contains the data and the hash of the previous block
# The hash of the previous block is used to link the blocks together
# The hash of the block is used to verify the integrity of the chain
# We plan to use the blockchain to store the data
# Need to solve below issues:
# 1. In CRUD operations, we need to be able to add, read data
# 2. How to solve the conflicts
# 3. Performance of reading data, especially when the data is large and have many nodes
from os.path import exists

from decouple import config

class Block:
    def __init__(self, index, data, timestamp, previous_hash):
        self.index = index
        self.data = data
        self.timestamp = timestamp
        self.previous_hash = previous_hash
        self.nonce = 0

    def compute_hash(self):
        """
        A function that return the hash of the block contents.
        """
        block_string = json.dumps(self.__dict__, sort_keys=True)
        return sha256(block_string.encode()).hexdigest()

class Blockchain:
    # difficulty of our PoW algorithm
    difficulty = 2
    file_name = config("BLOCK_CHAIN_BACKUP", default='./blockchain.bk')

    def __init__(self):
        if exists(self.file_name):
            with open(self.file_name, 'rb') as f:
                self.chain = pickle.load(f)
        else:
            self.unconfirmed_data = []
            self.chain = []
            self.create_genesis_block()

    def dump_data(self):
        pickle.dump(self.chain, open(self.file_name, 'wb'))

    def create_genesis_block(self):
        """
        A function to generate genesis block and appends it to
        the chain. The block has index number 0, previous_hash as 0, and
        a valid hash.
        """
        genesis_block = Block(0, [], time.time(), "0")
        genesis_block.hash = genesis_block.compute_hash()
        self.chain.append(genesis_block)

    @property
    def last_block(self):
        return self.chain[-1]

    def add_block(self, block, proof):
        """
        A function that adds the block to the chain after verification.
        Verification includes:
        * Checking if the proof is valid.
        * The previous_hash referred in the block and the hash of last block
          in the chain match.
        """
        previous_hash = self.last_block.hash

        if previous_hash != block.previous_hash:
            return False

        if not self.is_valid_proof(block, proof):
            return False

        block.hash = proof
        self.chain.append(block)
        return True

    def is_valid_proof(self, block, block_hash):
        """
        Check if block_hash is valid hash of block and satisfies
        the difficulty criteria.
        """
        return (block_hash.startswith('0' * Blockchain.difficulty) and
                block_hash == block.compute_hash())

    def proof_of_work(self, block):
        """
        Function that tries different values of nonce to get a hash
        that satisfies our difficulty criteria.
        """
        block.nonce = 0

        computed_hash = block.compute_hash()
        while not computed_hash.startswith('0' * Blockchain.difficulty):
            block.nonce += 1
            computed_hash = block.compute_hash()

        return computed_hash

    def set_data(self, data):
        self.unconfirmed_data.append(data)

    @classmethod
    def check_chain_validity(cls, chain):
        result = True
        previous_hash = "0"

        for block in chain:
            block_hash = block.hash
            # remove the hash field to recompute the hash again
            # using `compute_hash` method.
            delattr(block, "hash")

            if not cls.is_valid_proof(block, block_hash) or \
                    previous_hash != block.previous_hash:
                result = False
                break

            block.hash, previous_hash = block_hash, block_hash

        return result

    def mine(self):
        """
        This function serves as an interface to add the pending
        transactions to the blockchain by adding them to the block
        and figuring out Proof Of Work.
        """
        if not self.unconfirmed_data:
            return False

        last_block = self.last_block

        new_block = Block(index=last_block.index + 1,
                          data=self.unconfirmed_data,
                          timestamp=time.time(),
                          previous_hash=last_block.hash)

        proof = self.proof_of_work(new_block)
        self.add_block(new_block, proof)

        self.unconfirmed_data = []
        return new_block.index


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import os.path as osp
from os.path import join as pjoin
import numpy as np
# from distutils import spawn
# run: pip install easydict
from easydict import EasyDict as edict

__C = edict()
# get config by:
#   from lib.config import cfg
cfg = __C

#
# Training options
#

__C.TRAIN = edict()

# Whether to use focal loss to train
__C.TRAIN.USE_FOCAL_LOSS = False

# learning rate manully decay
__C.TRAIN.LR_DIY_DECAY = False

# training optimizer: either 'adam' 'sgd_m'
__C.TRAIN.OPTIMIZER = 'adam'

__C.TRAIN.MOMENTUM = 0.9

# Initial learning rate
__C.TRAIN.LEARNING_RATE = 1e-3

# Weight decay, for regularization
__C.TRAIN.WEIGHT_DECAY = 0.001

# Use horizontally-flipped images during training?
__C.TRAIN.USE_FLIPPED = True

# Weight initializer
__C.TRAIN.WEIGHT_INITIALIZER = 'normal'

# Image size
__C.TRAIN.IMG_WIDTH = 224
__C.TRAIN.IMG_HEIGHT = 224

__C.TRAIN.EXP_DECAY_STEPS = 5000
__C.TRAIN.EXP_DECAY_RATE = 0.8

__C.TRAIN.BATCH_SIZE = 32

# The time interval for saving tensorflow summaries
__C.TRAIN.SUMMARY_INTERVAL = 300

# Iterations between snapshots
__C.TRAIN.SNAPSHOT_ITERS = 5000

__C.TRAIN.DISPLAY = 10

# TEST OPTIONS

__C.TEST = edict()

__C.TEST.FLIP = False

__C.NET = 'res101'

# Global settings
__C.DATA_PATH = '/home/joe/git/furniture/data'

__C.EXP_DIR = 'default'

__C.DEBUG = False

# __C.PIXEL_MEANS = np.array([[[102.9801, 115.9465, 122.7717]]])
# VGG preprocessing tf.slim
__C.PIXEL_MEANS = np.array([[[123.681, 116.78, 103.94]]])

#
# ResNet options
#

__C.RESNET = edict()

__C.RESNET.FIXED_BLOCKS = 3

# Root directory of project
__C.ROOT_DIR = osp.abspath(pjoin(osp.dirname(__file__), '..'))

__C.RESULT_PATH = pjoin(__C.ROOT_DIR, 'result')

def get_output_dir():
    """Return the directory where experimental artifacts are placed.
    If the directory does not exist, it is created.

    A canonical path is built using the name from an imdb and a network
    (if not None).
    """
    outdir = osp.abspath(osp.join(__C.ROOT_DIR, 'output', __C.EXP_DIR, 'ckpt'))
    # if weights_filename is not None:
    #     outdir = osp.join(outdir, weights_filename)
    if not os.path.exists(outdir):
        os.makedirs(outdir)
    return outdir

def get_output_tb_dir():
    """Return the directory where tensorflow summaries are placed.
    If the directory does not exist, it is created.

    A canonical path is built using the name from an imdb and a network
    (if not None).
    """
    outdir = osp.abspath(osp.join(__C.ROOT_DIR, 'output', __C.EXP_DIR, 'tb'))
    # if weights_filename is None:
    #     weights_filename = 'default'
    # outdir = osp.join(outdir, weights_filename)
    if not os.path.exists(outdir):
        os.makedirs(outdir)
    return outdir

def cfg_from_list(cfg_list):
    """Set config keys via list (e.g., from command line)."""
    from ast import literal_eval
    assert len(cfg_list) % 2 == 0
    for k, v in zip(cfg_list[0::2], cfg_list[1::2]):
        key_list = k.split('.')
        d = __C
        for subkey in key_list[:-1]:
            assert d.has_key(subkey)
            d = d[subkey]
        subkey = key_list[-1]
        assert d.has_key(subkey)
        try:
            value = literal_eval(v)
        except:
            # handle the case when v is a string literal
            value = v
        assert type(value) == type(d[subkey]), \
            'type {} does not match original type {}'.format(
                type(value), type(d[subkey]))
        d[subkey] = value


import argparse
import glob
import os

import numpy as np
from scipy import ndimage
from PIL import Image
from tqdm import tqdm

def main(args):
    image_paths = glob.glob(os.path.join(args.annotation_train_dir, "*.png"))
    image_paths.extend(glob.glob(os.path.join(args.annotation_valid_dir, "*.png")))
    invalid_images = []
    for image_path in tqdm(image_paths):
        mask = Image.open(image_path).convert("L")

        # Convert mask to numpy array
        mask = np.array(mask)

        # Labels are decoded as different colors
        mask_labels = np.unique(mask)

        boxes = []

        for mask_label in mask_labels:
            # Ignore the background/unlabeled
            if mask_label == 255:
                continue

            # Extract the mask of the current label
            independent_mask = mask == mask_label

            # Extract instance in the current mask
            blobs, no_blobs = ndimage.label(independent_mask)

            # For each instance
            for i in range(1, no_blobs + 1):
                # Get bounding box
                pos = np.where(blobs == i)
                xmin = np.min(pos[1])
                xmax = np.max(pos[1])
                ymin = np.min(pos[0])
                ymax = np.max(pos[0])
                if (xmax - xmin) * (ymax - ymin) == 0:
                    continue
                boxes.append([xmin, ymin, xmax, ymax])
        if len(boxes) == 0:
            invalid_images.append(image_path)
    with open(args.output_file, "w") as f:
        f.write("\n".join(invalid_images))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Test and generate invalid image list"
    )
    parser.add_argument("--annotation-train-dir",
                        default="../cocostuff/dataset/annotations/train2017",
                        help="Annotation directory")
    parser.add_argument("--annotation-valid-dir",
                        default="../cocostuff/dataset/annotations/val2017",
                        help="Annotation directory")
    parser.add_argument("--output-file",
                        default="invalid_images.txt",
                        help="Output file of invalid images")

    args = parser.parse_args()
    main(args)


from django import forms
from datetime import *
from .models import Transaccion

from ..cliente.models import Cliente
from ..user.models import User

class TransaccionForm(forms.ModelForm):
    # constructor
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.Meta.fields:
            self.fields[field].widget.attrs.update({
                'class': 'form-control'
            })
            self.fields['fecha_trans'].widget.attrs = {
                'readonly': True,
                'class': 'form-control'
            }
            self.fields['user'].widget.attrs = {
                'class': 'custom-select select2'
            }
            self.fields["user"].queryset = User.objects.none()
            self.fields['subtotal'].widget.attrs = {
                'value': '0.00',
                'class': 'form-control',
                'readonly': True
            }
            self.fields['iva'].widget.attrs = {
                'value': '0.00',
                'class': 'form-control',
                'readonly': True
            }
            self.fields['total'].widget.attrs = {
                'value': '0.00',
                'class': 'form-control',
                'readonly': True
            }

        # habilitar, desabilitar, y mas

    class Meta:
        model = Transaccion
        fields = [
            'fecha_trans',
            'user',
            'subtotal',
            'iva',
            'total'
        ]
        labels = {
            'fecha_trans': 'Fecha',
            'user': 'Cliente',
            'subtotal': 'Subtotal',
            'iva': 'I.V.A.',
            'total': 'TOTAL'
        }
        widgets = {
            'fecha_trans': forms.DateInput(
                format='%Y-%m-%d',
                attrs={'value': datetime.now().strftime('%Y-%m-%d')},
            ),
            'subtotal': forms.TextInput(),
            'iva': forms.TextInput(),
            'total': forms.TextInput(),
        }


import argparse
import sys
from os.path import dirname, realpath
sys.path.append(dirname(dirname(realpath(__file__))))
import project.data.dataset_utils as data_utils
import project.models.model_utils as model_utils
import project.training.train_utils as train_utils
import torch.nn as N
import os
import torch
import datetime
import pickle
import pdb
from pytorch_pretrained_bert import BertForSequenceClassification

parser = argparse.ArgumentParser(description='Lung Cancer Disease Progression Classifier')
# learning
parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate [default: 0.001]')
parser.add_argument('--dropout', type=float, default=0.05, help='sets dropout layer [default: 0.4]')
parser.add_argument('--valid_split', type=float, default=0.2, help='sets validation split from data [default: 0.2]')
parser.add_argument('--epochs', type=int, default=30, help='number of epochs for train [default: 30]')
parser.add_argument('--batch_size', type=int, default=10, help='batch size for training [default: 32]')
parser.add_argument('--mid_dim', type=int, default=100, help='middle dimension of feature extraction architecture [default: 100]')
parser.add_argument('--max_base', type=int, default=400, help='maximum text features for baseline data [default: 400]')
parser.add_argument('--max_prog', type=int, default=800, help='maximum text features for baseline data [default: 800]')
parser.add_argument('--max_before', type=int, default=600, help='maximum text features for context before volume [default: 600]')
parser.add_argument('--max_after', type=int, default=300, help='maximum text features for context after volume [default: 300]')
parser.add_argument('--desired_features', type=tuple, default=("lens", "organs", "date_dist"), help='enter context features in format - (\"feat_1\", ..., \"feat_n\")')
# device
parser.add_argument('--cuda', action='store_true', default=False, help='enable the gpu [default: True]')
parser.add_argument('--train', action='store_true', default=False, help='enable train [default: False]')
# task
parser.add_argument('--snapshot', type=str, default=None, help='filename of model snapshot to load[default: None]')
parser.add_argument('--save_path', type=str, default="model2.pt", help='Path where to dump model')

args = parser.parse_args()

def test_hyperparamaters(args, model_save_directory="test_models/", dictionary_save_file="data.pkl"):
    MAX_ACC1, MAX_ACC2, MAX_ACC3 = 0, 0, 0
    print("\nParameters:")
    for attr, value in sorted(args.__dict__.items()):
        print("\t{}={}".format(attr.upper(), value))
    out_dict = {}
    train_data, valid_data = data_utils.make_datasets(args)
    for concat_func in (torch.sum, torch.max, torch.mean, torch.min):
        for lr in (0.0001, 0.0002, 0.0005, 0.001, 0.002, 0.005, 0.01):
            args.lr = lr
            for dropout in (0.05, 0.1, 0.2, 0.3, 0.4):
                args.dropout = dropout
                for mid_dim in (20, 50, 100, 200, 300):
                    args.mid_dim = mid_dim

                    args.save_path=model_save_directory + 'model_concat.pt'
                    model1 = model_utils.CombinedNet(args, concat_func)
                    print(model1)
                    MAX_ACC1, temp_max_acc = train_utils.train_model(train_data, valid_data, model1, args, MAX_ACC1, "combined")
                    if temp_max_acc not in out_dict:
                        out_dict[temp_max_acc] = [(concat_func, lr, dropout, mid_dim, "combined")]
                    else:
                        out_dict[temp_max_acc].append((concat_func, lr, dropout, mid_dim, "combined"))

                    print()

                    args.save_path=model_save_directory + 'model_features.pt'
                    model2 = model_utils.FeatureNet(args, concat_func)
                    print(model2)
                    MAX_ACC2, temp_max_acc = train_utils.train_model(train_data, valid_data, model2, args, MAX_ACC2, "features")
                    if temp_max_acc not in out_dict:
                        out_dict[temp_max_acc] = [(concat_func, lr, dropout, mid_dim, "features")]
                    else:
                        out_dict[temp_max_acc].append((concat_func, lr, dropout, mid_dim, "features"))
                    print()

                    args.save_path=model_save_directory + 'model_text.pt'
                    model3 = model_utils.TextNet(args)
                    print(model3)
                    MAX_ACC3, temp_max_acc = train_utils.train_model(train_data, valid_data, model3, args, MAX_ACC3, "text")
                    if temp_max_acc not in out_dict:
                        out_dict[temp_max_acc] = [(concat_func, lr, dropout, mid_dim, "text")]
                    else:
                        out_dict[temp_max_acc].append((concat_func, lr, dropout, mid_dim, "text"))
                    print()

                    pickle.dump(out_dict, open(dictionary_save_file, "wb"))

def finetune_bert(args, model_save_directory, bert_file_path):

    train_data, valid_data = data_utils.make_datasets(args)
    model = BertForSequenceClassification.from_pretrained("bert-base-uncased",  num_labels=4)

    args.save_path = model_save_directory + "bert_model.pt"
    ACC, _ = train_utils.train_model(train_data, valid_data, model, args, 0, "bert")

if __name__ == '__main__':
    #test_hyperparamaters(args)
    finetune_bert(args, "models", "BertModels/cased_bert.bin")


"""
Debug ORMAdapter calls within ORM runs.

Demos::

    python tools/trace_orm_adapter.py -m pytest \
        test/orm/inheritance/test_polymorphic_rel.py::PolymorphicAliasedJoinsTest::test_primary_eager_aliasing_joinedload

    python tools/trace_orm_adapter.py -m pytest \
        test/orm/test_eager_relations.py::LazyLoadOptSpecificityTest::test_pathed_joinedload_aliased_abs_bcs

    python tools/trace_orm_adapter.py my_test_script.py

The above two tests should spit out a ton of debug output.  If a test or program
has no debug output at all, that's a good thing!  it means ORMAdapter isn't
used for that case.

You can then set a breakpoint at the end of any adapt step:

    python tools/trace_orm_adapter.py -d 10 -m pytest -s \
        test/orm/test_eager_relations.py::LazyLoadOptSpecificityTest::test_pathed_joinedload_aliased_abs_bcs

"""  # noqa: E501
# mypy: ignore-errors

from __future__ import annotations

import argparse
import contextlib
import contextvars
import sys
from typing import TYPE_CHECKING

from sqlalchemy.orm import util

if TYPE_CHECKING:
    from typing import Any
    from typing import List
    from typing import Optional

    from sqlalchemy.sql.elements import ColumnElement

class _ORMAdapterTrace:
    def _locate_col(
        self, col: ColumnElement[Any]
    ) -> Optional[ColumnElement[Any]]:
        with self._tracer("_locate_col") as tracer:
            return tracer(super()._locate_col, col)

    def replace(self, col, _include_singleton_constants: bool = False):
        with self._tracer("replace") as tracer:
            return tracer(super().replace, col)

    _orm_adapter_trace_context = contextvars.ContextVar("_tracer")

    @contextlib.contextmanager
    def _tracer(self, meth):
        adapter = self
        ctx = self._orm_adapter_trace_context.get(
            {"stack": [], "last_depth": 0, "line_no": 0}
        )
        self._orm_adapter_trace_context.set(ctx)

        stack: List[Any] = ctx["stack"]  # type: ignore
        last_depth = len(stack)
        line_no: int = ctx["line_no"]  # type: ignore
        ctx["last_depth"] = last_depth
        stack.append((adapter, meth))
        indent = "    " * last_depth

        if hasattr(adapter, "mapper"):
            adapter_desc = (
                f"{adapter.__class__.__name__}"
                f"({adapter.role.name}, mapper={adapter.mapper})"
            )
        else:
            adapter_desc = f"{adapter.__class__.__name__}({adapter.role.name})"

        def tracer_fn(fn, arg):
            nonlocal line_no

            line_no += 1

            print(f"{indent} {line_no} {adapter_desc}", file=REAL_STDOUT)
            sub_indent = " " * len(f"{line_no} ")

            print(
                f"{indent}{sub_indent} -> "
                f"{meth} {_orm_adapter_trace_print(arg)}",
                file=REAL_STDOUT,
            )
            ctx["line_no"] = line_no
            ret = fn(arg)

            if DEBUG_ADAPT_STEP == line_no:
                breakpoint()

            if ret is arg:
                print(f"{indent} {line_no} <- same object", file=REAL_STDOUT)
            else:
                print(
                    f"{indent} {line_no} <- {_orm_adapter_trace_print(ret)}",
                    file=REAL_STDOUT,
                )

            if last_depth == 0:
                print("", file=REAL_STDOUT)
            return ret

        try:
            yield tracer_fn
        finally:
            stack.pop(-1)

util.ORMAdapter.__bases__ = (_ORMAdapterTrace,) + util.ORMAdapter.__bases__
util.ORMStatementAdapter.__bases__ = (
    _ORMAdapterTrace,
) + util.ORMStatementAdapter.__bases__

def _orm_adapter_trace_print(obj):
    if obj is None:
        return "None"

    t_print = _orm_adapter_trace_printers.get(obj.__visit_name__, None)
    if t_print:
        return t_print(obj)
    else:
        return f"{obj!r}"

_orm_adapter_trace_printers = {
    "table": lambda t: (
        f'Table("{t.name}", '
        f"entity={t._annotations.get('parentmapper', None)})"
    ),
    "column": lambda c: (
        f'Column("{c.name}", {_orm_adapter_trace_print(c.table)} '
        f"entity={c._annotations.get('parentmapper', None)})"
    ),
    "join": lambda j: (
        f"{j.__class__.__name__}({_orm_adapter_trace_print(j.left)}, "
        f"{_orm_adapter_trace_print(j.right)})"
    ),
    "label": lambda l: f"Label({_orm_adapter_trace_print(l.element)})",
}

DEBUG_ADAPT_STEP = None
REAL_STDOUT = sys.__stdout__

def main():
    global DEBUG_ADAPT_STEP

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-d", "--debug", type=int, help="breakpoint at this adaptation step"
    )
    parser.add_argument(
        "-m",
        "--module",
        type=str,
        help="import module name instead of running a script",
    )
    parser.add_argument(
        "args", metavar="N", type=str, nargs="*", help="additional arguments"
    )

    argparse_args = []
    sys_argv = list(sys.argv)

    progname = sys_argv.pop(0)

    # this is a little crazy, works at the moment for:
    # module w args:
    #    python tools/trace_orm_adapter.py -m  pytest test/orm/test_query.py -s
    # script:
    #   python tools/trace_orm_adapter.py test3.py
    has_module = False
    while sys_argv:
        arg = sys_argv.pop(0)
        if arg in ("-m", "--module", "-d", "--debug"):
            argparse_args.append(arg)
            argparse_args.append(sys_argv.pop(0))
            has_module = arg in ("-m", "--module")
        else:
            if not has_module:
                argparse_args.append(arg)
            else:
                sys_argv.insert(0, arg)
            break

    options = parser.parse_args(argparse_args)
    sys.argv = ["program.py"] + sys_argv

    if options.module == "pytest":
        sys.argv.extend(["--capture", "sys"])

    import runpy

    if options.debug:
        DEBUG_ADAPT_STEP = options.debug

    if options.module:
        runpy.run_module(options.module, run_name="__main__")
    else:
        progname = options.args[0]

        runpy.run_path(progname)

if __name__ == "__main__":
    main()


import torch
from torch.nn.utils.rnn import pad_sequence

from transformers4ime.data.logits_processor import ConstrainedLogitsProcessor

class PinyinGPTConcatLogitsProcessor(ConstrainedLogitsProcessor):

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, constraint_id) -> torch.FloatTensor:
        bs, il = input_ids.size()
        # gather index
        gather_index_list = []
        for _ in range(bs):
            pid = constraint_id
            c_df = self.pc_df.get(pid.item())
            if c_df is not None:
                gather_index_list.append(torch.tensor(c_df.index.tolist()))
            else:
                gather_index_list.append(torch.zeros(1))
        gather_index = pad_sequence(gather_index_list, batch_first=True, padding_value=0).long().to(scores.device)

        score = torch.gather(scores, 1, gather_index)

        scores.fill_(-float("inf"))
        scores.scatter_(1, gather_index, score)
        return scores


import os
import re
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import convertapi
import cv2
import pytesseract
from pdfminer.high_level import extract_text
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from django.shortcuts import render
from .forms import PersonalInformation
from .models import Information

EMAIL_REG = re.compile(r'[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+')
PHONE_REG = re.compile(r'[\+\(]?[1-9][0-9 .\-\(\)]{8,}[0-9]')
LINKEDIN_REG = re.compile(r'((http(s?)://)*([www])*\.|[linkedin])[linkedin/~\-]+\.[a-zA-Z0-9/~\-_,&=\?\.;]+[^\.,\s<]')

def extract_emails(resume_text):
    return re.findall(EMAIL_REG, resume_text)

def extract_linkedIn(resume_text):
    return re.findall(LINKEDIN_REG, resume_text)

def extract_phone_number(resume_text):
    phone = re.findall(PHONE_REG, resume_text)

    if phone:
        number = ''.join(phone[0])

        if resume_text.find(number) >= 0 and len(number) < 16:
            return number
    return None

def write_to_gsheet(folder_id, filename, phone, email):
    Scopes = [
    'https://www.googleapis.com/auth/spreadsheets',
    'https://www.googleapis.com/auth/drive'
]

    creds = ServiceAccountCredentials.from_json_keyfile_name("/home/samarth/pdfparser/pdfparser/secret_key.json", scopes=Scopes)
    file = gspread.authorize(creds)
    workbook = file.open("Candidates information")
    sheet = workbook.sheet1
    candidate_info = [folder_id, filename, phone, email, 'https://www.linkedin.com/in/sam-tyagi-6b6487245/']
    sheet.append_row(candidate_info)

def convert_to_pdf(file_path, typ):
    convertapi.api_secret = 'DBuhCGfisLXtWsTg'
    convertapi.convert('pdf', {
        'File': file_path
    }, from_format = typ).save_files('/home/samarth/pdfparser/pdfparser')

def get_form(request):
    gauth = GoogleAuth()
    drive = GoogleDrive(gauth)

    if request.method == 'POST':
        drive_link = request.POST.get('drive_link')
        data = Information(drive_link=drive_link)
        data.save()
        print('------------'+drive_link+'--------------------------')
        x = len(drive_link)
        for i in range(x-1,-1,-1):
            if drive_link[i] == '/':
                break

        folder = drive_link[i+1:]
        file_list = drive.ListFile({'q' : f"'{folder}' in parents and trashed=false and mimeType='application/vnd.google-apps.folder'"}).GetList()
        for index, file in enumerate(file_list):
            # print(index+1, 'file downloaded : ', file['title'])
            folder_id = file['id']
            print('folder id: ', file['id'])
            fl = drive.ListFile({'q' : f"'{folder_id}' in parents and trashed=false"}).GetList()
            for f in fl:
                length = len(f['title'])
                typ = ''
                for i in range(length-1,-1,-1):
                    if f['title'][i] == '.':
                        break
                typ = f['title'][i+1:]
                if typ == 'pdf':
                    f.GetContentFile(f['title'])
                    text = extract_text(f['title'])
                    # print(text)
                    emails = extract_emails(text)
                    phone_number = extract_phone_number(text)
                    linkedIn = extract_linkedIn(text)
                    if emails:
                        print(emails[0])
                    print(phone_number)
                    write_to_gsheet(folder_id,f['title'], phone_number, emails[0])
                    os.remove(f['title'])

                elif typ == 'docx' or typ == 'doc':
                    f.GetContentFile(f['title'])
                    convert_to_pdf(f['title'], typ)
                    converted_file_path = f['title'][:i+1] + 'pdf'
                    text = extract_text(converted_file_path)
                    emails = extract_emails(text)
                    phone_number = extract_phone_number(text)
                    linkedIn = extract_linkedIn(text)
                    if emails:
                        print(emails[0])
                    print(phone_number)
                    if emails and phone_number:
                        write_to_gsheet(folder_id, f['title'], phone_number, emails[0])
                    os.remove(f['title'])
                    os.remove(converted_file_path)

                elif typ in ['png', 'jpeg', 'jpg']:
                    f.GetContentFile(f['title'])
                    tessdata_dir_config= r'/--tessdata-dir "/home/samarth/pdfparser/my_env/lib/python3.8/site-packages"'
                    img = cv2.imread(f['title'],1)
                    img_scale_up = cv2.resize(img, (0, 0), fx=1.5, fy=1.5)
                    # cv2.imshow('Upscaled Image', img_scale_up)
                    if not cv2.imwrite(r'/home/samarth/pdfparser/pdfparser/upscaled.{0}'.format(typ), img_scale_up):
                        raise Exception('Could not write image')
                    cv2.waitKey(0)
                    upscaled_image = 'upscaled.{0}'.format(typ)
                    text = pytesseract.image_to_string(upscaled_image, config=tessdata_dir_config)
                    emails = extract_emails(text)
                    phone_number = extract_phone_number(text)
                    linkedIn = extract_linkedIn(text)
                    if emails:
                        print(emails[0])
                    print(phone_number)

                    if emails and phone_number:
                        write_to_gsheet(folder_id, f['title'], phone_number, emails[0])
                    os.remove(f['title'])
                    os.remove(upscaled_image)

        return render(request, 'app/handleForm.html')

    else:
        form = PersonalInformation()

    return render(request, 'app/userdata.html', {'form': form})

def upload(request):
    if request.method == 'POST':
       uploaded_file = request.FILES['document']
       print(uploaded_file.name)
    return render(request,  'app/upload.html')


import tempfile

import pdfkit

from django.contrib import messages

from django.http import FileResponse
from django.shortcuts import render
from django.template.loader import get_template

from rest_framework import generics
from rest_framework.permissions import (
    SAFE_METHODS,
    BasePermission,
    IsAuthenticated)

from .models import Event
from .models import Institution
from .performance_scheduling import get_event, schedule_performances_for_each_theater, generate_time_table
from .serializers import InstitutionSerializer

WKHTMLTOPDF_PATH: str = '/usr/local/bin/wkhtmltopdf'

class IsOwnerOrReadOnly(BasePermission):
    """Custom permission"""
    message = 'Updating of institution details and deregistration' \
              ' restricted to Head of Institution Only'

    def has_object_permission(self, request, view, obj):
        if request.method in SAFE_METHODS:
            return True
        return obj.head_of_institution == request.user

class RegisterInstitutions(generics.RetrieveUpdateAPIView):
    """
    Update institution details once  heads of institutions are registered into the system
    """
    queryset = Institution.objects.all()
    serializer_class = InstitutionSerializer
    permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
    lookup_field = 'id'
    lookup_url_kwarg = 'institution_pk'

def schedule_performances(request, festival_event):
    list(messages.get_messages(request))  # Clear messages.
    event = Event.objects.get(pk=festival_event)

    try:
        get_event(event=event)
        performances_for_each_theater: dict = schedule_performances_for_each_theater()
        time_table = generate_time_table(performances_for_each_theater)

        event_level: str = event.event_level.lower()
        ctx = {
            'time_table': time_table,
            'event': event,
            'event_level': event_level
        }

        # Getting template, and rendering data
        template = get_template('time_table.html')
        html = template.render(ctx)

        # Function for creating file name
        # Inner function
        def create_file_name():
            file_name = 'time_table_%s.pdf' % event
            return file_name.strip()

        filename = create_file_name()

        config = pdfkit.configuration(wkhtmltopdf=WKHTMLTOPDF_PATH)

        options = {
            'page-size': 'A4',
            'margin-top': '0.25in',
            'margin-right': '0.3in',
            'margin-bottom': '0.25in',
            'margin-left': '0.3in',
            'encoding': 'UTF-8',
            'custom-header': [
                ('Accept-Encoding', 'gzip')
            ],
            'no-outline': None,
            'enable-local-file-access': None,
            'enable-javascript': None,
        }

        with tempfile.NamedTemporaryFile(prefix=filename, suffix=".pdf") as f:
            pdfkit.from_string(html, f.name, configuration=config, options=options)
            return FileResponse(open(f.name, 'rb'), content_type='application/pdf')

    except ZeroDivisionError:
        messages.add_message(request, messages.ERROR, 'No theaters registered to the event!')
        return render(request, 'time_table.html')


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

import itertools

from Text_terms import *
from Symmetrical_summ import *
from Templates import *

# пересчет весов для предложений
def countFinalWeights(tf_weights, stemmed_text, stemmed_pnn):
    weighted_terms = dict(tf_weights.items())
    total_sents_in_text = stemmed_text.len

    # список первых и последних предложений
    collection_of_first_last_sents = list(itertools.chain.from_iterable(
        (paragraph[0], paragraph[-1]) if len(paragraph) > 1 else (paragraph[0],)
        for paragraph in stemmed_text.text if paragraph))

    # список слов первых и последних предложений абзацев
    pairs_collection_of_first_last_sents = list(
        itertools.chain.from_iterable(collection_of_first_last_sents))
    stems_collection_of_first_last_sents = {
        pair[0] for pair in pairs_collection_of_first_last_sents }

    # количество слов в первых и последних предложениях
    total_stems_in_first_last = len(stems_collection_of_first_last_sents)

    # количество слов из словаря в первых и последних предложениях
    total_dictwords_in_first_last = 0
    for s1 in stems_collection_of_first_last_sents:
        if s1 in tf_weights:
            total_dictwords_in_first_last += 1

    # количество слов в тексте
    total_stems_in_text = len(list(itertools.chain.from_iterable(stemmed_text.sentences())))

    # среднее количество слов из словаря в первых и последних предложениях абзацев
    avg_dictwords_in_first_last = total_dictwords_in_first_last / total_stems_in_first_last

    # среднее количество слов в первых и последних предложениях абзацев
    avg_stems_in_first_last = total_stems_in_first_last / total_stems_in_text

    # список вопросительных и восклиц. предложений
    collection_of_q_excl_sents = [
        sentence
        for sentence in stemmed_text.sentences()
        if sentence and sentence[-1][0] in {'?', '!'}]

    # список слов из вопросительных и восклицательных предложений
    stems_collection_of_q_excl_sents = {tpl[0] for tpl in itertools.chain.from_iterable(collection_of_q_excl_sents) if tpl[0] not in '?!'}

    # количество вопросительных и восклицательных предложений в тексте
    num_of_q_excl_sents = len(collection_of_q_excl_sents)

    """
    если термины есть в первых и последн. предложениях абзацев, то вес термина
    умножаем на частное среднего кол-ва терминов из словаря в первых и посл. предл.
    и среднего кол-ва терминов в первых и последн. предл-х.
    """
    for term in stems_collection_of_first_last_sents:
        if term in weighted_terms:
            weighted_terms[term] *= avg_dictwords_in_first_last / avg_stems_in_first_last
    """
    если термины есть в вопросительных и восклицательных предложениях,
    то умножаем вес термина на частное от кол-ва таких предложений
    и общего кол-ва предложений текста
    """
    for term in stems_collection_of_q_excl_sents:
        if term in weighted_terms:
            weighted_terms[term] *= num_of_q_excl_sents / total_sents_in_text
    """
    если термины из словаря - это "имена собственные", то умножаем вес
    термина на частное среднего кол-ва терминов из словаря в первых и посл. предл.
    и среднего кол-ва терминов в первых и последн. предл-х.
    """
    for term in stemmed_pnn:
        if term in weighted_terms:
            weighted_terms[term] *= avg_dictwords_in_first_last / avg_stems_in_first_last

    mean_weight = sum(weighted_terms.values()) / len(weighted_terms)
    sorted_tf = {term : weight
            for term, weight in weighted_terms.items()
            if weight > mean_weight}
    return sorted_tf

# пересчет предложений по весам
def convertFinalWeights(symmetry, symm_weights, ordinary_sents, indicators = True, adj = False):
    if indicators:
        """
        Здесь стоит надстройка, что пересчитывает веса в зависимости от индикаторов
        """
        processor = TextProcessor(flag = adj)
        result = []
        for (counter, weight),\
            (index, original),\
            ( _ , sentence)\
        in \
            zip(symm_weights,
                enumerate(ordinary_sents),
                processor.parse(ordinary_sents)
            ):
            search_result = processor.apply(sentence)
            weight_indicator = 1
            if search_result:
                for lst in search_result:
                    if lst:
                        pattern_len = list(lst[0].values())[1][2]
                        word_num = list(lst[0].values())[1][1]
                        if pattern_len > 3:
                            if word_num >= 3:
                                weight_indicator += 1
                            elif word_num == 2:
                                weight_indicator += 0.5
                        elif pattern_len == 3:
                            if word_num >= 2:
                                weight_indicator += 1
                            elif word_num == 1:
                                weight_indicator += 0.5
                        else:
                            if word_num >= pattern_len:
                                weight_indicator += 1
            if len(counter) > 6:
                result.append((original, weight * weight_indicator, index))
        return sorted(result, key=lambda x: x[1], reverse=True)

    else:
        return symmetry.convertSymmetryToOrdinary(symm_weights, ordinary_sents)

# процентная выборка
def selectFinalSents(converted_sents, percentage=10):
    """
    Метод выбирает n первых предложений из списка.
    n определяется указанным процентом. Список сортируется
    по позиции предложения в оригинальном тексте, таким образом
    возвращается оригинальная последовательность, чтобы хоть
    как-то сохранить связность.
    """
    compression_rate = int(len(converted_sents) * percentage / 100 + 0.5)
    sorted_salient_sentences = sorted(converted_sents[:compression_rate], key=lambda w: w[2])
    return sorted_salient_sentences

# суммаризатор
class SUMMARIZER():

    def __init__(self):
        self.language = 'ru'
        self.stopwords = list(stopwords.words('russian'))
        self.re_term = re.compile("[\wа-яА-Я]+\-[\wа-яА-Я]+|[\wа-яА-Я]+|[!?]")
        self.symmetry = SymmetricalSummarizationWeightCount()

    def check(self, term):
        if term in self.stopwords:
            return False
        elif re.match(self.re_term, term):
            return True
        else:
            return False

    def summarize(self, file_name, output_name, indicators = True, adj = False, percentage = 10):
        file = open(file_name, 'r')
        text = StructuredText(text_segmentor(file.read()))
        res = ''

        if text.len >= 3:
            # стемминг предложений
            # текст без стоп-слов: (стема, слово), предложения сгруппированны по абзацам
            STEMMED_SENTENCES = StructuredText(text.map_sent(
                    lambda sentence:
                    [(normalize(term), term)
                         for term
                         in word_tokenize(sentence)
                         if self.check(term)] ))
            # список всех стем
            BIG_LIST_OF_PAIRS = list(itertools.chain.from_iterable(STEMMED_SENTENCES.sentences()))
            LIST_OF_STEMS = [pair1[0] for pair1 in BIG_LIST_OF_PAIRS]

            if LIST_OF_STEMS:
                # список кортежей (слово, его относительная частота), усечённый по средней частоте
                TOTAL_STEM_COUNT = dict(simpleTermFreqCount(LIST_OF_STEMS))
                # список "имён собственных"
                STEMMED_PNN = lookForProper(STEMMED_SENTENCES.text)

                # список терминов с весовыми коэффициентами
                SORTED_TFIDF = countFinalWeights(TOTAL_STEM_COUNT, STEMMED_SENTENCES, STEMMED_PNN)
                SORTED_TFIDF = sorted(SORTED_TFIDF.items(), key=lambda w: w[1], reverse=True)

                # словари каждого предложения с частотностью по словам
                S_with_termfreqs = [Counter([word[0] for word in sentence]) for sentence in STEMMED_SENTENCES.sentences()]
                # общее количество стем в тексте
                TOTAL_STEMS_IN_TEXT = len(LIST_OF_STEMS)
                # общее количество предложений в тексте
                TOTAL_SENTS_IN_TEXT = len(text.sentences())

                # пересчет весов
                SYMMETRICAL_WEIGHTS = self.symmetry.countFinalSymmetryWeight(
                        SORTED_TFIDF, S_with_termfreqs,
                        TOTAL_STEMS_IN_TEXT, TOTAL_SENTS_IN_TEXT,
                        STEMMED_PNN)

                # отбор предложений
                ORIGINAL_SENTENCES = convertFinalWeights(
                        self.symmetry,
                        SYMMETRICAL_WEIGHTS,
                        text.sentences(),
                        indicators, adj)

                #print(ORIGINAL_SENTENCES)

                res = selectFinalSents(ORIGINAL_SENTENCES, percentage)

            else:
                print("There are no words to process!")

        else:
            print("Text should be at least 3 sentences long.")

        # результат записан в отдельный файл
        with open(output_name, 'w') as output_file:
            for sent3 in range(len(res)):
                #output_file.write(str(res[sent3][2]) + ',') # для выдачи № выбранных предложений
                output_file.write(res[sent3][0] + '\n')
                print(res[sent3][0])
            '''
            output_file.write(str(len(text.sentences()))) # для выдачи № выбранных предложений

            print(len(res)) # для подсчета длины реферата
            for i, x in enumerate(text.sentences()): # для получения разбиения на предложения
                output_file.write(str(i+1) + '. ' + x + '\n')'''

if __name__ == '__main__':

    Sum = SUMMARIZER()
    Sum.summarize('text.txt', 'output.txt', indicators = True, adj = True, percentage = 60)


"""
Define commonly used dialogs.
"""

import ceGUI
import cx_Exceptions
import cx_Logging
import os
import wx

__all__ = [ "AboutDialog", "PreferencesDialog", "SelectionListDialog",
            "SelectionCheckListDialog", "SelectionTreeDialog" ]

class AboutDialog(ceGUI.Dialog):
    baseSettingsName = "w_About"
    createCancelButton = False
    saveSize = False

    def __init__(self, parent):
        super(AboutDialog, self).__init__(parent, wx.CAPTION)

    def OnCreate(self):
        app = wx.GetApp()
        self.SetTitle("About %s" % app.description)
        self.panel = ceGUI.Panel(self, wx.SUNKEN_BORDER)
        aboutText = app.description
        if app.version is not None:
            aboutText = "%s\n\nVersion %s" % (aboutText, app.version)
        if app.copyrightOwner is not None:
            if app.copyrightStartYear == app.copyrightEndYear:
                copyrightYears = app.copyrightEndYear
            else:
                copyrightYears = "%s-%s" % \
                        (app.copyrightStartYear, app.copyrightEndYear)
            aboutText = "%s\n\nCopyright %s\n%s" % \
                    (aboutText, copyrightYears, app.copyrightOwner)
        self.aboutLabel = wx.StaticText(self.panel, -1, aboutText,
                style = wx.ALIGN_CENTRE)

    def OnLayout(self):
        panelSizer = wx.BoxSizer(wx.VERTICAL)
        panelSizer.Add(self.aboutLabel, flag = wx.ALL | wx.EXPAND, border = 5)
        self.panel.SetSizer(panelSizer)
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(self.panel, flag = wx.ALL | wx.EXPAND, border = 5)
        topSizer.Add(self.okButton,
                flag = wx.ALL | wx.ALIGN_CENTER_HORIZONTAL | \
                        wx.ALIGN_CENTER_VERTICAL, border = 5)
        return topSizer

class LoggingPreferencesPane(ceGUI.Panel):
    loggingLevels = "DEBUG INFO WARNING ERROR CRITICAL".split()

    def OnCreate(self):
        self.fileNameLabel = wx.StaticText(self, -1, "File Name:")
        self.fileNameField = wx.TextCtrl(self, -1)
        self.selectFileNameButton = wx.Button(self, -1, "...",
                size = (25, -1))
        self.BindEvent(self.selectFileNameButton, wx.EVT_BUTTON,
                self.OnSelectFileName)
        self.levelLabel = wx.StaticText(self, -1, "Level:")
        self.levelField = wx.Choice(self, -1, choices = self.loggingLevels)

    def OnLayout(self):
        fileNameSizer = wx.BoxSizer(wx.HORIZONTAL)
        fileNameSizer.Add(self.fileNameField, proportion = 1, flag = wx.RIGHT,
                border = 5)
        fileNameSizer.Add(self.selectFileNameButton)
        fieldLayout = self.CreateFieldLayout(self.fileNameLabel, fileNameSizer,
                self.levelLabel, self.levelField)
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(fieldLayout, flag = wx.ALL | wx.EXPAND, border = 5,
                proportion = 1)
        return topSizer

    def OnSelectFileName(self, event):
        currentFileName = self.fileNameField.GetValue()
        dir, fileName = os.path.split(currentFileName)
        dialog = wx.FileDialog(self, "Select log file", wildcard = "*.log",
                defaultDir = dir, defaultFile = fileName,
                style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if dialog.ShowModal() == wx.ID_OK:
            fileName = dialog.GetPath()
            if not fileName.lower().endswith(".log"):
                fileName += ".log"
            self.fileNameField.SetValue(fileName)

    def RestoreSettings(self):
        defaultFileName = wx.GetApp().GetDefaultLoggingFileName()
        fileName = self.settings.Read("LogFileName", defaultFileName)
        self.fileNameField.SetValue(fileName)
        levelName = self.settings.Read("LogLevel", "ERROR")
        self.levelField.SetStringSelection(levelName)

    def SaveSettings(self):
        fileName = self.fileNameField.GetValue()
        if not fileName:
            self.fileNameField.SetFocus()
            raise LoggingFileNameNotSpecified()
        levelName = self.levelField.GetStringSelection()
        level = getattr(cx_Logging, levelName)
        if fileName != cx_Logging.GetLoggingFileName():
            cx_Logging.StartLogging(fileName, level)
        elif level != cx_Logging.GetLoggingLevel():
            cx_Logging.SetLoggingLevel(level)
        self.settings.Write("LogFileName", fileName)
        self.settings.Write("LogLevel", levelName)

class PreferencesDialog(ceGUI.StandardDialog):
    baseSettingsName = "w_Preferences"
    defaultSize = (450, 157)

    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, -1, "Edit Preferences",
                style = wx.CAPTION | wx.RESIZE_BORDER)
        self._Initialize()

    def OnCreate(self):
        self.notebook = ceGUI.Notebook(self, -1)
        self.OnCreateNotebook()
        pane = LoggingPreferencesPane(self.notebook)
        self.notebook.AddPage(pane, "Logging")
        self.notebook.RestoreSettings()

    def OnCreateNotebook(self):
        pass

    def OnOk(self):
        self.notebook.SaveSettings()
        self.settings.Flush()

    def OnLayout(self):
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(self.notebook, proportion = 1,
                flag = wx.EXPAND | wx.RIGHT | wx.LEFT | wx.TOP, border = 5)
        return topSizer

    def RestoreSettings(self):
        pass

    def SaveSettings(self):
        pass

class SelectionListDialog(ceGUI.StandardDialog):
    listClassName = "List"
    selectFirstItem = True

    def _GetList(self):
        cls = self._GetClass(self.listClassName)
        return cls(self, wx.SUNKEN_BORDER)

    def GetSelectedItem(self):
        return self.selectionList.GetSelectedItem()

    def GetSelectedItems(self):
        return self.selectionList.GetSelectedItems()

    def OnCreate(self):
        self.okButton.Enable(False)
        self.selectionList = self._GetList()
        self.selectionList.SetFocus()
        self.BindEvent(self.selectionList, wx.EVT_LIST_ITEM_SELECTED,
                self.OnItemSelected)
        self.BindEvent(self.selectionList, wx.EVT_LIST_ITEM_DESELECTED,
                self.OnItemDeselected)
        self.BindEvent(self.selectionList, wx.EVT_LIST_ITEM_ACTIVATED,
                self.OnItemActivated)
        self.BindEvent(self.selectionList, wx.EVT_CHAR,
                self.OnCharPressed)

    def OnCharPressed(self, event):
        key = event.GetKeyCode()
        if key == 1 and not self.selectionList.singleSelection: # Ctrl-A
            self.selectionList.SelectAll()
        event.Skip()

    def OnItemActivated(self, event):
        if self.GetSelectedItems():
            self._OnOk(event)
            self.EndModal(wx.ID_OK)

    def OnItemDeselected(self, event):
        if self.selectionList.GetSelectedItemCount() == 0:
            self.okButton.Enable(False)

    def OnItemSelected(self, event):
        self.okButton.Enable()

    def OnLayout(self):
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(self.selectionList, proportion = 1, flag = wx.EXPAND)
        return topSizer

    def RestoreSettings(self):
        self.selectionList.RestoreColumnWidths()

    def Retrieve(self, *args):
        self.selectionList.Retrieve(*args)
        if self.selectFirstItem and len(self.selectionList.rowHandles) > 0:
            handle = self.selectionList.rowHandles[0]
            item = self.selectionList.dataSet.rows[handle]
            self.selectionList.SelectItems([item])

    def SaveSettings(self):
        self.selectionList.SaveColumnWidths()

    def SelectItems(self, items):
        self.selectionList.SelectItems(items)

class SelectionCheckListDialog(ceGUI.StandardDialog):
    listClassName = "List"
    checkedAttrName = "checked"

    def _GetList(self):
        cls = self._GetClass(self.listClassName)
        return cls(self, wx.SUNKEN_BORDER)

    def CheckAllItems(self):
        self.list.CheckAllItems()

    def GetCheckedItems(self):
        return self.list.GetCheckedItems()

    def OnCreate(self):
        self.list = self._GetList()

    def OnLayout(self):
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(self.list, proportion = 1, flag = wx.EXPAND)
        return topSizer

    def RestoreSettings(self):
        self.list.RestoreColumnWidths()

    def Retrieve(self, *args):
        self.list.Retrieve(*args)

    def SaveSettings(self):
        self.list.SaveColumnWidths()

    def UncheckAllItems(self):
        self.list.UncheckAllItems()

class SelectionTreeDialog(ceGUI.StandardDialog):
    treeClassName = "Tree"

    def _GetTree(self):
        cls = self._GetClass(self.treeClassName)
        return cls(self, -1, style = wx.TR_HAS_BUTTONS | wx.TR_HIDE_ROOT | \
                wx.TR_LINES_AT_ROOT)

    def _OnItemActivated(self, event):
        itemId = event.GetItem()
        item = self.selectionTree.GetItemData(itemId)
        if self.CanSelectItem(item.data):
            self.EndModal(wx.ID_OK)

    def _OnSelectionChanged(self, event):
        if self.okButton and self.selectionTree:
            itemId = event.GetItem()
            item = self.selectionTree.GetItemData(itemId)
            self.okButton.Enable(self.CanSelectItem(item.data))

    def CanSelectItem(self, item):
        return True

    def GetSelectedItem(self):
        return self.selectionTree.GetSelectedItem()

    def GetSelectedItemParents(self):
        item = self.selectionTree.GetSelectedItem()
        return self.selectionTree.GetItemParents(item)

    def OnCreate(self):
        self.okButton.Enable(False)
        self.selectionTree = self._GetTree()
        self.BindEvent(self.selectionTree, wx.EVT_TREE_SEL_CHANGED,
                self._OnSelectionChanged)
        self.BindEvent(self.selectionTree, wx.EVT_TREE_ITEM_ACTIVATED,
                self._OnItemActivated)

    def OnLayout(self):
        topSizer = wx.BoxSizer(wx.VERTICAL)
        topSizer.Add(self.selectionTree, proportion = 1, flag = wx.EXPAND)
        return topSizer

    def RestoreSettings(self):
        pass

    def SaveSettings(self):
        pass

class LoggingFileNameNotSpecified(cx_Exceptions.BaseException):
    message = "Logging file name must be specified."