"""

=======================================================================
WARNING: PYSHEETDATA IS NOT SECURE AGAINST MALICIOUSLY CONSTRUCTED DATA
=======================================================================
it is intended to be used only with trusted data.

note on file names:
    file names including ' : [ or ] are likely to mess things up, as
    they tend to do to other spreadsheet programs as well (due to
    the way file names and references are annotated in the xml file)

given a ods file -
    extract
    parse contents file
        for each instance of cell name:
            add cell to list
                get contents_string
                from string:
                    get value
                    get raw_formula
                    get formula from raw_formula
                        (use brackets to find reference)  - (so much easier)
                    get xy ref
                    get a1 ref
    return library or file

scripting variables:
    cells[spreadsheet reference] - gets a cell object, or matrix of objects
    sheet.rows[y]
    sheet.columns
"""

import zipfile
import lxml.etree as etree
import os.path as path

import eval.storage as storage
import eval.parser as parser
import script

class SheetDataError(Exception):
    pass

class LibComponent:
    """
    abstract library component class, sub-classed by cell, sheet, book, lib
    """
    def __init__(self):
        self.parent = None
        self._settings = {}
        self._sheet = None
        self._book = None
        self._lib = None

    def __str__(self):
        return '%s %s' % (self.class_name, self.identifier)

    @property
    def identifier(self):
        raise NotImplementedError('LibComponent should only be inherited from')

    @property
    def class_name(self):
        return self.__class__.__name__

    @property
    def inc_set(self):
        return self._settings.get('inc_set', True)

    @property
    def included(self):
        if all([parent.inc_set for parent in self.parents]):
            return True

    @property
    def parents(self):
        # returns list of parent row, column, sheet, book, lib
        return [getattr(self, parent_s) for parent_s in
                ['row', 'column', 'sheet', 'book', 'lib']
                if getattr(self, parent_s) is not None]

    #######################
    # parent object getters
    # iterates through hierarchy in order and attempts to find
    # appropriate instance

    @property
    def row(self):
        try:
            return self._row  # only cells have this attr
        except AttributeError:
            raise NotImplementedError('%s does not have a row parent obj'
                                      % self)

    @property
    def column(self):
        try:
            return self._column  # see above
        except AttributeError:
            raise NotImplementedError('%s does not have a column parent obj'
                                      % self)

    @property
    def sheet(self):
        return self.get_parent('Sheet')

    @property
    def book(self):
        return self.get_parent('Book')

    @property
    def lib(self):
        return self.get_parent('Library')

    @property
    def library(self):
        # backwards compatibility, hurrah.
        return self.get_parent('Library')

    @property
    def file(self):
        return self.get_parent('Book').file

    @file.setter
    def file(self, file):
        self.get_parent('Book').file = file

    def get_parent(self, hierarchy_s=None):
        # return parent in hierarchy of name 'hierarchy_s'
        # if none, returns direct parent of inst.
        if self.class_name == hierarchy_s:
            return self
        parent_attr = getattr(self, '_parent', None)
        if hierarchy_s is None:
            hierarchy_s = 'parent'
        if parent_attr is None:
            raise NotImplementedError(self.class_name + ' does not have a ' +
                                      hierarchy_s)
        if hierarchy_s is None:
            return self.parent
        else:
            return parent_attr.get_parent(hierarchy_s)

    def ns(self, string):
        # returns namespace instance for lib comp
        return self.file.map.ns(string)

class Cell(LibComponent):
    # in some sheets there are going to be a LOT of these, should be
    # coded as such.
    # 78,000 plus in some sheets that I'll be using this for,
    # and I'm sure others will have far more
    def __init__(self, cell_data, position, sheet, mode='standard'):
        super().__init__()
        self.mode = mode
        # changing mode allows different amounts of data to be stored
        # for each cell. speed vs memory usage
        self._cell_element = cell_data
        self._position = position
        self._cached_position = position
        self._parent = sheet
        # stores new values, without applying them to _cell_element
        self._new_attrib = {}
        self._new_text = None
        self._new_script = None
        self._change_flag = False  # not yet implemented
        # output vars

        # may be added in the future to speed up program
        # self._dependencies
        # self._dependants

    @property
    def identifier(self):
        return self.a1

    @property
    def has_contents(self):
        if self._cell_element is not None:  # for etree reasons, cannot
                # just use self._cell_element
            return True
        else:
            return False

    @property
    def data_type(self):
        return self.get('office:value-type')

    @data_type.setter
    def data_type(self, value):
        self.set('office:value-type', value)

    @property
    def content(self):
        # will be refactored as 'value' to return either string
        # or float value
        if self.data_type == 'string':
            self.evaluate()
            return self.text
        else:
            return self.value

    @content.setter
    def content(self, content):
        try:
            self.value = float(content)
        except ValueError:
            self.text = content

    @property
    def value(self):
        # at the moment, reevaluates all cells in dependency tree
        # in the future, once dependants and change flags are
        # instituted, will only reevaluate if a cell in the tree has
        # changed
        self.evaluate()
        return float(self.get('office:value'))

    @value.setter
    def value(self, value):
        # note: this only returns a numerical value only
        # this will be refactored soon to return either str or float
        self.set('office:value', float(value))
        self.data_type = 'float'

    @property
    def cached_value(self):
        # always returns original value from the xml file
        return float(self.get('office:value', True))

    @property
    def text(self):
        # text getter/setter is different from other attributes because
        # it is stored separately in the xml file
        if self._new_text is not None:
            return self._new_text
        return self._cell_element[0].text

    @text.setter
    def text(self, string):
        # not using self.set because text is stored separately
        # (ask whoever started that standard, no idea why)
        self.data_type = 'string'
        if string != self.text:
            self._new_text = string

    @property
    def cached_text(self):
        return self._cell_element[0].text  # get text directly from ET

    @property
    # this is the formula as modified to appear as it does as typed
    # by a user in the spreadsheet program (...eventually)
    def formula(self):
        return self.get('table:formula')[3:]

    @property
    # this is the formula as stored in the xml file, with formatting
    # left in
    def raw_formula(self):
        return self.get('table:formula')

    @property
    def is_script(self):
        if self.text.startswith(PYSCRIPT_FLAG):
            return True
        else:
            return False

    @property
    def script(self):
        # if a new script has been set, use that
        # otherwise, use the cached text to see if self is script.
        # scripts themselves can change self text value.
        if self._new_script:
            return self._new_script
        if self.is_script:
            return self.text[len(PYSCRIPT_FLAG):]

    @script.setter
    def script(self, script_string):
        self._new_script = script_string

    @property
    def a1(self):
        return a1_from_xy(self.position)

    @a1.setter
    def a1(self, a1_string):
        self.position = xy_from_a1(a1_string)

    @property
    def position(self):
        return self._position

    @position.setter
    def position(self, tuple_or_list):
        self.position = (tuple_or_list[0], tuple_or_list[1])

    @property
    def cached_position(self):
        return self._cached_position

    @property
    def column(self):
        return self.sheet.columns[self.position[0]]

    @property
    def row(self):
        return self.sheet[self.position[1]]

    @property
    # returns dictionary of dependencies of self.
    # referencing string is key
    # may just have them be stored as standard
    # I -don't think- this needs to be sent over to _new_attrib, but
    # if that proves to be the case, this will need to be updated.
    def dependencies(self):
        return self.find_dependencies()

    #############################
    # Output props
    @property
    def included(self):
        # if all parent objects are set to be included in output,
        # returns true as cell is to be included in output file
        if all([self.book.inc_set,
                self.sheet.inc_set,
                self.row.inc_set,
                self.column.inc_set]):
            return True

    def get(self, string, cached=False):
        # get method called by property getters that use the attrib
        # dictionary
        # check if attribute has a new value in self._new_attrib
        # before getting it from the element tree attrib dictionary
        string = self.ns(string)
        if string in self._new_attrib and not cached:
            return self._new_attrib[string]
        else:
            return self._cell_element.get(string)

    def set(self, key, entry):
        # set method called by properties using the attrib dict
        # if new val is different from original, put in new_attrib
        # dict, rather than editing loaded element tree. This allows
        # changes to be reverted
        if entry != self.get(key):
            ns_key = self.ns(key)
            self._new_attrib[ns_key] = entry

    def find_dependencies(self):
        # returns dictionary of referenced cells with reference as key
        # if reference is a range (like 'A1:B2') returns matrix
        if not self.has_contents or (self.raw_formula is None and
                                     self.script is None):
            return {}
        else:
            dependencies = {}
            # look in formula first
            if self.raw_formula is not None:
                # find start of a reference
                is_quote = False
                start = None
                for x in range(0, len(self.raw_formula)):
                    if self.raw_formula[x] == "'":
                        is_quote = not is_quote
                    elif self.raw_formula[x] == '[' and not is_quote:
                        # reference found!
                        start = x
                    elif self.raw_formula[x] == ']' and not is_quote:
                        # set reference string
                        reference = self.raw_formula[start + 1: x]
                        # set default values, will be changed in a
                        # moment if needed
                        dependencies['[' + reference + ']'] = \
                            self.cell_from_reference(reference)
            if self.script is not None:
                start = None
                script_s = self.script
                for x in range(0, len(script_s)):
                    if script_s[x: x + 6] == 'cells[':
                        start = x
                    elif script_s[x] == ']' and \
                            start is not None:
                        reference = script_s[start + 7:x - 1]
                        start = None
                        dependencies['cells[' + reference + ']'] = \
                            self.cell_from_reference(reference)
            return dependencies

    def cell_from_reference(self, reference):
        reference_type = 'cell'  # default reference
        range_start = None
        range_end = None
        # now that there's a reference, iterate through it
        # to see if there's a ':' outside of quotes
        # denoting a range of cells
        if ':' in reference:
            index = find_unquoted(':', reference)
            if index is not None:
                reference_type = 'range'
                range_start = reference[:index - 1]
                range_end = reference[index + 1:]
        if reference_type == 'cell':
            reference_parts = break_apart_reference(reference)
            reference_parts = self.complete_reference_parts(*reference_parts)
            return self.library[reference_parts]
        elif reference_type == 'range':
            start_parts = break_apart_reference(range_start)
            start_parts = self.complete_reference_parts(
                    start_parts)
            end_parts = break_apart_reference(range_end)
            end_parts = self.complete_reference_parts(
                    end_parts)
            return CellRange(
                self.sheet.book.library[start_parts],
                self.sheet.book.library[end_parts]
            )

    def complete_reference_parts(self, *parts):
        # unfilled parts of reference are completed with
        # self sheet and book
        sheet_default = self.sheet.name
        book_default = self.sheet.book.file_name
        length = len(parts)
        if 0 < length <= 3:  # if length is within possible ref. depths
            additions = [book_default, sheet_default]
            # add parts of reference that are missing from reference
            return additions[0: 3 - length] + list(parts)
        else:
            raise SheetDataError('len of reference parts outside 1-3 range')

    def evaluate(self, recursive=True, scripts=True):
        if self.has_contents:
            if recursive:
                for cell in self.dependencies:
                    self.dependencies[cell].evaluate()
            if scripts and self.script:
                self.run_script()
            elif self.raw_formula:
                evaluation = parser.evaluate(self.formula,
                                             self.dependencies)
                # if returned is value, put it in self.value
                # if that doesn't work, put it in self.string
                try:
                    self.value = float(evaluation)
                except ValueError:
                    try:
                        self.text = str(evaluation)
                    except ValueError:
                        print('could not set new value')
                        pass

    def run_script(self, auto_import=True):
        # dependencies is list of cells that are used

        class CellReferencer:
            def __init__(self, lookup_formula):
                self.lookup = lookup_formula

            def __getitem__(self, reference_string):
                return self.lookup(reference_string)

        if self.has_contents and self.is_script:
            # set script vars that can be called by the script
            script.cell = self
            script.cells = CellReferencer(self.cell_from_reference)
            script_string = self.script
            if auto_import:
                script_string = 'from script import *\n' + self.script
            exec(script_string)
        else:
            return ''

