"""
Stations/Channels download functions

:date: Dec 3, 2017

.. moduleauthor:: Riccardo Zaccarelli <rizac@gfz-potsdam.de>
"""
import re
from itertools import cycle
import logging
from urllib.request import Request

import pandas as pd
from sqlalchemy import or_, and_

from stream2segment.io.cli import get_progressbar
from stream2segment.io.db.pdsql import dbquery2df, shared_colnames, mergeupdate
from stream2segment.download.db.models import DataCenter, Station, Channel
from stream2segment.download.exc import FailedDownload
from stream2segment.download.url import read_async
from stream2segment.download.modules.utils import (get_dataframe_from_fdsn,
                                                   dbsyncdf, formatmsg,
                                                   logwarn_dataframe, strconvert)

# (https://docs.python.org/2/howto/logging.html#advanced-logging-tutorial):
logger = logging.getLogger(__name__)

def get_channels_df(session, datacenters_df, eidavalidator, net, sta, loc, cha,
                    starttime, endtime, min_sample_rate, update,
                    max_thread_workers, timeout, blocksize, db_bufsize,
                    show_progress=False):
    """Return a Dataframe representing a query to the station service of each
    URL in :func:`stream2segment.download.modules.datacenters_df` with the
    given arguments.

    :param datacenters_df: (DataFrame) the first item resulting from
        `get_datacenters_df`
    :param eidavalidator: None, or an instance of
        :class:`stream2segment.download.modules.datacenter.EidaValidator`
    :param min_sample_rate: minimum sampling rate, set to negative value
        for no-filtering (all channels)
    """
    postdata = get_post_data(net, sta, loc, cha, starttime, endtime)
    dc_url_key, dc_id_key = DataCenter.station_url.key, DataCenter.id.key
    iterable = ((id_, Request(url, data=('format=text\nlevel=channel\n'+
                                         post_data_str).encode('utf8')))
                for url, id_, post_data_str in zip(datacenters_df[dc_url_key],
                                                   datacenters_df[dc_id_key],
                                                   cycle([postdata])))

    ret = []
    url_failed_dc_ids = []
    with get_progressbar(show_progress, length=len(datacenters_df)) as pbar:
        for obj, url, result, exc, status_code in \
                read_async(iterable, urlkey=lambda obj: obj[-1], blocksize=blocksize,
                           max_workers=max_thread_workers, decode='utf8',
                           timeout=timeout):
            pbar.update(1)
            dcen_id = obj[0]
            if exc:
                url_failed_dc_ids.append(dcen_id)
                logger.warning(formatmsg("Unable to fetch stations", exc, url))
            else:
                try:
                    dframe = get_dataframe_from_fdsn(result, "channel", url)
                    if not dframe.empty:
                        dframe[Station.datacenter_id.key] = dcen_id
                        ret.append(dframe)
                except ValueError as verr:
                    logger.warning(formatmsg("Discarding response data", verr,
                                             url))

    db_cha_df = pd.DataFrame()
    if url_failed_dc_ids:
        # if some datacenter does not return station, warn with INFO
        dc_df_fromdb = datacenters_df.loc[datacenters_df[DataCenter.id.key].\
            isin(url_failed_dc_ids)]
        logger.info(formatmsg("Fetching stations from database for %d (of %d) "
                              "data center(s)", "download errors occurred"),
                    len(dc_df_fromdb), len(datacenters_df))
        logger.warning(dc_df_fromdb[DataCenter.dataselect_url.key].
                       to_string(index=False))
        db_cha_df = get_channels_df_from_db(session, dc_df_fromdb, net, sta,
                                            loc, cha, starttime, endtime,
                                            min_sample_rate)

    # build two dataframes which we will concatenate afterwards
    web_cha_df = pd.DataFrame()
    if ret:  # pd.concat complains for empty list
        try:
            web_cha_df = filter_channels_df(pd.concat(ret, axis=0,
                                                      ignore_index=True,
                                                      copy=False),
                                            net, sta, loc, cha,
                                            min_sample_rate)

            # this raises FailedDownload if we cannot save any element:
            web_cha_df = save_stations_and_channels(session, web_cha_df,
                                                    eidavalidator, update,
                                                    db_bufsize)
        except FailedDownload as qexc:
            if db_cha_df.empty:
                raise
            else:
                logger.warning(qexc)

    if db_cha_df.empty and web_cha_df.empty:
        # ok, now let's see if we have remaining datacenters to be
        # fetched from the db
        raise FailedDownload(formatmsg("No station found",
                                       "Unable to fetch stations from all "
                                       "data-centers, no data to fetch from "
                                       "the database. Check config and log "
                                       "for details"))
    ret = None
    if db_cha_df.empty:
        ret = web_cha_df
    elif web_cha_df.empty:
        ret = db_cha_df
    else:
        ret = pd.concat((web_cha_df, db_cha_df), axis=0, ignore_index=True,
                        sort=False)
    # the columns for the channels dataframe that will be returned
    return ret[[c.key for c in (Channel.id, Channel.station_id,
                                Station.latitude, Station.longitude,
                                Station.datacenter_id, Station.start_time,
                                Station.end_time, Station.network,
                                Station.station, Channel.location,
                                Channel.channel)]].copy()

def get_post_data(net, sta, loc, cha, starttime=None, endtime=None):
    """Return the string for a FDSN POST request according to the given
        net(works), sta(tions), loc(ations) and cha(nnels), all iterable of
        strings returned by :func:`stream2segment.download.utils.nslc_lists`

    Example:
    ```
    >>> get_post_data([], ['ABC'], [''], ['!A*', 'HH?', 'HN?'], None, None)
    '* ABC -- HH?,HN? * *'
    ```
    Note negations (!A*) not included: strings starting with "!" mean 'NOT' in
    this program's syntax: as this feature is not supported in an FDSN query it
    cannot be forwarded to any web service. The feature is used here in other
    module functions *after* downloading data

    Arguments are usually the output of
    :func:`stream2segment.download.utils.nslc_lists`:

    :param net: an iterable of strings denoting networks.
    :param sta: an iterable of strings denoting stations.
    :param loc: an iterable of strings denoting locations.
    :param cha: an iterable of strings denoting channels.
    """
    args = []
    for i, lst in enumerate([net, sta, loc, cha]):
        parsearg = '*'
        # parse arguments if given, and not all negations (in the latter case, just
        # provide * = accept all. We will filter out later, on the returned response)
        if lst and not all(v[0:1] == '!' for v in lst):
            parsearg = ",".join(v for v in lst if v[0:1] != '!')
            if i == 3 and not parsearg:  # loc: empty has to be input as '--'
                parsearg = '--'
        args.append(parsearg)

    args.append("*" if not starttime else starttime.isoformat())
    args.append("*" if not endtime else endtime.isoformat())

    return "{} {} {} {} {} {}".format(*args)

def filter_channels_df(channels_df, net, sta, loc, cha, min_sample_rate):
    """Filter out `channels_df` according to the given parameters. Raise
    `FailedDownload` if the returned filtered data frame woul be empty

    Note that `net, sta, loc, cha` filters will be considered only if negations
    (i.e., with leading exclamation mark: "!A*") because the 'positive' filters
    are FDSN stantard and are supposed to be already used in producing
    `channels_df`. Example:
    ```
        filter_channels_df(d, [], ['ABC'], [''], ['!A*', 'HH?', 'HN?'])
    ```
    basically takes the dataframe `d`, finds the column related to the
    `channels` key and removes all rows whose channel starts with 'A',
    returning the new filtered data frame.

    Arguments are usually the output of
    :func:`stream2segment.download.utils.nslc_lists`

    :param net: an iterable of strings denoting networks.
    :param sta: an iterable of strings denoting stations.
    :param loc: an iterable of strings denoting locations.
    :param cha: an iterable of strings denoting channels.
    :param min_sample_rate: numeric, minimum sample rate. If negative or zero,
        this parameter is ignored
    """
    # create a dict of regexps for pandas dataframe. FDSNWS do not support NOT
    # operators . Thus concatenate expression with OR
    dffilter = None
    sa_cols = (Station.network, Station.station, Channel.location,
               Channel.channel)

    for lst, sa_col in zip((net, sta, loc, cha), sa_cols):
        if not lst:
            continue
        lst = [_ for _ in lst if _[0:1] == '!']  # take only negation expr.
        if not lst:
            continue
        condition = ("^%s$" if len(lst) == 1 else "^(?:%s)$") % \
            "|".join(strconvert.wild2re(x[1:]) for x in lst)
        flt = channels_df[sa_col.key].str.match(re.compile(condition))
        if dffilter is None:
            dffilter = flt
        else:
            dffilter &= flt

    if min_sample_rate > 0:
        # account for Nones, thus negate the predicate below:
        flt = ~(channels_df[Channel.sample_rate.key] >= min_sample_rate)
        if dffilter is None:
            dffilter = flt
        else:
            dffilter &= flt

    ret = channels_df if dffilter is None else \
        channels_df[~dffilter].copy()  # noqa

    if ret.empty:
        raise FailedDownload("No channel matches user defined filters "
                             "(network, channel, sample rate, ...)")

    discarded_sr = len(channels_df) - len(ret)
    if discarded_sr:
        logger.warning("%d channel(s) discarded according to current "
                       "configuration filters (network, channel, sample rate, "
                       "...)", discarded_sr)

    return ret

def get_channels_df_from_db(session, datacenters_df, net, sta, loc, cha,
                            starttime, endtime, min_sample_rate):
    """Return a Dataframe of the database channels according to the
    arguments"""
    # Build SQL-Alchemy binary expressions (suffix '_be'), i.e. an object
    # reflecting a SQL clause)
    srate_be = True
    if min_sample_rate > 0:
        srate_be = Channel.sample_rate >= min_sample_rate
    # Select only relevant datacenters. Convert numnpy array `tolist()` because
    # database clauses work best with native Python objects:
    dc_be = Station.datacenter_id.in_(datacenters_df[DataCenter.id.key].
                                      tolist())
    # Select by starttime and endtime (below). Note that it must hold
    # station.endtime > starttime AND station.starttime< endtime
    stime_be = True
    if starttime:
        stime_be = ((Station.end_time == None) |
                    (Station.end_time > starttime))
    # endtime: Limit to metadata epochs ending on or before the specified end
    # time. Note that station's ent_time can be None
    etime_be = (Station.start_time < endtime) if endtime else True  # noqa
    sa_cols = [Channel.id, Channel.station_id, Station.latitude,
               Station.longitude, Station.start_time, Station.end_time,
               Station.datacenter_id, Station.network, Station.station,
               Channel.location, Channel.channel]
    # filter on net, sta, loc, cha, as specified in config and converted to
    # SQL-Alchemy binary expression:
    nslc_be = get_sqla_binexp(net, sta, loc, cha)
    # note below: binary expressions (all variables ending with "_be") might be
    # the boolean True. SQL-Alchemy seems to understand them as long as they
    # are preceded by a "normal" binary expression. Thus this works:
    # `q.filter(binary_expr & True)` and is equal to `q.filter(binary_expr)`,
    # whereas `q.filter(True & True)` (we hoped it could be a no-op filter)
    # is not working as a no-op filter, it simply does not work at all.
    # Here we should be safe cause `dc_be` is a non-True sql alchemy expression
    # (see above):
    qry = session.query(*sa_cols).join(Channel.station).filter(and_(dc_be,
                                                                    srate_be,
                                                                    nslc_be,
                                                                    stime_be,
                                                                    etime_be))
    return dbquery2df(qry)

