#!env python3
import sys
import os
import re
import time
import json, yaml
import subprocess
import threading
import codecs
import traceback
import string
import xml.etree.ElementTree as ET
from datetime import datetime
from queue import Queue, Empty

SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
CONFIG_PATH = os.path.join(SCRIPT_PATH, "../data/config.json")
STATIC_INFO_PATH = os.path.join(SCRIPT_PATH, "../data/static_info.json")
SERVICE_INFO_PATH = os.path.join(SCRIPT_PATH, "../data/service_info.json")
SUMMARY_PATH = os.path.join(SCRIPT_PATH, "../data/summary.json")
VULN_PATH = os.path.join(SCRIPT_PATH, "../data/vuln.yaml")
TMP_LOGCAT_PATH = '/sdcard/fuzzLogcat/tmp.logcat'
ON_POSIX = 'posix' in sys.builtin_module_names
PACKAGE_NAME = 'com.straw.strawfuzzer'
SYSTEM_CRASH_NEEDLEs = [
    '*** FATAL EXCEPTION IN SYSTEM PROCESS',
    '>>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<',
    'libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE)',
    ]
CRASH_NEEDLE = 'Data for crashing: '
STOP_NEEDLE = 'Data for stopping: '
PRINT_NEEDLE = 'Data for print: '
END_NEEDLE = 'Data for '

RUN_SUCCESS = 0
RUN_SUCCESS_CRASH = 1
RUN_FAIL = 2
RUN_INIT = RUN_FAIL
RUN_SKIP = 3
RUN_FAIL_APP_CRASH = 4

SKIP_NO = 0
SKIP_TO = 1
SKIP_SOME = 2
SKIP_ONLY = 3
SKIP_EXIST = 4
SKIP_DUP = 5
SKIP_VULN = 6

CONFIG = None

class MemInfo(object):
    @classmethod
    def get_meminfo(cls):
        selector = get_device_selector()
        execute_res = execute_wait(f"adb {selector} shell dumpsys meminfo system")
        if not execute_res:
            return None
        raw_info = codecs.decode(execute_res[0], 'utf-8', errors="ignore")
        return cls.parse_meminfo(raw_info)

    @classmethod
    def parse_meminfo(cls, raw_info):
        def get_number_next_to(text, needle):
            needle_idx = text.find(needle)
            if needle_idx < 0:
                return -1
            start_idx = needle_idx + len(needle)
            while text[start_idx] not in string.digits: start_idx += 1
            end_idx = start_idx
            while text[end_idx] in string.digits: end_idx += 1
            return int(text[start_idx: end_idx])
        pss = get_number_next_to(raw_info, 'TOTAL:')
        if -1 == pss:
            pss = get_number_next_to(raw_info, 'TOTAL PSS:')
        refs = get_number_next_to(raw_info, 'Death Recipients:')
        meminfo = MemInfo(pss, refs)
        return meminfo

    def __init__(self, pss, refs):
        self.pss = pss
        self.refs = refs

    def to_dict(self):
        return {
            'pss': self.pss,
            'refs': self.refs
        }

class MyLogger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log_path = os.path.join(SCRIPT_PATH, "../data/log")
        self.log = open(self.log_path, 'a+')
        self.lprint(f"-----------{datetime.now().strftime('%Y-%M-%D-%H:%M:%S')}-----------")

    def flush(self):
        self.terminal.flush()
        self.log.flush()

    def lprint(self, *args, **kwargs):
        if 'file' in kwargs:
            print(*args, **kwargs)
        else:
            kwargs['file'] = self.terminal
            print(*args, **kwargs)
            kwargs['file'] = self.log
            print(*args, **kwargs)
            self.log.flush()

L = MyLogger()

class LogP(object):
    def __init__(self):
        self.initialize()

    def initialize(self):
        self.selector = get_device_selector()
        self.lines = []
        self.fail_to = set()
        self.logAll = False
        self.closed = False
        self.no_clean = False
        self.q = Queue()
        self.start_logcat()
        self.start_thread()

    def clean(self):
        self.clean_logcat()
        self.clean_buf()

    def start_thread(self):
        self.t = threading.Thread(target=self._enqueue_output)
        self.t.daemon = True
        self.t.start()

    def start_logcat(self):
        self.p = subprocess.Popen(
            [f"adb {self.selector} logcat "],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            shell=True)

    def restart_logcat(self):
        self.p.kill()
        self.p.wait()
        self.start_logcat()

    def _enqueue_output(self):
        may_conflict = False
        lineset = None
        while not self.closed:
            try:
                line = self.p.stdout.readline()
                line = codecs.decode(line, "utf-8", errors="ignore")
                line = line.strip()
                if not line:
                    err_line = self.p.stderr.readline()
                    err_line = codecs.decode(err_line, "utf-8", errors="ignore")
                    err_line = err_line.strip()
                    if err_line:
                        L.lprint("[!] Logcat error " + err_line)
                        # restart the adb log
                        self.clean_logcat()
                        self.restart_logcat()
                        may_conflict = True
                        lineset = set(self.lines)
                    continue
                # L.lprint(line, flush=True)
                # if not self.logAll and suggest_system_crash(line):
                #     self.logAll = True
                if may_conflict:
                    if line in lineset:
                        continue
                    else:
                        may_conflict = False
                        lineset = None
                if self.logAll or 'Straw' in line or suggest_system_crash(line):
                    self.q.put(line)
                    self.lines.append(line)
            except Exception as e:
                L.lprint(e)

    def wait_for(self, message, timeout=-1):
        self.no_clean = True
        start_time = time.time()
        while timeout <= 0 or time.time() - start_time < timeout:
            line = self.readline()
            if not line:
                continue
            if message in line:
                self.no_clean = False
                return True
        self.no_clean = False
        return False

    def wait_for_all(self, messages, timeout=-1):
        self.no_clean = True
        start_time = time.time()
        occurs = [False for _ in messages]
        while timeout <= 0 or time.time() - start_time < timeout:
            line = self.readline()
            if not line:
                continue
            for i in range(len(messages)):
                if messages[i] in line:
                    occurs[i] = True
            if all(occurs):
                self.no_clean = False
                return True
        self.no_clean = False
        return False

    def wait_for_one(self, messages, timeout=-1):
        self.no_clean = True
        start_time = time.time()
        while timeout <= 0 or time.time() - start_time < timeout:
            line = self.readline()
            if not line:
                continue
            for i in range(len(messages)):
                if messages[i] in line:
                    self.no_clean = False
                    return i
        self.no_clean = False
        return -1

    def readline(self):
        try:
            line = self.q.get_nowait()
            self.handle_fail_to(line)
        except Empty:
            return None
        return line

    def handle_fail_to(self, line):
        if not line: return
        idx = line.find('Straw')
        if idx >= 0:
            if 'Fail to' in line:
                fail_to_msg = line[idx:].strip()
                if fail_to_msg not in self.fail_to:
                    L.lprint(fail_to_msg)
                    self.fail_to.add(fail_to_msg)

    def dumpLogcat(self, path, timeout=-1):
        start_time = time.time()
        while timeout <= 0 or time.time() - start_time < timeout:
            dt = self.get_dt(self.lines)
            if dt and get_dt_secs(dt) > start_time:
                break
            time.sleep(0.5)
        with open(path, 'w+') as f:
            f.write('\n'.join(self.lines))

    def dumpLog(self, path, timeout=-1):
        start_time = time.time()
        prev_size = 0
        fuzzLog = ''
        while timeout <= 0 or time.time() - start_time < timeout:
            dt = self.get_dt(self.lines)
            if dt and get_dt_secs(dt) > start_time:
                break
            time.sleep(0.5)
        for line in self.lines:
            if '!!!END' in line and (CRASH_NEEDLE in line or STOP_NEEDLE in line or PRINT_NEEDLE in line):
                break
            if CRASH_NEEDLE in line:
                fuzzLog += line[line.find(CRASH_NEEDLE) + len(CRASH_NEEDLE): ]
            elif STOP_NEEDLE in line:
                fuzzLog += line[line.find(STOP_NEEDLE) + len(STOP_NEEDLE): ]
            elif PRINT_NEEDLE in line:
                fuzzLog += line[line.find(PRINT_NEEDLE) + len(PRINT_NEEDLE): ]
        # time.sleep(3)
        with open(path, 'w+') as f:
            f.write(fuzzLog)

    @staticmethod
    def get_dt(lines):
        #09-16 14:38:30.640
        for i in range(len(lines)-1, -1, -1):
            line = lines[i]
            time_str = ' '.join(line.split(maxsplit=2)[:2]).split('.')[0]
            time_str = f'{datetime.now().year}-{time_str}'
            try:
                t = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
                return t
            except:
                continue
        return None

    def clean_logcat(self):
        if self.no_clean:
            return
        L.lprint("cleaning logcat")
        while True:
            cleanP = subprocess.Popen([f"adb {self.selector} logcat -c "], shell=True, stderr=subprocess.PIPE)
            cleanP.wait()
            err = codecs.decode(cleanP.communicate()[1], "utf-8", errors="ignore")
            for line in err.split('\n'):
                if 'failed to clear' in line:
                    continue
            break

    def clean_buf(self):
        self.lines.clear()
        self.fail_to.clear()
        for i in range(self.q.qsize()):
            self.q.get_nowait()

    def close(self):
        self.closed = True
        self.t.join()

def get_device_selector():
    config: dict = get_config()
    udid = config.get("udid", "") if config else ""
    selector = f'-s {udid}' if udid else ""
    return selector

def suggest_system_crash(s):
    for system_crash_needle in SYSTEM_CRASH_NEEDLEs:
        if system_crash_needle in s:
            return True
    return False

def sh_str_escape(s):
    return "'" + s.replace("(","\\(").replace(")","\\)").replace("<", "\\<").replace(">", "\\>").replace(" ", "\\ ").replace("$", "\\$").replace("*", "\\*") + "'"

def broadcast(action, kvs):
    count = 0
    while count < 3:
        es_lst = []
        for k, v in kvs.items():
            if isinstance(v, str):
                es_lst.append("--es")
                es_lst.append(k)
                es_lst.append(sh_str_escape(v))
            elif isinstance(v, bool):
                es_lst.append("--ez")
                es_lst.append(k)
                es_lst.append('true' if v else 'false')
            elif isinstance(v, int):
                es_lst.append("--ei")
                es_lst.append(k)
                es_lst.append(str(v))
        selector = get_device_selector()
        cmd = ' '.join(
            [f"adb {selector} shell am broadcast -a", sh_str_escape(action)] + es_lst
        )
        # L.lprint(cmd)
        try:
            res = subprocess.check_output([cmd], shell=True)
        except Exception:
            break
        if b'Broadcasting' in res:
            break
        else:
            time.sleep(0.5)
        count += 1

def get_dt_secs(dt):
    return (dt - datetime(1970, 1, 1)).total_seconds()

def get_curr_package():
    # Run #0: ActivityRecord{38d89a0 u0 com.android.quicksearchbox/.SearchActivity t216}
    selector = get_device_selector()
    cmd = f'adb {selector} shell dumpsys activity activities|grep -E ' + '"Run #|Hist #"'
    lines = codecs.decode(execute_wait(cmd)[0], 'utf-8', errors='ignore').split('\n')
    # lines = os.popen(cmd).readlines()
    if lines:
        for item in lines[0].strip().split():
            if '/' in item:
                packageName = item.split('/')[0]
                return packageName
    return ""

def start_app(logp=None, hookless=False, pkg=PACKAGE_NAME):
    selector = get_device_selector()
    while get_curr_package() == pkg:
        if hookless: break
        execute_wait(f'adb {selector} shell am force-stop {pkg}')
        time.sleep(1.0)
    while get_curr_package() != pkg:
        execute_wait(f"adb {selector} shell am start -n {pkg}/.MainActivity")
        time.sleep(2.0)
    if not hookless and logp:
        logp.wait_for("HookService Client connected", timeout=5.0)

