from __future__ import absolute_import

import itertools
import logging
from genshi import Markup, Namespace, Stream, QName
from genshi.core import START, TEXT
from genshi.template.eval import Expression

import flatland
from flatland.util import Maybe
from . taglistener import TagListener, default_start

__all__ = 'flatland_filter',

log = logging.getLogger('flatland.out.genshi')

NAMESPACE  = Namespace(u'http://ns.discorporate.us/flatland/genshi')

# filter attributes
F_BIND     = NAMESPACE[u'bind']

# HTML attributes
H_CHECKED = QName(u'checked')
H_FOR = QName(u'for')
H_ID = QName(u'id')
H_NAME = QName(u'name')
H_SELECTED = QName(u'selected')
H_TABINDEX = QName(u'tabindex')
H_VALUE = QName(u'value')

MAYBE = (u'auto',)
YES   = (u'1', u'true', u't', u'on', u'yes')
NO    = (u'0', u'false', u'nil', u'off', u'no')

# TODO:jek remember why mixing - and _ in these was a good idea and document
CTX_CUR_TABINDEX      = u'auto-tabindex_value'
CTX_FMT_DOMID         = u'auto-domid_format'
CTX_FILTERS           = u'auto-filter_filters'

def flatland_filter(stream, context):
    """flatland_filter(stream, context) -> stream

    Filter a stream through FlatlandFilter

    """
    return Stream(FlatlandFilter()(stream, context))

class ToggledAttribute(object):
    toggle_attribute = None
    toggle_default = False
    toggle_context_key = None

    attribute = None
    auto_tags = ()

    def pop_toggle(self, attrs, context):
        attrs, proceed = self.pop_attribute(
            attrs, self.toggle_attribute, u'auto', parse_trool)
        forced = proceed is True
        if proceed is Maybe:
            proceed = parse_trool(context.get(self.toggle_context_key, u'auto'))
            if proceed is Maybe:
                proceed = self.toggle_default
        return attrs, proceed, forced

    def pop_attribute(self, attrs, name, default=None, transform=None):
        value = attrs.get(name, default)
        if transform:
            value = transform(value)
        return (attrs - name), value

class NameAttribute(ToggledAttribute):
    toggle_default = True
    toggle_attribute = NAMESPACE[u'auto-name']
    toggle_context_key = u'auto-name'

    attribute = H_NAME
    auto_tags = set((u'input', u'button', u'select', u'textarea', u'form'))

    def apply_to(self, tag, attrs, context, node):
        attrs, proceed, forced = self.pop_toggle(attrs, context)

        if not proceed:
            return attrs

        # Abort on unbound or anonymous nodes
        if node is None or node.name is None:
            return attrs

        current = attrs.get(self.attribute, None)
        if forced or current is None and tag.localname in self.auto_tags:
            attrs |= ((self.attribute, node.flattened_name()),)
        return attrs

class ValueAttribute(ToggledAttribute):
    toggle_default = True
    toggle_attribute = NAMESPACE[u'auto-value']
    toggle_context_key = u'auto-value'

    attribute = H_VALUE
    auto_tags = set((u'input', u'select', u'textarea', u'button'))

    apply_child = (u'textarea',)
    apply_mixed = ()

    def apply_to(self, tag, attrs, stream, context, node):
        attrs, proceed, forced = self.pop_toggle(attrs, context)

        if not proceed:
            return stream, attrs

        # Abort on unbound nodes.
        if node is None:
            return stream, attrs

        if not forced and tag.localname not in self.auto_tags:
            return stream, attrs

        # VALUE_CHILD (e.g. <textarea>) always replaces the stream with
        # the node's string value.
        if tag.localname in self.apply_child:
            stream = self.set_stream_value(stream, node.u)

        elif tag.localname == u'select':
            stream = self.set_select(forced, attrs, stream, node)

        elif tag.localname in self.apply_mixed:
            stream, attrs = self.set_mixed_value(forced, attrs, stream, node)

        elif tag.localname == u'input':
            attrs = self.set_input(forced, attrs, node)

        else:
            attrs = self.set_simple_value(forced, attrs, node)

        return stream, attrs

    def set_stream_value(self, stream, text):
        stream = stream_is_empty(stream)
        if stream is None:
            return Stream([(TEXT, text, (None, -1, -1))])
        else:
            return stream

    def set_simple_value(self, override, attrs, node):
        current = attrs.get(H_VALUE)
        if current is None or override is True:
            attrs |= ((H_VALUE, node.u),)
        return attrs

    def set_mixed_value(self, override, attrs, stream, node):
        """
        For output nodes that may either take a 'value=""' or encode
        their value in nested content.  Node value will be passed
        along as unescaped markup if child nodes are generated!

        """
        if attrs.get(H_VALUE, None) is None:
            stream = self.set_stream_value(stream, Markup(node))
        else:
            attrs = self.set_simple_value(override, attrs, node)
        return stream, attrs

    def set_input(self, override, attrs, node):
        type = attrs.get(u'type', u'text').lower()

        if type in (u'text', u'hidden', u'button', u'submit', u'reset'):
            attrs = self.set_simple_value(override, attrs, node)
        elif type in (u'password', u'file', u'image'):
            if override is True:
                attrs = self.set_simple_value(override, attrs, node)
        elif type == u'checkbox':
            value = attrs.get(H_VALUE, None)
            if value is None and isinstance(node, flatland.Boolean):
                value = node.true
                attrs |= ((H_VALUE, value),)
            attrs = self.set_checked(attrs, node)
        elif type == u'radio':
            attrs = self.set_checked(attrs, node)
        else:
            if override is True:
                attrs = self.set_simple_value(override, attrs, node)
        return attrs

    def set_select(self, override, attrs, stream, node):
        return OptionToggler(node.u)(stream)

    def set_checked(self, attrs, node):
        value = attrs.get(H_VALUE, None)
        if value is None:
            return attrs
        if value == node.u:
            attrs |= ((H_CHECKED, u'checked'),)
        elif isinstance(node, flatland.Compound):
            attrs -= H_CHECKED
        else:
            for child in node.children:
                if value == child.u:
                    attrs |= ((H_CHECKED, u'checked'),)
                    break
            else:
                attrs -= H_CHECKED
        return attrs

class DomIDAttribute(ToggledAttribute):
    toggle_attribute = NAMESPACE[u'auto-domid']
    toggle_context_key = u'auto-domid'

    attribute = H_ID
    auto_tags = set((u'input', u'button', u'select', u'textarea'))

    def apply_to(self, tag, attrs, context, el):
        attrs, proceed, forced = self.pop_toggle(attrs, context)
        if not proceed:
            return attrs

        current = attrs.get(self.attribute, None)
        if forced or current is None and tag.localname in self.auto_tags:
            if el is not None:
                domid = self.id_for(el, context)
            else:
                domid = self.id_for_unbound(tag, attrs, context)
            attrs |= ((self.attribute, domid),)
        return attrs

    @classmethod
    def id_for(cls, el, context):
        fmt = context.get(CTX_FMT_DOMID, u'f_%s')
        return fmt % el.flattened_name()

    @classmethod
    def id_for_unbound(cls, tag, attrs, context):
        if tag in cls.auto_tags:
            name = attrs.get(H_NAME, None)
            if name is not None:
                fmt = context.get(CTX_FMT_DOMID, u'f_%s')
                return fmt % name
        return None

class ForAttribute(ToggledAttribute):
    toggle_attribute = NAMESPACE[u'auto-for']
    # tied to ID generation
    toggle_context_key = u'auto-domid'

    attribute = H_FOR
    auto_tags = set((u'label',))

    def apply_to(self, tag, attrs, context, node):
        attrs, proceed, forced = self.pop_toggle(attrs, context)
        if not proceed or node is None:
            return attrs

        current = attrs.get(self.attribute, None)
        if forced or current is None and tag.localname in self.auto_tags:
            attrs |= ((self.attribute, DomIDAttribute.id_for(node, context)),)
        return attrs

class TabIndexAttribute(ToggledAttribute):
    toggle_attribute = NAMESPACE[u'auto-tabindex']
    toggle_context_key = u'auto-tabindex'

    attribute = H_TABINDEX
    auto_tags = set((u'input', u'button', u'select', u'textarea'))

    def apply_to(self, tag, attrs, context):
        attrs, proceed, forced = self.pop_toggle(attrs, context)
        if not proceed:
            return attrs

        tabindex = context.get(CTX_CUR_TABINDEX, 0)
        if tabindex == 0:
            return attrs

        current = attrs.get(self.attribute, None)
        if forced or current is None and tag.localname in self.auto_tags:
            attrs |= ((self.attribute, unicode(tabindex)),)
            context[CTX_CUR_TABINDEX] = tabindex + 1
        return attrs

class Filter(ToggledAttribute):
    toggle_default = True
    toggle_attribute = NAMESPACE[u'auto-filter']
    toggle_context_key = u'auto-filter'

    def apply_to(self, tag, attrs, stream, context, node):
        attrs, proceed, forced = self.pop_toggle(attrs, context)
        filters = context.get(CTX_FILTERS, ())

        if not (proceed and filters):
            return tag, attrs, stream

        for filter_expr in filters:
            if callable(filter_expr):
                fn = filter_expr
            else:
                try:
                    fn = Expression(filter_expr).evaluate(context)
                except:
                    log.error("Failed to parse filter expression %r" %
                              filter_expr,)
                    raise
            want = getattr(fn, 'tags', None)
            if want is None or tag.localname not in want:
                continue

            tag, attrs, stream = fn(tag, attrs, stream, context, node)
            if isinstance(stream, basestring):
                stream = Stream([(TEXT, stream, (None, -1, -1))])

        return tag, attrs, stream

class OptionToggler(TagListener):
    __slots__ = (u'value',)

    activated = ((H_SELECTED, u'selected'),)

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

    def inspect(self, event, context):
        kind, data, pos = event

        if kind is START and data[0].localname == u'option':
            return (default_start, self.end)
        else:
            return False

    def end(self, start, end, stream, context, history):
        kind, (tag, attrs), pos = start
        attrs -= H_SELECTED

        value = attrs.get(H_VALUE, None)
        if value is not None:
            if value == self.value:
                attrs |= ((H_SELECTED, u'selected'),)
        else:
            children = list(stream)
            value = u''
            for ck, cd, cp in children:
                if ck is TEXT: value += cd
            stream = Stream(children)

            if value.strip() == self.value.strip():
                attrs |= ((H_SELECTED, u'selected'),)

        start = kind, (tag, attrs), pos

        return start, end, stream

class DecoratedElementDirective(object):
    set_name = NameAttribute().apply_to
    set_value = ValueAttribute().apply_to
    set_domid = DomIDAttribute().apply_to
    set_tabindex = TabIndexAttribute().apply_to
    set_for = ForAttribute().apply_to
    apply_filters = Filter().apply_to

    def start(self, event, context):
        kind, (tag, attrs), pos = event

        node = self.find_binding(tag, attrs, context)

        # Node-free transformations
        attrs = self.set_tabindex(tag, attrs, context)

        # Node-sensitive transformations
        attrs = self.set_domid(tag, attrs, context, node)

        return (kind, (tag, attrs), pos), dict(binding=node)

    def end(self, start, end, stream, context, history):
        kind, (tag, attrs), pos = start

        node = history.get('binding', None)
        attrs -= F_BIND

        # Set <... name=""> for bound nodes.
        attrs = self.set_name(tag, attrs, context, node)

        # Map <label for="..."> to bound tags.
        attrs = self.set_for(tag, attrs, context, node)

        # Set <... value=""> or tag-specific equivalent.
        stream, attrs = self.set_value(tag, attrs, stream, context, node)

        # Run user filters after all transformations are applied.
        filtered_tag, attrs, stream = \
          self.apply_filters(tag, attrs, stream, context, node)

        if filtered_tag != tag:
            tag = filtered_tag
            # Re-assemble end event with the new tag name.
            end = end[0], tag, end[2]

        # Re-assemble the start event.
        start = (kind, (tag, attrs), pos)

        return start, end, stream

    def find_binding(self, tag, attributes, context):
        expr = attributes.get(F_BIND, None)
        if expr is None:
            return expr
        try:
            return Expression(expr).evaluate(context)
        except:
            log.error("Failed to parse binding %r" % expr,)
            raise

