# SourcePawn Completions is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import re
import string
import sys
import sublime, sublime_plugin
import codecs
from collections import defaultdict
from queue import *
from threading import Timer, Thread

sys.path.append(os.path.dirname(__file__))
import watchdog.events
import watchdog.observers
import watchdog.utils
from watchdog.utils.bricks import OrderedSetQueue

class Wrapper:
    def __init__(self):
        self.value = []
    def set(self, newval):
        self.value = newval
    def get(self):
        return self.value

def plugin_loaded():
    load_include_dir(True)

def unload_handler():
    file_observer.stop()
    process_thread.stop()
    # Get process_thread to stop by adding something to the queue
    to_process.put(('', ''))
    # remove callback
    _get_settings().clear_on_change('SourcePawn Completions')

class SPCompletions(sublime_plugin.EventListener):
    def __init__(self):
        process_thread.start()
        self.delay_queue = None
        file_observer.start()

    def on_activated(self, view):
        if not self.is_sourcepawn_file(view):
            return
        file_name = view.file_name()
        if file_name is not None and file_name and not file_name in nodes:
            add_to_queue(view)

    def on_activated_async(self, view):
        _save_user_settings()

    def on_modified(self, view):
        self.add_to_queue_delayed(view)

    def on_post_save(self, view):
        self.add_to_queue_now(view)

    def on_load(self, view):
        self.add_to_queue_now(view)

    def add_to_queue_now(self, view):
        if not self.is_sourcepawn_file(view):
            return
        add_to_queue(view)

    def add_to_queue_delayed(self, view):
        if not self.is_sourcepawn_file(view):
            return

        if self.delay_queue is not None:
            self.delay_queue.cancel()

        delay_time = _get_settings().get('live_refresh_delay', 1.0)
        self.delay_queue = Timer(float(delay_time), add_to_queue_forward, [ view ])
        self.delay_queue.start()

    def is_sourcepawn_file(self, view):
        return view.file_name() is not None and (view.match_selector(0, 'source.sp') or view.match_selector(0, 'source.inc'))

    def on_query_completions(self, view, prefix, locations):
        # print('queried')
        if not view.match_selector(locations[0], 'source.sp -string -comment -constant') \
        and not view.match_selector(locations[0], 'source.inc -string -comment -constant'):
            return []

        file_name = view.file_name()
        if file_name is None:
            return []

        point = locations[0]-1;
        pointFound = False
        char = view.substr(point)
        if char == '.':
            pointFound = True
        else:
            while char.isalpha() and point > 1:
                point -= 1
                char = view.substr(point)
            if char == '.':
                pointFound = True

        if pointFound:
            current_node = nodes[file_name]

            classes = self.generate_classes(file_name)
            print('classes:')
            keys = classes.keys()
            if keys:
                for key in classes.keys():
                    print(' ' + key)
            else:
                print(' none')

            print('point found')
            wordpoint = point-1
            char = view.substr(point-1)
            hit_brace = False

            # do some stupid stuff if there are brackets.
            while char == ']':
                hit_brace = True
                bracelevel = 1
                wordpoint -= 1

                while bracelevel > 0 and point > 0:
                    char = view.substr(wordpoint)

                    if char == '[':
                        bracelevel -= 1
                    elif char == ']':
                        bracelevel += 1

                    wordpoint -= 1

                char = view.substr(wordpoint)

            if not char.isalpha():
                print('Could not find valid char: ' + char)
                return (
                    None,
                    sublime.INHIBIT_WORD_COMPLETIONS|
                    sublime.INHIBIT_EXPLICIT_COMPLETIONS
                )

            print('Found valid char')

            var_region = view.word(wordpoint)
            var = view.substr(var_region).strip()
            print('variable is: ' + var)

            if not var:
                return (
                    None,
                    sublime.INHIBIT_WORD_COMPLETIONS|
                    sublime.INHIBIT_EXPLICIT_COMPLETIONS
                )

            if re.match(r'\b[a-zA-Z_]\w*\b', var):
                # check if static access
                varstatic = var + '.static'
                # if varstatic in all_classes.keys():
                c = current_node.find_class(varstatic)
                if c is not None:
                    if c:
                        return (
                            c,
                            sublime.INHIBIT_WORD_COMPLETIONS|
                            sublime.INHIBIT_EXPLICIT_COMPLETIONS|
                            sublime.INHIBIT_REORDER
                        )
                    return (
                        None,
                        sublime.INHIBIT_WORD_COMPLETIONS|
                        sublime.INHIBIT_EXPLICIT_COMPLETIONS
                    )

                # check if local
                print(view.scope_name(point))
                begin = var_region.begin() - 1
                while view.match_selector(begin, 'source.sp meta.function | meta.function.parameters'):
                    begin -= 1;
                begin += 1

                region = view.substr(sublime.Region(begin, point))
                if region:
                    print('Found beginning at {}'.format(begin))
                    print(region)

                    print('searching')
                    m = re.search(r'\b([a-zA-Z_]\w+)\b\s+\b{}\b'.format(var), region)
                    if m:
                        retval = m.group(1)
                        # if retval in all_classes.keys():
                        c = current_node.find_class(retval)
                        if c is not None:
                            print('type found: ' + retval)
                            if c:
                                return (
                                    c,
                                    sublime.INHIBIT_WORD_COMPLETIONS|
                                    sublime.INHIBIT_EXPLICIT_COMPLETIONS|
                                    sublime.INHIBIT_REORDER
                                )
                            return (
                                None,
                                sublime.INHIBIT_WORD_COMPLETIONS|
                                sublime.INHIBIT_EXPLICIT_COMPLETIONS
                            )

                    # output text to a new view, apply syntax,
                    window = sublime.active_window()
                    panel = window.create_output_panel('temp_check_sp', unlisted=True)
                    panel.assign_syntax('Packages/SourcePawn/SourcePawn.sublime-syntax')
                    panel.run_command('append', {'characters': region})

                    for r in panel.find_by_selector('source.sp meta.variable.sp'):
                        region = re.sub('[ \t]{2,}', ' ', panel.substr(r).strip().replace('\n', ''))

                        print(region)

                        m = re.search(r'^([a-zA-Z_]\w+)\b', region)
                        if m:
                            retval = m.group(1)
                            if re.search(r'(?:{}|,) +{}'.format(retval, var), region):
                                print('Found local type. It\'s {}'.format(retval))

                                window.destroy_output_panel('temp_check_sp')

                                c = current_node.find_class(retval)
                                print(c)
                                if c is not None:
                                    if c:
                                        return (
                                            all_classes[retval],
                                            sublime.INHIBIT_WORD_COMPLETIONS|
                                            sublime.INHIBIT_EXPLICIT_COMPLETIONS|
                                            sublime.INHIBIT_REORDER
                                        )
                                return (
                                    None,
                                    sublime.INHIBIT_WORD_COMPLETIONS|
                                    sublime.INHIBIT_EXPLICIT_COMPLETIONS
                                )

                    window.destroy_output_panel('temp_check_sp')

                # check if global
                print('searching files for type')
                for v in sublime.active_window().views():
                    for r in v.find_by_selector('source.sp meta.variable.sp -meta.block.sp'):
                        region = re.sub('[ \t]{2,}', ' ', v.substr(r).strip().replace('\n', ''))
                        print(region)
                        m = re.search(r'^([a-zA-Z_]\w+)\b', region)
                        if m:
                            retval = m.group(1)
                            if re.search(r'(?:{}|,) +{}'.format(retval, var), region):

                                print('Found type. It\'s {}'.format(retval))
                                c = current_node.find_class(retval)
                                if c is not None:
                                    if c:
                                        return (
                                            c,
                                            sublime.INHIBIT_WORD_COMPLETIONS|
                                            sublime.INHIBIT_EXPLICIT_COMPLETIONS|
                                            sublime.INHIBIT_REORDER
                                        )
                                    return (
                                        None,
                                        sublime.INHIBIT_WORD_COMPLETIONS|
                                        sublime.INHIBIT_EXPLICIT_COMPLETIONS
                                    )

            return ( # Found a dot but unknown type
                None,
                sublime.INHIBIT_WORD_COMPLETIONS|
                sublime.INHIBIT_EXPLICIT_COMPLETIONS
            )

        # return (self.generate_funcset(view.file_name()), sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
        return (
            self.generate_funcset(file_name),
            sublime.INHIBIT_WORD_COMPLETIONS|
            sublime.INHIBIT_REORDER
        )

    def generate_funcset(self, file_name):
        funcset = set()
        visited = set()

        node = nodes[file_name]

        self.generate_funcset_recur(node, funcset, visited)
        return sorted_nicely(funcset)

    def generate_funcset_recur(self, node, funcset, visited):
        if node in visited:
            return

        visited.add(node)
        for child in node.children:
            self.generate_funcset_recur(child, funcset, visited)

        funcset.update(node.funcs)

    def generate_classes(self, file_name):
        classes = dict(
            {
                'Handle': [('Close()\t(function: void) [handles]', 'Close()')],
                'Handle.static':[]
            }
        )

        visited = set()

        node = nodes[file_name]
        self.generate_classes_recur(node, classes, visited)
        return classes

    def generate_classes_recur(self, node, classes, visited):
        if node in visited:
            return

        visited.add(node)
        for child in node.children:
            self.generate_classes_recur(child, classes, visited)

        classes.update(node.classes)

def _settings_filename():
    return 'SourcePawn Completions.sublime-settings'

def _get_settings():
    return sublime.load_settings(_settings_filename())

def on_settings_modified():
    load_include_dir()

def load_include_dir(register_callback = False):
    settings = _get_settings()
    if register_callback:
        settings.add_on_change('SourcePawn Completions', on_settings_modified)

    dirs = settings.get('include_directory', '.')
    include_dirs.set(dirs)
    if type(dirs) is not list:
        if not os.path.isabs(str(dirs)):
            raise RuntimeError("Invalid 'include_directory' setting (%s): directory doesn't exists" % str(dirs))

        file_observer.unschedule_all()
        file_observer.schedule(file_event_handler, dirs, True)
    else:
        for path in dirs:
            if not os.path.isabs(str(path)):
                raise RuntimeError("Invalid 'include_directory' setting (%s): directory doesn't exists" % str(path))

            file_observer.unschedule_all()
            file_observer.schedule(file_event_handler, path, True)

def sorted_nicely( l ):
    """ Sort the given iterable in the way that humans expect."""
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key[0]) ]
    return sorted(l, key = alphanum_key)

def add_to_queue_forward(view):
    sublime.set_timeout(lambda: add_to_queue(view), 0)

def add_to_queue(view):
    # The view can only be accessed from the main thread, so run the regex
    # now and process the results later
    file_name = view.file_name()
    if file_name is not None:
        to_process.put((file_name, view.substr(sublime.Region(0, view.size()))))

def add_include_to_queue(file_name):
    to_process.put((file_name, None))