def reboot(udid=""):
    broadcast("com.straw.strawfuzzer.Hook.XposedHook$RebootReceiver", {}, udid=udid)

def soft_reboot():
    selector = get_device_selector()
    execute_wait(f'adb {selector} shell su -c "killall zygote"')

def set_services(services):
    if isinstance(services, list):
        services = ','.join(services)
    kvs = {
        "services": services
    }
    broadcast("com.straw.strawfuzzer.UserCMDReceiver.SET_SERVICE", kvs)

def ensure_set_services(services, logp):
    while True:
        start_app(logp, True)
        set_services(services)
        if logp.wait_for("Set services to", timeout=5.0):
            break
        logp.restart_logcat()
    L.lprint("[+] Set services to " + services)

def get_services():
    selector = get_device_selector()
    xml_str = subprocess.check_output(f'adb {selector} shell su -c "cat /data/data/com.straw.strawfuzzer/shared_prefs/com.straw.strawfuzzer_preferences.xml"', shell=True)
    tree = ET.fromstring(xml_str)
    for ch in tree:
        if ch.tag == 'string' and ch.get('name') == 'services':
            return ch.text.split(',')
    return []

def fuzz(entrySignature, riskySignature, config):
    kvs = {
        "entrySignature": entrySignature,
        "riskySignature": riskySignature,
        "timeout": config['timeout'],
        "exploreTime": config['exploreTime'],
        "generate": config['generate'],
        "hookless": config['hookless']
    }

    broadcast('com.straw.strawfuzzer.UserCMDReceiver.START_FUZZING', kvs)

def ensure_fuzz(entrySignature, riskySignature, logp, config):
    status = True
    blocking_count = 0
    while True:
        logp.clean_logcat()
        if get_curr_package() != "com.straw.strawfuzzer":
            L.lprint("[.] Restarting app")
            start_app(logp, config['hookless'])
        fuzz(entrySignature, riskySignature, config)

        blocking_count += 1
        if blocking_count >= 7:
            L.lprint("[!] Fail to start fuzz")
            status = False
            break

        idx = logp.wait_for_one(['Start to fuzz on', 'Fail to fuzz on', 'HookService not ready'], timeout=10)
        if idx == 0:
            L.lprint("[+] Fuzzing started")
            break
        elif idx == 1:\
            L.lprint("[-] The signature can't be parsed")
        elif idx == 2:
            L.lprint("[-] HookService not ready")
            continue
        elif idx < 0:
            continue
    blocking_count = 0
    while status:
        L.lprint("[.] Waiting for fuzzing loop")
        blocking_count += 1
        if blocking_count >= 3:
            status = False
            L.lprint("[-] Fail to enter fuzzing loop")
            break
        if logp.wait_for('Fuzzing loop start', timeout=60):
            L.lprint("[+] Fuzzing loop started")
            break
    return status

def set_disable_hook(disable_hook):
    kvs = {"disable_hook": disable_hook}
    broadcast("com.straw.strawfuzzer.UserCMDReceiver.SET_DISABLE_HOOK", kvs)

def ensure_set_disable_hook(disable_hook, logp):
    while True:
        start_app(logp, True)
        set_disable_hook(disable_hook)
        if logp.wait_for("Set disable_hook to", timeout=5.0):
            break
    L.lprint(f"[+] Set disable_hook to {disable_hook}")

def set_disable_crash_hook(disable_crash_hook):
    kvs = {"disable_crash_hook": disable_crash_hook}
    broadcast("com.straw.strawfuzzer.UserCMDReceiver.SET_DISABLE_CRASH_HOOK", kvs)

def ensure_set_disable_crash_hook(disable_crash_hook, logp):
    while True:
        start_app(logp, True)
        set_disable_crash_hook(disable_crash_hook)
        if logp.wait_for("Set disable_hook to", timeout=5.0):
            break
    L.lprint(f"[+] Set disable_crash_hook to {disable_crash_hook}")

def stop():
    broadcast('com.straw.strawfuzzer.UserCMDReceiver.STOP_FUZZING', {})

def crash():
    broadcast('com.straw.strawfuzzer.Fuzz.Fuzzer$CrashStartReceiver', {})

def doprint():
    broadcast('com.straw.strawfuzzer.Fuzz.Fuzzer$DataPrintReceiver', {})

def prepare_fuzzing(logp=None, hookless=False):
    if hookless:
        return
    with open(os.path.join(SCRIPT_PATH, "prepare_fuzzing.sh"), 'r') as f:
        script = f.read()
    script = script.replace("adb ", f"adb {get_device_selector()} ")
    while True:
        # cmd = os.path.join(SCRIPT_PATH, "prepare_fuzzing.sh")
        execute_wait(script)
        # subprocess.check_output(cmd)
        # p = subprocess.Popen([cmd], shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        # p.wait()
        # if not logp or logp.wait_for("Registered CrashHandledReceiver", timeout=60.0):
        #     break
        if logp:
            logp.clean()
        break

def load_summary(path=SUMMARY_PATH):
    get_config()
    summary = {}
    try:
        with open(path) as f:
            summary = json.load(f)
    except IOError:
        pass
    for v in summary.values():
        scores = v['consumptionScores']
        for i, score in enumerate(scores):
            if score is None:
                scores[i] = 0
            elif type(score) == str:
                scores[i] = float(score)
    return summary