class ImmediateVarDirective(object):
    toggles = (u'auto-tabindex', u'auto-domid', u'auto-for',
               u'auto-name', u'auto-value', u'auto-filter')
    name = u'set'

    def start(self, event, context):
        kind, (tag, attrs), pos = event

        for toggle in self.toggles:
            val = attrs.get(toggle, None)
            if val is not None:
                context[toggle] = parse_trool(val)

        val = parse_int(attrs.get(u'tabindex', None))
        if val is not None:
            context[CTX_CUR_TABINDEX] = val

        val = attrs.get(u'domid-format', None)
        if val is not None:
            context[CTX_FMT_DOMID] = val

        val = parse_simple_csv(attrs.get(u'filters', None))
        if val:
            context[CTX_FILTERS] = val

        return None, None

    def end(self, start, end, stream, context, history):
        return None, None, stream

class ScopedVarDirective(ImmediateVarDirective):
    name = u'with'

    def start(self, event, context):
        context.push({})
        return ImmediateVarDirective.start(self, event, context)

    def end(self, start, end, stream, context, history):
        context.pop()
        return ImmediateVarDirective.end(self, start, end, stream,
                                         context, history)

class FlatlandFilter(TagListener):
    """TODO: Document

    Binds template form elements to flatland data elements and
    automatically sets name, and value.  Manages DOM id generation,
    links <label> to matching elements and manages tabindex.

    """

    dir_with = ScopedVarDirective()
    dir_set  = ImmediateVarDirective()
    dir_el = DecoratedElementDirective()

    inspect_with = (dir_with.start, dir_with.end)
    inspect_set = (dir_set.start, dir_set.end)
    inspect_el = (dir_el.start, dir_el.end)

    def inspect(self, event, context):
        if event[0] is not START:
            return False

        kind, (tag, attributes), pos = event

        if tag in NAMESPACE:
            if tag.localname == self.dir_with.name:
                return self.inspect_with
            elif tag.localname == self.dir_set.name:
                return self.inspect_set
        else:
            for attr, value in attributes:
                if attr in NAMESPACE:
                    return self.inspect_el

def stream_is_empty(stream):
    stream, dupe = itertools.tee(stream)
    try:
        dupe.next()
    except StopIteration:
        return None
    else:
        return stream

def parse_bool(value, yes=YES, no=NO):
    if value is True or value is False or value is None:
        return value
    if isinstance(value, unicode):
        value = value.lower()
    else:
        value = unicode(value).lower()
    if value in yes:
        return True
    if value in no:
        return False
    return None

def parse_trool(value):
    if value is True or value is False or value is Maybe:
        return value
    if isinstance(value, unicode):
        value = value.lower()
    else:
        value = unicode(value).lower()
    if value in YES:
        return True
    if value in NO:
        return False
    if value in MAYBE:
        return Maybe
    return Maybe

def parse_int(text):
    if type(text) is int:
        return text
    try:
        return int(text)
    except:
        return None

def parse_simple_csv(text):
    parts = []
    if text is None:
        return parts
    for part in (p.strip() for p in text.split(u',')):
        if part:
            parts.append(part)
    return parts


# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-

# This file is part of Guadalinex
#
# This software 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 2 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this package; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

__author__ = "David Amian <damian@emergya.com>"
__copyright__ = "Copyright (C) 2011, Junta de Andalucía <devmaster@guadalinex.org>"
__license__ = "GPL-2"

import os
import shlex
import subprocess
from gi.repository import Gtk
from firstboot_lib import PageWindow
from firstboot import serverconf

import gettext
from gettext import gettext as _
gettext.textdomain('firstboot')

import firstboot.pages

__REQUIRED__ = False

__TITLE__ = _('Auto Configuration')

def get_page(main_window):

    page = AutoConfigPage(main_window)
    return page

class AutoConfigPage(PageWindow.PageWindow):
    __gtype_name__ = "AutoConfigPage"

    def finish_initializing(self):
        self.set_status(None)

    def load_page(self, params=None):
        self.emit('status-changed', 'autoConfig', not __REQUIRED__)

        self.ui.chkAutoconf.set_visible(False)
        url_config = self.fbe.get_url()
        url = self.cmd_options.url

        if url == None or len(url) == 0:
            url = url_config

        if url == None or len(url) == 0:
            url = ''

        self.ui.txtAutoconf.set_text(url)
        if serverconf.json_is_cached():
            self.ui.boxCheckAutoconf.set_visible(True)
            self.ui.chkAutoconf.set_visible(True)
            self.ui.txtAutoconf.set_sensitive(False)
            self.serverconf = serverconf.get_server_conf(None)

    def translate(self):
        desc = _('Parameters can be filled automatically if an autoconfiguration file is available in your GECOS server.')

        self.ui.lblDescription.set_text(desc)
        self.ui.chkAutoconf.set_label(_('Download a new file with default configuration parameters.'))
        self.ui.lblAutoconf.set_label(_('Autoconfig file URL'))

    def on_chkAutoconf_toggled(self, widget):
        self.ui.txtAutoconf.set_sensitive(self.ui.chkAutoconf.get_active())

    def set_status(self, code, description=''):

        self.ui.imgStatus.set_visible(code != None)
        self.ui.lblStatus.set_visible(code != None)

        if code == None:
            return

        if code == 0:
            icon = Gtk.STOCK_YES

        else:
            icon = Gtk.STOCK_DIALOG_ERROR

        self.ui.imgStatus.set_from_stock(icon, Gtk.IconSize.MENU)
        self.ui.lblStatus.set_label(description)

    def previous_page(self, load_page_callback):

        load_page_callback(firstboot.pages.network)

    def next_page(self, load_page_callback):
        if not serverconf.json_is_cached() or (serverconf.json_is_cached() and self.ui.chkAutoconf.get_active()):
           url = self.ui.txtAutoconf.get_text()
           if url != '' and url != None:
               try:
                   if serverconf.json_is_cached():
                       serverconf.clean_json_cached()
                   self.serverconf = serverconf.get_server_conf(url)

               except Exception as e:
                    self.set_status(1, str(e))
                    return

        load_page_callback(firstboot.pages.dateSync)


""" Standard calculator input number module.
"""

import math
import enum
from collections import deque

class NumberModel:
    """ Standard calculator input number object.
    """

    class Symbols(enum.Enum):
        ZERO = "0"
        ONE = "1"
        TWO = "2"
        THREE = "3"
        FOUR = "4"
        FIVE = "5"
        SIX = "6"
        SEVEN = "7"
        EIGHT = "8"
        NINE = "9"
        NEGATIVE = "-"
        DECIMAL_PT = "."

    def __init__(self):
        self._appended = False
        self._digits = deque([self.Symbols.ZERO.value])

    def new(self):
        """ Create a new number.
        """
        self._digits.clear()
        self._appended = False
        self._digits.append(self.Symbols.ZERO.value)

    def append(self, symbol):
        """ Append NumberModel.Symbol to number.
        """
        assert isinstance(symbol, self.Symbols)

        # replace (default) initial zero (0) value.
        # this does not apply when appending a decimal point
        if (self._is_zero()) and (symbol != self.Symbols.DECIMAL_PT):
            self._digits.pop()

        # number should only contain one decimal point
        if (self._digits.count(self.Symbols.DECIMAL_PT.value) > 0) and\
                (symbol is self.Symbols.DECIMAL_PT):
            return

        self._appended = True
        self._digits.append(symbol.value)

    def backspace(self):
        """ Delete last added digit.
        """
        if self._is_zero():
            return

        is_one_digit_pos = len(self._digits) == 1 and\
            (self._digits[0] != self.Symbols.ZERO.value)

        is_one_digit_neg = len(self._digits) == 2 and\
            (self._digits[0] == self.Symbols.NEGATIVE.value)

        if is_one_digit_pos or is_one_digit_neg:
            self.new()
            return

        self._digits.pop()

    def change_sign(self):
        """ Change sign from positive to negative, and vice versa.
        """
        if self._is_zero():
            return

        if self._digits[0] != self.Symbols.NEGATIVE.value:
            self._digits.appendleft(self.Symbols.NEGATIVE.value)
        else:
            self._digits.popleft()

    def join(self):
        """ Join digits and return as string.
        """
        return "".join(self._digits)

    def is_appended(self):
        """ Return true if a value, zero or non-zero, has been appended.
        """
        return self._appended

    def _is_zero(self):
        """ Return True if number is zero (initial value).
        """
        return (len(self._digits) == 1) and\
            (self._digits[0] == self.Symbols.ZERO.value)


import time
import regarment.constants as const
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

class RegarmentScrapping(webdriver.Chrome):
    def __init__(self, driver_path = 'C:/chromedriver', teardown=False):
        self.teardown = teardown
        options = webdriver.ChromeOptions()
        options.add_experimental_option('excludeSwitches', ['enable-logging'])
        super(RegarmentScrapping, self).__init__(options=options, executable_path=driver_path)
        self.implicitly_wait(const.IMPLICIT_WAIT_TIME)

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.teardown:
            self.quit()

    def get_shop_page(self):
        return const.BASE_URL, const.BASE_URL_NO

    def land_first_page(self, url, i): # 페이지를 여는 함수
        self.get(url + f'&page={i}')

    def get_product_list(self): # 페이지에 존재하는 품목들을 가져오는 함수
        css = '#contents > div.xans-element-.xans-product.xans-product-listnormal.ec-base-product.prdlist_default > ul'
        xpath = '//*[starts-with(@id, "anchorBoxId_")]'
        product_list = WebDriverWait(self, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, css)))
        products = product_list.find_elements_by_xpath(xpath) # 여기에 모든 element가 담김(리스트로)
        print(f'length: {len(products)}')
        return products

    def get_product_category(self): # 품목 카테고리 가져오는 함수
        css = '#contents > div.xans-element-.xans-product.xans-product-menupackage > div.xans-element-.xans-product.xans-product-headcategory.title > h2 > span'
        category = self.find_element_by_css_selector(css).text.strip()
        print(category)
        return category

    def click_product(self, iter): # 품목을 클릭하는 함수
        css1 = '#contents > div.xans-element-.xans-product.xans-product-listnormal.ec-base-product.prdlist_default > ul'
        xpath = '//*[starts-with(@id, "anchorBoxId_")]'
        css2 = 'div > div.prdImg > a'
        # 드라이버 재정의
        product_list = WebDriverWait(self, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, css1)))
        products = product_list.find_elements_by_xpath(xpath)
        # url
        product_link = products[iter].find_element_by_css_selector(css2).get_attribute('href')
        print(f'link:{product_link}')
        # 박스 클릭
        self.get(product_link)
        time.sleep(0.5)
        return product_link

    def is_product_sold_out(self): # 품절 여부 확인하는 함수
        css = '#detail_info_wrap > div.detailArea > div.infoArea > div.headingArea > h2 > span.icon > img'
        try:
            ele = WebDriverWait(self, 0.5).until(EC.presence_of_element_located((By.CSS_SELECTOR, css))).get_attribute('src')
            if ele:
                print('품절 상품')
                return True
            else:
                print('판매중인 상품')
                return False
        except:
            print('판매중인 상품')
            return False

    def get_product_thumbnail(self): # 썸네일 이미지를 가져오는 함수
        css = '#detail_info_wrap > div.detailArea > div.xans-element-.xans-product.xans-product-image.imgArea > div.keyImg > div.thumbnail > a > img'
        product_thumbnail = self.find_element_by_css_selector(css).get_attribute('src')
        print(f'thumbnail:{product_thumbnail}')
        return product_thumbnail

    def get_product_name(self): # 품목 이름을 가져오는 함수
        css = '#detail_info_wrap > div.detailArea > div.infoArea > div.xans-element-.xans-product.xans-product-detaildesign > table > tbody > tr:nth-child(2) > td > span'
        product_name = WebDriverWait(self, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, css)))
        product_name = product_name.text.strip()
        print(f'name:{product_name}')
        return product_name

    def get_product_brand(self): # 품목 브랜드를 가져오는 함수
        """
        상품 이름에서 공백 기준 맨 앞 substring
        우리 브랜드명에 맞춘 변환은 get_brand_list.py 함수에서 함
        """
        css = '#detail_info_wrap > div.detailArea > div.infoArea > div.xans-element-.xans-product.xans-product-detaildesign > table > tbody > tr:nth-child(1) > td > span'
        product_brand = WebDriverWait(self, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, css))).text.strip()
        print(f'brand:{product_brand}')
        return product_brand

    def get_product_price(self): # 품목 가격을 가져오는 함수
        css = '#span_product_price_text'
        product_price = WebDriverWait(self, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, css)))
        product_price = product_price.text
        product_price = product_price.replace(",", '').replace(" ", "").replace("₩", '').split('(')[0]
        print(f'price:{product_price}')
        return product_price

    def get_product_sale_price(self): # 할인 가격을 가져오는 함수
        css = '#span_product_price_sale'
        try:
            product_sale_price = self.find_element_by_css_selector(css).text.replace(",", '').replace(" ", "").replace("₩", '').split('(')[0]
        except:
            product_sale_price = 0
        print(f'sale_price:{product_sale_price}')
        return product_sale_price

    def get_product_gender(self): # 성별 구분하는 함수
        return 'women'

    def get_product_category_type(self, product_category, product_name): # 품목 카테고리 구분하는 함수
        if product_category == 'OUTERWEAR':
            category = 'outer'
        elif product_category in ['T&SHIRTS', 'KNIT & CARDIGAN']:
            category = 'top'
        elif product_category == 'DRESS & BOTTOM':
            if '원피스' in product_name:
                category = 'dress'
            elif ('스커트' in product_name) or ('치마' in product_name):
                category = 'skirt'
            else:
                category = 'bottom'
        elif product_category in ['1%', 'LEATHER & FUR']:
            if '원피스' in product_name:
                category = 'dress'
            elif ('스커트' in product_name) or ('치마' in product_name):
                category = 'skirt'
            elif ('코트' in product_name) or ('자켓' in product_name) or ('블루종' in product_name):
                category = 'outer'
            elif ('바지' in product_name) or ('팬츠' in product_name):
                category = 'bottom'
            else:
                category = 'top'
        print(f'category:{category}')
        return category

    def get_product_size(self): # 품목 사이즈를 가져오는 함수
        css = '#detail_info_wrap > div.detailArea > div.infoArea > div.xans-element-.xans-product.xans-product-detaildesign > table > tbody > tr:nth-child(7) > td > span'
        size = self.find_element_by_css_selector(css).text
        if ('가슴' in size) and ('허리' in size):
            type_ = '가슴'
        elif '가슴' in size:
            type_ = '가슴'
        elif '허리' in size:
            type_ = '허리'
        else:
            css = '#detail_info_wrap > div.detailArea > div.infoArea > div.xans-element-.xans-product.xans-product-detaildesign > table > tbody > tr:nth-child(6) > td > span'
            size = self.find_element_by_css_selector(css).text
            if ('가슴' in size) and ('허리' in size):
                type_ = '가슴'
            elif '가슴' in size:
                type_ = '가슴'
            elif '허리' in size:
                type_ = '허리'
            else:
                css = '#detail_info_wrap > div.detailArea > div.infoArea > div.xans-element-.xans-product.xans-product-detaildesign > table > tbody > tr:nth-child(5) > td > span'
                size = self.find_element_by_css_selector(css).text
                if ('가슴' in size) and ('허리' in size):
                    type_ = '가슴'
                elif '가슴' in size:
                    type_ = '가슴'
                elif '허리' in size:
                    type_ = '허리'
                else:
                    raise Exception('사이즈 타입을 찾을 수 없습니다.')
        product_size = size.split(type_)[1].strip().split(' ')[0].strip()
        print(f'type: {type_}, size: {product_size}')
        return type_, product_size

