########################################################
#   Main driver for symbolic execution of EVM trace    #
########################################################
import re
import os
import json
import binascii
import subprocess
import sys
from prepare    import *
from macros     import *
from utils      import *

'''
Symbolic value tree
'''
class SVT:
    def __init__(self, _value):
        self.value = _value
        self.children = []

    def __str__(self):
        ret = str(self.value)
        if len(self.children)==0:
            return ret
        ret+="("
        for i in range(len(self.children)):
            if isinstance(self.children[i], tuple):
                s = str(self.children[i])
            elif isinstance(self.children[i].value, int):
                s = hex(self.children[i].value)
            else:
                s = str(self.children[i])
            if i<len(self.children)-1:
                ret+=s+","
            else:
                ret+=s
        ret+=")"
        return ret

'''
EVM core trace analysis
'''
class EVM:
    from memory import recognize_32B_mask, mem_item_len, content_item_len, handle_MLOAD, handle_MSTORE, handle_AND, handle_OR, memory_write
    from utils  import name_substitution
    def __init__(self, stacks, storage, storage_map, memories, output_file, final_path, final_vars, curr_contract, curr_function, call_stack, abi_info, var_prefix, non_static_calls):
        self._stacks            = stacks
        self._storage           = storage
        self._memories          = memories
        self._output_file       = output_file
        self._tmp_var_count     = 0
        self._final_path        = final_path
        self._final_vars        = final_vars
        self._storage_map       = storage_map
        self._curr_contract     = curr_contract
        self._curr_function     = curr_function
        self._call_stack        = call_stack
        self._abi_info          = abi_info
        self._var_prefix        = var_prefix
        self._return_data_size  = 0
        self._non_static_calls  = non_static_calls
        self._postcondition     = get_postcondition()

    '''perform symbolic execution'''
    def sym_exec(self, code_trace):
        for i in range(len(code_trace)):
            if(code_trace[i][1]=="JUMPI"):
                self.run_instruction(code_trace[i], (code_trace[i][0]+1 != code_trace[i+1][0]))
            else:
                self.run_instruction(code_trace[i], None)

    def isType(self, operand, check_type):
        if not isinstance(operand,str):
            return False
        i = operand.find('[');
        name= operand[0:i] if i>=0 else operand

        if name in self._final_vars:
            t=self._final_vars[name]
        else:
            return False

        bracket_count = operand.count(']')
        start = -1
        for _ in range(bracket_count):
            start = t.find(']', start + 1)
            if start == -1:
                return False
        return t[start+1:].strip()==check_type

    '''run each EVM instruction with PC, operator, and operand'''
    def run_instruction(self, instr, branch_taken):
        PC      = instr[0]
        opcode  = instr[1]
        operand = instr[2]

        if opcode=="JUMPDEST" or opcode=="CALL" or opcode=="STATICCALL":
            if (opcode=="CALL"):
                self._non_static_calls.append("non-static")
            elif (opcode=="STATICCALL"):
                self._non_static_calls.append("static")
            pass # no-op
        elif instr[0]==(">"):
            dest_contract, dest_function = get_dest_contract_and_function(instr)

            ### get call or staticcall
            static_idx_diff = 0 if instr.startswith(">>call") else 1
            ### calling a new contract, set up calle stack
            callee_stack    = []
            calldata_pos    = self._stacks[-1][-4+static_idx_diff].value
            calldata_len    = self._stacks[-1][-5+static_idx_diff].value
            func_selector   = self._memories[-1][calldata_pos].children[1].value
            if(isinstance(func_selector, int)):
                func_selector//=0x100**28
            else:
                func_selector = (self.find_key(self._memories[-1][calldata_pos].children[1].children[1]))
            callee_stack.append(SVT(func_selector))
            callee_stack.append(SVT("AConstantBySolc"))
            calldata_len -=4
            calldata_pos +=4

            for i in range(calldata_len//0x20):
                # if calldata_pos in self._memories[-1]:
                callee_stack.append(self._memories[-1][calldata_pos])
                calldata_pos += 0x20

            this_address = self._stacks[-1][-2]
            this_address = self.postorder_traversal(this_address)
            self._sym_this_addresses.append(SVT(this_address))
            MACROS.ALL_VARS[this_address] = "address"

            ### switch to a new contract and pops out the operands for a successful CALL operation
            for i in range(7-static_idx_diff):
                self._stacks[-1].pop()
            self._stacks[-1].append(SVT(1)) # CALL successed
            dest_address = get_var_prefix(instr)
            self._full_address = get_curr_address(instr)
            self._call_stack.append((dest_contract, dest_function, dest_address))
            self._curr_contract = dest_contract
            self._curr_function = dest_function
            MACROS.CONTRACT_NAME = self._curr_contract
            MACROS.FUNCTION_NAME = self._curr_function
            for asgmt in self._postcondition[self._curr_contract].get(self._curr_function, {}).get("assignment", []):
                self._final_path.append("\t" + asgmt.strip() + "\n")
            self._var_prefix = self._curr_contract # get_var_prefix(instr)
            self._stacks.append(callee_stack)
            self._memories.append({0x40: SVT(0x80),0x10000000000: SVT(0)}) # temp

            print(">>CALL,  switched to contract: ", self._call_stack[-1][0])

            ### TODO: make "this" as the correct mapping to the vars
            if(len(self._non_static_calls)>0 and self._non_static_calls[-1] == "non-static"):
                self._non_static_calls[-1] = self._var_prefix
                for contract in MACROS.INVARIANTS:
                    if (contract == dest_contract):
                        self._final_path.append("\t// insert invariant of " + dest_contract + '\n')
                        curr_address = (self._sym_this_addresses[-1]).value
                        for inv in MACROS.INVARIANTS[dest_contract]:
                            inv = inv.replace("this", curr_address)
                            inv = name_substitution(self._curr_contract, inv)
                            self._final_path.append("\tassume("+inv+");\n")
                        self._final_path.append("\n")

        elif instr[0]==("<"):
            pass
        elif opcode=="RETURN" or opcode=="STOP":
            self._return_data_size =0

            if(len(self._non_static_calls)>0 and self._non_static_calls[-1] == "static"):
                self._non_static_calls.pop()
            else:
                self._final_path.append("\t// (post) insert invariant of " + self._curr_contract + '\n')
                curr_address = (self._sym_this_addresses[-1]).value
                for inv in MACROS.INVARIANTS.get(self._curr_contract, []):
                    inv = inv.replace("this", curr_address)
                    inv = name_substitution(self._curr_contract, inv)
                    self._final_path.append("\tassert("+inv+");\n")

            postcons = self._postcondition[self._curr_contract].get(self._curr_function, {}).get("postcondition", [])
            if postcons:
                self._final_path.append("\t// (post) insert postcondition of " + self._curr_function + '\n')
                for postcon in postcons:
                    self._final_path.append("\t" + postcon.strip() + "\n")

            if opcode=="RETURN":
                return_data_start = self._stacks[-1][-1].value
                self._return_data_size = self._stacks[-1][-2].value
                pos_src = return_data_start
                pos_dst = self._memories[-2][0x40].value
                count = self._return_data_size
                while count>0:
                    data = self._memories[-1][pos_src]
                    self.memory_write(pos_dst, data, 32, -2)
                    pos_src+=32
                    pos_dst+=32
                    count-=32
            elif opcode=="STOP":
                self._return_data_size = 0

            self._call_stack.pop()
            self._curr_contract = self._call_stack[-1][0]
            self._curr_function = self._call_stack[-1][1]
            MACROS.CONTRACT_NAME = self._curr_contract
            MACROS.FUNCTION_NAME = self._curr_function

            self._stacks.pop()
            self._memories.pop()
            self._sym_this_addresses.pop()
            self._var_prefix = self._curr_contract
            print(">>LEAVE, switched to contract: ", self._call_stack[-1][0])
        elif opcode=="GAS":
            self._stacks[-1].append(SVT("GAS"))
        elif opcode=="RETURNDATASIZE":
            self._stacks[-1].append(SVT(self._return_data_size))
        elif opcode=="TIMESTAMP":
            self._stacks[-1].append(SVT("BLOCKTIME"))
        elif opcode=="EXTCODESIZE":
            node=SVT("ACCOUNT_CODESIZE")
            node.children.append(self._stacks[-1].pop())
            self._stacks[-1].append(node)
        elif opcode=="JUMP":
            self._stacks[-1].pop()
        elif opcode=="JUMPI":
            self.boogie_gen_jumpi(self._stacks[-1][-2], branch_taken)
            self._stacks[-1].pop()
            self._stacks[-1].pop()
        elif opcode=="MSTORE":
            self.handle_MSTORE()
        elif opcode=="MLOAD":
            node = self.handle_MLOAD()
            self._stacks[-1].append(node)
        elif opcode=="SSTORE":
            self.boogie_gen_sstore(self._stacks[-1].pop(), self._stacks[-1].pop())
        elif opcode=="SLOAD":
            to_load = self._stacks[-1].pop()
            if to_load.value == "MapElement":
                node = SVT("SLOAD")
                node.children.append(to_load)
                self._stacks[-1].append(node)
                self.postorder_traversal(node)
            else:
                stored_value = self._var_prefix+'.'+self._storage_map[self._curr_contract][str(to_load.value)]
                self.add_new_vars(stored_value)
                self._stacks[-1].append(SVT(stored_value+"["+self.postorder_traversal(self._sym_this_addresses[-1])+"]"))
                self.postorder_traversal(self._stacks[-1][-1])
        elif opcode=="PC":
            self._stacks[-1].append(SVT(PC))
        elif opcode.startswith("LOG"):
            position=int(re.search('[0-9]+', opcode)[0])
            for _ in range(position+2):
                self._stacks[-1].pop()
        elif opcode.startswith("PUSH"):
            self._stacks[-1].append(SVT(operand))
        elif opcode.startswith("POP"):
            self._stacks[-1].pop()
        elif opcode.startswith("CALLER"):
            self._stacks[-1].append(self._sym_this_addresses[-2])
        elif opcode.startswith("ORIGIN"):
            self._stacks[-1].append(SVT("tx_origin")) # symbolic
        elif opcode.startswith("DUP"):
            position=int(re.search('[0-9]+', opcode)[0])
            self._stacks[-1].append(self._stacks[-1][len(self._stacks[-1])-position])
        elif opcode.startswith("SWAP"):
            position=int(re.search('[0-9]+', opcode)[0])
            dest = self._stacks[-1][len(self._stacks[-1])-position-1]
            self._stacks[-1][len(self._stacks[-1])-position] = self._stacks[-1].pop()
            self._stacks[-1].append(dest)
        elif opcode=="ISZERO":
            if isinstance(self._stacks[-1][-1].value, int):
                val = self._stacks[-1].pop().value
                # if val == 0:
                self._stacks[-1].append(SVT(1 if val==0 else 0))
                # else:
                #     self._stacks[-1].append(SVT(0))
            else:
                node = SVT(opcode)
                node.children.append(self._stacks[-1].pop())
                self._stacks[-1].append(node)
        elif opcode=="NOT":
            if type(self._stacks[-1][-1].value) == int:
                val = self._stacks[-1].pop().value
                node = SVT(~(2**256|val) & (2**256-1))
                self._stacks[-1].append(node)
            else:
                node = SVT(opcode)
                node.children.append(self._stacks[-1].pop())
                self._stacks[-1].append(node)
        elif opcode=="AND":
            node = self.handle_AND()
            self._stacks[-1].append(node)
        elif opcode=="OR":
            node = self.handle_OR()
            self._stacks[-1].append(node)
        elif opcode=="ADD" or opcode=="LT" or opcode=="GT" or opcode=="EQ" or opcode=="SUB" or opcode=="DIV" or opcode=="EXP" or opcode=="SHL" or opcode=="SLT" or opcode=="MUL" or opcode=="SHR" or opcode=="MOD":
            if isinstance(self._stacks[-1][-1].value, int) and isinstance(self._stacks[-1][-2].value, int):
                if opcode == "ADD":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT((val1 + val2)%2**256)
                elif opcode == "SUB":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT((val1 - val2)%2**256)
                elif opcode == "MUL":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT((val1 * val2)%2**256)
                elif opcode == "DIV":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT((val1 // val2)%2**256)
                elif opcode == "EXP":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT((val1 ** val2)%2**256)
                elif opcode == "SHL":
                    shift= self._stacks[-1].pop().value
                    base = self._stacks[-1].pop().value
                    node = SVT((base << shift)%2**256)
                elif opcode == "SHR":
                    shift = self._stacks[-1].pop().value
                    base = self._stacks[-1].pop().value
                    node = SVT(base >> shift)
                elif opcode == "MOD":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    node = SVT(val1 % val2)
                elif opcode == "LT" or opcode == "SLT":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    result = val1 < val2
                    node = SVT(1) if result else SVT(0)
                elif opcode == "GT":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    result = val1 > val2
                    node = SVT(1) if result else SVT(0)
                elif opcode == "EQ":
                    val1 = self._stacks[-1].pop().value
                    val2 = self._stacks[-1].pop().value
                    result = val1 == val2
                    node = SVT(1) if result else SVT(0)
            else:
                if opcode == "DIV" and self._stacks[-1][-2].value == 1:
                    node = self._stacks[-1].pop() # actual address
                    self._stacks[-1].pop() # dummy 0x1
                else:
                    node = SVT(opcode)
                    node.children.append(self._stacks[-1].pop())
                    node.children.append(self._stacks[-1].pop())
            self._stacks[-1].append(node)
        elif opcode=="SHA3":
            if self._stacks[-1][-2].value == 64:
                start_offset = self._stacks[-1].pop().value
                if not isinstance(start_offset, int):
                    raise Exception("start offset not constant")
                node = SVT("MapElement")
                mapID = self._memories[-1][start_offset+32]
                if(mapID.value!="MapElement"):
                    var_name = self._var_prefix+'.'+self._storage_map[self._curr_contract][str(mapID.value)]
                    self.add_new_vars(var_name)
                    node.children.append(SVT(var_name))
                else:
                    node.children.append(mapID)
                node.children.append(self._memories[-1][start_offset])
                self._stacks[-1].pop() # pop 64
                self._stacks[-1].append(node)
            else:
                self._stacks[-1].pop()    # TODO: this is a temporary patch. It makes the stack layout correct. The content is still incorrect.
                self._stacks[-1].pop()
                self._stacks[-1].append(SVT(0xdeadbeef))
        elif opcode=="ADDRESS":
            self._stacks[-1].append(self._sym_this_addresses[-1])
        elif opcode=="CALLDATACOPY": # TODO: this is a temporary patch. It makes the stack layout correct. The content is still incorrect.
            destOffset  = self._stacks[-1].pop()
            offset      = self._stacks[-1].pop()
            size        = self._stacks[-1].pop()
        elif opcode=="CALLDATASIZE":
            self._stacks[-1].append(SVT("CALLDATASIZE"))
        else:
            print('[!]',str(instr), 'not supported yet')
            self.inspect("currstack")
            self.inspect("currmemory")
            raise Exception("not handled")

    '''recursively traverse an SVT node'''
    def postorder_traversal(self, node):
        to_return = ""
        if not node.children:
            return node.value

        if node.value == "ISZERO":
            to_return = self.postorder_traversal(node.children[0])
            if isinstance(to_return, int):
                if to_return == 0:
                    to_return = "true"
                else:
                    to_return = "false"
            elif to_return == "false":
                to_return = "true"
            elif to_return == "true":
                to_return = "false"
            else:
                val1 = to_return
                self._tmp_var_count+=1
                to_return = "tmp" + str(self._tmp_var_count)
                if (self.isType(val1, 'bool')):
                    to_boogie = "\ttmp" + str(self._tmp_var_count) + ":=!" + str(val1) + ";\n"
                elif (self.isType(val1, 'uint256')):
                    to_boogie = "\ttmp" + str(self._tmp_var_count) + ":=" + str(val1) + "==Zero;\n"
                node.value = to_return
                node.children = []
                self._final_vars[to_return] = 'bool'
                self._final_path.append(to_boogie)
        elif node.value == "SLOAD":
            sym_this = self.postorder_traversal(self._sym_this_addresses[-1])
            if node.children[0].value=="MapElement":
                if node.children[0].children[0].value=="MapElement":
                    map_ID = node.children[0].children[0].children[0].value
                    self.postorder_traversal(node.children[0].children[0].children[1])
                    self.postorder_traversal(node.children[0].children[1])
                    map_key1 = self.find_key(node.children[0].children[0].children[1])
                    map_key2 = self.find_key(node.children[0].children[1])
                    key_for_boogie = f"[{sym_this}][{str(map_key1)}][{str(map_key2)}]"
                    var_name = map_ID+key_for_boogie
                else:
                    map_ID  = node.children[0].children[0].value
                    self.postorder_traversal(node.children[0].children[1])
                    map_key = self.find_key(node.children[0].children[1])
                    key_for_boogie = f"[{sym_this}][{str(map_key)}]"
                    var_name = map_ID + key_for_boogie
            self._tmp_var_count+=1
            to_return = "tmp" + str(self._tmp_var_count)
            self.add_new_vars(var_name)
            to_boogie = "\ttmp"+str(self._tmp_var_count)+":="+ var_name +";\n"
            node.value = to_return
            node.children = []
            self._final_vars[to_return] = self._final_vars[map_ID].split()[-1] # patch
            self._final_path.append(to_boogie)
        elif node.value == "LT" or node.value == "GT" or node.value == "EQ" or node.value == "SLT": #TODO: SLT implementation
            if node.value == "EQ" and node.children[0] == node.children[1]:
                to_return = "true"
            else:
                val1 = self.postorder_traversal(node.children[0])
                val2 = self.postorder_traversal(node.children[1])
                if (str(val1).isdigit() and MACROS.NUM_TYPE == "real"):
                     val1 = str(val1)+'.0'
                if (str(val2).isdigit() and MACROS.NUM_TYPE == "real"):
                     val2 = str(val2)+'.0'
                if isinstance(val1, int) and isinstance(val2, int):
                    to_return = ""
                    if node.value == "LT" or node.value == "SLT": #TODO: SLT implementation
                        to_return = "true" if val1 < val2 else "false"
                    elif node.value == "GT":
                        to_return = "true" if val1 > val2 else "false"
                    elif node.value == "EQ":
                        to_return = "true" if val1 == val2 else "false"
                else:
                    self._tmp_var_count+=1
                    to_return = "tmp" + str(self._tmp_var_count)
                    if node.value == "LT" or node.value == "SLT": #TODO: SLT implementation
                        to_boogie = "\ttmp"+str(self._tmp_var_count)+":= ("+str(val1)+"<"+str(val2)+");\n"
                    elif node.value == "GT":
                        to_boogie = "\ttmp"+str(self._tmp_var_count)+":= ("+str(val1)+">"+str(val2)+");\n"
                    elif node.value == "EQ":
                        to_boogie = "\ttmp"+str(self._tmp_var_count)+":= ("+str(val1)+"=="+str(val2)+");\n"
                    node.value = to_return
                    node.children = []
                    self._final_vars[to_return] = 'bool'
                    self._final_path.append(to_boogie)
        elif node.value == "ADD" or node.value == "SUB" or node.value == "AND" or node.value == "OR" or node.value == "MUL" or node.value == "DIV" or node.value == "MOD":
            val1=self.postorder_traversal(node.children[0])
            val2=self.postorder_traversal(node.children[1])
            if isinstance(val1, int) and isinstance(val2, int):
                if (str(val1).isdigit() and MACROS.NUM_TYPE == "real"):
                         val1 = str(val1)+'.0'
                if (str(val2).isdigit() and MACROS.NUM_TYPE == "real"):
                         val2 = str(val2)+'.0'
                if node.value == "ADD":
                    to_return = val1 + val2
                elif node.value == "SUB":
                    to_return = val1 - val2
                elif node.value == "AND":
                    to_return = val1 & val2
                elif node.value == "OR":
                    to_return = val1 | val2
                elif node.value == "MUL":
                    to_return = val1 * val2
                elif node.value == "DIV":
                    to_return = val1 / val2
            else:
                self._tmp_var_count+=1
                to_return =  "tmp" + str(self._tmp_var_count)
                if (val1 in self._final_vars and self._final_vars[val1] == 'bool') or (val2 in self._final_vars and self._final_vars[val2] == 'bool'):
                    if isinstance(val1, int):
                        str_val1="false" if val1==0 else "true"
                    else:
                        str_val1=str(val1)
                    if isinstance(val2, int):
                        str_val2="false" if val2==0 else "true"
                    else:
                        str_val2=str(val2)
                    if node.value == "AND":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":="+str_val1+"&&"+str_val2+";\n"
                    elif node.value == "OR":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":="+str_val1+"||"+str_val2+";\n"
                    self._final_vars[to_return] = 'bool'
                elif  node.value == "SUB" and (self.isType(val1, "address") or self.isType(val2, "address")):
                    to_boogie ="\ttmp"+str(self._tmp_var_count)+":=("+str(val1)+"!="+str(val2)+");\n"
                    self._final_vars[to_return] = 'bool'
                else:
                    if (str(val1).isdigit() and MACROS.NUM_TYPE == "real"):
                         val1 = str(val1)+'.0'
                    if (str(val2).isdigit() and MACROS.NUM_TYPE == "real"):
                         val2 = str(val2)+'.0'
                    if node.value == "ADD":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmadd("+str(val1)+","+str(val2)+");\n"
                    elif node.value == "SUB":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmsub("+str(val1)+","+str(val2)+");\n"
                    elif node.value == "AND":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmand("+str(val1)+","+str(val2)+");\n"
                    elif node.value == "OR":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmor("+str(val1)+","+str(val2)+");\n"
                        print(f"{val1}   {type(val1)}")
                    elif node.value == "MUL":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmmul("+str(val1)+","+str(val2)+");\n"
                    elif node.value == "DIV":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmdiv("+str(val1)+","+str(val2)+");\n"
                    if node.value == "MOD":
                        to_boogie ="\ttmp"+str(self._tmp_var_count)+":=evmmod("+str(val1)+","+str(val2)+");\n"
                    self._final_vars[to_return] = 'uint256'
                node.value = to_return
                node.children = []
                self._final_path.append(to_boogie)
        elif node.value == "Partial32B":
            to_return = self.postorder_traversal(node.children[1])
        elif node.value == "SHL":
            shift = self.postorder_traversal(node.children[0])
            val = self.postorder_traversal(node.children[1])
            to_return = val << shift
            node.value = to_return
            node.children = []
        elif node.value == "ACCOUNT_CODESIZE":
            self._tmp_var_count+=1
            to_return =  "tmp" + str(self._tmp_var_count)
            to_boogie ="\ttmp"+str(self._tmp_var_count)+":=nondet(); //EXTCODESIZE\n"
            self._final_vars[to_return] = 'uint256'
            node.value = to_return
            node.children = []
            self._final_path.append(to_boogie)
        else:
            raise Exception(f"Codegen {node} -- not implemented")
            # return str(node)
        return to_return

    '''generate boogie code when SSTORE happens'''
    def boogie_gen_sstore(self, node0, node1):
        sym_this = str(self.postorder_traversal(self._sym_this_addresses[-1]))
        if node0.value=="MapElement":
            if node0.children[0].value=="MapElement":
                map_ID = (node0.children[0].children[0])
                self.postorder_traversal(node0.children[0].children[1])
                self.postorder_traversal(node0.children[1].children[1])
                map_key1 = self.find_key(node0.children[0].children[1])
                map_key2 = self.find_key(node0.children[1].children[1])
                if "." in str(map_ID):
                    var_name = f"{map_ID}[{sym_this}][{map_key1}][{map_key2}]"
                else:
                    var_name = f"{self._storage_map[self._curr_contract][str(map_ID)]}[{sym_this}][{str(map_key1)}][{str(map_key2)}]"
            else:
                map_ID = self.find_mapID(node0)
                self.postorder_traversal(node0.children[1])
                map_key = self.find_key(node0.children[1])
                if "." in str(map_ID):
                    var_name = f"{str(map_ID)}[{sym_this}][{str(map_key)}]"
                else:
                    var_name = f"{self._storage_map[self._curr_contract][str(map_ID)]}[{sym_this}][{str(map_key)}]"
        else:
            var_name = f"{self._var_prefix}.{self._storage_map[self._curr_contract][str(node0.value)]}[{sym_this}]"
        path="\t"+var_name+":=" + str(self.postorder_traversal(node1))
        if isinstance(node1.value,int) and MACROS.NUM_TYPE == "real":
            path+=".0"
        path+=";\n\n"
        self.add_new_vars(var_name)
        self._final_path.append(path)

    def is_called_param(self, map_key):
        if (re.search("c\_(.*).\_", map_key)):
            print(map_key, "TRUE")
            return True
        print(map_key, "FALSE")
        return False

    '''generate boogie code when JUMPI happens'''
    def boogie_gen_jumpi(self, node, isNotZero):
        var = self.postorder_traversal(node)
        if var == "true":
            if isNotZero:
                return
            else:
                path = "\tassume(false);\n\n"
        elif var == "false":
            if isNotZero:
                path = "\tassume(false);\n\n"
            else:
                return
        elif(isinstance(var, int)):
            if (isNotZero and var==0) or (not isNotZero and var!=0):
                raise Exception("JUMPI condition exception")
            else:
                return
        elif "." in var:
            return
        elif(self._final_vars[var]=='bool'):
            if (isNotZero):
                path = "\tassume("+ var +");\n\n"
            else:
                path = "\tassume(!"+ var +");\n\n"
        elif(self._final_vars[var]=='uint256'):
            if (isNotZero):
                path = "\tassume("+ var +"!=Zero);\n\n"
            else:
                path = "\tassume("+ var +"==Zero);\n\n"
        else:
            raise Exception("JUMPI stack[-1] is_not_zero error")
        self._final_path.append(path)

    '''write aux vars to Boogie'''
    def write_vars(self):
        for var in self._final_vars.keys():
            MACROS.ALL_VARS[var] = self._final_vars[var]
            if var.startswith("tmp"):
                self._output_file.write("\tvar " + var + ":  " + self._final_vars[var] + ";\n")
        self._output_file.write("\n")

    '''write global vars to Boogie'''
    def write_global_vars(self):
        modified = []
        for var in self._final_vars.keys():
            MACROS.ALL_VARS[var] = self._final_vars[var]
            if not var.startswith("tmp"):
                modified.append(var)
                self._output_file.write("var " + var + ":  " + self._final_vars[var] + ";\n")
        self._output_file.write("\n")

        self._output_file.write("""procedure straightline_code ()
modifies """)
        for i in range(len(modified)-1):
            self._output_file.write(modified[i] + ", ")
        self._output_file.write(modified[-1] + ";\n")
        self._output_file.write("""{
    var tx_origin: address;
    var entry_contract: address;
    var BLOCKTIME: uint256;
""")

    '''write declared vars to Boogie'''
    def write_declared_vars(self):
        self._output_file.write("\t// declare-vars\n")
        declaration = self._postcondition.get(self._curr_contract, {}).get(self._curr_function, {}).get("declaration", [])
        for decl in declaration:
            decl = decl.strip()
            original_name = re.search("var (.*):", decl)[0].strip('var').strip(':').strip()
            decl_name = "decl_"+original_name
            decl_type = decl.strip('var').strip(':').strip(';').strip(decl_name).strip()

            MACROS.DECL_SUBS[original_name] = decl_name
            MACROS.DECL_VARS[original_name] = decl_type

            self._output_file.write("\t" + decl.replace(original_name, decl_name) + "\n")
        self._output_file.write("\n")

    '''write entry assignment to Boogie'''
    def write_entry_assignment(self):
        for asgmt in self._postcondition[self._curr_contract].get(self._curr_function, {}).get("assignment", []):
            asgmt = asgmt.strip()
            asgmt = asgmt.strip(";")
            curr_address = (self._sym_this_addresses[-1]).value
            asgmt = asgmt.replace("this", curr_address)
            if(asgmt):
                test = asgmt.split(":=")
            name = (test[0])
            expr = (test[1])
            self._output_file.write("\t"+MACROS.DECL_SUBS[name] + ":=" + name_substitution(self._var_prefix, expr) + ";\n")
        self._output_file.write("\n")

    '''write entry postcondition to Boogie'''
    def write_entry_postcondition(self):
        postcons = self._postcondition[self._curr_contract].get(self._curr_function, {}).get("postcondition", [])
        if postcons:
            self._output_file.write("\t// (post) insert postcondition of " + self._curr_function + '\n')
            for postcon in postcons:
                postcon = postcon.strip(";")
                expr = name_substitution(self._curr_contract, postcon)
                for to_sub in MACROS.DECL_SUBS:
                    expr = expr.replace(to_sub, MACROS.DECL_SUBS[to_sub])
                self._output_file.write("\tassert( " + expr + " );\n")
            self._output_file.write("\n")

    '''write all generated code to Boogie'''
    def write_paths(self):
        for path in self._final_path:
            self._output_file.write(path)

    def is_hex(self, s):
        try:
            int(s, 16)
            return True
        except ValueError:
            return False

    def add_new_vars(self, var_name):
        mapping = get_var_mapping(var_name)
        var_name = var_name.split('[')[0]
        var_type = ""
        if var_name in self._final_vars:
            return
        else:
            var_type += "[address] "
            for i in range(1, len(mapping)):
                if mapping[i][mapping[i].find("[")+1:mapping[i].find("]")].isnumeric():
                    mapping[i] = mapping[i][:mapping[i].find("[")]
                var_type += "[" + self._final_vars[mapping[i]] + "] "
            if ('.' in var_name):
                self._final_vars[var_name] = var_type + MACROS.VAR_TYPES[self._curr_contract][var_name[var_name.find('.')+1:]]
            else:
                self._final_vars[self._var_prefix+'.'+var_name] = var_type + MACROS.VAR_TYPES[self._curr_contract][var_name]

    '''helper to find the key of a node'''
    def find_key(self, node):
        if not node.children:
            if isinstance(node.value, str) or (self.is_hex(str(node.value))):
                return node.value
        for c in node.children:
            if not isinstance(c, tuple):
                return_val = self.find_key(c)
                if return_val:
                    return return_val

    '''helper to find the map ID'''
    def find_mapID(self, node):
        if node.value == "MapElement":
            return node.children[0]
        for c in node.children:
            self.find_mapID(c)

    ''' helper to inspect the data structures'''
    def inspect(self, what):
        if what == "stack":
            for stack_name in self._stacks:
                print("-----Stack: "+stack_name+"-----")
                c=0
                for elem in self._stacks[stack_name][::-1]:
                    if isinstance(elem.value, int):
                        s = hex(elem.value)
                    else:
                        s = elem
                    print('stack['+str(c)+'] ', s)
                    c=c+1
        elif what == "currstack":
            # for stack_name in self._stacks:
            print("-----Stack: "+self._curr_contract+"-----")
            c=0
            for elem in self._stacks[-1][::-1]:
                if isinstance(elem.value, int):
                    s = hex(elem.value)
                else:
                    s = elem
                print('stack['+str(c)+'] ', s)
                c=c+1
        elif what == "memory":
            for memory_name in self._memories.keys():
                print("-----Memory: "+memory_name+"-----")
                temp = self._memories[memory_name]
                for key in temp.keys():
                    if isinstance(temp[key].value, int):
                        s = hex(temp[key].value)
                    else:
                        s = temp[key]
                    print(hex(key), ": ", s)
        elif what == "currmemory":
            print("-----Memory: "+self._curr_contract+"-----")
            temp = self._memories[-1]
            for key in temp.keys():
                if isinstance(temp[key].value, int):
                    s = hex(temp[key].value)
                else:
                    s = temp[key]
                print(hex(key), ": ", s)
        elif what == "storage":
            print("-----Storage-----")
            for key in self._storage:
                print('(', key, ',', self._storage[key], ')')

'''
main symexec
'''
def main():
    ''' read user arguments: [solidity, theorem, trace] '''
    ARGS = sys.argv
    MACROS.SOLIDITY_FNAME  = ARGS[1]
    MACROS.THEOREM_FNAME   = ARGS[2]
    MACROS.TRACE_FNAME     = ARGS[3]
    MACROS.BOOGIE          = MACROS.TRACE_FNAME[:-4]+".bpl"

    ''' initial generation of solc files and essential trace '''
    gen_solc()
    CONTRACT_NAME,FUNCTION_NAME = get_contract_and_function_names()
    MACROS.CONTRACT_NAME    = CONTRACT_NAME
    MACROS.FUNCTION_NAME    = FUNCTION_NAME
    VAR_PREFIX              = CONTRACT_NAME
    check_entrypoint()
    entry_contract_address  = gen_trace_essential()[0]

    ABI_INFO    = get_ABI_info()
    STOR_INFO   = get_STORAGE_info()

    ''' parameters setup '''
    STACKS      = gen_init_STACK(VAR_PREFIX, ABI_INFO)
    STORAGE     = gen_init_STORAGE()
    MEMORIES    = gen_init_MEMORY()
    BOOGIE_OUT  = open(MACROS.BOOGIE, "w")
    PATHS       = []
    CALL_STACK  = gen_init_CALL_STACK(VAR_PREFIX)

    HYPOTHESIS  = get_hypothesis()
    MACROS.INVARIANTS  = get_invariant()
    VARS        = get_init_vars(STOR_INFO, ABI_INFO, VAR_PREFIX)
    TRACE       = gen_path()
    MAP         = get_MAPS(STOR_INFO)
    MACROS.VAR_TYPES = get_types(STOR_INFO)
    MACROS.NUM_TYPE  = get_numerical_type()
    MACROS.DEF_VARS  = get_defvars()

    ''' run EVM trace instructions '''
    evm = EVM(STACKS, STORAGE, MAP, MEMORIES, BOOGIE_OUT, PATHS, VARS, CONTRACT_NAME, FUNCTION_NAME, CALL_STACK, ABI_INFO, VAR_PREFIX, [])
    evm._sym_this_addresses  = [SVT("tx_origin"),SVT("entry_contract")]
    print('inputs: ', MACROS.SOLIDITY_FNAME, MACROS.THEOREM_FNAME, MACROS.TRACE_FNAME)
    print('\n(executing instructions...)')
    evm.sym_exec(TRACE)

    ''' write Boogie output '''
    if (MACROS.NUM_TYPE == 'real'):
        BOOGIE_OUT.write(MACROS.PREAMBLE_REAL)
    elif (MACROS.NUM_TYPE == 'int'):
        BOOGIE_OUT.write(MACROS.PREAMBLE_INT)

    evm.write_global_vars()
    evm.write_vars() # aux vars for Boogie Proofs
    evm.write_declared_vars() # postcondition vars for Boogie proofs

    BOOGIE_OUT.write(write_defvars(VAR_PREFIX))
    BOOGIE_OUT.write(write_hypothesis(HYPOTHESIS,VAR_PREFIX))
    BOOGIE_OUT.write(write_invariants(MACROS.INVARIANTS,VAR_PREFIX))

    evm.write_paths() # codegen for Boogie proofs
    evm.write_entry_assignment() # from AST file
    evm.write_entry_postcondition() # from AST file
    BOOGIE_OUT.write(write_epilogue(MACROS.INVARIANTS,VAR_PREFIX))

    BOOGIE_OUT.close() # close file

if __name__ == '__main__':
    main()

{'recognize_32B_mask': 'memory.recognize_32B_mask', 'mem_item_len': 'memory.mem_item_len', 'content_item_len': 'memory.content_item_len', 'handle_MLOAD': 'memory.handle_MLOAD', 'handle_MSTORE': 'memory.handle_MSTORE', 'handle_AND': 'memory.handle_AND', 'handle_OR': 'memory.handle_OR', 'memory_write': 'memory.memory_write', 'name_substitution': 'utils.name_substitution'}


#!/usr/bin/python

import twitter

api = twitter.Api()

usernames = ["gdickinson",
	"jwgayle",
	"feneets",
	"bennettmorrison",
	"BarackObama",
	"briansabbeth",
	"JustinBieber",
	"jesuschrist",
	"deez79",
	"nycresistor",
	"mikebloomberg"]

for name in usernames:
	user = api.GetUser(name)
	# Get total number of tweets
	#print("%s  %d" % (name, user.statuses_count))
	print(name)
	print(user.statuses_count)
	print()
	# Print out the result


from __future__ import division
from hex.genmodel.easy import RowData
from hex.genmodel.easy import EasyPredictModelWrapper
from java.lang import Math
import MaliciousDomainModel
import MaliciousDomainModel.BETA
import NamesHolder_MaliciousDomainModel
from collections import Counter

f = open('../var/task/words.txt', 'r')
words = set(f.read().splitlines())

def predict(domain):
  domain = domain.split('.')[0]
  row = RowData()
  functions = [len, entropy, p_vowels, num_valid_substrings]
  eval_features = [f(domain) for f in functions]
  names = NamesHolder_MaliciousDomainModel().VALUES
  beta = MaliciousDomainModel().BETA().VALUES
  feature_coef_product = [beta[len(beta) - 1]]
  for i in range(len(names)):
    row.put(names[i], float(eval_features[i]))
    feature_coef_product.append(eval_features[i] * beta[i])

  #prediction
  model = EasyPredictModelWrapper(MaliciousDomainModel())
  p = model.predictBinomial(row)

  #[label, class0Prob, class1Prob], [intercept], [features] = 3 + 1 + x
  return [float(p.label), p.classProbabilities[0], p.classProbabilities[1]] + feature_coef_product

# Shannon entropy
def entropy(domain):
  sume = 0
  chars = Counter(domain)
  N = len(domain)
  for n in chars.values():
    sume += - n / N * Math.log(n / N) / Math.log(2)
  return sume

# proportion of vowels
def p_vowels(domain):
  sumv = 0
  chars = Counter(domain)
  vowels = 'aeiou'
  for v in vowels:
    sumv += chars[v]
  return sumv / len(domain)

# num of all substrings >= 2 characters that are valid english words
def num_valid_substrings(domain):
  word_count = 0
  for i in range(len(domain) - 1):
    for j in range(i + 2, len(domain) + 1):
      if domain[i:j] in words:
        word_count += 1
  return word_count


# Test script for the ADC108S022 being used on a Raspberry Pi 3 B+
# Remember to enable SPI with raspi-config
# Pinout is as follows:

'''
ADC108S022          Rpi3B+
``````````          ````````````
DOUT    --------    MOSI GPIO 10 - SPI0
DIN     --------    MISO GPIO 9  - SPI0
SCLK    --------    SCLK GPIO 11 - SPI0
CS      --------    CS0  GPIO 8  - SPI0

ADC: ADC108S022
10 bit
50 kHz
8 channels:
- 0: Supply Current
- 1: 24V Battery Voltage
- 2: Available?
- 3: Available?
- 4: 2.5V Reference?
- 5: Rpi 3.3V
- 6: Rpi 5V
- 7: Temperature

Current sensor: ACS712ELCTR-20A
Sensitivity = 100mV/A
At zero current - Vout = 2.5V
'''

import time
import spidev
#import math

# We use SPI0 on the pi Pi
spi_bus = 0

#Using Chip Select 0, (CS0)
cs = 0

# Create spi object
spi_object = spidev.SpiDev()

# Open a connection
spi_object.open(spi_bus, cs)

# Set SPI speed and mode
spi_object.max_speed_hz = 1000000
spi_object.mode = 0

for channel in range(0,8):
    msg = [channel*8, 0x00]
    returnchars = spi_object.xfer2(msg)
    value = returnchars[0]*64 + returnchars[1]/4
    time.sleep(1)
    output = "Channel %i, Return Value of: %i"%(channel, value)
    print(returnchars)
    print(output)


import re
import argparse
import os
import json

from github import Github
from httplib2 import Http

from settings import SETTINGS

class ProjectIdFormatError(Exception):
    pass

class RepositoryNotFoundError(Exception):
    pass

def root_parser():
    """
    parses arguments passed on command line when running program
    :return: list of arguments
    """
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawTextHelpFormatter
    )
    parser.set_defaults(force=False)
    parser.add_argument(
        "--api-url",
        "-a",
        help="URL to GitHub API",
        default=SETTINGS.DEFAULT_GITHUB_API_URL,
    )
    parser.add_argument(
        "--code-org",
        "-o",
        help="ID of the organisation where the Terraform code" "repository is",
        default=SETTINGS.DEFAULT_CODE_ORG,
    )
    parser.add_argument(
        "--config-org",
        "-O",
        help="ID of the organisation where the configuration" "repository is",
        default=SETTINGS.DEFAULT_CONFIG_ORG,
    )
    parser.add_argument(
        "--vcs-token",
        "-t",
        help="Authentication for VCS platform"
    )
    parser.add_argument(
        "--config-version",
        "-c",
        help="git branch for the configuration",
        default=SETTINGS.DEFAULT_GIT_REF,
    )
    parser.add_argument(
        "--code-version",
        "-T",
        help="git branch for the code",
        default=SETTINGS.DEFAULT_GIT_REF,
    )
    parser.add_argument(
        "--key-file",
        help="path to the file containing the private "
        "key used for authentication on CSP",
        type=argparse.FileType("r"),
    )
    parser.add_argument(
        "--monitoring-namespace",
        help="CSP specific location where monitoring data is aggregated. For"
        "example, a GCP project",
    )
    parser.add_argument(
        "--log-file",
        help="path to log file, if different from default",
        default=SETTINGS.DEFAULT_LOG_FILE,
    )
    parser.add_argument(
        "--metrics-file",
        help="path to file containing monitoring metrics, if different from default",
        default=SETTINGS.DEFAULT_METRICS_FILE,
    )
    parser.add_argument(
        "--debug",
        help="output debug information to help troubleshoot issues",
        default=False,
    )
    parser.add_argument(
        "--disable-local-reporter",
        help="disable logging and monitoring to local files",
        default=False,
        action="store_true",
    )
    parser.add_argument(
        "--json-logging",
        help="Enable logging in json logging format",
        default=False,
        action="store_true",
    )
    parser.add_argument(
        "--slack-token",
        "-st",
        help="Slack bot user OAuth access token"
    )
    parser.add_argument(
        "--slack-channel",
        "-sc",
        help="Name of channel, where notifications will go",
    )
    parser.add_argument(
        "--vcs-platform",
        choices=["all"] + SETTINGS.SUPPORTED_VCS_PLATFORMS,
        default="github"
    )
    return parser

class GcpAuth:
    def __init__(self, key_file=None):
        self.key_file = key_file
        if self.key_file:
            self.service_account_info = self._get_service_account_info(key_file)
        self.credentials = self.get_gcp_credentials()

    def get_gcp_credentials(self):
        """
        construct credentials object to authenticate against APIs with
        :return: object: of type google.auth.credentials.Credentials
        """
        if self.key_file:
            from google.oauth2 import service_account

            return service_account.Credentials.from_service_account_info(
                self.service_account_info
            )
        else:
            import google.auth

            credentials, project_id = google.auth.default()
            return credentials

    def _get_http_auth(self):
        """
        Add credentials to an HTTP request object
        :return: HTTP request object with added credential information
        """
        credentials = self.get_gcp_credentials()
        return credentials.authorize(Http())

    @staticmethod
    def _get_service_account_info(creds_file):
        with open(creds_file.name, "r") as f:
            ext = os.path.splitext(f.name)[-1].lower()
            if ext == ".json":
                return json.loads(f.read())

    # def _get_project_id():
    #     """
    #     query Google Metadata server
    #     :return: string of project id
    #     """
    #     url = GCP_METADATA_URL + '/project/project-id'
    #     try:
    #         project_id = requests.get(url)
    #     except (requests.ConnectionError, requests.ConnectTimeout):
    #         return _DEFAULT_GCP_PROJECT
    #
    #     return project_id
    #
    # def _get_storage_client(storage_class=storage.Client):
    #     """
    #     set up our local storage client
    #     :param storage_class: what Python class to use to set up our client
    #     :return: Object of our client
    #     """
    #     return storage_class(project=_get_project_id(),
    #                          credentials=get_gcs_credentials())

def get_org(parsed_args, org):
    github = Github(
        base_url=parsed_args.api_url, login_or_token=parsed_args.vcs_token
    )
    return github.get_organization(org)

def get_repo(org, name=SETTINGS.DEFAULT_PROJECT_ID):
    return org.get_repo(name)

def get_team(org, team_name):
    """
    returns team from org by searching the name
    :param org: obj: of the organisation to search
    :param team_name: string: name of the team to return
    :return: obj: github.Team.Team
    """
    for team in org.get_teams():
        if team.slug == team_name:
            return team
    return None

def get_files(org, repo_name, directory, version):
    """
    Get a list of the files from given repository
    :param org: object: of :class:`github.Organization.Organization`
    :param repo_name: string: of name of the organisational repository where
     files are located
    :param directory: string: of directory in reposo
    :param version: string : branch or tag of repo
    :return: list :class:`github.ContentFile.ContentFile`
    """
    repo = get_repo(org, repo_name)
    return repo.get_dir_contents(directory, version)

def get_hash_of_latest_commit(org, repo_name, branch):
    """
    Get sha256 hash of latest commit in some branch of the repo.
    :param org: object: of :class:`github.Organization.Organization`
    :param repo_name: string: of name of the organisational repository where
     files are located
    :param branch: string : name of the git branch
    :return: sha256 hash string
    """
    repo = get_repo(org, repo_name)
    branch = repo.get_branch(branch)
    return branch.commit.sha

def valid_project_id_format(project_id):
    if not re.match(SETTINGS.VALID_PROJECT_ID_FORMAT, project_id):
        raise ProjectIdFormatError(
            project_id
            + " does not match the "
            + SETTINGS.VALID_PROJECT_ID_FORMAT
            + "format"
        )
    return True


import sys
from setuptools import setup
from setuptools.command.egg_info import egg_info
from torch.utils.cpp_extension import BuildExtension, CppExtension, IS_WINDOWS, IS_MACOS

extra_compile_args = []
if IS_WINDOWS:
    extra_compile_args.append('/std:c++17')
elif IS_MACOS:
    extra_compile_args.append('-std=c++17')
else:
    extra_compile_args.append('-std=c++17')

class EggInfoInstallLicense(egg_info):
    def run(self):
        if not self.distribution.have_run.get('install', True):
            self.mkpath(self.egg_info)
            self.copy_file('LICENSE', self.egg_info)
        egg_info.run(self)

setup(
    name='pycorlimbo',
    author='Christoph Neuhauser',
    ext_modules=[
        CppExtension(
            'pycorlimbo',
            [
                'src/PyCorLimbo.cpp',
            ],
            libraries=['nlopt'],
            extra_compile_args=extra_compile_args,
        )
    ],
    data_files=[
        ( '.', ['src/pycorlimbo.pyi'] )
    ],
    cmdclass={
        'build_ext': BuildExtension,
        'egg_info': EggInfoInstallLicense
    },
    license_files = ('LICENSE',),
    include_dirs=['third_party/limbo/src', 'third_party/eigen']
)


# all the libraries we'll need
import json
import os
import requests
import sys
from youtube_title_parse import get_artist_title

import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors

# this is for the Google API, which specifies what we're going to do with the data we retrieve
scopes = ["https://www.googleapis.com/auth/youtube.readonly"]

# get id of youtube playlist that you are taking videos from
def get_playlist_id(playlist_name):
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

    api_service_name = "youtube"
    api_version = "v3"
    client_secrets_file = "client_secret_386197436539-v4o3p4ov2kt7f4j039p1r1qt4jfekimk.apps.googleusercontent.com.json"

    # Get credentials and create an API client
    flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
        client_secrets_file, scopes)
    credentials = flow.run_console()
    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, credentials=credentials)

    request = youtube.playlists().list(
        part="snippet",
        maxResults=25,
        mine=True
    )
    response = request.execute()
    # everything above was taken from the Google API
    # and everything below is what I added in
    # what this does is it takes the data retrieved by the API and parses it out so that I can get the only piece of data I actually need,
    # which is the id of the youtube playlist
    for item in response['items']:
        if item['snippet']['title'] == playlist_name:
            return item['id']
        else:
            continue