class CellRange:
    # range of cells intended for evaluator - acts similar to cell
    # in that it returns (total) value, dictionary of all dependencies,
    # etc
    def __init__(self, start_cell, end_cell):
        sheet_list = start_cell.sheet.book.sheet_list

        # create 3d matrix of cells inside the range (sheet, row, cell)
        indexes = {
            'sheets': [sheet_list.index(start_cell.sheet.name),
                       sheet_list.index(end_cell.sheet.name)],
            'rows': [start_cell.position[1], end_cell.position[1]],
            'cells': [start_cell.position[0], end_cell.position[0]]
        }
        for pair in indexes:
            indexes[pair].sort()
        self._matrix = []
        for sheet in start_cell.sheet.book.sheet_list[indexes['sheets'][0]:
                                                      indexes['sheets'][1]]:
            sheet_matrix = []
            self._matrix.append(sheet_matrix)
            for row in sheet.matrix[indexes['rows'][0]:indexes['rows'][1]]:
                row_matrix = []
                sheet_matrix.append(row_matrix)
                for cell in row[indexes['cells'][0]:indexes['cells'][1]]:
                    row_matrix.append(cell)

    @property
    def identifier(self):
        return '%s %s' % (self.start_cell.a1, self.end_cell.a1)

    @property
    def start_cell(self):
        return self.matrix[1][1][1]

    @property
    def end_cell(self):
        return self.matrix[-1][-1][-1]

    @property
    def matrix(self):
        return self._matrix

    @matrix.setter
    def matrix(self, matrix):
        self._matrix = matrix

    @property
    def cells(self):
        cells = []
        [[[cells.append(cell) for cell in row] for row in sheet] for sheet in
         self.matrix]
        return cells

    @property
    def value(self):
        return sum([sum([sum([cell.value for cell in row])
                   for row in sheet]) for sheet in self.matrix])

    @property
    def dependencies(self):
        # returns dictionary of dependencies
        # reference string is key, referenced cell or range is value
        d = {}
        for sheet in self.matrix:
            for row in sheet:
                for cell in row:
                    d.update(cell.dependencies)
        return d

    def evaluate(self):  # evaluates each cell in matrix
        [[[cell.evaluate() for cell in row]
          for row in sheet]
         for sheet in self.matrix]

class Row(LibComponent):
    def __init__(self, sheet, y, tree):
        super().__init__()
        self.y = y
        self._parent = sheet
        self._tree = tree
        self._cells = []
        self._loaded = False
        self._settings = {}

    def __getitem__(self, item):
        if not self._loaded:
            self.load()
        return self._cells[item]

    @property
    def identifier(self):
        return self.y

    @property
    def list(self):
        return [cell.content for cell in self._cells]

    def load(self):
        cell_elements = self._tree.findall(self.ns('table:table-cell'))
        [self._cells.append(Cell(cell_elements[x], (x, self.y), self.sheet))
         for x in range(0, len(cell_elements))]
        self._loaded = True

class Column(LibComponent):
    # used by spreadsheet xml for storing formatting, also useful for
    # references.
    def __init__(self, sheet, x, tree):
        super().__init__()
        self.x = x
        self.parent = sheet
        self._tree = tree

    def __getitem__(self, y):
        # unlike row, does not store cells.
        return self.sheet[(self.x, y)]

    @property
    def identifier(self):
        return x_to_letter(self.x)

class Sheet(LibComponent):
    def __init__(self, book, element_tree):
        super().__init__()
        self._rows = []
        self._columns = []
        self._tree = element_tree
        self._attributes = self._tree.attrib
        self._loaded = False
        self._parent = book
        self.name = [self._attributes[attribute]
                     for attribute in self._attributes
                     if not attribute.endswith('style-name') and
                     attribute.endswith('name')][0]
        self._settings = {}

    def __getitem__(self, item):
        # if item is tuple or list, return the referenced cell
        # if item is string, convert it from a1 and return the cell
        # if item is int, return the referenced row
        # if self is not yet loaded, do that now
        if not self._loaded:
            self.load()
        if isinstance(item, (list, tuple)):
            x, y = item
        elif isinstance(item, str):
            x, y = xy_from_a1(item)
        else:
            try:
                y = item
            except:
                raise KeyError(str(item) + ' is not a valid key for sheet ' +
                               self.name)
            else:
                return self._rows[y]
        return self._rows[y][x]

    @property
    def identifier(self):
        return self.name

    @property
    def columns(self):
        return self._columns

    @property
    def matrix(self):
        """
        returns a matrix of sheet data
        :return: matrix
        """
        return [row.list for row in self._rows]

    def load(self):
        # loads rows and columns into sheet lists

        # load rows
        row_elements = self._tree.findall(self.ns('table:table-row'))
        [self._rows.append(Row(self, y, row_elements[y])) for y in
         range(0, len(row_elements))]
        self._loaded = True

        # load columns
        column_elements = self._tree.findall(self.ns('table:table-column'))
        x = 0
        for column_tree in column_elements:
            repeat = column_tree.get(self.ns(
                    'table:number-columns-repeated'))
            if repeat:
                for x in range(0, int(repeat)):
                    self._columns.append(Column(self, x, column_tree))
                    x += 1
            else:
                self._columns.append(Column(self, x, column_tree))
                x += 1

    def find(self, column_or_row, name_to_find,
             name_index=0, case_sensitive=False):
        if column_or_row == 'row' or column_or_row == 'rows':
            list_to_search = self._rows
        elif column_or_row == 'column' or column_or_row == 'columns':
            list_to_search = self._columns
        else:
            raise KeyError('list to search should be \'row\' or \'column\', '
                           'not %s' % column_or_row)
        if not case_sensitive:
            name_to_find = name_to_find.lower()
        result = None
        for row in list_to_search:
            row_name = row[name_index].text
            if not case_sensitive:
                row_name = row_name.lower()
            if row_name == name_to_find:
                if result is None:
                    result = row
                else:
                    raise KeyError('multiple rows with name \'%s\'' %
                                   name_to_find)

class Book(LibComponent):
    # gets passed relevant dictionary of elements by file.load()
    # should not load cells until that function is called
    # then pass on relevant sub-dictionary to sheets that are created
    # so on
    def __init__(self, library, file, element_tree):
        super().__init__()
        self._file = file
        self._element_tree = element_tree
        self._parent = library
        self._settings = {}
        self.sheets = {}
        self.sheet_list = []  # list of sheets, in order of file

    @property
    def identifier(self):
        return path.split(self._file.file_id)[-1]

    @property
    def file_name(self):
        return self.file.file_id

    @property
    def file(self):
        return self._file

    @file.setter
    def file(self, file):
        self._file = file

    @property
    def dictionary(self):
        """
        creates and returns dictionary of book content
        :return: content dictionary
        """
        return {sheet.name: sheet.matrix for sheet in self.sheets}

    def __getitem__(self, item):
        item = strip_quotes(item.lower())
        if item in self.sheets:
            pass
        elif item in self.sheet_list:
            if self.library.recursive:
                self.load(item)
            else:
                raise KeyError(str(item) + ' is in Book ' + self.file_name +
                               ' but not loaded, and recursive loading is'
                               ' not enabled')
        else:
            raise KeyError(str(item) + ' is not in Book ' + self.file_name)
        return self.sheets[item]

    def load(self, sheet_to_load):
        # load sheet of name (arg) or else load everything
        # from xml module, response to simple 'if self._element_tree';
        # "FutureWarning: The behavior of this method will change in
        # future versions. Use specific 'len(elem)' or
        # 'elem is not None' test instead."
        if self._element_tree is not None:
            [self.add_sheet(Sheet(self, sheet))
             for sheet in self._element_tree.findall(self.ns('table:table'))
             if (sheet.attrib[self.ns('table:name')] == sheet_to_load or
                 sheet_to_load is None)]
        # check

    def write(self, name, overwrite):
        """
        writes content dictionary to a file of name
        :param name: name to write as.
        :param overwrite: Bool, write over existing file of name
        """

    def add_sheet(self, sheet):
        self.sheets[sheet.name.lower()] = sheet