if __name__ == '__main__':
    print(RegarmentScrapping().get_shop_page())


from pulp import *

# Man könnte auch direkt Funktionen von vorheriger Lösung aufrufen.
# Dann könnte man bei neuen Daten vollautomatisch alles neu berechnen.
KE1 = 3.05860622
KE2 = 1.76585626
KE3 = 13.69481487
KE4 = -11.28930098
KE5 = 19.86780881
KE6 = -1.24669877
KE7 = 8.53057966
KE8 = 6.3504065
KE9 = 2.42236723
KE10 = 0.09754178
KE11 = -0.79181241

"""
# Weiterführender Tipp: Enum statt Stringkonstanten verwenden
# * Tippfehler ausgeschlossen
# * Klarheit über mögliche Werte

from enum import Enum

class Umgebungsbedingung(Enum):
    UB1 = "UB1"
    UB2 = "UB2"
    UB3 = "UB3"

TE = {
    Umgebungsbedingung.UB1: 45,
    Umgebungsbedingung.UB2: 84,
    Umgebungsbedingung.UB3: 35,
}

"""

TE = {"ub1": 13.0, "ub2": 22.0, "ub3": 31.0}
RL = {"ub1": 45.0, "ub2": 62.0, "ub3": 77.0}
LA = {"bt1": 120.0, "bt2": 100.0, "bt3": 200.0}
MATK = {
    "ft1": {"bt1": 5.00, "bt2": 4.00, "bt3": 6.00},
    "ft2": {"bt1": 3.00, "bt2": 2.00, "bt3": 4.00},
    "ft3": {"bt1": 1.00, "bt2": 0.50, "bt3": 1.50},
    "ft4": {"bt1": 2.00, "bt2": 1.00, "bt3": 3.00},
}
LAMZ = [12, 5, 24]
PRODK = {
    ft_k: {bt_k: 1.0 for bt_k in ["bt1", "bt2", "bt3"]}
    for ft_k in ["ft1", "ft2", "ft3", "ft4"]
}
BH = [480.0, 200.0, 960.0]
BL = [13000, 9000, 18000]
VK = {
    "ub1": {"bt1": 0.09, "bt2": 0.18, "bt3": 0.03,},
    "ub2": {"bt1": 0.15, "bt2": 0.30, "bt3": 0.05,},
    "ub3": {"bt1": 0.06, "bt2": 0.12, "bt3": 0.02,},
}
LFK = [5.00, 4.00, 7.00]
LAMP = 230
# Konstanten werden auch gerne in Datei "constants.py" geschrieben um sie
# deutlich vom restlichen Code zu trennen:
# import constants
# f(constants.LAMP)

umgebungsbedingungen = ["ub" + str(i) for i in range(1, 4)]
bindertypen = ["bt" + str(i) for i in range(1, 4)]

def make_var(name):
    return LpVariable.dicts(name, (umgebungsbedingungen, bindertypen), lowBound=0)

S1 = make_var("S1")
S2 = make_var("S2")
S3 = make_var("S3")
LF = make_var("LF")
HLB = make_var("HLB")
HKB = make_var("HKB")
HBH = make_var("HBH")
HBB = make_var("HBB")
HKS = make_var("HKS")
# LP-Variablen sind hier global. Bei komplexeren Programmen sollten sie immer
# in einem eigenen Bereich definiert nud dann mitgegeben werden, z.b. als Dict:
# lp_variables = { key: make_var(key) for key in ["S1", "S2", "S3", "LF", "HLB"] }

#  aa(ub, bt) = forall(1 in KOE) KE(koe) * (S1(ub, bt) + S2(ub, bt) + S3(ub, bt))
def aa(ub, bt):
    return KE1 * (S1[ub][bt] + S2[ub][bt] + S3[ub][bt])

# de(ub, bt) = forall(2 in KOE) KE(koe) * LA(bt) + forall(3 in KOE) KE(koe) * TE(ub) + forall(4 in KOE) KE(koe) * RL(ub) + forall(5 in KOE) KE(koe) * LF(ub, bt) + forall(6 in KOE) KE(koe) * (HLB(ub, bt) + HKB(ub, bt))
def de(ub, bt):
    return (
        KE2 * LA[bt]
        + KE3 * TE[ub]
        + KE4 * RL[ub]
        + KE5 * LF[ub][bt]
        + KE6 * (HLB[ub][bt] + HKB[ub][bt])
    )

# fe(ub, bt) = forall(7 in KOE) KE(koe) * S1(ub, bt) + forall(8 in KOE) KE(koe) * S2(ub, bt) + forall(9 in KOE) KE(koe) * S3(ub, bt)
def fe(ub, bt):
    return KE7 * S1[ub][bt] + KE8 * S2[ub][bt] + KE9 * S3[ub][bt]

# hm(ub, bt) = forall(10 in KOE) KE(koe) * LA(bt) + forall(11 in KOE) KE(koe) * (HLB(ub, bt) + HBH(ub, bt) + HKB(ub, bt))
def hm(ub, bt):
    return KE10 * LA[bt] + KE11 * (HLB[ub][bt] + HBH[ub][bt] + HKB[ub][bt])

def define_restrictions(prog):
    # forall(ub in UB, bt in BT) de(ub, bt) <= 100
    # forall(ub in UB, bt in BT) fe(ub, bt) >= 100
    for ub in umgebungsbedingungen:
        for bt in bindertypen:
            prog += de(ub, bt) <= 100
            prog += fe(ub, bt) >= 100

def define_objective_function(prog):
    # ZF := sum(ub in UB, bt in BT)
    #     VK(ub, bt) * ((LAMP / (aa(ub, bt)/100)) + (hm(ub, bt) * (MATK(ft, bt | ft = 1)+PRODK(ft, bt | ft = 1))) + (ol(ub, bt) * (MATK(ft, bt | ft = 2)+PRODK(ft, bt | ft = 2))) + (au(ub, bt) * (MATK(ft, bt | ft = 3)+PRODK(ft, bt | ft = 3))) + (sl(ub, bt) * (MATK(ft, bt | ft = 4)+PRODK(ft, bt | ft = 4))) + (LAMP / (aus(ub, bt))) + (LF(ub, bt) * LFK(bt)))
    prog += lpSum(
        [
            VK[ub][bt] * ((1 / LAMP) * (aa(ub, bt) * 0.01))
            + (hm(ub, bt) * (MATK["ft1"][bt] + PRODK["ft1"][bt]))
            for ub in umgebungsbedingungen
            for bt in bindertypen
        ]
    )

def solve_program():
    prog = LpProblem("pulp", LpMinimize)
    define_restrictions(prog)
    define_objective_function(prog)
    status = prog.solve()
    print("Result:", LpStatus[status])
    for var in prog.variables():
        print(var.name, "=", var.varValue)

if __name__ == "__main__":
    solve_program()


"""Parse date notations."""

from calendar import IllegalMonthError
from datetime import date

import regex
from dateutil import parser
from dateutil.relativedelta import relativedelta
from traiter.old.vocabulary import LOWEST, Vocabulary

from digi_leap.parsers.base import Base
from digi_leap.pylib import patterns
from digi_leap.pylib.trait import Trait

VOCAB = Vocabulary(patterns.VOCAB)

YEAR_LEN = 2

def convert(token):
    """Normalize a parsed date."""
    trait = Trait(start=token.start, end=token.end)

    value = regex.sub(
        r'[^a-z\d]+', '-', token.group['value'], flags=regex.I | regex.X)

    if len(value) < 4:
        return None

    try:
        trait.value = parser.parse(value).date()
    except (parser.ParserError, IllegalMonthError):
        return None

    if trait.value > date.today():
        trait.value -= relativedelta(years=100)
        trait.century_adjust = True

    trait.value = trait.value.isoformat()[:10]
    return trait

def short_date_name(token):
    """Normalize a month name & year notation."""
    if token.group.get('month') and len(token.group['digits']) < YEAR_LEN:
        return None

    trait = convert(token)
    if trait:
        trait.value = str(trait.value[:-2]) + '??'
    return trait

# Until dateutils IllegalMonthError is fixes do this
def short_date_digits(token):
    """Normalize a month year as all digits notation."""
    digits = token.group['digits']

    has_month = any(x for x in digits if 0 < int(x) <= 12)
    has_year = any(x for x in digits if len(x) >= YEAR_LEN)
    if not (has_month and has_year):
        return None

    trait = convert(token)
    if trait:
        trait.value = str(trait.value[:-2]) + '??'
    return trait

LABEL_DATE = Base(
    name=__name__.split('.')[-1],
    rules=[
        VOCAB['eol'],
        VOCAB['uuid'],  # Get rid of these before they're a problem

        VOCAB.term('label', ' date '.split()),

        VOCAB.part(
            'digits', r'(?<! \d ) ( [12]\d{3} | \d{1,2} ) (?! \d )'),

        VOCAB.part('sep', r' [/_-]+ ', capture=False),

        VOCAB.part('noise', r""" \w+ """, priority=LOWEST, capture=False),

        VOCAB.producer(convert, """
            label? (?P<value> digits sep? month_name sep? digits ) """),

        VOCAB.producer(convert, """
            label? (?P<value> month_name sep? digits sep? digits ) """),

        VOCAB.producer(convert, """
            label? (?P<value> digits sep digits sep digits ) """),

        VOCAB.producer(short_date_digits, f"""
            label? (?P<value> digits sep digits ) """),

        VOCAB.producer(short_date_name, f"""
            label? (?P<value> month_name sep? digits ) """),

        VOCAB.producer(short_date_name, f"""
            label? (?P<value> digits sep? month_name ) """),
    ])


import socket
import time
import MySQLdb