def get_sqla_binexp(net, sta, loc, cha):
    """Return the sql-alchemy binary expression to be used as argument for
    database queries (e.g., `session.query(...)`) which translates to SQL the
    given net(works), sta(tions), loc(ations) and cha(nnels), all iterable of
    strings. Example:
    ```
    >>> get_sqla_binexp([], ['ABC'], [''], ['!A*', 'HH?', 'HN?'])
    'sta=ABC&loc=&cha=HH?,HN?'
    ```
    Note negations (!A*) mean 'NOT' in this program's syntax (this feature is
    not standard in an FDSN query).

    Arguments are usually the output of
    :func:`stream2segment.download.utils.nslc_lists`.

    :param net: an iterable of strings denoting networks.
    :param sta: an iterable of strings denoting stations.
    :param loc: an iterable of strings denoting locations.
    :param cha: an iterable of strings denoting channels.
    """
    # build a sql alchemy filter condition
    sa_cols = (Station.network, Station.station, Channel.location,
               Channel.channel)

    sa_bin_exprs = []

    wild2sql = strconvert.wild2sql  # conversion function

    for column, lst in zip(sa_cols, (net, sta, loc, cha)):
        matches = []
        for string in lst:
            negate = False
            if string[0:1] == '!':
                negate = True
                string = string[1:]

            if '?' in string or '*' in string:
                condition = column.like(wild2sql(string))
            else:
                condition = (column == string)

            if negate:
                condition = ~condition

            matches.append(condition)

        if matches:
            sa_bin_exprs.append(or_(*matches))

    return True if not sa_bin_exprs else and_(*sa_bin_exprs)

class ST:  # noqa
    """Simple enum-like container of strings defining the station's related
    database/dataframe columns needed in this module
    """
    ID = Station.id.key  # pylint: disable=invalid-name
    NET = Station.network.key  # pylint: disable=invalid-name
    STA = Station.station.key  # pylint: disable=invalid-name
    STIME = Station.start_time.key  # pylint: disable=invalid-name
    ETIME = Station.end_time.key  # pylint: disable=invalid-name
    DCID = Station.datacenter_id.key  # pylint: disable=invalid-name
    # set columns to show in the log on error ("no row written"):
    ERRCOLS = [NET, STA, STIME, DCID]  # pylint: disable=invalid-name

class CH:  # noqa
    """Simple enum-like container of strings defining the channel's related
    database/dataframe columns needed in this module
    """
    ID = Channel.id.key  # pylint: disable=invalid-name
    STAID = Channel.station_id.key  # pylint: disable=invalid-name
    LOC = Channel.location.key  # pylint: disable=invalid-name
    CHA = Channel.channel.key  # pylint: disable=invalid-name
    # set columns to show in the log on error ("no row written"):
    ERRCOLS = [ST.NET, ST.STA, LOC, CHA, ST.STIME, ST.DCID]  # noqa

def save_stations_and_channels(session, channels_df, eidavalidator, update,
                               db_bufsize):
    """Saves to db channels (and their stations) and returns a dataframe with
    only channels saved. The returned Dataframe will have the column 'id'
    (`Station.id`) renamed to 'station_id' (`Channel.station_id`) and a new
    'id' column referring to the Channel id (`Channel.id`)

    :param channels_df: pandas DataFrame
    """
    channels_df, conflict_between, conflict_within = \
        drop_duplicates(session, channels_df, eidavalidator)

    if channels_df.empty:
        raise FailedDownload('No channel left after cleanup '
                             '(e.g., drop duplicates)')

    # if update is True, don't update inventories HERE (handled later)
    _update_stations = update
    if _update_stations:
        _update_stations = [_ for _ in shared_colnames(Station, channels_df,
                                                       pkey=False)
                            if _ != Station.inventory_xml.key]

    # Add stations to db (Note: no need to check for `empty(channels_df)`,
    # `dbsyncdf` raises a `FailedDownload` in case). First set columns
    # defining channel identity (db unique constraint):
    cols = [Station.network, Station.station, Station.start_time]
    # Then add (sync actually, already existing stations are not inserted):
    sta_df = dbsyncdf(channels_df.drop_duplicates(subset=[ST.NET, ST.STA,
                                                          ST.STIME, ST.DCID]),
                      session, cols, Station.id, _update_stations,
                      buf_size=db_bufsize, keep_duplicates=False,
                      cols_to_print_on_err=ST.ERRCOLS)
    # `sta_df` will have the STA_ID columns, `channels_df` not: set it from the
    # former to the latter:
    channels_df = mergeupdate(channels_df, sta_df,
                              [ST.NET, ST.STA, ST.STIME, ST.DCID],
                              [ST.ID])
    # rename now 'id' to 'station_id' before writing the channels to db:
    channels_df.rename(columns={ST.ID: CH.STAID}, inplace=True)

    # check channels with empty station id (should never happen, let's be
    # picky):
    null_sta_id = channels_df[CH.STAID].isnull()
    conflict_null_sta_id = pd.DataFrame()
    if null_sta_id.any():
        conflict_null_sta_id = channels_df[null_sta_id]
        channels_df = channels_df[~null_sta_id]

    # Add channels to db. First seet columns defining channel identity (db
    # unique constraint):
    cols = [Channel.station_id, Channel.location, Channel.channel]
    # Then add (sync actually, already existing channels are not inserted):
    channels_df = dbsyncdf(channels_df, session, cols, Channel.id, update,
                           buf_size=db_bufsize, keep_duplicates=False,
                           cols_to_print_on_err=CH.ERRCOLS)

    log_unsaved_channels(conflict_between, conflict_within,
                         conflict_null_sta_id)

    return channels_df

def drop_duplicates(session, channels_df, eidavalidator):
    """Drop from channels_df duplicates (same station between or within data
    centers). For duplicates between data centers, uses `eidavalidator` or the
    database accessible via the session object, if `eidavalidator` is None.

    :return: the tuple of Dataframes:
        `(oks, conflict_between_dc, conflict_within_dc)`, where `oks` is a
        subset of `channels_df` with valid channels (one row per channel), and
        the other two contain channels discarded: `conflict between_dc`
        contains channels whose station is associated to several dc_id
        (datacenter id) and `conflict_within_dc` contains channels of the same
        dc_id violating a database unique constraint, e.g. two different
        channels with the same (network, station, location, channel,
        start_time, dc_id).
    """
    # Add to the list below the stations discarded because not uniquely mapped
    # to a single data center (dc_id). E.g.:
    #   net sta loc cha start_time dc_id
    #   N   S   L   C   2010-01-01 1
    #   N   S   L   C   2010-01-01 2
    # (Depending on the eidavalidator, only one or both rows will be added)
    conflict_between_dc = []
    # Add to the list below the stations discarded because of some non-unique
    # database constraint. E.g.:
    #   net sta loc cha start_time end_time   dc_id
    #   N   S   L   C   2010-01-01 None       1
    #   N   S   L   C   2010-01-01 2011-01-01 1
    # (both rows will be added)
    conflict_within_dc = []
    # list of ok channels (not falling in any category above):
    oks = []
    # station_datacenters_from_db = None  # dataframe lazy loaded (see below)

    # first drop duplicates (all columns the same):
    channels_df = channels_df.drop_duplicates()

    # From now on do not use anymore duplicated or drop_duplicates: the removal
    # of duplicates now is more tricky.
    # Let's  group by (net, sta, starttime), which is a unique constraints of
    # the station table, and analyse what we get:
    for (net, sta, stime), df_ in channels_df.\
            groupby([ST.NET, ST.STA, ST.STIME], sort=False):
        # if we have only ONE dc_id, skip "if" below.. Otherwise:
        if len(pd.unique(df_[ST.DCID])) > 1:
            # We have more than one data center mapped to the tuple
            # (net, sta, stime): get all ids from the eidavalidator (=object
            # representing the eida routing service) and put them in the set
            # below:
            real_dc_ids = set()
            # group stations by tuples (net, sta, stime, etime), because etime
            # is needed by the eidavalidator.get_dc_id. (pd.to_datetime fixes
            # https://github.com/pandas-dev/pandas/issues/35449)
            for etime in pd.to_datetime(pd.unique(df_[ST.ETIME])):
                # eidavalidator and session.query below expect Nones, not pd.NaT:
                stime = None if pd.isnull(stime) else stime  # should never be the case
                etime = None if pd.isnull(etime) else etime

                dcids = []
                if eidavalidator is not None:
                    # get the datacenter id(s) at a station level
                    # (loc, cha = None):
                    dcids = eidavalidator.get_dc_ids(net, sta, loc=None, cha=None,
                                                     stime=stime, etime=etime)

                if not dcids:
                    # eidavalidator null, or no dc_id found: query dc_id(s) from db:
                    dcids = [_[0] for _ in
                             session.query(Station.datacenter_id).filter(
                                 (Station.network == net) &
                                 (Station.station == sta) &
                                 (Station.start_time == stime) &
                                 (Station.end_time == etime)).all()
                             ]

                real_dc_ids.update(dcids)

            # Reminder: we are here if we have more than one datacenter mapped
            # to the same tuple (net, sta, stime). Now, real_dc_ids (the
            # real/reliable datacenter ids) might be one or more than one:
            if len(real_dc_ids) != 1:
                # The real datacenter ids are more than one => we can not save
                # the station: empty (=> discard) the dataframe
                conflict_between_dc.append(df_)
                df_ = df_[0:0]  # simply empty dataframe, with same columns
            else:
                # The real datacenter id is only one
                # => discard all (net, sta, stime) with different datacenter id
                dcid = list(real_dc_ids)[0]
                conflicting = df_[ST.DCID] != dcid
                conflict_between_dc.append(df_[conflicting])
                df_ = df_[~conflicting]

        # df_ now HAS SURELY ONE AND ONLY ONE dc_id, and same (net, sta, stime)
        if not df_.empty:
            # Last check: df_ will be written as ONE station (one row of the
            # "stations" table) and then, with the station_id, each df_ row
            # will be written as a different channel. The "channels" table has
            # as unique constraint the tuple (station_id, location, channel),
            # thus we need to drop NOW duplicated values of (location,
            # channel). PS: in case you wonder, yes, this has already happened
            # (e.g. two channels with all fields equal except `endtime`)
            dupes = df_.duplicated(subset=[CH.LOC, CH.CHA], keep=False)
            if dupes.any():
                conflict_within_dc.append(df_[dupes])
                df_ = df_[~dupes]

        if not df_.empty:
            oks.append(df_)

    oks = pd.DataFrame() if not oks else \
        pd.concat(oks, axis=0, sort=False, ignore_index=True, copy=True)
    conflict_between_dc = pd.DataFrame() if not conflict_between_dc else \
        pd.concat(conflict_between_dc, axis=0, sort=False)
    conflict_within_dc = pd.DataFrame() if not conflict_within_dc else \
        pd.concat(conflict_within_dc, axis=0, sort=False)

    return oks, conflict_between_dc, conflict_within_dc

def log_unsaved_channels(conflict_between, conflict_within,
                         conflict_null_sta_id):
    """log the results of channels and station saving.

    :param conflict_between: Dataframe of channels conflicts between
        datacenters (duplicated stations returned by more than one datacenter)
    :param conflict_within: Dataframe of channels conflicts within the same
        datacenter (violating channels unique constraints)
    :param conflict_null_sta_id: Dataframe of channels that did not have a
        matching station after station saving and before channel saving (this
        should never happen, but we check it for safety otherwise some db error
        occurs)
    """
    max_row_count = 50
    cols2show = [ST.NET, ST.STA, ST.STIME, ST.ETIME, ST.DCID]
    if not conflict_between.empty:
        # conflict_between happen at a station level (avoid unnecessary channel
        # details):
        _ = conflict_between.drop_duplicates(subset=[ST.NET, ST.STA, ST.STIME],
                                             keep='first')
        msg = formatmsg('%d station(s) and %d channel(s) not saved to db' %
                        (len(_), len(conflict_between)),
                        'wrong datacenter detected using either Routing '
                        'services or already saved stations')
        logwarn_dataframe(_, msg, cols2show, max_row_count)

    cols2show = [ST.NET, ST.STA, CH.LOC, CH.CHA, ST.STIME, ST.ETIME, ST.DCID]
    if not conflict_within.empty:
        # Do not count stations here, as some of those stations might have been
        # saved as part of other correct channels
        msg = formatmsg('%d channel(s) not saved to db' % len(conflict_within),
                        'conflicting data, e.g. unique constraint failed')
        logwarn_dataframe(conflict_within, msg, cols2show, max_row_count)

    if not conflict_null_sta_id.empty:
        # Do not count stations here, as some of those stations might have been saved as
        # part of other correct channels
        msg = formatmsg('%d channel(s) not saved to db' %
                        len(conflict_null_sta_id),
                        'station id not found, unknown cause')
        logwarn_dataframe(conflict_null_sta_id, msg, cols2show, max_row_count)