# get titles from the playlist
def get_song_titles(playlist_id):
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

    api_service_name = "youtube"
    api_version = "v3"
    client_secrets_file = "client_secret_386197436539-v4o3p4ov2kt7f4j039p1r1qt4jfekimk.apps.googleusercontent.com.json"

    # Get credentials and create an API client
    flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
        client_secrets_file, scopes)
    credentials = flow.run_console()
    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, credentials=credentials)

    request = youtube.playlistItems().list(
        part="snippet",
        maxResults=50,
        playlistId=playlist_id,
    )
    response = request.execute()
    # ^ from Google API
    # everything down here is from yours truly
    # this parsed out the API response, and just returned the titles of each song in the yt playlist
    # then it put each song title in a list and returned that list
    playlist_items = response['items']
    song_titles = []
    for item in playlist_items:
        title = item['snippet']['title']
        # the function below was downloaded from the Internet
        artist, song = get_artist_title(title)
        song_titles.append(song)
    return song_titles

# creates spotify playlist and returns its id
def create_spotify_playlist(playlist_name, id, token):  # requires a name, a user id, and a token that the person can make off the Spotify website
    playlist_body = json.dumps({  # request body data which is being turned into json script
        "name": playlist_name,
        "public": True
    })

    # playlist endpoint: not sure what it does but it's necessary
    playlist_endpoint = f"https://api.spotify.com/v1/users/{id}/playlists"
    # makes an http request (meaning it searches up whatever is in the parameters on the browser)
    playlist_request = requests.post(
        playlist_endpoint,  # this and everything below is based off Spotify Web API docs
        data=playlist_body,
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {token}"
        }
    )
    # ^ from Spotify API, which creates a Spotify playlist and needs the id of the user and a token
    # the token authorizes the app to make a playlist
    # not as much work needed from me here down below
    # just had to find the id of the playlist from the response given by Spotify and return it
    playlist_json = playlist_request.json()
    playlist_id = playlist_json["id"]
    return playlist_id