def index(req, address="", port=29502, measuredSampleCount=10000, delaySampleCount=1000, db="no", table="data"):
	output = ""
	samples = 1

	if db == "yes":
		mysql = MySQLdb.connect("127.0.0.1", "root", "aaa", "rtaixml")
		c = mysql.cursor()
		c.execute("DELETE FROM " + table + " WHERE server = '" + address + "';")
		mysql.commit()

	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((address, int(port)))

	seqLoop = {}
	seqLoopChangeIndicator = {}
	sampleCounts = []
	totalSampleCount = 0
	delayedSampleCount = 0
	clockStarted = False

	while samples:

		if not clockStarted and delayedSampleCount >= delaySampleCount:
			executionTime = -time.time()
			clockStarted = True

		samples = s.recv(8096)

		samplesList = samples.split("\n")

		queryValues = []
		for sample in samplesList[:-1]:
			#create mysql string
			value = sample.split(" ")

			if len(value) >= 3 and value[0] != "":
				#set sequence loop default values
				if not int(value[0]) in seqLoop:
					seqLoop[int(value[0])] = 0
					seqLoopChangeIndicator[int(value[0])] = False

				if int(value[1]) < 32768:
					if seqLoopChangeIndicator[int(value[0])] == True: #increase sequence loop number after sequence number restart
						seqLoop[int(value[0])] += 1
					seqLoopChangeIndicator[int(value[0])] = False; #we do not need to watch for sequence number restart
				else:
					seqLoopChangeIndicator[int(value[0])] = True; #we need to watch for restart

				queryValues.append("('" + address + "', '" + str(value[0]) + "', '" + str(seqLoop[int(value[0])]) + "', '" + str(value[1]) + "','" + str(value[2]) + "')")

		sampleCount = len(queryValues)
		if sampleCount > 0:
			if clockStarted:
				if db == "yes":
					c.execute("INSERT INTO " + table + " (server, signalId, seqLoop, seq, value) VALUES " + ",".join(queryValues) + ";")
					mysql.commit()
				sampleCounts.append(sampleCount)
				totalSampleCount += sampleCount
			else:
				delayedSampleCount += sampleCount

		if int(measuredSampleCount) and totalSampleCount >= int(measuredSampleCount):
			break

	executionTime += time.time()
	s.close()

	#average sample count in one packet
	count = len(sampleCounts) #total numbers in array
	total = 0
	for value in sampleCounts:
		total = total + value #total value of array numbers
	average = float(total)/float(count) #get average value
	output += "\nAverage sample count in one packet: " + str(average).replace(".", ",") + "\n";

	#average packet count in time
	output += "\nAverage packet count in one second: " + str(count/executionTime).replace(".", ",") + "\n\n";

	output += "Sample count: " + str(totalSampleCount) + "\n"
	output += "Execution time: " + str(executionTime).replace(".", ",") + " s\n"

	return output


class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:

        ans = 0
        left = 0
        window = 0
        for right in range(1, len(s)):
            window += 1
            while left < right and s[left] == s[right]:
                window -= 1
                left += 1
            ans = max(ans, window)
        return ans

s = "abccd"
s = "bbbbb"
s = "abcabcbb"

ob = Solution()
ans = ob.lengthOfLongestSubstring(s)
ans


import sys
from  nltk.corpus import brown, conll2000, alpino, dependency_treebank,treebank
from collections import defaultdict
from hmm import data_processing
from viterbi import viterbi
import time
'''
the main file ask user input the corpus they want to test (we use 90% corpus to train and test the next 10%)
different copus accuracy is :
brown: Accuracy rate:91.29838016806018%
conll2000: Accuracy rate: 88.68818363888461%
alpino: Accuracy rate: 84.39314646211199%
dependency_treebank : Accuracy rate: 83.61317051897078%
treebank :Accuracy rate:84.70229007633587%
'''
def select_corpus(corpus):
    if corpus == '1':
        sent = brown.tagged_sents(tagset ='universal')
    elif corpus == '2':
        sent = conll2000.tagged_sents()
    elif corpus == '3':
        sent = alpino.tagged_sents()
    elif corpus == '4':
        sent = dependency_treebank.tagged_sents()
    elif corpus == '5':
        sent = treebank.tagged_sents()
    else:
        print("you input wrong arg, it shoule be : python main.py numCorpus numSmoothing")
        sys.exit(0)
    return sent

corpus = sys.argv[1]
smoothing = sys.argv[2]
sent =select_corpus(corpus)

print("-----------------------------------------start:",time.clock())
training_sents = []
test_sents = []
transition = defaultdict(dict)
emission = defaultdict(dict)

emission ,transition, emission_2 = data_processing(sent,corpus,smoothing)

viterbi(transition,emission,emission_2,sent)
print("-----------------------------------------finish:",time.clock())


import os
from collections import defaultdict

import numpy as np
import pandas as pd
import pylab as plt
import seaborn as sns
import matplotlib.patches as mpatches
import pymzml

from vimms.Chemicals import UnknownChemical, get_absolute_intensity, get_key
from vimms.Common import load_obj, PROTON_MASS, find_nearest_index_in_array
from vimms.MassSpec import FragmentationEvent
from vimms.Roi import make_roi, RoiToChemicalCreator
from vimms.SpectralUtils import get_precursor_info, get_chemicals

def get_N(row):
    if 'T10' in row['filename']:
        return 10
    else:
        return row['filename'].split('_')[3]

def get_dew(row):
    if 'T10' in row['filename']:
        return 15
    else:
        tok = row['filename'].split('_')[5]  # get the dew value in the filename
        return tok.split('.')[0]  # get the part before '.mzML'

def experiment_group(row):
    if 'experiment' in row:
        col_to_check = 'experiment'
    else:
        col_to_check = 'filename'

    if 'beer' in row[col_to_check]:
        return 'beer'
    else:
        return 'urine'

def add_group_column(df):
    df['group'] = df.apply(lambda row: experiment_group(row), axis=1)

def get_df(csv_file, min_ms1_intensity, rt_range, mz_range):
    df = pd.read_csv(csv_file)
    return filter_df(df, min_ms1_intensity, rt_range, mz_range)

def filter_df(df, min_ms1_intensity, rt_range, mz_range):
    # filter by rt range
    if rt_range is not None:
        df = df[(df['rt'] > rt_range[0][0]) & (df['rt'] < rt_range[0][1])]

    # filter by mz range
    if mz_range is not None:
        df = df[(df['rt'] > mz_range[0][0]) & (df['rt'] < mz_range[0][1])]

    # filter by min intensity
    intensity_col = 'maxo'
    if min_ms1_intensity is not None:
        df = df[(df[intensity_col] > min_ms1_intensity)]

    # add log intensity column
    df['log_intensity'] = df.apply(lambda row: np.log(row[intensity_col]), axis=1)

    # add N column
    try:
        df['N'] = df.apply(lambda row: get_N(row), axis=1)
        df[['N']] = df[['N']].astype('int')
    except IndexError:
        pass
    except ValueError:
        df['N'] = df.apply(lambda row: np.nan, axis=1)

    # add group column
    df['group'] = df.apply(lambda row: experiment_group(row), axis=1)
    return df

def make_boxplot(df, x, y, xticklabels, title, outfile=None):
    g = sns.catplot(x=x, y=y, kind='box', data=df)
    g.fig.set_size_inches(10, 3)
    if xticklabels is not None:
        g.set_xticklabels(xticklabels, rotation=90)
    else:
        g.set_xticklabels(rotation=90)
    plt.title(title)
    plt.tight_layout()
    if outfile is not None:
        plt.savefig(outfile, dpi=300)
    plt.show()

def make_hist(df, col_name, file_name, title):
    gb = df.groupby('filename')
    group_df = gb.get_group(file_name)
    vals = group_df[col_name].values
    print(vals, len(vals))
    _ = plt.hist(vals, bins=100)
    plt.title(title)
    plt.tight_layout()
    plt.show()

def to_chemical(row):
    mz = row['mz'] - PROTON_MASS
    rt = row['rt']
    max_intensity = row['maxo']
    chrom = None
    chem = UnknownChemical(mz, rt, max_intensity, chrom, children=None)
    return chem

def df_to_chemicals(df, filename=None):
    if filename is not None:
        filtered_df = df.loc[df['filename'] == filename]
    else:
        filtered_df = df
    chems = filtered_df.apply(lambda row: to_chemical(row), axis=1).values
    return chems

def find_chem(to_find, min_rts, max_rts, min_mzs, max_mzs, chem_list):
    query_mz = to_find.isotopes[0][0]
    query_rt = to_find.rt
    min_rt_check = min_rts <= query_rt
    max_rt_check = query_rt <= max_rts
    min_mz_check = min_mzs <= query_mz
    max_mz_check = query_mz <= max_mzs
    idx = np.nonzero(min_rt_check & max_rt_check & min_mz_check & max_mz_check)[0]
    matches = chem_list[idx]

    # pick a match
    if len(matches) == 0:
        return None
    elif len(matches) == 1:
        return matches[0]
    else:  # multiple matches, take the closest in rt
        diffs = [np.abs(chem.rt - to_find.rt) for chem in matches]
        idx = np.argmin(diffs)
        return matches[idx]

def match(chemical_list_1, chemical_list_2, mz_tol, rt_tol, verbose=False):
    matches = {}
    chem_list = np.array(chemical_list_2)
    min_rts = np.array([chem.rt - rt_tol for chem in chem_list])
    max_rts = np.array([chem.rt + rt_tol for chem in chem_list])
    min_mzs = np.array([chem.isotopes[0][0] * (1 - mz_tol / 1e6) for chem in chem_list])
    max_mzs = np.array([chem.isotopes[0][0] * (1 + mz_tol / 1e6) for chem in chem_list])
    for i in range(len(chemical_list_1)):
        to_find = chemical_list_1[i]
        if i % 1000 == 0 and verbose:
            print('%d/%d found %d' % (i, len(chemical_list_1), len(matches)))
        match = find_chem(to_find, min_rts, max_rts, min_mzs, max_mzs, chem_list)
        if match:
            matches[to_find] = match
    return matches

def match_peaklist(mz_list_1, rt_list_1, intensity_list_1, mz_list_2, rt_list_2, intensity_list_2, mz_tol, rt_tol):
    if mz_tol is not None:  # create mz range for matching in ppm
        min_mzs = np.array([mz * (1 - mz_tol / 1e6) for mz in mz_list_2])
        max_mzs = np.array([mz * (1 + mz_tol / 1e6) for mz in mz_list_2])

    else:  # create mz ranges by rounding to 2dp
        min_mzs = np.around(mz_list_2, decimals=2)
        max_mzs = np.around(mz_list_2, decimals=2)
        mz_list_1 = np.around(mz_list_1, decimals=2)

    # create rt ranges for matching
    min_rts = np.array([rt - rt_tol for rt in rt_list_2])
    max_rts = np.array([rt + rt_tol for rt in rt_list_2])

    matches = {}
    for i in range(len(mz_list_1)):  # loop over query and find a match
        query = (mz_list_1[i], rt_list_1[i], intensity_list_1[i],)
        match = find_match(query, min_rts, max_rts, min_mzs, max_mzs, mz_list_2, rt_list_2, intensity_list_2)
        matches[query] = match
    return matches

def check_found_matches(matches, left_label, right_label, N=20):
    found = [key for key in matches if matches[key] is not None]
    print('Found %d/%d (%f)' % (len(found), len(matches), len(found) / len(matches)))

    print('%s\t\t\t\t\t\t%s' % (left_label, right_label))
    for key, value in list(matches.items())[0:N]:
        if value is not None:
            print('mz %.2f rt %.4f intensity %.4f\tmz %.2f rt %.4f intensity %.4f' % (
                key[0], key[1], key[2], value[0], value[1], value[2]))

def plot_matched_precursors(matches, min_mz, max_mz, min_rt, max_rt, out_file=None):
    plt.figure(figsize=(12, 6))
    plt.rcParams.update({'font.size': 24})
    for key in matches:
        mz, rt, intensity = key
        if min_mz < mz < max_mz and min_rt < rt < max_rt:
            if matches[key] is not None:
                plt.plot([rt], [mz], marker='.', markersize=5, color='blue', alpha=0.1)
            else:
                plt.plot([rt], [mz], marker='.', markersize=5, color='red', alpha=0.1)

    blue_patch = mpatches.Patch(color='blue', label='Matched')
    red_patch = mpatches.Patch(color='red', label='Unmatched')
    plt.legend(handles=[blue_patch, red_patch])
    plt.title('Matched fragmentation events', fontsize=30)
    plt.xlabel('Retention Time (s)')
    plt.ylabel('m/z')
    plt.tight_layout()
    if out_file is not None:
        plt.savefig(out_file, dpi=300)