class Library(LibComponent):
    def __init__(self, list_of_addresses, recursive_loading=False):
        super().__init__()
        self.list = list_of_addresses
        self.files = {address: File(address, self) for address in self.list}
        self.books = {}
        self.recursive = recursive_loading
        self._settings = {}

        [self.files[file].load() for file in self.files]

    @property
    def identifier(self):
        return 'base'

    def load_books(self):
        for book_name in self.list:
            self.load_book(book_name)

    def load_book(self, book_name):
        self.files[book_name] = File(book_name, self)
        self.files[book_name].load()

    def __getitem__(self, item):
        # the new improved method for returning cells / books / sheets
        # if item is list, break apart and recall self
        # (allows passing of lists of getters)
        if isinstance(item, (list, tuple)):
            return self[item[0]][item[1]][item[2]]
        item = remove_file_prefix(strip_quotes(item))
        if item in self.books:
            book = self.books[item]
        elif '/' not in item and \
             any([book_name.endswith(item) for book_name in self.books]):
            # if there are no backspaces in item string, and one of the
            # library's books ends with the string 'item,'
            # that's the book
            book = [self.books[book_name] for book_name in self.books if
                    book_name.endswith(item)][0]
            # this has the potential for bugs, should be refined in the
            # future
        elif self.recursive:
            try:
                self.load_book(item)
                book = self.books[item]
            except:
                error_string = 'could not find referenced book ' + str(
                       item)
                raise SheetDataError(error_string)
        else:
            error_string = 'cell referenced cell not in loaded'\
                                         'book' + str(item)
            raise SheetDataError(error_string)
        return book

class File:
    def __init__(self, file_address, library=None):
        self.file_id = file_address
        self.body = None
        self.map = None
        self.library = library

        if self.file_id[:7] == 'file://':
            self.file_id = self.file_id[7:]

        if library is None:
            self.library = Library([file_address])

    def load(self, sheet_name=None):
        # load cell instances into
        #
        # dictionary (library)
        # of dictionaries (book)
        # of lists (sheet)
        # of lists (row)
        # of objects (cell)

        # tree structure:
        # content
        #   body
        #       spreadsheet
        #           table
        #               table-row
        #                   table-cell

        # create element tree by extracting xml file and parsing it
        with zipfile.ZipFile(self.file_id).open('content.xml') as content:
            data = etree.parse(content).getroot()

            # get prefix map
            self.map = NSMap(data.nsmap)

            # set library.books [file_address]
            # to book of appropriate data
            if self.file_id not in self.library.books:
                body_element = data.find(self.ns('office:body'))
                spreadsheet_element = body_element.find(self.ns(
                        'office:spreadsheet'))
                self.library.books[self.file_id] = \
                    Book(self.library, self, spreadsheet_element)

            self.library.books[self.file_id].load(sheet_name)

    def ns(self, s):
        return self.map.ns(s)

class NSMap:
    # simple object for dealing with namespace mapping
    def __init__(self, map_dictionary):
        self.dict = map_dictionary

    def ns(self, s):
        # return string with prefix converted to namespace
        # string:tag --> {namespace}tag
        for x in range(0, len(s) - 1):
            if s[x] == ':':
                prefix = s[:x]
                suffix = s[x + 1:]
                s = '{%s}%s' % (self.dict[prefix], suffix)
                break
        return s

def a1_from_xy(pos):
    # returns excel-type cell given X, Y position
    # A corresponds to 0 in x-axis
    # 1 corresponds to 0 in y-axis

    x_ref = x_to_letter(pos[0] + 1)
    y_ref = str(pos[1] + 1)

    return x_ref + y_ref

def xy_from_a1(s):
    # returns x, y from inputted 'a1' string
    s = s.lower()
    x = None
    y = None
    for a in range(0, len(s)):
        if s[a - 1] in storage.ENGLISH_ALPHABET and \
                s[a] in storage.ARABIC_NUMBERS:
            x = s[:a]
            y = s[a:]
            break

    if x is None:
        raise SheetDataError('could not parse reference to %s' % s)

    x = letter_to_x(x)
    y = int(y) - 1

    return x, y

def x_to_letter(x):
    # takes in a number and returns it as letter(s)
    # ex.: 1 = 'a', 26 = 'aa'

    l = []
    s = ''

    # while x > 26 divides it by 26 and adds the remainder to l
    while x > 26:
        l.append(x % 26)
        x //= 26

    l.append(x % 26)

    # since the above worked from the right
    # (smallest to largest place digit)
    # this reverses the order
    l = l[::-1]

    # convert each i in l into the corresponding letter
    for i in l:
        s += storage.ENGLISH_ALPHABET[i - 1]

    return s

def letter_to_x(s):
    # converts letter or letter series to arabic number value
    # example: a --> 0, ab --> 28
    s = s.lower()[::-1]
    val = -1  # starts at -1 so that a, when evaluated as 1, returns 0
    for x in range(0, len(s)):
        val += (ord(s[x]) - 96) * 26 ** x
    return val

def break_apart_reference(s):
    # takes a reference string and breaks it down into a list of
    # file name, sheet name, cell name
    parts = []

    # iterate backwards through string looking for '.' then '#$'
    dot = find_unquoted('.', s, True)
    if dot is None:
        parts.append(s)
        return parts
    elif dot is 0:
        parts.append(s[dot + 1:])
        return parts
    else:
        parts.append(s[dot + 1:])
    # now try to find the #$
    hd = find_unquoted('#$', s, True)
    if hd is None:
        parts.append(s[:dot])
    else:
        parts.append(s[hd + 2: dot])
        parts.append(s[:hd])
    # reverse order to go book, sheet, cell rather than the reverse
    return list(reversed(parts))

def find_unquoted(target, string, back=False, list_mode=False):
    # finds unquoted target in string and returns the position of the
    # first character
    # this function is used for finding a string in a parent string
    # but only if it is not enclosed in quotes - useful for finding a
    # cell reference in a formula, where you want to find 'cell['
    # but not when used as in a script saying
    # print('you can access cells by typing cell[<reference>]')
    motion = 1
    index = 0
    target_length = len(target)
    if back:
        motion *= -1
        index = len(string) - 1
    if list_mode:
        matches = []
        while 0 <= index < len(string):
            if string[index] == "'":
                index += motion
                while string[index] != "'":
                    index += motion
            elif string[index: index + target_length] == target:
                matches.append(index)
            index += motion
        return matches
    else:
        while string[index: index + target_length] != target:
            if string[index] == "'":
                index += motion
                while string[index] != "'":
                    index += motion
            index += motion
            if not 0 <= index < len(string):
                return
        return index

PYSCRIPT_FLAG = 'py='  # flag denoting start of python script

def strip_quotes(string):
    def is_quote(char):
            if char == '\'' or char == '\"':
                return True
            else:
                return False

    if is_quote(string[0]) and is_quote(string[-1]):
        string = string[1:-1]
    return string

def remove_file_prefix(string):
    pre = 'file://'
    if string.startswith(pre):
        string = string[len(pre):]
    return string


import json
import re
import csv

FILE = 'dubai_data.json'
FILE_EXT = 'dubai_data_extended.json'

def extract_square_meters(string):

    # Use a regular expression to match the pattern of digits after "sqm"
    match = re.search(r"\d+sqm", string)

    if match:
        # Extract the digits
        digits = match.group(0).replace("sqm", "")
        return digits
    else:
        print("No match found")
        return -1

def clean_facts(facts):
    try:
        age = [item for item in facts if "Years" in item][0].replace(" Years", '')
    except:
        age = None
    bedrooms = facts[-2].replace('+Maid', '')
    if bedrooms == 'studio':
        bedrooms = 0
    return {"apartment type": facts[0], "size(sqm)": extract_square_meters(facts[1]), "bedrooms": bedrooms, "age": age}

def clean_data(file):
    with open(file, 'r') as f:
        # Load the JSON data
        data = json.load(f)
        cleaned_data = []
        for apartment in data:
            if 'url' in apartment.keys():
                if apartment['price'] != 'Ask' and apartment['price'] != '\n':
                    apartment['area'] = apartment['area'].strip()
                    cleaned_facts = clean_facts(apartment["facts"])
                    apartment.update(cleaned_facts)
                    apartment.pop('facts')
                    apartment.pop('input')
                    try:
                        apartment['price(USD/month)'] = float(apartment['price'].replace(",", "")) * 0.27 / 12
                        apartment.pop('price')
                    except:
                        print(apartment['price'])
                    try:
                        apartment['amenities'][0] = apartment['amenities'][0].replace(" ", "")
                    except:
                        pass
                    cleaned_data.append(apartment)
    return cleaned_data

def get_all_amenities(data):
    amenities = set()
    for item in data:
        for amenity in item['amenities']:
            if amenity == 'Unfurnished':
                continue
            amenities.add(amenity)
    return amenities

def clean_amenities(amenities, all_amenities):
    new_amenities = {}
    for amenity in all_amenities:
        new_amenities[amenity] = 1 if amenity in amenities else 0
    return new_amenities

def load_to_csv():
    cleaned_data = clean_data(FILE)
    cleaned_data_ext = clean_data(FILE_EXT)
    all_amenities = get_all_amenities(cleaned_data)
    for item in cleaned_data:
        item.update(clean_amenities(item['amenities'], all_amenities))
        item.pop('amenities')
    for item in cleaned_data_ext:
        item.update(clean_amenities(item['amenities'], all_amenities))
        item.pop('amenities')
    with open('dubai_data.csv', 'w') as csv_file:
        # Create a CSV writer
        writer = csv.writer(csv_file)

        # Add the header row
        keys = list(cleaned_data[0].keys())
        print(list(keys))
        writer.writerow(keys)

        # Add the data rows
        for row in cleaned_data:
            writer.writerow(row.values())
        for row in cleaned_data_ext:
            writer.writerow(row.values())

# load_to_csv()

cleaned_data_ext = clean_data(FILE_EXT)
print(get_all_amenities(cleaned_data_ext))


# Time: 29.14 / Memory : 59.73
from re import sub
from collections import Counter