# searches spotify for song titles and adds it to newly created playlist
def add_songs(query, playlist_id, token):  # token is the same, playlist_id was given by the function above
    # query is the only thing that is different: it just means the song title, so when the API adds a song to a playlist,
    # it knows the name of the song that needs to be added
    search_endpoint = f"https://api.spotify.com/v1/search?q={query}&type=track"

    search_request = requests.get(
        search_endpoint,
        headers={
            "Authorization": f"Bearer {token}"
        }
    )
    search_json = search_request.json()
    search_id = search_json["tracks"]["items"][0]["id"]
    # Add liked songs to Spotify playlist
    add_items_endpoint = f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks?uris=spotify%3Atrack%3A{search_id}"
    add_items_request = requests.post(
        add_items_endpoint,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
    )
    # ^ all from Spotify API
    # nothing needed from me except adding the token, playlist id, and the query

# now we gotta run everything
if __name__ == '__main__':
    print("Hello! This app will take your liked songs in a YouTube playlist of your choice and "
          "add them to a newly created playlist on your Spotify!")
    # loops so that if an incorrect playlist name was inputted, it would re-prompt the user
    while True:
        try:
            yt_playlist_name = input("Enter the exact name of the YouTube playlist that has your favorite songs: ")
            yt_playlist_id = get_playlist_id(yt_playlist_name)
            break
        except:
            print("There is no playlist that matches that name.")

    try:
        song_titles = get_song_titles(yt_playlist_id)
    except:  # exits the program if there was an error in retrieving the songs
        print("There was an error in retrieving your songs.")
        sys.exit()

    # asks user for user id
    sp_user_id = input(
        "Enter your Spotify user ID. This can be found by going to your profile, clicking 'Share', and copying your Spotify URI. "
        "The string of numbers and letters after 'spotify:user:' is your ID: ")

    # asks user for the name of the playlist they want to make
    sp_playlist_name = input(
        "Now we're gonna make a new playlist on your Spotify. Enter the name you would like for the playlist: ")

    # wow lot's of text
    # asks user to input a token to authorize the program. Without it, we won't be able to make a playlist or add songs
    token = input(
        "Now go to this url https://developer.spotify.com/console/post-playlists/?user_id=&body=%7B%22name%22%3A%22New%20Playlist%22%2C%22description%22%3A%22New%20playlist%20description%22%2C%22public%22%3Afalse%7D, "
        "click Get Token, and checkmark either playlist-modify-public or private (it doesn't matter which). "
        "Click Request Token and copy and paste it here: ")

    # makes a playlist and returns the id in this variable
    sp_playlist_id = create_spotify_playlist(sp_playlist_name, sp_user_id, token)

    # i have to change the titles so that the Spotify API can use them
    # it requires that each space be a '+' or a '%20'
    # after changing the names, I put the new titles into another list
    alt_song_titles = []
    for title in song_titles:
        new_title = ''
        for letter in title:
            if letter == ' ':
                new_title += '+'  # replacing spaces with '+' because spotify api reads it like that
            elif letter.isalnum():
                new_title += letter
            else:
                break
        alt_song_titles.append(new_title)

    # this adds each song from the new list into the playlist
    for title in alt_song_titles:
        add_songs(title, sp_playlist_id, token)

    print("Check your Spotify!")