def count_stuff(input_file, min_rt, max_rt):
    run = pymzml.run.Reader(input_file, MS1_Precision=5e-6,
                            extraAccessions=[('MS:1000016', ['value', 'unitName'])],
                            obo_version='4.0.1')
    mzs = []
    rts = []
    intensities = []
    count_ms1_scans = 0
    count_ms2_scans = 0
    cumsum_ms1_scans = []
    cumsum_ms2_scans = []
    count_selected_precursors = 0
    for spectrum in run:
        ms_level = spectrum['ms level']
        current_scan_rt, units = spectrum.scan_time
        if units == 'minute':
            current_scan_rt *= 60.0
        if min_rt < current_scan_rt < max_rt:
            if ms_level == 1:
                count_ms1_scans += 1
                cumsum_ms1_scans.append((current_scan_rt, count_ms1_scans,))
            elif ms_level == 2:
                try:
                    selected_precursors = spectrum.selected_precursors
                    count_selected_precursors += len(selected_precursors)
                    mz = selected_precursors[0]['mz']
                    intensity = selected_precursors[0]['i']

                    count_ms2_scans += 1
                    mzs.append(mz)
                    rts.append(current_scan_rt)
                    intensities.append(intensity)
                    cumsum_ms2_scans.append((current_scan_rt, count_ms2_scans,))
                except KeyError:
                    # print(selected_precursors)
                    pass

    print('Number of ms1 scans =', count_ms1_scans)
    print('Number of ms2 scans =', count_ms2_scans)
    print('Total scans =', count_ms1_scans + count_ms2_scans)
    print('Number of selected precursors =', count_selected_precursors)
    return np.array(mzs), np.array(rts), np.array(intensities), np.array(cumsum_ms1_scans), np.array(cumsum_ms2_scans)

def find_match(query, min_rts, max_rts, min_mzs, max_mzs, mz_list, rt_list, intensity_list):
    # check ranges
    query_mz, query_rt, query_intensity = query
    min_rt_check = min_rts <= query_rt
    max_rt_check = query_rt <= max_rts
    min_mz_check = min_mzs <= query_mz
    max_mz_check = query_mz <= max_mzs
    idx = np.nonzero(min_rt_check & max_rt_check & min_mz_check & max_mz_check)[0]

    # get mz, rt and intensity of matching indices
    matches_mz = mz_list[idx]
    matches_rt = rt_list[idx]
    matches_intensity = intensity_list[idx]

    if len(idx) == 0:  # no match
        return None

    elif len(idx) == 1:  # single match
        return (matches_mz[0], matches_rt[0], matches_intensity[0],)

    else:  # multiple matches, take the closest in rt
        diffs = [np.abs(rt - query_rt) for rt in matches_rt]
        idx = np.argmin(diffs)
        return (matches_mz[idx], matches_rt[idx], matches_intensity[idx],)

def plot_num_scans(real_cumsum_ms1, real_cumsum_ms2, simulated_cumsum_ms1, simulated_cumsum_ms2, out_file=None):
    plt.plot(real_cumsum_ms1[:, 0], real_cumsum_ms1[:, 1], 'r')
    plt.plot(real_cumsum_ms2[:, 0], real_cumsum_ms2[:, 1], 'b')
    plt.plot(simulated_cumsum_ms1[:, 0], simulated_cumsum_ms1[:, 1], 'r--')
    plt.plot(simulated_cumsum_ms2[:, 0], simulated_cumsum_ms2[:, 1], 'b--')

    plt.legend(['Actual MS1', 'Actual MS2', 'Simulated MS1', 'Simulated MS2'])
    plt.xlabel('Retention Time (s)')
    plt.ylabel('Cumulative sum')
    plt.title('Cumulative number of MS1 and MS2 scans', fontsize=18)
    plt.tight_layout()

    if out_file is not None:
        plt.savefig(out_file, dpi=300)

def plot_matched_intensities(matched_intensities, unmatched_intensities, out_file=None):
    plt.figure()
    temp1 = plt.hist(np.log(matched_intensities), bins = np.linspace(10,20,50), color='blue')
    temp2 = plt.hist(np.log(unmatched_intensities), bins = np.linspace(10,20,50), color='red')
    plt.title('Matched precursor intensities')

    blue_patch = mpatches.Patch(color='blue', label='Matched')
    red_patch = mpatches.Patch(color='red', label='Unmatched')
    plt.legend(handles=[blue_patch, red_patch])
    plt.xlabel('log(intensity)')
    plt.ylabel('Precursor count')
    plt.tight_layout()

    if out_file is not None:
        plt.savefig(out_file, dpi=300)

def load_controller(results_dir, experiment_name, N, rt_tol):
    analysis_name = 'experiment_%s_N_%d_rttol_%d' % (experiment_name, N, rt_tol)
    pickle_in = '%s/%s.p' % (results_dir, analysis_name)
    print('Loading %s' % analysis_name)
    try:
        controller = load_obj(pickle_in)
    except FileNotFoundError:
        controller = None
    return controller

def load_controllers(results_dir, Ns, rt_tols):
    controllers = []
    for N in Ns:
        for rt_tol in rt_tols:
            controller = load_controller(results_dir, N, rt_tol)
            if controller is not None:
                controllers.append(controller)
    return controllers

def compute_performance_scenario_1(controller, dataset, min_ms1_intensity,
                                   fullscan_filename, P_peaks_df,
                                   matching_mz_tol, matching_rt_tol,
                                   chem_to_frag_events=None):
    if chem_to_frag_events is None:  # read MS2 fragmentation events from pickled controller
        chem_to_frag_events = get_frag_events(controller, 2)

    # match with xcms peak-picked ms1 data
    detected_ms1 = df_to_chemicals(P_peaks_df, fullscan_filename)
    matches_fullscan = match(dataset, detected_ms1, matching_mz_tol, matching_rt_tol, verbose=False)

    # check if matched and set a flag to indicate that
    update_matched_status(dataset, matches_fullscan, None)

    # positive instances are ground truth MS1 peaks found by XCMS
    # negative instances are chemicals that cannot be matched to XCMS output
    positives = list(filter(lambda x: x.found_in_fullscan, dataset))
    negatives = list(filter(lambda x: not x.found_in_fullscan, dataset))

    # for both positive and negative instances, count how many frag events they have
    # and whether it's above (good) or below (bad) the minimum ms1 intensity at the time of fragmentation.
    positives_count = get_chem_frag_counts(positives, chem_to_frag_events, min_ms1_intensity)
    negatives_count = get_chem_frag_counts(negatives, chem_to_frag_events, min_ms1_intensity)

    # TP = positive instances that are good only
    tp = [chem for chem in positives if positives_count[chem]['good'] > 0 and positives_count[chem]['bad'] == 0]

    # FP = negative instances that are fragmented (both good + bad)
    fp = [chem for chem in negatives if negatives_count[chem]['good'] > 0 or negatives_count[chem]['bad'] > 0]

    # FN = positive instances that are not fragmented at all + positive instances that are bad only
    fn = [chem for chem in positives if \
          (positives_count[chem]['good'] == 0 and positives_count[chem]['bad'] == 0) or \
          (positives_count[chem]['good'] == 0 and positives_count[chem]['bad'] > 0)]

    tp = len(tp)
    fp = len(fp)
    fn = len(fn)
    prec, rec, f1 = compute_pref_rec_f1(tp, fp, fn)
    return tp, fp, fn, prec, rec, f1

# def compute_performance_scenario_1(controller, chemicals, min_ms1_intensity,
#                                    fullscan_filename, P_peaks_df,
#                                    matching_mz_tol, matching_rt_tol,
#                                    chem_to_frag_events=None):

#     if chem_to_frag_events is None: # read MS2 fragmentation events from pickled controller
#         chem_to_frag_events = get_frag_events(controller, 2)

#     # match xcms picked ms1 peaks to fragmentation peaks
#     detected_ms1 = df_to_chemicals(P_peaks_df, fullscan_filename)
#     matches_fullscan = match(detected_ms1, chemicals, matching_mz_tol, matching_rt_tol, verbose=False)
#     matched_frags = set(matches_fullscan.values())
#     print('%d/%d %d/%d' % (len(matches_fullscan), len(detected_ms1), len(matched_frags), len(chemicals)))

#     # ms1 peaks that are also fragmented
#     positives = []
#     for ms1_peak in matches_fullscan:
#         frag_peak = matches_fullscan[ms1_peak]
#         frag_events = chem_to_frag_events[frag_peak]
#         if len(frag_events) > 0:
#             positives.append(frag_peak)

#     # fragmentation peaks that are not in ms1 peaks
#     negatives = []
#     for frag_peak in chemicals:
#         if frag_peak not in matched_frags:
#             frag_events = chem_to_frag_events[frag_peak]
#             if len(frag_events) > 0:
#                 negatives.append(frag_peak)

#     positives_count = get_chem_frag_counts(positives, chem_to_frag_events, min_ms1_intensity)
#     negatives_count = get_chem_frag_counts(negatives, chem_to_frag_events, min_ms1_intensity)

#     # peaks from ground truth (found in full-scan files) that are fragmented above the minimum intensity threshold
#     tp = [chem for chem in positives if positives_count[chem]['good'] > 0 and positives_count[chem]['bad'] == 0]
#     tp = len(tp)

#     # peaks from ground truth that are not fragmented + peaks from ground truth that are fragmented below the minimum intensity threshold.
#     fp = len(detected_ms1) - tp

#     # peaks not from ground truth that are fragmented above the minimum intensity threshold.
#     fn = [chem for chem in negatives if negatives_count[chem]['good'] > 0 and negatives_count[chem]['bad'] == 0]
#     fn = len(fn)

#     prec, rec, f1 = compute_pref_rec_f1(tp, fp, fn)
#     return tp, fp, fn, prec, rec, f1

def compute_performance_scenario_2(controller, dataset, min_ms1_intensity,
                                   fullscan_filename, fragfile_filename,
                                   fullscan_peaks_df, fragmentation_peaks_df,
                                   matching_mz_tol, matching_rt_tol,
                                   chem_to_frag_events=None):
    if chem_to_frag_events is None:  # read MS2 fragmentation events from pickled controller
        chem_to_frag_events = get_frag_events(controller, 2)

    # load the list of xcms-picked peaks
    detected_from_fullscan = df_to_chemicals(fullscan_peaks_df, fullscan_filename)
    detected_from_fragfile = df_to_chemicals(fragmentation_peaks_df, fragfile_filename)

    # match with xcms peak-picked ms1 data from fullscan file
    matches_fullscan = match(dataset, detected_from_fullscan, matching_mz_tol, matching_rt_tol, verbose=False)

    # match with xcms peak-picked ms1 data from fragmentation file
    matches_fragfile = match(dataset, detected_from_fragfile, matching_mz_tol, matching_rt_tol, verbose=False)

    # check if matched and set a flag to indicate that
    update_matched_status(dataset, matches_fullscan, matches_fragfile)

    # True positive: a peak that is fragmented above the minimum MS1 intensity and is picked by XCMS from
    # the MS1 information in the DDA file and is picked in the fullscan file.
    found_in_both = list(filter(lambda x: x.found_in_fullscan and x.found_in_fragfile, dataset))
    frag_count = get_chem_frag_counts(found_in_both, chem_to_frag_events, min_ms1_intensity)
    tp = [chem for chem in found_in_both if frag_count[chem]['good'] > 0 and frag_count[chem]['bad'] == 0]
    tp = len(tp)

    # False positive: any peak that is above minimum intensity and is picked by XCMS
    # from the DDA file but is not picked from the fullscan.
    found_in_dda_only = list(filter(lambda x: not x.found_in_fullscan and x.found_in_fragfile, dataset))
    frag_count = get_chem_frag_counts(found_in_dda_only, chem_to_frag_events, min_ms1_intensity)
    fp = [chem for chem in found_in_dda_only if frag_count[chem]['good'] > 0 and frag_count[chem]['bad'] == 0]
    fp = len(fp)

    # False negative: any peak that is picked from fullscan data, and is not fragmented, or
    # is fragmented below the minimum intensity.
    found_in_fullscan = list(filter(lambda x: x.found_in_fullscan, dataset))
    fn = len(found_in_fullscan) - tp

    prec, rec, f1 = compute_pref_rec_f1(tp, fp, fn)
    return tp, fp, fn, prec, rec, f1