class Solution:
    def mostCommonWord(self, paragraph: str, banned: List[str]) -> str:
        paragraph = sub(r'[^a-z ]', ' ', paragraph.lower()).split(" ")
        banned = {k: True for k in banned}
        print(paragraph)
        for k, v in Counter(paragraph).most_common():
            if not k or k in banned:
                continue
            return k
        return -1


from server import app

from flask import abort
from flask import render_template
from flask import request

from flask_login import login_required

from models.blog import Post

create_page_title = 'Create Post'
edit_page_title = 'Edit Post'
posts_per_page = 5

@app.route('/admin/blog/post')
@login_required
def blog():
    blog = Post()
    return render_template('/admin/post.html', posts = blog.get_all(), page_title = create_page_title)

@app.route('/admin/blog/post/create', methods = ['POST'])
@login_required
def create_post():
    blog = Post()
    posts = blog.get_all()
    message = ''
    if request.method == 'POST':
        data = {
            'title': request.form['title'],
            'description': request.form['description'],
            'content': request.form['content'],
            'status': int(request.form['status']),
        }
        post = blog.create(data)
        message = post.title + ' was created'
    else:
        message = 'There was an error trying to create post'
    return render_template('admin/post.html', posts = posts, message = message, page_title = create_page_title)

@app.route('/admin/blog/post/edit/<post_id>', methods = ['POST', 'GET'])
@login_required
def edit_post(post_id):
    post = Post().get_by_id(post_id)
    return render_template('admin/update_post.html', post = post, page_title = edit_page_title)

@app.route('/admin/blog/post/update', methods = ['POST'])
@login_required
def update_post():
    blog = Post()
    posts = blog.get_all()
    message = ''
    if request.method == 'POST':
        data = {
            'id': request.form['id'],
            'title': request.form['title'],
            'description': request.form['description'],
            'content': request.form['content'],
            'status': int(request.form['status']),
        }
        blog.update(data)
        message = data['title'] + ' was updated'
    else:
        message = 'There was an error trying to create post'
    return render_template('admin/post.html', posts = posts, message = message, page_title = edit_page_title)

@app.route('/admin/blog/post/delete/<int:post_id>')
@login_required
def delete_post(post_id):
    blog = Post()
    posts = blog.get_all()
    post = blog.delete(post_id)
    message = post.title + ' deleted'
    return render_template('admin/post.html', posts = posts, message = message, page_title = create_page_title)

@app.route('/blog/post/<slug>', methods = ['GET'])
def post(slug):
    blog = Post()
    posts = blog.get_all()
    post = blog.get_by_slug(slug)
    slugs = [p.slug for p in posts]
    if(slug not in slugs):
        abort(404)
    return render_template('pages/post.html', post = post)

@app.route('/blog/', methods = ['GET'])
@app.route('/blog/<int:page>', methods=['GET'])
def blog_home(page=1):
    blog = Post()
    posts = blog.get_publish().paginate(page, posts_per_page, False)
    return render_template('pages/blog.html', posts = posts)


import logging
from abc import ABC, abstractmethod
from typing import Type

import pydantic

from core.loggers import CONSUMER_LOGGER
from message_consumers.dependencies.di_container import BaseContainer
from ports.services.message_broker import MessageBroker

logger = logging.getLogger(CONSUMER_LOGGER)

class BaseConsumer(ABC):
    """
    A base class for SQS consumers. In a child class `queue_name` should be defined
    to receive messages from the queue.
    Other attributes:
        - `dead_letter_queue_name` (optional) - can be specified to perform
           a health check on the dead letter queue if one is configured;
        - `health_check_frequency_in_sec` (default: 60) - frequency of the
           heath check requests;
        - `graceful_shutdown_in_sec` (default: 3) - time in seconds for the pending message
           handler tasks to finish after either SIGINT or SIGTERM is triggered;
        - `dead_letter_queue_threshold` (default: 10) - the warning message is logged in case
           the number of the messages in the dead letter queue is higher than the threshold;
        - `message_schema` (optional) - pydantic model to serialize and validate
           the message from the queue. If specified, the model instance will be passed
           to the message handler in case of successful data serialization and validation;
        - `delete_on_exceptions` (optional) - in occurrence of the specified exceptions
           the message will be deleted from the queue.
    """

    queue_name: str
    dead_letter_queue_name: str | None = None
    health_check_frequency_in_sec: int = 60
    graceful_shutdown_in_sec: int = 3
    dead_letter_queue_threshold: int = 10
    message_schema: Type[pydantic.BaseModel] | None = None
    delete_on_exceptions: set[Exception] | None = None
    di_container: BaseContainer | None = None

    def __init__(self, message_broker: MessageBroker):
        self.message_broker = message_broker
        if not hasattr(self, "queue_name"):
            raise ValueError(f"Please define queue name for {self.__class__.__name__}")

    async def start(self) -> None:
        await self.message_broker.pool(
            self.queue_name,
            self.message_handler,
            self.dead_letter_queue_name,
            self.message_schema,
            self.delete_on_exceptions,
            self.graceful_shutdown_in_sec,
            self.dead_letter_queue_threshold,
            self.health_check_frequency_in_sec,
            self.di_container,
        )

    @abstractmethod
    async def message_handler(self, message: Type[pydantic.BaseModel], container: BaseContainer) -> None:
        raise NotImplementedError


# -*- coding: utf-8 -*-
"""
Created on 2019/9/25 10:17
@Author:lilu
@Desc:
"""
import os
import random
import string
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import shutil

# 字体的位置
font_path = './verification_code/fonts/arial.ttf'
# 生成几位数的验证码
number = 4
# 生成验证码图片的高度和宽度
size = (100, 30)
# 背景颜色，默认为白色
bgcolor = (255, 255, 255)
# 字体颜色，默认为蓝色
fontcolor = (0, 0, 255)
# 干扰线颜色，默认为红色
linecolor = (255, 0, 0)
# 是否要加入干扰线
draw_line = True
# 加入干扰线条数的上下限
line_number = (1, 5)

def gen_text():
    """随机生成一个字符串"""
    source = list(string.ascii_letters)
    for index in range(0, 10):
        source.append(str(index))
    return ''.join(random.sample(source, number))  # number是生成验证码的位数

def gen_line(draw, width, height):
    """绘制干扰线"""
    begin = (random.randint(0, width), random.randint(0, height))
    end = (random.randint(0, width), random.randint(0, height))
    draw.line([begin, end], fill=linecolor)

def gen_code(num):
    """生成验证码"""

    while num > 0:
        width, height = size  # 宽和高
        image = Image.new('RGBA', (width, height), bgcolor)  # 创建图片
        font = ImageFont.truetype(font_path, 25)  # 验证码的字体
        draw = ImageDraw.Draw(image)  # 创建画笔
        text = gen_text()  # 生成字符串
        font_width, font_height = font.getsize(text)
        draw.text(((width - font_width) / number, (height - font_height) / number), text, font=font,
                  fill=fontcolor)  # 填充字符串
        if draw_line:
            gen_line(draw, width, height)
        # image = image.transform((width+30,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR)  #创建扭曲
        image = image.transform((width + 20, height + 10), Image.AFFINE, (1, -0.3, 0, -0.1, 1, 0),
                                Image.BILINEAR)  # 创建扭曲
        image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜，边界加强
        save_code(image, num)
        num -= 1

def save_code(image, num):
    image.save('./gen_imgs/code' + str(num) + '.png')  # 保存验证码图片

def remove_folder():
    shutil.rmtree('./gen_imgs')
    os.mkdir('./gen_imgs')

if __name__ == "__main__":
    remove_folder()
    print("gen_imgs文件夹已清空...")
    num = input("请输入生成的验证码的个数：")
    gen_code(int(num))


from collections import deque

N = int(input())
S = input()
S_num = [num for num in range(1, len(S)+1)]
A = [0]

for idx, direction in enumerate(S):
    pre_num_idx = A.index(S_num[idx]-1)

    if direction == 'L':
        if pre_num_idx == 0:
            STACK_RANGE = len(A)
        else:
            STACK_RANGE = len(A) - (pre_num_idx)
    else:
        STACK_RANGE = len(A) - (pre_num_idx + 1)

    stack = []
    for _ in range(STACK_RANGE):
        s = A.pop()
        stack.append(s)

    A.append(S_num[idx])

    for _ in range(STACK_RANGE):
        s = stack.pop()
        A.append(s)

print(*A)


lst = ['Awebisam', 'Astik', 'Mahesh', 1299]
lst.append("Ganesh")
print(lst)

tpl = ('Ram', "hari", "Shyam", 2829)
# tpl[0] = "Ganesh"
# print(tpl[0])

st = {'Krishna', "Mahesh", "Ganesh", 8929}
# st.add('Apple')

lst1 = list() #lst1 = []
dict1 = dict() #lst1 = []


import pickle as pkl
from tqdm import tqdm
from treelib import Tree

# G = Tree()
# G.create_node(tag = "Blah", identifier= "blah", parent=None, data = {
#     "name" : "Sandipan"
# })
# leaves = list(filter(lambda node : node, G.leaves()))
# print(leaves[0].data["name"])

# datapath = "data/com2sense/dev.G.pkl"
datapath = "data/com2sense/dev_G_normal_modified.pkl_21"

with open(datapath, "rb") as fp:
    samples = pkl.load(fp)

i = 0

for G in tqdm(samples):
    print(G)
    i += 1
    if i == 30:
        break