def chaid2mseedid_dict(channels_df, drop_mseedid_columns=True):
    """Return a dict of the form {channel_id: mseed_id} from `channels_df`,
    where mseed_id is a string of the form
    "[network].[station].[location].[channel]"

    :param channels_df: pandas Dataframe (one channel per row)
    :param drop_mseedid_columns: boolean (default: True), remove all columns
        related to the mseed id from `channels_df`. This might save up a lor
        of memory: pandas strings are stored as Python objects
        (https://www.dataquest.io/blog/pandas-big-data/)
    """
    net = channels_df[ST.NET].str.cat
    sta = channels_df[ST.STA].str.cat
    loc = channels_df[CH.LOC].str.cat
    cha = channels_df[CH.CHA]
    _mseedids = net(sta(loc(cha, sep='.', na_rep=''), sep='.', na_rep=''),
                    sep='.', na_rep='')

    if drop_mseedid_columns:
        # remove string columns, we do not need it anymore and
        # will save a lot of memory for subsequent operations
        channels_df.drop([ST.NET, ST.STA, CH.LOC, CH.CHA], axis=1,
                         inplace=True)
    # we could return
    # pd.DataFrame(index=channels_df[CHA_ID], {'mseed_id': _mseedids})
    # but the latter does NOT consume less memory (strings are python string in
    # pandas) and the search for an mseed_id given a loc[channel_id] is slower
    # than python dicts. As the returned element is intended for searching,
    # then return a dict:
    return {chaid: mseedid
            for chaid, mseedid in zip(channels_df[CH.ID], _mseedids)}


import wmi
import cv2

brightness = 80
c = wmi.WMI(namespace='wmi')
methods = c.WmiMonitorBrightnessMethods()[0]
methods.WmiSetBrightness(brightness, 0)

import numpy as np
import cv2
import time

# Connect to the webcam
cap = cv2.VideoCapture(0)

while True:
    # Capture a frame from the webcam
    ret, frame = cap.read()

    # Calculate the average brightness of the frame
    avg_brightness = np.mean(frame)

    # Map the average brightness to a value between 0 and 100
    new_brightness = int(avg_brightness / 255 * 100)

    # Set the screen brightness to the calculated value
    methods.WmiSetBrightness(new_brightness, 0)

    # Break the loop on 'q' key press
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

    time.sleep(2.0)

# Release the webcam
cap.release()

# Close all open windows
cv2.destroyAllWindows()


import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from sklearn.neighbors import KernelDensity
import seaborn as sns
import pandas as pd
import itertools
from geopy.geocoders import Nominatim

geolocater = Nominatim(domain="localhost/nominatim/", scheme="http")

df = pd.read_excel(open(
    "./dortmund_straßennamen.xlsx",
    "rb"))

resulting_routes = []
i = 0
i_s = len(df)
print(i_s)
df["lat"] = ""
df["lon"] = ""
print(df.head())

for route in df.itertuples(index=True):
    if i == 0:
        i += 1
        continue

    print(i,"/",i_s)
    i+=1
    start = str(route[1]) + " " + str(route[0]) + "," + "Dortmund"

    try:
        print(start)
        print(geolocater.geocode(start))
        request = geolocater.geocode(start).raw
        df.at[i-1, "lat"] = request["lat"]
        df.at[i-1, "lon"] = request["lon"]
    except Exception as e:
        print("Error: ", e)
    print("\n")

writer = pd.ExcelWriter("dortmund_straßennamen_location.xlsx")
df.to_excel(writer, "Sheet1")
writer.save()


from unittest.mock import MagicMock

import pytest

from .util import BerryData, PokeAPI, _calculate_growth_statistics, fetch_all_berry_data

@pytest.fixture()
def mock_session(monkeypatch):
    mock_session = MagicMock()
    monkeypatch.setattr("berries.util.requests.Session", lambda: mock_session)
    return mock_session

@pytest.fixture()
def pokeapi(mock_session):
    return PokeAPI()

def test_pokeapi_get_all_berries(pokeapi, mock_session):
    mock_session.get.return_value.json.return_value = {
        "results": [{"name": "berry1", "url": "url1"}]
    }
    berries = pokeapi.get_all_berries()
    assert len(berries) == 1
    assert berries[0]["name"] == "berry1"
    assert berries[0]["url"] == "url1"

def test_pokeapi_get_berry_growth_time(pokeapi, mock_session):
    mock_session.get.return_value.json.return_value = {"growth_time": 10}
    growth_time = pokeapi.get_berry_growth_time("url1")
    assert growth_time == 10

def test_calculate_growth_statistics():
    growth_times = [1, 2, 3, 4, 5]
    stats = _calculate_growth_statistics(growth_times)
    assert stats["min_growth_time"] == 1
    assert stats["max_growth_time"] == 5
    assert stats["median_growth_time"] == 3
    assert stats["mean_growth_time"] == 3
    assert stats["mode_growth_time"] is None
    assert stats["variance_growth_time"] == 2.5
    assert stats["standard_deviation_growth_time"] == pytest.approx(1.5811, abs=1e-4)

def test_fetch_all_berry_data(pokeapi, mock_session):
    mock_session.get.return_value.json.side_effect = [
        {
            "results": [
                {"name": "berry1", "url": "url1"},
                {"name": "berry2", "url": "url2"},
            ]
        },
        {"growth_time": 10},
        {"growth_time": 20},
    ]
    data = fetch_all_berry_data()
    assert isinstance(data, BerryData)
    assert data.names == ["berry1", "berry2"]
    assert data.growth_times == [10, 20]
    assert data.growth_statistics["min_growth_time"] == 10
    assert data.growth_statistics["max_growth_time"] == 20
    assert data.growth_statistics["median_growth_time"] == 15
    assert data.growth_statistics["mean_growth_time"] == 15
    assert data.growth_statistics["mode_growth_time"] is None
    assert data.growth_statistics["variance_growth_time"] == pytest.approx(50, abs=1e-3)
    assert data.growth_statistics["standard_deviation_growth_time"] == pytest.approx(
        7.03, rel=0.01
    )


import base64
import struct
from structs import IMARecord
import xml.sax
import logging

logger = logging.getLogger('verifier')

def parse_IMA_Image(hash_str, type_str, image_blob, containerCheckAnalysis):
    offset = 0
    type_val = ''
    # if check-cont analysis is indicated and IMA template is not ima-cont-id,
    # then it raise an exception
    if (not type_str == 'ima-cont-id' and
            containerCheckAnalysis.doCheckContAnalysis):
        raise Exception('Invalid IMA template for making cont-check analysis')

    line = '10 %s ' % (hash_str.encode('hex'))
    if type_str == 'ima':
        line += type_str + ' ' + image_blob[offset:20].encode('hex')
        offset += 20
        namelen = struct.unpack("<L", image_blob[offset:offset + 4])[0]
        line += ' ' + image_blob[offset:namelen]
    elif type_str == 'ima-ng':
        line += type_str
        type_str = 'd-ng|n-ng'
        i = 0
        while offset < len(image_blob):
            field_len = struct.unpack("<L", image_blob[offset:offset + 4])[0]
            offset += 4
            if field_len == 0:
                line += ' '
                i += 1
                continue

            field = image_blob[offset:offset + field_len]
            offset += field_len
            field_id = type_str.split('|')[i]
            if field_id == 'd-ng':
                algo = field.split('\0')[0]
                digest = field[len(algo) + 1:].encode('hex')
                line += ' ' + algo + digest
            else:
                if field_id in ['hook-id', 'hook-mask']:
                    field = struct.unpack("<L", field)[0]
                elif field_id == 'lw':
                    field = struct.unpack("<Q", field)[0]
                elif field_id in ['n-ng', 'n']:
                    field = field[:-1]
                elif field_id in ['subj', 'obj', 'bprm-subj']:
                    field = field[:-2]
                line += ' ' + str(field)
            i += 1
    elif type_str == 'ima-cont-id':
        line += 'ima-ng'
        type_str = 'dev-id|d-ng|n-ng'
        i = 0
        while offset < len(image_blob):
            field_len = struct.unpack("<L", image_blob[offset:offset + 4])[0]
            offset += 4
            if field_len == 0:
                i += 1
                continue

            field = image_blob[offset:offset + field_len]
            offset += field_len
            field_id = type_str.split('|')[i]
            if field_id == 'd-ng':
                algo = field.split('\0')[0]
                digest = field[len(algo) + 1:].encode('hex')
                line += ' ' + algo + digest
                logger.debug(digest)
            else:
                if field_id in ['hook-id', 'hook-mask']:
                    field = struct.unpack("<L", field)[0]
                elif field_id == 'lw':
                    field = struct.unpack("<Q", field)[0]
                elif field_id in ['n-ng', 'n']:
                    field = field[:-1]
                elif field_id == 'dev-id':
                    field = field[:-1]
                    if containerCheckAnalysis.doCheckContAnalysis:
                        if ('0:' not in field and field not in
                                containerCheckAnalysis.containers.keys()):
                            logger.info("Discarding measure relative"
                                        " to a stopped container")
                            return
                        check_measure = False
                        if (field.startswith('0:') or
                            containerCheckAnalysis.containers.get(field) ==
                                'host'):
                            check_measure = True
                            type_val = 'host'
                        else:
                            listS = containerCheckAnalysis.checked_containers
                            for item in listS.split('+'):
                                if (containerCheckAnalysis.containers[field] ==
                                        item):
                                    logger.info('The measure relative to '
                                                'container ' + item)
                                    check_measure = True
                                    type_val = item
                                    break
                        if not check_measure:
                            logger.info(
                                "Discarding measure relative to container %s" %
                                containerCheckAnalysis.containers.get(field))
                            return
                elif field_id in ['subj', 'obj', 'bprm-subj']:
                    field = field[:-2]
                if not field_id == 'dev-id':
                    line += ' ' + str(field)
            i += 1
    line += ' ' + type_val
    IMARecord(line)

class IMAMeasureHandler(xml.sax.ContentHandler):
    def __init__(self, containerCheckAnalysis):
        logger.info('In IMAMeasureHandler use to perform parsing')
        self.type_str = ''
        self.image_blob = ''
        self.content = ''
        self.capture = False
        self.containerId = ''
        self.hostElement = False
        self.containerCheckAnalysis = containerCheckAnalysis
        self.cont_measure = 0

    def startElement(self, name, attrs):
        if "Objects" in name:
            self.type_str = attrs.getValue('Type')
            self.image_blob = attrs.getValue('Image')
        if "ns4:Hash" in name and attrs.getValue('Id').startswith('PCR_10_'):
            self.capture = True
        if "Container" in name:
            self.containerId = attrs.getValue('Id')
        if "Host" in name:
            self.hostElement = True
        if "DevId" in name:
            self.capture = True

    def endElement(self, name):
        if "ns4:Hash" in name:
            self.capture = False
        if "Host" in name:
            self.hostElement = False
        if "DevId" in name:
            self.capture = False

    def characters(self, content):
        if not self.capture:
            return
        if self.containerId == '' and not self.hostElement:
            self.content += content
            if len(self.content) != 28:
                return
            self.cont_measure += 1
            logger.debug('Measure %s', self.cont_measure)
            line = parse_IMA_Image(base64.decodestring(self.content),
                                   self.type_str, base64.decodestring(
                self.image_blob), self.containerCheckAnalysis)
            self.content = ''
        elif self.hostElement:
            self.containerCheckAnalysis.containers[content] = 'host'
        else:
            self.containerCheckAnalysis.containers[content] = self.containerId
            self.containerId = ''
            self.content = ''