def get_frag_events(controller, ms_level):
    '''
    Gets the fragmentation events for all chemicals for an ms level from the controller
    :param controller: A Top-N controller object
    :param ms_level: The MS-level (usually 2)
    :return: A dictionary where keys are chemicals and values are a list of fragmentation events
    '''
    filtered_frag_events = list(filter(lambda x: x.ms_level == ms_level, controller.mass_spec.fragmentation_events))
    chem_to_frag_events = defaultdict(list)
    for frag_event in filtered_frag_events:
        key = frag_event.chem
        chem_to_frag_events[key].append(frag_event)
    return dict(chem_to_frag_events)

def count_frag_events(chem, chem_to_frag_events, min_ms1_intensity):
    '''
    Counts how many good and bad fragmentation events for each chemical (key).
    Good fragmentation events are defined as fragmentation events that occur when at the time of fragmentation,
    the chemical MS1 intensity is above the min_ms1_intensity threshold.
    :param chem: the chemical to count
    :param chem_to_frag_events: a dictionary of chemicals to frag events (from get_frag_events above())
    :return: a tuple of good and bad fragmentation event counts
    '''
    frag_events = chem_to_frag_events[chem]
    good_count = 0
    bad_count = 0
    for frag_event in frag_events:
        chem = frag_event.chem
        query_rt = frag_event.query_rt
        if get_absolute_intensity(chem, query_rt) < min_ms1_intensity:
            bad_count += 1
        else:
            good_count += 1
    return good_count, bad_count

def get_chem_frag_counts(chem_list, chem_to_frag_events, min_ms1_intensity):
    # get the count of good/bad fragmentation events for all chemicals in chem_list
    results = {}
    for i in range(len(chem_list)):
        chem = chem_list[i]
        try:
            good_count, bad_count = count_frag_events(chem, chem_to_frag_events, min_ms1_intensity)
        except KeyError:
            good_count = 0
            bad_count = 0
        results[chem] = {
            'good': good_count,
            'bad': bad_count
        }
    return results

def update_matched_status(dataset, matches_fullscan, matches_fragfile):
    '''
    Update a boolean flag in the Chemical object that tells us if it is found in fullscan or fragmentation data
    :param dataset: a list of Chemicals
    :param matches_fullscan: the result of matching Chemicals in dataset to fullscan file
    :param matches_fragfile: the result of matching Chemicals in dataset to fragmentation file
    :return: None, but the Chemical objects in dataset is modified
    '''
    found_in_fullscan = 0
    found_in_fragfile = 0
    for chem in dataset:
        if matches_fullscan is not None:  # check if a match is found in fullscan mzML
            if chem in matches_fullscan:
                chem.found_in_fullscan = True
                found_in_fullscan += 1
            else:
                chem.found_in_fullscan = False

        if matches_fragfile is not None:  # check if a match is found in fragmentation mzML
            if chem in matches_fragfile:
                chem.found_in_fragfile = True
                found_in_fragfile += 1
            else:
                chem.found_in_fragfile = False

    print('Matched %d/%d in fullscan data, %d/%d in fragmentation data' % (found_in_fullscan, len(dataset),
                                                                           found_in_fragfile, len(dataset)))

def compute_pref_rec_f1(tp, fp, fn):
    prec = tp / (tp + fp)
    rec = tp / (tp + fn)
    f1 = (2 * prec * rec) / (prec + rec)
    return prec, rec, f1

def calculate_performance(params):
    # get parameters
    fragfile = params['fragfile']
    N = params['N']
    rt_tol = params['rt_tol']
    roi_mz_tol = params['roi_mz_tol']
    roi_min_ms1_intensity = params['roi_min_ms1_intensity']
    fragmentation_min_ms1_intensity = params['fragmentation_min_ms1_intensity']
    min_rt = params['min_rt']
    max_rt = params['max_rt']
    roi_min_length = params['roi_min_length']
    fullscan_filename = params['fullscan_filename']
    P_peaks_df = params['P_peaks_df']
    Q_peaks_df = params['Q_peaks_df']
    matching_mz_tol = params['matching_mz_tol']
    matching_rt_tol = params['matching_rt_tol']
    scenario = params['scenario']

    controller_file = params['controller_file']
    chemicals_file = params['chemicals_file']

    if chemicals_file.endswith('.p'):
        print('Loading chemicals')
        chemicals = load_obj(chemicals_file)
    else:
        print('Extracting chemicals')
        chemicals = get_chemicals(chemicals_file, roi_mz_tol, roi_min_ms1_intensity, min_rt, max_rt,
                                  min_length=roi_min_length)

    if type(chemicals) == list:
        chemicals = np.array(chemicals)

    if controller_file.endswith('.p'):
        print('Loading fragmentation events')
        controller = load_obj(controller_file)
        chem_to_frag_events = None
    else:
        print('Extracting fragmentation events')
        controller = None
        precursor_df = get_precursor_info(controller_file)
        chem_to_frag_events = get_chem_to_frag_events(chemicals, precursor_df)

    # compute performance under each scenario
    print('Computing performance under scenario %d' % scenario)
    tp, fp, fn, prec, rec, f1 = 0, 0, 0, 0, 0, 0
    if scenario == 1:
        tp, fp, fn, prec, rec, f1 = compute_performance_scenario_1(controller, chemicals,
                                                                   fragmentation_min_ms1_intensity,
                                                                   fullscan_filename, P_peaks_df,
                                                                   matching_mz_tol, matching_rt_tol,
                                                                   chem_to_frag_events=chem_to_frag_events)
    elif scenario == 2:
        fragfile_filename = os.path.basename(fragfile)
        tp, fp, fn, prec, rec, f1 = compute_performance_scenario_2(controller, chemicals,
                                                                   fragmentation_min_ms1_intensity,
                                                                   fullscan_filename, fragfile_filename,
                                                                   P_peaks_df, Q_peaks_df, matching_mz_tol,
                                                                   matching_rt_tol,
                                                                   chem_to_frag_events=chem_to_frag_events)

    return N, rt_tol, scenario, tp, fp, fn, prec, rec, f1

def get_chem_to_frag_events(chemicals, ms1_df):
    # used for searching later
    min_rts = np.array([min(chem.chromatogram.raw_rts) for chem in chemicals])
    max_rts = np.array([max(chem.chromatogram.raw_rts) for chem in chemicals])
    min_mzs = np.array([min(chem.chromatogram.raw_mzs) for chem in chemicals])
    max_mzs = np.array([max(chem.chromatogram.raw_mzs) for chem in chemicals])

    # loop over each fragmentation event in ms1_df, attempt to match it to chemicals
    chem_to_frag_events = defaultdict(list)
    for idx, row in ms1_df.iterrows():
        query_rt = row['ms1_scan_rt']
        query_mz = row['ms1_mz']
        query_intensity = row['ms1_intensity']
        scan_id = row['ms2_scan_id']

        chem = None
        idx = _get_chem_indices(query_mz, query_rt, min_mzs, max_mzs, min_rts, max_rts)
        if len(idx) == 1:  # single match
            chem = chemicals[idx][0]

        elif len(
                idx) > 1:  # multiple matches, find the closest in intensity to query_intensity at the time of fragmentation
            matches = chemicals[idx]
            possible_intensities = np.array([get_absolute_intensity(chem, query_rt) for chem in matches])
            closest = find_nearest_index_in_array(possible_intensities, query_intensity)
            chem = matches[closest]

        # create frag event for the given chem
        if chem is not None:
            ms_level = 2
            peaks = []  # we don't know which ms2 peaks are linked to this chem object
            # key = get_key(chem)
            frag_event = FragmentationEvent(chem, query_rt, ms_level, peaks, scan_id)
            chem_to_frag_events[chem].append(frag_event)
    return dict(chem_to_frag_events)

def get_chemicals(mzML_file, mz_tol, min_ms1_intensity, start_rt, stop_rt, min_length=1):
    '''
    Extract ROI from an mzML file and turn them into UnknownChemical objects
    :param mzML_file: input mzML file
    :param mz_tol: mz tolerance for ROI extraction
    :param min_ms1_intensity: ROI will only be kept if it has one point above this threshold
    :param start_rt: start RT to extract ROI
    :param stop_rt: end RT to extract ROI
    :return: a list of UnknownChemical objects
    '''
    min_intensity = 0
    good_roi, junk = make_roi(mzML_file, mz_tol=mz_tol, mz_units='ppm', min_length=min_length,
                              min_intensity=min_intensity, start_rt=start_rt, stop_rt=stop_rt)

    # keep ROI that have at least one point above the minimum to fragment threshold
    keep = []
    for roi in good_roi:
        if np.count_nonzero(np.array(roi.intensity_list) > min_ms1_intensity) > 0:
            keep.append(roi)

    ps = None  # unused
    rtcc = RoiToChemicalCreator(ps, keep)
    chemicals = np.array(rtcc.chemicals)
    return chemicals

def evaluate_serial(all_params):
    results = []
    for params in all_params:
        res = calculate_performance(params)
        results.append(res)
        print('N=%d rt_tol=%d scenario=%d tp=%d fp=%d fn=%d prec=%.3f rec=%.3f f1=%.3f\n' % res)
    result_df = pd.DataFrame(results, columns=['N', 'rt_tol', 'scenario', 'TP', 'FP', 'FN', 'Prec', 'Rec', 'F1'])
    return result_df

def evaluate_parallel(all_params, pushed_dict=None):
    import ipyparallel as ipp
    rc = ipp.Client()
    dview = rc[:]  # use all engines
    with dview.sync_imports():
        import os
        from vimms.Common import load_obj

    if pushed_dict is not None:
        dview.push(pushed_dict)

    results = dview.map_sync(calculate_performance, all_params)
    result_df = pd.DataFrame(results, columns=['N', 'rt_tol', 'scenario', 'TP', 'FP', 'FN', 'Prec', 'Rec', 'F1'])
    return result_df


# 输入: [1,3,5,4,7]
# 输出: 2
# 输入: [2,2,2,2,2]
# 输出: 5

class Solution:
    def findNumberOfLIS(self, nums: [int]) -> int:
        if not nums:
            return 0
        n = len(nums)
        length = [1] * n
        counter = [1] * n

        for i in range(1, n):
            for j in range(i):
                if nums[j] < nums[i]:
                    if length[j] + 1 > length[i]:
                        length[i] = length[j] + 1
                        counter[i] = counter[j]
                    elif length[j] + 1 == length[i]:
                        counter[i] = counter[i] + counter[j]
        temp = max(length)
        res = sum([counter[i] for i in range(n) if length[i] == temp])

        print(length)
        print(counter)
        return res