def _save_user_settings():
    settings = _get_settings()
    if not settings.get('bootstrapped'):
        settings.set('bootstrapped', True)
        sublime.save_settings(_settings_filename())
        # build-system
        build_filename = 'SourcePawn.sublime-build'
        build = sublime.load_settings(build_filename)

        if not build.get('file_patterns'):
            build.set('file_patterns', ['*.sp'])
        if not build.get('quiet'):
            build.set('quiet', true)
        if not build.get('file_regex'):
            build.set('file_regex', '(.*)\\((\\d+)\\) : ()(.*$)')
        if not build.get('selector'):
            build.set('selector', 'source.sp')

        sublime.save_settings(build_filename)

class IncludeFileEventHandler(watchdog.events.FileSystemEventHandler):
    def __init__(self):
        watchdog.events.FileSystemEventHandler.__init__(self)

    def on_created(self, event):
        sublime.set_timeout(lambda: on_modified_main_thread(event.src_path), 0)

    def on_modified(self, event):
        sublime.set_timeout(lambda: on_modified_main_thread(event.src_path), 0)

    def on_deleted(self, event):
        sublime.set_timeout(lambda: on_deleted_main_thread(event.src_path), 0)

def on_modified_main_thread(file_path):
    if not is_active(file_path):
        add_include_to_queue(file_path)

def on_deleted_main_thread(file_path):
    if is_active(file_path):
        return

    node = nodes.get(file_path)
    if node is None:
        return

    node.remove_all_children_and_funcs()

def is_active(file_name):
    return sublime.active_window().active_view().file_name() == file_name

class ProcessQueueThread(watchdog.utils.DaemonThread):
    def run(self):
        while self.should_keep_running():
            (file_name, view_buffer) = to_process.get()
            if view_buffer is None:
                self.process_existing_include(file_name)
            else:
                self.process(file_name, view_buffer)

    def process(self, view_file_name, view_buffer):
        (current_node, node_added) = get_or_add_node(view_file_name)

        base_includes = set()
        includes = includes_re.findall(view_buffer)

        self.load_from_file(view_file_name, 'sourcemod', current_node, current_node, base_includes)

        for include in includes:
            if include == 'sourcemod':
                continue
            self.load_from_file(view_file_name, include, current_node, current_node, base_includes)

        for removed_node in current_node.children.difference(base_includes):
            current_node.remove_child(removed_node)

        process_buffer(view_buffer, current_node)

    def process_existing_include(self, file_name):
        current_node = nodes.get(file_name)
        if current_node is None:
            return

        base_includes = set()

        with codecs.open(file_name, 'r', 'utf-8') as f:
            print ('Processing Include File %s' % file_name)
            includes = includes_re.findall(f.read())

        self.load_from_file(file_name, 'sourcemod', current_node, current_node, base_includes)
        for include in includes:
            if include == 'sourcemod':
                continue
            self.load_from_file(file_name, include, current_node, current_node, base_includes)

        for removed_node in current_node.children.difference(base_includes):
            current_node.remove_child(removed_node)

        process_include_file(current_node)

    def load_from_file(self, view_file_name, base_file_name, parent_node, base_node, base_includes):
        (file_name, exists) = get_file_name(view_file_name, base_file_name)
        if not exists:
            print ('Include File Not Found: %s' % base_file_name)
            print ('Result: %s' % file_name)

        (node, node_added) = get_or_add_node(file_name)
        parent_node.add_child(node)

        if parent_node == base_node:
            base_includes.add(node)

        if not node_added or not exists:
            return

        with codecs.open(file_name, 'r', 'utf-8') as f:
            print ('Processing Include File %s' % file_name)
            includes = includes_re.findall(f.read())

        for include in includes:
            self.load_from_file(view_file_name, include, node, base_node, base_includes)

        process_include_file(node)

def get_file_name(view_file_name, base_file_name):
    file_name = ''
    if local_re.search(base_file_name) == None:
        dirs = include_dirs.get()
        if type(dirs) is not list:
            file_name = os.path.join(dirs, base_file_name + '.inc')
        else:
            for path in dirs:
                file_name = os.path.join(path, base_file_name + '.inc')
                if os.path.exists(file_name):
                    break
    else:
        file_name = os.path.join(os.path.dirname(view_file_name), base_file_name)

    return (file_name, os.path.exists(file_name))

def get_or_add_node(file_name):
    node = nodes.get(file_name)
    if node is None:
        node = Node(file_name)
        nodes[file_name] = node
        return (node, True)

    return (node, False)

# class SPObj:
#     def __init__(self):
#         self.name = ''
#         self.properties = dict() # name: ret
#         self.functions = dict() # name: ret

class Node:
    def __init__(self, file_name):
        self.file_name = file_name
        self.children = set()
        self.parents = set()
        self.funcs = set()
        self.classes = dict()
        self.globals = dict()

    def add_child(self, node):
        self.children.add(node)
        node.parents.add(self)

    def remove_child(self, node):
        self.children.remove(node)
        node.parents.remove(self)

        if len(node.parents) <= 0:
            nodes.pop(node.file_name)

    def remove_all_children(self):
        for child in self.children:
            self.remove_child(node)
        self.funcs.clear()
        self.classes.clear()

    def find_class(self, class_name):
        visited = set()
        if class_name == 'Handle':
            return [('Close()\t(function: void) [handles]', 'Close()')]
        if class_name == 'Handle.static':
            return []
        return self.__find_class_recur(class_name, visited)

    def __find_class_recur(self, class_name, visited):
        if self in visited:
            return
        visited.add(self)
        print('searching {} for {}'.format(self.file_name, class_name))
        if class_name in self.classes.keys():
            return self.classes[class_name]

        for child in self.children:
            c = child.__find_class_recur(class_name, visited)
            if c is not None:
                return c

        return None

class TextReader:
    def __init__(self, text):
        self.text = text.splitlines()
        self.position = -1

    def readline(self):
        self.position += 1

        if self.position < len(self.text):
            retval = self.text[self.position]
            if retval == '':
                return '\n'
            return retval
        return ''

DEPRECATED_FUNCTIONS = [
    'native Float:operator*',
    'native Float:operator/',
    'native Float:operator+',
    'native Float:operator-',
    'stock Float:operator*',
    'stock Float:operator/',
    'stock Float:operator+',
    'stock Float:operator-',
    'stock bool:operator=',
    'stock bool:operator!',
    'stock bool:operator>',
    'stock bool:operator<',
    'forward operator%('
]

loaded_files = set() # to prevent loading files more than once
docs = dict() # map function name to documentation
included_files = defaultdict(set) # map project files to included files
funcs = defaultdict(list) # map include files to functions

# Code after this point adapted from
# https://forums.alliedmods.net/showpost.php?p=1866026&postcount=19
# Credit to MCPAN (mcpan@foxmail.com)
def read_line(file):
    """read_line(File) -> string"""
    line = file.readline()
    if len(line) > 0:
        return comment_re.sub(' ', line).strip()
    return None

def process_buffer(text, node):
    text_reader = TextReader(text)
    process_lines(text_reader, node)

def process_include_file(node):
    with codecs.open(node.file_name, 'r', 'utf-8') as file:
        process_lines(file, node)

def skipMultiline(line_reader, buffer):
    while buffer.startswith('/*'):
        pos = buffer.find('*/')
        while pos == -1:
            buffer = read_line(line_reader)
            if buffer is None:
                return None
            pos = buffer.find('*/')

        idx = pos + 2
        length = len(buffer)
        if idx >= length:
            idx = length - 1
        buffer = buffer[idx].strip()
    return buffer