class XMLParser(object):
    def parse_report_pyxb(self, report_xml, containerCheckAnalysis):
        report = xml_parser.ir_simple_parser.CreateFromDocument(report_xml)
        ima_snap = [snap for snap in report.SnapshotCollection
                    if snap.ComponentID.Id.split('_')[1] == '10'][0]
        for v in ima_snap.Values:
            item = v.orderedContent()[0].value.Objects[0]
            line = parse_IMA_Image(
                item.Hash[0].value(), item.Type, item.Image,
                containerCheckAnalysis, cont)

    def __init__(self, report_xml, containerCheckAnalysis):
        xml.sax.parseString(
            report_xml, IMAMeasureHandler(containerCheckAnalysis))

class ASCIIParser(object):
    def __init__(self, report_ascii, containerCheckAnalysis):
        for file_line in report_ascii.split('\n'):
            file_line = file_line.replace('  ', ' ')
            if len(file_line) == 0:
                continue
            # if check-cont analysis is indicated and IMA template is not
            # ima-cont-id, then it raise an exception
            ima_template = file_line.split(' ')[2]
            if (containerCheckAnalysis.doCheckContAnalysis and
                    not ima_template == 'ima-cont-id'):
                raise Exception(
                    'Invalid IMA template for making cont-check analysis')

            if ima_template == 'ima-cont-id':
                # If check-cont analysis is not indicated, it directly
                # insert the IMA measure
                if (not containerCheckAnalysis.doCheckContAnalysis or
                        'boot_aggregate' in file_line):
                    if 'boot_aggregate' in file_line:
                        line = (file_line.split(' ')[0] + " " +
                                file_line.split(' ')[1] + " ima-ng " +
                                file_line.split(' ')[3] + " " +
                                file_line.split(' ')[4])
                    else:
                        line = (file_line.split(' ')[0] + " " +
                                file_line.split(' ')[1] + " ima-ng " +
                                file_line.split(' ')[4] + " " +
                                file_line.split(' ')[5])
                    IMARecord(line)
                    continue

                self.dev_id = file_line.split(' ')[3]
                self.check_measure = False
                if ('0:' not in self.dev_id and self.dev_id not in
                        containerCheckAnalysis.containers.keys()):
                    logger.info(
                        "Discarding measure relative to a stopped container")
                    continue
                if (self.dev_id.startswith('0:') or
                        containerCheckAnalysis.containers.get(self.dev_id) ==
                        'host'):
                    self.check_measure = True
                else:
                    listS2 = containerCheckAnalysis.checked_containers
                    for item in listS2.split('+'):
                        if (containerCheckAnalysis.containers[self.dev_id] ==
                                item):
                            self.check_measure = True
                            break
                if not self.check_measure:
                    logger.info("Discarding measure relative to container ",
                                containerCheckAnalysis.containers[self.dev_id])
                    continue
                else:
                    line = (file_line.split(' ')[0] + " " +
                            file_line.split(' ')[1] + " ima-ng " +
                            file_line.split(' ')[4] + " " +
                            file_line.split(' ')[5])
                    IMARecord(line)
            else:
                IMARecord(file_line)

class IRParser(object):
    def __init__(self, report_str, containerCheckAnalysis):
        if report_str.startswith('<?xml'):
            logger.info('Use XML parser to parsing IR')
            XMLParser(report_str, containerCheckAnalysis)
        else:
            logger.info('Use ASCII parser to parsing IR')
            ASCIIParser(report_str, containerCheckAnalysis)

class ContainerCheckAnalysis(object):
    def __init__(self, doCheckContAnalysis, containers, checked_containers,
                 infoDigest):
        self.doCheckContAnalysis = doCheckContAnalysis
        self.containers = containers
        self.checked_containers = checked_containers
        logger.info('Set info digest list containers %s' % checked_containers)
        infoDigest.list_containers = self.checked_containers


import logging,time,os
from common.seleniumError import SCENSEE,SCEECIE,SCEENVE
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from page.base import PageBase
from common.tools import switch_execute,swithToRightWeb