from time import sleep
def linha(texto = '', cor = 'white', backcor = '', menu = True):
    '''
    -> Imprime o menu nas cores selecionadas
    :param texto: Recebe o texto que vai ser adiconado e impresso no menu
    :param cor: A Sintaxe para adicionar cores a um texto e \033[style:text:background m]
    :param backcor: A sintaxe para adicionar cores de fundo
    :param menu: printa resultado na tela como menu padrao se True, se falso imprime help
    Tabela de cores:
    Style           Text        Background
    0 none          30 white    40 white
    1 Bold          31 red      41 red
    4 underline     32 green    42 green
    7 negative      33 yellow   43 yellow
                    34 Blue     44 Blue
                    35 Purple   45 Purple
                    36 Cyan     46 Cyan
                    37 gray     47 gray
    :return: nao ha retorno
    '''
    cores = {'end': '\033[m',
             'white': '\033[038m',
             'red': '\033[031m',
             'green': '\033[032m',
             'yellow': '\033[032m',
             'blue': '\033[034m',
             'purple': '\033[035m',
             'cyan': '\033[036m',
             'gray': '\033[037m'
             }
    bgcor = {'end': '\033[m',
            'white' : '\033[7:40m',
            'red' : '\033[41m',
            'green' : '\033[42m',
            'yellow' : '\033[43m',
            'blue' : '\033[44m',
            'purple' : '\033[45m',
            'cyan' : '\033[46m',
            'gray' : '\033[47m'
            }
    menu = menu
    corin = cores[cor.lower()]
    fundo = bgcor[backcor.lower()]
    tamlin= '~' * (len(texto) + 4)
    if menu == True:
        print(fundo,tamlin,corin)
        print(texto.center(len(texto)+5))
        print(fundo,tamlin,corin)
        print(cores['end'], end='')

    else:
        print(fundo,corin)
        help(texto)
        print(cores['end'], end='')

#PROGRAMA PRINCIPAL;
while True:
    linha("SISTEMA DE AJUDA PyHELP", backcor='green', menu=True)
    resp = str(input("Funcao ou biblioteca > "))
    if resp.upper() in 'FIM':
        linha("ATE LOGO!", backcor='red')
        break
    linha(f"Acessando o manual do comando '{resp}'", backcor='blue')
    sleep(1)
    linha(texto=resp, backcor='white', menu=False)
    sleep(1)


import numpy as np
from scipy import signal, misc
import matplotlib.pyplot as plt
from scipy import ndimage
from mpl_toolkits.mplot3d import Axes3D

sigma = 30

x=np.arange(-128,127,1.0)
y=np.arange(-128,127,1.0)
X,Y=np.meshgrid(x,y)

s=1/(np.pi*pow(sigma,4))
a=-(pow(X,2)+pow(Y,2))/(2*pow(sigma,2))
g=-s*(1+a)*np.exp(a)

#a
plt.imshow(g)
plt.gray()
plt.title('LoG(x,y)')
plt.axis('off')
plt.show()

#b
fig=plt.figure()
ax=Axes3D(fig)
ax.plot_surface(X,Y,g)
plt.show()

#c
#9*9 LoG 필터
def LoG_FIlter(sigma,Filter_Size):
    g = np.zeros(shape=(Filter_Size,Filter_Size), dtype=np.float)
    for y in range(-4,5):
        for x in range(-4,5):
            s=1/(np.pi*pow(sigma,4))
            a=-(pow(x,2)+pow(y,2))/(2*pow(sigma,2))
            p=-s*(1+a)*np.exp(a)
            g[y+4,x+4]=p
    return g
Filter_Size = 9
print(LoG_FIlter(0.8,Filter_Size))

#d

def im_filtering(im, Filter, FilterSize):
    row, col = im.shape
    padding=int(FilterSize/2)

    Image_Buffer = np.zeros(shape=(row+2*padding,col+2*padding), dtype=np.uint8)
    Image_Buffer[padding:row+padding, padding:col+padding] = im[:,:]
    Image_New = np.zeros(shape=(row,col), dtype=np.uint8)
    for y in range(padding,row+padding):
        for x in range(padding,col+padding):
            buff = Image_Buffer[y-padding:y+padding+1,x-padding:x+padding+1]
            pixel = np.sum(buff * Filter)
            pixel = np.uint8(np.where(pixel>255,255,np.where(pixel<0,0,pixel)))
            Image_New[y-padding,x-padding] = pixel
    return Image_New

lena = misc.imread('image/lena_256.bmp')
filtering_img = im_filtering(lena, LoG_FIlter(0.8,Filter_Size), Filter_Size)

# 이미지 출력 함수
def image_print(img, title, print_num, current_num):
    plt.subplot(print_num[0],print_num[1],current_num)
    plt.title(title)
    plt.gray()
    plt.imshow(img)
    plt.axis('off')

print_num = [1,2]
image_print(lena, "InputImage",  print_num, 1)
image_print(filtering_img, "Log Filtering Image",  print_num, 2)
plt.show()


import matplotlib.pyplot as plt

# 示例数据
categories_left = ['Category A', 'Category B']
values_left_row1 = [30, 50]
values_left_row2 = [40, 20]

categories_right = ['Category X', 'Category Y']
values_right = [70, 30]

# 创建画布和子图
fig, axs = plt.subplots(2, 2, figsize=(10, 8))

# 左上角子图：第一行的柱状图
axs[0, 0].bar(categories_left, values_left_row1)
axs[0, 0].set_title('Upper Left Bar Chart')
axs[0, 0].set_xlabel('Categories')
axs[0, 0].set_ylabel('Values')
axs[0, 0].grid(True)
axs[0, 0].set_xticks(range(len(categories_left)))
axs[0, 0].text(0.5, 35, 'Custom Text', fontsize=12, color='blue')

# 右上角子图：第二行的柱状图
axs[0, 1].bar(categories_left, values_left_row2)
axs[0, 1].set_title('Upper Right Bar Chart')
axs[0, 1].set_xlabel('Categories')
axs[0, 1].set_ylabel('Values')
axs[0, 1].grid(True)
axs[0, 1].set_xticks(range(len(categories_left)))
axs[0, 1].text(0.5, 30, 'Another Text', fontsize=12, color='red')

# 左下角子图：饼状图
axs[1, 0].pie(values_right, labels=categories_right, autopct='%1.1f%%', startangle=90)
axs[1, 0].set_title('Lower Left Pie Chart')
axs[1, 0].text(0.5, 0.5, 'Pie Chart Text', fontsize=12, color='green', transform=axs[1, 0].transAxes)

# 右下角子图：空白，不画图
axs[1, 1].axis('off')

# 调整布局
plt.tight_layout()

# 显示图形
plt.show()


import collections
import enum
import sys

class Logger:
  class Level(enum.IntEnum):
    NO_OUTPUT, ERROR, INFO = range(3)

  class Color(enum.Enum):
    DEFAULT, BLUE, GRAY, PURPLE, RED, GREEN = range(6)

    @staticmethod
    def terminal_code(color, out=sys.stdout):
      if not out.isatty():
        return ""
      elif color == Logger.Color.BLUE:
        return "\033[94m"
      elif color == Logger.Color.GRAY:
        return "\033[37m"
      elif color == Logger.Color.PURPLE:
        return "\033[95m"
      elif color == Logger.Color.RED:
        return "\033[91m"
      elif color == Logger.Color.GREEN:
        return "\033[32m"
      else:
        return "\033[0m"

  Verbosity = Level.INFO

  @staticmethod
  def log(content, level=Level.INFO, color=Color.DEFAULT, new_line=True, out=sys.stdout):
    if level <= Logger.Verbosity:
      content = "{}{}{}".format(Logger.Color.terminal_code(color, out), content,
                                Logger.Color.terminal_code(Logger.Color.DEFAULT, out))
      if new_line:
        print(content, file=out)
      else:
        print(content, end="", file=out)
      out.flush()

  @staticmethod
  def fail(msg, file=None, line=-1, line_text=None, variables=None):
    Logger.log("error: ", Logger.Level.ERROR, color=Logger.Color.RED, new_line=False,
               out=sys.stderr)
    Logger.log(msg, Logger.Level.ERROR, out=sys.stderr)

    if line_text:
      loc = ""
      if file:
        loc += file + ":"
      if line > 0:
        loc += str(line) + ":"
      if loc:
        loc += " "
      Logger.log(loc, Logger.Level.ERROR, color=Logger.Color.GRAY, new_line=False,
                 out=sys.stderr)
      Logger.log(line_text, Logger.Level.ERROR, out=sys.stderr)

    if variables:
      longest_name = max(len(var) for var in variables)

      for var in collections.OrderedDict(sorted(variables.items())):
        padding = " " * (longest_name - len(var))
        Logger.log(var, Logger.Level.ERROR, color=Logger.Color.GREEN, new_line=False,
                   out=sys.stderr)
        Logger.log(padding, Logger.Level.ERROR, new_line=False, out=sys.stderr)
        Logger.log(" = ", Logger.Level.ERROR, new_line=False, out=sys.stderr)
        Logger.log(variables[var], Logger.Level.ERROR, out=sys.stderr)

    sys.exit(1)

  @staticmethod
  def start_test(name):
    Logger.log("TEST ", color=Logger.Color.PURPLE, new_line=False)
    Logger.log(name + "... ", new_line=False)

  @staticmethod
  def test_passed():
    Logger.log("PASS", color=Logger.Color.BLUE)

  @staticmethod
  def test_failed(msg, statement, variables):
    Logger.log("FAIL", color=Logger.Color.RED)
    Logger.fail(msg, statement.filename, statement.line_no, statement.original_text, variables)


class Solution(object):
    def isPowerOfTwo(self, n):
        """
        :type n: int
        :rtype: bool
        """
        z=[]
        for i in range(50):
            x=2**i
            z.append(x)
        if n in z:
            return True
        else:
            return False


from selenium import webdriver
import win32com.client
import win32com
import win32gui
import time
driver=webdriver.Chrome('D:\chromedriver_win32\chromedriver.exe')
driver.get('https://tinypng.com/ ')
driver.find_element_by_class_name('icon').click()
time.sleep(5)
dialog = win32gui.FindWindow('#32770', '文件上传')  # 对话框
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)  # 上面三句依次寻找对象，直到找到输入框Edit对象的句柄
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)  # 确定按钮Button

win32gui.SendMessage(Edit, win32com.WM_SETTEXT, None, r'C:\Users\Administrator\Desktop\157673009.jpg')  # 往输入框输入绝对地址
win32gui.SendMessage(dialog, win32com.WM_COMMAND, 1, button)  # 按button
driver.quit()
# shell=win32com.client.Dispatch("WScript.Shell")
# shell.Sendkeys(r'C:\Users\Administrator\Desktop\157673009.jpg'+'\r')
# win32api.keybd_event(13,0,0,0)
# print('############3')
#driver.find_element_by_class_name('progress success')
# driver.quit()