def process_lines(line_reader, node):
    node.funcs.clear()

    found_comment = False
    found_enum = False
    brace_level = 0

    global file
    file = os.path.basename(node.file_name).rsplit('.')[0]
    if file:
        file = ' [' + file + ']'

    semicolonRequired = False

    while True:
        buffer = read_line(line_reader)

        if buffer is None:
            break

        if not buffer or buffer.startswith('//'):
            continue

        buffer = skipMultiline(line_reader, buffer)

        if buffer is None:
            break

        if not buffer or buffer.startswith('//'):
            continue

        if brace_level == 0:
            m = enum_re.search(buffer)
            if m:
                enum_type = m.group(2)
                if not m.group(1): # if struct was found, dont do anything. Unsupported currently
                    print('Found enum: ' + m.group(0))
                    found_enum = True
                    enum_contents = ''

                    if enum_type is not None:
                        node.funcs.add((enum_type+'\t(enum)' + file, enum_type))
                else:
                    node.funcs.add((enum_type+'\t(enum struct)' + file, enum_type))

            elif buffer.startswith('#'):
                if buffer.strip().startswith('#pragma deprecated'):
                    buffer = read_line(line_reader)
                    if buffer is not None and buffer.startswith('stock '):
                        pos = buffer.find('{')
                        if pos != -1: # if line contains {, jump to it
                            buffer = buffer[pos:]
                        buffer = skip_brace_line(line_reader, buffer)
                        continue
                elif buffer.startswith('#define '):
                    buffer = get_preprocessor_define(node, buffer)
                continue

            elif buffer.startswith('public '):
                m = pubvar_re.search(buffer)
                if m:
                    val = m.group(1)
                    print('Found public const: ' + val)
                    node.funcs.add((val + '\t(const)' + file, val))
                    continue

                pos = buffer.find('{')
                # print('Skipping public')
                if pos != -1: # if line contains {, jump to it
                    buffer = buffer[pos:]
                else: # otherwise, skip to next line
                    continue

            elif buffer.startswith('struct '):
                pos = buffer.find('{')
                print('Skipping struct')
                if pos != -1: # if line contains {, jump to it
                    buffer = buffer[pos:]
                else: # otherwise, skip to next line
                    continue

            elif buffer.startswith('methodmap '):

                #  (funcname + '\t(function' + return_type + ')' + file, autocomplete)
                m = methodmap_re.search(buffer)
                if not m:
                    continue

                name = m.group(1)
                static_name = name+'.static'
                inherited = m.group(2)
                node.funcs.add((name + '\t(methodmap)' + file, name))

                if inherited is not None:
                    c = node.find_class(inherited)
                    if c is not None:
                        node.classes[name] = set(c)
                        node.classes[static_name] = set(node.find_class(inherited+'.static'))
                    else:
                        node.classes[name] = set()
                        node.classes[static_name] = set()
                else:
                    node.classes[name] = set()
                    node.classes[static_name] = set()

                in_comment = False
                searching = True
                pos = -1
                buffer = buffer[len(m.group(0)):]
                strlen = 0

                # print('new buffer: \'' + buffer + '\'')
                while pos == -1 and searching:
                    if buffer:
                        i = 0
                        strlen = len(buffer)
                        while i < strlen:
                            if in_comment:
                                if buffer[i] == '*' and i < strlen - 1 and buffer[i+1] == '/':
                                    in_comment = False
                                    i += 2
                                    continue
                            else:
                                if buffer[i] == '{':
                                    pos = i
                                    break
                                if buffer[i] == '/' and i < strlen - 1:
                                    if buffer[i+1] == '/':
                                        buffer = read_line(line_reader)
                                        break;
                                    if buffer[i+1] == '*':
                                        in_comment = True
                                        i += 2
                                        continue
                                elif buffer[i] > ' ':
                                    searching = False # found something other than comment and brace
                                    break
                            i += 1

                    if pos == -1 and searching:
                        buffer = read_line(line_reader)
                        if buffer is None:
                            return

                if pos == -1:
                    continue

                mmbody = ''
                brace_level = 1
                buffer = buffer[pos:]
                strlen = len(buffer)
                if strlen == 1:
                    buffer = read_line(line_reader)
                    while not buffer:
                        buffer = read_line(line_reader)
                    strlen = len(buffer)

                # print('found methodmap brace. new buffer: \'' + buffer + '\'' + ' len: ' + str(strlen))
                while brace_level > 0:
                    i = 0
                    while i < strlen:
                        c = buffer[i]
                        if in_comment:
                            if c == '*' and i < strlen - 1 and buffer[i+1] == '/':
                                in_comment = False
                                i += 2
                                continue
                        else:
                            if c == '/' and i < strlen - 1:
                                if buffer[i+1] == '/':
                                    break
                                if buffer[i+1] == '*':
                                    in_comment = True
                                    i += 2
                                    continue
                            else:
                                if c == '{':
                                    # brace_level += 1
                                    buffer = skip_brace_line(line_reader, buffer[i:])
                                    strlen = len(buffer)
                                    break
                                elif c == '}':
                                    brace_level -= 1
                                    buffer = buffer[i+1:]
                                    if brace_level == 0:
                                        break
                                else:
                                    mmbody += c

                        i += 1

                    if brace_level > 0:
                        buffer = read_line(line_reader)
                        strlen = len(buffer)
                        mmbody += ' '

                mmbody = re.sub(r'[ \t]{2,}', ' ', mmbody).strip()
                mmbody = re.sub(r'(\)|property[ \t]\b\w+\b[ \t]\b\w+\b);? ', r'\1\n', mmbody)
                # print('Body: ' + mmbody + '\n')

                # constructor
                m = re.search(r'public[ \t](?:native[ \t])?{}[ \t]*\((.*?)\)'.format(name), mmbody)
                if m:
                    params = m.group(1).split(',')

                    autocomplete = name + '('
                    i = 1
                    for param in params:
                        if i > 1:
                            autocomplete += ', '
                        if param:
                            autocomplete += '${%d:%s}' % (i, param.strip())
                        i += 1
                    autocomplete += ')'

                    node.funcs.add((name+'()\t(constructor)' + file, autocomplete))
                # function
                for m in re.finditer(r'public[ \t](?:native[ \t])?\b(?!native)(\w+)\b[ \t](\w+)[ \t]*\((.*?)\)', mmbody):
                    ret = m.group(1)
                    func = m.group(2)
                    params = m.group(3).split(',')

                    autocomplete = func + '('
                    i = 1
                    for param in params:
                        if i > 1:
                            autocomplete += ', '
                        if param:
                            autocomplete += '${%d:%s}' % (i, param.strip())
                        i += 1
                    autocomplete += ')'
                    node.classes[name].add((func + '()\t(function: ' + ret + ')' + file, autocomplete))
                # static function
                for m in re.finditer(r'public[ \t]static[ \t](?:native[ \t])?(\w+)\b[ \t](\w+)[ \t]*\((.*?)\)', mmbody):
                    ret = m.group(1)
                    func = m.group(2)
                    params = m.group(3).split(',')

                    autocomplete = func + '('
                    i = 1
                    for param in params:
                        if i > 1:
                            autocomplete += ', '
                        if param:
                            autocomplete += '${%d:%s}' % (i, param.strip())
                        i += 1
                    autocomplete += ')'
                    node.classes[static_name].add((func + '()\t(function: ' + ret + ')' + file, autocomplete))
                # property
                for m in re.finditer(r'property[ \t](\w+)[ \t](\w+)', mmbody):
                    ret = m.group(1)
                    prop = m.group(2)

                    node.classes[name].add((prop+'\t(property: ' + ret + ')' + file, prop))

                node.classes[name] = sorted(node.classes[name])
                node.classes[static_name] = sorted(node.classes[static_name])

            elif function_re.search(buffer):
                (buffer, found_comment, brace_level) = get_full_function_string(line_reader, node, buffer, found_comment, brace_level)

            elif re.search('^[ \t]*(?:type(?:def|set)|func(?:tag|enum))', buffer):
                pos = buffer.find('{')
                print('Skipping typedef')
                if pos != -1: # if line contains {, jump to it
                    buffer = buffer[pos:]
                else: # otherwise, skip to next line
                    continue
            # else:
                # print('End of checks: ' + buffer)

        (buffer, found_comment, brace_level) = read_string(buffer, found_comment, brace_level)

        if not buffer:
            continue

        if found_enum:
            (buffer, enum_contents, found_enum) = process_enum(node, buffer, enum_contents, found_enum)
        elif buffer.startswith('#define '):
            buffer = get_preprocessor_define(node, buffer)

# def process_methodmap(node, buffer):

def process_variable(node, buffer):
    result = ''
    consumingKeyword = True
    consumingName = False
    consumingBrackets = False

    for c in buffer:
        if consumingKeyword:
            if c == ' ':
                consumingKeyword = False
                consumingName = True
        elif consumingName:
            if c == ':':
                result = ''
            elif c == ' ' or c == '=' or c == ';':
                result = result.strip()
                if result != '':
                    node.funcs.add((result + '\t(variable)' + file, result))
                result = ''
                consumingName = False
                consumingBrackets = False
            elif c == '[':
                consumingBrackets = True
            elif not consumingBrackets:
                result += c
        elif c == ',':
            consumingName = True

    result = result.strip()
    if result != '':
        node.funcs.add((result + '\t(variable)' + file, result))

    return ''

def process_enum(node, buffer, enum_contents, found_enum):
    print('Processing enum: ' + buffer)

    pos = buffer.find('}')
    if pos != -1:
        buffer = buffer[0:pos]
        found_enum = False

    enum_contents = '%s%s' % (enum_contents, buffer)
    buffer = ''

    enum_type = ''
    m = enum_re.search(enum_contents)
    if m:
        if m.group(2):
            enum_type = ': ' + m.group(2)

    ignore = False
    if not found_enum:
        pos = enum_contents.find('{')
        enum_contents = enum_contents[pos + 1:]

        for c in enum_contents:
            if c == '=':
                ignore = True
            elif c == ':':
                buffer = ''
                continue
            elif c == ',':
                buffer = buffer.strip()
                if buffer != '':
                    node.funcs.add((buffer + '\t(enum' + enum_type + ')' + file, buffer))

                ignore = False
                buffer = ''
                continue

            if not ignore:
                buffer += c

        buffer = buffer.strip()
        if buffer != '':
            node.funcs.add((buffer + '\t(enum' + enum_type + ')' + file, buffer))

        buffer = ''

    return (buffer, enum_contents, found_enum)

def get_preprocessor_define(node, buffer):
    print('Processing define: ' + buffer)
    """get_preprocessor_define(File, string) -> string"""
    # Regex the #define. Group 1 is the name, Group 2 is the value
    define = define_re.search(buffer)
    if define:
        # The whole line is consumed, return an empty string to indicate that
        buffer = ''
        name = define.group(1)
        value = define.group(2).strip()
        node.funcs.add((name + '\t(constant: ' + value + ')' + file, name))
    return buffer

def get_full_function_string(line_reader, node, buffer, found_comment, brace_level):
    """get_full_function_string(File, string, string, bool) -> string"""
    multi_line = False
    temp = ''
    full_func_str = None
    open_paren_found = False

    while buffer is not None:
        buffer = buffer.strip()
        if not open_paren_found:
            parenpos = buffer.find('(')
            eqpos = buffer.find('=')

            if eqpos != -1 and (parenpos == -1 or eqpos < parenpos):
                return ('', found_comment, brace_level)

            if buffer.find(';') != -1 and parenpos == -1:
                return ('', found_comment, brace_level)

            if parenpos != -1:
                open_paren_found = True

        pos = buffer.rfind(')')
        if pos != -1:
            full_func_str = buffer[0:pos + 1]

            if (multi_line):
                full_func_str = '%s%s' % (temp, full_func_str)

            break

        multi_line = True
        temp = '%s%s' % (temp, buffer)

        buffer = read_line(line_reader)
        if buffer is None:
            return (buffer, found_comment, brace_level)

        (buffer, found_comment, brace_level) = read_string(buffer, found_comment, brace_level)

    if full_func_str is not None and not full_func_str in DEPRECATED_FUNCTIONS:
        process_function_string(node, full_func_str)

    return (buffer, found_comment, brace_level)

def process_function_string(node, func):
    """process_function_string(string, string, bool)"""
    if re.search(r'deprecated', func):
        return

    print('Processing Function: ' + func)

    file = os.path.basename(node.file_name).rsplit('.')[0]
    if file:
        file = ' [' + file + ']'

    func_type = ''
    return_type = ': '
    remaining = ''

    m = fullfunction_re.search(func)
    if m:
        if m.group(1):
            func_type += m.group(1) + ' '
        return_type += func_type + (m.group(2) if m.group(2) else '_')
        remaining = m.group(3)
    else:
        return

    split = remaining.split('(', 1)
    funcname = split[0].strip()
    remaining = split[1].strip()

    if remaining == ')':
        params = []
    else:
        params = remaining.strip()[:-1].split(',')

    autocomplete = funcname + '('
    i = 1
    for param in params:
        if i > 1:
            autocomplete += ', '
        if param:
            autocomplete += '${%d:%s}' % (i, param.strip())
        i += 1
    autocomplete += ')'

    node.funcs.add((funcname + '()\t(function' + return_type + ')' + file, autocomplete))

def skip_brace_line(line_reader, buffer):
    """skip_brace_line(File, string) -> string"""
    num_brace = 0
    in_comment = False

    while buffer is not None:
        print('Skipping brace: ' + buffer)
        i = 0
        pos = 0

        strlen = len(buffer)
        while i < strlen:
            c = buffer[i]
            if in_comment:
                if c == '*' and i < strlen - 1 and buffer[i+1] == '/':
                    in_comment = False
                    i += 2
                    continue
            else:
                if c == '{':
                    num_brace += 1
                elif c == '}':
                    num_brace -= 1
                elif c == '/' and i < strlen - 1:
                    if buffer[i+1] == '*':
                        in_comment = True
                        i += 2
                        continue
                    if buffer[i+1] == '/':
                        break

                if num_brace == 0:
                    print('Brace skip end.')
                    return buffer[i+1:]

            i += 1

        buffer = read_line(line_reader)
    return buffer