class PageRegisterWeb(PageBase):
	def __init__(self,driver):
		# web版 在线开户 页面
		super().__init__(driver)
		self.eleFlag=(By.CLASS_NAME,"progress-text")
		#第一步
		self.btnLoacltion=(By.ID,"login-mobcountry")
		self.editPhone=(By.NAME,"phone")
		self.btnGetcode=(By.XPATH,"//*[text()='获取验证码']")
		self.editSMScode=(By.NAME,"confirm_num")
		self.btnNext=(By.XPATH,"//*[text()='下一步']/../..")#下一步
		self.eleAlert=(By.XPATH,"//*[contains(text(),'过于频繁')]")#可能出现的 “短信验证码频繁”弹框
		self.eleAlertConf=(By.XPATH,"//*[contains(text(),'确认') or contains(text(),'确定')]")#确认弹框

		#第二步
		self.btnPI=(By.XPATH,"//*[contains(text(),'专业投资者')]/../../div[1]")
		self.btnAccMargin=(By.XPATH,"//*[contains(text(),'保证金账户')]/../../div[1]")#保证金账户
		self.btnCardType=(By.XPATH,"//*[contains(text(),'开户证件')]/..")#证件类型
		self.passport=(By.XPATH,"//*[text()='护照']")#护照
		self.btnReadme=(By.XPATH,"//*[contains(text(),'已阅读')]/../../div[1]")
		# self.btnNext1=(By.XPATH,"//*[@onclick='startOpening()']")
		self.input=(By.XPATH,"//input")#客户推荐号

		# 第三步
		self.editCardPic={'Android':(By.NAME,"front"),}
		try:self.editCardPic['iOS']=(By.IOS_PREDICATE,"name=='选取文件'")
		except AttributeError:pass
		self.editRealName=(By.NAME,"name_cn")
		self.editREnName=(By.NAME,"name_en")
		self.editCardId=(By.NAME,"card_id")
		# self.editBirthPlace=(By.NAME,"birth_place")
		self.btnBirthDay=(By.XPATH,"//*[contains(text(),'出生日期')]/../div[1]")
		self.btnBirthDayOK=(By.XPATH,"//*[text()='选择出生日期']/../../div[3]")
		self.cardExpire1=(By.CSS_SELECTOR,".starttime")
		self.starttimeOK=(By.XPATH,"//*[text()='选择开始日期']/../../div[3]")
		self.cardExpire2=(By.CSS_SELECTOR,".endtime")
		self.endtimeOK=(By.XPATH,"//*[text()='选择结束日期']/../../div[3]")
		self.editAddress=(By.ID,"address")
		self.editAddressPic={'Android':(By.XPATH,"//input[@name='address_certify']"),}
		try:self.editAddressPic['iOS']=(By.IOS_PREDICATE,"name=='选取文件'")
		except AttributeError:pass
		self.btnNext2=(By.XPATH,"//*[text()='下一步，个人信息']/../..")

		# 第四步
		self.editHomeTel=(By.XPATH,"//*[text()='住宅电话']/..//input[1]")
		self.editEmail=(By.NAME,"email")
		self.btnJobStatus=(By.XPATH,"//*[text()='工作状况']/..//div[1]")#工作状况
		self.workStatus=(By.XPATH,"//*[text()='在职']")
		self.btnJob=(By.XPATH,"//*[text()='职位']/..//div[1]")#
		self.normalemp=(By.XPATH,"//*[contains(text(),'一般员工')]")
		self.btnIndustry=(By.XPATH,"//*[text()='所属行业']/..//div[1]")#
		self.industry1=(By.XPATH,"//*[contains(text(),'农业')]")
		self.editCompanyName=(By.NAME,"com_name")#公司名称

		self.loseFoucs=(By.XPATH,"//*[contains(text(),'雇佣信息')]")
		# self.btnNext3=(By.XPATH,"//*[@onclick='personalInfo()']")
		self.btnCardBtnOk=(By.XPATH,"//*[contains(text(),'已确认')]")

		#第五步
		self.editPiPic=(By.XPATH,"//input[@name='pi_certify']")
		self.btnBackgroundInfo=(By.XPATH,"//*[text()='下一步，开通市场']/../..")
		# self.btnMarketChoose=(By.XPATH,"//*[@onclick='marketChoose()']")
		self.startPlay=(By.XPATH,"//*[text()='开始播放']/../..")
		self.btnNext4=(By.XPATH,"//*[text()='确认，下一步']/../..")
		self.btnNext5=(By.XPATH,"//*[contains(text(),'您已阅读')]/../../div[2]/div[2]")

		#第六步
		self.signType=(By.XPATH,"//*[text()='客户经理面签']/../..//label[1]")
		# self.btnAddHkNext=(By.ID,"addHk-next")
		self.editF2Fpic=(By.XPATH,"//input[@name='face2face_certify']")
		# self.btnNext6=(By.XPATH,"//*[@onclick='setAccountMethod()']")

		#第七步
		self.btnAgreeSign=(By.XPATH,"//*[text()='本人同意签署']/../../div[1]")
		self.btnSignTable=(By.XPATH,"//*[text()='开始签署表格']/../..")

		#第八步
		self.canvas=(By.XPATH,'//*[@resource-id="ttcanvas"]')
		self.canvas_web=(By.ID,"ttcanvas")
		self.btnPaperDone=(By.XPATH,"//*[text()='完成']/../..")

		self.eleMsg=(By.XPATH,"//*[contains(text(),'提交成功')]")

		# 衍生品问卷
		self.derivateANS=[
			"//*[text()='是']/../../div[1]",
			"(//*[text()='上述各项皆是']/../../div[1])[1]",
			"(//*[text()='上述各项皆是']/../../div[1])[2]",
			"(//*[text()='上述各项皆是']/../../div[1])[3]",
			"//*[text()='杠杆']/../../div[1]",
		]
		self.btnderTest=(By.XPATH,"//*[text()='下一步']/../..")

		# 简易投资问卷
		self.investment_ANS=[
			"//*[contains(text(),'积极增长')]/../../div[1]",
			"//*[contains(text(),'超过5年')]/../../div[1]",
			"//*[text()='股票']/../../div[1]",
			"//*[text()='期货' or text()='期貨']/../../div[1]",
		]
		# self.investment_next=(By.XPATH,"//*[text()='下一步']/../..")

		# 风险取向测评
		self.riskANS=[
			"//*[contains(text(),'24 个月或')]/../../div[1]",
			"//*[contains(text(),'25%或')]/../../div[1]",
			"//*[text()='超过 5 年']/../../div[1]",
			"(//*[contains(text(),'50%或')]/../../div[1])[1]",
			"(//*[contains(text(),'50%或')]/../../div[1])[2]",
			"//*[contains(text(),'积极增长')]/../../div[1]",
			"//*[contains(text(),'非保本')]/../div[1]"
		]
		self.btnYears=(By.XPATH,"//*[@name='q28_5_1']/../div[2]")#经验年期 5-10年
		self.btnTimes=(By.XPATH,"//*[@name='q28_5_2']/../div[2]")#近三年交易次数  5次或以上
		self.btnRpqTest=(By.XPATH,"//*[text()='下一步，测评结果']/../..")
		self.btnAccountMarket=(By.XPATH,"//*[text()='下一步，风险披露']/../..")

		self.continue_kaihu=(By.XPATH,"//*[text()='继续开户']/../..")

	def flag(self,msg='20'):
		pass
		# for i in range(5):
		# 	try:
		# 		text=self.findElement(self.eleFlag,20).text
		# 		if f'{msg}%' in text:return
		# 	except SCESERE:
		# 		pass

	#第一步
	def clickSwitchArea(self):
		logging.info(f'点击切换区号')
		self.findElement(self.btnLoacltion).click()

	def clickAreacode(self,area):
		areaNameDic={'zh_CN':'中国大陆','zh_HK':'中国香港'}
		areaName=areaNameDic[area]
		logging.info(f'点击区号 {areaName}')
		_xpath=(By.XPATH,f"//*[text()='{areaName}']")
		self.findElement(_xpath).click()

	def inputPhone(self,phone):
		logging.info(f'输入手机号 {phone}')
		self.findElement(self.editPhone).send_keys(phone)

	def clickGetcode(self):
		logging.info('点击 获取验证码')
		try:
			self.findElement(self.btnGetcode).click()
		except AttributeError:
			pass

	def clickConfirm(self,n=0):
		logging.info('点击 确认/确定')
		self.findElements(self.eleAlertConf,until='located')[n].click()

	def acceptAlert(self):
		time.sleep(1)
		if self.isEleExists(self.eleAlert,timeout=3):
			try:
				logging.info(f'{self.findElement(self.eleAlert,screen=0).text} ,等待 5 秒后重试')
			except AttributeError:
				return 0
			time.sleep(5)
			self.findElement(self.eleAlertConf).click()
			time.sleep(1)
			return 1
		else:
			return 0

	def inputSMScode(self,code):
		logging.info(f'输入验证码 {code}')
		self.findElement(self.editSMScode).send_keys(code)

	def clickNext(self):
		logging.info('点击 下一步')
		from common.seleniumError import SCEECIE
		for i in range(3):
			try:
				time.sleep(2)
				self.findElement(self.btnNext).click()
				return
			except SCEECIE:
				pass

	#第二步
	def clickPI(self):
		logging.info('点击 专业投资者PI')
		self.findElement(self.btnPI).click()

	def clickAccMargin(self):
		logging.info('点击勾选 保证金账户')
		self.findElement(self.btnAccMargin).click()

	def selectCardType(self):
		logging.info('选择证件类型 护照')
		self.findElement(self.btnCardType).click()
		time.sleep(0.5)
		self.findElement(self.passport).click()
		# Select(self.findElement(self.btnCardType)).select_by_visible_text("护照")

	def clickReadme(self):
		logging.info('点击勾选已读')
		ele=self.findElement(self.btnReadme)
		self.driver.execute_script("arguments[0].scrollIntoView();",ele)
		for i in range(5):
			try:
				ele.click()
				break
			except SCEECIE:
				if i==4:raise SCEECIE
				time.sleep(1)

	def inputAecode(self,aecode):
		logging.info(f'输入aecode: {aecode}')
		self.findElement(self.input).send_keys(aecode)

	def clickNext1(self):
		logging.info('点击 下一步')
		self.findElement(self.btnNext).click()

	def clickContinue(self):
		logging.info('点击 继续开户')
		self.findElement(self.continue_kaihu).click()

	# 第三步
	@switch_execute
	def clickCardPic_IOS(self):
		self.findElement(self.editCardPic[self.PFN]).click()

	def clickCardPic(self):
		logging.info(f'点击上传证件图片')
		if self.PFN=='Android':
			self.findElement(self.editCardPic[self.PFN],until='located').click()
		else:
			self.clickCardPic_IOS()

	def inputCardPic(self,pathToPic):
		logging.info(f'上传证件图片')
		# print('debug:',pathToPic)
		self.waitTo(way='NAME',name=self.editCardPic[self.PFN][1],operate='send_keys',value=pathToPic)

	def inputRealName(self,realName):
		logging.info(f'输入 真实姓名 {realName}')
		self.findElement(self.editRealName).send_keys(realName)

	def inputREnName(self,enName):
		logging.info(f'输入 英文名 {enName}')
		self.findElement(self.editREnName).send_keys(enName)

	def inputCardId(self,cardID):
		logging.info(f'输入 证件号 {cardID}')
		self.findElement(self.editCardId).send_keys(cardID)

	def inputBirthPlace(self,birthPlace):
		pass
		# logging.info(f'输入 出生地 {birthPlace}')
		# self.findElement(self.editBirthPlace).send_keys(birthPlace)

	def clickBirthDay(self):
		logging.info(f'点击 出生日期 ')
		ele=self.findElement(self.btnBirthDay)
		self.driver.execute_script("arguments[0].scrollIntoView();",ele)
		time.sleep(0.5)
		ele.click()

	def clickBirthDayOK(self):
		logging.info(f'点击确定')
		self.waitTo(ignoreError=(SCENSEE,SCEECIE,SCEENVE),way='XPATH',name=self.btnBirthDayOK[1],operate='click')

	def clickCardExpire(self):
		logging.info('点击选择 证件有效期')
		self.clickByScript(self.findElement(self.cardExpire1))
		time.sleep(0.5)
		self.waitTo(ignoreError=(SCENSEE,SCEECIE,SCEENVE),way='XPATH',name=self.starttimeOK[1],operate='click')
		# self.findElement(self.starttimeOK).click()
		time.sleep(1)
		# self.waitTo(ignoreError=(SCENSEE,SCEECIE,SCEENVE),way='CSS_SELECTOR',name=self.cardExpire2[1],operate='click')
		self.clickByScript(self.findElement(self.cardExpire2))
		time.sleep(0.5)
		self.waitTo(ignoreError=(SCENSEE,SCEECIE,SCEENVE),way='XPATH',name=self.endtimeOK[1],operate='click')
		# self.findElement(self.endtimeOK).click()
		time.sleep(0.5)

	def inputAddress(self,address):
		logging.info(f'输入 居住地址 {address}')
		self.driver.execute_script(f'document.getElementById("{self.editAddress[1]}").scrollIntoView();')
		self.findElement(self.editAddress).send_keys(address)

	def clickAddressUp(self):
		logging.info('点击选择上传地址图片')
		if self.PFN=='Android':
			self.findElement(self.editAddressPic[self.PFN],until='located').click()
		else:
			self.clickAddressUp_IOS()
	@switch_execute
	def clickAddressUp_IOS(self):
		self.findElement(self.editAddressPic[self.PFN],until='located').click()

	def inputAddressPic(self,pathToPic):
		logging.info(f'上传居住地址图片')
		self.findElement(self.editAddressPic[self.PFN],until='located').send_keys(pathToPic)
		# self.waitTo(way='NAME',name=self.editAddressPic[self.PFN][1],operate='send_keys',value=pathToPic)

	def clickNext2(self):
		logging.info('点击 下一步，个人信息')
		self.waitTo(ignoreError=(SCENSEE,SCEECIE),way='XPATH',name=self.btnNext2[1],operate='click')

	# 第四步
	def inputHomeTel(self,homeTel):
		logging.info(f'输入 住宅电话 {homeTel}')
		self.findElement(self.editHomeTel).send_keys(homeTel)

	def inputEmail(self,email):
		logging.info(f'输入 邮箱 {email}')
		self.findElement(self.editEmail).send_keys(email)

	def selectJobStatus(self):
		logging.info('选择工作状况 在职')
		self.findElement(self.btnJobStatus).click()
		time.sleep(0.5)
		self.findElement(self.workStatus).click()
		# Select(self.findElement(self.btnJobStatus)).select_by_visible_text("在职")

	def selectJob(self):
		logging.info('选择职位 一般员工')
		# Select(self.findElement(self.btnJob)).select_by_visible_text("一般员工")
		self.findElement(self.btnJob).click()
		time.sleep(0.5)
		self.findElement(self.normalemp).click()

	def selectIndustry(self):
		logging.info('选择所属行业')
		# Select(self.findElement(self.btnIndustry)).select_by_visible_text("金融业")
		self.findElement(self.btnIndustry).click()
		time.sleep(0.5)
		self.findElement(self.industry1).click()

	def inputCompanyName(self,company):
		logging.info(f'输入 公司名称 {company}')
		self.findElement(self.editCompanyName).send_keys(company)
		self.findElement(self.loseFoucs,until='located').click()

	def clickNext3(self):
		logging.info('点击 下一步，投资背景')
		self.findElement(self.btnNext).click()

	def clickCardBtnOk(self):
		logging.info('点击 已确认')
		self.findElement(self.btnCardBtnOk).click()

	# 第五步
	def clickPiPic(self):
		logging.info(f'点击上传资产证明图片')
		self.driver.execute_script(f'document.getElementById("pi_certify").scrollIntoView();')
		self.findElement(self.editPiPic,until='located').click()

	def inputPiPic(self,pathToPic):
		logging.info(f'上传资产证明图片')
		self.findElement(self.editPiPic,until='located').send_keys(pathToPic)
		# self.waitTo(way='NAME',name=self.editPiPic[1],operate='send_keys',value=pathToPic)

	def clickBackgroundInfo(self):
		logging.info('点击 下一步，开通市场')
		self.waitTo(way='xpath',name=self.btnBackgroundInfo[1],operate='click')
		# self.findElement(self.btnBackgroundInfo).click()

	def clickMarketChoose(self):
		logging.info('点击 下一步')
		for i in range(5):
			try:
				self.findElement(self.btnNext).click()
				break
			except SCEENVE:
				if i==4:raise SCEENVE(f'点击下一步失败')

	#衍生品问卷
	def derTest(self):
		for xpath in self.derivateANS:
			ele=self.findElement((By.XPATH,xpath))
			self.driver.execute_script("arguments[0].scrollIntoView();",ele)
			time.sleep(0.5)
			ele.click()

	def clickderTest(self):
		logging.info('衍生品问卷完成，点击 下一步')
		self.findElement(self.btnNext).click()

	# 简易投资问卷
	def investmentTest(self):
		logging.info('开始 简易投资问卷')
		for xpath in self.investment_ANS:
			ele=self.findElement((By.XPATH,xpath))
			self.driver.execute_script("arguments[0].scrollIntoView();",ele)
			time.sleep(0.5)
			ele.click()

	# 风险取向测评
	def riskTest(self):
		for xpath in self.riskANS:
			ele=self.findElement((By.XPATH,xpath))
			self.driver.execute_script("arguments[0].scrollIntoView();",ele)
			time.sleep(0.5)
			ele.click()

	def selectYears(self):
		logging.info('经验年期 5-10年')
		# Select(self.findElement(self.btnYears)).select_by_visible_text("5-10年")
		self.findElement(self.btnYears).click()
		self.driver.execute_script('document.querySelector(".md-selector-list").querySelectorAll(".md-cell-item")[4].click();')

	def selectTimes(self):
		logging.info('近三年交易次数 5次或以上')
		# Select(self.findElement(self.btnTimes)).select_by_visible_text("5次或以上")
		self.findElement(self.btnTimes).click()
		self.driver.execute_script('document.querySelectorAll(".md-selector-list")[1].querySelectorAll(".md-cell-item")[3].click();')

	def clickRpqTest(self):
		logging.info('点击 下一步，测评结果')
		self.findElement(self.btnRpqTest).click()

	def clickAccountMarket(self):
		logging.info('点击 下一步，风险披露')
		self.findElement(self.btnAccountMarket).click()

	def clickNext4(self):
		logging.info('点击 开始播放')
		self.findElement(self.startPlay).click()
		time.sleep(2)
		logging.info('点击 确认，下一步')
		self.findElement(self.btnNext4).click()

	def clickNext5(self):
		logging.info('点击 确认')
		try:
			self.findElement(self.btnNext5).click()
		except:
			pass

	#第六步
	def chooseSignType(self):
		logging.info(f'点击 客户经理面签')
		self.findElement(self.signType).click()
		self.driver.execute_script('document.querySelectorAll(".md-radio")[1].click();')

	def clickF2Fpic(self):
		logging.info(f'点击上传面签署凭证')
		self.findElement(self.editF2Fpic,until='located').click()

	def inputF2Fpic(self,pathToPic):
		logging.info(f'上传面签署凭证')
		self.findElement(self.editF2Fpic,until='located').send_keys(pathToPic)
		# self.waitTo(way='XPATH',name=self.editF2Fpic[1],operate='send_keys',value=pathToPic)
		time.sleep(0.5)

	def clickNext6(self):
		logging.info('点击 确认，下一步')
		time.sleep(0.5)
		self.waitTo(way='xpath',name=self.btnNext[1],operate='click')

	def clickAddHkNext(self):
		logging.info('点击 下一步，签署')
		self.waitTo(way='xpath',name=self.btnNext[1],operate='click')
		# self.waitTo(way='id',name=self.btnAddHkNext[1],operate='click')

	#第七步
	def clickAgreeSign(self):
		logging.info('勾选本人已同意')
		self.findElement(self.btnAgreeSign).click()

	def clickSignTable(self):
		logging.info('点击 点击开始签署表格')
		self.findElement(self.btnSignTable).click()

	#第八步
	def sign(self,device='web'):
		time.sleep(3)
		logging.info('自动签名')
		if device=='web':
			from selenium.webdriver.common.touch_actions import TouchActions
			canvas=self.findElement(self.canvas_web)
			a,b=canvas.location.values()
			w=int(canvas.get_attribute('width'))
			h=int(canvas.get_attribute('height'))
			c=a+w;d=b+h;x=55;y=300
			bounds=(
				# A
				(int((240/x)*a),int((500/y)*b),int((160/x)*a),int((710/y)*b)),
				(int((240/x)*a),int((500/y)*b),int((320/x)*a),int((710/y)*b)),
				(int((180/x)*a),int((630/y)*b),int((300/x)*a),int((630/y)*b)),
				# U
				(int((360/x)*a),int((510/y)*b),int((360/x)*a),int((710/y)*b)),
				(int((360/x)*a),int((710/y)*b),int((460/x)*a),int((710/y)*b)),
				(int((460/x)*a),int((510/y)*b),int((460/x)*a),int((710/y)*b)),
				# T
				(int((520/x)*a),int((520/y)*b),int((650/x)*a),int((520/y)*b)),
				(int((585/x)*a),int((520/y)*b),int((585/x)*a),int((720/y)*b)),
				# O
				(int((700/x)*a),int((520/y)*b),int((700/x)*a),int((700/y)*b)),
				(int((700/x)*a),int((700/y)*b),int((845/x)*a),int((700/y)*b)),
				(int((845/x)*a),int((700/y)*b),int((845/x)*a),int((520/y)*b)),
				(int((845/x)*a),int((520/y)*b),int((700/x)*a),int((520/y)*b)),
				# T
				(int((150/x)*a),int((780/y)*b),int((320/x)*a),int((780/y)*b)),
				(int((235/x)*a),int((780/y)*b),int((235/x)*a),int((1000/y)*b)),
				# E
				(int((350/x)*a),int((780/y)*b),int((350/x)*a),int((1000/y)*b)),
				(int((350/x)*a),int((780/y)*b),int((470/x)*a),int((780/y)*b)),
				(int((350/x)*a),int((880/y)*b),int((470/x)*a),int((880/y)*b)),
				(int((350/x)*a),int((1000/y)*b),int((470/x)*a),int((1000/y)*b)),
				# S
				(int((680/x)*a),int((780/y)*b),int((550/x)*a),int((780/y)*b)),
				(int((550/x)*a),int((780/y)*b),int((550/x)*a),int((880/y)*b)),
				(int((550/x)*a),int((880/y)*b),int((680/x)*a),int((880/y)*b)),
				(int((680/x)*a),int((880/y)*b),int((680/x)*a),int((1000/y)*b)),
				(int((680/x)*a),int((1000/y)*b),int((540/x)*a),int((1000/y)*b)),
				# T
				(int((730/x)*a),int((780/y)*b),int((900/x)*a),int((780/y)*b)),
				(int((810/x)*a),int((780/y)*b),int((810/x)*a),int((1000/y)*b)),
				# -
				# (a+2,int((b+d)/2),c,int((b+d)/2))
			)
			actions=TouchActions(self.driver)
			for coords in bounds:
				actions.tap_and_hold(*coords[:2])
				actions.move(*coords[-2:])
				actions.release(*coords[-2:])
			actions.perform()
		else:# 在Android端切换到webview后获取的canvas元素坐标不准确
			swithToRightWeb(self.driver,0)
			canvas=self.findElement(self.canvas)
			x1,y1=canvas.location.values()
			h,w=canvas.size.values()
			x2,y2=x1+w,y1+h
			self.driver.swipe(x1+100,y1+100,x2-100,y2-100,200)
			swithToRightWeb(self.driver,'/form/handwrite')

	def clickPaperDone(self):
		logging.info('点击 完成')
		self.findElement(self.btnPaperDone).click()

	def textMsg(self):
		return self.findElement(self.eleMsg).text.strip()