def emote_convert(words, message=False):
    convert = {
        "a": "🇦",
        "b": "🇧",
        "c": "🇨",
        "d": "🇩",
        "e": "🇪",
        "f": "🇫",
        "g": "🇬",
        "h": "🇭",
        "i": "🇮",
        "j": "🇯",
        "k": "🇰",
        "l": "🇱",
        "m": "🇲",
        "n": "🇳",
        "o": "🇴",
        "p": "🇵",
        "q": "🇶",
        "r": "🇷",
        "s": "🇸",
        "t": "🇹",
        "u": "🇺",
        "v": "🇻",
        "w": "🇼",
        "x": "🇽",
        "y": "🇾",
        "z": "🇿"
    }

    words = words.lower()

    if message:
        output = ""
        for word in words:
            output += convert.get(word, word) + " "
        return output

    emote_list = []

    for word in words:
        emote_list.append((word, convert.get(word, word)))

    return emote_list

def fallback_emote(emote_list):
    fallback = {
        "a": "🅰",
        "b": "🅱",
        "m": "Ⓜ",
        "o": "🅾"
    }

    character = emote_list[0][0]

    output = (character, fallback.get(character, character))

    if character not in list(fallback.keys()):
        output = emote_list

    return output


# https://leetcode.com/problems/longest-word-in-dictionary/

class Solution:

    # Runtime: 239 ms, faster than 28.22% of Python3 online submissions for Longest Word in Dictionary.
    # Memory Usage: 14.4 MB, less than 71.32% of Python3 online submissions for Longest Word in Dictionary.

    # TC : O(N*S)
    # SC : O(N)
    def longestWord(self, words):

        max_word = ""
        words = set(words)

        for i in words:

            for pointer in range (len(i)):
                if i[:pointer+1] not in words:
                    break
            else:

                if len(max_word) < len(i):
                    max_word = i
                elif len(max_word)==len(i):
                    max_word = min (i, max_word)

                # ABOVE FOUR LINES CAN ALSO BE WRITTEN AS
                # if len(max_word) > len(i) or  i < max_word: max_word = word

        return max_word


import subprocess

import pytest

import graphviz

@pytest.mark.usefixtures('unknown_platform')
def test_view_unknown_platform():
    with pytest.raises(RuntimeError, match=r'platform'):
        graphviz.view('nonfilepath')

def test_view_mocked(mocker, mock_platform, mock_popen, mock_startfile, quiet):
    assert graphviz.view('nonfilepath', quiet=quiet) is None

    if mock_platform == 'windows':
        mock_startfile.assert_called_once_with('nonfilepath')
        return

    if quiet:
        kwargs = {'stderr': subprocess.DEVNULL}
    else:
        kwargs = {}

    if mock_platform == 'darwin':
        mock_popen.assert_called_once_with(['open', 'nonfilepath'], **kwargs)
    elif mock_platform in ('linux', 'freebsd'):
        mock_popen.assert_called_once_with(['xdg-open', 'nonfilepath'], **kwargs)
    else:
        raise RuntimeError


import json
import requests
from abc import ABC, abstractmethod
from bs4 import BeautifulSoup as Bs

class Parsing(ABC):
    html = None

    def __init__(self, url):
        self.url = url

    def get_html(self):
        response = requests.get(self.url)

        if response.status_code == 200:
            self.html = Bs(response.text, features='lxml')
        else:
            raise RuntimeError(f'status code: {response.status_code}; {response.text}')

    @abstractmethod
    def parsing(self):
        ...

    def save(self, file_name):
        with open(file_name, 'w') as file:
            json.dump(self.parsing(), file, indent=4, ensure_ascii=False)


""" This script creates an experiment set that runs for three hours: one
of pre-load, and two of actual trace. It does include workflows,
and uses the fake model Edison (not actual Edison system).

Env vars:
- ANALYSIS_DB_HOST: hostname of the system hosting the database.
- ANALYSIS_DB_NAME: database name to read from.
- ANALYSIS_DB_USER: user to be used to access the database.
- ANALYSIS_DB_PASS: password to be used to used to access the database.
- ANALYSIS_DB_PORT: port on which the database runs.
"""

from orchestration.definition import ExperimentDefinition
from orchestration import get_central_db

import sys

db_obj = get_central_db()

overload=1.0

if len(sys.argv)>=2:
    overload=float(sys.argv[1])

exp = ExperimentDefinition(
                 seed="AAAAA",
                 machine="edison",
                 trace_type="single",
                 manifest_list=[{"share": 1.0, "manifest":"floodplain.json"}],
                 workflow_policy="period",
                 workflow_period_s=300,
                 workflow_handling="manifest",
                 preload_time_s = 0,
                 workload_duration_s=3600*24*7,
                 overload_target=overload)
exp.store(db_obj)


from abc import ABC
import dearpygui.dearpygui as dpg
from pyneurode.processor_node.Message import Message
import numpy as np
import shortuuid
from pyneurode.RingBuffer.RingBuffer import RingBuffer
from typing import List, Union
from .Visualizer import Visualizer

class AnalogVisualizer(Visualizer):
    '''
    Display a analog value
    '''
    def __init__(self, name:str,  buffer_length:int = 500, scale = 1, time_scale=None) -> None:
        super().__init__(name)
        self.plot_data = (np.arange(buffer_length), np.zeros((buffer_length,)))
        self.name = name #unique identying string for the visualizer
        self.data_count = 0
        self.plot_data_tag = self.name+'_plot_data'
        self.buffer = None
        self.buffer_length = buffer_length
        self.first_run = True
        self.scale = scale
        self.time_scale = time_scale # time period of each data point
        self.time_cursor = 'time_cursor'
        self.data_idx = None

    def init_gui(self):
        with dpg.window(label=self.name, width=800, height=500, tag=self.name):
            with dpg.plot(label='Plot', height=-1, width=-1) as plot_id:
                self.x_axis = dpg.add_plot_axis(dpg.mvXAxis, label="")
                self.y_axis = dpg.add_plot_axis(dpg.mvYAxis, label="")
                dpg.set_axis_limits_auto(self.x_axis)
                dpg.set_axis_limits_auto(self.y_axis)

    def update(self, messages: List[Message]):
        # message data format time x channel
        if self.buffer is None:
            self.buffer = RingBuffer((self.buffer_length, messages[0].data.shape[1]))

        for m in messages:
            if m.data.shape[0] > self.buffer.length:
                #if the input data is too large, resize the data buffer
                self.buffer = RingBuffer((m.data.shape[0]*2, m.data.shape[1]))
            else:
                self.buffer.write(m.data)

        ####
        # update the plot

        # Re-arrange the data to be suitable for plotting
        ydata = self.buffer.buffer.T.copy()
        shift = np.arange(ydata.shape[0])[None,].T * self.scale
        ydata += shift #shift the data for different channel

        ydata = ydata.tolist()

        xdata = np.arange(len(ydata[0]))
        if self.time_scale:
            xdata = xdata *self.time_scale

        xdata = xdata.tolist()

        series_name = [f'{i}_{self.name}' for i in range(len(ydata))]

        if self.first_run:
            self.first_run = False
            # print(series_name)
            for i in range(len(ydata)):
                dpg.add_line_series(xdata, ydata[i], label=series_name[i], parent=self.y_axis, tag=series_name[i])
                dpg.fit_axis_data(self.y_axis)
                dpg.fit_axis_data(self.x_axis)

            # dpg.add_vline_series([1.0], parent = self.y_axis, tag=self.time_cursor)
        else:
            for i in range(len(ydata)):
                dpg.set_value(series_name[i],(xdata,ydata[i])) #must be called in main thread

        # print(message)
        # self.plot_data[1][self.data_count%500]=message.data[0]
        # self.data_count += 1

        # dpg.set_value(self.plot_data_tag, self.plot_data)


from fastapi import Request, HTTPException
from fastapi.security import HTTPBearer,HTTPAuthorizationCredentials

from auth.authenticateHandler import decodeJWT

class JWTBearer(HTTPBearer):
    def __init__(self,auto_error:bool = True):
        super(JWTBearer,self).__init__(auto_error=auto_error)

    async def __call__(self,request:Request):
        creadentials:HTTPAuthorizationCredentials = await super(JWTBearer,self).__call__(request)
        if creadentials:
            if not creadentials.scheme == "Bearer":
                raise HTTPException(status_code=403,detail={})
            if not self.verifyJWT(creadentials.credentials):
                raise HTTPException(status_code=403,detail="Invalid token or expired token")
            return creadentials.credentials
        else:
            raise HTTPException(status_code=403,detail="Invalid Authorization token")

    def verifyJWT(self,JWTToken:str) -> bool:
        isTokenValid:bool = False
        try:
            payload = decodeJWT(JWTToken)
        except:
            payload = None
        if payload:
            isTokenValid = True
        return isTokenValid


import platform

import gym
from allenact.algorithms.onpolicy_sync.losses import PPO
from allenact.algorithms.onpolicy_sync.losses.ppo import PPOConfig
from allenact.utils.experiment_utils import TrainingPipeline, Builder, PipelineStage, LinearDecay
from allenact_plugins.ithor_plugin.ithor_sensors import RGBSensorThor
from torch import nn, optim
from torch.optim.lr_scheduler import LambdaLR

from ithor_arm.bring_object_sensors import TargetObjectBBox, TargetLocationBBox
from ithor_arm.bring_object_task_samplers import DiverseBringObjectTaskSampler, OnlyAppleBreadBringObjectTaskSampler
from ithor_arm.ithor_arm_constants import ENV_ARGS, TRAIN_OBJECTS, TEST_OBJECTS
from ithor_arm.ithor_arm_sensors import (
    InitialAgentArmToObjectSensor,
    InitialObjectToGoalSensor,
    PickedUpObjSensor,
    DepthSensorThor, RelativeAgentArmToObjectSensor, RelativeObjectToGoalSensor,
)
from manipulathor_baselines.bring_object_baselines.experiments.bring_object_mixin_ddppo import BringObjectMixInPPOConfig
from manipulathor_baselines.bring_object_baselines.experiments.bring_object_mixin_simplegru import BringObjectMixInSimpleGRUConfig
from manipulathor_baselines.bring_object_baselines.experiments.ithor.bring_object_ithor_base import BringObjectiThorBaseConfig
from manipulathor_baselines.bring_object_baselines.losses.bring_object_losses import PredictBoxBCELsss
from manipulathor_baselines.bring_object_baselines.models.pickup_object_with_mask_model import PickUpWMaskBaselineActorCritic
from manipulathor_baselines.bring_object_baselines.models.temp_pred_box_bring_object import PredictBBoxwTFBringObjectModel
from manipulathor_baselines.bring_object_baselines.models.small_bring_object_with_mask_model import SmallBringObjectWMaskDepthBaselineActorCritic
from manipulathor_baselines.bring_object_baselines.models.small_depth_pickup_object_with_mask_model import SmallPickUpWMaskDepthBaselineActorCritic
from manipulathor_utils.debugger_util import ForkedPdb