def execute_wait(cmd, timeout=60):
    p = subprocess.Popen([cmd], shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    try:
        p.wait(timeout=timeout)
    except:
        return None
    return p.communicate(timeout=timeout)

def prepare_static_info(static_info_path):
    selector = get_device_selector()
    execute_wait(f'adb {selector} push {static_info_path} /sdcard')
    static_info_file_name = os.path.basename(static_info_path)
    execute_wait(f'adb {selector} shell su -c "mv /sdcard/{static_info_file_name} /sdcard/static_info.json"')
    execute_wait(f'adb {selector} shell su -c "mv /sdcard/static_info.json /data/data/com.straw.strawfuzzer/static_info.json"')
    execute_wait(f'adb {selector} shell su -c "chmod a+r /data/data/com.straw.strawfuzzer/static_info.json"')

def get_config(path=CONFIG_PATH):
    global CONFIG
    if CONFIG: return CONFIG
    return load_config(path=path)

def load_config(path=CONFIG_PATH):
    global CONFIG, SUMMARY_PATH
    with open(path, 'r') as config_file:
        config = json.load(config_file)
    config['skip_exist'] = config.get('skip_exist', False)
    config['skip_vuln'] = config.get('skip_vuln', False)
    config['skip_to'] = (lambda e: (e[0], e[1]) if e else None)(config.get('skip_to'))
    config['skip_some'] = set(map(lambda e: (e[0], e[1]), config.get('skip_some', [])))
    config['only_some'] = set(map(lambda e: (e[0], e[1]), config.get('only_some', [])))

    summary_path = config.get('summary')
    if summary_path:
        SUMMARY_PATH = summary_path

    only_some = config.get('only_some')

    # Only test different serivices of different os version
    difference_infos = config.get('difference_infos')
    if difference_infos:
        run_pairs = load_difference(difference_infos[0])
        only_some.update(run_pairs)

    only_interesting = config.get('only_interesting', False)
    if only_interesting:
        config['skip_exist'] = False
        config['skip_to'] = None
        interesting = load_interesting(load_summary(), config['timeout'])
        config['only_some'] = interesting
        L.lprint("[+] There are {} interesting pairs".format(len(interesting)))
        if not interesting:
            return
    config['hookless'] = config.get('hookless', False)
    config['generate'] = config.get('generate', False)
    config['exploreTime'] = config.get('exploreTime', -1)

    CONFIG = config
    return config

def load_all_static_info(static_info_paths=None):
    if not static_info_paths:
        static_info_paths = load_config()['static_infos']
    static_info_paths = get_static_info_paths(static_info_paths)
    all_static_info = []
    for static_info_path in static_info_paths:
        static_info = load_static_info(static_info_path)
        all_static_info.extend(static_info)
    return all_static_info

def load_static_info(static_info_path):
    try:
        with open(static_info_path, 'r') as f:
            static_info = json.load(f)
        return static_info
    except IOError:
        return {}
    except json.JSONDecodeError as e:
        L.lprint(f"[!] Fail to load static_info {static_info_path} " + ' '.join(e.args))
        exit(0)

def load_real_vuln():
    try:
        with open(VULN_PATH, 'r') as f:
            return yaml.load(f)
    except IOError:
        return {}

def load_service_info():
    with open(SERVICE_INFO_PATH, 'r') as f:
        service_info_raw = json.load(f)
    service_info = {}
    for service_info_raw_one in service_info_raw:
        service_info[service_info_raw_one[0]] = service_info_raw_one
        service_info[service_info_raw_one[1]] = service_info_raw_one
        service_info[service_info_raw_one[2]] = service_info_raw_one
    return service_info

def get_service_name(method, service_info):
    className = method['Class']
    if className.endswith("$Proxy"):
        className = className.replace("$Proxy", "")
    if className in service_info:
        serviceName = service_info[className][0]
    else:
        serviceName = ""
    return serviceName

def get_service_method_map(static_info, service_info):
    service_method_map = {}
    for entry_method in static_info:
        entryMethod = parse_signature(entry_method['signature'])
        serviceName = get_service_name(entry_method, service_info)
        if serviceName:
            if serviceName not in service_method_map:
                service_method_map[serviceName] = []
            service_method_map[serviceName].append(entry_method)
        else:
            L.lprint("[!] Fail to find corresponding service for " + entryMethod['Class'] + ": " + entryMethod['Method'], flush=True)
            continue

    return service_method_map

def monitor_fuzz(logp, timeout):
    start_time = time.time()
    crashed = False
    prev_spent = 0
    prev_spent_for_app_crashed = 0
    app_crashed = False
    waiting_for_block = 0
    going_to_crash = False
    while True:
        spent = time.time() - start_time
        if spent >= timeout:
            break
        if spent - prev_spent > 0.5:
            prev_spent = spent
            L.lprint('\r({:.2f}/{}) '.format(spent, timeout), end='', file=sys.stdout)
        if spent - prev_spent_for_app_crashed > 3.0:
            prev_spent_for_app_crashed = spent
            if app_crashed:
                break
            if get_curr_package() != PACKAGE_NAME:
                # The app crashed
                if going_to_crash:
                    crashed = True
                app_crashed = True

        line = logp.readline()
        if not line:
            time.sleep(0.3)
            continue
        if 'JNI ERROR (app bug)' in line:
            crashed = True
            crash()
        elif 'Waiting for a blocking GC Alloc' in line:
            waiting_for_block += 1
        elif CRASH_NEEDLE in line:
            crashed = True
            break
        elif '----------------Before' in line:
            crashed = True
            crash()
        # currently disable this optimization
        # else:
        #     if waiting_for_block > 5:
        #         going_to_crash = True
        #         doprint()
        #     else:
        #         waiting_for_block = 0

    if not crashed and not app_crashed:
        stop()
    sys.stdout.write('\n')
    sys.stdout.flush()
    if not app_crashed:
        idx = logp.wait_for_one([PRINT_NEEDLE, STOP_NEEDLE, CRASH_NEEDLE], timeout=timeout/10)
    L.lprint("[+] End, crashed: {}, app_crashed: {} ... Dumping logs".format(crashed, app_crashed), flush=True)
    # Add to VULNS

    return crashed, app_crashed

def dump_check(logp, target_type, entrySignature, riskySignature, summary, meminfo_before, meminfo_after):
    entryMethod = parse_signature(entrySignature)
    riskyMethod = parse_signature(riskySignature)
    def getMethodStr(method):
        return method['Class'].replace('$', '.') + '.' + method['Method'].replace('$', '.') if method else 'unknown'
    basename = target_type + "-" + getMethodStr(entryMethod) + '-' + getMethodStr(riskyMethod)
    fuzzLogDir = os.path.join(SCRIPT_PATH, "../data/fuzzLog")
    if not os.path.exists(fuzzLogDir):
        os.mkdir(fuzzLogDir)
    fuzzLogcatPath = os.path.join(fuzzLogDir, basename + ".logcat")
    fuzzLogPath = os.path.join(fuzzLogDir, basename + ".log")
    fuzzLogDevicePath = os.path.join("/sdcard/fuzzLog", basename + ".log")

    logp.dumpLog(fuzzLogPath, timeout=10.0)
    logp.dumpLogcat(fuzzLogcatPath, timeout=5.0)

    time.sleep(1)
    if not os.path.exists(fuzzLogcatPath):
        L.lprint("[!] logcat not saved " + fuzzLogcatPath, flush=True)
    else:
        with open(fuzzLogcatPath, 'r') as f:
            if not f.read().strip():
                L.lprint("[!] logcat is empty " + fuzzLogcatPath, flush=True)
    if not os.path.exists(fuzzLogPath):
        L.lprint("[!] log not saved " + fuzzLogPath, flush=True)
    else:
        with open(fuzzLogPath, 'r') as f:
            s = f.read().strip()
            if not s:
                L.lprint("[!] log is empty " + fuzzLogPath, flush=True)
                return False
            else:
                try:
                    fuzzData = json.loads(s)
                    fuzzData['entry'] = entrySignature
                    fuzzData['risky'] = riskySignature
                    if meminfo_before and meminfo_after:
                        fuzzData['meminfo_before'] = meminfo_before.to_dict()
                        fuzzData['meminfo_after'] = meminfo_after.to_dict()
                    pair = (entrySignature, riskySignature)
                    entry_name = get_entry_name(target_type, pair)
                    summary[entry_name] = fuzzData
                except:
                    L.lprint("[!] log is invalid " + fuzzLogPath, flush=True)
                with open(SUMMARY_PATH, 'w+') as sf:
                    json.dump(summary, sf)
    return True

def initialize_service(service, logp, first_reboot, hookless):
    # initialize service
    logp.clean()

    # force reboot at the first time
    if not first_reboot or service not in get_services():
        ensure_set_services(service, logp)
        ensure_set_disable_hook(hookless, logp)
        prepare_fuzzing(logp, hookless)
        start_app(logp, hookless)
        # Reduce reboot overhead
    else:
        L.lprint("[+] Detected service " + service)
    L.lprint("[+] Start fuzzing service " + service)

def run_one(config, count, entrySignature, riskySignature, logp, summary):

    logp.clean()

    L.lprint("[{}] Fuzz on {} -- {} ... ".format(count, entrySignature, riskySignature), flush=True)

    # loop to confirm the fuzzing started
    status = ensure_fuzz(entrySignature, riskySignature, logp, config)
    meminfo_before = MemInfo.get_meminfo()
    if not status:
        return RUN_SKIP

    # Monitor fuzzing
    crashed, app_crashed = monitor_fuzz(logp, config['timeout'])
    meminfo_after = MemInfo.get_meminfo()

    dump_success = dump_check(logp, config['type'], entrySignature, riskySignature, summary, meminfo_before, meminfo_after)
    if dump_success:
        if crashed:
            VULNS.add(riskySignature)
            CRASHED.add((entrySignature, riskySignature))
            return RUN_SUCCESS_CRASH
        return RUN_SUCCESS
    elif app_crashed:
        return RUN_FAIL_APP_CRASH
    else:
        return RUN_FAIL

def parse_signatures(signatures):
    regex = "\\<(?P<Class>[\\w\\.\\$]+)\\s*:\\s*(?P<Ret>[\\w\\.\\$\\[\\]]+)\\s*(?P<Method>[\\w\\$\\<\\>]+)\\s*\\((?P<Params>[\\w\\.\\$,\\s\\[\\]]*)\\)\\s*\\>"
    res = []
    sigs = []
    for m in re.finditer(regex, signatures.strip()):
        if not m:
            return None
        e = {}
        e['Class'] = m.group('Class')
        e['Ret'] = m.group('Ret')
        e['Method'] = m.group('Method')
        e['Params'] = m.group('Params')
        res.append(e)
        sigs.append(m.group())
    return sigs, res

def parse_signature(signature):
    _, res = parse_signatures(signature)
    if res:
        return res[0]
    return None

warned_is_potential = False
def is_potential(v, use_lingress=True):
    global warned_is_potential
    avgScore = get_avg_score(v)
    consumptionScores = v['consumptionScores']
    result_potential = False
    var_score = get_var_score(v)
    result_potential = var_score > 40
    rootset_potential = 'changeSize' in v and v['sizeChange'] > 50

    score_potential = False
    lingress_not_supported = False
    if len(consumptionScores) > 2:
        if use_lingress:
            try:
                score_potential = get_consumption_slope(v) > 0.1
            except Exception as e:
                lingress_not_supported = True
                if not warned_is_potential:
                    print("[!] Warning: scipy not installed, use simple check")
                    warned_is_potential = True
        if not use_lingress or lingress_not_supported:
            score_potential = avgScore > 0.1 and len(consumptionScores) >= 10
    return score_potential or rootset_potential or result_potential

def get_consumption_slope(v):
    import scipy
    import scipy.stats as st
    # get relative memory usage
    consumptionScores = v['consumptionScores']
    y = [0]
    for score in consumptionScores:
        y.append(y[-1] + score)

    # remove outliers
    # new_y = [0]
    # ref = 0
    # for i in range(1, len(y)):
    #     if abs(y[i] - ref) > 100:
    #         continue
    #     else:
    #         new_y.append(y[i])
    #         ref = y[i]
    # y = new_y
    # if len(y) < 2:
    #     return 0

    x = scipy.arange(len(y))
    slope, intercept, r_value, p_value, std_err = st.linregress(x, y)
    return slope

def get_var_score(v):
    if 'meminfo_before' not in v or 'meminfo_after' not in v:
        return 0.0
    ma = v['meminfo_after']
    mb = v['meminfo_before']
    score = (ma['pss'] - mb['pss']) / 512 + (ma['refs'] - mb['refs']) / 100
    return score

def get_avg_score(v):
    consumptionScores = v['consumptionScores']
    if not consumptionScores:
        return 0
    sumScore = get_sum_score(v)
    avgScore = sumScore / len(consumptionScores)
    return avgScore

def get_sum_score(v):
    consumptionScores = v['consumptionScores']
    sumScore = 0
    for consumptionScore in consumptionScores:
        sumScore += consumptionScore if consumptionScore else 0
    return sumScore

VULNS = set()
def load_vulns(summary, force=False):
    if not force and VULNS:
        return VULNS
    for k, v in summary.items():
        if v['crashed']:
            if v['exploitationCount'] < sum(v['consumptionScores']) / 10:
                continue
            else:
                risky = v['risky']
                VULNS.add(risky)
    return VULNS

CRASHED = set()
def load_crashed(summary, force=False):
    if not force and CRASHED:
        return CRASHED
    for k, v in summary.items():
        if v['crashed']:
            pair = (v['entry'], v['risky'])
            CRASHED.add(pair)
    return CRASHED

def load_interesting(summary, timeout):
    interesting = set()
    for k, v in summary.items():
        crashed = v['crashed']
        if not crashed and is_potential(v):
            # if v['duration'] < timeout * 5 * 1000:
                interesting.add((v['entry'], v['risky']))
    return interesting

def get_entry_name(prefix, pair):
    return "{}-{}-{}".format(prefix, pair[0], pair[1])

skip_to_already = False
def should_skip(config, pair, summary, visited):
    global skip_to_already
    skip_to = config['skip_to']
    skip_some = config['skip_some']
    only_some = config['only_some']
    skip_exist = config['skip_exist']
    skip_vuln = config['skip_vuln']

    wild_entry_pair = ('*', pair[1])
    wild_risky_pair = (pair[0], '*')
    if pair in visited:
        return SKIP_DUP
    if not skip_to_already:
        if skip_to and pair != skip_to and wild_entry_pair != skip_to and wild_risky_pair != skip_to:
            return SKIP_TO
        else:
            skip_to_already = True
    if skip_some and ((pair in skip_some) or (wild_entry_pair in skip_some) or (wild_risky_pair in skip_some)):
        return SKIP_SOME
    if only_some and ((pair not in only_some) and (wild_entry_pair not in only_some) and (wild_risky_pair not in only_some)):
        return SKIP_ONLY
    if skip_exist:
        entry_name = get_entry_name(config['type'], (pair[0], pair[1]))
        if entry_name in summary:
            return SKIP_EXIST
    if skip_vuln and pair[1] in load_vulns(summary):
        return SKIP_VULN
    return SKIP_NO

def run_pair(config, entrySignature, riskySignature, logp, count, summary):
    MAX_FAIL_COUNT = 3
    fail_count = 0
    runStat = RUN_INIT
    while runStat == RUN_INIT or runStat == RUN_FAIL:
        try:
            if fail_count >= MAX_FAIL_COUNT:
                print("[-] Fail and drop")
                break
            runStat = run_one(config, count, entrySignature, riskySignature, logp, summary)
            if runStat == RUN_FAIL or runStat == RUN_FAIL_APP_CRASH:
                if runStat == RUN_FAIL_APP_CRASH:
                    soft_reboot()
                start_app(logp, config['hookless'])
                fail_count += 1
                continue
        except KeyboardInterrupt:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            sys.exit()
        except Exception as e:
            print("[-] during fuzzing " + str(e))
            fail_count += 1
            continue
        break
    return runStat

def get_static_info_paths(raw_static_info_paths):
    static_info_paths = []
    for static_info_path in raw_static_info_paths:
        try:
            if static_info_path.endswith('*'):
                static_info_path = static_info_path.replace('*', '')
                for filename in os.listdir(static_info_path):
                    if filename.endswith('.json'):
                        static_info_paths.append(os.path.join(static_info_path, filename))
            else:
                static_info_paths.append(static_info_path)
        except: pass
    static_info_paths = list(map(os.path.realpath, static_info_paths))
    static_info_paths.sort()
    return static_info_paths

def get_pair_risky_set(static_info_path):
    pair_set = set()
    risky_set = set()
    static_info = load_static_info(static_info_path)
    for entry in static_info:
        if 'riskyMethods' not in entry:
            pair_set.add((entry['signature'], entry['signature']))
            risky_set.add(entry['signature'])
            continue
        for risky in entry['riskyMethods']:
            pair = (entry['signature'], risky['signature'])
            pair_set.add(pair)
            risky_set.add(risky['signature'])
    return pair_set, risky_set

def print_static_info_summary(static_info_path, visited):
    pair_set, risky_set = get_pair_risky_set(static_info_path)
    pair_set = pair_set - visited
    print("[+] There are {} new pairs and {} risky methods in {}".format(len(pair_set), len(risky_set), static_info_path))

def print_static_infos_summary(static_info_paths, service_info):
    pair_set = set()
    risky_set = set()
    for static_info_path in static_info_paths:
        sub_pair_set, sub_risky_set = get_pair_risky_set(static_info_path)
        pair_set.update(sub_pair_set)
        risky_set.update(sub_risky_set)
    print("[+] There are {} pairs and {} risky methods in total".format(len(pair_set), len(risky_set)))

def auto_run(config):
    service_info = load_service_info()

    summary = load_summary()
    count = 0
    logp = LogP()

    static_info_paths = get_static_info_paths(config['static_infos'])
    print_static_infos_summary(static_info_paths, service_info)

    visited = set()
    for static_info_path in static_info_paths:
        static_info_parepared = False
        first_reboot = False
        static_info = load_static_info(static_info_path)
        service_method_map = get_service_method_map(static_info, service_info)

        print_static_info_summary(static_info_path, visited)

        for service, entry_method_entries in service_method_map.items():
            service_initialized = False
            # Fuzzing on each interface method
            for entry_method_entry in entry_method_entries:
                entrySignature = entry_method_entry['signature']
                if not entry_method_entry.get('riskyMethods'):
                    riskySignatures = ['*']
                else:
                    riskySignatures = list(map(lambda e: e['signature'], entry_method_entry['riskyMethods']))
                for riskySignature in riskySignatures:
                    # check skip
                    pair = (entrySignature, riskySignature)
                    if not should_skip(config, pair, summary, visited):
                        if not static_info_parepared:
                            prepare_static_info(static_info_path)
                            static_info_parepared = True
                        if not service_initialized and not config['hookless']:
                            initialize_service(service, logp, first_reboot, False)
                            first_reboot = True
                            service_initialized = True
                        runStatus = run_pair(config, entrySignature, riskySignature, logp, count, summary)
                        # Force reboot because the crash may no be really triggered
                        if runStatus == RUN_SUCCESS_CRASH:
                            service_initialized = False
                    count += 1
                    visited.add(pair)

def load_difference(difference_info_file):
    new_pairs = set()
    with open(difference_info_file, 'r') as diff_info_file:
        diff_info = json.load(diff_info_file)
        all_diff_pairs = diff_info["AllNewPairs"]
        for risky_method in all_diff_pairs.keys():
            for interface in all_diff_pairs[risky_method]:
                new_pairs.add((interface,risky_method))
    return new_pairs

def main():
    config = load_config()

    only_interesting = config['only_interesting']
    if only_interesting:
        config['timeout'] *= 10
        interesting = config['only_some']
        if not interesting:
            return
        L.lprint("[+] There are {} interesting pairs".format(len(interesting)))

    auto_run(config)

if __name__ == '__main__':
    main()


import os.path as osp
import numpy as np
import time
import torch

import os
os.environ['CUDA_VISIBLE_DEVICES'] = "1"

import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
import torch_geometric.transforms as T
from gcn import GCN_PYG

import ctypes

_cudart = ctypes.CDLL('libcudart.so')

def cu_prof_start():
  ret = _cudart.cudaProfilerStart()
  if ret != 0:
    raise Exception('cudaProfilerStart() returned %d' % ret)

def cu_prof_stop():
  ret = _cudart.cudaProfilerStop()
  if ret != 0:
    raise Exception('cudaProfilerStop() returned %d' % ret)

t0 = time.time()

dataset = 'Pubmed'
path = osp.join(osp.dirname(osp.realpath(__file__)), '..', 'data', dataset)
dataset = Planetoid(path, dataset,transform=T.NormalizeFeatures())
data = dataset[0]

print("data load time: {:.4f}\n".format(time.time()-t0))

'''
gdc = T.GDC(self_loop_weight=1, normalization_in='sym',
                normalization_out='col',
                diffusion_kwargs=dict(method='ppr', alpha=0.05),
                sparsification_kwargs=dict(method='topk', k=128,
                                           dim=0), exact=True)
data = gdc(data)
'''

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print("cuda: \n",torch.cuda.is_available())

in_feats, n_classes = dataset.num_features,dataset.num_classes
model, data = GCN_PYG(in_feats, n_classes).to(device), data.to(device)

total_param = 0
print("MODEL DETAILS:\n")
# print(model)
for param in model.parameters():
    # print(param.data.size())
    total_param += np.prod(list(param.data.size()))
print('MODEL/Total parameters:',total_param)

optimizer = torch.optim.Adam(model.parameters(), weight_decay=5e-4, lr=0.01)  # Only perform weight-decay on first convolution.

x, edge_index, edge_weight = data.x, data.edge_index, data.edge_attr

print(edge_index)

def train():
    model.train()
    optimizer.zero_grad()
    F.nll_loss(model(x, edge_index, edge_weight)[data.train_mask], data.y[data.train_mask]).backward()
    optimizer.step()

@torch.no_grad()
def test():
    model.eval()
    logits, accs = model(x, edge_index, edge_weight), []
    for _, mask in data('train_mask', 'val_mask', 'test_mask'):
        pred = logits[mask].max(1)[1]
        acc = pred.eq(data.y[mask]).sum().item() / mask.sum().item()
        accs.append(acc)
    return accs

dur = []
best_val_acc = test_acc = 0

for epoch in range(1, 201):
    if epoch >= 3:
        t1 = time.time()
    #flag = False
    #if flag:

    #flag = True

    #if  epoch == 100:
        #cu_prof_start()

    model.train()
    loss = F.nll_loss(model(x, edge_index, edge_weight)[data.train_mask], data.y[data.train_mask])
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    #if epoch == 100:
       # cu_prof_stop()

    if epoch >= 3:
        dur.append(time.time() - t1)
    train_acc, val_acc, test_acc = test()

    log = 'Epoch: {:03d}, Train: {:.4f}, Val: {:.4f}, Test: {:.4f}, Time: {:.4f}'
    print(log.format(epoch, train_acc, val_acc, test_acc, np.mean(dur)))

print("total time: {:.4f}\n".format(time.time()-t0))


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from targets.firefox.fx_testcase import *

class Test(FirefoxTest):

    @pytest.mark.details(
        description='Open a bookmark with drag&drop from Library',
        locale=['en-US'],
        test_case_id='169271',
        test_suite_id='2525'
    )
    def run(self, firefox):
        soap_wiki_tab_pattern = Pattern('soap_wiki_tab.png')
        wiki_bookmark_logo_pattern = Pattern('wiki_bookmark_logo.png')

        home_width, home_height = NavBar.HOME_BUTTON.get_size()
        tabs_region = Region(0, 0, Screen.SCREEN_WIDTH, home_height * 4)

        centre_location = Location(Screen.SCREEN_WIDTH/2, Screen.SCREEN_HEIGHT/4)

        navigate(LocalWeb.SOAP_WIKI_TEST_SITE)

        soap_wiki_opened = exists(soap_wiki_tab_pattern, FirefoxSettings.FIREFOX_TIMEOUT*3, tabs_region)
        assert soap_wiki_opened is True, 'The test page is opened'

        bookmark_page()

        stardialog_displayed = exists(Bookmarks.StarDialog.DONE, FirefoxSettings.FIREFOX_TIMEOUT)
        assert stardialog_displayed is True, 'StarDialog displayed'

        click(Bookmarks.StarDialog.DONE)

        new_tab()

        previous_tab()

        close_tab()

        open_library()

        drag_drop(Library.TITLE, centre_location, duration=FirefoxSettings.FIREFOX_TIMEOUT*0.3)

        library_opened = exists(Library.TITLE, FirefoxSettings.FIREFOX_TIMEOUT)
        assert library_opened is True, 'Library opened'

        click(Library.OTHER_BOOKMARKS)

        bookmark_exists = exists(wiki_bookmark_logo_pattern)
        assert bookmark_exists is True, 'Previously added bookmark exists in Library'

        drag_drop(soap_wiki_tab_pattern, LocationBar.SEARCH_BAR, duration=FirefoxSettings.FIREFOX_TIMEOUT*0.3)

        soap_wiki_opened_from_bookmarks = exists(soap_wiki_tab_pattern, FirefoxSettings.FIREFOX_TIMEOUT*3, tabs_region)
        assert soap_wiki_opened_from_bookmarks is True, 'The test page is opened with drag and drop from Library'

        open_library()

        click(Library.TITLE)

        close_window_control('auxiliary')


import requests
import json
import pathlib

def getContracts(slug, apiKey):
    url = "https://api.footprint.network/api/v1/protocol/{slug}/contract".format(
        slug=slug)
    print("url: ", url)
    headers = {
        "accept": "application/json",
        "API-KEY": apiKey
    }
    # print(headers["API-KEY"])
    # print("API-KEY: " ,apiKey)

    path = pathlib.Path('./log/{slug}.json'.format(slug=slug))
    if path.is_file() :
        result = ''
        with open('./log/{slug}.json'.format(slug=slug)) as fr:
            result = json.load(fr)
        # 如果已经存在并且成功获取过，则跳过
        if result["message"]=="success":
            return "already found"
    response = requests.get(url, headers=headers)
    data = json.loads(response.text)
    f = open('./log/{slug}.json'.format(slug=slug),'w',encoding='utf-8')
    json.dump(data,f) # 写入
    f.close()
    # print(data['data'][0])
    empty = []
    try:
        all = data['data']

        # d0 = data['data'][0]
        # print(d0['chain'])
        size = len(all)
        print("contract number: ", size)
        return all
    except:
        print(Exception)
        return empty

    return all

if __name__ == '__main__':
    slug = "mobox"
    getContracts(slug=slug)


from rest_framework.viewsets import ModelViewSet
from rest_framework.views import Response
from rest_framework.status import (
    HTTP_201_CREATED,
    HTTP_204_NO_CONTENT,
    HTTP_400_BAD_REQUEST,
    HTTP_404_NOT_FOUND
)
from rest_framework.decorators import action
from apps.financeiro.models import Venda, ItemVenda
from apps.financeiro.serializers import VendaSerializer, ItemVendaSerializer
from apps.financeiro.services import VendaServices
from apps.utilities.choices import FORMA_PAGAMENTO_CHOICES

class VendaViewSet(ModelViewSet):
    serializer_class = VendaSerializer
    class_model = Venda
    class_services = VendaServices

    def get_queryset(self):
        return self.class_model.objects.filter(
            finalizada=True,
            forma_pagamento__in=[
                FORMA_PAGAMENTO_CHOICES[1][0],
                FORMA_PAGAMENTO_CHOICES[2][0],
                FORMA_PAGAMENTO_CHOICES[3][0]
            ]
        )

    @action(methods=['get'], detail=True, url_path='itens_venda')
    def get_listar_itens_venda(self, request, *args, **kwargs):
        queryset = ItemVenda.objects.filter(venda=kwargs.get('pk'))
        serializer = ItemVendaSerializer(queryset, many=True)

        return Response(serializer.data)

    @action(methods=['put'], detail=True, url_path='criar_item_venda')
    def criar_item_para_venda(self, request, *args, **kwargs):
        error = {'msg': 'Produto não existe no sistema.'}
        data = request.data.copy()

        services = self.class_services(data=request.data.copy())

        if not services.nao_existe_produto_origem():
            return Response(error, status=HTTP_404_NOT_FOUND)

        produto = services.get_produto()
        has_quantidade = services.verificar_quantidade(produto)

        if has_quantidade >= 0:
            data.pop('produto_origem')

            item_venda = ItemVendaSerializer(data=data)
            item_venda.is_valid(raise_exception=True)

            self.perform_create(item_venda)

            services.atualizar_estoque(produto)

            headers = self.get_success_headers(item_venda.data)

            return Response(
                data=item_venda.data,
                status=HTTP_201_CREATED,
                headers=headers
            )

        return Response(
            data={'msg': 'Quantidade insufíciente no estoque.'},
            status=HTTP_400_BAD_REQUEST
        )

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()

        if instance.item_venda_venda.all().exists():
            return Response(
                {'msg': 'Impossível excluir venda com itens vinculados a ela.'},
                HTTP_400_BAD_REQUEST
            )

        return super().destroy(request, *args, **kwargs)

    @action(methods=['delete'], detail=True, url_path='excluir_item')
    def excuilr_item(self, request, *args, **kwargs):
        instance = ItemVenda.objects.get(pk=kwargs.get('pk'))

        self.perform_destroy(instance)

        return Response(status=HTTP_204_NO_CONTENT)

    @action(methods=['put'], detail=True, url_path='concluir_venda')
    def concluir_venda(self, request, *args, **kwargs):
        instance = self.class_model.objects.get(pk=kwargs.get('pk'))

        serializer = self.serializer_class(
            instance,
            data=request.data,
            partial=True
        )
        serializer.is_valid(raise_exception=True)

        self.perform_update(serializer)

        return Response(serializer.data)


import io
import base64
import logging
from reportlab.pdfbase import pdfmetrics, ttfonts
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from PyPDF2 import PdfFileWriter, PdfFileReader
from odoo import fields, models
from io import BytesIO
from PIL import Image, ImageFont, ImageDraw
import os
from .config import FLAGS

_logger = logging.getLogger(__name__)

class IrHttp(models.AbstractModel):
    _inherit = 'ir.http'

    def binary_content(self, *args, **kwargs):
        """附件上传时候不添加水印，只有下载时候添加"""
        status, headers, content = super(IrHttp, self).binary_content(*args, **kwargs)
        content_type = dict(headers).get('Content-Type')
        download = kwargs.get('download')

        # 给PDF添加水印
        if content_type == 'application/pdf' and download == 'true':
            content = self.add_watermark(base64.b64decode(content))
            content = base64.b64encode(content)

        # 给图片添加水印
        if content_type in ['image/png', 'image/jpeg'] and download == 'true':
            stream = self.image_add_watermark(base64.b64decode(content))
            content = base64.b64encode(stream)
        return status, headers, content

    def _generate_watermark(self):
        """
        pdf生成水印
        :return:
        """
        # 水印文件临时存储路径
        filename = f'watermark.pdf'
        design_id = self.env['watermark.design.order'].search([('create_uid', '=', self.env.user.id)],
                                                              limit=1, order='create_date DESC')
        font_txt = f'{self.env.user.name} {self.env.company.name} {fields.Date.context_today(self)}'
        font_color = '#d21717'
        font_size = 30
        if design_id:
            font_size = design_id.font_size
            font_txt = f'%s' % design_id.name
            font_color = '%s' % design_id.colorpicker
            if design_id.show_date:
                font_txt = f'%s %s' % (font_txt, fields.Date.context_today(self))
        watermark = font_txt
        # 获取画布并修改原点坐标
        c = canvas.Canvas(filename)
        # translate设置水印起始位置：translate(x, y)：x约小越 y越大约上
        c.translate(-10 * cm, 8 * cm)
        try:
            font_name = 'SimSun'
            # 从系统路径中引入中文字体(新宋)
            f_name = 'SimSun.ttf'
            font_path = os.path.join(FLAGS.model_dir, f_name)
            pdfmetrics.registerFont(ttfonts.TTFont(font_name, font_path))
        except Exception as e:
            # 默认字体，不支持中文
            font_name = 'Helvetica'
            _logger.error(f'Register Font Error: {e}')
        # 设置字体及大小，旋转 -20 度并设置颜色和透明度
        c.setFont(font_name, font_size)

        # 旋转角度
        c.rotate(-20)
        # 设置填充颜色
        c.setFillColor(font_color, 0.30)
        # 平铺写入水印，(0, 30, 15) 其中15是指的文字字间距
        for i in range(0, 30, 15):
            for j in range(0, 30, 5):
                c.drawString(i * cm, j * cm, watermark)
        c.save()
        return filename

    def add_watermark(self, content):
        """
        PDF添加水印功能
        :param content:
        :return:
        """
        watermark = self._generate_watermark()
        pdf_input = PdfFileReader(io.BytesIO(content), strict=False)
        watermark = PdfFileReader(open(watermark, "rb"), strict=False)
        pdf_output = PdfFileWriter()
        page_count = pdf_input.getNumPages()
        for page_number in range(page_count):
            input_page = pdf_input.getPage(page_number)
            input_page.mergePage(watermark.getPage(0))
            pdf_output.addPage(input_page)
        stream = io.BytesIO()
        pdf_output.write(stream)
        data = stream.getvalue()
        return data

    def image_add_watermark(self, content):
        """
        给图片添加水印
        :param content:
        :return:
        """
        # 水印内容 和 字体
        design_id = self.env['watermark.design.order'].search(
            [('create_uid', '=', self.env.user.id)], limit=1, order='create_date DESC')
        font_txt = f'{self.env.user.name} {self.env.company.name} {fields.Date.context_today(self)}'
        font_color = '#d21717'
        font_size = 20
        if design_id:
            font_size = design_id.font_size
            font_txt = f'%s' % design_id.name
            font_color = '%s' % design_id.colorpicker
            if design_id.show_date:
                font_txt = f'%s %s' % (font_txt, fields.Date.context_today(self))
        image_name = 'SimSun.ttf'
        font_path = os.path.join(FLAGS.model_dir, image_name)
        font = ImageFont.truetype(font_path, font_size)
        # 二进制流图片内容
        image = Image.open(BytesIO(content)).convert('RGBA')
        # 添加背景
        new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (0, 0, 0, 0))
        new_img.paste(image, image.size)

        # 添加水印
        font_len = len(font_txt)
        rgba_image = new_img.convert('RGBA')
        text_overlay = Image.new('RGBA', rgba_image.size, (255, 255, 255, 0))
        image_draw = ImageDraw.Draw(text_overlay)
        for i in range(0, rgba_image.size[0], font_len * 15 + 150):
            for j in range(0, rgba_image.size[1], 100):
                # draw.text #设置文字位置/内容/颜色/字体
                image_draw.text((i, j), font_txt, font_color, font=font)
        text_overlay = text_overlay.rotate(-20)
        # 合并原图与文字图片
        out = Image.alpha_composite(rgba_image, text_overlay)
        # 裁切图片
        out = out.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2))
        out = out.convert('RGB')
        stream = io.BytesIO()
        out.save(stream, format="PNG")
        data = stream.getvalue()
        return data