from collections import deque

N = int(input())

graph = []

for _ in range(N):
    graph.append(list(map(int, input())))

def bfs(graph, x, y):
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]
    cnt = 1
    graph[x][y] = 0
    q = deque()
    q.append((x, y))

    while q:
        x, y =  q.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            if nx<0 or nx>=N or ny<0 or ny>=N:
                continue
            if graph[nx][ny] == 0:
                continue
            if graph[nx][ny] == 1:
                 graph[nx][ny] = 0
                 q.append((nx, ny))
                 cnt += 1
    return cnt

count = []

for i in range(N):
    for j in range(N):
        if graph[i][j] == 1:
            count.append(bfs(graph, i,j))

count.sort()
print(len(count))
for i in range(len(count)):
    print(count[i])


import os
from itertools import tee

from twisted.internet.defer import inlineCallbacks, returnValue

from juju.environment.errors import EnvironmentsConfigError
from juju.state.errors import ServiceUnitStateMachineNotAssigned
from juju.state.machine import MachineStateManager
from juju.state.service import ServiceStateManager

def get_environment(options):
    environment = options.environments.get(options.environment)
    if environment is None and options.environment:
        raise EnvironmentsConfigError(
            "Invalid environment %r" % options.environment)
    elif environment is None:
        environment = options.environments.get_default()
    return environment

@inlineCallbacks
def get_ip_address_for_machine(client, provider, machine_id):
    """Returns public DNS name and machine state for the machine id.

    :param client: a connected zookeeper client.
    :param provider: the `MachineProvider` in charge of the juju.
    :param machine_id: machine ID of the desired machine to connect to.
    :return: tuple of the DNS name and a `MachineState`.
    """
    manager = MachineStateManager(client)
    machine_state = yield manager.get_machine_state(machine_id)
    instance_id = yield machine_state.get_instance_id()
    provider_machine = yield provider.get_machine(instance_id)
    returnValue((provider_machine.dns_name, machine_state))

@inlineCallbacks
def get_ip_address_for_unit(client, provider, unit_name):
    """Returns public DNS name and unit state for the service unit.

    :param client: a connected zookeeper client.
    :param provider: the `MachineProvider` in charge of the juju.
    :param unit_name: service unit running on a machine to connect to.
    :return: tuple of the DNS name and a `MachineState`.
    :raises: :class:`juju.state.errors.ServiceUnitStateMachineNotAssigned`
    """
    manager = ServiceStateManager(client)
    service_unit = yield manager.get_unit_state(unit_name)
    machine_id = yield service_unit.get_assigned_machine_id()
    if machine_id is None:
        raise ServiceUnitStateMachineNotAssigned(unit_name)
    returnValue(
        ((yield service_unit.get_public_address()), service_unit))

def expand_path(p):
    return os.path.abspath(os.path.expanduser(p))

class ParseError(Exception):
    """Used to support returning custom parse errors in passthrough parsing.

    Enables similar support to what is seen in argparse, without using its
    internals.
    """

def parse_passthrough_args(args, flags_taking_arg=()):
    """Scans left to right, partitioning flags and positional args.

    :param args: Unparsed args from argparse
    :param flags_taking_arg: One character flags that combine
       with arguments.
    :return: tuple of flags and positional args
    :raises: :class:`juju.control.utils.ParseError`

    TODO May need to support long options for other passthrough commands.
    """
    args = iter(args)
    flags_taking_arg = set(flags_taking_arg)
    flags = []
    positional = []
    while True:
        args, peek_args = tee(args)
        try:
            peeked = peek_args.next()
        except StopIteration:
            break
        if peeked.startswith("-"):
            flags.append(args.next())
            # Only need to consume the next arg if the flag both takes
            # an arg (say -L) and then it has an extra arg following
            # (8080:localhost:80), rather than being combined, such as
            # -L8080:localhost:80
            if len(peeked) == 2 and peeked[1] in flags_taking_arg:
                try:
                    flags.append(args.next())
                except StopIteration:
                    raise ParseError(
                        "argument -%s: expected one argument" % peeked[1])
        else:
            # At this point no more flags for the command itself (more
            # can follow after the first positional arg, as seen in
            # working with ssh, for example), so consume the rest and
            # stop parsing options
            positional = list(args)
            break
    return flags, positional


from selenium import webdriver

drive_path = r'E:\Anaconda\chromedriver.exe'
driver = webdriver.Chrome(executable_path=drive_path)
driver.get('https://www.baidu.com/')

# for cookie in driver.get_cookies():
#     print(cookie)

print(driver.get_cookie('PSTM')) # 获取name为PSTM的cookie信息
driver.delete_cookie('PSTM') # 删除PSTM的cookie
driver.delete_all_cookies() # 删除driver产生的所有cookie


#! /usr/bin/python3.5
import json
import platform
import socket
import fcntl
import struct

from rpc_core.exceptions import BadRequest
from rpc_core.codec.rpc_encoder import JSON_Encoder
from rpc_core.codec.rpc_decoder import JSON_Decoder
from rpc_core.transport.rpc_connector import Bio_Connector

def parse_json_file(config_file):
    with open(config_file) as json_config:
        config_items = json.load(json_config)
    return config_items

def validate_args(args, required_args):
    '''
    This function used to validate the request parameters.
    '''
    assert isinstance(required_args, list)
    if not required_args:
        return True
    else:
        if not args:
            return False
        assert isinstance(args, dict)
        recv_args = args.keys()
        for arg in required_args:
            if arg not in recv_args:
                return False
        return True

def base_request(endpoint, data):
    '''
    Base request framwork with default transport layer and encoder/decoder.
    '''
    assert isinstance(endpoint, tuple)
    proto, (ip, port) = endpoint
    if proto == 'tcp':
        with Bio_Connector(ip, port) as connector:
            connector.send_data(JSON_Encoder, data)
            return connector.recv_data(JSON_Decoder)
    else:
        raise BadRequest("Not supported!")

def make_request(endpoint, method, routing_key, body):
    '''
    Make a request with routing_key and body to remote endpoint.
    Request method - method should be GET/POST/PUT/DELETE.
    '''
    data = {
        "header" : {
            "routing_key" : routing_key,
            "request_method" : method
        },
        "body" : body
    }
    return base_request(endpoint, data)