def read_string(buffer, found_comment, brace_level):
    """read_string(string, bool) -> (string, bool)"""
    buffer = buffer.replace('\t', ' ').strip()
    result = ''

    i = 0
    while i < len(buffer):
        if buffer[i] == '/' and i + 1 < len(buffer):
            if buffer[i + 1] == '/':
                return (result, found_comment, brace_level + result.count('{') - result.count('}'))
            elif buffer[i + 1] == '*':
                found_comment = True
                i += 1
            elif not found_comment:
                result += '/'
        elif found_comment:
            if buffer[i] == '*' and i + 1 < len(buffer) and buffer[i + 1] == '/':
                found_comment = False
                i += 1
        elif not (i > 0 and buffer[i] == ' ' and buffer[i - 1] == ' '):
            result += buffer[i]

        i += 1

    return (result, found_comment, brace_level + result.count('{') - result.count('}'))

to_process = OrderedSetQueue()
nodes = dict() # map files to nodes
file_observer = watchdog.observers.Observer()
process_thread = ProcessQueueThread()
file_event_handler = IncludeFileEventHandler()
include_dirs = Wrapper()
includes_re = re.compile(r'^[ \t]*#include[ \t]+[<"]([^>"]+)[>"]', re.MULTILINE)
local_re = re.compile(r'\.(sp|inc)$')
enum_re = re.compile(r'^[ \t]*enum\b[ \t]+(struct\b[ \t]+)?([\w_]+)?')
function_re = re.compile(r'^[ \t]*(?:(native|stock|forward)\b[ \t]+)?(?:([\w_]+)(?:[ \t]+|:))?([\w_]+[ \t]*\()')
fullfunction_re = re.compile(r'^[ \t]*(?:(native|stock|forward)\b[ \t]+)?(?:([\w_]+)(?: +|:))?([\w_]+ *\(.*?\))')
define_re = re.compile(r'#define[ \t]+([^\s]+)[\s]+(.+)')
comment_re = re.compile(r'\/\*(.*?)\*\/')
pubvar_re = re.compile(r'^[ \t]*public[ \t]+const[ \t]+\w+[ \t]+(\w+)\b\s*;')
methodmap_re = re.compile(r'^[ \t]*methodmap[ \t]+\b(\w+)\b(?:\s*<\s*(\w+)\b)?')
file = ''
# all_classes = dict(
#     {
#         'Handle': [('Close()\t(function: void) [handles]', 'Close()')],
#         'Handle.static':[]
#     }
# )


from argparse import Namespace
import pandas as pd
import numpy as np
from tqdm import tqdm
from src import download, download_csv
from src.jasmes import JASMESProd
from src.api_types import SGLIAPIs
from src.gportal import GportalApi, GPortalLvlProd, GPortalResolution
from src.jasmes import JasmesApi
from sys import exit

"""
Utility function to get the value from a dict and validate it
"""
def get_value(d: dict, key: str):
    """
    Utility function to get the value from a dict and validate it
    """
    if key in d and d[key]:
        return d[key]

def fill_group(df, g):
    for j in range(len(g)):
        df.loc[df.index[g.index[j]], "identifier"] = g.iloc[0]["identifier"]
        df.loc[df.index[g.index[j]], "file_status"] = g.iloc[0]["file_status"]
        df.loc[df.index[g.index[j]], "resolution"] = g.iloc[0]["resolution"]
        df.loc[df.index[g.index[j]], "download_url"] = g.iloc[0]["download_url"]
        df.loc[df.index[g.index[j]], "preview_url"] = g.iloc[0]["preview_url"]
        df.loc[df.index[g.index[j]], "cloud_coverage"] = g.iloc[0]["cloud_coverage"]

def search(args: Namespace):
    """
    Search a single instance and print the result to the terminal
    arguments provided through json file or cmdline arguments:
        - api: GPORTAL or JASMES, default: GPORTAL
        - product: GPortal Products or Jasmes Products
        - date: string date
        - latitude
        - longitude
        - resolution: str(250m or 1km) or int(250 or 1000)
    """
    # selecting which API
    if args.api == SGLIAPIs.GPORTAL:
        pl = GPortalLvlProd(args.product)
        api = GportalApi(pl)
        # send search request
        resolution = GPortalResolution.from_str(args.resolution)
        result = api.search(args.date, args.latitude, args.longitude, resolution)
        setattr(args, "download_url", result.properties.product.downloadUrl.geturl())
    elif args.api == SGLIAPIs.JASMES:
        pl = JASMESProd(args.product)
        api = JasmesApi(pl)
        # send search request
        api.set_auth_details(args.cred)
        result = api.search(args.date, args.latitude, args.longitude, None)
        setattr(args, "ftp_path", result.filePath)
    else:
        print("API name is not recognized")
        exit(1)

    # print results
    print("returned results: ")
    result.print()

    # if download option is set, call the download function
    if args.download:
        download(args)

def search_csv(args: Namespace):
    """
    Bulk search operation using csv file
    arguments provided through json file or cmdline arguments:
        - api: GPORTAL or JASMES, default: GPORTAL
        - product: GPortal Products or Jasmes Products
        - csv: path to csv file
        - no_repeat: boolean, if identifier exists will not search the corresponding row
    CSV file columns:
        - date
        - lat
        - lon
        - identifier/file_name: optional (if no_repeat set and identifier/file_name provided the corresponding row will be skipped)

    Output columns for GPORTAL:
        - identifier
        - file_status
        - resolution
        - download_url
        - preview_url
        - cloud_coverage (%)
    Output columns for JASMES:
        - ftp_path
        - file_name
        - file_size
        - box_id
    """
    if args.api == SGLIAPIs.GPORTAL:
        pl = GPortalLvlProd(args.product)
        api = GportalApi(pl)
        id_key = "identifier"
    elif args.api == SGLIAPIs.JASMES:
        pl = JASMESProd(args.product)
        api = JasmesApi(pl)
        api.set_auth_details(args.cred)
        id_key = "file_name"

    print("=============================")
    print("Searching CSV ...")
    print("=============================")

    df = pd.read_csv(args.csv) # read csv
    grouped = df.groupby(["lat", "lon", "date"])
    pbar = tqdm(total=len(df), position=0, leave=True) # prepare progress bar

    for i, ((lat, lon, date), g) in enumerate(grouped):

        id = get_value(g.iloc[0].fillna(0).to_dict(), id_key)
        resolution = GPortalResolution.H

        # progress if no repeat and id exists
        if id and args.no_repeat:
            fill_group(df, g)
            pbar.update(len(g))
            continue

        # send search request
        result = api.search(date, lat, lon, resolution, verbose=False)
        # if results returned add to the data
        if result != None:
            for j in range(len(g)):
                result.to_dataframe(df, g.index[j])

        pbar.update(len(g)) # update progress bar

        # save to csv every 100 row
        if (i % 100 == 0): df.to_csv(args.csv, index=False)

    for c in df.columns:
        if c.startswith("Unnamed"):
            df.drop(columns=c, inplace=True)
    df.to_csv(args.csv, index=False) # save to csv
    pbar.close()

    # move to download option if download is set
    if args.download:
        download_csv(args)


import os
import numpy as np
from torch.utils.data import Dataset
import json
import albumentations as A
import cv2
from PIL import Image
import seaborn as sns