import json
import boto3
import sys
import os
import zipfile
import traceback
from botocore.client import Config

print('Loading function')

code_pipeline = boto3.client('codepipeline')
elbclient = boto3.client('elbv2')

def put_job_success(job, message):
    """Notify CodePipeline of a successful job
    Args:
        job: The CodePipeline job ID
        message: A message to be logged relating to the job status
    Raises:
        Exception: Any exception thrown by .put_job_success_result()
    """
    print('Putting job success')
    print(message)
    code_pipeline.put_job_success_result(jobId=job)

def put_job_failure(job, message):
    """Notify CodePipeline of a failed job
    Args:
        job: The CodePipeline job ID
        message: A message to be logged relating to the job status
    Raises:
        Exception: Any exception thrown by .put_job_failure_result()
    """
    print('Putting job failure')
    print(message)
    code_pipeline.put_job_failure_result(jobId=job, failureDetails={'message': message, 'type': 'JobFailed'})

def continue_job_later(job, message):
    """Notify CodePipeline of a continuing job
    This will cause CodePipeline to invoke the function again with the
    supplied continuation token.
    Args:
        job: The JobID
        message: A message to be logged relating to the job status
        continuation_token: The continuation token
    Raises:
        Exception: Any exception thrown by .put_job_success_result()
    """

    # Use the continuation token to keep track of any job execution state
    # This data will be available when a new job is scheduled to continue the current execution
    continuation_token = json.dumps({'previous_job_id': job})

    print('Putting job continuation')
    print(message)
    code_pipeline.put_job_success_result(jobId=job, continuationToken=continuation_token)