class AttentionBBoxBringObject(
    BringObjectiThorBaseConfig,
    BringObjectMixInPPOConfig,
    BringObjectMixInSimpleGRUConfig,
):
    """An Object Navigation experiment configuration in iThor with RGB
    input."""

    SENSORS = [
        DepthSensorThor(
            height=BringObjectiThorBaseConfig.SCREEN_SIZE,
            width=BringObjectiThorBaseConfig.SCREEN_SIZE,
            use_normalization=True,
            uuid="depth_lowres",
        ),
        RGBSensorThor(
            height=BringObjectiThorBaseConfig.SCREEN_SIZE,
            width=BringObjectiThorBaseConfig.SCREEN_SIZE,
            use_resnet_normalization=True,
            uuid="rgb_lowres",
        ),
        PickedUpObjSensor(),
        TargetObjectBBox(),
        TargetLocationBBox(),
    ]

    MAX_STEPS = 200
    TASK_SAMPLER = OnlyAppleBreadBringObjectTaskSampler
    NUM_PROCESSES = 40
    # TRAIN_SCENES = ['FloorPlan1_physics']
    # TEST_SCENES = ['FloorPlan1_physics']
    OBJECT_TYPES = TRAIN_OBJECTS + TEST_OBJECTS

    def __init__(self):
        super().__init__()

        assert (
            self.CAMERA_WIDTH == 224
            and self.CAMERA_HEIGHT == 224
            and self.VISIBILITY_DISTANCE == 1
            and self.STEP_SIZE == 0.25
        )
        self.ENV_ARGS = {**ENV_ARGS, "renderDepthImage": True}

    @classmethod
    def create_model(cls, **kwargs) -> nn.Module:
        return PredictBBoxwTFBringObjectModel(
            action_space=gym.spaces.Discrete(
                len(cls.TASK_SAMPLER._TASK_TYPE.class_action_names())
            ),
            observation_space=kwargs["sensor_preprocessor_graph"].observation_spaces,
            hidden_size=512,
        )

    def training_pipeline(self, **kwargs):
        print('resolve todo')
        ForkedPdb().set_trace()
        ppo_steps = int(300000000)
        lr = 3e-4
        num_mini_batch = 1
        update_repeats = 4
        num_steps = 128 #self.MAX_STEPS
        #
        save_interval = 500000  # from 50k
        log_interval = 1000
        gamma = 0.99
        use_gae = True
        gae_lambda = 0.95
        max_grad_norm = 0.5
        return TrainingPipeline(
            save_interval=save_interval,
            metric_accumulate_interval=log_interval,
            optimizer_builder=Builder(optim.Adam, dict(lr=lr)),
            num_mini_batch=num_mini_batch,
            update_repeats=update_repeats,
            max_grad_norm=max_grad_norm,
            num_steps=num_steps,
            named_losses={"ppo_loss": PPO(**PPOConfig), "pred_box_bce": PredictBoxBCELsss()},
            gamma=gamma,
            use_gae=use_gae,
            gae_lambda=gae_lambda,
            advance_scene_rollout_period=self.ADVANCE_SCENE_ROLLOUT_PERIOD,
            pipeline_stages=[
                # PipelineStage(loss_names=["ppo_loss"], max_stage_steps=ppo_steps)
                PipelineStage(
                    loss_names=["ppo_loss", "pred_box_bce"],
                    loss_weights=[1.0, 1.0], #LATER_TODO how is this?
                    max_stage_steps=ppo_steps,
                )
            ],

            lr_scheduler_builder=Builder(
                LambdaLR, {"lr_lambda": LinearDecay(steps=ppo_steps)}
            ),
        )
    @classmethod
    def tag(cls):
        return cls.__name__


import sys
import logging
from utils.settings import data

# Set the logging settings
formatting = '%(asctime)s [%(levelname)s]: %(message)s'
if data.get('logging') not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
    logging.error("Check the JSON configuration logging option. Only options allowed:"
                  "\nDEBUG"
                  "\nINFO"
                  "\nWARNING"
                  "\nERROR"
                  "\nCRITICAL")
    sys.exit(1)
level = logging.getLevelName(data.get('logging'))
logging.basicConfig(format=formatting, level=level)


# 1
def is_odd(number):
    if number % 2 == 1:     # 2로 나누었을 때 나머지가 1이면 홀수이다.
        return True
    else:
        return False

n1 = is_odd(10)
print(n1)
print(is_odd(11))

# 2
def avg_numbers(*args):
    result = 0      # 합계
    for i in args:
        result += i
    return result / len(args)   # 평균 = 합계 / 개수

print(avg_numbers(1, 2))        # 1.5 출력
print(avg_numbers(1,2,3,4,5))   # 3.0 출력

"""
# 3
input1 = input("첫번째 숫자를 입력하세요 : ")
x = int(input1)
input2 = input("두번째 숫자를 입력하세요 : ")
y = int(input2)

total = x + y
# total = int(input1) + int(input2)
print("두 수의 합은 %s 입니다" % total)
"""

# 4
print("you""need""python")
print("you"+"need"+"python")
print("you","need","python")
print("".join(["you","need","python"]))
# join() : 리스트의 요소를 문자열로 바꿈

# 5
"""
f1 = open("test.txt", 'w')
f1.write("Life is too short")
f1.close()

f2 = open("test.txt", 'r')
print(f2.read())
f2.close()
"""

with open("test.txt", 'w') as f1:
    f1.write("Life is too short")

with open("test.txt", 'r') as f2:
    print(f2.read())

# 6
user_input = input("저장할 내용을 입력하세요 : ")
f = open("test2.txt", 'a')       # 내용을 추가하기 위해 'a'를 사용
f.write(user_input)
f.write('\n')       # 입력한 내용을 줄 단위로 구분하기 위해 줄 바꿈 문자 삽입
f.close()


"""
Fludetector: website, REST API, and data processors for the Fludetector service from UCL.
(c) 2019, UCL <https://www.ucl.ac.uk/

This file is part of Fludetector

Fludetector 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.

Fludetector is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Fludetector.  If not, see <http://www.gnu.org/licenses/>.
"""
import csv
import os
from functools import wraps
from collections import defaultdict
from datetime import timedelta
from StringIO import StringIO

import sh
from flask import Flask, request, jsonify, render_template, make_response, Response, abort, redirect, url_for, flash
from flask_dotenv import DotEnv

from fludetector import models, scripts, forms
from fludetector.errors import FluDetectorError
from fludetector.models import db, get_region, REGIONS, Model, ModelScore, GoogleScore

app = Flask(__name__)
env = DotEnv(app)

os.environ['GOOGLE_API_KEY'] = app.config['GOOGLE_API_KEY']
os.environ['MODEL_ENGINE'] = app.config['MODEL_ENGINE']
os.environ['TWITTER_ENABLED'] = app.config.get('TWITTER_ENABLED', 'False')

models.init_app(app)
scripts.init_app(app)

@app.errorhandler(FluDetectorError)
def handle_bad_request(e):
    return jsonify({'error': e.message})

