# plugins

repository: sneakyevil/ida_functioncolor
file: hexrays_functioncol.py
description: IDA Plugin to colorize function definition in pseudocode.
wanted_name: Hex-rays Function Colors
comment: Color function in pseudocode
created_at: 2024-05-10 21:11:05+00:00
pushed_at: 2024-09-30 23:37:42+00:00
url:
https://github.com/sneakyevil/ida_functioncolor/blob/b627bdfa9a828f9f1533202a41a341e9da48eeac/hexrays_functioncol.py

content:
import ida_hexrays
import ida_idaapi
import ida_idp
import ida_lines
import re

# Colors
FCOL_START = ida_lines.SCOLOR_DEFAULT + ida_lines.SCOLOR_DREF
FCOL_NAME = ida_lines.SCOLOR_REG
FCOL_NAMESPACE_END = ida_lines.SCOLOR_DEFAULT + ida_lines.SCOLOR_CNAME
FCOL_TEMPLATE = ida_lines.SCOLOR_DEFAULT + ida_lines.SCOLOR_SYMBOL
FCOL_BRACKET = ida_lines.SCOLOR_DEFAULT + ida_lines.SCOLOR_VOIDOP
FCOL_ARG = ida_lines.SCOLOR_DEFAULT + ida_lines.SCOLOR_REG

class HexRaysFunctionColHooks(ida_hexrays.Hexrays_Hooks):
    def _insert_color_at(self, string, index, color):
        return string[:index] + ida_lines.SCOLOR_DEFAULT + color + string[index:]

    def func_printed(self, cfunc):
        pseudocode = cfunc.get_pseudocode()
        for sl in pseudocode:
            #print(sl.line) # Print in output for testing purposes...

            # Basically first line...
            begin_bracket = sl.line.find("\x09(")
            if (begin_bracket != -1):
                # Ignores arguments that are "inline" typedefs or __shifted and other crap (maybe should find better way to fix this)
                if (sl.line.find("\x01(") == -1):
                    # Start (data_type call_convetion)
                    sl.line = sl.line.replace("\x01\x17", FCOL_START)
                    sl.line = sl.line.replace("\x01\x21", FCOL_START)

                    last_space_bb = sl.line.rfind(" ", 0, begin_bracket) # Last space before bracket (Function name start)
                    if (last_space_bb != -1):
                        sl.line = self._insert_color_at(sl.line, last_space_bb + 1, FCOL_NAME) # Function color
                        begin_bracket += 2 # Offset due to color insert

                        # Function namespace end
                        template_start = sl.line.rfind("<", last_space_bb, begin_bracket)
                        template_end = sl.line.rfind(">", last_space_bb, begin_bracket)
                        if (template_start != -1): # Has template?
                            sl.line = sl.line[:last_space_bb] + re.sub("([<)([>])", FCOL_TEMPLATE + "\\1" + ida_lines.SCOLOR_DEFAULT + FCOL_NAME, sl.line[last_space_bb:])
                            sl.line = sl.line[:last_space_bb] + re.sub("(::)([^:]+<)", "\\1" + FCOL_NAMESPACE_END + "\\2", sl.line[last_space_bb:])
                        
                        if (template_end == -1 or begin_bracket > template_end + 3):
                            sl.line = sl.line[:last_space_bb] + re.sub("(::)([^:]+\()", "\\1" + FCOL_NAMESPACE_END + "\\2", sl.line[last_space_bb:])

                    # Left bracket
                    sl.line = re.sub("(..)\(", "\\1" + FCOL_BRACKET + "(", sl.line)

                    # Arg/s
                    sl.line = re.sub("\(..", "(" + FCOL_ARG, sl.line)
                    sl.line = re.sub("(\(....)", "\\1" + FCOL_ARG, sl.line)
            else:
                # Arg
                sl.line = sl.line.replace("\x01\x17", FCOL_ARG)
                sl.line = sl.line.replace("\x01\x21", FCOL_ARG)

            # Break out of loop if we reached end
            end_bracket = sl.line.find(')')
            if (end_bracket != -1 and end_bracket > (len(sl.line) - 8)):
                sl.line = re.sub("(..)\\)", "\\1" + FCOL_BRACKET + ")", sl.line)
                break
        return 0

class HexRaysFunctionColPlugin(ida_idaapi.plugin_t):
    flags = ida_idaapi.PLUGIN_HIDE

    comment = "Color function in pseudocode"
    wanted_name = "Hex-rays Function Colors"
    wanted_hotkey = ""
    help = ""

    def init(self):
        self.hexrays_hooks = None
        self.hexrays_hooks = HexRaysFunctionColHooks()
        self.hexrays_hooks.hook()
        return ida_idaapi.PLUGIN_KEEP

    def run(self, arg):
        return

    def term(self):
        if self.hexrays_hooks:
            self.hexrays_hooks.unhook()
        pass

def PLUGIN_ENTRY():
    return HexRaysFunctionColPlugin()


repository: zhouzhicun/ida-scripts
file: python/IDA/IDAScripts/plugin_zzDumpFuncList.py
description: ida相关脚本，包括字符串解密，BR/BLR混淆, 常见加密算法实现。
created_at: 2024-09-10 08:31:38+00:00
pushed_at: 2024-09-18 03:02:56+00:00
url:
https://github.com/zhouzhicun/ida-scripts/blob/fa533f6a4130921a0013133a9777847842d87c63/python/IDA/IDAScripts/plugin_zzDumpFuncList.py

content:
import idaapi
from idaapi import plugin_t

import zzPluginBase.utils as utils
import zzPluginBase.funcUtils as funcUtils
import zzPluginBase.pluginUtils as pluginUtils


############################# 插件逻辑 ######################################

def get_all_instructions():
    allInsn = funcUtils.get_all_instructions()
    utils.writeFile("allInstructions.txt", allInsn)

#获取所有函数伪代码
def get_all_func_code():
    allFuncCode = funcUtils.get_all_func_code()
    utils.writeFile("functionCode.txt", allFuncCode)


#获取函数列表
def get_func_list():
    funcList = funcUtils.get_func_list()
    utils.writeFile("functionList.txt", funcList)


#获取函数列表，按照xref数量排序
def get_func_list_orderby_xref():
    funcList = funcUtils.get_func_list_orderby_xref()
    utils.writeFile("functionList_xref.txt", funcList)


#获取函数列表，按照指令数量排序
def get_func_list_orderby_insn_count():
    funcList = funcUtils.get_func_list_orderby_insn_count()
    utils.writeFile("functionList_insnCount.txt", funcList)

#获取函数列表，按照加解密特征指令数量排序(LSL, AND, ORR, LSR, ROR)
def get_func_list_orderby_eor():
    funcList = funcUtils.get_func_list_orderby_eor()
    utils.writeFile("functionList_eor.txt", funcList)


#获取导出函数列表
def get_export_func_list():
    funcList = funcUtils.get_export_func_list()
    utils.writeFile("functionList_export.txt", funcList)

#获取导入函数列表
def get_import_func_list():
    funcList = funcUtils.get_import_func_list()
    utils.writeFile("functionList_import.txt", funcList)





#################################### 插件配置 ##################################################

ZZDumpFunc_wanted_name = 'ZZDumpFunc'
ZZDumpFunc_comment = ''
ZZDumpFunc_help = ''
ZZDumpFunc_wanted_hotkey = ''
ZZDumpFunc_flags = idaapi.PLUGIN_KEEP

ZZDumpFuncMenuConfig = pluginUtils.PluginMenuConfig("ZZDumpFunc/", [
    pluginUtils.PluginSubMenu('my:dump_all_instructions', 'dump函数所有汇编', get_all_instructions),
    pluginUtils.PluginSubMenu('my:dump_func_code', 'dump函数伪代码', get_all_func_code),
    pluginUtils.PluginSubMenu('my:dump_func_list', 'dump函数列表', get_func_list),
    pluginUtils.PluginSubMenu('my:dump_func_orderby_xref', 'dump函数列表，按xref引用排序', get_func_list_orderby_xref),
    pluginUtils.PluginSubMenu('my:dump_func_orderby_insnCount', 'dump函数列表，按指令数排序', get_func_list_orderby_insn_count),
    pluginUtils.PluginSubMenu('my:dump_func_orderby_eor', 'dump函数列表，按逻辑指令数排序', get_func_list_orderby_eor),
    pluginUtils.PluginSubMenu('my:dump_func_exports', 'dump导出符号表', get_export_func_list),
    pluginUtils.PluginSubMenu('my:dump_func_imports', 'dump导入符号表', get_import_func_list),
])




#################################### 插件框架 ##################################################

class ZZDumpFuncUIHooks(idaapi.UI_Hooks):
    def finish_populating_widget_popup(self, widget, popup_handle, ctx):
        pluginUtils.registerUIHook(widget, popup_handle, ZZDumpFuncMenuConfig)


class ZZDumpFunc(plugin_t):

    wanted_name = ZZDumpFunc_wanted_name
    comment = ZZDumpFunc_comment
    help = ZZDumpFunc_help
    wanted_hotkey = ZZDumpFunc_wanted_hotkey
    flags = ZZDumpFunc_flags


    def init(self):

        pluginUtils.registerAction(ZZDumpFuncMenuConfig)

        global my_ui_hooks
        my_ui_hooks = ZZDumpFuncUIHooks()
        my_ui_hooks.hook()

        return idaapi.PLUGIN_KEEP

    # 插件运行中 这里是主要逻辑
    def run(self, arg: int):
        pass

    def term(self):
        pass 


# 注册插件
def PLUGIN_ENTRY():
    return ZZDumpFunc()


repository: BlackVS/IDA-exportsymbols
file: plugin/exportsymbols.py
description: IDA 7.0 plugin to export different symbols from ELF to txt and/or ELF file
created_at: 2020-10-31 06:32:33+00:00
pushed_at: 2020-10-31 06:53:36+00:00
url:
https://github.com/BlackVS/IDA-exportsymbols/blob/ecbd5b34a2a87091cd0ddf8d088f53bb700d6d49/plugin/exportsymbols.py

content:
#!/usr/bin/python
# -*- coding: utf-8 -*-

#  Export symbols
#  2020 
#
#  Volodymyr Sydorenko <vvs [at] coders.in.ua>
#  www: coders.in.ua
#  git: github.com/BlackVS 
#       gitlab.com/BlackVS
#
#  This program 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.


import os,sys

from exportsymbols.elf import *
from ctypes import *
from struct import unpack

DEBUG = False
PLUG_NAME    = "Export symbols to file"

sys.path.append('..\\python')
sys.path.append('..\\python\\lib\\python2.7\\lib-dynload\\ida_64')

import idc
import idaapi
import idautils


from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt

def dummy_breakpoint():
    return

BREAK = dummy_breakpoint
if DEBUG:
    import ptvsd
    try:
        ptvsd.enable_attach(address=('127.0.0.1', 5678))
        ptvsd.wait_for_attach()
        BREAK = ptvsd.break_into_debugger
    except:
        pass


LOG_ENABLE=True
def logger(arg):
    if LOG_ENABLE:
        print(arg)



###################################################################################################

def show_proc_info():
    info = idaapi.get_inf_structure()
    if info.is_64bit():
        bits = 64
    elif info.is_32bit():
        bits = 32
    else:
        bits = 16

    try:
        is_be = info.is_be()
    except:
        is_be = info.mf
    endian = "big" if is_be else "little"

    print("Processor: {}, {}-bit, {} endian".format(info.procName, bits, endian))


###################################################################################################
#  ELF parser - based on the lib of ROPgadget tool by Jonathan Salwan
#  http://shell-storm.org/project/ROPgadget/
#  taken from https://github.com/danigargu/syms2elf

SHN_UNDEF = 0
STB_GLOBAL_FUNC = 0x12

class SHTypes:
    SHT_NULL      = 0
    SHT_PROGBITS  = 1
    SHT_SYMTAB    = 2
    SHT_STRTAB    = 3
    SHT_RELA      = 4
    SHT_HASH      = 5
    SHT_DYNAMIC   = 6
    SHT_NOTE      = 7
    SHT_NOBITS    = 8
    SHT_REL       = 9
    SHT_SHLIB     = 10
    SHT_DYNSYM    = 11
    SHT_NUM       = 12
    SHT_LOPROC    = 0x70000000
    SHT_HIPROC    = 0x7fffffff
    SHT_LOUSER    = 0x80000000
    SHT_HIUSER    = 0xffffffff

class ELFFlags:
    ELFCLASS32  = 0x01
    ELFCLASS64  = 0x02
    EI_CLASS    = 0x04
    EI_DATA     = 0x05
    ELFDATA2LSB = 0x01
    ELFDATA2MSB = 0x02
    EM_386      = 0x03
    EM_X86_64   = 0x3e
    EM_ARM      = 0x28
    EM_MIPS     = 0x08
    EM_SPARCv8p = 0x12
    EM_PowerPC  = 0x14
    EM_ARM64    = 0xb7

class SymFlags:
    STB_LOCAL   = 0
    STB_GLOBAL  = 1
    STB_WEAK    = 2
    STT_NOTYPE  = 0
    STT_OBJECT  = 1
    STT_FUNC    = 2
    STT_SECTION = 3
    STT_FILE    = 4
    STT_COMMON  = 5
    STT_TLS     = 6

class Elf32_Ehdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("e_ident",         c_ubyte * 16),
                    ("e_type",          c_ushort),
                    ("e_machine",       c_ushort),
                    ("e_version",       c_uint),
                    ("e_entry",         c_uint),
                    ("e_phoff",         c_uint),
                    ("e_shoff",         c_uint),
                    ("e_flags",         c_uint),
                    ("e_ehsize",        c_ushort),
                    ("e_phentsize",     c_ushort),
                    ("e_phnum",         c_ushort),
                    ("e_shentsize",     c_ushort),
                    ("e_shnum",         c_ushort),
                    ("e_shstrndx",      c_ushort)
                ]
 
class Elf64_Ehdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("e_ident",         c_ubyte * 16),
                    ("e_type",          c_ushort),
                    ("e_machine",       c_ushort),
                    ("e_version",       c_uint),
                    ("e_entry",         c_ulonglong),
                    ("e_phoff",         c_ulonglong),
                    ("e_shoff",         c_ulonglong),
                    ("e_flags",         c_uint),
                    ("e_ehsize",        c_ushort),
                    ("e_phentsize",     c_ushort),
                    ("e_phnum",         c_ushort),
                    ("e_shentsize",     c_ushort),
                    ("e_shnum",         c_ushort),
                    ("e_shstrndx",      c_ushort)
                ]

class Elf32_Phdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("p_type",          c_uint),
                    ("p_offset",        c_uint),
                    ("p_vaddr",         c_uint),
                    ("p_paddr",         c_uint),
                    ("p_filesz",        c_uint),
                    ("p_memsz",         c_uint),
                    ("p_flags",         c_uint),
                    ("p_align",         c_uint)
                ]

class Elf64_Phdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("p_type",          c_uint),
                    ("p_flags",         c_uint),
                    ("p_offset",        c_ulonglong),
                    ("p_vaddr",         c_ulonglong),
                    ("p_paddr",         c_ulonglong),
                    ("p_filesz",        c_ulonglong),
                    ("p_memsz",         c_ulonglong),
                    ("p_align",         c_ulonglong)
                ]

class Elf32_Shdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("sh_name",         c_uint),
                    ("sh_type",         c_uint),
                    ("sh_flags",        c_uint),
                    ("sh_addr",         c_uint),
                    ("sh_offset",       c_uint),
                    ("sh_size",         c_uint),
                    ("sh_link",         c_uint),
                    ("sh_info",         c_uint),
                    ("sh_addralign",    c_uint),
                    ("sh_entsize",      c_uint)
                ]

class Elf64_Shdr_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("sh_name",         c_uint),
                    ("sh_type",         c_uint),
                    ("sh_flags",        c_ulonglong),
                    ("sh_addr",         c_ulonglong),
                    ("sh_offset",       c_ulonglong),
                    ("sh_size",         c_ulonglong),
                    ("sh_link",         c_uint),
                    ("sh_info",         c_uint),
                    ("sh_addralign",    c_ulonglong),
                    ("sh_entsize",      c_ulonglong)
                ]

class Elf32_Ehdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("e_ident",         c_ubyte * 16),
                    ("e_type",          c_ushort),
                    ("e_machine",       c_ushort),
                    ("e_version",       c_uint),
                    ("e_entry",         c_uint),
                    ("e_phoff",         c_uint),
                    ("e_shoff",         c_uint),
                    ("e_flags",         c_uint),
                    ("e_ehsize",        c_ushort),
                    ("e_phentsize",     c_ushort),
                    ("e_phnum",         c_ushort),
                    ("e_shentsize",     c_ushort),
                    ("e_shnum",         c_ushort),
                    ("e_shstrndx",      c_ushort)
                ]
 
class Elf64_Ehdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("e_ident",         c_ubyte * 16),
                    ("e_type",          c_ushort),
                    ("e_machine",       c_ushort),
                    ("e_version",       c_uint),
                    ("e_entry",         c_ulonglong),
                    ("e_phoff",         c_ulonglong),
                    ("e_shoff",         c_ulonglong),
                    ("e_flags",         c_uint),
                    ("e_ehsize",        c_ushort),
                    ("e_phentsize",     c_ushort),
                    ("e_phnum",         c_ushort),
                    ("e_shentsize",     c_ushort),
                    ("e_shnum",         c_ushort),
                    ("e_shstrndx",      c_ushort)
                ]

class Elf32_Phdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("p_type",          c_uint),
                    ("p_offset",        c_uint),
                    ("p_vaddr",         c_uint),
                    ("p_paddr",         c_uint),
                    ("p_filesz",        c_uint),
                    ("p_memsz",         c_uint),
                    ("p_flags",         c_uint),
                    ("p_align",         c_uint)
                ]

class Elf64_Phdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("p_type",          c_uint),
                    ("p_flags",         c_uint),
                    ("p_offset",        c_ulonglong),
                    ("p_vaddr",         c_ulonglong),
                    ("p_paddr",         c_ulonglong),
                    ("p_filesz",        c_ulonglong),
                    ("p_memsz",         c_ulonglong),
                    ("p_align",         c_ulonglong)
                ]

class Elf32_Shdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("sh_name",         c_uint),
                    ("sh_type",         c_uint),
                    ("sh_flags",        c_uint),
                    ("sh_addr",         c_uint),
                    ("sh_offset",       c_uint),
                    ("sh_size",         c_uint),
                    ("sh_link",         c_uint),
                    ("sh_info",         c_uint),
                    ("sh_addralign",    c_uint),
                    ("sh_entsize",      c_uint)
                ]

class Elf64_Shdr_MSB(BigEndianStructure):
    _fields_ =  [
                    ("sh_name",         c_uint),
                    ("sh_type",         c_uint),
                    ("sh_flags",        c_ulonglong),
                    ("sh_addr",         c_ulonglong),
                    ("sh_offset",       c_ulonglong),
                    ("sh_size",         c_ulonglong),
                    ("sh_link",         c_uint),
                    ("sh_info",         c_uint),
                    ("sh_addralign",    c_ulonglong),
                    ("sh_entsize",      c_ulonglong)
                ]

class Elf32_Sym_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("st_name",         c_uint),
                    ("st_value",        c_uint),
                    ("st_size",         c_uint),
                    ("st_info",         c_ubyte),
                    ("st_other",        c_ubyte),
                    ("st_shndx",        c_ushort)
                ]

class Elf64_Sym_LSB(LittleEndianStructure):
    _fields_ =  [
                    ("st_name",         c_uint),
                    ("st_info",         c_ubyte),
                    ("st_other",        c_ubyte),
                    ("st_shndx",        c_ushort),
                    ("st_value",        c_ulonglong),
                    ("st_size",         c_ulonglong)
                ]

class Elf32_Sym_MSB(BigEndianStructure):
    _fields_ =  [
                    ("st_name",         c_uint),
                    ("st_value",        c_uint),
                    ("st_size",         c_uint),
                    ("st_info",         c_ubyte),
                    ("st_other",        c_ubyte),
                    ("st_shndx",        c_ushort)
                ]

class Elf64_Sym_MSB(BigEndianStructure):
    _fields_ =  [
                    ("st_name",         c_uint),
                    ("st_info",         c_ubyte),
                    ("st_other",        c_ubyte),
                    ("st_shndx",        c_ushort),
                    ("st_value",        c_ulonglong),
                    ("st_size",         c_ulonglong)
                ]


""" This class parses the ELF """
class ELF:
    def __init__(self, binary):
        self.binary    = bytearray(binary)
        self.ElfHeader = None
        self.shdr_l    = []
        self.phdr_l    = []
        self.syms_l    = []
        self.e_ident   = self.binary[:15]
        self.ei_data   = unpack("<B", self.e_ident[ELFFlags.EI_DATA:ELFFlags.EI_DATA+1])[0] # LSB/MSB
        
        self.__setHeaderElf()
        self.__setShdr()
        self.__setPhdr()

    def is_stripped(self):
        if not self.get_symtab():
            return True
        if not self.get_strtab():
            return True
        return False

    def strip_symbols(self):        
        sh2delete = 2
        size2dec  = 0
        end_shdr  = self.ElfHeader.e_shoff + (self.sizeof_sh() * self.ElfHeader.e_shnum)

        symtab = self.get_symtab()
        strtab = self.get_strtab()

        if not symtab or not strtab:
            return False

        log("Stripping binary...")

        if symtab.sh_offset < end_shdr:
            size2dec += symtab.sh_size

        if strtab.sh_offset < end_shdr:
            size2dec += strtab.sh_size

        self.ElfHeader.e_shoff -= size2dec
        self.ElfHeader.e_shnum -= sh2delete

        e_shnum = self.ElfHeader.e_shnum
        e_shoff = self.ElfHeader.e_shoff
        sz_striped = (e_shoff + (e_shnum * self.sizeof_sh()))        

        if strtab.sh_offset > symtab.sh_offset:
            self.cut_at_offset(strtab.sh_offset, strtab.sh_size)  
            self.cut_at_offset(symtab.sh_offset, symtab.sh_size)
        else:
            self.cut_at_offset(symtab.sh_offset, symtab.sh_size)
            self.cut_at_offset(strtab.sh_offset, strtab.sh_size)

        self.binary = self.binary[0:sz_striped]
        self.write(0, self.ElfHeader)
        return True

    def get_symtab(self):
        shstrtab = bytes(self.get_shstrtab_data())
        for sh in self.shdr_l:
            sh_name = shstrtab[sh.sh_name:].split(b"\0")[0]
            if  sh.sh_type == SHTypes.SHT_SYMTAB and \
                (sh.sh_name == SHN_UNDEF or sh_name == ".symtab"):
                return sh
        return None

    def get_strtab(self):
        shstrtab = bytes(self.get_shstrtab_data())
        for sh in self.shdr_l:
            sh_name = shstrtab[sh.sh_name:].split(b"\0")[0]
            if  sh.sh_type == SHTypes.SHT_STRTAB and \
                (sh.sh_name == SHN_UNDEF or sh_name == ".strtab"):
                return sh
        return None

    def getArchMode(self):
        if self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS32: 
            return 32
        elif self.ElfHeader.e_ident[ELFFlags.EI_CLASS] == ELFFlags.ELFCLASS64: 
            return 64
        else:
            log("[Error] ELF.getArchMode() - Bad Arch size")
            return None

    """ Parse ELF header """
    def __setHeaderElf(self):
        e_ident = self.binary[:15]

        ei_class = unpack("<B", e_ident[ELFFlags.EI_CLASS:ELFFlags.EI_CLASS+1])[0]
        ei_data  = unpack("<B", e_ident[ELFFlags.EI_DATA:ELFFlags.EI_DATA+1])[0]

        if ei_class != ELFFlags.ELFCLASS32 and ei_class != ELFFlags.ELFCLASS64:
            log("[Error] ELF.__setHeaderElf() - Bad Arch size")
            return None

        if ei_data != ELFFlags.ELFDATA2LSB and ei_data != ELFFlags.ELFDATA2MSB:
            log("[Error] ELF.__setHeaderElf() - Bad architecture endian")
            return None

        if ei_class == ELFFlags.ELFCLASS32: 
            if   ei_data == ELFFlags.ELFDATA2LSB: self.ElfHeader = Elf32_Ehdr_LSB.from_buffer_copy(self.binary)
            elif ei_data == ELFFlags.ELFDATA2MSB: self.ElfHeader = Elf32_Ehdr_MSB.from_buffer_copy(self.binary)
        elif ei_class == ELFFlags.ELFCLASS64: 
            if   ei_data == ELFFlags.ELFDATA2LSB: self.ElfHeader = Elf64_Ehdr_LSB.from_buffer_copy(self.binary)
            elif ei_data == ELFFlags.ELFDATA2MSB: self.ElfHeader = Elf64_Ehdr_MSB.from_buffer_copy(self.binary)

    """ Write the section header to self.binary """
    def write_shdr(self):
        off = self.ElfHeader.e_shoff
        for sh in self.shdr_l:
            self.write(off, sh)
            off += off + sizeof(sh) 

    """ Parse Section header """
    def __setShdr(self):
        shdr_num = self.ElfHeader.e_shnum
        base = self.binary[self.ElfHeader.e_shoff:]
        shdr_l = []

        e_ident = self.binary[:15]
        ei_data = unpack("<B", e_ident[ELFFlags.EI_DATA:ELFFlags.EI_DATA+1])[0]

        for i in range(shdr_num):
            if self.getArchMode() == 32:
                if   ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
                elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
            elif self.getArchMode() == 64:
                if   ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
                elif ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)

            self.shdr_l.append(shdr)
            base = base[self.ElfHeader.e_shentsize:]

        string_table = self.binary[(self.shdr_l[self.ElfHeader.e_shstrndx].sh_offset):]
        for i in range(shdr_num):
            self.shdr_l[i].str_name = string_table[self.shdr_l[i].sh_name:].split(b'\0')[0]

    """ Parse Program header """
    def __setPhdr(self):
        pdhr_num = self.ElfHeader.e_phnum
        base = self.binary[self.ElfHeader.e_phoff:]
        phdr_l = []

        e_ident = self.binary[:15]
        ei_data = unpack("<B", e_ident[ELFFlags.EI_DATA:ELFFlags.EI_DATA+1])[0]

        for i in range(pdhr_num):
            if self.getArchMode() == 32:
                if   ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf32_Phdr_LSB.from_buffer_copy(base)
                elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf32_Phdr_MSB.from_buffer_copy(base)
            elif self.getArchMode() == 64:
                if   ei_data == ELFFlags.ELFDATA2LSB: phdr = Elf64_Phdr_LSB.from_buffer_copy(base)
                elif ei_data == ELFFlags.ELFDATA2MSB: phdr = Elf64_Phdr_MSB.from_buffer_copy(base)

            self.phdr_l.append(phdr)
            base = base[self.ElfHeader.e_phentsize:]

    def get_section_id(self, sh_name):
        for idx, sh in enumerate(self.shdr_l):
            if sh.str_name == sh_name.encode('ascii'):
                return idx
        return None

    def get_shstrtab_data(self):
        sh = self.shdr_l[self.ElfHeader.e_shstrndx]
        if sh.sh_type == SHTypes.SHT_STRTAB:
            return self.binary[sh.sh_offset:sh.sh_offset+sh.sh_size]
        return None

    def get_sym_at_offset(self, off):
        if self.getArchMode() == 32:
            if   ei_data == ELFFlags.ELFDATA2LSB: sym = Elf32_Sym_LSB.from_buffer_copy(self.binary[off:])
            elif ei_data == ELFFlags.ELFDATA2MSB: sym = Elf32_Sym_MSB.from_buffer_copy(self.binary[off:])
        elif self.getArchMode() == 64:
            if   ei_data == ELFFlags.ELFDATA2LSB: sym = Elf64_Sym_LSB.from_buffer_copy(self.binary[off:])
            elif ei_data == ELFFlags.ELFDATA2MSB: sym = Elf64_Sym_MSB.from_buffer_copy(self.binary[off:])
        return sym

    def get_entrypoint(self):
        return self.e_entry

    def sizeof_sh(self):
        size = None
        if self.getArchMode() == 32:
            size = sizeof(Elf32_Shdr_LSB())
        elif self.getArchMode() == 64:
            size = sizeof(Elf64_Shdr_LSB())
        return size

    def sizeof_sym(self):
        size = None
        if self.getArchMode() == 32:
            size = sizeof(Elf32_Sym_LSB)
        elif self.getArchMode() == 64:
            size = sizeof(Elf64_Sym_LSB)
        return size

    def append_section_header(self, section):
        sh = None

        if self.getArchMode() == 32:
            if   self.ei_data == ELFFlags.ELFDATA2LSB: sh = Elf32_Shdr_LSB()
            elif self.ei_data == ELFFlags.ELFDATA2MSB: sh = Elf32_Shdr_MSB()
        elif self.getArchMode() == 64:
            if   self.ei_data == ELFFlags.ELFDATA2LSB: sh = Elf64_Shdr_LSB()
            elif self.ei_data == ELFFlags.ELFDATA2MSB: sh = Elf64_Shdr_MSB()

        sh.sh_name      = section["name"]
        sh.sh_type      = section["type"]
        sh.sh_flags     = section["flags"]
        sh.sh_addr      = section["addr"]
        sh.sh_offset    = section["offset"]
        sh.sh_size      = section["size"]
        sh.sh_link      = section["link"]
        sh.sh_info      = section["info"]
        sh.sh_addralign = section["addralign"]
        sh.sh_entsize   = section["entsize"]

        self.binary.extend(sh)

    def append_symbol(self, symbol):
        if self.getArchMode() == 32:
            if   self.ei_data == ELFFlags.ELFDATA2LSB: sym = Elf32_Sym_LSB()
            elif self.ei_data == ELFFlags.ELFDATA2MSB: sym = Elf32_Sym_MSB()
        elif self.getArchMode() == 64:
            if   self.ei_data == ELFFlags.ELFDATA2LSB: sym = Elf64_Sym_LSB()
            elif self.ei_data == ELFFlags.ELFDATA2MSB: sym = Elf64_Sym_MSB()

        sym.st_name   = symbol["name"]
        sym.st_value  = symbol["value"]
        sym.st_size   = symbol["size"]
        sym.st_info   = symbol["info"]
        sym.st_other  = symbol["other"]
        sym.st_shndx  = symbol["shndx"]

        self.binary.extend(sym)

    def get_binary(self):
        return self.binary

    def write(self, offset, data):
        self.binary[offset:offset+sizeof(data)] = data

    def expand_at_offset(self, offset, data):
        self.binary = self.binary[:offset] + data + self.binary[offset:]

    def cut_at_offset(self, offset, size):
        self.binary = self.binary[:offset] + self.binary[offset+size:]

    def save(self, output):
        with open(output, 'wb') as f:
            f.write(self.binary)


###################################################################################################
def write_symbols(input_file, output_file, symbols):
    try:        
        with open(input_file, 'rb') as f:
            bin = ELF(f.read())

        if len(symbols) < 1:
            log("No symbols to export")
            return

        log("Exporting symbols to ELF...")
        bin.strip_symbols()

        # raw strtab
        strtab_raw = b"\x00" + b"\x00".join([sym_name.encode('ascii') for sym_name in symbols.keys()]) + b"\x00"

        symtab = {
            "name"      : SHN_UNDEF,
            "type"      : SHTypes.SHT_SYMTAB,
            "flags"     : 0,
            "addr"      : 0,
            "offset"    : len(bin.binary) + (bin.sizeof_sh() * (bin.ElfHeader.e_shnum + 2)),
            "size"      : (len(symbols) + 1) * bin.sizeof_sym(),
            "link"      : bin.ElfHeader.e_shnum + 1, # index of SHT_STRTAB
            "info"      : 1,
            "addralign" : 4,
            "entsize"   : bin.sizeof_sym()
        }

        off_strtab = (len(bin.binary) + (bin.sizeof_sh() * (bin.ElfHeader.e_shnum + 2)) + (bin.sizeof_sym() * (len(symbols) + 1)))

        strtab = {
            "name"      : SHN_UNDEF,
            "type"      : SHTypes.SHT_STRTAB,
            "flags"     : 0,
            "addr"      : 0,
            "offset"    : off_strtab,
            "size"      : len(strtab_raw),
            "link"      : 0,
            "info"      : 0,
            "addralign" : 1,
            "entsize"   : 0
        }

        shdrs = bin.binary[bin.ElfHeader.e_shoff:bin.ElfHeader.e_shoff + (bin.sizeof_sh() * bin.ElfHeader.e_shnum)]
        bin.ElfHeader.e_shnum += 2
        bin.ElfHeader.e_shoff = len(bin.binary)
        bin.write(0, bin.ElfHeader)
        bin.binary.extend(shdrs)

        base = bin.binary[bin.ElfHeader.e_shoff:]
        _off = bin.ElfHeader.e_shoff
        for i in range(bin.ElfHeader.e_shnum - 2):
            if bin.getArchMode() == 32:
                if   bin.ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf32_Shdr_LSB.from_buffer_copy(base)
                elif bin.ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf32_Shdr_MSB.from_buffer_copy(base)
            elif bin.getArchMode() == 64:
                if   bin.ei_data == ELFFlags.ELFDATA2LSB: shdr = Elf64_Shdr_LSB.from_buffer_copy(base)
                elif bin.ei_data == ELFFlags.ELFDATA2MSB: shdr = Elf64_Shdr_MSB.from_buffer_copy(base)
            base = base[bin.ElfHeader.e_shentsize:]
            bin.write(_off, shdr)
            _off += bin.sizeof_sh()
        bin.append_section_header(symtab)
        bin.append_section_header(strtab)

        # Local symbol - separator
        sym = {
            "name"  : 0,
            "value" : 0,
            "size"  : 0,
            "info"  : SymFlags.STB_LOCAL,
            "other" : 0,
            "shndx" : 0 
        }
        bin.append_symbol(sym)

        # add symbols  
        BREAK()
        for st_name, (st_type, st_ea, st_size, st_seg) in symbols.items():
            
            st_info = SymFlags.STB_GLOBAL << 4
            if st_type=="FUNC":
                st_info|=SymFlags.STT_FUNC
            elif st_type=="OBJECT":
                st_info|=SymFlags.STT_OBJECT
            else:
                st_info|=SymFlags.STT_NOTYPE
    

            sh_idx = bin.get_section_id(st_seg)
            if not sh_idx:
                log("ERROR: Section ID for '%s' not found" % st_seg)
                continue

            sym = {
                "name"  : strtab_raw.index(st_name.encode('ascii')),
                "value" : st_ea,
                "size"  : st_size,
                "info"  : st_info,
                "other" : 0,
                "shndx" : sh_idx
            }

            #log("0x%08x - 0x%08x - %s - %d/%d - %d" % (s.value, s.size, s.name, strtab_raw.index(s.name), len(strtab_raw), s.info))
            bin.append_symbol(sym)

        # add symbol strings
        bin.binary.extend(strtab_raw)

        log("ELF saved to: %s" % output_file)
        bin.save(output_file)

    except:
        log(traceback.format_exc())


def export2elf(filename, symbols):
    show_proc_info()
    input_file_name = idc.GetInputFile()
    input_file_type = idaapi.get_file_type_name(input_file_name)
    print("Input file type: {}".format(input_file_type))
    if  "ELF" not in input_file_type:
        msg("Only ELF input file supported!")
        return 

    write_symbols(input_file_name, filename, symbols)
    









###################################################################################################


IDAVIEW_FUNCTIONS = 1
IDAVIEW_NAMES     = 2
IDAVIEW_EXPORTS   = 3

OPTIONS_EXCLUDE_PRE_SUB = 1
OPTIONS_EXCLUDE_PRE_UNKNOWN = 2
OPTIONS_EXCLUDE_FUNCTIONS = 3
OPTIONS_EXCLUDE_DATA = 4

class Ui_ExportSymbols_Dialog(object):
    parent = None
    data_segments = None
    data_views = None
    data_options = None

    def setupUi(self, Dialog):
        self.parent=Dialog
        Dialog.setObjectName("Dialog")
        Dialog.resize(600, 400)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth())
        Dialog.setSizePolicy(sizePolicy)
        Dialog.setMinimumSize(QtCore.QSize(600, 400))
        Dialog.setMaximumSize(QtCore.QSize(600, 400))
        Dialog.setModal(True)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(420, 360, 161, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.labelSegments = QtWidgets.QLabel(Dialog)
        self.labelSegments.setGeometry(QtCore.QRect(30, 10, 231, 16))
        self.labelSegments.setObjectName("labelSegments")
        self.groupViews2Export = QtWidgets.QGroupBox(Dialog)
        self.groupViews2Export.setGeometry(QtCore.QRect(380, 30, 201, 131))
        self.groupViews2Export.setObjectName("groupViews2Export")
        self.checkFunctions = QtWidgets.QCheckBox(self.groupViews2Export)
        self.checkFunctions.setGeometry(QtCore.QRect(20, 20, 70, 17))
        self.checkFunctions.setChecked(True)
        self.checkFunctions.setObjectName("checkFunctions")
        self.checkNames = QtWidgets.QCheckBox(self.groupViews2Export)
        self.checkNames.setGeometry(QtCore.QRect(20, 40, 70, 17))
        self.checkNames.setObjectName("checkNames")
        self.checkExports = QtWidgets.QCheckBox(self.groupViews2Export)
        self.checkExports.setGeometry(QtCore.QRect(20, 60, 70, 17))
        self.checkExports.setObjectName("checkExports")
        self.segmentsWidget = QtWidgets.QTableWidget(Dialog)
        self.segmentsWidget.setGeometry(QtCore.QRect(20, 31, 351, 281))
        self.segmentsWidget.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.segmentsWidget.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.segmentsWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
        #self.segmentsWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.segmentsWidget.setGridStyle(QtCore.Qt.DashLine)
        self.segmentsWidget.setWordWrap(False)
        self.segmentsWidget.setRowCount(0)
        self.segmentsWidget.setColumnCount(3)
        self.segmentsWidget.setObjectName("segmentsWidget")
        self.segmentsWidget.horizontalHeader().setVisible(True)
        self.segmentsWidget.horizontalHeader().setCascadingSectionResizes(True)
        self.segmentsWidget.horizontalHeader().setSortIndicatorShown(False)
        self.segmentsWidget.horizontalHeader().setStretchLastSection(False)
        self.segmentsWidget.verticalHeader().setVisible(False)
        self.segmentsWidget.verticalHeader().setMinimumSectionSize(15)
        self.segmentsWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        self.groupOptions = QtWidgets.QGroupBox(Dialog)
        self.groupOptions.setGeometry(QtCore.QRect(380, 160, 201, 151))
        self.groupOptions.setObjectName("groupOptions")
        self.checkExcludeSub = QtWidgets.QCheckBox(self.groupOptions)
        self.checkExcludeSub.setGeometry(QtCore.QRect(10, 20, 171, 17))
        self.checkExcludeSub.setChecked(True)
        self.checkExcludeSub.setObjectName("checkExcludeSub")
        self.checkExcludeUnknown = QtWidgets.QCheckBox(self.groupOptions)
        self.checkExcludeUnknown.setGeometry(QtCore.QRect(10, 40, 181, 17))
        self.checkExcludeUnknown.setChecked(True)
        self.checkExcludeUnknown.setObjectName("checkExcludeUnknown")
        self.checkExcludeFuncs = QtWidgets.QCheckBox(self.groupOptions)
        self.checkExcludeFuncs.setGeometry(QtCore.QRect(10, 60, 181, 17))
        self.checkExcludeFuncs.setObjectName("checkExcludeFuncs")
        self.checkExcludeData = QtWidgets.QCheckBox(self.groupOptions)
        self.checkExcludeData.setGeometry(QtCore.QRect(10, 80, 181, 17))
        self.checkExcludeData.setObjectName("checkExcludeData")

        self.retranslateUi(Dialog)
        #self.buttonBox.accepted.connect(Dialog.accept)
        self.buttonBox.accepted.connect(self.accept_and_save_data)
        self.buttonBox.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Export symbols"))
        self.labelSegments.setText(_translate("Dialog", "Segments to export"))
        self.groupViews2Export.setTitle(_translate("Dialog", "Symbols types to export"))
        self.checkFunctions.setToolTip(_translate("Dialog", "<html><head/><body><p>Export symbols from Functions IDA view</p></body></html>"))
        self.checkFunctions.setText(_translate("Dialog", "Functions"))
        self.checkNames.setToolTip(_translate("Dialog", "<html><head/><body><p>Export symbols from Names IDA view</p></body></html>"))
        self.checkNames.setText(_translate("Dialog", "Names"))
        self.checkExports.setToolTip(_translate("Dialog", "<html><head/><body><p>Export symbols from Exports IDA view</p></body></html>"))
        self.checkExports.setText(_translate("Dialog", "Exports"))
        self.segmentsWidget.setSortingEnabled(False)
        self.segmentsWidget.setHorizontalHeaderLabels( ["Name","Start","End"])
        self.segmentsWidget.setColumnWidth(0, self.segmentsWidget.width() / 2  )
        self.segmentsWidget.setColumnWidth(1, self.segmentsWidget.width() / 4  )
        self.segmentsWidget.setColumnWidth(2, self.segmentsWidget.width() / 4  )
        # palette = self.segmentsWidget.horizontalHeader().palette()
        # palette.setColor( QtGui.QPalette.Normal, QtGui.QPalette.Window, Qt.red )
        # self.segmentsWidget.horizontalHeader().setPalette( palette )
        self.groupOptions.setTitle(_translate("Dialog", "Options"))
        self.checkExcludeSub.setText(_translate("Dialog", "Exclude \"sub_*\""))
        self.checkExcludeUnknown.setText(_translate("Dialog", "Exclude \"unknown_*\""))
        self.checkExcludeFuncs.setText(_translate("Dialog", "Exclude functions"))
        self.checkExcludeData.setText(_translate("Dialog", "Exclude data"))

    def accept_and_save_data(self):
        logger("Saving data from dialog...")

        #print( self.segmentsWidget.item(0, 0).text() )
        self.data_segments = []
        #ptvsd.break_into_debugger()        
        for idx in range( self.segmentsWidget.rowCount() ):
            if self.segmentsWidget.item(idx, 0).checkState()!=QtCore.Qt.Checked:
                continue
            sname = self.segmentsWidget.item(idx, 0).text()
            saddr = self.segmentsWidget.item(idx, 1).text()
            send  = self.segmentsWidget.item(idx, 2).text()
            self.data_segments.append( (sname, saddr, send) )

        self.data_views = dict()
        self.data_views[IDAVIEW_FUNCTIONS] = self.checkFunctions.checkState() == QtCore.Qt.Checked
        self.data_views[IDAVIEW_NAMES] = self.checkNames.checkState() == QtCore.Qt.Checked
        self.data_views[IDAVIEW_EXPORTS] = self.checkExports.checkState() == QtCore.Qt.Checked


        self.data_options = dict()
        self.data_options[OPTIONS_EXCLUDE_DATA] = self.checkExcludeData.checkState() == QtCore.Qt.Checked
        self.data_options[OPTIONS_EXCLUDE_FUNCTIONS] = self.checkExcludeFuncs.checkState() == QtCore.Qt.Checked
        self.data_options[OPTIONS_EXCLUDE_PRE_SUB] = self.checkExcludeSub.checkState() == QtCore.Qt.Checked
        self.data_options[OPTIONS_EXCLUDE_PRE_UNKNOWN] = self.checkExcludeUnknown.checkState() == QtCore.Qt.Checked

        self.parent.accept()

class ExportSymbolsWidget(QtWidgets.QDialog):
    UNKNOWN_TYPE    = 0
    USER_TYPE       = 1
    STANDARD_TYPE   = 2
    LOCAL_TYPE      = 3

    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self, parent)
        try:
            self.tinfo = None
            self.inputType = self.USER_TYPE
            logger('ExportSymbolsWidget starting up')
            self.ui = Ui_ExportSymbols_Dialog()
            self.ui.setupUi(self)
        except Exception as err:
            logger('Error during init: %s' % str(err))

    def LoadData(self):
        cnt = ida_segment.get_segm_qty()
        self.ui.segmentsWidget.setRowCount(cnt)
        for idx, s_ea in enumerate(idautils.Segments()):
            seg_name =idc.get_segm_name(s_ea)
            seg_start=idc.get_segm_start(s_ea)
            seg_end  =idc.get_segm_end(s_ea)-1
             
            item0 = QtWidgets.QTableWidgetItem()
            item0.setText(seg_name)
            item0.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
            item0.setCheckState(QtCore.Qt.Checked)
            self.ui.segmentsWidget.setItem(idx, 0, item0)

            item1 = QtWidgets.QTableWidgetItem()
            item1.setText( "0x{:04x}".format(seg_start))
            self.ui.segmentsWidget.setItem(idx, 1, item1)

            item2 = QtWidgets.QTableWidgetItem()
            item2.setText( "0x{:04x}".format(seg_end))
            self.ui.segmentsWidget.setItem(idx, 2, item2)

        self.ui.segmentsWidget.resizeRowsToContents()
        

    def get_segments(self):
        return self.ui.data_segments

    def get_views(self):
        return self.ui.data_views

    def get_options(self):
        return self.ui.data_options



class ExportSymsPlugin(idaapi.plugin_t):
    flags = idaapi.PLUGIN_UNL #unload after each run, for debug. After - FIX
    comment = ""
    help = ""
    wanted_name = PLUG_NAME
    wanted_hotkey = "Ctrl+`"

    ida_segments = None
    ida_views = None
    ida_options = dict()
    
    exported_symbols = None

    def init(self):
        return idaapi.PLUGIN_OK #Plugin agrees to work with the current database but will be loaded only when it is about to be invoked.

    def run(self, arg=0):
        logger('Starting up')

        show_proc_info()

        try:
            dlg = ExportSymbolsWidget()
            dlg.LoadData()
            oldTo = idaapi.set_script_timeout(0)
            res = dlg.exec_()
            idaapi.set_script_timeout(oldTo)

            if res != QtWidgets.QDialog.Accepted:
                #logger('Dialog rejected')
                return
            #logger('Dialog accepted. Input type: %d' % dlg.inputType)

            fileName, fileExt = QtWidgets.QFileDialog.getSaveFileName(caption="Save file", filter = "Text file (*.txt);;ELF file (*.elf)")
            logger(fileName)
            if "ELF" in fileName:
                print("Output to ELF not yet supported")
                return

            #ptvsd.break_into_debugger()
            self.ida_segments = dlg.get_segments()
            self.ida_views    = dlg.get_views()
            self.ida_options  = dlg.get_options()
            
            self.exported_symbols = self.get_symbols_from_ida()

            #ptvsd.break_into_debugger()

            if ".txt" in fileExt:
                with open(fileName,"wt") as ft:
                    idx = 0
                    exclude_pre_sub = self.ida_options[OPTIONS_EXCLUDE_PRE_SUB]
                    exclude_pre_unknown = self.ida_options[OPTIONS_EXCLUDE_PRE_UNKNOWN]
                    exclude_functions = self.ida_options[OPTIONS_EXCLUDE_FUNCTIONS]
                    exclude_data = self.ida_options[OPTIONS_EXCLUDE_DATA]
                    for s_name, sdata in sorted(self.exported_symbols.items(), key=lambda a: a[1][1]):
                        if exclude_pre_sub and s_name.startswith("sub_"):
                            continue
                        if exclude_pre_unknown and s_name.startswith("unknown_"):
                            continue
                        s_type, s_start, s_size, s_seg = sdata[0], sdata[1], sdata[2], sdata[3]
                        if exclude_functions and s_type=="FUNC":
                            continue
                        if exclude_data and s_type=="OBJECT":
                            continue
                        ft.write("{:4} 0x{:04x} {:4} {:6} {:7} {:7} {:10} {}\n".format(idx, s_start, s_size, s_type, "GLOBAL", "DEFAULT", s_seg, s_name))
                        idx+=1
                    print("Finally wrote {} symbols. Some symbols could be skipped due to set options".format(idx))
            elif ".elf" in fileExt:
                export2elf(fileName, self.exported_symbols)

        except Exception as err:
            logger("Exception caught: %s" % str(err))

    def term(self):
        pass


    def get_symbols_from_ida(self):
        symbols = dict()
        segs = [ s[0] for s in self.ida_segments]

        if self.ida_views[IDAVIEW_FUNCTIONS] and not self.ida_options.get(OPTIONS_EXCLUDE_FUNCTIONS,False):
            for f in idautils.Functions():
                fn_seg = idc.SegName(f)
                if fn_seg not in segs:
                    continue
                func     = idaapi.get_func(f)
                fn_name  = idc.GetFunctionName(f)
                fn_start = int(func.startEA)
                fn_size  = int(func.size())
                symbols[fn_name] = ("FUNC", fn_start, fn_size, fn_seg) 
            print("Found {} functions names from Functions IDA view".format(len(symbols)))

        #ptvsd.break_into_debugger()
        if self.ida_views[IDAVIEW_NAMES]:
            cnt_unk = 0
            cnt_data = 0
            cnt_code = 0
            for n_ea, n_name in idautils.Names():
                n_seg = idc.get_segm_name(n_ea)
                if n_seg not in segs:
                    continue
                n_flags = idc.GetFlags(n_ea)
                is_data = idc.is_data(n_flags)
                is_code = idc.is_code(n_flags)
                is_unknown = idc.is_unknown(n_flags) #not explored
                is_head = idc.is_head(n_flags)

                n_size = idc.get_item_size(n_ea)
                if symbols.get(n_name, False):
                    #print("Found duplicate {}, skip".format(n_name))
                    continue

                if is_unknown: #write as NOTYPE
                    symbols[n_name] = ("NOTYPE", n_ea, n_size, n_seg) 
                    cnt_unk+=1

                if is_data: #write as OBJECT
                    symbols[n_name] = ("OBJECT", n_ea, n_size, n_seg) 
                    cnt_data+=1

                if is_code: #write as FUNC, but they couldbe inside func
                    if is_head: #function name, some of them not listed in Functions View
                        symbols[n_name] = ("FUNC", n_ea, n_size, n_seg) 
                    else:
                        #ptvsd.break_into_debugger()
                        symbols[n_name] = ("FUNC", n_ea, n_size, n_seg) 
                    cnt_code+=1

            print("Found new {} unexplored data names from Names IDA view".format(cnt_unk))
            print("Found new {} data names from Names IDA view".format(cnt_data))
            print("Found new {} code names from Names IDA view".format(cnt_code))

        #ptvsd.break_into_debugger()
        if self.ida_views[IDAVIEW_EXPORTS]:
            cnt_unk = 0
            cnt_data = 0
            cnt_code = 0
            for exp_i, exp_ord, exp_ea, exp_name in idautils.Entries():
                #print("idx=%s ordinal=[#%d] name=[0x%08x]" % (exp_name, exp_ord, exp_ea))
                exp_seg = idc.get_segm_name(exp_ea)
                if exp_seg not in segs:
                    continue
                exp_flags = idc.GetFlags(exp_ea)
                is_data = idc.is_data(exp_flags)
                is_code = idc.is_code(exp_flags)
                is_unknown = idc.is_unknown(exp_flags) #not explored
                is_head = idc.is_head(exp_flags)

                exp_size = idc.get_item_size(exp_ea)
                if symbols.get(exp_name, False):
                    #print("Found duplicate {}, skip".format(exp_name))
                    continue

                if is_unknown: #write as NOTYPE
                    symbols[exp_name] = ("NOTYPE", exp_ea, exp_size, exp_seg) 
                    cnt_unk+=1

                if is_data: #write as OBJECT
                    symbols[exp_name] = ("OBJECT", exp_ea, exp_size, exp_seg) 
                    cnt_data+=1

                if is_code: #write as FUNC, but they couldbe inside func
                    func     = idaapi.get_func(exp_ea)
                    symbols[exp_name] = ("FUNC", exp_ea, 0, exp_seg) #set zero size due to exp_size = operator size
                    cnt_code+=1

            print("Found new {} unexplored data names from Exports IDA view".format(cnt_unk))
            print("Found new {} data names from Exports IDA view".format(cnt_data))
            print("Found new {} code names from Exports IDA view".format(cnt_code))

        #ptvsd.break_into_debugger()
        return symbols

def PLUGIN_ENTRY():
    return ExportSymsPlugin()


repository: VNRev/awesome_ida_9_plugins
file: lazyida/LazyIDA.py
description: make ida9 plugin great again!
wanted_name: LazyIDA
comment: LazyIDA
created_at: 2024-08-10 10:05:08+00:00
pushed_at: 2024-08-11 22:05:36+00:00
url:
https://github.com/VNRev/awesome_ida_9_plugins/blob/6d770ae29019dab0d7fe0e0e840a444c706811f6/lazyida/LazyIDA.py

content:
from __future__ import division
from __future__ import print_function
from struct import unpack
import idaapi
import idautils
import idc

from PyQt5.Qt import QApplication

ACTION_CONVERT = ["lazyida:convert%d" % i for i in range(10)]
ACTION_SCANVUL = "lazyida:scanvul"
ACTION_COPYEA = "lazyida:copyea"
ACTION_GOTOCLIP = "lazyida:gotoclip"
ACTION_XORDATA = "lazyida:xordata"
ACTION_FILLNOP = "lazyida:fillnop"

ACTION_HX_REMOVERETTYPE = "lazyida:hx_removerettype"
ACTION_HX_COPYEA = "lazyida:hx_copyea"
ACTION_HX_COPYNAME = "lazyida:hx_copyname"
ACTION_HX_GOTOCLIP = "lazyida:hx_gotoclip"

u16 = lambda x: unpack("<H", x)[0]
u32 = lambda x: unpack("<I", x)[0]
u64 = lambda x: unpack("<Q", x)[0]

ARCH = 0
BITS = 0

def copy_to_clip(data):
    QApplication.clipboard().setText(data)

def clip_text():
    return QApplication.clipboard().text()

def parse_location(loc):
    try:
        loc = int(loc, 16)
    except ValueError:
        try:
            loc = idc.get_name_ea_simple(loc.encode().strip())
        except:
            return idaapi.BADADDR
    return loc

class VulnChoose(idaapi.Choose):
    """
    Chooser class to display result of format string vuln scan
    """
    def __init__(self, title, items, icon, embedded=False):
        idaapi.Choose.__init__(self, title, [["Address", 20], ["Function", 30], ["Format", 30]], embedded=embedded)
        self.items = items
        self.icon = 45

    def GetItems(self):
        return self.items

    def SetItems(self, items):
        self.items = [] if items is None else items

    def OnClose(self):
        pass

    def OnGetLine(self, n):
        return self.items[n]

    def OnGetSize(self):
        return len(self.items)

    def OnSelectLine(self, n):
        idc.jumpto(int(self.items[n][0], 16))

class hotkey_action_handler_t(idaapi.action_handler_t):
    """
    Action handler for hotkey actions
    """
    def __init__(self, action):
        idaapi.action_handler_t.__init__(self)
        self.action = action

    def activate(self, ctx):
        if self.action == ACTION_COPYEA:
            ea = idc.get_screen_ea()
            if ea != idaapi.BADADDR:
                copy_to_clip("0x%X" % ea)
                print("Address 0x%X has been copied to clipboard" % ea)
        elif self.action == ACTION_GOTOCLIP:
            loc = parse_location(clip_text())
            if loc != idaapi.BADADDR:
                print("Goto location 0x%x" % loc)
                idc.jumpto(loc)
        return 1

    def update(self, ctx):
        if idaapi.IDA_SDK_VERSION >= 770:
            target_attr = "widget_type"
        else:
            target_attr = "form_type"
        if ctx.__getattribute__(target_attr) in (idaapi.BWN_DISASM, idaapi.BWN_DUMP):
            return idaapi.AST_ENABLE_FOR_WIDGET
        else:
            return idaapi.AST_DISABLE_FOR_WIDGET

class menu_action_handler_t(idaapi.action_handler_t):
    """
    Action handler for menu actions
    """
    def __init__(self, action):
        idaapi.action_handler_t.__init__(self)
        self.action = action

    def activate(self, ctx):
        if self.action in ACTION_CONVERT:
            # convert
            t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t(), idaapi.get_current_viewer()
            if idaapi.read_selection(view, t0, t1):
                start, end = t0.place(view).toea(), t1.place(view).toea()
                size = end - start + 1
            elif idc.get_item_size(idc.get_screen_ea()) > 1:
                start = idc.get_screen_ea()
                size = idc.get_item_size(start)
                end = start + size
            else:
                return False

            data = idc.get_bytes(start, size)
            if isinstance(data, str):  # python2 compatibility
                data = bytearray(data)
            name = idc.get_name(start, idc.GN_VISIBLE)
            if not name:
                name = "data"
            if data:
                print("\n[+] Dump 0x%X - 0x%X (%u bytes) :" % (start, end, size))
                if self.action == ACTION_CONVERT[0]:
                    # escaped string
                    output = '"%s"' % "".join("\\x%02X" % b for b in data)
                elif self.action == ACTION_CONVERT[1]:
                    # hex string
                    output = "".join("%02X" % b for b in data)
                elif self.action == ACTION_CONVERT[2]:
                    # C array
                    output = "unsigned char %s[%d] = {" % (name, size)
                    for i in range(size):
                        if i % 16 == 0:
                            output += "\n    "
                        output += "0x%02X, " % data[i]
                    output = output[:-2] + "\n};"
                elif self.action == ACTION_CONVERT[3]:
                    # C array word
                    data += b"\x00"
                    array_size = (size + 1) // 2
                    output = "unsigned short %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 2):
                        if i % 16 == 0:
                            output += "\n    "
                        output += "0x%04X, " % u16(data[i:i+2])
                    output = output[:-2] + "\n};"
                elif self.action == ACTION_CONVERT[4]:
                    # C array dword
                    data += b"\x00" * 3
                    array_size = (size + 3) // 4
                    output = "unsigned int %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 4):
                        if i % 32 == 0:
                            output += "\n    "
                        output += "0x%08X, " % u32(data[i:i+4])
                    output = output[:-2] + "\n};"
                elif self.action == ACTION_CONVERT[5]:
                    # C array qword
                    data += b"\x00" * 7
                    array_size = (size + 7) // 8
                    output = "unsigned long %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 8):
                        if i % 32 == 0:
                            output += "\n    "
                        output += "0x%016X, " % u64(data[i:i+8])
                    output = output[:-2] + "\n};"
                elif self.action == ACTION_CONVERT[6]:
                    # python list
                    output = "[%s]" % ", ".join("0x%02X" % b for b in data)
                elif self.action == ACTION_CONVERT[7]:
                    # python list word
                    data += b"\x00"
                    output = "[%s]" % ", ".join("0x%04X" % u16(data[i:i+2]) for i in range(0, size, 2))
                elif self.action == ACTION_CONVERT[8]:
                    # python list dword
                    data += b"\x00" * 3
                    output = "[%s]" % ", ".join("0x%08X" % u32(data[i:i+4]) for i in range(0, size, 4))
                elif self.action == ACTION_CONVERT[9]:
                    # python list qword
                    data += b"\x00" * 7
                    output = "[%s]" %  ", ".join("%#018X" % u64(data[i:i+8]) for i in range(0, size, 8)).replace("0X", "0x")
                copy_to_clip(output)
                print(output)
        elif self.action == ACTION_XORDATA:
            t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t(), idaapi.get_current_viewer()
            if idaapi.read_selection(view, t0, t1):
                start, end = t0.place(view).toea(), t1.place(view).toea()
            else:
                if idc.get_item_size(idc.get_screen_ea()) > 1:
                    start = idc.get_screen_ea()
                    end = start + idc.get_item_size(start)
                else:
                    return False

            data = idc.get_bytes(start, end - start)
            if isinstance(data, str):  # python2 compatibility
                data = bytearray(data)
            x = idaapi.ask_long(0, "Xor with...")
            if x:
                x &= 0xFF
                print("\n[+] Xor 0x%X - 0x%X (%u bytes) with 0x%02X:" % (start, end, end - start, x))
                print(repr("".join(chr(b ^ x) for b in data)))
        elif self.action == ACTION_FILLNOP:
            t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t(), idaapi.get_current_viewer()
            if idaapi.read_selection(view, t0, t1):
                start, end = t0.place(view).toea(), t1.place(view).toea()
                idaapi.patch_bytes(start, b"\x90" * (end - start))
                print("\n[+] Fill 0x%X - 0x%X (%u bytes) with NOPs" % (start, end, end - start))
        elif self.action == ACTION_SCANVUL:
            print("\n[+] Finding Format String Vulnerability...")
            found = []
            for addr in idautils.Functions():
                name = idc.get_func_name(addr)
                if "printf" in name and "v" not in name and idc.get_segm_name(addr) in (".text", ".plt", ".idata", ".plt.got"):
                    xrefs = idautils.CodeRefsTo(addr, False)
                    for xref in xrefs:
                        vul = self.check_fmt_function(name, xref)
                        if vul:
                            found.append(vul)
            if found:
                print("[!] Done! %d possible vulnerabilities found." % len(found))
                ch = VulnChoose("Vulnerability", found, None, False)
                ch.Show()
            else:
                print("[-] No format string vulnerabilities found.")
        else:
            return 0

        return 1

    def update(self, ctx):
        return idaapi.AST_ENABLE_ALWAYS

    @staticmethod
    def check_fmt_function(name, addr):
        """
        Check if the format string argument is not valid
        """
        function_head = idc.get_func_attr(addr, idc.FUNCATTR_START)

        while True:
            addr = idc.prev_head(addr)
            op = idc.print_insn_mnem(addr).lower()
            dst = idc.print_operand(addr, 0)

            if op in ("ret", "retn", "jmp", "b") or addr < function_head:
                return

            c = idc.get_cmt(addr, 0)
            if c and c.lower() == "format":
                break
            elif name.endswith(("snprintf_chk",)):
                if op in ("mov", "lea") and dst.endswith(("r8", "r8d", "[esp+10h]")):
                    break
            elif name.endswith(("sprintf_chk",)):
                if op in ("mov", "lea") and (dst.endswith(("rcx", "[esp+0Ch]", "R3")) or
                                             dst.endswith("ecx") and BITS == 64):
                    break
            elif name.endswith(("snprintf", "fnprintf")):
                if op in ("mov", "lea") and (dst.endswith(("rdx", "[esp+8]", "R2")) or
                                             dst.endswith("edx") and BITS== 64):
                    break
            elif name.endswith(("sprintf", "fprintf", "dprintf", "printf_chk")):
                if op in ("mov", "lea") and (dst.endswith(("rsi", "[esp+4]", "R1")) or
                                             dst.endswith("esi") and BITS == 64):
                    break
            elif name.endswith("printf"):
                if op in ("mov", "lea") and (dst.endswith(("rdi", "[esp]", "R0")) or
                                             dst.endswith("edi") and BITS == 64):
                    break

        # format arg found, check its type and value
        # get last oprend
        op_index = idc.generate_disasm_line(addr, 0).count(",")
        op_type = idc.get_operand_type(addr, op_index)
        opnd = idc.print_operand(addr, op_index)

        if op_type == idc.o_reg:
            # format is in register, try to track back and get the source
            _addr = addr
            while True:
                _addr = idc.prev_head(_addr)
                _op = idc.print_insn_mnem(_addr).lower()
                if _op in ("ret", "retn", "jmp", "b") or _addr < function_head:
                    break
                elif _op in ("mov", "lea", "ldr") and idc.print_operand(_addr, 0) == opnd:
                    op_type = idc.get_operand_type(_addr, 1)
                    opnd = idc.print_operand(_addr, 1)
                    addr = _addr
                    break

        if op_type == idc.o_imm or op_type == idc.o_mem:
            # format is a memory address, check if it's in writable segment
            op_addr = idc.get_operand_value(addr, op_index)
            seg = idaapi.getseg(op_addr)
            if seg:
                if not seg.perm & idaapi.SEGPERM_WRITE:
                    # format is in read-only segment
                    return

        print("0x%X: Possible Vulnerability: %s, format = %s" % (addr, name, opnd))
        return ["0x%X" % addr, name, opnd]

class hexrays_action_handler_t(idaapi.action_handler_t):
    """
    Action handler for hexrays actions
    """
    def __init__(self, action):
        idaapi.action_handler_t.__init__(self)
        self.action = action
        self.ret_type = {}

    def activate(self, ctx):
        if self.action == ACTION_HX_REMOVERETTYPE:
            vdui = idaapi.get_widget_vdui(ctx.widget)
            self.remove_rettype(vdui)
            vdui.refresh_ctext()
        elif self.action == ACTION_HX_COPYEA:
            ea = idaapi.get_screen_ea()
            if ea != idaapi.BADADDR:
                copy_to_clip("0x%X" % ea)
                print("Address 0x%X has been copied to clipboard" % ea)
        elif self.action == ACTION_HX_COPYNAME:
            highlight = idaapi.get_highlight(idaapi.get_current_viewer()) 
            name = highlight[0] if highlight else None
            if name:
                copy_to_clip(name)
                print("%s has been copied to clipboard" % name)
        elif self.action == ACTION_HX_GOTOCLIP:
            loc = parse_location(clip_text())
            print("Goto location 0x%x" % loc)
            idc.jumpto(loc)
        else:
            return 0

        return 1

    def update(self, ctx):
        vdui = idaapi.get_widget_vdui(ctx.widget)
        return idaapi.AST_ENABLE_FOR_WIDGET if vdui else idaapi.AST_DISABLE_FOR_WIDGET

    def remove_rettype(self, vu):
        if vu.item.citype == idaapi.VDI_FUNC:
            # current function
            ea = vu.cfunc.entry_ea
            old_func_type = idaapi.tinfo_t()
            if not vu.cfunc.get_func_type(old_func_type):
                return False
        elif vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr() and vu.item.e.type.is_funcptr():
            # call xxx
            ea = vu.item.get_ea()
            old_func_type = idaapi.tinfo_t()

            func = idaapi.get_func(ea)
            if func:
                try:
                    cfunc = idaapi.decompile(func)
                except idaapi.DecompilationFailure:
                    return False

                if not cfunc.get_func_type(old_func_type):
                    return False
            else:
                return False
        else:
            return False

        fi = idaapi.func_type_data_t()
        if ea != idaapi.BADADDR and old_func_type.get_func_details(fi):
            # Return type is already void
            if fi.rettype.is_decl_void():
                # Restore ret type
                if ea not in self.ret_type:
                    return True
                ret = self.ret_type[ea]
            else:
                # Save ret type and change it to void
                self.ret_type[ea] = fi.rettype
                ret = idaapi.BT_VOID

            # Create new function info with new rettype
            fi.rettype = idaapi.tinfo_t(ret)

            # Create new function type with function info
            new_func_type = idaapi.tinfo_t()
            new_func_type.create_func(fi)

            # Apply new function type
            if idaapi.apply_tinfo(ea, new_func_type, idaapi.TINFO_DEFINITE):
                return vu.refresh_view(True)

        return False

class UI_Hook(idaapi.UI_Hooks):
    def __init__(self):
        idaapi.UI_Hooks.__init__(self)

    def finish_populating_widget_popup(self, form, popup):
        form_type = idaapi.get_widget_type(form)

        if form_type == idaapi.BWN_DISASM or form_type == idaapi.BWN_DUMP:
            t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t(), idaapi.get_current_viewer()
            if idaapi.read_selection(view, t0, t1) or idc.get_item_size(idc.get_screen_ea()) > 1:
                idaapi.attach_action_to_popup(form, popup, ACTION_XORDATA, None)
                idaapi.attach_action_to_popup(form, popup, ACTION_FILLNOP, None)
                for action in ACTION_CONVERT:
                    idaapi.attach_action_to_popup(form, popup, action, "Convert/")

        if form_type == idaapi.BWN_DISASM and (ARCH, BITS) in [(idaapi.PLFM_386, 32),
                                                               (idaapi.PLFM_386, 64),
                                                               (idaapi.PLFM_ARM, 32),]:
            idaapi.attach_action_to_popup(form, popup, ACTION_SCANVUL, None)


class HexRays_Hook(object):
    def callback(self, event, *args):
        if event == idaapi.hxe_populating_popup:
            form, phandle, vu = args
            if vu.item.citype == idaapi.VDI_FUNC or (vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr() and vu.item.e.type.is_funcptr()):
                idaapi.attach_action_to_popup(form, phandle, ACTION_HX_REMOVERETTYPE, None)
        elif event == idaapi.hxe_double_click:
            vu, shift_state = args
            # auto jump to target if clicked item is xxx->func();
            if vu.item.citype == idaapi.VDI_EXPR and vu.item.e.is_expr():
                expr = idaapi.tag_remove(vu.item.e.print1(None))
                if "->" in expr:
                    # find target function
                    name = expr.split("->")[-1]
                    addr = idc.get_name_ea_simple(name)
                    if addr == idaapi.BADADDR:
                        # try class::function
                        e = vu.item.e
                        while e.x:
                            e = e.x
                        addr = idc.get_name_ea_simple("%s::%s" % (str(e.type).split()[0], name))

                    if addr != idaapi.BADADDR:
                        idc.jumpto(addr)
                        return 1
        return 0

class LazyIDA_t(idaapi.plugin_t):
    flags = idaapi.PLUGIN_HIDE
    comment = "LazyIDA"
    help = ""
    wanted_name = "LazyIDA"
    wanted_hotkey = ""

    def init(self):
        self.hexrays_inited = False
        self.registered_actions = []
        self.registered_hx_actions = []

        global ARCH
        global BITS
        ARCH = idaapi.ph_get_id()

        if idaapi.inf_is_64bit():
            BITS = 64
        elif idaapi.inf_is_32bit_exactly():
            BITS = 32
        else:
            BITS = 16

        print("LazyIDA (v1.0.0.3) plugin has been loaded.")

        # Register menu actions
        menu_actions = (
            idaapi.action_desc_t(ACTION_CONVERT[0], "Convert to string", menu_action_handler_t(ACTION_CONVERT[0]), None, None, 80),
            idaapi.action_desc_t(ACTION_CONVERT[1], "Convert to hex string", menu_action_handler_t(ACTION_CONVERT[1]), None, None, 8),
            idaapi.action_desc_t(ACTION_CONVERT[2], "Convert to C/C++ array (BYTE)", menu_action_handler_t(ACTION_CONVERT[2]), None, None, 38),
            idaapi.action_desc_t(ACTION_CONVERT[3], "Convert to C/C++ array (WORD)", menu_action_handler_t(ACTION_CONVERT[3]), None, None, 38),
            idaapi.action_desc_t(ACTION_CONVERT[4], "Convert to C/C++ array (DWORD)", menu_action_handler_t(ACTION_CONVERT[4]), None, None, 38),
            idaapi.action_desc_t(ACTION_CONVERT[5], "Convert to C/C++ array (QWORD)", menu_action_handler_t(ACTION_CONVERT[5]), None, None, 38),
            idaapi.action_desc_t(ACTION_CONVERT[6], "Convert to python list (BYTE)", menu_action_handler_t(ACTION_CONVERT[6]), None, None, 201),
            idaapi.action_desc_t(ACTION_CONVERT[7], "Convert to python list (WORD)", menu_action_handler_t(ACTION_CONVERT[7]), None, None, 201),
            idaapi.action_desc_t(ACTION_CONVERT[8], "Convert to python list (DWORD)", menu_action_handler_t(ACTION_CONVERT[8]), None, None, 201),
            idaapi.action_desc_t(ACTION_CONVERT[9], "Convert to python list (QWORD)", menu_action_handler_t(ACTION_CONVERT[9]), None, None, 201),
            idaapi.action_desc_t(ACTION_XORDATA, "Get xored data", menu_action_handler_t(ACTION_XORDATA), None, None, 9),
            idaapi.action_desc_t(ACTION_FILLNOP, "Fill with NOPs", menu_action_handler_t(ACTION_FILLNOP), None, None, 9),
            idaapi.action_desc_t(ACTION_SCANVUL, "Scan format string vulnerabilities", menu_action_handler_t(ACTION_SCANVUL), None, None, 160),
        )
        for action in menu_actions:
            idaapi.register_action(action)
            self.registered_actions.append(action.name)

        # Register hotkey actions
        hotkey_actions = (
            idaapi.action_desc_t(ACTION_COPYEA, "Copy EA", hotkey_action_handler_t(ACTION_COPYEA), "w", "Copy current EA", 0),
            idaapi.action_desc_t(ACTION_GOTOCLIP, "Goto clip EA", hotkey_action_handler_t(ACTION_GOTOCLIP), "Shift-G", "Goto clipboard EA", 0),
        )
        for action in hotkey_actions:
            idaapi.register_action(action)
            self.registered_actions.append(action.name)

        # Add ui hook
        self.ui_hook = UI_Hook()
        self.ui_hook.hook()

        # Add hexrays ui callback
        if idaapi.init_hexrays_plugin():
            addon = idaapi.addon_info_t()
            addon.id = "tw.l4ys.lazyida"
            addon.name = "LazyIDA"
            addon.producer = "Lays"
            addon.url = "https://github.com/L4ys/LazyIDA"
            addon.version = "1.0.0.3"
            idaapi.register_addon(addon)

            hx_actions = (
                idaapi.action_desc_t(ACTION_HX_REMOVERETTYPE, "Remove return type", hexrays_action_handler_t(ACTION_HX_REMOVERETTYPE), "v"),
                idaapi.action_desc_t(ACTION_HX_COPYEA, "Copy ea", hexrays_action_handler_t(ACTION_HX_COPYEA), "w"),
                idaapi.action_desc_t(ACTION_HX_COPYNAME, "Copy name", hexrays_action_handler_t(ACTION_HX_COPYNAME), "c"),
                idaapi.action_desc_t(ACTION_HX_GOTOCLIP, "Goto clipboard ea", hexrays_action_handler_t(ACTION_HX_GOTOCLIP), "Shift-G"),
            )
            for action in hx_actions:
                idaapi.register_action(action)
                self.registered_hx_actions.append(action.name)

            self.hx_hook = HexRays_Hook()
            idaapi.install_hexrays_callback(self.hx_hook.callback)
            self.hexrays_inited = True

        return idaapi.PLUGIN_KEEP

    def run(self, arg):
        pass

    def term(self):
        if hasattr(self, "ui_hook"):
            self.ui_hook.unhook()

        # Unregister actions
        for action in self.registered_actions:
            idaapi.unregister_action(action)

        if self.hexrays_inited:
            # Unregister hexrays actions
            for action in self.registered_hx_actions:
                idaapi.unregister_action(action)
            if self.hx_hook:
                idaapi.remove_hexrays_callback(self.hx_hook.callback)
            idaapi.term_hexrays_plugin()

def PLUGIN_ENTRY():
    return LazyIDA_t()


repository: michaeljgoodman/Dumpulator-IDA
file: dumpulator.py
description: Currently proof-of-concept
comment: Dumpulate
created_at: 2021-12-16 19:59:14+00:00
pushed_at: 2021-12-17 00:06:07+00:00
url:
https://github.com/michaeljgoodman/Dumpulator-IDA/blob/1e9d71637db34f55df5d5f45a985605b922150ed/dumpulator.py

content:
import sys
import idaapi
import idautils
import idc
import ida_kernwin
from ida_kernwin import Choose
import ida_enum
import ida_bytes
import ida_netnode

from dumpulator import Dumpulator

__AUTHOR__ = 'Micycle'

PLUGIN_NAME = "dumpulate"
PLUGIN_HOTKEY = 'Alt+Shift+d'
VERSION = '0.0.0'


major, minor = map(int, idaapi.get_kernel_version().split("."))
using_ida7api = (major > 6)


#--------------------------------------------------------------------------
# Global settings
#--------------------------------------------------------------------------
def global_settings():
    global DUMP_FILE
    DUMP_FILE = ida_kernwin.ask_file(1, "*", "Enter the name of dump file:")
    print("You have selected " + DUMP_FILE)
    global dp
    dp = Dumpulator(DUMP_FILE)
    return 




#--------------------------------------------------------------------------
# Number of Args Form
#--------------------------------------------------------------------------
class arg_num_select_t(ida_kernwin.Form):
    """Simple form to select how many args to initialise"""
    def __init__(self):
        self.__n = 0
        F = ida_kernwin.Form
        F.__init__(self,
r"""BUTTON YES* Select
BUTTON CANCEL Cancel
Creating Function Arg Array

{FormChangeCb}
{cStr1} 
<##Number of args      :{iArgCount}>



""", {      'FormChangeCb': F.FormChangeCb(self.OnFormChange),
            'cStr1': F.StringLabel("<span style='float:left;'>How many arguments will you be passing?<span>", tp=F.FT_HTML_LABEL),
            'iArgCount': F.StringInput(),
        })

        
    def OnFormChange(self, fid):
        return 1

    @staticmethod
    def show():
        f = arg_num_select_t()
        f, args = f.Compile()
        # Show form
        ok = f.Execute()
        if ok == 1:
            arg_count = f.iArgCount.value
            f.Free()
            print("Initiated " + arg_count + " args in array")
            return arg_count
        else:
            f.Free()
            return None
#--------------------------------------------------------------------------
# Arg chooser Form
#--------------------------------------------------------------------------
class arg_select_t(ida_kernwin.Form):
    """Simple form to select argument"""
    def __init__(self):
        self.__n = 0
        F = ida_kernwin.Form
        F.__init__(self,
r"""BUTTON YES* Select
BUTTON CANCEL Cancel
Choose which argument to set

{FormChangeCb}
{cStr1} 
<##Argument      :{iArgNum}>



""", {      'FormChangeCb': F.FormChangeCb(self.OnFormChange),
            'cStr1': F.StringLabel("<span style='float:left;'>Which argument would you like to set?<span>", tp=F.FT_HTML_LABEL),
            'iArgNum': F.StringInput(),
        })

        
    def OnFormChange(self, fid):
        return 1

    @staticmethod
    def show():
        f = arg_select_t()
        f, args = f.Compile()
        # Show form
        ok = f.Execute()
        if ok == 1:
            arg_choice = f.iArgNum.value
            f.Free()
            print("Setting argument " + arg_choice)
            return arg_choice
        else:
            f.Free()
            return None
#--------------------------------------------------------------------------
# Dumpulator functions
#--------------------------------------------------------------------------
def emulate_func():
    """
    Emulate your function
    """

    idaapi.msg("Emulating function:\n")


    dp.call(CALL_ADDRESS, func_args)
    
    for arg in func_args:
        try:
            print("Address " + str(arg) + ": " + dp.read_str(arg))
        except:
            print("Address " + str(arg) + " could not be stringified")

    return True


def set_temp_addr_arg():
    """
    Set argument to a temp address
    """
    argument_selection = (int(arg_select_t.show()) - 1)
    if ((argument_selection)>len(func_args)):
        print("Argument " + str(argument_selection) + " doesn't exist...")
    else:
        func_args[argument_selection] = dp.allocate(256)
        print("Allocated temporary space for argument " + str(argument_selection+1) + ". Address set to " + str(hex(func_args[argument_selection])))

    return True

def set_arg():
    """
    Set argument to selected address
    """
    global first_arg
    #value = parse_highlighted_value("ERROR: Not a valid value selection\n")
    #value = copy_bytes_py3()
    value = idc.get_screen_ea()

    argument_selection = (int(arg_select_t.show()) - 1)
    if ((argument_selection)>len(func_args)):
        print("Argument " + str(argument_selection) + " doesn't exist...")
    else:
        print("Setting argument " + str(argument_selection+1) + " to " + str(hex(value)))
        func_args[argument_selection] = value

    return True

def run_single_arg():
    """
    Run with dumpulator single argument
    """
    global first_arg
    #value = parse_highlighted_value("ERROR: Not a valid value selection\n")
    #value = copy_bytes_py3()
    value = idc.get_screen_ea()
    if value is None:
        return False
    first_arg = value
    idaapi.msg("running with %s as single arg\n" % value)
    print(hex(value))

    

    temp_addr = dp.allocate(256)

    dp.call(CALL_ADDRESS, [temp_addr, first_arg])
    

    decrypted = dp.read_str(temp_addr)

    print(f"decrypted: '{decrypted}'")

    return True
    
def set_call_addr():
    """
    Set call address
    """
    value = idc.get_screen_ea()

    if value is None:
        return False
    global CALL_ADDRESS
    CALL_ADDRESS = value

    idaapi.msg("call address is set: %s\n" % value)
    print(hex(value))

    global func_args
    func_arg_num = arg_num_select_t.show()
    func_args = [0] * int(func_arg_num)
    
    return True
#--------------------------------------------------------------------------
# Plugin
#--------------------------------------------------------------------------
class dumpulate_Plugin_t(idaapi.plugin_t):
    """
    IDA Plugin for Dumpulate
    """
    comment = "Dumpulate"
    help = ""
    wanted_name = PLUGIN_NAME
    # We only want a hotkey for the actual hash lookup
    wanted_hotkey = ''
    flags = idaapi.PLUGIN_KEEP

    #--------------------------------------------------------------------------
    # Plugin Overloads
    #--------------------------------------------------------------------------
    def init(self):
        """
        This is called by IDA when it is loading the plugin.
        """
        global p_initialized

        # Check if already initialized 
        if p_initialized is False:
            p_initialized = True
            ## Print a nice header
            print("You've taken your dump... It's time to play with it")
            # initialize the menu actions our plugin will inject
            self._init_action_run_single_arg()
            self._init_action_set_call_addr()
            self._init_action_set_temp_addr_arg()
            self._init_action_set_arg()
            self._init_action_emulate_func()
            # initialize plugin hooks
            self._init_hooks()
            return idaapi.PLUGIN_KEEP


    def run(self, arg):
        """
        This is called by IDA when the plugin is run from the plugins menu
        """
        global_settings()
        


    def term(self):
        """
        This is called by IDA when it is unloading the plugin.
        """
        
        # unhook our plugin hooks
        self._hooks.unhook()
        # unregister our actions & free their resources
        self._del_action_run_single_arg()
        self._del_action_set_call_addr()
        self._del_action_set_temp_addr_arg()
        self._del_action_set_arg()
        self._del_action_emulate_func
        # done
        idaapi.msg("%s terminated...\n" % self.wanted_name)


    #--------------------------------------------------------------------------
    # IDA Actions
    #--------------------------------------------------------------------------
    ACTION_RUN_SINGLE_ARG  = "dumpulate:runsinglearg"
    ACTION_SET_CALL_ADDR = "dumpulate:setcalladdr"
    ACTION_SET_TEMP_ADDR_ARG = "dumpulate:settempaddrarg"
    ACTION_SET_ARG = "dumpulate:setarg"
    ACTION_EMULATE_FUNC = "dumpulate:emulatefunc"
    
    def _init_action_run_single_arg(self):
        """
        Register the run single arg action with IDA.
        """
        action_desc = idaapi.action_desc_t(
            self.ACTION_RUN_SINGLE_ARG,         # The action name.
            "Dumpulate run with single arg",                     # The action text.
            IDACtxEntry(run_single_arg),        # The action handler.
            None,                  # Optional: action shortcut
            "Run with single arg"   # Optional: tooltip
            
        )
        # register the action with IDA
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_set_call_addr(self):
        """
        Register the set call address action with IDA.
        """
        action_desc = idaapi.action_desc_t(
            self.ACTION_SET_CALL_ADDR,         # The action name.
            "Dumpulate Set Call Address",                     # The action text.
            IDACtxEntry(set_call_addr),        # The action handler.
            None,                  # Optional: action shortcut
            "Set call address"   # Optional: tooltip
            
        )
        # register the action with IDA
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_set_temp_addr_arg(self):
        """
        Register the set temp addr arg action with IDA.
        """
        action_desc = idaapi.action_desc_t(
            self.ACTION_SET_TEMP_ADDR_ARG,         # The action name.
            "Dumpulate Allocate Temp For Argument",                     # The action text.
            IDACtxEntry(set_temp_addr_arg),        # The action handler.
            None,                  # Optional: action shortcut
            "Allocate temporary address space for arg"   # Optional: tooltip
            
        )
        # register the action with IDA
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_set_arg(self):
        """
        Register the set arg action with IDA.
        """
        action_desc = idaapi.action_desc_t(
            self.ACTION_SET_ARG,         # The action name.
            "Dumpulate Set Argument",                     # The action text.
            IDACtxEntry(set_arg),        # The action handler.
            None,                  # Optional: action shortcut
            "Set arg to selected address"   # Optional: tooltip
            
        )
        # register the action with IDA
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_emulate_func(self):
        """
        Register the set arg action with IDA.
        """
        action_desc = idaapi.action_desc_t(
            self.ACTION_EMULATE_FUNC,         # The action name.
            "Dumpulate Emulate Function",                     # The action text.
            IDACtxEntry(emulate_func),        # The action handler.
            None,                  # Optional: action shortcut
            "Emulate your function"   # Optional: tooltip
            
        )
        # register the action with IDA
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _del_action_set_call_addr(self):
        idaapi.unregister_action(self.ACTION_SET_CALL_ADDR)

    def _del_action_run_single_arg(self):
        idaapi.unregister_action(self.ACTION_RUN_SINGLE_ARG)

    def _del_action_set_temp_addr_arg(self):
        idaapi.unregister_action(self.ACTION_SET_TEMP_ADDR_ARG)

    def _del_action_set_arg(self):
        idaapi.unregister_action(self.ACTION_SET_ARG)

    def _del_action_emulate_func(self):
        idaapi.unregister_action(self.ACTION_EMULATE_FUNC)

    #--------------------------------------------------------------------------
    # Initialize Hooks
    #--------------------------------------------------------------------------

    def _init_hooks(self):
        """
        Install plugin hooks into IDA.
        """
        self._hooks = Hooks()
        self._hooks.ready_to_run = self._init_hexrays_hooks
        self._hooks.hook()


    def _init_hexrays_hooks(self):
        """
        Install Hex-Rays hooks (when available).
        NOTE: This is called when the ui_ready_to_run event fires.
        """
        if idaapi.init_hexrays_plugin():
            idaapi.install_hexrays_callback(self._hooks.hxe_callback)


#------------------------------------------------------------------------------
# Plugin Hooks
#------------------------------------------------------------------------------
class Hooks(idaapi.UI_Hooks):

    def finish_populating_widget_popup(self, widget, popup):
        """
        A right click menu is about to be shown. (IDA 7)
        """
        inject_actions(widget, popup, idaapi.get_widget_type(widget))
        return 0

    def hxe_callback(self, event, *args):
        """
        HexRays event callback.
        We lump this under the (UI) Hooks class for organizational reasons.
        """

        #
        # if the event callback indicates that this is a popup menu event
        # (in the hexrays window), we may want to install our menu
        # actions depending on what the cursor right clicked.
        #

        if event == idaapi.hxe_populating_popup:
            form, popup, vu = args

            
            idaapi.attach_action_to_popup(
                form,
                popup,
                dumpulate_Plugin_t.ACTION_RUN_SINGLE_ARG,
                "Dumpulate - run single arg",
                idaapi.SETMENU_APP,
            )

            idaapi.attach_action_to_popup(
                form,
                popup,
                dumpulate_Plugin_t.ACTION_SET_CALL_ADDR,
                "Dumpulate - set call address",
                idaapi.SETMENU_APP,
            )

            idaapi.attach_action_to_popup(
                form,
                popup,
                dumpulate_Plugin_t.ACTION_SET_TEMP_ADDR_ARG,
                "Dumpulate - set temp addr arg",
                idaapi.SETMENU_APP,
            )

            idaapi.attach_action_to_popup(
                form,
                popup,
                dumpulate_Plugin_t.ACTION_SET_ARG,
                "Dumpulate - set argument",
                idaapi.SETMENU_APP,
            )

            idaapi.attach_action_to_popup(
                form,
                popup,
                dumpulate_Plugin_t.ACTION_EMULATE_FUNC,
                "Dumpulate - emulate function",
                idaapi.SETMENU_APP,
            )

        # done
        return 0

#------------------------------------------------------------------------------
# Prefix Wrappers
#------------------------------------------------------------------------------
def inject_actions(form, popup, form_type):
    """
    Inject actions to popup menu(s) based on context.
    """

    #
    # disassembly window
    #

    if (form_type == idaapi.BWN_DISASMS) or (form_type == idaapi.BWN_PSEUDOCODE):
        # insert the action entry into the menu
        #

        idaapi.attach_action_to_popup(
            form,
            popup,
            dumpulate_Plugin_t.ACTION_RUN_SINGLE_ARG,
            "Dumpulate run with single arg",
            idaapi.SETMENU_APP
        )

        idaapi.attach_action_to_popup(
            form,
            popup,
            dumpulate_Plugin_t.ACTION_SET_CALL_ADDR,
            "Dumpulate set call address",
            idaapi.SETMENU_APP
        )

        idaapi.attach_action_to_popup(
            form,
            popup,
            dumpulate_Plugin_t.ACTION_SET_TEMP_ADDR_ARG,
            "Dumpulate set temp addr arg",
            idaapi.SETMENU_APP
        )

        idaapi.attach_action_to_popup(
            form,
            popup,
            dumpulate_Plugin_t.ACTION_SET_ARG,
            "Dumpulate set argument",
            idaapi.SETMENU_APP
        )

        idaapi.attach_action_to_popup(
            form,
            popup,
            dumpulate_Plugin_t.ACTION_EMULATE_FUNC,
            "Dumpulate Emulate Function",
            idaapi.SETMENU_APP
        )

    # done
    return 0

#------------------------------------------------------------------------------
# IDA ctxt
#------------------------------------------------------------------------------

class IDACtxEntry(idaapi.action_handler_t):
    """
    A basic Context Menu class to utilize IDA's action handlers.
    """

    def __init__(self, action_function):
        idaapi.action_handler_t.__init__(self)
        self.action_function = action_function

    def activate(self, ctx):
        """
        Execute the embedded action_function when this context menu is invoked.
        """
        self.action_function()
        return 1

    def update(self, ctx):
        """
        Ensure the context menu is always available in IDA.
        """
        return idaapi.AST_ENABLE_ALWAYS


#--------------------------------------------------------------------------
# Plugin Registration
#--------------------------------------------------------------------------

# Global flag to ensure plugin is only initialized once
p_initialized = False

# Register IDA plugin
def PLUGIN_ENTRY():
    return dumpulate_Plugin_t()


repository: michal-kapala/dubRE
file: plugins/xref_export.py
description: ML-driven function symbol extraction plugin for IDA Pro
wanted_name: dubRE XRef Path Exporter
comment: dubRE Xref Path Exporter
created_at: 2023-05-23 15:03:18+00:00
pushed_at: 2024-12-17 22:26:33+00:00
url:
https://github.com/michal-kapala/dubRE/blob/ce7be63623178ed55081e3b3297a4b4f3d49ac6a/plugins/xref_export.py

content:
import idaapi, idc, sark
import sqlite3
import os, platform

MAX_UP_REFERENCE_DEPTH = 1
"""Maximal evaluated distance in upward traversal of reference graph (measured in function calls)."""

MAX_DOWN_REFERENCE_DEPTH = 2
"""Maximal evaluated distance in downward traversal of reference graph (measured in function calls)."""

IDATA = sark.Segment(name=".idata")
"""`.idata` imports section (Sark segment)."""

RDATA = sark.Segment(name=".rdata")
"""`.rdata` data section (Sark segment)."""

def get_filename():
  """Returns the extensionless IDB file name."""
  path = idc.get_input_file_path()
  return os.path.splitext(os.path.basename(path))[0]

def is_import(ea):
  """Checks if an address belongs to `.idata` section."""
  return ea >= IDATA.ea and ea < IDATA.ea + IDATA.size

def is_before_rdata(ea):
  """Checks if the address is from before `.rdata` section."""
  return ea < RDATA.ea

def is_tostring_xref(xref):
  """Checks if cross reference points to a string."""
  # IDAPython docs say it returns empty string on failure but it actually returns None
  # https://www.hex-rays.com/products/ida/support/idapython_docs/idc.html#idc.get_strlit_contents
  return xref.type.is_data and idc.get_strlit_contents(xref.to) not in [None, ""] and not is_before_rdata(xref.to)

def try_get_func(ea):
  """Returns the parent function or `None` on failure."""
  try:
    return sark.Function(ea)
  except:
    return None

def traverse_referrer_referee(cur, top_func, path_func1, path_func2, path_func3, ref_depth, is_upward):
  """Adds string xrefs from a referrer or referee function."""
  # depth checks
  ref_depth += 1
  if not is_upward and ref_depth > MAX_DOWN_REFERENCE_DEPTH:
    return
  
  if is_upward and ref_depth > MAX_UP_REFERENCE_DEPTH:
    return
  
  # choose passed function
  func = None
  if ref_depth == 1:
    func = try_get_func(path_func1)
  elif ref_depth == 2:
    func = try_get_func(path_func2)
  elif ref_depth == 3:
    func = try_get_func(path_func3)
  else:
    raise Exception("Max reference recursion depth violated: " + str(ref_depth))
  
  if func is None:
    return

  # add string references
  for xref in func.xrefs_from:
    # skip all xrefs pointing neither to a function nor a string
    if not is_tostring_xref(xref) and not xref.type.is_code:
      continue

    # skip import xrefs
    if is_import(xref.to):
      continue

    # function xref - traverse downward function xrefs
    if xref.type.is_code and not is_upward:
      # skip xrefs to instruction blocks (unstructured functions)
      referee = idaapi.get_func(xref.to)
      if referee is None:
        continue

      if ref_depth == 1:
        traverse_referrer_referee(cur, top_func, path_func1, xref.to, path_func3, ref_depth, False)
      elif ref_depth == 2:
        traverse_referrer_referee(cur, top_func, path_func1, path_func2, xref.to, ref_depth, False)
      elif ref_depth == 3:
        # dont enter 4th depth level
        continue

    # function xref - wrong direction, skip
    elif xref.type.is_code and is_upward:
      continue

    # string xref - add x-level reference
    else:
      try:
        cur.execute("INSERT INTO paths (func_addr,string_addr,path_func1,path_func2,path_func3,ref_depth,is_upward) VALUES (?,?,?,?,?,?,?)", (
          top_func, xref.to, path_func1, path_func2, path_func3, ref_depth, is_upward
          ))
      except sqlite3.IntegrityError:
        pass
    
  # traverse upward function xrefs
  if is_upward and ref_depth < MAX_UP_REFERENCE_DEPTH:
    for xref in func.xrefs_to:
      # functions can only be referenced by other functions
      if not xref.type.is_code:
        continue
      # skip xrefs from instruction blocks (unstructured functions)
      referrer = idaapi.get_func(xref.frm)
      if referrer is None:
        continue
      
      if ref_depth == 1:
        traverse_referrer_referee(cur, top_func, path_func1, referrer.start_ea, path_func3, ref_depth, True)
      elif ref_depth == 2:
        traverse_referrer_referee(cur, top_func, path_func1, path_func2, referrer.start_ea, ref_depth, True)
      else:
        raise Exception("Unimplemented reference recursion depth for MAX_REF_DEPTH=" + str(MAX_DOWN_REFERENCE_DEPTH))


def export_xrefs():
  """Exports a function's from-references from IDB to SQLite database (`xrefs` table) in the current directory."""
  filename = get_filename() + '.db'
  trailing_slash = "\\" if platform.system() == "Windows" else "/"
  print("Exporting xrefs to " + os.getcwd() + trailing_slash + filename)
  
  conn = sqlite3.connect(filename)
  conn.text_factory = lambda x: x.decode("utf-8")
  c = conn.cursor()

  # Create function-string xrefs table
  c.execute('''CREATE TABLE IF NOT EXISTS paths (
              id INTEGER PRIMARY KEY,
              func_addr INTEGER NOT NULL,
              string_addr INTEGER NOT NULL,
              path_func1 INTEGER NOT NULL,
              path_func2 INTEGER NOT NULL,
              path_func3 INTEGER NOT NULL,
              ref_depth INTEGER NOT NULL,
              is_upward INTEGER NOT NULL,
              to_name INTEGER,
              UNIQUE (func_addr, string_addr, path_func1, path_func2, path_func3))''')
  
  # Export xrefs to db
  exported = 0
  
  ref_depth = 0

  funcs = sark.functions()
  func_cnt = 1

  for func in funcs:
    print(str(func_cnt) + " - " + func.name)
    func_cnt += 1
    # level 0 - downward search
    for xref in func.xrefs_from:
      # skip all xrefs pointing neither to a function nor a string
      if not is_tostring_xref(xref) and not xref.type.is_code:
        continue

      # skip import xrefs
      if is_import(xref.to):
        continue

      # function xref - traverse reference graph neighbours
      if xref.type.is_code:
        # using -1 because SQLite treats NULL as a unique value
        # and as a consequence doesn't honor the multi-column UNIQUE constraint
        # https://stackoverflow.com/a/2701903/14807735
        traverse_referrer_referee(c, func.ea, xref.to, -1, -1, ref_depth, False)
      # string xref - add 0-level reference
      else:
        try:
          c.execute("INSERT INTO paths (func_addr,string_addr,path_func1,path_func2,path_func3,ref_depth,is_upward) VALUES (?,?,?,?,?,?,?)", (
            func.ea, xref.to, -1, -1, -1, 0, False
            ))
          exported += 1
        except sqlite3.IntegrityError:
          pass

    # level 0 - upward search
    for xref in func.xrefs_to:
      # functions can only be referenced by other functions
      if not xref.type.is_code:
        continue
      # skip xrefs from instruction blocks (unstructured functions)
      referrer = idaapi.get_func(xref.frm)
      if referrer is None:
        continue

      # function xref - traverse reference graph neighbours
      traverse_referrer_referee(c, func.ea, referrer.start_ea, -1, -1, ref_depth, True)

  print("Exported " + str(exported) + " zero-level xref paths.")
  conn.commit()
  conn.close()


class XrefExporterPlugin(idaapi.plugin_t):
  flags = idaapi.PLUGIN_PROC
  comment = "dubRE Xref Path Exporter"
  help = "This plugin exports cross-reference paths to SQLite database."
  wanted_name = "dubRE XRef Path Exporter"
  wanted_hotkey = "Shift+X"

  def init(self):
    return idaapi.PLUGIN_KEEP

  def term(self):
    pass

  def run(self, arg):
    export_xrefs()


def PLUGIN_ENTRY():
  return XrefExporterPlugin()


repository: Krietz7/IDA-DataExportPlus
file: DataExportPlus.py
description: a IDA Pro plugin to export data better
wanted_name: Data Export Plus
comment: Export Data
created_at: 2024-10-11 15:44:01+00:00
pushed_at: 2025-04-14 10:37:01+00:00
url:
https://github.com/Krietz7/IDA-DataExportPlus/blob/54005db0afc652e98adc2f6d0a39b4fb2a63b521/DataExportPlus.py

content:
from os import getcwd, path

import idc
import idaapi
import ida_ida
from ida_kernwin import add_hotkey
from ida_bytes import get_flags

VERSION = "1.1.2"

class DEP_Conversion():

    @classmethod
    def get_list(self):
        Data_base_list = {"Hexadecimal":16,"Decimal":10,"Octal":8,"Binary":2,}
        Data_type_list = {"Byte":1,"Word":2,"Dword":3,"Qword":4,"String literal":5,"Assembly Code":6,"Raw bytes":7}
        Data_exported_format_list = {"String":0,"C variable":1,"Python variable":2}
        return (Data_base_list,Data_type_list,Data_exported_format_list)

    # data(bytes) big_endian(Bool) data_type(int) base(int) delimiter(str) prefix(str) suffix(str)
    def __init__(self, address, data_bytes, data_type_key = 1, export_type_key = 0,big_endian = False, base_key = 0, delimiter = " ",prefix = "",suffix = "",keep_comments = False, keep_names = False):
        self.address = address
        self.Data_base_list, self.Data_type_list, _ = self.get_list()
        self.data_bytes = data_bytes
        self.export_type_key = export_type_key
        self.big_endian = big_endian
        self.base_key = base_key
        self.data_type_key = data_type_key 
        self.delimiter = delimiter
        self.prefix = prefix
        self.suffix = suffix
        self.keep_comments = keep_comments
        self.keep_names = keep_names

    @classmethod
    def dict_key_to_list(self,dictionary):
        t = list(dictionary.items())
        key = [i[0] for i in t]
        return key

    @classmethod
    def dict_value_to_list(self,dictionary):
        t = list(dictionary.items())
        value = [i[1] for i in t]
        return value


    def activate(self):
        self.base = self.dict_value_to_list(self.Data_base_list)[self.base_key]
        self.type = self.dict_key_to_list(self.Data_type_list)[self.data_type_key]

        output = ""
        if(self.type in ['Byte','Word','Dword','Qword']):
            output = self.NumberConversion()

        elif(self.type == "String literal"):
            output = self.StringLiteralConversion()

        elif(self.type == "Assembly Code"):
            output = self.AssemblyCodeConversion()

        elif(self.type == "Raw bytes"):
            return "Cannot preview binary data"

        # String
        if(self.export_type_key == 0):
            return output

        # C variable
        elif(self.export_type_key == 1):
            if(self.type in ['Byte','Word','Dword','Qword']):
                C_type = {"Byte":"unsigned char","Word":"unsigned short","Dword":"unsigned int","Qword":"unsigned long long int"}[self.type]
                return C_type+" IDA_"+ hex(self.address)[2:] + "[] = {" + output + "};"

            elif(self.type == "String literal"):
                return "unsigned char IDA_"+ hex(self.address)[2:] + "[] = \"" + output + "\";"

            elif(self.type == "Assembly Code"):
                output = '\\n\"\n\"'.join([line for line in output.splitlines()])[:-1]
                return "std:string IDA_"+ hex(self.address)[2:] + " = \"" + output + "\";"

            return None

        # Python variable
        elif(self.export_type_key == 2):
            if(self.type in ['Byte','Word','Dword','Qword']):
                return "IDA_" + hex(self.address)[2:] + " = [" +output + "]"

            elif(self.type == "String literal"):
                return "IDA_" + hex(self.address)[2:] + " = b\'" + output + '\''

            elif(self.type == "Assembly Code"):
                return "IDA_" + hex(self.address)[2:] + " = \'\'\'" + output + '\'\'\''

        return None

    def convert_base(self, number, target_base):
        digit_map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        result = ''
        while number:
            remainder = number % target_base
            result = digit_map[remainder] + result
            number //= target_base

        if(result == ''):
            return "0"
        return result

    # base on Byte/Word/Dword/Qword convert byte stream to number
    # parameter: base big_endian prefix suffix
    def NumberConversion(self):
        Number_array = []
        type_len_list = {"Byte":1,"Word":2,"Dword":4,"Qword":8}
        Number_len = type_len_list[self.type]
        if(not self.big_endian):
            for i in range(0, len(self.data_bytes), Number_len):
                Number_array.append(int.from_bytes(self.data_bytes[i:i+Number_len],byteorder='little'))
        else:
            for i in range(0, len(self.data_bytes), Number_len):
                Number_array.append(int.from_bytes(self.data_bytes[i:i+Number_len],byteorder='big'))
        if(self.base > 0 and self.base < 36):
            return self.delimiter.join("{0}{1}{2}".format(self.prefix,str(self.convert_base(i,self.base)),self.suffix) for i in Number_array)
        return None

    def StringLiteralConversion(self):
        return str(self.data_bytes)[2:-1]


    def AssemblyCodeConversion(self):
        assembly_code_start = self.address
        assembly_code_end = self.address + len(self.data_bytes)

        output = ""
        i = assembly_code_start
        if(assembly_code_start > ida_ida.inf_get_max_ea() or assembly_code_start < ida_ida.inf_get_min_ea()):
            return ""
        while i < assembly_code_end:
            if(self.keep_names):
                addr_name = idc.get_name(i)
                if addr_name:
                    output += "\n" + addr_name + ":\n"
            if(self.keep_comments):
                output += idc.generate_disasm_line(i,0)
            else:
                output += idc.generate_disasm_line(i,0).split(";")[0]
            output += "\n"

            i = idc.find_code(i, 1)
        return output


class DEP_Form(idaapi.Form):
    # idaapi information
    min_ea = ida_ida.inf_get_min_ea()
    max_ea = ida_ida.inf_get_max_ea()

    # list
    Data_base_list,Data_type_list,Data_exported_format_list = DEP_Conversion.get_list()

    def __init__(self,select_addr,select_len):
        self.export_address = select_addr
        self.export_address_len = select_len
        self.Data_bytes = b""
        self.export_data_type_key = 0


        # Format Options
        self.export_big_endian = False
        self.export_base_key = 0
        self.export_delimiter = ","
        self.export_prefix = "0x"
        self.export_suffix = ""
        self.export_type_key = 0
        self.export_keep_comments = False
        self.export_keep_names = False

        self.export_data = None
        self.export_file_path = getcwd() + "\\export_results.txt"


        data_type_flag = get_flags(self.export_address)
        checks = [
            (idc.is_byte, 0),
            (idc.is_word, 1),
            (idc.is_dword, 2),
            (idc.is_qword, 3),
            (idc.is_strlit, 4),
            (idc.is_code, 5)
        ]
        self.export_data_type_key = next((key for func, key in checks if func(data_type_flag)), 0)

        super(DEP_Form, self).__init__(

            r'''STARTITEM 0
BUTTON YES* Export
Export Plus: Export Data
            
            {FormChangeCb}
            <Selected address :{_address}>
            <Selected Length  :{_length}>
            <~Selected Data~    :{_select_data}>
            < Data Type       :{_data_type}>
            < Export As       :{_export_type}>

            Export Format:
            <##-   Endianness :{_endianness}>
            <##-   Base       :{_base}>
            <##-   Delimiter  :{_delimiter}>
            <##-   Prefix     :{_prefix}>
            <##-   Suffix     :{_suffix}>

            <##-   Keep Comments:{_keep_comments}>
            <##-   Keep Names   :{_keep_names}>
            <~Export Window~: {_export_text}>
            <Export File Path: {_export_file_path}>
            ''',
            {
                "FormChangeCb": self.FormChangeCb(self.OnFormChange),

                "_address": self.NumericInput(value = self.export_address, tp=self.FT_ADDR, swidth=30),
                "_length": self.NumericInput(value = self.export_address_len, swidth = 30),
                "_select_data": self.StringInput(value = "",swidth = 30),                
                "_data_type": self.DropdownListControl(items = list(self.Data_type_list.keys()),selval = self.export_data_type_key),
                "_export_type": self.DropdownListControl(items =list(self.Data_exported_format_list.keys())),

                "_endianness": self.DropdownListControl(items = ["Little-endian","Big-endian"]),
                "_base": self.DropdownListControl(items = list(self.Data_base_list.keys())),
                "_delimiter": self.StringInput(value = self.export_delimiter,swidth = 30),
                "_prefix": self.StringInput(value = self.export_prefix,swidth = 30),
                "_suffix": self.StringInput(value = self.export_suffix,swidth = 30),
                "_keep_comments": self.DropdownListControl(items = ["False", "True"]),
                "_keep_names": self.DropdownListControl(items = ["False", "True"]),


                "_export_text": self.MultiLineTextControl(text = "",swidth = 48),
                "_export_file_path": self.FileInput(value = self.export_file_path, save = True,swidth = 30),
            }

        )
        self.Compile()

    def OnFormChange(self,fid):
        # initialization
        data_str = ""
        if(fid == -1):
            self.EnableField(self._select_data,False)
            try:
                input_export_address = self.GetControlValue(self._address)
                input_export_address_len = self.GetControlValue(self._length)

                self.min_ea = ida_ida.inf_get_min_ea()
                self.max_ea = ida_ida.inf_get_max_ea()

                if(self.min_ea < input_export_address and self.max_ea > input_export_address and self.max_ea > input_export_address + input_export_address_len):
                    self.Data_bytes,data_str =self.GetEAData(input_export_address,input_export_address_len)
                    self.SetControlValue(self._select_data,data_str)

                    self.export_address = input_export_address
                    self.export_address_len = input_export_address_len
            except:
                return 1

        # change Selected information
        elif(fid == self._address.id or fid == self._length.id):
            try:
                input_export_address = self.GetControlValue(self._address)
                input_export_address_len = self.GetControlValue(self._length)
    
                self.min_ea = ida_ida.inf_get_min_ea()
                self.max_ea = ida_ida.inf_get_max_ea()

                if(self.min_ea < input_export_address and self.max_ea > input_export_address and self.max_ea > input_export_address + input_export_address_len):
                    self.Data_bytes,data_str =self.GetEAData(input_export_address,input_export_address_len)
                    self.SetControlValue(self._select_data,data_str)

                    self.export_address = input_export_address
                    self.export_address_len = input_export_address_len
            except:
                return 1

        # change export format or export type
        if(fid in [-1, self._data_type.id, self._export_type.id]):
            self.export_data_type_key = self.GetControlValue(self._data_type)
            self.export_type_key = self.GetControlValue(self._export_type)

            # change Form Controls property

            # Byte
            if(self.export_data_type_key == 0):
                self.ShowField(self._export_type,True)

                self.ShowField(self._endianness,False)
                self.ShowField(self._base,True)
                self.ShowField(self._delimiter,True)
                self.ShowField(self._prefix,True)
                self.ShowField(self._suffix,True)
                self.ShowField(self._keep_comments,False)
                self.ShowField(self._keep_names,False)

                # export as string
                if(self.export_type_key == 0):
                    self.EnableField(self._delimiter,True)
                    self.EnableField(self._prefix,True)
                    self.EnableField(self._suffix,True)

            # Word,Dword,Qword
            elif(self.export_data_type_key in [1,2,3]):
                self.ShowField(self._export_type,True)

                self.ShowField(self._endianness,True)
                self.ShowField(self._base,True)
                self.ShowField(self._delimiter,True)
                self.ShowField(self._prefix,True)
                self.ShowField(self._suffix,True)
                self.ShowField(self._keep_comments,False)
                self.ShowField(self._keep_names,False)

                # export as string
                if(self.export_type_key == 0):
                    self.EnableField(self._endianness,True)
                    self.EnableField(self._delimiter,True)
                    self.EnableField(self._prefix,True)
                    self.EnableField(self._suffix,True)

            # String literal
            elif(self.export_data_type_key == 4):
                self.ShowField(self._export_type,True)

                self.ShowField(self._endianness,False)
                self.ShowField(self._base,False)
                self.ShowField(self._delimiter,False)
                self.ShowField(self._prefix,False)
                self.ShowField(self._suffix,False)
                self.ShowField(self._keep_comments,False)
                self.ShowField(self._keep_names,False)

            # Assembly Code
            elif(self.export_data_type_key == 5):
                self.ShowField(self._export_type,True)

                self.ShowField(self._endianness,False)
                self.ShowField(self._base,False)
                self.ShowField(self._delimiter,False)
                self.ShowField(self._prefix,False)
                self.ShowField(self._suffix,False)
                self.ShowField(self._keep_comments,True)
                self.ShowField(self._keep_names,True)

            # Raw bytes
            elif(self.export_data_type_key == 6):
                self.ShowField(self._export_type,False)

                self.ShowField(self._endianness,False)
                self.ShowField(self._base,False)
                self.ShowField(self._delimiter,False)
                self.ShowField(self._prefix,False)
                self.ShowField(self._suffix,False)
                self.ShowField(self._keep_comments,False)
                self.ShowField(self._keep_names,False)

            # export as string
            if(self.export_type_key == 0):
                pass

            # export as C varible
            elif(self.export_type_key == 1):
                self.EnableField(self._delimiter,False)
                self.EnableField(self._prefix,False)
                self.EnableField(self._suffix,False)

            # export as Python varible
            elif(self.export_type_key == 2):
                self.EnableField(self._delimiter,False)
                self.EnableField(self._prefix,False)
                self.EnableField(self._suffix,False)

            # change default value
            self.SetControlsDefaultValue()





        elif(fid in [self._endianness.id,self._base.id,self._delimiter.id,self._prefix.id,self._suffix.id,self._keep_comments.id,self._keep_names.id]):
            self.export_big_endian = self.GetControlValue(self._endianness)
            self.export_base_key = self.GetControlValue(self._base)
            self.export_delimiter = self.GetControlValue(self._delimiter)
            self.export_prefix = self.GetControlValue(self._prefix)
            self.export_suffix = self.GetControlValue(self._suffix)
            self.export_keep_comments = {0:False,1:True}[self.GetControlValue(self._keep_comments)]
            self.export_keep_names = {0:False,1:True}[self.GetControlValue(self._keep_names)]


            if(fid == self._base.id):
                self.SetControlsDefaultValue()


        elif(fid == self._export_file_path.id):
            self.export_file_path = self.GetControlValue(self._export_file_path)




        # refresh MultiLineTextControl
        self.RefreshExportWindow()

        return 1


    def GetEAData(self,address,length):
        data_byte = idc.get_bytes(address,length)
        data_str = ' '.join([f"{i:02X}" for i in bytearray(data_byte)])

        return data_byte,data_str.strip()


    def RefreshExportWindow(self):
        t = DEP_Conversion(address = self.export_address, data_bytes = self.Data_bytes,
                           data_type_key = self.export_data_type_key,
                           export_type_key = self.export_type_key,
                           big_endian = self.export_big_endian,
                           base_key = self.export_base_key,
                           delimiter = self.export_delimiter,
                           prefix = self.export_prefix,
                           suffix = self.export_suffix, 
                           keep_comments = self.export_keep_comments,
                           keep_names = self.export_keep_names)
        self.export_data = t.activate()
        self.SetControlValue(self._export_text,  idaapi.textctrl_info_t(text = self.export_data, flags = 32, tabsize = 0))


    def SetControlsDefaultValue(self):
        if(self.export_data_type_key in [0,1,2,3]):

            Prefix_list = {0:"0x",1:"",2:"0o",3:"0b"}
            self.export_prefix = Prefix_list[self.export_base_key]
            self.SetControlValue(self._prefix,self.export_prefix)

            if(self.export_type_key == 1):
                self.export_delimiter = ", "
                self.SetControlValue(self._delimiter,", ")
                self.export_suffix = ""
                self.SetControlValue(self._suffix,"")
                # export as C array
                if(self.export_data_type_key == 3):
                    self.export_suffix = "ULL"
                    self.SetControlValue(self._suffix,"ULL")
                if(self.export_base_key == 2):
                    self.export_prefix = "0"
                    self.SetControlValue(self._prefix,self.export_prefix)


            if(self.export_type_key == 2):
                self.export_delimiter = ", "
                self.SetControlValue(self._delimiter,", ")
                self.export_suffix = ""
                self.SetControlValue(self._suffix,"")
                # export as Python array



class DataExportPlus(idaapi.plugin_t):
    flags = idaapi.PLUGIN_DRAW
    comment = "Export Data"
    help = ""
    wanted_name = "Data Export Plus"
    version = VERSION

    def init(self):
        print("=" * 80)
        print("Start Data Export Plus plugin")

        idc.del_idc_hotkey("Shift+E")
        add_hotkey("Shift-E", self.hotkeystart)

        return idaapi.PLUGIN_OK

    def term(self):
        return

    def hotkeystart(self):
        self.run(None)

    def run(self, args):
        ea_addr,ea_item_size = self.GetEAItem()
        form = DEP_Form(ea_addr,ea_item_size)
        IsExport = form.Execute()


        if(IsExport):
            if(path.exists(form.export_file_path)):
                k = idc.ask_yn(1,"Export file already exists, Do you want to overwrite it?")
                if(k == -1 or k == 0):
                    form.Free()
                    return 1
            try:
                if(form.export_data_type_key == 6):
                    with open(form.export_file_path, "wb") as file_handle:
                        file_handle.write(form.Data_bytes)
                else:
                    with open(form.export_file_path, "w", encoding="utf-8") as file_handle:
                        file_handle.write(form.export_data)

                print("Stored export results in",form.export_file_path)

            except:
                idc.warning("Export file failed")

        form.Free()
        return 1


    def GetEAItem(self):
        selection, ea_addr, ea_addr_end = idaapi.read_range_selection(None)

        if (selection):
            ea_item_size = ea_addr_end - ea_addr
        else:
            ea_addr = idc.get_screen_ea()
            ea_item_size = idc.get_item_size(idc.get_screen_ea())

        return ea_addr,ea_item_size




def PLUGIN_ENTRY():
    return DataExportPlus()


repository: mahmoudimus/ida-pysigmaker
file: sigmaker.py
description: IDA Pro 9.0+ cross-platform port of @A200K's IDA-Pro-SigMaker to Python
comment: f"{PLUGIN_NAME} v{PLUGIN_VERSION} for IDA Pro by {PLUGIN_AUTHOR}
created_at: 2024-08-03 01:42:15+00:00
pushed_at: 2025-04-03 17:47:34+00:00
url:
https://github.com/mahmoudimus/ida-pysigmaker/blob/287fe8bf4f16d3b42bae4aefd54231c8e9e2838c/sigmaker.py

content:
"""
sigmaker.py - IDA Python port of Signature Maker (from A200K)
https://github.com/mahmoudimus/ida-pysigmaker

by @mahmoudimus (Mahmoud Abdelkader)
"""

import ctypes
import enum
import os
import platform
import re
import sys
import traceback

import ida_bytes
import ida_ida
import ida_idaapi
import ida_idp
import ida_kernwin
import ida_xref
import idaapi
import idc


def _IsProcessorFeaturePresent(feature: int) -> bool:
    if platform.system() != "Windows":
        return False

    try:
        is_present = ctypes.windll.kernel32.IsProcessorFeaturePresent(feature)
    except Exception:
        is_present = False
    return is_present


def _IsAVX2Available() -> bool:
    # Check for AVX2 feature to enable QIS signature scanning.
    PF_AVX2_INSTRUCTIONS_AVAILABLE = 10
    return _IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE)


# Globals
__author__ = "mahmoudimus"
__version__ = "1.1.2"

PLUGIN_NAME = "Signature Maker (py)"
PLUGIN_VERSION = __version__
PLUGIN_AUTHOR = __author__
USE_QIS_SIGNATURE = False  # _IsAVX2Available()  # TODO: add this later
PRINT_TOP_X = 5
MAX_SINGLE_SIGNATURE_LENGTH = 1000
MAX_XREF_SIGNATURE_LENGTH = 250
FILE_BUFFER = None
PROCESSOR_ARCH = ida_idp.ph_get_id()  # Check what processor we have
WILDCARD_OPTIMIZED_INSTRUCTION = True
WildcardableOperandTypeBitmask = 0  # Will be set based on processor

# Helpers


def BIT(x):
    return 1 << x


class ProgressDialog:
    def __init__(self, message="Please wait...", hide_cancel=False):
        self._default_msg: str
        self.hide_cancel: bool
        self.configure(message, hide_cancel)

    def _message(self, message=None, hide_cancel=None):
        display_msg = self._default_msg if message is None else message
        hide_cancel = self.hide_cancel if hide_cancel is None else hide_cancel
        prefix = "HIDECANCEL\n" if hide_cancel else ""
        return prefix + display_msg

    def configure(self, message="Please wait...", hide_cancel=False):
        self._default_msg = message
        self.hide_cancel = hide_cancel
        return self

    __call__ = configure

    def __enter__(self):
        ida_kernwin.show_wait_box(self._message())
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        ida_kernwin.hide_wait_box()

    def replace_message(self, new_message, hide_cancel=False):
        msg = self._message(message=new_message, hide_cancel=hide_cancel)
        ida_kernwin.replace_wait_box(msg)

    def user_canceled(self):
        return ida_kernwin.user_cancelled()

    user_cancelled = user_canceled


class Clipboard:
    @staticmethod
    def _set_text_windows(text: str) -> bool:
        import ctypes.util
        from ctypes import wintypes as w

        GMEM_MOVEABLE = 0x0002
        GMEM_ZEROINIT = 0x0040
        CF_TEXT = 1

        user32 = ctypes.WinDLL("user32")
        kernel32 = ctypes.WinDLL("kernel32")

        OpenClipboard = user32.OpenClipboard
        OpenClipboard.argtypes = (w.HWND,)
        OpenClipboard.restype = w.BOOL

        EmptyClipboard = user32.EmptyClipboard
        EmptyClipboard.restype = w.BOOL

        GlobalAlloc = kernel32.GlobalAlloc
        GlobalAlloc.argtypes = (w.UINT, w.UINT)
        GlobalAlloc.restype = w.HGLOBAL

        GlobalLock = kernel32.GlobalLock
        GlobalLock.argtypes = (w.HGLOBAL,)
        GlobalLock.restype = w.LPVOID

        GlobalUnlock = kernel32.GlobalUnlock
        GlobalUnlock.argtypes = (w.HGLOBAL,)
        GlobalUnlock.restype = w.BOOL

        SetClipboardData = user32.SetClipboardData
        SetClipboardData.argtypes = (w.UINT, w.HANDLE)
        SetClipboardData.restype = w.HANDLE

        CloseClipboard = user32.CloseClipboard
        CloseClipboard.restype = w.BOOL

        if not text:
            return False

        if not OpenClipboard(None) or not EmptyClipboard():
            return False

        h_mem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, len(text) + 1)
        if not h_mem:
            CloseClipboard()
            return False

        lp_str = GlobalLock(h_mem)
        if not lp_str:
            kernel32.GlobalFree(h_mem)
            CloseClipboard()
            return False

        ctypes.memmove(lp_str, text.encode("utf-8"), len(text))
        GlobalUnlock(h_mem)

        if not SetClipboardData(CF_TEXT, h_mem):
            kernel32.GlobalFree(h_mem)
            CloseClipboard()
            return False

        CloseClipboard()
        return True

    @staticmethod
    def _set_text_macos(text: str) -> bool:
        import subprocess

        try:
            process = subprocess.Popen(
                ["pbcopy"], stdin=subprocess.PIPE, close_fds=True
            )
            process.communicate(input=text.encode("utf-8"))
            return process.returncode == 0
        except Exception as e:
            print(f"Error setting clipboard text on macOS: {e}")
            return False

    @staticmethod
    def _set_text_linux(text: str) -> bool:
        import subprocess

        try:
            process = subprocess.Popen(
                ["xclip", "-selection", "clipboard"],
                stdin=subprocess.PIPE,
                close_fds=True,
            )
            process.communicate(input=text.encode("utf-8"))
            return process.returncode == 0
        except Exception as e:
            print(f"Error setting clipboard text on Linux: {e}")
            return False

    @staticmethod
    def _set_text_pyqt5(text: str) -> bool:
        try:
            from PyQt5.QtWidgets import QApplication

            QApplication.clipboard().setText(text)
            return True
        except ImportError:
            return False
        except Exception as e:
            print(f"Error setting clipboard text on PyQt5: {e}")
            return False

    @classmethod
    def set_text(cls, text: str) -> bool:
        """
        Sets the clipboard text on the current operating system.
        Returns True on success, False on failure.
        """
        # Try to use PyQt5 to set the clipboard text, since
        # that is cross-platform and doesn't require any
        # external dependencies.
        success = cls._set_text_pyqt5(text)
        if success:
            return success

        # Otherwise, use the platform-specific method.
        if sys.platform.startswith("win"):
            return cls._set_text_windows(text)
        elif sys.platform == "darwin":
            return cls._set_text_macos(text)
        elif sys.platform.startswith("linux"):
            return cls._set_text_linux(text)
        else:
            print("Unsupported operating system")
            return False

    def __call__(self, text: str) -> bool:
        """
        Allow instances of Clipboard to be called like a function.
        """
        return self.set_text(text)


SetClipboardText = Clipboard.set_text


# -------------------------
# Signature structures and output functions
# -------------------------


class SignatureType(enum.Enum):
    IDA = 0
    x64Dbg = 1
    Signature_Mask = 2
    SignatureByteArray_Bitmask = 3


class SignatureByte:
    def __init__(self, value: int, isWildcard: bool):
        self.value = value
        self.isWildcard = isWildcard


Signature = list  # list of SignatureByte


def BuildIDASignatureString(signature: Signature, doubleQM: bool = False) -> str:
    result = []
    # Build hex pattern
    for byte in signature:
        if byte.isWildcard:
            result.append("??" if doubleQM else "?")
        else:
            result.append(f"{byte.value:02X}")
        result.append(" ")
    s = "".join(result).rstrip()
    return s


def BuildByteArrayWithMaskSignatureString(signature: Signature) -> str:
    pattern = []
    mask = []
    for byte in signature:
        pattern.append(f"\\x{byte.value:02X}" if not byte.isWildcard else "\\x00")
        mask.append("x" if not byte.isWildcard else "?")
    return "".join(pattern) + " " + "".join(mask)


def BuildBytesWithBitmaskSignatureString(signature: Signature) -> str:
    pattern = []
    mask = []
    for byte in signature:
        pattern.append(f"0x{byte.value:02X}, " if not byte.isWildcard else "0x00, ")
        mask.append("1" if not byte.isWildcard else "0")
    pattern_str = "".join(pattern).rstrip(", ")
    mask_str = "".join(mask)[::-1]  # Reverse the bitmask
    return pattern_str + " 0b" + mask_str


def FormatSignature(signature: Signature, sig_type: SignatureType) -> str:
    if sig_type == SignatureType.IDA:
        return BuildIDASignatureString(signature)
    elif sig_type == SignatureType.x64Dbg:
        return BuildIDASignatureString(signature, True)
    elif sig_type == SignatureType.Signature_Mask:
        return BuildByteArrayWithMaskSignatureString(signature)
    elif sig_type == SignatureType.SignatureByteArray_Bitmask:
        return BuildBytesWithBitmaskSignatureString(signature)
    return ""


# -------------------------
# Utility functions (signature byte addition, trim, clipboard, regex)
# -------------------------


def AddByteToSignature(signature: Signature, address, wildcard: bool):
    b = ida_bytes.get_byte(address)
    signature.append(SignatureByte(b, wildcard))


def AddBytesToSignature(signature: Signature, address, count: int, wildcard: bool):
    for i in range(count):
        AddByteToSignature(signature, address + i, wildcard)


def TrimSignature(signature: Signature):
    # Remove trailing wildcards
    while signature and signature[-1].isWildcard:
        signature.pop()


def GetRegexMatches(string: str, regex: re.Pattern, matches: list) -> bool:
    matches.clear()
    matches.extend(re.findall(regex, string))
    return bool(matches)


# -------------------------
# Exception for errors
# -------------------------
class Unexpected(Exception):
    pass


class ConfigureOperandWildcardBitmaskForm(ida_kernwin.Form):
    """Interactive Form to configure wildcardable operands using checkboxes."""

    def __init__(self):
        F = ida_kernwin.Form
        # Define the form layout
        form_text = """BUTTON YES* OK
BUTTON CANCEL Cancel
Wildcardable Operands
{FormChangeCb}
Select operand types that should be wildcarded:

<General Register (al, ax, es, ds...):{opt1}>
<Direct Memory Reference (DATA) :{opt2}>
<Memory Ref [Base Reg + Index Reg] :{opt3}>
<Memory Ref [Base Reg + Index Reg + Displacement] :{opt4}>
<Immediate Value :{opt5}>
<Immediate Far Address (CODE) :{opt6}>
<Immediate Near Address (CODE) :{opt7}>"""
        registers = ["opt1", "opt2", "opt3", "opt4", "opt5", "opt6", "opt7"]

        # Processor-specific operand types
        PROCESSOR_ARCH = ida_idp.ph_get_id()
        if PROCESSOR_ARCH == ida_idp.PLFM_386:
            form_text += """
<Trace Register :{opt8}>
<Debug Register :{opt9}>
<Control Register :{opt10}>
<Floating Point Register :{opt11}>
<MMX Register :{opt12}>
<XMM Register :{opt13}>
<YMM Register :{opt14}>
<ZMM Register :{opt15}>
<Opmask Register :{opt16}>{cWildcardableOperands}>"""
            registers.extend(
                [
                    "opt8",
                    "opt9",
                    "opt10",
                    "opt11",
                    "opt12",
                    "opt13",
                    "opt14",
                    "opt15",
                    "opt16",
                ]
            )
        elif PROCESSOR_ARCH == ida_idp.PLFM_ARM:
            form_text += """
<(Unused) :{opt8}>
<Register list (for LDM/STM) :{opt9}>
<Coprocessor register list (for CDP) :{opt10}>
<Coprocessor register (for LDC/STC) :{opt11}>
<Floating point register list :{opt12}>
<Arbitrary text stored in the operand :{opt13}>
<ARM condition as an operand :{opt14}>{cWildcardableOperands}>"""
            registers.extend(
                ["opt8", "opt9", "opt10", "opt11", "opt12", "opt13", "opt14"]
            )
        elif PROCESSOR_ARCH == ida_idp.PLFM_PPC:
            form_text += """
<Special purpose register :{opt8}>
<Two FPRs :{opt9}>
<SH & MB & ME :{opt10}>
<crfield :{opt11}>
<crbit :{opt12}>
<Device control register :{opt13}>{cWildcardableOperands}>"""
            registers.extend(["opt8", "opt9", "opt10", "opt11", "opt12", "opt13"])
        else:
            form_text += """{cWildcardableOperands}>
"""
        # Shift by one because we skip o_void
        options = WildcardableOperandTypeBitmask >> 1
        # Define checkboxes
        controls = {
            "FormChangeCb": F.FormChangeCb(self.OnFormChange),
            "cWildcardableOperands": F.ChkGroupControl(
                tuple(registers),
                value=options,
            ),
        }
        # Initialize form
        super().__init__(form_text, controls)

    def OnFormChange(self, fid):
        """Handle form changes."""
        if fid == self.cWildcardableOperands.id:
            global WildcardableOperandTypeBitmask
            # print(f"cWildcardableOperands changed: {self.GetControlValue(self.cWildcardableOperands):06x}")
            # Re-shift by one because we skipped o_void
            WildcardableOperandTypeBitmask = (
                self.GetControlValue(self.cWildcardableOperands) << 1
            )
        return 1


class ConfigureOptionsForm(ida_kernwin.Form):
    """Interactive Form to configure XREF and signature generation options."""

    def __init__(self):
        F = ida_kernwin.Form

        # Define the form layout
        form_text = """BUTTON YES* OK
BUTTON CANCEL Cancel
Options

<#Print top X shortest signatures when generating xref signatures#Print top X XREF signatures     :{opt1}>
<#Stop after reaching X bytes when generating a single signature#Maximum single signature length :{opt2}>
<#Stop after reaching X bytes when generating xref signatures#Maximum xref signature length   :{opt3}>
"""

        # Define numerical input fields (corresponding to `u` in C++)
        self.controls = {
            "opt1": F.NumericInput(tp=F.FT_DEC),  # PRINT_TOP_X
            "opt2": F.NumericInput(tp=F.FT_DEC),  # MAX_SINGLE_SIGNATURE_LENGTH
            "opt3": F.NumericInput(tp=F.FT_DEC),  # MAX_XREF_SIGNATURE_LENGTH
        }

        # Initialize form
        super().__init__(form_text, self.controls)

    def ExecuteForm(self):
        """Execute the form and apply changes."""
        global PRINT_TOP_X, MAX_SINGLE_SIGNATURE_LENGTH, MAX_XREF_SIGNATURE_LENGTH

        # Pre-fill form values
        self.controls["opt1"].value = PRINT_TOP_X
        self.controls["opt2"].value = MAX_SINGLE_SIGNATURE_LENGTH
        self.controls["opt3"].value = MAX_XREF_SIGNATURE_LENGTH

        result = self.Execute()
        # Show form
        if result != 1:
            self.Free()
            return result

        # Apply the new values to the global variables
        PRINT_TOP_X = self.controls["opt1"].value
        MAX_SINGLE_SIGNATURE_LENGTH = self.controls["opt2"].value
        MAX_XREF_SIGNATURE_LENGTH = self.controls["opt3"].value
        self.Free()
        return result


class SignatureMakerForm(ida_kernwin.Form):
    def __init__(self):
        F = ida_kernwin.Form
        form_text = (
            f"""STARTITEM 0
BUTTON YES* OK
BUTTON CANCEL Cancel
Signature Maker v{PLUGIN_VERSION} {("(AVX2)" if USE_QIS_SIGNATURE else "")}"""
            + r"""
{FormChangeCb}
Select action:
<#Select an address, and create a code signature for it#Create unique signature for current code address:{rCreateUniqueSig}>
<#Select an address or variable, and create code signatures for its references. Will output the shortest 5 signatures#Find shortest XREF signature for current data or code address:{rFindXRefSig}>
<#Select 1+ instructions, and copy the bytes using the specified output format#Copy selected code:{rCopyCode}>
<#Paste any string containing your signature/mask and find matches#Search for a signature:{rSearchSignature}>{rAction}>

Output format:
<#Example - E8 ? ? ? ? 45 33 F6 66 44 89 34 33#IDA Signature:{rIDASig}>
<#Example - E8 ?? ?? ?? ?? 45 33 F6 66 44 89 34 33#x64Dbg Signature:{rx64DbgSig}>
<#Example - \\xE8\\x00\\x00\\x00\\x00\\x45\\x33\\xF6\\x66\\x44\\x89\\x34\\x33 x????xxxxxxxx#C Byte Array String Signature + String mask:{rByteArrayMaskSig}>
<#Example - 0xE8, 0x00, 0x00, 0x00, 0x00, 0x45, 0x33, 0xF6, 0x66, 0x44, 0x89, 0x34, 0x33 0b1111111100001#C Bytes Signature + Bitmask:{rRawBytesBitmaskSig}>{rOutputFormat}>

Quick Options:
<#Enable wildcarding for operands, to improve stability of created signatures#Wildcards for operands:{cWildcardOperands}>
<#Don't stop signature generation when reaching end of function#Continue when leaving function scope:{cContinueOutside}>
<#Wildcard the whole instruction when the operand (usually a register) is encoded into the operator#Wildcard optimized / combined instructions:{cWildcardOptimized}>{cGroupOptions}>

<Operand types...:{bOperandTypes}><Other options...:{bOtherOptions}>
"""
        )
        controls = {
            "cVersion": F.StringLabel(PLUGIN_VERSION),
            "FormChangeCb": F.FormChangeCb(self.OnFormChange),
            # Radio group for selecting the main action.
            "rAction": F.RadGroupControl(
                ("rCreateUniqueSig", "rFindXRefSig", "rCopyCode", "rSearchSignature")
            ),
            # Radio group for selecting output format.
            "rOutputFormat": F.RadGroupControl(
                ("rIDASig", "rx64DbgSig", "rByteArrayMaskSig", "rRawBytesBitmaskSig")
            ),
            # Checkboxes for quick options.
            "cGroupOptions": ida_kernwin.Form.ChkGroupControl(
                ("cWildcardOperands", "cContinueOutside", "cWildcardOptimized"),
                value=5,
            ),
            # Buttons for further configuration.
            "bOperandTypes": F.ButtonInput(self.ConfigureOperandWildcardBitmask),
            "bOtherOptions": F.ButtonInput(self.ConfigureOptions),
        }
        super().__init__(form_text, controls)

    def OnFormChange(self, fid):
        # (Optional: add code to respond to field changes.)
        # print(f"Form changed, fid: {fid}", self.rAction.id, self.rOutputFormat.id, self.cGroupOptions.id)
        # if fid == self.rAction.id:
        #     print(
        #         f"Action [{fid}] rAction changed: {self.GetControlValue(self.rAction):06x}"
        #     )
        # elif fid == self.rOutputFormat.id:
        #     print(
        #         f"Action [{fid}] rOutputFormat changed: {self.GetControlValue(self.rOutputFormat):06x}"
        #     )
        # elif fid == self.cGroupOptions.id:
        #     print(
        #         f"Action [{fid}] cGroupOptions changed: {self.GetControlValue(self.cGroupOptions):06x}"
        #     )
        # else:
        #     print(">>fid:%d" % fid)
        return 1

    def ConfigureOperandWildcardBitmask(self, code=0):
        form = ConfigureOperandWildcardBitmaskForm()
        form.Compile()
        ok = form.Execute()
        if not ok:
            return 0
        return 1

    def ConfigureOptions(self, code=0):
        """Launch the options configuration form."""
        form = ConfigureOptionsForm()
        form.Compile()
        return form.ExecuteForm()


# -------------------------
# The main plugin class
# -------------------------


def set_wildcardable_operand_type_bitmask():
    global WildcardableOperandTypeBitmask

    # Default wildcard setting depending on processor arch
    if PROCESSOR_ARCH == ida_idp.PLFM_386:
        o_ymmreg = idc.o_xmmreg + 1
        o_zmmreg = o_ymmreg + 1
        o_kreg = o_zmmreg + 1
        WildcardableOperandTypeBitmask = (
            BIT(idc.o_mem)
            | BIT(idc.o_phrase)
            | BIT(idc.o_displ)
            | BIT(idc.o_far)
            | BIT(idc.o_near)
            | BIT(idc.o_imm)
            | BIT(idc.o_trreg)
            | BIT(idc.o_dbreg)
            | BIT(idc.o_crreg)
            | BIT(idc.o_fpreg)
            | BIT(idc.o_mmxreg)
            | BIT(idc.o_xmmreg)
            | BIT(o_ymmreg)
            | BIT(o_zmmreg)
            | BIT(o_kreg)
        )
    elif PROCESSOR_ARCH == ida_idp.PLFM_ARM:
        WildcardableOperandTypeBitmask = (
            BIT(idc.o_mem)
            | BIT(idc.o_phrase)
            | BIT(idc.o_displ)
            | BIT(idc.o_far)
            | BIT(idc.o_near)
            | BIT(idc.o_imm)
        )
    elif PROCESSOR_ARCH == ida_idp.PLFM_MIPS:
        WildcardableOperandTypeBitmask = (
            BIT(idc.o_mem) | BIT(idc.o_far) | BIT(idc.o_near)
        )
    else:
        WildcardableOperandTypeBitmask = (
            BIT(idc.o_mem)
            | BIT(idc.o_phrase)
            | BIT(idc.o_displ)
            | BIT(idc.o_far)
            | BIT(idc.o_near)
            | BIT(idc.o_imm)
        )


class _ActionHandler(idaapi.action_handler_t):

    def __init__(self, action_function):
        super().__init__()
        self.action_function = action_function

    def activate(self, ctx):
        self.action_function(ctx=ctx)
        return 1

    def update(self, ctx):
        if ctx.widget_type == idaapi.BWN_DISASM:
            return idaapi.AST_ENABLE_FOR_WIDGET
        return idaapi.AST_DISABLE_FOR_WIDGET


def is_disassembly_widget(widget, popup, ctx):
    return idaapi.get_widget_type(widget) == idaapi.BWN_DISASM


class _PopupHook(idaapi.UI_Hooks):

    def __init__(
        self, action_name, predicate=None, widget_populator=None, category=None
    ):
        super().__init__()
        self.action_name = action_name
        self.predicate = predicate or is_disassembly_widget
        self.widget_populator = widget_populator or self._default_populator
        self.category = category

    def term(self):
        idaapi.unregister_action(self.action_name)

    @staticmethod
    def _default_populator(instance, widget, popup_handle, ctx):
        if instance.predicate(widget, popup_handle, ctx):
            args = [widget, popup_handle, instance.action_name]
            if instance.category:
                args.append(f"{instance.category}/")
            idaapi.attach_action_to_popup(*args)

    def finish_populating_widget_popup(self, widget, popup_handle, ctx=None):
        return self.widget_populator(self, widget, popup_handle, ctx)


class PySigMaker(ida_idaapi.plugin_t):
    flags = ida_idaapi.PLUGIN_KEEP
    comment = f"{PLUGIN_NAME} v{PLUGIN_VERSION} for IDA Pro by {PLUGIN_AUTHOR}"
    help = "Select location in disassembly and press CTRL+ALT+S to open menu"
    wanted_name = PLUGIN_NAME
    wanted_hotkey = "Ctrl-Alt-S"
    IS_ARM = False

    ACTION_SHOW_SIGMAKER = "pysigmaker:show"

    def init(self):
        self.progress_dialog = ProgressDialog()
        self._hooks = self._init_hooks(_PopupHook(self.ACTION_SHOW_SIGMAKER))
        self._register_actions()
        return ida_idaapi.PLUGIN_KEEP

    def run(self, arg):
        self.run_plugin()

    def term(self):
        # unregister our actions & free their resources
        self._deregister_actions()
        # unhook our plugin hooks
        self._deinit_hooks(*self._hooks)

    def _init_hooks(self, *hooks):
        for hook in hooks:
            hook.hook()
        return hooks

    def _deinit_hooks(self, *hooks):
        for hook in hooks:
            hook.unhook()

    def _register_actions(self):
        # If the action is already registered, unregister it first.
        self._deregister_actions()
        # Describe the action using python3 copy
        idaapi.register_action(
            idaapi.action_desc_t(
                self.ACTION_SHOW_SIGMAKER,  # The action name.
                "SigMaker",  # The action text.
                _ActionHandler(self.run_plugin),  # The action handler.
                self.wanted_hotkey,  # Optional: action shortcut
                "Show the signature maker dialog.",  # Optional: tooltip
                154,  # magnifying glass icon
            )
        )

    def _deregister_actions(self):
        return idaapi.unregister_action(self.ACTION_SHOW_SIGMAKER)

    # -------------------------
    # Processor and operand handling
    # -------------------------
    def IsARM(self) -> bool:
        procname = ida_ida.inf_get_procname()
        return "ARM" in procname.upper()

    def GetOperandOffsetARM(self, instruction, operand_offset, operand_length) -> bool:
        # For ARM: assume operand is 3 bytes if size==4, 7 bytes if size==8.
        for op in instruction.ops:
            if op.type in {
                idaapi.o_mem,
                idaapi.o_far,
                idaapi.o_near,
                idaapi.o_phrase,
                idaapi.o_displ,
                idaapi.o_imm,
            }:
                operand_offset[0] = op.offb
                if instruction.size == 4:
                    operand_length[0] = 3
                elif instruction.size == 8:
                    operand_length[0] = 7
                else:
                    operand_length[0] = 0
                return True
        return False

    def GetOperand(
        self, instruction, operand_offset, operand_length, wildcard_optimized
    ) -> bool:
        # For non-ARM: iterate over operands and apply the bitmask and optimized–instruction check.
        if self.IS_ARM:
            return self.GetOperandOffsetARM(instruction, operand_offset, operand_length)
        for op in instruction.ops:
            if op.type == idaapi.o_void:
                continue
            # Only process operands that are marked in our bitmask.
            if (BIT(op.type) & WildcardableOperandTypeBitmask) == 0:
                continue
            isOptimizedInstr = op.offb == 0
            if isOptimizedInstr and not wildcard_optimized:
                continue
            operand_offset[0] = op.offb
            operand_length[0] = instruction.size - op.offb
            return True
        return False

    # -------------------------
    # QIS scanning support
    # -------------------------
    def ReadSegmentsToBuffer(self) -> bytes:
        buf = bytearray()
        seg = idaapi.get_first_seg()
        while seg:
            size = seg.end_ea - seg.start_ea
            data = ida_bytes.get_bytes(seg.start_ea, size)
            if data:
                buf.extend(data)
            seg = idaapi.get_next_seg(seg)
        return bytes(buf)

    def parse_signature(self, sig_str: str):
        # Convert a signature string (tokens separated by whitespace)
        # into a list of tuples (value, is_wildcard)
        tokens = sig_str.split()
        pattern = []
        for token in tokens:
            if "?" in token:
                pattern.append((0, True))
            else:
                try:
                    val = int(token, 16)
                except Exception:
                    val = 0
                pattern.append((val, False))
        return pattern

    def FindSignatureOccurencesQis(
        self, ida_signature: str, skip_more_than_one: bool = False
    ) -> list:
        global FILE_BUFFER
        if not FILE_BUFFER:
            with ProgressDialog("Please stand by, copying segments..."):
                FILE_BUFFER = self.ReadSegmentsToBuffer()
        # Convert to QIS signature string: simply double each '?'
        qis_signature = ida_signature.replace("?", "??")
        pattern = self.parse_signature(qis_signature)
        results = []
        base_ea = ida_ida.inf_get_min_ea()
        data = FILE_BUFFER
        pat_len = len(pattern)
        i = 0
        while i <= len(data) - pat_len:
            match = True
            for j, (val, is_wildcard) in enumerate(pattern):
                if not is_wildcard and data[i + j] != val:
                    match = False
                    break
            if match:
                results.append(base_ea + i)
                if skip_more_than_one and len(results) > 1:
                    break
            i += 1
        return results

    def FindSignatureOccurences(self, ida_signature: str) -> list:
        if USE_QIS_SIGNATURE:
            return self.FindSignatureOccurencesQis(ida_signature)
        # Otherwise use IDA’s built-in binary pattern search.
        binary_pattern = idaapi.compiled_binpat_vec_t()
        idaapi.parse_binpat_str(
            binary_pattern, ida_ida.inf_get_min_ea(), ida_signature, 16
        )
        results = []
        ea = ida_ida.inf_get_min_ea()
        _bin_search = getattr(ida_bytes, "bin_search", None)
        # See https://github.com/mahmoudimus/ida-pysigmaker/pull/2
        # In particular this discussion:
        # https://github.com/mahmoudimus/ida-pysigmaker/pull/2#discussion_r1991913976
        if not _bin_search:
            _bin_search = getattr(ida_bytes, "bin_search3")
        while True:
            occurence, _ = _bin_search(
                ea,
                ida_ida.inf_get_max_ea(),
                binary_pattern,
                ida_bytes.BIN_SEARCH_NOCASE | ida_bytes.BIN_SEARCH_FORWARD,
            )
            if occurence == idaapi.BADADDR:
                break
            results.append(occurence)
            ea = occurence + 1
        return results

    def IsSignatureUnique(self, ida_signature: str) -> bool:
        return len(self.FindSignatureOccurences(ida_signature)) == 1

    # -------------------------
    # Signature generation for unique EA and a range
    # -------------------------
    def GenerateUniqueSignatureForEA(
        self,
        ea,
        wildcard_operands,
        continue_outside_of_function,
        wildcard_optimized,
        max_signature_length=1000,
        ask_longer_signature=True,
    ):
        if ea == idaapi.BADADDR:
            raise Unexpected("Invalid address")
        if not idaapi.is_code(ida_bytes.get_flags(ea)):
            raise Unexpected("Cannot create code signature for data")
        signature = []
        sig_part_length = 0
        current_function = idaapi.get_func(ea)
        current_address = ea

        while True:
            if idaapi.user_cancelled():
                raise Unexpected("Aborted")
            instruction = idaapi.insn_t()
            current_instruction_length = idaapi.decode_insn(
                instruction, current_address
            )
            if current_instruction_length <= 0:
                if not signature:
                    raise Unexpected("Failed to decode first instruction")
                idc.msg(
                    f"Signature reached end of executable code @ {current_address:X}\n"
                )
                sig_str = BuildIDASignatureString(signature)
                idc.msg(f"NOT UNIQUE Signature for {ea:X}: {sig_str}\n")
                raise Unexpected("Signature not unique")
            if sig_part_length > max_signature_length:
                if ask_longer_signature:
                    result = idaapi.ask_yn(
                        idaapi.ASKBTN_YES,
                        f"Signature is already at {len(signature)} bytes. Continue?",
                    )
                    if result == 1:
                        sig_part_length = 0
                    elif result == 0:
                        sig_str = BuildIDASignatureString(signature)
                        idc.msg(f"NOT UNIQUE Signature for {ea:X}: {sig_str}\n")
                        raise Unexpected("Signature not unique")
                    else:
                        raise Unexpected("Aborted")
                else:
                    raise Unexpected("Signature exceeded maximum length")
            sig_part_length += current_instruction_length

            operand_offset = [0]
            operand_length = [0]
            if (
                wildcard_operands
                and self.GetOperand(
                    instruction, operand_offset, operand_length, wildcard_optimized
                )
                and operand_length[0] > 0
            ):
                AddBytesToSignature(
                    signature, current_address, operand_offset[0], False
                )
                AddBytesToSignature(
                    signature,
                    current_address + operand_offset[0],
                    operand_length[0],
                    True,
                )
                if operand_offset[0] == 0:
                    AddBytesToSignature(
                        signature,
                        current_address + operand_length[0],
                        current_instruction_length - operand_length[0],
                        False,
                    )
            else:
                AddBytesToSignature(
                    signature, current_address, current_instruction_length, False
                )

            current_sig = BuildIDASignatureString(signature)
            if self.IsSignatureUnique(current_sig):
                TrimSignature(signature)
                return signature

            current_address += current_instruction_length

            if (
                not continue_outside_of_function
                and current_function
                and idaapi.get_func(current_address) != current_function
            ):
                raise Unexpected("Signature left function scope")
        raise Unexpected("Unknown")

    def GenerateSignatureForEARange(
        self, ea_start, ea_end, wildcard_operands, wildcard_optimized
    ):
        if ea_start == idaapi.BADADDR or ea_end == idaapi.BADADDR:
            raise Unexpected("Invalid address")
        signature = []
        sig_part_length = 0
        if not idaapi.is_code(ida_bytes.get_flags(ea_start)):
            AddBytesToSignature(signature, ea_start, ea_end - ea_start, False)
            return signature

        current_address = ea_start
        while True:
            if idaapi.user_cancelled():
                raise Unexpected("Aborted")
            instruction = idaapi.insn_t()
            current_instruction_length = idaapi.decode_insn(
                instruction, current_address
            )
            if current_instruction_length <= 0:
                if not signature:
                    raise Unexpected("Failed to decode first instruction")
                idc.msg(
                    f"Signature reached end of executable code @ {current_address:X}\n"
                )
                if current_address < ea_end:
                    AddBytesToSignature(
                        signature, current_address, ea_end - current_address, False
                    )
                TrimSignature(signature)
                return signature
            sig_part_length += current_instruction_length

            operand_offset = [0]
            operand_length = [0]
            if (
                wildcard_operands
                and self.GetOperand(
                    instruction, operand_offset, operand_length, wildcard_optimized
                )
                and operand_length[0] > 0
            ):
                AddBytesToSignature(
                    signature, current_address, operand_offset[0], False
                )
                AddBytesToSignature(
                    signature,
                    current_address + operand_offset[0],
                    operand_length[0],
                    True,
                )
                if operand_offset[0] == 0:
                    AddBytesToSignature(
                        signature,
                        current_address + operand_length[0],
                        current_instruction_length - operand_length[0],
                        False,
                    )
            else:
                AddBytesToSignature(
                    signature, current_address, current_instruction_length, False
                )
            current_address += current_instruction_length

            if current_address >= ea_end:
                TrimSignature(signature)
                return signature
        raise Unexpected("Unknown")

    # -------------------------
    # Output functions
    # -------------------------
    def PrintSignatureForEA(self, signature, ea, sig_type):
        if not signature:
            idc.msg(f"Error: {signature}\n")
            return
        sig_str = FormatSignature(signature, sig_type)
        idc.msg(f"Signature for {ea:X}: {sig_str}\n")
        if not SetClipboardText(sig_str):
            idc.msg("Failed to copy to clipboard!")

    def FindXRefs(
        self,
        ea,
        wildcard_operands,
        continue_outside_of_function,
        wildcard_optimized,
        xref_signatures,
        max_signature_length,
    ):
        # Count code xrefs.
        xref_count = 0
        xb = ida_xref.xrefblk_t()
        if xb.first_to(ea, ida_xref.XREF_ALL):
            while True:
                if idaapi.is_code(ida_bytes.get_flags(xb.frm)):
                    xref_count += 1
                if not xb.next_to():
                    break
        # Process each xref.
        xb = ida_xref.xrefblk_t()
        if not xb.first_to(ea, ida_xref.XREF_ALL):
            return
        i = 0
        shortest_signature_length = max_signature_length + 1
        while True:
            if self.progress_dialog.user_cancelled():
                break
            if not idaapi.is_code(ida_bytes.get_flags(xb.frm)):
                if not xb.next_to():
                    break
                continue
            i += 1
            idaapi.replace_wait_box(
                f"Processing xref {i} of {xref_count} ({(i / xref_count) * 100.0:.1f}%)...\n\n"
                f"Suitable Signatures: {len(xref_signatures)}\n"
                f"Shortest Signature: {shortest_signature_length if shortest_signature_length <= max_signature_length else 0} Bytes"
            )
            try:
                sig = self.GenerateUniqueSignatureForEA(
                    xb.frm,
                    wildcard_operands,
                    continue_outside_of_function,
                    wildcard_optimized,
                    max_signature_length,
                    False,
                )
            except Exception:
                sig = None
            if sig:
                if len(sig) < shortest_signature_length:
                    shortest_signature_length = len(sig)
                xref_signatures.append((xb.frm, sig))
            if not xb.next_to():
                break
        xref_signatures.sort(key=lambda tup: len(tup[1]))

    def PrintXRefSignaturesForEA(self, ea, xref_signatures, sig_type, top_count):
        if not xref_signatures:
            idc.msg("No XREFs have been found for your address\n")
            return
        top_length = min(top_count, len(xref_signatures))
        idc.msg(
            f"Top {top_length} Signatures out of {len(xref_signatures)} xrefs for {ea:X}:\n"
        )
        for i in range(top_length):
            origin_address, signature = xref_signatures[i]
            sig_str = FormatSignature(signature, sig_type)
            idc.msg(f"XREF Signature #{i+1} @ {origin_address:X}: {sig_str}\n")
            if i == 0:
                SetClipboardText(sig_str)

    def PrintSelectedCode(
        self, start, end, sig_type, wildcard_operands, wildcard_optimized
    ):
        selection_size = end - start
        if selection_size <= 0:
            idc.msg("Invalid selection size\n")
            return
        try:
            signature = self.GenerateSignatureForEARange(
                start, end, wildcard_operands, wildcard_optimized
            )
        except Unexpected as e:
            idc.msg(f"Error: {str(e)}\n")
            return
        sig_str = FormatSignature(signature, sig_type)
        idc.msg(f"Code for {start:X}-{end:X}: {sig_str}\n")
        SetClipboardText(sig_str)

    def SearchSignatureString(self, input_str: str):
        converted_signature_string = ""
        string_mask = ""
        # Try to detect a string mask like "xx????xx?xx"
        m = re.search(r"x(?:x|\?)+", input_str)
        if m:
            string_mask = m.group(0)
        else:
            m = re.search(r"0b(?:[01]+)", input_str)
            if m:
                bits = m.group(0)[2:]
                reversed_bits = bits[::-1]
                string_mask = "".join("x" if b == "1" else "?" for b in reversed_bits)
        if string_mask:
            raw_byte_strings = []
            if GetRegexMatches(
                input_str,
                re.compile(r"\\x[0-9A-F]{2}", re.IGNORECASE),
                raw_byte_strings,
            ) and len(raw_byte_strings) == len(string_mask):
                converted_signature = []
                for i, m in enumerate(raw_byte_strings):
                    b = SignatureByte(int(m[2:], 16), string_mask[i] == "?")
                    converted_signature.append(b)
                converted_signature_string = BuildIDASignatureString(
                    converted_signature
                )
            elif GetRegexMatches(
                input_str,
                re.compile(r"(?:0x[0-9A-F]{2})+", re.IGNORECASE),
                raw_byte_strings,
            ) and len(raw_byte_strings) == len(string_mask):
                converted_signature = []
                for i, m in enumerate(raw_byte_strings):
                    b = SignatureByte(int(m[2:], 16), string_mask[i] == "?")
                    converted_signature.append(b)
                converted_signature_string = BuildIDASignatureString(
                    converted_signature
                )
            else:
                idc.msg(
                    f'Detected mask "{string_mask}" but failed to match corresponding bytes\n'
                )
        else:
            # Remove extraneous characters and normalize
            s = re.sub(r"[\)\(\[\]]+", "", input_str)
            s = re.sub(r"^\s+", "", s)
            s = re.sub(r"[? ]+$", "", s) + " "
            s = re.sub(r"\\?\\x", "", s)
            s = re.sub(r"\s+", " ", s)
            converted_signature_string = s

        if not converted_signature_string:
            idc.msg("Unrecognized signature type\n")
            return

        idc.msg(f"Signature: {converted_signature_string}\n")
        signature_matches = self.FindSignatureOccurences(converted_signature_string)
        if not signature_matches:
            idc.msg("Signature does not match!\n")
            return
        for ea in signature_matches:
            idc.msg(f"Match @ {ea:X}\n")

    # -------------------------
    # Main plugin UI and dispatch
    # -------------------------
    def run_plugin(self, ctx=None):
        # Determine processor type and set globals.
        self.IS_ARM = self.IsARM()

        set_wildcardable_operand_type_bitmask()

        # Show the main form.
        form = SignatureMakerForm()
        form.Compile()
        ok = form.Execute()
        if not ok:
            form.Free()
            return

        action = form.rAction.value
        output_format = form.rOutputFormat.value
        wildcard_operands = form.cGroupOptions.value & 1
        continue_outside_of_function = form.cGroupOptions.value & 2
        wildcard_optimized = form.cGroupOptions.value & 4

        # If the configuration buttons were pressed, they may have updated globals.
        form.Free()

        sig_type = SignatureType(output_format)

        try:
            if action == 0:
                # Create unique signature for current code address.
                ea = ida_kernwin.get_screen_ea()
                with self.progress_dialog("Generating signature..."):
                    sig = self.GenerateUniqueSignatureForEA(
                        ea,
                        wildcard_operands,
                        continue_outside_of_function,
                        wildcard_optimized,
                        MAX_SINGLE_SIGNATURE_LENGTH,
                    )
                    self.PrintSignatureForEA(sig, ea, sig_type)
            elif action == 1:
                # Find XREF signatures.
                ea = ida_kernwin.get_screen_ea()
                xref_signatures = []
                with self.progress_dialog(
                    "Finding references and generating signatures. This can take a while..."
                ):
                    self.FindXRefs(
                        ea,
                        wildcard_operands,
                        continue_outside_of_function,
                        wildcard_optimized,
                        xref_signatures,
                        MAX_XREF_SIGNATURE_LENGTH,
                    )
                    self.PrintXRefSignaturesForEA(
                        ea, xref_signatures, sig_type, PRINT_TOP_X
                    )
            elif action == 2:
                # Copy selected code.
                start, end = get_selected_addresses(idaapi.get_current_viewer())
                if start and end:
                    with self.progress_dialog("Please stand by..."):
                        self.PrintSelectedCode(
                            start, end, sig_type, wildcard_operands, wildcard_optimized
                        )
                else:
                    idc.msg("Select a range to copy the code!\n")
            elif action == 3:
                # Search for a signature.
                input_signature = idaapi.ask_str(
                    "", idaapi.HIST_SRCH, "Enter a signature"
                )
                if input_signature:
                    with self.progress_dialog("Searching..."):
                        self.SearchSignatureString(input_signature)
        except Unexpected as e:
            idc.msg(f"Error: {str(e)}\n")
        except Exception as e:
            print(e, os.linesep, traceback.format_exc())
            return


def get_selected_addresses(ctx):
    is_selected, start_ea, end_ea = idaapi.read_range_selection(ctx)
    if is_selected:
        return start_ea, end_ea

    # maybe it's the same line?
    p0, p1 = ida_kernwin.twinpos_t(), ida_kernwin.twinpos_t()
    ida_kernwin.read_selection(ctx, p0, p1)
    p0.place(ctx)
    p1.place(ctx)
    if p0.at and p1.at:
        start_ea = p0.at.toea()
        end_ea = p1.at.toea()
        if start_ea == end_ea:
            start_ea = idc.get_item_head(start_ea)
            end_ea = idc.get_item_end(start_ea)
            return start_ea, end_ea

    # if we are here, we haven't selected anything, so we use the current address
    start_ea = idaapi.get_screen_ea()
    try:
        end_ea = ida_kernwin.ask_addr(start_ea, "Enter end address for selection:")
    finally:
        # restore the cursor to the original address
        idc.jumpto(start_ea)

    if end_ea and end_ea <= start_ea:
        print(
            f"Error: End address 0x{end_ea:X} must be greater than start address 0x{start_ea:X}."
        )
        end_ea = None

    if end_ea is None:
        # if we canceled the dialog, let's assume the user wants
        # to select just the line they're on
        end_ea = idc.get_item_end(start_ea)
        print(f"No end address selected, using line end: 0x{end_ea:X}")

    return start_ea, end_ea


def PLUGIN_ENTRY():
    return PySigMaker()


repository: andreafioraldi/IdaGrabStrings
file: IdaGrabStrings.py
description: IDAPython plugin to search strings in a specified range of addresses and map it to a C struct
wanted_name: IDA Grab Strings
created_at: 2017-04-24 17:41:00+00:00
pushed_at: 2017-05-12 12:09:26+00:00
url:
https://github.com/andreafioraldi/IdaGrabStrings/blob/f001759ba8424e9bcf2845d9f725916e8f0e2572/IdaGrabStrings.py

content:
__author__ = "Andrea Fioraldi"
__copyright__ = "Copyright 2017, Andrea Fioraldi"
__license__ = "MIT"
__email__ = "andreafioraldi@gmail.com"

import idaapi
import subprocess
import idc
import os
import threading

pwd = os.path.dirname(__file__)

def startView(buf):
    view = subprocess.Popen(
        [os.path.join(pwd, "IdaGrabStringsView.exe")],
        stdout=subprocess.PIPE,
        stdin=subprocess.PIPE,
        shell=True
        )
    view.communicate(input=buf)

def startViewGetPosition():
    pos = idc.ScreenEA()
    view = subprocess.Popen(
        [os.path.join(pwd, "IdaGrabStringsView.exe"), "0x"+hex(pos)],
        stdout=subprocess.PIPE,
        stdin=subprocess.PIPE
        )
    output = view.communicate()[0]
    lines = output.split("\n")
    return (int(lines[0]), int(lines[1]))

def fromPositionThread():
    pos, length = startViewGetPosition()
    idaapi.msg("IdaGrabStrings: getted position = "+hex(pos)+" "+str(length)+"\n")
    buf = idc.GetManyBytes(pos, length, False)
    startView(buf)

def fromPosition():
    thread = threading.Thread(target=fromPositionThread, args=tuple())
    thread.deamon = True
    thread.start()

def fromSelection():
    sel = idaapi.read_selection()
    buf = idc.GetManyBytes(sel[1], sel[2] - sel[1], False)
    thread = threading.Thread(target=startView, args=(buf, ))
    thread.deamon = True
    thread.start()
          

MENU_PATH = 'Edit/Other'
class IdaGrabStringsPlugin(idaapi.plugin_t):
    flags = idaapi.PLUGIN_KEEP
    comment = ""

    help = "IdaGrabStrings: Grab strings from a bytes buffer in IDA"
    wanted_name = "IDA Grab Strings"
    wanted_hotkey = "Alt-8"
    
    def init(self):
        r = idaapi.add_menu_item(MENU_PATH, 'IdaGrabStrings - From position', '', 1, fromPosition, tuple())
        if r is None:
            idaapi.msg("IdaGrabStrings: add menu failed!\n")
            return idaapi.PLUGIN_SKIP
        r = idaapi.add_menu_item(MENU_PATH, 'IdaGrabStrings - From selection', '', 1, fromSelection, tuple())
        if r is None:
            idaapi.msg("IdaGrabStrings: add menu failed!\n")
            return idaapi.PLUGIN_SKIP
        idaapi.msg("IdaGrabStrings: initialized\n")
        return idaapi.PLUGIN_KEEP

    def run(self, arg):
        pass

    def term(self):
        idaapi.msg("IdaGrabStrings: terminated\n")


def PLUGIN_ENTRY():
    return IdaGrabStringsPlugin()


repository: williballenthin/idawilli
file: plugins/tag_func.py
description: IDA Pro resources, scripts, and configurations
comment: Quickly organize functions into tags via hotkey
created_at: 2016-12-14 02:23:46+00:00
pushed_at: 2025-05-12 10:45:42+00:00
url:
https://github.com/williballenthin/idawilli/blob/063417207eebd061fbd58f6441e6b5e9ffc43f8e/plugins/tag_func.py

content:
import logging
from typing import Iterator, List, Optional, Tuple

import ida_ua
import ida_name
import ida_funcs
import ida_idaapi
import ida_kernwin
import ida_dirtree

from ida_dirtree import dirtree_t

logger = logging.getLogger("tag_func")


def dirtree_find(dir, pattern) -> Iterator[ida_dirtree.dirtree_cursor_t]:
    """
    enumerate the matches for the given pattern against the given dirtree.
    this is just a Pythonic helper over the SWIG-generated routines.
    """
    # pattern format:
    #  "*" for all in current directory, does not recurse
    #  "/" for root directory
    #  "/sub_410000" for item by name
    #  "/foo" for directory by name, no trailing slash
    #  "/foo/*" for path prefix
    #      does not recurse beyond the prefix path
    #      matches "/foo/sub_401000" and but not "/foo/bar/sub_4010005"
    #  "/foo/sub_*" for path prefix (matches "/foo/sub_401000")
    #  "*main" for suffix (matches "/_main" because leading / is implied)
    #  "*mai*" for substring (matches "/_main" and "/_main_0" because leading / is implied)
    #
    #  wildcards only seem to match within path components
    #    does *not* work:
    #      "/*/sub_401000"
    #      "*/sub_401000"
    #      "*"
    #
    # to search by name, i guess use pattern "*" and check get_entry_name
    ff = ida_dirtree.dirtree_iterator_t()
    ok = dir.findfirst(ff, pattern)
    while ok:
        yield ff.cursor
        ok = dir.findnext(ff)


def dirtree_join(*parts) -> str:
    return "/".join(parts)


def dirtree_walk(dir: dirtree_t, top: str) -> Iterator[Tuple[str, List[str], List[str]]]:
    """
    like os.walk over the given dirtree.

    yields tuples: (root, [dirs], [files])
    use dirtree_join(*parts) to join root and dir/file entry:

        # print all files
        for root, dirs, files in dirtree_walk(func_dir, "/"):
            for file in files:
                print(dirtree_join(root, file))
    """
    top = top.rstrip("/")
    directories = [top]

    while len(directories) > 0:
        directory = directories.pop(0)

        dirs = []
        files = []

        for cursor in dirtree_find(dir, f"{directory}/*"):
            dirent = dir.resolve_cursor(cursor)
            name = dir.get_entry_name(dirent)

            if dirent.isdir:
                dirs.append(name)
                directories.append(dirtree_join(directory, name))
            else:
                files.append(name)

        yield (directory, dirs, files)


def find_function_dirtree_path(va: int) -> Optional[str]:
    """
    given the address of a function
    find its absolute path within the function dirtree.
    """
    func_dir: dirtree_t = ida_dirtree.get_std_dirtree(ida_dirtree.DIRTREE_FUNCS)

    name = ida_name.get_name(va)
    if not name:
        return None

    for root, _, files in dirtree_walk(func_dir, "/"):
        for file in files:
            if file == name:
                return dirtree_join(root, file)

    return None


def dirtree_mkdirs(dir, path):
    parts = path.split("/")

    for i in range(2, len(parts) + 1):
        prefix = "/".join(parts[:i])

        if not dir.isdir(prefix):
            e = dir.mkdir(prefix)
            if e != ida_dirtree.DTE_OK:
                logger.error("error: %s", ida_dirtree.dirtree_t_errstr(e))
                return e

    return ida_dirtree.DTE_OK


def set_tagged_func_cmt(tag: str, va: int, cmt: str, repeatable: bool):
    func = ida_funcs.get_func(va)
    existing = (ida_funcs.get_func_cmt(func, repeatable) or "").strip()

    prefix = f"{tag}: "
    line = f"{prefix}{cmt}"

    if prefix in existing:
        rest = existing.partition(prefix)[2].partition("\n")[0]
        new = existing.replace(f"{prefix}{rest}", line)
    elif existing == "":
        new = line
    else:
        new = existing + f"\n{line}"

    ida_funcs.set_func_cmt(func, new, repeatable)


def set_func_folder_cmt(va: int, folder: str):
    set_tagged_func_cmt("📁", va, folder, True)


def sync_func_folder_cmts():
    func_dir: dirtree_t = ida_dirtree.get_std_dirtree(ida_dirtree.DIRTREE_FUNCS)
    for root, _, files in dirtree_walk(func_dir, "/"):
        if root == "/" or root == "":
            continue

        tag = root.lstrip("/")
        for file in files:
            va = ida_name.get_name_ea(ida_idaapi.BADADDR, file)
            if va == ida_idaapi.BADADDR:
                continue

            set_func_folder_cmt(va, tag)


def main():
    va = ida_kernwin.get_screen_ea()
    f = ida_funcs.get_func(va)
    if not f:
        logger.error("function not found: 0x%x", va)
        return

    path = find_function_dirtree_path(f.start_ea)
    if not path:
        logger.error("function directory entry not found: 0x%x", f.start_ea)
        return

    func_dir: dirtree_t = ida_dirtree.get_std_dirtree(ida_dirtree.DIRTREE_FUNCS)

    dirent = func_dir.resolve_path(path)
    name = func_dir.get_entry_name(dirent)
    existing_tag = path[:-(len("/") + len(name))].lstrip("/")

    # ask_str(defval, hist, prompt) -> PyObject *
    # I'm not sure what "history id" does.
    tag = ida_kernwin.ask_str(existing_tag, 69, "tag:")
    if not tag:
        return

    tag_path = f"/{tag}"
    if not func_dir.isdir(tag_path):
        logger.info("creating tag: %s", tag)

        e = dirtree_mkdirs(func_dir, tag_path)
        if e != ida_dirtree.DTE_OK:
            logger.error("error: failed to create tag: %s", tag)
            return
 
    else:
        logger.debug("tag exists: %s", tag)

    src_path = path
    src_dirent = func_dir.resolve_path(src_path)
    src_name = func_dir.get_entry_name(src_dirent)

    dst_name = src_name
    dst_path = f"{tag_path}/{dst_name}"

    if src_path == dst_path:
        logger.info("skipping move to itself")
        return

    logger.info("moving %s from %s to %s", src_name, src_path, dst_path)
    e = func_dir.rename(src_path, dst_path)
    if e != ida_dirtree.DTE_OK:
        logger.error("error: %s", ida_dirtree.dirtree_t_errstr(e))
        return

    set_func_folder_cmt(f.start_ea, tag)


class FunctionTagPlugin(ida_idaapi.plugin_t):
    # Mandatory definitions
    PLUGIN_NAME = "Function Tag"
    PLUGIN_VERSION = "1.0.0"
    PLUGIN_AUTHORS = "william.ballenthin@mandiant.com"

    wanted_name = PLUGIN_NAME
    wanted_hotkey = "Z"
    comment = "Quickly organize functions into tags via hotkey"
    version = ""
    flags = 0

    def __init__(self):
        """initialize plugin"""
        pass

    def init(self):
        """called when IDA is loading the plugin"""
        print("Function Tag: loaded")
        sync_func_folder_cmts()
        return ida_idaapi.PLUGIN_OK

    def term(self):
        """called when IDA is unloading the plugin"""
        pass

    def run(self, arg):
        """called when IDA is running the plugin as a script"""
        main()
        return True


def PLUGIN_ENTRY():
    return FunctionTagPlugin()


if __name__ == "__main__":
    sync_func_folder_cmts()
    main()


repository: ZetaTwo/binja-experiments
file: script_pbctf_bintree/pbctf_bintree.py
description: Experiments, snippets and other things related to Binary Ninja
created_at: 2021-10-05 13:29:15+00:00
pushed_at: 2024-10-22 23:18:02+00:00
url:
https://github.com/ZetaTwo/binja-experiments/blob/ca5ba019f1346604aeaa21aff313f139b519db0f/script_pbctf_bintree/pbctf_bintree.py

content:
#!/usr/bin/env python3

import binaryninja
from binaryninja.mediumlevelil import MediumLevelILOperation
import collections
import heapq


TreeNode = collections.namedtuple('TreeNode', ['Code', 'Id', 'Left', 'Right'])
TreeEdge = collections.namedtuple('TreeEdge', ['Dest', 'Val'])
TreePathPartial = collections.namedtuple('TreePathPartial', ['Sum', 'Id', 'Path'])

TARGET_FUNC = 0x400080
MOD_SITE = 0x4000AD
MODS_LIST = 0x400176
PATCH_LEN = 4*8


def apply_patch(bv, base, patch_idx):
    patch = bv.read(MODS_LIST + patch_idx*PATCH_LEN, PATCH_LEN)
    patched = bytes(x^y for x,y in zip(base, patch))
    assert len(patched) == PATCH_LEN, len(patched)
    bv.write(MOD_SITE, patched)
    return patched


def parse_node(bv):
    # Find if statement and branch destinations
    target_func = bv.get_function_at(TARGET_FUNC)
    for mlil_ins in target_func.mlil.instructions:
        if mlil_ins.operation == MediumLevelILOperation.MLIL_IF:
            left = mlil_ins.operands[1]
            left_mlil_bb = [bb for bb in target_func.mlil.basic_blocks if bb.start == left][0]
            right = mlil_ins.operands[2]
            right_mlil_bb = [bb for bb in target_func.mlil.basic_blocks if bb.start == right][0]
            break
    
    if not left_mlil_bb or not right_mlil_bb:
        binaryninja.log_warn(f'Could not parse if-else expression')
        return None, None
    
    # Get variable assignments from basic blocks
    res = {'left': {}, 'right': {}}
    for ins in left_mlil_bb:
        if ins.operation == MediumLevelILOperation.MLIL_SET_VAR:
            if ins.dest.name in ['arg7', 'arg6']:
                res['left'][ins.dest.name] = (ins.src.operands[0].src.name, ins.src.operands[1].value.value)
    for ins in right_mlil_bb:
        if ins.operation == MediumLevelILOperation.MLIL_SET_VAR:
            if ins.dest.name in ['arg7', 'arg6']:
                res['right'][ins.dest.name] = (ins.src.operands[0].src.name, ins.src.operands[1].value.value)
    
    # Convert arg6/arg7 data to TreeEdge objects
    left = TreeEdge(res['left']['arg7'][1]//PATCH_LEN if 'arg7' in res['left'] else None, res['left']['arg6'][1] if 'arg6' in res['left'] else None)
    right = TreeEdge(res['right']['arg7'][1]//PATCH_LEN if 'arg7' in res['right'] else None, res['right']['arg6'][1] if 'arg6' in res['right'] else None)
    return left, right


def traverse_tree(bv):
    root_node = TreeNode(bv.read(MOD_SITE, PATCH_LEN), 0, None, None)
    tree = {}
    queue = [root_node]
    visited = set([0])
    while len(queue) > 0:
        cur_node = queue.pop(0)
        node_code = apply_patch(bv, cur_node.Code, cur_node.Id)
        bv.update_analysis_and_wait()
        left_branch, right_branch = parse_node(bv)
        
        if left_branch.Dest and left_branch.Dest not in visited:
                visited.add(left_branch.Dest)
                queue.append(TreeNode(node_code, left_branch.Dest, None, None)) 
        
        if right_branch.Dest and right_branch.Dest not in visited:
                visited.add(right_branch.Dest)
                queue.append(TreeNode(node_code, right_branch.Dest, None, None)) 
        
        tree[cur_node.Id] = TreeNode(node_code, cur_node.Id, left_branch, right_branch)

    return tree


def min_path(tree):
    queue = [TreePathPartial(0, 0, [])]    
    visited = set()

    while len(queue) > 0:
        cur_path = heapq.heappop(queue)
        visited.add(cur_path.Id)
        cur_node = tree.get(cur_path.Id, None)

        if len(cur_path.Path) == 800:
            return cur_path.Path
        
        if not cur_node:
            binaryninja.log_warn(f'Missing node {cur_path.Id}')
            continue

        if cur_node.Left and cur_node.Left.Dest not in visited:
            heapq.heappush(queue, TreePathPartial(cur_path.Sum + cur_node.Left.Val, cur_node.Left.Dest, cur_path.Path + [0]))
                
        if cur_node.Right and cur_node.Right.Dest not in visited:
            heapq.heappush(queue, TreePathPartial(cur_path.Sum + cur_node.Right.Val, cur_node.Right.Dest, cur_path.Path + [1]))


def convert_path(path):
    return bytes(int(''.join(str(x) for x in path[i:i+8][::-1]), 2) for i in range(0, len(path), 8)).decode('ascii')


class NodeAnalysis(binaryninja.plugin.BackgroundTaskThread):
    def __init__(self, bv, patch_idx):
        super().__init__("Analyising node", False)
        self.bv = bv
        self.patch_idx = patch_idx
        
    def run(self):
        binaryninja.log_info('Building binary tree')
        tree = traverse_tree(self.bv)
        binaryninja.log_info('Searching tree')
        path = min_path(tree)
        binaryninja.log_info(f'Flag: {convert_path(path)}')
        
        self.finish()


def plugin_entry(bv):
    task = NodeAnalysis(bv, 0)
    task.start()
    task.join()

binaryninja.PluginCommand.register("PBCTF Binary Tree", "", plugin_entry)

# Flag: pbctf{!!finding_the_shortest_path_in_self-modifying_code!!_e74c30e30bb22a478ac513c9017f1b2608abfee7}


repository: HACK-THE-WORLD/IDAPluginList
file: export_func_code/export_func_code.py
description: IDA插件集合，含项目名称及项目地址，每日定时Clone项目。
wanted_name: export_func_code
comment: export_func_code
created_at: 2022-03-21 02:05:27+00:00
pushed_at: 2024-09-21 02:08:36+00:00
url:
https://github.com/HACK-THE-WORLD/IDAPluginList/blob/a6367e2126fca45260d1052b0c54bd332490fd60/export_func_code/export_func_code.py

content:
# -*- coding:utf-8 -*-
import os
from idaapi import plugin_t
from idaapi import PLUGIN_PROC
from idaapi import PLUGIN_OK
import ida_nalt
import idaapi
import idautils
import idc
import time


# 获取SO文件名和路径
def getSoPathAndName():
    fullpath = ida_nalt.get_input_file_path()
    filepath,filename = os.path.split(fullpath)
    return filepath,filename

# 获取代码段的范围
def getSegAddr():
    textStart = []
    textEnd = []

    for seg in idautils.Segments():
        if (idc.get_segm_name(seg)).lower() == '.text' or (
        idc.get_segm_name(seg)).lower() == 'text'or (
        idc.get_segm_name(seg)).lower() == '__text':
            tempStart = idc.get_segm_start(seg)
            tempEnd = idc.get_segm_end(seg)

            textStart.append(tempStart)
            textEnd.append(tempEnd)

    return min(textStart), max(textEnd)


class traceNatives(plugin_t):
    flags = PLUGIN_PROC
    comment = "export_func_code"
    help = ""
    wanted_name = "export_func_code"
    wanted_hotkey = ""

    def init(self):
        print("export_func_code(v0.1) plugin has been loaded.")
        return PLUGIN_OK

    def run(self, arg):
        # 查找需要的函数
        ea, ed = getSegAddr()
        so_path, so_name = getSoPathAndName()
        script_name = so_name.split(".")[0] + "_" + str(int(time.time())) +".txt"
        save_path = os.path.join(so_path, script_name)
        print(f"导出路径：{save_path}")
        F=open(save_path, "w+", encoding="utf-8")
        F.write("\n#####################################\n")
        for func in idautils.Functions(ea, ed):
            try:
                functionName = str(idaapi.ida_funcs.get_func_name(func))
                if len(list(idautils.FuncItems(func))) > 10:
                    # 如果是thumb模式，地址+1
                    arm_or_thumb = idc.get_sreg(func, "T")
                    if arm_or_thumb:
                        func += 1
                    code=str(idaapi.decompile(func))+"\n#####################################\n"
                    print(code)
                    F.write(code)
                    F.flush()
            except Exception as e:
                print(e)
        print(f"导出完成：{save_path}")
        F.close()

    def term(self):
        pass


def PLUGIN_ENTRY():
    return traceNatives()


repository: runope/reserve_android_notes
file: ida/scripts/findcrypt/findcrypt3.py
wanted_name: Findcrypt
comment: Findcrypt plugin for IDA Pro (using yara framework)
created_at: 2022-04-25 09:06:38+00:00
pushed_at: 2022-08-09 06:46:31+00:00
url:
https://github.com/runope/reserve_android_notes/blob/9f436a36245b6c6e0ca0d2b93ee1872960b83d7e/ida/scripts/findcrypt/findcrypt3.py

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

import idaapi
import idautils
import ida_bytes
import ida_diskio
import idc
import operator
import yara
import os
import glob

VERSION = "0.2"
YARARULES_CFGFILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "findcrypt3.rules")

try:
    class Kp_Menu_Context(idaapi.action_handler_t):
        def __init__(self):
            idaapi.action_handler_t.__init__(self)

        @classmethod
        def get_name(self):
            return self.__name__

        @classmethod
        def get_label(self):
            return self.label

        @classmethod
        def register(self, plugin, label):
            self.plugin = plugin
            self.label = label
            instance = self()
            return idaapi.register_action(idaapi.action_desc_t(
                self.get_name(),  # Name. Acts as an ID. Must be unique.
                instance.get_label(),  # Label. That's what users see.
                instance  # Handler. Called when activated, and for updating
            ))

        @classmethod
        def unregister(self):
            """Unregister the action.
            After unregistering the class cannot be used.
            """
            idaapi.unregister_action(self.get_name())

        @classmethod
        def activate(self, ctx):
            # dummy method
            return 1

        @classmethod
        def update(self, ctx):
            if ctx.widget_type == idaapi.BWN_DISASM:
                return idaapi.AST_ENABLE_FOR_WIDGET
            return idaapi.AST_DISABLE_FOR_WIDGET

    class Searcher(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.search()
            return 1

except:
    pass


p_initialized = False


class YaraSearchResultChooser(idaapi.Choose):
    def __init__(self, title, items, flags=0, width=None, height=None, embedded=False, modal=False):
        idaapi.Choose.__init__(
            self,
            title,
            [
                ["Address", idaapi.Choose.CHCOL_HEX|10],
                ["Rules file", idaapi.Choose.CHCOL_PLAIN|12],
                ["Name", idaapi.Choose.CHCOL_PLAIN|25],
                ["String", idaapi.Choose.CHCOL_PLAIN|25],
                ["Value", idaapi.Choose.CHCOL_PLAIN|40],
            ],
            flags=flags,
            width=width,
            height=height,
            embedded=embedded)
        self.items = items
        self.selcount = 0
        self.n = len(items)

    def OnClose(self):
        return

    def OnSelectLine(self, n):
        self.selcount += 1
        idc.jumpto(self.items[n][0])

    def OnGetLine(self, n):
        res = self.items[n]
        res = [idc.atoa(res[0]), res[1], res[2], res[3], res[4]]
        return res

    def OnGetSize(self):
        n = len(self.items)
        return n

    def show(self):
        return self.Show() >= 0

#--------------------------------------------------------------------------
# Plugin
#--------------------------------------------------------------------------
class Findcrypt_Plugin_t(idaapi.plugin_t):
    comment = "Findcrypt plugin for IDA Pro (using yara framework)"
    help = "todo"
    wanted_name = "Findcrypt"
    wanted_hotkey = "Ctrl-Alt-F"
    flags = idaapi.PLUGIN_KEEP

    def init(self):
        global p_initialized

        # register popup menu handlers
        try:
            Searcher.register(self, "Findcrypt")
        except:
            pass

        if p_initialized is False:
            p_initialized = True
            self.user_directory = self.get_user_directory()
            idaapi.register_action(idaapi.action_desc_t(
                "Findcrypt",
                "Find crypto constants",
                Searcher(),
                None,
                None,
                0))
            idaapi.attach_action_to_menu("Search", "Findcrypt", idaapi.SETMENU_APP)
            print("=" * 80)
            print("Findcrypt v{0} by David BERARD, 2017".format(VERSION))
            print("Findcrypt search shortcut key is Ctrl-Alt-F")
            print("Global rules in %s" % YARARULES_CFGFILE)
            print("User-defined rules in %s/*.rules" % self.user_directory)
            print("=" * 80)

        return idaapi.PLUGIN_KEEP

    def term(self):
        pass


    def toVirtualAddress(self, offset, segments):
        va_offset = 0
        for seg in segments:
            if seg[1] <= offset < seg[2]:
                va_offset = seg[0] + (offset - seg[1])
        return va_offset


    def get_user_directory(self):
        user_dir = ida_diskio.get_user_idadir()
        plug_dir = os.path.join(user_dir, "plugins")
        res_dir = os.path.join(plug_dir, "findcrypt-yara")
        if not os.path.exists(res_dir):
            os.makedirs(res_dir, 0o755)
        return res_dir


    def get_rules_files(self):
        rules_filepaths = {"global":YARARULES_CFGFILE}
        for fpath in glob.glob(os.path.join(self.user_directory, "*.rules")):
            name = os.path.basename(fpath)
            rules_filepaths.update({name:fpath})
        return rules_filepaths


    def search(self):
        memory, offsets = self._get_memory()
        rules = yara.compile(filepaths=self.get_rules_files())
        values = self.yarasearch(memory, offsets, rules)
        c = YaraSearchResultChooser("Findcrypt results", values)
        r = c.show()

    def yarasearch(self, memory, offsets, rules):
        print(">>> start yara search")
        values = list()
        matches = rules.match(data=memory)
        for match in matches:
            for string in match.strings:
                name = match.rule
                if name.endswith("_API"):
                    try:
                        name = name + "_" + idc.GetString(self.toVirtualAddress(string[0], offsets))
                    except:
                        pass
                value = [
                    self.toVirtualAddress(string[0], offsets),
                    match.namespace,
                    name + "_" + hex(self.toVirtualAddress(string[0], offsets)).lstrip("0x").rstrip("L").upper(),
                    string[1],
                    repr(string[2]),
                ]
                idaapi.set_name(value[0], name
                             + "_"
                             + hex(self.toVirtualAddress(string[0], offsets)).lstrip("0x").rstrip("L").upper()
                             , 0)
                values.append(value)
        print("<<< end yara search")
        return values

    def _get_memory(self):
        result = bytearray()
        segment_starts = [ea for ea in idautils.Segments()]
        offsets = []
        start_len = 0
        for start in segment_starts:
            end = idc.get_segm_attr(start, idc.SEGATTR_END)
            result += ida_bytes.get_bytes(start, end - start)
            offsets.append((start, start_len, len(result)))
            start_len = len(result)
        return bytes(result), offsets

    def run(self, arg):
        self.search()


# register IDA plugin
def PLUGIN_ENTRY():
    return Findcrypt_Plugin_t()


repository: sean2077/big5-decode-ida
file: big5-decode.py
description: IDA Plugin for decoding bytes as big5.
comment: Big5 Decode
created_at: 2024-06-16 05:04:29+00:00
pushed_at: 2024-06-28 04:01:37+00:00
url:
https://github.com/sean2077/big5-decode-ida/blob/ba0fffd45092037d23c6ec52e2317097fd44732c/big5-decode.py

content:
############################################################################################
##
## IDA Pro Plugin: Big5 Decode
##
## Decode bytes as Big5 at the current address
##
## Available for IDA 7+ and Python 3.8+
##
## To install:
##      Copy script into plugins directory, i.e: C:\Program Files\<ida version>\plugins
##
## To use:
##      Right-click an address and select 'Big5 Decode',
##      the decoded string will be added as a repeatable comment.
##
############################################################################################

__AUTHOR__ = "@sean2077"

PLUGIN_NAME = "Big5 Decode"
PLUGIN_HOTKEY = ""
VERSION = "1.3.2"

ACTION_PREFIX = "sean2077"

import codecs

import ida_kernwin
import idaapi
import idc


def big5_decode_action():
    ea = idc.get_screen_ea()
    if ea == idaapi.BADADDR:
        idaapi.warning("Invalid address selected")
        return

    # Start reading bytes from the current address
    byte_list = []
    while True:
        byte_value = idc.get_wide_byte(ea)
        if byte_value == 0:
            break
        byte_list.append(byte_value)
        ea += 1

    # Convert byte list to byte array
    byte_array = bytearray(byte_list)

    # Decode byte array using Big5 encoding
    try:
        decoded_string = codecs.decode(byte_array, "big5")
    except Exception as e:
        idaapi.msg("Error decoding Big5: {}\n".format(e))
        return

    # Add a repeatable comment to the address
    idc.set_cmt(idc.get_screen_ea(), decoded_string, 1)
    idaapi.msg(f"Added comment: {decoded_string} at {idc.get_screen_ea()}\n")


def big5_batch_decode_action():
    start_ea = idc.read_selection_start()
    end_ea = idc.read_selection_end()

    if start_ea == end_ea:
        start_ea = idc.get_screen_ea()
        if start_ea == idaapi.BADADDR:
            idaapi.warning("Invalid start address selected")
            return
        end_ea = ida_kernwin.ask_addr(start_ea, "Enter the end address")
        if not end_ea:  # Cancelled
            return
        if end_ea == idaapi.BADADDR or end_ea <= start_ea:
            idaapi.warning("Invalid end address selected")
            return

    print(f"start_ea: {start_ea:x}, end_ea: {end_ea:x}")

    ea = start_ea
    byte_list = []
    while ea <= end_ea:
        byte_value = idc.get_wide_byte(ea)
        if byte_value == 0:
            if byte_list:
                # Convert byte list to byte array
                byte_array = bytearray(byte_list)
                # Decode byte array using Big5 encoding
                try:
                    decoded_string = codecs.decode(byte_array, "big5")
                    idc.set_cmt(ea - len(byte_list), decoded_string, 1)
                    idaapi.msg(f"Added comment: {decoded_string} at {ea - len(byte_list)}\n")
                except Exception as e:
                    idaapi.msg(f"Error decoding Big5 at {ea - len(byte_list)}: {e}\n")
                byte_list = []
        else:
            byte_list.append(byte_value)
        ea += 1

    if byte_list:
        # Handle the case where the last sequence does not end with a 0 byte
        byte_array = bytearray(byte_list)
        try:
            decoded_string = codecs.decode(byte_array, "big5")
            idc.set_cmt(ea - len(byte_list), decoded_string, 1)
            idaapi.msg(f"Added comment: {decoded_string} at {ea - len(byte_list)}\n")
        except Exception as e:
            idaapi.msg(f"Error decoding Big5 at {ea - len(byte_list)}: {e}\n")


def batch_delete_comments_action():
    start_ea = idc.read_selection_start()
    end_ea = idc.read_selection_end()

    if start_ea == end_ea:
        start_ea = idc.get_screen_ea()
        if start_ea == idaapi.BADADDR:
            idaapi.warning("Invalid start address selected")
            return
        end_ea = ida_kernwin.ask_addr(start_ea, "Enter the end address")
        if not end_ea:  # Cancelled
            return
        if end_ea == idaapi.BADADDR or end_ea <= start_ea:
            idaapi.warning("Invalid end address selected")
            return

    print(f"start_ea: {start_ea:x}, end_ea: {end_ea:x}")

    ea = start_ea
    while ea <= end_ea:
        idc.set_cmt(ea, "", 1)
        ea += 1


class Big5DecodePlugin(idaapi.plugin_t):
    flags = idaapi.PLUGIN_PROC | idaapi.PLUGIN_HIDE
    comment = "Big5 Decode"
    help = "Right-click an address and select 'Big5 Decode'"
    wanted_name = PLUGIN_NAME
    wanted_hotkey = PLUGIN_HOTKEY

    def init(self):
        self._init_action_big5_decode()
        self._init_action_big5_batch_decode()
        self._init_action_batch_delete_comment()
        self._init_hooks()
        idaapi.msg("%s %s initialized...\n" % (self.wanted_name, VERSION))
        return idaapi.PLUGIN_KEEP

    def run(self, arg):
        idaapi.msg("%s cannot be run as a script.\n" % self.wanted_name)

    def term(self):
        self._hooks.unhook()
        self._del_action_big5_decode()
        self._del_action_big5_batch_decode()
        self._del_action_batch_delete_comment()
        idaapi.msg("%s terminated...\n" % self.wanted_name)

    def _init_hooks(self):
        self._hooks = Hooks()
        self._hooks.hook()

    ACTION_BIG5_DECODE = f"{ACTION_PREFIX}:big5_decode"
    ACTION_BIG5_BATCH_DECODE = f"{ACTION_PREFIX}:big5_batch_decode"
    ACTION_BATCH_DELETE_COMMENT = f"{ACTION_PREFIX}:batch_delete_comment"

    def _init_action_big5_decode(self):
        action_desc = idaapi.action_desc_t(
            self.ACTION_BIG5_DECODE,
            "Big5 decode",
            IDACtxEntry(big5_decode_action),
            PLUGIN_HOTKEY,
            "Decode bytes as Big5 at the current address",
            0,
        )
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_big5_batch_decode(self):
        action_desc = idaapi.action_desc_t(
            self.ACTION_BIG5_BATCH_DECODE,
            "Big5 batch decode",
            IDACtxEntry(big5_batch_decode_action),
            "",  # No hotkey
            "Batch decode bytes as Big5 between the selected addresses",
            0,
        )
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _init_action_batch_delete_comment(self):
        action_desc = idaapi.action_desc_t(
            self.ACTION_BATCH_DELETE_COMMENT,
            "Batch delete comments",
            IDACtxEntry(batch_delete_comments_action),
            "",  # No hotkey
            "Batch delete comments between the selected addresses",
            0,
        )
        assert idaapi.register_action(action_desc), "Action registration failed"

    def _del_action_big5_decode(self):
        idaapi.unregister_action(self.ACTION_BIG5_DECODE)

    def _del_action_big5_batch_decode(self):
        idaapi.unregister_action(self.ACTION_BIG5_BATCH_DECODE)

    def _del_action_batch_delete_comment(self):
        idaapi.unregister_action(self.ACTION_BATCH_DELETE_COMMENT)


class Hooks(idaapi.UI_Hooks):
    def finish_populating_widget_popup(self, widget, popup):
        inject_big5_decode_actions(widget, popup, idaapi.get_widget_type(widget))
        return 0


def inject_big5_decode_actions(form, popup, form_type):
    if form_type == idaapi.BWN_DISASM:
        idaapi.attach_action_to_popup(form, popup, Big5DecodePlugin.ACTION_BIG5_DECODE, "Big5 decode", idaapi.SETMENU_APP)
        idaapi.attach_action_to_popup(
            form, popup, Big5DecodePlugin.ACTION_BIG5_BATCH_DECODE, "Big5 batch decode", idaapi.SETMENU_APP
        )
        idaapi.attach_action_to_popup(
            form, popup, Big5DecodePlugin.ACTION_BATCH_DELETE_COMMENT, "Batch delete comments", idaapi.SETMENU_APP
        )
    return 0


class IDACtxEntry(idaapi.action_handler_t):
    def __init__(self, action_function):
        idaapi.action_handler_t.__init__(self)
        self.action_function = action_function

    def activate(self, ctx):
        self.action_function()
        return 1

    def update(self, ctx):
        return idaapi.AST_ENABLE_ALWAYS


def PLUGIN_ENTRY():
    return Big5DecodePlugin()


repository: zh-explorer/ida_script
file: firmware_fix.py
description: some ida script
wanted_name: FirmwareFix
comment: FirmwareFix
created_at: 2021-08-18 09:17:51+00:00
pushed_at: 2021-08-18 10:08:46+00:00
url:
https://github.com/zh-explorer/ida_script/blob/c2821754520af4b033c9def4aa41da6b8161423a/firmware_fix.py

content:
import ida_ida
import ida_kernwin
import ida_search
import ida_funcs
import idautils
import ida_bytes
import ida_offset
import ida_segment
import ida_idaapi

import functools
import typing


class InfoForm(ida_kernwin.Form):
    def __init__(self):
        self.first = True
        F = ida_kernwin.Form
        F.__init__(
            self,
            r"""Segment Info

{FormChangeCb}
<Fix function: {rFunc}>{ChkFunc}>
<## Start of code        :{iStartCode}>
<## End of code          :{iEndCode}>

<Fix string: {rString}>{ChkStr}>
<## Start of string      :{iStartStr}>
<## End of string        :{iEndStr}>

<Fix data reg: {rData}>{ChkData}>
<## Start of data point  :{iStartP}>
<## End of data point    :{iEndP}>
            """, {
                "ChkFunc": F.ChkGroupControl(("rFunc",)),
                "ChkStr": F.ChkGroupControl(("rString",)),
                "ChkData": F.ChkGroupControl(("rData",)),
                "iStartCode": F.NumericInput(tp=F.FT_ADDR),
                "iEndCode": F.NumericInput(tp=F.FT_ADDR),
                "iStartStr": F.NumericInput(tp=F.FT_ADDR),
                "iEndStr": F.NumericInput(tp=F.FT_ADDR),
                "iStartP": F.NumericInput(tp=F.FT_ADDR),
                "iEndP": F.NumericInput(tp=F.FT_ADDR),
                "FormChangeCb": F.FormChangeCb(self.OnFormChange)
            }
        )

    def OnFormChange(self, fid):
        if self.first:
            input_list = [self.iStartCode, self.iEndCode, self.iStartStr, self.iEndStr, self.iStartP, self.iEndP]
            for ctrl in input_list:
                self.EnableField(ctrl, 0)
            self.first = False

        notify_ctr = (self.rFunc, self.rString, self.rData)
        notify_map = dict(map(lambda x: (x.id, x), notify_ctr))

        control_map = {
            self.rFunc: (self.iStartCode, self.iEndCode),
            self.rString: (self.iStartStr, self.iEndStr),
            self.rData: (self.iStartP, self.iEndP),
        }

        if fid in notify_map:
            ctrl = notify_map[fid]
            for i in control_map[ctrl]:
                self.EnableField(i, self.GetControlValue(ctrl))
        return 1

    @staticmethod
    def show_from() -> typing.Dict[str, typing.Tuple]:
        f = InfoForm()
        f.Compile()

        value_map = {
            "func": {"ctrl": f.rFunc, "start": f.iStartCode, "end": f.iEndCode},
            "str": {"ctrl": f.rString, "start": f.iStartStr, "end": f.iEndStr},
            "data": {"ctrl": f.rData, "start": f.iStartP, "end": f.iEndP},
        }

        for key, value in value_map.items():
            value["start"].value = ida_ida.inf_get_min_ea()
            value["end"].value = ida_ida.inf_get_max_ea()

        ok = f.Execute()
        if ok == 1:
            res = {}
            for key, value in value_map.items():
                if value["ctrl"].checked:
                    res[key] = (value["start"].value, value["end"].value)
            return res
        else:
            return {}


class Context(object):
    accept_process = ("ARM", "MIPS", "metapc")

    def __init__(self):
        if ida_ida.idainfo_is_64bit():
            self.bits = 64
        elif ida_ida.idainfo_is_32bit():
            self.bits = 32
        else:
            self.bits = 16

        self.is_be = ida_ida.idainfo_is_be()
        self.proc_name = ida_ida.inf_get_procname()
        if self.proc_name not in self.accept_process:
            print(f"The process {self.proc_name} not support, the result maybe not right")


def search_function(start: int, end: int):
    ea = start
    while ea < end:
        ea1 = ida_search.find_unknown(ea, ida_search.SEARCH_DOWN | ida_search.SEARCH_NEXT)
        ea2 = ida_search.find_not_func(ea, ida_search.SEARCH_DOWN | ida_search.SEARCH_NEXT)
        ea = min(ea1, ea2)
        ida_funcs.add_func(ea)


def search_string(start: int, end: int):
    for s in filter(lambda x: start < x.ea < end, idautils.Strings()):
        ida_bytes.create_strlit(s.ea, s.length, 0)

    # for str in idautils.Strings():
    #     if start < str.ea < end:
    #         ida_bytes.create_strlit(str.ea, str.length, 0)


def search_data(start: int, end: int):
    process_bytes = context.bits // 8

    find_next_data = lambda x: ida_search.find_data(x, ida_search.SEARCH_DOWN | ida_search.SEARCH_NEXT)
    find_next_unknown = lambda x: ida_search.find_unknown(x, ida_search.SEARCH_DOWN | ida_search.SEARCH_NEXT)
    check_data_size = lambda x: ida_bytes.get_item_size(x) == process_bytes
    check_data_align = lambda x: x % process_bytes == 0
    is_unknown = lambda x: ida_bytes.is_unknown(ida_bytes.get_flags(x))
    all_unknown = lambda x: all(map(lambda i: is_unknown(x + i), range(process_bytes)))
    get_data = (lambda x: ida_bytes.get_wide_dword(x)) if process_bytes == 4 else (
        lambda x: ida_bytes.get_qword(x))
    in_mem_range = lambda x: ida_segment.getseg(get_data(x)) is not None

    def ea_iter(find_next):
        ea = start
        while ea < end:
            ea = find_next(ea)
            yield ea

    f = ea_iter(find_next_data)
    f = filter(check_data_size, f)
    f = filter(in_mem_range, f)
    for ea in f:
        ida_offset.op_plain_offset(ea, 0, 0)

    f = ea_iter(find_next_unknown)
    f = filter(check_data_align, f)
    f = filter(all_unknown, f)
    f = filter(in_mem_range, f)
    for ea in f:
        ida_offset.op_plain_offset(ea, 0, 0)


def main_process():
    result = InfoForm.show_from()
    if "func" in result:
        code_start, code_end = result["func"]
        search_function(code_start, code_end)

    if "str" in result:
        str_start, str_end = result["str"]
        search_string(str_start, str_end)

    if "data" in result:
        data_start, data_end = result["data"]
        search_data(data_start, data_end)


class DoFix(ida_kernwin.action_handler_t):
    def __init__(self):
        ida_kernwin.action_handler_t.__init__(self)

    def activate(self, ctx):
        main_process()
        return 1

    def update(self, ctx):
        return ida_kernwin.AST_ENABLE_ALWAYS


context = None


class FirmwareFix_t(ida_idaapi.plugin_t):
    flags = ida_idaapi.PLUGIN_KEEP
    comment = "FirmwareFix"
    help = ""
    wanted_name = "FirmwareFix"
    wanted_hotkey = ""

    def init(self):
        global context
        context = Context()

        self.act_name = "firmware:Fixed"
        if ida_kernwin.register_action(ida_kernwin.action_desc_t(
                self.act_name,
                "fix firmware",
                DoFix()
        )):
            print("add firmware fix plugins")
            ida_kernwin.attach_action_to_menu("Edit/Plugins/", self.act_name, ida_kernwin.SETMENU_APP)
        return ida_idaapi.PLUGIN_KEEP

    def run(self, arg):
        main_process()

    def term(self):
        ida_kernwin.unregister_action(self.act_name)


def PLUGIN_ENTRY():
    return FirmwareFix_t()

# print("big" if context.is_be else "little")
# print(f"bits {context.bits}")
# print(f"process name {context.proc_name}")


repository: rmmenosfbarra/arsenal
file: Reversing&Exploiting/IDA/Plugins/Keypatch/keypatch.py
wanted_name: Keypatch Patcher
comment: Keypatch plugin for IDA Pro (using Keystone framework)
created_at: 2017-02-27 17:52:25+00:00
pushed_at: 2019-06-30 11:14:50+00:00
url:
https://github.com/rmmenosfbarra/arsenal/blob/67060284c34e411646beacb0b304338a1eabc18b/Reversing&Exploiting/IDA/Plugins/Keypatch/keypatch.py

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

# Keypatch IDA Plugin, powered by Keystone Engine (http://www.keystone-engine.org).
# By Nguyen Anh Quynh & Thanh Nguyen, 2016.

# Keypatch is released under the GPL v2. See COPYING for more information.
# Find docs & latest version at http://keystone-engine.org/keypatch

# This IDA plugin includes 3 tools inside: Patcher, Fill Range & Search.
# Access to these tools via menu "Edit | Keypatch", or via right-click popup menu "Keypatch".

# Hotkey Ctrl-Alt-K opens either Patcher or "Fill Range" window, depending on context.
#  - If there is no code selection, hotkey opens Patcher dialog
#  - If a range of code is selected, hotkey opens "Fill Range" dialog

# To revert (undo) the last patching, choose menu "Edit | Keypatch | Undo last patching".
# To check for update version, choose menu "Edit | Keypatch | Check for update".

import idc
import idaapi
import re
import json
from keystone import *


# bleeding-edge version
# on a new release, this should be sync with VERSION_STABLE file
VERSION = "2.2"


MAX_INSTRUCTION_STRLEN = 64
MAX_ENCODING_LEN = 40
MAX_ADDRESS_LEN = 40
ENCODING_ERR_OUTPUT = "..."
KP_GITHUB_VERSION = "https://raw.githubusercontent.com/keystone-engine/keypatch/master/VERSION_STABLE"
KP_HOMEPAGE = "http://keystone-engine.org/keypatch"

X86_NOP = "\x90"

# Configuration file
KP_CFGFILE = os.path.join(idaapi.get_user_idadir(), "keypatch.cfg")

# save all the info on patching
patch_info = []


def to_hexstr(buf, sep=' '):
    return sep.join("{0:02x}".format(ord(c)) for c in buf).upper()

# return a normalized code, or None if input is invalid
def convert_hexstr(code):
    # normalize code
    code = code.lower()
    code = code.replace(' ', '')    # remove space
    code = code.replace('h', '')    # remove trailing 'h' in 90h
    code = code.replace('0x', '')   # remove 0x
    code = code.replace('\\x', '')  # remove \x
    code = code.replace(',', '')    # remove ,
    code = code.replace(';', '')    # remove ;
    code = code.replace('"', '')    # remove "
    code = code.replace("'", '')    # remove '
    code = code.replace("+", '')    # remove +

    # single-digit hexcode?
    if len(code) == 1 and ((code >= '0' and code <= '9') or (code >= 'a' and code <= 'f')):
        # stick 0 in front (so 'a' --> '0a')
        code = '0' + code

    # odd-length is invalid
    if len(code) % 2 != 0:
        return None

    try:
        hex_data = code.decode('hex')
        # we want a list of int
        return [ord(i) for i in hex_data]
    except:
        # invalid hex
        return None

# download a file from @url, then return (result, file-content)
# return (0, content) on success, or ({1|2}, None) on download failure
def url_download(url):
    from urllib2 import Request, urlopen, URLError, HTTPError

    # create the url and the request
    req = Request(url)

    # Open the url
    try:
        # download this URL
        f = urlopen(req)
        content = f.read()
        return (0, content)

    # handle errors
    except HTTPError, e:
        # print "HTTP Error:", e.code , url
        # fail to download this file
        return (1, None)
    except URLError, e:
        # print "URL Error:", e.reason , url
        # fail to download this file
        return (1, None)
    except Exception as e:
        # fail to save the downloaded file
        # print("Error:", e)
        return (2, None)


## Main Keypatch class
class Keypatch_Asm:
    # supported architectures
    arch_lists = {
        "X86 16-bit": (KS_ARCH_X86, KS_MODE_16),                # X86 16-bit
        "X86 32-bit": (KS_ARCH_X86, KS_MODE_32),                # X86 32-bit
        "X86 64-bit": (KS_ARCH_X86, KS_MODE_64),                # X86 64-bit
        "ARM": (KS_ARCH_ARM, KS_MODE_ARM),                      # ARM
        "ARM Thumb": (KS_ARCH_ARM, KS_MODE_THUMB),              # ARM Thumb
        "ARM64 (ARMV8)": (KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN),# ARM64
        "Hexagon": (KS_ARCH_HEXAGON, KS_MODE_BIG_ENDIAN),       # Hexagon
        "Mips32": (KS_ARCH_MIPS, KS_MODE_MIPS32),               # Mips32
        "Mips64": (KS_ARCH_MIPS, KS_MODE_MIPS64),               # Mips64
        "PowerPC 32": (KS_ARCH_PPC, KS_MODE_PPC32),             # PPC32
        "PowerPC 64": (KS_ARCH_PPC, KS_MODE_PPC64),             # PPC64
        "Sparc 32": (KS_ARCH_SPARC, KS_MODE_SPARC32),           # Sparc32
        "Sparc 64": (KS_ARCH_SPARC, KS_MODE_SPARC64),           # Sparc64
        "SystemZ": (KS_ARCH_SYSTEMZ, KS_MODE_BIG_ENDIAN),       # SystemZ
    }

    endian_lists = {
        "Little Endian": KS_MODE_LITTLE_ENDIAN,                 # little endian
        "Big Endian": KS_MODE_BIG_ENDIAN,                       # big endian
    }

    syntax_lists = {
        "Intel": KS_OPT_SYNTAX_INTEL,
        "Nasm": KS_OPT_SYNTAX_NASM,
        "AT&T": KS_OPT_SYNTAX_ATT
    }

    def __init__(self, arch=None, mode=None):
        # update current arch and mode
        self.update_hardware_mode()

        # override arch & mode if provided
        if arch is not None:
            self.arch = arch
        if mode is not None:
            self.mode = mode

        # IDA uses Intel syntax by default
        self.syntax = KS_OPT_SYNTAX_INTEL

    # return Keystone arch & mode (with endianess included)
    @staticmethod
    def get_hardware_mode():
        (arch, mode) = (None, None)

        # heuristically detect hardware setup
        info = idaapi.get_inf_structure()
        if idaapi.IDA_SDK_VERSION >= 700:
            # IDA >= 7.0 case change
            cpuname = info.procname.lower()
        else:
            cpuname = info.procName.lower()
        
        try:
            # since IDA7 beta 3 (170724) renamed inf.mf -> is_be()/set_be()
            is_be = idaapi.cvar.inf.is_be()
        except:
            # older IDA versions
            is_be = idaapi.cvar.inf.mf
        # print("Keypatch BIG_ENDIAN = %s" %is_be)
        
        if cpuname == "metapc":
            arch = KS_ARCH_X86
            if info.is_64bit():
                mode = KS_MODE_64
            elif info.is_32bit():
                mode = KS_MODE_32
            else:
                mode = KS_MODE_16
        elif cpuname.startswith("arm"):
            # ARM or ARM64
            if info.is_64bit():
                arch = KS_ARCH_ARM64
                if is_be:
                    mode = KS_MODE_BIG_ENDIAN
                else:
                    mode = KS_MODE_LITTLE_ENDIAN
            else:
                arch = KS_ARCH_ARM
                # either big-endian or little-endian
                if is_be:
                    mode = KS_MODE_ARM | KS_MODE_BIG_ENDIAN
                else:
                    mode = KS_MODE_ARM | KS_MODE_LITTLE_ENDIAN
        elif cpuname.startswith("sparc"):
            arch = KS_ARCH_SPARC
            if info.is_64bit():
                mode = KS_MODE_SPARC64
            else:
                mode = KS_MODE_SPARC32
            if is_be:
                mode |= KS_MODE_BIG_ENDIAN
            else:
                mode |= KS_MODE_LITTLE_ENDIAN
        elif cpuname.startswith("ppc"):
            arch = KS_ARCH_PPC
            if info.is_64bit():
                mode = KS_MODE_PPC64
            else:
                mode = KS_MODE_PPC32
            if cpuname == "ppc":
                # do not support Little Endian mode for PPC
                mode += KS_MODE_BIG_ENDIAN
        elif cpuname.startswith("mips"):
            arch = KS_ARCH_MIPS
            if info.is_64bit():
                mode = KS_MODE_MIPS64
            else:
                mode = KS_MODE_MIPS32
            if is_be:
                mode |= KS_MODE_BIG_ENDIAN
            else:
                mode |= KS_MODE_LITTLE_ENDIAN
        elif cpuname.startswith("systemz") or cpuname.startswith("s390x"):
            arch = KS_ARCH_SYSTEMZ
            mode = KS_MODE_BIG_ENDIAN

        return (arch, mode)

    def update_hardware_mode(self):
        (self.arch, self.mode) = self.get_hardware_mode()

    # normalize assembly code
    # remove comment at the end of assembly code
    @staticmethod
    def asm_normalize(text):
        text = ' '.join(text.split())
        if text.rfind(';') != -1:
            return text[:text.rfind(';')].strip()

        return text.strip()

    @staticmethod
    # check if input address is valid
    # return
    #       -1  invalid address at target binary
    #        0  type mismatch of input address
    #        1  valid address at target binary
    def check_address(address):
        try:
            if idaapi.isEnabled(address):
                return 1
            else:
                return -1
        except:
            # invalid type
            return 0

    ### resolve IDA names from input asm code
    # todo: a better syntax parser for all archs
    def ida_resolve(self, assembly, address=idc.BADADDR):
        def _resolve(_op, ignore_kw=True):
            names = re.findall(r"\b[a-z0-9_:\.]+\b", _op, re.I)

            # try to resolve all names
            for name in names:
                # ignore known keywords
                if ignore_kw and name in ('byte', 'near', 'short', 'word', 'dword', 'ptr', 'offset'):
                    continue

                sym = name

                # split segment reg
                parts = name.partition(':')
                if parts[2] != '':
                    sym = parts[2]

                (t, v) = idaapi.get_name_value(address, sym)

                # skip if name doesn't exist or segment / segment registers
                if t in (idaapi.NT_SEG, idaapi.NT_NONE):
                    continue

                _op = _op.replace(sym, '0x{0:X}'.format(v))

            return _op

        if self.check_address(address) == 0:
            print("Keypatch: WARNING: invalid input address {0}".format(address))
            return assembly

        # for now, we only support IDA name resolve for X86, ARM, ARM64, MIPS, PPC, SPARC
        if not (self.arch in (KS_ARCH_X86, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_PPC, KS_ARCH_SPARC)):
            return assembly

        _asm = assembly.partition(' ')
        mnem = _asm[0]
        opers = _asm[2].split(',')

        for idx, op in enumerate(opers):
            _op = list(op.partition('['))
            ignore_kw = True
            if _op[1] == '':
                _op[2] = _op[0]
                _op[0] = ''
            else:
                _op[0] = _resolve(_op[0], ignore_kw=True)
                ignore_kw = False

            _op[2] = _resolve(_op[2], ignore_kw=ignore_kw)

            opers[idx] = ''.join(_op)

        asm = "{0} {1}".format(mnem, ','.join(opers))
        return asm

    # return bytes of instruction or data
    # return None on failure
    def ida_get_item(self, address, hex_output=False):
        if self.check_address(address) != 1:
            # not a valid address
            return (None, 0)

        # return None if address is in the middle of instruction / data
        if address != idc.ItemHead(address):
            return (None, 0)

        len = idc.ItemSize(address)
        item = idaapi.get_many_bytes(address, len)

        if item is None:
            return (None, 0)

        if hex_output:
            item = to_hexstr(item)

        return (item, len)

    @staticmethod
    def get_op_dtype_name(op_idx):
        dtyp_lists = {
            idaapi.dt_byte: 'byte',     #  8 bit
            idaapi.dt_word: 'word',     #  16 bit
            idaapi.dt_dword: 'dword',   #  32 bit
            idaapi.dt_float: 'dword',   #  4 byte
            idaapi.dt_double: 'dword',  #  8 byte
            #idaapi.dt_tbyte = 5        #  variable size (ph.tbyte_size)
            #idaapi.dt_packreal = 6         #  packed real format for mc68040
            idaapi.dt_qword: 'qword',   #  64 bit
            idaapi.dt_byte16: 'xmmword',#  128 bit
            #idaapi.dt_code = 9         #  ptr to code (not used?)
            #idaapi.dt_void = 10        #  none
            #idaapi.dt_fword = 11       #  48 bit
            #idaapi.dt_bitfild = 12     #  bit field (mc680x0)
            #idaapi.dt_string = 13      #  pointer to asciiz string
            #idaapi.dt_unicode = 14     #  pointer to unicode string
            #idaapi.dt_3byte = 15       #  3-byte data
            #idaapi.dt_ldbl = 16        #  long double (which may be different from tbyte)
            idaapi.dt_byte32: 'ymmword',# 256 bit
        }

        dtype = idaapi.cmd.Operands[op_idx].dtyp
        dtyp_size = idaapi.get_dtyp_size(dtype)
        if dtype == idaapi.dt_tbyte:
            if dtyp_size == 10:
                return 'xword'

        dtyp_name = dtyp_lists.get(idaapi.cmd.Operands[op_idx].dtyp, None)

        return dtyp_name

    # return asm instructions from start to end
    def ida_get_disasm_range(self, start, end):
        codes = []
        while start < end:
            asm = self.asm_normalize(idc.GetDisasm(start))
            if asm == None:
                asm = ''
            codes.append(asm)
            start = start + idc.ItemSize(start)

        return codes

    # get disasm from IDA
    # return '' on invalid address
    def ida_get_disasm(self, address, fixup=False):

        def GetMnem(asm):
            sp = asm.find(' ')
            if (sp == -1):
                return asm
            return asm[:sp]

        if self.check_address(address) != 1:
            # not a valid address
            return ''

        # return if address is in the middle of instruction / data
        if address != idc.ItemHead(address):
            return ''

        asm = self.asm_normalize(idc.GetDisasm(address))
        # for now, only support IDA syntax fixup for Intel CPU
        if not fixup or self.arch != KS_ARCH_X86:
            return asm

        # KS_ARCH_X86 mode
        # rebuild disasm code from IDA
        i = 0
        mnem = GetMnem(asm)
        if mnem == '' or mnem in ('rep', 'repne', 'repe'):
            return asm

        opers = []
        while GetOpType(address, i) > 0 and i < 6:
            t = GetOpType(address, i)
            o = GetOpnd(address, i)

            if t in (idc.o_mem, o_displ):
                parts = list(o.partition(':'))
                if parts[2] == '':
                    parts[2] = parts[0]
                    parts[0] = ''

                if '[' not in parts[2]:
                    parts[2] = '[{0}]'.format(parts[2])

                o = ''.join(parts)

                if 'ptr ' not in o:
                    dtyp_name = self.get_op_dtype_name(i)
                    if dtyp_name != None:
                        o = "{0} ptr {1}".format(dtyp_name, o)

            opers.append(o)
            i += 1

        asm = mnem
        for o in opers:
            if o != '':
                asm = "{0} {1},".format(asm, o)

        asm = asm.strip(',')
        return asm

    # assemble code with Keystone
    # return (encoding, count), or (None, 0) on failure
    def assemble(self, assembly, address, arch=None, mode=None, syntax=None):

        # return assembly with arithmetic equation evaluated
        def eval_operand(assembly, start, stop, prefix=''):
            imm = assembly[start+1:stop]
            try:
                eval_imm = eval(imm)
                if eval_imm > 0x80000000:
                    eval_imm = 0xffffffff - eval_imm
                    eval_imm += 1
                    eval_imm = -eval_imm
                return assembly.replace(prefix + imm, prefix + hex(eval_imm))
            except:
                return assembly

        # IDA uses different syntax from Keystone
        # sometimes, we can convert code to be consumable by Keystone
        def fix_ida_syntax(assembly):

            # return True if this insn needs to be fixed
            def check_arm_arm64_insn(arch, mnem):
                if arch == KS_ARCH_ARM:
                    if mnem.startswith("ldr") or mnem.startswith("str"):
                        return True
                    return False
                elif arch == KS_ARCH_ARM64:
                    if mnem.startswith("ldr") or mnem.startswith("str"):
                        return True
                    return mnem in ("stp")
                return False

            # return True if this insn needs to be fixed
            def check_ppc_insn(mnem):
                return mnem in ("stw")

            # replace the right most string occurred
            def rreplace(s, old, new):
                li = s.rsplit(old, 1)
                return new.join(li)

            # convert some ARM pre-UAL assembly to UAL, so Keystone can handle it
            # example: streqb --> strbeq
            def fix_arm_ual(mnem, assembly):
                # TODO: this is not an exhaustive list yet
                if len(mnem) != 6:
                    return assembly

                if (mnem[-1] in ('s', 'b', 'h', 'd')):
                    #print(">> 222", mnem[3:5])
                    if mnem[3:5] in ("cc", "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al"):
                        return assembly.replace(mnem, mnem[:3] + mnem[-1] + mnem[3:5], 1)

                return assembly

            if self.arch != KS_ARCH_X86:
                assembly = assembly.lower()
            else:
                # Keystone does not support immediate 0bh, but only 0Bh
                assembly = assembly.upper()

            # however, 0X must be converted to 0x
            # Keystone should fix this limitation in the future
            assembly = assembly.replace("0X", " 0x")

            _asm = assembly.partition(' ')
            mnem = _asm[0]
            if mnem == '':
                return assembly

            # for PPC, Keystone does not accept registers with 'r' prefix,
            # but only the number behind. lets try to fix that here by
            # removing the prefix 'r'.
            if self.arch == KS_ARCH_PPC:
                for n in range(32):
                    r = " r%u," %n
                    if r in assembly:
                        assembly = assembly.replace(r, " %u," %n)
                for n in range(32):
                    r = "(r%u)" %n
                    if r in assembly:
                        assembly = assembly.replace(r, "(%u)" %n)
                for n in range(32):
                    r = ", r%u" %n
                    if assembly.endswith(r):
                        assembly = rreplace(assembly, r, ", %u" %n)

            if self.arch == KS_ARCH_X86:
                if mnem == "RETN":
                    # replace retn with ret
                    return assembly.replace('RETN', 'RET', 1)
                if 'OFFSET ' in assembly:
                    return assembly.replace('OFFSET ', ' ')
                if mnem in ('CALL', 'JMP') or mnem.startswith('LOOP'):
                    # remove 'NEAR PTR'
                    if ' NEAR PTR ' in assembly:
                        return assembly.replace(' NEAR PTR ', ' ')
                elif mnem[0] == 'J':
                    # JMP instruction
                    if ' SHORT ' in assembly:
                        # remove ' short '
                        return assembly.replace(' SHORT ', ' ')
            elif self.arch in (KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_PPC):
                # *** ARM
                # LDR     R1, [SP+rtld_fini],#4
                # STR     R2, [SP,#-4+rtld_fini]!
                # STR     R0, [SP,#fini]!
                # STR     R12, [SP,#4+var_8]!

                # *** ARM64
                # STP     X29, X30, [SP,#-0x10+var_150]!
                # STR     W0, [X29,#0x150+var_8]
                # LDR     X0, [X0,#(qword_4D6678 - 0x4D6660)]
                # TODO:
                # ADRP    X19, #interactive@PAGE

                # *** PPC
                # stw     r5, 0x120+var_108(r1)

                if self.arch == KS_ARCH_ARM:
                    #print(">> before UAL fix: ", assembly)
                    assembly = fix_arm_ual(mnem, assembly)
                    #print(">> after UAL fix: ", assembly)

                if check_arm_arm64_insn(self.arch, mnem) or (("[" in assembly) and ("]" in assembly)):
                    bang = assembly.find('#')
                    bracket = assembly.find(']')
                    if bang != -1 and bracket != -1 and bang < bracket:
                        return eval_operand(assembly, bang, bracket, '#')
                    elif '+0x0]' in assembly:
                        return assembly.replace('+0x0]', ']')
                elif check_ppc_insn(mnem):
                    start = assembly.find(', ')
                    stop = assembly.find('(')
                    if start != -1 and stop != -1 and start < stop:
                        return eval_operand(assembly, start, stop)
            return assembly

        def is_thumb(address):
            return idc.GetReg(address, 'T') == 1

        if self.check_address(address) == 0:
            return (None, 0)

        # use default syntax, arch and mode if not provided
        if syntax is None:
            syntax = self.syntax
        if arch is None:
            arch = self.arch
        if mode is None:
            mode = self.mode

        if arch == KS_ARCH_ARM and is_thumb(address):
            mode = KS_MODE_THUMB

        try:
            ks = Ks(arch, mode)
            if arch == KS_ARCH_X86:
                ks.syntax = syntax
            encoding, count = ks.asm(fix_ida_syntax(assembly), address)
        except KsError as e:
            # keep the below code for debugging
            #print("Keypatch Error: {0}".format(e))
            #print("Original asm: {0}".format(assembly))
            #print("Fixed up asm: {0}".format(fix_ida_syntax(assembly)))
            encoding, count = None, 0

        return (encoding, count)


    # patch at address, return the number of written bytes & original data
    # this process can fail in some cases
    @staticmethod
    def patch_raw(address, patch_data, len):
        ea = address
        orig_data = ''

        while ea < (address + len):

            if not idc.hasValue(idc.GetFlags(ea)):
                print("Keypatch: FAILED to read data at 0x{0:X}".format(ea))
                break

            orig_byte = idc.Byte(ea)
            orig_data += chr(orig_byte)
            patch_byte = ord(patch_data[ea - address])

            if patch_byte != orig_byte:
                # patch one byte
                if idaapi.patch_byte(ea, patch_byte) != 1:
                    print("Keypatch: FAILED to patch byte at 0x{0:X} [0x{1:X}]".format(ea, patch_byte))
                    break
            ea += 1
        return (ea - address, orig_data)

    # patch at address, return the number of written bytes & original data
    # on patch failure, we revert to the original code, then return (None, None)
    def patch(self, address, patch_data, len):
        # save original function end to fix IDA re-analyze issue after patching
        orig_func_end = idc.GetFunctionAttr(address, idc.FUNCATTR_END)

        (patched_len, orig_data) = self.patch_raw(address, patch_data, len)

        if len != patched_len:
            # patch failure
            if patched_len > 0:
                # revert the changes
                (rlen, _) = self.patch_raw(address, orig_data, patched_len)
                if rlen == patched_len:
                    print("Keypatch: successfully reverted changes of {0:d} byte(s) at 0x{1:X} [{2}]".format(
                                        patched_len, address, to_hexstr(orig_data)))
                else:
                    print("Keypatch: FAILED to revert changes of {0:d} byte(s) at 0x{1:X} [{2}]".format(
                                        patched_len, address, to_hexstr(orig_data)))

            return (None, None)

        # ask IDA to re-analyze the patched area
        if orig_func_end == idc.BADADDR:
            # only analyze patched bytes, otherwise it would take a lot of time to re-analyze the whole binary
            idaapi.analyze_area(address, address + patched_len + 1)
        else:
            idaapi.analyze_area(address, orig_func_end)

            # try to fix IDA function re-analyze issue after patching
            idaapi.func_setend(address, orig_func_end)

        return (patched_len, orig_data)

    # return number of bytes patched
    # return
    #    0  Invalid assembly
    #   -1  PatchByte failure
    #   -2  Can't read original data
    #   -3  Invalid address
    def patch_code(self, address, assembly, syntax, padding, save_origcode, orig_asm=None, patch_data=None, patch_comment=None, undo=False):
        global patch_info

        if self.check_address(address) != 1:
            # not a valid address
            return -3

        orig_comment = idc.Comment(address)
        if orig_comment == None:
            orig_comment = ''

        nop_comment = ""
        padding_len = 0
        if not undo:
            # we are patching via Patcher
            (orig_encoding, orig_len) = self.ida_get_item(address)
            if (orig_encoding, orig_len) == (None, 0):
                return -2

            (encoding, count) = self.assemble(assembly, address, syntax=syntax)
            if encoding is None:
                return 0

            patch_len = len(encoding)
            patch_data = ''.join(chr(c) for c in encoding)

            if patch_data == orig_encoding:
                #print("Keypatch: no need to patch, same encoding data [{0}] at 0x{1:X}".format(to_hexstr(orig_encoding), address))
                return orig_len

            # for now, only support NOP padding on Intel CPU
            if padding and self.arch == KS_ARCH_X86:
                if patch_len < orig_len:
                    padding_len = orig_len - patch_len
                    patch_len = orig_len
                    patch_data = patch_data.ljust(patch_len, X86_NOP)
                elif patch_len > orig_len:
                    patch_end = address + patch_len - 1
                    ins_end = ItemEnd(patch_end)
                    padding_len = ins_end - patch_end - 1

                    if padding_len > 0:
                        patch_len = ins_end - address
                        patch_data = patch_data.ljust(patch_len, X86_NOP)

                if padding_len > 0:
                    nop_comment = "\nKeypatch padded NOP to next boundary: {0} bytes".format(padding_len)

            orig_asm = self.ida_get_disasm_range(address, address + patch_len)
        else:
            # we are reverting the change via "Undo" menu
            patch_len = len(patch_data)

        (plen, p_orig_data) = self.patch(address, patch_data, patch_len)
        if plen == None:
            # failed to patch
            return -1

        if not undo: # we are patching
            new_patch_comment = None
            if save_origcode == True:
                # append original instruction to comments
                if orig_comment == '':
                    new_patch_comment = "Keypatch modified this from:\n  {0}{1}".format('\n  '.join(orig_asm), nop_comment)
                else:
                    new_patch_comment = "\nKeypatch modified this from:\n  {0}{1}".format('\n  '.join(orig_asm), nop_comment)

                new_comment = "{0}{1}".format(orig_comment, new_patch_comment)
                idc.MakeComm(address, new_comment)

            if padding_len == 0:
                print("Keypatch: successfully patched {0:d} byte(s) at 0x{1:X} from [{2}] to [{3}]".format(plen,
                                        address, to_hexstr(p_orig_data), to_hexstr(patch_data)))
            else:
                print("Keypatch: successfully patched {0:d} byte(s) at 0x{1:X} from [{2}] to [{3}], with {4} byte(s) NOP padded".format(plen,
                                        address, to_hexstr(p_orig_data), to_hexstr(patch_data), padding_len))
            # save this patching for future "undo"
            patch_info.append((address, assembly, p_orig_data, new_patch_comment))
        else:   # we are reverting
            if patch_comment:
                # clean previous IDA comment by replacing it with ''
                new_comment = orig_comment.replace(patch_comment, '')
                idc.MakeComm(address, new_comment)

            print("Keypatch: successfully reverted {0:d} byte(s) at 0x{1:X} from [{2}] to [{3}]".format(plen,
                                        address, to_hexstr(p_orig_data), to_hexstr(patch_data)))

        return plen

    # fill a range of code [addr_begin, addr_end].
    # return the length of patched area
    # on failure, return 0 = wrong input, -1 = failed to patch
    def fill_code(self, addr_begin, addr_end, assembly, syntax, padding, save_origcode, orig_asm=None):
        # treat input as assembly code first
        (encoding, _) =  self.assemble(assembly, addr_begin, syntax=syntax)

        if encoding is None:
            # input might be a hexcode string. try to convert it to raw bytes
            encoding = convert_hexstr(assembly)

        if encoding == None:
            # invalid input: this is neither assembly nor hexcode string
            return 0

        # save original assembly code before overwritting them
        orig_asm = self.ida_get_disasm_range(addr_begin, addr_end)

        # save original comment at addr_begin
        # TODO: save comments in this range, but how to interleave them?
        orig_comment = idc.Comment(addr_begin)
        if orig_comment == None:
            orig_comment = ''

        patch_data = ""
        assembly_new = []
        size = addr_end - addr_begin
        # calculate filling data
        encode_chr = ''.join(chr(c) for c in encoding)
        while True:
            if len(patch_data) + len(encode_chr) <= size:
                patch_data = patch_data + encode_chr
                assembly_new += [assembly.strip()]
            else:
                break

        # for now, only support NOP padding on Intel CPU
        if padding and self.arch == KS_ARCH_X86:
            for i in range(size -len(patch_data)):
                assembly_new += ["nop"]
            patch_data = patch_data.ljust(size, X86_NOP)

        (plen, p_orig_data) = self.patch(addr_begin, patch_data, len(patch_data))
        if plen == None:
            # failed to patch
            return -1

        new_patch_comment = ''
        # append original instruction to comments
        if save_origcode == True:
            if orig_comment == '':
                new_patch_comment = "Keypatch filled range [0x{0:X}:0x{1:X}] ({2} bytes), replaced:\n  {3}".format(addr_begin, addr_end - 1, addr_end - addr_begin, '\n  '.join(orig_asm))
            else:
                new_patch_comment = "\nKeypatch filled range [0x{0:X}:0x{1:X}] ({2} bytes), replaced:\n  {3}".format(addr_begin, addr_end - 1, addr_end - addr_begin, '\n  '.join(orig_asm))

            new_comment = "{0}{1}".format(orig_comment, new_patch_comment)
            idc.MakeComm(addr_begin, new_comment)

        print("Keypatch: successfully filled range [0x{0:X}:0x{1:X}] ({2} bytes) with \"{3}\", replaced \"{4}\"".format(
                    addr_begin, addr_end - 1, addr_end - addr_begin, assembly, '; '.join(orig_asm)))

        # save this modification for future "undo"
        patch_info.append((addr_begin, '\n  '.join(assembly_new), p_orig_data, new_patch_comment))

        return plen


    ### Form helper functions
    @staticmethod
    def dict_to_ordered_list(dictionary):
        list = sorted(dictionary.items(), key=lambda t: t[0], reverse=False)
        keys = [i[0] for i in list]
        values = [i[1] for i in list]

        return (keys, values)

    def get_value_by_idx(self, dictionary, idx, default=None):
        (keys, values) = self.dict_to_ordered_list(dictionary)

        try:
            val = values[idx]
        except IndexError:
            val = default

        return val

    def find_idx_by_value(self, dictionary, value, default=None):
        (keys, values) = self.dict_to_ordered_list(dictionary)

        try:
            idx = values.index(value)
        except:
            idx = default

        return idx

    def get_arch_by_idx(self, idx):
        return self.get_value_by_idx(self.arch_lists, idx)

    def find_arch_idx(self, arch, mode):
        return self.find_idx_by_value(self.arch_lists, (arch, mode))

    def get_syntax_by_idx(self, idx):
        return self.get_value_by_idx(self.syntax_lists, idx, self.syntax)

    def find_syntax_idx(self, syntax):
        return self.find_idx_by_value(self.syntax_lists, syntax)
    ### /Form helper functions


# Common ancestor form to be derived by Patcher, FillRange & Search
class Keypatch_Form(idaapi.Form):
    # prepare for form initializing
    def setup(self, kp_asm, address, assembly=None):
        self.kp_asm = kp_asm
        self.address = address

        # update ordered list of arch and syntax
        self.syntax_keys = self.kp_asm.dict_to_ordered_list(self.kp_asm.syntax_lists)[0]
        self.arch_keys = self.kp_asm.dict_to_ordered_list(self.kp_asm.arch_lists)[0]

        # update current arch & mode
        self.kp_asm.update_hardware_mode()

        # find right value for c_arch & c_endian controls
        mode = self.kp_asm.mode
        self.endian_id = 0   # little endian
        if self.kp_asm.mode & KS_MODE_BIG_ENDIAN:
            self.endian_id = 1   # big endian
            mode = self.kp_asm.mode - KS_MODE_BIG_ENDIAN

        self.arch_id = self.kp_asm.find_arch_idx(self.kp_asm.arch, mode)

        self.syntax_id = 0  # to make non-X86 arch happy
        if self.kp_asm.arch == KS_ARCH_X86:
            self.syntax_id = self.kp_asm.find_syntax_idx(self.kp_asm.syntax)

        # get original instruction and bytes
        self.orig_asm = kp_asm.ida_get_disasm(address)
        (self.orig_encoding, self.orig_len) = kp_asm.ida_get_item(address, hex_output=True)
        if self.orig_encoding == None:
            self.orig_encoding = ''

        if assembly is None:
            self.asm = self.kp_asm.ida_get_disasm(self.address, fixup=True)
        else:
            self.asm = assembly

    def __init__(self, kp_asm, address, assembly=None, patch_mode=False, opts=0):
        pass

    # update Encoding control
    # return True on success, False on failure
    def _update_encoding(self, arch, mode):
        try:
            syntax = None
            if arch == KS_ARCH_X86:
                syntax_id = self.GetControlValue(self.c_syntax)
                syntax = self.kp_asm.get_syntax_by_idx(syntax_id)

            address = self.GetControlValue(self.c_addr)
            try:
                idaapi.isEnabled(address)
            except:
                # invalid address value
                address = 0

            assembly = self.GetControlValue(self.c_assembly)
            raw_assembly = self.kp_asm.ida_resolve(assembly, address)
            self.SetControlValue(self.c_raw_assembly, raw_assembly)

            (encoding, count) =  self.kp_asm.assemble(raw_assembly, address, arch=arch,
                                                    mode=mode, syntax=syntax)

            if encoding is None:
                self.SetControlValue(self.c_encoding, ENCODING_ERR_OUTPUT)
                self.SetControlValue(self.c_encoding_len, 0)
                return False
            else:
                text = ""
                for byte in encoding:
                    text += "%02X " % byte
                text.strip()
                if text == "":
                    # error?
                    self.SetControlValue(self.c_encoding, ENCODING_ERR_OUTPUT)
                    return False
                else:
                    self.SetControlValue(self.c_encoding, text.strip())
                    self.SetControlValue(self.c_encoding_len, len(encoding))
                    return True
        except Exception,e:
            print (str(e))
            import traceback
            traceback.print_exc()
            self.SetControlValue(self.c_encoding, ENCODING_ERR_OUTPUT)
            return False

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        return 1

    # update Patcher & Fillrange controls
    def update_patchform(self, fid):
        self.EnableField(self.c_endian, False)
        self.EnableField(self.c_addr, False)

        (arch, mode) = (self.kp_asm.arch, self.kp_asm.mode)
        # assembly is focused
        self.SetFocusedField(self.c_assembly)

        if arch == KS_ARCH_X86:
            # do not show Endian control
            self.ShowField(self.c_endian, False)
            # allow to choose Syntax
            self.ShowField(self.c_syntax, True)
            self.ShowField(self.c_opt_padding, True)
        else:   # do not show Syntax control for non-X86 mode
            self.ShowField(self.c_syntax, False)
            # for now, we do not support padding for non-X86 archs
            self.ShowField(self.c_opt_padding, False)
            #self.EnableField(self.c_opt_padding, False)

        # update other controls & Encoding with live assembling
        self.update_controls(arch, mode)

        return 1

    # update some controls - including Encoding control
    def update_controls(self, arch, mode):
        # Fixup & Encoding-len are read-only controls
        self.EnableField(self.c_raw_assembly, False)
        self.EnableField(self.c_encoding_len, False)

        # Encoding is enable to allow user to select & copy
        self.EnableField(self.c_encoding, True)

        if self.GetControlValue(self.c_endian) == 1:
            endian = KS_MODE_BIG_ENDIAN
        else:
            endian = KS_MODE_LITTLE_ENDIAN

        # update encoding with live assembling
        self._update_encoding(arch, mode | endian)

        return 1

    # get Patcher/FillRange options
    def get_opts(self, name=None):
        names = self.c_opt_chk.children_names
        val = self.c_opt_chk.value
        opts = {}
        for i in range(len(names)):
            opts[names[i]] = val & (2**i)

        if name != None:
            opts[name] = val

        return opts


# Fill Range form
class Keypatch_FillRange(Keypatch_Form):
    def __init__(self, kp_asm, addr_begin, addr_end, assembly=None, opts=None):
        self.setup(kp_asm, addr_begin, assembly)
        self.addr_end = addr_end

        # create FillRange form
        Form.__init__(self,
            r"""STARTITEM {id:c_assembly}
BUTTON YES* Patch
KEYPATCH:: Fill Range

            {FormChangeCb}
            <Endian     :{c_endian}>
            <~S~yntax     :{c_syntax}>
            <Start      :{c_addr}>
            <End        :{c_addr_end}>
            <Size       :{c_size}>
            <~A~ssembly   :{c_assembly}>
             <-   Fixup :{c_raw_assembly}>
             <-   Encode:{c_encoding}>
             <-   Size  :{c_encoding_len}>
            <~N~OPs padding until next instruction boundary:{c_opt_padding}>
            <Save ~o~riginal instructions in IDA comment:{c_opt_comment}>{c_opt_chk}>
            """, {
            'c_endian': Form.DropdownListControl(
                          items = self.kp_asm.endian_lists.keys(),
                          readonly = True,
                          selval = self.endian_id),
            'c_addr': Form.NumericInput(value=addr_begin, swidth=MAX_ADDRESS_LEN, tp=Form.FT_ADDR),
            'c_addr_end': Form.NumericInput(value=addr_end - 1, swidth=MAX_ADDRESS_LEN, tp=Form.FT_ADDR),
            'c_assembly': Form.StringInput(value=self.asm[:MAX_INSTRUCTION_STRLEN], width=MAX_INSTRUCTION_STRLEN),
            'c_size': Form.NumericInput(value=addr_end - addr_begin, swidth=8, tp=Form.FT_DEC),
            'c_raw_assembly': Form.StringInput(value='', width=MAX_INSTRUCTION_STRLEN),
            'c_encoding': Form.StringInput(value='', width=MAX_ENCODING_LEN),
            'c_encoding_len': Form.NumericInput(value=0, swidth=8, tp=Form.FT_DEC),
            'c_syntax': Form.DropdownListControl(
                          items = self.syntax_keys,
                          readonly = True,
                          selval = self.syntax_id),
            'c_opt_chk':idaapi.Form.ChkGroupControl(('c_opt_padding', 'c_opt_comment', ''), value=opts['c_opt_chk']),
            'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
            })

        self.Compile()

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        # make some controls read-only in FillRange mode
        self.EnableField(self.c_size, False)
        self.EnableField(self.c_addr_end, False)

        return self.update_patchform(fid)


# Patcher form
class Keypatch_Patcher(Keypatch_Form):
    def __init__(self, kp_asm, address, assembly=None, opts=None):
        self.setup(kp_asm, address, assembly)

        # create Patcher form
        Form.__init__(self,
            r"""STARTITEM {id:c_assembly}
BUTTON YES* Patch
KEYPATCH:: Patcher

            {FormChangeCb}
            <Endian     :{c_endian}>
            <~S~yntax     :{c_syntax}>
            <Address    :{c_addr}>
            <Original   :{c_orig_assembly}>
             <-   Encode:{c_orig_encoding}>
             <-   Size  :{c_orig_len}>
            <~A~ssembly   :{c_assembly}>
             <-   Fixup :{c_raw_assembly}>
             <-   Encode:{c_encoding}>
             <-   Size  :{c_encoding_len}>
            <~N~OPs padding until next instruction boundary:{c_opt_padding}>
            <Save ~o~riginal instructions in IDA comment:{c_opt_comment}>{c_opt_chk}>
            """, {
            'c_endian': Form.DropdownListControl(
                          items = self.kp_asm.endian_lists.keys(),
                          readonly = True,
                          selval = self.endian_id),
            'c_addr': Form.NumericInput(value=address, swidth=MAX_ADDRESS_LEN, tp=Form.FT_ADDR),
            'c_assembly': Form.StringInput(value=self.asm[:MAX_INSTRUCTION_STRLEN], width=MAX_INSTRUCTION_STRLEN),
            'c_orig_assembly': Form.StringInput(value=self.orig_asm[:MAX_INSTRUCTION_STRLEN], width=MAX_INSTRUCTION_STRLEN),
            'c_orig_encoding': Form.StringInput(value=self.orig_encoding[:MAX_ENCODING_LEN], width=MAX_ENCODING_LEN),
            'c_orig_len': Form.NumericInput(value=self.orig_len, swidth=8, tp=Form.FT_DEC),
            'c_raw_assembly': Form.StringInput(value='', width=MAX_INSTRUCTION_STRLEN),
            'c_encoding': Form.StringInput(value='', width=MAX_ENCODING_LEN),
            'c_encoding_len': Form.NumericInput(value=0, swidth=8, tp=Form.FT_DEC),
            'c_syntax': Form.DropdownListControl(
                          items = self.syntax_keys,
                          readonly = True,
                          selval = self.syntax_id),
            'c_opt_chk':idaapi.Form.ChkGroupControl(('c_opt_padding', 'c_opt_comment', ''), value=opts['c_opt_chk']),
            'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
            })

        self.Compile()

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        # make some fields read-only in Patch mode
        self.EnableField(self.c_orig_assembly, False)
        self.EnableField(self.c_orig_encoding, False)
        self.EnableField(self.c_orig_len, False)

        return self.update_patchform(fid)


# Search position chooser
class SearchResultChooser(idaapi.Choose2):
    def __init__(self, title, items, flags=0, width=None, height=None, embedded=False, modal=False):        
        Choose2.__init__(
            self,
            title,
            [["Address", idaapi.Choose2.CHCOL_HEX|40]],
            flags = flags,
            width = width,
            height = height,
            embedded = embedded)
        self.n = 0
        self.items = items
        self.selcount = 0
        self.modal = modal

    def OnClose(self):
        return

    def OnSelectLine(self, n):
        self.selcount += 1
        idc.Jump(self.items[n][0])

    def OnGetLine(self, n):
        res = self.items[n]
        res = [atoa(res[0])]
        return res

    def OnGetSize(self):
        n = len(self.items)
        return n

    def show(self):
        return self.Show(self.modal) >= 0


# Search form
class Keypatch_Search(Keypatch_Form):
    def __init__(self, kp_asm, address, assembly=None):
        self.setup(kp_asm, address, assembly)

        # create Search form
        Form.__init__(self,
            r"""STARTITEM {id:c_assembly}
BUTTON YES* Search
KEYPATCH:: Search

            {FormChangeCb}
            <A~r~ch       :{c_arch}>
            <E~n~dian     :{c_endian}>
            <~S~yntax     :{c_syntax}>
            <A~d~dress    :{c_addr}>
            <~A~ssembly   :{c_assembly}>
             <-   Fixup :{c_raw_assembly}>
             <-   Encode:{c_encoding}>
             <-   Size  :{c_encoding_len}>
            """, {
            'c_addr': Form.NumericInput(value=address, swidth=MAX_ADDRESS_LEN, tp=Form.FT_ADDR),
            'c_assembly': Form.StringInput(value=self.asm[:MAX_INSTRUCTION_STRLEN], width=MAX_INSTRUCTION_STRLEN),
            'c_raw_assembly': Form.StringInput(value='', width=MAX_INSTRUCTION_STRLEN),
            'c_encoding': Form.StringInput(value='', width=MAX_ENCODING_LEN),
            'c_encoding_len': Form.NumericInput(value=0, swidth=8, tp=Form.FT_DEC),
            'c_arch': Form.DropdownListControl(
                          items = self.arch_keys,
                          readonly = True,
                          selval = self.arch_id,
                          width = 32),
            'c_endian': Form.DropdownListControl(
                          items = self.kp_asm.endian_lists.keys(),
                          readonly = True,
                          selval = self.endian_id),
            'c_syntax': Form.DropdownListControl(
                          items = self.syntax_keys,
                          readonly = True,
                          selval = self.syntax_id),
            'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
            })

        self.Compile()

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        # handle the search button
        if fid == -2:
            address = 0
            addresses = []
            while address != idc.BADADDR:
                address = idc.FindBinary(address, SEARCH_DOWN, self.GetControlValue(self.c_encoding))
                if address == idc.BADADDR:
                    break
                addresses.append([address])
                address = address + 1
            c = SearchResultChooser("Searching for [{0}]".format(self.GetControlValue(self.c_raw_assembly)), addresses)
            r = c.show()
            return 1

        # only Search mode allows to select arch+mode
        arch_id = self.GetControlValue(self.c_arch)
        (arch, mode) = self.kp_asm.get_arch_by_idx(arch_id)

        # assembly is focused
        self.SetFocusedField(self.c_assembly)

        if arch == KS_ARCH_X86:
            # enable Syntax and disable Endian for x86
            self.ShowField(self.c_syntax, True)
            self.EnableField(self.c_syntax, True)
            self.syntax_id = self.GetControlValue(self.c_syntax)
            self.EnableField(self.c_endian, False)
            # set Endian index properly
            self.SetControlValue(self.c_endian, 0)
        elif arch in (KS_ARCH_ARM64, KS_ARCH_HEXAGON, KS_ARCH_SYSTEMZ):
            # no Syntax & Endian option for these archs
            self.ShowField(self.c_syntax, False)
            self.EnableField(self.c_syntax, False)
            self.EnableField(self.c_endian, False)
            # set Endian index properly
            self.SetControlValue(self.c_endian, (mode & KS_MODE_BIG_ENDIAN != 0))
        elif (arch == KS_ARCH_PPC) and (mode & KS_MODE_PPC32 != 0):
            # no Syntax & Endian option for these archs
            self.ShowField(self.c_syntax, False)
            self.EnableField(self.c_syntax, False)
            self.EnableField(self.c_endian, False)
            # set Endian index properly
            self.SetControlValue(self.c_endian, (mode & KS_MODE_BIG_ENDIAN != 0))
        else:
            # no Syntax & Endian option
            self.ShowField(self.c_syntax, False)
            self.EnableField(self.c_syntax, False)
            self.EnableField(self.c_endian, True)

        if self.GetControlValue(self.c_endian) == 1:
            endian = KS_MODE_BIG_ENDIAN
        else:
            endian = KS_MODE_LITTLE_ENDIAN

        # update other controls & Encoding with live assembling
        self.update_controls(arch, mode)

        return 1


# About form
class About_Form(idaapi.Form):
    def __init__(self, version):
        # create About form
        Form.__init__(self,
            r"""STARTITEM 0
BUTTON YES* Open Keypatch Website
KEYPATCH:: About

            {FormChangeCb}
            Keypatch IDA plugin v%s, using Keystone Engine v%s.
            (c) Nguyen Anh Quynh + Thanh Nguyen, 2016.

            Keypatch is released under the GPL v2.
            Find more info at http://www.keystone-engine.org/keypatch
            """ %(version, keystone.__version__), {
            'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
            })

        self.Compile()

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        if fid == -2:   # Goto homepage
            import webbrowser
            # open Keypatch homepage in a new tab, if possible
            webbrowser.open(KP_HOMEPAGE, new = 2)

        return 1


# Check-for-update form
class Update_Form(idaapi.Form):
    def __init__(self, version, message):
        # create Update form
        Form.__init__(self,
            r"""STARTITEM 0
BUTTON YES* Open Keypatch Website
KEYPATCH:: Check for update

            {FormChangeCb}
            Your Keypatch is v%s
            %s
            """ %(version, message), {
            'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
            })

        self.Compile()

    # callback to be executed when any form control changed
    def OnFormChange(self, fid):
        if fid == -2:   # Goto homepage
            import webbrowser
            # open Keypatch homepage in a new tab, if possible
            webbrowser.open(KP_HOMEPAGE, new = 2)

        return 1


try:
    # adapted from pull request #7 by @quangnh89
    class Kp_Menu_Context(idaapi.action_handler_t):
        def __init__(self):
            idaapi.action_handler_t.__init__(self)

        @classmethod
        def get_name(self):
            return self.__name__

        @classmethod
        def get_label(self):
            return self.label

        @classmethod
        def register(self, plugin, label):
            self.plugin = plugin
            self.label = label
            instance = self()
            return idaapi.register_action(idaapi.action_desc_t(
                self.get_name(),  # Name. Acts as an ID. Must be unique.
                instance.get_label(),  # Label. That's what users see.
                instance  # Handler. Called when activated, and for updating
            ))

        @classmethod
        def unregister(self):
            """Unregister the action.
            After unregistering the class cannot be used.
            """
            idaapi.unregister_action(self.get_name())

        @classmethod
        def activate(self, ctx):
            # dummy method
            return 1

        @classmethod
        def update(self, ctx):
            try:
                if ctx.form_type == idaapi.BWN_DISASM:
                    return idaapi.AST_ENABLE_FOR_FORM
                else:
                    return idaapi.AST_DISABLE_FOR_FORM
            except:
                # Add exception for main menu on >= IDA 7.0
                return idaapi.AST_ENABLE_ALWAYS
            
    # context menu for Patcher
    class Kp_MC_Patcher(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.patcher()
            return 1

    # context menu for Fill Range
    class Kp_MC_Fill_Range(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.fill_range()
            return 1

    # context menu for Undo
    class Kp_MC_Undo(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.undo()
            return 1

    # context menu for Search
    class Kp_MC_Search(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.search()
            return 1

    # context menu for Check Update
    class Kp_MC_Updater(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.updater()
            return 1

    # context menu for About
    class Kp_MC_About(Kp_Menu_Context):
        def activate(self, ctx):
            self.plugin.about()
            return 1
except:
    pass


# hooks for popup menu
class Hooks(idaapi.UI_Hooks):
    if idaapi.IDA_SDK_VERSION >= 700:
        # IDA >= 700 right click widget popup
        def finish_populating_widget_popup(self, form, popup):
            if idaapi.get_widget_type(form) == idaapi.BWN_DISASM:
                try:
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Patcher.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Fill_Range.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Undo.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, "-", 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Search.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, "-", 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Updater.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_About.get_name(), 'Keypatch/')
                except:
                    pass
    else:
        # IDA < 700 right click popup
        def finish_populating_tform_popup(self, form, popup):
            # We'll add our action to all "IDA View-*"s.
            # If we wanted to add it only to "IDA View-A", we could
            # also discriminate on the widget's title:
            #
            #  if idaapi.get_tform_title(form) == "IDA View-A":
            #      ...
            #
            if idaapi.get_tform_type(form) == idaapi.BWN_DISASM:
                try:
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Patcher.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Fill_Range.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Undo.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, "-", 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Search.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, "-", 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_Updater.get_name(), 'Keypatch/')
                    idaapi.attach_action_to_popup(form, popup, Kp_MC_About.get_name(), 'Keypatch/')
                except:
                    pass


# check if we already initialized Keypatch
kp_initialized = False

#--------------------------------------------------------------------------
# Plugin
#--------------------------------------------------------------------------
class Keypatch_Plugin_t(idaapi.plugin_t):
    comment = "Keypatch plugin for IDA Pro (using Keystone framework)"
    help = "Find more information on Keypatch at http://keystone-engine.org/keypatch"
    wanted_name = "Keypatch Patcher"
    wanted_hotkey = "Ctrl-Alt-K"
    flags = idaapi.PLUGIN_KEEP


    def load_configuration(self):
        # default
        self.opts = {}

        # load configuration from file
        try:
            f = open(KP_CFGFILE, "rt")
            self.opts = json.load(f)
            f.close()
        except IOError:
            print("Keypatch: FAILED to load config file. Use default setup now.")
        except Exception as e:
            print("Keypatch: FAILED to load config file, with exception: {0}".format(str(e)))

        # use default values if not defined in config file
        if 'c_opt_padding' not in self.opts:
            self.opts['c_opt_padding'] = 1

        if 'c_opt_comment' not in self.opts:
            self.opts['c_opt_comment'] = 2

        self.opts['c_opt_chk'] = self.opts['c_opt_padding'] | self.opts['c_opt_comment']

    def init(self):
        global kp_initialized

        # register popup menu handlers
        try:
            Kp_MC_Patcher.register(self, "Patcher    (Ctrl-Alt-K)")
            Kp_MC_Fill_Range.register(self, "Fill Range")
            Kp_MC_Undo.register(self, "Undo last patching")
            Kp_MC_Search.register(self, "Search")
            Kp_MC_Updater.register(self, "Check for update")
            Kp_MC_About.register(self, "About")
        except:
            pass

        # setup popup menu
        self.hooks = Hooks()
        self.hooks.hook()

        self.opts = None
        if kp_initialized == False:
            kp_initialized = True

            if idaapi.IDA_SDK_VERSION >= 700:
                # Add menu IDA >= 7.0
                idaapi.attach_action_to_menu("Edit/Keypatch/Patcher", Kp_MC_Patcher.get_name(), idaapi.SETMENU_APP)
                idaapi.attach_action_to_menu("Edit/Keypatch/About", Kp_MC_About.get_name(), idaapi.SETMENU_APP)
                idaapi.attach_action_to_menu("Edit/Keypatch/Check for update", Kp_MC_Updater.get_name(), idaapi.SETMENU_APP)
                idaapi.attach_action_to_menu("Edit/Keypatch/Search", Kp_MC_Search.get_name(), idaapi.SETMENU_APP)
                idaapi.attach_action_to_menu("Edit/Keypatch/Undo last patching", Kp_MC_Undo.get_name(), idaapi.SETMENU_APP)
                idaapi.attach_action_to_menu("Edit/Keypatch/Fill Range", Kp_MC_Fill_Range.get_name(), idaapi.SETMENU_APP)
            else:
                # add Keypatch menu
                menu = idaapi.add_menu_item("Edit/Keypatch/", "Patcher     (Ctrl-Alt-K)", "", 1, self.patcher, None)
                if menu is not None:
                    idaapi.add_menu_item("Edit/Keypatch/", "About", "", 1, self.about, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "Check for update", "", 1, self.updater, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "-", "", 1, self.menu_null, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "Search", "", 1, self.search, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "-", "", 1, self.menu_null, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "Undo last patching", "", 1, self.undo, None)
                    idaapi.add_menu_item("Edit/Keypatch/", "Fill Range", "", 1, self.fill_range, None)
                elif idaapi.IDA_SDK_VERSION < 680:
                    # older IDAPython (such as in IDAPro 6.6) does add new submenu.
                    # in this case, put Keypatch menu in menu Edit \ Patch program
                    # not sure about v6.7, so to be safe we just check against v6.8
                    idaapi.add_menu_item("Edit/Patch program/", "-", "", 0, self.menu_null, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: About", "", 0, self.about, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: Check for update", "", 0, self.updater, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: Search", "", 0, self.search, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: Undo last patching", "", 0, self.undo, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: Fill Range", "", 0, self.fill_range, None)
                    idaapi.add_menu_item("Edit/Patch program/", "Keypatch:: Patcher     (Ctrl-Alt-K)", "", 0, self.patcher, None)

            print("=" * 80)
            print("Keypatch v{0} (c) Nguyen Anh Quynh & Thanh Nguyen, 2016".format(VERSION))
            print("Keypatch is using Keystone v{0}".format(keystone.__version__))
            print("Keypatch Patcher's shortcut key is Ctrl-Alt-K")
            print("Use the same hotkey Ctrl-Alt-K to open 'Fill Range' window on a selected range of code")
            print("To revert (undo) the last patching, choose menu Edit | Keypatch | Undo last patching")
            print("Keypatch Search is available from menu Edit | Keypatch | Search")
            print("Find more information about Keypatch at http://keystone-engine.org/keypatch")

            self.load_configuration()

            print("=" * 80)
            self.kp_asm = Keypatch_Asm()

        return idaapi.PLUGIN_KEEP

    def term(self):
        if self.hooks is not None:
            self.hooks.unhook()
            self.hooks = None

        if self.opts is None:
            return
        #save configuration to file
        try:
            json.dump(self.opts, open(KP_CFGFILE, "wt"))
        except Exception as e:
            print("Keypatch: FAILED to save config file, with exception: {0}".format(str(e)))
        else:
            print("Keypatch: configuration is saved to {0}".format(KP_CFGFILE))

    # null handler
    def menu_null(self):
        pass

    # handler for About menu
    def about(self):
        f = About_Form(VERSION)
        f.Execute()
        f.Free()

    # handler for Check-for-Update menu
    def updater(self):
        (r, content) = url_download(KP_GITHUB_VERSION)
        if r == 0:
            # find stable version
            sig = 'VERSION_STABLE = "'
            tmp = content[content.find(sig)+len(sig):]
            version_stable = tmp[:tmp.find('"')]

            # compare with the current version
            if version_stable == VERSION:
                f = Update_Form(VERSION, "Good, you are already on the latest stable version!")
                f.Execute()
                # free this form
                f.Free()
            else:
                f = Update_Form(VERSION, "Download latest stable version {0} from http://keystone-engine.org/keypatch".format(version_stable))
                f.Execute()
                # free this form
                f.Free()
        else:
            # fail to download
            idc.Warning("ERROR: Keypatch failed to connect to internet (Github). Try again later.")
            print("Keypatch: FAILED to connect to Github to check for latest update. Try again later.")

    # handler for Undo menu
    def undo(self):
        global patch_info
        if len(patch_info) == 0:
            # TODO: disable Undo menu?
            idc.Warning("ERROR: Keypatch already got to the last undo patching!")
        else:
            (address, assembly, p_orig_data, patch_comment) = patch_info[-1]

            # undo the patch
            self.kp_asm.patch_code(address, None, None, None, None, orig_asm=[assembly], patch_data=p_orig_data, patch_comment=patch_comment, undo=True)
            del(patch_info[-1])

    # handler for Search menu
    def search(self):
        address = idc.ScreenEA()
        f = Keypatch_Search(self.kp_asm, address)
        f.Execute()
        f.Free()

    # handler for Patcher menu
    def patcher(self):
        # be sure that this arch is supported by Keystone
        if self.kp_asm.arch is None:
            idc.Warning("ERROR: Keypatch cannot handle this architecture (unsupported by Keystone), quit!")
            return

        if idaapi.IDA_SDK_VERSION >= 700:
            # IDA >= 7.0 read selection change
            p0 = idaapi.twinpos_t()
            p1 = idaapi.twinpos_t()
            view = idaapi.get_current_viewer()
            selection = idaapi.read_selection(view, p0, p1)
            if selection:
                place0  = p0.place(view)
                place1 = p1.place(view)

                addr_begin  = place0.toea()
                addr_end = place1.toea()
        else:
            selection, addr_begin, addr_end = idaapi.read_selection()

        if selection:
            # call Fill Range function on this selected code
            return self.fill_range()

        address = idc.ScreenEA()

        if self.opts is None:
            self.load_configuration()

        init_assembly = None
        while True:
            f = Keypatch_Patcher(self.kp_asm, address, assembly=init_assembly, opts=self.opts)
            ok = f.Execute()
            if ok == 1:
                try:
                    syntax = None
                    if f.kp_asm.arch == KS_ARCH_X86:
                        syntax_id = f.c_syntax.value
                        syntax = self.kp_asm.get_syntax_by_idx(syntax_id)

                    assembly = f.c_assembly.value
                    self.opts = f.get_opts('c_opt_chk')
                    padding = (self.opts.get("c_opt_padding", 0) != 0)
                    comment = (self.opts.get("c_opt_comment", 0) != 0)

                    raw_assembly = self.kp_asm.ida_resolve(assembly, address)

                    print("Keypatch: attempting to modify \"{0}\" at 0x{1:X} to \"{2}\"".format(
                            self.kp_asm.ida_get_disasm(address), address, assembly))

                    length = self.kp_asm.patch_code(address, raw_assembly, syntax, padding, comment, None)
                    if length > 0:
                        # update start address pointing to the next instruction
                        init_assembly = None
                        address += length
                    else:
                        init_assembly = f.c_assembly.value
                        if length == 0:
                            idc.Warning("ERROR: Keypatch found invalid assembly [{0}]".format(assembly))
                        elif length == -1:
                            idc.Warning("ERROR: Keypatch failed to patch binary at 0x{0:X}!".format(address))
                        elif length == -2:
                            idc.Warning("ERROR: Keypatch can't read original data at 0x{0:X}, try again".format(address))

                except KsError as e:
                    print("Keypatch Error: {0}".format(e))
            else:   # Cancel
                break
            f.Free()

    # handler for Fill Range menu
    def fill_range(self):
        # be sure that this arch is supported by Keystone
        if self.kp_asm.arch is None:
            idc.Warning("ERROR: Keypatch cannot handle this architecture (unsupported by Keystone), quit!")
            return

        if idaapi.IDA_SDK_VERSION >= 700:
            # IDA >= 7.0 read selection change
            p0 = idaapi.twinpos_t()
            p1 = idaapi.twinpos_t()
            view = idaapi.get_current_viewer()
            selection = idaapi.read_selection(view, p0, p1)

            place0  = p0.place(view)
            place1 = p1.place(view)

            if selection:
                place0  = p0.place(view)
                place1 = p1.place(view)
    
                addr_begin  = place0.toea()
                addr_end = place1.toea()
        else:
            selection, addr_begin, addr_end = idaapi.read_selection()

        if not selection:
            idc.Warning("ERROR: Keypatch requires a range to be selected for fill in, try again")
            return

        if self.opts is None:
            self.load_configuration()

        init_assembly = None
        f = Keypatch_FillRange(self.kp_asm, addr_begin, addr_end, assembly=init_assembly, opts=self.opts)
        ok = f.Execute()
        if ok == 1:
            try:
                syntax = None
                if f.kp_asm.arch == KS_ARCH_X86:
                    syntax_id = f.c_syntax.value
                    syntax = self.kp_asm.get_syntax_by_idx(syntax_id)

                assembly = f.c_assembly.value
                self.opts = f.get_opts('c_opt_chk')
                padding = (self.opts.get("c_opt_padding", 0) != 0)
                comment = (self.opts.get("c_opt_comment", 0) != 0)

                raw_assembly = self.kp_asm.ida_resolve(assembly, addr_begin)

                print("Keypatch: attempting to fill range [0x{0:X}:0x{1:X}] with \"{2}\"".format(
                    addr_begin, addr_end - 1, assembly))

                length = self.kp_asm.fill_code(addr_begin, addr_end, raw_assembly, syntax, padding, comment, None)
                if length == 0:
                    idc.Warning("ERROR: Keypatch failed to process this input.")
                    print("Keypatch: FAILED to process this input '{0}'".format(assembly))
                elif length == -1:
                    idc.Warning("ERROR: Keypatch failed to patch binary at 0x{0:X}!".format(addr_begin))

            except KsError as e:
                print("Keypatch Error: {0}".format(e))

        # free this form
        f.Free()

    def run(self, arg):
        self.patcher()


# register IDA plugin
def PLUGIN_ENTRY():
    return Keypatch_Plugin_t()


repository: clovme/WTools
file: software/Reverse Cracking/IDA Professional 9.0/python/examples/merge/py_mex3.py
wanted_name: IDAPython: Merge example 3
comment: IDAPython: An example 1 how to implement IDA merge functionality
created_at: 2025-03-27 00:14:54+00:00
pushed_at: 2025-05-11 10:18:21+00:00
url:
https://github.com/clovme/WTools/blob/f12f01c833a6a6241799a9d01e9117cc28a65dbc/software/Reverse%20Cracking/IDA%20Professional%209.0/python/examples/merge/py_mex3.py

content:
# pylint: disable=line-too-long,invalid-name,import-error

"""
summary: This example uses the mex1 example and improves the user-interface for it.

description:
  IDA Teams uses a chooser to display the merge conflicts.
  To fill the chooser columns IDA Teams uses the following methods from diff_source_t type:
    * print_diffpos_name()
    * print_diffpos_details()
  and UI hints from merge_handler_params_t type:
    * ui_has_details()
    * ui_complex_details()
    * ui_complex_name()

  In general, chooser columns are filled as following:
    columns.clear()
    NAME = print_diffpos_name()
    if ui_complex_name()
    then
      columns.add(split NAME by ui_split_char())
    else
      columns[0] = NAME
    if not ui_complex_details()
    then
      columns.add(print_diffpos_details())

  Also, see SDK/plugins/mex3 example
"""


import ida_idaapi
import ida_ida
import ida_kernwin
import ida_netnode
import ida_funcs
import ida_merge
import ida_mergemod
import ida_idp
import ida_nalt


# --------------------------------------------------------------------------
# netnode to store plugin data
MEX_NODE_NAME = "$ idapython mex3"
# user input
MEX_OPTION_FLAGS_IDX = ida_idaapi.BADADDR & -1   # atag
MEX_OPTION_IDENT_IDX = ida_idaapi.BADADDR & -2   # stag
# EA marks
MEX_EA_TAG = 'm'

# mex_ctx_t::flags bits
MEX_FLAGS_0 = 0x01
MEX_FLAGS_1 = 0x02

# --------------------------------------------------------------------------
class idp_listener_t(ida_idp.IDP_Hooks):
    """
    we need an event listener to catch processor_t::ev_create_merge_handlers
    """

    def __init__(self, ctx):
        # by default IDP_Hooks uses ida_idp.HKCB_GLOBAL hkcb_flags,
        # in that case IDP events are sent to all DB instances.
        # Such behaviour does not matter for IDA Pro
        # but IDA Teams needs to have only one IDP event sent to plugin.
        # We set hkcb_flags to 0
        ida_idp.IDP_Hooks.__init__(self, 0, 0)
        self.ctx = ctx

    def ev_ending_undo(self):
        """
        A well behaving plugin should restore its state from the database
        upon ev_ending_undo. Otherwise its state may be conflicting with the
        database.
        """
        self.ctx.restore_from_idb()
        return 0

    def ev_create_merge_handlers(self, md):
        """
        This event occurs when IDA is performing a 3-way merge (for IDA Teams)
        Our plugins should create and register merge handler(s) for its data.
        """
        self.ctx.create_merge_handlers(md)
        return 0


    def ev_cvt64_supval(self, node, tag, idx, data):
        """
        Converter to i64 database
        """
        nn = ida_netnode.netnode(MEX_NODE_NAME)
        if nn == node:
            if tag == ida_netnode.stag:
                nn.supset(MEX_OPTION_IDENT_IDX, data)
                return 1
            if tag == ida_netnode.atag and len(data):
                val = int.from_bytes(data, 'little')
                nn.altset(MEX_OPTION_FLAGS_IDX, val)
                return 1
            if chr(tag) == MEX_EA_TAG:
                nn.supset(idx, data, MEX_EA_TAG)
                return 1
        return 0


# --------------------------------------------------------------------------
class mex_ctx_t(ida_idaapi.plugmod_t):
    """
    Regular plugin implementation below.
    For example, in our case the plugin asks for 2 bit values and a string value.
    Then the plugin stores this data in the database.
    And mark the start address of the current function.
    These data will be merged later.
    """

    def __init__(self):
        # bit flags, see above MEX_FLAGS_0/MEX_FLAGS_1
        self.flags = 0
        # unique database ident
        self.ident = ""
        # Restore the plugin data from the database into the memory.
        self.restore_from_idb()
        # Hook an event listener, to catch the merge-related event(s).
        self.idp_listener = idp_listener_t(self)
        self.idp_listener.hook()
        # MERGE: the following data must exist during plugin lifetime
        self.modmerger_helper = None
        self.idpopts_info = None
        self.node_helper = None
        self.merge_node_info = None

    def save_to_idb(self):
        """ Save the plugin state to the idb. """
        nn = ida_netnode.netnode(MEX_NODE_NAME, 0, True)
        nn.altset(MEX_OPTION_FLAGS_IDX, self.flags)
        nn.supset(MEX_OPTION_IDENT_IDX, self.ident)

    def restore_from_idb(self):
        """ Restore plugin variables from the idb. """
        nn = ida_netnode.netnode(MEX_NODE_NAME)
        if nn != ida_netnode.BADNODE:
            self.flags = nn.altval(MEX_OPTION_FLAGS_IDX)
            self.ident = nn.supstr(MEX_OPTION_IDENT_IDX)

    def run(self, _):
        """
        Ask user for the data and save them to database.
        Add mark for current EA.
        """
        if self._ask_form():
            self.save_to_idb()
        # Our plugin stores a string for the current function.
        # Just for illustration purposes of how plugins should merge address-specific info
        # stored in a netnode.
        ea = ida_kernwin.get_screen_ea()
        pfn = ida_funcs.get_func(ea)
        if pfn:
            one = ""
            if (self.flags & MEX_FLAGS_0) != 0:
                one = " one"
            two = ""
            if (self.flags & MEX_FLAGS_1) != 0:
                one = " two"
            mark = "IPMEX1" + one + two
            nn = ida_netnode.netnode(MEX_NODE_NAME, 0, True)
            nn.supset_ea(pfn.start_ea, mark, MEX_EA_TAG)

    def _ask_form(self):
        class MexForm(ida_kernwin.Form):
            def __init__(self):
                ida_kernwin.Form.__init__(self,
                r"""
IDAPython: merge example 1

<Flag 0:{optFlag0}>
<Flag 1:{optFlag1}>{grpFlags}>
<Ident prefix:{ident}>
                """,
                {
                    "grpFlags": ida_kernwin.Form.ChkGroupControl(("optFlag0", "optFlag1")),
                    "ident"   : ida_kernwin.Form.StringInput(swidth=10),
                })

        form = MexForm()
        form, _ = form.Compile()
        form.grpFlags.value = self.flags
        form.ident.value = self.ident
        ok = form.Execute()
        if ok == 1:
            self.flags = form.grpFlags.value
            self.ident = form.ident.value
        form.Free()
        return ok == 1

    def create_merge_handlers(self, md):
        """
        Create merge handlers for plugin
        """

        #-------------------------------------------------------------------------
        # 1. Data common for entire database (e.g. the options).
        #
        # This example shows how to merge the data from database.
        # We will describe the items to merge and pass the description
        # to create_std_modmerge_handlers(), which will do all the work for us.
        sizeof_flags = ida_netnode.SIZEOF_nodeidx_t
        self.idpopts_info = [
            # Describe both flags
            ida_ida.idbattr_info_t("MEX flag 0", MEX_OPTION_FLAGS_IDX, sizeof_flags, MEX_FLAGS_0, ida_netnode.atag, ida_ida.IDI_ALTVAL|ida_ida.IDI_SCALAR),
            ida_ida.idbattr_info_t("MEX flag 1", MEX_OPTION_FLAGS_IDX, sizeof_flags, MEX_FLAGS_1, ida_netnode.atag, ida_ida.IDI_ALTVAL|ida_ida.IDI_SCALAR),
            # Describe ident
            ida_ida.idbattr_info_t("MEX ident",  MEX_OPTION_IDENT_IDX, 0,            0,           ida_netnode.stag, ida_ida.IDI_SUPVAL|ida_ida.IDI_CSTR),
        ]

        # The descriptions are ready. Now create an instance of the standard helper
        # class to be passed to the kernel, and the kernel will take care of organizing
        # the merge process for them.

        # helper instance name
        self.modmerger_helper = ida_merge.moddata_diff_helper_t(
            "Sample merge data", # label: prefix for the attribute names, e.g. "Sample merge data.MEX flag 0"
            MEX_NODE_NAME,       # netnode name for idpopts_info and merge_node_info
            self.idpopts_info)   # field descriptions

        # Merge handler created from idbattr_info_t with the MH_UI_NODETAILS UI hint.
        # Its linear_diff_source_t::get_diffpos_name() method returns NAME constructed as following:
        #   * prefix if any, f.e. "Sample merge data", concatenated with "."
        #   * add item name, f.e. "MEX flag 0"
        #   * add ": "
        #   * add item value
        # You might have noticed this when checking the mex1 and mex2 examples
        #
        # In this case we can improve UI look if add MH_UI_COLONNAME UI hint to merge_handler_params_t.

        #-------------------------------------------------------------------------
        # 2. Data specific to a particular address.
        #
        # To improve UI look for this merge handler we can create a subclass of merge_node_helper_t type.
        class node_helper_t(ida_merge.merge_node_helper_t):
            def __init__(self):
                ida_merge.merge_node_helper_t.__init__(self)
            def print_entry_name(self, tag, ndx, _):
                """ is called from print_diffpos_name() """
                if  tag != ord(MEX_EA_TAG):
                    return ""
                # get item value
                eanode = ida_netnode.netnode(MEX_NODE_NAME)
                ea = ida_nalt.node2ea(ndx)
                mark = eanode.supstr_ea(ea, MEX_EA_TAG)
                # prepare NAME
                ea_nice_name = ida_merge.get_ea_diffpos_name(ea)
                return "%s,%s" % (ea_nice_name, mark)
            def get_column_headers(self, _1, tag, _2):
                """ column headers for chooser """
                return ["Address", "Mark"] if tag == ord(MEX_EA_TAG) else []
        self.node_helper = node_helper_t()

        # We describe how the data is stored in a netnode.
        self.merge_node_info = [
            ida_merge.merge_node_info_t(
                "Function marks",       # label of the merge handler, e.g. "Plugins/Merge example 3/Function marks"
                MEX_EA_TAG,             # netnode tag
                ida_merge.NDS_MAP_IDX|ida_merge.NDS_IS_STR,
                                        # netnode value descriptors and modificators, see \ref nds_flags_t
                self.node_helper
            ),
        ]

        #-------------------------------------------------------------------------
        # Now we should combine together in function create_merge_handlers.
        # This function will be called on processor_t::ev_create_merge_handlers event.
        # As a result, two merge handlers with labels
        #   "Plugins/Merge example 3/Database attributes"
        #   "Plugins/Merge example 3/Function marks"
        # will be created.
        mhp = ida_merge.merge_handler_params_t(
            md,                                  # merge handler data
            "Plugins/IDAPython merge example 3", # Label of the merge handler
            ida_merge.MERGE_KIND_NONE,           # allocate a merge kind
            ida_merge.MERGE_KIND_END,            # insert to the end of handler list
            ida_merge.MH_UI_COLONNAME)           # Create multi-column chooser, split diffpos names using ':'

        # create merge handler for idbattr_info_t, it will use MH_UI_COLONNAME.
        # MH_UI_COLONNAME will ensure that the diffpos names will be split by ':'
        # and displayed as separate columns in a chooser. Multi-column choosers
        # are easier to work with for the user.
        ida_mergemod.create_std_modmerge_handlers(mhp, self.modmerger_helper)

        # create merge handlers for merge_node_info_t, it will use MH_UI_NODETAILS.
        mhp.mh_flags = (ida_merge.MH_UI_COMMANAME  # Create multi-column chooser, split diffpos names using ','
                      | ida_merge.MH_UI_NODETAILS) # do not display the detail pane
        ida_merge.create_nodeval_merge_handlers(
              None,
              mhp,
              MEX_NODE_NAME,
              self.merge_node_info)


# --------------------------------------------------------------------------
class mex3_plugin_t(ida_idaapi.plugin_t):
    flags = ida_idaapi.PLUGIN_MULTI | ida_idaapi.PLUGIN_MOD
    wanted_name = "IDAPython: Merge example 3"
    comment = "IDAPython: An example 1 how to implement IDA merge functionality"
    wanted_hotkey = ""
    help = ""
    def init(self):
        return mex_ctx_t()
    def term(self):
        pass
    def run(self, arg):
        pass
def PLUGIN_ENTRY():
    return mex3_plugin_t()


repository: JPCERTCC/GobRAT-Analysis
file: DecryptTool/Decrypt_GobRAT.py
wanted_name: DecryptGobRAT
comment: Decrypt GobRAT strings.
created_at: 2023-11-27 00:33:16+00:00
pushed_at: 2023-12-21 01:00:24+00:00
url:
https://github.com/JPCERTCC/GobRAT-Analysis/blob/064630f6c90894f1e2bd5b296f5116774e2e2fe3/DecryptTool/Decrypt_GobRAT.py

content:
#---------------------------------------------------------------------------------
# 202301030 JPCERT/CC masubuchi
# IDA Version 8.4
#---------------------------------------------------------------------------------
try:
    import idaapi
    import idautils
    import ida_funcs
    import ida_bytes
    import ida_nalt
    import ida_search
    import ida_idaapi
    import idc
except ImportError:
    pass

try:
    from Crypto.Cipher import AES
    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_OAEP
    from Crypto.IO import PEM
    from Crypto.Util import Counter
except ImportError:
    pass

import binascii

def read_ptr(ea):
    if idaapi.get_inf_structure().is_64bit():
        return idaapi.get_qword(ea)
    return idaapi.get_dword(ea)


def read_string(ea):
    size = ida_bytes.get_max_strlit_length(ea, ida_nalt.STRTYPE_C)
    strings_bytes = ida_bytes.get_strlit_contents(ea, size, ida_nalt.STRTYPE_C)
    print(strings_bytes)


def dbg_priHex(byte):
    print('[*] 0x{:02X}'.format(byte))


def dbg_priHex_bytes(bytes):
    print('[*] 0x', end="")
    for byte in bytes:
        print('{:02X}'.format(byte), end="")
    print("\t", end="")
    for byte in bytes:
        print('{}'.format(chr(byte)), end="")
    print("")


def get_list_of_xrefAddr_from_funcAddr(functionAddr, enablePrint=True):
    print("[*] FUNC address: {:02X}" .format(functionAddr))

    Xref_functionAddr = []
    for addr in idautils.CodeRefsTo(functionAddr, 0):
        Xref_functionAddr.append(addr)
    print("[*] XREF count: {}".format(len(Xref_functionAddr)))
    if enablePrint == True:
        for addr in Xref_functionAddr:
            print("[*] XREF Addr: 0x{:02X}".format(addr))

    return Xref_functionAddr
    

'''
How to use
    addr   : specified address
    offset: number of offset instruction from addr
    addrF  : get address
    opNum  : get string(opcode) or value(operand)
                0:opcode |  1:operand1 | 2:operand2  | 3:operand3
    typeF  : get type specified opNum
    dbgF   : debug print
'''
def get_op_type_addr_from_addr(addr, offset=-1, opNum=0, addrF=False, typeF=False, dbgF=False):
    target_addr = addr
    if offset < 0:
        for x in range(offset * -1):
            target_addr = idc.prev_head(target_addr)
    elif offset > 0:
        for x in range(offset):
            target_addr = idc.next_head(target_addr)

    if dbgF: 
        print("[*] XREF target instruction: 0x{:02X} {}" 
            .format(target_addr, idc.generate_disasm_line(target_addr, 0) ))
    if addrF:
        return target_addr

    if opNum == 0: 
        opcode = idc.print_insn_mnem(target_addr)
        return opcode
    elif opNum == 1 or opNum == 2 or opNum == 3: 
        oprValue = idc.get_operand_value(target_addr, opNum -1)
        oprType = idc.get_operand_type(target_addr, opNum -1)
        if typeF:
            return oprType
        else:
            return oprValue
    else:
        print("ERROR: Check arguments! into  get_opcode_oprand_addr_in_NumOfPrev()")


def ascii_to_bytes(inputstr):
    return inputstr.encode('utf-8')


def getAddr_from_FunctionName(SearchFuncName):
    for segea in idautils.Segments():
        for funcea in idautils.Functions(segea, idc.get_segm_end(segea)):
            functionName = ida_funcs.get_func_name(funcea)
            if functionName == SearchFuncName:
                return funcea
    print("Error Not Found function: {}".format(SearchFuncName))
    return False


def find_func_byName(functionname, notprint = False):
    EncFuncAddr = getAddr_from_FunctionName(functionname)
    if EncFuncAddr != False and notprint == False:
        dbg_priHex(EncFuncAddr)
    return EncFuncAddr


def decrypt_AES_from_key(enc, key, iv):
    ctr = Counter.new(128, initial_value=int.from_bytes(iv, byteorder='big'))

    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
    return cipher.decrypt(enc)


def decrypt_gobrat(EncDATA):
    AES_IV = ascii_to_bytes("12345678abcdefgh")
    AESkey = b"\x05\x0C\xFE\x37\x06\x38\x07\x23\x43\x38\x07\x19\x3E\x03\xFE\x2F"

    bindata = decrypt_AES_from_key(EncDATA, AESkey, AES_IV)

    print(bindata)


def findBin_on_range_from_addr(Addr, SearchBytes, Range = -1):
    target_addr = Addr

    if Range < 0:
        for x in range(Range * -1):
            target_addr = idc.prev_head(target_addr)

        hit_addr = ida_search.find_binary(target_addr, Addr, SearchBytes, 0, idaapi.SEARCH_DOWN | idaapi.SEARCH_CASE)
        if hit_addr != idc.BADADDR: 
            return hit_addr

    elif Range > 0:
        for x in range(offset):
            target_addr = idc.next_head(target_addr)

        hit_addr = ida_search.find_binary(Addr, target_addr, SearchBytes, 0, idaapi.SEARCH_DOWN | idaapi.SEARCH_CASE)
        if hit_addr != idc.BADADDR: 
            return hit_addr

    return False

def extract_bytes_from_addr(addr, size):
    bytesdata = idaapi.get_bytes(addr, size)
    if bytesdata != ida_idaapi.BADADDR:
        return idaapi.get_bytes(addr, size)
    return False 


def get_ampersand_var(addr):
    if addr != ida_idaapi.BADADDR:
        if idaapi.get_inf_structure().is_64bit():
            return idaapi.get_qword(addr)
        return idaapi.get_dword(addr)
    return False


def get_ptr_var(addr, size):
    paddr = 0x0
    if idaapi.get_inf_structure().is_64bit():
        paddr = idaapi.get_qword(addr)
    else:
        paddr =  idaapi.get_dword(addr)
    if paddr != idc.BADADDR: 
        value = extract_bytes_from_addr(paddr, size)
        return value
    return False    


def wrap_decrypt():
    print('--Start!')
    EncFuncAddr = find_func_byName("aaa.com_bbb_mecrypt.AesEncrypt")

    xref_list = get_list_of_xrefAddr_from_funcAddr(EncFuncAddr)
    for xrefAddr in xref_list:
        dbg_priHex(xrefAddr)
        funcRef = ida_funcs.get_func(xrefAddr)
        xrefAddr

        # decrypt function itself
        if funcRef.start_ea == EncFuncAddr:
            print("[+] Skip decrypt function")
            continue

        # C2 strings
        hitAddr = findBin_on_range_from_addr(xrefAddr, "4C 8B 0D ?? ?? ?? ??", Range = -30)
        if hitAddr != False:
            pEncDATA = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
            EncDATA_size = get_ptr_var(pEncDATA, 2)
            if EncDATA_size != False:
                EncDATA_size_int = int.from_bytes(EncDATA_size, byteorder='little', signed=False) >> 0x8
        
                ptr_EncData = get_ampersand_var(pEncDATA) + 2

                EncDATA = extract_bytes_from_addr(ptr_EncData, EncDATA_size_int)
                dbg_priHex_bytes(EncDATA)
                decrypt_gobrat(EncDATA)
                continue



        # strings pattern 0
        hitAddr = findBin_on_range_from_addr(xrefAddr, "E8 ?? ?? ?? ?? 48 B9 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 08 48 B9 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 48 08", Range = -15)        
        if hitAddr != False:
            EncdataVal01 = get_op_type_addr_from_addr(hitAddr, offset=1, opNum=2)
            EncdataVal01_bytes = EncdataVal01.to_bytes(8,'little')

            hitAddr = findBin_on_range_from_addr(xrefAddr, "48 B9 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 48 08", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02_bytes = EncdataVal02.to_bytes(8,'little')
        
                hitAddr = findBin_on_range_from_addr(xrefAddr, "48 B9 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 48 10", Range = -15)
                if hitAddr != False:
                    EncdataVal03 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                    EncdataVal03_bytes = EncdataVal03.to_bytes(8,'little')

                    hitAddr = findBin_on_range_from_addr(xrefAddr, "48 B9 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 48 18", Range = -15)
                    if hitAddr != False:
                        EncdataVal04 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                        EncdataVal04_bytes = EncdataVal04.to_bytes(8,'little')

                        hitAddr = findBin_on_range_from_addr(xrefAddr, " C7 40 20", Range = -15)
                        if hitAddr != False:
                            EncdataVal05 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                            EncdataVal05_bytes = EncdataVal05.to_bytes(4,'little')

                        decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes + EncdataVal03_bytes + EncdataVal04_bytes + EncdataVal05_bytes)
                        continue
            continue
        
        # strings pattern 1
        hitAddr = findBin_on_range_from_addr(xrefAddr, "E8 ?? ?? ?? ?? 48 B9", Range = -15)       
        if hitAddr != False:
            EncdataVal01 = get_op_type_addr_from_addr(hitAddr, offset=1, opNum=2)
            EncdataVal01_bytes = EncdataVal01.to_bytes(8,'little')

            hitAddr = findBin_on_range_from_addr(xrefAddr, "66 C7 40 08", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02 = EncdataVal02  & 0xffff
                EncdataVal02_bytes = EncdataVal02.to_bytes(2,'little', signed=False)
                
                hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 0A", Range = -15)
                if hitAddr != False:
                    EncdataVal03 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                    EncdataVal03_bytes = EncdataVal03.to_bytes(1,'little')

                    decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes + EncdataVal03_bytes)
                    continue
                continue

            hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 08", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02_bytes = EncdataVal02.to_bytes(1,'little')
                
                decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes)
                continue


            hitAddr = findBin_on_range_from_addr(xrefAddr, "C7 40 08", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02 = EncdataVal02  & 0xffffffff
                EncdataVal02_bytes = EncdataVal02.to_bytes(4,'little')
                
                hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 0C", Range = -15)
                if hitAddr != False:
                    EncdataVal03 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                    EncdataVal03_bytes = EncdataVal03.to_bytes(1,'little')

                    decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes + EncdataVal03_bytes)
                    continue
                continue


        # strings pattern 2
        hitAddr = findBin_on_range_from_addr(xrefAddr, "E8 ?? ?? ?? ?? C7", Range = -15)        
        if hitAddr != False:
            EncdataVal01 = get_op_type_addr_from_addr(hitAddr, offset=1, opNum=2)
            EncdataVal01_bytes = EncdataVal01.to_bytes(4,'little')

            hitAddr = findBin_on_range_from_addr(xrefAddr, "66 C7 40", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02_bytes = EncdataVal02.to_bytes(2,'little')
        
                hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 06", Range = -15)
                if hitAddr != False:
                    EncdataVal03 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                    EncdataVal03_bytes = EncdataVal03.to_bytes(1,'little')
            
                    decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes + EncdataVal03_bytes)
                    continue

                hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 0A", Range = -15)
                if hitAddr != False:
                    EncdataVal03 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                    EncdataVal03_bytes = EncdataVal03.to_bytes(1,'little')
            
                    decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes + EncdataVal03_bytes)
                    continue

                decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes)
                continue


            hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 04", Range = -15)
            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02_bytes = EncdataVal02.to_bytes(1,'little')
        
                decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes)
                continue

            decrypt_gobrat(EncdataVal01_bytes)
            continue


        # strings pattern 3
        hitAddr = findBin_on_range_from_addr(xrefAddr, "E8 ?? ?? ?? ?? 66 C7", Range = -15)        
        if hitAddr != False:
            EncdataVal01 = get_op_type_addr_from_addr(hitAddr, offset=1, opNum=2)
            EncdataVal01_bytes = EncdataVal01.to_bytes(2,'little')

            hitAddr = findBin_on_range_from_addr(xrefAddr, "C6 40 02", Range = -15)

            if hitAddr != False:
                EncdataVal02 = get_op_type_addr_from_addr(hitAddr, offset=0, opNum=2)
                EncdataVal02_bytes = EncdataVal02.to_bytes(1,'little')
        
                decrypt_gobrat(EncdataVal01_bytes + EncdataVal02_bytes)
                continue
            else:
                decrypt_gobrat(EncdataVal01_bytes)
                continue


def Enable_addr_into_Function_quickly(checkAddr, FuncName):
    chkfuncname = idaapi.get_func_name(checkAddr)
    if chkfuncname == FuncName:
        return True
    else:
        return False


def find_version_x86_64():
    print("Start!")
    EncFuncAddr = find_func_byName("runtime.convTstring", notprint=True)
    xref_list = get_list_of_xrefAddr_from_funcAddr(EncFuncAddr, enablePrint=False)
    for xrefAddr in xref_list:
        funcname = "main.main"
        if Enable_addr_into_Function_quickly(xrefAddr, funcname) == True:

            argAddr = findBin_on_range_from_addr(xrefAddr, "48 8B 05 ?? ?? ?? ?? 48 8B 1D", Range = -3)
            if argAddr != False:
                ptr_version = get_op_type_addr_from_addr(argAddr, offset=0, opNum=2)
                dbg_priHex(ptr_version)

                addr_version = read_ptr(ptr_version)
                dbg_priHex(addr_version)

                read_string(addr_version)

    print("Finish!")


def main():
    find_version_x86_64()
    find_func_byName("aaa.com_bbb_mecrypt.AesEncrypt")
    wrap_decrypt()


if __name__ == '__main__':
    main()


class DecryptGobRAT_Plugin(idaapi.plugin_t):
    flags = idaapi.PLUGIN_DRAW
    comment = "Decrypt GobRAT strings."
    help = "Decrypt GobRAT"
    wanted_name = "DecryptGobRAT"
    wanted_hotkey = "" # = "Alt-F10"

    def init(self):
        return idaapi.PLUGIN_KEEP

    def run(self, arg):
        main()
        return

    def term(self):
        pass


def PLUGIN_ENTRY():
    return DecryptGobRAT_Plugin()


repository: Donaldduck8/IDA-Scripts-and-Tools
file: donald_ida_plugin.py
description: A collection of plug-ins I've developed for IDA Pro.
wanted_name: Donald's Plugin
comment: Donald's IDA Tools Plugin
created_at: 2023-08-02 10:06:40+00:00
pushed_at: 2024-04-09 16:47:04+00:00
url:
https://github.com/Donaldduck8/IDA-Scripts-and-Tools/blob/4ec79fdcd2a2a43348282ee427944ed8a7593a57/donald_ida_plugin.py

content:
import ida_kernwin
import ida_idaapi
import donald_ida_utils
import idaapi
import ida_ida

class OpenSyncedDisassemblyViewActionHandler(ida_kernwin.action_handler_t):
    """Action handler for opening a synchronized flat disassembly view."""

    def __init__(self):
        ida_kernwin.action_handler_t.__init__(self)

    def activate(self, ctx):
        donald_ida_utils.open_synced_disassembly_view()

    def update(self, ctx):
        return ida_kernwin.AST_ENABLE_FOR_IDB
    

class OpenManageAutomaticCommentsViewActionHandler(ida_kernwin.action_handler_t):

    def __init__(self):
        ida_kernwin.action_handler_t.__init__(self)
    

class DonaldPlugin(ida_idaapi.plugin_t):
    """IDA Plugin to integrate my personal tools into the UI."""

    # These fields are necessary for whatever reason
    flags = ida_idaapi.PLUGIN_KEEP
    comment = "Donald's IDA Tools Plugin"
    help = ""
    wanted_name = "Donald's Plugin"
    wanted_hotkey = ""

    def __init__(self):
        self.actions = []

    def init(self):
        sync_disasm_action_icon = ida_kernwin.load_custom_icon(data=sync_disasm_action_icon_data, format="png")

        # Create an action
        action = ida_kernwin.action_desc_t(
            "donald_plugin:open_synced_disassembly_view",
            "Disassembly (synced)",
            OpenSyncedDisassemblyViewActionHandler(),
            "Ctrl+4",
            "Open a disassembly text view that is synchronized with the current view",
            sync_disasm_action_icon,
        )

        self.actions.append(action)

        if not ida_kernwin.register_action(action):
            print(f"Failed to register {action.name} action")
        if not ida_kernwin.attach_action_to_menu("View/Open subviews/Disassembly", action.name, ida_kernwin.SETMENU_APP):
            print(f"Failed attaching {action.name} to menu.")

        return ida_idaapi.PLUGIN_KEEP

    def run(self, arg):
        pass

    def term(self):
        for action in self.actions:
            ida_kernwin.unregister_action(action.name)


def PLUGIN_ENTRY():
    return DonaldPlugin()

if __name__ == "__main__":
    pass


repository: mayl8822/IDA
file: search_google.py
description: Some useful ida script plugin
url: https://github.com/mayl8822/IDA/blob/4a5cc13fbb0387041f287193f776487b7ceaab56/search_google.py
wanted_name: Search Google for it
comment: Search Google for it
created_at: 2018-02-28 06:26:36+00:00
pushed_at: 2018-03-01 09:51:43+00:00
content:
# -=-=-=-=-=-=-=-=-=- 
#  search_google.py
# -=-=-=-=-=-=-=-=-=-
# IDAPython plugging adding "Search Google for..." to right click context menu
# Created By Omri Ben-Bassat of Intezer Labs
# Visit us at http://intezer.com
#

import os
import idaapi

highlight = ""

google_icon_data = "".join(["\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x01\x00\x00\x00\x01\x00\x08\x06\x00\x00\x00\x5C\x72\xA8\x66\x00\x00\x1F\xA1\x49\x44\x41\x54\x78\xDA\xED\x9D\x07\x54\x54\x67\xDA\xC7\xD5\xB4\x35\x9A\x6C\x92\x6F\xE3\x6E\xB2\xD9\xCD\x96\x6C\xB2\xBB\xC9\xF7\x65\x53\x8D\xC6\x44\x63\xC3\x8E\x0D\x50\x8A\x22\x20\x0A\x02\x52\x54\x14\x81\x91\x8E\x74\x10\x50\x8A\x0D\x44\xA5\x49\x11\x01\x05\x19\xBA\x5D\x50\xB1\xC4\xAE\xB1\x21\x6D\x86\x19\xA6\x01\xF3\x7E\xF7\x6A\x30\x6E\x6C\x80\xDC\x99\x7B\xEF\xFC\x7F\xE7\xFC\x0F\xBB\x39\x7B\x4E\xCE\xCE\xFB\xFC\x9F\xFB\xBE\xCF\xF3\x96\x7E\xFD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2F\x20\xFD\xFA\xF5\x27\x06\x06\x2F\xA8\x43\x9D\x06\x36\xAC\x5D\xFB\x1A\xFD\x9F\xF1\xAB\x00\xC0\x41\x23\x4B\xE2\xA3\x3F\x6E\x8D\x09\xB5\x14\x87\xF9\x05\x8A\x03\xDC\x77\x8A\x04\x2B\xCA\x9B\x5D\x97\x9C\x6B\x5A\x62\x7E\xA7\x79\xB1\xA9\xA8\xC9\x7C\xA6\xAC\xC1\x70\xB2\xEA\xEE\xB4\x1F\x3A\xEF\xEA\x0D\x27\x77\xC7\x0E\x25\x77\xC7\x7C\xF5\xA8\xC6\x7F\x43\xEA\x27\x7D\xA7\xAE\x9F\x3A\xAA\xF3\xEE\xCC\xF1\x1D\x0D\x26\xD3\x15\xCD\xD6\x26\xA2\x66\x7B\x8B\x5B\xCD\xCB\xED\x7E\x6C\x76\x77\x3E\x24\xF2\x75\xCB\x6A\x0D\xF2\x09\x12\x47\x05\x99\x4B\xD6\x05\xFC\x2F\x12\x07\x00\x1A\x40\x1D\x1A\x3A\xB0\x35\x26\x64\xBA\x38\xD8\x2B\xB6\x65\xB5\x73\x75\x8B\xD3\xA2\x9F\x9A\xCC\x67\xC9\xEA\x27\x7F\xAF\x7E\xAC\x99\x35\x25\x2A\x69\x34\x1A\x4F\x53\xB4\x38\x58\xDD\x6C\x71\x77\xAC\x12\x07\xAE\x59\x2F\x0E\xF3\x37\x13\x85\x0A\xDE\xC2\xA8\x01\xD0\x9B\xAF\x7A\x5C\xDC\x4B\xAD\xD1\x61\xB3\xC5\x81\x82\xED\x4D\xCB\x16\x5F\xA0\xBF\xE0\x77\xF5\x86\x11\xAD\x1A\xBD\xA7\xA2\x66\x19\x8D\x26\xFA\xF2\x26\xA7\xC5\xE7\xC5\xBE\xAB\x76\x8A\x43\x7C\xCD\xEB\x05\x82\xC1\x18\x5D\x00\x7E\x6D\x78\x81\xE0\x37\xAD\xD1\x41\x36\x62\x81\x6B\x49\x93\x8D\x79\x63\xFD\x14\x2D\x7F\xD5\x19\x52\xC3\x84\x6F\x49\x83\xD5\x9C\x66\x91\xC7\xB2\xFD\xA2\x10\x1F\xFB\x46\x81\xFD\xEB\x18\x7D\xA0\x93\x50\x6B\xF6\x91\x62\x7F\xCF\x1D\x2D\xF6\x96\xB7\xF8\x6A\xF8\x67\x8A\x9A\xD5\x34\x2E\x36\x6D\x10\x7B\xAD\x4C\x6B\xF5\xF3\xF8\x8E\xAE\x67\x20\x32\x00\x6F\x8B\x75\xAD\xB1\x11\xB3\x44\x02\xD7\xD2\x26\xD3\x19\x72\x9D\x34\xFC\x33\xD4\x38\x67\x8A\xA2\xD9\xD5\xFE\x90\x38\xD0\x73\x3E\x11\xF4\x1B\x80\xA8\x01\x9C\x47\x1C\x1B\x3E\xAD\xC5\x63\xD9\x81\x86\xB9\x53\x55\x30\x79\x0F\x34\x4B\x4F\xD5\xE2\xEA\x50\xD9\xEA\xE7\x3E\x13\x33\x03\xC0\x2D\xD3\x27\x86\x7F\x24\x0E\xF0\x48\x6F\x34\x37\x68\x83\x99\xFB\x66\x66\xD0\xE2\xE1\xB2\x5B\xE2\xB7\xEA\x13\x44\x17\x60\xE7\x14\x3F\xCD\xE0\x85\xD6\xF0\x00\x77\x7A\x4D\x4F\xB7\xC6\x60\x5C\x26\x3A\x0B\x5F\x93\xA6\xC5\x66\x37\xC5\x01\x9E\xCB\xB1\xFF\x00\xB0\x82\xB6\xC4\x75\xEF\xD2\x5F\xFB\x06\xE3\x29\x4A\x98\x54\x83\x1D\x05\xA3\x09\x4A\xB1\x60\xC5\x4E\x89\xC0\x65\x08\xA2\x10\x68\x1C\xC9\xFA\xF0\x51\x22\xB7\xA5\xB5\x3A\x5B\xC1\x67\x89\xE8\xDF\x9F\xAA\x15\x54\x49\xBC\xDD\x3F\x46\x54\x02\xC6\x91\xC6\x85\x4F\x6C\x5E\xB6\xE4\xD2\x13\xB7\xD3\x42\x5A\x6B\x29\xB6\x38\x2F\x3A\x41\x6D\x55\xFE\x1A\x51\x0A\xFA\x9C\xD6\xB8\xF0\xE9\x2D\xCE\x8B\xAF\xD1\xEB\x50\x18\x8E\xC5\x1A\x47\xED\x40\x74\x5E\x74\xB2\xC5\xDB\xFD\x33\x44\x2D\x78\xFE\xA9\x7E\x6C\xD8\xE8\x16\xC7\x85\xD7\x61\x2E\x0E\xCE\x08\x96\x2D\x39\xD0\xEC\xE3\xF2\x3E\xA2\x18\xF4\x18\x71\xFC\xBA\x0F\x45\xAB\x9D\x6A\x38\xB7\x07\x1F\x7A\xA4\x46\x20\xF2\x70\xC9\xBA\x69\x6D\xFD\x2A\xA2\x1A\x3C\x93\xE6\xB8\xB8\xDF\xB6\xF8\xBA\xED\xA1\x8E\xC4\xA2\xB8\xC7\xB3\xAE\x01\x55\x1F\x10\x60\x53\x11\x78\xF2\x3A\x9F\xEA\xE3\x37\x18\x4D\xC1\x8E\x3D\x1E\xAB\xC9\xDA\xF8\x36\x75\xEE\xE0\x5B\x44\x3B\xF8\xA5\xB2\xBF\x61\xDD\xE7\xF4\xF9\x7A\x18\x44\x57\xEA\x03\xC3\x49\x8B\xDB\xD2\x3D\xD7\x9D\x66\x0F\x44\xF4\xEB\x30\xEA\xC8\xC8\x57\x44\x7E\xEE\xBB\xB4\x7E\xA9\x06\xA4\x9D\x65\x81\xC9\x54\x99\x28\x40\x60\x0C\x27\xE8\xE2\x57\x9F\xEA\xE7\x37\x59\x1A\x4A\x61\x04\x5D\xDF\x5E\x3C\x94\x88\x56\xD9\x97\xDD\x76\x71\x19\x04\x57\xE8\x00\xF4\x9E\x7D\x91\xBF\x47\x66\xC3\xC4\x6F\x11\xFC\xD0\x2F\x07\x8E\x4C\xA7\xC9\xA8\xEB\xD6\xA6\xC2\x21\x7C\x6E\xED\x6D\x08\x1F\xD6\xB8\xC8\xAC\x19\x01\x0F\x3D\x69\xEF\x40\xB3\xC7\xB2\x54\xDC\x45\xC0\xC7\x0A\x7F\xA8\x6F\x04\xF6\xED\x43\xDD\xEB\x14\x98\xDC\xA6\x6A\x03\x7F\x83\x6B\x78\x40\x63\x72\xE4\xEB\x22\x37\xC7\x53\x08\x6C\xA8\x47\x9A\x39\xBE\x5D\x1C\x20\xB0\x80\x83\xB8\xFC\xD5\x8F\x8B\x1C\xD9\xB4\xC0\x10\x97\x72\x40\xBD\x3E\x57\x20\x16\x2C\xDB\x8E\xCD\x43\x5C\x5C\xEF\x47\x04\xF8\x63\x37\x1F\xD4\x27\x4B\x02\x7B\xAB\x0B\xCD\x81\xAE\xBF\x85\xAB\xB8\x50\xE5\xA7\xB2\xB5\xD8\x6B\x55\x11\x02\x17\xEA\xD3\x24\x30\x6F\x76\xAB\x24\x48\xF0\x7F\x70\x18\x8B\x69\xD9\xBC\xF9\x8D\x26\x17\xDB\x2B\x08\x58\x88\x11\x4D\x1F\xD3\x21\x09\xF5\x35\x80\xD3\x58\x88\x24\x31\xF6\x93\x26\x8B\x39\x12\x04\x2A\xC4\xE8\xE9\xC2\x89\xDF\xAA\x45\x01\x1E\xEE\x70\x1C\x9B\x8A\x7D\xEB\x23\xF5\xEF\x1A\x4E\x6A\x47\x80\x42\x9A\xBA\x9C\x54\xE4\xBD\x6A\x13\x9C\xC7\x06\xF3\xC7\x86\x59\xD5\xEB\xFF\x80\x62\x1F\xA4\x71\x35\xAF\x76\x29\x84\x03\xB5\x69\xFE\xA8\xB5\xEE\x0D\x93\xBE\x43\x30\x42\x5A\x51\x6B\xB0\xEF\x1E\xB8\x50\x5B\x6D\xBE\x50\xDF\x68\xDC\xBF\x0F\x69\x4B\xD4\x79\x92\x0A\xB8\x50\x5B\x5F\xFE\x20\xAF\x6D\xB8\x9C\x13\xD2\x96\xC4\x3E\x6E\x47\xE1\x42\x6D\x99\x3F\x78\x4D\x32\x82\x10\xD2\x9A\xF9\xBD\x5D\x4F\x50\xCF\xB9\xE3\xB0\x90\x56\xCC\x1F\xE2\xBD\x05\x41\x08\x69\x6D\xDA\xBF\x66\xC5\x29\x98\x5F\x4B\x88\x42\x7C\x13\x31\xED\x87\xB4\x66\x7E\x81\x6B\x1D\xCC\xAF\xCD\x82\x1F\xCC\x0F\x69\x49\x2D\x82\xE5\x27\x61\x7E\xAD\xB5\xFA\x82\x56\xE2\x6E\x7E\x48\x6B\x5F\x7E\x2F\xD7\x1A\x98\x5F\x4B\x48\xD6\x87\x99\xE0\xC2\x4E\x48\x9B\xD5\x7E\x98\x5F\x5B\xE6\x8F\x8F\x1A\x4D\x1D\xBE\xE8\x44\x20\x42\x5A\xD9\xE5\xE7\xBD\xF2\x08\xEE\x01\xD0\xD6\xB4\x7F\x73\xD4\x3F\x1B\xE6\x4E\xC5\x03\x1D\x10\xCC\xAF\x6B\x90\xB8\xB8\x57\x9B\x17\x9B\x8A\x10\x88\x90\x76\xFA\xFC\x2B\x8F\xC1\xFC\x5A\xA4\xC5\xCD\xF1\x34\x02\x11\xD2\x4A\xC1\x0F\xE6\xD7\x72\xBB\x6F\xED\x9A\x1D\x08\x44\x48\x2B\xE6\xA7\x0B\x7E\x30\xBF\x16\x8B\x7E\xB1\xE1\x0E\x38\xDC\x03\xC1\xFC\x3A\x88\x74\x73\xFC\x7F\x50\xF1\x67\xE8\xC5\x9B\x99\xE3\x48\xE3\x02\x03\x55\x8B\xA3\x95\xB8\x65\xA5\xC3\xAD\x66\xC1\x8A\xF3\x22\x7F\xF7\x9A\xD6\x40\xEF\x6A\x6A\x77\x65\x99\x38\xC4\x57\x28\x0A\xF6\x2E\xBD\xF7\xDF\xFD\xDC\x8F\x35\x0B\x5C\xCF\x89\x56\x2D\xBD\xDE\xE4\x64\xDD\xD2\x68\x39\x57\x71\x77\xF6\x04\x5E\xB7\x61\xC5\x30\xBF\x96\x8B\x7E\x69\x69\x2F\x37\xD9\xCE\xC7\x6B\x3D\xCF\x2B\xC3\x89\xEA\x26\x67\xEB\x46\x71\x80\xE7\x61\xC9\x86\xB0\x44\x69\xEA\xB6\x85\xCA\x43\x15\x1F\x13\x42\x5E\x78\xAE\xF1\x21\xA4\xBF\xAC\xEE\xE8\x9F\x65\xA9\xDB\x8C\xA4\xEB\x23\x22\x45\x41\xDE\xA5\xCD\xCB\x97\xDC\x6A\x98\x37\xB3\x9D\xEB\xBB\x33\x51\xF0\x63\x01\x22\x9F\xD5\x25\x30\x70\xCF\xD5\x60\x36\xB3\xBD\xC5\xD3\xE5\x9C\x24\x26\x24\x5E\x9E\x99\x3A\x9A\x36\xAA\xA6\xC7\x4E\x51\x9C\xFF\x6F\x49\xC2\x3A\x1F\xB1\xAF\xDB\x61\xAA\x73\xD3\x46\xDF\xA3\xCF\x9D\x83\x3D\xAB\x8E\x63\x93\x0F\x1B\xD6\xFD\x63\x87\xC2\xD0\xDD\x11\x55\x1F\x69\xB2\xB3\x68\x11\x85\xF9\xED\x92\x67\x6E\x1F\xC7\xC6\xF1\x54\x14\x64\x7F\x24\x89\x0D\x8B\x11\xB9\xDA\x5F\x67\xF3\x9B\x0C\x98\xF6\xB3\xA1\xE2\xBF\x35\xFE\xC3\xBB\x86\x7A\x1D\x30\xF7\x33\x36\xA5\x2C\x32\x93\x48\x22\x02\xD2\x14\xBB\x76\xFD\x8B\x53\x4B\xBB\x8A\xBC\x37\x5B\x63\x43\xC3\x9A\x9D\x17\xDF\x61\xD3\x59\x0E\x14\xFC\xD8\xD2\xEF\x77\xB1\xBD\x06\x83\x3F\x41\x33\xC6\xAA\x45\x82\xE5\xC7\xDB\x52\x36\xF1\xE2\xB9\x6A\x69\xDA\xB6\xFF\x88\xFD\x3C\x8A\xEE\x1A\x4D\xEC\x80\xF9\x01\x75\xC2\x2F\x38\x18\x46\x7F\x4C\xC5\x7E\xFE\x0C\x65\x6B\x44\xC0\xF6\xD6\xDC\xDC\xDF\xF1\xB2\xE0\x9B\x9B\xFB\xAA\x64\x5D\x50\x4C\xA3\x85\x81\x1C\x05\x3F\x5D\x9D\xFA\x27\x27\x7E\x44\x7D\xE1\xD0\xF2\x7B\xF8\xD9\x29\x4B\x23\x59\x6B\x4C\x48\x08\x11\x0A\x5E\xD4\x89\xCE\x0F\x55\x7C\xA3\x6A\x05\xFE\xF4\xFF\x6F\xCD\xAC\xF9\x51\xF0\x63\x0D\xCD\xCB\x6C\xAF\xC3\xF4\x3F\x57\xF2\xE7\x4D\x57\xDE\x33\xBE\x8E\x06\x27\xD5\x02\x7E\xA1\x35\x32\x68\x5D\x83\xF1\x34\xC6\x1E\x75\xC1\xF6\x5E\x36\x55\xFD\xA3\x82\x02\x61\x7C\x7A\x8D\x3F\x4E\x2D\x0E\xF3\xD9\xA1\x4E\x4D\x1D\x88\xA8\xA0\x5A\xC1\x79\x29\x6F\x8A\x03\xD7\x14\x35\x4C\xFE\x1E\x6B\x7E\xDE\x9A\x3F\x33\x69\x88\xB6\x8B\x40\x5A\x17\xD5\x27\x17\x79\x2E\xAB\x95\xA7\x26\xFD\x15\x11\xF1\x28\xB2\x94\x8D\x23\x9A\x1C\xAD\xEF\xC2\xFC\x7C\xAC\xFA\x7B\xAF\xAA\xD6\xF5\x75\xBE\x34\x31\xDA\x0C\x91\xF0\x8C\x65\x01\x65\x5A\x49\x54\x68\x2C\xB5\x35\x5C\x8D\x3E\x3F\x4F\x90\x6E\x8A\xD5\xBB\xAB\x37\x5C\x37\xCD\x4F\xF5\xC0\xE9\xDD\x8E\x98\xEE\xF7\x8C\xB6\xED\x5B\xBF\x6C\xB4\x5F\xD0\x8C\x6A\x3F\x0F\x32\x7A\x93\x83\x65\xA3\x4E\x16\xF9\x4C\xF5\x95\x92\x8D\x31\xA6\x88\x82\x5E\xC6\xCE\xD1\xB8\x97\x44\x01\x82\xE2\xEE\x6E\x31\xBE\x67\x7E\x54\xFB\x59\xB6\xF6\x8F\x0E\xF1\xD7\xC9\x29\xBF\xAB\xFD\x65\xC9\xF6\x84\xDF\x23\x02\xFA\x60\x06\x99\x10\xB3\xE2\x59\xAD\x63\x4C\xFB\x59\x88\x3A\x3F\xFF\x15\xBA\xD5\xA5\x5B\x53\xFE\xE1\xA4\x35\xCC\x3F\x05\xA3\xDF\xC7\x05\xC2\x9D\x5B\xBE\x6F\xB2\x34\x94\xA3\xE0\xC7\x21\x5A\xC3\x03\x36\xE9\x94\xF9\x67\xE9\x75\x4A\xE3\xA3\x16\x62\xE4\x19\xAA\x0B\x64\x6F\x7F\xB7\xD1\xD1\xAA\x11\xE6\xE7\x00\x2D\x59\x9B\xDF\x68\x98\x33\x49\x67\xDA\x7E\x4D\x0B\x66\xCB\xDB\x36\xC7\x7F\x83\x91\x67\x78\x56\x59\x5D\x3D\xB0\xC9\xCD\xE9\x12\x0A\x7E\x6C\xFF\xFA\x07\x79\xE5\xE8\xCC\x1E\x7E\xBB\x05\xCD\x6D\xDB\x13\xDF\xC5\xA8\x6B\xA8\x38\x48\xED\x20\x94\xC4\x45\x04\xA1\xE0\xC7\xD6\x2C\x7D\x26\xEC\x9D\x26\x97\x71\x3A\xB1\xDF\x9F\xDA\xDA\x7C\x43\x9D\x9F\xFC\x3A\x46\x1D\x80\x9F\xE9\x38\x6D\x51\xD8\x5E\x32\x88\x48\x42\xA9\xAD\x9D\x63\xF9\x5C\xE9\x5F\x7A\x99\xD4\xA5\xBD\x8C\x11\x07\xA0\xEB\xEB\x7F\x3B\x76\x88\xB2\xF4\xDD\xCE\xF6\xE2\x97\x08\x2D\x45\xE6\x37\xA4\x61\xC2\x17\xFC\x33\xBF\x9B\xC3\x25\xBA\x4F\x8D\x11\x07\xE0\xE1\xAF\xFF\x19\xAB\xAC\x2E\xF3\x3F\xD0\xFE\x8F\x48\x93\x31\x7F\xAE\xFE\x12\xB9\x3A\x5C\xC5\x97\x1F\x80\x5F\x17\x67\x6E\xC6\xBD\xAA\xAA\xF8\x6B\xC7\x23\x09\x80\x56\xC9\xFF\x10\xB1\xFB\x77\xDC\x5F\xF3\xBB\xD8\xDC\xA1\x2B\xD1\x18\x6D\x00\x7E\x45\xE7\xB9\xA5\xEB\x1F\x6B\xFE\x87\x24\xDB\x4A\xD7\x05\xBE\xE4\xA6\xF9\x6D\xE6\x8B\x45\x85\xA9\x6F\x61\xA4\x01\x78\x0C\xAA\xEA\xCF\xDA\x9E\x95\x00\x68\xA9\x0A\x3F\x23\x8D\xD3\xBF\xE4\xD8\xBE\xFE\xE9\x2A\x45\x46\xCA\x3F\x30\xCA\x00\x3C\x6E\xED\x7F\xD1\x63\x71\x77\xCC\xFF\x20\x09\x08\xDF\x23\x2D\x4B\x46\x70\x23\x01\x50\x47\x53\xA5\x3B\xB6\x8C\xC7\x28\x03\xF0\xA4\xAF\xFF\xB1\x09\xD7\x7A\x92\x00\xEE\xD7\x05\x06\x11\x69\xE4\x28\x76\xB7\x0A\xA9\x93\x68\xD2\x84\x68\x0F\x8C\x30\x00\x4F\x40\x7D\x2D\xEC\xE3\xF6\x92\xC1\xA4\xC7\x09\xA0\xAB\x55\x98\x3D\x8C\x34\xE8\xB1\xB3\x55\x48\x1D\x47\x2D\xC1\x08\x03\xF0\xB4\xE9\xFF\x29\x8B\x3D\xBD\x35\xFF\x2F\xB3\x81\x0F\x49\x93\x19\xBB\x5E\x07\x6E\xA2\x0E\x9E\xA0\xD7\x0F\xC0\x53\x20\x44\x30\x40\x55\xF9\x4F\xE5\x73\x27\x00\x5A\xC2\x37\x49\xEB\x9A\x91\xEC\x48\x00\x33\xC7\x77\x4A\x52\xB7\xFD\x2F\x46\x18\x80\xA7\x16\xFF\x04\xD6\x7D\x62\xFE\x87\x24\x4F\xA6\x5A\x85\xE3\xB4\xDB\x25\x90\xC4\xAD\xF3\xC1\xE8\x02\xF0\x0C\xDA\x4F\xCC\x3C\xDD\xD7\x09\xE0\x5E\x97\x60\xDF\x7F\x48\xE3\x0C\x2D\xF5\xFB\x57\xBB\x5C\xC0\xC8\x02\xF0\xAC\xE2\xDF\xED\xA4\x41\xD4\xBE\x7F\x35\x13\x09\xE0\xFE\x92\xE0\x5D\xD2\xE2\xA8\xE1\x56\xA1\xC1\x84\x4E\x59\x46\xC6\xFB\x18\x5D\x00\x9E\x35\xFD\x3F\xBF\x42\xC0\x98\xF9\x1F\x9C\x23\x18\x48\xA4\xD1\x9A\x6B\x15\xD2\x2F\xDA\x62\x64\x01\xE8\xCE\xF4\xFF\xF8\xD4\x4B\x8C\x27\x80\xAE\x56\xE1\x6E\xEA\x54\xE1\xA4\x2F\x18\xAF\xFA\x63\x54\x01\xE8\x06\xA4\x3E\x6D\xB0\x52\xF8\x7B\xB5\xA6\x12\xC0\xFD\x56\xE1\x07\xA4\xC9\x7C\x18\x63\x97\x79\x4A\x93\x12\x26\x60\x64\x01\xE8\xCE\xF4\xFF\xC2\x2A\x37\x8D\x9A\xFF\x41\x12\x78\x83\x48\x7C\x47\xF5\xFD\x0B\xB2\x82\x95\xC7\x31\xAA\x00\x74\x37\x01\x9C\x98\x7D\x4A\x2B\x09\xA0\xAB\x55\xB8\x83\x6A\x15\x8E\xEF\x9B\x56\x61\xBD\xFE\x0F\x6A\xEA\xBD\xBE\x0F\x30\xAA\x00\x74\x67\xFA\x4F\x6D\xFE\x51\x56\xFC\xBD\x43\x9B\x09\xE0\x5E\xAB\xB0\xE8\x53\xD2\x34\xBB\x0F\xBE\xFE\xD4\xCB\xB4\x18\x55\x00\xBA\x5B\xFC\xBB\x12\x32\x5D\xDB\xE6\xFF\xA5\x55\xF8\x07\x22\x72\x79\x8E\x8B\x46\xA8\xA7\xBA\x25\x39\xDB\xF1\x82\x0F\x00\xDD\x9E\xFE\x9F\x5E\x94\xCB\x9A\x04\x70\xAF\x55\xF8\x1B\xD2\x16\x37\xB2\x57\xAD\x42\xB1\x9F\x07\xBE\xFE\x00\xF4\x04\xD5\xE1\xD1\x0D\xAC\x4A\x00\x3F\x4B\xB9\xE7\xAB\x1E\xB5\x0A\xEB\xA7\x8C\x54\xCB\x32\xB6\x61\xD3\x0F\x00\xDD\x5E\xFF\x53\xED\xBF\xF6\xD2\xFF\x21\x6C\x4C\x00\xF7\xBB\x04\x7F\x25\xCD\x96\xDD\x6B\x15\x8A\x3C\x56\x1C\xC3\x88\x02\xD0\x93\xE9\xFF\x45\xAF\xC5\xAC\x35\xFF\x83\x24\xF0\x3A\x91\x04\x3C\xE3\x54\xE1\xD8\xA1\xD4\xFD\x84\x71\x23\x30\xA2\x00\xF4\x68\xFD\x6F\xB9\x97\xF5\x09\xA0\xAB\x55\x98\x3A\xE2\x89\xA7\x0A\x9B\x1D\x17\xDE\xC1\x68\x02\xD0\xD3\xF5\xFF\x91\xD1\xF5\x5C\x49\x00\xF7\x5A\x85\xC5\x9F\x90\x26\xC3\xAF\x1F\xB3\xE7\x3F\x4C\x80\xD1\x04\xA0\x27\xEB\x7F\x92\xF6\x82\xB2\xF4\x8F\x6A\x2E\x25\x80\xFB\x4B\x82\x21\x44\xBC\xE2\xA1\x56\xA1\xE1\x84\x0E\xEA\x81\x49\x3C\xEC\x01\x40\x4F\x50\x5F\x8B\x18\xC7\x39\xF3\x3F\x68\x15\xBE\x42\xDA\xE2\xBF\xBF\x3F\xFD\x17\xAC\x38\x88\xD1\x04\xA0\x87\x74\x9E\x73\x5E\xC7\xD9\x04\xD0\xD5\x2A\xCC\xFB\x82\x48\xB6\x84\x19\x62\x34\x01\xE8\x69\x01\xF0\xA4\xF1\x21\xAE\x27\x00\x55\xF9\xDF\x54\x84\xF4\xEB\x8F\xD1\xBC\x4F\x70\x9E\xD2\xCC\x37\x4B\x1E\x00\x71\x53\x21\x79\xB2\xE1\x1A\x2C\x00\x8E\x68\xE4\x7A\x02\xA0\x0E\x31\x61\xFA\xFF\x10\x2E\xC9\x6D\x57\x46\xFB\x49\x09\xC4\x4D\x09\x32\xDB\x34\x77\x6D\xBD\xB2\xEC\xBD\x4E\xCE\x27\x80\x73\x0E\x96\xB0\x3D\x12\x00\x5F\x64\xBF\x55\x7A\x5D\x33\x05\xC0\x5B\x31\xFF\xE2\xBA\xF9\x15\x25\x6F\xAB\x89\x70\xE4\x8B\xB0\x3D\x12\x00\x5F\x64\x12\x23\x95\x6B\x66\xFD\x7F\xDE\xDD\x89\xF3\xEB\xFF\xC3\xA3\xAE\xC1\xF2\x48\x00\x7C\xD2\xF8\x00\x29\xB1\x8E\x23\xCC\x3F\x5E\xA3\x3A\x63\x9B\xCC\xF5\x04\xD0\x7E\x6A\xDE\x66\x58\x1E\x09\x80\x6F\x5A\x57\xA0\x1A\xA6\x81\x0E\x80\x11\xE7\x3B\x00\xED\x67\x97\xE8\xC1\xF2\x48\x00\x7C\x53\xE8\x1E\x85\x0B\xF3\x33\x80\xA3\xE3\x6E\x70\xBA\xFF\x5F\xF2\xBB\x4E\x22\xE8\x37\x00\x96\x47\x02\xE0\x9B\xFC\x73\x14\x5B\x99\xEF\x00\x1C\xF8\x4C\xC6\xED\xF5\xFF\x70\x1C\xFE\x41\x02\xE0\xA5\x56\xA7\xCB\xAB\x99\x4F\x00\xA5\xEF\xA9\xB9\xDD\xFF\x9F\x59\x01\xBB\x23\x01\xF0\x51\x4E\xDB\xDA\x2E\x33\x1A\x24\x44\x94\xF7\x66\x7B\xF1\xCB\x9C\x5E\xFF\x77\x9E\xB6\x0A\x81\xDD\x91\x00\xF8\xA8\x85\xF1\xB2\x16\x66\xF7\x00\x5C\x0E\xFE\x9E\xF3\x05\xC0\x73\xB6\x78\xF4\x03\x09\x80\x97\x32\x8A\x92\xAA\x98\xED\x00\x5C\xF0\x5C\xC8\xED\x04\xF0\x32\x51\xD7\x8E\x1B\x04\xBB\x3F\x8A\x33\x12\x00\xE7\x35\x61\xAD\x94\x50\x67\xF5\x99\x3B\xDF\xD2\x79\x7E\x99\x3F\xA7\x3B\x00\x65\xEF\xA9\x60\x75\x24\x00\x3E\x2B\x78\xAF\x64\x08\x73\x09\xE0\x9C\xDD\x16\x4E\x77\x00\x0E\x7D\xD1\x04\xAB\x23\x01\xF0\x59\xD1\x7B\x65\xDF\x33\xB7\x04\x38\x63\x9D\xC3\xE9\x25\xC0\xB1\x31\x17\x61\x75\x24\x00\x3E\x2B\xAA\x50\x39\x8F\xB9\x04\x70\xCA\xA4\x94\xD3\x2D\xC0\x9A\x69\xD5\xB0\x3A\x12\x00\x9F\x15\x5E\xA0\x70\x67\x2C\x48\xDA\x4F\x1A\x1D\xE5\x74\x02\x38\x69\x90\x0D\xAB\x23\x01\xF0\x59\x41\x79\xB2\x08\xE6\x12\x40\xED\xAC\x33\xDC\x3E\x04\x64\xBA\x11\x56\x47\x02\xE0\xB3\x02\xB2\x15\x49\xCC\x25\x80\x1A\xFD\x4B\x9C\xDE\x04\x54\x67\x1E\x04\xAB\x23\x01\xF0\x59\x7E\x59\x32\xE6\x66\xB9\xAA\x9A\x29\x57\x39\xBD\x04\x38\x6D\xE1\x06\xAB\x23\x01\xF0\x59\xDE\xBB\x14\xCC\x5D\x0D\xA6\x3A\x3A\xFE\x27\x4E\x27\x80\x3A\x4B\x17\x58\x1D\x09\x80\xCF\xF2\xC8\x90\x57\x31\x98\x00\xF4\x38\x7D\x14\xB8\xE3\xCC\x42\x3B\x58\x1D\x09\x80\xCF\x72\x4B\x93\x1D\x65\x2E\x01\x1C\x9F\x78\x93\xE3\x33\x00\x24\x80\x27\xB0\x74\xAB\xF4\x2A\x0C\xC4\x83\x04\xB0\x53\x76\x82\xB9\x04\x70\x6C\x22\xB7\x67\x00\x75\x0B\xB0\x04\x78\x52\x02\x48\x92\x23\x01\xF0\x40\xAE\x3B\xDA\x4E\xA3\x08\x88\x22\x60\x2F\x66\x00\x48\x00\x7C\xD0\xCA\x9D\x6D\x67\x18\xDC\x07\xA0\x7F\x01\x6D\x40\x24\x00\x88\xC5\x33\x80\x14\x46\x13\xC0\xEC\x3A\x6E\x6F\x04\x32\xDE\x04\xAB\x23\x01\xF0\xBA\x06\xC0\xE4\x12\xA0\xFD\xA4\x09\xB7\xB7\x02\xD7\xCC\xCA\x81\xD5\x91\x00\x78\x7D\x2F\x60\x9A\xEC\x14\x63\x41\xA2\xAC\x5B\x20\xE4\x76\x02\x98\x7C\x00\x56\x7F\x52\x11\x50\x7A\x0D\x06\xE2\xBE\xDC\xD3\xE4\xC7\x18\x0B\x92\x8E\xB3\xB6\x99\x9C\x5E\x02\x1C\x1D\x79\x09\x56\x47\x02\xE0\xB3\xD6\xA4\xCB\x99\xFB\xC8\x75\x9E\x73\xDE\xC0\xE9\x1B\x81\x0E\x7C\xD6\x0C\xAB\x3F\xB1\x0D\x88\x04\xC0\x03\x79\x65\x2A\x84\xCC\xCD\x00\x2E\xAE\xF6\xE4\x74\x02\x28\x7F\xB7\x1D\x56\x47\x02\xE0\xF5\x69\xC0\x5C\x45\x01\x73\x09\xE0\x4A\x90\x39\xD7\x6F\x05\x56\x57\x7E\xF4\x1A\xEC\x8E\x04\xC0\x57\xAD\xCD\x93\xEF\x60\x2C\x48\xD4\xB7\x93\x86\x72\xFE\x5A\xF0\x13\xC6\x13\x61\x77\x24\x00\xDE\xDE\x08\x94\xAF\x88\x66\x2C\x48\x08\xB9\xF9\x6A\x7B\xC9\x60\x6E\x3F\x0C\x72\xCA\x04\x0F\x83\x20\x01\xF0\xF7\x52\xD0\x7D\x0A\x01\xA3\x81\xA2\xAA\xFC\x7B\x07\xA7\x5B\x81\xC7\x27\xE1\x69\xB0\xC7\x60\xBF\x45\x7A\x1D\x06\xE2\xBE\x12\x4A\x54\xD6\x8C\x06\x8A\xF2\xD0\x70\x09\xA7\xAF\x06\x3F\xF8\x65\x3D\xEC\xFE\x98\x04\xB0\x15\x09\x80\x0F\x4A\xA9\x68\x1F\xCB\x68\xA0\xB4\xD7\x4E\xBF\xC6\xE9\x4E\xC0\xFE\x37\xD4\x44\xD8\xEF\x45\x58\xFE\xBF\xB1\xC3\x0C\x80\x17\xCA\x3C\xD8\xF6\x1E\xB3\x09\xA0\xCE\xA2\x8A\xF3\x85\xC0\xDA\xD9\x78\x1F\xF0\x57\xD8\x6E\x96\xFC\x04\x03\x71\x5B\x93\x83\xDB\x08\xE3\x81\xD2\x79\x7E\x79\x3C\xF7\x13\xC0\x8C\xCD\xB0\x3C\x12\x00\xDF\x64\x1C\x2D\x65\x7E\x9F\x4B\xC7\x95\xB5\x16\x5C\x4F\x00\xAA\x83\x43\xAF\xC1\xF2\xBF\x4E\x00\x32\x24\x00\x8E\x6B\x51\x62\x9B\x98\xF1\x40\x21\x2D\xC2\xBF\xB4\xEF\x7F\x85\x70\xBB\x0E\xF0\x5B\x35\x49\xEB\xF7\x32\x6C\xFF\x50\x02\xD8\x28\xB9\x01\x13\x71\x5B\xCB\x53\xDA\xAE\x68\x24\x58\x54\x95\x1F\x75\x72\x7D\x16\xD0\x51\xA3\x6F\x0E\xDB\x3F\x9C\x00\x64\x48\x00\x5C\xBF\x12\x3C\x43\xAA\x99\xA7\xEF\x94\xC7\xF4\x1A\x38\x9F\x00\x8E\x8C\xC5\x3B\x81\x48\x00\xBC\x52\x68\x9E\x7C\x9B\x46\x82\x85\xBA\x5B\x8F\xF3\x9D\x00\x65\xE9\x3B\x2A\x22\xE8\x37\x00\xD6\x47\x02\xE0\x8B\x36\x14\x2B\x34\x73\xE9\x6D\xE7\x45\xF7\x60\x4E\x9B\xBF\xF8\x65\x92\x50\x66\x45\x36\x9F\xD8\xFC\x0D\xAC\x8F\x04\xC0\x17\xED\x3C\xA8\xD2\x4C\x3C\xAB\xEB\xB3\x86\x73\xD5\xFC\x4D\xFB\x87\x10\xC7\x62\x07\xF2\xE5\xCE\x59\xC4\xBD\x3A\x22\x0F\xD6\xBF\xCF\xCE\x6A\xE5\xE7\x19\x47\xDA\x27\xE9\xB2\xA6\x85\x4A\x3A\xB8\xBC\x07\x20\x8D\x90\x17\x34\x12\x2C\x84\xFA\x17\xA9\x2A\x3E\xE4\x5C\x21\xF0\x4C\xD9\x97\x64\x5A\xAE\xD5\x3D\xF3\xD3\x9A\x99\x67\x2F\x87\xF5\x01\x8D\x63\xB2\xF4\x1D\x2E\x7F\xFD\x2D\xE2\xA4\x32\x8D\xFE\x60\xCA\x1A\xFD\xDB\x5C\x32\x7F\x76\x85\x11\x19\x9E\x3E\xE7\x81\xF9\xBB\x14\x76\x6C\xB3\x19\xC2\x1F\xF8\x64\xC9\xED\xB9\x9C\x00\x56\x6C\x97\x5E\xD6\xE8\x0F\xD6\x71\xCE\x21\x97\x0B\xC6\x6F\x2B\x1E\x4C\x7C\x84\x4B\x1E\x31\x7E\x97\xEC\x84\xDE\x3F\x22\xFC\xC1\xCA\x54\x59\x21\x97\x13\x80\x7F\xB6\x2C\x5F\xB3\x09\xE0\xC6\x86\xF9\x6C\x37\xFF\xF5\x92\xBF\x13\xB3\x02\xDB\x27\x9A\x9F\xD6\xB7\xE9\x73\x49\xF0\xB1\x6D\xEF\xC3\x02\xBA\x8D\x65\x82\xAC\x81\xD3\x1D\x80\x22\x85\xBB\x46\x7F\x30\xB5\xFA\xF6\x20\x55\xF9\x9F\x58\x6B\xFE\xAA\xF2\xF1\x64\xF4\x2E\xB3\xA7\x9A\xBF\x4B\x2B\xAB\x42\xF3\x61\x01\xDD\xC5\x22\x51\xFD\xDA\xF8\x40\x6E\x77\x00\xD2\x0E\x29\xFF\xA3\xF1\x1F\x4E\x55\xAB\x7F\x97\x95\x2D\xBE\x72\x2B\xF2\xD5\xCE\xD9\xDD\x32\x3F\xAD\x31\x59\x0B\x3A\x04\x75\xD1\x83\x61\x05\x5D\x5D\xFF\x2B\x56\x70\xD9\xFC\x86\x11\x92\x0E\xAD\xFC\x70\x9D\x17\x56\x66\xB0\xB5\xC5\xD7\x53\x79\x54\x45\xE0\x84\xA0\x8E\xE2\x94\x2C\x3B\xC1\xE5\x04\xE0\xB4\x55\x7E\x4B\x2B\x3F\x9C\xBA\x7E\xA7\x1E\x7B\x5A\x7C\x5F\xFD\x57\x8B\xAF\xA7\x9A\x94\x6D\xD5\xEE\x54\x1D\x3A\x10\x76\xD0\x2D\xBE\x88\x23\x2F\x4D\x09\xE6\x6E\xFF\xFF\xDE\x55\xE0\xD9\x8A\xBD\x5A\xF9\xF1\xA8\xFD\x00\xFD\x95\x07\x3F\x6F\xD7\x7E\x8B\x6F\x0E\x19\x9E\x36\xA7\xD7\xE6\xC7\x2C\x40\x77\xF1\xCE\x56\x38\x71\x7E\x0B\x70\x91\xC2\x59\x6B\x3F\x60\xC7\x19\xAB\x5A\xB6\xB6\xF8\x7A\xAA\x71\xD9\x96\x1D\x82\xEA\x84\xB7\x60\x0B\xDD\xC1\x7E\x73\xDB\x05\x2E\x9B\x7F\x7C\x80\x94\xA4\x1E\x57\xBF\xAD\xBD\x04\x70\x23\x6E\x99\x56\x5A\x7C\xC2\x0F\x88\x59\xBE\x4D\x9F\x99\xBF\x4B\xCB\x2A\x82\x0A\x61\x0B\xDD\x60\xF5\x36\xD9\xFB\x5C\xAF\xFE\x5B\x26\x48\x25\x5A\xFD\x11\x09\xA9\x1F\xAC\xAA\xF8\x87\x5A\xB3\x2D\x3E\xBD\x6E\xB7\xF8\x7A\xAA\xEF\xD2\x8C\xD5\x7E\x87\x63\x3F\x81\x3D\xF8\x8F\x5B\x9A\x3C\x8B\xF3\x8F\x81\x66\xC8\x0F\x69\xFD\x87\x6C\x3F\x39\xEF\x3C\x5B\x5B\x7C\xBD\x91\x55\x91\xC7\x45\xD8\x83\xDF\x4C\x88\x54\xBF\x32\x3D\x54\xA2\xE2\x7A\x02\x88\x29\x56\x78\x6A\xFD\xC7\xEC\xF8\x69\x83\x9B\x26\x5A\x7C\x4E\x45\x0E\x8C\x1A\xFF\x61\x79\x1D\x8C\xB6\x83\x4D\xF8\x8B\x67\x86\x2C\x92\xEB\xE6\xA7\x97\x2F\x99\x55\xEA\x21\x5A\xFF\x31\xD5\xEA\xC6\xD7\x55\x95\xFF\x62\x6C\x19\x70\xB6\xFC\x2B\xA2\xBF\x7B\xA1\xC6\xCC\x7F\xAF\x2D\x98\xBB\x48\x29\xA8\x09\x7F\x03\x56\xE1\x1F\x23\x05\xE4\x45\x83\x48\xA9\x9C\xFB\x97\x80\xCA\x5A\x58\xF3\xA3\x76\x9C\xB5\x3D\xC5\x84\xF9\x73\x9E\x70\x8A\x4F\x13\x72\x28\xF5\x3E\x00\xBB\xF0\x0F\x8F\x74\x59\x04\x1F\x2E\x00\xF1\xD5\x56\xFF\xFF\xB1\x09\xA0\x3E\x7D\x7E\xDF\xB7\xF8\xEC\xB4\x62\xFC\x2E\xD1\xB5\x86\x35\x07\x63\x2C\x61\x19\xFE\x60\x1B\x4D\x06\xCF\x0C\xE3\xFE\xDA\x9F\x56\xBC\x50\x31\x9B\x35\x3F\xEC\xBD\x4B\x42\x0E\x8F\x54\xF4\x85\xF9\x7F\x2A\xFD\xE0\x99\xA7\xF8\x34\xA5\x09\xD9\x16\x2A\xB7\x23\x61\xEF\xC0\x3A\xFC\xC0\x75\x07\xF7\x2B\xFF\xB4\x8C\xA2\x24\xED\x94\xE9\xFA\xB3\xEA\xC7\xED\xBC\xE4\x9D\xFD\xBC\xE6\xAF\x2C\x9F\xC0\x58\x8B\xAF\xB7\xB2\x2C\x5E\x7D\xA9\x1F\xE9\xD7\x1F\xF6\xE1\x36\xDE\x99\xCA\x4F\x27\x04\xB4\xAA\xF9\x90\x00\x3C\x52\xE5\xC7\x59\xF7\x03\xAB\x25\xA7\x3F\x6E\x2F\x7B\xA7\xD7\x2D\xBE\xB8\xF2\x85\x8C\xB7\xF8\x7A\x2B\xD7\xCA\x90\x24\x58\x88\xC3\x50\x5F\xCB\x45\x9B\xA4\x57\xF9\x72\x01\x68\x6C\x91\xC2\x81\x95\xBF\x73\x7B\x9D\xF5\xE5\x1E\xB7\xF8\x4A\x86\x10\x87\x22\x7B\x56\x1A\xBF\x4B\xDF\xA4\x19\x12\x9F\xC3\xB1\xB8\x3E\x8C\xA3\x78\xA6\xCB\x7D\xF8\x62\xFE\x19\xE1\xAD\x9D\x42\x21\x61\xE7\x0B\xD7\x1D\x77\x77\x59\xF4\xE4\xE9\xB0\xBA\xB2\xA1\x64\x6A\xAE\x25\xAB\xCD\xFF\xF0\xBD\x01\xDE\x07\xA3\x3E\x85\x9D\xB8\x85\x20\x43\xF1\xCF\x29\x21\x92\x4E\xBE\x24\x00\xF7\x74\x79\x0D\x8B\x67\x5A\x64\x80\xEA\xF8\x54\xC9\x33\x1F\xE8\xA4\x94\x59\x31\x97\x0C\x4B\x33\xE2\x84\xF9\xBB\x34\x63\xF7\x12\xE9\xCA\x8A\xD8\x37\x61\x2B\x8E\x98\x5F\x40\x06\x58\x26\xCA\x6E\xF1\xEB\x01\x10\xA5\x15\xAB\x7F\xF4\xCE\x1B\x89\x91\x4F\x33\xBF\xB4\xF8\x35\xB2\xA6\xC4\x8E\x53\xC6\x7F\x58\x66\x85\xAE\x37\x0D\xD2\x04\x78\x5C\x94\x0B\x55\xFF\x54\x7E\x54\xFD\xBB\x64\x12\x2D\x55\xB2\xAE\xFA\xFF\x48\x31\x50\xAD\x7E\x5D\x75\x64\xF8\x63\xEF\x09\xB8\x2A\xFC\x90\xCC\xDD\x63\xC3\x59\xF3\x77\x69\x61\x89\xC7\x69\x74\x06\xD8\xCD\x9A\x5D\x72\x9B\x31\x3C\x7B\xFD\x87\x55\x9B\x7F\x9E\x86\xEA\x4A\xE8\xCE\x5F\x9B\xBF\xB4\x62\x32\x19\x95\x69\xCA\x79\xF3\x3F\xB8\x52\xBC\xC4\xA7\x1A\x49\x80\x9D\xF8\xEC\x92\x8D\x98\xCC\xA3\x75\x3F\xAD\xB1\xFE\x52\x92\x58\xAA\xFC\x8C\x13\x03\xA0\x56\xB7\xBE\xAD\x3A\xF0\x79\x67\x57\x8B\x2F\xBA\x6C\x11\x6F\x8C\xFF\xB0\xEC\xCB\x7C\xCA\x91\x04\xD8\x85\xF3\x0E\xD9\x9F\x8C\xD6\x49\x15\x7C\x7B\xFB\xCF\x71\xAB\xEC\x0E\xA7\x06\xA2\xE3\x4A\x48\xEE\xDD\x92\x3F\x10\x9B\x7D\x76\xBC\x34\x3F\x92\x00\xFB\x70\x4A\x15\xBD\x35\x2F\xB6\x4D\xC4\xC7\xC7\x3F\xA3\xF6\x2A\x3C\x38\x35\x18\x6D\xEA\xC6\xF7\x8C\xF2\xEC\xD4\x7C\x36\x7F\x97\x16\xED\x5F\x53\x63\x90\x66\xF0\x02\x2C\xA8\x3D\xE8\x7D\xFE\x56\x71\xB2\x3B\x7C\x34\xFF\x9C\x28\xA9\x8A\xB5\xBD\xFF\xA7\xE1\x75\x28\xB6\x42\x17\x12\x00\x2D\x8B\xBD\xAB\x2E\xB9\xEC\x0D\x1E\x04\x2B\x6A\x1E\xFB\x64\xF5\xEB\x56\xF1\xB2\xDB\x7C\x7D\xFA\x3B\x30\x47\x96\xCB\xC9\x81\xC9\xBB\x5C\xF5\xFE\xB8\x5D\x16\x6A\x5D\x49\x02\x06\x05\x8E\xCD\xAB\xAB\xA2\xF1\xD4\x98\x06\x71\x49\x92\x0C\x59\xB0\xA1\xAD\x91\xAF\xE6\x9F\x12\x24\x51\x6F\xA9\x6E\xFB\x23\x67\x07\xC8\xFF\x48\x7C\xBE\xAE\x24\x00\x5A\x13\x73\xAD\x95\x1E\x87\xD6\xE9\xC1\x9A\xCC\x43\xEF\xF2\x33\x8D\x95\x4A\xF8\x6A\x7E\x5A\x9E\x69\xF2\xC3\x9C\x1E\xA4\x8A\x6B\x27\xDF\x9C\x9E\x6B\xD3\xAE\x4B\x49\x60\x44\xDA\x5C\xF5\xAA\xEA\x70\x6F\x58\x94\x39\xBC\xB3\x14\x93\x66\xF0\xE4\x6C\xFF\xD3\xAE\xFD\xDA\x54\xA6\xFC\x9C\xF3\x83\x15\x7D\x32\x25\x5A\x97\x12\x40\x97\x6C\xF7\x7B\x1D\xB0\xCE\x15\xBC\x0A\xBB\xF6\x2D\x9E\x19\x72\x3F\xBE\x1C\xED\x7D\x9A\x5C\x77\xB6\x9D\xE5\xC5\x80\x09\x89\xF0\x45\xF3\x7D\x6E\xAD\xBA\x98\x04\xA6\xE7\xD9\x49\x56\x57\x85\x7F\x0F\xDB\x3E\x3F\xA6\x49\xEA\x41\x4E\xC9\xF2\x83\x7C\x37\x3E\xAD\x71\xD4\xA3\x1F\x89\x65\x2A\xFE\xC4\x4D\xD2\xD9\x6C\x93\xA1\xA9\x86\x44\x17\x93\xC0\xB0\x54\x23\xB5\x73\x69\x60\x32\x5A\x85\xBD\xC7\x23\xF3\xF6\xE4\xB9\x31\x52\xA9\x2E\x98\x9F\xD6\xAA\x9D\x6D\x3F\xF2\x6E\x10\xDD\xAA\xC2\x4E\xEB\x62\x02\xE8\xD2\xAC\x3D\x0E\xCD\xAB\x2A\x43\x7F\x80\x9D\xBB\xCF\xBF\xD3\x0C\x06\x53\xB7\x32\x15\xFF\x90\x3E\x5F\x6D\x96\x7C\x40\x27\xCC\x4F\xAF\xFD\xB7\xF0\xE9\xEB\xFF\xA0\x2D\x78\xAD\xE2\x6F\x13\x72\xAC\x3A\x75\x39\x09\xD0\xB3\x20\x5B\xA1\xD7\x7E\x9B\x8A\x95\x38\x56\xFC\x34\xA8\xDD\x95\x36\x25\x6B\x96\x8E\xDD\xB5\x40\xF1\x5F\x57\xB4\xE5\xA4\x50\x26\x69\xE5\x75\x02\xF0\x48\x93\xD5\xF2\x76\x5C\x75\xB5\x20\xF8\xC8\x63\xA4\xBB\xCC\xDB\x5D\xCA\x03\x82\xB1\x2C\x78\x14\xEA\xB4\xE5\xC8\x59\x7B\xEC\x6F\x3C\xE9\xB7\x33\xC9\xF3\x26\x13\x42\xEF\xF0\xD2\xFC\x93\xA9\xBE\xFF\xD6\x52\xC5\xBF\xF8\x9B\xD8\xA9\xF3\xCC\x4B\xF6\x7B\x35\x20\x09\xDC\xD7\xD4\xDD\x8B\x25\xCE\xE5\x81\xCE\x38\x4F\xD0\xAF\xDF\x82\x42\xD7\x4F\xE7\xED\x5B\x5E\xDB\xBD\x1B\x9B\x17\x11\xA3\x84\xD3\xBC\x4B\x00\x7E\x39\x8A\x22\xDE\x0F\x74\xFA\x8F\x7B\x87\x8E\xC9\x9C\xAF\x46\x02\xF8\x45\x33\xF3\x6C\x5B\x9C\x4A\xFD\x5C\xA8\x6B\x6C\x06\xE8\x9A\xF1\x2D\x8A\x56\x0E\xA3\x8D\xFF\x75\x6A\xCF\x2E\x85\xA5\x6F\x94\xB2\x48\xCF\xA7\x8C\x23\xE1\x85\xF9\x8D\xD6\x49\xDA\x53\xAB\xD5\xBA\xF1\x44\x7D\x44\x6D\xF2\x66\x18\xFF\x31\x33\x82\x9C\xC5\xD2\xA5\xA5\xFE\x61\xDF\xA4\xCE\x1E\xC8\xEB\x00\xA0\x12\xDD\xA2\x62\x77\x73\xC3\x02\xC7\xAB\xCF\xFB\x9B\x99\xE7\x45\x91\xB1\x01\xCD\x9C\x4F\x00\x91\xF9\xCA\x10\xDD\xA9\xF1\x50\x4B\x01\x7B\xA1\x4F\x3D\x4C\xFF\x78\x7D\x9F\x69\xD6\xB1\x58\x28\x28\xB6\x29\xF5\xFA\x8A\x4F\xE3\x3E\x33\xCF\xE6\x6F\x54\x71\x2F\x65\x7C\xB6\xA5\xAC\x4F\xEF\x6B\xCC\x75\x26\xFA\xEB\xAE\x70\xD6\xFC\x4B\x36\xC9\x9A\x59\x7F\xDD\x57\x5F\x93\x79\x51\xF8\x89\xAE\x77\x05\xBA\xB5\x3C\xD8\x63\xD7\xB0\xB4\xCC\x2F\x66\x46\x81\x23\x27\x5F\x29\x9A\xBC\x7B\xD1\x1F\x6D\x4A\xBD\xC3\x0D\xF2\xEC\x6F\x31\xF9\xF6\xC3\xA8\x8C\x79\xC4\x74\x5B\x35\xE7\xCC\xAF\x47\xB7\xFD\x4A\x15\x13\x75\xB2\xF0\x13\x7F\x2A\xCD\x9B\xAD\x0F\x82\xB0\x4D\xF4\x1A\xD9\x30\xDF\xF1\xA6\x7D\xA9\x6F\xFC\x82\xE2\x55\xFF\x66\xEB\x98\xD2\x9D\x0D\xD3\xBD\x2E\xA3\xAD\xF7\x7B\xEE\xA0\x6E\x52\xBE\xAB\xE9\xF1\xB5\xCC\x49\xE6\x54\xAB\xD0\x2B\x53\x21\xD4\xE9\xEA\xAF\x67\x75\x44\x2D\x0C\xDE\x9B\xB7\x0B\x2D\x65\x0B\xF7\xBB\x1F\x72\x2C\xF7\x17\xD0\x53\x6B\x6D\x75\x12\x86\x67\x4F\x7B\xCD\xA2\xC8\x6D\x96\x4D\x89\x57\x92\x49\x81\xCB\xA5\xEF\x32\x4C\x3B\xB4\xFD\xDB\x18\xEF\xF1\x22\x13\x43\xEB\x59\x6F\x7E\xB3\xF5\x52\x45\x76\xA5\xFA\x35\x9D\x4E\x00\x95\x0D\x95\xAF\xCD\xDF\xE7\x2A\x85\xA9\x9F\x4F\x63\xB3\xE6\xAB\x4C\xF7\x2E\xBF\x6A\x57\xEA\x55\x40\xB5\x16\x7D\xA8\xEB\xCA\xC6\x7F\x9A\xA5\xFF\x46\x5F\x7D\xD5\xBF\x4D\x33\xF8\xB3\x79\x91\x9B\xBE\x5D\xA9\x8F\xBF\xF5\x7E\x8F\xDD\xC6\x85\xCB\x7E\x9C\x98\xBD\x50\xCA\xD6\x19\xDC\xBD\x56\xE1\xC6\x3A\x56\x5F\xF4\x99\x20\x54\x2E\xC0\xCE\x0F\x8A\xD4\xF3\xF9\x23\xC7\xED\x5A\x80\xD6\x20\x03\xFA\x2E\x63\x6E\x27\xDD\x5D\x30\xDC\xB3\xB4\x7E\xFE\x5E\xD7\x8B\x0B\x8B\xDD\x6B\x16\xEF\xF7\xAA\xA0\x6E\x36\xDE\x47\x99\x79\x37\x95\x28\x72\xE8\xBF\x36\x42\xEF\xC2\x45\x42\x41\xA9\xE5\xFE\xD5\x87\xCD\xF6\xAD\x38\x3B\xA7\xD0\xE9\xA7\xE9\x79\x36\x2D\xD4\xAB\x48\xCA\x9E\xB6\xE8\xD8\xF4\xAC\xDB\x82\x8C\x3D\xAC\x6C\x15\x7A\x67\xC8\xAB\xE1\xFC\x87\x48\xA8\x4B\xF5\xD4\xD5\x03\x43\x10\xB3\x32\xCF\x8B\x20\x63\x02\x9B\x58\x63\xFE\x05\xEB\xA5\x72\x9D\x9F\xFA\x3F\x0E\xFF\xC3\x71\xC5\x08\x58\x88\x99\xA7\xDD\x9C\x88\x7E\xF4\x65\xAD\x9B\x7F\xE2\x5A\xFA\xA2\x0F\x85\x3E\xDC\xFE\x18\xE8\xBB\x03\x96\x96\xF9\xDF\x40\xC0\x42\x4C\x68\x64\x86\x19\x31\x4B\xAE\xD4\x6A\x02\x08\xDD\x23\xDF\x0E\xA7\x3F\x85\xFC\x5B\xE5\x6F\x9B\xED\x5B\xDE\x86\x80\x85\x18\x6B\x15\xE6\x26\x69\xA5\x55\xE8\xB2\x5D\xFE\x93\xCE\x6D\xF8\xE9\x0D\xE9\x17\xF7\x7D\x39\x79\xF7\xE2\x0E\x04\x2B\xC4\x94\xE6\xE6\x09\xC8\xC4\x30\xCD\x9D\x2A\x34\x5E\x27\x51\xA5\x72\xF9\x86\x5F\x4D\x93\x72\x2E\xC7\x60\x74\x06\x0E\x0D\x41\xCC\x49\x2F\xDB\x9A\x18\x26\x9E\x62\xFE\x98\x6F\x70\x1B\x49\x14\x2A\xA6\xC3\xD5\x3D\x64\xE3\xE9\x8C\x15\xC3\xD3\xE7\x20\x58\x21\x86\x5B\x85\xBB\x19\x6D\x15\x46\x14\xCA\x22\xE1\xE6\x5E\x12\x7B\x62\x5B\x14\xDA\x83\x10\xD3\x9A\x9F\x17\x4E\xC6\x32\xD0\x2A\xF4\xC9\x56\x94\xC3\xC5\xCF\x49\x44\xCD\xD6\xED\x38\x33\x00\x31\x7E\x8B\x73\xAE\x23\x99\x11\x7D\xA9\xCF\xCC\xBF\x7C\x9B\xFC\xBA\x80\x90\x01\x70\x70\x1F\xB0\xF6\x68\x42\x3E\x82\x14\x62\xFC\x28\x76\x86\x29\x99\x97\xF2\xFC\xAD\xC2\x85\x89\x52\x49\xDE\x49\x82\xBB\x1F\xFB\x92\xC0\x23\xF1\x45\x08\x52\x48\x33\xAD\xC2\x2D\x64\xB4\xBF\xB8\x57\xE6\x37\x8D\x91\x2A\x53\x0E\x28\xFE\x01\xC7\x32\x91\x04\x0E\xC5\x09\x11\xA0\x90\x66\x5A\x85\x9E\xD4\xA9\xC2\xDB\x3D\x32\xFF\xAC\x08\x49\x47\x52\x99\x6A\x38\x9C\xCA\xE4\x72\xE0\x70\x42\x21\x02\x14\xD2\x84\xC6\x67\x2D\x24\x73\x37\x9D\xEC\x96\xF9\xF5\xC3\x25\x9D\xD4\xE5\x1E\xD3\xE0\x50\x0D\x10\x7A\x7C\x73\x26\x57\x4F\xA9\x41\xDC\x7B\xCF\xC1\x32\x33\xF7\xA9\xAD\x42\xFD\x10\x89\x7A\x53\x89\xD2\x08\xCE\xD4\x20\x31\x35\xDB\x12\x86\xA7\x61\x9F\x00\xA4\xA1\x53\x85\x7B\xC2\xC8\xB8\xC7\xB4\x0A\xA7\x51\xE6\x4F\x14\x2A\xCD\xE0\x48\x2D\x40\x5F\x2B\x46\x57\x6E\x11\xA0\x90\x26\xA4\x4F\xB7\x0A\x63\x2E\x3E\x30\xFF\x8C\x50\x89\x7A\xA3\x50\x39\x17\x4E\xD4\x22\x5B\xCF\x64\x2F\xD4\xCB\xB1\xC4\x05\xA3\x90\x66\x2E\x59\x49\x37\x25\xF3\xB7\x57\x90\x59\x91\x92\xCE\xCD\xD8\xE2\xCB\x0E\x32\x2E\x14\xFE\x60\x54\xB0\x54\x89\x00\x85\x34\x21\xC3\xFC\xA5\xCA\xE4\x43\x37\xC6\xC0\x79\x2C\x22\xFF\x5A\xE5\xDF\xA9\x7B\xE7\x9B\x10\xA0\x10\xA3\xB5\x80\x7D\x6E\xAD\x7B\x2E\x95\x7F\x08\xC7\xB1\x90\xEA\xEB\xD7\x07\xAE\x39\x18\x7D\x1C\x81\x0A\x31\x21\x07\xA1\xDF\x2D\xE1\xCD\xA3\xBF\x83\xD3\x58\x4E\xEC\xC9\x1D\xF1\x23\x33\x51\x1C\x84\xFA\x46\xF4\x59\x14\xDF\x83\xEB\xAB\x8E\x92\xA3\x2F\xC1\x5D\x1C\x21\xF5\x5C\x9E\xE1\xAC\x3C\x07\x15\x02\x18\x7A\xBE\xF3\x01\x26\x64\x5D\xED\xB6\x18\x38\x8A\x83\x14\xDD\xAC\xF8\xF3\xB2\x8A\xC0\xEB\x08\x64\xA8\x77\xEF\x0E\xDA\xB6\x27\x9F\xC9\x41\x9B\x8F\xCB\xD0\x8F\x91\x46\xD5\x26\x6F\xC3\x92\x00\xEA\x89\xEC\x4A\xBD\xEF\x64\x5D\x11\xFE\x05\x0E\xE2\xCB\x92\xE0\xC7\x82\xC9\xD4\xA3\x17\xB8\x70\x14\x7A\xAA\x46\xA4\x1B\x93\xA0\x63\x1B\xB3\xD2\x48\xDA\x0B\x70\x0D\xCF\xA8\xBD\x5D\x3B\xC8\xFF\xF0\x86\x72\x6C\x21\x86\x1E\xDF\xDF\x77\x50\x26\x9D\xC9\x9E\x03\xA7\xF0\x9C\x94\xB3\xBB\x4D\x8C\x0B\x5C\xE4\x08\x7A\x88\xD6\xD7\xA9\x06\xC4\xE3\x60\xE4\x31\xB4\xF8\x74\x88\xBA\xFA\xBA\xC1\x01\x47\xE2\x8A\xE9\x2A\x2F\x4C\xA0\xBB\xA2\x3B\x45\x9B\xCE\x64\xDA\xC2\x11\x3A\x4A\xE6\xF9\xC2\x71\x36\x42\x2F\xEC\x20\xD4\x31\x7D\x9B\x3E\x97\x78\x1F\x8C\xA9\xAC\xBE\x5E\xF7\x16\x5C\x80\x4E\x41\xFF\x0D\x27\x77\x84\x4D\xCB\x5B\x82\x07\x49\x74\x40\x56\xFB\x57\x8B\xB7\x9F\xDD\x8D\xCB\x3B\xC0\x7F\x53\x7E\xEB\xF8\xDB\x7E\x87\x63\xCB\x46\x65\x9A\xC1\x28\x3C\xD4\xD4\x3C\xDB\x8E\x98\x13\x29\x91\xA8\xF0\x83\xA7\x92\x77\xAD\xE4\x8B\x95\x95\xA1\xE7\xE9\x87\x23\x60\x1C\xEE\xEB\x87\xCC\x79\xC4\xF7\x50\x8C\x10\x45\x3E\xD0\x23\x76\x5D\x28\xD0\x77\x2C\xF3\xBF\x89\xEB\xC7\xB8\xBB\xCE\x77\xAF\x8A\x3C\x91\x73\x6D\xFF\xC7\x88\x66\xD0\x6B\x76\xFC\x98\x67\xEE\x50\xEA\x57\x8F\x44\xC0\x1D\xE3\xAF\xAA\x0E\x3D\x97\x75\xA1\x68\x14\xA2\x17\xF4\x19\x69\xE7\xF3\x4D\x1C\x4B\xFD\x6E\x62\x69\xC0\xDE\x87\x3D\x56\x55\x86\x9E\xC9\xBD\x54\x34\x02\xD1\x0A\x18\x63\xF7\xE5\x12\x3D\xF7\xEA\xF0\xD3\x28\x16\xB2\x43\x13\xB2\xAC\xD4\xBE\x87\x62\x2B\xF6\x5E\xAF\xFA\x04\xD1\x09\x34\x06\x55\x54\xFA\x27\xFD\x4E\xC1\x8C\x3D\xF6\x68\x1F\x6A\x41\x66\x85\xCB\xE5\x91\xB5\x49\xC9\x07\xEE\x9C\xFC\x3D\xA2\x11\x68\x8D\xEB\xEA\xEB\x03\x37\x9E\xCE\xF4\x5F\x2A\xF4\xB9\x8B\x73\x06\xCC\x57\xF4\x97\x55\x04\x5D\xD9\x7E\x2E\x77\x09\xBD\x7F\x03\xD1\x07\x58\x45\xD1\x8D\xCA\x61\xC1\x47\x13\x8A\x4C\x0A\x9D\x71\x49\x69\x1F\xEE\xD5\xB7\x2C\x72\x93\x50\x5F\xFB\x94\xAA\x5B\xC7\xDE\x47\x94\x01\xD6\x43\x7D\x9D\x06\x64\x5E\xDC\xB7\xC0\xFB\x50\xCC\x31\x2C\x11\x7A\x77\x0D\x97\xF9\xDE\x15\xF2\xC0\xC3\xF1\x7B\x0B\xAE\x54\xA0\x9A\x0F\x38\x9D\x0C\x5E\xCA\x38\x5F\x68\xE3\x75\x20\xE6\xC8\xDC\x82\x65\xB8\xA6\xEC\x29\xED\xBB\xC5\xC5\x9E\xAD\x21\x47\x36\xE6\xEE\xBB\x5A\x85\x6B\xB7\x01\x2F\x93\x41\xFF\x82\xAB\x65\x93\xC3\x6B\x36\x67\x3B\x94\x7A\x37\x8E\xDE\x35\x5F\xD7\xEF\xD8\xEF\xA0\x5A\x77\xE7\x13\xEA\xD2\xC3\xEB\xEA\x2F\x7C\x80\x08\x01\xBA\x55\x40\x14\x89\xDE\xA2\x6E\x2B\x72\xA0\x9F\x3E\xB7\x29\xF5\x6E\x19\xB3\xCB\x9C\xB7\x66\xA7\x0B\xA4\x66\x7B\x97\x29\xDD\x2A\xC3\x2F\xAC\x3F\x91\xB2\xB1\xE2\xF6\x91\x51\xF4\x52\x09\x51\x00\xC0\xCF\x34\xAA\x1B\x5F\xCF\xB9\x54\x6C\x1A\x79\x3C\x69\xE7\xAA\xAA\xE0\x4B\xF3\xF6\x2E\x57\x72\xF1\x3E\xC3\xEF\x32\x8C\xEF\x99\x7D\x79\x65\xF0\xB5\xA0\x63\x89\x85\x29\x3F\xE6\x2D\x3F\xD7\x72\xF5\xAF\x18\x61\x00\x7A\x88\x48\x2D\x7A\x2B\xEF\x72\xA9\x21\x75\x64\x39\xDE\xF7\x70\x6C\xF5\xF2\xF2\xC0\x1B\xF3\xF6\xAD\x54\xE8\x65\x5B\x6A\xD5\xE4\xF4\x8E\x48\xFD\x5C\x5B\xB5\x45\xB1\x5B\xDB\x8A\xCA\xB5\xD7\x03\x8F\xC4\x95\xC5\x9F\xDA\xB9\x2E\xF7\xE2\x7E\xE3\x3B\x12\x09\x7A\xF3\x00\x30\x5C\x4F\xF8\xCD\xF9\xD6\xAB\xFF\xA6\x0D\xB7\xE9\x74\x66\x40\x54\x4D\x52\x7A\x00\x75\xE7\xA1\x47\x75\xD4\x69\xE7\xB2\x80\x9B\xB6\x42\x81\xC8\xB2\x68\xB5\x8C\x2E\x3C\xCE\xDC\x6D\xA7\x9E\x9C\xBB\x88\xD0\x49\x83\x5E\x66\xD0\xDB\x66\x69\xD1\xBB\x19\x47\xEF\x9A\x77\xEF\x9F\x4D\xCA\xB5\x26\x33\xA8\xFF\x9D\x51\x81\x53\x07\xFD\xF5\xB6\x2E\xF6\x90\xD0\x7B\x1B\x56\x56\x85\x5D\xA6\x0A\x98\x35\xF4\x97\x7C\xC3\x89\x9D\x89\xC9\x67\x73\xDC\x0A\xAE\x94\xCE\x6C\x96\x35\xBF\x8F\x29\x3C\x00\xDC\x49\x18\xFD\x29\xBD\xAC\x56\xAB\x07\x51\x7F\xDF\xA4\xFE\xBE\x45\xFD\x7D\x83\xFA\xFB\xDA\xCF\xFF\x0C\xE7\xE4\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\xC4\xFF\x03\x85\x44\xB0\x88\x63\x0E\xFB\x65\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"])                     
baidu_icon_data = "".join(["\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x02\x00\x00\x00\x02\x00\x08\x06\x00\x00\x00\xF4\x78\xD4\xFA\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x16\x21\x00\x00\x16\x21\x01\xB6\xAF\xA3\xE2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6F\x66\x74\x77\x61\x72\x65\x00\x41\x64\x6F\x62\x65\x20\x49\x6D\x61\x67\x65\x52\x65\x61\x64\x79\x71\xC9\x65\x3C\x00\x00\x24\xDF\x49\x44\x41\x54\x78\xDA\xEC\xDD\xDD\x71\x14\xD7\xBA\x06\xE0\xF6\xAE\x7D\x0F\x11\xC0\xF8\xD6\x37\x92\xCB\x01\x30\x8E\x00\x39\x02\x0D\x11\x58\x8E\x00\x39\x02\x8B\x08\x18\x22\xB0\x88\xC0\xA3\x00\x28\x4B\x37\xDC\xEE\xC1\x09\x1C\x14\x81\x4E\x7F\x68\xC9\x16\x58\x80\x46\xEA\xE9\x5E\x3F\xCF\x53\x35\xA5\xB3\xF7\xA9\x73\x90\x56\xF7\xF4\xF7\xAE\xDF\xFE\xE6\xE2\xE2\xA2\x03\x00\xDA\xF2\x1F\x4D\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x08\x00\x00\x80\x00\x00\x00\x7C\xF0\x5F\x4D\x00\x9F\xF7\xDD\x0F\x7F\xCD\xFA\x1F\xB3\xF4\x1F\xD7\x6F\xDF\x3C\x5A\x6B\x15\xA0\x06\xDF\x5C\x5C\x5C\x68\x05\x5A\x2F\xF2\xBB\xFD\x8F\x4F\x3F\x0F\xBE\xF2\x7F\xF6\x2E\x02\x41\xFF\x39\x4D\x9F\x95\x70\x00\x08\x00\x90\x7F\xD1\xDF\xEB\x7F\x5C\x7D\x1E\x0C\xF4\xFF\x36\x42\xC1\xAA\xFF\x1C\xF7\x61\xE0\x58\x2B\x03\x02\x00\xE4\xD3\xD3\x3F\x18\xB8\xE8\x7F\xCE\x79\xFF\x59\xF6\x9F\x23\x23\x03\x80\x00\x00\xD3\x14\xFE\x79\xFF\xE3\xB0\xFF\x3C\x99\xE8\x57\x78\x15\x61\xA0\x0F\x02\x2B\x57\x03\x10\x00\xA0\xFE\xC2\xFF\xA9\xD7\xFD\xE7\xC0\x88\x00\x20\x00\xC0\x76\x0A\xFF\xC3\xFE\xC7\x51\xFF\xD9\xCF\xF4\x57\xFC\xB5\xBB\x9C\x1A\x78\xEF\x6A\x01\x02\x00\x0C\x53\xFC\x0F\x52\xAF\xFF\x41\xE6\xBF\x6A\x2C\x18\x5C\x98\x16\x00\x04\x00\xB8\x7F\xAF\x7F\xD9\x7F\x9E\x16\xF6\xAB\xBF\xE8\x43\xC0\x81\x2B\x58\xCC\x7D\x16\x0B\x49\x1F\x5E\xFD\x67\x01\x0E\x01\x00\xA6\x7F\x28\xC7\xB6\xBB\xC7\x85\xFE\x09\x67\xFD\x67\xCF\xDA\x80\x6C\xEE\xA7\x79\xF7\xCF\x79\x10\xB3\xEE\x76\xE7\x42\x84\x93\xFE\x13\xD3\x3A\x57\xE7\x42\x08\x07\x08\x00\xB0\xC5\x87\xF5\xA2\xBB\x9C\xEF\x7F\x50\xF8\x9F\x12\xDB\x06\xE7\x7D\xD1\x38\x75\x55\x27\x09\x90\x51\xF4\x63\x7B\xE8\xD0\x0B\x46\x63\x07\xC8\xA1\x70\x87\x00\x00\xC3\x3E\xB8\x0F\xFB\x1F\xCF\x2B\xFB\xB3\x9E\xF5\xC5\x62\xE9\xEA\x6E\xFD\xDE\x99\xA5\x82\x1F\xD3\x2F\x63\x8C\x1C\xBD\x48\x41\xC0\xC2\x4F\x04\x00\xB8\xE7\x03\x3C\x8A\xE4\x7E\xA5\x7F\x9E\x10\xB0\xBD\xFB\x66\x9E\x8A\xFE\x14\x6B\x45\x62\x94\x67\xE1\x94\x48\x04\x00\x50\xFC\x85\x80\x71\x0B\xFF\x61\x97\xC7\x99\x10\x16\x7E\x22\x00\x80\xE2\x2F\x04\x34\x54\xF8\xAF\x8B\x85\x9F\x73\x53\x02\x08\x00\x70\xBB\x87\x79\x2C\xF6\xFB\xB9\xB1\x3F\x5B\x08\xB8\xDB\xBD\x32\xEB\x2E\x17\x87\xE6\xBC\x2D\xD4\xC2\x4F\x04\x00\xB8\xC5\x03\x7D\xD1\xFF\x78\xD9\xE8\x9F\xFF\xBD\x22\xB1\xD1\xBD\x52\xCA\x61\x50\x57\x21\xC0\xBA\x00\x04\x00\xF8\xCC\x03\x7D\xDE\xFF\xF8\xA3\xE1\x26\xD0\x53\xBC\x7D\xAF\x7F\xD9\xE5\x37\xDC\x7F\x1B\x46\x7A\x18\xDD\x7F\x34\x01\x05\x3C\xD4\x5B\xEF\x1D\x45\x4F\x76\x99\x4E\x3B\xE4\xE6\xFB\x64\xD1\x5D\x1E\xC0\xF3\xA4\xD0\x3F\xE1\x65\xFA\x1B\x40\x00\x80\xE4\xB8\x2B\xFF\x90\x9F\x21\xEC\x74\x97\x73\xDA\x7C\x5C\xF8\x1F\xA6\x85\xA1\x2F\x2B\xB8\x4F\x84\x00\x04\x00\x48\x0F\xF7\xA3\x54\xF8\xB8\xB4\xAF\x40\x7C\x5C\xFC\xFB\x1F\xAB\xAE\xAE\x5D\x21\x42\x00\xA3\xB1\x06\x80\x5C\x1F\xEE\xF3\xAE\xED\x79\xFF\xCF\x89\xF5\x00\xBB\xAD\x1F\x2D\x9B\x8E\xEF\x5D\x75\xF5\x8E\x0E\x59\x13\x80\x11\x00\x9A\xED\xD9\x79\xF8\xDD\xEC\x41\xEB\x6D\x93\xC2\x61\xCD\xC5\xFF\x6A\x24\x60\xD7\xED\x8E\x00\x40\x6B\x0E\xBB\x72\xDF\xEC\x37\x86\x27\x69\xAB\x5B\x8B\xC5\x7F\xD1\x5D\x8E\x0C\xB5\xB0\x2E\x64\x25\x04\xB0\x4D\xA6\x00\xC8\xB1\x77\x67\xE8\xFF\xEB\x9A\x9B\x0A\x68\xF4\x2C\x88\x77\xE9\x3A\x3B\x31\x10\x23\x00\x54\xCF\x4A\xF7\xDB\x79\xD0\x52\x5B\x35\x7C\x10\x54\x8C\x84\x39\x24\x08\x01\x80\xEA\x1F\xF2\x31\xAC\x6D\xD5\xFF\xED\x3D\x4D\x23\x26\x8A\x7F\xDD\x9E\xA4\x1D\x31\x30\x28\x53\x00\xE4\xF2\x90\x8F\x85\x7F\xEB\xCE\x9E\xFF\x4D\x9D\xBD\x7D\xF3\x68\xB7\xE2\xFB\x22\xFE\xB6\x3F\x5D\xE6\x0F\x7E\x72\x64\x30\x46\x00\xA8\xD1\x81\xE2\x7F\x27\x3B\xB5\xEE\x1B\xBF\xB6\xD5\x8F\x4B\xCB\x74\x32\x26\x08\x00\x54\xD5\xFB\xF7\x7E\xF4\xBB\x3B\xAC\xF4\x9E\x70\x0A\xE4\xC7\x9A\xDF\x02\x8A\x00\x80\xDE\x3F\x1F\x7B\x5C\xE1\x28\x40\xF4\xFC\x6D\x05\xFD\xB7\x66\xB7\x80\x32\x3C\x6B\x00\xC8\xA1\xA7\xB7\x16\x00\xEE\xED\xDD\xDB\x37\x8F\x66\x95\xDC\x13\xD1\xCB\xDD\x77\x49\x3F\xCB\x69\x90\x18\x01\x40\xEF\x9F\x8F\x46\x01\xF6\x2A\x28\xFE\x0B\xC5\xFF\xAB\x4C\x05\x20\x00\x50\x85\x85\x26\x18\x34\x4C\x95\x5C\xFC\x63\xD1\x9F\xED\x6E\xB7\xF3\xC4\x4B\x83\x10\x00\x28\xBD\xB7\x67\x9E\x77\xD8\xA2\x30\x2B\xF8\xF7\x5F\x76\x46\x83\x36\x71\x94\xA6\xD0\x40\x00\x40\xEF\x9F\x32\x77\x04\xF4\x85\x2C\x7E\x6F\x87\x40\x6D\xE6\x41\x57\xE1\x0E\x10\xC6\x63\x11\x20\x53\x3D\xF0\xA3\xA7\xFA\x3F\x2D\x31\xB8\xF3\xB7\x6F\x1E\x3D\x2C\xEC\x5E\x70\xD8\xCF\xFD\x7C\x6B\x41\x20\x46\x00\x28\x89\xAD\x4C\x5B\xEA\x15\x16\x38\x37\xBC\x74\xD9\xEE\xC5\x28\x00\x02\x00\x45\xD9\xD3\x04\xDA\xD6\xD0\xFF\x20\xF6\xBD\x36\x18\x01\x80\x52\x1E\xFA\xF1\xB0\xB2\xF8\x6F\x7B\x9E\x96\xB0\x38\x2C\x4D\x03\x19\x09\x32\x0A\x80\x00\x40\x43\x16\x9A\xC0\x28\x40\x77\xB9\xE5\xCF\xAA\xFF\xE1\x42\xDF\x4C\x33\x20\x00\xA0\x38\x91\x75\x1B\xA7\xD7\x18\x3F\x75\x99\x8C\x02\x20\x00\xD0\x08\xC3\xFF\xA3\xF6\x08\x73\x9E\x06\x70\xE0\xCF\xF0\xF6\x8D\x02\x20\x00\x90\xB3\xB9\x26\x68\xBB\xAD\xD3\x2E\x05\x0B\xFF\xB6\x63\xA1\x09\x10\x00\xC8\x95\xE1\x7F\x61\xEB\xD0\xA5\x11\x00\x10\x00\x68\xCF\x13\x4D\xD0\x6E\xD8\x72\xFC\xF3\xD6\x55\xF1\x52\x28\x04\x00\x2A\x93\x16\x7E\x31\x6E\x31\x98\xE9\xFD\x1B\x05\x00\x01\x80\xA9\x09\x00\xE3\xCB\xE6\x80\x18\xBD\xFF\xD1\x3C\xF5\x92\x20\x04\x00\x04\x00\x72\x6A\x73\x3D\xD3\xF1\x98\x06\x40\x00\x40\x6F\x54\x9B\x67\xD1\xFB\x8F\x20\x62\xFD\x87\x00\x80\x00\x40\x6B\xD2\xFE\x7F\xA7\xBE\x8D\x2F\x97\xA2\xAB\xF7\x3F\x2E\x87\x2C\x21\x00\x90\x8D\x99\x26\x98\x34\x7C\x4D\xF9\xEF\xC7\x7C\xF4\xBE\x2B\x31\x7A\xBB\x1B\x05\x40\x00\x20\x0B\x86\xFF\xDB\x0D\x5F\x7A\xFF\xD3\x98\x6B\x02\x04\x00\x3C\x8C\x84\xAF\x29\x79\xE3\x9F\xEF\x1C\x02\x00\x0D\xB3\x2D\xA9\xC1\x00\xE0\xDD\x0F\x93\xDA\xB1\x1D\x10\x01\x80\x2C\x1E\x46\x9A\xA0\xC9\xF0\xB5\xD0\xFC\x6D\x86\x3F\x04\x00\xE8\xBC\xA1\x6C\x72\x53\xEE\x04\x10\x00\xA6\x35\xD7\x04\x08\x00\x4C\x49\x00\x68\x33\xF8\x45\xF1\xB1\xF5\xD3\x08\x00\x02\x00\x0D\x33\x0F\x99\x47\x31\x1E\x9B\x6D\x68\xC2\x37\x02\x00\x7A\x21\x34\x48\x00\x98\x9E\xB5\x37\x08\x00\xD0\xB8\x51\x47\x61\xAC\xFE\xCF\xC7\xD4\x07\x41\x21\x00\xA0\xF8\x30\xAD\xB1\x8B\xC0\x5C\x93\xFB\xFE\x21\x00\x80\x1E\x48\x7B\x0C\xFF\xFB\xFE\x21\x00\x00\x0D\xF2\xE6\x3F\x23\x00\x08\x00\x40\x4B\x26\xDA\x71\x00\x08\x00\xC0\x0D\x66\x23\xFE\x5B\x02\x40\x5E\x5C\x0F\x04\x00\x10\x00\x46\x61\xCE\x19\x04\x00\x40\x8F\x13\x10\x00\x80\xAA\xA5\xF7\x3E\x38\xFE\x17\x04\x00\xA0\x31\x33\x4D\x00\x02\x00\x90\x8F\xF7\x23\xFD\x3B\x73\x4D\x0D\x02\x00\x90\x8F\x53\x23\x00\x80\x00\x00\x08\x00\x20\x00\x00\x0C\xC6\x09\x80\x20\x00\xC0\xDF\xD6\x9A\x00\x26\xF3\x5E\x13\x20\x00\x20\x00\xB8\x06\x5B\xE3\x08\xE0\x6C\x9D\x6A\x02\x04\x00\x10\x00\x00\x04\x00\x14\x1F\x06\xE5\x08\x60\xDF\x3F\x04\x00\xF0\x00\xCA\xCC\x18\xC3\xC0\x5E\x3B\xEB\xFB\x87\x00\x00\x1F\xB1\x08\x69\x62\x6F\xDF\x3C\x72\x0D\x7C\xFF\x40\x00\x60\xF4\xE2\x63\x11\xD2\xB4\xDE\x8D\xF4\xEF\xCC\x34\xB5\xEF\x1F\x02\x00\x4C\x55\x84\xF8\xB7\xB5\x00\xD0\xAC\x33\x4D\x80\x00\x40\x2B\x45\x88\x7F\xD3\x03\xF4\xBD\x03\x01\x00\x45\x48\x11\xC0\xF7\x0E\x04\x00\x14\x21\x45\x00\xD7\x1E\x01\x00\x3C\x88\xEA\xF3\xF6\xCD\xA3\x95\x56\xF0\xBD\x03\x01\x00\x45\xA8\x2D\x16\x5F\x36\x7C\xED\xFB\xEF\xDD\x5A\x33\x20\x00\x90\x03\x2B\x92\xC7\x27\x78\xB9\xF6\x20\x00\xE0\x81\xD4\x20\x43\xC0\xBE\x6F\x20\x00\xA0\x18\x29\x02\xB8\xF6\x20\x00\xE0\x81\x54\xBB\xF3\x91\x4F\x81\x5B\x6B\xF2\x6C\x98\xFF\x47\x00\x20\x1F\xE9\x81\x64\x51\x5A\xBD\x81\x4B\xC1\xC9\xC7\xB1\x26\x40\x00\xC0\x83\x49\x00\xC0\xB5\x07\x01\x00\x0F\x26\x61\x6B\x6B\xBC\x75\x2E\x0F\x31\xF5\x23\x68\x23\x00\x90\x17\x0F\xA6\xD1\x9C\x4D\x30\x07\x6C\x91\x67\x9B\xC1\x0F\x01\x00\x6E\xED\xB5\x26\xD8\xBA\x95\x26\x10\x00\x40\x00\xC0\x03\xAA\x3D\xCB\xB1\xFF\x41\xA7\x3D\x66\xC1\xF0\x3F\x02\x00\x02\x40\xC3\xDE\x8D\xBC\xFD\xEF\xA3\x02\xA4\xF9\x7D\xB7\x10\x00\xE0\x73\x3D\xC5\x58\x2C\xF6\x4A\x4B\x6C\xCD\xD1\x84\xFF\xB6\x75\x00\xED\x5E\x7B\x04\x00\xD0\x53\x69\xB8\x6D\x05\x80\xE9\x4C\x39\xF2\x43\x81\xFE\xAB\x09\xA6\xF7\xDD\x0F\x7F\xED\xF6\x3F\x1E\x7E\xE9\xA1\x9A\x7A\xCD\x35\x8D\x02\x1C\xF7\x7F\x77\x1C\x0A\xF4\xD8\x1D\x30\xA8\xD7\x13\x9F\x00\xB7\x76\x09\xF4\xFE\x11\x00\xF8\x77\xA1\x8F\x22\x3F\x4F\x9F\xDD\xF4\x79\x70\xCB\xFF\xDB\xF8\x71\x92\x1E\xB0\x91\xF2\x57\x15\xA4\xFD\x65\xFF\x79\xEE\xCE\x18\xBC\x4D\xA7\xA4\x07\x3A\x8D\xF3\x0C\xAE\x3D\x85\xF9\xE6\xE2\xE2\x42\x2B\x6C\xB7\xE8\xCF\xFA\x1F\x8B\xFE\xB3\xD7\x7F\x76\xB6\xF0\xA5\x8F\xE1\xDE\xE3\x12\x57\xFE\xA6\x40\xF4\x7F\xEE\x92\xC1\xC4\x10\xF0\x2C\x83\xEB\xEA\xA1\x32\xBE\x57\xFD\xB5\x5F\x68\x06\x8C\x00\xE4\x51\xD8\xA2\xE0\x1F\x6C\xA1\xE8\x5F\x17\xA3\x07\xFB\xF1\xE9\xFF\xCD\xAB\x30\x70\x54\xCA\xC8\x40\x4C\x6B\xF4\xBF\xF7\xAB\xF4\x37\x50\x7E\xEF\xFF\x4A\x8C\x54\x3D\x71\x39\x46\x75\xA8\x09\xD8\x94\x45\x80\x03\x17\xFE\xFE\x13\x5F\xC4\x75\xFF\x79\xB9\xE5\xE2\xFF\xB9\x30\xF0\x67\xFF\x3B\xAC\xFA\xCF\xDC\x83\xAB\x29\x11\x00\x73\x99\x03\x36\x0D\x30\x7E\xEF\x7F\xAD\x19\x10\x00\xA6\x2B\xFE\x57\x85\xFF\x79\x77\xCB\x79\xFD\x2D\x8A\xDE\xD7\x1F\x25\x04\x81\xF4\xE0\x3A\x71\x07\xDD\xDB\x51\x46\x0B\x45\x57\x2E\xC7\xA8\x96\x9A\x80\xBB\xB0\x06\xE0\xFE\x85\x7F\x9E\xBE\x80\x39\xAF\x66\x8F\xA3\x77\x0F\x72\xED\x25\xA4\x36\xFC\xC3\xDD\x74\xAF\xDE\xFF\x2C\x97\x00\x60\x6D\xC7\xA8\x4E\xFA\xEB\x3E\xD7\x0C\x18\x01\x18\xF9\x21\xD7\x7F\x8E\x53\xE1\xCA\x7D\x2B\xDB\xD3\xFE\x73\x9A\x46\x29\x72\x1C\x05\x58\x19\x05\xA8\xA6\xF7\x7F\x75\xD0\x93\xEB\x39\x8E\x43\x4D\x80\x00\x30\x7E\x8F\x75\x9D\x0A\x6B\x29\x62\x5A\xE2\x79\xFF\xBB\x9F\xA6\x9D\x09\xB9\x39\x70\x67\xDD\xB9\xF7\x9F\xE3\xFE\x6F\x07\x3D\x6D\xDF\x6B\xEF\x5F\x40\x00\x18\xB7\xF8\x1F\xA4\x5E\xFF\x83\x42\xFF\x84\x9D\x34\x1A\xB0\xC8\x6C\x14\x20\x16\x8E\x39\x1E\xB8\xF0\xDE\xBF\x00\x20\x34\x53\x0E\x6B\x00\x6E\x5F\xF8\x1F\xA6\x9E\x56\x4D\x5B\xD6\xB2\xDA\x3B\x9C\xDA\x78\x5D\x70\xB8\x1A\x5B\x16\xFB\xFE\xBF\x70\x3D\x4F\xBB\x71\x77\xC2\xB4\xE4\x45\x7F\xED\x05\x00\x8C\x00\x8C\x54\x98\x56\x5D\x7D\xFB\xD5\xF7\xD3\x94\xC0\xC3\x4C\x46\x01\xDE\x77\x8E\x33\xDD\xC4\x22\xF3\xDF\xCF\xB5\xDC\x8E\x98\xF6\x39\xD4\x0C\x08\x00\xE3\x15\xFF\x5A\x7B\x32\xF1\x77\xAD\x72\x59\x17\xD0\x87\x80\x78\xB0\x9D\xB9\xF3\xBE\xAA\x84\xF9\x5F\xD3\x00\xDB\x71\x58\xDB\xBB\x41\x10\x00\x14\xFF\x69\x43\xC0\x69\x7A\x29\x91\x9E\x6D\x19\x3D\xC0\xEC\xDB\xC8\x6B\x9F\xB7\x22\xB6\xFD\x19\x59\x41\x00\x50\xFC\x07\xF5\x20\x8D\x04\x4C\x1E\x02\xD2\x82\xC0\x5F\xDD\x85\x9F\x0F\x48\x05\xF5\x00\x97\x2E\xD7\xA0\xCC\xFB\x23\x00\x28\xFE\xD5\x87\x80\xC3\xCE\x54\xC0\x4D\x5E\x95\xF4\xE2\xA7\x34\x4D\xE1\x3A\x0E\xE3\xD7\x0A\xDE\x00\x8A\x00\x90\xBD\xA3\xAE\xDD\xD5\xCB\x57\x21\x20\x87\x85\x81\xF1\x42\xA5\x73\xB7\xE3\xDF\xDE\x15\xDA\x03\x34\x64\x7D\x7F\x67\x29\x14\x83\x00\xB0\xC5\xDE\x7F\x6D\x5B\xFD\x8A\x0D\x01\xE9\xE8\xE2\x85\xBB\xF2\x83\x08\x42\x7B\x25\x2E\xFE\xEA\x7F\xE7\x65\x0A\x2F\xDC\xFD\xDA\xFB\x1E\x20\x00\x6C\xB9\xF8\x47\x8F\xF3\x67\x2D\xF1\x41\x8C\x80\x4C\x3E\xD4\x9C\x86\xBB\x5F\xB8\x1C\x1F\xDE\xE5\x50\xF2\xF0\xAF\xDE\x6B\xBB\xD7\x9E\x4C\x39\x08\xE8\x9F\xE2\x3F\xEB\x2E\x5F\x63\xEA\x10\x9A\x8F\x65\x71\xE0\x48\x7A\xEF\xC2\x53\xD7\xA0\xE8\xEF\xD8\xBA\xCB\xFF\xBD\x19\xB9\xC9\xEA\xB0\x2E\x8C\x00\xD4\xEA\x58\xF1\xBF\xD1\xCF\x99\x1C\x1B\x1C\xBF\x43\x8B\x8B\xC9\x5E\x55\x74\xE2\x9B\x42\xB6\x99\xB8\xDF\xAD\xFA\x47\x00\xD8\x72\xCF\xE4\xB0\x73\x64\xE9\x97\x1C\x4D\xBD\x33\x20\xCD\x7D\xCF\x1B\x0B\x01\x27\x35\xF5\xFE\xBC\xF5\x71\x23\xC5\xAE\xF9\x40\x00\x28\xA9\xF8\x47\x61\x7B\xEE\x56\xF8\xA2\x18\x19\x59\x66\x50\x40\x5A\x0A\x01\xF1\x37\xEE\x55\xF8\x77\x19\x05\xB8\x9D\xBD\xB4\x08\x16\x04\x80\x2D\x5A\x6A\x82\x5B\xD9\x49\x3B\x24\x84\x80\x71\x8A\xFF\xBC\xC6\xDE\x5F\x2A\x6A\x0E\x79\xFA\xB2\x67\x5E\xF3\xCB\x18\x9A\x5E\x04\x98\x5E\xED\xFB\x9B\xDB\x60\x23\x3F\xE6\xF0\x70\xAA\xF8\xB0\xA6\x26\x16\x7D\x79\x53\xE0\x67\xFD\xE2\xA8\x5F\x8C\x00\x8C\x53\x40\x0E\xDD\x02\x1B\x5B\x66\xD2\x93\xBC\x1A\x09\x78\x5D\x51\xDB\xBE\x68\x68\xC5\xB7\x43\x9E\x6E\x0E\x7F\x8A\x3F\x02\xC0\x08\xA2\xF8\x5B\xF5\xBF\xB9\xC7\x69\xD1\x64\x16\x21\xA0\xFF\x44\x21\xA9\x61\x48\xF9\x59\x4B\xEF\x77\x4F\x53\x01\x56\xB8\x7F\x5C\xFC\x17\x9A\x81\x31\x35\x39\x05\x90\xF6\xFC\xFF\xCF\xE5\xBF\x97\x6F\x73\x5A\xA4\x94\x0E\x71\x5A\x16\x18\xEA\xE2\x84\xBC\xBD\x56\x0F\x7A\x49\xEB\x4A\x5A\x3F\x7C\x4B\xF1\xC7\x08\xC0\xC8\xBD\x7F\xEE\x27\xAB\xA1\xCA\x74\x62\x60\x04\xBB\x92\xB6\x99\xC5\x09\x87\xBB\x2D\x9F\xF2\x96\x46\x3D\x5A\xDE\x1A\xF8\x42\xF1\xC7\x08\x80\xDE\x7F\x89\x7E\xCC\x71\xB5\x72\x3A\xB8\xE8\x28\xE3\xD1\x80\xE8\xF5\x2F\xAC\xF4\xFE\xFB\x7A\xB5\xFA\xF6\xCD\x67\xE9\x3D\x09\x60\x04\x40\xEF\x5F\x5B\x0E\xD4\xAB\x5C\xA6\xD1\x80\xDC\xDE\x21\x10\x8B\xDE\xE2\x95\xAE\x33\xC5\xFF\xA3\xEB\xD5\xDA\x21\x4F\x71\x1F\xFC\xA4\xF8\x63\x04\x60\xFC\x9E\xC6\xFF\xB9\xEC\xED\xF4\x62\xD2\x88\x4F\x04\x95\x29\xDF\xF0\x18\x0F\xFC\x18\x91\x38\x72\xB2\x5B\xF3\x23\x01\x4D\xAF\xF9\x40\x00\x98\xF2\x01\x13\x85\xC0\xA9\x7F\x03\x3F\xD0\xA2\x47\x5B\xC0\xB5\x8F\xDF\x31\xE6\x9B\x17\xDD\x78\x53\x03\xF1\xB0\x5F\x2A\xFC\x42\x40\x12\x5B\x56\x17\x35\xDD\x0B\xE9\x24\xD5\xB8\x66\x57\x3F\x3F\x15\x7F\xEB\xA9\x11\x2F\x01\x20\x87\x9B\x75\xDD\x79\x1B\xD9\x36\xFC\x94\x16\xE1\x95\x72\x1F\x44\x08\x88\x5D\x03\xF3\x2D\x84\x81\xE8\xED\x47\x5B\x1C\x97\xD4\x26\x19\x86\x80\x68\xBB\x27\x15\xFD\x59\xC5\x1F\xF0\x93\x42\xF4\x3C\x7D\x76\xEF\x10\xD2\x4E\xAE\x7D\x37\xD6\xEE\x74\x01\x60\xEC\x87\xFE\x4B\x97\x7C\x2B\xE2\xA5\x35\xF3\x42\xEF\x8B\xF9\x27\x0F\xB5\x4D\x03\x41\x14\xFC\xD3\xD4\x6B\x3D\x36\xB4\x3B\xE8\xB5\xA9\x61\x8B\xE0\x59\xEA\xF5\x9F\x16\x7A\x0D\xE2\x3B\xB1\x48\xDF\x8F\x9D\x81\xDB\x65\x29\x0C\x08\x00\x63\xDD\xC8\x2D\xBF\x4F\x7E\x0C\x3F\xD6\x30\xCC\x97\x7A\x9F\xD7\x87\x35\x6F\x72\xF5\x77\x9E\x1A\xDA\xDF\xFA\xF5\x28\xF5\x7C\x87\x0F\xEB\x3E\xFA\xFB\xE3\xB0\xD0\xEF\x40\xB4\xFB\x41\x37\xCE\x54\xCC\xEB\xD4\x56\x2B\x77\xBC\x00\xB0\x8D\x1B\x7A\xD6\xD9\xFA\xB7\x6D\x0E\x33\x61\x9B\xDF\xDF\x08\x01\xA5\x4C\x09\x44\x41\x3B\x28\xAD\x67\x9B\xDA\x79\x91\x0A\xFF\x14\x81\x2B\xD6\xCC\x1C\xDA\x1D\x21\x00\x0C\x7D\x63\x7B\xE9\xCF\x38\xBE\x35\x9C\xC7\x16\xBF\xC7\x51\x9C\x72\x3E\xDF\xE1\x24\x15\xB0\x55\x61\xED\xFA\x30\x15\xFD\x5C\x16\x48\x0B\x02\x23\x69\xE5\x1C\x00\x3D\x53\xED\x4C\xE1\xAE\x9D\xEF\x10\xEF\x7E\xC8\xE9\x45\x42\x51\xF8\x63\x0A\x6C\x5E\x60\xF1\x8F\xC2\xBF\xEE\xF2\xDA\x1D\x15\x0B\xB5\x5F\xC6\xA2\xED\x34\x05\x84\x11\x80\x3B\xDF\xE0\xF1\xC0\x30\xFC\x3F\x52\x72\x2F\x61\x4B\x20\x55\x7C\xAF\xAF\x7A\xAD\x53\x0D\x57\x87\x57\xDD\xE5\xDC\xF5\x69\x81\xED\x17\xEB\x5B\x22\x50\x95\xB0\xDD\x32\x02\xD6\x81\x05\xB6\x02\xC0\x5D\x13\xAE\xE1\xFF\xF1\xFC\x68\x31\x0F\x23\x7F\xC7\x17\xDD\xE5\xA2\xB5\x31\x16\xF9\xC6\xFC\xFE\xD5\x56\xB6\xF7\x85\xB6\xD7\x61\x57\xE6\x79\x28\x71\xB2\xE7\xA1\x85\xB7\x02\xC0\x26\x37\xBB\xD5\xFF\x23\xF7\x8A\x2C\x06\x64\xC2\x51\x81\xAB\xF3\x1D\xE2\x33\xC4\x99\x1F\x31\x1F\xBD\xEA\xFE\xD9\xE6\xF9\xBE\xF0\xF6\x29\xFD\x7C\x05\xEF\xD1\x10\x00\x36\xBA\xE9\x2F\x5C\xE6\x51\x9D\xF7\x5F\xCE\x87\x9A\x81\x0C\xBE\xFB\xB3\xEE\x72\x2B\x67\x7C\x66\xE9\xD3\xA5\x9F\xD7\xC3\x41\xEC\x49\xBF\x2A\xEC\xA7\xE9\x7F\x8E\x02\x53\xCD\x36\xCF\x34\xE4\x7F\xDC\xD5\x73\x10\x9A\xD1\x00\x01\xE0\xAB\x37\x7D\xF4\x06\x7E\x77\x99\x47\xF7\x93\x53\xF0\x20\xAB\xE7\xE0\xB2\x2B\xEF\x2C\x85\xAF\x29\xFA\x90\xA5\x1C\xD4\xBE\x0B\x60\xEE\x12\x4F\xC2\xCA\x5D\xC8\xA3\xF8\x2F\x52\x27\xE8\x41\x85\x7F\x5E\x2C\x60\x5C\xA5\xBF\x11\x01\xE0\x5F\x76\x5D\x62\x01\x00\x1A\x2E\xFE\xB5\x1F\x7F\x1E\xC1\xE6\x65\x3A\x36\x9A\x0D\xD5\x3E\x05\x60\xFE\x7F\x3A\xDF\x1B\x9A\x03\xC5\x7F\x44\xD5\xBD\x6D\xD1\x08\xC0\xDD\xBF\x00\x73\x97\xD7\x28\x00\x28\xFE\xCD\x88\xDD\x5E\xAB\xB4\xDB\x81\x96\x03\x40\x67\xF8\x7F\x6A\x02\x18\x4C\xD3\xF1\x69\xF9\xAD\xA7\x3B\x42\x80\x00\x20\x00\x4C\xEF\x89\x26\x80\x51\x8B\xFF\xD5\x56\xBF\xD6\x09\x01\x02\xC0\xDF\x7B\x7E\x99\xB6\x37\x02\x6C\xFF\xBB\x16\xC5\x6E\xD9\xD5\xB9\xDA\x5F\x08\x10\x00\xF4\x40\x0B\x24\x00\xC0\x38\x96\x5D\x19\xE7\xFA\x0B\x01\x02\xC0\xD6\xD3\xB0\xDE\x7F\x1E\x4C\xC3\xC0\xF6\x9F\x77\xF1\xBE\x13\xC7\x9D\x0B\x01\x02\x40\x22\x00\x08\x00\xD0\x42\xF1\x8F\x67\xDD\xA1\x96\xF8\x6A\x08\x70\x4E\x80\x00\xC0\xC8\x1E\x4B\xDE\xB0\x55\xCB\xCE\xBC\xFF\x6D\xEC\xA7\xB7\x20\x22\x00\x60\x14\x00\x8A\xEF\xFD\xC7\xD0\xBF\xB5\x4E\xB7\xF7\x3C\xBD\x17\x81\xCA\x03\x80\x5E\xA7\x00\x00\x35\x17\xFF\x78\xC6\xE9\xD1\x6E\x6E\x69\x8D\x58\xFD\x01\x40\xD1\xC9\x87\x2F\x1B\x0C\x2F\xE6\xB4\x0D\xFD\x6F\x2E\xDA\xCC\x59\x09\x95\x07\x00\x84\x31\xA8\xB5\xF7\x3F\xEF\x7F\xEC\x6B\x89\x3B\xDB\xB1\x1E\xA0\xEE\x00\x60\x0A\xC0\x08\x00\xD4\x4A\xF1\xBA\xBF\xE7\xE9\xE4\x44\x01\xA0\xC6\x84\xE7\xFE\xCE\xC6\x63\x4D\x00\x83\xF6\xFE\x2D\xFC\x1B\xC6\x52\x00\x80\xED\x3F\xB4\x8C\xC8\x80\xDE\x7F\x76\x1D\xC5\xD6\xA7\x02\x04\x00\xC6\x60\x1D\x00\xE8\xFD\xE7\xE8\xA0\xE5\x5D\x01\x02\x00\x40\x21\xC5\x4A\x13\x0C\x2E\x76\x05\x34\x3B\x0A\x20\x00\x30\x86\x99\x26\x80\x7B\xF5\xFE\xE3\x3B\xE4\xBC\xFF\xED\xD8\x6F\x75\x41\xA0\x00\x80\x00\x00\x7A\xFF\xAD\x6B\xF2\x5D\x01\x02\x00\x40\xFE\x16\x9A\x60\xAB\x9E\xA4\x35\x16\x02\x00\x00\x79\xE8\x0B\x53\x14\x7F\xA7\xFE\x6D\x5F\x73\xA3\x2C\x02\x00\x40\xDE\xBC\xC0\x66\x1C\x4F\x5B\xDB\x11\x20\x00\x30\x06\xE7\x00\xC0\xDD\x7A\xFF\xF1\xDD\xB1\xF8\x6F\x3C\x87\x02\x00\x0C\xCB\x39\x00\xA0\xF7\x5F\x44\x7B\xB7\x74\x70\x59\xAD\x01\xE0\x9D\xFB\x18\x10\x00\xD8\x50\xAC\xB5\x58\x08\x00\x65\x5B\xBB\x8F\x81\x92\x19\xFE\x9F\x8C\x00\x00\x03\x3A\xD5\x04\xB0\xB1\xB9\x26\x98\xC4\x4E\x2B\x07\x03\x19\x01\x60\x0C\xEF\x35\x01\x6C\xCC\xF0\xBF\x51\x00\x01\x40\x00\x00\x8C\x00\x20\x7C\x09\x00\x00\x55\x4B\xFB\xD1\x1F\x6B\x89\xC9\x3C\x6E\x61\x1A\xA0\xD6\x00\xB0\x72\xFF\x02\x7A\xFF\x18\x05\x68\x2F\x00\x98\x73\xCE\xCB\x5A\x13\xC0\x46\x9C\x9D\x21\x00\x08\x00\x77\xF1\xF6\xCD\x23\xAB\xCE\x05\x00\x10\x00\xB8\x8F\x9D\xDA\x0F\x05\xFA\x6F\xC5\x7F\x5B\x1C\x06\x64\x0E\x8D\x66\xA4\x79\xE3\xD9\x27\x45\xE4\x4B\x0F\xB0\x08\xCA\x9F\x8E\x96\x9D\xF6\x01\xDA\x08\xDA\xF4\x9E\x68\x82\x2C\xCC\xFB\xCF\xB1\x00\x50\x66\xAF\x53\x00\xC8\x83\x11\x99\x61\x8B\xFC\xEE\xB5\xCF\xC3\xA1\x8B\x45\xFF\x6F\x5C\xFD\x8F\x27\xE9\xE7\x2A\x05\x85\x53\x01\x61\x94\x6B\xAC\xF7\x2F\x00\x08\x00\xF7\xB4\x92\xA2\xF3\xA0\x60\xDC\xAB\x18\xCC\xD3\x43\x68\x9E\x0A\xFE\x98\xAF\x85\x7D\x72\x53\x6F\xB4\xFF\x9D\xDE\xA5\x30\x10\xDF\xB1\x95\x29\xB7\xC1\x09\x00\xAE\x85\x00\xA0\xD7\x59\x05\xEF\x65\xD8\xAC\xE0\x47\x8F\x7E\x2F\x7D\xE6\x5D\x9E\xEF\x81\x7F\x9C\x3E\x4F\xD3\xEF\x7C\x9E\x7A\x49\xC7\x29\x10\x08\x7C\xF7\x33\xD3\x04\xD9\xA8\xBA\x13\x29\x00\xB0\x6D\x6B\x4D\x70\xAB\xC2\xBF\x48\x45\xBF\xC4\xB3\xDF\x23\xA4\xEC\xA7\xCF\x79\xFF\xB7\x7C\x08\x03\x7D\x10\x38\x76\x65\xEF\x64\xAE\x09\xB2\xFA\x6E\xEE\xD6\x3A\xCA\x55\x6D\x00\xE8\x2F\xD8\x3A\xF5\x4C\x1E\xB8\x85\x05\xB1\x4C\x1F\x2C\xD1\xD3\x3B\xE8\x2E\x8F\x1D\xAD\xE5\x3E\xFD\x3B\x0C\xA4\xA9\x82\xA3\xFE\xB3\x34\x2A\xB0\x91\x87\x9A\x20\x2B\xBB\xB5\x3E\xC7\x6A\x3F\x09\x70\xE5\xDE\x35\x02\x90\x61\xE1\x9F\xA7\x5E\xF2\xFF\xFA\xCF\xCF\x15\x87\xD4\x98\x26\xF8\x2D\xEE\x81\xFE\xEF\x3D\x6C\xE9\x3D\xEB\xF7\xB4\xA3\x09\xB2\x32\xAB\xF5\x0F\x13\x00\x30\x02\x30\x6E\xE1\x8F\x7B\xF2\x8F\xAE\xAD\xD7\xBC\x46\xC0\x79\x2E\x08\xDC\xEA\x1E\xD1\x36\xF9\x99\x0B\x00\x02\x00\x77\xF0\xF6\xCD\xA3\xE6\xAF\x41\x0C\xF5\xA7\x1E\x7F\x14\xFE\x96\x77\xA6\x5C\x05\x81\xD3\xBE\x3D\xBC\xE9\xEE\x66\x76\x00\xE4\xA7\xDA\x50\x56\x75\x00\x48\x0B\x37\xCE\xDD\xBF\x93\x39\x6B\xBD\x37\x17\x3D\xDE\xEE\x72\xA8\xFF\xA9\xDB\xE1\x6F\x31\x35\xF0\x7B\x84\x22\x3D\x5E\x0A\x50\xED\x94\x4C\x0B\x6F\x03\x34\x0A\x30\x9D\x66\x87\xFF\xD3\xFE\xFD\xD3\xD4\xE3\xE5\x66\x11\x8A\xD6\x46\x03\x8C\x00\x94\x10\xE6\x05\x80\x32\xD9\x8A\x24\x7C\x8D\xDD\xEB\x8F\x95\xEF\x7F\x74\x4E\xA2\xBC\x8D\x07\x69\x34\x60\x69\x34\xE0\x03\x6D\x20\x98\x09\x00\x02\x80\x11\x80\x02\x8B\xFF\xD5\x76\xA1\x9F\x5D\xFA\x8D\xC5\xD6\xC1\x55\xDA\x1A\x09\x08\x00\xF7\x97\xF6\x1F\x9F\xB8\xD4\xA3\x3B\x6F\xE9\x88\xD8\x74\x90\xCF\x9F\x7A\xFD\xF7\x12\x73\xAD\xA7\xCE\xC2\xC7\x08\x80\x00\x60\x14\x40\x9B\x97\x52\xFC\x97\xFD\x8F\x97\x2E\xF9\x20\x1E\xA4\x91\x80\x45\xA3\x7F\xFF\xDC\x2D\x90\x25\x6B\x00\x14\x23\x36\xB0\x6A\xA0\xF0\xC7\x7C\x7F\x8C\x72\xEC\xBB\xDC\x83\x87\x80\x97\x0D\x87\x00\x10\x00\x86\x12\xC7\x02\xF7\x3F\x5E\xBB\xDC\x42\xD7\x80\xC5\x7F\x96\x42\x8E\x53\xDB\xB6\x47\x08\x00\x01\x40\x41\x2A\xCC\x49\xCD\x67\xBF\x5F\x5B\xEC\xA7\xF8\x0B\x01\xB4\x61\x26\x00\x94\x3D\x0A\xB0\xEC\x1C\x0A\x24\x6C\x0D\x53\xFC\xA3\xE7\xEF\x25\x53\x42\x00\x02\x80\x00\x50\x90\xA5\xFB\x58\x00\x50\xFC\x8B\x0D\x01\x76\x07\x80\x00\x70\x67\x47\x2E\xF9\xD6\xBD\x4E\x6B\x2E\x14\x7F\x86\xB6\x12\x02\x40\x00\xB8\x93\x54\x98\x9C\x09\xA0\xF7\xBF\x69\xF1\x9F\x29\xFE\x59\x88\xF6\x77\x62\x20\x08\x00\x77\x76\xE8\xB2\x6F\xCD\x79\x6D\x01\x20\x15\x9B\x63\xC5\x3F\x1B\x3B\x9D\x05\xBD\x20\x00\xDC\x71\x14\x60\x65\x14\x60\x7B\xBD\xFF\x0A\x57\xFF\x1F\x77\x56\xFB\xE7\xE6\x49\x7A\xCB\x22\x20\x00\x6C\x6C\xE9\xD2\x6F\x45\x55\x0F\xE5\x74\xC2\xDF\x13\x97\x35\x4B\xCF\xD3\x1B\x17\x01\x01\x60\xA3\x51\x80\x78\xB0\x9F\xB9\xFC\x83\x3A\xA9\x69\xF1\x5F\xDA\x76\xE6\x84\xBF\xBC\x1D\x57\xB8\x1E\x60\xED\xB2\xBA\x2E\x02\xC0\xF6\x1D\xB8\xA7\xF5\xFE\x3F\x53\xFC\x63\xA5\xB9\xB3\xFD\xF3\xF7\x61\x51\xA0\x42\x83\xEB\x22\x00\x6C\x3A\x0A\xB0\xEA\xAC\x05\x18\xB2\xF7\xBF\xAA\xA4\xF8\x5F\x2D\xFA\xA3\x0C\x4F\xFB\x6B\x26\xCC\x83\x00\x60\x14\x40\xEF\xFF\xDE\xA2\x47\xE9\x95\xBE\x65\xF9\xCD\xF9\x00\x20\x00\x6C\x3A\x0A\x10\xE7\xB9\xBF\x72\x1B\xE8\xFD\xA7\xDE\xFF\x22\x7A\x94\x2E\x69\x99\xC1\xAD\x92\xF5\x00\x2B\x97\x32\x4B\x55\xBE\xDB\xE4\x3F\xAE\xEB\x87\x51\x00\xEF\x08\x68\xBC\xF7\x9F\x0E\xFB\x71\x52\x64\xB9\x76\x5C\x3F\xB6\xE8\x54\x00\xA8\x73\x14\xE0\x7D\x67\x2A\xE0\xAE\x5E\xD7\xD2\xFB\xEF\x2E\x87\xFE\x1D\xF6\x53\xB6\xFD\x0A\x5E\x1A\xB4\x76\x19\x11\x00\xC6\x0D\x01\xF1\xF0\xB7\x20\x70\x33\xE7\xB5\x04\xA7\x74\xA8\x8C\xFD\xFE\x75\x38\x2A\x79\x3D\x40\x8D\xEF\xD1\xA8\x44\x95\xD7\x45\x00\xF8\xC7\xA2\x33\x15\xB0\xD1\x83\xB6\x86\x87\x55\x2A\x16\xCF\x5D\xCE\x6A\xD4\xB0\x35\xF0\x9D\xCB\x28\x98\x09\x00\xE3\x5F\x60\x53\x01\xB7\x73\xD6\xB7\xD7\x61\x05\xC5\xDF\x96\xBF\x3A\xED\xF4\xD7\xB6\xE4\xF5\x00\x46\x01\x04\x32\x01\x60\x82\x10\x10\x3D\x07\xBB\x02\xBE\x6E\x51\xC9\xDF\x11\x45\xC2\x96\xBF\x3A\xFD\xDC\x87\x80\xBD\x42\x7F\xF7\x53\x97\x4F\x20\x13\x00\xA6\x11\xA3\x00\x8E\x09\xFE\xBC\x5F\xD3\xF6\xC9\xD2\x7B\xFF\x51\x1C\x1C\xF5\x5B\xB7\x65\xDA\xDD\xA1\xE0\x20\x90\x09\x00\xB7\x1A\x05\x78\xDF\x59\x0F\xF0\x39\x27\x95\x0C\xFD\x47\x51\x58\xBA\x9C\xD5\x8B\xF5\x00\x25\xBE\x2F\xC0\x08\x80\x40\x26\x00\x4C\x18\x02\x4E\xBB\x7A\x86\xB9\x87\x12\x81\x68\xAF\x92\xBF\xE5\xB8\xB3\xE5\xAF\x15\xC5\x9D\x0F\x50\xD1\xD6\x5A\x23\x00\x02\x40\xB1\x21\x20\x8A\xC4\x33\x2D\xF1\xB7\xBD\x34\x3A\x52\x7A\xEF\xFF\x28\x15\x05\xDA\x51\xE2\xF9\x00\xA6\x21\x05\x32\x01\x60\xE2\x0B\xBF\xEC\x2C\x0A\x0C\xCF\x6A\xF8\x12\xA4\xF7\xC7\xFF\xEC\x72\x36\xA9\xB4\xF3\x01\x4C\x03\x08\x62\x02\x40\x06\x21\x60\xD1\x78\x08\x78\x95\x82\x50\xE9\xC5\xDF\x96\xBF\xB6\x7D\x38\x1F\xA0\xA0\xF5\x00\x2B\x97\x4C\x10\x13\x00\x84\x80\xA9\x8B\xFF\xA2\x92\xBF\xC5\xBC\x3F\x31\xF5\x53\x4A\x98\x15\x00\x5C\x07\x01\x40\x08\x50\xFC\x07\xE8\xFD\xC7\xBC\xBF\xA3\x7E\x09\x4F\xFB\xFB\x21\xFB\x03\xBF\xD2\xC1\x64\x4E\x04\x14\x00\x04\x00\x21\x40\xF1\xBF\x47\xF1\x8F\x9D\x0B\xE6\xFD\xB9\xEE\xB7\xB4\x1E\x24\x77\xA6\xAC\xA6\xF5\xAE\xF6\x77\x33\x08\x00\x77\x0B\x01\x35\xEF\x0E\xA8\xA9\xF8\xCF\x3A\xFB\xFD\xF9\x4C\x71\x2D\x60\x3D\xC0\xCA\x65\x12\xC0\x04\x80\xFC\x42\x40\x14\x95\x1F\xBB\xFA\x0E\x0B\xFA\xA5\xA2\xE2\x7F\xB5\xE8\xCF\xBC\x3F\x37\x79\x90\x7B\x81\x4D\x5B\x91\x1D\x48\x26\x80\x09\x00\x19\x7E\x39\xE3\xE6\x88\x6D\x45\x35\x6C\x13\x89\x87\xCC\x4F\xFD\xDF\x74\x54\xD1\x25\xB2\xDF\x9F\xAF\x89\x97\x06\x2D\xF5\x42\xB9\xE9\x99\x98\x02\x98\x00\xC0\x67\x43\xC0\xBA\xFF\x44\x08\x78\x51\xF0\x9F\x11\x01\x66\xB7\xA6\x9B\x3D\x1D\xFA\xE2\x9C\x7F\x6E\x23\xF7\x43\x82\x04\x00\xED\xBE\x35\xDF\x5C\x5C\x5C\xB8\xD4\xC3\x14\x9D\x79\x77\x39\xDF\x5C\xD2\xDB\xE5\x7E\xAD\xE1\x6C\xFF\x4F\xAE\x43\x04\xB2\x3F\xDD\x91\x6C\xE8\xFB\x5C\x5F\x72\xD5\xDF\xD3\x71\x02\xA7\xA9\xAC\x71\xFD\xD8\xC2\x91\xCC\x46\x00\x86\x1B\x0D\x58\xF5\x9F\x59\x14\xD5\x2E\xFF\x79\xBB\xB3\xF4\xC0\xAB\xAD\xF8\xC7\xBC\xFF\xCA\xDD\xC8\x1D\xAC\x32\x5E\x14\xB8\x74\x79\x46\xF5\xAE\x95\xF7\x31\x08\x00\xC3\x07\x81\x28\xAA\xD1\x0B\xCD\x71\xBB\x60\xEC\x2B\x8E\x63\x7D\x77\x6B\x78\xA5\xEF\x4D\x0F\x71\x3D\x25\xEE\xE8\x41\xC6\x21\xE0\xC8\xE5\x11\xB8\x04\x80\x72\x42\xC0\x3A\xAD\xA6\xFF\x36\x93\x20\x10\x85\x3F\x46\x26\x76\x6B\x38\xD6\xF7\x33\xBD\xFF\xF8\xBB\x2C\xFA\xE3\x3E\xB2\x7C\x73\x60\xDA\x8B\xFE\xDA\xE5\x11\x00\x86\x66\x0D\xC0\x38\xC5\x69\xD6\x5D\xBE\x5E\x38\x3E\x63\xAE\x11\x88\xA1\xFE\xA3\x5A\x8B\xFE\xB5\xF6\x8D\x93\xDD\x7E\x73\xA7\x31\x90\x5F\x72\xDB\x11\x93\xD6\x18\xFD\xE1\xD2\x6C\x5D\x4D\xC7\x9F\x0B\x00\x19\x16\xAB\x38\x99\x2E\x3E\xF3\x2D\x85\x81\x28\xFA\xAB\x54\xF8\xD7\x8D\xB4\xE7\xEF\xEE\x2C\x06\xF6\x53\x6E\x3B\x63\xFA\x7B\x3D\xBE\xD7\x8E\xB4\xDE\xAE\x6F\x5B\x78\x6E\x0A\x00\x79\x7C\xA1\x77\x53\x10\x88\xCF\xEE\x1D\x03\x41\x14\xFC\xD3\x54\xF4\x57\x2D\xDD\xBC\xA9\xFD\xE2\xEF\x36\xEF\xCF\xD0\x62\x21\xEF\x3C\xA7\xB5\x32\x46\x01\xF4\xFE\x05\x80\x36\x8A\x5A\x2C\x44\x9A\xA5\xCF\xA7\xE2\x81\x14\xDB\x82\xD6\x2D\x15\xFB\x1B\xDA\xE9\x61\x6A\x8B\xC7\xEE\x1A\xB6\x24\xD6\xCE\xC4\xBA\x99\xF7\x46\x01\xF4\xFE\x05\x00\xC8\xA7\xF8\xC7\x83\xD0\xA2\x3F\xB6\xED\x2C\x8D\x04\xBC\xCF\xE4\xDE\x37\x0A\xA0\xF7\x3F\x18\xBB\x00\x28\x91\x63\x7E\x19\x4B\x56\x3B\x03\xD2\xFE\xF4\x57\x2E\xCB\xA0\x62\xBA\xE7\xB0\xC5\x3F\x5C\x00\xA0\xB4\xDE\x7F\x3C\x8C\x1D\xF3\xCB\x98\xE2\xB8\xE0\x9C\x0A\xC4\x41\xE7\x25\x41\x83\x76\x28\x5A\x9D\x4E\x35\x05\x40\x49\xC5\x7F\xD1\xFF\x78\xA9\x25\x98\xC8\xB3\x5C\xB6\xD4\xDA\xFA\x3A\x98\xB3\xF4\x3E\x97\x26\x19\x01\xA0\x94\xE2\xBF\xA7\xF8\x33\xB1\x97\x69\x0E\x7E\x72\xE9\x9C\x02\x87\x03\xDD\xDF\xA2\xE5\x3F\x5E\x00\xA0\x84\xE2\x1F\x09\x7D\xA9\x25\xC8\xC0\x71\xBA\x1F\x73\x29\x5E\xA6\x02\xEE\xEE\x97\x4A\x8F\x44\xBF\x35\x53\x00\x94\x50\xFC\x57\x9D\xBD\xFE\xE4\x23\x8A\xEE\x2C\x87\x9D\x01\x76\x05\xDC\xD9\xEB\xFE\xFA\xED\xB5\xDE\x08\x46\x00\xC8\xB9\xF8\xC7\x76\xBF\x63\xC5\x9F\xCC\x64\xF3\xE2\xA0\xB4\x2B\xE0\x17\x97\x64\x23\xB1\xB5\x73\xA1\x19\x04\x00\xF2\x2E\xFE\xF1\x70\x73\xD0\x0F\x39\xDA\xE9\x32\x79\xF5\x74\x5A\x0F\x60\x6B\xE0\xED\xC4\xE8\xCD\x22\xA7\xC3\x9D\x04\x00\xB8\xB9\xF8\xDB\xEB\x4F\xD6\x21\x20\xBD\x85\x32\x87\x10\x10\x3D\x5A\x8B\x02\xBF\x5E\xFC\xE7\xAD\xCF\xFB\x0B\x00\xE4\x6E\xA9\xF8\x53\x88\xFD\x5C\x42\x40\x77\x39\xAC\x7D\xE6\x92\x7C\xD6\x81\xE2\x2F\x00\x90\x77\xEF\x3F\x1E\xA6\x4F\xB5\x04\x85\x85\x80\x83\x0C\x46\x01\x62\x58\x7B\x2E\x04\xDC\xE8\x59\xED\xAF\x45\x17\x00\xA8\xA1\xF8\x3B\xE5\x8F\x12\xFD\x96\x0E\xAA\xCA\x25\x04\x58\x13\x70\x29\x86\xFD\x7F\x54\xFC\x6F\x66\x1B\x20\x8A\x3F\x54\xD8\xD3\xF4\x9D\x32\xE7\x2F\x00\xA0\xF8\xC3\xB8\x7E\xEA\x8B\xCE\x71\x26\xDF\xAD\x45\xD7\xE6\x09\x9A\x59\xBD\xC5\x51\x00\x80\x9B\x1F\x50\xCE\x34\x47\xCF\x73\xBB\xDF\xB1\xAB\x93\x34\x5B\x59\x58\xFB\xA2\x6F\xFB\x03\xB7\xE1\xD7\x59\x03\xC0\xD4\xBD\x13\xC5\x9F\xDA\x5C\x1D\x14\x94\xC5\x91\xC1\x29\x88\xCC\xA3\x30\x56\xDE\xEE\xEF\xBA\xCB\xF9\x7E\xC5\xDF\x08\x00\x05\x14\x7F\x2F\xF7\xC1\x48\xC0\xB8\xDF\xBB\x08\x02\x47\x15\x8E\x06\xFC\xDA\x5D\xBE\xD6\xD7\x90\xBF\x00\x80\xE2\x0F\x42\xC0\x57\xBE\x83\x11\x04\x4A\x3F\x66\x3B\x0E\x3F\x8A\xFD\xFD\x6B\xB7\x9A\x00\x80\xE2\x0F\x42\xC0\xED\xBE\x8B\x71\xE2\xE6\x41\xFA\x94\x16\x04\x4E\xFA\xCF\x61\x7A\x17\x02\x02\x00\x8A\x3F\x08\x01\xF7\xF8\x6E\x46\x10\xD8\xC9\xBC\x0D\x8F\x53\xE1\xD7\xE3\x17\x00\x50\xFC\xA1\xA8\x10\xB0\x9B\x73\xF1\x4A\x0B\x17\x23\x08\xEC\x65\x34\x2A\x10\xBD\xFD\x65\x14\x7F\x73\xFC\x02\x00\xE5\x15\x7F\x5B\xFD\xE0\x52\x31\xFB\xD3\xD3\x82\xC1\x08\x02\xF3\x91\x47\x06\x22\x28\xAD\x52\x6F\x5F\xD1\x17\x00\x28\xB8\xF8\x47\x72\x77\xC8\x0F\x7C\x1C\x02\xF6\x4A\x1A\xC6\x4E\xEB\x05\x22\x08\xEC\xA6\x9F\xB3\x6E\xB8\x57\x75\x47\x0F\xFF\xF4\xEA\xE3\xE4\x3E\x01\x00\xC5\x1F\x6A\x56\xC5\x31\xB5\x69\xCA\xE0\x61\xFA\xDC\xE6\xDC\x83\xF7\xA9\xD0\x77\xA9\xD8\xEB\xDD\x0B\x00\x28\xFE\x20\x04\xC0\x98\x9C\x04\x88\xE2\x0F\xD3\xC8\xEA\xC4\x40\x8C\x00\xC0\x7D\x0A\x7F\x0C\x03\x1E\x29\xFE\x60\x24\x00\x01\x80\xB6\x8A\xFF\xAA\x6B\xE7\x85\x23\x20\x04\x50\x34\x53\x00\x28\xFE\x30\x3D\xD3\x01\x08\x00\x14\x57\xFC\x67\x8A\x3F\x0C\x1A\x02\xE6\x9A\x02\x01\x80\xDC\x8B\x7F\xF4\x56\x4E\x15\x7F\x18\x34\x04\xFC\x91\x4E\xCE\x04\x01\x80\x6C\x8B\xFF\xAA\x2B\xFF\x6D\x62\x90\xA3\x97\x42\x00\x02\x00\x39\x16\xFF\x85\xE2\x0F\x42\x00\x65\xB3\x0B\x80\xBB\x14\x7F\x2F\xF5\x81\xF1\xBC\x7A\xFB\xE6\x91\x20\x80\x11\x00\x26\x2D\xFE\x47\x8A\x3F\x8C\x6E\x3F\x1D\xAE\x05\x46\x00\x98\xA4\xF8\xC7\x03\xC8\x01\x3F\x30\xE1\x48\x40\xFF\x39\x70\x7E\x3E\x02\x00\x63\x15\xFE\xD8\xE3\x1F\xAF\xE5\x7C\xA2\x35\x60\x72\xC5\xBC\x4E\x18\x01\x80\xF2\x8B\xFF\xAA\xB3\xCD\x0F\x84\x00\xAA\x63\x0D\x00\x9F\x2B\xFE\xB1\xCD\x6F\xAD\xF8\x43\x76\xE2\x3B\xB9\x76\x6A\x20\x02\x00\xDB\x28\xFE\x7B\x9D\x6D\x7E\x90\x33\x47\x07\x23\x00\x30\x78\xF1\x5F\xF4\x3F\x7E\x57\xFC\xA1\x88\x10\xF0\xA7\xB3\x02\x10\x00\x18\xA2\xF8\x2F\x3B\xDB\xFC\xA0\x34\x0E\x0C\xE2\x4E\x2C\x02\xC4\x4A\x7F\xA8\x83\x03\x83\x30\x02\xC0\x46\xC5\x7F\xD6\x5D\xCE\xF7\x2B\xFE\x50\x36\x07\x06\x61\x04\x80\x5B\x17\x7F\x2F\xF4\x81\xFA\xD8\x26\x88\x11\x00\xBE\x58\xFC\x17\xFD\x8F\x3F\x15\x7F\xA8\x4E\x6C\x13\x5C\xA5\xD1\x3D\x10\x00\xF8\xA8\xF8\x3B\xD3\x1F\xEA\x0F\x01\xA7\xB6\x09\xF2\x25\xA6\x00\xDA\x2A\xFC\xB1\xD8\x2F\x8A\xBF\x33\xFD\xA1\x0D\xE7\xFD\x67\xF1\xF6\xCD\xA3\x63\x4D\x81\x00\xD0\x76\xF1\x5F\x75\x4E\xF6\x83\x16\x3D\xEB\x43\xC0\x52\x33\x70\x9D\x29\x80\x36\x8A\x7F\x0C\x03\x9E\x2A\xFE\xD0\xAC\x97\x69\xEA\x0F\x8C\x00\x34\x56\xFC\xA3\xE7\x6F\xB1\x1F\xE0\xAC\x00\x04\x80\x46\x8A\x7F\x7C\xD1\x2D\xF6\x03\xAE\x3B\xE9\x3F\x7B\xB6\x09\x62\x0A\xA0\xDE\xE2\x7F\xA0\xF8\x03\x37\x88\x43\xBF\x56\x69\x5D\x10\x46\x00\xA8\xAC\xF8\x2F\x3B\x2B\xFD\x81\x2F\x8B\x1D\x02\x71\x60\xD0\xA9\xA6\x30\x02\x80\xE2\x0F\xB4\xC3\x2B\x85\x8D\x00\x18\x01\xA8\xA4\xF0\x7B\xA1\x0F\x70\xD7\x91\x80\x03\xDB\x04\x05\x00\xCA\x2D\xFE\xAB\xCE\x36\x3F\xE0\xEE\x9C\x15\xD0\x18\x53\x00\x8A\x3F\x40\x78\x99\x76\x0E\x21\x00\x50\x40\xF1\xDF\x55\xFC\x81\x81\x43\x80\x51\x80\x46\x98\x02\x28\xBF\xF8\x3B\xE0\x07\x18\x9A\x03\x83\x8C\x00\xA0\xF8\x03\x0D\xDA\x37\x12\x60\x04\x00\xC5\x1F\x68\x78\x24\xA0\xBB\xDC\x21\xE0\xD4\x40\x01\x00\xC5\x1F\x68\xCC\x59\x77\x79\x60\x90\x10\x50\x19\x53\x00\x8A\x3F\xC0\x97\xC4\x22\x63\x47\x07\x0B\x00\x28\xFE\x80\x10\x80\x00\x80\xE2\x0F\x08\x01\x14\xC9\x1A\x80\xBC\x8B\x7F\x7C\xD1\xE2\x45\x1D\x8F\xB5\x06\x90\x09\x6B\x02\x8C\x00\x30\x42\xF1\x5F\x29\xFE\x80\x91\x00\x04\x80\xF6\x8A\xBF\x13\xFE\x00\x21\x00\x01\xA0\x21\x4B\xC5\x1F\x10\x02\x10\x00\xDA\xEA\xFD\x47\xF1\x7F\xAA\x25\x80\x42\x42\xC0\x52\x33\x08\x00\xDC\xBF\xF8\x1F\xF4\x3F\xF6\xB5\x04\x50\x90\xA7\x8E\x0D\x2E\x93\x5D\x00\xF9\x14\xFF\x45\xFF\xE3\xA5\x96\x00\x0A\xE5\x05\x42\x46\x00\xB8\x43\xF1\x8F\xBD\xFE\x47\x5A\x02\x28\x58\xBC\x40\xE8\x50\x33\x18\x01\xE0\xF6\xC5\xDF\x5E\x7F\xA0\x26\xCF\xDE\xBE\x79\xB4\xD4\x0C\x46\x00\xF8\xBA\x63\xC5\x1F\xA8\xC8\xCB\xBE\x63\xB3\xA7\x19\x04\x00\xBE\xDC\xFB\x8F\x61\xFF\x27\x5A\x02\xA8\xCC\x32\x4D\x6D\x92\x31\x53\x00\xD3\x15\xFF\x48\xC8\xBF\x6B\x09\xA0\x52\xEF\xFA\xCF\xAE\x23\x83\x8D\x00\xF0\x71\xF1\x9F\x75\xF6\xCE\x02\x75\x8B\xA9\xCD\x95\x66\x10\x00\xF8\x58\x14\x7F\x6F\xF7\x03\x6A\xB7\xE3\x8C\x00\x01\x80\x7F\x7A\xFF\x71\xD8\x8F\x79\x7F\xA0\x15\xFB\xE9\x9C\x13\x32\x63\x0D\xC0\xB8\xC5\x3F\x16\xC5\xFC\xA9\x25\x80\x06\x7D\xFF\xF6\xCD\xA3\x53\xCD\x60\x04\xA0\x55\x0E\xFB\x01\x5A\x75\xEC\xC5\x41\x02\x40\xAB\xBD\x7F\x43\xFF\x40\xCB\x62\x51\xE0\x52\x33\xE4\xC3\x14\xC0\x38\xC5\x7F\xD6\x5D\x9E\xF6\x67\xE1\x1F\xD0\x3A\x27\x05\x1A\x01\x68\xCA\x91\xE2\x0F\x70\xF9\x3C\x4C\x9D\x22\x04\x80\xEA\x7B\xFF\xF3\xFE\xC7\x53\x2D\x01\xF0\x41\x74\x86\x8C\x00\x08\x00\x4D\x38\xD4\x04\x00\x1F\x79\x92\xD6\x45\x31\x21\x6B\x00\xB6\xDB\xFB\x5F\xF4\x3F\x5E\x6A\x09\x80\x7F\x39\xEF\x2E\x8F\x0A\x5E\x6B\x0A\x23\x00\x7A\xFF\x00\xED\x88\xA9\x00\x5B\xA3\x05\x80\x6A\x7B\xFF\x5E\xF3\x0B\xF0\x79\x4F\xD3\x3A\x29\x04\x00\xBD\x7F\x80\xC6\x2C\x35\x81\x00\x50\x53\xEF\x7F\x4F\xEF\x1F\xE0\x56\x1E\x7B\x57\x80\x00\x50\x13\xAB\x5B\x01\x6E\xEF\xD0\x31\xC1\x02\x40\x0D\xBD\xFF\x78\xE1\x8F\x23\x7F\x01\x36\x18\x05\xD0\x71\x12\x00\xF4\xFE\x01\xDA\xB4\xD0\x04\x02\x40\xE9\xF6\x34\x01\xC0\xE6\xA3\x00\xD6\x02\x08\x00\xC5\x4A\x37\xAF\x33\xFF\x01\xEE\xE6\x50\x13\x08\x00\x7A\xFF\x00\x6D\x8E\x02\xCC\x35\x83\x00\x50\x5A\xEF\x3F\x56\xB0\x7A\xE9\x0F\xC0\xFD\x58\x47\x25\x00\xE8\xFD\x03\x34\xE8\xA9\xD7\x05\x0B\x00\xA5\x99\x6B\x02\x00\x1D\x2A\x01\xC0\x0D\x0B\xC0\xDD\x2C\x34\x81\x00\x50\x84\x74\xF8\x8F\xD5\xFF\x00\xC3\xD8\x31\x0D\x20\x00\x94\x62\xAE\x09\x00\x06\x65\x54\x55\x00\x10\x00\x00\x3C\x57\x11\x00\xF2\xB4\xAB\x09\x00\x06\x65\x5B\xB5\x00\x90\xB7\xB4\xFF\xDF\xAB\x7F\x01\x86\x7F\xBE\x1A\x05\x10\x00\xF4\xFE\x01\x1A\x24\x00\x08\x00\x02\x00\x80\x00\x80\x00\x90\x97\x87\x9A\x00\x40\x07\x4B\x00\x90\x50\x01\x18\xC6\x03\xE7\x01\x08\x00\x00\xB4\x49\x00\x10\x00\xB2\x65\x88\x0A\x60\x7B\xE6\x9A\x40\x00\xC8\x95\x23\x80\x01\x8C\x00\x08\x00\x00\x20\x00\x08\x00\x55\x4B\x2F\x01\x02\x40\x00\x10\x00\x1A\x63\x0B\x20\xC0\x76\x39\x69\x55\x00\x00\x00\x04\x00\x00\x9A\xE0\x9D\x00\x02\x00\x00\x20\x00\x00\x00\x02\x00\x00\xB5\xB2\xE0\x5A\x00\x00\xA0\x41\xB6\x5C\x0B\x00\x00\x80\x00\x00\x00\x08\x00\x13\x58\x6B\x02\x00\x04\x80\xC6\xBC\x7D\xF3\x48\x00\x00\x40\x00\x00\x00\x04\x80\x56\x9C\x6B\x02\x00\x04\x80\xF6\x9C\x6A\x02\x00\x04\x00\x00\x40\x00\x68\xC0\x4A\x13\x00\x20\x00\xB4\xE7\xBD\x26\x00\xF0\x9C\x15\x00\xDA\x63\x0D\x00\x80\xE7\xAC\x00\xD0\xA0\xB5\x26\x00\x40\x00\x68\x8C\xC3\x80\x00\x74\xB4\x04\x80\x76\x9D\x68\x02\x00\x1D\x2D\x01\x40\x3A\x05\x60\x18\x0E\x5B\x13\x00\xB2\x66\x81\x0A\x80\xE7\xAB\x00\xE0\x06\x05\x60\x20\x6B\x4D\x20\x00\x64\xEB\xED\x9B\x47\x2B\xAD\x00\x20\x00\x08\x00\x6D\xB2\x10\x10\x60\x78\x3A\x58\x02\x80\x9B\x14\xA0\x41\xA6\x58\x05\x00\x37\x29\x40\x63\xDE\xBD\x7D\xF3\xC8\x31\xC0\x02\x80\x11\x00\x00\x1D\x2B\x04\x80\xCC\xA4\x94\x6A\x1D\x00\x80\x00\x20\x00\x34\xE8\x58\x13\x00\x0C\x66\xA5\x09\x04\x00\x37\x2B\x40\x63\x6C\xB1\x16\x00\x4A\xBA\x59\x63\xB8\xEA\x9D\x96\x00\xB8\xB7\xD7\x9A\x40\x00\x28\x8D\x69\x00\x80\xFB\xD3\xFB\x17\x00\x04\x00\x00\xCF\x52\x86\xF6\xCD\xC5\xC5\x85\x56\x18\xD8\x77\x3F\xFC\xB5\xEE\x7F\x3C\xD6\x12\x00\x77\x12\xFB\xFF\x67\x9A\xC1\x08\x80\xE4\x0A\xE0\x19\x8A\x00\x50\x84\xA5\x26\x00\xF0\x0C\xCD\x99\x29\x80\x2D\xF9\xEE\x87\xBF\x62\x47\xC0\x8E\x96\x00\xD8\x88\xE1\x7F\x23\x00\x12\x2C\x40\x83\x0C\xFF\x0B\x00\x02\x00\x40\x83\x8E\x34\x81\x00\x50\xB4\xF4\x6E\x80\x57\x5A\x02\xE0\xD6\xCE\xFA\x67\xE7\x5A\x33\x08\x00\x92\x2C\x80\x67\x26\x02\x40\x91\xA3\x00\xB1\x10\xD0\x1B\x02\x01\xBE\xEE\xBC\x33\xFF\x2F\x00\x54\xE6\x50\x13\x00\x7C\xD5\x32\x4D\x9D\x22\x00\x54\x33\x0A\xB0\xEA\xBC\x20\x08\xE0\x6B\x0C\xFF\x0B\x00\x46\x01\x00\x1A\xF3\xCA\xE2\x3F\x01\xA0\xD6\x51\x80\xA5\x51\x00\x00\xBD\x7F\x01\xA0\x4D\x0B\x4D\x00\xF0\x2F\x27\x69\xC1\x34\x02\x40\xB5\xA3\x00\xAB\xCE\x8E\x00\x80\x4F\x1D\x6A\x02\x01\xC0\x8D\x0E\xD0\x96\x57\xA9\x73\x84\x00\xD0\xC4\x28\x80\xD3\x01\x01\x74\x8A\x04\x80\x06\x1D\x74\x97\x07\x5E\x00\xB4\xEC\x85\x95\xFF\x02\x40\x6B\xA3\x00\xEF\xA5\x5E\xA0\x71\xE7\x9E\x83\x02\x40\xAB\x21\x20\xB6\xBC\x58\x10\x08\xB4\xEA\xD0\xA9\x7F\x02\x40\xCB\x16\x9D\xA9\x00\xA0\x3D\x27\xA9\x13\x84\x00\xD0\xEC\x28\xC0\xBA\x33\x04\x06\xB4\xE7\x40\x13\x08\x00\x42\xC0\x65\x0A\x7E\xAD\x25\x80\x46\xFC\xEA\xD0\x1F\x01\x80\x7F\x2C\x3A\xC7\x04\x03\xF5\x3B\xEB\x8B\xFF\xA1\x66\x10\x00\xF8\x67\x14\x20\x16\xC2\xEC\x69\x09\xA0\x62\xE7\x9E\x73\x02\x00\x37\x87\x80\x18\x12\x7B\xA6\x25\x80\x4A\x1D\xD8\xF3\x2F\x00\xF0\xF9\x10\xB0\xEC\x7F\xBC\xD0\x12\x40\x65\x5E\xA5\xE7\x1B\x99\xF9\xE6\xE2\xE2\x42\x2B\x64\xE4\xBB\x1F\xFE\x8A\x2F\xCA\xBE\x96\x00\x2A\x10\xF3\xFE\xBB\x9A\xC1\x08\x00\xB7\x13\x5B\x64\xCE\x34\x03\x50\xB8\x98\xF7\x9F\x6B\x06\x01\x80\x5B\x4A\x8B\x02\xE7\x42\x00\x50\x7A\xF1\x77\xDA\x9F\x00\x80\x10\x00\xB4\x65\xCF\x7E\x7F\x01\x00\x21\x00\x68\xCB\xB3\xF4\xEA\x73\x04\x00\x06\x08\x01\x4E\x0B\x04\x4A\x29\xFE\x4B\xCD\x50\x06\xBB\x00\x0A\x61\x77\x00\xA0\xF8\x63\x04\xA0\xCD\xD1\x80\x45\xE7\xB0\x20\x40\xF1\xC7\x08\x40\xB3\x23\x01\xB1\xA7\xF6\xB8\xFF\x3C\xD6\x1A\xC0\xC4\x3E\x1C\xF1\x6B\xCE\x5F\x00\x60\xBC\x10\xF0\xB0\xFF\x11\x69\xFB\xA9\xD6\x68\x4A\x2C\x08\xBD\xBE\xAD\xEA\xA6\x87\x6E\xFC\xEF\x6F\xBB\xFA\x3A\xC2\xE4\xC3\x2F\xFC\x77\x33\x41\x93\xAF\x14\xFF\xB9\xD5\xFE\x02\x00\xD3\x04\x81\xBD\x14\x04\x1E\x68\x8D\x2A\x0A\xFB\x69\xFA\x79\xBD\x88\x9F\xE6\xB0\x97\xBA\xBF\xD7\xE6\x9F\x04\x84\xAB\x9F\x4F\x5C\xBE\x66\xEF\x59\xFB\xFC\x05\x00\x32\x18\x0D\x38\xEA\x2C\x10\xCC\x59\xBC\xEE\x79\x7D\xAD\xC0\x7F\xF8\x59\xCB\xB0\x69\xBA\x07\x77\xD3\x88\x41\x7C\xE6\x46\x0F\xAA\xF6\xA2\xBF\x77\x0F\x34\x83\x00\x40\x3E\x0F\xE1\x79\x0A\x02\x3B\x5A\x63\x12\xE7\xA9\xB0\xAF\xD3\x67\x95\x8A\xFC\x69\xC3\xF7\xE4\x55\x30\xD8\xBD\x16\x10\x8C\x18\x94\x7D\x8F\x2F\xFA\x7B\xFA\x58\x53\x08\x00\xE4\xF9\xD0\x5D\xF4\x3F\x0E\xF5\xBE\xB6\xDE\x9B\x5F\x5D\xEB\xCD\x9F\x1A\x0A\xDD\xE8\x1E\xDD\xFD\x24\x18\x08\x05\xF9\x7B\x9D\x8A\xBF\xFB\x5C\x00\xA0\x90\x20\x70\x60\x44\xE0\xCE\xCE\xBA\x7F\x86\xED\x3F\xF4\xEA\xAD\x74\xDE\xEA\xFD\x3A\xBF\x16\x08\xE6\x02\xAC\x5E\x3F\x02\x00\xC3\x3C\x58\x23\x0C\x58\x23\x70\xF3\xC3\xCD\xB0\x7D\x9E\xF7\xED\xC3\x6B\x61\xE0\x2A\x1C\x58\xEC\x3A\xAE\x17\xFD\xE7\x50\xAF\x5F\x00\xA0\x8E\x07\xEA\x5E\xFA\xB4\xB4\x7D\xF0\xD3\x22\x5F\xD5\x02\xBC\xC6\xEE\xE1\xDD\x4F\x46\x09\x8C\x6E\x6D\xC7\x49\xEA\xF5\xAF\x35\x85\x00\x40\xBD\x61\xE0\xAA\x77\x55\xF2\x70\xEB\xD5\x9C\xFC\xF5\x6D\x74\xA7\x7A\xF2\xCD\xDC\xCB\xF3\x6B\x81\x60\xB7\x33\x75\x70\xDF\xC2\x7F\x28\x1C\x0B\x00\xB4\xF5\x10\x9D\x5D\x7B\x80\x5E\x7D\xA6\x1C\x6E\xBD\x2A\xEA\x5D\xF7\xF1\x9E\xF8\xAB\x5E\x7C\xE7\x21\xC5\x17\xC2\xED\xEE\x27\xF7\xB3\x50\xF0\x65\xAF\x52\xE1\xD7\xE3\x17\x00\xE0\xA3\xDE\x55\xD7\xFD\xFB\xC4\xB8\x9B\x4E\x90\xBB\xF2\xB5\xC2\x7C\xD3\x49\x75\x7A\xEB\x8C\x19\x0A\x22\xF0\xB6\x3E\x7D\x10\x21\x3B\xB6\x0D\x2F\xCD\xF1\x0B\x00\x00\x2D\x06\xDC\x59\xD7\xCE\xE1\x45\x51\xF4\x8F\x53\xD1\x17\xB8\x11\x00\x00\x3E\x09\x06\x57\xA3\x04\xD7\x4F\x37\x2C\x35\x1C\x9C\xA4\xA2\xBF\x52\xF4\x11\x00\x00\xEE\x17\x0E\x1E\x5E\x0B\x05\x57\xD3\x0B\x5D\x37\xFD\xDA\x99\x38\xBB\xE2\xB4\xFB\xE7\x70\xAA\x95\x2B\x86\x00\x00\x30\x4D\x50\xE8\x3E\x09\x09\xDD\x17\xFE\xBB\xDB\xB8\x69\x51\xEC\xDA\x02\x3E\x04\x00\x00\xE0\x56\xFE\xA3\x09\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x04\x00\x00\x40\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x10\x00\x00\x00\x01\x00\x00\x5A\xF5\xFF\x02\x0C\x00\x5A\xC1\xE5\x7E\xCD\xCE\xB7\xDC\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"])
bing_icon_data = "".join(["\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x01\x00\x00\x00\x01\x00\x08\x06\x00\x00\x00\x5C\x72\xA8\x66\x00\x00\x6D\x7C\x49\x44\x41\x54\x78\xDA\xED\xBD\x07\x80\x25\x55\x95\x3E\xFE\xD5\xEB\x9E\x9E\x3C\x30\x04\x09\x82\xA0\x24\x45\x4C\x08\x2A\x48\x10\x56\x72\x90\x60\xC0\xB4\x6E\x50\xB7\x51\x57\xD7\x9F\xAB\xBB\x86\x35\xA0\x6B\x58\x77\x71\x4D\x98\x98\x75\x15\x15\x41\x47\x44\x24\x0C\x82\x64\x14\x11\x1C\x82\xC0\x90\x73\x8E\x93\x7A\x66\xBA\xFB\xD5\xFF\xBE\x50\xD5\xE7\x9E\xFB\x9D\x7B\xEB\xF5\x8C\x74\xED\x9F\x77\xA0\xE7\x55\xDD\x78\x6E\x38\xF1\x86\xCA\xD0\x87\x3E\xF4\xE1\x19\x0B\xD9\x54\x23\xD0\x87\x3E\xF4\x61\xEA\xA0\xCF\x00\xFA\xD0\x87\x67\x30\xF4\x19\x40\x1F\xFA\xF0\x0C\x86\x3E\x03\xE8\x43\x1F\x9E\xC1\xD0\x67\x00\x7D\xE8\xC3\x33\x18\xFA\x0C\xA0\x0F\x7D\x78\x06\x43\x9F\x01\xF4\xA1\x0F\xCF\x60\xE8\x33\x80\x3E\xF4\xE1\x19\x0C\x7D\x06\xD0\x87\x3E\x3C\x83\xA1\xCF\x00\xFA\xD0\x87\x67\x30\xF4\x19\x40\x1F\xFA\xF0\x0C\x86\x5A\x31\x80\x7C\x11\x56\x22\x77\x7F\x19\x7E\xE6\x5E\x2F\x72\x7F\x7F\x70\xEF\x0F\xE7\x19\x56\x35\x0E\xC0\x58\x91\xEE\xB9\x9B\x22\x7B\x72\x39\xB2\x27\x96\xA3\xB9\x16\xD5\x35\x5A\x55\x16\x55\x1B\xF1\xB1\xF2\x33\x95\xB7\xD1\xFD\x6D\xAA\x67\x99\x3E\xEB\xA6\xCF\xB1\x76\x20\x71\x93\x63\x58\x94\x5F\x76\x69\xA2\x3D\x19\x49\xA7\xD3\x17\xBF\xAC\xBD\x56\x5B\x1B\xAA\xAC\x1C\xBC\x9F\x58\x39\x45\x5A\xDD\x2E\x5D\x7E\x91\xA7\x6A\x7B\x53\xE3\x9D\xEA\x67\x89\x4B\x81\x5B\x93\xA4\xB7\xDA\x90\x23\x3D\xA7\x9E\x76\xA8\x1B\x03\x58\x93\xE7\x98\x96\x75\xA6\xF1\x52\x87\xDD\x4D\xEE\xFD\x22\xF7\x7E\xB3\xFB\x5D\x92\x0D\xE2\x96\x3B\xEF\xC7\x93\x3F\x38\x17\xAB\x3F\xFD\xA3\xCE\x20\xCE\x9D\x85\x6C\xD9\x4A\xEF\xB9\x5D\x14\xFC\x81\x6A\x41\x6C\xB0\x02\x54\x60\x4F\xA0\x5C\x3D\x17\xF5\xC8\x49\x0C\xF2\x0E\x55\x5F\x36\x89\x74\x05\x1E\xF2\x99\xE5\x29\xF2\xB1\x3C\x99\x8A\x93\x84\xAD\x89\x3E\x56\x3E\x23\x36\xD6\x8E\x5E\xA0\xD7\xF2\xD7\xC5\xD8\xC9\x3C\x05\x30\xE6\x22\xFB\xD4\x1A\x03\x9D\x2F\x53\xCF\xB5\x22\xFE\x02\xA9\xDA\x40\xD3\x31\x00\x87\xD0\xB4\xD6\xB3\x23\x78\xB4\x18\x81\xF8\xBD\xDF\x61\xFB\x3B\xF7\xF8\x3B\x0C\xE1\x0A\x8C\xE2\x81\xD5\x6B\xF0\xD8\xC2\x4B\xB0\xEC\xAD\x5F\xC2\x78\xA2\xE8\x2A\x9C\xD7\x92\x70\xF2\x39\x56\x4E\xAF\x1A\x43\xAA\x0C\x96\x9E\x49\x5B\x56\x8F\x9E\xA8\x6C\xC2\x32\x29\x55\x84\xEB\x49\x9D\xAA\x87\xE1\xAF\xEB\x99\x6C\x9F\x59\xD2\x56\xA7\x91\xD2\x3D\x46\xA0\xBA\x5F\x53\x82\x42\xD6\x23\xF3\xB1\x76\xB0\x3E\xE9\xB5\xCD\x4F\x2B\xD4\x8A\x01\xB4\x35\x80\x2E\x03\x68\x8F\xA8\x62\x02\x98\x08\xBB\xC5\x3D\xDE\xEF\xFE\x16\x63\x06\xFE\xB0\x6A\x29\xAE\xBB\xF5\x7E\xDC\xF3\xA2\x7F\xC0\x93\x91\xE2\x35\x71\xE5\x08\x55\xE6\x2A\x79\x53\xFD\x98\x27\xD2\x30\xA9\x52\x55\x25\xD5\x12\x4B\xB7\x41\x13\x82\x9E\xDC\x31\x68\xC2\x36\x27\x98\x86\xA3\xEB\x94\xCC\x24\x83\xCD\x5C\xA0\xCA\x8C\xE1\xA8\x99\x98\x2C\x33\x26\xA5\x35\x68\x6D\xCA\xD2\xC2\xA4\x96\x90\x6A\xAF\x2C\x8B\xF5\x8F\xD5\xDE\x5A\x41\xAD\x18\x40\x4B\x03\x40\xD7\x04\xD0\x23\x54\x00\x99\x55\x2D\xA2\xBF\x1E\x83\xB8\xDA\xFD\xFE\x1E\x63\xF8\xB3\x1B\x86\xC7\x96\xAD\xC0\x23\xF3\x8E\x70\xE5\x75\x61\xCF\x9D\x90\x5D\x72\xBD\x57\x44\x55\x9B\xAC\xAA\xE4\x96\x13\xA1\xC8\x97\x1B\xE5\x69\xE9\xC3\x54\x75\x0B\x17\x4D\x38\x96\x2D\xAC\x27\xA8\xCC\xA7\xD3\x59\x2A\x2B\x53\x93\x7B\x51\x69\x33\x70\x46\x92\x91\xF2\xAC\xBE\xD2\xEF\x4D\xC4\xA7\x05\x6B\xAF\xD5\xCE\x58\x98\x8E\xB3\x70\x2C\xC6\xCD\xEA\x17\x8D\xD7\xDA\xFA\x7F\xD6\x29\xD4\x92\x01\xB4\xB0\x2A\x7B\xAD\xDB\x5D\xA5\x06\xD0\x7A\x16\xC3\xAD\xE2\x9F\x72\xAF\xB7\xBA\xE7\x7B\x9D\x79\xF0\xC7\x15\x23\xB8\x7C\xEE\x2C\xDC\x38\x74\x08\x1E\xE8\xB1\xFD\x5A\xED\xD6\x6A\x6C\x95\xC9\x04\x54\x9B\x64\xBD\x32\x00\x8B\x81\x31\x69\x25\xDF\xF5\x24\x95\x71\xCC\xCC\xD0\x78\x02\x9C\x51\x54\xE9\x0F\xDD\xDF\x56\x39\xB1\x31\x60\x52\x9A\xA5\xB5\x98\xA2\xE5\x80\xD5\x63\x11\xF3\xF3\x30\x46\x26\xF3\x37\x49\xBE\x1C\x9C\x41\xD7\x02\x6A\xC7\x00\x1C\x71\x4F\xCB\xB3\x2E\x91\x77\x31\x2C\x1F\xD5\x70\x9A\x3A\x66\xCB\x4C\x68\x60\xD4\x45\xDE\xE5\x9E\x6F\x1A\x1B\xC3\xA5\xCE\x44\xB8\x7F\xD9\x4A\x2C\x3E\xFB\x8F\xB8\xEB\x53\x3F\xC4\xD2\x44\x7F\xE8\xC1\x6B\xA3\x27\xD2\x68\x75\x57\xDB\xD9\x8C\xC0\xD9\x24\xD2\x5A\x03\x53\x69\x61\x94\xA5\x71\xD3\xEA\x3B\x44\x59\x4C\x3D\x87\x4A\xC3\x3C\xEB\xAC\x7B\x19\x41\xE8\xB4\x6C\x68\x74\xB8\x6C\x7B\x46\xF2\xB3\xBE\x6D\x90\x78\xC6\xA0\x58\x7B\x2D\x26\x6D\x39\xEA\x34\x33\x66\x63\x67\xF5\xBF\x35\x0E\x30\xDE\xA7\x0C\xEA\xC5\x00\xCE\x71\x0C\x20\xE3\x4E\x40\xAA\x9C\x09\xEC\xAD\x19\x5B\x46\x4E\xC7\x4A\x37\x5C\xD7\x60\xA6\x33\x11\xC6\x71\x01\x96\xE3\xEA\x6C\x3F\xDC\xA4\x93\x9E\xF0\x01\x64\xEF\xF9\xAA\x29\xA5\x2D\x0F\x32\xC0\x35\x05\xC0\x9F\x38\x2C\xBF\x95\x56\xB7\x80\x11\x08\x5B\xC9\xD0\xE6\x85\x8E\xD3\x6A\x77\x6C\xA9\x2A\x56\xBE\x6E\xAF\x96\xC8\x6C\x29\x8F\xF9\x0A\xAC\xBA\xB4\x7D\x6E\xAD\xB2\xE8\xD5\x0D\x59\x86\x65\xE6\x59\x63\x12\x5B\x2D\x91\x79\x65\xD9\x05\x2E\x8C\x01\x66\x24\xBE\x36\xC4\x2F\x1B\x53\x0B\x90\x0C\x40\x4E\x03\xE9\x04\x6C\x85\xB7\x7B\x37\x9B\x50\xFF\x51\xBC\x77\xE3\x0B\x86\x91\x0B\x12\x56\x62\xE7\x31\xF7\x7B\xA7\xFB\xBD\x12\x9D\xBD\x06\x77\x39\xC6\x70\x4D\xB6\x37\x1E\x93\xF8\xEC\xB1\x13\xB2\x4B\xAF\xF7\x06\x9A\x71\x72\xCB\x4E\xED\x05\x58\x19\x92\xB8\x62\x76\x64\xCA\xAE\x8C\x11\x78\xA6\x7E\xAB\x10\x95\x86\xAA\xFE\x03\x96\x06\x89\x77\xB6\x22\x93\xC2\xA7\x4A\x7B\x63\xB6\xBE\xD5\xE7\x88\xA4\xB7\x7C\x00\x56\xD9\xB5\x81\x7A\x31\x80\x45\x6D\xA7\xDD\xB4\x82\x88\xCB\xDE\x2A\x88\x58\xDA\xFE\x02\xF9\x5C\x13\xB9\xA1\x0E\x18\xAE\xFA\x27\x5C\xF8\x13\xEE\xFD\x76\xF7\x7C\x81\x4B\x74\xD9\xF2\x15\xB8\x6E\xEE\x86\x58\x96\xED\xE5\xCC\x88\x6A\x7D\x57\x95\x20\xD9\xE4\x4D\x49\xA8\xAA\xC4\xAF\x25\x93\x76\x14\x32\x8D\x40\xF5\xB0\xC7\x08\x34\x3E\x96\xDF\xA0\xEA\x1E\x03\xD9\xDE\xDC\x48\xC7\x40\xB7\x27\x46\xA0\xAC\x3D\x4C\xBA\xEB\x36\x31\x86\x6D\xF9\x7E\xAC\xF6\x30\x9F\x8E\xD5\x7F\xB5\x59\x0D\xA8\x17\x03\x70\x1A\x80\xC3\x68\x5A\x40\x59\x42\x03\xD0\xC4\x2E\xC3\x74\x83\x98\x08\x2A\xD2\x18\xDE\xA9\x11\x17\xFE\x68\xD6\x32\x15\x9A\x78\xD8\x0D\xED\x59\x6B\xD6\xE0\x86\xA1\x99\xB8\x29\xDB\x37\xC9\xBD\x63\xBB\xC6\xAA\xAA\x80\xB1\xDD\x7A\x40\x38\xB9\xF4\x2E\x3D\x09\x4C\x9D\x6F\x46\xCA\x05\xAA\xA9\xD9\x31\x5C\x00\x5B\x7B\xB0\x9C\x7A\xB1\xDD\x92\xCC\xCC\x48\xF9\x4B\x58\xDB\xAD\xF2\x53\x7D\x9F\xDA\x71\x68\xE1\x9F\x0A\xAB\x0D\xD4\x8A\x01\xE4\x85\x06\x00\x9F\xF0\x4B\x4F\x3F\x88\x0B\x20\x0B\x19\x40\xCC\xE5\x5E\x98\x10\xED\x78\x65\x5E\xE4\x7E\x7D\xE3\xEE\xF9\x49\x97\xE9\x7E\xF7\xFE\x87\xF1\x71\x5C\x32\x38\x80\xAB\xD6\x8C\xE1\xAE\x95\xAB\xB1\x7A\xFE\x51\x13\x4B\x8C\x15\xFB\xD9\x9A\x78\x12\x52\xAB\x00\x6C\x87\x9B\xB5\xFE\xCC\x3C\xFB\x05\x58\xEB\xEF\xD6\x6E\x49\x59\x26\xB3\x81\x75\x19\xB1\x9D\x81\xCD\x48\xD9\x31\x07\x64\x6A\x87\x62\xAA\xBD\x55\xB7\x0F\x6B\x1C\xAD\x15\x06\x0B\x9F\x98\x8F\x88\xF5\xF1\x94\x42\xED\x18\x40\xDE\x5D\x06\x2C\x90\x6B\x13\x25\x7C\x7B\x5E\x22\xCE\xA8\x89\xEA\xCC\xD2\xAC\x90\x7E\x02\x40\xEF\x38\x64\x05\xB4\x99\x81\x7B\xBD\xC3\x3D\x5F\xEB\x46\xF0\xA6\x81\x06\x2E\xC5\x10\x6E\xB9\x7E\x09\x9E\xF8\xF8\xF7\x91\xFF\xEA\xF7\x93\xDA\x69\xD8\x02\x6B\x27\x5D\x0C\x52\xC4\xA3\xEB\x89\x39\xDA\x2C\x0F\xB8\x04\xE6\xE4\xB2\xDA\x20\x71\x64\xAA\x31\xC3\xA7\x8A\xA4\x4E\x6D\xD5\x8D\xB5\x57\xF7\x55\x95\x7E\xAD\xB2\x94\x58\x65\x87\x68\xAD\xA1\x56\x0C\xA0\xF0\x01\x94\x48\x09\x47\x9E\x74\xEC\xA5\x90\xF6\x9C\x86\x32\x1C\x9C\x21\x50\x33\xA1\x1B\xA1\x1D\x90\xDD\x5E\x6B\x1D\x4C\x6A\x2D\x25\x2E\x76\xF1\x97\xB9\xBF\x4B\x1B\x43\x78\xE0\x07\x67\xE1\xEE\x1B\xEE\xC1\x8A\xFF\x38\x75\xE2\xE0\x52\x05\x60\x6A\x3A\x73\x88\x31\x7B\xD5\x92\x3C\x31\xDB\x37\xA5\xD2\xC7\x0E\xEB\xA4\x54\x67\xCB\xF7\x00\x52\x5F\xCC\xE1\x08\x23\x5D\x4C\x93\xA9\xD2\x5E\x09\x96\x0C\xA9\xD2\x5E\xAB\x2E\xAB\xDC\xD8\xC1\xA9\x29\x85\x5A\x31\x00\xB9\x15\x58\x4B\x69\x4F\xF2\x17\xC4\x89\x50\x58\x43\xBD\xB3\x55\xC3\x94\x0B\x38\x08\x53\xCC\x42\x99\x0D\xAD\x95\x8B\xD6\xEA\xC1\x23\x2E\xF2\x77\x6E\x88\x2F\x77\xC3\xBB\x78\xD5\x6A\xDC\x73\xCD\x9D\x58\xE1\x9E\x47\x5F\xF5\x01\x93\xCF\x68\xE8\x55\x92\x30\x09\xC4\x98\x85\xB5\x1F\xDE\xF2\xC4\x03\x5C\xD5\x95\xE5\xC7\x24\x61\x4C\x72\x36\x2A\x94\xAF\x21\x43\x1A\x1F\x90\x3A\x74\x3D\xDA\x11\xCA\xFA\xA9\x6A\xF9\x96\x29\x60\xB9\x9B\x2C\x86\x31\xA5\x50\x4F\x06\xA0\x09\x0E\x82\xF0\xBB\x58\xB7\xC3\xD8\xAA\x80\x90\xDC\xED\xA4\x19\x9F\xDD\x81\x64\x57\x79\x64\xBA\x02\x09\xCF\x57\x00\x61\x96\xF8\x79\x46\x5C\xD8\x9D\x2E\xC1\x05\x98\x87\xB3\x17\x9E\x85\x33\x5F\xFF\xD9\x4A\x0C\x20\xA6\x0E\xCB\xE7\x98\x06\xC0\x20\xE6\xE9\x66\x04\xA1\xED\x5F\x49\x7C\x31\xD3\x21\x65\x0F\x5B\x2A\x7D\xD5\xA5\xB8\x1C\xE9\xF6\xC6\x3C\xF1\x56\x7B\x2D\x87\x63\x81\x23\xD3\x32\x60\xA4\x89\x8D\x01\x33\x81\xA6\x1C\xEA\xC7\x00\x8A\xE3\xC0\x45\x18\xF8\x8C\xF0\x33\x22\x64\x04\xE0\xB3\xA8\x8A\x36\x20\xCD\x84\x62\xC5\x41\x4B\xFF\x98\xA3\xB1\x2C\x7F\x36\x16\x9C\x72\x26\xDE\x7D\xCC\x17\x2A\xAD\x02\x58\xEB\xCE\x05\xB0\x4D\x44\x99\x0A\xD3\x8A\x90\x54\xC3\x99\x9F\x80\xA9\xCE\xAC\x9C\x58\x9D\x8C\xC1\x58\xF3\x2A\xE5\xBA\x49\x85\x5B\xF8\x4A\x90\x7D\xA1\x0F\x4C\xB1\x29\x11\xC3\x8F\xF9\x3D\x18\x83\x89\xF9\x56\x34\x73\x89\x31\x8A\xA7\x1D\x6A\xC7\x00\xDC\xCF\x34\x6A\xC3\x77\xBB\x8C\xFA\x00\xA4\x49\x20\x99\x81\x2A\x27\xD8\x50\x94\xD9\xB3\xC7\x7A\xB7\xCA\x22\x89\x72\x0C\x61\xC1\x1F\x97\xE0\x1F\x76\x1D\xAE\xB4\xCE\xAF\x5A\x4A\xD3\xCB\x5F\x49\x78\x55\x88\x3F\xCA\xAB\x0C\x1C\xAC\x34\xCC\x37\x61\x79\xD6\x99\x0F\x20\x27\xE5\xE9\xDE\xCC\x8C\x72\x58\x7B\xAB\x5A\x80\xA9\xB6\x58\x38\xE9\x77\xC9\x00\xA8\xCF\xB9\x02\x3E\xB5\x80\x5A\x31\x00\xBA\x15\x18\x71\x9B\x1C\x32\x5E\x48\xEC\x02\x3C\xAF\xBF\x0C\xD3\x9D\x20\x18\x82\x37\xB3\xD4\x70\x6A\x1F\x00\x10\xCE\xC4\xA2\x39\x2E\xDD\x82\xC6\x46\x18\xCE\x76\x31\x4F\x87\xE9\x77\xB6\xB6\xAD\x25\x9A\xE5\xC0\xCB\x49\xFA\x0C\xF1\x89\x27\xD5\xF1\xDC\xA8\x23\x56\x2F\x6B\x8F\xEE\x12\xAD\x31\xC8\x30\x49\xD4\xEC\x9E\x02\xE6\x48\x84\x0A\xB7\x9C\x74\xBA\x4F\x2C\x9C\x19\xE1\xA7\x0E\x80\xB1\x3E\xB2\xFA\x02\x15\xE2\xA6\x0C\xEA\xC5\x00\xF4\x2A\x40\x17\xCA\xCD\x3F\x05\x91\x4A\x62\x25\x44\xDF\xCE\x23\x1A\xE8\x8D\xB2\x21\xF3\x72\x12\x5E\x32\x86\xE2\x9D\x69\x0F\x96\x0C\x75\xCD\x71\x33\x64\x41\x63\x8E\x63\x00\xAF\x4E\xDA\x91\x05\xF4\xB2\x0F\x40\x13\x93\x0C\xD3\x36\x73\x4C\xE2\xCA\x32\x18\xF3\x98\x2C\xA1\x31\xC7\x63\x8C\x58\x58\x1D\x96\xFF\x01\x88\x33\x8D\x18\x13\xB5\x34\x0B\xC6\x80\x99\x16\x00\xA3\x0C\xDD\xDF\xB1\x3E\xAE\x0D\xD4\x8A\x01\x48\x1F\x80\xDE\xE7\xEF\xA5\x23\x0D\x28\xD4\x7F\x2D\xC5\xA5\x04\xA7\xE6\x81\x62\x26\xF2\xE0\x51\x15\x7D\x91\x99\x2B\xDD\xB0\x66\xB3\xA5\x01\xCC\x2D\x19\x40\x91\x2D\x36\x01\xAC\xC9\x59\x36\x11\x71\xB4\x00\x3E\xA6\x96\xE3\xCA\xAA\x47\x77\x6D\x0A\xBF\x1C\xF6\x92\x98\x39\x5C\xA4\x5D\x56\x7F\xA4\xCC\x94\x54\x7B\x7B\xB5\xF9\x2D\x9C\x62\xE5\xA4\xD4\xFB\x5A\xA9\xFE\xBA\x41\xB5\x00\xEF\x4A\x30\xD8\x33\x50\x86\x49\x29\xCC\xCE\x04\xC8\x7B\x04\x8A\xF4\xC1\x0A\x01\xF3\x39\x88\x7A\x4C\x62\xB7\xB4\x89\x4E\x70\xDB\x04\xC8\xE6\x7A\x1A\x40\x11\x9D\x52\xB9\x25\xC4\xC2\x62\x04\x25\xA5\x37\x93\xA4\xBA\x5B\x2C\x49\xAE\x1D\x6A\x96\xFF\x33\xB5\x94\xA7\xBB\x28\xD6\x36\x9D\x4E\xC7\x55\x6D\xBB\x75\xF2\xB1\x0A\x21\x4E\x86\x60\x6B\x49\xE4\x29\x84\x6B\x03\xB9\xB8\x10\x44\x12\x26\x73\xE6\x31\x12\xA0\x3B\xFA\x94\xBF\xA0\xFD\x5E\x64\x65\x92\xBB\x1B\x27\x6D\xFE\x22\x5F\xC1\x64\x02\x3D\x56\xE3\xD6\x81\xA6\x0B\x5F\x90\xCD\xF1\x34\x00\xD9\xEF\x8C\x08\xAA\xEC\x6F\xEF\x94\x1D\x3F\x20\x23\xD3\xB3\x8B\x2B\x62\xCE\xB5\x98\x8A\xAD\x4D\x0A\x0B\x27\xB6\x64\xC8\x98\x08\x2B\x3F\x66\x06\xC4\x0E\x04\xC1\xA8\xD7\xF2\x23\x30\x66\x51\xB4\x03\xB0\x57\x19\x24\x4E\x20\x69\x2D\x07\x61\x2D\xA1\x76\x0C\xA0\xD8\x0A\x5C\xEE\xC4\x33\x10\x95\x2A\x3E\x73\x16\x96\x0D\xCC\x27\x08\x9A\x7A\x7E\x94\xBA\xCF\xC4\x04\xF3\x49\x64\x91\x9E\x2B\x4C\x00\xF7\x23\x19\x40\xCA\x07\x10\xDB\x56\x6A\xC5\xC5\x96\xC2\x8A\x78\x20\x24\x20\xAD\x1D\x14\x79\x2C\x1B\x9E\xD9\xC5\x8C\x70\x52\x1B\x68\x74\xD9\x7A\xCF\x41\xAE\xF2\x81\xA4\x63\xFB\xF4\xB5\x26\xC3\xB6\x1C\x57\x21\xCA\xD4\xAE\x41\xF9\x5E\x25\x1D\xF3\x03\xD4\x66\x0F\x00\x43\x78\x4A\x41\x1F\x06\xCA\x14\x71\x7A\x69\x11\x12\xB4\x67\xF7\x8B\x0C\xA6\x1D\x9F\x4F\x68\x02\xDA\x5C\x88\x19\xC5\x5E\x1A\xC9\xA8\x7C\x66\xC4\x7C\x00\xEB\x0A\xAA\xDE\x44\x63\xED\x70\x8B\xA9\xD9\x32\xBD\x05\x4C\xF2\x56\x6D\x63\x6C\x17\x1D\xF3\x4B\xC4\x08\x3A\x53\x69\xB5\x59\x15\xDB\x82\x6B\x69\x4B\x31\xA6\xC9\xA6\x42\x4C\x13\x60\x2B\x1A\xB5\x82\x5A\x31\x00\xB9\x0A\xE0\x49\x76\x41\xA8\x05\x48\x06\xC1\x28\xB6\x54\xE3\xA5\xBD\x9F\x4F\xA8\xEC\x9A\x59\xC8\xBD\xFF\x65\xE7\xA8\x3C\x90\xE9\x55\x3D\x9A\x01\x65\xDD\x55\x00\xF7\x38\x3C\x78\xE0\x5A\x0D\x7C\xCA\xD1\x16\x5B\x3A\xD4\x8C\x00\x08\x27\x63\x15\xA9\x19\xBB\xC9\x48\x9B\x01\x32\x2F\x23\x9C\x94\xBA\xAD\x4D\x06\x0B\x2F\x66\xDF\xB3\xF6\xEA\xB6\x30\x89\x1C\x23\x50\x96\x3E\x75\x2A\x93\x99\x77\x16\x6E\x53\x0A\xB5\x64\x00\x96\x53\x2E\xE6\x0E\x96\xCC\x80\x79\xF5\xE5\xA1\xA2\xE8\x1E\x83\xC8\x6F\xD9\x61\x64\x35\x41\xAF\x3A\xB4\x4D\x00\xDF\x09\x28\xC1\xDA\x76\xDA\xEE\x06\x32\x3E\x3A\x9D\x26\x22\x4D\x68\x45\x9E\x5E\x4E\xAB\xF5\x8A\x93\xAC\xA3\x48\xC3\xEE\x04\xA8\x82\xBF\x95\x56\xE3\x21\xD3\x33\x87\x66\x15\x33\x2A\x56\x57\xEA\x3E\x06\x19\x16\x33\x2F\x24\x4E\xB1\xB2\xA7\x1C\x6A\xC5\x00\xF4\x56\xE0\x40\xCD\xB7\xBC\xEE\x36\x11\x72\x82\x16\x4C\x42\xD7\xC3\x56\x14\xE8\x4A\x80\xC2\x85\xAC\x10\x34\x9B\x59\xB0\x0F\xA0\xA8\xC1\x82\x5E\xF6\x01\x68\xC2\x63\xE5\xE6\xB0\x25\x39\x73\xC0\xB1\x0B\x41\x64\xBD\x31\x89\x1E\x3B\x3D\xA8\xB5\x18\x90\xBA\x98\x86\x91\x81\xE3\xD4\x4B\x7B\x65\x3B\xAC\x95\x03\xAB\xDF\x63\x6D\xB0\x34\xA5\xD8\x58\xD7\x8E\x09\xD4\x8A\x01\x30\x0D\x40\x4B\x5E\xB9\xCE\x8F\x9C\x48\x72\x15\xD6\x0E\x22\xF6\xBD\xBA\xFC\xC3\x2C\x47\xE7\x91\x2B\x0B\xB2\x6C\x92\xA6\x35\xD0\x0B\xB2\xF9\x8E\x01\xBC\x92\x4E\x0A\x8B\xE0\x98\x0F\x52\x7B\xE6\x63\x36\xB3\x7C\x67\x12\xBD\x8A\xC6\x60\xD9\xDF\x96\xD7\x9D\xA9\xED\x16\x11\x64\xB0\x89\x8E\xE1\x65\xA9\xDD\xD6\xDC\xB5\xDA\xCB\xFA\xB3\x48\x2F\x19\x93\x1C\x0B\x8D\x9B\xEE\x27\x20\xCE\x88\x99\x82\x59\xAB\x15\x81\x5A\x31\x00\x7D\x1A\xB0\x1D\x86\xB8\xC4\xA6\x46\x69\xB1\x54\x57\x2C\xE5\x91\x44\x74\x1D\x49\xA4\xB3\x1C\x8C\x65\xF9\x46\xCF\x95\x9A\x4A\x6B\x1F\xC0\x20\x16\x3C\xB4\x1C\xC3\x9B\x1D\x11\xF5\xD4\x33\xA8\xBA\x7C\xA4\x3D\xED\xCC\x23\xD2\xC6\x05\x71\x29\xAE\x6D\x69\x90\x77\xE6\x37\x60\xED\x91\xCB\x79\x8C\x99\x69\xE6\x90\x62\x5C\x3A\x6D\x74\x68\xC0\x99\x96\xD6\x24\x18\x21\x6A\xC6\x14\x73\x98\x5A\x0E\xCC\x58\xDF\xEA\x32\x6A\x01\xB5\x62\x00\x4D\xB1\x0A\x00\x49\xC4\xCA\x21\x48\xCD\x00\xF8\xE9\xBC\xC6\xA5\x4C\x07\xCD\x30\x60\xA7\xD5\xCF\x16\xB8\x24\xCD\x6C\x36\x16\x9C\x7C\x06\x86\xDF\xF2\xA5\x60\xA3\x4F\x15\xF5\x93\x81\x9E\x50\xD6\x84\x66\x1B\x8D\x62\xA7\xFD\x22\xCD\x88\xAE\x9F\x03\xA1\xC6\x60\x31\x13\x46\x48\x92\x59\xC8\x74\x6C\xB9\x52\x9B\x2D\xF2\x97\xF5\xA7\xD5\xDE\xD8\xA2\x4E\xD4\xF5\x63\xA4\x95\x38\xEB\xB4\xAC\x1F\xFB\x0C\xC0\x82\x42\x03\x90\xB6\x7A\xE9\x6C\xC3\x84\x26\xE0\x79\xF6\xA1\xBC\xF9\x08\x09\x1A\x2A\x4E\x4A\x79\x36\xC2\x25\x3E\x4A\xE5\x97\x9B\x80\xBC\x4B\x4A\x55\x59\x85\x09\x90\xCD\x71\x0C\xE0\xD7\x38\xF6\x2D\x5F\x6C\x7F\xBC\x54\x7B\xB8\xFD\xD4\xA4\x18\xD8\x93\xA9\x00\xA6\x6E\xEB\x49\xA9\x27\xB4\x75\xD3\x0D\x12\x71\x16\xC4\x26\x7C\x8C\x21\x58\xED\x62\x12\x9E\xE1\xC7\x88\x30\x27\x79\x27\xDB\xDE\x18\xC1\xB2\xA9\xC3\xB4\x27\xD6\x47\x7D\x06\x60\x41\xFB\x34\x20\xBA\x3B\x01\x0B\xA2\xCD\x15\xC1\xA1\x02\x4B\x27\x89\x22\x7B\xF6\x3D\xC7\x5F\x46\x86\xBD\xA8\x5F\x3B\x12\x8B\xE5\x44\xA3\x33\x9B\xAE\x25\x0B\x6E\xBE\x1F\xC3\x3B\xBC\xAD\xF2\xCE\xB0\x2C\x11\xA7\x9B\x2B\x25\x8F\x84\xD8\x69\x36\x76\x88\x47\x43\x8C\x41\xD1\x2E\x57\x3D\xAF\x47\xC1\x6A\x0B\x4B\x97\x3A\x50\x13\xBB\xE8\x43\xFB\x08\x18\x03\x60\xFE\x00\x16\xAF\x2F\x44\x91\x7D\x0B\x80\x6A\x75\x19\xC9\x63\x4D\xD7\x5A\x40\xAD\x18\x80\xDC\x0A\xDC\x09\x80\x7F\xEA\x0F\x36\x11\x07\x3D\xAC\xCC\x01\x88\xB0\x22\x4D\x15\x87\x1F\xF3\x2F\xC8\x70\x76\x5C\xB8\x0B\xCD\xE6\x38\x16\x34\xB6\xC4\x70\xF6\xA2\x4A\x2A\xBE\x25\xFD\xAD\xB0\xD8\xB6\xE1\x22\x6D\x95\xB5\x6F\x26\x35\x41\xF2\x31\x3C\x65\x1D\xD6\x5D\x7A\xAC\x1D\x96\x77\xDD\xAA\x0F\xA4\x0C\x2B\x2F\x63\x1A\xBA\x8D\xAC\x0D\x29\xC7\xA7\xEC\x77\xEB\x92\x95\x98\x19\xA1\xF1\xAF\x05\xD4\x8E\x01\x48\x13\xA0\x40\xD0\x5A\x92\x03\x14\xB1\x2B\x55\x3D\xA9\x70\x2A\xED\x20\x66\xE7\xC7\x2E\x13\x31\x66\x6E\x33\x9F\x8E\x05\x17\x5D\x85\xE1\x7D\x3E\x14\x5D\x16\x93\x63\xC1\x24\x1C\x93\xBA\x96\xED\xCB\xCA\xD4\x66\x80\x25\xC5\xB5\x5D\x9D\xF2\x68\x03\xA1\x27\x5C\xF7\x6E\x8C\x48\xAD\x32\x8B\x78\x4B\x73\xA8\x2A\x51\x75\x7B\x0B\x7C\x63\x1B\xA7\x74\x79\xB1\xF3\x00\xBA\xEF\x62\x4A\xA9\x36\x49\x6A\xB3\x14\x58\x2B\x06\xE0\xED\x04\x04\xEF\xBD\x22\x20\x65\x12\x48\x09\x6D\x3A\xEF\x84\x79\x41\xED\x7B\xD1\x49\xA6\x21\x68\xE1\xD2\xDA\x07\x30\x80\x05\x4F\xAE\xC1\xF0\x86\x87\x44\x9D\x51\x2D\xA8\x72\xAF\x1C\xDB\x7D\xC6\x24\x31\x53\xCB\x59\x59\x6C\xD2\xEA\xCD\x45\x29\x73\xC4\xF2\x33\x58\xE9\x25\x4E\x29\x42\xD4\x61\x52\x55\xAF\xBA\xF9\x86\xF5\x2F\x10\xE2\xC9\xC6\x22\x76\x11\x6A\x66\xE4\xE9\xA5\xAF\x6A\x01\xB5\x62\x00\xEC\x3E\x80\x52\x92\x33\x3B\x1D\xE0\x53\x86\x84\x7B\xAF\x31\xE9\xAF\x1D\x8F\x32\x0F\xE9\x31\xCF\x59\xD9\x65\x28\x5D\x6D\xA5\x09\xA7\x01\x5C\x38\xA1\x01\xF4\x6A\x03\xC6\x18\x05\x54\x98\x65\x26\x54\x95\x38\x9A\x09\x58\xF7\xDD\x55\xC5\xDD\xBA\x88\x84\x85\xA5\x2E\xE1\x60\xDA\x06\xDB\xE7\x9F\x6A\xEF\x64\x24\x6F\x8C\x09\x54\x2D\xB3\x96\xB6\xBF\x46\xAE\x16\x20\xF7\x01\x14\x0E\x40\xED\x68\x2B\x90\x4E\x79\xB1\x82\x74\xDA\x76\xEF\xFE\x23\xEF\x04\xD0\x36\xBF\x5E\x59\xF0\x56\x04\x48\xE7\xA9\x3A\x9A\x98\x85\x05\x0B\x17\xE1\xD8\xD7\x7F\xAE\xBD\x0A\xC0\xFA\x5B\x4F\xA4\x5E\xA4\x19\x8C\x32\x59\xDE\xAA\x87\x81\xAA\x6E\x1D\xAE\xE2\xCC\x8C\x39\x28\x63\x75\x4C\x46\xA2\xA7\xDA\x61\x6D\x4E\x92\x78\xB2\x3C\x96\x96\xA4\x99\x4D\x95\xAB\xDA\xAC\xFE\x98\x52\xA8\x1D\x03\x90\x4E\xC0\x40\x2D\x57\x52\x38\xB8\xF0\x43\x48\xF1\x5C\xA4\x93\x26\x43\x99\x98\xE5\x63\x65\x02\xDE\xF2\x63\x15\x1F\x41\xB7\xCC\xF6\x3E\x80\xD3\x7E\x83\xE1\xA3\x8E\x5B\x67\x03\x9F\x3A\x0E\xAC\xED\x77\xCB\xCC\x88\x4D\x46\xAB\x0E\x96\xCE\x92\x86\xA9\x7D\xF7\x93\x6D\xC7\x64\xEB\x88\x31\x34\xEB\x8E\x82\xD4\xF9\xFE\xAA\xFD\x94\xEA\xDF\x29\x85\x5A\x31\x00\xF6\x65\x20\x10\x69\x9B\xBA\x03\xA0\xC8\xCB\xB6\x04\x6B\x2D\x40\xDF\x2F\x18\x5C\x36\x4A\x08\xBD\x1D\x97\x85\xB8\xA8\x4E\x6D\x6B\x00\x82\x01\x30\x47\x5C\x27\x1D\x57\x99\xAB\xFA\x02\x2C\x75\xB9\xEA\xDD\x01\xB2\x3E\xEB\xF4\x5D\x0A\xB7\xD8\x7E\x78\x18\xF9\x62\xF7\x08\xC8\xB4\xA9\xFB\x11\x2C\xDC\x62\x67\x20\x2C\xC9\xDE\xAB\xD6\xC0\xDA\xA1\xD3\xCA\x7A\x81\x1A\x11\xBF\xEC\xEC\x5A\x40\x71\x25\x98\x75\xB5\x17\xBB\xED\x07\x9A\x78\xA5\x16\xA0\x6C\xFA\xF6\x8F\x70\xFC\x95\xA0\x7D\x02\x80\xB7\x2B\xD0\x33\x23\x60\xE0\x56\x94\x83\x12\x8F\xB6\x06\xF0\x73\x67\x02\xBC\xE1\x73\xDE\x46\xA0\x76\x53\x81\x40\xFD\x2C\x4A\xC8\xC9\x7B\x01\xA9\x73\xEE\x6C\xC9\x0A\xE0\xAA\xAD\x86\x98\x2A\x1C\xF3\x9E\xC7\xCE\xD1\x33\x82\xB0\x0E\xF7\xF4\x5A\x87\x6E\x6F\xAA\x1D\x93\x85\x2A\x0C\xD3\x4A\x2B\x99\x4C\xDF\x04\x48\x81\xFE\x3C\x38\x3D\xA8\xA3\xED\xF2\xA2\x11\x19\x4C\xB5\x9C\x11\x6E\x27\x81\x70\xDA\xE5\x62\xE6\x29\xA6\x52\xA4\x95\x4C\x42\x16\xE4\x31\x03\x94\x0C\xA6\xED\x04\xBC\xF8\x4F\x18\xDE\xFB\x83\xE6\xA1\x97\xC9\xA8\x90\x3A\x7D\x6C\x89\xAA\xEA\xFE\x03\xF6\xCC\x3C\xD6\x96\xED\x9F\x52\xCD\x41\xF2\xAD\xCB\x0B\x41\xAC\x3A\x18\x8E\x7A\xF5\x04\xF0\xF1\x65\xF5\xB1\x7E\xB2\x18\x19\x10\x6A\x00\xAC\xAE\x5A\x40\xAD\x18\x80\xDC\x07\xD0\x09\xF0\xBC\xEA\x7C\x69\x50\x49\xE0\xD8\xF2\x20\x00\x73\x59\x50\xAB\xFD\xED\x67\x15\x07\x52\x3F\x54\xD9\x42\xDB\xE8\xDC\x07\xB0\x21\x86\xB3\x5D\x93\x67\xFC\x65\x9C\x15\xAE\x3D\xD0\x72\xB2\xB2\x89\x66\xAD\x4B\x33\x9F\xAA\xD5\xCC\x22\x3C\xE5\x07\x60\x4B\x64\x96\x83\x4E\xE3\x2A\xCD\xA2\x66\x24\xFF\xDA\xB4\x97\x85\x6B\xD0\xE6\x59\x4A\x5B\x8A\xAD\x5C\xE8\x74\x96\xF9\x30\xE5\x50\x2B\x06\xD0\xD6\x00\x20\xEE\x03\xD0\x6A\xBD\x01\xD6\xAE\xBD\x20\x5D\xF7\x1F\x7A\xD1\xA8\xE8\x0C\x7D\x5E\x00\x46\xB8\xC5\x74\xBA\xCF\x4D\xF8\x0C\x20\x46\x8C\x29\xA2\x01\xAA\x11\xB3\x4C\x5B\x75\x92\x5A\x0C\x45\xC6\xC7\x54\xF3\x14\x03\x88\x2D\xE2\x00\x3E\x41\x68\xBC\x75\x5C\xAA\xBD\xB2\x3E\xAB\xBD\xBA\xCD\x3A\x6D\xD5\xB1\x48\x2D\xBD\x42\x85\xC5\xCA\x9B\x32\xA8\x15\x03\x28\x3F\x0D\x06\x78\x97\x79\x4E\x24\x10\x3D\xAF\x7D\x00\x66\xA1\x08\x87\x99\x2C\x33\x96\xFE\x81\xCC\x7F\x2E\xEB\x95\x5A\x06\xC2\x55\x81\x76\x94\xEF\x95\x6C\x66\xCE\x04\xB8\xF6\x76\x0C\xBF\xE4\xEF\x93\xBB\xF1\x24\xB6\xB1\x2D\xBE\x4C\x82\x31\xA2\x93\x5D\x62\x2D\x5D\x59\x4A\x15\x2B\x37\xE6\xA5\xB7\x96\x17\x2D\x49\x97\x19\x65\xCB\x78\x6B\x04\x63\xED\x2D\xE2\x62\xED\xD5\x7D\x93\x91\x3C\x0C\x57\xAB\x3F\xD8\x66\xAC\x2A\x34\xD5\x67\x00\x0C\xBC\xEF\x02\x08\x22\x2D\x9C\x76\x9E\xA3\x4D\x61\x6F\x89\x1E\xED\xF1\x2F\x12\xC5\xBE\x0B\x18\x9C\x2F\xC8\xC3\xBA\x64\xF5\xE5\xD6\x63\x78\xE5\xB6\xEF\x03\xB8\xED\x21\x0C\x6F\xF7\x96\xE4\x19\xF8\x5E\xA4\x7F\x95\x31\xD3\x76\xAC\x94\xAC\xB1\x7A\x34\xF1\xE8\xFA\x99\xE4\x63\x65\x30\x49\x1E\xF3\xC2\x83\x94\x21\xA1\xCA\xB9\x87\x98\xA6\x91\x1B\xE5\x5A\x65\x58\x47\x94\x75\x7F\xB0\xF6\x46\xA7\x20\x6C\xC6\x38\x25\x50\x2B\x06\xA0\x7D\x00\xDA\x2E\xAF\x72\x8F\x5F\x3B\x4C\x32\x0D\xA5\x25\x78\x6B\xFA\x45\x3D\x8A\xD1\x40\xD6\x47\xA6\x29\xBB\x4D\x98\x30\xA0\xF6\x69\xC0\xEB\xEF\xC4\xF0\x8B\xFE\x2E\x79\x2E\x5D\x4F\xBC\xD4\x24\x82\xF1\x6E\x49\x2C\x3D\xCE\x0C\x17\x4B\xBB\x60\xDD\xAC\x19\x82\x1E\x02\x90\xFA\x8A\xF2\x1A\x3D\xE6\xF1\xA6\x48\xA2\xBD\x56\x5E\xCB\xB4\x61\xE5\x58\x75\xEB\x3E\xB5\x76\x09\xA6\xA0\xCF\x00\x2C\xF0\xAE\x05\x97\x1A\x00\xF9\x2D\x90\x67\x4B\x84\x7A\x73\x90\xF4\x0F\xB0\xB0\xB2\x7E\x31\xDD\x99\xED\xEF\xD9\xFD\xDD\x74\xB4\x8E\xCE\x7B\x7B\x19\xF0\x94\x33\x31\xDC\xFD\x3C\x78\x6C\x2D\x9A\xA9\xAA\x25\xBA\x62\xAC\x2C\xA6\xC1\x1C\x56\x96\x64\x62\x93\x57\xFE\x6A\x6D\x45\xDB\xB3\x0C\x9F\x98\x14\x04\xC2\xAE\xD6\x8E\x3C\xEB\x06\x21\x6F\x78\x8C\xB2\xAA\xB6\x37\x55\x0E\x3B\xBE\xAB\xF3\xCA\xB4\x96\x5F\x44\xB6\xD9\xD2\xF4\xFA\x0C\x80\x41\x2E\xEE\x04\x64\x44\x4E\xF3\xB0\x29\x99\xF9\xA3\x48\x55\xFE\x5C\xFC\x64\xAA\x1E\x31\x15\xAD\xBA\xE9\x6C\xCD\xBD\xB2\x3A\x3B\x01\xCF\xC3\xB1\x47\x7D\xC6\xDB\x0A\x2C\x27\xA8\x1E\x0B\xE6\x9C\xB2\xA0\xCA\xC6\x1E\x66\xB3\xA6\x4E\x1B\x02\x21\x53\x61\x0E\x45\xD2\xEB\xE5\xBB\xC5\xC8\x62\x8C\x2B\x26\xCD\x35\x73\xB2\x4C\x0F\x86\x7F\x93\x94\x65\x99\x3E\x56\xFF\xB1\xE1\xB6\xEE\x10\x64\xC7\x83\x65\x3F\xD7\x86\xF8\x25\x52\xB5\x00\xE9\x03\x68\x81\x79\xD2\x0E\x64\x06\x6A\x87\x1C\xC2\x99\xA9\x25\x3C\x5B\x42\xF4\xFC\x0C\x44\x93\x08\xE2\xC4\xBB\xF2\x19\xE8\x9D\x80\xB2\xBF\x53\xAA\x62\x2C\x5D\xD5\xBD\xF4\x99\x91\x2E\xC6\x04\x52\x79\x2C\xD5\x1A\x89\xB4\x8C\x38\x53\xED\x49\xE1\xA4\xD3\x59\x38\x59\x1A\x12\x63\x2A\xD6\x5E\x06\x66\x2A\xB1\xF6\xA4\x6E\x54\xAA\xD5\x36\x60\xD6\x79\x53\x0A\xC1\x3E\x00\x1D\xDF\xFD\x27\x90\xC8\x8C\x3B\x44\x5A\x16\xDB\xDE\x6B\x99\x12\x99\xCA\xCB\x0C\x73\xA5\x41\x30\x06\x90\x82\xA9\x70\x12\x59\x92\x6D\x5D\xE0\xC0\x46\x4A\x83\xB5\x0D\x58\x33\x80\xB5\x05\xB6\x34\x57\x94\x6F\x31\x0D\xAB\x7F\x62\xDA\x94\xD4\x80\x62\x9A\x53\x2D\xA0\x56\x0C\x20\xB8\x16\xBC\x3B\x0D\xA8\xE3\x4F\x49\x5E\x0F\xA4\x8D\x4E\x88\x9D\x6D\x2B\x66\xFE\x04\xC0\x27\xEE\xB2\x3E\xCB\x21\x29\x4C\x8D\xBC\xB5\x0C\xE8\x18\xC0\x2F\xCE\xC5\xB1\x47\x7F\x36\xB8\x13\x50\x60\xDA\x06\xEB\x6A\x70\xD2\xB2\xE4\xD2\x5B\xAE\xD2\x56\x85\x9C\x94\x0F\xD8\x75\x49\xFC\x81\x50\x12\xEA\x9D\x72\xE6\xB0\x27\xCA\xB7\xCE\x27\x58\x76\x78\xAC\xEF\x72\xD8\xB6\xBB\x1E\x03\x80\xFB\x55\x7A\xDD\xFA\xDC\x37\x01\xAA\x82\x77\x1A\xB0\x20\x7E\xE1\x0C\xD4\xEF\xEC\x0B\x40\x72\x99\x4F\x36\x52\xAE\x00\x98\xB3\x98\x98\x11\x54\xE3\xD0\x99\x79\x9E\x26\x66\x60\xC1\xB9\x97\x63\xF8\x80\x8F\x56\x36\x01\x52\x2A\x62\xEA\xC0\x8A\x6C\x72\x01\x8C\x10\x2D\xA9\x34\x19\xE9\x6F\x11\x42\x4C\x85\x66\x0C\x2F\x43\x28\x75\x01\xCE\x04\xD8\xDA\x7E\xAC\xBD\xB2\x2C\x66\x06\xF4\xAA\x65\x58\xCC\x42\xB6\x45\xF6\x6D\x2D\x89\x5F\x22\x56\x0B\x28\x0F\x03\xC9\x40\xE2\xB3\xD5\xCE\x3C\x7D\x9D\x37\x63\xBF\x3A\x2F\xD5\x00\xC0\xCB\x81\xA1\x11\xB0\x0F\x8B\x94\xF9\xBB\x5F\x06\x5A\x31\x82\xE1\x79\x47\x54\x22\x6A\x89\xA2\x76\x14\xA6\x8E\xF7\xB2\x1E\x8B\x9D\xA2\xB3\xBA\x4B\xDB\xDB\x55\xED\xF3\x58\x5B\x34\x6E\xA9\xB2\xAD\xFE\xB1\x34\x80\x5E\x8E\x04\x5B\x8C\x37\x66\xFE\xF4\xAA\xCA\xC7\x9C\x80\x7D\x06\x10\x03\x6F\x23\x50\x11\xA8\xD5\x6D\x62\x83\xCB\xF4\xCC\x88\xD4\xDA\x44\x20\xE9\xBB\x26\x83\x3C\x3D\xA8\x19\x45\xF1\x5C\xC6\x19\x7E\x06\x51\x45\x67\x19\xF0\x2C\x0C\x1F\xF3\xF9\xE4\xE1\x98\x28\xAF\xAA\xD8\x7D\x31\x67\x15\x93\xC8\xD6\x19\x77\xB6\x54\x55\x95\x48\xE5\x33\x9B\x5B\x6C\xD8\xAC\x76\xA6\xA4\x73\xAF\xED\x85\xC2\x4B\x2F\x1B\x5A\x6D\xD6\x26\x16\xDB\x60\x65\xAD\x00\x48\xDC\xA6\xC2\xBF\x93\x84\x7A\x31\x80\xD6\xB5\xE0\xD9\xC4\x2A\x40\xB9\x54\x27\x97\x04\xE1\x13\x67\xD9\x10\x62\xE7\xC7\x9E\x45\xF1\x81\xF3\xB0\xB4\xF9\x09\xB3\x90\xE9\xE9\xA1\xA1\x89\x32\x9A\x68\x31\x80\x5F\xE3\xD8\x63\xBE\x58\x2E\x03\xCA\x3E\xD7\x92\xD7\x5A\x6E\x82\xCA\x5B\xD5\xE5\x19\xB3\x8D\x99\x1A\x5C\x45\x73\xB0\x54\x5B\x8D\x5F\xAC\xFC\xA2\x3C\xA6\xE1\xF4\xD2\xEE\xAC\x42\x9E\xE2\xD7\xF2\x95\xB0\x36\x33\x47\x9E\xC5\x38\x20\xCA\xA9\xC2\xF8\x72\xA4\x99\xE9\xD3\x0A\xF5\x62\x00\xE4\x5A\x70\x4F\x1A\x0B\xA4\xB5\x4D\x1F\x5B\x40\x67\x0E\xC4\x40\x7D\x37\x9C\x83\xBA\x0C\xCF\xE7\x00\xC2\x28\x26\x98\x43\x33\x1B\xC2\x82\xC5\xB7\x61\xF8\x65\xEF\xAA\x74\x6C\xB7\xD7\xB1\xB0\x18\x80\xB4\xB1\x99\x64\xB2\x88\x37\x55\x9E\x65\x02\xE4\x15\xCB\xD0\x04\xA0\x09\xD4\x52\xD1\x19\xC3\x4B\x5D\xDA\x51\xA5\xBD\xAC\x0E\x6B\x6C\x2C\x1F\x4A\xAC\xAF\x98\xE9\xA0\xF3\x4F\x39\xD4\x8A\x01\x94\x87\x81\x88\x4A\x4E\x08\x2C\x38\xEB\x5F\xFC\xE8\x4B\x41\x98\x29\x90\xC5\xF8\x34\x42\x75\xBF\xFD\x9A\xD0\x32\x94\x46\xD2\xCC\x9B\x58\x90\x6D\x8C\xE1\x6C\x97\xA8\x44\xD5\x2A\x24\x95\x0E\x33\x87\x90\x8D\xAC\x61\x98\x9A\x93\x2C\xDA\xD5\x00\x95\x88\x32\x4E\x4B\xBC\x58\x1D\x2C\x5E\x32\x22\xBD\x32\x11\xB3\x91\xB5\x63\x8F\x99\x4F\xBD\xB6\xD9\xD2\xB6\x74\x1B\x64\x1C\xDB\xB9\x29\xD3\x5A\x4C\x9B\x31\x45\xCB\xB4\x9A\x72\xA8\x15\x03\x90\x37\x02\xA5\x36\xF5\x44\xD7\xFA\x0D\xC7\xA0\xC7\xAA\x15\x93\x28\x13\x81\xD7\x2D\xDF\xF5\xA6\x21\xE3\x78\x71\xE7\x38\xF0\x46\x1E\x03\x90\x12\x4C\xAA\xFC\x16\x41\xA4\x88\x4E\xFE\xC6\xD6\xD2\x61\x94\xA9\x9B\x96\x93\xB2\x59\xFA\x98\xA3\x4F\x13\x91\x04\xB6\x77\x9E\xF5\x81\x2C\xAB\x59\x31\xDC\xCA\x6F\x11\x23\x10\xB6\x8D\xB5\x37\x76\xA2\x51\xDF\x1F\xA8\xEB\x64\xCF\xB5\x91\xFE\xBA\xB3\xA6\x1C\xDA\x0C\xA0\x6B\x02\x78\xF6\x74\xAE\x66\x89\x26\x6E\xA2\xB6\x6B\x87\x61\x09\x4C\xB5\xD7\xE9\x94\xD7\x3F\xEA\x23\x90\xE5\xA8\xE6\xB4\x4C\x80\x3F\x2E\xC1\xF0\xAE\xC3\x51\x6F\x3D\x93\xB4\xED\xDF\xAF\xBD\x07\x73\xFE\xF1\x1D\xD8\x39\x7F\x1C\x2B\xB2\x79\xB8\xD9\xF5\xCC\xF2\xEC\x15\x51\x7B\x57\x97\x9B\x47\xE2\x5B\xC0\xAE\xD8\x62\x44\xC2\x6C\x6F\xED\xAF\xE8\xD5\xB9\x87\x48\x7A\xCB\xF6\x4E\xB5\x37\x86\x4B\xAC\x5F\x74\xFD\xEC\x66\x60\xA8\xFC\xCC\x0F\x51\x55\x2B\xAB\x0D\x13\xA8\x1D\x03\x40\x71\x2D\x38\xC0\x37\xDB\xC0\x27\xD4\x32\x1D\x91\xC4\xA6\xCD\x2E\x1B\x9F\x55\x60\x00\x2A\xDC\xBA\x22\x5C\xF9\x19\x8A\x55\x80\x63\x8F\xF9\x42\xB9\x11\xC8\x52\xBD\x99\xFA\xDB\xFC\xFA\x7B\xB0\xD1\xFB\xFE\x06\xC7\x39\x06\xB0\xAB\xAB\xE7\x76\x17\x76\xD3\x8A\xD5\xB8\xA4\xD9\xC4\xE2\x79\x47\xE0\xD1\xC4\x98\x5A\xD2\x33\xA6\xD2\xC7\x2E\xD2\x8C\xDD\xC3\xC7\x98\x43\x6A\xEB\x2E\xEB\x0B\xAD\x59\x68\xD5\xDD\xDA\xC2\xCC\x70\xB1\xDE\x61\x94\x6B\x95\x95\xDA\xDC\x93\x27\xCA\x80\x51\x6E\x2D\xA0\x7E\x0C\x20\xEF\x7E\x19\x48\x3A\xFF\x0C\xA9\x5D\x4A\x63\xA8\x51\x21\x5E\x7A\xD3\xB5\x6C\x31\x07\xE5\x43\x60\xB7\x04\xE5\x1A\x17\xDF\x87\xA0\xAF\x05\x67\x44\xC7\x88\xB5\x0C\xFF\xB7\xB7\x62\xE0\xB8\xBF\xC7\xFF\xC3\x18\x3E\xEB\x72\x0E\xB9\x32\x57\x66\x0D\x47\xF8\x19\x6E\xC8\xC7\x71\xDD\x78\x13\xBF\x19\x68\x60\x89\x0B\x7B\xE0\xEE\x87\x30\xB6\xD5\xDB\x3B\xE5\x7F\xEB\x1F\x91\x1D\xFB\x75\xBA\x2C\x96\x5A\xD7\xCF\x13\xE9\x99\xBA\x5F\x65\x8D\x3E\x05\x8C\xC0\xA5\x1F\x42\xF6\x5F\x2F\xBB\x12\x53\x27\x25\x19\x1E\x40\x28\xFD\x63\xCC\x2D\xB5\xD7\x40\xE3\x55\x2B\x33\xA0\x56\x0C\x40\x7F\x19\xC8\xBA\xFA\xDB\xD4\xAF\x22\xD6\x24\xD5\x81\x0D\x95\x5E\x8B\xEA\xC8\x99\xFF\xE8\xC7\x41\xC9\xB5\xE0\x5E\xF5\x5D\xB0\x26\x53\x1B\x6E\x3A\x11\xBB\xEF\xB0\x2D\x4E\xC4\x6A\xBC\x40\xF5\xC1\x6A\xF7\xF3\x80\xAB\xFF\xE6\x66\x8E\x25\x63\xE3\x58\x3C\x7D\x08\x17\xAE\x58\x85\x7B\xE7\x1C\xDE\xD6\xA4\xB0\xC7\x4E\xC8\x2E\xBD\x3E\xB0\xDB\x99\x7A\x1F\x9B\xDC\x00\x27\x64\xAD\x21\xE8\x91\xB0\xA4\x27\xBB\x4C\x53\x0F\x91\x65\x2F\x5B\x57\x70\x6B\x89\xAE\xDB\x6B\x5D\x06\xCA\xFC\x03\x55\x36\x36\x65\xB0\x19\x9E\xF6\xCD\x00\x71\xE6\x3B\xA5\x50\x2B\x06\x10\xDB\x08\x54\x84\x59\x0E\x39\x19\xE8\xDD\x1F\x20\x0B\x23\xCE\x3A\x5D\x68\xFB\x35\x17\x59\x0C\x2B\xB1\xF0\x45\xC8\xFB\x09\x54\x99\xCD\x6C\xA6\x63\x00\xE7\x7B\xC7\x81\x01\x9B\x11\x80\xA5\xF9\xC5\x27\x31\x74\xE4\x6B\x70\x9C\xD3\x02\xFE\x29\x6F\xDD\x33\xAC\xF1\xEA\x94\x33\xEE\x72\x8C\xBA\xA7\x7B\xDC\xF4\xBA\xD6\x4D\xAF\x45\x18\xC4\x1F\x97\x2E\xC5\x2D\xAB\xD6\x60\x64\x93\x37\x75\x26\xDC\x4B\xB6\x41\x76\xDD\xED\x2E\x6B\x86\x7C\xBC\x69\x7A\xC1\x27\xB3\x01\x88\x31\x0D\xE6\x27\xB0\xCA\x8C\xA9\xF8\x55\x3D\xE7\xAC\x5F\xAD\x33\x16\x8C\xF1\xE9\xF6\x00\xB6\xB4\x66\xED\xD5\x75\x00\x36\x23\xAB\x0D\xD4\x8A\x01\xC8\x4F\x83\xE9\xE3\xB5\xED\x67\x35\x7C\xCC\x10\xF3\x94\x00\xC3\xB6\xD7\xBE\x81\xD8\xF5\xE3\xBA\xB3\xD8\x45\x25\x45\xA4\x32\x41\x9A\xE8\x30\x80\x61\xC7\x00\x2C\x09\xDA\x02\x8B\x80\x8A\x38\x3C\x79\x1A\x5E\xB9\xDE\x1C\x7C\xD7\xBD\xBD\x18\x12\x6F\x84\x33\xBA\x1D\x9D\x63\xA9\x8B\x7F\xD0\x05\x5C\xE6\xFE\xEE\x75\x61\xE7\xBB\xBC\xB7\xDD\x72\x1F\x1E\x7D\x72\x05\xD6\xBC\xE2\x1F\x27\xBA\x64\x97\xED\x90\xDD\x7C\x1F\xB0\x74\xA5\x47\x04\x1A\xAF\xAA\xC7\x81\xAD\x36\x31\x07\x9B\xCC\xD3\xEB\x71\xE0\xAA\x47\x8E\x59\x5D\x32\x7D\x4E\xC2\x01\x1F\xEF\xAC\xC7\x3C\x50\x79\xFB\x0C\xA0\x2A\x58\x5F\x07\x06\x79\x8F\x81\x75\x94\x57\x96\xC5\x1A\x9F\xFA\x3C\x78\x61\x2E\xA4\xCA\x29\x9A\xA3\x18\xC0\xA4\xED\xBF\x73\x3E\x8F\x81\x57\xEC\x80\x2F\xCD\x9F\x8B\x7F\x6C\xFB\x02\x64\xBD\x8A\xF3\x19\x67\x1C\x1E\x71\x3F\x4B\xDC\xF3\x22\x17\x70\xB9\xC3\xE6\x26\xCC\xC1\x63\xA7\x9F\x87\xF1\x23\x3E\xED\x74\x8B\x2E\xEC\xB6\x23\x1A\xBF\xBB\xC1\x54\x6D\xD9\xDE\x05\xF9\x1C\xDB\x7C\xC4\xD4\x61\xC0\x66\x14\xF2\xB9\xEA\x39\x00\xC9\x64\x18\x91\xA6\x4E\x0F\x56\xB9\x43\x40\x0E\x7D\xCC\x54\xD2\x8C\xA3\x6F\x02\x54\x01\x6D\x02\x94\x12\xB7\x8B\xA9\xC5\x18\xD8\x32\x1D\x00\xCF\x5B\x2F\xA7\x47\xE9\x64\x94\x66\x82\x2C\xAF\x48\xA7\xB4\x07\xAD\x62\x04\x5F\x20\x92\x1D\x3B\xA1\x01\x68\x13\xA0\x05\xEC\xB8\x6C\xD4\xB1\xB5\x64\x01\x76\xDF\x7E\x6B\xA7\x05\x8C\xE1\x85\x31\x87\xA4\xEE\x3B\xF2\xDD\x83\xC7\xDC\xCB\x0D\xEE\xE1\x3C\x57\xFB\xBD\x8F\x3F\x85\x6B\x9F\x5A\x81\xDB\x67\x0C\xE1\xC9\xCD\xDF\xEC\x4F\xCC\x9D\xB6\x46\x76\xFD\x9D\x95\x18\x56\xD4\x8F\x11\x49\xAB\xFB\x62\x32\x17\x82\xE8\xF4\x96\x96\x01\x52\xBE\x66\x32\x50\xE9\xAC\x1D\x85\xDA\x07\x20\xF3\xB0\x31\xAC\x25\xF1\x33\x64\xA7\x14\x3C\x0D\x80\x79\xE7\x33\x32\xC9\xC5\x8B\x36\x02\x3D\xAF\xBC\xD1\x58\x76\xBC\x18\xB2\x1C\x8D\x47\xE8\xED\xE7\x5B\x89\xBB\xF7\x01\x44\x2E\x04\x31\x7D\x99\x22\xBE\x44\xE3\xE4\x8F\x62\xDA\x11\xBB\xE3\xF3\x33\xA6\xE3\x9F\x5C\x1D\x83\x81\xEF\x43\xE1\x1B\xFB\xEE\x81\x08\x5B\x93\x35\x70\xAB\x7B\xBC\xD4\xFD\x5D\xE6\x4A\xBD\xDE\xB1\xAA\xBB\x6E\xBC\x1D\xCB\x76\x7C\x37\xD6\xC8\xB4\x2D\xED\xE0\xE1\x27\x80\xBB\x1F\x41\x3E\x3A\x66\xAE\x16\x40\x85\x5B\xC4\x00\x84\x04\x14\xF3\x9E\xEB\xBA\x00\xDB\x24\x91\x0E\x48\xBD\x44\x17\x5B\x89\xD1\x04\x2C\x19\x8F\xF6\x67\x68\xA6\x54\xE5\x3E\x00\xE9\x77\xA8\x0D\x13\xA8\x15\x03\xF0\xBE\x0B\x80\x50\x82\xEB\xE5\xBF\x52\xFA\x02\x86\x08\x44\xB8\x5D\x58\xDB\xFB\x52\x82\x17\x79\x74\xCF\xC8\xE5\x40\xC0\x26\x32\xF9\x9E\x77\x0E\x03\x11\x06\x90\x29\x6C\xD8\x7A\xB8\xE7\xD9\x7E\xF9\x76\xC0\x55\xB7\x20\xBF\xF3\x87\xD8\x7B\xAB\x67\xE3\xB4\x7C\x0C\xF3\x33\x95\x2B\x90\xFA\x8C\xF9\x89\x36\x96\x61\x7E\x3B\x97\xB8\x76\x5E\x9C\x0D\x38\x13\x61\x1C\xB7\x8D\xAC\xC6\xB5\x17\x5F\x87\x7B\x0F\xFC\x38\x46\x8D\x21\x63\x1B\x66\x98\xA2\x16\xA0\x49\x7E\x75\xFB\xD9\xC8\x16\xEF\xA9\x63\xC0\x31\xED\x41\xD7\x67\x5D\xF0\x51\x3C\x5B\x4C\x2C\xC6\xBC\x25\xB1\x4B\xDC\x6A\xE7\x0B\xA8\x1D\x03\xF0\x96\x01\x01\xF3\x26\xE0\x40\x6A\xEB\x67\xD1\x3A\xED\xF0\xD3\x8E\x3F\xE9\x54\x64\xCE\x41\x3D\xFD\xAC\x7D\x03\xEA\x8E\xC1\x62\x1F\xC0\xB1\x8E\x01\x8C\xAB\x92\x98\xFF\x52\xD4\x40\x99\x04\x6E\xFE\x1F\x6C\xB8\xDD\x96\x58\x98\x8F\x63\x6F\x6D\xE7\x4B\x7C\xD8\x27\xD3\xA9\x0F\x43\xF4\xB1\x6A\xE6\xB8\x8B\xBB\xDF\x69\x07\x37\x60\x86\xD3\x0C\x9A\xF8\xF3\x9D\x77\x63\xF1\x92\x7B\xF1\xC0\x81\x1F\xC3\x88\x1C\xB3\xA1\x41\x64\x6B\xC6\xCA\xEC\x7A\xBF\x03\x5B\x11\xD0\x04\x64\xB9\x52\x2C\xC2\x8E\x69\x0A\x16\xD3\xA9\xB2\x3E\xCF\x9C\x78\xBA\x6C\x4B\x9B\x60\x8C\x4F\xFB\x24\x2C\x86\x37\xA5\x50\x2F\x06\xD0\xFD\x38\x68\xFB\x19\x6A\x06\x10\xBB\x17\x24\x21\x53\xE3\x63\x8D\xB4\xD6\xF8\xBD\x5F\x3D\x45\x59\x3D\xB2\x1C\xBE\x0A\x20\x07\x3E\x26\xF5\x0C\xB6\xD3\x81\xD1\x33\xF1\xB7\x83\xD3\x70\x7C\xDE\xC4\xFA\xDA\x1C\x61\xFD\xC1\x1A\x5F\x7E\xC8\x84\x99\x08\x82\x79\x96\x5A\x43\x03\x8F\x60\x00\x57\xB9\x91\xB9\x1A\x73\x71\xEB\xFD\x37\xE2\xA6\x4D\x37\xC4\x8D\x03\x07\xE0\x49\x5D\xF6\x3B\x0F\x44\x76\xE2\x39\x5E\x9B\x4C\x9F\xAB\xD1\xDE\x3C\x92\xD6\xCA\x0B\x52\x86\x0E\x67\xBE\x81\x02\xAA\xD8\xE6\xDA\xAB\x1F\x23\x68\xCD\x2C\x24\x4E\x7D\x06\x60\x81\xF4\x01\xB4\xC0\x24\x4A\x25\xD5\x74\x63\x82\xD9\xA2\x1D\x7A\xB2\x1C\x84\x0E\x41\xFD\xD5\x61\x59\xA8\x35\xB3\xDA\xCF\xBE\x6F\xA0\xE3\x03\x38\x3F\xB8\x16\x5C\x37\x0D\x88\x33\x07\x2F\x5F\x7E\x2E\x36\x73\x6F\xDF\x73\x53\xEB\x10\xDD\xB6\x54\xE1\xDA\xCF\xC1\x44\x67\x30\xA3\xFD\xF2\xC7\xDD\xC3\x32\x0C\xE1\x3E\xF7\xFB\xC7\x65\xCB\xB0\xF8\x8E\x87\x70\xE9\x8B\x5F\x88\x5B\xB2\x3D\xF0\x94\x44\x78\x1B\x87\xE5\x6D\x0F\x24\xD7\xD0\xAD\xF6\xB2\x2E\x4E\x11\xBC\x15\xAF\xBB\xC1\x3A\x8D\x28\xC1\x62\x42\xBA\x4E\x86\x83\x05\xB5\x93\xFE\x12\xF9\x5A\x40\x6E\xDC\x07\x40\xBD\xDE\x86\x4A\xCB\x7C\x05\x31\xBB\x38\x37\xCA\xB4\x98\x4D\x0F\x79\x62\xB7\x02\x33\x67\x50\xA5\xB5\xED\x05\xFF\x0F\xD9\x5F\xEF\x87\x37\x0D\x34\xF0\x7D\xF7\x3E\xC3\x52\xE9\x75\xBB\xF3\x2C\xA4\x24\xE9\x17\x08\x08\xDE\xF7\x67\x78\xE3\x50\xD6\x99\x61\x25\xA6\xE3\x26\xAC\xC6\xCD\x2E\xCD\x65\x2E\xFA\x81\x6C\x08\xBF\x1F\x59\x86\xFB\x67\x1D\xEE\x4F\xF4\xAF\x0C\x23\xFB\xE0\xB7\x03\xEF\xB9\xA5\x4E\xCB\xA1\x96\xC3\xA5\xFB\x2C\xE6\x67\x90\xCD\xEC\xF5\xBE\x05\xE6\x9F\x61\xBE\x1A\xEB\x14\x60\xAC\x4C\xDD\x86\x29\x85\x5A\x31\x00\x79\x27\xA0\xC5\x66\xA1\xC2\xA9\xD3\x4E\x26\x52\x4E\xBA\x76\xD2\x2C\x9A\x8C\x86\x31\x15\x19\xE0\xD4\xDA\x1D\x69\xBD\x0A\xC0\x9C\x5B\x2D\x90\x84\x50\x65\x02\x61\xF4\x2C\x6C\x3A\x38\x80\x9F\xB8\xC7\x7D\x2C\x82\x2E\xDB\x9B\x19\x5D\x43\x98\x03\x63\x14\x3D\xF4\xD3\x0A\xF7\xB7\xD4\xFD\xDD\xE0\x5A\x74\x95\x0B\xBC\xE0\xDE\x87\x70\xF9\x96\x6F\x6D\x87\x95\xF0\xD5\x63\x91\x7D\xE0\x5B\xA6\xCD\x9C\x52\x99\xB5\x2A\x1F\xDB\x6C\x64\xF5\x65\x2F\x52\x1F\x46\x3A\x5D\x5F\x55\x2D\x40\x97\x31\xE5\x50\x2B\x06\x20\x3F\x0D\xD6\x7E\x57\xAA\x7B\xCC\xB6\xB7\xD4\x59\xD6\xD8\xD4\x46\x21\xA8\x72\x2D\xD5\xD9\x9A\x01\xDD\xB8\x42\x03\x28\x9C\x80\x16\x5A\x3D\xC3\xC8\x19\x18\x98\x3E\x84\x63\x5C\x81\xDF\x76\xAF\x73\x24\x12\x52\x0B\x29\x1D\xA5\x08\x1D\x83\x9E\x76\xD4\x45\xD8\xBC\x87\x21\x17\xC8\x77\xC9\x47\x3B\x49\x95\x36\xD1\x62\xE4\x8F\x62\x00\xF7\xB8\xF7\x4B\xF2\x35\xF8\x43\x36\x0D\xB7\x63\x06\x6E\x76\xA6\xC2\x32\xD2\x24\x6B\x35\x41\xF7\x57\x95\x2D\xC7\x72\x68\xAC\xDB\x7C\xD8\x94\xB2\x34\xB2\xD4\x79\x86\x5E\xF3\xD4\x46\xFA\xEB\x0E\x98\x72\xF0\x56\x01\x80\xF8\x47\x38\x0D\x15\x95\xDE\x05\xC8\x1A\xAB\x09\x43\x4D\xFE\x52\x1A\xAA\x74\x26\xEE\xB2\xFC\xC2\x09\xE8\x6B\x00\xDA\xF6\xB4\x4E\x93\x25\x0F\x0E\xFD\xCD\x7E\xC8\xBE\xFF\x11\xBC\x3C\x1F\xC7\x8F\xDD\xFB\xF6\xE6\x71\xE8\xD8\x33\x42\x62\xF6\x34\x02\xD5\xA7\x05\xE3\xB0\xBE\xD4\xC4\x3A\xA4\xCB\x34\x47\xDB\xA7\x18\x33\xDC\x87\x8E\x76\x70\x46\xB3\x89\x3F\x35\x86\x70\x07\x46\x31\x92\xED\x8F\xF1\x0F\x1C\x89\x6C\xF1\x6D\xC0\x45\xD7\xD2\xF6\x4A\x82\xAD\x72\x8A\xB1\x48\x9F\xD2\x12\xB4\xC6\xD0\xCB\x19\x88\x5E\x60\x9D\x31\xFE\xBF\x04\xD4\x96\x01\x94\x61\x20\x9E\x6E\x11\x69\x32\x08\x95\xC5\x62\x20\xDA\x3F\xE0\xE9\x9A\x2A\x0D\xFD\xD2\x30\x42\xFF\x42\x17\xDA\x0C\xE0\x17\x4E\x03\x38\xFA\xB8\x60\x27\x60\x06\x5F\x4A\xB5\x20\x75\x3D\x78\x29\xC9\x36\x9C\xEB\xBA\xEA\x0B\x98\xFD\xF2\xED\xF1\x51\x17\xF3\xB1\x40\x07\x15\x9D\x60\x1D\xAB\xF6\xDA\x07\x95\x06\x30\x35\x24\x73\x33\x14\x40\xC9\xAB\x64\x1C\x05\x3A\x19\x56\xB7\x96\x18\xDD\xEB\x15\x2E\xF0\xA2\xF1\x71\xDC\xDC\x1C\xC7\xDD\x4E\x65\xB8\xEF\xAA\x1B\x31\xFA\x9A\x0F\x4F\xF4\xD5\xF4\x69\x68\xCC\x9A\x8E\xFC\x89\xE5\xA6\x33\x31\xA6\x2D\xC8\x74\x29\x62\xEE\x65\x27\x63\x2C\x8D\xD6\x28\x24\x3E\x79\x22\xEF\x94\x40\xAD\x18\x80\xBC\x12\xAC\x44\xCE\x22\xBC\x0C\xF4\xE3\x20\xE6\xE5\x9E\xB9\xC8\x6F\xA9\xCA\xA4\x2C\x18\xE5\x03\x89\xBA\xBA\x1F\x06\x39\xEB\x12\x0C\x1F\xF2\x89\xE4\x8D\xB3\xD6\x56\x55\x3D\x56\xA5\x44\x3B\xF6\x50\x64\x27\xBC\x1F\xAF\x76\x75\x7D\xD7\xBD\xBF\xC0\x72\x6A\x7A\xED\xD0\xFD\x96\x87\xFD\x51\x30\x0D\xA8\xF2\x34\x63\xB1\x4C\x06\x99\x4F\x36\x42\xC7\x75\x7F\x9F\x72\xBF\xCB\xDC\xCB\x2D\xEE\xF5\xF2\x66\x86\xDF\x3D\xF1\x24\x6E\x7E\x62\x19\x1E\x38\x7E\x21\x56\x7D\xEB\xCC\x89\x73\x0A\x83\x03\xC8\xC6\xC6\xA3\x1A\x42\x4A\x9D\x97\x8C\x54\xA3\xC7\xB6\x02\xB3\xE3\xCE\x96\x19\xC0\xCA\x30\xA7\x79\x85\x34\x4F\x1B\xD4\x8A\x01\xC8\x6F\x03\x32\x8F\xFE\x44\x42\x04\xCB\x7A\x6A\xB9\xAA\x13\xA4\x24\x5E\x39\xB9\xB5\x94\x23\xDA\x03\xD8\xE4\x26\xB2\xC6\xB4\xAD\x3B\x03\xBD\x60\xE5\x2A\x0C\xCF\x79\x9D\xA9\xB6\x56\xF9\xC0\x05\xF3\x7E\xB7\xD3\x5F\xFD\x4D\xAC\xFF\xB2\x1D\xF1\x11\xAC\xC1\xBF\xB4\xC3\x84\x83\xD2\xF2\x4A\x59\x8E\x3C\xAD\xDE\x17\x15\x6B\xD3\xC6\x72\x12\x5A\x62\x98\xA5\x31\xB4\xB4\xD6\x30\xB4\x6E\x39\xBA\x21\x6B\x9D\x62\x6C\xE0\x4A\x17\x79\xEF\xBD\x0F\xE2\xAE\x2D\x9E\x85\x27\xB3\xFD\x26\x76\x23\x6E\xB5\x09\xB2\xBB\x1E\x42\xDE\x65\x0A\x4C\xD2\xC6\xCE\x17\x30\xA7\xA2\xA7\x61\x81\xFB\x23\x18\x5F\x83\xAA\x87\x5D\x1E\x5A\xBC\xCB\x3A\x6A\xC3\x04\x6A\xC5\x00\xE8\xD7\x81\xE1\xDB\xA4\x45\x78\x1B\x79\x65\x9B\xC6\x9C\x73\x5A\x1D\x06\x49\x13\x7C\x25\xC8\x70\x8A\x21\x52\x86\x78\x6F\x9B\x00\xA7\x2E\xC2\xF0\x9B\x3E\xD7\xF3\x80\x33\x69\x46\x55\xC7\x35\x17\x60\xF7\x69\xA3\x38\xD1\xE1\xFE\x82\xCC\xA4\x5C\x85\x9B\x90\xE0\x45\x3F\x96\xFD\x9D\x85\xE9\x13\x45\x52\xF0\x4C\x05\x80\xED\x36\xF4\x1D\x90\x08\x28\xEC\x09\xB4\x0E\x2E\x35\x70\xB5\x6B\xF5\xA5\x2E\xED\xE2\x25\xF7\xE0\xC6\xE7\xEF\x80\x65\xD9\x5E\xED\xCB\x50\x3C\x98\x3B\x13\xD9\xFA\x73\x80\x7B\x1E\x49\xAE\xA4\xE8\x66\x31\xE6\x0A\x70\xC2\x4E\xA9\xF1\xEC\x84\x62\x95\x7C\x53\x06\xB5\x62\x00\xD6\xD7\x81\x63\x13\x93\x4A\x6A\x08\xCD\xA1\xFB\x62\xD9\xB8\xB2\x7C\x4B\xCD\xD7\x76\xB3\x16\x63\xC6\x67\xC5\xF5\x69\x40\xCD\x97\xE4\xBB\xF6\x74\x6B\x4F\x35\x9B\x48\xED\x3A\x16\x7D\x1E\x1B\xEC\xBF\x1B\xBE\x90\xAF\xC1\xBB\xCD\xC1\x24\xBE\x00\xCB\xA9\x69\x49\x69\xCA\xE4\x74\xB9\xF0\x89\xB8\x1C\x1B\xE1\x5F\x61\x66\x05\x63\xCC\xAA\xBC\x96\x13\xF1\x01\xF7\x72\xF1\xF8\x38\xEE\x5B\xB5\x1A\x57\x3E\xFC\x24\x6E\xB8\xF3\x21\xDC\xB7\xEF\x47\xFC\xAD\xC9\x2D\xD8\xFB\xC5\xC8\x5A\x0E\x45\xB1\x19\xC9\xEA\x6F\x6D\x86\x69\x69\x1D\xDB\x3F\xC0\x34\x8D\x8C\xA4\x67\x65\xD6\x06\x6A\xC7\x00\x50\x1C\x07\x26\x84\xEA\xA5\x25\x2A\xFF\x44\x64\x62\xC2\xB3\x99\xA8\x7B\x23\xF0\xAC\x19\xC9\x73\x12\xDE\x79\xE9\x1C\x06\x3A\x8F\x6E\x05\x2E\xB2\x6B\x47\xA0\x05\x4C\x52\xB5\xE1\x5F\xDE\x88\x69\x5F\x3C\x16\x7F\xE3\x7A\xEE\x3F\x5D\xE1\xF3\x60\x30\x33\xAA\xD1\x08\x8D\xC7\xEB\x53\xD9\xB7\xB9\x6A\xAF\x08\x67\x1A\x19\x1B\x23\x44\xD2\xB2\xAF\x3B\xC5\xEE\x65\xE8\x22\x32\xE2\x48\xE9\x46\xF7\x7B\x8E\xFB\xBB\xDA\x85\x5C\x85\x41\xDC\xED\x34\x83\xAA\xC7\x90\xD9\xAC\x92\xBE\x19\x6D\xF7\x07\xBC\x0D\xFE\x0C\xD2\x79\xF5\xF8\x4A\x33\xA3\xCF\x00\x2C\xD0\x5B\x81\xA5\x43\x4A\x76\xAB\xA6\x53\xC6\x05\xBC\x49\x0D\x7F\xE4\xFC\x04\x98\x70\x90\xC9\x38\x6D\x0E\x00\xE1\x9A\xBA\x32\x45\xD4\xD2\x59\xEC\x3E\x00\x8D\x81\xAC\x55\xC7\x17\xCF\xC1\x6E\xC2\xF5\x9C\xCA\xFB\xD4\x72\xE4\x77\x9E\x84\xAD\xB7\xDA\x1A\xDF\xC0\x0A\x1C\x42\xEF\x39\x90\x2A\xBF\x28\x55\xAA\xE7\xD2\xEC\xA9\xE4\xF8\x34\x10\xA5\x2B\x0D\x22\x91\xE5\x67\x31\x3F\xB9\xAE\x9E\xE5\xBC\xE8\x96\xFB\xB8\x7B\xBF\x06\x2D\x26\x00\xDC\xE9\xC2\xAF\x5F\xBE\x12\xD7\xCF\x3B\xC2\x99\x0F\x1C\xDA\x45\x4E\x9F\x86\x6C\xF5\x28\x75\x02\x6A\xBB\x5F\xEF\x56\x8C\x31\x0A\x36\x86\xC1\x6D\xCF\xA8\x11\xD4\x8A\x01\x78\x5F\x06\x12\xE4\xA1\xF7\xE8\x17\x98\x33\x5B\xDF\x23\x44\x84\xEA\x2B\x35\x27\x0C\xC9\x57\x2E\x0B\x32\x42\xD0\x65\x87\x4C\x48\x6F\x04\x62\xFD\x6E\x39\xCB\x63\x69\xCB\xF0\xAD\x37\x71\x33\xFE\xA1\x4E\xF8\x1D\x3F\xC1\xDF\xBA\xF7\x6F\x60\xD4\xD5\x2A\xDB\xA6\x88\x59\xF7\xA9\x87\x7A\x05\x75\x5C\x37\x5C\xAA\xF1\x12\x59\x3A\x2E\xE4\x39\x88\x33\xFC\x02\xB1\x31\x95\xBD\xE3\xF0\xB8\x3D\x6B\xB4\x4F\x30\x5E\xE7\x18\xF0\x6F\xF3\x11\xDC\xD5\x38\x80\x5E\xA1\xEE\x69\x60\xF3\xE7\x20\x7B\x62\x79\xD0\xCF\x4C\x76\x68\x6D\x2C\x23\xF1\xA9\x4B\x54\x6B\x03\xB5\x62\x00\xAD\x8F\x83\x02\x13\x1B\x81\x98\x34\x12\xC1\xFC\x50\x90\xB2\xCD\xB5\xFA\x69\x39\x0B\x01\x5E\x8F\xEE\xA4\xD4\x06\xA4\x22\x0D\x32\x7A\x21\x08\x9B\x3C\x85\x14\x91\x92\x47\xB6\x44\x9B\x09\xCC\x78\xC1\xC5\xFF\x89\xAD\xF7\xDC\x0D\xDF\xC5\x32\xEC\xA7\xDB\x5B\x05\x62\x44\x19\xA4\x4D\x38\x47\x29\x71\x5A\x3E\x00\x92\xCF\x33\x31\x94\xF6\x12\x6B\x8E\xC2\xAB\xB5\x84\x78\x63\xFB\x6F\xA8\x6D\x26\xDC\xB5\xF4\x49\x5C\x36\x6F\x53\xDC\x97\xED\x56\xF9\x92\x51\xAB\x1B\xB4\x16\x90\xEA\x65\x3D\xC6\xB5\x81\x5A\x31\x80\xE0\x30\x50\x11\x8E\x08\xD7\x4F\x88\x95\xE8\xA4\x42\xA8\xD6\x4B\xAA\xD7\xB6\xAE\xAE\xDA\xEB\xC0\x50\x0A\x5A\x5B\x81\x65\xDF\x5B\x93\x47\x3A\x8E\x34\x66\xF4\xEC\xC0\x47\x8F\x41\x76\xF4\x9E\xF8\xFB\x97\xEF\x84\xFF\xC0\x2A\xCC\x8F\xED\x57\x28\x2B\x21\xF6\x38\x63\x18\xD4\x8F\xA0\x34\x33\x76\x7B\x72\x6A\x77\x22\x74\xDF\x6B\x9C\x48\x59\x0C\x2F\xEB\x59\x84\xB5\x56\x0D\x9E\x40\xEB\x7E\x03\xE0\x9A\xB1\x51\x5C\x3E\x38\xDB\x31\x85\x06\xEE\xCD\xF6\xF4\x6F\x3E\x12\x60\xF9\x0C\x62\x7E\x00\x69\xEB\x6B\x42\x97\xE6\x42\x6D\xCC\x80\x5A\x31\x00\x7D\x29\xA8\xF4\xB0\x4B\x22\xCE\xBB\x98\xB3\x51\xD1\xD7\x80\x15\x0F\xED\xFC\x62\xE2\x05\x13\x47\x91\xA2\xB1\xB9\xC7\x8C\x0B\xD2\x4C\x1C\x06\xD2\x26\x00\x43\xBB\xEA\x81\x20\x09\x81\x43\xE9\x27\xFF\x8A\xCD\xDE\x7C\x38\x4E\x74\x5A\xC0\xC1\x9E\x3A\x4F\x08\xCD\xC3\xC0\x62\xA2\x46\x32\xF9\x6E\x28\x5F\x3E\xE3\xAC\x22\x23\x23\x75\xE9\xCE\x92\x1D\x49\xCD\x97\x58\x7B\xD1\x1E\x8B\x87\x5C\xC2\xDB\x9B\xE3\xF8\xDD\xE8\x38\x6E\x1E\x68\xE0\x9A\x5B\xEE\xC7\x8D\x3B\xBE\x13\xCB\x75\xE2\x7D\x5F\x8A\xEC\xB7\x8B\xBD\xEA\x64\x33\x1B\x08\xBB\xC2\x1A\x3F\xED\x10\xAC\x05\xD4\x9A\x01\x78\x6A\x3E\x40\x45\xA6\xB5\x44\x18\x9D\x80\x9A\x49\x48\x47\x15\x63\x04\xF0\xD3\x33\xAD\x80\xD8\xAE\xEC\xC3\x20\x9A\xE0\xD9\x9A\xB3\xA5\x4D\x67\x24\x8F\x2C\xAB\x93\xE1\x7C\x7C\xCA\x4D\xF1\x4F\xCB\xD5\x09\x88\x8A\xAD\x19\xCA\x1C\x6F\xD6\x32\x5F\xD0\xEF\xBA\xCF\xD0\x1B\xB3\xF0\x18\xBD\xA1\x15\x44\xB5\x14\xE5\xCC\x64\xED\x65\x0E\x44\xF7\xB8\xDA\xFD\xAE\x72\x2F\x0F\x3B\xBD\x73\xC9\xCA\xA5\xB8\x6C\xCD\x38\x2E\x5B\x7F\x0E\x6E\xCA\xF6\x6F\xDF\xA4\x5C\x00\xDB\xE1\x67\x9D\xE5\xB0\xBA\x3B\x47\x7F\x15\x20\x0E\x6C\x15\x80\x99\x03\x4A\xD2\xC6\xED\x49\x15\xC1\xDC\xB4\xD4\x37\xA0\x54\xFA\x5C\x21\x41\x37\x21\x89\xBA\x32\xDB\x09\xA8\xFD\x00\xA9\x03\x2E\x29\x06\xE0\x95\xF7\xD4\x2F\xF0\x9A\x79\xEB\xE3\xDB\x18\xC5\x0E\xF4\x4E\x04\x05\xCC\x94\xD1\xA6\x93\x46\x2A\x65\x8E\x31\x26\x5D\x6A\x6C\x92\xC0\x49\x1F\x53\x51\xCA\xB4\xAF\x70\x6A\x20\xD9\x5E\xD5\xB6\x20\x2A\x6B\x6F\x4B\xBE\x3B\x1F\xC7\x2D\x2B\x46\x70\xFE\xAA\x26\xEE\x7E\xF8\x51\x2C\xFE\xFD\x12\x3C\x30\x6F\x36\xC6\x7E\x74\x1E\x70\xFA\xEF\x90\xFF\xD5\x4B\xD1\x38\x7F\xB1\x79\x29\xA8\xE5\x44\xEC\x33\x80\x14\x78\xFB\x00\x04\x82\xFA\xF4\xDA\x44\x84\x7A\xCE\x10\x9E\x62\x4B\xD8\xB9\xBA\x1E\x5A\x96\x8C\x17\xF5\xB1\x72\x4A\x73\x03\xDD\x3B\x01\xC3\x7D\x00\xD2\xB1\xD7\x82\xD4\x3D\xF9\x19\x09\x37\xEF\xB0\x7B\x7C\x21\x06\xE7\xCF\xC7\x97\x1C\x03\x78\xBF\xAB\x6C\xB0\x1D\x61\xF9\x31\x54\xDF\xC8\x70\xC6\x60\x81\x90\x11\x78\xED\x37\xB4\x31\x18\xCC\x07\xA4\x2C\x69\xCA\x59\x97\x98\xB0\x8D\x5A\x99\xCA\x6B\x7B\x30\x09\xE2\x21\x47\xCB\xDD\x73\x6B\x2E\xAE\x74\x7F\x77\x34\x9B\xB8\xA2\x91\x39\x86\xB0\x06\xD7\xCC\x98\x87\x7B\x16\x9C\x8E\xD1\x77\x1E\x3F\xD1\xFF\xD3\x07\xD1\x68\xE1\xBA\x66\xD4\x2B\x55\xD7\x50\x94\xDE\x67\x00\x16\xB0\x9D\x80\xEC\x14\x5F\x89\x39\xE3\xF8\x44\xBD\xF7\xD2\x8B\x96\x7B\xFE\x84\xDC\x8F\x2E\xD3\xC8\x72\x52\x16\x9E\x5F\x57\xC1\x00\xE4\x4E\x40\x3D\xFD\x2C\xE2\x06\xC2\x49\x64\x7D\x88\xA2\x2C\xEF\xC8\xDD\x81\xD3\x2E\x77\x5D\x71\x21\x5E\x89\xD5\xF8\x5F\x17\xF4\xFC\x2A\x96\x10\x25\xE6\x48\x9C\xE5\xBD\xA4\xCC\x42\x71\x0E\x6D\x42\xAD\x8B\xBA\x2C\x9B\xC9\xCC\xC7\xCC\x0C\x18\x4C\xA6\x13\xD0\x1A\xBF\xD6\xFD\x87\x77\xBB\xF7\x0B\x1D\xB1\xFF\x3E\xEB\x7C\x71\xE9\x76\xA7\x2D\x3C\x71\xEB\x03\x58\xB3\xFD\xDF\x4D\x8C\xD7\xC6\xEB\x75\x9A\xE8\x18\x47\x6B\x69\x31\xEF\xCE\xD9\xBE\x06\x90\x02\xAD\x01\xC4\x54\xD7\x32\x0F\x6B\x88\x92\x1E\xED\x78\xA6\xA2\x26\x66\x4B\x2F\xCB\x68\xA4\x0C\xEB\xE3\xA0\x05\x68\xE2\xAF\xF2\x35\x9A\x02\xA2\x13\x69\xC5\x59\x98\x36\x6B\x08\x5F\x76\xD3\xF6\xBD\xEE\x75\xD0\x14\x88\x8A\x10\x4C\x1B\xDF\x08\xAB\xB2\xA5\x78\x6D\x41\x5F\x73\x16\x94\x4D\xD4\x7A\xD3\x89\xA8\x7D\x0D\x29\xF3\x28\xA7\x4C\xA2\xF5\x33\xD6\xBE\x35\xB9\xB3\x0B\xF1\x3C\x17\xD8\x72\x13\xDE\xE2\xF4\xAD\xA7\xB2\x7D\xFD\x55\x85\x23\x5E\x8D\xEC\xEA\x9B\x3B\xDF\x53\xA8\x32\x76\x4F\x37\xD4\x8A\x01\x78\xC7\x81\x95\x0A\x5E\x20\x6B\xD9\xEF\x05\x58\x4E\x42\x2D\xC5\xD9\xD6\xE0\xD4\xF6\x62\xED\xE8\x2A\x1E\x8C\xC9\x63\x99\x00\xEB\x0A\xA2\x13\x69\xF5\xF9\x78\xC5\x50\x8E\xEF\x3B\x26\xB0\x63\x94\x38\x0C\x3F\x8B\x64\x90\x96\x9F\x80\x76\x11\xF1\x21\x64\xF1\xEA\x4C\xA8\x92\x36\xE6\x60\xB4\xCA\x30\xF7\x14\x98\x9C\x43\x77\x80\xD7\xDE\x96\xB9\xD0\x72\x18\x5E\x8C\xD6\x1D\x07\xC0\x35\x2D\xE6\xB0\x7A\x0C\x77\xCC\x3C\xB4\x6D\x42\xB4\x61\xB3\x0D\x91\x3D\xF0\x98\x57\x5A\x2D\xA0\x56\x0C\x40\x5F\x08\x12\x3B\xCF\x0E\x11\xDE\x49\x0C\xDF\xD1\xA4\xD4\xF7\xE0\x43\x20\x22\x8F\x5E\x26\x64\x76\x26\xFB\x4C\x98\x94\x96\xBA\x27\xB3\x50\x03\xB0\xFA\x9F\x19\x17\x31\xAD\x9D\x2D\x19\x06\x2D\xBA\xFE\x3B\x98\xF6\xC2\xED\xF0\x95\x7C\x0D\x86\x1D\xEE\x03\xCC\xD1\xC9\x36\x52\x59\x04\xEC\x49\x4D\x62\x9F\x33\x27\x60\xF2\x74\xA1\x36\xEF\x40\x70\x60\x75\x29\xDC\x63\x17\xBD\x18\xB4\x1B\x76\xAE\xE1\x20\x2C\x99\x9A\x2A\xC4\x60\x2C\x63\xAE\xCE\x27\xF3\xCE\x77\x18\x2F\x71\xBA\xEC\x1F\x5D\xC2\xEB\xFE\x7C\x1B\x1E\xDA\xE9\xDD\xFE\xAD\xC9\x75\x81\xFA\x31\x00\xF2\x75\xE0\x28\xE1\xE9\xC6\x10\x67\x1F\xDD\x29\x68\x74\x02\xB3\x49\x03\xFF\x03\x42\x4D\x41\xDA\x96\x5D\xD0\x3E\x00\xD6\xDF\x85\x19\x60\x99\xBA\x06\xC6\xA6\x47\xC2\xF3\xA5\x8D\xFC\x0A\x47\xCF\x98\x89\xEF\xB8\x1A\x36\xA4\x9A\x51\x37\x87\xA9\xFA\x4B\xA2\x56\x8E\xC1\xB2\x8F\x72\xBF\xDF\xA1\xEB\x88\xD8\xFA\x96\xA6\x55\x98\x25\x56\xC3\xF5\x3C\x90\xF5\x21\xE3\x65\xC7\x56\x41\xAA\x68\x36\x65\x13\x63\x1C\x25\xAC\xAF\x35\xB6\x7F\x74\xA6\xC1\x1F\x30\xBB\xCD\x10\x1E\xBA\xE4\x42\x5C\xBF\xD7\x87\xCC\x73\x0A\x4F\x3B\xD4\x8E\x01\xB8\x0E\x9E\x96\x0B\xAC\xD8\x24\x0B\xBE\x68\xA3\x54\x55\xD9\xB0\x60\x09\x4A\x9A\x00\x5A\x1B\x00\xE1\x13\x42\x9A\x68\x9B\x59\x97\xA7\xEA\x62\xA7\x01\xCD\xA6\x77\xE3\xA5\x5F\xA0\x08\x97\xF4\x62\x7D\x82\x8B\x4D\xCB\xFC\xC1\x9F\x62\xAB\x4D\x36\xC4\x37\xF3\x71\x1C\xA2\x09\xD1\x4B\xCC\xA4\x37\xC4\x84\x8F\xD9\xFD\x8A\x49\x94\x65\x0B\xB3\x4B\xDA\xF0\xE6\x79\x0B\xF9\x6E\xF8\x1A\x68\x23\x8B\x7C\x1A\xF7\x18\xE3\x31\xB4\x45\xA8\x77\x89\xBF\xC6\x2B\x27\x3D\x2F\x35\x25\xED\xF4\x74\x65\x3E\xE2\xF2\x3E\x7C\xD1\xB5\x38\xF6\x35\xFF\xEC\x98\x41\x4D\xA0\x96\x0C\x00\x84\xD8\x4C\x2F\x6D\xAC\x3C\xF8\x04\xDD\x6E\xB0\x98\x2C\x96\x36\x51\x4E\x58\x69\x72\x00\xD4\x69\x44\xBF\x59\x80\x4A\x26\x00\x55\x32\x44\x9C\x2C\x4E\x36\x45\x6B\x0D\xBA\xEA\x16\xB4\xCD\x84\x3F\x7F\x0F\xD9\x8E\xCF\xC1\xDB\xDC\xF3\xD7\x5D\xC4\x7A\x96\x9D\xE1\xF5\x75\x05\x3D\xC4\x30\x79\x82\xB2\xCC\x3B\x07\x05\xF1\x69\x73\x03\x9A\xD8\x89\xF6\x66\x1D\x29\x66\x37\x15\x07\x06\x77\xAE\x98\x84\x66\x00\x10\x44\x0B\x3F\x2D\x35\x37\xC8\x5C\xD2\x7D\x26\x84\xC9\x1A\xC7\x00\x0E\x77\x0C\x60\x11\x6A\x02\xB5\x63\x00\xB9\xFA\x32\x90\x44\xD2\x1B\x18\x65\x8F\x15\xE9\x82\xC9\x26\x0A\xD0\x92\x4D\x0F\xAC\x2C\xCF\x34\x0B\x98\xB4\x57\xE9\x50\xA8\x7F\x33\xCD\x2F\x03\x05\x59\x10\x12\x34\x23\x7A\xDA\x4C\x84\x0C\xA0\x84\x7B\x7F\x82\xCD\x36\xDF\x10\x3F\x76\x09\xF6\x31\xFB\x5D\xB5\x2D\xD5\x07\x34\x2F\x89\xD7\x52\x3E\xAB\x90\xA7\x18\x37\xCB\x2B\xAF\x55\xFC\xA8\x39\xC1\x10\x35\xCA\xAB\x92\xA7\xD2\xAA\x90\xD2\x62\xBC\x3C\x19\x9E\x72\x0C\xE0\x0D\x8E\x01\xFC\x06\x35\x81\x5A\x32\x00\x66\xEB\x97\xCF\x8A\xAD\x9B\x1A\x02\xF9\x05\xF8\x64\xB1\xEC\x45\x6D\xFB\xB1\x9D\x81\x72\x2F\x81\x9A\xD1\xD6\xE7\xC1\x29\xCF\x00\x27\x76\x19\x1E\xB5\xF7\x63\xE5\x8C\x9C\x81\x7F\x98\x31\x1D\x9F\x77\x29\x37\xF0\x2A\x64\xAA\xBF\xE5\x03\x10\xFD\xC0\x9C\x65\xDE\x38\xCA\x7E\x66\x84\x67\xC4\x57\x26\xE6\xC8\x98\xB1\x74\x5E\xA7\xC7\x38\x87\xD4\x30\x32\x92\xA7\x0A\x6E\xAA\x5C\xCF\x7C\xED\x33\x80\x38\x04\xD7\x82\x2B\xA2\xF3\xD2\x82\x10\x31\x53\x29\x75\x43\xA5\x8D\xA7\xB8\x82\xB6\x4D\x81\x70\x02\xC5\xA4\x86\x32\x0D\xF4\x32\xA0\x46\x45\xA2\x67\x7D\x83\x1E\x22\xDC\xFA\xA6\x9E\xF4\x1D\x80\xC4\x63\xE9\x2F\xB1\xCD\xDC\x99\xF8\x86\x7B\x3C\x30\x76\xED\x99\xC5\x04\x35\xB1\x7A\xB6\xB4\x57\x93\xB2\xF7\x8B\x3C\x40\x72\xCB\x2F\xFD\x4C\x7B\x86\x34\x63\x67\x6A\xB9\x25\x81\x23\x10\xD5\xFA\xC8\x80\x64\x20\x11\x29\xE8\x33\x80\x38\x48\x27\x20\xFB\xA2\x8D\xC5\xF1\x2D\xC7\x54\x15\x6E\xED\xD5\x11\x51\x3D\x2D\x9B\x36\x52\x76\xC7\x09\x18\x7E\x1E\x5C\x67\x95\xBB\xFB\x24\xB1\xE7\x5E\x69\x13\x69\x74\x3E\x09\x94\xB9\xBC\xFF\x75\x18\xF8\xEA\x7B\xF1\xF7\x2E\xB4\xC5\x04\x06\x64\x7F\x06\xAB\x01\x15\xC4\xB0\xB9\x04\xA7\xB0\x0D\x1C\x71\xDA\x8F\x80\x70\xDC\x02\x27\x2D\xC2\x31\xA1\x63\x2F\xFD\x35\x96\x26\xA0\x34\x47\xCD\xC8\xD8\xD8\xD2\x3B\x24\x11\x32\x83\x60\xC5\x43\x33\xD8\x4E\x19\x1D\x06\xF0\xE1\x3E\x03\xA0\x50\xEE\x04\x54\x13\x21\xD8\xD7\x2F\x30\x8F\x9D\x16\x54\x36\x39\xB5\xE9\x3C\x87\x94\x2A\xB7\xEC\x24\xA2\xC2\x7A\x9D\xC7\x89\xC6\x3A\x0D\xA8\x25\xB6\x75\x46\xDC\xB4\xEB\x11\x6E\x05\xD6\x3E\x02\x2F\xDF\xE6\x1B\x22\x3B\xE3\x33\x78\xC5\xCE\x3B\xE0\x94\xBC\x89\xAD\x64\x05\xD6\x99\x09\xDD\xB4\xEA\x83\x58\x31\x83\x95\x2E\x21\x55\xCD\xE2\xA5\x66\x67\x74\x9E\x67\x52\x1A\xDA\x01\x2D\xBF\x8A\xBD\x93\x6A\x47\x87\xAD\xF7\x35\x80\x18\x94\xA7\x01\xA5\x83\x0E\xBE\x36\x90\x93\xD1\xD5\x9B\x85\xCA\xA5\x25\x39\xD0\x88\x38\xFD\x62\xDA\x84\x82\xAA\x97\x6C\xE6\x2D\x1F\x40\xC7\x09\x28\x4D\x00\x4B\x03\x60\x04\x4D\xBB\xA8\xFB\xDB\xD3\xC5\x12\xAD\xFB\xF3\x7F\xF6\x71\xCC\x39\x62\x2F\x7C\x21\x1F\xC7\x7B\xB2\xC8\x1C\xB7\xFC\x23\x31\x47\x21\xA3\x01\xEA\x7B\xA9\xDA\xB7\x86\x1F\xA2\x2A\x58\x1E\xD2\x54\xDA\xC9\x94\x2F\x03\xAD\x8B\x68\xCB\xE7\xBE\x09\x10\x87\xA6\xFA\x38\xA8\x35\x11\x3D\x3B\x11\x8A\xCB\x6B\x09\xAE\x6D\x4F\xE1\x57\x90\xF5\x30\x86\xCD\xE2\x11\x63\x1E\x7E\x1E\x76\x1C\x58\x17\x5F\x85\x90\x2D\x9F\x81\x65\x02\x14\xE8\x7A\x9A\xC3\x2E\x3B\xA0\x71\xD9\xD7\xB0\xF7\x10\xF0\x3D\xF7\xBA\x4D\x89\x3B\x60\xDE\xE7\xC7\xFA\x28\x20\x74\x9F\xE9\x45\xC7\x2D\x45\x94\x5E\x38\x51\xE9\xB5\x23\x52\xD7\x8F\x8A\xF5\x58\x75\xF6\xAA\xBC\x44\x95\x15\x16\xD9\x67\x00\x71\x08\x6E\x04\x02\x3C\x67\x90\x46\x3C\x79\x4D\x14\x42\xEA\x61\x92\xAA\x2C\x8F\xFC\xB2\x8E\xD2\xDA\x85\x74\x5A\x15\x38\xC0\xBE\x13\x10\x08\x9B\xD3\x0B\xB0\xBB\xE8\x19\x68\x33\xA3\x79\xE1\x97\x31\x77\xEF\x9D\xF1\x39\x8C\xE1\x1F\x41\xCC\xFD\x24\x01\x4B\x87\x9E\xF4\x6E\x57\xEC\x53\x80\xF4\xAB\x61\xBB\x07\x26\x09\x71\xF0\x06\x76\xB8\xD1\xC9\x9A\x69\xE8\xB6\x05\xF8\x1B\x4C\x25\xB6\xEB\x31\x55\x70\x57\xFB\xEC\x33\x80\x18\xE8\xCF\x83\x77\x02\xB9\x6D\x17\xE4\x35\xE2\xA2\xE1\xC5\xA4\xD2\x8E\x30\xA3\x10\x6D\x66\xB4\xA3\x6C\xB5\x36\xB6\x11\x48\xDA\xED\x8C\xD7\xE8\xF9\x5C\xE5\x3E\x80\x28\xCC\x9C\x8E\x6C\x64\x75\x79\x54\xF8\x14\x57\xF8\x56\xC1\xD9\x0A\xDD\x27\x3D\x78\xD1\xD7\x06\x82\xF5\x7D\xD1\xF2\x5E\xF0\x88\x49\x73\xAF\x6D\x88\xCF\xA7\x2A\xDB\x86\xCD\x95\x81\x18\x1E\x7D\x06\x10\x07\xF9\x69\x30\x4B\x62\xA0\x1B\xC9\xEE\xA6\xD7\x66\x02\xBB\x75\xA6\x1D\x25\x08\x99\xAE\xED\x4F\x54\x33\x11\x97\xAB\x7A\x44\xFD\xAC\x9C\x8C\x7F\x19\x48\xAA\xFE\xAC\x89\x96\xFF\x0A\x24\xBF\x75\xD3\xB0\x95\xBE\xDD\xC5\x23\xE7\x61\xA3\x19\x4D\x1C\xEF\xDA\xF3\x76\x53\x3B\xD2\xF6\x2C\xC2\x67\x46\x60\x00\x38\xF3\x04\x31\x33\x48\x41\x5A\x62\x5B\x17\x82\xB0\x75\xF9\xD4\x2F\x41\xC9\x6F\x53\x05\xFD\xBF\x92\xB9\xA0\x98\xA9\xBC\xA7\xB0\xEF\x04\x4C\x40\xF0\x65\xA0\x4C\x10\x9F\x50\xB3\x73\x36\xBA\x5A\x3A\x33\xC2\x17\xE9\xF4\x08\x6A\x47\x97\x54\x01\x41\xE2\x74\x84\xC7\x5C\x3A\x05\x6A\x13\x80\xCD\x4B\xA9\x05\x00\x7C\x8E\x31\x4D\x21\xE5\xB6\x68\x01\xD5\x12\xEE\x3E\x09\x83\x5B\x3E\x1B\x7F\x8D\x51\x9C\xE0\x5E\xA7\x97\xCD\x10\x4C\xB5\xB2\xB6\x15\xF3\xFE\x21\x4D\x30\xDA\xE6\xA7\x1D\x4E\x70\xAB\x52\x9F\x5D\x91\x5F\xA6\x09\xCA\x11\x8D\x1E\xCA\x36\xCB\xEF\x6B\x00\x71\x08\x4E\x03\x12\x42\x0C\xF2\xC0\x9F\x44\x72\x33\x89\x39\x81\x85\x76\x60\xDA\x85\x11\x0A\xA8\x74\xB2\x6C\x42\x03\xD0\x1B\x81\x80\xB4\xCB\x81\x41\x4C\xF0\x02\x21\x23\xD0\x5A\x42\x3E\x67\x26\xB2\xE5\x23\xC8\x97\x2C\xC0\x56\xDB\x3F\x0F\x27\x3A\x53\xE0\xB5\x49\x8F\x9D\x6A\x33\x45\x20\xD6\x9F\xC6\x58\x98\xAB\x09\x82\xF0\xCC\xBE\x17\xBD\x11\x9C\xCF\x50\x5C\x27\x28\xCB\x92\xD0\x55\x41\x31\x06\xAB\x5D\xC1\xE0\xB6\xC2\xFB\x1A\x40\x1C\xE4\x4E\xC0\x40\x5A\x17\x08\x67\xFE\xA4\xCB\x2D\xF6\xAC\x64\xA5\xB7\x24\x03\x31\x88\xD2\xD9\x24\x19\x08\x40\x1D\x8C\x9E\x26\x22\x71\x94\x75\x76\xC0\xBA\x12\xAC\x05\xEC\xB4\x9F\xD1\xE2\xB2\x15\x52\x13\xC8\x54\x5E\x69\x02\x58\x9A\x79\x59\xF6\xC2\x7F\x43\x76\xE8\x9E\x78\xD7\x50\x6B\x63\x90\x38\x7D\xC9\xCE\xFB\xCB\x92\xF2\x6E\x49\x16\x27\xCA\xAC\x0A\x55\x43\xAC\x33\xFB\x5E\xBE\x84\xD3\x8E\x11\x30\xF3\x25\x68\x06\xC0\x04\x46\x8A\x88\x4D\x29\x4F\xDA\x14\x85\xBE\x06\x10\x07\x7A\x29\xA8\x72\x4A\x95\x69\x85\x4D\x9E\x72\xDE\xB1\x57\x76\xC4\x58\x9A\x1C\xB1\xAB\xC6\xA3\x9A\xC9\x84\x84\x69\x33\x80\x93\xCF\xC0\xF0\x5B\xBE\x94\xBC\x14\x34\x65\x5A\x6A\x02\x97\xEF\xD6\xAE\x41\x99\x37\x74\xA3\xFC\x16\x5B\x38\xB6\xF4\x11\x57\xCA\xDB\xDD\xEB\xFA\x41\xBC\xEC\x83\xAA\x8E\x41\xD9\x3F\x88\x10\x44\xCA\xDE\xD6\xE3\xA6\xB0\x0F\x34\x07\x22\x0C\x98\x96\x22\xF3\x47\x1D\x7A\xCC\xE4\x04\x02\xA6\xA5\xE7\x92\x79\x6D\xD9\xC4\x48\xF4\x19\x40\x0C\xCC\x4B\x41\x81\xE8\x4A\x40\x2F\x0E\x43\xE6\xF8\x61\x03\x2C\xCB\x0E\x24\x9B\x65\x02\xF8\x13\xB0\x99\x0F\x60\xC1\x83\xCB\x30\xBC\xF9\x91\xE6\x2E\x3F\x56\x45\x11\x2F\x89\x5C\x82\xFC\x18\x85\x66\x1E\x3A\x9D\xDE\x29\xD8\x0E\x5B\x7F\x36\xB2\x27\x57\x38\x74\xAF\xC6\xC6\xF9\xC3\x78\xA9\x53\x4D\x5F\xE6\xC2\x0F\x75\x25\xBC\x2A\x17\x5F\x66\x2A\x91\x52\xCC\x56\xB7\x99\x5E\x8E\x82\x38\x91\x99\xE9\x08\x31\x85\x1D\x3D\x91\x21\xE6\x94\xEC\x85\xFF\x54\xF1\x7D\xF4\x02\x7D\x1F\xC0\x24\xA0\xBC\x13\x30\x82\x6C\x6C\xED\xDF\x9C\x0C\x84\xA8\x81\x6A\x93\x54\x83\x54\x0B\xD9\xEA\x82\x90\x9A\x4D\x47\x71\x0B\x1A\xF3\x31\x9C\xBD\xB2\xF2\x92\x5D\x8C\xF0\x0B\x30\xAF\x04\x17\xF9\x8B\xA6\xB0\xAE\x0C\xEA\x18\x3B\x1B\x03\xAB\x47\xB1\xFD\x8C\x21\x1C\xDC\xC8\xF0\x56\x97\xEB\x25\x2E\x45\x23\xE8\xAB\x08\xE3\xB3\x98\xAC\x44\x4E\xF7\xAD\x26\xFC\xA4\x79\x61\xF8\x86\x62\xF5\x06\xE3\x02\x50\xED\x2F\x76\xE6\xA4\xAC\x4B\x98\x88\xEC\xB4\xA8\xA9\x89\x4E\xF4\x7C\x9F\x01\xC4\x80\x6A\x00\x40\x20\x59\xAC\x65\x2A\x6B\x12\x05\x13\x08\xF0\x97\xEE\x88\x99\x11\xBB\x73\x2E\xEA\x60\x9C\x78\x6C\x11\xD8\x82\x6C\x3D\xC7\x00\x5E\x15\x9C\xE2\x63\x44\xAE\x25\x76\x51\x9C\xC5\x0F\xAD\x8D\x40\x79\x24\xAD\x57\xC7\xDC\x99\xC8\x97\x8D\x4C\xA4\x6F\x9E\x83\xA1\x15\xAB\xB1\xD5\xAC\xE9\xD8\xAB\xD1\xC0\x6E\x2E\x66\x3F\x17\xF9\x9C\x18\x33\xD5\x15\xC7\x1C\x10\x40\x84\x01\x44\xD2\x59\xE5\xB3\x7A\xF4\xD8\x49\xE2\x8D\xF9\x14\x2C\x7C\x3C\xDC\x08\xE3\xB1\xDA\x4B\xAB\xEC\x33\x80\x38\xC8\xAD\xC0\x29\x07\x53\x3B\x5C\x11\xAC\xCC\x54\x0E\x58\xF1\xAE\x6D\x58\x59\xAE\xB2\xF7\xAC\xE3\xA4\xEC\x72\x50\x7A\x58\xA9\xF3\xDC\x5E\x06\x3C\xFB\x12\x0C\x1F\xFC\x71\xCA\x00\x82\xE6\x1B\xE1\x99\x88\x6F\x41\x6C\x27\x60\xD1\x2C\x8B\x69\x54\x82\x96\x46\x70\xFB\x83\xD8\x70\xCB\x0D\xF1\xF2\x19\x33\xF0\x16\x57\xDA\x6B\x5C\xF0\x16\x4C\xCA\xF5\xAA\x6A\xF7\x9A\x87\x32\xF7\x62\x4C\x52\x4E\x3E\xC0\xD4\x18\x01\xA4\x9D\x76\xA2\xCC\x72\x20\xAA\xDA\x08\x4C\x1D\xED\x33\x80\x38\xB4\x3E\x0F\xEE\x06\xA5\xDC\x07\x10\x3B\x0F\x0E\xA4\xC7\x82\x5D\xD7\xE5\xC5\x75\x23\x4C\xC9\x6E\xD9\x9A\xDD\xBC\xB9\x91\xBE\x1B\xDD\x66\x00\xBF\x38\x17\xC7\x1E\xFD\x59\xEF\xEB\xC0\xDA\x01\xD8\x02\xBD\xCB\x2F\x8F\xA4\xAD\x02\x55\x3F\x45\x6D\xF9\x0F\xDA\xF0\xF0\xA9\x6D\x2D\x61\xFD\xA1\x69\x78\xA5\x4B\x78\x8C\x1B\x8F\xDD\x5C\x3F\x6D\xEE\xA2\xE6\x54\x26\x1E\x45\x6C\x5A\x1B\x93\xE9\x34\x33\x2E\x11\x4B\x68\x5D\x00\xA2\xA6\xA1\x87\x4B\x16\x3A\x73\x65\xF9\xBA\x3E\xED\x0C\x35\xAF\x85\x43\x58\x96\x5C\x39\x69\xB7\xA9\xBF\x0C\x18\x87\x62\x19\x50\x77\x7E\xEA\x04\x9A\xF6\x9E\xA5\x54\x31\xEB\xB6\x5A\x2F\x1E\x71\x1B\xDF\x5C\xC2\x9A\x48\x63\x6D\x05\x96\x68\x69\x7B\x5E\x2F\x0F\xEA\xF4\x50\x69\x63\xC7\x81\x65\x98\xD6\x1A\x52\x50\xA6\xDB\x65\x7B\x64\x1F\x7E\x3D\xB2\x43\x5F\x85\xF5\x66\xCD\xC3\x73\x30\x86\x3D\x5D\xCC\xD1\xAE\x9D\xBB\xB8\x0A\xE6\xD0\x3B\x11\x75\x3F\xA9\xBE\xD4\x79\x62\x97\x80\xC6\x4C\x8A\x98\xBA\x6E\x8D\x6D\x2A\x9C\xE2\x43\x06\x22\x45\x38\xD4\x5C\xE8\x6B\x00\x71\x28\x37\x02\x11\x04\x83\x49\x03\x3E\x39\x64\x7C\x95\x06\x06\xAA\xA5\xCA\x14\x38\xAA\x44\xBC\xD4\x08\x0A\x4E\x2F\x26\x10\xBB\x13\x90\x41\x8A\x28\x35\x41\x5B\x97\x82\x64\x24\x1F\x63\x00\xB2\xBB\xB4\xAF\xC1\x63\x14\xD3\x06\xD1\x18\x1D\x43\xF3\x15\x3B\xA0\xF1\x87\x25\x9D\xB2\xEE\xFE\x11\x06\x9E\xB5\x3E\xB6\x74\x71\x47\x37\x32\xBC\xD1\x65\xDA\xD1\x15\x32\xBB\xDD\x0D\x06\x53\xF4\x3B\x1C\x52\x4B\xF2\xC7\x92\x49\x58\xE5\xEF\xD1\xE3\x1D\xF3\xCB\x14\xD2\x3C\xB3\x28\x9D\x41\x2F\xCB\x00\x31\x6E\xA3\xCC\x93\x3E\x03\xA8\x00\xE5\x59\x00\xE2\x94\x6B\x81\xDE\xC3\xAF\xF7\xE0\xB7\xD3\x80\x48\x08\x41\xD8\xE6\x5D\x00\x64\xF2\x99\xDA\x01\x71\x0A\x4E\x24\x40\x31\x19\xAB\x7E\x1A\xAC\x78\xB6\x3C\xF6\x05\x61\xE6\xF0\x9B\x67\x7D\x4A\x4C\xA7\xB7\x20\xE6\x3C\xAC\xA4\x29\x8C\x9F\x83\x4D\x5D\x5F\xBC\xDE\x15\xB4\x9B\xCB\xBC\x9B\x0B\x7A\x2E\x63\xCE\x29\x08\x24\xB8\x1C\x0B\x84\x0C\x38\x66\xD3\x07\x26\x63\xC4\x69\x99\xC2\x25\x9A\x4E\x99\x06\x95\x32\xF5\x19\x40\x1C\x92\x5F\x06\x82\xF2\xE0\xC7\x5C\xCB\xE2\x37\x38\x3F\x80\x70\x72\xC9\xEC\x5E\x02\x84\xB6\x9E\xB4\x55\x03\x55\xB6\xFB\x92\xF3\x0B\x41\x18\xB6\x4C\xA2\x33\x7F\x41\x11\x9F\xD2\x68\x19\x4B\x62\x26\x80\xA9\x01\x47\x86\x28\x2B\x3E\x40\xEA\x65\xFC\x0D\xE6\xB8\x52\x77\xC7\x00\xDE\xEE\x7E\x5B\xAB\x07\xDB\xE8\x42\x83\xB1\x16\x8C\x57\xFB\x59\x3C\xE9\xC9\x98\x01\x5B\xB5\x91\x8D\xB2\x7C\x37\x02\xA9\xD2\x36\x37\xF2\x68\xBF\x43\x95\x53\x89\x4C\xAB\xF1\xF2\xF5\x7D\x00\x71\x28\x76\x02\x32\x2E\xDE\x46\x96\x60\x4B\x89\x98\xF8\x0C\x68\xBC\x54\x2F\x63\xCC\x64\x72\xC0\x2E\x04\x29\x6A\xC8\xC9\xB3\xB5\x0C\x28\xF3\xB1\x5D\x83\x31\x82\x8D\x5D\x1C\x62\xB5\x78\xD2\xF0\xF8\x42\x4C\x9B\xBF\x21\xF6\xC6\x2A\xBC\x15\x83\xD8\xC3\x05\x6D\x89\x31\x4C\xEF\x45\xA5\x36\x3F\xD8\x49\x3C\xFE\x50\xE9\x2C\x22\xA5\xC4\x58\xC1\x61\x68\x6D\x70\x2A\xE2\x3D\xB3\x43\x8C\x86\x74\xFC\x49\x21\xD4\xD7\x00\x12\xD0\x14\x77\x02\x7A\xDE\x79\x10\xB5\xDB\x68\x05\xFD\xA0\xA8\xD4\x02\xCA\x40\x45\x05\x4C\x4B\xC8\x54\x5D\x6A\x50\x83\xFA\x7D\x86\xA1\x35\x80\x98\xD5\x09\xD8\x44\x29\x09\x5F\x32\x8B\xAA\x2A\x3E\x13\x82\xD2\xFC\x90\xE9\x59\x5D\x3D\x43\xBE\x18\x73\xC7\xEE\xC3\xCB\x96\xAD\xC2\x2E\xF3\x37\xC5\x21\x58\x86\x57\x3B\xC2\x9E\xAE\xA5\xBB\x29\x9D\xB3\xB0\xAB\xA3\x13\x55\xF9\x60\xF4\x50\xA4\xF2\x5B\x97\xCA\x96\xB8\x76\xCB\xEE\xE5\x52\x58\x83\xD9\xF4\x2F\x05\x8D\x81\x75\x21\x08\xD8\x64\xC9\x7D\xE2\x55\xC9\x27\xDE\x89\x9A\x28\x1B\xCF\x1C\x50\x9E\x3A\xA8\x98\x41\xA9\xFE\x23\x64\x50\x65\x1D\x9D\xFC\xC5\x71\xE0\x42\x03\xB0\x08\xD8\x62\x2B\x26\xAA\x2A\xCC\x9A\x8F\xCC\xC7\xA0\xB5\x0C\xE6\x3B\xD0\x7B\x0C\x34\x8E\x32\x5F\x12\xFF\x33\x3F\x8F\xED\x0E\xDE\xD5\x31\x01\xE0\x75\x79\x73\x62\xE5\xA0\xC2\x56\xEA\x4A\x3B\x38\x0B\x93\x10\x7A\x5C\x60\x8C\x25\x31\xED\xAC\xB9\xC3\x5A\x67\x5E\x53\x9F\x1B\xE5\xF9\x85\xF6\x19\x40\x0C\xBC\x0B\x41\x88\x77\x3E\xF6\x3D\xF7\x5C\x3E\x90\x41\x0A\x38\xB2\xF4\x23\x64\x08\x0F\xFA\x44\xBC\xCF\xDA\x2E\xD4\xF5\x97\xCB\x80\x71\x1F\x00\x53\xFD\x63\x0E\x3C\x66\xD7\xCB\x74\x56\xB9\x00\x67\x00\x1A\x18\x03\xD0\xE9\x53\xCC\xAA\x8C\xDB\x68\x1E\x1A\x8F\x2E\x9D\x68\x77\xFE\x07\xEC\xE0\xD8\xFB\x81\x18\xC1\xEE\x6D\x7F\x01\xB0\x05\x75\xD8\x46\x90\xB3\xB4\x82\x40\x6D\x8A\x10\x6A\x0C\x08\xC1\x56\xCA\xA4\xF7\x2E\x98\xAA\x4B\xDF\x04\x88\x43\xF0\x65\x20\x25\xFD\xBD\xB4\x10\xB3\x50\xAB\x66\x44\xCD\xD4\x79\xCC\xBC\xB0\x27\x61\x59\xB7\x21\xF5\x95\xB4\xB2\x9C\x80\x29\xB0\x88\x8B\xCD\xFF\x18\xAA\x31\x0D\x00\xE0\x5D\x6A\x69\x00\x45\x7A\xD9\x45\x39\x6C\xE6\xA5\xEB\x6F\xC3\xC9\x1F\xC5\xB4\x03\x5E\x8E\x0D\xE7\x6F\x80\x17\x61\xCC\x69\x05\x79\x5B\x33\xD8\x96\x8D\xAB\xF5\x5E\xF4\xBF\x75\xA2\xCF\x6A\xD8\xDA\x4C\x74\x66\x97\x4D\xAA\xEC\x3E\x03\x88\x83\xBC\x14\xB4\x0D\x11\x7B\x5E\x42\xF4\x22\x50\xA9\x3D\x08\x55\xD1\x33\x23\x34\xB3\x21\x8C\xC7\x32\x15\xB4\xC3\x47\xE0\x5E\x7C\x1D\x98\xED\x03\xD0\x1F\x01\xB1\x34\x04\xC6\xBB\xAC\xC3\x40\x65\x93\x45\x1D\xB1\x9B\x83\xAD\x93\x86\xA9\x7B\x07\x63\x75\x59\x9A\x46\xA0\x35\xAC\x3C\x03\x1B\xCC\x9C\x8E\x97\xBA\x90\xD7\xBB\xBF\x43\x5D\x9F\x6E\x59\x32\xD1\x1C\xF6\x8D\xC0\x64\x6E\x04\xAA\xBE\x42\x54\xCF\x93\x32\x9E\xCC\x2F\xB3\x7C\x20\x58\xFA\xAB\x72\x97\x80\x87\x5F\x7F\x15\x20\x0E\x9E\x0F\x40\xA8\x71\x5A\x1E\xC6\x1C\x31\x81\x3E\x4C\x1C\x8A\x45\x02\xAD\x2D\x14\xE9\xD9\xEE\x43\x5D\x66\x06\x82\x80\xAF\x0E\xEA\x55\x80\x94\x63\x8D\x49\x67\xCB\x71\x17\xFB\x30\x08\x2B\xCF\xDA\x08\xA4\x9F\x2D\x13\xA0\xD7\x83\x4A\xE6\xBC\xFA\xD3\x37\x81\x97\xBD\xB7\x93\xAF\x79\x0E\x36\xC8\x3A\x9B\x89\x3E\xEC\x32\x3C\xCF\x52\x6B\x02\xB5\x47\x33\x5B\x96\x46\x44\x54\x39\xBC\x54\x30\x7E\x7A\xEC\x5C\xCD\x91\x58\x39\xB2\xAC\xA0\x27\xFA\x1A\x40\x1C\xE4\x32\x60\x27\x20\xE4\xA6\x6D\xA4\x95\xBD\xCE\xD4\x78\xC0\x9F\x04\xA5\x5D\x0F\x84\x1E\x7F\xE5\x5B\x88\xAA\x98\x42\x4A\x79\x3E\x83\x22\xCD\x44\x19\xED\x0B\x41\x7E\x79\x1E\x86\x8F\x0C\x57\x01\x0A\x29\xD9\x02\xF6\x61\x90\xA0\x6B\xD4\x7B\xEC\x52\x50\xC6\x30\xAA\x82\xB5\x65\xB8\x97\x5B\x88\x99\x9F\xA1\xC4\x7F\xEC\x6C\x34\x06\x06\xB1\xE1\xF8\x18\x5E\x3D\xD0\xC0\x5B\x5C\x50\xCB\x1F\xB0\x89\x4B\x30\x68\xD9\x34\x55\xEC\x9D\xAA\xB6\x11\x55\xAB\xB4\xF9\x66\xCC\x27\x54\x2C\x0F\xC6\x7B\x9F\x01\x24\x40\xDF\x0A\x6C\x19\xBD\x72\x09\xCF\xBC\x9B\x4D\x87\x11\x15\xB1\xEC\x04\xC9\xF9\xE5\xE0\xAB\x42\x98\x04\x0A\xF6\x7C\x4F\xF8\x07\x9A\xCD\x1C\x0B\xF2\xD9\x18\x1E\xDC\x33\x20\x56\x2D\x3D\x99\x19\x10\x93\xB4\x31\x33\xA0\x78\x8E\x49\xF2\x46\xA4\x6C\x20\xBE\x71\x48\xCF\x79\x8B\x91\xB5\xF3\xEC\xB1\x13\x70\xE9\xF5\xDD\x61\xFB\x0D\xE6\xB7\x37\x0A\x01\x7F\xEB\xFE\xF6\x76\x7F\x1B\xC9\x6E\xAE\x62\xFF\xB3\x21\x8D\x3A\x89\x49\x21\x55\x4E\x03\x56\x61\x36\xD6\x9C\xCA\xAC\x42\xFA\x0C\x20\x0E\xC1\x32\xA0\xF2\xB0\x5A\xA7\xB7\x52\x0E\x42\x83\x40\x3D\x29\x5E\xA8\xF4\xEC\x43\x1F\x45\x31\xF2\x85\x6A\x08\x3E\x7E\x9D\xFB\x00\xE6\x60\x38\x7B\xF5\x3A\xBD\x10\xA4\x80\xD4\x07\x42\x24\x13\x40\x0F\x69\xAD\xDF\x94\xBA\x6F\xE2\x7C\xC7\x0F\x31\x63\xEB\x2D\x9C\x8D\x3F\x8A\x0F\xBB\xD7\xD6\x41\xA2\x0D\x34\x93\x65\xB6\x76\xCC\x01\x18\x3C\x03\x21\x03\x37\xF0\xE9\x55\xB2\x07\x71\x64\x6E\x98\x1E\x5A\xDF\x88\xEB\x33\x80\x18\xC8\xE3\xC0\x1A\x72\x2B\x40\x3B\xE0\x12\xBA\x9F\x39\x38\xAC\xE8\x88\x13\x8A\x49\x2D\x65\x42\x74\x6E\x04\xE2\x17\x82\xE8\x67\xA6\xCE\x1B\x1E\x90\x36\x34\x48\x3E\x99\xB6\xD7\xD3\x7F\x29\xE8\x85\x31\x4D\xF4\xD1\x79\x98\xD1\x1C\xC3\x36\x8D\x01\x1C\xE8\x72\xB6\x6C\xFD\x5D\x85\x2F\x36\x90\xD6\xD1\x3B\x18\x18\x23\x97\x63\x8E\xD0\x29\xC7\x7C\x07\xD4\xBF\x43\xCA\xB6\x56\x78\xAA\x94\x61\x9E\x5E\xED\x33\x80\x38\xC8\xE3\xC0\x9D\x80\x2E\x92\x96\xF3\xA5\x82\x71\x98\x91\xF4\xDA\x3B\xAB\xFD\x02\x9E\xBF\xC1\x47\xA5\x13\x66\x39\x8B\xFC\x7C\xFA\x4E\xC0\x80\x5F\xC0\x57\xF5\xAD\x1D\x78\xDA\x6C\xB0\xCC\x05\xB6\xBC\x67\x49\x76\x9D\x0E\xAA\xEC\x46\x24\x9F\x84\x76\xF8\x96\x1B\xA3\x71\xCF\x23\x13\xF1\x97\xFF\x37\x66\xEC\xF6\x22\xBC\x00\x63\x38\xCC\xD5\xF2\x66\x57\xF2\xF3\x65\x83\x83\x5A\xB5\xFD\xDD\xC5\xAE\x8A\x5D\x9F\x62\xE8\xF4\xCC\x01\x71\x22\x5A\xF8\x44\xCB\xAA\xA2\x4A\xF8\x23\xDD\x67\x00\x31\xD0\xB7\x02\x4B\xEE\x8E\x2C\x21\x21\xBA\x69\x03\xD5\x52\x69\x0A\xDE\x4D\x32\xAA\x17\xF4\xAE\xBF\x22\x3C\x70\x1A\x15\xBF\xDA\x69\xE8\x9B\x17\x4D\xCC\xC0\x82\xDF\x5F\x8F\xE1\xDD\xDE\xE7\xA9\xD1\xCC\x3F\x2C\x99\x81\x25\xFD\x8B\xAA\xAB\x7E\x1B\x50\xE6\x8F\x69\x02\xAC\x79\x96\x13\xD0\x32\x1D\xDA\x70\xE5\xD7\x30\x73\x97\x1D\x1D\xB1\x0F\xE0\x50\x37\x92\x87\xBB\xA0\x9D\xF3\xAE\xB6\x12\xF3\xC7\xE8\xB8\x94\x24\xB7\x5A\x99\xBC\x95\x17\x3D\x30\x21\x35\xA7\x64\xB8\x7E\x66\xEF\xB4\xE8\x3E\x03\x88\x83\xB7\x0A\xA0\x88\x91\x1E\x0B\x86\x22\x7C\x35\x40\x9A\x80\xCB\xFC\xFA\x25\x43\xD2\x1C\x28\xCB\x21\x8E\x1F\xED\x6F\xE8\x46\x34\x31\x88\x05\x0F\x2D\xC7\xF0\x66\x47\x54\xBA\x15\x38\x40\x8D\xA4\x03\x49\x6B\x35\x4F\x6A\x13\x55\x99\x85\xC5\x64\x28\x03\xD9\x64\x3E\xB2\x87\x9E\x40\x7E\xF9\x57\x31\xB8\xCB\x76\x78\xD1\xB4\x99\x8E\xE8\x47\x71\x88\xEB\xFB\x5D\x19\x92\x9E\xB3\xCE\x60\x02\x56\xA3\x18\x92\x9E\xB3\x4D\x65\xEA\x55\x48\x07\x88\x54\x09\xEF\x25\x5D\xA7\x57\xFB\x0C\x20\x06\xED\x55\x80\xBC\x7B\x1A\x90\xA8\x6B\x01\x05\x48\x89\x2E\x88\xDD\xA2\x28\xC6\xF9\xBD\x8F\x63\x92\x89\xA4\x4D\x88\xE0\x83\x11\x22\x91\x52\x43\xDB\x1B\x81\x4E\x3E\x03\xC7\xBE\xE5\x4B\xDE\x95\x60\x04\x0B\x6A\x16\x48\x6D\x81\xD9\xFC\x31\x5A\xC9\x49\x1A\x49\xD8\x96\xF5\x62\x85\xB7\xF3\x7D\xFC\xCD\xC8\x96\x8D\x00\x5F\xFB\xE5\x44\xB7\xDE\x71\x12\x36\xD8\x7A\x4B\x1C\xE9\x58\xF7\xBB\x5D\xE8\xCB\x5D\xD0\x40\xD0\xAF\xA4\x81\x26\x81\x2A\xC7\x2F\x5B\x83\xB7\x54\x28\x6B\xBC\x8A\xE7\xC0\x5F\x04\x3F\x8E\x32\x21\xA2\x1D\x00\x44\x30\xE9\x74\x22\xBF\x98\x9B\xFD\xB3\x00\x31\xD0\x57\x82\x99\xE9\x0C\xDF\x80\x56\xDD\x8A\x34\xC4\x5F\x18\x48\xA6\xD2\x44\x88\xF5\x8A\x18\x4C\x9A\xB6\x3B\x59\xBB\xF8\x77\x18\xC0\xAF\x1D\x03\xF8\x62\xC9\x00\x24\x61\x53\x21\x19\x79\xD6\xFE\x01\xE6\x2F\x90\x71\xAC\x6C\x6D\x86\xF4\x72\xEE\xC0\xD3\x00\x1E\x3E\x15\x1B\x6D\x3C\x1F\x7B\x3B\x72\x7F\x5D\xBE\x06\xFB\xB9\x7E\xDE\x54\x9B\x46\x74\x09\x4E\x35\x48\xAB\xFC\x3A\xAF\x36\xE7\x18\xE1\x05\x7B\xF1\xD9\x9C\x50\x3D\x98\x19\x44\x5D\xBE\x67\x36\x7E\x65\x5A\x82\xA3\x6E\xA7\x1A\x84\x3E\x03\x88\x81\x77\x16\xA0\x8B\x9D\xE5\x55\x05\x60\xDB\xFF\x22\xDE\xE2\xF6\xED\xE2\x0D\xD5\x51\x8F\x1E\xBB\x09\x18\x0C\x07\x78\x93\xBB\x99\x3B\x13\xE0\xAE\x7B\x31\xFC\xDC\x77\x4C\xCA\x13\x6F\x99\x05\x05\xA4\xD4\x7A\x69\x9F\xC7\x96\xF3\x18\x53\xB1\x98\x0E\x56\xFC\x0A\x33\x06\x1B\xD8\x77\x68\x46\xFB\xF2\x8F\x7D\x5C\xEC\x26\xB2\x20\xA9\x96\xA7\xBE\xBB\xE7\x69\x52\x11\xC7\x5B\x4C\x20\x44\x4F\x0C\x46\x18\xD1\xBA\x80\x2A\xC5\x7A\xF8\xF5\x7D\x00\x71\x68\x9F\x05\x28\xBE\x0D\x68\xA8\x6F\x5A\xEA\x5A\xAA\x9D\x75\x67\x80\xA5\x3B\x5B\x06\xB6\xCC\x4E\x55\x59\x35\x0B\xC4\xC4\x6B\x36\x9B\x58\xD0\xD8\x08\xC3\xD9\xAE\xE6\x77\xFB\xD8\x99\x00\x86\x56\x0C\xAA\x30\x80\x02\x52\xA7\x01\x4D\xC2\xCF\x2F\xC6\x06\xF9\x08\xFE\xAA\xB5\x75\x17\x68\xDF\x0E\xFC\xEC\x4C\xE7\x64\x05\x4A\xAD\x49\x22\xA7\xCC\x36\x36\x0E\xCC\x4C\x60\x55\xC5\xC2\x92\x4C\x86\x69\x29\x31\x93\x80\xE4\xA9\xC4\xF8\xFA\x3E\x80\x34\x04\xDF\x05\x10\x2A\x96\x87\x2C\x99\x11\xCC\xD6\x67\x07\x33\xBC\x34\x4A\x7D\xF4\xD2\x11\x95\xD2\xFC\x02\x0E\xF1\x0E\xE7\xAD\xD3\x80\xD3\xB1\xE0\xC2\x3F\x61\x78\x9F\x0F\x52\x42\x94\xC5\xA4\x0E\xF7\x30\x46\x91\xD2\x00\x64\x73\x53\x3B\x07\xCD\xF4\x57\x7C\x0D\x33\x5E\xF1\x42\xEC\x87\x31\xBC\xD5\xBD\xEE\xE5\xFE\x36\xD3\xB9\xA2\xDE\x77\xE5\x07\xB0\x08\x92\x11\x3E\xAC\x32\x61\x33\x05\x36\x57\xF2\x08\x31\x53\xAE\x17\x19\xE7\x22\xA0\x4A\x7D\x9E\xD6\xD8\x49\xD4\x37\x01\x62\x60\x6D\x04\x32\x99\xB7\xD0\x08\xA8\x69\x20\xBC\xCE\x96\x8D\xA8\xEB\x91\x9D\x12\xF3\x92\x31\x67\x52\x51\x77\xD1\x9C\xD6\x59\x80\x9F\x2F\xC2\xB1\x6F\xF8\x5C\x79\x1A\x50\x26\xD7\x2A\x3A\x00\xBA\x5C\x08\x91\x66\xB2\x7B\xFB\x35\xA4\xCC\x8B\xD6\x85\x9F\x03\x4B\x57\x60\xDB\xF5\x66\xE3\x6F\x5C\xBF\xB5\x3E\x20\xBA\x99\x6B\x5B\x23\xFA\xAD\x86\x88\xCD\xCF\xFA\x3A\xEA\x0C\x84\x5D\x8E\xC5\x10\x02\xF3\x4C\xA5\xAB\xF2\xAD\x89\x20\xAD\xCE\x23\xB5\xD1\xCC\xAF\xBB\xE8\xD9\x4C\xE5\x2F\xC3\xFB\x26\x40\x1C\x3C\x13\x00\x6A\x90\x72\x35\x01\x88\xC3\x46\xDB\xE9\xD6\x55\xE2\x81\x13\x09\xC4\x8E\x97\x03\x2F\x34\x05\x6F\xF0\xB5\x74\xF3\x99\x42\xE7\x42\x90\xF3\x82\x3B\x01\x5B\xD0\xAB\x44\xB7\x98\x05\x8C\xB4\x2C\x8F\xB9\x11\xE8\xB8\x77\x00\x9F\xFC\x41\xA7\xF9\x77\xFF\x08\x33\xB7\xDC\x04\xCF\xCD\xC7\x71\x44\x36\x80\xD7\xB9\xD4\x2F\x76\xC1\x33\xCA\x7E\x27\x5E\x71\xED\xAD\x0F\x88\x51\x99\x01\x5A\x43\xF0\xF6\xF0\x07\x09\xBC\xA4\x36\xE1\xAB\x7C\x41\x78\x0F\x26\x80\x95\x26\xBA\x0F\xA0\x42\x31\x7D\x1F\x40\x02\x82\xC3\x40\xCC\x7E\x34\xC4\x34\x55\xC7\x8D\x78\x8F\x61\x48\x2D\x01\x71\x15\x94\x7E\x02\x0C\x9C\xF9\xB4\x9A\xD3\xDA\x08\x74\xE6\x25\x18\x3E\xF4\x13\xE6\x96\xDD\x16\xC4\xEE\x03\x00\x49\xD7\xF3\xC7\x3D\x58\xD8\xF4\x69\xC8\x5A\x7F\xDB\x3F\x1B\xF9\x7B\x0E\x07\x8E\xD8\x1D\xD3\xE6\xCD\xC5\x56\xD9\x38\x8E\x6E\x34\x70\x94\x4B\xF2\x22\x87\xC1\x0C\x4B\xBD\x67\x7D\x24\x81\xA9\xD8\xC9\xFE\x55\x79\x63\x10\x55\xFB\x8D\x74\x65\x18\xF1\xFA\x57\xD9\xE1\x67\x3A\x1C\x45\xBE\x84\xE3\xB3\x6F\x02\xC4\x40\x1F\x07\xD6\x44\x5B\x86\x89\x77\xF6\x31\x0A\xA8\x34\x99\x35\xE3\x48\x50\x34\xA9\x90\x04\xCC\x29\xC9\xCE\x02\xAC\x99\x86\xE1\x99\xFB\xAE\x93\xFD\xF8\x1A\x7A\xF9\x38\xA8\xCE\x53\x32\x82\x65\xBF\xC4\xD0\x9C\x99\xED\xAD\xBA\x07\xB9\xBF\x63\xDC\xDF\x0B\x21\xBF\xCD\x00\xC5\xFC\x48\x7F\xD2\x34\x32\x8E\xF9\x01\x0A\x62\x11\xBF\xD4\xDF\xC3\x06\x82\x8C\x7F\x6C\xBC\xD6\x1A\x14\x52\xB4\x58\xD5\x46\xAF\x5F\x8A\x3E\xE8\x3B\x01\xE3\x20\xBF\x0B\xE0\x4D\x12\x08\xC9\x2D\x54\x4D\xE6\xC4\x93\x8D\x62\x36\x2A\x75\xFA\x49\xAD\x40\xA9\xF9\xD4\x39\x64\xA8\x82\x4A\xBB\x68\x5F\x0A\xFA\xB3\x73\x30\xFC\xC6\x7F\x0F\x6C\x7B\xEB\x46\x20\x7D\x59\x28\x48\x7A\x90\x3C\x16\x83\x69\xC7\x39\xFC\x1A\xAD\xFB\x09\x06\x1A\x68\x8C\x37\x27\xD2\x36\xCF\xC1\x66\xD9\x20\x5E\xE7\xD4\xFD\x77\xB8\x7E\xDD\xC5\xD5\x38\x68\x8E\x0D\x2A\x30\xC8\x48\x5A\xA6\x01\x54\x2D\x33\xA5\x21\x44\xB5\x0B\x2D\xDD\x7B\x01\x83\xD1\x55\x48\xCA\xC3\xFB\x26\x40\x1C\xE4\x95\x60\x8C\x98\x4B\x20\x04\x2F\xE3\x99\x39\x00\xD8\x13\x48\xC6\x7B\x75\x2B\xA9\x14\xD4\x9D\x8B\x49\x17\x4A\x07\xF6\x65\x20\x3D\x4F\x0A\x3B\x3D\x76\x48\x47\xA7\xB1\x4C\x01\xDD\x55\xEC\x52\xD0\x36\xDC\x79\x12\x9E\xB5\xD5\x36\xD8\x23\x5F\x8A\x37\xBA\x98\x23\x5D\xE4\x90\x49\x38\xA9\x30\x80\x5F\xA0\x4A\xA4\xBE\xEC\x53\xD5\x57\x41\xFF\x9B\xCE\x39\x12\x17\xDC\xD6\xAC\x12\xF5\xAA\x15\x98\x1F\xFF\x60\x93\x0C\x3C\x1D\xBD\x9B\xA0\xCF\x00\xE2\xA0\x0F\x03\x69\x89\x1B\xD8\xD9\x96\x2A\xA8\x26\x59\xA9\xAA\x63\x82\x58\x2B\x1D\xEC\x20\xA2\xC7\xBC\x43\xBE\xFB\xEC\x95\x3F\x1B\x27\x39\x06\xF0\xB7\xE2\x4A\xB0\xA2\xCF\xD9\x4D\xBB\x45\x49\xFA\x5D\xD6\x54\x40\x95\xEF\x09\x06\xA6\xC0\x4F\x3F\x86\xCD\xDE\xB4\x37\x76\x75\x3D\xFC\x06\x8C\xE2\x00\x97\x60\xE3\x76\xE2\xB5\x50\x95\x7B\xFD\xF4\x56\xBA\x40\x44\x6F\x7F\xEE\xA1\x98\xA4\xB9\x98\xF2\x0D\x06\x2B\x3D\x11\xE6\x55\xA5\xFE\x3E\x03\x48\x80\x74\x02\xB6\x20\xF6\xDD\x3E\xC0\x56\x35\x99\x97\x99\x35\x58\x0F\xB2\x37\x31\xB4\xDF\x01\x84\x01\x81\x33\xAA\x2E\x3C\x8C\xF5\xF0\x95\x0B\x2E\xC6\x7F\xEC\xFB\x91\xE0\x2E\xFE\x94\x36\xC9\xAA\xB5\xB4\xE7\xB2\x69\x4E\xC5\x87\x53\xF1\xF3\x57\x3D\x1F\x8D\xDF\xDF\x24\xAE\xE4\xFE\x9D\x23\xF4\x71\xEC\xE1\x52\xBF\x21\x5F\x81\xD7\x3A\x1C\x37\x36\x0B\x26\xA6\x4F\xAF\xC4\x58\x95\x38\x22\xE6\x53\xE5\x89\x59\x6A\x20\xA0\x63\xB0\xEE\x19\xD4\xDA\x40\x9F\x01\xC4\xA1\xD8\x0A\x9C\x52\x45\xAB\xAA\x71\x7A\x42\x95\x04\x8F\x70\x92\x14\xFE\x05\xE6\x1C\xF4\x3A\xCB\x90\x28\x4A\xB5\xBD\x27\x9B\x89\xCF\xAF\x1A\xC1\xCF\x67\x1E\x80\x47\x45\x76\x26\xED\x99\x2D\xCF\x8E\x0E\x4B\x53\x20\x17\xEF\x9E\x49\xF1\xAC\xF5\x91\x3F\xFC\x64\x27\xDF\x8A\x33\x30\x6F\xD6\x1C\xEC\xE3\xA4\xFD\x9B\x5C\xC8\x6B\xDC\xDF\x66\xD1\x0F\x5B\x74\x23\xB4\x7A\x5D\xF4\x97\x56\xA5\x73\x70\x66\xA1\x9D\xA5\x49\x07\xBB\x96\xAC\xDA\x41\xA8\x93\x1A\x1A\x99\xE9\xF3\x41\x58\x06\x00\xF3\xDB\x0F\x5E\x3D\x84\x99\x98\xED\x55\x73\x25\x68\x6B\x9F\x01\xC4\xA1\xD0\x00\xD8\x26\x8C\x36\x48\x5B\x4F\x11\xB2\x3E\xC9\xA7\x1D\x7A\xD0\x13\x49\xD4\xA1\xD5\x3C\x39\xB1\x21\xEB\x56\x75\x05\x92\xA6\x53\xF1\x3D\x18\xC0\x67\x1E\x7A\x02\x3F\xD8\xF4\x0D\x18\x23\xFD\xAD\x25\xB7\x16\xC4\x55\xF6\xEB\xCB\xF4\xED\xB8\x7D\x5F\x8A\xEC\xB7\x8B\x27\xD2\x35\xCF\xC1\x41\xD9\x00\xDE\x9C\x37\xB1\xAF\x4B\xF8\x6C\xD3\x9E\x96\x44\x20\x27\x72\x1E\x12\xBD\xBE\x3A\xCD\xF2\xBE\x07\x44\x69\x10\x1A\x23\x54\x6F\xEC\xC4\x38\x78\x57\xBA\xE7\x13\x73\x40\xE3\x13\xF5\x1F\x30\xD3\x8E\x98\x81\x56\x3A\xAB\x8D\xC5\x9C\xD1\x1A\x23\xF1\xF8\xF4\x19\x40\x0C\x82\x55\x00\x70\x7D\x58\x77\x70\xB0\x3B\xCB\x18\x90\x60\x67\x20\xE0\x0F\xB0\xD0\x04\x4A\xC7\x9E\xA1\x15\x68\x06\xD3\x9D\x0C\x8F\x60\x36\x3E\xF6\xD8\x03\x38\x69\xA3\x37\x60\xF5\xCC\x21\x64\x63\xCE\xFA\x1F\x1D\x0F\xD4\x79\xD6\xBC\x82\xF8\x75\x3A\xD6\x7C\x9D\x6F\x02\xB7\xDF\xE2\x79\x2E\xE4\x48\xC7\x7A\x86\xD1\xFD\xE8\x86\xD6\x80\xE8\x7D\x76\x11\x55\xD9\x72\x10\xB2\xF2\x60\xA4\xF3\x3A\x80\x84\xCB\xCA\xCA\xBE\x87\x3D\x0F\x62\xC0\xDA\x2B\xCD\x3D\xA8\xB2\xAC\x2B\xC0\x98\xCF\x49\x6F\xF3\x65\xF3\x32\x70\xBE\xA0\x9C\x6B\x7D\x06\x10\x03\xF9\x71\xD0\xD8\x81\x20\x66\x2B\x5A\x1E\x33\x6D\xCF\xCB\x08\x2D\x69\x40\xF2\x6B\x7B\x9F\x51\x62\x37\xEC\x6E\x0C\xE2\xF3\xFF\x79\x32\x4E\xFA\xF0\x89\x58\x09\x7E\x02\xCF\x72\xE4\x35\x48\xD5\xAC\x49\xA5\x69\x30\x38\xD0\x66\x2E\x65\x79\xAB\xCF\xC4\x4E\x43\x73\x71\x34\x56\xE1\x50\xD7\xA6\xE7\x67\xC6\x37\xF8\xB4\xD4\x35\x19\x03\xD1\x9A\xBC\x72\x22\x44\xCC\x18\x46\xA0\x81\x19\x75\xA6\xAE\xE7\x8E\xF9\x7D\xA2\xED\x4D\x40\x55\x06\xD3\x8B\x7F\x22\xC0\x37\xC3\x0A\xC7\x00\x8E\x72\x0C\xE0\xDC\x1E\x8A\xF8\x8B\x42\xAD\x18\x40\xE0\x03\x90\x92\x19\x5E\x47\x96\xF1\xB9\x9A\x55\x99\x66\xCF\xA2\x0C\x1A\x07\x84\x7B\x03\x74\x1E\x81\x8B\x24\x9C\x6E\x58\xEE\x54\xFE\x4B\xF3\x31\x7C\xF7\xBF\x7E\x8E\xD3\x1C\xF1\xAF\x78\xDA\xFA\xEB\x7C\x57\xF3\x20\xB6\x73\x6C\xE4\x30\x27\xF1\x5B\x37\x0F\xEE\xEC\xB0\x09\x3E\xC7\x6D\x5C\x59\x46\x55\x79\xAF\xAD\x2A\x7F\xA0\x12\x5B\x79\xC5\x38\x31\x2E\x16\x68\x13\xC5\xB3\x32\xC5\x3C\xD5\x9E\xA9\xE8\x09\x7C\xD9\x15\x6F\x8C\x51\x78\xCC\x48\x9A\x80\xD2\x37\x54\xE0\xA7\xEC\xFD\xD8\x26\xA7\x40\x90\x39\xF3\xD0\x31\x80\xB7\x39\x06\x70\xF1\xD3\x35\x47\x52\x50\x3B\x06\x00\x79\x29\x28\x42\x5B\xD0\x42\x3C\xA5\x8E\xD2\xFA\xC0\xF5\x69\x39\x49\x92\xD7\x4C\x4F\xC3\x29\xBF\xBF\x16\x9F\x79\xC1\x73\x70\xCB\xFA\x47\xB5\x6D\xFE\xAA\x9F\xFA\x92\x52\x5F\xDF\xBF\x57\x36\x49\x95\xD3\x4E\x97\x5F\x80\xC1\xF1\xD5\x78\x41\x23\xC7\xE1\x59\x03\xAF\x73\x09\x77\x72\x91\x33\x8B\xFE\xCA\x74\xCD\xBA\xDD\x84\xA8\x58\xBF\x58\xF9\x82\x71\xD1\xC4\x63\xB5\xDA\x18\x83\x60\x55\x05\x7C\x7C\x29\xB1\xC9\x36\x27\xDA\xEB\xD5\x29\x51\x54\x5A\x25\xF4\x9C\x33\x4C\x82\x5C\x4D\xC8\x40\xB3\x9A\xA8\xB7\x35\x2F\xAE\x70\xEC\xFA\x2B\x17\x2D\xC6\x6F\x1D\x03\x78\x02\x35\x81\xFA\x31\x80\xEE\x56\x60\x8F\x08\x35\xD2\x55\xF4\x30\xC3\xF1\x24\xA5\xBE\xA9\xA6\xC6\xC4\xD6\x84\x84\x68\xBA\xB0\x53\x31\x07\x9F\xCA\x76\xC7\xCD\xAA\x96\xD4\x77\xF9\x00\x7B\x27\x5F\xC9\x18\x1A\x0D\xE4\xCD\x26\xF2\x69\x83\xC8\x5A\xFB\x8A\x5B\x4B\x7C\x8F\xFC\x0C\xCF\xDA\x60\x2E\x0E\x76\x71\xEF\x73\x88\x6C\xEF\xFE\xE6\x06\x1A\x8E\xA1\x46\x03\xBC\x59\x96\x24\x67\xA7\x28\xE9\x5A\xBA\x66\x96\x44\xDA\x06\xA6\x16\x71\xC0\xC5\xAE\xDC\xD6\xF9\x7A\x6D\xAF\x94\xCC\xA9\x55\x04\x36\x87\x02\x07\xA0\xEE\x4C\x70\x66\xE1\x1E\xAF\x76\xE9\x4F\x71\x8C\xFA\x9C\x2F\xFF\x0C\x37\x7C\xE4\x7B\x81\x63\x78\x4A\xA1\x96\x0C\xA0\xFD\xAC\x1C\x2F\x9E\xD7\x5F\x0E\xA4\x56\xDB\x21\x88\x18\xBE\x44\xD2\x2A\x1D\x48\x59\x65\x1E\xE6\x66\x9B\x48\x3F\xEE\xF0\x58\xB8\x7A\x0D\x3E\x3E\xE3\x50\xDC\x2A\x9A\x50\x75\xB7\x5E\xD9\x64\xAB\x2F\x66\x39\x45\x7E\xE5\xEA\x4E\xBC\xB3\xEF\x33\xA7\x3A\xCE\x7D\xE5\xF3\xB1\xCB\xBC\xD9\x78\x77\xDE\xC4\xDE\xAD\x2B\xB8\x64\x21\xCC\x49\x67\xF6\x73\xF7\x9F\xAA\x36\x3C\x2D\x80\x48\x62\x99\xB7\xAA\xF3\xCE\x5A\x4D\x48\xF9\x77\x02\xE6\x8D\xB8\x13\xB3\x78\xB0\x7C\x0A\xD0\xE3\x0F\x32\x97\x98\x03\x91\xE3\x96\xBB\xFF\x9E\x74\xA3\xFF\x1B\x37\x9B\xBF\x7E\xCD\x8D\xB8\xE2\xA5\xEF\xC1\x28\x6A\x08\xF5\x65\x00\x88\x48\x27\x99\x27\x31\xF8\x41\x7A\x88\xC1\x55\xF6\x9E\xB5\xCD\x15\xFE\x04\x1D\xCF\x06\xF1\xE3\x91\x35\xF8\xD4\xAC\x83\x70\xA7\x2A\x5E\xAB\xF5\xDA\x01\xA8\x4D\x80\xE4\x21\xA1\xFC\x3C\x6C\xB0\x66\x35\x76\x73\x5A\x40\x6B\xBF\xFE\xBE\x6E\x12\x6E\x88\x48\xDF\x98\xA6\x4B\xCA\xA6\x2E\x10\x95\x36\x6F\xD1\xAF\x11\xE2\xA0\xEA\xB8\x51\x0F\x22\x78\x50\x87\x9F\x0A\x8B\xAE\x54\x54\x6D\xAF\x52\xD1\x0B\xA0\x67\xFF\xBB\xE5\x50\xA1\x23\xFA\x4C\xE1\xD8\xBA\xD3\xE2\x02\xF7\x7B\xBC\x93\xFA\x97\x67\xFB\x63\x79\xB5\x99\x39\x35\x50\x2B\x06\x50\xDC\x0A\x8C\xC8\x84\x51\xC1\xFC\x99\x38\xF7\x8A\x48\xCF\xC1\x53\xE4\x23\x6A\x2B\xF3\x5A\x67\x03\x78\xC4\x91\xED\xCF\x57\x03\x5F\x9D\xB1\x2F\x96\xAC\x45\x7F\xE7\xA9\x84\x8E\xF0\x37\x74\xA9\x77\xC9\x47\xF1\x46\x87\xEF\x21\x68\xDD\xBD\x67\x38\xC1\xA2\x6A\xAC\xEC\x43\x70\x62\x0D\x92\x2B\xF5\xDA\xD2\x30\x62\x44\xCB\xC6\x89\xA0\x14\x12\xAA\xC2\x8D\x6A\x28\xA9\x3A\x48\x7B\x91\xDB\x44\x2E\xFD\x08\xDA\x01\xD8\x1E\xB4\xDC\x27\x74\x39\x98\x02\x97\xA6\x9B\xB9\x7F\x76\xBF\xBF\x70\xB2\xFE\xE4\xEC\x80\xCE\xFC\x78\xD3\xDE\x68\x9C\x72\x51\xA5\x8F\xAC\x4C\x09\xD4\x8A\x01\x04\xDF\x06\x6C\x07\x72\x3B\x6C\xAD\xEB\x02\xE8\x26\x18\xB3\x97\x32\xDC\xF6\xE0\x63\x38\x6E\xB3\x63\xF0\xC3\x56\xD0\xE1\xAF\x42\xF6\xAB\xDF\x97\xF3\x41\x7F\x74\x13\xEA\x9D\x99\xA4\xA5\x16\x70\xF0\xAE\xC8\xCE\xBA\xB2\x93\x66\xD5\x99\x98\x3D\x7D\x1A\xF6\x75\x6F\xC7\xB8\xC9\x75\x98\x9B\x5C\x73\x03\x3B\x17\x11\x82\x33\x24\x7C\xBB\x72\xCB\xE1\x27\x26\x78\x10\x1F\x71\x18\xB2\xBC\x92\xA0\x58\x9D\x31\x73\x85\x5E\x2E\xA2\xCA\x49\x32\xAD\x54\x7B\x05\xE5\x5B\x4C\x93\xF6\xAF\xF2\x59\xA8\xA5\xE8\x07\x9A\x39\xCE\xBB\xFF\x31\xFC\xD7\x96\x6F\xC5\x35\x45\x39\x07\xED\x82\xEC\xEC\x3F\x7A\xC5\xD6\x0E\x6A\xC7\x00\x72\xB1\x0C\x18\x3B\xBC\x61\x4E\x9C\x2C\xE4\xD8\x31\x7B\xCF\xC4\x45\xA4\x6D\x66\xB8\xCB\x0D\xF0\x27\x7E\x7D\x39\x7E\x7A\xE4\x71\xD4\x89\x23\xCD\x5D\x09\xA9\x5D\x7D\x25\x5C\xFE\xDF\x98\xF6\xE2\xAD\xB1\xC3\xEC\xD9\x78\xA3\xB3\xF1\xDF\xE5\x0A\xDC\x54\xCC\xD5\xCA\x03\x55\x25\x6D\x2A\xCD\xBA\x62\xB4\xEB\x92\x61\xAF\xD3\xF6\x28\x76\x1C\x5B\x56\x4C\x98\x21\xAB\xDD\x08\x5F\x8E\x01\x7C\x7D\x74\x04\x17\x0E\x1D\x12\xF5\xEE\x5B\x73\x64\x4A\xA1\x5E\x0C\xE0\x9C\xAE\x06\xA0\x54\x35\x54\x19\x20\xAD\xB6\x6B\xCA\x2F\x1E\x0B\xEE\xDF\x6D\x3D\x2B\x3F\x17\xF9\x5D\xF8\xED\x98\x89\x7F\xCF\xF6\xC4\xFF\x44\xFA\xCE\xF2\x75\x31\x7F\x96\x87\xD1\x45\x5F\xC6\xD0\x1E\x2F\xC2\xF3\x1B\xD3\xB1\x9F\x53\x1D\x8F\x74\xED\xD8\xCD\x31\xB0\x86\x2C\x81\xDE\x52\x2B\xA4\x5C\x52\x05\x56\x0E\x54\xDA\xBF\xF0\xB1\xD4\x1F\xE7\x90\x0E\x53\xBD\x0C\x16\xAC\x00\x80\xF4\xA7\xEA\x10\xEF\x5D\xE1\xE7\x69\x14\xAC\x2E\xD5\xA1\xDE\x3A\x7D\xA4\xBD\x60\xF1\xB2\xDB\x0C\x2D\x22\xD0\x16\x3B\xB0\xD8\xFD\x2D\x5C\x3A\x82\x5F\xAE\x77\x04\xAE\x37\xC6\x5F\x37\x95\x85\x4F\x29\xD4\x8F\x01\x64\xFE\xE7\xC1\xB5\xF8\x8E\x5D\xD8\xE1\xD9\xFE\xF0\xD3\xD0\xC6\xAA\x41\xD5\xCB\x3B\x2E\xEE\x2E\x97\xFF\x13\xFF\xFA\x5D\x9C\xFC\xA5\x9F\x79\xF7\xFA\x65\x0A\x33\x56\x85\xF6\x91\x05\x83\xBE\xE2\x74\xBC\x68\xD6\x3C\x67\xDF\xAF\xC1\xA1\xEE\x75\x17\x97\x60\x7A\xA0\xA1\x18\x6A\x80\xE5\x00\x54\xAA\x69\xB4\xAD\x9A\xA9\xE8\x38\x19\x51\xE2\x05\x41\xA0\xCA\x84\xF2\xEA\x94\xFD\x9E\x83\x5E\xB9\xE6\xA5\x37\xBC\x8A\x51\x7F\x45\xCC\x3C\x0C\x09\x36\xBA\xB2\x20\x9A\xE7\xE3\x1C\x6A\x00\x8F\x67\x83\x38\xD3\x19\x66\xDF\xCE\x5E\xE9\xA4\xBF\x0F\x29\x29\x5F\xD9\x07\xF4\x74\x41\xAD\x18\x40\x79\x21\x08\x23\x4C\xC9\xF9\x2D\x0F\x2F\xC2\x81\x8D\x3A\x0B\xBB\x0F\x64\x4F\xC0\x58\x36\x80\x85\x98\x85\x1F\x5F\xF6\x07\x9C\xB3\xC7\x07\xDB\x4B\x38\xD6\xDC\xB5\x06\xB3\xBC\xB2\x6B\xDB\xCD\x81\x5B\xEF\x17\xAB\x51\xE7\xE1\x25\xF9\x28\x0E\x70\x75\x1C\xE1\x42\x5F\xE2\xFE\x66\x31\x1B\x9F\x4A\x3A\x6B\xC4\x22\x6A\x6B\x89\xA4\xE1\xB4\x83\xAC\x8F\xE1\xC1\xCC\x2D\x85\x93\x7E\x06\x23\x58\x36\x28\x80\xC9\xCC\xA4\x96\x16\x63\xDE\xF2\x8C\x47\xE5\xF6\x1A\x9A\x95\x99\x3F\xC7\xA3\x4E\xD5\x3F\xD7\x25\x38\xE3\xE1\xC7\x70\xF1\x26\x6F\xC2\xFD\xF8\xFF\x01\xD4\x8A\x01\xC8\xC3\x40\x13\x81\xA8\x34\xE9\xD1\x63\x12\x4A\x64\x13\x13\xF1\x87\x6E\xB0\x3F\x9B\xBD\xB6\xB3\xC6\x3F\x30\x80\x6C\x7C\xBC\x74\xDA\xB5\xC0\xFA\x82\x6F\x70\x55\xD7\x97\xDF\x89\xEC\xC3\x27\x76\xD2\x8C\x9C\x8D\x6D\x5A\x97\x6E\x4E\x1F\xC2\xEB\x5C\xC8\xCE\xE8\xDE\xB6\xCB\x90\x4C\x35\x1B\x48\x30\x36\xAB\xAD\x15\x1C\x0B\x6B\xE3\x23\xF8\x4B\xD9\xFD\xB1\x36\x5A\xEF\x9A\x69\x5A\x9A\x60\x12\xE7\x26\x6E\xC0\x1C\x9C\x30\xB6\x0C\x27\x4F\x3B\x18\x8F\xFF\x05\x9A\x37\x65\x50\x3B\x06\x00\xB1\x11\xC8\xC3\x50\x4A\x89\x0A\x33\x30\xA5\x3A\xCA\xB5\x5C\x51\x56\x8B\x78\x7F\xE2\xE4\xF1\xA7\x9C\xCD\x7F\x7B\x37\x6C\x6D\x6E\xE1\x6D\xC3\x8D\x27\x62\xE6\xD6\x9B\xE0\xF0\x19\x33\xF1\x1E\x67\x48\xBC\xDC\x55\x3B\x5B\x7B\x36\xD9\xB2\x9B\x27\xD9\xB4\xD4\x14\x69\x2C\x29\x16\xEF\x6C\x78\x8C\x80\xED\xBE\x6B\xA3\xA7\xFD\x02\xB1\xAE\x67\xF6\xBF\x0A\x8B\x32\x21\xA2\xC5\x94\x65\x64\x61\x7B\x7B\x71\x92\xEA\x9D\x9E\xE6\x0E\x3F\x5F\x9B\xB9\xD7\x8D\xEA\x09\x6E\xB4\xCE\xFE\xF2\xFF\xE0\x86\x8F\x9C\xD8\x9E\x9F\x6D\xD8\x7A\x53\x64\x77\x3E\x58\x1F\x55\x7E\xB2\x50\x3F\x06\x20\xF6\x01\x54\x19\x60\xCF\x61\x27\x02\xA5\x1F\xA0\xDD\x50\x3D\x29\x95\xFA\xD8\xFE\xA7\x81\x1F\xAD\x5E\x8D\xCF\xA8\xDD\x7D\x05\xC4\x2E\xF5\x2C\x9F\x9F\xB3\x31\xF0\xE3\x7F\x45\xBE\xE7\x87\x5C\xD1\x17\x60\xA6\x33\x1E\xF6\x70\x2D\x7A\xA7\xFB\xDD\x3D\x6F\x62\x0B\x6B\x59\xAC\xCA\xC5\x16\x31\xC2\xA3\x8E\x50\x15\xAF\xEB\xD4\xCF\xB1\x72\x63\xA6\x41\x54\xEB\x48\xE4\xA5\xE3\x09\x84\x3B\x3B\xD7\xB2\xBD\x50\x8C\xA3\x18\xF2\x5C\x57\xDE\x49\xF3\xA4\x7B\xBA\x00\x83\xF8\xC1\x13\x4F\x62\xD1\x06\xAD\x33\x96\x0E\xE6\x39\x43\x6D\xE9\x4A\x73\xB5\x27\x75\x43\x73\xAD\xD6\xFF\x0B\xA8\x1F\x03\x80\x72\x02\x16\x58\xEA\x6E\x27\x36\x7F\xE9\xAD\x85\x61\x7F\x12\xBB\xB1\x2B\xFD\x96\x67\x83\xF8\x79\x3E\x86\x2F\x34\x0E\xF4\xF6\xF5\xB3\x8F\x70\x50\xDB\x7F\x8F\x1D\xD1\xB8\xF4\x86\x4E\xBA\x95\x67\x60\xBD\x99\x43\xD8\xDD\xA5\x78\x9B\x4B\xDD\x5A\xD3\xDF\xC4\xD5\x3B\xA1\x6C\xA4\x9C\x7C\x31\xCE\x97\x60\x06\x50\x45\x98\x11\x86\xE4\x0F\x50\x60\xF6\xB9\x2C\xC2\xD0\x4C\x2A\x8D\x07\xCB\x13\x61\x2A\x6B\xD3\x5E\x7A\x3E\x21\x6C\x6F\x6B\xFC\x6E\x74\xE6\xDF\xF1\x23\x23\x38\xFD\x83\xDF\xC6\x13\xDF\x39\xB3\xD2\x37\x1B\x64\x7C\xEB\xAF\x97\x3C\x53\x0A\xF5\x66\x00\xB0\x69\x81\x39\x6C\xDA\x0D\x8A\x68\x0F\xC6\xE4\x5A\xE2\xC8\xFC\x8B\x2E\xF0\xB4\x0F\x9C\x80\xA5\x5F\x3F\xBD\x9D\xAE\x18\x44\xB6\xC1\x47\x7A\xF4\xB3\x77\xEC\x07\xFC\xE0\x37\xC8\xAF\xF9\x36\x06\x5E\xBC\x0D\xE6\xBB\x9C\xAF\x72\x39\xDE\x8C\xD6\xB6\x5D\xE0\x59\x59\x37\x2F\x53\x85\xCB\x01\x90\x1E\x67\x63\x54\x28\xA1\xC6\xEC\x78\x22\x25\x99\x4D\xCC\x9C\x7C\x05\x58\x9B\x6F\x64\xDF\x4A\x1C\x52\x0E\x43\x60\x82\x21\x78\xA6\x8F\xC2\x5B\x4B\xF5\x75\xD1\xDE\xC0\x04\x00\xBC\xE5\x45\x17\x71\xB3\x7B\xFD\xB9\x1B\xEC\x93\x7F\x7F\x23\x6E\x79\xF5\x3F\x61\x75\xB7\x0F\xDA\x57\xAA\xCB\xE1\xC2\x84\xE6\x67\xED\xF0\x33\xFD\x8A\xA8\x99\x26\x50\x3B\x06\x60\x39\x01\x03\x06\x20\xEC\x66\x26\x61\x52\x1E\xF4\x76\xFE\x06\x6E\x1F\x1B\xC7\x27\xA7\x1D\x84\x1F\xB7\xC2\x0E\x79\x25\xB2\x33\xAF\x28\xB3\x68\x28\x55\xFD\x69\x83\x68\x38\x75\x30\x7F\x6C\x69\x27\xDD\xD2\xD3\x30\x38\x34\x0D\x7B\x4D\x1F\x6A\x13\xFE\xC1\x2E\x68\xF3\xA0\x6D\xCA\xBE\xB4\xCE\xBE\xB3\x65\x3C\xCB\x79\x55\x44\x96\x69\x2D\x49\xAC\x09\x38\x17\x71\x99\x4F\xCC\xA9\xB5\xF1\xAA\xBB\x05\x3D\x1F\x05\x0C\x42\xC7\x44\x9C\xE5\xA9\x5F\x67\xED\x25\x7E\xA1\xEE\x1C\x78\xCA\x99\x66\x57\xBA\xE7\x6F\x35\x86\x70\x76\xF6\x57\x18\x39\xF0\xE5\xC8\xCE\xB9\x2A\x10\x02\x25\xBA\xA2\x2A\xEB\xF3\xEB\xB9\x4A\x2F\x9F\x6B\x43\xFC\x1A\xB9\x29\x07\xC6\x00\xA2\x5B\x4A\x15\x27\x37\x77\x06\x42\x4D\x8A\x56\xA6\x01\x2C\x19\xCD\xF1\xD1\xA1\xFD\x71\x1A\xE9\x13\x3D\x50\xF4\x8E\xFD\xBC\x75\xD6\x6B\x1C\xDB\xBA\x97\xFD\x5C\xD9\x1F\x76\x41\x5B\xE8\x7A\xD8\x56\x63\xAD\xB1\x58\xDB\x4D\x85\x89\xE2\x5D\x66\x12\x7C\x0C\x85\x4D\x70\x39\xBA\x55\xF5\x69\x6D\x1E\xE8\x22\x44\xFD\x96\x36\xE6\x05\x12\x1C\x82\x71\x80\x4A\x47\xCA\xB0\xDA\xEB\xA1\xAC\xCB\x8D\x31\xB2\xCE\xCF\xA8\x23\xFE\xEB\xDD\xA8\x1E\x8F\x21\xFC\x3A\xDB\xA7\x6D\xF7\x6B\xB0\xA4\xB5\x25\xFD\x27\x7D\xFA\x73\xAA\xA0\x9E\x0C\x00\x08\x6E\x85\x65\x73\x25\xD7\x03\x5D\x48\x50\x45\xF8\x32\x4D\xF7\x71\x09\xE6\xE2\xDF\xB3\xDD\x71\x52\xA4\x1F\xDA\x6A\xDE\x9C\x99\xC0\xF2\x11\x34\x0F\xD8\x19\xD9\xA2\xAB\x3B\x68\x7C\xFA\x1D\x18\x7A\xD7\x81\xD8\x76\xF3\x0D\xB0\xBF\x7B\x3D\xCA\x05\xEE\xEA\x0A\x98\xC1\x26\xA7\x24\x04\x6D\x7F\xCA\x9A\xAC\x3C\x5E\xBB\x64\x3F\x30\x69\x4C\xD4\x7B\x2F\xDA\x90\x8C\x24\xBB\x99\xBE\x8D\x96\xAC\x83\x69\x56\x0A\xF7\x3C\x91\x27\xA8\x9C\xF8\x39\x52\x37\x17\x55\x69\x6F\x99\x70\x00\xB7\x61\x10\x0B\xC7\x47\xB1\x70\xD1\x15\xB8\xFA\x90\x7F\x0B\xB6\x77\x4B\xA7\x5E\x4A\x6A\xCB\xB4\xC6\xC8\x4D\x0C\x6D\xDD\xA0\x56\x0C\xA0\xD9\xDD\x0A\x1C\x73\x02\x69\xD5\x5F\xDB\x92\x52\x52\x11\xE7\xC1\x88\x9B\x58\x17\x8D\x8E\xE2\x84\xE9\x87\xE0\x0C\xD2\x07\x45\x0E\xCF\xCC\x2D\xE0\x84\xF7\x61\xE8\x0D\x7B\x61\x87\x8D\x9E\xE3\x08\x7F\x99\x53\xF7\x9B\x78\xB9\x37\xE1\x45\xAE\x60\xE9\xCE\x9A\xE0\x5A\x32\x32\x9B\x55\x14\x41\xAA\x32\x4D\x0A\x5D\xAD\xDF\x91\xDD\x1F\x6D\x8B\xAB\x96\x97\xAF\xA2\xFC\xD4\x11\x6D\x36\x5E\x96\x89\x01\x52\xA6\xF6\x31\xB0\x1D\x9F\x41\x7B\xBB\x1D\x13\x6B\xAF\xCB\xF3\x88\x7B\xBA\xDC\x99\x7D\xDF\x1E\x3A\x18\xE7\xB4\x82\x9F\xBD\x11\xB2\xFB\x1E\x2D\x4B\xB1\xF6\x79\x58\xAA\xBD\xE5\x9E\xD2\x43\x05\xE3\x7D\xCA\xA1\x56\x0C\x40\x3B\x01\xCD\xDB\x6C\x34\xA1\xC9\x32\x10\x12\x48\xD7\xB9\x36\xEA\x4A\xFE\xBE\x7B\xFB\xB2\xB3\xF3\xE4\x32\x1F\xA5\xB1\xBF\x7A\x29\x70\x7E\xF7\x9A\xED\x65\xA7\x23\x73\x9A\xC0\x8B\x30\xCB\x11\xFE\x2A\x1C\x9D\x8F\x61\x67\x87\xD7\x10\xAB\xD3\x2C\x10\x7E\xA0\xFE\x8C\x95\x74\x74\x49\x87\xA0\x5E\x7B\x8F\x49\x3A\xD3\x01\x67\xD9\xC4\x5A\xA2\x47\xD2\x99\x36\x74\xB6\xEE\x70\xA9\x12\x3E\xC9\x3A\x56\xB5\xB7\xEF\x0E\xE2\x97\x8E\x94\x17\x65\x7B\xB5\x19\x41\xD1\xAD\x79\xEB\x2B\xC9\xAB\x47\xA3\xAB\x99\x65\x5A\x11\xAE\x97\xFE\x58\x7E\x9D\xA7\xCF\x00\x62\xD0\xEC\xEE\x03\xD0\xD2\x3C\xD8\xE2\x89\x90\x19\x24\xD4\xD7\xD6\x56\xDE\x93\x6E\xBD\x1F\xC7\x6D\xF7\xB7\xB8\x2B\x85\xC7\x07\x8F\x42\xF6\x95\x5F\x74\x79\xC7\x65\xD8\x01\x23\x38\xD4\x29\x89\xAF\x77\x15\xB4\x76\xEF\x0D\x41\xD6\x0D\xF0\x65\x39\x26\xE5\xE1\x13\xB9\xA5\x21\xC4\x96\xDE\x82\x97\x9C\xD7\x6F\x1E\xA2\x31\x1C\x8E\x93\xF5\x23\x68\x86\x0B\x5D\x1E\x91\xEC\x41\x19\x8A\x78\x0B\x7C\x29\x18\xED\x95\x65\x95\xED\xCD\x9D\x9D\xDF\x5A\xD6\x9B\x85\x5F\xAC\x59\x86\xEF\x39\xAD\x4F\x6E\xDF\x8D\x11\x23\x6D\x92\x8A\x67\x5D\xC0\xD2\xD4\x8A\xE0\x59\x43\x6B\x03\xD4\x09\xA8\x91\x54\xCA\x15\xF3\x08\x07\x99\xB3\xB6\xAD\xFF\x6F\xD9\xFE\x26\xF1\x07\x83\x35\xF2\x6B\x0C\x0D\x0D\xE0\xB5\x8D\x0C\xC7\xBA\xD8\xD6\x77\xF4\xDA\x9A\x49\x70\x63\xB0\xB6\x81\x11\x32\x22\x0F\x3D\xC5\x08\x4C\x37\x51\x16\x0D\xB2\x89\xD6\x90\x9A\x00\x4C\x9B\xDF\x72\xA0\x59\x1A\x82\xB5\x11\x27\x20\x5E\xD5\x57\xB4\x1D\x09\x29\x2E\x77\x43\x5A\xE6\x00\x78\x9B\x5B\x47\x75\xBF\xD3\x1C\xC3\x29\x7F\xB8\x05\x57\xEE\xF6\x7E\x8C\xEE\xBC\x2D\xB2\xAB\x6F\x9D\x34\x41\x66\x46\x98\xB5\x2D\x5C\xA6\x61\xBE\x81\x5A\x40\xED\x18\x00\x0A\x13\xC0\x20\x2C\x53\xBA\xE8\x49\xD9\x61\x0E\x63\x59\x03\xFF\xBB\x6A\x35\xBE\x38\xF3\x30\xDC\xA6\xDA\x5C\x0E\xC2\xDB\x5F\x8B\xEC\xA4\xF3\xBA\x45\xFF\x16\x73\x1D\x16\xFB\xBA\xC9\x73\x98\x0B\x79\xAD\x0B\xDA\xAA\x48\xCD\xBE\x67\x1F\xA0\xCA\x6C\x10\x66\xE3\x43\x30\x81\x22\x6B\xE6\x67\xD5\x5A\x44\xE9\x4C\x13\xE1\x39\xAB\x0F\x06\x51\x01\xDE\x36\x5C\xCF\xD4\x50\x65\x07\xF6\xBA\xC0\x5B\x76\x62\x19\x2D\xFA\x9D\xB5\x5B\x2E\x3D\xCA\xF6\x4A\xBC\xD9\x65\x20\x05\x73\x97\xCC\x8A\xC9\x67\xD1\xDE\x35\x6E\xCC\xCF\x74\x61\x67\x34\x9B\x38\x7D\xE0\xA0\x72\xEF\xFE\x64\x89\x2F\xA6\x05\x14\x0C\xA0\x78\xB7\xB4\x06\x8B\xCD\x4F\x39\xD4\x97\x01\x94\x81\x13\x58\x5A\x5B\x3F\x83\x72\x3A\x13\xE2\x56\xCC\xC0\xB7\x9B\x23\xF8\xF1\xC0\x81\x78\x50\x44\x37\xA6\x0D\x22\x1F\x1D\x43\xFE\xBD\x7F\x42\xF6\xAE\xFF\xEE\x0C\xC6\xC8\x59\x18\x9C\x31\xC7\x11\xFE\x4A\xBC\xD1\x4D\xCC\xFD\x5D\x1D\x5B\x52\x49\xCD\x86\x98\x38\xAF\xCC\xEF\xCA\x99\x5E\x2A\x22\x8D\x01\x53\x4A\x97\x04\xAB\xCA\x66\x5A\x49\x89\x2A\x91\xE0\x55\x1C\xAE\xCC\x41\x19\xE4\x97\x0C\x42\x9A\x17\x29\x2D\x02\xA0\xAB\x36\x99\x51\x97\x89\x57\x07\xEE\x74\xEC\xFB\x87\xAB\x1F\xC7\xFF\xCC\x38\x2C\xD0\xF6\x98\xDA\xAE\xBB\x88\x2D\xE3\xA5\x7C\x03\x3A\x5F\x66\xE4\xCF\x51\x23\xC2\x67\x9D\x32\xE5\x40\x19\x00\x4B\x07\x7B\x64\xDA\xD0\xC0\xAD\xF9\x38\x3E\x7A\xF1\x75\x38\xFD\x35\x1F\x8E\xDF\xC6\xFA\xE0\x42\xCC\xDA\xA4\xF5\x01\xCD\x01\x47\xF8\xE3\xD8\x27\xEB\x7C\x47\xAF\xA1\xD3\xC5\x2C\x8C\xF6\xB3\x92\xB4\x45\x9E\x3C\x42\x74\xB2\xA0\x18\x41\x7A\xD2\x0F\x9C\xE8\x24\xE3\xC9\x05\xC2\xCC\x6C\x60\xB6\x3F\x6B\x9C\x36\x6E\x0B\x55\x5C\x33\x24\x0B\x3F\xA6\x8D\x94\xFD\x59\x81\xB8\x8B\x4A\x03\x75\x5F\xF7\x3B\xB0\xDC\xFD\xFC\x6F\xB6\x3E\x4E\xFA\xEC\xB7\xF0\xE7\x4F\xFE\xA0\xE7\x8F\xB3\xB0\xA5\xBC\xA2\xC9\x5A\xCA\x7B\x4D\x36\xD2\xC9\xFC\xB5\x23\x7A\x8D\x60\x6D\x80\x9E\x05\x88\xD8\x9C\x74\x5D\xAC\x81\x25\x8E\x98\x3F\x79\xFC\x4F\xB1\xF0\x43\xDF\xF5\x2E\xF1\xF0\xB8\xFB\x75\xDF\xC1\xC0\x36\x5B\x60\xD7\x99\xD3\xF1\x5E\x97\x6A\x4F\x97\xFF\x39\xE8\xEE\xD7\xB7\x1C\x8B\x32\xCE\x7B\x66\xE6\x80\x56\x85\x0B\x54\x29\x55\x91\xFA\x44\x3C\x33\x31\xF2\x08\xE1\x9A\x4B\x80\x52\xBD\x96\xB8\xC0\xF6\x03\x04\x65\xC3\x8F\x8B\x28\x34\xD1\xB8\x54\x35\xCC\xC4\x20\xED\x1D\x71\x89\x2F\xC2\x20\x7E\x8C\xD9\x38\x27\xDB\xAD\xFC\x12\x73\x01\xFA\x2C\x07\x5B\xCE\x63\x61\x45\xF8\x5A\x9D\x02\x9D\x64\xBA\xA7\x15\x6A\xC5\x00\x8A\xAF\x03\x17\xEF\x52\xA2\x55\x39\x51\xE6\xDE\x6F\xC9\x06\xF1\x09\xC7\x00\x16\x66\xFB\xB4\x89\xBF\xE0\xCC\xED\xE2\x7F\xFE\x09\x64\x47\xBF\x06\x8D\x55\x23\x78\xEE\xE0\x00\x0E\x1D\x1C\xC4\x3B\x5C\x61\x2F\x2E\x24\x3E\x93\x8A\xE5\x7B\x37\x81\x61\xE2\x53\x1B\x99\xF1\x27\x6A\x02\x48\xC9\x19\x23\x44\xE9\x13\x30\xC0\x92\xCC\xFA\x68\xAD\x96\xFC\x51\x66\x21\xDA\xCF\x3A\xC0\x4B\xA7\x7C\x14\x26\x4E\x08\x99\x5A\xAC\x6C\x02\x77\xB8\x34\xFF\x83\x79\xF8\xDF\xAF\xFF\x10\xF7\xBF\xFF\x04\x34\xB7\xDC\x18\xD9\x3D\x8F\xB4\xBF\x9B\xD8\x18\x1B\x8F\x12\x5B\x26\x6A\xD2\xCC\xC0\xBA\xB9\xD7\x52\xF9\x41\xF2\x23\x12\x57\x2B\x46\x50\x2B\x06\x60\x7D\x17\xA0\x8D\xA8\x94\x54\x05\xE6\x13\xD2\x70\xB5\x23\xFC\x2B\x56\xAF\xC2\x57\x2F\xB8\x06\xBF\x3C\xE8\xE3\x7E\x07\x7F\xFF\x43\x8E\xF0\xF7\xC4\xF4\x99\xD3\xB0\x8D\x9B\x1C\xFB\xB9\x21\x78\x8B\xCB\xFB\x42\x17\x35\xAB\x2C\x33\x66\x21\x4A\xA9\xAB\xEA\x8E\x89\xB9\xA0\x18\xC9\x48\x62\xAA\x77\x61\x03\x47\xD2\x06\xF7\xDE\x85\x7D\x62\xD6\x45\x89\x4F\x95\xA9\x1D\x86\x10\x61\x9A\xE0\x63\xA6\x50\xD2\xF0\x56\x4E\xC8\xD8\x0A\x46\x1B\xB7\x06\x1E\x72\xCF\x3F\x7A\x7C\x29\x16\x5E\x7E\x03\x16\x1F\xFE\x29\xA7\x05\x74\xA0\x94\xF6\xDD\x03\x3C\x05\xE8\xFD\xFA\x31\x6F\x8E\x4C\x67\xE5\x81\x91\xB6\x0A\xD4\x8A\xF8\x81\x9A\x31\x80\xD6\x4E\xC0\x2C\xB3\x9D\x80\x1A\xBA\x51\x23\xEE\x9F\x9F\xAF\x1A\xC7\x67\x4F\x5A\x84\x3B\x9D\xDA\x3F\x36\xDD\x95\xF0\xE8\x53\x9D\xC1\xBA\xF7\xC7\x18\x7A\xF6\x66\xD8\x02\xA3\x38\xD0\xBD\xBE\xC9\xFD\xED\xEC\x26\xC7\x1C\xE6\x4C\x0C\xBC\xCE\xCC\x99\xC6\xEC\x56\x70\x5E\x40\x2F\xB5\x30\xA4\xB8\x69\xF7\x2B\x3C\xA2\x87\x73\x88\x53\x12\x7E\x10\x37\xA7\x52\xBA\xBA\xCE\x8B\x90\x81\xC4\x36\x0B\xB5\xEB\xCF\x22\x65\xA8\x3A\x82\xB1\xE9\x84\x2D\x73\x3F\x8B\x57\xAE\xC2\x8F\xCF\xBD\x1A\xA7\x1C\xF5\x99\x89\xBD\xFB\xAE\xBC\x2C\xF7\x49\xD3\x72\xE8\x15\x76\xBA\xD6\x00\xD8\xE7\xD9\x98\xDD\xAF\xA1\x76\x04\xDD\x2B\xD4\x8A\x01\xE4\xE2\xF3\xE0\x52\x05\x2C\x11\x0D\xB1\x5D\xD5\x5A\xEB\x1D\x1F\xC7\x17\x07\x7D\x4F\x3F\x46\xCF\x42\x63\x70\x3A\xB6\x75\x86\xC0\xEB\xDC\xE4\x38\xC6\x15\xF4\xD2\x96\x64\x08\xEA\xC4\x04\x11\xC4\xF6\x9F\x6B\xF3\xD7\x54\x00\x22\x6A\x7A\xE0\x1F\x40\x2C\x91\x0A\x8A\x89\x53\xE6\x57\xD0\xC5\x12\x33\x26\xE9\x4F\x40\xBC\x4C\x99\xBF\x9D\x44\x32\x44\xA6\x89\xE8\x70\xDD\x81\xFC\xB9\xB5\x47\xEF\x2E\x4C\xC7\x57\x9E\x7A\x02\x0B\xD7\x3F\x0A\x0F\x6D\xB4\x1E\xB2\x2E\x83\x37\x8C\xA9\x36\xF4\x62\x9B\x4B\x53\xC0\xD2\x00\x62\x0C\xA3\x00\xCB\x19\xD8\x0B\x3E\x4F\x2B\xD4\x8A\x01\x68\x1F\x40\x0B\x22\x9A\xF6\x4A\x17\x70\xCA\xB2\x15\xF8\xF8\xBC\x23\xF1\x80\x8C\xF8\xD3\x09\x58\x7F\xC7\xAD\xF0\xDA\xA1\x21\x0C\xBB\x2E\xDF\xC3\xE5\x9D\xAE\x1B\x1C\x78\xC4\x89\x34\xA5\x1F\xC7\x04\xA7\xC3\x40\x02\xEA\x0E\x26\xD2\x39\x90\xA2\x88\x33\x8E\xD8\x2D\x3A\x09\x6B\xC4\x6C\x80\x45\x7F\xA9\xC2\x92\x17\x89\xC0\xD6\x76\xAA\x56\xE1\xFE\x6E\xC1\x20\xCE\x76\x4C\xFC\x8C\xAB\x6E\xC6\x65\xBB\xBC\xAF\x73\x33\x8F\x80\x98\x74\x2E\xA0\x0A\xE1\x59\xCB\x7F\x1A\x2C\x96\x5B\xB5\x9E\x5E\xD2\x3D\x2D\x50\x2B\x06\x60\xDD\x07\xA0\xB7\x02\xBB\xE7\xD6\x96\xE1\x13\xD7\x8C\xE3\xDF\xE5\xF6\xCE\xB1\x73\xB0\xFE\xC0\x00\x76\x73\x5D\x7C\xB4\x9B\x34\x87\xBB\x34\x1B\xCB\x72\x2C\xBD\x5B\x4B\x26\xBD\x84\x16\x3B\x45\xA7\x9D\x6A\x31\x62\x68\x87\x29\xE7\x18\x7A\x20\x10\xCB\xC4\xA8\x72\x66\x5F\xE7\x4F\xDA\xEA\x89\xFE\x02\xA9\x3B\x48\xA7\xF1\x82\xE8\x63\x84\x0C\xB3\xD4\xC4\x80\xA7\x5C\xDC\xB9\xA3\x63\xF8\xC6\x53\x2B\x71\xE9\xC6\x6F\xA0\xE7\xEE\x53\x04\xCB\xBA\x8E\x39\xFE\x98\x69\x00\x23\x5D\x6E\xE4\x81\x8A\xD3\xBD\x61\xE1\x38\xE5\x50\x3B\x06\x00\xB5\x0C\x48\xB6\x80\xB6\x0E\xF2\xFC\xD4\xFD\x7D\x33\x3B\xA0\xA3\xF6\x3F\x70\x32\xD6\xDF\x74\x63\xEC\xE1\x12\xBC\xCE\x11\xFE\xA1\x10\x5F\xCE\x2D\x8B\x8A\x39\xFA\x0C\x11\x5A\xD1\x34\xB6\xD3\x46\x7C\x08\xE9\xCC\xA4\x0E\x63\x85\x20\x75\x3A\x4F\x4B\x76\xC2\x50\xCB\xA9\x19\x3B\x57\xA0\xC7\x25\xAB\xD0\x3E\x66\x3A\xE9\xBD\x08\xA5\x76\xD3\x8A\x6B\xE0\x62\x0C\xE1\x47\x6E\x16\x9C\x95\xBD\x1A\xF7\x15\xE5\xCC\x9F\x83\xEC\x09\xFF\x33\x9B\xB2\xF6\x14\x71\x59\xEB\x0C\x55\xBA\x2C\xEA\x9E\xA9\xD2\xE5\x02\xC7\xDA\x48\x7E\x89\x54\x6D\x80\x6A\x00\x45\x5C\xE7\xE7\x26\x17\xF5\x31\x47\xF8\xED\x4B\x3C\x6E\x3C\x11\xEB\x3D\x7F\x0B\xEC\x89\x01\x27\xED\x9B\x38\x24\xEF\xDE\xC4\xA3\x6D\xFA\xD4\x95\x57\x65\x05\x62\xC8\x03\x4F\xB7\x94\x5A\x86\x46\x90\x93\x72\xE8\x21\x97\xB4\xDD\xEB\x11\x59\x2E\x70\x95\x04\x43\x97\xF3\x84\xA4\x95\x61\x81\x96\xA2\x09\x5E\xF9\x5D\xE8\x7E\xFE\x62\x1C\x94\x16\x63\x3A\xFB\x20\xF2\x32\xC9\x9F\x7B\xE5\xDD\xE4\xFE\x39\x7B\x64\x35\x16\xCC\x3A\xAC\xFD\x91\xCD\x36\xBC\x6C\x5B\x64\x7F\xBA\x95\x12\x21\x80\x40\x2A\xC7\x24\x3D\x4B\xAF\x7B\x1D\x2A\x8F\x66\x1A\xBA\x8C\xC9\x38\x0B\x6B\xA5\x09\xD4\x8E\x01\xB8\x9F\x69\x65\x4F\xFB\xBC\xF6\x2E\xF7\xEF\xFB\x1C\xF1\xFF\xBA\x9B\xF6\x40\x67\x1F\x1E\x81\x31\x1C\xE6\x26\xD6\xE6\x85\x87\x9D\x3A\x9E\x2A\x55\x2E\xD2\x57\x30\x4E\x99\x08\x88\xAD\x0C\x78\xB3\xAE\xD0\x6C\x10\x10\x81\x57\x96\x36\x45\x4C\x44\xC4\x2B\x10\xD6\x4B\x71\x94\x1A\x44\x91\xD6\x70\x14\x9A\xDB\x74\x23\x75\x05\xDB\x74\x15\x73\x15\xED\x1D\xC3\x4C\x9C\xE3\xC6\xF2\x73\xEE\xE9\xAA\x6C\xAF\xCE\xE5\x1C\x1B\xCC\x45\xF6\xF8\xB2\x20\xB7\x96\xA2\xDA\x81\x27\x89\x5F\x76\x89\xC2\xC0\x4C\xC7\xEC\x7A\x8B\x89\x58\xEE\x1E\xCB\x14\xA9\xA5\x29\x50\x2B\x06\xD0\xEC\x7E\x1A\x8C\x08\xE6\x6B\xDD\xCF\xBF\x38\xE2\x3F\xA7\xB9\x08\xDB\xB9\xF7\x0F\xB8\xF7\xD6\xDD\x7B\xCF\x0D\xEC\x52\x84\x92\x5F\xDF\x81\xA7\xA5\xA6\x84\x60\x2B\x2A\x84\x74\x37\x3A\xAC\x92\x0D\x6E\x14\xC0\xD4\xF3\x00\x3F\x49\x84\x50\xC4\x08\x42\xD4\x2C\x3D\x54\x5A\x85\x96\xA7\xAD\x18\x6D\xB5\x08\xBD\xE8\xA3\x00\x7F\xED\x04\xF4\xDF\xC7\x1D\x79\x5D\xE8\x88\xFF\xD4\xB3\x2E\xC4\x6F\x0E\xF9\x04\xEE\x88\x4C\x8D\xA2\x5A\x6B\xCB\x2E\x4B\xCB\xF8\x6F\xAA\x7C\x0D\xD6\x2E\xC1\x58\x7D\x29\xE8\x33\x00\x0B\x82\x55\x80\x4E\x37\xFD\xD1\x4D\x9A\xE3\x5C\xF8\xD5\xEE\xF9\x70\x37\xE1\x5E\x9F\x75\xAE\xDA\x0E\x1C\x4D\x1E\x18\x52\x5C\x13\x9C\xD6\x18\xDA\xC1\x4A\xD2\x55\x2C\xDA\x4F\x53\xC5\xE7\x40\x33\x0A\x3C\x08\xAE\xB4\xFC\x88\x3F\xA0\xD2\x65\x1C\xDD\xF7\x64\x5D\x2A\x61\xD4\x91\x18\xC7\xAF\xB5\xAC\x77\x86\x63\xF7\xDF\xCD\xF6\xC7\x75\xAD\xF0\x19\x43\xC8\x5E\xB4\x35\x70\xA5\xBC\x94\x7D\x22\x37\xFC\x9A\x79\x95\xA4\x87\xA5\xB4\x4F\x5D\xDE\x21\x19\x0C\x22\x65\x49\x9C\x64\xD9\x30\xD2\x65\xAA\xFC\x14\x43\x79\x5A\xA1\x56\x0C\x40\x7D\x1C\x74\x29\x3A\xCE\xBE\x45\xAE\xB7\xB6\x75\xBF\x87\x3A\x64\x5F\xE2\x7E\xE7\xB5\xD3\x12\x55\xD6\x0B\x57\xEF\x4C\x3D\x0D\x74\x37\x22\x1D\x63\xEA\xB3\x75\xD0\xA7\xC8\x1C\xB3\x97\x83\xBB\xF6\x2C\xAD\x25\x33\xDA\xAA\x7D\x04\x45\x5A\x84\x5A\x81\xF6\x67\xB0\xF6\x48\x5C\x29\x7F\xB2\xCA\x11\x78\xC8\xCE\x34\x4E\xEC\xAD\x72\xF1\xBF\xC4\x6C\x9C\x78\xC9\x15\xB8\x7A\xAF\x0F\xD1\xCF\x69\xC7\x6C\xE9\x16\x58\xD7\x76\xB1\x7C\x7A\x27\x9F\x36\x21\x74\xB8\xD4\x34\x8A\x3A\xAC\x4D\x42\xD6\x39\x03\x06\xBA\xFC\xDA\x40\xED\x18\x40\xDE\xB9\x13\x70\xA5\x7B\xBD\xC0\x4D\x9E\x1B\xDD\xF3\x4B\xDD\xEF\x2E\xEE\x77\x7D\xA8\xC9\xDE\xD3\x5A\x35\x9B\xB4\x13\xAF\xDE\x39\x7F\xAF\x0E\x90\x3C\x2C\xBF\x0C\x67\x69\x0D\x02\x62\x04\xEF\x37\xC2\xAE\x2B\xE9\xC7\xC6\x44\x9D\x2C\x5E\xE2\x83\xCC\x2E\xD7\xB4\xE7\x13\x7D\x2E\x64\xE7\xA8\xFB\xFD\x83\x7B\x3A\xC9\xFD\x9E\xEB\xA4\xFE\x1D\xA2\x24\x2D\x79\xA1\x6A\xA9\xAA\x56\xCB\xE7\x2A\xDE\xF6\x5E\xCA\x8F\xC1\xFF\xC9\xF5\x7F\xDD\x09\xB5\x00\xB1\x0C\xD8\xDA\xDF\xDD\x5A\xE2\x5B\xCF\x0D\xCF\x06\x54\x25\x96\xF9\x2C\x75\x53\x35\x92\x49\xFC\xF6\xBB\x26\x02\x59\x36\x42\xE9\x56\xE6\x2D\xEC\xDD\x6E\x9C\xA7\x2B\x46\x1C\x74\xBA\x2D\x4C\x6A\xC7\x7C\x05\x51\xC6\x86\x88\x7F\x43\x22\xD2\x45\x86\x7D\xA7\x4F\x33\x44\x58\x4C\x4B\x20\x16\x71\x7B\x3C\x9A\xA1\x7D\x23\xD3\x77\x31\x0B\xB7\x66\x7B\x46\x6F\xE0\x65\x5D\x03\x23\xFD\xDA\x82\x36\x1F\x2C\x26\x54\x95\xA1\xE8\x3D\x0A\xEB\x8A\xC1\xFC\x45\xA1\x56\x0C\xA0\x79\x0E\x46\xDD\xC4\x1A\xF4\x02\x2D\x9B\x18\xB6\x4A\xED\x65\x65\x1E\x6B\xAD\xC2\xB3\x72\x31\xE1\xD0\x2A\x3B\x8A\x30\x96\x98\x66\x41\xF1\x89\x05\x46\x3D\x8D\x91\xB8\x44\x7F\xB0\x7B\xF6\x92\xF7\xF0\x11\xD3\x8A\x95\xE1\x69\x0E\x3E\x7E\xF7\xB8\xBF\xD3\x1C\x39\x9C\x32\xDE\xC4\xB5\x83\x07\xC0\x5F\xC5\x9F\x80\x18\x41\x67\xA2\xC4\x66\x0F\xF9\x52\xC4\x5C\xC5\xCC\xB0\xB6\xFA\xA6\xF2\xC9\x38\x36\xBA\xB5\xD2\x04\x6A\xC5\x00\x9C\x06\x70\xB7\xEB\xA5\x2D\x3D\xA4\x62\xCE\x33\xC3\xF9\xC5\x92\x41\x11\xAA\xB6\xAD\x4B\xC9\x49\x18\x4E\x72\xF3\x8E\x62\x32\x0C\x89\xE4\x65\x97\x04\xEF\xA8\x5B\x4B\xE1\xCC\xBE\xA3\x60\x69\x0C\xCC\x2F\x41\xAB\x53\x5A\x00\xF4\xBB\x28\x0F\x13\x3F\xAD\xC3\x59\x8B\xDD\xEF\xD7\x9C\x2E\xF7\x8B\x6C\x9F\xCE\x17\x75\xF7\x7C\x21\xB2\x4B\xFE\x1C\x48\x5A\x4B\x6A\x7A\x43\x07\xBE\x03\x50\x13\x5B\xD1\x6C\xAB\x0E\x99\x8E\x35\x57\x82\xFE\xD2\x0F\x4B\x63\xA5\x9F\xCC\x31\xE2\x29\x83\xBA\x31\x80\xFD\x5D\x17\x7D\x2C\x1F\xC7\x2B\xDD\xA4\x9C\x41\xE6\x7C\x54\xBA\x16\x44\x4E\x09\xBE\xDB\x5A\xCF\x5E\xEF\x86\x15\x44\xAE\xA7\x46\x66\x55\xC4\xD4\xEF\x0A\xF1\x9E\x0A\x4E\x0A\x8F\xBA\xA8\x95\x8F\xA0\xD2\x55\x59\x3A\xBF\xD4\x60\xA4\xF6\x63\x38\xF0\x00\xBB\x0C\xD2\xDE\xA6\x1B\xBB\xEB\xC6\x47\xF1\xBD\xAC\x81\x9F\x0C\x1C\x48\x1D\x7C\x31\x2F\x78\xAF\x1E\xF2\x5E\xD4\xF3\xC9\x96\xD3\x0B\xC1\x32\x26\x26\x99\x52\x2D\xA1\x5E\x0C\xE0\x62\x64\x4F\x3E\x82\xE7\xAD\x3F\xAF\x7D\x13\xEF\x9B\x31\x8E\xCD\x53\xAA\x2F\x53\xE9\xCB\xF0\x20\x61\xE4\x59\x49\x39\x28\x82\x93\x75\x59\xA7\x06\x99\x2F\x42\xE6\x29\x8B\x4B\xA9\xFD\x8C\xE3\xA9\x30\xCA\x24\x8C\x36\x53\xC5\xA9\x42\x39\x96\xC2\x15\xA0\x35\x80\x3B\x30\x84\x0B\x96\x3D\x8E\x1F\xCF\x3B\x02\xBF\xED\x61\xC8\xAB\xEC\xA4\xD3\x04\xCA\xDC\x91\x52\x53\x60\x5A\x00\x54\xDE\xC9\xDA\xE7\x81\x62\x39\x09\xA8\xD5\x4A\x40\xAD\x18\x40\x01\xF9\x1F\x30\x7D\xF5\xC3\x38\x74\xFA\x0C\xFC\x6B\x3E\x86\x5D\x24\x96\xCC\x0B\x5F\xE6\x53\x84\x18\xD3\x1C\x3C\x47\x9D\xE9\x5D\x44\xC8\x00\x8C\x3A\x11\x29\x86\xA5\x35\xD3\x80\xCF\x70\xAB\xBC\x76\x1A\xC9\x18\xB4\xA9\x11\x31\x77\xCC\xE5\x45\xC0\xD7\x0E\x0C\x7F\x89\x7B\x5E\x9E\xCD\xC1\xD5\x8F\xDD\x8F\xFF\xFA\xDD\x8D\x58\x74\xD8\x27\x3B\x5F\xD4\x4D\xA1\x6D\x84\x5B\x84\xCD\x58\xA5\xD5\x3D\xB9\x51\x5E\x01\xCC\x46\x2F\xC2\x2D\x06\xA3\xA5\xB8\xA5\x31\x54\xF5\x1B\xF4\x19\x40\x0C\x66\x4D\x47\xB6\x72\x75\xA7\x83\xC6\xCF\xC5\x9E\x8D\x99\x18\xCE\x57\xE2\x30\x87\xE8\xDC\x56\x98\x65\x97\x9B\x02\xDE\xF2\x98\x33\x20\x9A\x44\x19\x0E\xD0\xBB\xE9\x83\x22\x14\x51\xC5\xF0\x95\x03\xA0\xD3\xA5\x18\x94\xE5\x10\x65\xEF\xD2\xF4\xB0\xD2\x58\xDD\xA1\x4D\xA9\x7C\xA2\x8C\xAB\x30\x07\x27\x2F\x5C\x84\x5F\xBD\xFE\x38\xDC\x22\xB2\xC5\x26\x78\xC4\xCD\x48\xBB\x05\x08\x89\xDA\xEB\xAE\x44\xD9\x4C\x9B\x00\x38\x7E\x19\xC9\x67\xE9\x69\x29\x46\x13\xAB\xB3\xCF\x00\x2A\xE0\x54\x76\xD0\x85\xC7\x63\xB3\xBD\x76\xC2\x1B\x5C\xE0\xDF\xB9\xD0\x97\x68\xD5\x3A\x2A\xB9\xB5\x5A\xAF\xF3\x48\xA9\x29\x35\x0A\x41\xF0\xA5\x7F\x00\x86\xCD\x4C\x88\x34\xD8\xC4\x23\x9F\x75\x19\x10\x44\xA5\x35\x1B\xED\x90\x64\x4E\x3E\xE1\xCB\x80\x08\x8B\xF5\x51\xD9\x1E\x28\xA6\xA6\x7C\x28\xDE\x32\x67\xD1\x1F\xB9\x53\xF7\x67\xE0\x62\xAC\xC1\x89\xD9\xFE\xB8\xB4\x28\x73\x68\x10\xD9\x9A\xB1\x4A\xEE\x1A\x29\x51\x2D\x86\x60\x49\xE0\x06\x79\x66\xE5\xC7\x8E\x0A\xC7\xF0\xB2\x36\xEB\xC4\x08\xDF\x62\x4A\xBD\x32\xA0\x29\x81\x3A\x32\x80\x16\x04\xEA\x54\x7E\x09\x5E\x93\xAF\xC0\xA7\x1D\xC6\x7B\xB3\x8F\x5B\xC8\xC9\x5A\xBE\x0A\xCF\x78\xA7\x10\xEE\x38\x83\x4C\x47\xA6\xB0\xD6\x26\x24\xF1\xE9\xA5\x41\xCF\x77\xA0\x19\x8C\xC1\x2C\x8A\x4A\x64\x3D\x9A\xB9\x30\x93\xC6\xFB\x55\x7E\x06\xB6\x47\x9F\x69\x45\xDE\x0A\x02\x04\xEE\xB2\xFC\x09\x26\x70\x1E\xA6\xE1\x9B\xD7\xDD\x86\xDF\xBC\xF8\xDD\xE5\xD5\xDB\x96\x37\x45\xF4\x88\x97\x0E\x24\x3D\x23\x66\x26\x75\x99\xAA\xAE\x9D\x6E\xBD\x2C\x17\x5A\xF5\x5B\x12\xDE\x12\x37\xA9\x55\x83\x0C\x21\xFE\xB5\x80\xBA\x31\x00\x36\x20\x13\xB4\x75\x05\xB6\xC7\x72\xBC\x03\xE3\xF8\x6B\x17\xBA\x85\xCC\x68\x2D\xB3\x59\xC4\x2A\xA5\x27\x25\x12\xF8\xD2\x53\x9B\x15\x92\xA0\x3D\xD6\xAF\x18\x07\xF5\xC8\x93\xCE\x2F\x89\xB8\x1B\x11\xA8\xF7\x2A\x83\x29\xDD\x01\xFB\x32\x4F\x25\xED\xCB\x7A\x88\xAF\xC3\x33\x19\x32\xA7\xEE\x0F\x60\x81\xEB\xF7\xF3\x9D\xD4\x2F\x77\xEB\x6F\x38\x0F\xD9\x63\x4B\xA3\xBE\x42\x89\x35\x1B\x57\xA6\x76\x17\x79\xB4\xA6\x60\xA9\xF5\x12\x18\x83\x48\x11\x9D\xC4\x29\x43\x6F\xBB\x08\x63\xED\x60\x8C\xA9\x56\xEA\xBF\x46\xB2\x0E\x10\x73\x04\xB5\xC3\x6F\xFD\x3E\xE6\x6E\xBD\x29\x5E\x33\xD0\xC0\xBF\xBA\xD7\x57\xBA\xBF\x81\xD4\x69\x38\xA8\xC9\xEE\x49\x4A\x56\xB1\x22\x6C\x10\x44\xA4\x9A\xEE\xD5\x05\x9F\xA8\x3C\x0D\x03\xBE\x23\x0E\x0A\x0F\xEF\xEB\x3A\xDD\x32\xD8\x2D\x43\x54\x93\x01\xA7\x22\x0F\x3F\xA9\x6D\xF8\xF6\xFC\x44\x19\x7E\xA3\x1F\x73\x12\x7F\xA1\x23\xFC\x1F\x66\xFB\xE1\xB2\x0A\x63\x57\xA2\x48\xDE\x7B\x1D\x6F\x5D\x96\x2E\x27\xF6\x35\x1E\xBD\xAF\x5F\xDE\xF6\xC3\x76\x1D\xB2\x3A\xAD\x76\x31\xDC\x2D\x7C\x58\xB9\xB5\xD2\x02\xEA\xC6\x00\xCC\x4D\x1B\x73\x66\x20\x5B\xBE\x4A\xD0\xC6\x22\xBC\xC0\xA5\x3E\x26\x1F\xC7\x47\x5A\x7B\x06\x98\xDD\x6E\x1E\x16\x52\xA5\x07\x44\x2A\xE2\x83\x8B\x37\xB4\x1D\x1E\x65\x57\x13\x65\x30\x93\x03\x32\x99\x92\xD4\x99\x2E\x8B\x30\x24\xE6\x68\x2C\xCA\x02\x49\x17\x05\x3F\x4D\x6B\x0C\x2E\xC2\x10\xBE\x7C\xED\x12\x5C\xF1\x92\xE1\xF2\xFB\x7A\x78\xD6\xFA\xC8\x1E\x7E\xD2\xCB\x15\x93\xBA\x0D\x91\x8E\xE5\x61\xE9\x18\xB6\x8C\x78\x98\x99\xC1\x60\x6D\x76\xF5\x59\x87\x81\x72\x70\xE2\x97\x4C\xC6\x82\x5A\x69\x01\x75\x63\x00\x05\x44\x37\x85\x3C\x77\x33\x64\x77\x3C\x80\xFC\xF1\x85\x98\x3F\x7F\x0E\xDE\xE9\x82\xDE\xEC\x12\xBE\xAC\x68\x50\xF4\xCE\xB9\x2E\x04\xE1\x84\xC8\xB4\xDA\xCF\x4E\xCE\x01\x11\xFA\x62\x4E\x3B\x20\x74\x3A\x2A\x3C\x82\xFB\x0C\x08\x4E\x55\x37\x00\x29\xCF\x7D\xD0\x16\xE5\x9C\x1C\x75\x0C\xE8\x2A\xD7\xFB\x0B\xC7\xC6\x70\xC6\xB4\x83\xB1\xA4\x95\x7E\xFD\x39\xC8\x9E\x5C\x8E\x7C\xB6\x63\xC2\x2B\x56\xE9\xD2\x29\x81\xC5\xF6\xC3\x4F\x85\x04\x8C\x6D\xD2\x81\x08\x67\x3B\x14\x19\xF3\x62\x0C\x00\xB0\x77\x03\xD6\x16\xEA\xCA\x00\x62\xB8\xB6\x3B\xBE\xF5\xF5\x97\x23\x77\x47\x7E\xEA\xC7\x9D\x9C\xCA\xB0\x8B\x0B\xFA\x88\xFB\xDB\x07\xDD\xE5\x42\xCF\x1C\x00\x2A\x2D\xFF\xB5\x1F\x35\x11\x29\x22\x09\xD2\x58\xBE\x5F\xA6\x05\x88\xF8\xC0\xE1\x26\x89\x5D\x32\x19\x53\xB7\xB7\xDB\x90\x02\x86\xAA\x83\x47\xDD\xC3\x09\x2E\xE0\x64\xF7\x7B\xBB\xB3\xF5\xD7\x74\x93\x59\x5A\x59\x51\x54\xEA\xB8\xAC\xC9\xC8\x45\x7A\x4B\xED\x06\x6C\x62\xAA\x62\xDB\xEB\x63\xBB\x16\x43\x4A\xE1\x18\x03\xAD\x95\x54\xF5\x23\xD4\x02\xEA\xCA\x00\x2C\x4E\x5D\xBC\x07\x1D\x9C\x9F\x8F\x8D\x30\xE6\x4C\x02\xE0\x1F\x5C\x82\x9D\x00\x3E\xA2\x94\x76\x04\xF1\x69\xCF\x7B\x11\xDF\xCE\xAB\xED\x65\xF9\xAC\x35\x08\x51\xB9\xB7\x0B\x50\xE4\x61\xF8\x48\x1B\x5F\x6A\x25\xB2\x23\x7A\x1A\x34\xCD\xC0\xB4\x9F\x24\x73\x76\x7E\x8E\x33\xC6\x1C\xE1\xDF\x76\x1F\x2E\x7B\xFE\xDF\xD3\x0F\x6B\x56\x55\xE9\x75\x7A\x56\x4E\x0E\x5B\x73\x58\x17\xC0\xCC\x0B\xA6\x9E\x6B\x9F\x80\x9E\x57\xD6\x75\x63\x29\x29\x6F\x99\x16\xB5\xD4\x0C\xEA\xC6\x00\x7A\x3A\x54\xD1\x68\xA0\xD1\x6C\xA2\x79\xD4\xAB\x91\xFD\xE2\x32\xE4\x7F\xFC\x06\x06\x5E\xFE\x42\xEC\x81\x51\x7C\x32\x6F\xE2\xD5\x6E\x72\xB7\xBF\x07\x90\x3A\x2E\x1C\x74\x86\xE1\xFD\x0F\x02\x88\xF7\xDC\xA3\x31\xA1\xEA\x07\x57\x8D\x65\x61\xDD\xE6\xC5\x20\x44\xBD\x67\x04\x9D\x5C\x90\xEB\xC6\x75\x97\xFD\x56\x61\x10\x37\x60\x1C\xDF\x77\x3A\xD4\xA9\xD9\x3E\x78\x38\x32\x2E\x8C\x4F\xA5\x24\xA7\xE5\x08\xB3\x0E\xEA\xA4\xA4\x33\x9B\x1B\x96\xAF\x00\xAA\x8C\x5E\x09\x6F\xB2\x7E\x83\xFF\x73\x50\x37\x06\xD0\x82\xC9\x76\x7E\xA9\x29\x3C\xF8\x53\x6C\xB5\xC9\x06\x78\x97\x7B\x7B\x87\x7B\xDD\x22\xD8\x06\xAB\x5A\x4E\x89\x4B\xF7\x8E\xF2\xE2\x33\xC2\x0F\xDE\x7B\x31\x43\xA0\xEA\x52\x5A\x08\x75\x66\x5A\x66\x8B\x4A\xA3\xE2\x73\xB4\x36\xF3\x4C\xC3\x89\x2B\xD7\xE0\x27\xB3\x0F\x6A\x5F\xB6\x8A\xDD\x77\x44\x76\xF9\x0D\x51\x5B\x58\x4B\x4E\x8B\xF8\xB5\xFD\x9C\x72\xB2\xC9\xF7\x54\x7A\x80\x4B\x77\x56\xB7\x84\xD4\x71\x63\xEB\xE4\x20\x6B\x6F\xEC\x4B\x42\xA8\x58\x4F\x6D\xA0\x8E\x0C\xA0\xC0\x8B\x75\x58\xD1\xF9\x4C\x5D\x6B\xDD\x24\x9B\x17\x37\xC9\xE6\x57\x62\x0E\x56\x62\x5F\x67\xC9\xBE\xCF\xA5\xDC\xD3\x05\xCD\x60\x02\xB1\x12\x54\xC8\x18\xBB\xCC\x23\x28\x22\x52\x5E\xAC\x2A\xF3\x44\x9F\xA1\x1D\x90\x6B\xB9\x1E\xC0\x00\x2E\x70\xC4\xFF\xA3\xE5\x2B\xF0\x9B\xB9\x87\x60\x6C\xDA\x00\x1A\xA3\xE3\xDE\xDA\x3C\x53\x7D\x63\xA8\x4A\x13\x8D\xE5\xD1\x1E\x12\x7D\x9C\x57\xAB\xE5\xBA\x8E\x22\x6D\x53\xE5\x41\x24\x9F\x56\xD5\x65\x9B\x2C\x6D\x26\x66\xB2\x58\xED\xD7\x69\xFF\xCF\x1D\x09\xAE\x1B\x03\x88\xAD\xB9\x5A\x6B\xB8\x2C\x7D\x09\xCB\x7E\x89\x17\xCC\x99\x85\xB7\xBA\xC7\x77\x39\xB3\xE0\x59\x72\x09\xAE\x28\x59\x2F\xE7\x79\x76\x38\x42\x89\x4E\x55\x75\x4C\x60\x12\x73\x22\x5A\x3B\xFF\xA4\x83\xD0\x5B\x9E\x2C\x92\xB3\x96\x5A\x9E\x7F\x4C\xE0\xD8\x4D\xB6\xC2\xFD\x73\xDD\xE8\x28\xBE\x33\xD6\xC4\xCF\x66\x1D\x16\xEC\xE2\x63\xC0\x08\x9C\x8D\x17\xBB\x1F\x4F\x8F\xA7\x2E\xB7\x00\xF6\xED\x3D\x5D\x7F\xCC\x6C\xD0\x75\xE9\xB9\x11\xFB\xE0\x27\x9B\x3F\x86\x0B\x97\xF5\x7C\xD4\xC5\xC4\xE6\x6F\x9E\xC8\x3B\x25\x50\x37\x06\xA0\x77\x65\xB1\x8E\xD2\x16\xAE\x66\x0C\x65\x9A\x6D\x37\x07\x6E\xBD\x1F\xF9\xC8\xAF\x31\x34\x63\x26\x86\x9D\xBD\xDB\x39\x4F\x40\x4A\x2C\xBC\xEE\xED\x1F\xA2\xD3\x07\x4B\x69\x22\x9D\x27\x8D\x49\xC7\x4A\xCF\x7E\xF4\xEA\x6D\xC5\x84\xD8\xF2\x61\x4C\xED\x37\x3E\xD2\x71\x0F\x66\xE2\x5B\xCE\xCE\x3F\x23\x7B\x15\xAE\x17\xC9\xB3\x59\xD3\x81\x95\xAB\xBD\xDA\xB3\xC4\x6F\x2F\x10\x63\xCE\xCC\xB1\x1B\x4B\xC7\xE2\x35\x51\xC5\xCC\x12\x8D\x93\xEE\x71\x7D\xDD\x38\x9B\x5F\xB1\x36\x59\xEB\x34\x79\x22\xDF\x94\x43\xDD\x18\x80\xEC\xC8\xD4\x4E\x2F\x9D\x27\x33\xCA\x6B\xA7\xBD\xED\x7F\x31\xB4\xF9\x86\x78\xE5\x8C\xE9\xF8\x07\x97\xBA\xF5\x4D\x81\xF9\xDE\x9A\xBE\xF4\xDA\x17\x99\x35\x21\x76\x23\xF4\x2D\x39\x72\x78\x83\x9B\x79\xB4\x26\x61\x4C\x81\x92\x01\x69\xFF\x43\xE1\x0F\x40\x58\x9E\xA7\x5D\x40\x3C\x77\x7E\x1F\xCC\x06\x71\x3E\x66\xE1\xB4\x3F\xFD\x09\xA7\xEF\xFC\x5E\xEF\x2E\xBE\x2A\x04\x07\xC4\x27\xB5\x55\x8E\x25\x45\x7B\x25\x56\xAB\xDE\x98\x56\x91\x92\xB4\x5A\x53\x61\x0B\x33\xA8\x10\xD7\x4B\x9A\x58\x5F\x4D\x39\xD4\x8D\x01\x14\x10\x3B\x9C\xD1\xCB\x5D\x70\x81\x63\x29\xBF\x14\x1B\xE7\xCB\xF1\x36\xD7\xF2\x61\xD7\xF8\xED\x3D\x55\x59\x2F\xE5\x89\xDA\xCB\x19\x9D\x19\x54\xA2\x09\xB3\xDB\xBB\xC1\x8D\xBA\x45\x92\x4C\xCD\x1E\x45\xC4\xA5\x89\xA0\x4D\x02\xCD\x58\x72\x51\xE5\x84\xE3\xF0\x7A\x67\xE7\x1F\xFF\xD8\xE3\x38\x6D\xA3\xD7\xA3\xD8\xB7\x67\xD9\xF6\x96\x2A\x2C\xE3\x58\x9A\xD8\xBE\x7E\x81\x0D\x7D\x86\xCA\x1B\xC3\x87\x39\xEA\xB4\xCF\x82\x09\x84\x5E\xBF\x1A\x54\x95\x01\x30\x81\x13\x33\x21\x34\xCE\xBA\xBC\x29\x85\xBA\x33\x80\x2A\xEA\xA3\xD5\x1E\x53\x85\xCD\xAF\xC4\x74\xAC\xC6\x2E\x58\x8E\x8F\xBB\x98\x83\x82\x52\x72\xA3\x44\x99\x24\x57\x51\xA2\xA6\xC0\xA7\x20\x89\x1B\x82\x80\x49\xF9\xC9\x3B\xF7\x19\xA9\x15\x38\x37\x70\x25\x5A\x17\x71\x66\x58\x74\xEF\x23\x58\xBC\xE5\x5B\xD0\xDC\x7E\x0B\x64\x37\xDF\xEB\xE5\x8E\xB5\x2E\x66\x17\xB3\x31\xB2\xEE\xDC\x4F\xDD\x91\xAF\x7B\x39\x45\x10\xDA\x89\xA7\x19\x0D\x44\x7C\x43\xA5\x5B\x1B\xDB\x9D\x6D\x66\x62\x07\xD5\x24\xD3\x01\xD2\xBE\x90\x3E\x03\xA8\x88\x9B\x25\x35\xAC\x5D\x5E\x96\xC4\xA2\x4B\x53\xF9\x22\xEC\xE8\x42\xDE\x95\x8F\xE3\x4D\x8E\xE8\x36\x63\xB6\x7A\x3B\x1D\xB3\xBD\x85\x9A\x5F\x86\x83\x48\x76\xF8\x69\x84\x63\xCE\x8B\x4F\x5E\xDC\x09\x1F\x2F\xD5\x31\x4F\x61\x00\xA7\x8E\xAC\xC4\x37\x9A\x4D\xFC\x79\xCE\x11\x18\x8F\xF4\x65\x2F\xFD\x1E\x03\xE6\x59\xD7\xE6\x19\x1B\x3B\x6D\x02\x54\x35\x3B\x52\xC4\xAB\xEB\xB0\x24\x7A\x15\x06\x90\xEA\x03\x66\xF3\x33\x27\x35\xEB\xAB\x5A\x41\x9D\x19\x40\x0A\x62\x3B\xB5\x64\xFB\xA2\x76\xEC\xD2\xD3\x30\x6F\xEE\x5C\x1C\xE8\x2C\xE4\xF7\xB8\xD8\xBD\xCB\x58\x2D\xD1\x21\x72\x2A\x2F\x3D\xDB\x21\x18\xFD\x34\x98\x0C\xB2\xBC\x17\x82\x11\x15\x26\x86\xAE\xCB\x41\x6B\xBB\xEE\x99\x4E\x9F\xF9\xE1\xD8\x08\x2E\x9B\x76\x10\x1E\x21\x7D\x04\xD8\x6B\xE7\x31\xBF\x89\x66\xAE\xCC\x4B\x2F\xEB\x61\x27\xF0\x64\x99\x5A\x22\xC7\xB6\x18\x33\x5C\x62\xAB\x0D\xBA\x9E\xD8\x5E\x01\x9D\x16\xA4\xEC\xD4\x76\xE6\xD8\x7D\x83\x16\xD4\x6A\xF9\x4F\x22\x5D\x37\xA8\xD2\xF9\x05\x54\xD9\xEB\x1D\xAB\xA3\x0D\x77\x9E\x84\xC6\x56\x9B\xE3\xF9\x2E\xE4\x1D\xEE\xEF\x2D\x2E\x68\x0B\x59\x48\x6C\xCD\x48\x82\xA5\x9D\xEB\xF8\xA0\x6C\x25\xF1\x69\x3E\xBF\xD0\xD5\x2E\xCF\xF5\xD9\x20\x16\x36\x47\x71\xEA\xC0\x41\xB8\x6D\x1D\xF5\xFB\xBA\x92\x52\x8C\x19\x57\xCD\x27\xBB\x67\x5D\x42\x4C\x4A\x57\x25\xCE\xC9\xE0\x37\xD9\xBA\x9E\x16\xA8\x23\x03\xD0\xB8\xC5\x24\x7C\x6A\x7D\x38\xB5\x63\x0C\xF3\xE7\x20\x7B\xDE\x66\xC0\x55\xB7\x20\xBF\xF8\x78\xCC\xD9\xE3\xA5\x78\x7B\x36\x8A\x7F\x76\x95\x3E\xCF\xDB\x0B\x40\x96\xDD\x0A\xE4\x52\xC4\xAE\xF3\x07\x8C\x42\x6A\x15\xA2\xB1\xDA\x7C\xE8\xE6\x7F\xDC\x05\xFE\xCA\xA9\xFA\xFF\x7D\xF5\xAD\xB8\x65\xD7\xF7\xB5\x3F\xA3\xA6\xFB\xAB\x97\x6D\xBA\xB2\x4F\x26\xC3\x00\x52\x63\x10\xB3\xAF\x2D\xC7\x5E\xAC\x0E\x59\x6E\x4C\xED\x66\x65\x68\x93\x45\x9B\x87\xA9\xBD\x06\xB1\xB2\x81\xF8\x72\x61\xAD\x08\xBF\x80\x3A\x33\x80\x75\x05\xB1\x5D\x5E\xE5\x80\x39\xE2\xCA\x1C\x91\x35\xCF\xFE\x77\x4C\xFF\xAB\x9D\xB1\xD3\xB4\x01\x7C\x30\x6F\xE2\x60\xD7\x43\xF3\x4B\x29\x0D\x63\x49\xCF\xB2\x20\x8D\x25\xBA\x22\xAD\xF6\x35\xD0\x32\x26\x9E\x97\xE6\xAD\xEF\x25\x02\xDF\x79\xF4\x29\x5C\xF1\xCF\xDF\xC3\x13\xA7\x5C\x08\x8C\x37\x3B\x65\x8C\x8D\x7B\xB9\xAB\x1C\x59\xB5\x56\x04\x58\x7A\x4D\x6C\x52\x9D\xD7\xDB\x6E\x75\x39\x96\x7D\x2F\xC7\xA0\x8A\xD3\xD0\x52\xD3\xAB\xE0\x1F\x33\x1D\x52\x1F\xFB\x8C\xAD\x4A\x68\x6D\x54\xE3\x6C\x31\x9B\xDA\xC0\xFF\x05\x06\xA0\x6D\x35\xCB\x76\x63\x93\x8E\xA5\x93\xEF\x2C\x7F\xFB\x77\xF1\xB7\xB0\xF5\x4E\xCF\xC3\x61\x03\xC0\xFB\xDD\xEB\x56\x2E\x74\x9A\x77\xB3\x4E\xD7\x3B\x1F\xBB\x66\xAB\x58\x9A\x63\x9A\x80\x36\x01\xCA\x34\x9A\xC1\x64\x6D\x3B\xFF\x56\x4C\xC3\xCF\x30\x86\xEF\x67\xFB\xE3\xAE\x83\x77\x45\x76\xD6\x95\xD1\xFD\x12\x31\x29\x1A\xBB\x7F\x8F\xA5\x97\x63\xD0\xCB\xC7\x33\x7A\xD5\xE0\x62\x79\x7B\x39\x40\xC4\xDA\x9B\xBA\xAC\x63\x5D\x9B\x00\xB1\x25\xD6\x5A\x41\xDD\x18\xC0\xBA\x3A\xB9\xC5\x9C\x4E\x3D\xC3\xF2\x5F\x22\x9B\x3D\x1B\x7B\xB8\xC7\x77\x3B\x6D\xE0\xCD\xAE\xC0\x81\x20\x91\x92\xA1\x96\x49\x50\xC6\xB1\xC5\x49\xBD\x3C\x38\xC1\x4C\x1E\xCD\x06\x70\x52\x3E\x8E\x13\x6F\xB9\x0F\x37\xEE\xF0\x77\xA6\x04\xB5\xD6\xE8\x99\x0A\x5A\xF5\x73\x57\xA9\x3A\x62\x04\x3D\x19\x1F\x40\xAC\xDB\x52\x6A\x7A\x4C\xE5\xAE\x9D\xD4\xAD\x13\xD4\x8D\x01\x14\x38\x31\x8F\x6A\x4E\xE2\x24\x19\x55\xB9\x26\x5A\x6A\x05\x7A\x69\x49\xF6\x45\x73\xEE\x4C\x34\x96\x8D\x74\xF2\xAD\xFA\x35\xB6\x6A\x7D\xA4\xC4\xBD\x1D\xE2\xFE\xB6\x94\xAB\x00\xB1\xDB\x7A\xBD\x4A\xC8\x5E\x00\xA8\xB4\x62\x69\xB1\xB5\x77\x7F\x11\x66\xE3\xD4\x27\x1E\xC4\x39\x1B\x1C\x8D\xA7\x04\x6E\xD6\xC6\x97\x5E\xFB\x38\xB5\x64\x56\x4B\x89\xB5\x0E\xDA\x6B\xBD\x23\xD1\x27\x93\x29\x33\x4F\x3C\x4F\x39\xD4\x8D\x01\xA4\x24\x87\x24\x60\x20\x24\x04\x4D\xEC\x05\xA4\x36\xB8\x30\xA6\xE0\xA5\x5F\x73\x36\xA6\x3B\xCA\x3B\x6C\x60\x3A\xFE\xD9\x29\xE5\x3B\xBB\xD8\x69\x49\x69\x1F\x69\xA8\xB1\x62\xD0\x52\xF7\x6F\x71\x01\x27\xAF\x19\xC5\xD7\xA7\x1F\x82\xA5\x45\xC4\x76\xCF\x46\xE6\xB4\x00\xB6\xF6\x2C\xFB\x21\xD6\x66\xE6\x24\x64\x92\xB3\x8A\x13\x11\x46\x5E\xCD\x07\xAD\x7C\x2C\x4F\x15\xC7\x65\xAA\xBD\x1A\x07\xD9\x9E\xD8\xC7\x47\x2D\x1B\x1F\x15\xF3\x00\xDC\x64\x92\x69\x27\xEB\x60\xFC\x8B\x42\xDD\x18\x40\xEA\xFA\xA9\xE4\xBA\xBE\x11\x56\xA5\x2C\x0B\x9F\xFC\xBD\x87\x03\xDF\xFC\x55\x27\xED\xB2\xD3\xB1\xED\x9C\x67\xE3\x58\x47\x9A\x6F\x73\xE4\xFA\xAC\xE8\xBA\x1F\x78\x1C\x4D\xDE\xC0\x13\x98\x83\x1F\x38\x5B\xFF\xFB\xD9\x2E\xB8\xB6\x15\x74\x80\x63\x33\x8B\xAE\x36\x27\x9C\x36\x73\x64\x91\x6C\xCD\xDE\x5A\xC5\x4C\xF5\x93\x0E\x63\x2D\xD4\xF5\x56\x59\x31\x65\x79\x2C\xAD\x4C\x6B\x7F\x3A\x5E\xD7\x67\x31\x37\x4B\xDB\xD1\xFD\x94\x1B\x71\x3A\x5F\x15\x33\xA7\xEF\x03\xE8\x11\x1F\x46\xCC\x40\x9A\x01\x54\x55\xDB\x8A\xF4\xA9\x25\xAB\xF6\xF3\xE0\x00\xB2\xB1\x71\x34\xA7\xB9\xDF\xE2\xDC\xFC\xF1\xEF\xC5\x9C\xC3\x77\xC1\x51\xDB\x3C\x07\x1F\x71\xF6\xF9\x0B\x33\x3D\xED\x82\x35\x40\xC4\xE4\xC8\x63\x98\x81\x0B\x30\x8A\xD3\xBF\xF7\x6B\xFC\xFA\xDD\xFF\xDD\xD9\xBB\xFF\x96\x7D\x90\xDD\x78\x37\xF0\xA7\xDB\xA2\x1B\x70\x62\x0C\x90\x61\x54\x65\x12\x56\x19\x03\xAB\xEC\xA4\x25\x64\xC4\xB1\x65\xB4\xAA\x4C\x2B\xB6\x0A\xCB\x56\x05\x2C\xC6\x18\x1B\x41\xAB\x4E\xAD\x29\xA4\x18\x58\xED\x98\x40\xDD\x18\x80\xC6\x8B\x39\xBD\xA4\xC4\x63\x9C\xDA\x92\x7E\x56\x59\x3A\x9D\xCE\x23\xF3\x7A\x4C\x23\xFF\x1D\x76\xC7\x08\x3E\xE8\x34\x81\xC3\x5C\xAA\xE9\xDE\xBA\x3E\x43\xB2\xFB\x52\xA6\xCB\xF0\xDB\xD6\xE5\x1C\x97\xFE\x09\x67\xEE\xF9\xA1\xF2\x4A\x2E\x4B\x7D\xB4\x26\x10\x9B\xC0\x6C\x62\x56\x5D\xA3\x8F\x31\x00\x2B\x6D\x8A\x88\x7A\x61\x0E\xAC\x1E\x18\x75\xC6\x4C\x3B\xB6\xF7\x03\xB0\x57\x1D\x72\xA3\x7C\xAB\x1F\x34\x9E\x29\x5D\x30\xD6\xA6\x29\x83\xBA\x31\x80\xD8\x11\xE0\x02\xAC\x4B\x1D\xAD\xF5\x5A\x9D\xCF\xBA\x83\x5E\x13\x79\x4C\x5D\x2C\x09\xEC\xF1\x9F\x63\xAB\xF9\x9B\x63\x7F\x2C\xC3\x87\x5D\xEA\xED\xAC\xD5\x00\xC5\xA9\xAE\x73\xB5\x9C\x85\xB9\xF8\xC9\x0D\xD7\xE1\xBA\x17\xBE\x8B\x32\x1A\x8D\x63\x51\x67\x95\x4F\x5D\xAD\xCD\x92\x5B\x2F\x0E\xB0\xAA\xCE\xAD\x2A\xE9\xAA\x9A\x28\x55\xD3\x5B\x1B\xC3\x98\x36\x35\x19\x75\x3E\x86\x9F\xD5\xC6\x5A\xD9\xFF\xB2\x41\x75\x81\x2A\x52\x4E\x12\x3D\x10\x4E\x00\x88\x70\x76\xA9\x24\x4B\x67\x49\x23\x4D\x74\x96\xD4\xC1\xE8\xD9\x38\x7A\xB0\x81\xF7\xBA\xC7\x57\xBB\xBF\x21\x59\x5A\xB1\xFC\xE7\xFE\x5F\xE6\xB4\x80\x73\x31\x80\x13\xC6\x47\xF1\xFB\xC1\x83\xCA\x5D\x7C\x40\x38\x09\x99\x04\x92\x36\x30\x53\x69\x63\xFD\x96\x93\xFC\xBA\xEF\xF4\x12\x9E\x75\xC7\x9E\x26\x66\x8B\xF9\x5A\xAB\x0B\x99\x2A\x37\x85\x53\x43\xD5\xAD\xE7\x40\x4C\xED\x2E\xCA\x00\x89\x07\xA9\x33\x76\x8B\x90\xEE\xEF\xD8\xF9\x8A\x98\x19\x55\x1B\xA8\x1B\x03\x60\xB8\x59\x9C\xB4\x05\x6C\x72\x42\xE5\x8B\xA9\x83\x79\x24\x6F\x95\x0F\x5E\x94\xE9\xC7\xCF\xC6\x60\x63\xBA\xD3\x00\x46\xF1\x6E\xF7\xFE\x26\xF7\xB7\x99\x4A\x73\x89\xCB\xFD\x4D\xCC\xC7\xA5\xBF\xF8\x15\xEE\x3F\xFA\xB8\x40\x52\x59\x0E\xD0\x2A\x8E\xCA\xA7\x4B\xAA\xC4\x88\x40\xB7\x85\x39\xEB\x52\xFD\x5B\x05\x26\x9B\x2F\x26\xE5\xAB\x5E\xEC\xA9\xF1\x47\x0F\xF9\xAA\x68\x70\x4F\x3B\xD4\x99\x01\x30\xA8\xBA\x5F\x7D\x32\x9E\xD7\x75\xE2\xAD\x1D\x3B\x1B\x1B\x0C\x34\xB0\x4F\x9E\xE3\x43\x59\xEB\x6B\x45\x19\xEE\x72\x7F\xA7\xAE\x5A\x83\x53\x96\xDC\x83\x1B\x5E\x7A\x6C\xB4\xFC\xAA\x1F\xBB\x90\xCF\xB1\x8D\x3D\x56\x7A\x26\x7D\xD9\x32\x9B\x55\x8F\x55\x97\xCC\xCB\xE6\x16\xD3\x2C\xAC\x3D\x1A\x96\x06\x17\xDB\xE0\x93\xBA\x46\x5C\xE3\xC2\xDA\xCB\xD2\xB1\xF6\x56\x19\xAF\x5A\xAF\x00\x48\x04\xEB\x02\xEB\xFA\x0E\x77\xA6\x46\xA6\x8E\xBA\x5A\x79\x8A\xBA\x18\xC1\xC8\x34\x78\xF0\x64\x4C\xDB\x64\x03\xA7\x0D\xE4\xD8\xC3\xE5\xF8\xF3\x9A\x51\x5C\x3D\xFD\x10\x8C\x48\x7C\x1B\x0D\x64\xCD\xA6\x39\x01\xD9\x12\x5F\x6D\xD7\x92\xFF\x0F\x81\x25\x40\x62\x67\x0C\xD6\x46\x6B\xC0\x3A\xCC\xF7\x17\x81\xBA\x31\x80\x3E\xF4\xA1\x0F\x4F\x23\xF4\x19\x40\x1F\xFA\xF0\x0C\x86\x3E\x03\xE8\x43\x1F\x9E\xC1\xD0\x67\x00\x7D\xE8\xC3\x33\x18\xFA\x0C\xA0\x0F\x7D\x78\x06\x43\x9F\x01\xF4\xA1\x0F\xCF\x60\xE8\x33\x80\x3E\xF4\xE1\x19\x0C\x7D\x06\xD0\x87\x3E\x3C\x83\xA1\xCF\x00\xFA\xD0\x87\x67\x30\xF4\x19\x40\x1F\xFA\xF0\x0C\x86\x3E\x03\xE8\x43\x1F\x9E\xC1\xD0\x67\x00\x7D\xE8\xC3\x33\x18\xFA\x0C\xA0\x0F\x7D\x78\x06\xC3\xFF\x07\xA4\x22\xBD\xFD\x06\x72\xA2\xBE\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"])

google_act_icon = idaapi.load_custom_icon(data=google_icon_data, format="png")
baidu_act_icon = idaapi.load_custom_icon(data=baidu_icon_data, format="png")
bing_act_icon = idaapi.load_custom_icon(data=bing_icon_data, format="png")                     

class GoogleSearchHandler(idaapi.action_handler_t):
    def __init__(self):
        idaapi.action_handler_t.__init__(self)
        
    def activate(self, ctx):
        os.system("START http://www.google.com/search?q=\"" + highlight + "\"")
        
        return 1
        
    def update(self, ctx):
        return idaapi.AST_ENABLE_ALWAYS

class BaiduSearchHandler(idaapi.action_handler_t):
    def __init__(self):
        idaapi.action_handler_t.__init__(self)
        
    def activate(self, ctx):
        os.system("START https://www.baidu.com/s?wd=\"" + highlight + "\"")
        
        return 1
        
    def update(self, ctx):
        return idaapi.AST_ENABLE_ALWAYS        

class BingSearchHandler(idaapi.action_handler_t):
    def __init__(self):
        idaapi.action_handler_t.__init__(self)
        
    def activate(self, ctx):
        os.system("START https://cn.bing.com/search?q=\"" + highlight + "&ensearch=1" + "\"")
        
        return 1
        
    def update(self, ctx):
        return idaapi.AST_ENABLE_ALWAYS           

google_action_desc = idaapi.action_desc_t('search:google_action',
                                   'Search Google for \"\"',
                                   GoogleSearchHandler(),
                                   None,
                                   None,
                                   google_act_icon)
                                   
baidu_action_desc = idaapi.action_desc_t('search:baidu_action',
                                   'Search Baidu for \"\"',
                                   BaiduSearchHandler(),
                                   None,
                                   None,
                                   baidu_act_icon)    
                                                                  
bing_action_desc = idaapi.action_desc_t('search:bing_action',
                                   'Search Bing for \"\"',
                                   BingSearchHandler(),
                                   None,
                                   None,
                                   bing_act_icon)                                                                    

idaapi.register_action(google_action_desc)
idaapi.register_action(baidu_action_desc)
idaapi.register_action(bing_action_desc)

class Hooks(idaapi.UI_Hooks):
    def populating_tform_popup(self, form, popup):
        global highlight
        
        if idaapi.get_tform_type(form) == idaapi.BWN_DISASM:
            #ida 7.0
            #highlight = idaapi.get_highlight(form)
            #ida 6.8 higher
            highlight = idaapi.get_highlighted_identifier()
            if highlight:
                idaapi.update_action_label("search:google_action", "Search Google for \"" + highlight + "\"")
                idaapi.attach_action_to_popup(form, popup, "search:google_action", None)
                idaapi.update_action_label("search:baidu_action", "Search Baidu for \"\"" + highlight + "\"")
                idaapi.attach_action_to_popup(form, popup, "search:baidu_action", None)
                idaapi.update_action_label("search:bing_action", "Search Bing for \"\"" + highlight + "\"")
                idaapi.attach_action_to_popup(form, popup, "search:bing_action", None)



class SEARCH(idaapi.plugin_t):
    flags = idaapi.PLUGIN_PROC
    comment = "Search Google for it"
    help = "Search Google for it"
    wanted_name = "Search Google for it"
    wanted_hotkey = ""

    def init(self):
        self._hooks = Hooks()
        self._hooks.hook()

        return idaapi.PLUGIN_KEEP

    def term(self):
        pass

    def run(self, arg):
        pass
        
def PLUGIN_ENTRY():
    return SEARCH()