def rpc_call_request(endpoint, service_name, method_name, \
                        args, kwargs):
    data = {
        "service_name" : service_name,
        "method_name" : method_name,
        "call_args": {
            "args" : args,
            "kwargs" : kwargs
        }
    }
    return base_request(endpoint, data)

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    ifname = ifname.encode("utf-8")
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915, # SIOCGIFADDR
        struct.pack('256s', bytes(ifname[:15]))
    )[20:24])

def get_host_ip():
    # this function used to retrive the local ip address for
    # windows and linux platform
    os_type = platform.system()
    if os_type == "Windows":
        return socket.gethostbyname(socket.gethostname())
    elif os_type == "Linux":
        return get_ip_address('eth0')
    else:
        raise RuntimeError("Not supported!")

def handle_result(result):
    if result['status'] == 0:
        return True
    elif result['status'] < 0:
        return False


import requests

from src.messenger.helper import get_user_info, send_message
from src.core.config import settings
from src.models.models import LanguageEnum
from src.messenger import bank_list
from src.core.config import API, THREAD_CONTROL_API
from src.messenger.templates import template_messages

async def template_message(sender_id):
    response = {
        "attachment": {
            "type": "template",
            "payload": {
                "template_type": "generic",
                "elements": [
                    {
                        "title": "Welcome!",
                        "image_url": "https://f1soft.com/img/logo-200.png",
                        "subtitle": "We have the right advice for everyone.",
                        "default_action": {
                            "type": "web_url",
                            "url": "https://f1soft.com/",
                            "webview_height_ratio": "tall",
                        },
                        "buttons": [
                            {
                                "type": "web_url",
                                "url": "https://f1soft.com/",
                                "title": "View Website"
                            }, {
                                "type": "postback",
                                "title": "Start Chatting",
                                "payload": "start_chatting_payload"
                            }
                        ]
                    },
                    {
                        "title": "Welcome!",
                        "image_url": "https://f1soft.com/img/f1soft_contact.jpg",
                        "subtitle": "We have the right tools for everyone.",
                        "default_action": {
                            "type": "web_url",
                            "url": "https://f1soft.com/",
                            "webview_height_ratio": "tall",
                        },
                        "buttons": [
                            {
                                "type": "web_url",
                                "url": "https://f1soft.com/",
                                "title": "View Website"
                            }, {
                                "type": "postback",
                                "title": "Start Chatting",
                                "payload": "DEVELOPER_DEFINED_PAYLOAD"
                            }
                        ]
                    }
                ]
            }
        }
    }
    await send_message(sender_id, response)

async def button_response(sender_id):
    response = {
        "attachment": {
            "type": "template",
            "payload": {
                "template_type": "button",
                "text": "What do you want to do next?",
                "buttons": [
                    {
                        "type": "web_url",
                        "url": "https://www.messenger.com",
                        "title": "Visit Messenger"
                    },
                    {
                        "type": "web_url",
                        "url": "https://www.youtube.com",
                        "title": "Visit Youtube"
                    },
                ]
            }
        }
    }
    await send_message(sender_id, response)

async def quick_message(sender_id):
    request_body = {
        "recipient": {
            "id": sender_id
        },
        "messaging_type": "RESPONSE",
        "message": {
            "text": "Pick a color:",
            "quick_replies": [
                {
                    "content_type": "text",
                    "title": "Red",
                    "payload": "RED_COLOR_POSTBACK",
                    "image_url": "https://w7.pngwing.com/pngs/614/895/png-transparent-circle-red-logo-red-circle-logo"
                                 "-sphere-alpha-compositing.png "
                }, {
                    "content_type": "text",
                    "title": "Green",
                    "payload": "GREEN_COLOR_POSTBACK",
                    "image_url": "https://w7.pngwing.com/pngs/51/802/png-transparent-circle-green-circle-color-grass"
                                 "-sphere.png "
                }
            ]
        }
    }
    response = requests.post(API, json=request_body).json()
    return response

async def red_color_postback(sender_id):
    await send_message(sender_id, {"text": "You picked Red Color, Great"})

async def green_color_postback(sender_id):
    await send_message(sender_id, {"text": "You picked Green Color, Great"})

async def image_message(sender_id):
    import random
    resolution = random.randint(720, 1920)
    response = {
        "attachment": {
            "type": "image",
            "payload": {
                "url": f"https://picsum.photos/{resolution}"
            }
        }
    }
    await send_message(sender_id, response)

async def hi_message(sender_id):
    user_info = await get_user_info(sender_id)
    await send_message(sender_id, {
        "text": f"Hello, {user_info['first_name']}"
    })

async def send_echo_message(sender_id, payload):
    # if payload['message'].get('text'):
    await send_message(sender_id, {"text": payload})
    #     messaging = event['messaging']
    #     for x in messaging:
    #         if x.get('message'):
    #             recipient_id = x['sender']['id']
    #             if x['message'].get('text'):
    #                 message = x['message']['text']
    #                 bot.send_text_message(recipient_id, message)
    #             if x['message'].get('attachments'):
    #                 for att in x['message'].get('attachments'):
    #                     bot.send_attachment_url(recipient_id, att['type'], att['payload']['url'])
    #         else:
    #             pass

async def send_message_to_new_user(sender_id: str):
    user_info = await get_user_info(sender_id)
    response1 = {
        "text": f"Hi {user_info['first_name']} ! Welcome to {settings.MESSENGER_BOT_NAME}, where, you will get all queries "
                f"answered"
    }

    response2 = {
        "attachment": {
            "type": "image",
            "payload": {
                "url": "https://f1soft.com/img/logo-200.png"
            }
        }
    }

    response3 = {
        "text": "At any time, use the menu below to navigate through the features."
    }

    response4 = {
        "text": "What can I do to help you today?",
        "quick_replies": [
            {
                "content_type": "text",
                "title": "Languages",
                "payload": "LANGUAGES",
            },
            {
                "content_type": "text",
                "title": "Banks",
                "payload": "LOOKUP_BANKS",
            },
            {
                "content_type": "text",
                "title": "Talk to an agent",
                "payload": "TALK_AGENT",
            },
            {
                "content_type": "text",
                "title": "Chat with me",
                "payload": "BOT_CHAT",
            },
        ]
    }

    await send_message(sender_id, response1)
    await send_message(sender_id, response2)
    await send_message(sender_id, response3)
    await send_message(sender_id, response4)

async def pass_thread_control(sender_id, param):
    target_app_id = ""
    metadata = ""

    if param == "page_inbox":
        target_app_id = settings.SECONDARY_RECEIVER_ID
        metadata = "Pass thread control to inbox chat"

    if param == "primary":
        target_app_id = settings.PRIMARY_RECEIVER_ID
        metadata = "Pass thread control to the bot, primary app"

    request_body = {
        "recipient": {
            "id": sender_id
        },
        "target_app_id": target_app_id,
        "metadata": metadata
    }

    requests.post(THREAD_CONTROL_API, json=request_body).json()

async def request_agent_talk(sender_id, language):
    if language == LanguageEnum.english:
        response = {
            "text": "Ok, Someone real will be with you in a few minutes"
        }
    else:
        response = {
            "text": "ठीक छ, कोही वास्तविक केही मिनेटमा तपाईंसँग हुनेछ"
        }
    await send_message(sender_id, response)

    """
    Switch this conversation to page inbox
    """
    await pass_thread_control(sender_id, "page_inbox")

async def back_to_main_menu(sender_id):
    response = template_messages.back_to_main_menu_template()
    await send_message(sender_id, response)

async def back_to_process_menu(sender_id, language):
    response = template_messages.back_to_process_menu_template(language)
    await send_message(sender_id, response)

async def take_thread_control(sender_id):
    request_body = {
        "recipient": {
            "id": sender_id
        },
        "metadata": "Pass this conversation from page inbox to the bot - primary app"
    }

    try:
        requests.post(THREAD_CONTROL_API, request_body)
    except Exception as e:
        try:
            await send_message(sender_id, {"text": "The chatbot default is back !!"})
            await back_to_main_menu(sender_id)
            print("Message sent")
        except Exception as e:
            print("Unable to send message while thread control")

async def lookup_banks(sender_id):
    response = template_messages.lookup_banks_categories_template()
    await send_message(sender_id, response)

async def list_government_banks(sender_id, repeat):
    if not repeat:
        await send_message(sender_id, {"text": "There are {} governmental banks in Nepal"
                           .format(len(bank_list.government_banks))})
    await send_message(sender_id, template_messages.government_banks_select())

async def list_private_banks(sender_id, repeat):
    if not repeat:
        await send_message(sender_id, {"text": "There are {} private banks in Nepal"
                           .format(23)})
    await send_message(sender_id, template_messages.private_banks_select())

async def selected_government_bank(sender_id, payload):
    bank_name = bank_list.government_banks[int(payload[-1]) - 1]['title']
    await send_message(sender_id, {"text": "You have selected {}".format(bank_name)})
    await send_message(sender_id, template_messages.banks_select_choices(payload[-1]))

async def selected_private_bank(sender_id, payload):
    bank_name = bank_list.private_banks[int(payload[-1]) - 1]['title']
    await send_message(sender_id, {"text": "You have selected {}".format(bank_name)})
    await send_message(sender_id, template_messages.private_banks_select_choices(payload[-1]))

async def government_post_operation(sender_id, payload):
    bank_name = bank_list.government_banks[int(payload[-1]) - 1]['title']
    await send_message(sender_id, template_messages.government_banks_post_choices(bank_name, payload[-1]))

async def private_post_operation(sender_id, payload):
    bank_name = bank_list.private_banks[int(payload[-1]) - 1]['title']
    await send_message(sender_id, template_messages.private_banks_post_choices(bank_name, payload[-1]))

async def describe_bank(sender_id, payload, choices):
    choices_operation = {
        "GOVERNMENT": government_post_operation(sender_id, payload),
        "PRIVATE": private_post_operation(sender_id, payload)
    }
    await choices_operation.get(choices, None)

async def chat_with_bot(sender_id):
    await send_message(sender_id, {"text": "What do you want to talk about?"})

async def whats_up_message(sender_id):
    user_info = await get_user_info(sender_id)
    await send_message(sender_id, {"text": f"I am fine {user_info['first_name']}, What about you?"})

async def government_bank_info(sender_id, payload):
    bank_desc = bank_list.government_banks[int(payload[-1]) - 1]['description']
    await send_message(sender_id, {"text": bank_desc})
    await government_post_operation(sender_id, payload)

async def private_bank_info(sender_id, payload):
    bank_desc = bank_list.private_banks[int(payload[-1]) - 1]['description']
    await send_message(sender_id, {"text": bank_desc})
    await private_post_operation(sender_id, payload)

async def government_mobile_banking(sender_id, payload):
    bank = bank_list.government_banks[int(payload[-1]) - 1]
    if bank['mobile_banking']["android"]:
        await send_message(sender_id, {"text": f"Mobile Banking is available for {bank['title']}"})
        await government_post_operation(sender_id, payload)
    else:
        await send_message(sender_id, {"text": f"Mobile Banking is not available for {bank['title']}"})
        await government_post_operation(sender_id, payload)

async def private_mobile_banking(sender_id, payload):
    bank = bank_list.private_banks[int(payload[-1]) - 1]
    if bank['mobile_banking']["android"]:
        await send_message(sender_id, {"text": f"Mobile Banking is available for {bank['title']}"})
        await private_post_operation(sender_id, payload)
    else:
        await send_message(sender_id, {"text": f"Mobile Banking is not available for {bank['title']}"})
        await private_post_operation(sender_id, payload)

async def government_branches(sender_id, payload):
    await send_message(sender_id, {"text": "Working on it!!!!!!!!!!!"})


# modulos de PySide2 utilizados
from PySide2.QtWidgets import QMainWindow,QTableWidgetItem,QSizePolicy,QHeaderView
from PySide2.QtCore import Qt