so = Solution()
print(so.findNumberOfLIS([1, 3, 5, 4, 7]))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
-----------------------------------------
@Created: 2020/12/11
------------------------------------------
@Modify: 2020/12/11
------------------------------------------
@Description:
"""
import os
import sys
import traceback
from typing import Union, List, Optional

import mysql.connector
from mysql.connector import MySQLConnection
from mysql.connector.pooling import PooledMySQLConnection

_PROJECT_NAME = 'VulnerabilityAnalysis'
_CURRENT_ABSPATH = os.path.abspath(__file__)
sys.path.insert(0, _CURRENT_ABSPATH[:_CURRENT_ABSPATH.find(_PROJECT_NAME) + len(_PROJECT_NAME) + 1])

from vulnerability_analysis import privacy

def connect(new_connect: bool = False) -> Union[MySQLConnection, PooledMySQLConnection]:
    """
    连接服务器.
    :param new_connect: 是否重新连接
    :return: MySQL 连接
    """
    global __connection
    if new_connect: __connection = mysql.connector.connect(**privacy.MYSQL_SERVER_KWARGS)
    return __connection

def query(sql: str, val: Union[tuple, list] = (), new_connect: bool = False) -> Optional[List[tuple]]:
    """
    根据 SQL 语句查询结果. 传入 val 的字符串会被自动转义.
    val 参数使用样例: sql = ‘UPDATE oss.pypi_pkg SET raw=%s WHERE name=%s;’; val = ("'\n\r", '"\n\r').
    :param sql: MySQL 查询语句
    :param val: 查询语句 参数
    :param new_connect: 是否强制建立新连接
    :return: 查询到的所有结果 (行)
    """
    res: Optional[List[tuple]] = None
    try:
        cursor = connect(new_connect).cursor()
        if type(val) is tuple: cursor.execute(sql, val)
        else: cursor.executemany(sql, val)
        try: res = cursor.fetchall()
        except mysql.connector.errors.InterfaceError: res = None
        cursor.close()
    except mysql.connector.errors.OperationalError as ex:
        if new_connect: raise ex
        print('Connection timeout. Retrying...')
        res = query(sql, val, True)
    return res

def commit():
    """
    INSERT, UPDATE 与 DELETE 操作之后务必 commit, 否则数据库不会更新.
    :return: 无.
    """
    connect(False).commit()

# 一些初始化
__connection = None
connect(True)

if __name__ == '__main__':
    print(query("select * from oss.pypi_pkg;"))


#Escreva um programa para aprovar o empréstimo bancário para a compra de uma casa.
#Pergunte o valor da casa, o salário do comprador e em quantos anos ele vai pagar.
#A prestação mensal não pode exceder 30% do salário ou então o empréstimo será negado.
from time import sleep
print('==+' * 10)
print('\033[31mSIMULADOR DE EMPRÉSTIMO\033[m')
print('==+' * 10)
imovel = float(input('Qual o valor da imóvel? '))
salario = float(input('Qual o salário do comprador? '))
anos = int(input('Por quantos anos pretende pagar o imóvel? '))
meses = anos * 12
parcela = imovel / meses
print('O valor da parcela será de R$ \033[4m{:.2f}\033[m.'.format(parcela))
trinta = salario * 0.30
sleep(1)
print('PROCESSANDO...')
sleep(3)
if parcela > trinta:
    print('Sinto muito mas seu empréstimo foi \033[7mNEGADO\033[m.')
else:
    print('Parabéns!!! Seu empréstimo foi \033[32mAPROVADO\033[m.')


import sys
from pathlib import Path

from dflow.python import OP, OPIO, Artifact, OPIOSign, Parameter

"""@OP.function
def Duplicate(
    foo: Artifact(Path, description="input file"),
    num: Parameter(int, default=2, description="number"),
) -> {"bar": Artifact(Path)}:
    with open(foo, "r") as f:
        content = f.read()
    with open("bar.txt", "w") as f:
        f.write(content * num)
    return {"bar": Path("bar.txt")}"""

class Duplicate(OP):
    def __init__(self):
        pass

    @classmethod
    def get_input_sign(cls):
        return OPIOSign({
            "foo": Artifact(Path, description="input file"),
            "num": Parameter(int, default=2, description="number"),
        })

    @classmethod
    def get_output_sign(cls):
        return OPIOSign({
            "bar": Artifact(Path),
        })

    @OP.exec_sign_check
    def execute(
            self,
            op_in: OPIO,
    ) -> OPIO:
        with open(op_in["foo"], "r") as f:
            content = f.read()
        with open("bar.txt", "w") as f:
            f.write(content * op_in["num"])
        return OPIO({"bar": Path("bar.txt")})

if __name__ == '__main__':
    from dflow.plugins.launching import OP_to_parser
    to_parser = OP_to_parser(Duplicate)
    to_parser()(sys.argv[1:])


# vending machine
def view(D):

    d = ['콜라','사이다','식혜','옥수수수염차','레쓰비']

    for i in range(5):
        value = D.get(d[i])
        if value[0] <= 0 :
            value[2] = 'X'

    print("************Vending Machine****************")
    print("콜라\t","사이다\t","식혜\t","옥수수수염차\t","레쓰비")
    coke = D.get('콜라')
    v1 = coke[2]
    x1 = coke[0]
    cider = D.get('사이다')
    v2 = cider[2]
    x2 = cider[0]
    sikhye = D.get('식혜')
    v3 = sikhye[2]
    x3 = sikhye[0]
    corn = D.get('옥수수수염차')
    v4 = corn[2]
    x4 = corn[0]
    letsbe = D.get('레쓰비')
    v5 = letsbe[2]
    x5 = letsbe[0]

    print("구매가능여부>>")
    print(v1,"\t",v2,"\t",v3,"\t\t",v4,"\t",v5)
    print("수량>>")
    print(x1,"\t",x2,"\t",x3,"\t\t",x4,"\t",x5)

def put(drink, n, drinks):
    if drink in drinks:
        drinks[drink][0] += n

def buy(money, drinks):
    d = ['콜라','사이다','식혜','옥수수수염차','레쓰비']
    a = {}

    while True:
        ask =  input("계속 구매하시겠습니까?(yes 또는 no 입력/no 입력 시 잔액 반환): ")
        if ask == 'no':
            print("잔액 : ",money)
            break

        elif money <= 0:
            break
        else:
            for i in range(5):
                value = drinks.get(d[i])
                if value[1] <= money:
                    a[d[i]] = 'ON'
                else:
                    a[d[i]] = 'OFF'

            print("**************************현황****************************")
            print(d[0],": ",a.get(d[0])," ",d[1],": ",a.get(d[1])," ",d[2],": ",a.get(d[2])," ",d[3],": ",a.get(d[3])," ",d[4],": ",a.get(d[4]))

            drink = input("구매할 음료: ")
            value = drinks.get(drink)
            if value[0] > 0:
                value[0] -= 1
                money -= value[1]
                print(drink," 구매 완료")
                print("남은 수량: ",value[0])
                print("잔액: ",money)
            else:
                print("수량이 없어 구매할 수 없습니다.")

#main

drinks = { '콜라':[3, 500, 'O'], '사이다':[3, 600, 'O'], '식혜':[3,700, 'O'],
           '옥수수수염차' : [3, 800, 'O'], '레쓰비': [3, 1000, 'O']}

while True:
    view(drinks)
    num = int(input("1.음료 채우기   2.구매   3.종료"))

    if num == 3:
        print("종료")
        break

    elif num == 1:
        drink = input("채워넣을 음료를 입력하세요(콜라,사이다,식혜,옥수수수염차,레쓰비): ")
        n = int(input("채워넣을 음료의 수량을 입력하세요: "))
        put(drink, n, drinks)

    elif num == 2:
        money = int(input("돈을 넣어주세요: "))
        buy(money, drinks)


# coding: utf-8

import logging

from PIL import Image, ImageDraw, ImageFont

class UnicodeGlyphGenerator(object):

    def __init__(self, path_to_font: str = None, font_size: int = 72,
                 layout_engine=None, pixels_margin: int = 10, bkgr_color="#000000"):

        self.pixels_margin = pixels_margin
        self.bkgr_color = bkgr_color
        logging.debug("Reading fonts...")

        if path_to_font is None:

            try:
                import importlib.resources as pkg_resources
            except ImportError:
                # Trying backported to PY<37 `importlib_resources`.
                import importlib_resources as pkg_resources

            from . import data

            with pkg_resources.path(data, "NewGardinerSMP.ttf") as filepath:
                self.font = ImageFont.truetype(str(filepath), size=font_size, encoding="unic", layout_engine=layout_engine)
        else:
            self.font = ImageFont.truetype(path_to_font, size=font_size, encoding="unic", layout_engine=layout_engine)

    def generate_image(self, unicode_text: str, save_path_png=None):
        """
            Draws an image of the provided Unicode character using the font provided
            on construction of the `UnicodeGlyphGenerator` object
        :param unicode_text: a character to draw
        :param save_path_png: path for saving the PNG image
        """

        if len(unicode_text) > 1:
            logging.warning("Please not that the generated image might be formatted poorly "
                            "since you are trying to draw multiple signs.")

        text_width, text_height = self.font.getsize(unicode_text)
        canvas = Image.new("RGB", (text_width + self.pixels_margin, text_height + self.pixels_margin), (255, 255, 255))
        drawing_engine = ImageDraw.Draw(canvas)
        drawing_engine.text(xy=(self.pixels_margin // 2, self.pixels_margin // 2),
                            text=unicode_text, font=self.font, fill=self.bkgr_color)
        canvas.save(save_path_png, "PNG")


#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2022/3/18 20:03
Desc: 谷歌指数, 必须使用代理, 获得的数据是小时频率的, 所以获取时间周期太长会很慢
"""
from akshare.index.request import TrendReq
import pandas as pd

def google_index(
    symbol: str = "python",
    start_date: str = "20191201",
    end_date: str = "20191204",
):
    """
    谷歌指数
    :param symbol: 关键词
    :type symbol: str
    :param start_date: 开始时间
    :type start_date: str
    :param end_date: 结束时间
    :type end_date: str
    :return: 谷歌指数
    :rtype: pandas
    """

    start_date = "-".join([start_date[:4], start_date[4:6], start_date[6:]])
    end_date = "-".join([end_date[:4], end_date[4:6], end_date[6:]])
    pytrends = TrendReq(hl="en-US", tz=360)
    kw_list = [symbol]
    pytrends.build_payload(
        kw_list, cat=0, timeframe=start_date + " " + end_date, geo="", gprop=""
    )
    search_df = pytrends.interest_over_time()
    search_se = search_df[symbol]
    search_df = pd.DataFrame(search_se)
    search_df.reset_index(inplace=True)
    if "T" not in start_date:
        search_df['date'] = pd.to_datetime(search_df['date']).dt.date
    return search_df

if __name__ == "__main__":
    google_index_df = google_index(symbol="bitcoin", start_date="20000101", end_date="20220303")
    print(google_index_df)

    google_index_df = google_index(symbol="python", start_date='20040101', end_date='20191201')
    print(google_index_df)

    google_index_df = df = google_index(symbol="AI", start_date="20191210T10", end_date="20191210T23")
    print(google_index_df)


#!/usr/bin/env python3

import osmfilter.osm_colors           as CC
import osmfilter.pre_filter           as pre_filter
import osmfilter.osm_info             as osm_info
import osmfilter.osm_pickle           as osm_pickle
import os
from osmfilter.element_filter     import GetOSM_IDs

import json
import sys
import pprint
import logging

logging.basicConfig()
logger=logging.getLogger(__name__)
#logger.setLevel(logging.INFO)
logger.setLevel(logging.WARNING)

def write_overview(elements,elementname,outputdir):
    """
    **Purpose**
        writes overview of elements to outputdir

    **Input**
        elements:
            list of filtered element items
        elementname:
            name of the elements (e.g. 'pipelines')
        outputdir:
            relative name of outputdir
    """

    original = sys.stdout
    if outputdir  != "":
        filename   = elementname+"_short.json"
        logdirbase = (os.path.dirname(outputdir)+"/Analysis/Elements")
        logfile    = os.path.join(logdirbase,filename)
#        print("Outputfile: ", logfile)
        os.makedirs(os.path.dirname(logfile), exist_ok=True)
        f = open(logfile, 'w')
        sys.stdout = f#Tee(f)
    sys.stdout.write("Overview OSM "+elementname +"\n")
    sys.stdout.write("===========\n")
    sys.stdout.write("Nodes:       " + "{:>26}".format(str(len(elements["Node"])))+"\n")
    sys.stdout.write("Ways:        " + "{:>26}".format(str(len(elements["Way"])))+"\n")
    sys.stdout.write("Relations:   " + "{:>26}".format(str(len(elements["Relation"])))+"\n")
    sys.stdout.write("===========\n\n\n")
    counter=0

    for entry in elements["Node"]:
        sys.stdout.write('\n------Node--------\n')
        counter+=1
        sys.stdout.write('\n'+'Nr. '+str(counter)+" of "+ elementname+"\n")
        sys.stdout.write('Id: ' +str(elements["Node"][entry]['id'])+"\n")
        sys.stdout.write('Tags:\n')
        dictstring = pprint.pformat(elements["Node"][entry]['tags'],width=35)
        sys.stdout.write(dictstring +"\n")
    counter=0
    for entry in elements["Way"]:
        sys.stdout.write('\n------Way--------\n')
        counter+=1
        sys.stdout.write('\n'+'Nr. '+str(counter)+" of "+ elementname+"\n")
        sys.stdout.write('Id: ' +str(elements["Way"][entry]['id'])+"\n")
        sys.stdout.write('Tags:\n')
        dictstring = pprint.pformat(elements["Way"][entry]['tags'],width=35)
        sys.stdout.write(dictstring +"\n")
    counter=0
    for entry in elements["Relation"]:
        sys.stdout.write('\n------Relation--------\n')
        counter+=1
        sys.stdout.write('\n'+'Nr. '+str(counter)+" of "+ elementname+"\n")
        sys.stdout.write('Id: ' +str(elements["Relation"][entry]['id'])+"\n")
        sys.stdout.write('Tags:\n')
        dictstring = pprint.pformat(elements["Relation"][entry]['tags'],width=35)
        sys.stdout.write(dictstring +"\n")
    sys.stdout = original
    pass

def write_elements(elements,elementname,outputdir):
    """
    **Purpose**
        writes elements to JSON file in outputdir

    **Input**
        elements:
            list of filtered element items
        elementname:
            name of the elements (e.g. 'pipelines')

    **Return**
        writes elements to jsonfile at outputdir
    """

    write_overview(elements,elementname,outputdir)
    filename   = elementname+".json"
    logdirbase = (os.path.dirname(outputdir)+"/Analysis/Elements/")
    logfile    = os.path.join(logdirbase,filename)

    os.makedirs(os.path.dirname(logfile), exist_ok=True)
    with open(logfile, 'w') as target:
            json.dump(elements, target, indent=4, separators=(',', ':'))
    pass