#    0  1  2  3  4  5  6  7  8  9  10
A = [64,25,12,22,11,37,98,47,58,20,98]

'''
Selection Sort O(n^2)
'''
def selectionSort(nums):
    for i in range(len(nums)-1):
        minValue_idx = i
        for j in range(i+1,len(nums)):
            if nums[j] < nums[minValue_idx]:
                minValue_idx = j
        nums[i], nums[minValue_idx] = nums[minValue_idx], nums[i]
    return nums

'''
Bubble Sort O(n^2) min -> max
'''

def bubbleSort(nlist):
    for passnum in range(len(nlist)-1,0,-1):
        for i in range(passnum):
            if nlist[i]>nlist[i+1]:
                temp = nlist[i]
                nlist[i] = nlist[i+1]
                nlist[i+1] = temp

'''
Insertion Sort
'''
def insertionSort(arr):

    # Traverse through 1 to len(arr)
    for i in range(1, len(arr)):

        key = arr[i]

        # Move elements of arr[0..i-1], that are
        # greater than key, to one position ahead
        # of their current position
        j = i-1
        while j >=0 and key < arr[j] :
                arr[j+1] = arr[j]
                j -= 1
        arr[j+1] = key

'''
Linear Search
'''

def linearSearch(arr,n):
    for i in range(len(arr)):
        if arr[i] == n:
            return i+1
    return -1