def get_artifact(job_id,job_data):
    print('get Artifact')
    try:
        input_artifact = job_data['inputArtifacts'][0]
        input_s3_location = input_artifact['location']['s3Location']
        bucket = input_s3_location['bucketName']
        key = input_s3_location['objectKey']
        print("bucket:"+bucket)
        print("key:"+key)
    except Exception as e:
        put_job_failure(job_id,e)
        raise Exception('Input Artifacts convert to reteral')

    try:
        print('Get S3 Object')
        s3_client = boto3.client('s3', config=Config(signature_version='s3v4'))
        s3_client.download_file(bucket, key, '/tmp/downloaded_object')
        print('Unzipping')
        zip_ref = zipfile.ZipFile('/tmp/downloaded_object', 'r')
        zip_ref.extractall('/tmp/downloaded_folder')
        zip_ref.close()
        with open('/tmp/downloaded_folder/imageDetail.json','r') as data_file:
            input_json = data_file.read()
        return input_json
    except Exception as e:
        put_job_failure(job_id,e)
        raise Exception('Input Artifacts did not get S3')

def create_image_definition(job_id,input_json):
    print('Shaping JSON')
    try:
        input_dict = json.loads(input_json)
        output_dict = []
        name = input_dict['RepositoryName'].split('/')[-1]
        imageUri = input_dict['ImageURI']
        output_dict.append({"name":name,"imageUri":imageUri})
        output_json = json.dumps(output_dict)
        print(output_json)
        return output_json
    except Exception as e:
        put_job_failure(job_id,e)
        raise Exception('Outputs Artifacts convert to reteral')