def find_elements(data, ID_type_list):
    """
    **Purpose**
        use ID_type_list to find items in the prefiltered data and return
        them in a dict

    **Input**
        data:
            dictionary of prefiltered Data
        ID_type_list:
            [({OSM_id},{OSM_item_type}),]

            e.g. [('457320703','Node'),('457320703','Node')]

    **Output**
        elements:
            dictionary of Nodes, Ways and Relation
    """

    elements={'Node':{},'Way':{},'Relation':{}}

    for i in range(len(ID_type_list)):
        if ID_type_list[i][1] == "Way":
                elements['Way'][ID_type_list[i][0]]=data["Way"][ID_type_list[i][0]]
        elif ID_type_list[i][1] == "Node":
                elements['Node'][ID_type_list[i][0]]=data["Node"][ID_type_list[i][0]]
        elif ID_type_list[i][1] == "Relation":
                elements['Relation'][ID_type_list[i][0]]=data["Relation"][ID_type_list[i][0]]
    return elements

def create_single_element(data,JSON_outputfile,whitefilter,blackfilter):
    '''
    **Purpose**
        the prefiltered OSM data are filtered for a specific element.

    **Input**
        data:
            dictionary of prefiltered data
        whitefilter:
            (see doc: filter)
        blackfilter:
            (see doc: filter)

    **Return**
        elements:
           dictionaries with filtered elements
    '''

    elementIDs = GetOSM_IDs(data,whitefilter,blackfilter)
    elements = find_elements(data,elementIDs)
    write_elements(elements,"pipelines",JSON_outputfile)

    logging.info('Save elements as jsonfiles at\n'+CC.Cyan+ os.path.dirname(JSON_outputfile)+"/Analysis/Elements\n"+CC.End)
    return elements

def run_filter(elementname,countrycode,PBF_inputfile,JSON_outputfile,
                    prefilter,whitefilter,blackfilter, NewPreFilterData=True,
                    CreateElements=True, LoadElements=True,verbose=False):
    '''
    **Purpose**
        Reads OSM pbf-files, filters data and storages the output as elements in JSON files`

    **Input**
        elementname:
            name of the element (e.g. 'pipelines')
        countrycode:
            two digits, (e.g. 'EU')
        PBF_inputfile:
            filepathname of inputfile
        JSON_outputfile:
            filedir of output
        prefilter:
            prefilter data (see doc: filter)
        whitefilter:
            whitefilter data (see doc:   :ref:`filter <filter>' )
        blackfilter:
            blackfilter data (see doc: filter)
        NewPreFilterData:
            prefilter and store Data from pbf
        CreateElements:
            filter and store Elements from Data
        LoadElements:
            load Elements

    **Return**
       Data:
           prefiltered Data of pbf
       Elements:
           filtered Elements from Data

    **Example**

    Access output:
        Data['Node']['6037838916']['lonlat']
    '''
    if verbose == False: logging.disable(logging.INFO)

    element         = ()
    Data           = {}

    if NewPreFilterData==True:
        ###Create and Save Gas Data
        logger.info(CC.Script+'Filter Gas Data for country ' + countrycode+ CC.End)
        logger.info('Load OSM data from '+CC.Cyan+ PBF_inputfile+'\n'+CC.End)
        pre_filter.filter_pbf(PBF_inputfile, JSON_outputfile,prefilter)
        logger.info('\nRead gas data from \n'+CC.Cyan+ JSON_outputfile+CC.End)
        Data = osm_info.ReadJason(JSON_outputfile,verbose='no')
        ###Save Gas Data (Pickle)
        DataDict = {"Data":Data}
        logger.info('\nPickle gas data to \n'+os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile))+CC.End)
        osm_pickle.picklesave(DataDict,os.path.realpath(os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile))))

    # loading of OSM Gas daten filtered data
    DataDict      = {"Data":Data}
    DataDict      = osm_pickle.pickleload(DataDict,os.path.realpath(os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile))))
    Data      = DataDict["Data"]

    if CreateElements==True:
        ###Create Elements
        logger.info(CC.Script+'\nCreate the OSM-elements\n'+CC.End)
        element = create_single_element(Data,JSON_outputfile,whitefilter,blackfilter)
        ###Save Elements(Pickle)
    Elements = {
                  elementname:element
                }

    if CreateElements==True:
        logger.info('\nPickle OSM-elements to \n'+CC.Cyan+ os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile), 'Elements/')+'\n'+CC.End)
        osm_pickle.picklesave(Elements,os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile), 'Elements/'))

    if LoadElements==True:
        logger.info('\nUnpickle OSM-elements from \n'+CC.Cyan +os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile), 'Elements/')+CC.End)

        Elements = osm_pickle.pickleload(Elements,os.path.join(os.getcwd(),os.path.dirname(JSON_outputfile), 'Elements/'))

    return Data, Elements


import http.client
import json

DICT_GENES = {
    "FRAT 1": "ENSG00000165879",
    "ADA": "ENSG00000196839",
    "FXN": "ENSG00000165060",
    "RNU6_269P": "ENSG00000212379",
    "MIR633": "ENSG00000207552",
    "TTTY4C": "ENSG00000226906",
    "RBMY2YP": "ENSG00000227633",
    "FGFR3": "ENSG00000068078",
    "KDR": "ENSG00000128052",
    "ANK2": "ENSG00000145362"
}

SERVER = "rest.ensembl.org"
ENDPOINT = "/sequence/id/"
ID = DICT_GENES["MIR633"]
PARAMETERS = "?content-type=application/json"

connection = http.client.HTTPConnection(SERVER)
connection.request("GET", ENDPOINT + ID + PARAMETERS)
response = connection.getresponse()
print("response received: ", response.status, response.reason)
if response.status == 200: #if everything is fine in the server
    response = json.loads(response.read().decode())
    #print(json.dumps(response, indent=4, short_keys=True)) #json.dumps is to transform it to str, the rest is to print it in several lines
    print("Gene:", ID)
    print("Description:", response["desc"])
    print("Bases:", response["seq"])
elif response.status == 404:
    print("check if the ENDPOINT was correctly written")
# we do not need to write the else as if the server is wrong, it will be printed in thee response


import pytest
from django.core.exceptions import ValidationError

pytestmark = pytest.mark.django_db

class TestCategoryModel:
    def test_str_method(self, category_factory):
        post = category_factory(name='test_category')
        assert post.__str__() == 'test_category Category'

class TestProductModel:
    def test_str_method(self, brand_factory):
        post = brand_factory(name='test_brand')
        assert post.__str__() == 'test_brand Brand'

class TestBrandModel:
    def test_str_method(self, product_factory):
        post = product_factory()
        assert post.__str__() == 'test_product Product'

class TestProductLineModel:
    def test_str_method(self, product_factory, product_line_factory):
        post = product_line_factory(sku='sku_1', product=product_factory(name='for_pl_prod'))
        assert post.__str__() == 'for_pl_prod Product Line sku_1'

    def test_clean(self, product_line_factory, product_factory):
        obj = product_factory()
        product_line_factory(product=obj)
        with pytest.raises(ValidationError):
            product_line_factory(order=1, product=obj).clean()
        with pytest.raises(ValidationError):
            product_line_factory(order=0).clean()


from typing import Annotated

from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.security import get_current_user
from app.db.session import get_session
from app.models import Team, User
from app.schemas import TeamList, TeamPublic, TeamSchema

CurrentUser = Annotated[User, Depends(get_current_user)]

router = APIRouter(prefix='/teams', tags=['teams'])

@router.post('/', response_model=TeamPublic)
def create_team(
    team: TeamSchema,
    user: CurrentUser,
    db: Session = Depends(get_session),
):
    db_team: Team = Team(
        name=team.name,
        team_members=team.team_members,
        owner_id=user.id,
    )
    db.add(db_team)
    db.commit()
    db.refresh(db_team)

    return db_team

@router.get('/', response_model=TeamList)
def read_users(
    user: CurrentUser,
    db: Session = Depends(get_session),
    skip: int = 0,
    limit: int = 100,
):
    teams = db.scalars(
        select(Team).where(Team.owner_id == user.id).offset(skip).limit(limit)
    ).all()
    return {'teams': teams}


from collections import Counter, defaultdict
from typing import List, NamedTuple, Optional, Tuple, Union, Dict

import numpy as np

from vizseq._data import VizSeqDataSources

class VizSeqStatsResult(NamedTuple):
    n_examples: int
    # number of tokens for text, number of filter bank feature frames for speech
    n_src_tokens: Dict[str, int]
    n_ref_tokens: Dict[str, int]
    # number of chars for text, duration (ms) for speech
    n_src_chars: Dict[str, int]
    n_ref_chars: Dict[str, int]
    tag_freq: List[Tuple[str, int]]
    src_vocab: Dict[str, List[Tuple[str, int]]]
    ref_vocab: Dict[str, List[Tuple[str, int]]]
    src_tkn_log2_freq: Dict[str, List[float]]
    ref_tkn_log2_freq: Dict[str, List[float]]
    src_lens: Dict[str, List[int]]
    ref_lens: Dict[str, List[int]]

    def to_dict(self, formatting: bool = True) -> Dict:
        r = self._asdict()

        if formatting:
            def _format(d):
                if isinstance(d, (int, float)):
                    return f'{d:,}'
                elif isinstance(d, dict):
                    return {k: _format(v) for k, v in d.items()}
                else:
                    return d

            return {k: _format(v) for k, v in r.items()}

        return r

class VizSeqStats(object):
    MAX_SAMPLES = 4096

    @classmethod
    def auto_sample(cls, data: Union[List[int], List[float]]):
        n = len(data)
        if n > cls.MAX_SAMPLES:
            return [data[i] for i in range(0, n, n // cls.MAX_SAMPLES)]
        return data

    @classmethod
    def get(
            cls, src: VizSeqDataSources, ref: VizSeqDataSources,
            tags: Optional[VizSeqDataSources] = None
    ) -> VizSeqStatsResult:
        n_examples = len(src)
        n_src_tokens, n_ref_tokens = defaultdict(int), defaultdict(int)
        n_src_chars, n_ref_chars = defaultdict(int), defaultdict(int)
        src_vocab, ref_vocab = {}, {}
        src_lens, ref_lens = defaultdict(list), defaultdict(list)
        tag_freq = Counter()

        for name, cur_src in zip(src.names, src.data):
            for i in range(len(cur_src)):
                src_lens[name].append(cur_src.get_len(i))
                n_src_chars[name] += cur_src.get_len(i, finer=True)
            src_vocab[name] = cur_src.vocab
            n_src_tokens[name] = sum(src_lens[name])
            src_lens[name] = cls.auto_sample(src_lens[name])
            if n_src_chars[name] == 0:
                src_lens[name] = []

        for name, cur_ref in zip(ref.names, ref.data):
            for i in range(len(cur_ref)):
                ref_lens[name].append(cur_ref.get_len(i))
                n_ref_chars[name] += cur_ref.get_len(i, finer=True)
            ref_vocab[name] = cur_ref.vocab
            n_ref_tokens[name] = sum(ref_lens[name])
            ref_lens[name] = cls.auto_sample(ref_lens[name])
            if n_ref_chars[name] == 0:
                ref_lens[name] = []

        if tags is not None:
            assert tags.text_merged
            for cur_tags in tags.text:
                tag_freq.update(cur_tags)
        tag_freq = tag_freq.most_common()
        src_tkn_log2_freq = {
            k: cls.auto_sample([np.round(np.log2(f + 1), 2) for _, f in v])
            for k, v in src_vocab.items()
        }
        ref_tkn_log2_freq = {
            k: cls.auto_sample([np.round(np.log2(f + 1), 2) for _, f in v])
            for k, v in ref_vocab.items()
        }
        return VizSeqStatsResult(
            n_examples=n_examples,
            n_src_tokens=n_src_tokens,
            n_ref_tokens=n_ref_tokens,
            n_src_chars=n_src_chars,
            n_ref_chars=n_ref_chars,
            tag_freq=tag_freq,
            src_vocab=src_vocab,
            ref_vocab=ref_vocab,
            src_tkn_log2_freq=src_tkn_log2_freq,
            ref_tkn_log2_freq=ref_tkn_log2_freq,
            src_lens=src_lens,
            ref_lens=ref_lens,
        )