'''
# Merge Sort

def mergeSort(alist):
    print("Splitting ",alist)
    if len(alist)>1:
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]

        mergeSort(lefthalf)
        mergeSort(righthalf)

        i=0
        j=0
        k=0
        while i < len(lefthalf) and j < len(righthalf):
            if lefthalf[i] < righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                alist[k]=righthalf[j]
                j=j+1
            k=k+1

        while i < len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1

        while j < len(righthalf):
            alist[k]=righthalf[j]
            j=j+1
            k=k+1
    print("Merging ",alist)

alist = [54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)

'''

'''
Binary Search
'''

def binarySearch(alist, item):
	first = 0
	last = len(alist)-1
	while first<=last:
	    midpoint = (first + last)//2
	    if alist[midpoint] == item:
	        return midpoint
	    else:
	        if item < alist[midpoint]:
	            last = midpoint-1
	        else:
	            first = midpoint+1

# for i in range(len(A)):
#     print("%d" %A[i])


from numpy import amax, inf, log, mean, prod, sqrt, sum, take

def shrink(arr, factor):

    n = len(arr)
    assert n % factor == 0
    data = arr.reshape(int(n / factor), factor)
    return data.sum(axis=1) / factor

def error_norms(arr, exact):

    n = len(arr)
    diff = arr - shrink(exact, int(len(exact) / n))

    ε1 = sum(abs(diff)) / n
    ε2 = sqrt(sum(diff**2) / n)
    εinf = amax(abs(diff))

    return ε1, ε2, εinf

def rate(ε1, ε2, n1, n2):
    return log(ε2 / ε1) / log(n1 / n2)

def convergence_rate(NDIM, exact1, exact2, results1, results2, L=2, var=0):

    if results1.ndim > NDIM:
        diff1 = take(results1 - exact1, var, axis=-1)
        diff2 = take(results2 - exact2, var, axis=-1)
    else:
        diff1 = results1 - exact1
        diff2 = results2 - exact2

    n1 = prod(diff1.shape[:NDIM])
    n2 = prod(diff2.shape[:NDIM])

    if L == 1:
        ε1 = sum(abs(diff1)) / n1
        ε2 = sum(abs(diff2)) / n2
    elif L == 2:
        ε1 = sqrt(sum(diff1**2) / n1)
        ε2 = sqrt(sum(diff2**2) / n2)
    elif L == inf:
        ε1 = amax(abs(diff1))
        ε2 = amax(abs(diff2))

    print(ε1)
    print(ε2)
    return rate(ε1, ε2, n1, n2)

def reduce(u, n):
    """ averages cell values of u to produce array of length n
    """
    N = int(len(u) / n)
    return mean(u.reshape([n, N, -1]), axis=1)


import json
import logging
import os
from functools import partial
from pathlib import Path
from typing import Optional

from mpu.card_market_client import (CardMarketClient, get_conditions,
                                    get_language_id)

logger = logging.getLogger(__name__)

def get_market_extract_path(market_extract_parent_path: Path) -> Path:
    _market_extract_path = market_extract_parent_path / "market_extract"
    try:
        os.mkdir(str(_market_extract_path))
    except FileExistsError:
        pass

    return _market_extract_path

def save_market_extract(
    product_market_extract: dict, market_extract_path: Path, product_id: int
) -> None:
    logger.info(f"Saving market extract for {product_id}.")
    with (market_extract_path / f"{product_id}.json").open("w") as product_file:
        json.dump(obj=product_market_extract, fp=product_file)

def add_foil_articles_if_needed(
    market_extract: dict,
    stock_info: dict,
    card_market_client: CardMarketClient,
    config: dict,
    max_results: int = 50,
):
    if market_extract.get("articles_foil") is not None or stock_info["Foil?"] == "":
        return market_extract

    _config = config.copy()
    _config["max_results"] = {k: max_results for k, v in _config["max_results"].items()}
    _config["default_max_results"] = max_results

    return {
        **market_extract,
        **{
            "articles_foil": get_product_articles_language_and_conditions(
                card_market_client=card_market_client,
                stock_info=stock_info,
                config=_config,
                foil=True,
            )
        },
    }

def get_product_articles_from_card_market_with_languages(
    stock_info: dict,
    card_market_client: CardMarketClient,
    config: dict,
    min_condition: str,
    foil: Optional[bool] = None,
):
    product_id = stock_info["idProduct"]

    languages_names = config.get("languages")
    if languages_names is None:
        return card_market_client.get_product_articles(
            product_id=product_id,
            min_condition=min_condition,
            max_results=config.get("default_max_results"),
            foil=foil,
        )

    # Case of multiple requests per language
    articles = []

    language_ids = [
        get_language_id(language) if language != "CARD" else stock_info["Language"]
        for language in languages_names
    ]
    # Removing duplicated languages
    language_ids = list(set(language_ids))

    for language_name, language_id in zip(languages_names, language_ids):
        max_results = config.get("max_results").get(
            language_name, config.get("default_max_results")
        )
        articles.extend(
            card_market_client.get_product_articles(
                product_id=product_id,
                min_condition=min_condition,
                max_results=max_results,
                language_id=language_id,
                foil=foil,
            )
        )

    return articles