def put_artifact(job_id,job_data,image_definition_json):
    print('put Artifact')
    try:
        output_artifact = job_data['outputArtifacts'][0]
        output_s3_location = output_artifact['location']['s3Location']
        bucket = output_s3_location['bucketName']
        key = output_s3_location['objectKey']
    except Exception as e:
        put_job_failure(job_id,e)
        raise Exception('Outputs Artifacts convert to reteral')

    try:
        print('Zipping')
        # zipping
        os.makedirs('/tmp/.test',exist_ok=True)
        with open('/tmp/.test/imagedefinitions.json','w+') as idf:
            idf.write(image_definition_json)
        import shutil
        shutil.make_archive('/tmp/upload_object','zip',root_dir='/tmp/.test')
        # put object
        print('Put S3 Object')
        s3_client = boto3.client('s3', config=Config(signature_version='s3v4'))
        s3_client.upload_file('/tmp/upload_object.zip',bucket, key)
    except Exception as e:
        put_job_failure(job_id,e)
        raise Exception('Output Artifacts dose not put S3 or missed zip')

def handler(event, context):
    """ Main haldler as an entry point of the AWS Lambda function. Handler controls the sequence of methods to call
    1. Read Job Data from input json
    2. Read Job ID from input json
    3. Get parameters from input json
    4. Get Artifact for  ECR from S3
    5. Shaping ECR Artifact to ECS format
    6. Put Artifact for ECS to S3
    7. Send success or failure to codepipeline
                Args:
                    event : http://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html
                    #actions-invoke-lambda-function-json-event-example
                    context: not used but required for Lambda function
                Raises:
                    Exception: Any exception thrown by handler
    """

    try:
        job_id = event['CodePipeline.job']['id']
        job_data = event['CodePipeline.job']['data']
        input_json = get_artifact(job_id,job_data)
        output_json = create_image_definition(job_id,input_json)
        put_artifact(job_id,job_data,output_json)
        put_job_success(job_id,"Shaping Artifact Success!")

    except Exception as e:
        print('Function failed due to exception.')
        print(e)
        traceback.print_exc()
        put_job_failure(job_id, 'Function exception: ' + str(e))

    print('Function complete.')
    return "Complete!"

if __name__ == "__main__":
    handler(sys.argv[0], None)


import logging
import time

logging.basicConfig(level=logging.INFO)