def check_auth(username, password):
    """This function is called to check if a username password combination is valid."""
    return username == app.config['ADMIN_USERNAME'] and password == app.config['ADMIN_PASSWORD']

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
        'Could not verify your access level for that URL.\n'
        'You have to login with proper credentials', 401,
        {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

def calculate_averages(scores):
    averages = defaultdict(lambda: defaultdict(list))
    for (s, smoothed) in scores:
        averages[s.model][s.region].append(smoothed)
    for model, regions in averages.iteritems():
        for region, scores in regions.iteritems():
            yield (model, get_region(region), sum(scores) / len(scores))

def calculate_raw_scores(scores):
    raw_scores = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
    for s, smoothed in scores:
        raw_scores[s.day][s.model][s.region] = smoothed
    return raw_scores

def get_scores_form(public=True):
    all_models = Model.query
    if public:
        all_models = all_models.filter_by(public=public)
    all_models = all_models.all()
    score = None
    for m in all_models:
        score = m.last_score
        if score is not None:
            break
    form = forms.GetScoresWebForm(request.args, model_regions=[(score.model, score.region)])
    return all_models, form

def is_admin_enabled():
    return app.config.get('ADMIN_ENABLED')

@app.route('/')
def home():
    all_models, form = get_scores_form()
    scores = form.scores()

    return render_template(
        'home.html',
        models=all_models,
        form=form,
        regions=REGIONS,
        averages=calculate_averages(scores),
        raw_scores=calculate_raw_scores(scores),
        admin_enabled=is_admin_enabled()
    )

@app.route('/export/')
def export():
    all_models, form = get_scores_form()

    raw_scores = calculate_raw_scores(form.scores())

    fd = StringIO()
    csv_fd = csv.writer(fd)

    headers = [
        [''] + [m.name for m, r in form.model_regions.data],
        ['Date'] + [REGIONS[r] for m, r in form.model_regions.data]
    ]
    for r in headers:
        csv_fd.writerow(r)

    for day, models_ in sorted(raw_scores.iteritems()):
        row = [[day.strftime('%Y-%m-%d')]]
        row.append([models_[m][r] for m, r in form.model_regions.data])
        csv_fd.writerow(row)

    resp = make_response(fd.getvalue())
    resp.headers["Content-Disposition"] = "attachment; filename=fluedetector-export.csv"
    resp.headers["Content-type"] = "text/csv"
    return resp

@app.route('/about/')
def about():
    return render_template('about.html')

@app.route('/docs/')
def docs():
    model = Model.query.filter_by(public=True).first()
    score = model.scores.first()
    example = {
        'model': model.id,
        'region': score.region,
        'resolution': 'day',
        'smoothing': 3,
        'start': score.day - timedelta(days=7),
        'end': score.day + timedelta(days=7)
    }
    return render_template('docs.html', example=example, model=model)

@app.route('/api/scores/')
def api_scores():
    form = forms.GetScoresApiForm(request.args)

    if not form.validate():
        return jsonify({'errors': form.errors}), 400

    model = form.model.data

    return jsonify({
        'model': {'id': model.id, 'name': model.name},
        'region': form.region.data,
        'start': form.start.data.strftime('%Y-%m-%d'),
        'end': form.end.data.strftime('%Y-%m-%d'),
        'resolution': form.resolution.data,
        'smoothing': form.smoothing.data,
        'scores': form.scores()})

@app.route('/api/models/')
def api_models():
    models = Model.query.filter_by(public=True).all()
    return jsonify([
        {'id': m.id, 'name': m.name}
        for m in models])

@app.route('/admin/')
@requires_auth
def admin_home():
    all_models, form = get_scores_form(public=False)
    scores = form.scores()

    return render_template(
        'admin/home.html',
        models=all_models,
        form=form,
        regions=REGIONS,
        all_model_regions=[(m, r) for m in all_models for r in m.regions],
        averages=calculate_averages(scores),
        raw_scores=calculate_raw_scores(scores))

@app.route('/admin/models/')
@requires_auth
def admin_list_models():
    return render_template(
        'admin/model_list.html',
        models=Model.query.all(),
        region_codes=list(REGIONS.keys()))

@app.route('/admin/models/<int:id>/')
@requires_auth
def admin_retrieve_model(id):
    model = Model.query.get(id)
    if not model:
        abort(404)
    return render_template('admin/model_retrieve.html', model=model, REGIONS=REGIONS)

@app.route('/admin/models/<int:id>/delete/', methods=['GET', 'POST'])
@requires_auth
def admin_delete_model(id):
    model = Model.query.get(id)
    if not model:
        abort(404)
    form = forms.DeleteModelForm(model)
    if form.validate_on_submit():
        for term in model.google_terms:
            # Delete any orphaned GoogleTerms
            # There should be a way to cascade these deletes automatically?
            # I couldn't work it out :(
            if len(term.models) == 1:
                db.session.delete(term)
        db.session.delete(model)
        db.session.commit()
        flash('Model deleted!', 'success')
        return redirect(url_for('admin_list_models'))
    return render_template('admin/model_delete.html', form=form, model=model)

@app.route('/admin/models/create/', methods=['GET', 'POST'])
@requires_auth
def admin_create_model():
    form = forms.CreateModelForm.factory(request.args.get('type', 'csv'))
    if form.validate_on_submit():
        model = Model()
        form.populate_obj(model)
        db.session.add(model)
        db.session.commit()
        return redirect(url_for('admin_retrieve_model', id=model.id))
    return render_template('admin/model_create.html', form=form)

@app.route('/admin/models/<int:id>/update/', methods=['GET', 'POST'])
@requires_auth
def admin_update_model(id):
    model = Model.query.get(id)
    if not model:
        abort(404)
    form = forms.CreateModelForm.factory(model.type, model=model)
    if form.validate_on_submit():
        form.populate_obj(model)
        db.session.add(model)
        db.session.commit()
        return redirect(url_for('admin_retrieve_model', id=model.id))
    return render_template('admin/model_create.html', form=form, model=model)

@app.route('/admin/models/<int:id>/run/', methods=['GET', 'POST'])
@requires_auth
def admin_run_model(id):
    model = Model.query.get(id)
    if not model:
        abort(404)
    form = forms.RunModelForm.factory(model)
    if form.validate_on_submit():
        run = sh.Command('./scripts/run.sh')
        run('runmodel', str(id), _bg=True, **form.to_dict())
        flash('Model running in background, check logs for details', 'info')
        return redirect(url_for('admin_list_models'))
    return render_template('admin/model_run.html', form=form, model=model)

@app.route('/admin/logs/')
@requires_auth
def admin_list_logs():
    logs = os.listdir('logs')
    return render_template('admin/log_list.html', logs=logs)

@app.route('/admin/logs/<filename>')
@requires_auth
def admin_retrieve_log(filename):
    """This feels dangerous. However, filename cannot contain slashes so we
    should be confined to direct children of the logs directory. Also, only
    admins can access this file so hopefully exposure is minimal.

    Famous last words :)
    """
    with open(os.path.join('logs', filename), 'rb') as fd:
        return fd.read(), {'Content-Type': 'text/plain'}

def admin_export_google(model, start, end, writer):
    writer.writerow(['Term', 'Day', 'Value'])
    for term in model.google_terms:
        scores = term.scores.filter(GoogleScore.day >= start, GoogleScore.day < end)
        for score in scores:
            writer.writerow([term.term, score.day.strftime('%Y-%m-%d'), score.value])

def admin_export_csv(model, start, end, writer):
    scores = model.scores.filter(ModelScore.day >= start, ModelScore.day < end)
    by_date = defaultdict(lambda: defaultdict(int))
    regions = set()
    for s in scores:
        regions.add(s.region)
        by_date[s.day][s.region] = s.value
    regions = list(regions)
    writer.writerow(['Date'] + [REGIONS[code] for code in regions])
    for day, by_region in sorted(by_date.iteritems()):
        writer.writerow([day.strftime('%Y-%m-%d')] + [by_region.get(code) for code in regions])

@app.route('/admin/models/<int:id>/export/', methods=['GET', 'POST'])
@requires_auth
def admin_export_model(id):
    model = Model.query.get(id)
    if not model:
        abort(404)
    form = forms.ExportModelForm()

    if form.validate_on_submit():
        fd = StringIO()
        csv_fd = csv.writer(fd)

        {
            'google': admin_export_google,
            'csv': admin_export_csv
        }.get(model.type)(model, form.start.data, form.end.data, csv_fd)

        resp = make_response(fd.getvalue())
        resp.headers["Content-Disposition"] = "attachment; filename=fluedetector-export.csv"
        resp.headers["Content-type"] = "text/csv"
        return resp

    return render_template('admin/model_export.html', form=form, model=model)


import numpy as np
import os
from tqdm import tqdm
import math
from os import listdir
from os.path import isfile, join
import sys
import argparse
import random

MAX = 5500000

parser = argparse.ArgumentParser(description='Runs sample data')

parser.add_argument('-n', dest="n", type=int,
                    required=True,
                    help='N samples to extract\n'
                         '(type: int)\n'
                         '(REQUIRED)')

parser.add_argument('-src', dest="src", type=str,
                    required=True,
                    help='Path to source file\n'
                         '(type: str)\n'
                         '(REQUIRED)')

parser.add_argument('-tgt', dest="tgt", type=str,
                    required=True,
                    help='Path to target file\n'
                         '(type: str)\n'
                         '(REQUIRED)')

args = parser.parse_args()

N = args.n

src = args.src
tgt = args.tgt

sample_dir = "sample"
try:
  os.mkdir(sample_dir)
except:
  print(sample_dir+" dir already exist")

data = []
with open(src, "r") as s_file, open(tgt, "r") as t_file:
  for s, t in tqdm(zip(s_file, t_file)):
    data.append([s.rstrip(), t.rstrip()])
    #tgt_data.append(t.rstrip())

res = random.sample(data, N)

print(len(res))

name_s = src.split("/")[-1]
name_t = tgt.split("/")[-1]
with open(sample_dir+"/"+name_s.split(".")[0]+"_"+str(N)+"."+name_s.split(".")[1], "w") as s_file, open(sample_dir+"/"+name_t.split(".")[0]+"_"+str(N)+"."+name_t.split(".")[1], "w") as t_file:
  for s, t in res:
    s_file.write(s+'\n')
    t_file.write(t+'\n')


"""This is 'myclass.py' it is a programme that returns
the following:
    1. The artist in a list.
    2. The albums of the list of a particular artist.

This program utilises a class with two functions."""

# define the class

class MyAlbumCollection():
    """'MyAlbumCollection' class that receives three variables namely:
        a. artist - for receiving the artist name in any class object
        b. album_name - "                   "                       "
        c. number_of_tracks - "              "                      "
    """
    # initiate the variables through the constuctor

    def __init__(self, artist, album_name, number_of_tracks):
        self.artist = artist
        self.album_name = album_name
        self.number_of_tracks = number_of_tracks
    # function 1

    def artist_list(self):
        """'artist_list' function returns the artist in a
        album collection list"""
        artists = self.artist
        print(artists)
    # function2

    def artist_album(self):
        """'artist_album' this function returns a list of artists with
        their corresponding albums"""
        albums = self.album_name
        for i in albums:
            print(i)

    def number_tracks(self):
        """'number_tracks' a function for returning the number of
        tracks in a collection"""
        calc = sum(self.number_of_tracks)
        return calc

# set album collections by creating class objects
ALBUMS1 = MyAlbumCollection(
    'Fred Hammond', ['Speak those things', 'The Spirit of David'], [12, 10])
ALBUMS2 = MyAlbumCollection(
    'J Moss', ['Grown folks gospel', 'Psalm 150'], [11, 14])
ALBUMS3 = MyAlbumCollection('Carmen', ['The Champion', 'Redemption'], [10, 13])
# call some test functions
ALBUMS1.artist_album()
ALBUMS3.artist_list()
print(f'{ALBUMS2.number_tracks()} tracks in the {ALBUMS2.artist} collection')
# sum all the tracks on the collections
NUMBER = [ALBUMS1, ALBUMS2, ALBUMS3]
TOTALTRACKS = []
for num in NUMBER:
    TOTALTRACKS.append(MyAlbumCollection.number_tracks(num))
print(
    f'The total no. of tracks of all the collections is, {sum(TOTALTRACKS)}.')