# the HumanSD dataset
class HumanSDPoseBase(Dataset):
    def __init__(self,
                 map_file,
                 base_path,
                 image_size,
                 max_person_num,
                 keypoint_num,
                 keypoint_dim,
                 skeleton_width,
                 keypoint_thresh,
                 pose_skeleton
                 ):
        self.base_path = base_path
        with open(map_file, "r",encoding='utf-8') as f:
            self.map_json = json.load(f)
        self._length = len(self.map_json)

        data_list=list(self.map_json.keys())
        self.index_to_data = dict((k, data_list[k]) for k in range(self._length))

        self.image_size = image_size
        self.max_person_num=max_person_num
        self.keypoint_num=keypoint_num
        self.keypoint_dim=keypoint_dim

        keypoint_index=[ keypoint_i for keypoint_i in range(self.keypoint_num)]*self.max_person_num
        person_index=[ keypoint_i//self.keypoint_num for keypoint_i in range(self.keypoint_num*self.max_person_num)]
        self.person_keypoint_index=[[person_index[ii],keypoint_index[ii]] for ii in range(self.keypoint_num*self.max_person_num)]

        self.skeleton_width=skeleton_width
        self.keypoint_thresh=keypoint_thresh
        self.pose_skeleton=pose_skeleton
        self.color=sns.color_palette("hls", len(self.pose_skeleton))

        self.transform = A.Compose([
                A.HorizontalFlip(p=0.2),
                A.VerticalFlip(p=0.1),
                A.Rotate(p=0.1),
                A.SmallestMaxSize(max_size=self.image_size, interpolation=cv2.INTER_AREA),
                A.RandomCrop(width=self.image_size, height=self.image_size),
                A.OneOf([
                    A.HueSaturationValue(p=0.5),
                    A.RGBShift(p=0.5)
                ], p=0.4),
                A.RandomBrightnessContrast(p=0.2),
            ], keypoint_params=A.KeypointParams(format='xy',
                                                label_fields=["person_keypoint_index"],
                                                remove_invisible=True))

    def __len__(self):
        return self._length

    def __getitem__(self, i):
        def plot_kpts(img_draw, kpts, color=self.color, edgs=self.pose_skeleton,width=self.skeleton_width):
            for idx, kpta, kptb in edgs:
                if int(kpts[kpta,0])!=-1 and \
                    int(kpts[kpta,1])!=-1 and \
                    int(kpts[kptb,0])!=-1 and \
                    int(kpts[kptb,1])!=-1 and \
                    kpts[kpta,2]>self.keypoint_thresh and \
                    kpts[kptb,2]>self.keypoint_thresh :
                    line_color = tuple([int(255*color_i) for color_i in color[idx]])

                    cv2.line(img_draw, (int(kpts[kpta,0]),int(kpts[kpta,1])), (int(kpts[kptb,0]),int(kpts[kptb,1])), line_color,width)

                    cv2.circle(img_draw, (int(kpts[kpta,0]),int(kpts[kpta,1])), width//2, line_color, -1)
                    cv2.circle(img_draw, (int(kpts[kptb,0]),int(kpts[kptb,1])), width//2, line_color, -1)

        example = self.map_json[self.index_to_data[i]]
        image = Image.open(os.path.join(self.base_path,example["img_path"]))
        if not image.mode == "RGB":
            image = image.convert("RGB")

        # default to score-sde preprocessing
        image = np.array(image).astype(np.uint8)

        # pose
        detected_results = np.load(os.path.join(self.base_path,example["pose_path"]),allow_pickle=True)["arr_0"]

        pose_list=[[0,0]  for ii in range(self.max_person_num*self.keypoint_num)]

        for detected_pose_i in range(min(len(detected_results),self.max_person_num)):
            for keypoint_i in range(self.keypoint_num):
                keypoints=detected_results[detected_pose_i]["keypoints"]
                if keypoints[keypoint_i,1]<int(image.shape[0])\
                    and keypoints[keypoint_i,0]<int(image.shape[1])\
                    and keypoints[keypoint_i,1]>=0\
                    and keypoints[keypoint_i,0]>=0:
                    pose_list[detected_pose_i*self.keypoint_num+keypoint_i][0]=keypoints[keypoint_i,0]
                    pose_list[detected_pose_i*self.keypoint_num+keypoint_i][1]=keypoints[keypoint_i,1]

        # augmentation
        transformed = self.transform(image=image, keypoints=pose_list, person_keypoint_index=self.person_keypoint_index)
        transformed_person_keypoint_index = transformed['person_keypoint_index']
        transformed_keypoints = transformed['keypoints']
        transformed_image = transformed['image']

        scaled_pose=np.array([-1,-1,0])*np.ones((self.max_person_num,self.keypoint_num,self.keypoint_dim))

        for detected_pose_i in range(min(len(detected_results),self.max_person_num)):
            for keypoint_i in range(self.keypoint_num):
                if [detected_pose_i,keypoint_i] in transformed_person_keypoint_index:
                    pos=transformed_person_keypoint_index.index([detected_pose_i,keypoint_i])
                    if detected_results[detected_pose_i]["keypoints"][keypoint_i,2]>self.keypoint_thresh:
                        scaled_pose[detected_pose_i,keypoint_i,0]=transformed_keypoints[pos][0]
                        scaled_pose[detected_pose_i,keypoint_i,1]=transformed_keypoints[pos][1]
                        scaled_pose[detected_pose_i,keypoint_i,2]=detected_results[detected_pose_i]["keypoints"][keypoint_i,2]

        scaled_image=transformed_image

        # normalize to [-1,1]
        return_example={}
        return_example["jpg"] = (scaled_image / 255 *2 - 1.0).astype(np.float32)

        return_example["pose"] = scaled_pose

        return_example["txt"] = example["prompt"]

        pose_img = np.zeros((self.image_size,self.image_size,3))
        for person_i in range(self.max_person_num):
            if np.sum(scaled_pose[person_i,:,:])>0:
                try:
                    plot_kpts(pose_img, scaled_pose[person_i,:,:],self.color,self.pose_skeleton,self.skeleton_width)
                except:
                    print("Can not draw poses ... Skipping.")

        return_example["pose_img"]= (pose_img / 255 *2 - 1.0).astype(np.float32)

        return return_example

class HumanSDPoseTrain(HumanSDPoseBase):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

class HumanSDPoseValidation(HumanSDPoseBase):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class TCSocks(object):

  def profit(self, visitedCities, money, cost, time, competitors):
    totalProfit = 0
    currCity    = 0

    for nextCity in visitedCities:
      revenue    = money[nextCity]
      travelCost = cost[currCity][nextCity]
      localProfit = (revenue - travelCost)

      currCity     = nextCity
      totalProfit += localProfit

    return totalProfit

  def _listFromFormatString(self, s):
    numbers = s.split()
    return [int(number) for number in numbers]


import os
import json
import torch
import numpy as np
from requests import post
from argparse import ArgumentParser
from tqdm import tqdm
from opennre import encoder
from opennre.model import SoftmaxNN
from functools import partial
import logging

from config import *
from server.saliency_utils import *

# Set global device
if DEVICE == 'gpu':
    device = torch.device(
        'cuda:0') if torch.cuda.is_available() else torch.device('cpu')
else:
    device = torch.device('cpu')

# Storages for hooks to fetch gradient & input
input_storage = []
gradient_storage = []

# Load model & register hooks
def load_model(_dataset_name, _model_name, _rel2id):
    # Silent unimportant log messages
    for logger_name in ['transformers.configuration_utils',
                        'transformers.modeling_utils',
                        'transformers.tokenization_utils_base', 'absl']:
        logging.getLogger(logger_name).setLevel(logging.WARNING)
    # Load model by path
    _encoders = {'bert': encoder.BERTEncoder,
                 'bertentity': encoder.BERTEntityEncoder}
    if _model_name in _encoders:
        _sentence_encoder = _encoders[_model_name](
            max_length=MAX_SEQ_LEN,
            pretrain_path=PRETRAIN_PATH,
            mask_entity=False
        )
        _model = SoftmaxNN(_sentence_encoder, len(_rel2id), _rel2id)
        _model.load_state_dict(torch.load(MODEL_PATH_DICT[_dataset_name][_model_name],
                                          map_location=device)['state_dict'])
        # input_data is an empty tuple
        # output_data is tensor (batch, seq_len, model_dim)
        _model.sentence_encoder.bert.embeddings.register_forward_hook(
            lambda module, input_data, output_data:
            input_storage.append(
                output_data.detach().squeeze(0).cpu().numpy()))  # (128, 768)
        # grad_input is a tuple containing one tensor (batch, seq_len, model_dim)
        # grad_output is a tuple containing one tensor (batch, seq_len, model_dim)
        _model.sentence_encoder.bert.embeddings.register_backward_hook(
            lambda module, grad_input, grad_output:
            gradient_storage.append(
                grad_input[0].detach().squeeze(0).cpu().numpy()))  # (128, 768)
        _model.to(device)
        _model.eval()

        return _model
    else:
        raise NotImplementedError

def get_saliency_local(model, sample, rel2id, id2rel):
    def get_saliency(unsupervised=False):
        def forward_backward(_inputs):
            _logits = sentence_encoder(*_inputs)
            _logits = model.softmax(model.fc(model.drop(_logits)))
            if unsupervised:
                # Use model's prediction as target
                _, pred = _logits.max(-1)
                target_label_id = pred[0].item()
            else:
                # Use supervised label as target
                target_label_id = rel2id[sample['relation']]
            ce = torch.nn.CrossEntropyLoss()
            loss = ce(_logits, torch.LongTensor([target_label_id]).to(device))
            loss.backward()
            return _logits[0].detach().cpu().numpy()

        # Tokenize sample
        sentence_encoder = model.sentence_encoder
        inputs = sentence_encoder.tokenize(sample)
        inputs = [i.to(device) for i in inputs]
        token_ids = inputs[0][0]
        tokens = sentence_encoder.tokenizer.convert_ids_to_tokens(token_ids)
        if '[PAD]' in tokens:
            tokens = tokens[:tokens.index('[PAD]')]

        # Process forward-backward once
        logits = forward_backward(inputs)
        pred = logits.argmax()
        confidence = float(logits[pred])
        pred_label = id2rel[pred]

        # Start calculating integrated gradients
        alpha_levels = 10
        for alpha_i in range(1, alpha_levels):
            alpha_rate = 1.0 * alpha_i / alpha_levels
            # Register new hook to modify embedding output each time
            alpha_hook = sentence_encoder.bert.embeddings.register_forward_hook(
                lambda module, input_data, output_data: output_data * alpha_rate)

            try:
                _ = forward_backward(inputs)
            except Exception as e:
                alpha_hook.remove()
                raise e

            alpha_hook.remove()
        gradient_average = np.mean(gradient_storage, axis=0)
        # Use first time's input
        saliency = gradient_average * input_storage[0]

        # Convert float32 to float, so that the dict is JSON serializable
        saliency = normalize(saliency[:len(tokens)])
        saliency = [float(score) for score in saliency]
        token_saliency = list(zip(tokens, saliency))
        word_saliency = merge_token_saliency(token_saliency)

        # Clear input / gradient storage
        input_storage.clear()
        gradient_storage.clear()

        return {'pred_label': pred_label,
                'confidence': confidence,
                'word_saliency': word_saliency}

    label = sample['relation']
    saliency_dict = {'label': label,
                     'prediction': '',
                     'confidence': 0.0,
                     'supervised': None,
                     'unsupervised': None}
    supervised_dict = get_saliency()
    saliency_dict['prediction'] = supervised_dict['pred_label']
    saliency_dict['confidence'] = supervised_dict['confidence']
    saliency_dict['supervised'] = supervised_dict['word_saliency']
    if supervised_dict['pred_label'] != label:
        unsupervised_dict = get_saliency(unsupervised=True)
        saliency_dict['unsupervised'] = unsupervised_dict['word_saliency']

    return saliency_dict

def get_saliency_server(args, sample):
    url = 'http://localhost:{}/saliency'.format(PORT)
    label = sample['relation']
    model = args.model
    dataset = args.dataset
    method = 'integrated_gradient'
    saliency_dict = {'label': label,
                     'prediction': '',
                     'confidence': 0.0,
                     'supervised': None,
                     'unsupervised': None}
    r = post(url, data=json.dumps({'model': model,
                                   'dataset': dataset,
                                   'method': method,
                                   'sample': sample}))
    supervised_dict = json.loads(r.text)
    saliency_dict['prediction'] = supervised_dict['pred_label']
    saliency_dict['confidence'] = supervised_dict['confidence']
    saliency_dict['supervised'] = supervised_dict['word_saliency']
    if supervised_dict['pred_label'] != label:
        r = post(url, data=json.dumps({'model': model,
                                       'dataset': dataset,
                                       'method': method,
                                       'sample': sample,
                                       'unsupervised': True}))
        unsupervised_dict = json.loads(r.text)
        saliency_dict['unsupervised'] = unsupervised_dict['word_saliency']

    return saliency_dict

if __name__ == "__main__":
    parser = ArgumentParser('Saliency fetching tool')
    parser.add_argument('--dataset', '-d', required=True,
                        choices=['tacred', 'wiki80'])
    parser.add_argument('--model', '-m', required=True,
                        choices=['bert', 'bertentity'])
    parser.add_argument('--adversary', '-a', default='none',
                        choices=['none', 'pw', 'tf', 'hf', 'uat', 'gen'])
    parser.add_argument('--mode', default='local', choices=['local', 'server'])

    args = parser.parse_args()

    if args.mode == 'local':
        rel2id = json.load(open(RELATION_PATH_DICT[args.dataset], 'r'))
        id2rel = {v: k for (k, v) in rel2id.items()}
        model = load_model(args.dataset, args.model, rel2id)
        saliency_func = partial(
            get_saliency_local, model=model, rel2id=rel2id, id2rel=id2rel)
    else:
        saliency_func = partial(get_saliency_server, args=args)

    if args.adversary == 'none':
        for data_type in DATA_TYPES[args.dataset]:
            input_file = os.path.join(
                DATA_ROOT, args.dataset, data_type + '.txt')
            output_file = os.path.join(
                DATA_ROOT, args.dataset, args.model, data_type + '_ig.txt')
            if os.path.exists(output_file):
                progress = len(open(output_file, 'r').readlines())
                logging.info('Restore progress from {} at index {}'.format(
                    output_file, progress))
            else:
                progress = 0
            out_handler = open(output_file, 'a')
            samples = [json.loads(line)
                       for line in open(input_file, 'r').readlines()]
            for sample in tqdm(samples[progress:],
                               desc='Fetching saliency for samples in ' + input_file):
                saliency = saliency_func(sample=sample)
                out_handler.write(json.dumps(saliency) + '\n')
    else:
        for data_type in DATA_TYPES[args.dataset]:
            input_file = os.path.join(
                DATA_ROOT, args.dataset, args.model,
                '{}_{}.txt'.format(data_type, args.adversary))
            output_file = os.path.join(
                DATA_ROOT, args.dataset, args.model,
                '{}_{}_ig.txt'.format(data_type, args.adversary))
            if os.path.exists(output_file):
                progress = max([json.loads(line)['index']
                                for line in open(output_file, 'r').readlines()])
                logging.info('Restore progress from {} at {}'.format(
                    output_file, progress))
            else:
                progress = -1
            out_handler = open(output_file, 'a')
            samples = [json.loads(line)
                       for line in open(input_file, 'r').readlines()]
            samples = [s for s in samples if s['index'] > progress]
            for sample_dict in tqdm(samples, desc='Fetching saliency for samples in ' + input_file):
                index = sample_dict['index']
                for sample in sample_dict['adversary_samples']:
                    saliency = saliency_func(sample=sample)
                    saliency['index'] = index
                    out_handler.write(json.dumps(saliency) + '\n')


import sys
input = sys.stdin.readline

n, m = map(int, input().split())
ans = 0
strings = set()

for _ in range(n):
    s = input()
    strings.add(s)

for _ in range(m):
    target = input()
    if target in strings:
        ans += 1

print(ans)


import torch
from slam_rcnn.utils.visualization import visualize_path
from slam_rcnn.nn.base_projection_layer import BaseProjectionLayer
from typing import Dict, Any

class OccupancyProjectionLayer(BaseProjectionLayer):
    """Create a feature projection layer in PyTorch that maintains a voxel
    grid description of the world world, where each voxel grid cell has
    a feature vector associated with it, typically semantic labels.

    Arguments:

    camera_height: int
        the map_height of the image generated by a pinhole camera onboard the
        agent, corresponding to a map_depth and semantic observation.
    camera_width: int
        the map_width of the image generated by a pinhole camera onboard the
        agent, corresponding to a map_depth and semantic observation.
    vertical_fov: float
        the vertical field of view of the onboard camera, measure in
        radians from the bottom of the viewport to the top.

    map_height: int
        the number of grid cells along the 'map_height' axis of the semantic
        map, as rendered using the top down rendering function.
    map_width: int
        the number of grid cells along the 'map_width' axis of the semantic
        map, as rendered using the top down rendering function.
    map_depth: int
        the number of grid cells that are collapsed along the 'up'
        direction by the top down rendering function.

    origin_y: float
        the center of the semantic map along the 'map_height' axis of the
        semantic map as viewed from a top-down render of the map.
    origin_x: float
        the center of the semantic map along the 'map_width' axis of the
        semantic map as viewed from a top-down render of the map.
    origin_z: float
        the center of the semantic map along the 'map_depth' axis of the
        semantic map as viewed from a top-down render of the map.
    grid_resolution: float
        the length of a single side of each voxel in the semantic map in
        units of the world coordinate system, which is typically meters.

    interpolation_weight: float
        float representing the interpolation weight used when adding
        new features in the feature map weighted by interpolation_weight.
    initial_feature_map: torch.Tensor
        tensor representing the initial feature map tensor,
        which will be set to zero if the value not specified by default.

    """

    def __init__(self, camera_height: int = 224, camera_width: int = 224,
                 vertical_fov: float = 90.0, map_height: int = 256,
                 map_width: int = 256, map_depth: int = 64,
                 dtype: torch.dtype = torch.float32,
                 origin_y: float = 0.0, origin_x: float = 0.0,
                 origin_z: float = 0.0, grid_resolution: float = 0.05,
                 interpolation_weight: float = 0.5,
                 initial_feature_map: torch.Tensor = None):
        """Create a feature projection layer in PyTorch that maintains a voxel
        grid description of the world world, where each voxel grid cell has
        a feature vector associated with it, typically semantic labels.

        Arguments:

        camera_height: int
            the map_height of the image generated by a pinhole camera onboard the
            agent, corresponding to a map_depth and semantic observation.
        camera_width: int
            the map_width of the image generated by a pinhole camera onboard the
            agent, corresponding to a map_depth and semantic observation.
        vertical_fov: float
            the vertical field of view of the onboard camera, measure in
            radians from the bottom of the viewport to the top.

        map_height: int
            the number of grid cells along the 'map_height' axis of the semantic
            map, as rendered using the top down rendering function.
        map_width: int
            the number of grid cells along the 'map_width' axis of the semantic
            map, as rendered using the top down rendering function.
        map_depth: int
            the number of grid cells that are collapsed along the 'up'
            direction by the top down rendering function.

        origin_y: float
            the center of the semantic map along the 'map_height' axis of the
            semantic map as viewed from a top-down render of the map.
        origin_x: float
            the center of the semantic map along the 'map_width' axis of the
            semantic map as viewed from a top-down render of the map.
        origin_z: float
            the center of the semantic map along the 'map_depth' axis of the
            semantic map as viewed from a top-down render of the map.
        grid_resolution: float
            the length of a single side of each voxel in the semantic map in
            units of the world coordinate system, which is typically meters.

        interpolation_weight: float
            float representing the interpolation weight used when adding
            new features in the feature map weighted by interpolation_weight.
        initial_feature_map: torch.Tensor
            tensor representing the initial feature map tensor,
            which will be set to zero if the value not specified by default.

        """

        super(OccupancyProjectionLayer, self).__init__(
            camera_height=camera_height, camera_width=camera_width,
            vertical_fov=vertical_fov, map_height=map_height,
            map_width=map_width, map_depth=map_depth,
            feature_size=1, dtype=dtype,
            origin_y=origin_y, origin_x=origin_x,
            origin_z=origin_z, grid_resolution=grid_resolution,
            interpolation_weight=interpolation_weight,
            initial_feature_map=initial_feature_map)

    def update(self, observation: Dict[str, torch.Tensor]):
        """Update the semantic map given a map_depth image and a feature image
        by projecting the features onto voxels in the semantic map using
        a set of rays emanating from a virtual pinhole camera.

        Arguments:

        observation["position"]: torch.Tensor
            the position of the agent in the world coordinate system, where
            the position will be binned to voxels in a semantic map.
        observation["yaw"]: torch.Tensor
            a tensor representing the yaw in radians of the coordinate,
            starting from the x-axis and turning counter-clockwise.
        observation["elevation"]: torch.Tensor
            a tensor representing the elevation in radians about the x-axis,
            with positive corresponding to upwards tilt.

        observation["map_depth"]: torch.FloatTensor
            the length of the corresponding ray in world coordinates before
            hitting a surface, with shape: [height, width, 1].
        observation["features"]: Any
            a feature vector for every pixel in the imaging plane, to be
            scattered on the map, with shape: [height, width, num_classes].

        """

        # ensure all tensors have the appropriate device and dtype
        position = torch.as_tensor(observation[
            "position"], dtype=torch.float32, device=self.data.device)
        yaw = torch.as_tensor(observation[
            "yaw"], dtype=torch.float32, device=self.data.device)
        elevation = torch.as_tensor(observation[
            "elevation"], dtype=torch.float32, device=self.data.device)
        depth = torch.as_tensor(observation[
            "depth"], dtype=torch.float32, device=self.data.device)

        # update the semantic feature map using the latest observations
        super(OccupancyProjectionLayer, self).update(  # from the environment
            dict(position=position, yaw=yaw, elevation=elevation,
                 depth=depth, features=torch.ones_like(depth)))

        return self  # return self for chaining additional functions

    def visualize(self, obs: Dict[str, Any], depth_slice: slice = slice(4, 32)):
        """Helper function that returns a list of images that are used for
        visualizing the contents of the feature map contained in subclasses,
        such as visualizing object categories, or which voxels are obstacles.

        Arguments:

        obs: Dict[str, dict]
            the current observation, as a dict or Tensor, which can be
            used to visualize the current location of the agent in the scene.
        slice: Union[slice, Dict[str, slice]]
            an slice that specifies which map_depth components to use
            when rendering a top down visualization of the feature map.

        Returns:

        image: np.ndarray
            a list of numpy arrays that visualize the contents of this layer,
             such as an image showing semantic categories.

        """

        return visualize_path(
            self.data, self.world_to_map(obs["position"]), obs["yaw"],
            self.world_to_map(obs["path"]), depth_slice=depth_slice)


# Importing Libraries
import serial
import time
arduino = serial.Serial(port='/dev/ttyACM0', baudrate=9600, timeout=.1)
def write_read(x):
    arduino.write(bytes(x, 'utf-8'))
    arduino.flush()
    time.sleep(0.3)
    data = arduino.readline().decode('utf-8').rstrip()
    arduino.flush()
    return data
while True:
    num = "0.15/0.22/0.34/0.44/0.54/0.63/0.73/0.86/0.98/0.10/0.11/0.12\n"
    value = write_read(num)
    print(value)


import pygame
from globalVals import *
from scenes import *
from util import *

class Main():
    def __init__(self):
        # initialize pygame
        pygame.init()
        pygame.font.init()

        # check for config file
        configUtil.loadConfig()

        # set up window
        self.surface = pygame.display.set_mode(constants.SSIZE)
        pygame.display.set_caption(constants.TITLE)

        # pygame specifics
        self.clock = pygame.time.Clock()

        # starter scene
        self.scene = title.Title()

    def run(self):
        # main game loop
        while not flags.done:
            # get pressed keys
            keys = pygame.key.get_pressed()

            # events
            filteredEvents = []
            for event in pygame.event.get():
                filteredEvents.append(event)

            self.scene.events(filteredEvents, keys)

            # logic
            self.scene.update()

            # rendering
            self.scene.render(self.surface)

            if flags.debug:
                # show fps
                font = textUtil.setupFont(fonts.FMONO, fonts.FSML)
                text = textUtil.renderText(str(round(self.clock.get_fps())), font, colors.BLACK)
                textUtil.drawText(self.surface, text, constants.SSIZE[0] - text.get_width(), text.get_height())

            # set the next scene
            self.scene = self.scene.nextScene

            # update loop
            pygame.display.flip()
            self.clock.tick(constants.FPS)

    def quit(self):
        # terminate
        pygame.quit()

if __name__ == '__main__':
    m = Main()
    m.run()
    m.quit()


#!/usr/bin/env python

import networkx as nx

from sys import argv
from biom import example_table as et
from biom import load_table
from itertools import permutations

def make_graph(bt, shared_otus):
    """Make a graph out of shared OTUs

    Parameters
    ----------
    bt : bt.Table
        BIOM table, must have a 'taxonomy' metadata attribute for their
        observations.
    shared_otus : int
        Minimum number of shared OTUs to create an edge between two samples.

    Returns
    -------
    nx.Graph
        Graph object with the minimum number of shared OTUs.
    """
    graph = nx.Graph()
    kpc = ['k', 'p', 'c', 'o', 'f', 'g', 's']

    for o in bt.ids('observation'):
        vec = (bt.data(o, axis='observation') >= shared_otus)

        # instead of the samples themselves, these should be the latitudes
        # and longitudes
        samples = bt.ids()[vec]

        if len(samples) > 1:
            tax = bt.metadata(o, 'observation')['taxonomy']

            # pad with empty strings
            tax = tax + ((len(kpc) - len(tax)) * ['unclassified'])

            metadata = dict(zip(kpc, tax))

            for pair in permutations(samples, 2):
                graph.add_edge(pair[0], pair[1], metadata)

    return graph

if __name__ == '__main__':

    if len(argv) == 2:
        g = make_graph(load_table(argv[1]), 10)
    if len(argv) == 3:
        g = make_graph(load_table(argv[1]), int(argv[2]))
    else:
        print("Running a demo.")
        g = make_graph(et, 2)

    print('Edges: %d, Nodes: %d' % (g.number_of_edges(),
          g.number_of_nodes()))


#encoding：utf-8
#文本的格式是，id\ttitle\tcontent\tlabel
from prepcrocess import *

if __name__=='__main__':
    filename=''
    dictname = '../data/dataset_Dict.txt'
    word2vecfile = '../data/dataset_Word2Vec.txt'
    doc2Vecfilename=''
    #类别标签转换
    labeldic={'positive':1,'negative':-1}
    #K折交叉验证
    n_split=4
    #word2Vec Dim
    word2VecSize=200
    #按类别输出所有的doc及其字典,这里是为了找强特,集中在某几个类别出现的词可以单独作为特征append
    stopWfilenam = ''
    stopwords = getStopWords(stopWfilenam)
    docs,docID,labels,labelDict=getDoc(filename,labeldic)
    stopwords=getStopWords(stopWfilenam)
    docV, AllTFdic, DFdic, IDFdic,word2vec= getFeature(docs,stopwords,dictname,word2vecfile,word2VecSize)
    bdc={}
    bdcFile=open('','w',encoding='utf-8')
    for categorylabel in labeldic:
        resultname='../data/dataset_'+categorylabel+'.txt'
        getSpeCateDoc(filename, categorylabel, resultname)
        docs, docID,labels, labelDict = getDoc(resultname, labeldic)
        dictname = '../data/dataset_' + categorylabel + '_Dict.txt'
        dictname = '../data/dataset_' + categorylabel + '_Word2Vec.txt'
        docV, AllTFdic, DF_category_dic, IDFdic, word2vec= getFeature(docs,stopwords,dictname,word2vecfile,word2VecSize)
        for word in DF_category_dic:
            bdc[word]+=DF_category_dic[word]/DFdic[word]*log(DF_category_dic[word]/DFdic[word])
    for word in DFdic:
        bdc[word]=1+bdc[word]
    bdcDict=sorted(bdc.items(),key=lambda word:word[1],reversed=False)
    for word in bdcDict:
        bdcFile.write('%s,%d'%(word,bdcDict[word]))
    #这里是用AllTF/DF做特征选择
    minDF=0
    maxDF=10000
    featurelist=selectFeatByDF(DFdic,minDF,maxDF)
    # text embedding,TF*IDF/bdc,fasttext,bag of words,此处用tf*idf
    #docVec=getTextVecByTF_BDC(docV,featurelist,bdc)
    #docVec=getTextVecByOne_hot(docV,featurelist,bdc)
    #word2Vec就不用np.array()
    #docVec=getTextVecByWord2vec(docV,featurelist,word2vec,word2VecSize)
    #docVec=getTextVecByDoc2vec(docV,docID,doc2Vecfilename)
    docVec=getTextVecByTF_IDF(docV,featurelist,IDFdic)
    datasetX = np.array(docVec)
    datasetY = np.array(labels)
    kf = StratifiedKFold(n_splits=n_split)
    #model=RandomForestClassifier()
    model = GradientBoostingClassifier()
    #model = LGBMClassifier()
    #model=XGBClassifier()
    for train_index, test_index in kf.split(datasetX, datasetY):
        train_X = datasetX[train_index]
        train_y = datasetY[train_index]
        test_X = datasetX[test_index]
        test_y = datasetY[test_index]
        model.fit(train_X, train_y)
        pred_y = model.predict(test_X)
        print('micro_f1', f1_score(test_y, pred_y, average='micro'))
        print('macro_f1', f1_score(test_y, pred_y, average='macro'))


"""
The :py:mod:`vc2_conformance.decoder.assertions` module contains functions
which perform checks which are used in multiple places within a bitstream and
have been factored-out to avoid repetition.
"""

from collections import OrderedDict

from vc2_data_tables import (
    ParseCodes,
    PictureCodingModes,
)

from vc2_conformance.level_constraints import LEVEL_CONSTRAINTS

from vc2_conformance.version_constraints import MINIMUM_MAJOR_VERSION

from vc2_conformance.symbol_re import WILDCARD, END_OF_SEQUENCE

from vc2_conformance.constraint_table import allowed_values_for

from vc2_conformance.decoder.exceptions import (
    ValueNotAllowedInLevel,
    NonConsecutivePictureNumbers,
    EarliestFieldHasOddPictureNumber,
    MajorVersionTooHigh,
)

def assert_in(value, collection, exception_type, *args):
    """
    Check to see if a value is a member of the provided collection using
    ``in``. If it is not, throws an exception of the given type with the value
    and collection passed as as arguments.
    """
    if value not in collection:
        raise exception_type(value, collection, *args)

def assert_in_enum(value, enum, exception_type):
    """
    Check to see if a value is a member of the provided assertion type. If it
    is not, throws an exception of the given type with the value as argument.
    """
    try:
        enum(value)
    except ValueError:
        raise exception_type(value)

def assert_parse_code_in_sequence(parse_code, matcher, exception_type, *args):
    """
    Check that the specified parse code's name matches the next value in the
    sequence defined by :py:class:`vc2_conformance.symbol_re.Matcher`.

    If it does not, ``exception_type`` will be raised with the following
    arguments:

    * The ``parse_code`` (as a :py:class:`~vc2_data_tables.ParseCodes`)
    * A list of parse codes (as a
      :py:class:`~vc2_data_tables.ParseCodes`) which would have been
      valid (or ``None`` if any parse code would be allowed.
    * A boolean which is True if it would have been valid to end the sequence
      at this point.
    * Any additional arguments passed to this function
    """
    parse_code = ParseCodes(parse_code)

    if not matcher.match_symbol(parse_code.name):
        expected_parse_codes = []
        expected_end = False
        for parse_code_name in matcher.valid_next_symbols():
            if parse_code_name == WILDCARD:
                expected_parse_codes = None
                break
            elif parse_code_name == END_OF_SEQUENCE:
                expected_end = True
            elif expected_parse_codes is not None:
                expected_parse_codes.append(getattr(ParseCodes, parse_code_name))

        raise exception_type(parse_code, expected_parse_codes, expected_end, *args)

def assert_parse_code_sequence_ended(matcher, exception_type, *args):
    """
    Check that the specified :py:class:`vc2_conformance.symbol_re.Matcher` has
    reached a valid end for the sequence of parse codes specified.

    If the matcher still expects more parse codes, ``exception_type`` will be
    raised with the following arguments:

    * The ``parse_code`` will be None
    * A list of parse codes (as a
      :py:class:`~vc2_data_tables.ParseCodes`) which would have been
      valid (or ``None`` if any parse code would be allowed.
    * A boolean which is True if it would have been valid to end the sequence
      at this point. (Always False, in this case)
    * Any additional arguments passed to this function
    """
    if not matcher.is_complete():
        expected_parse_codes = []
        for parse_code_name in matcher.valid_next_symbols():
            if parse_code_name == WILDCARD:
                expected_parse_codes = None
                break
            elif expected_parse_codes is not None:
                expected_parse_codes.append(getattr(ParseCodes, parse_code_name))

        raise exception_type(None, expected_parse_codes, False, *args)

def assert_level_constraint(state, key, value):
    """
    Check that the given key and value is allowed according to the
    :py:data:`vc2_conformance.level_constraints.LEVEL_CONSTRAINTS`. Throws a
    :py;exc:`vc2_conformance.decoder.exceptions.ValueNotAllowedInLevel`
    exception on failure.

    Takes the current :py:class:`~vc2_conformance.pseudocode.state.State` instance from
    which the current
    :py:attr:`~vc2_conformance.pseudocode.state.State._level_constrained_values` will be
    created/updated.
    """
    state.setdefault("_level_constrained_values", OrderedDict())

    allowed_values = allowed_values_for(
        LEVEL_CONSTRAINTS,
        key,
        state["_level_constrained_values"],
    )

    if value not in allowed_values:
        raise ValueNotAllowedInLevel(
            state["_level_constrained_values"], key, value, allowed_values
        )
    else:
        state["_level_constrained_values"][key] = value

def assert_picture_number_incremented_as_expected(state, picture_number_offset):
    """
    Check that ``state["picture_number"]`` has been set to an appropriate value
    by (12.2) picture_header or (14.2) fragment_header.  It should be called
    after the picture number has been read from the stream into
    ``state["picture_number"]`` and with the
    :py:func:`~vc2_conformance.decoder.io.tell` value just after the value was
    read.

    This assertion will check that:

    * (12.2), (14.2) Picture numbers in a sequence must increment by 1 and wrap after
      2^32-1 back to zero, throwing :py:exc:`NonConsecutivePictureNumbers` if
      this is not the case.
    * (12.2), (14.2) When coded as fields, the first field in the sequence must
      have an even picture number, throwing
      :py:exc:`EarliestFieldHasOddPictureNumber` if this is not the case.

    This assertion also has the following side-effects:

    * Sets ``state["_last_picture_number"]`` to ``state["picture_number"]``
    * Sets ``state["_last_picture_number_offset"]`` to the value passed in the
      picture_number_offset argument.
    * Increments ``state["_num_pictures_in_sequence"]``

    In the case of fragments (14.2), this assertion should be called only for
    the first fragment in a picture (with fragment_slice_count==0).
    """
    # (12.2), (14.4) Picture numbers in a sequence must increment by 1 and wrap
    # after 2^32-1 back to zero
    if "_last_picture_number" in state:
        expected_picture_number = (state["_last_picture_number"] + 1) & 0xFFFFFFFF
        if state["picture_number"] != expected_picture_number:
            raise NonConsecutivePictureNumbers(
                state["_last_picture_number_offset"],
                state["_last_picture_number"],
                picture_number_offset,
                state["picture_number"],
            )
    state["_last_picture_number"] = state["picture_number"]
    state["_last_picture_number_offset"] = picture_number_offset

    # (12.2), (14.4) When coded as fields, the first field in the sequence must
    # have an even picture number.
    if state["picture_coding_mode"] == PictureCodingModes.pictures_are_fields:
        early_field = state["_num_pictures_in_sequence"] % 2 == 0
        even_number = state["picture_number"] % 2 == 0
        if early_field and not even_number:
            raise EarliestFieldHasOddPictureNumber(state["picture_number"])
    state["_num_pictures_in_sequence"] += 1

def log_version_lower_bound(state, minimum_major_version):
    """
    Records an instance where a value in the stream requires that
    major_version have a certain value. These will later be checked by
    :py:func:`assert_major_version_is_minimal`. Bounds are logged in
    ``state["_expected_major_version"]``

    Parameters
    ==========
    state : :py:class:`~vc2_conformance.pseudocode.state.State`
    minimum_major_version : int
        The minimum major version number allowed to support the feature being
        logged.
    """
    state["_expected_major_version"] = max(
        state.get("_expected_major_version", MINIMUM_MAJOR_VERSION),
        minimum_major_version,
    )

def assert_major_version_is_minimal(state):
    """
    Checks whether the major_version number supplied is the lowest possible
    major_version number for this stream (as required by (11.2.2)). Should be
    called once at the end of a stream.
    """
    major_version = state["major_version"]
    expected_major_version = state.get("_expected_major_version", MINIMUM_MAJOR_VERSION)

    # Errata: The following special case was missing from the spec
    #
    # (11.2.2) Special case for empty sequences of fragmented pictures: When an
    # encoder is configured to produce fragmented pictures in streams the
    # major_version needs to be set to '3' to allow fragmented picture data
    # units. In the case of an empty sequence, major_version may not have to be
    # '3' since no data units with a fragment parse code will be present. To
    # make the life of encoders developers easier in this special case, the
    # spec permits them to set major_version to '3' even when no fragmented
    # picture data units appear in the stream enabling them to use the same
    # sequence header for all sequences, regardless of length.
    if state["_num_pictures_in_sequence"] == 0 and major_version == 3:
        return

    if major_version > expected_major_version:
        raise MajorVersionTooHigh(major_version, expected_major_version)


# -*- coding: utf-8 -*-
# @Author  : Virace
# @Email   : Virace@aliyun.com
# @Site    : x-item.com
# @Software: Pycharm
# @Create  : 2022/8/26 14:10
# @Update  : 2023/3/9 17:11
# @Detail  : 描述

__all__ = [
    'EVENT_HASH_PATH',
    'E2A_HASH_PATH',
    'get_bin_hashes',
    'get_bnk_hashes',
    'get_event_hashes',
    'get_audio_hashes',
    'game_data',
    'game_data_default'
]

from Hashes.__main__ import E2A_HASH_PATH, EVENT_HASH_PATH, get_audio_hashes, get_bin_hashes, get_bnk_hashes, \
    get_event_hashes, game_data, game_data_default


from __future__ import print_function
from __future__ import absolute_import

import yui

import dnf.callback

class TransactionProgress(dnf.callback.TransactionProgress):

    def __init__(self):
        self.actions = {dnf.callback.PKG_CLEANUP: 'cleanup',
                        dnf.callback.PKG_DOWNGRADE: 'downgrade',
                        dnf.callback.PKG_REMOVE: 'erase',
                        dnf.callback.PKG_INSTALL: 'install',
                        dnf.callback.PKG_OBSOLETE: 'obsolete',
                        dnf.callback.PKG_REINSTALL: 'reinstall',
                        dnf.callback.PKG_UPGRADE: 'update',
                        dnf.callback.PKG_VERIFY: 'verify'}

        super(dnf.callback.TransactionProgress, self).__init__()
        self.do_verify = False

    def progress(self, package, action, te_current, te_total, ts_current,
              ts_total):
        """
        @param package: A yum package object or simple string of a package name
        @param action: A constant transaction set state
        @param te_current: current number of bytes processed in the transaction
                           element being processed
        @param te_total: total number of bytes in the transaction element being
                         processed
        @param ts_current: number of processes completed in whole transaction
        @param ts_total: total number of processes in the transaction.
        """
        if package:
            # package can be both str or dnf package object
            if not isinstance(package, str):
                pkg_id = str(package)
            else:
                pkg_id = package
            if action in self.actions:
                action = self.actions[action]

            print ("%s %s"%(pkg_id, action))
            #self.base.RPMProgress(
                #pkg_id, action, te_current, te_total, ts_current, ts_total)

class ProgressBar:

    def __init__(self, main_dialog, layout):
        self.factory = yui.YUI.widgetFactory()

        self.main_dialog = main_dialog
        self.layout = layout
        vbox = self.factory.createVBox(layout)
        hbox = self.factory.createHBox(vbox)
        self.info_widget = self.factory.createLabel(hbox, "")
        self.info_widget.setStretchable( yui.YD_HORIZ, True )
        self.info_sub_widget = self.factory.createLabel(hbox, "")
        self.info_sub_widget.setStretchable( yui.YD_HORIZ, True )
        self.progressbar = self.factory.createProgressBar(vbox, "")

    def info(self, text) :
        self.info_widget.setValue(text)
        #self.__flush()

    def info_sub(self, text) :
        self.info_sub_widget.setValue(text)
        #self.__flush()

    def set_progress(self, frac, label=None) :
        if label is not None:
            self.progressbar.setLabel(label)
        val = self.progressbar.value()
        newval = int(100*frac)
        if (val != newval) :
            self.progressbar.setValue(newval)
        #self.__flush()

    def reset_all(self) :
        self.info_widget.setValue('')
        self.info_sub_widget.setValue('')
        self.set_progress(0, "")
        self.__flush()

    def __flush(self) :
        if self.main_dialog.isTopmostDialog() :
            self.main_dialog.pollEvent()

class Progress(dnf.callback.DownloadProgress):

    def __init__(self):
        '''
        Progress bar dialog class
        '''
        super(Progress, self).__init__()
        self.factory = yui.YUI.widgetFactory()

        self.main_dialog = self.factory.createPopupDialog()
        vbox = self.factory.createVBox(self.main_dialog)
        self.label_widget = self.factory.createLabel(vbox, "")
        self.label_widget.setStretchable( yui.YD_HORIZ, True )
        self.progressbar = self.factory.createProgressBar(vbox, "")
        self.wrongValue = self.factory.createLabel(vbox, "")
        self.wrongValue.setStretchable( yui.YD_HORIZ, True )

        self.total_files = 0
        self.total_size = 0.0
        self.download_files = 0
        self.download_size = 0.0
        self.dnl = {}
        self.last_pct = 0

    def __del__(self):
        print ("Progress destroyed")
        self.main_dialog.destroy()

    def info(self, text) :
        self._setLabel(self.label_widget, text)

    def info_sub(self, text) :
        self._setLabel(self.wrongValue, text)

    def set_progress(self, frac, label=None) :
        if label is not None:
            self.progressbar.setLabel(label)
        self.progressbar.setValue(int(100*frac))

    def start(self, total_files, total_size):
        text = _("Downloading :  %(files)d files,  %(size)d bytes") % {'files': total_files, 'bytes': total_size}
        print (text)

        self._setLabel(self.label_widget, text)

        self.total_files = total_files
        self.total_size = total_size
        self.download_files = 0
        self.download_size = 0.0

        self.progressbar.setValue(0)
        self.wrongValue.setValue("")

    def end(self,payload, status, msg):
        if not status: # payload download complete
            self.download_files += 1
            self.update()
        else: # dnl end with errors
            self.update()
        self.progressbar.setValue(100)

    def progress(self, payload, done):
        pload = str(payload)
        if not pload in self.dnl:
            self.dnl[pload] = 0.0
            text = _("Starting to download : %s ") % str(payload)
            self._setLabel(self.label_widget, text)

        else:
            self.dnl[pload] = done
            pct = self.get_total()
            if pct > self.last_pct:
                self.last_pct = pct
                self.update()

    def get_total(self):
        """ Get the total downloaded percentage"""
        tot = 0.0
        for value in self.dnl.values():
            tot += value
        pct = int((tot / float(self.total_size)) * 100)
        return pct

    def update(self):
        """ Output the current progress"""
        text = _("Progress files (%(downloaded)d/%(total)d)") % {'downloaded': self.download_files, 'total': self.total_files}
        # TODO remove print(text)
        self._setLabel(self.label_widget, text)
        value = self.last_pct
        # TODO remove print ( "Value %d" % (self.last_pct))

        if (value <= 100) :
            self.progressbar.setValue(value)
        else:
            self._setLabel(self.wrongValue, text=("%d"%value))
            self.progressbar.setValue(99)

        self._flush()

    def _setLabel(self, label_widget, text=""):
        self.main_dialog.startMultipleChanges()
        label_widget.setValue(text)
        self.main_dialog.doneMultipleChanges()
        self._flush()

    def _flush (self) :
        self.main_dialog.startMultipleChanges()
        self.main_dialog.recalcLayout()
        self.main_dialog.doneMultipleChanges()

        if self.main_dialog.isTopmostDialog() :
           self.main_dialog.waitForEvent(10)
           self.main_dialog.pollEvent()
        #else :
            #Exception?  "This dialog is not a top most dialog\n"

        yui.YUI.app().redrawScreen()


from time import sleep
from random import randrange, randint
n = 0
count = 0
acertou = False
print('-=' * 30)
print('Vou pensar em um numero entre 0 e 10. Tente adivinhar...')
print('-=' * 30)
numr = int(randint(0, 10))  # randomiza o int tambem
while not acertou:
    usernum = int(input('Qual o numero que estou pensando? '))
    if usernum in range(0,11):
        if numr == usernum:
            print(f'Voce acertou na {count+1}ª tentativa(s), Parabens!')
            numr = True
        else:
            if numr < usernum:
                print("Menos... Tente outra vez.")
                count += 1
            else:
                print("Mais... Tente outra vez.")
                count += 1
    else:
        print('O numero digitado e invalido.')

CursoemVideo/Aulas/Mundo 2/Repeticao em Python (While)/ex058.py


# pylint: skip-file
"""create submissions table

Revision ID: 27a4d2c98234
Revises:
Create Date: 2020-03-26 16:24:18.968441

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import func

# revision identifiers, used by Alembic.
revision = '27a4d2c98234'
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    op.create_table(
        'submission',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('data', sa.JSON, nullable=False),
        sa.Column('date_received', sa.DateTime(timezone=True), server_default=func.now()),
        sa.Column('date_exported', sa.DateTime(timezone=True)),
        sa.Column('bluebeam_project_id', sa.String(11)),
        sa.Column('error_message', sa.String(255))
    )

def downgrade():
    op.drop_table('submission')