class TimerError(Exception):
    """A custom exception used to report errors in use of Timer class"""

class Timer:
    """
    Timer class obtained from realpython.com/python-timer/
    """
    def __init__(self):
        self._start_time = None

    def start(self):
        """Start a new timer"""
        if self._start_time is not None:
            raise TimerError(f"Timer is running. Use .stop() to stop it")

        self._start_time = time.perf_counter()

    def stop(self):
        """Stop the timer, and report the elapsed time"""
        if self._start_time is None:
            raise TimerError(f"Timer is not running. Use .start() to start it")

        minutes = (time.perf_counter() - self._start_time) / 60
        seconds = (time.perf_counter() - self._start_time) % 60
        self._start_time = None
        logging.info(f"Elapsed time: {int(minutes)} minutes and {int(seconds)} seconds")


import time

import progressbar
import sqlalchemy as db
from telethon import events, utils
from telethon.tl.functions.channels import GetFullChannelRequest

from tg_companion import STATS_TIMER
from tg_companion.tgclient import DB_URI, LOGGER, client

engine = db.create_engine(DB_URI)
metadata = db.MetaData()

stats_tbl = db.Table("stats", metadata,
                     db.Column("updatetime", db.String(), primary_key=True),

                     db.Column("totaldialogs", db.Integer()),

                     db.Column("usercount", db.Integer()),

                     db.Column("channelcount", db.Integer()),

                     db.Column("supcount", db.Integer()),

                     db.Column("convertedgroups", db.Integer()),

                     db.Column("numchannel", db.Integer()),

                     db.Column("numuser", db.Integer()),

                     db.Column("numdeleted", db.Integer()),

                     db.Column("numbot", db.Integer()),

                     db.Column("numchat", db.Integer()),
                     db.Column("numsuper", db.Integer()),
                     )

GroupsInfo_tbl = db.Table("groups_info", metadata,
                          db.Column("supergroupid", db.Integer()),
                          db.Column("oldgroupid", db.Integer()))

FirstRun = None

@client.on_timer(STATS_TIMER)
@client.log_exception
async def GetStats():
    global FirstRun

    TotalDialogs = 0
    UserCount = 0
    ChannelCount = 0
    SupCount = 0
    ConvertedGroupsIDs = []
    NewGroupsIDs = []
    NumChannel = 0
    NumUser = 0
    NumBot = 0
    NumDeleted = 0
    NumChat = 0
    NumSuper = 0

    FirstTimeRunning = None

    UpdateTime = time.strftime("%c")

    connection = engine.connect()
    if not engine.dialect.has_table(engine, stats_tbl):
        metadata.create_all(
            bind=engine, tables=[
                stats_tbl, GroupsInfo_tbl])
    connection.close()

    connection = engine.connect()
    query = db.select([stats_tbl])
    if not connection.execute(query).fetchall():
        FirstTimeRunning = True

    if FirstRun:
        LOGGER.info(
            "Gathering Stats. You'll be able to use this app during this process without problems"
        )
        LOGGER.info(
            "The companion may not respond to your command for 5 second. Don't panic and try again if your command didn't worked")

        LOGGER.info("You can disable this in the config.env file")

        if FirstTimeRunning:
            LOGGER.info(
                "Because this is your first time running this, the .stats command won't work until this process isn't over"
            )

    else:
        LOGGER.info("Updating Stats...")
        LOGGER.info(
            "The companion may not respond to your command for 5 second. Don't panic and try again if your command didn't worked")

    CachedSupergroups = []

    if not FirstTimeRunning:
        connection = engine.connect()
        query = db.select([GroupsInfo_tbl.columns.supergroupid])
        result = connection.execute(query).fetchall()
        for row in result:
            CachedSupergroups.append(row[0])
        connection.close()

    UserId = await client.get_me()
    UserId = UserId.id

    dialogs = await client.get_dialogs(limit=None)
    for dialog in dialogs:
        if dialog.is_group:
            NumChat = NumChat + 1
        if dialog.is_user:
            if dialog.entity.bot:
                NumBot = NumBot + 1
            else:
                NumUser = NumUser + 1
        if dialog.is_channel:
            if dialog.is_group:
                NumSuper = NumSuper + 1
            else:
                NumChannel = NumChannel + 1
    completed = 0
    bar = progressbar.ProgressBar(
        max_value=NumSuper,
        widget=None,
        poll_interval=1)
    bar.update(completed)
    for dialog in dialogs:
        if dialog.is_channel:
            if dialog.is_group:
                ID1 = utils.get_peer_id(
                    utils.get_input_peer(
                        dialog, allow_self=False))
                strid = str(ID1).replace("-100", "")
                ID = int(strid)
                if ID not in CachedSupergroups:
                    ent = await client.get_input_entity(ID1)
                    gotChatFull = await client(GetFullChannelRequest(ent))

                    connection = engine.connect()

                    query = db.insert(GroupsInfo_tbl).values(
                        supergroupid=gotChatFull.full_chat.id,
                        oldgroupid=gotChatFull.full_chat.migrated_from_chat_id)

                    connection.execute(query)
                    connection.close()

    LookIds = []

    for dialog in dialogs:
        ID = None
        try:
            ID = utils.get_peer_id(
                utils.get_input_peer(
                    dialog, allow_self=False))
        except Exception:
            ID = UserId
        if dialog.is_channel:
            strid = str(ID).replace("-100", "")
            ID = int(strid)
        elif dialog.is_group:
            strid = str(ID).replace("-", "")
            ID = int(strid)
        LookIds.append(ID)

    for dialog in dialogs:
        if dialog.is_group:
            ID = utils.get_peer_id(
                utils.get_input_peer(
                    dialog, allow_self=False))
            strid = str(ID).replace("-100", "")
            ID = int(strid)

            connection = engine.connect()
            query = db.select(
                [GroupsInfo_tbl]).where(
                GroupsInfo_tbl.columns.supergroupid == ID)
            exec = connection.execute(query)
            result = exec.fetchall()
            connection.close()
            for row in result:
                if row[1] is not None:
                    NewGroupsIDs.append(row[0])
                    ConvertedGroupsIDs.append(row[1])
    bar.finish()

    print("Counting your chats...")

    for dialog in dialogs:
        try:
            ID = utils.get_peer_id(
                utils.get_input_peer(
                    dialog, allow_self=False))
        except Exception:
            ID = UserId
        if dialog.is_channel:
            strid = str(ID).replace("-100", "")
            ID = int(strid)
        elif dialog.is_group:
            strid = str(ID).replace("-", "")
            ID = int(strid)
        if utils.get_display_name(dialog.entity) == "":
            NumDeleted = NumDeleted + 1
        elif ID == UserId:
            pass
        if ID not in ConvertedGroupsIDs:
            ent = await client.get_input_entity(dialog)
            msgs = await client.get_messages(ent, limit=0)
            count = msgs.total
            if dialog.is_channel:
                if dialog.entity.megagroup:
                    SupCount = SupCount + count
                else:
                    ChannelCount = ChannelCount + count
            elif dialog.is_group and dialog.is_user:
                UserCount = UserCount + count
        if ID in NewGroupsIDs:
            if ID in LookIds and ID not in ConvertedGroupsIDs:
                index = NewGroupsIDs.index(ID)
                ent = await client.get_input_entity(int("-" + str(ConvertedGroupsIDs[index])))
                msgs = await client.get_messages(ent)
                OldChatCount = msgs.total
                UserCount = UserCount + OldChatCount

    ConvertedCount = len(NewGroupsIDs)
    NumChat = NumChat - ConvertedCount
    TotalDialogs = UserCount + ChannelCount + SupCount

    connection = engine.connect()
    query = db.select([stats_tbl.columns.updatetime])

    if not connection.execute(query).fetchall():
        query = db.insert(stats_tbl).values(
            updatetime=UpdateTime,
            totaldialogs=TotalDialogs,
            usercount=UserCount,
            channelcount=ChannelCount,
            supcount=SupCount,
            convertedgroups=ConvertedCount,
            numchannel=NumChannel,
            numuser=NumUser,
            numdeleted=NumDeleted,
            numbot=NumBot,
            numchat=NumChat,
            numsuper=NumSuper,
        )
    else:
        query = db.update(stats_tbl).values(
            updatetime=UpdateTime,
            totaldialogs=TotalDialogs,
            usercount=UserCount,
            channelcount=ChannelCount,
            supcount=SupCount,
            convertedgroups=ConvertedCount,
            numchannel=NumChannel,
            numuser=NumUser,
            numdeleted=NumDeleted,
            numbot=NumBot,
            numchat=NumChat,
            numsuper=NumSuper,
        )
    connection.execute(query)
    connection.close()

    LOGGER.info("DONE!! You can see your stats by sending .stats in any chat")

@client.on(events.NewMessage(outgoing=True, pattern=r"^\.stats"))
@client.log_exception
async def show_stats(e):
    stats = None

    connection = engine.connect()
    query = db.select([stats_tbl])
    result = connection.execute(query).fetchall()
    if result:
        stats = result[0]
    connection.close()

    if stats:
        updatetime, totaldialogs, usercount, channelcount, supcount, convertedgroups, numchannel, numuser, numdeleted, numbot, numchat, numsuper = (
            stats
        )

        if convertedgroups != 0:
            if convertedgroups != numsuper:
                convertedgroups = convertedgroups
            else:
                convertedgroups = "all"
        else:
            convertedgroups = None

        REPLY = f"""

    **\nMESSAGES COUNTS:**
    Normal groups and chats: `{usercount}`
    Channels: `{channelcount}`
    Supergroups: `{supcount}`
    TOTAL MESSAGES: `{totaldialogs}`

    **\nCHAT COUNTS:**
    Number of Channels: `{numchannel}`
    Number of Supergroups: `{numsuper}` from where `{convertedgroups}` of them converted from normal groups.
    Number of Normal groups: `{numchat}`
    Number of Private conversations: `{numuser}` from where `{numdeleted}` are now Deleted Accounts.
    Number of Bot conversations:  `{numbot}`
    Last Update Time :  `{updatetime}`
    """

        await e.edit(REPLY)
    else:
        await e.edit("`Stats are unavailable!! Try again later. `")