def get_product_articles_language_and_conditions(
    stock_info: dict,
    card_market_client: CardMarketClient,
    config: dict,
    foil: Optional[bool] = None,
):
    if not config.get("one_request_per_condition", False):
        return get_product_articles_from_card_market_with_languages(
            stock_info=stock_info,
            card_market_client=card_market_client,
            config=config,
            min_condition=config["min_condition"],
            foil=foil,
        )

    # Case of multiple requests per condition
    product_articles = []

    for condition in get_conditions(config["min_condition"]):
        product_articles.extend(
            get_product_articles_from_card_market_with_languages(
                stock_info=stock_info,
                card_market_client=card_market_client,
                config=config,
                min_condition=condition,
                foil=foil,
            )
        )

    return product_articles

def get_market_extract_from_card_market(
    stock_info: dict,
    card_market_client: CardMarketClient,
    market_extract_path: Path,
    config: dict,
):
    product_id = stock_info["idProduct"]

    product_market_extract = {
        "articles": get_product_articles_language_and_conditions(
            stock_info=stock_info, card_market_client=card_market_client, config=config
        ),
        "info": card_market_client.get_product_info(product_id=product_id),
    }
    add_foil_articles_if_needed(
        card_market_client=card_market_client,
        stock_info=stock_info,
        market_extract=product_market_extract,
        config=config,
        max_results=50,
    )

    save_market_extract(
        product_market_extract=product_market_extract,
        product_id=product_id,
        market_extract_path=market_extract_path,
    )

    return product_market_extract

def get_single_product_market_extract(
    stock_info: dict,
    market_extract_path: Path,
    card_market_client: CardMarketClient,
    config: dict,
    force_update: bool = False,
) -> dict:
    """Get a product price from the local file if possible, otherwise from the API"""
    product_id = stock_info["idProduct"]

    single_product_market_extract_path = market_extract_path / f"{product_id}.json"
    _get_market_extract_from_card_market = partial(
        get_market_extract_from_card_market,
        stock_info=stock_info,
        market_extract_path=market_extract_path,
        card_market_client=card_market_client,
        config=config,
    )

    if force_update:
        return _get_market_extract_from_card_market()

    try:
        with single_product_market_extract_path.open("r") as product_prices_file:
            product_market_extract = json.load(fp=product_prices_file)
    except FileNotFoundError:
        return _get_market_extract_from_card_market()

    new_product_market_extract = add_foil_articles_if_needed(
        card_market_client=card_market_client,
        stock_info=stock_info,
        market_extract=product_market_extract,
        config=config,
        max_results=50,
    )
    if new_product_market_extract != product_market_extract:
        save_market_extract(
            product_market_extract=new_product_market_extract,
            product_id=product_id,
            market_extract_path=market_extract_path,
        )

    return product_market_extract


from django.shortcuts import render,get_object_or_404
from curriculo.models import Curso, Disciplina, DisciplinaOfertada
from datetime import datetime

def curso(request, sigla):
    curso = get_object_or_404(Curso, sigla=sigla)
    curso.semestres = [
        'Semestre 2',
    ]
    ano = datetime.now().year
    sem_corrente = 1 if datetime.now().month <=6 else 2
    disciplinas = DisciplinaOfertada.objects.filter(ano=ano,semestre=sem_corrente,curso=curso)

    context = {
        "curso": curso,
        "disciplinas_ofertadas": disciplinas
    }

    return render(request, "curriculo/curso.html", context)

def disciplina(request,sigla,sigla_disciplina):
    context = {}
    disciplina = Disciplina.objects.get(identificador=sigla_disciplina)
    context = {
        "disciplina": disciplina
    }

    return render(request, "curriculo/disciplina.html", context)


# -*- coding:UTF-8 -*-
"""
-------------------------------------------------
   File Name：     SoldHouseCrawler.py
   Description :   to crawler sold house from http://house.ksou.cn/p.php
   Author :       elvisfang
   date：          2017/8/2
-------------------------------------------------
   Change Activity:
                   2017/8/2:
-------------------------------------------------
"""
__author__ = 'elvisfang'

import basecrawler
import time
from Database import MongoDBClient
from bs4 import BeautifulSoup
import re
from Log import logger

class SoldhouseCrawler():

    __crawl_url = 'http://house.ksou.cn/p.php'
    __porxy_enabled = False

    def __init__(self, proxy_enable=False):
        self.__proxy_enabled = proxy_enable
        self.__crawler = basecrawler.BaseCrawler(self.__crawl_url,self.__proxy_enabled)

    #generate the query string of the search data for http://house.ksou.cn/p.php
    def __generate_query_string(self,query,page,region,state):
        Query_String = {}
        Query_String['q'] = query
        Query_String['p'] = page
        Query_String['s'] = 1
        Query_String['st'] = ''
        Query_String['type'] = ''
        Query_String['count'] = '300'
        Query_String['region'] = region
        Query_String['lat'] = '0'
        Query_String['lng'] = '0'
        Query_String['sta'] = state
        Query_String['htype'] = ''
        Query_String['agent'] = '0'
        Query_String['minprice'] = '0'
        Query_String['maxprice'] = '0'
        Query_String['minned'] = '0'
        Query_String['maxbed'] = '0'
        Query_String['minland'] = '0'
        Query_String['maxland'] = '0'
        return Query_String

    def __absctract_house_info(self,bs):
        if not isinstance(bs,BeautifulSoup):
            raise TypeError('bs must be bs4.BeautifulSoup, now: ' + type(bs))

        _house_info = {}
        addr_tag = bs.find('span', class_='addr')
        detail_tag = addr_tag.parent.parent.next_sibling
        # find detail info in the currnet page

        # Get Address sample "37 Clendon Road, Toorak"
        _house_info['Addr'] = addr_tag.text.split(',')[0]

        # Get Sold Price sample Sold $8,790,000 unit AU dollar
        if detail_tag.find(text=re.compile('Sold')):
            _house_info['SoldPrice'] = detail_tag.find(text=re.compile('Sold'))[6:]
        else:
            _house_info['SoldPrice'] = 'null'
        # Get Sold Date sample in Jun 2017(Auction)
        if detail_tag.find(text=re.compile('Sold')):
            _house_info['SoldDate'] = detail_tag.find(text=re.compile('Sold')).parent.next_sibling[3:].replace('(Auction)','').strip()
        else:
            _house_info['SoldDate'] = 'null'
        # Get Last Sold Price sample " $1,505,000 in Oct 1997"
        if detail_tag.find(text=re.compile('Last Sold')):
            _sl = detail_tag.find(text=re.compile('Last Sold')).parent.next_sibling
            _house_info['LastSoldPrice'] = _sl.split('in')[0].strip()[1:]
            _house_info['LastSoldDate'] = _sl.split('in')[1].replace('(Auction)','').strip()
        else:
            _house_info['LastSoldPrice'] = 'null'
            _house_info['LastSoldDate'] = 'null'
        # Get Rent Price
        if detail_tag.find(text=re.compile('Rent')):
            if detail_tag.find(text=re.compile('Rent')).parent.parent.find('a'):
                _rp = detail_tag.find(text=re.compile('Rent')).parent.parent.a.string  # with Rent link
            else:
                _rp = detail_tag.find(
                    text=re.compile('Rent')).parent.next_sibling  # Rent $1,150pw in Jun 2014
            _house_info['RentPrice'] = _rp.split('in')[0].strip()[1:-2]
            _house_info['RentDate'] = _rp.split('in')[1].strip()
        else:
            _house_info['RentPrice'] = 'null'
            _house_info['RentDate'] = 'null'
        # get property type
        if detail_tag.find(text=re.compile('Apartment|Unit|House')):
            _house_info['Type'] = detail_tag.find(text=re.compile('Apartment|Unit|House'))[:-1]
        else:
            _house_info['Type'] = 'null'
        # get Bed Room Number
        if detail_tag.find(title='Bed rooms'):
            _house_info['BedRoom'] = detail_tag.find(title='Bed rooms').previous_sibling
        else:
            _house_info['BedRoom'] = '0'
        # get Bath Room Number
        if detail_tag.find(title='Bath rooms'):
            _house_info['BathRoom'] = detail_tag.find(title='Bath rooms').previous_sibling
        else:
            _house_info['BathRoom'] = '0'
        # Get car space
        if detail_tag.find(title='Car spaces'):
            _house_info['CarSpace'] = detail_tag.find(title='Car spaces').previous_sibling
        else:
            _house_info['CarSpace'] = '0'
        # Get Land Size
        if detail_tag.find(text=re.compile('Land size:')):
            _house_info['LandSize'] = detail_tag.find(text=re.compile('Land size:')).parent.next_sibling.split('sqm')[0].strip()
            if _house_info['LandSize'] == '':
                _house_info['LandSize'] = 'null'
        else:
            _house_info['LandSize'] = 'null'
        # get building size
        if detail_tag.find(text=re.compile('Building size:')):
            _house_info['BuildingSize'] = detail_tag.find(text=re.compile('Building size:')).parent.next_sibling.split('sqm')[0].strip()
            if _house_info['BuildingSize'] == '':
                _house_info['BuildingSize'] = 'null'
        else:
            _house_info['BuildingSize'] = 'null'
        # get Build Year
        if detail_tag.find(text=re.compile('Build year:')):
            _house_info['BuildYear'] = detail_tag.find(text=re.compile('Build year:')).parent.next_sibling
        else:
            _house_info['BuildYear'] = 'null'
        # Get Agent Name
        if detail_tag.find(text=re.compile('Agent')):
            # Agent: Rodney Morley Pty Ltd -
            if detail_tag.find(text=re.compile('Agent')).parent.parent.find('a'):
                _house_info['Agent'] = detail_tag.find(text=re.compile('Agent')).parent.parent.a.string.strip()
            else:  # Agent: hockingstuart  Armadale
                _house_info['Agent'] = detail_tag.find(text=re.compile('Agent')).parent.next_sibling.strip()
        else:
            _house_info['Agent'] = 'null'
        # get distance to cbd sample 5.3 km to CBD; 825 metres to Heyington Station, unit meters
        if detail_tag.find(text=re.compile('Distance')):
            _dist = detail_tag.find(text=re.compile('Distance')).parent.next_sibling
            _house_info['Distance2CBD'] = _dist.split(';')[0].split('to')[0].strip()
            _house_info['Distance2Stat'] = _dist.split(';')[1].split('to')[0].strip()
        else:
            _house_info['Distance2CBD'] = 'null'
            _house_info['Distance2Stat'] = 'null'

        #return one house info
        return _house_info

    def crawl_sold_house(self,state,mode='CONTINUE',excluderegion=''):
        _region_list = self.__crawler.load_region_list(state)
        _excludelist = excluderegion
        #create a new crawler to fro detail data
        _crawler = basecrawler.BaseCrawler()
        #-------------------
        # set both crawler proxy enabled
        _crawler.proxy_enabled = True
        self.__crawler.proxy_enabled = True
        #------------------
        #new collction for detail property
        _mongoclient = MongoDBClient.MongodbClient('PropertyDetails')
        for _region in _region_list:
            if _region in _excludelist:
                continue
            for i in range(30):
                _query = self.__generate_query_string(_region,i,_region,state)
                #_bs_searchresult = self.__crawler.crawl_data(**_query)
                _bs_searchresult = self.__crawler.requests_crawl_data(**_query)
                for addr in _bs_searchresult.find_all('span', class_='addr'):
                    _crawler.crawl_url = self.__crawl_url + addr.a.get('href')[5:]
                    try:
                        if mode == 'FULL' or \
                                (mode == 'CONTINUE' and (not _mongoclient.get_one_value_by_key({'URL':_crawler.crawl_url}))):
                            #_bs_detailinfo = _crawler.crawl_data()
                            _bs_detailinfo = _crawler.requests_crawl_data()
                            _house_data = self.__absctract_house_info(_bs_detailinfo)
                            _house_data['State'] = state
                            _house_data['Region'] = _region
                            _house_data['URL'] = self.__crawl_url + addr.a.get('href')[5:]
                            #save data to mongodb
                            _mongoclient.update_one_record({'Addr':_house_data['Addr']},_house_data,'PropertyDetails')
                            # sleep 2 second
                            time.sleep(2)
                            print('save data:' + _house_data['URL'])
                        else:
                            print(_crawler.crawl_url + 'existed')
                    except BaseException as e:
                        logger.log_to_file('SoldHouseCrawler.log', 'error when processing '+ _crawler.crawl_url +'err: ' + str(e))
                #time.sleep(10)
        _mongoclient.close_bd()