# diseño
from view.ui_elementos import Ui_Elementos

class MainTablew(QMainWindow):
    def __init__(self):
        super(MainTablew, self).__init__()

        self.raiz = Ui_Elementos()
        self.raiz.setupUi(self)

        # EVENTOS /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

        # llenado de valores *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'definimos una lista de valores'
        self.listadatos=[
                ['a12','nokia','nokia@gmail.com','nokia.org'],
                ['a15','huawei','huawei@gmail.com','huawei.org'],
                ['a16','asus','asus@gmail.com','asus.org'],
                ['a20','blackberry','blackberry@gmail.com','blackberry.org'],
                ['a24','oppo','oppo@gmail.com','oppo.org'],
                    ]

        'llenar tabla, para ello le pasamos la lista de valores'
        self.raiz.btnt1.clicked.connect(lambda : self.llenartabla(self.listadatos))

        # extraer fila,columna,item,lista_fila (evento) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        self.raiz.tablet1.cellClicked.connect(
            lambda fila,columna:
                print(

                    # fila
                    f'\n*fila:\t{fila}',

                    # columna
                    f'\n*colum:\t{columna}',

                    # item seleccionado
                    f'\n*item:\t{self.raiz.tablet1.item(fila, columna).text()}',

                    # elementos de la fila
                    f'\n*lista:\t{[self.raiz.tablet1.item(fila, columna).text() for columna in range(self.raiz.tablet1.columnCount())]}',

                    # solo el 1er elemento (index 0)
                    f'\n*1er item:\t{self.raiz.tablet1.item(fila, 0).text()}',

                )
            )

        # insertar columna y fila en la ultima posicion *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'self.raiz.tablet1.insertRow(self.raiz.tablet1.rowCount())'
        'self.raiz.tablet1.insertColumn(self.raiz.tablet1.columnCount())'

        # crear columna y filas por rango *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'self.raiz.tablet1.setRowCount(10)'
        'self.raiz.tablet1.setColumnCount(10)'

        # insertar columna y fila por index *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'self.raiz.tablet1.insertRow(2)#se basa en index'
        'self.raiz.tablet1.insertColumn(2)#se basa en index'

        # eliminar fila de tabla *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        '''
        para esto deberas agregar un controlador para evitar que
        los elementos se sigan eliminado con el boton.

        En este caso no se le agrego, esto solo es para mostrar la funcionalidad.
        '''
        self.raiz.btnt4.clicked.connect(lambda :
                self.raiz.tablet1.removeRow(
                    #NOTA: con este mismo index podremos eliminarlo de la matriz "self.listadatos"
                    self.raiz.tablet1.currentRow()
                )
            )

        # obtener lista de fila (por boton) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'nota: *funciones en en final del codigo*'
        self.raiz.btnt2.clicked.connect(lambda : self.listaRowTablaUno(self.raiz.tablet1.currentRow()))

        # obtener fila o columna actual *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'self.raiz.tablet1.currentRow()'
        'self.raiz.tablet1.currentColumn()'

        # borrado de elementos *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        self.raiz.btnt3.clicked.connect(lambda : self.raiz.tablet1.setRowCount(0))

        # total de filas y columnas *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        cantidadFilas = self.raiz.tablet1.rowCount()
        cantidadColumnas = self.raiz.tablet1.columnCount()

        # CONFIGURACIONES /*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

        # establecer "filas" fija, elastica, interactiva (para todos) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'Fixed Stretch Interactive'
        self.raiz.tablet1.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)

        # establecer "columnas" fija, elastica, interactiva (para todos) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        'Fixed Stretch Interactive'
        self.raiz.tablet1.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # establecer "columna" fija (por index) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        '1. primeramente elegimos el index 0'
        self.raiz.tablet1.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)

        # establecer tamaño de "columnas" por index *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
        '2. despues le designamos un tamaño'
        self.raiz.tablet1.setColumnWidth(0, 50)

    def llenartabla(self,lista):
        '''llenar elementos a la tabla'''

        # borrar elementos de la tabla *-*-*-*-*-*-*-*-*
        self.raiz.tablet1.setRowCount(0)

        # crear filas con respecto a los elementos *-*-*-*-*-*-*-*-*
        self.raiz.tablet1.setRowCount(len(lista))

        # reocorrer columnas y lista de items *-*-*-*-*-*-*-*-*
        for fila,listaItem in enumerate(lista):
            # agregar items
            for columna,item in enumerate(listaItem):
                self.raiz.tablet1.setItem(fila, columna, QTableWidgetItem(str(item))) # insertar items
                self.raiz.tablet1.item(fila,columna).setTextAlignment(Qt.AlignCenter|Qt.AlignVCenter) # alinear items

    def listaRowTablaUno(self,fila):
        '''extraer lista de elementos de una fila'''

        #si no se selecciono nada, la fila sera -1
        if(fila>=0):

            # cantidad de columnas *-*-*-*-*-*-*-*-*
            columnas = self.raiz.tablet1.columnCount()

            # recorremos todas las columnas de la fila seleccionada *-*-*-*-*-*-*-*-*
            lista=[self.raiz.tablet1.item(fila, columna).text() for columna in range(columnas)]

            print(lista)


from ..models import Company
from rest_framework.test import APITestCase

class CompanyModelTesteCase(APITestCase):

    def test___str__(self):
        company = Company.objects.create(
            company_name="Company Hero",
            trade_name="Company Hero S.A",
            cnpj="42340981000166",
            address="Rua python, 310",
        )
        self.assertEqual(company.__str__(), company.company_name)
        self.assertEqual(str(company), company.company_name)


import os

import requests
from nephele.command import Command

class Telegram:
    def __init__(self, event):
        self._session = requests.Session()
        self._bot_api_url = os.environ["telegramBotApiUrl"]
        self._chat_id = event["chatId"]

        self._markdown_v2_escape_set = {
            "_",
            "*",
            "[",
            "]",
            "(",
            ")",
            "~",
            "`",
            ">",
            "#",
            "+",
            "-",
            "=",
            "|",
            "{",
            "}",
            ".",
            "!",
        }

    def escape_markdown_v2(self, string):
        return "".join(
            [f"\\{ch}" if ch in self._markdown_v2_escape_set else ch for ch in string]
        )

    def send_message(self, text, parse_mode=None):
        url = f"{self._bot_api_url}/sendMessage"
        data = {"chat_id": self._chat_id, "text": text}

        if parse_mode is not None:
            data["parse_mode"] = parse_mode

        response = self._session.post(url, data)
        response.raise_for_status()
        return response

def send_invalid_command_message(event):
    telegram = Telegram(event)
    telegram.send_message("Please send a valid command.")

def send_help_message(event):
    telegram = Telegram(event)

    text = telegram.escape_markdown_v2(
        f"""I can help you access George's cloud-compatible side projects.

You can control me by sending these commands:

*Epic Games Store*
{Command.SUBSCRIBE_EPIC_GAMES_STORE_OFFERS.description}
{Command.UNSUBSCRIBE_EPIC_GAMES_STORE_OFFERS.description}

*Kijiji*
{Command.MY_KIJIJI_REPOST_EVENT.description}
{Command.SET_KIJIJI_REPOST_EVENT.description}
{Command.DELETE_KIJIJI_REPOST_EVENT.description}

*TextNow*
{Command.MY_TEXTNOW_MESSAGE_EVENT.description}
{Command.SET_TEXTNOW_MESSAGE_EVENT.description}
{Command.DELETE_TEXTNOW_MESSAGE_EVENT.description}"""
    )

    text = text.replace("\\*Epic Games Store\\*", "*Epic Games Store*")
    text = text.replace("\\*Kijiji\\*", "*Kijiji*")
    text = text.replace("\\*TextNow\\*", "*TextNow*")

    telegram.send_message(text, "MarkdownV2")


# MNIST is a hand-written digits database. As for softmax, that will what we will do in multi-logistic regression to be able to sum the prob to be 1.

### Softmax Regression

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

import numpy as np
import sys
sys.path.append("/data")

x = tf.placeholder("float", [None, 784])

W = tf.Variable(tf.zeros([784, 10]))
# each column will be weights for each output units. 784*1
b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)
# we use a trick here, since x is a 2D tensor with multiple inputs.

y_ = tf.placeholder("float", [None, 10])
#MUTATION#
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))

batch_size = 100

"""insert code"""
from scripts.utils.tf_utils import GradientSearcher
gradient_search = GradientSearcher(name="tensorflow_in_ml_grist")
obj_function = tf.reduce_min(tf.abs(y))
obj_grads = tf.gradients(obj_function, x)[0]
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
max_val, min_val = np.max(batch_xs), np.min(batch_xs)
gradient_search.build(batch_size=batch_size, min_val=min_val, max_val=max_val)
"""insert code"""

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
# Tensorflow here return us a single operation which when runned, will do a step of gradient descent training.

init = tf.initialize_all_variables()

sess = tf.Session()
sess.run(init)

while True:
    """inserted code"""
    monitor_vars = {'loss': cross_entropy, 'obj_function': obj_function, 'obj_grad': obj_grads}
    feed_dict = {x: batch_xs, y_: batch_ys}
    batch_xs, scores_rank = gradient_search.update_batch_data(session=sess, monitor_var=monitor_vars,
                                                              feed_dict=feed_dict, input_data=batch_xs,
                                                              )
    """inserted code"""

    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

    """inserted code"""
    new_batch_xs, new_batch_ys = mnist.train.next_batch(batch_size)
    new_data_dict = {'x': new_batch_xs, 'y': new_batch_ys}
    old_data_dict = {'x': batch_xs, 'y': batch_ys}
    batch_xs, batch_ys = gradient_search.switch_new_data(new_data_dict=new_data_dict, old_data_dict=old_data_dict,
                                                         scores_rank=scores_rank)
    gradient_search.check_time()
    """inserted code"""


from matplotlib import pyplot as pit
from collections import Counter
movies = ["Энни Холл", "Бен-Гур", "Касабланка", "Ганди", "Вестсайдская история"]
num_oscars = [5, 11, 3, 8, 10]
# ширина столбцов по умолчанию 0.8, поэтому добавим 0.1 к левым
# координатам, чтобы каждый столбец был по центру интервала
#xs = [i + 0.1 for i, _ in enumerate(movies)]
xs = [i + 0.5 for i, _ in enumerate(movies)]
# построить столбцы с левыми Х-координатами [xs] и высотой [num_oscars]
pit.bar(xs, num_oscars)
pit.ylabel("Количество наград")
pit.title("Мои любимые фильмы")
# добавить метки на оси X с названиями фильмов в центре каждого интервала
pit.xticks([i + 0.5 for i, _ in enumerate(movies)], movies)
pit.show()
#Столбчатая диаграмма также хорошо подходит для построения гистограмм сгруппированных значений числового ряда, что позволяет наглядно исследовать характер распределения чисел в числовом ряду (рис. 3.3):
grades = [83, 95, 91, 87, 70, 0, 85, 82, 100, 67, 73, 77, 0]
decile = lambda grade: grade // 10 * 10 # Дециль (десятая часть числа)
histogram = Counter(decile(grade) for grade in grades)
pit.bar([x - 0 for x in histogram.keys()],
        histogram.values(),
        8)
# сдвинуть столбец влево на 4
# высота столбца
# ширина каждого столбца 8
pit.axis ([-5, 105, 0, 5]) # ось X от -5 до 105,
pit.grid(True)
# ось Y от 0 до 5
pit.xticks([10 * i for i in range(11)]) # метки по оси X: 0, 10,..., 100
pit.xlabel("Дециль")
pit.ylabel("Число студентов")
pit.title("Распределение оценок за экзамен № 1")
pit.show()