from django.contrib import admin
from .models import Category, Product, Order, TimestampModel

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ["category_name", "category_description", "created_at", "updated_at"]

    # def created_at(self, obj):
    #     return obj.TimestampModel.created_at

    # def updated_at(self, obj):
    #     return obj.TimestampModel.updated_at

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ["product_name", "description", "price", "image", "category"]

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ["Customer_name", "customer_email", "product", "quantity"]


import requests
import datetime
import random
import json
from tkinter import filedialog
from tkinter.messagebox import askyesno, showinfo
# Javascript to get onlyinfo
# Array.from(document.querySelectorAll(".b-photos__item__img")).map(img => img?.src)
# const d = new Set()
# data_file = open("data/alina.json")
# urls = json.load(data_file)

# IMAGES_PREFIX = "alina_rose"
# # result_dir = "D:\\totig\\totig\\Imagenes\\Only\\alina_rose"
# result_dir = f"C:\\Users\\ricar\\OneDrive\\Imágenes\\Only\\{IMAGES_PREFIX}"

def save_image(image_content, dir, name, image_prefix):
    with open(dir + f"\\{image_prefix}-{name}.jpg", 'wb') as img:
        img.write(image_content)

def main():
        # unique_urls = set(urls)
    # data_file = input("Introduzca la fuente de descarga (una lista json con los urls que desea)")
    data_file = filedialog.askopenfile("r")
    result_dir = filedialog.askdirectory()
    if not data_file or not result_dir:
        finished = askyesno("Los datos introducidos no son validos","¿Desea salir?")
        if finished: return
        return main()
    showinfo("El resultado será", f"Origen (Json): {data_file.name}\n" + f"Resultado: {result_dir}")
    data_file = open(data_file.name)
    urls = json.load(data_file)
    image_prefix = result_dir.split("\\")[0].split("/")[-1]

    for url in urls:
        try:
            response = requests.get(url, stream=True, allow_redirects=True)
            image_content = response.content
            save_image(image_content, result_dir, str(datetime.datetime.now().time().microsecond + random.random() *100), image_prefix)
        except Exception as e:
            print("Error", e)

    showinfo("Proceso completado")
    repeat = askyesno("Proceso completado","¿Desea realizar otra descarga?")
    print(repeat)
    if repeat:
        main()

main()


# Approach : Neetcode
# https://youtu.be/nIVW4P8b1VA

from typing import List

class Solution:
    def findMin(self, nums: List[int]) -> int:
        res = nums[0]
        l, r = 0, len(nums) - 1

        while l <= r:
            # if sliced array is sorted
            if nums[l] < nums[r]:
                res = min(res, nums[l])
                break

            m = ( l + r ) // 2
            res = min(res, nums[m])
            if nums[m] >= nums[l]:
                l = m + 1
            else:
                r = m - 1

        return res

nums = [3,4,5,1,2]
obj = Solution()
print(obj.findMin(nums))

# Complexity Analysis:
# Time Complexity : Same as Binary Search O(logN)
# Space Complexity : O(1)


from flask import Flask
from flask_security import Security, SQLAlchemyUserDatastore
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from .models import db, Loja
from .models.auth import User, Role
from .models.moveis import BalcaoCooktop, Sofa, GuardaRoupa
from .models.eletrodomesticos import (
    Geladeira, Fogao, Microondas, MaquinaDeLavar
)
from .models.imoveis import Imovel, Bairro, Imobiliaria, Pergunta
from .models.checklist import CheckListItem
from .models.mercado import ItemDespensa, GrupoDespensa
from .modelviews import BaseItemModelView
from .modelviews.imovel import ImovelModelView
from .modelviews.checklist import ChecklistModelView
from .modelviews.mercado import ItemDespensaModelView
from .blueprints.error_handler import error_handler
from .blueprints.restful import mobile_api

def factory(config):
    """
    Flask Application Factory function

    Generate a new Flask application through this function by specifying
    a config object.

    Args:
        config: The configuration class to be used.
    """

    app = Flask(__name__)

    config = config or 'DefaultConfig'
    app.config.from_object('etc.config.{}'.format(config))

    auth_datastore = SQLAlchemyUserDatastore(db, User, Role)
    Security(app, auth_datastore)
    db.init_app(app)

    if app.config['RECREATE_DATABASE']:
        with app.app_context():
            db.drop_all()
            db.create_all()

    app.register_blueprint(error_handler)
    app.register_blueprint(mobile_api)

    admin = Admin(
        app,
        'Casa Planner',
        template_mode='bootstrap3',
        url='/',
        index_view=ChecklistModelView(
            CheckListItem,
            db.session,
            name='Checklist',
            url='/',
            endpoint='admin'
        )
    )

    with app.app_context():

        admin.add_view(
            BaseItemModelView(
                Geladeira,
                db.session,
                category='Eletrodomesticos',
                name='Geladeiras',
                endpoint='geladeiras'
            )
        )

        admin.add_view(
            BaseItemModelView(
                Fogao,
                db.session,
                category='Eletrodomesticos',
                name='Fogões',
                endpoint='fogoes'
            )
        )

        admin.add_view(
            BaseItemModelView(
                Microondas,
                db.session,
                category='Eletrodomesticos',
                name='Microondas',
                endpoint='microondas'
            )
        )

        admin.add_view(
            BaseItemModelView(
                MaquinaDeLavar,
                db.session,
                category='Eletrodomesticos',
                name='Máquinas de lavar',
                endpoint='maquinas-de-lavar'
            )
        )

        admin.add_view(
            BaseItemModelView(
                BalcaoCooktop,
                db.session,
                category='Moveis',
                name='Balcão Cooktop',
                endpoint='balcoes-cooktop'
            )
        )

        admin.add_view(
            BaseItemModelView(
                GuardaRoupa,
                db.session,
                category='Moveis',
                name='Guarda roupa',
                endpoint='guardas-roupas'
            )
        )

        admin.add_view(
            BaseItemModelView(
                Sofa,
                db.session,
                category='Moveis',
                name='Sofás',
                endpoint='sofas'
            )
        )

        admin.add_view(
            ModelView(
                Loja,
                db.session,
                name='Lojas',
                endpoint='lojas'
            )
        )

        admin.add_view(
            ModelView(
                Bairro,
                db.session,
                category='Imoveis',
                name='Bairros',
                endpoint='bairros'
            )
        )

        admin.add_view(
            ModelView(
                Imobiliaria,
                db.session,
                category='Imoveis',
                name='Imobiliarias',
                endpoint='imobiliarias'
            )
        )

        admin.add_view(
            ImovelModelView(
                Imovel,
                db.session,
                category='Imoveis',
                name='Aluguel',
                endpoint='alugueis'
            )
        )

        admin.add_view(
            ModelView(
                Pergunta,
                db.session,
                category='Imoveis',
                name='Perguntas',
                endpoint='perguntas'
            )
        )

        admin.add_view(
            ItemDespensaModelView(
                ItemDespensa,
                db.session,
                category='Despensa',
                name='Itens',
                endpoint='itens-despensa'
            )
        )

        admin.add_view(
            ModelView(
                GrupoDespensa,
                db.session,
                category='Despensa',
                name='Grupos Despensa',
                endpoint='grupos-despensa'
            )
        )

    return app


from copy import copy
import os
import openpyxl as xl
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.cell_range import CellRange
from openpyxl.styles import Border,Side,Alignment

os.chdir(r"D:\python_project\log")
logs_path = os.getcwd()
report = os.path.join(logs_path,"report.xlsx")

def set_format(ws, row, col):
    #设置单元格格式
    thin = Side(border_style = "thin",color = "000000")
    border = Border(left = thin,right = thin, top = thin,bottom = thin)
    align = Alignment(horizontal = "center",vertical = "center")

    for i in range(1,row+1):
        for j in range(1, col+1):
            ws.cell(i, j).border = border
            ws.cell(i, j).alignment =align

def merge_ws():
    logs = [] #.xlsx文件

    for *dir, logs_file in os.walk(logs_path):
        for log_file in logs_file:
            if  log_file.endswith(".xlsx"):
                logs.append(log_file)
    des_file = logs[0]
    src_files = logs[1:]
    des_wb = xl.load_workbook(des_file)
    des_ws = des_wb.active
    des_cols = des_ws.max_column
    for src_file in src_files:
        src_wb = xl.load_workbook(src_file)
        src_ws = src_wb.active
        src_rows = src_ws.max_row
        src_cols = src_ws.max_column

        for i in range(src_rows):
            for j in range(src_cols):
                des_ws.column_dimensions[get_column_letter( des_cols+j+1)].width = src_ws.column_dimensions[get_column_letter(j+3)].width
                if src_ws.cell(row=i+1,column=j+3).has_style:
                    des_ws.cell(i+1, des_cols+j+1, src_ws.cell(row=i+1,column=j+3).value)
                    des_ws.cell(i+1, des_cols+j+1).font = copy(src_ws.cell(row=i+1,column=j+3).font)
                    des_ws.cell(i+1, des_cols+j+1).fill = copy(src_ws.cell(row=i+1,column=j+3).fill)
                    des_ws.cell(i+1, des_cols+j+1).alignment = copy(src_ws.cell(row=i+1,column=j+3).alignment)
        for mcr in src_ws.merged_cells:
            cr = CellRange(mcr.coord)
            if ((cr.min_row <= 8 and cr.min_col >4) or (cr.min_row >= 9 and cr.min_col >2)):
                cr.shift(col_shift=(des_cols-2))
                des_ws.merge_cells(cr.coord)

        des_cols += 4
    set_format(des_ws, des_ws.max_row, des_ws.max_column)
    des_wb.save(report)

if __name__ == "__main__":
    merge_ws()