if __name__ =='__main__':
    _crawler1 = SoldhouseCrawler()
    _crawler1.crawl_sold_house('vic',mode='FULL')
    #TODO exclude regions if 300 entries are existed in CONTINUE Mode, and how to process crawler in different mode
    #TODO using proxy and change IP address when error occures


from oslo_log import log as logging

import trove.common.apischema as apischema
from trove.common.auth import admin_context
from trove.common import wsgi
from trove.extensions.mgmt.upgrade.models import UpgradeMessageSender

LOG = logging.getLogger(__name__)

class UpgradeController(wsgi.Controller):
    """
    Controller for guest agent upgrade
    """
    schemas = apischema.upgrade

    @admin_context
    def create(self, req, body, tenant_id, instance_id):
        LOG.info("Sending upgrade notifications\nreq : '%(req)s'\n"
                 "Admin tenant_id: %(tenant_id)s",
                 {"tenant_id": tenant_id, "req": req})

        context = req.environ.get(wsgi.CONTEXT_KEY)
        upgrade = body['upgrade']

        instance_version = upgrade.get('instance_version')
        location = upgrade.get('location')
        metadata = upgrade.get('metadata')

        send = UpgradeMessageSender.create(
            context, instance_id, instance_version, location, metadata)

        send()
        return wsgi.Result(None, 202)


# rock, scissors, paper
import random

def check_match(decision, computer_choice):
    if decision == computer_choice:
        print(f"""
        !!! IT'S A TIE !!!
{show_gestures}
        """)
    else:
        check_winner(decision, computer_choice)

def check_winner(decision, computer_choice):
    if (decision == 0 and computer_choice == 2) or\
       (decision == 1 and computer_choice == 0) or \
       (decision == 2 and computer_choice == 1):
        print(f"""
        !!!YOU WIN!!!
{show_gestures}
        """)
    else:
        print(f"""
        !!!YOU LOSE!!!
{show_gestures}
        """)

def will_next(game):
    next_game = input("Will you continue? y or n? ")
    if next_game.lower() == "n":
        return False
    return game

rock = """Rock
    _______
---'   ____)
      (_____)
      (_____)
      (____)
---.__(___)

"""
paper = """Paper
    _______
---'   ____)____
          ______)
          _______)
         _______)
---.__________)

"""

scissors = """Scissors
    _______
---'   ____)____
          ______)
       __________)
      (____)
---.__(___)

"""
rules = """Here the WIN conditions:
Rock brakes the Scissors
Paper covers the Rock
Scissors cut the Paper
"""

# Starting sentence
print("Welcome to the Rock, Paper, Scissors game\n"
      "type: help for instructions\n"
      "or type 0 for Rock, 1 for Paper, and 2 for Scissors")

conditions = [rock, paper, scissors]
is_game = True

while is_game:
    user_choice = input("Your decision: ")
    computer_choice = random.randint(0, 2)
    decision = computer_choice
    if user_choice == "help":
        print(f"{rock}\n{paper}\n{scissors}\n{rules}")
        user_choice = input("So you know the rules. Make a decision: ")
    if user_choice.lower() == "rock" or user_choice == "0":
        decision = 0
    elif user_choice.lower() == "paper" or user_choice == "1":
        decision = 1
    elif user_choice.lower() == "scissors" or user_choice == "2":
        decision = 2
    else:
        print("\n\nCarefully, that way you can't win computer\n")
    show_gestures = f"""
        Your choice is {conditions[decision]}
        The computer choice is {conditions[computer_choice]}
        """
    check_match(decision, computer_choice)
    is_game = will_next(is_game)
quit()


import requests
import json

data = {'age': 50,
        'workclass': 'Private',
        'fnlgt': 367260,
        'education': 'Bachelors',
        'education-num': 13,
        'marital-status': 'Never-married',
        'occupation': 'Tech-support',
        'relationship': 'Unmarried',
        'race': 'White',
        'sex': 'Male',
        'capital-gain': 14084,
        'capital-loss': 0,
        'hours-per-week': 45,
        'native-country': 'Canada'}

url = 'https://udacity-mlop-project3-hs.herokuapp.com/predict'

resp = requests.post(url, data=json.dumps(data))
print(url)
print(json.dumps(data))
print(resp.status_code)
print(resp.text)


import pickle

inputpath = "./nodes/"

def connectedComponents(comp1, comp2):
    edges = set()
    for i in range(len(comp1)):
        if(comp1[i]>0 and comp2[i]>0):
            edges.add((comp1[i],comp2[i]))
    return edges

#NESTING TREE
def createNestedTrees():
    EdgesN = set()
    for timestep in range(41,45):
        inputFile = inputpath+"nodes_t"+str(timestep)+".pickle"
        pickle_in = open(inputFile,"rb")
        nodes_in_timestep = pickle.load(pickle_in)
        pickle_in.close()

        comp1 = nodes_in_timestep["componentMatrix1"]
        comp2 = nodes_in_timestep["componentMatrix2"]
        comp3 = nodes_in_timestep["componentMatrix3"]

        #level 1 and level 2 - connected components
        edges_l1_l2 = connectedComponents(comp1, comp2)

        #level 2 and level 3
        edges_l2_l3 = connectedComponents(comp2, comp3)

        for (p1,p2) in list(edges_l1_l2):
            id1 = "t"+str(timestep)+"_l1_"+str(p1)
            id2 = "t"+str(timestep)+"_l2_"+str(p2)
            EdgesN.add((id1,id2))

        for (p1,p2) in list(edges_l2_l3):
            id1 = "t"+str(timestep)+"_l2_"+str(p1)
            id2 = "t"+str(timestep)+"_l3_"+str(p2)
            EdgesN.add((id1,id2))
    return EdgesN

#TRACKING GRAPH
def createTrackingTree():
    EdgesT = set()
    inputFile1 = inputpath+"nodes_t41.pickle"
    pickle_in = open(inputFile1,"rb")
    nodes_in_timestep1 = pickle.load(pickle_in)
    pickle_in.close()

    for timestep in range(42,45):
        inputFile = inputpath+"nodes_t"+str(timestep)+".pickle"
        pickle_in = open(inputFile,"rb")
        nodes_in_timestep2 = pickle.load(pickle_in)
        pickle_in.close()

        #level 1
        t1_comp = nodes_in_timestep1["componentMatrix1"]
        t2_comp = nodes_in_timestep2["componentMatrix1"]
        edgesL1_t1_t2 = connectedComponents(t1_comp, t2_comp)

        #level 2
        t1_comp = nodes_in_timestep1["componentMatrix2"]
        t2_comp = nodes_in_timestep2["componentMatrix2"]
        edgesL2_t1_t2 = connectedComponents(t1_comp, t2_comp)

        #level 3
        t1_comp = nodes_in_timestep1["componentMatrix3"]
        t2_comp = nodes_in_timestep2["componentMatrix3"]
        edgesL3_t1_t2 = connectedComponents(t1_comp, t2_comp)

        for (p1,p2) in list(edgesL1_t1_t2):
            id1 = "t"+str(timestep-1)+"_l1_"+str(p1)
            id2 = "t"+str(timestep)+"_l1_"+str(p2)
            EdgesT.add((id1,id2))

        for (p1,p2) in list(edgesL2_t1_t2):
            id1 = "t"+str(timestep-1)+"_l2_"+str(p1)
            id2 = "t"+str(timestep)+"_l2_"+str(p2)
            EdgesT.add((id1,id2))

        for (p1,p2) in list(edgesL3_t1_t2):
            id1 = "t"+str(timestep-1)+"_l3_"+str(p1)
            id2 = "t"+str(timestep)+"_l3_"+str(p2)
            EdgesT.add((id1,id2))

        nodes_in_timestep1  = nodes_in_timestep2
    return EdgesT


from django.urls import path
from . import views

# register app here
app_name = "education"

urlpatterns = [
    path('', views.index, name="index"),
    path('about_us/', views.about_us, name="about_us"),
    path('courses/', views.courses, name="courses"),
    path('contact/', views.contact, name="contact"),
    path('pricing/', views.pricing, name="pricing"),
    path('portfolio/', views.portfolio, name="portfolio"),

    path('course/<int:course_id>', views.course, name="course")
]


import io
import os
from argparse import ArgumentParser

from django.core.management import BaseCommand
from django.core.management.base import OutputWrapper
from django.core.management.color import no_style
from django.template.loader import render_to_string
from django.utils.translation import gettext as _

from df_config import __version__ as version
from df_config.config.base import merger
from df_config.utils import guess_version, remove_arguments_from_help

__author__ = "Matthieu Gallet"

from df_config.config.values_providers import (
    EnvironmentConfigProvider,
    IniConfigProvider,
)

class Command(BaseCommand):
    help = (
        "show the current configuration."
        'Can display as python file ("config python") or as .ini file ("config ini"). Use -v 2 to display more info.'
    )
    requires_system_checks = []
    options = {
        "python": "display the current config as Python module",
        "ini": "display the current config as .ini file",
        "env": "display the current config as environment variables",
    }

    def add_arguments(self, parser: ArgumentParser):
        parser.add_argument(
            "action",
            default="show",
            choices=self.options,
            help=",\n".join(['"%s": %s' % x for x in self.options.items()]),
        )
        parser.add_argument(
            "--filename", default=None, help="write output to this file"
        )
        remove_arguments_from_help(
            parser, {"--settings", "--traceback", "--pythonpath"}
        )

    def handle(self, *args, **options):
        try:
            self.handle_head(**options)
        except BrokenPipeError:
            # this exception is raised when `manage.py config python | head` is used
            pass

    def handle_head(self, **options):
        action = options["action"]
        verbosity = options["verbosity"]
        filename = options["filename"]
        fd = None
        if filename:
            fd = io.StringIO()
            self.stdout = OutputWrapper(fd)
            self.style = no_style()
        if action == "python":
            self.show_python_config(verbosity)
        elif action == "ini":
            self.show_ini_config(verbosity)
        elif action == "env":
            self.show_env_config(verbosity)

        if filename and action in {"python", "env"}:
            content = fd.getvalue()
            if action == "python":
                # noinspection PyBroadException
                try:
                    # noinspection PyPackageRequirements,PyUnresolvedReferences
                    import black

                    mode = black.FileMode()
                    # noinspection PyArgumentList
                    content = black.format_file_contents(content, fast=False, mode=mode)
                except Exception:  # nosec  # nosec
                    pass
            os.makedirs(os.path.dirname(filename), exist_ok=True)
            with open(filename, "w") as dst_fd:
                dst_fd.write(content)

    def show_external_config(self, config):
        content = render_to_string(config, merger.settings)
        self.stdout.write(content)

    def show_ini_config(self, verbosity):
        if verbosity >= 2:
            p = merger.fields_provider
            self.stdout.write(
                self.style.SUCCESS(f"# configuration fields read from {p}")
            )
            self.stdout.write(self.style.SUCCESS("# read configuration files:"))
        for provider in merger.providers:
            if not isinstance(provider, IniConfigProvider):
                continue
            elif provider.is_valid():
                self.stdout.write(
                    self.style.SUCCESS('    #  - %s "%s"' % (provider.name, provider))
                )
            elif verbosity >= 2:
                self.stdout.write(
                    self.style.ERROR(
                        '    #  - %s "%s" (not found)' % (provider.name, provider)
                    )
                )
        provider = IniConfigProvider()
        merger.write_provider(provider, include_doc=verbosity >= 2)
        self.stdout.write(provider.to_str())

    def show_env_config(self, verbosity):
        prefix = None
        for provider in merger.providers:
            if not isinstance(provider, EnvironmentConfigProvider):
                continue
            prefix = provider.prefix
        if not prefix:
            self.stderr.write("Environment variables are not used•")
            return
        if verbosity >= 2:
            p = merger.fields_provider
            self.stdout.write(
                self.style.SUCCESS(f"# configuration fields read from {p}")
            )
            self.stdout.write(self.style.SUCCESS("# read environment variables:"))
        provider = EnvironmentConfigProvider(prefix)
        merger.write_provider(provider, include_doc=verbosity >= 2)
        self.stdout.write(provider.to_str())

    def show_python_config(self, verbosity):
        self.stdout.write(self.style.SUCCESS("# " + "-" * 80))
        self.stdout.write(
            self.style.SUCCESS(
                _("# df_config version %(version)s") % {"version": version}
            )
        )
        self.stdout.write(
            self.style.SUCCESS(
                _("# %(project)s version %(version)s")
                % {
                    "version": guess_version(merger.settings),
                    "project": merger.settings["DF_PROJECT_NAME"],
                }
            )
        )
        self.stdout.write(self.style.SUCCESS("# Configuration providers:"))
        for provider in merger.providers:
            if provider.is_valid():
                self.stdout.write(
                    self.style.SUCCESS('#  - %s "%s"' % (provider.name, provider))
                )
            elif verbosity > 1:
                self.stdout.write(
                    self.style.ERROR(
                        '#  - %s "%s" (not found)' % (provider.name, provider)
                    )
                )
        self.stdout.write(self.style.SUCCESS("# " + "-" * 80))
        setting_names = list(merger.raw_settings)
        setting_names.sort()

        # first, compute all imports to do
        imports = {}

        def add_import(val):
            if not isinstance(val, type):
                val = val.__class__
            if val.__module__ != "builtins":
                imports.setdefault(val.__module__, set()).add(val.__name__)

        for setting_name in setting_names:
            if setting_name not in merger.settings:
                continue
            value = merger.settings[setting_name]
            add_import(value)
        if imports:
            self.stdout.write("\n")
            for module_name in sorted(imports):
                objects = ", ".join(sorted(imports[module_name]))
                self.stdout.write(
                    self.style.WARNING("from %s import %s" % (module_name, objects))
                )
            self.stdout.write("\n")

        for setting_name in setting_names:
            if setting_name not in merger.settings:
                continue
            value = merger.settings[setting_name]
            self.stdout.write(self.style.SUCCESS("%s = %r" % (setting_name, value)))
            if verbosity <= 1:
                continue
            for provider_name, raw_value in merger.raw_settings[setting_name].items():
                self.stdout.write(
                    self.style.WARNING(
                        "    #   %s -> %r" % (provider_name or "built-in", raw_value)
                    )
                )


from .resource import *

class V1(object):
    def __init__(self, config: Config) -> None:
        self.mailgroup: Mailgroup = Mailgroup(config)
        self.mailgroup_alias: MailgroupAlias = MailgroupAlias(config)
        self.mailgroup_manager: MailgroupManager = MailgroupManager(config)
        self.mailgroup_member: MailgroupMember = MailgroupMember(config)
        self.mailgroup_permission_member: MailgroupPermissionMember = MailgroupPermissionMember(config)
        self.public_mailbox: PublicMailbox = PublicMailbox(config)
        self.public_mailbox_alias: PublicMailboxAlias = PublicMailboxAlias(config)
        self.public_mailbox_member: PublicMailboxMember = PublicMailboxMember(config)
        self.user: User = User(config)
        self.user_mailbox: UserMailbox = UserMailbox(config)
        self.user_mailbox_alias: UserMailboxAlias = UserMailboxAlias(config)


def oddEven(num,check):
    if(num%2==0):
        if(num%4==0):
            print(num," is an even number and multiple of 4")
        else:
            print(num," is an even number")
    elif(num%2!=0):
        print(num," is an odd number")
    if(num%check==0):
        print("%d divides %d completely" %(check,num))
    else:
        print("%d does not divides %d completely" %(check,num))

numb =  int(input("Enter a number to check even/odd = "))
divisor = int(input("Enter Check to divide completely - "))
oddEven(numb,divisor)


from briefcase.exceptions import BriefcaseCommandError
from briefcase.integrations.xcode import verify_command_line_tools_install

DEFAULT_OUTPUT_FORMAT = 'dmg'

class macOSMixin:
    platform = 'macOS'

    def verify_tools(self):
        if self.host_os != 'Darwin':
            raise BriefcaseCommandError("""
macOS applications require the Xcode command line tools, which are
only available on macOS.
""")
        # Require the XCode command line tools.
        verify_command_line_tools_install(self)

        # Verify superclass tools *after* xcode. This ensures we get the
        # git check *after* the xcode check.
        super().verify_tools()


import ctypes

class stackusingarray():

    def __init__(self):
        self.b = None
        self.n = -1  # size of array
        self.c = 8  # capacity of array
        # self.t = 0
        self.a = self._make_array(self.c)

    def _make_array(self, new_cap):
        return (new_cap * ctypes.py_object)()

    def push(self, ele):
        if self.n == self.c:
            return f"stak is full"
        self.a[self.n] = ele
        self.n += 1
        # return self.n
        # self.t+=1

    # def _resize(self, new_cap):
    #     b = self._make_array(new_cap)
    #     for i in range(self.n):
    #         b[i] = self.a[i]
    #     self.a = b
    #     self.c = new_cap

    def pop(self):
        if self.n == 0:
            return f"stack is empty"
        self.a[self.n - 1] = 0
        self.n -= 1

    def trav(self):
        for i in range(self.n):
            r = self.a[i]
            print(r)

    def peek(self, index):
        if self.n < index < 0:
            return f"index out of bound"
        for i in range(self.n):
            if i == index:
                return self.a[i]

    def isEmpty(self):
        # i = 0
        if self.n <= self.c:
            # self.a[self.n] = None
            print("stack is empty")
        else:
            print("stack is full")

    def bracketmatching(self, arr):
        stack = []
        b =[]
        for i in range(len(arr)):
            b.append(arr[i])

        for i in b:
            if i in ["(", "[", "{"]:
                stack.append(i)
            print(stack)

            if not stack:
                return False

            char_popped = stack.pop()
            if char_popped == "(":
                if i != ")":
                    return False
            if char_popped == "[":
                if i != "]":
                    return False
            if char_popped == "{":
                if i != "}":
                    return False

        if stack:
            return False
        else:
            return True

    # def isfull(self):
    #     if self.n == self.c:
    #         print("stack is full")

re = stackusingarray()
arr = "2*4(7*9)[]{}"
if re.bracketmatching(arr):
    print("balanced")
else:
    print("not balanced")

# b = []
# s = []
#
# for i in range(len(a)):
#     b.append(a[i])
# print(b)
# for i in range(len(b)):
#     if b[i] is '(' or "[" or '{':
#         s.append(b[i])

    # if b[i] == ')'  :
    #     s.pop()
    #
    # if b[i] == '[':
    #     s.append(b[i])
    #
    # if b[i] == ']':
    #     s.pop()
    #
    # if b[i] == '{':
    #     s.append(b[i])
    #
    # if b[i] == "}":
    #     s.pop()
# print(s)
# if not s:
#     print("the expression is balanced")
# else:
#     print("expression is not balanced")


import torch.nn.functional as F

def train(model, device, dataloader, optimizer, steps, log_steps, print_flag):
    """
    Train the model.

    Args:
        model: Model to train.
        device: Device to run the model.
        dataloader: Dataloader of train data.
        optimizer: Optimizer for training.
        steps: Number of training iterations.
        log_steps: Iterations interval for logging.
        print_flag: Whether to print training log.
    """
    model.train()
    step_num = 0
    while True:
        for data, target in dataloader:
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = F.nll_loss(output, target)
            loss.backward()
            optimizer.step()
            step_num += 1
            if print_flag and step_num % log_steps == 0:
                print('[Train] Step[{}/{}] Loss: {:.6f}'.format(
                    step_num, steps, loss.item()), flush=True)
            if step_num == steps:
                return


import tensorflow as tf
import numpy as np

class Actor(object):
    # init first build the structure, nn layer and input/output size/type

    def __init__(self, sess, n_features, n_actions, lr=0.001):
        self.sess = sess

        # single train, input one state, action, reward
        self.s = tf.placeholder(tf.float32, [1, n_features], name='state')
        self.a = tf.placeholder(tf.int32, None, name='act')
        self.td_error = tf.placeholder(tf.float32, None, name='td_error')

        with tf.variable_scope('Actor'):
            l1 = tf.layers.dense(
                inputs=self.s,
                units=20,
                activation=tf.nn.relu,
                kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.1),
                bias_initializer=tf.constant_initializer(0.1),
                name='l1'
            )

            self.acts_prob = tf.layers.dense(
                inputs=l1,
                units=n_actions,
                activation=tf.nn.softmax,
                kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.1),
                bias_initializer=tf.constant_initializer(0.1),
                name='acts_prob'
            )

            with tf.variable_scope('exp_v'):
                log_prob = tf.log(self.acts_prob[0, self.a])
                self.exp_v = tf.reduce_mean(log_prob * self.td_error)

            with tf.variable_scope('train'):
                self.train_op = tf.train.AdamOptimizer(lr).minimize(-self.exp_v)

    # feed in the data
    def learn(self, s, a, td):
        # add a dim(sample num), here is single sample train
        s = s[np.newaxis, :]
        feed_dict = {self.s: s, self.a: a, self.td_error: td}
        _, exp_v = self.sess.run([self.train_op, self.exp_v], feed_dict=feed_dict)
        return exp_v

    def choose_action(self, s):
        s = s[np.newaxis, :]
        probs = self.sess.run(self.acts_prob, feed_dict={self.s: s})
        return np.random.choice(np.arange(probs.shape[1]), p=probs.ravel())


from collections import deque
import sys, os, io, atexit

input = lambda: sys.stdin.readline().rstrip('\r\n')
stdout = io.BytesIO()
sys.stdout.write = lambda s: stdout.write(s.encode("ascii"))
atexit.register(lambda: os.write(1, stdout.getvalue()))

# 230619 28069 김밥천국의 계단

# 정답코드

N, K = map(int, input().split())

current = 0

visited = [0 for _ in range(N + 1)]

def bfs(curr, cnt):

    queue = deque()
    queue.append((curr, cnt))
    visited[curr] = 1

    while queue:

        curr, cnt = queue.popleft()
        # print(curr, cnt)

        if curr == N:
            print("minigimbob")
            return

        next_1 = curr + 1
        next_2 = curr + curr//2

        if next_1 <= N and cnt < K and not visited[next_1]:
            visited[next_1] = 1
            queue.append((next_1, cnt + 1))

        if next_2 <= N and cnt < K and not visited[next_2]:
            # print(next_2, cnt)
            visited[next_2] = 1
            queue.append((next_2, cnt + 1))

    print("water")
    return

bfs(0, 0)