import os
import tempfile
from datetime import datetime
from typing import TYPE_CHECKING, List, Optional, Union
from urllib.parse import urlparse, urlunparse

from feast.config import Config
from feast.constants import ConfigOptions as opt
from feast.data_format import ParquetFormat
from feast.data_source import BigQuerySource, DataSource, FileSource, KafkaSource
from feast.feature_table import FeatureTable
from feast.pyspark.abc import (
    BatchIngestionJob,
    BatchIngestionJobParameters,
    JobLauncher,
    RetrievalJob,
    RetrievalJobParameters,
    SparkJob,
    StreamIngestionJob,
    StreamIngestionJobParameters,
)
from feast.staging.entities import create_bq_view_of_joined_features_and_entities
from feast.staging.storage_client import get_staging_client
from feast.value_type import ValueType

if TYPE_CHECKING:
    from feast.client import Client

def _standalone_launcher(config: Config) -> JobLauncher:
    from feast.pyspark.launchers import standalone

    return standalone.StandaloneClusterLauncher(
        config.get(opt.SPARK_STANDALONE_MASTER), config.get(opt.SPARK_HOME),
    )

def _dataproc_launcher(config: Config) -> JobLauncher:
    from feast.pyspark.launchers import gcloud

    return gcloud.DataprocClusterLauncher(
        cluster_name=config.get(opt.DATAPROC_CLUSTER_NAME),
        staging_location=config.get(opt.SPARK_STAGING_LOCATION),
        region=config.get(opt.DATAPROC_REGION),
        project_id=config.get(opt.DATAPROC_PROJECT),
        executor_instances=config.get(opt.DATAPROC_EXECUTOR_INSTANCES),
        executor_cores=config.get(opt.DATAPROC_EXECUTOR_CORES),
        executor_memory=config.get(opt.DATAPROC_EXECUTOR_MEMORY),
    )

def _emr_launcher(config: Config) -> JobLauncher:
    from feast.pyspark.launchers import aws

    def _get_optional(option):
        if config.exists(option):
            return config.get(option)

    return aws.EmrClusterLauncher(
        region=config.get(opt.EMR_REGION),
        existing_cluster_id=_get_optional(opt.EMR_CLUSTER_ID),
        new_cluster_template_path=_get_optional(opt.EMR_CLUSTER_TEMPLATE_PATH),
        staging_location=config.get(opt.SPARK_STAGING_LOCATION),
        emr_log_location=config.get(opt.EMR_LOG_LOCATION),
    )

def _k8s_launcher(config: Config) -> JobLauncher:
    from feast.pyspark.launchers import k8s

    staging_location = config.get(opt.SPARK_STAGING_LOCATION)
    staging_uri = urlparse(staging_location)

    return k8s.KubernetesJobLauncher(
        namespace=config.get(opt.SPARK_K8S_NAMESPACE),
        resource_template_path=config.get(opt.SPARK_K8S_JOB_TEMPLATE_PATH, None),
        staging_location=staging_location,
        incluster=config.getboolean(opt.SPARK_K8S_USE_INCLUSTER_CONFIG),
        staging_client=get_staging_client(staging_uri.scheme, config),
        # azure-related arguments are None if not using Azure blob storage
        azure_account_name=config.get(opt.AZURE_BLOB_ACCOUNT_NAME, None),
        azure_account_key=config.get(opt.AZURE_BLOB_ACCOUNT_ACCESS_KEY, None),
    )

_launchers = {
    "standalone": _standalone_launcher,
    "dataproc": _dataproc_launcher,
    "emr": _emr_launcher,
    "k8s": _k8s_launcher,
}

def resolve_launcher(config: Config) -> JobLauncher:
    return _launchers[config.get(opt.SPARK_LAUNCHER)](config)

def _source_to_argument(source: DataSource, config: Config):
    common_properties = {
        "field_mapping": dict(source.field_mapping),
        "event_timestamp_column": source.event_timestamp_column,
        "created_timestamp_column": source.created_timestamp_column,
        "date_partition_column": source.date_partition_column,
    }

    properties = {**common_properties}

    if isinstance(source, FileSource):
        properties["path"] = source.file_options.file_url
        properties["format"] = dict(
            json_class=source.file_options.file_format.__class__.__name__
        )
        return {"file": properties}

    if isinstance(source, BigQuerySource):
        project, dataset_and_table = source.bigquery_options.table_ref.split(":")
        dataset, table = dataset_and_table.split(".")
        properties["project"] = project
        properties["dataset"] = dataset
        properties["table"] = table
        if config.exists(opt.SPARK_BQ_MATERIALIZATION_PROJECT) and config.exists(
            opt.SPARK_BQ_MATERIALIZATION_DATASET
        ):
            properties["materialization"] = dict(
                project=config.get(opt.SPARK_BQ_MATERIALIZATION_PROJECT),
                dataset=config.get(opt.SPARK_BQ_MATERIALIZATION_DATASET),
            )

        return {"bq": properties}

    if isinstance(source, KafkaSource):
        properties["bootstrap_servers"] = source.kafka_options.bootstrap_servers
        properties["topic"] = source.kafka_options.topic
        properties["format"] = {
            **source.kafka_options.message_format.__dict__,
            "json_class": source.kafka_options.message_format.__class__.__name__,
        }
        return {"kafka": properties}

    raise NotImplementedError(f"Unsupported Datasource: {type(source)}")

def _feature_table_to_argument(
    client: "Client", project: str, feature_table: FeatureTable
):
    return {
        "features": [
            {"name": f.name, "type": ValueType(f.dtype).name}
            for f in feature_table.features
        ],
        "project": project,
        "name": feature_table.name,
        "entities": [
            {"name": n, "type": client.get_entity(n, project=project).value_type}
            for n in feature_table.entities
        ],
        "max_age": feature_table.max_age.ToSeconds() if feature_table.max_age else None,
        "labels": dict(feature_table.labels),
    }

def start_historical_feature_retrieval_spark_session(
    client: "Client",
    project: str,
    entity_source: Union[FileSource, BigQuerySource],
    feature_tables: List[FeatureTable],
):
    from pyspark.sql import SparkSession

    from feast.pyspark.historical_feature_retrieval_job import (
        retrieve_historical_features,
    )

    spark_session = SparkSession.builder.getOrCreate()
    return retrieve_historical_features(
        spark=spark_session,
        entity_source_conf=_source_to_argument(entity_source, client._config),
        feature_tables_sources_conf=[
            _source_to_argument(feature_table.batch_source, client._config)
            for feature_table in feature_tables
        ],
        feature_tables_conf=[
            _feature_table_to_argument(client, project, feature_table)
            for feature_table in feature_tables
        ],
    )

def start_historical_feature_retrieval_job(
    client: "Client",
    project: str,
    entity_source: Union[FileSource, BigQuerySource],
    feature_tables: List[FeatureTable],
    output_format: str,
    output_path: str,
) -> RetrievalJob:
    launcher = resolve_launcher(client._config)
    feature_sources = [
        _source_to_argument(
            replace_bq_table_with_joined_view(feature_table, entity_source),
            client._config,
        )
        for feature_table in feature_tables
    ]

    extra_packages = []
    if output_format == "tfrecord":
        extra_packages.append("com.linkedin.sparktfrecord:spark-tfrecord_2.12:0.3.0")

    return launcher.historical_feature_retrieval(
        RetrievalJobParameters(
            entity_source=_source_to_argument(entity_source, client._config),
            feature_tables_sources=feature_sources,
            feature_tables=[
                _feature_table_to_argument(client, project, feature_table)
                for feature_table in feature_tables
            ],
            destination={"format": output_format, "path": output_path},
            extra_packages=extra_packages,
        )
    )

def replace_bq_table_with_joined_view(
    feature_table: FeatureTable, entity_source: Union[FileSource, BigQuerySource],
) -> Union[FileSource, BigQuerySource]:
    """
    Applies optimization to historical retrieval. Instead of pulling all data from Batch Source,
    with this optimization we join feature values & entities on Data Warehouse side (improving data locality).
    Several conditions should be met to enable this optimization:
    * entities are staged to BigQuery
    * feature values are in in BigQuery
    * Entity columns are not mapped (ToDo: fix this limitation)
    :return: replacement for feature source
    """
    if not isinstance(feature_table.batch_source, BigQuerySource):
        return feature_table.batch_source

    if not isinstance(entity_source, BigQuerySource):
        return feature_table.batch_source

    if any(
        entity in feature_table.batch_source.field_mapping
        for entity in feature_table.entities
    ):
        return feature_table.batch_source

    return create_bq_view_of_joined_features_and_entities(
        feature_table.batch_source, entity_source, feature_table.entities,
    )

def start_offline_to_online_ingestion(
    client: "Client",
    project: str,
    feature_table: FeatureTable,
    start: datetime,
    end: datetime,
) -> BatchIngestionJob:

    launcher = resolve_launcher(client._config)

    return launcher.offline_to_online_ingestion(
        BatchIngestionJobParameters(
            jar=client._config.get(opt.SPARK_INGESTION_JAR),
            source=_source_to_argument(feature_table.batch_source, client._config),
            feature_table=_feature_table_to_argument(client, project, feature_table),
            start=start,
            end=end,
            redis_host=client._config.get(opt.REDIS_HOST),
            redis_port=client._config.getint(opt.REDIS_PORT),
            redis_ssl=client._config.getboolean(opt.REDIS_SSL),
            statsd_host=(
                client._config.getboolean(opt.STATSD_ENABLED)
                and client._config.get(opt.STATSD_HOST)
            ),
            statsd_port=(
                client._config.getboolean(opt.STATSD_ENABLED)
                and client._config.getint(opt.STATSD_PORT)
            ),
            deadletter_path=client._config.get(opt.DEADLETTER_PATH),
            stencil_url=client._config.get(opt.STENCIL_URL),
        )
    )

def get_stream_to_online_ingestion_params(
    client: "Client", project: str, feature_table: FeatureTable, extra_jars: List[str]
) -> StreamIngestionJobParameters:
    return StreamIngestionJobParameters(
        jar=client._config.get(opt.SPARK_INGESTION_JAR),
        extra_jars=extra_jars,
        source=_source_to_argument(feature_table.stream_source, client._config),
        feature_table=_feature_table_to_argument(client, project, feature_table),
        redis_host=client._config.get(opt.REDIS_HOST),
        redis_port=client._config.getint(opt.REDIS_PORT),
        redis_ssl=client._config.getboolean(opt.REDIS_SSL),
        statsd_host=client._config.getboolean(opt.STATSD_ENABLED)
        and client._config.get(opt.STATSD_HOST),
        statsd_port=client._config.getboolean(opt.STATSD_ENABLED)
        and client._config.getint(opt.STATSD_PORT),
        deadletter_path=client._config.get(opt.DEADLETTER_PATH),
        stencil_url=client._config.get(opt.STENCIL_URL),
        drop_invalid_rows=client._config.get(opt.INGESTION_DROP_INVALID_ROWS),
    )

def start_stream_to_online_ingestion(
    client: "Client", project: str, feature_table: FeatureTable, extra_jars: List[str]
) -> StreamIngestionJob:

    launcher = resolve_launcher(client._config)

    return launcher.start_stream_to_online_ingestion(
        get_stream_to_online_ingestion_params(
            client, project, feature_table, extra_jars
        )
    )

def list_jobs(
    include_terminated: bool, client: "Client", table_name: Optional[str] = None
) -> List[SparkJob]:
    launcher = resolve_launcher(client._config)
    return launcher.list_jobs(
        include_terminated=include_terminated, table_name=table_name
    )

def get_job_by_id(job_id: str, client: "Client") -> SparkJob:
    launcher = resolve_launcher(client._config)
    return launcher.get_job_by_id(job_id)

def stage_dataframe(df, event_timestamp_column: str, config: Config) -> FileSource:
    """
    Helper function to upload a pandas dataframe in parquet format to a temporary location (under
    SPARK_STAGING_LOCATION) and return it wrapped in a FileSource.

    Args:
        event_timestamp_column(str): the name of the timestamp column in the dataframe.
        config(Config): feast config.
    """
    staging_location = config.get(opt.SPARK_STAGING_LOCATION)
    staging_uri = urlparse(staging_location)

    with tempfile.NamedTemporaryFile() as f:
        df.to_parquet(f)

        file_url = urlunparse(
            get_staging_client(staging_uri.scheme, config).upload_fileobj(
                f,
                f.name,
                remote_path_prefix=os.path.join(staging_location, "dataframes"),
                remote_path_suffix=".parquet",
            )
        )

    return FileSource(
        event_timestamp_column=event_timestamp_column,
        file_format=ParquetFormat(),
        file_url=file_url,
    )


import math
_f_ = 0
# (whatever the highest story is that the egg will not break being dropped from. Whole numbers only!)
_n_ = 197
# (total stories of building starting with ground floor=1 (American standard) Whole numbers only!)

def throwing_egg(x):

    if x > _f_:
        return False
    if x <= _f_:
        return True

def making_an_omelette(top_floor, base_floor=0):
    if top_floor < 0:
        print("What, are you underground?")
        return
    if top_floor < base_floor:
        print(
            "Are you in 'The Upside-Down'? I'll string some Christmas lights to communicate.")
        return
    if throwing_egg(top_floor):
        print("This egg will survive anything. The highest floor that can be thrown from is %s" % top_floor)
        return top_floor
    floor_being_tested = top_floor - math.ceil((top_floor - base_floor)/2)
    if floor_being_tested == base_floor:
        found_f_ = floor_being_tested
        if floor_being_tested == 0:
            print(
                "This egg can survive nothing. It survives no drops and must remain at level 0.")
            return floor_being_tested
        print("The highest floor that can be thrown from is %s" % found_f_)
        return floor_being_tested
    if throwing_egg(floor_being_tested):
        making_an_omelette(top_floor, floor_being_tested)
    else:
        making_an_omelette(floor_being_tested, base_floor)

making_an_omelette(_n_)


from . import IntervalModule
from .core.util import round_dict
import psutil

class NetworkTraffic(IntervalModule):
    """
    Network traffic per interface, i.e., packets/bytes sent/received per second.

    Requires the PyPI packages `psutil`.

    Available formatters:

    * `{interface}` — the configured network interface
    * `{bytes_sent}` — bytes sent per second (divided by divisor)
    * `{bytes_recv}` — bytes received per second (divided by divisor)
    * `{packets_sent}` — bytes sent per second (divided by divisor)
    * `{packets_recv}` — bytes received per second (divided by divisor)
    """

    interval = 1
    settings = (
        ("format", "format string"),
        ("interface", "network interface"),
        ("divisor", "divide all byte values by this value"),
        ("round_size", "defines number of digits in round"),
    )

    format = "{interface} \u2197{bytes_sent}kB/s \u2198{bytes_recv}kB/s"
    interface = "eth0"
    divisor = 1024
    round_size = None

    pnic = None
    def run(self):
        pnic_before = self.pnic
        self.pnic = psutil.net_io_counters(pernic=True)[self.interface]
        if not pnic_before: return
        cdict = {
            "bytes_sent": (self.pnic.bytes_sent - pnic_before.bytes_sent) / self.divisor,
            "bytes_recv": (self.pnic.bytes_recv - pnic_before.bytes_recv) / self.divisor,
            "packets_sent": self.pnic.packets_sent - pnic_before.packets_sent,
            "packets_recv": self.pnic.packets_recv - pnic_before.packets_recv,
        }
        round_dict(cdict, self.round_size)
        cdict["interface"] = self.interface
        self.output = {
            "full_text": self.format.format(**cdict),
            "instance": self.interface,
        }


import numpy as np
from sklearn.preprocessing import StandardScaler
import maxent as maxent
import gridworld as gridworld
import plot as plot
import deep_maxent as deep_maxent

def main(method):
    if(method=="linear"):
        print("lenear method")
        recovered_reward = maxent.irl(feature_matrix, gw.n_actions, discount,
            gw.transition_probability, trajectories, epochs, learning_rate)
    elif(method=="deep"):
        print("deep method")
        l1 = l2 = 0
        recovered_reward = deep_maxent.irl((feature_matrix.shape[1],) + structure, feature_matrix,
            gw.n_actions, discount, gw.transition_probability, trajectories, epochs,
            learning_rate, l1=l1, l2=l2)
    scaler = StandardScaler()
    standardised_reward=scaler.fit_transform(recovered_reward.reshape(-1,1))

    plot.plot(ground_r,standardised_reward, grid_size)

grid_size=5
discount=0.01
n_trajectories=25
epochs=700
learning_rate=0.01
wind=0.3
trajectory_length = 3*grid_size
gw = gridworld.Gridworld(grid_size, wind, discount)
ground_r = np.array([gw.reward(s) for s in range(gw.n_states)])

feature_matrix = gw.feature_matrix()
#feature_matrix = gw.feature_matrix_goalVsOther()
#feature_matrix = gw.feature_matrix_goalVsOtherTwo()
#feature_matrix = gw.feature_matrix_goalVsOtherThree()
feature_space=feature_matrix.shape[1]

#trajectories = gw.my_generate_trajectories(n_trajectories,trajectory_length,gw.optimal_policy)
trajectories = gw.my_generate_trajectories_some_without_goal(n_trajectories,trajectory_length,gw.optimal_policy)

n_states, d_states = feature_matrix.shape
no_of_iterations=20
structure=(3, 3)

if __name__ == '__main__':
    #main(method="linear")
    main(method="deep")


#
# @lc app=leetcode id=529 lang=python3
#
# [529] Minesweeper
#
from typing import List
# @lc code=start
class Solution:
    def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]:
        if(len(board) == 0 or len(board[0]) == 0):
            return
        row = click[0]
        col = click[1]
        num = 0
        rec = []
        if(board[row][col] == 'M'):
            board[row][col] = 'X'
        else:
            for i in range(-1, 2):
                for j in range(-1, 2):
                    x = row + i
                    y = col + j
                    if(x < 0 or x >= len(board) or y < 0 or y >= len(board[0])):
                        continue
                    if(board[x][y] == 'M'):
                        num += 1
                    elif(num == 0 and board[x][y] == 'E'):
                        rec.append([x,y])
            if(num > 0):
                board[row][col] = str(num)
            else:
                for i in rec:
                    board[i[0]][i[1]] = 'B'
                    self.updateBoard(board, i)
        return board
# @lc code=end
print(Solution().updateBoard([["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]], [1,2]))


#!/usr/bin/env python

import tensorflow as tf
import numpy as np

from TensorflowUtil import weight_variable, bias_variable, conv2d, conv_layer
from TensorflowUtil import conv_layer_, fc_layer, fc_layer_, identity_in, flattened
from TensorflowUtil import normal_log, negative_log_likelihood, max_pool_2x2

# 640 x 480
class cnn_cccccfffff(object):

    def __init__(self):
        self.x = tf.placeholder(tf.float32, [None, 115, 200, 3])
        self.y_ = tf.placeholder(tf.float32, [None, 1])
        (self.h_conv1, _) = conv_layer(self.x, conv=(5, 5), stride=2, n_filters=24, use_bias=True)
        (self.h_conv2, _) = conv_layer(self.h_conv1, conv=(5, 5), stride=2, n_filters=36, use_bias=True)
        (self.h_conv3, _) = conv_layer(self.h_conv2, conv=(5, 5), stride=2, n_filters=48, use_bias=True)
        (self.h_conv4, _) = conv_layer(self.h_conv3, conv=(3, 3), stride=1, n_filters=64, use_bias=True)
        (self.h_conv5, _) = conv_layer(self.h_conv4, conv=(3, 3), stride=1, n_filters=64, use_bias=True)
        self.h_conv5_flat = flattened(self.h_conv5)
        (self.h_fc1_drop, _, _, self.keep_prob_fc1) = fc_layer(x=self.h_conv5_flat, n_neurons=512, activation=tf.nn.relu, use_bias=True, dropout=True)
        (self.h_fc2_drop, _, _, self.keep_prob_fc2) = fc_layer(self.h_fc1_drop, 100, tf.nn.relu, True, True)
        (self.h_fc3_drop, _, _, self.keep_prob_fc3) = fc_layer(self.h_fc2_drop, 50, tf.nn.relu, True, True)
        (self.h_fc4_drop, _, _, self.keep_prob_fc4) = fc_layer(self.h_fc3_drop, 10, tf.nn.relu, True, True)
        W_fc5 = weight_variable([10, 1])
        b_fc5 = bias_variable([1])
        self.y_out = tf.matmul(self.h_fc4_drop, W_fc5) + b_fc5
        self.loss = tf.reduce_mean(tf.abs(tf.subtract(self.y_, self.y_out)))


"""Support for showing device locations."""
DOMAIN = "ais_help"

async def async_setup(hass, config):
    """Register the built-in help panel."""
    hass.components.frontend.async_register_built_in_panel(
        "aishelp", "Przydatne linki", "mdi:qrcode"
    )
    """Register the built-in doc panel."""
    hass.components.frontend.async_register_built_in_panel(
        "aisdocs", "Dokumentacja", "mdi:book-open"
    )
    """Register the built-in galery panel."""
    hass.components.frontend.async_register_built_in_panel(
        "aisgalery", "Galeria", "mdi:image-search"
    )
    return True


import csv, os, shutil

from jisc1_locations import SHARES, JISC1_LOCATIONS

N_FOLDERS = {}

STORE = "."
MISSINGPAGE_TOLERANCE = 3

def page_to_file_guess(n, y, m, d, page, prefix="WO1"):
  base = "_".join([prefix, n, y, m, d])
  return base + "-%04d" % page

def page_to_xml_guess(n,y,m,d,page, prefix="WO1"):
  return page_to_file_guess(n,y,m,d,page,prefix) + ".xml"

def get_newspaper_root(newspaper):
  l = os.path.join(STORE, newspaper)
  if newspaper in N_FOLDERS:
    return l
  if not os.path.isdir(l):
    os.mkdir(l)
  N_FOLDERS[newspaper] = []
  return l

def get_store(newspaper, year):
  n_root = get_newspaper_root(newspaper)
  l = os.path.join(n_root, year)
  if year in N_FOLDERS[newspaper]:
    return l
  if not os.path.isdir(l):
    os.mkdir(l)
  N_FOLDERS[newspaper].append(year)
  return l

if __name__ == "__main__":
  for share in SHARES:
    setheaders = os.path.isfile(share+".log")
    logf = open(share+".log", "a+")
    logfc = csv.writer(logf)
    if setheaders:
      logfc.writerow(["newspaper", "year", "month", "day", "pages"])
    with open(share+".csv", "r") as csvfile:
      doc = csv.reader(csvfile)
      for row in doc:
        i = 1
        missed = 0
        page_root, newspaper, year, month, day = row
        cpyto = get_store(newspaper, year)
        while(missed<MISSINGPAGE_TOLERANCE):
          xmlpage = page_to_xml_guess(newspaper, year, month, day, i, "WO2")
          location = os.path.join(page_root, xmlpage)
          if not os.path.isfile(os.path.join(cpyto, xmlpage)):
            if os.path.isfile(location):
              missed = 0
              print("Copying to NAS - {0}".format(xmlpage))
              shutil.copy(location, os.path.join(cpyto, xmlpage))
            else:
              missed +=1
          else:
            print("Already got - {0}".format(xmlpage))
          i+=1
        # log page captures
        logfc.writerow([newspaper, year, month, day, str(i-missed)])


import json
import datetime
from server.http_codes import http_response_code

'''
Create a topic manager to manage overall topics
The types of topics are broadly divided into a topic to receive data transmitted from the
Arduino board and a topic to check the ping status.
Other topics can be additionally managed
'''

class MqttMessages:
    nodes = []
    ping_receive = []
    mqtt_topic = []
    topics = []
    ping_message = {}
    vos = 0
    delete_topic = []

    def __init__(self):
        self.ping_message_format = []

    def set_vos(self, number):
        self.vos = number

    def get_nodes(self):
        return self.nodes

    def add_node(self, nodeid):
        if nodeid not in self.nodes:
            self.nodes.append(nodeid)
            return True
        else:
            return False

    def get_message_format(self, format):
        self.clear_topics()
        temp = format['nodes']
        self.sensors = temp
        for i in range(len(temp)):
            temp[i]['id'] = str(temp[i]['id'])
            topic = "data/" + temp[i]['id']
            self.nodes.append(str(temp[i]['id']))
            self.ping_receive.append(("ping/" + temp[i]['id']))
            self.add_mqtt_topic(topic, self.vos)

    def add_mqtt_topic(self, topic, vos):
        self.topics.append(topic)
        topic = (topic, vos)
        self.mqtt_topic.append(topic)

    def get_delete_node(self, nodeid):
        self.delete_topic = []
        for i in range(len(self.topics)):
            v_topic = self.topics[i].split('/')
            if v_topic[1] is nodeid:
                self.nodes.remove(nodeid)
                self.delete_topic.append(self.topics[i])
                print(self.delete_topic)
        return self.delete_topic

    def clear_topics(self):
        self.mqtt_topic = []
        self.topics = []
        self.nodes = []
        self.ping_receive = []
        self.sensors = []


"""
Solution for "Xedni Drawkcab"
http://auacm.com/#/problems/xednidrawkcab

Simply reverse all input and sort.
"""

from sys import stdin

for word in sorted(
            map(
                lambda item: ''.join(item),
                map(reversed, stdin.read().split('\n')[1:-1])
            )
        ):
    print(word)


import logging
import random

from elev_sim.conf.elevator_conf import ELEV_CONFIG
from elev_sim.elevator.elevator import Elevator, displacement
from elev_sim.elevator.simple_data_structure import Mission
from elev_sim.elevator.logger import (Customer_logger, Elev_logger)

class ElevatorController:
    def __init__(self, env, elevatorList, floorList, EVENT, customer_logger:Customer_logger = None, elev_logger:Elev_logger = None):
        self.env = env
        self.elevatorList = elevatorList
        self.elevators = dict()
        self.EVENT = EVENT

        for elevatorName in elevatorList:
            self.elevators[elevatorName] = Elevator(env, elevatorName, floorList, self.EVENT, customer_logger=customer_logger, elev_logger=elev_logger)
        self.env.process(self.assignCalls())

    def assignCalls(self):
        while True:
            mission = yield self.EVENT.CALL

            # candidate = random.choices(self.elevatorList, weights=[1/len(self.elevatorList)] * len(self.elevatorList))[0]
            candidate = self.bestCandidate(mission)
            self.elevators[candidate].assign_event.succeed(value=mission)

            yield self.elevators[candidate].finish_event
            logging.info('[AssignCalls] Succeed')

    def bestCandidate(self, mission):
        '''Assignment Policy'''
        bestElevator = str()
        direction, source = mission

        if(isinstance(ELEV_CONFIG.VERSION, int)):
            DIFFERENT_DIR_BASE = 1000
            SAME_DIR_BACK_BASE = 2000

            minDistance = 50000000
            logging.warning("Mission: dir {}, des {}".format(direction, source))

            elevators = [elevator for elevator in self.elevators.values() if not elevator.stop_list.isNA(direction, source)]

            for elevator in elevators:
                elevator_score = int()
                if ((direction == elevator.direction and displacement(elevator.current_floor, source) * direction > 0) \
                    or (elevator.direction == 0)):
                    elevator_score = abs(displacement(source, elevator.current_floor))

                elif(direction != elevator.direction):
                    elevator_score  = DIFFERENT_DIR_BASE + displacement(elevator.current_floor, source) * elevator.direction

                # we should notice that the situation of the same direction and same floor belongs to this block
                elif(direction == elevator.direction and displacement(elevator.current_floor, source) * direction <= 0):
                    elevator_score  = SAME_DIR_BACK_BASE + displacement(elevator.current_floor, source) * -elevator.direction

                if(elevator_score < minDistance):
                    bestElevator = elevator.elevIndex
                    minDistance = elevator_score

                logging.warning(elevator.elevIndex)
                logging.warning("dir: {}, curr: {}".format(elevator.direction, elevator.current_floor))
                logging.warning("score: {}".format(elevator_score))

        logging.warning("best: {}".format(bestElevator))
        logging.warning("---------------------------------------------")

        return bestElevator


class Solution(object):
    def lengthOfLongestSubstring(self, s):
        if s == "":
            return 0
        n = len(s)
        dp = [0] * n
        nearest = [-1] * 256
        ans = 1
        dp[0] = 1
        nearest[ord(s[0])] = 0
        for i in xrange(1, n):
            if nearest[ord(s[i])] < i - dp[i - 1]:
                dp[i] = dp[i - 1] + 1
            else:
                dp[i] = i - nearest[ord(s[i])]
            nearest[ord(s[i])] = i
            ans = max(ans, dp[i])
        return ans

#solution = Solution()
#print solution.lengthOfLongestSubstring('aaabbaa')


# -*- coding: utf-8 -*-
import scrapy
from ..items import PolItem

class FloorSpider(scrapy.Spider):
    name = 'floor'
    allowed_domains = ['polvamvdom.ru']
    start_urls = ['https://polvamvdom.ru/laminat/']
    page_number = 2
    def parse(self, response):
        items = PolItem()
        catalog = response.xpath("//div[contains(@class, 'product short-view')]")
        for cat in catalog:
            articul = cat.xpath('.//div[contains(@class, "product-name")]//span[2]/text()').get()
            link = cat.xpath('.//div[contains(@class, "product-name")]//a/@href').get()
            price = cat.xpath('.//div[contains(@class, "product-price")]//div[@class="price"]//span/text()').getall()
            img_lnk = ''
            galery = []
            description = ''

            items['title'] = articul
            items['link'] = link
            items['price'] = price
            yield items

        next_page = response.xpath('//li[@class="next"]/a/@href').getall()[0]

        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)


# Write a function called poly_sum that takes 2 arguments, n and s.
# This function should sum the area and square of the perimeter of the regular polygon.
# The function returns the sum, rounded to 4 decimal places.
from math import tan, pi

def poly_sum(n, s):
    area = (0.25*n*s**2) / tan(pi / n)
    perimeter = 0
    for i in range(0, n):
        perimeter += s
    return round(area + perimeter**2, 4)


import sys
sys.path.append('../../')

from NetworkCore.Network import *
from NetworkCore.Synapse_Group import *
from NetworkBehaviour.Structure.Structure import *
import Exploration.UI.Network_UI.Network_UI as SUI
from Exploration.UI.Network_UI.Tabs.activity_tab import *
from Exploration.UI.Network_UI.Tabs.sidebar_activity_module import *
from Exploration.UI.Network_UI.Tabs.spiketrain_tab import *
from Exploration.UI.Network_UI.Tabs.fourier_tab import *
from Exploration.UI.Network_UI.Tabs.weight_tab import *
from Exploration.UI.Network_UI.Tabs.sidebar_fast_forward_module import *
from Exploration.UI.Network_UI.Tabs.sidebar_save_load_module import *
from Exploration.UI.Network_UI.Tabs.stability_tab import *
from Exploration.UI.Network_UI.Tabs.hist_tab import *
from Exploration.UI.Network_UI.Tabs.inh_exc_tab import *
from Exploration.UI.Network_UI.Tabs.buffer_tab import *

from NetworkBehaviour.Logic.Example_SORN.SORN_advanced_behaviour import *
from NetworkBehaviour.Input.SORN.TextActivator import *

from Exploration.UI.Network_UI.Tabs.sidebar_grammar_module import *

N_neurons = 900

source = FDTGrammarActivator_New(tag='grammar_act', output_size=N_neurons, random_blocks=True)

SORN = Network()

e_ng = NeuronGroup(net=SORN, tag='main_exc_group,prediction_source', size=get_squared_dim(N_neurons), behaviour={

    2: SORN_init_neuron_vars(init_TH='uniform(0.0,0.5)'),
    3: SORN_init_afferent_synapses(transmitter='GLU', density=10, distribution='uniform(0.0,0.5)', normalize=True),
    4: SORN_init_afferent_synapses(transmitter='GABA', density='full', distribution='uniform(0.0,0.5)', normalize=True),

    9: SORN_external_input(strength=1.0, pattern_groups=[source]),

    12: SORN_slow_syn(transmitter='GLU', strength='1.0'),
    13: SORN_slow_syn(transmitter='GABA', strength='-1.0'),
    20: SORN_input_collect(),

    21: SORN_STDP(eta_stdp='0.005', prune_stdp=False),
    22: SORN_SN(syn_type='GLU', clip_max=None),
    23: SORN_IP_TI(h_ip='0.1', eta_ip='0.001', integration_length=1, gap_percent=None, clip_min=None),
    30: SORN_finish()
})

i_ng = NeuronGroup(net=SORN, tag='main_inh_group', size=get_squared_dim(int(0.2 * N_neurons)), behaviour={
    2: SORN_init_neuron_vars(init_TH='uniform(0.0,0.5)'),
    3: SORN_init_afferent_synapses(transmitter='GLU', density='full', distribution='uniform(0.0,0.5)', normalize=True),

    14: SORN_fast_syn(transmitter='GLU', strength='1.0'),
    20: SORN_input_collect(),

    30: SORN_finish()
})

SynapseGroup(net=SORN, src=e_ng, dst=e_ng, connectivity='s_id!=d_id', tag='GLU')
SynapseGroup(net=SORN, src=e_ng, dst=i_ng, tag='GLU')
SynapseGroup(net=SORN, src=i_ng, dst=e_ng, tag='GABA')

SORN.initialize(info=False)

e_ng.color = (0, 0, 255, 255)
i_ng.color = (255, 0, 0, 255)

#train_and_generate_text(SORN, steps_plastic=15000, steps_train=5000, steps_spont=2000, storage_manager=None)

SUI.Network_UI(SORN, label='SORN Simple', group_display_count=2, modules=[
    UI_sidebar_activity_module(),
    activity_tab(['output', 'TH']),
    stability_tab(),
    spiketrain_tab(),
    fourier_tab(),
    buffer_tab(),
    hist_tab(),
    weight_tab(),
    info_tab(),
    inh_exc_tab(),
    sidebar_grammar_module(),
    sidebar_fast_forward_module(),
    sidebar_save_load_module()
]).show()


import os
import re
import hashlib
from flask import jsonify, url_for
from flask_jwt_simple import create_jwt, jwt_required, get_jwt
from datetime import datetime
from models import Users

class APIException(Exception):
    status_code = 400

    def __init__(self, message, status_code=None, payload=None):
        Exception.__init__(self)
        self.message = message
        if status_code is not None:
            self.status_code = status_code
        self.payload = payload

    def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv

# Raises an exception if required params not in body
def check_params(body, *args):
    msg = ''
    if body is None:
        msg = 'request body as a json object, '
    else:
        for prop in args:
            if prop not in body:
                msg += f'{prop}, '
    if msg:
        msg = re.sub(r'(.*),', r'\1 and', msg[:-2])
        raise Exception('You must specify the ' + msg, 400)

def update_table(table, body, ignore=[]):
    for attr, value in body.items():
        if attr not in ignore:
            if not hasattr(table, attr):
                raise Exception(f'Incorrect parameter in body: {attr}', 400)
            setattr(table, attr, value)

def validation_link(id):
    return os.environ.get('API_HOST') + '/users/validate/' + create_jwt({'id':id, 'role':'validating'})

def sha256(string):
    m = hashlib.sha256()
    m.update(string.encode('utf-8'))
    return m.hexdigest()

# Notes: 'admin' will have access even if arg not passed
def role_jwt_required(valid_roles=['invalid']):
    def decorator(func):

        @jwt_required
        def wrapper(*args, **kwargs):

            jwt_role = get_jwt()['role']
            valid = True if jwt_role == 'admin' else False

            for role in valid_roles:
                if role == jwt_role:
                    valid = True

            if not valid:
                raise Exception('Access denied', 401)

            user_id = get_jwt()['sub']
            if not Users.query.get(user_id):
                raise Exception('User not found', 404)

            kwargs = {
                **kwargs,
                'user_id': user_id
            }

            return func(*args, **kwargs)

        # change wrapper name so it can be used for more than one function
        wrapper.__name__ = func.__name__

        return wrapper
    return decorator


class Symbol:
    GlbVariable="test Global Variable";

    def __init__(self,CompanyName,CompanySymbol):
        self.CompanyName=CompanyName;
        self.CompanySymbol=CompanySymbol;

testsymbol=Symbol("testsymbol","testname");
testsymbol1=Symbol("testsymbol1","testsymbol2");

print(testsymbol.CompanyName,testsymbol.CompanySymbol, testsymbol.GlbVariable);

print(testsymbol1.CompanyName,testsymbol1.CompanySymbol,testsymbol1.GlbVariable);


#!/usr/bin/env python3
import datetime
from agency_common import Agency

_added_arguments = False
_handled_arguments = False
_max_seconds_unlimited = (
    datetime.datetime.max - datetime.datetime.min
).total_seconds()
_max_seconds = _max_seconds_unlimited

def set_max_seconds(value):
    global _max_seconds
    _max_seconds = value
def set_max_seconds_unlimited():
    global _max_seconds
    _max_seconds = _max_seconds_unlimited

class MaxSecondsGet:
    def __get__(self, instance, owner):
        return _max_seconds
class AgencyWalking(Agency):
    '''
    The purpose of this class is to add the --walking-max argument to the
    command line. Agencies whose edges involve walking should subclass this
    class and check the max_seconds property; the user should not be suggested
    to walk more that this number of seconds at a time.

    Agencies whose edges involve walking should also make sure that the
    consecutive_agency parameter to get_edge is not a subclass of this one.
    This will prevent consecutive walking directions in the itinerary.

    This class does not implement get_edge, so it cannot yield edges. However,
    subclasses of this class may implement get_edge.
    '''
    max_seconds = MaxSecondsGet()
    @staticmethod
    def add_arguments(arg_parser_add_argument):
        global _added_arguments
        if not _added_arguments:
            arg_parser_add_argument(
                "--walking-max",
                type=float,
                default=_max_seconds_unlimited / 60.0,
                metavar="minutes",
                help=
                    "the longest period of time that you are willing to walk "
                    "at a time without using some other form of transportation"
            )
            _added_arguments = True
    @staticmethod
    def handle_parsed_arguments(args_parsed, arg_parser_error):
        global _handled_arguments
        if not _handled_arguments:
            max_seconds = args_parsed.walking_max * 60.0
            if 0.0 <= max_seconds <= _max_seconds_unlimited:
                set_max_seconds(max_seconds)
            else:
                arg_parser_error(
                    "--walking-max must be between 0.0 and " +
                    str(_max_seconds_unlimited / 60.0)
                )
            _handled_arguments = True


import datetime
import faulthandler
import os
import platform
import sys
import unittest
import inspect

faulthandler.enable()  # to debug seg faults and timeouts

import cf

class functionTest(unittest.TestCase):
    def setUp(self):
        self.test_only = ()

    def test_example_field(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        for n in range(8):
            f = cf.example_field(n)
            _ = f.array
            _ = f.dump(display=False)

        with self.assertRaises(Exception):
            _ = cf.example_field(-999)

    def test_keyword_deprecation(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        # Use as test case 'i' kwarg, the deprecated old name for
        # 'inplace':
        a = cf.Data([list(range(100))])
        a.squeeze(inplace=True)  # new way to specify operation tested below

        b = cf.Data([list(range(100))])
        with self.assertRaises(cf.functions.DeprecationError):
            b.squeeze(i=True)

    def test_aliases(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        self.assertEqual(cf.log_level(), cf.LOG_LEVEL())
        self.assertEqual(cf.free_memory(), cf.FREE_MEMORY())
        self.assertEqual(cf.free_memory_factor(), cf.FREE_MEMORY_FACTOR())
        self.assertEqual(cf.fm_threshold(), cf.FM_THRESHOLD())
        self.assertEqual(cf.total_memory(), cf.TOTAL_MEMORY())
        self.assertEqual(cf.regrid_logging(), cf.REGRID_LOGGING())
        self.assertEqual(cf.relaxed_identities(), cf.RELAXED_IDENTITIES())
        self.assertEqual(cf.tempdir(), cf.TEMPDIR())
        self.assertEqual(cf.chunksize(), cf.CHUNKSIZE())
        self.assertEqual(cf.set_performance(), cf.SET_PERFORMANCE())
        self.assertEqual(cf.of_fraction(), cf.OF_FRACTION())
        self.assertEqual(
            cf.collapse_parallel_mode(), cf.COLLAPSE_PARALLEL_MODE()
        )

    def test_configuration(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        # This test assumes 'total_memory' remains constant throughout
        # the test run, which should be true generally in any
        # reasonable context.

        # Test getting of all config. and store original values to
        # test on:
        org = cf.configuration()
        self.assertIsInstance(org, dict)

        # Check all keys that should be there are, with correct value type:
        self.assertEqual(len(org), 11)  # update expected len if add new key(s)

        # Floats expected as values for most keys. Store these for
        # later as floats need assertAlmostEqual rather than
        # assertEqual tests:
        keys_with_float_values = [
            "atol",
            "rtol",
            "of_fraction",
            "free_memory_factor",
            "chunksize",
        ]
        for key in keys_with_float_values:
            self.assertIsInstance(org[key], float)

        # Other types expected:
        self.assertIsInstance(org["collapse_parallel_mode"], int)
        self.assertIsInstance(org["relaxed_identities"], bool)
        self.assertIsInstance(org["bounds_combination_mode"], str)
        self.assertIsInstance(org["regrid_logging"], bool)
        # Log level may be input as an int but always given as
        # equiv. string
        self.assertIsInstance(org["log_level"], str)
        self.assertIsInstance(org["tempdir"], str)

        # Store some sensible values to reset items to for testing, ensuring:
        # 1) they are kept different to the defaults (i.e. org values); and
        # 2) floats differ sufficiently that they will be picked up as
        #    qdifferent by the assertAlmostEqual decimal places (8, see
        #    below)
        reset_values = {
            "rtol": 5e-7,
            "atol": 2e-7,
            "tempdir": "/my-custom-tmpdir",
            "of_fraction": 0.1,
            "free_memory_factor": 0.25,
            "regrid_logging": True,
            "collapse_parallel_mode": 2,
            "relaxed_identities": True,
            "bounds_combination_mode": "XOR",
            "log_level": "INFO",
            "chunksize": 8e9,
        }

        # Test the setting of each lone item.
        expected_post_set = dict(org)  # copy for safety with mutable dict
        for setting, value in reset_values.items():
            cf.configuration(**{setting: value})
            post_set = cf.configuration()

            # Expect a dict that is identical to the original to start
            # with but as we set values incrementally they should be
            # reflected:
            expected_post_set[setting] = value

            # Can't trivially do a direct test that the actual and
            # expected return dicts are the same as there are float
            # values which have limited float precision so need
            # assertAlmostEqual testing:
            for name, val in expected_post_set.items():
                if isinstance(val, float):
                    self.assertAlmostEqual(
                        post_set[name], val, places=8, msg=setting
                    )
                else:
                    self.assertEqual(post_set[name], val)
        # --- End: for

        # Test the setting of more than one, but not all, items
        # simultaneously:
        new_values = {
            "regrid_logging": True,
            "tempdir": "/bin/bag",
            "of_fraction": 0.33,
        }
        cf.configuration(**new_values)
        post_set = cf.configuration()
        for name, val in new_values.items():  # test values that should change
            self.assertEqual(post_set[name], val)
        # ...and some values that should not:
        self.assertEqual(post_set["log_level"], "INFO")
        self.assertAlmostEqual(post_set["rtol"], 5e-7)

        # Test setting all possible items simultaneously (back to originals):
        cf.configuration(**org)
        post_set = cf.configuration()
        for name, val in org.items():
            if isinstance(val, float):
                self.assertAlmostEqual(post_set[name], val, places=8)
            else:
                self.assertEqual(post_set[name], val)
        # --- End: for

        # Test edge cases & invalid inputs...
        # ... 1. Falsy value inputs on some representative items:
        pre_set_config = cf.configuration()
        with self.assertRaises(ValueError):
            cf.configuration(of_fraction=0.0)
        with self.assertRaises(ValueError):
            cf.configuration(free_memory_factor=0.0)
        new_values = {
            "tempdir": "",
            "atol": 0.0,
            "regrid_logging": False,
        }
        cf.configuration(**new_values)
        post_set = cf.configuration()
        for name, val in new_values.items():  # test values that should change
            self.assertEqual(post_set[name], val)
        # ...and some values that should not:
        self.assertEqual(post_set["log_level"], pre_set_config["log_level"])
        self.assertAlmostEqual(post_set["rtol"], pre_set_config["rtol"])

        # 2. None as an input kwarg rather than as a default:
        pre_set_config = cf.configuration()
        set_of = 0.45
        cf.configuration(of_fraction=set_of, rtol=None, log_level=None)
        post_set = cf.configuration()
        # test values that should change
        self.assertEqual(post_set["of_fraction"], set_of)
        # ...and values that should not:
        self.assertEqual(post_set["rtol"], pre_set_config["rtol"])
        self.assertAlmostEqual(
            post_set["log_level"], pre_set_config["log_level"]
        )

        # 3. Gracefully error with invalid inputs:
        with self.assertRaises(ValueError):
            cf.configuration(of_fraction="bad")

        with self.assertRaises(ValueError):
            cf.configuration(log_level=7)

        # 4. Check invalid kwarg given logic processes **kwargs:
        with self.assertRaises(TypeError):
            cf.configuration(bad_kwarg=1e-15)

        old = cf.configuration()
        try:
            cf.configuration(atol=888, rtol=999, log_level="BAD")
        except ValueError:
            self.assertEqual(cf.configuration(), old)
        else:
            raise RuntimeError(
                "A ValueError should have been raised, but wasn't"
            )

        # Reset so later test fixtures don't spam with output
        # messages:
        cf.log_level("DISABLE")

    def test_context_managers(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        # rtol, atol, chunksize
        for func in (
            cf.atol,
            cf.rtol,
            cf.chunksize,
            cf.free_memory_factor,
            cf.of_fraction,
        ):
            old = func()
            new = old * 1.001
            with func(new):
                self.assertEqual(func(), new)
                self.assertEqual(func(new * 1.001), new)
                self.assertEqual(func(), new * 1.001)

            self.assertEqual(func(), old)

        # collapse_parallel_mode
        func = cf.collapse_parallel_mode

        org = func(0)
        old = func()
        new = old + 1
        with func(new):
            self.assertEqual(func(), new)
            self.assertEqual(func(new + 1), new)
            self.assertEqual(func(), new + 1)

        self.assertEqual(func(), old)
        func(org)

        # log_level
        func = cf.log_level

        org = func("DETAIL")
        old = func()
        new = "DEBUG"
        with func(new):
            self.assertEqual(func(), new)

        self.assertEqual(func(), old)
        func(org)

        del org._func
        with self.assertRaises(AttributeError):
            with org:
                pass
        # --- End: with

        # bounds_combination_mode
        func = cf.bounds_combination_mode

        org = func("XOR")
        old = func()
        new = "AND"
        with func(new):
            self.assertEqual(func(), new)

        self.assertEqual(func(), old)
        func(org)

        del org._func
        with self.assertRaises(AttributeError):
            with org:
                pass
        # --- End: with

        # Full configuration
        func = cf.configuration

        org = func(rtol=cf.Constant(10), atol=20, log_level="WARNING")
        old = func()
        new = dict(rtol=cf.Constant(20), atol=40, log_level="DISABLE")

        with func(**new):
            self.assertEqual(cf.atol(), 40)

        self.assertEqual(func(), old)
        func(**org)

    def test_Constant(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        c = cf.atol()
        self.assertIs(c._func, cf.atol)

    def test_Configuration(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        c = cf.Configuration()
        self.assertIs(c._func, cf.configuration)

    def test_environment(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        e = cf.environment(display=False)
        ep = cf.environment(display=False, paths=False)
        self.assertIsInstance(e, str)
        self.assertIsInstance(ep, str)

        components = ["Platform: ", "udunits2 library: ", "numpy: ", "cfdm: "]
        for component in components:
            self.assertIn(component, e)
            self.assertIn(component, ep)
        for component in [
            "cf: {} {}".format(cf.__version__, os.path.abspath(cf.__file__)),
            "Python: {} {}".format(platform.python_version(), sys.executable),
        ]:
            self.assertIn(component, e)
            self.assertNotIn(component, ep)  # paths shouldn't be present here
        for component in [
            "cf: {}".format(cf.__version__),
            "Python: {}".format(platform.python_version()),
        ]:
            self.assertIn(component, ep)

# --- End: class

if __name__ == "__main__":
    print("Run date:", datetime.datetime.now())
    cf.environment()
    print()
    unittest.main(verbosity=2)


import math

def find_roots(a, b, c):

    detriment = b**2 - 4*a*c
    if detriment < 0:
        raise ArithmeticError("The detriment can't be negative!  There are no roots")

    first_root = ( -b + math.sqrt(detriment) ) / (2*a)
    second_root = (-b - math.sqrt(detriment)) / (2 * a)
    return first_root, second_root

if __name__ == '__main__':
    print("This is more math!")


import time
from solenoid import Solenoid

# import curses
# from curses import wrapper

class SysExec():
    def __init__(self):
        self._timedelay = 0

        self._top_menu_options = [
            {'description': 'AUTO', 'function': self.AutoMenuProcessing},
            {'description': 'MANUAL', 'function': self.ManualMenuProcessing}
        ]

        self._manual_menu_options = [
            {'description': 'Close both Solenoids', 'function': self.CloseBothSolenoids},
            {'description': 'Open both Solenoids', 'function': self.OpenBothSolenoids },
            {'description': 'Close Solenoid 1', 'function': self.CloseSolenoid1 },
            {'description': 'Open Solenoid 1', 'function': self.OpenSolenoid1 },
            {'description': 'Close Solenoid 2', 'function': self.CloseSolenoid2 },
            {'description': 'Open Solenoid 2', 'function': self.OpenSolenoid2 },
        ]

        self._auto_menu_options = [
            {'description': 'Start Auto Mode', 'function': self.Auto},
        ]

        self._current_menu = self._top_menu_options
        self._exit_flag = False
        self._solenoid = Solenoid()

    def Exec(self):
        self.TopMenuProcessing()

    def TopMenuProcessing(self):
        menuIndex = 0
        active = True
        while active:
            if (self._exit_flag == True):
                break;
            self._current_menu = self._top_menu_options
            self.PrintCurrentMenuOptions();
            menuIndex = self._GetMenuOptionNumber()
            if (menuIndex == -1):
                active = False
            else:
                option = self._current_menu[menuIndex]
                option['function']()

    def AutoMenuProcessing(self):
        menuIndex = 0
        active = True
        while active:
            if (self._exit_flag == True):
                break;
            self._current_menu = self._auto_menu_options
            self.PrintCurrentMenuOptions();
            menuIndex = self._GetMenuOptionNumber()
            if (menuIndex == -1):
                active = False
            else:
                option = self._current_menu[menuIndex]
                option['function']()

    def ManualMenuProcessing(self):
        menuIndex = 0
        active = True
        while active:
            if (self._exit_flag == True):
                break;
            self._current_menu = self._manual_menu_options
            self.PrintCurrentMenuOptions();
            menuIndex = self._GetMenuOptionNumber()
            if (menuIndex == -1):
                active = False
            else:
                option = self._current_menu[menuIndex]
                option['function']()

    def DoNothing(self):
        menuIndex = 0

    def PrintCurrentMenuOptions(self):
        menuIndex = 0
        MyPrint("\nCommands (use b for back, q to exit)")
        for menuOptions in self._current_menu:
            description = menuOptions['description']
            MyPrint("\t{0}. {1}".format(menuIndex + 1, description))
            menuIndex += 1

    def PrintMenuOptions(self,menu):
        menuIndex = 0
        print("\nCommands (use b for back, q to exit")
        for menuOptions in menu:
            description = menuOptions['description']
            print("\t{0}. {1}".format(menuIndex + 1, description))
            menuIndex += 1

    def _GetMenuOptionNumber(self):
        loopForever = True;
        while loopForever:
            commandNumber = -1
            commandIsGood = True

            command = GetMenuInput()
            # print("GOT {0}".format(command))

            if command == 'b' or command == 'B':
                return -1
            elif command == 'q' or command == 'Q':
                self._exit_flag = True
                return -1

            try:
                commandNumber = int(command)
                commandNumber -= 1
            except:
                commandIsGood = False

            if not commandIsGood or ((commandNumber < 0) or (commandNumber > (len(self._manual_menu_options) - 1))):
                MyPrint("Illegal Command")
            else:
                loopForever = False

        return commandNumber

    def OpenBothSolenoids(self):
        self._solenoid.OpenBothSolenoids()

    def CloseBothSolenoids(self):
        self._solenoid.CloseBothSolenoids()

    def OpenSolenoid1(self):
        self._solenoid.OpenSolenoid1()

    def CloseSolenoid1(self):
        self._solenoid.CloseSolenoid1()

    def OpenSolenoid2(self):
        self._solenoid.OpenSolenoid2()

    def CloseSolenoid2(self):
        self._solenoid.CloseSolenoid2()

    def Auto(self):
        print("\n\t >>>> Running Auto Mode <<<<")

def GetMenuInput():
    prompt = ("ENTER COMMAND >> ")
    command = input(prompt)
    # print("ENTER COMMAND >> ")
    # return stdscr.getkey()
    return command

def MyPrint(string):
    #stdscr.addscr(string)
    print(string)

if __name__ == '__main__':

#def main(stdscr):

    # stdscr = curses.initscr()
    # curses.noecho()
    # curses.cbreak()

    sysExec = SysExec()
    sysExec.Exec()

    # curses.nocbreak()
    # stdscr.keypad(False)
    # curses.echo()

    print("Goodbye")

# wrapper(main)


# -*- coding: utf-8 -*-
"""
data_info.py

Created on Mon Mar 25 09:52:56 2019

@author: Yansong Tu @ SUTPC

"""

import os
import math
import statistics as st

# ===== CONSTANTS =====

#地球半径
EARTH_RADIUS = 6378.137

# 汽车种类 (手动修改)
CAR_TYPE = "taxi"

# 有无进行过排序处理
SORTED = False

# get_time 获取单条记录的时间
def get_time(line):
    sep = line.split(",")[1]
    return sep

# get_coor 获取单条记录的坐标 (lon经度, lat纬度)
def get_coor(line):
    return [line.split(",")[3].rstrip("\n"), line.split(",")[2]]

# difference in time 获取两个timestamps的时间差
def TimeDiff(t1, t2):
    return abs(int(t2) - int(t1))

# 通过时间判断两条记录之间是否为间隔可行的分割点
def checkTime(t1, t2, lines):
    result = abs(int(t2) - int(t1))
    if result > time_eval(lines):
        return True #filter out
    else:
        return False

# difference in distances 获取两个坐标的距离差
def DistDiff(lat1, lng1, lat2, lng2):
    radLat1 = math.radians(float(lat1))
    radLat2 = math.radians(float(lat2))
    a = radLat1 - radLat2
    b = math.radians(float(lng1)) - math.radians(float(lng2))

    s = 2 * math.asin(math.sqrt(math.pow(math.sin(a / 2), 2) + \
                               math.cos(radLat1) * math.cos(radLat2) * \
                               math.pow(math.sin(b / 2), 2)))
    s = s * EARTH_RADIUS
    return round(s * 10000) / 10000

# 通过路程判断两条记录之间是否为间隔可行的分割点
def checkDistance(lat1, lng1, lat2, lng2, lines):
    radLat1 = math.radians(lat1)
    radLat2 = math.radians(lat2)
    a = radLat1 - radLat2
    b = math.radians(lng1) - math.radians(lng2)

    s = 2 * math.asin(math.sqrt(math.pow(math.sin(a / 2), 2) + \
                               math.cos(radLat1) * math.cos(radLat2) * \
                               math.pow(math.sin(b / 2), 2)))
    s = s * EARTH_RADIUS
    s = round(s * 10000) / 10000
    if s >= dist_eval(lines):
        return True # filter out
    else:
        return False

# count the number of files in a directory 获取单个文件夹内的文件数量
def file_count(rootDir):
    count = 0
    for file in rootDir:
        count += 1
    return count

# total travel time 计算一辆车的行驶总时间
def totalTime(lines):
    time_traveled = 0
    index = 0
    curr_line = lines[index]
    while curr_line != '':
        if index == 0:
            index += 1
            curr_line = lines[index]
            try:
                curr_line = lines[index]
            except:
                break
        elif index == 1:
            prev_time = get_time(curr_line)
            index += 1
            try:
                curr_line = lines[index]
            except:
                break
        else:
            curr_time = get_time(curr_line)
            td = TimeDiff(curr_time, prev_time)
            time_traveled += td
            prev_time = curr_time
            index += 1
            try:
                curr_line = lines[index]
            except:
                break
    return time_traveled

# total travel distance 计算一辆车的行驶总路程
def totalDistance(lines):
    dist_traveled = 0
    index = 0
    curr_line = lines[index]
    prev_coor = get_coor(lines[0])
    while curr_line != '':
        if index == 0:
            index += 1
            try:
                curr_line = lines[index]
            except:
                break
        elif index == 1:
            prev_coor = get_coor(curr_line)
            index += 1
            try:
                curr_line = lines[index]
            except:
                break
        else:
            curr_coor = get_coor(curr_line)
            dist = DistDiff(prev_coor[0], prev_coor[1], curr_coor[0], curr_coor[1])
            dist_traveled += dist
            prev_coor = curr_coor
            index += 1
            try:
                curr_line = lines[index]
            except:
                break
    return dist_traveled

# create a list of time differences 生成时间差的list
def l_timeDiff(lines):
    length = len(lines)
    l = []
    prev_i = 1
    curr_i = 2
    try:
        prev_line = lines[prev_i]
        curr_line = lines[curr_i]
    except:
        return
    while curr_line != None and prev_line != None:
        prev_line = lines[prev_i]
        curr_line = lines[curr_i]
        if isinstance(prev_line, int):
            break
        prev_time = get_time(prev_line)
        curr_time = get_time(curr_line)
        t = TimeDiff(prev_time, curr_time)
        l.append(float(t))
        prev_i += 1
        curr_i += 1
        if curr_i == length:
            break
    return l

# create a list of distance differences 生成距离差的list
def l_distDiff(lines):
    length = len(lines)
    l = []
    prev_i = 1
    curr_i = 2
    try:
        prev_line = lines(prev_i)
        curr_line = lines(curr_i)
    except:
        return
    while lines[prev_i] != None and lines[curr_i] != None:
        prev_line = lines[prev_i]
        curr_line = lines[curr_i]
        if isinstance(prev_line, int) or isinstance(prev_line, float):
            break
        prev_coor = get_coor(prev_line)
        curr_coor = get_coor(curr_line)
        d = DistDiff(prev_coor[1], prev_coor[0], curr_coor[1], prev_coor[0])
        l.append(float(d))
        prev_i += 1
        curr_i += 1
        if curr_i == length:
            break
        return l

# 该车拥有最长停车记录的坐标点
def maxStoppedat(lines):
    # 生成停车记录参照表
    stop_dict = {}

    prev_coor = get_coor(lines[0])
    for line in lines:
        curr_coor = get_coor(lines[0])
        if prev_coor == curr_coor:
            if stop_dict:
                stop_dict[curr_coor[0] + "," + curr_coor[1]] += 1
            else:
                stop_dict[curr_coor[0] + "," + curr_coor[1]] = 2

    # 最长停车点(坐标)
    max_at = max(dict.values(stop_dict))
    for key in dict.keys(stop_dict):
        if stop_dict[key] == max_at:
            max_stopping_at = stop_dict[key]
            return max_stopping_at

# 备注:
# 时间/距离差的计算方式
# stdv - standard deviation - 标准差
# 根据每一个数据的分布情况和波动大小来判断 - 具有独一性
# 平均值+标准差*0.9

# 计算分离文件的时间点
def time_eval(lines):
    ltd = l_timeDiff(lines)
    stdv = st.pstdev(ltd)
    return (totalTime(lines)/(len(lines) - 1)) + stdv*0.9

# 计算分离文件的距离
def dist_eval(lines):
    lte = l_timeDiff(lines)
    stdv = st.pstdev(lte)
    return (totalTime(lines)/(len(lines) - 1)) + stdv*0.9

# 检查车辆全记录中的停车所占比
def stop_eval(lines):
    num = 0
    prev_coor = get_coor(lines[0])
    for line in lines:
        curr_coor = get_coor(line)
        if curr_coor == prev_coor:
            num += 1
        prev_coor = curr_coor
    actual_p = (num - 1)/len(lines)
    return actual_p

# 生成一个文件夹内的文件大小表
def file_sizes(rootDir):
    l = []
    for file in os.listdir(rootDir):
        size = os.path.getsize(file)
        l + [size]
    return l

# index: the index of the file 该车辆在全部同种类车辆的序号
# inner_i: the index of current line 车辆分割文件的序号

# 根据通过时间与距离上的正态分布检查
def file_seperation(lines, plate_num, directory):
    srt = sorted(lines, key = lambda line:line.split(",")[1])

    index = 1
    inner_i = 1
    lst = []

    curr_time = None
    curr_coor = []
    curr_line = lines[0]

    # 创建新的文件夹以装载分割文件 (nfpath: new file path)
    nfpath = plate_num.rstrip(".txt") + "_sep"
    if not os.path.exists(nfpath):
        os.makedirs(nfpath)

    os.chdir(nfpath)

    for line in srt:
        if line == curr_line:
            continue

        l_sep = line.split(",")

        if curr_time == None or curr_coor == []:
            curr_time = l_sep[1]
            curr_coor = l_sep[2], l_sep[3]
            continue

        t1, t2 = curr_time, l_sep[1]
        lat1, lng1, lat2, lng2 = curr_coor[0], curr_coor[1], l_sep[2], l_sep[3]
        if [lat1, lng1] == [lat2, lng2]:
            lst.append(line.rstrip("\n") + "," + str(index) + "\n")
            continue

        elif checkDistance(float(lat1), float(lng1), float(lat2), float(lng2), lines) or checkTime(t1, t2, lines):
            lst.append(line.rstrip("\n") + "," + str(index) + "\n")
            curr_f = open(plate_num.rstrip(".txt") + "_" + str(index) + ".txt", "w", encoding = "UTF-8-Sig")
            curr_f.write("plate_num, timestamp, lat, lon\n")
            curr_f.writelines(lst)
            curr_f.close()
            lst = []
            index += 1
        else:
            lst.append(l_sep[0] + "," + l_sep[1] + "," + l_sep[2] + "," + \
                       l_sep[3].rstrip("\n") + "," + str(index) + "\n")
        inner_i += 1
        curr_time = l_sep[1]
        curr_coor = [l_sep[2], l_sep[3]]

# 分割后平均每条记录的样本分析
log_lst = []

def spcheck(plate, param, directory):
    d = {}
    for file in os.listdir(directory):
        cf = open(file, mode = 'r', encoding = 'UTF-8-Sig')
        lines = cf.readlines()
        length = len(lines)
        d[file.rstrip(".txt")] = length - 1
        cf.close()

    #检查dictionary是否为空 - 如果是手动添加
    if d == {}:
        d = {plate + "_1": length}
    if param == "files_sep":
        print("\n")
        print(d)
        # 分割后的文件总数
        files_sep = len(d)
        return files_sep
    elif param == "max_file_index":
        # 分割后拥有最多记录的文件索引
        maxcount = max(d.values())
        for key in d.keys():
            if d[key] == maxcount:
                return key.lstrip(plate + "_")
    elif param == "max_log_count":
        # 该文件所含有的记录数量
        max_log_count = max(d.values())
        return max_log_count
    elif param == "min_file_index":
        #分割后拥有最少记录的文件索引
        mincount = min(d.values())
        for key in d.keys():
            if d[key] == mincount:
                return key.lstrip(plate + "_")
    elif param == "min_log_count":
        # 该文件所含有的记录数量
        min_log_count = min(d.values())
        return min_log_count
    elif param == "avg_log_per_file":
        # === configure log_lst
        avg_log_per_file = sum(d.values())/length
        return avg_log_per_file


import lightgbm as lgb
import pytest

import optuna
from optuna.integration.lightgbm import LightGBMPruningCallback
from optuna.testing.integration import DeterministicPruner

def test_lightgbm_pruning_callback_call():
    # type: () -> None

    env = lgb.callback.CallbackEnv(
        model='test',
        params={},
        begin_iteration=0,
        end_iteration=1,
        iteration=1,
        evaluation_result_list=[('validation', 'binary_error', 1., False)])

    # The pruner is deactivated.
    study = optuna.create_study(pruner=DeterministicPruner(False))
    trial = study._run_trial(func=lambda _: 1.0, catch=(Exception,))
    pruning_callback = LightGBMPruningCallback(trial, 'binary_error', valid_name='validation')
    pruning_callback(env)

    # The pruner is activated.
    study = optuna.create_study(pruner=DeterministicPruner(True))
    trial = study._run_trial(func=lambda _: 1.0, catch=(Exception,))
    pruning_callback = LightGBMPruningCallback(trial, 'binary_error', valid_name='validation')
    with pytest.raises(optuna.structs.TrialPruned):
        pruning_callback(env)

def test_lightgbm_pruning_callback():
    # type: () -> None

    study = optuna.create_study(pruner=DeterministicPruner(True))
    study.optimize(objective, n_trials=1)
    assert study.trials[0].state == optuna.structs.TrialState.PRUNED

    study = optuna.create_study(pruner=DeterministicPruner(False))
    study.optimize(objective, n_trials=1)
    assert study.trials[0].state == optuna.structs.TrialState.COMPLETE
    assert study.trials[0].value == 1.

    # Use non default validation name.
    custom_valid_name = 'my_validation'
    study = optuna.create_study(pruner=DeterministicPruner(False))
    study.optimize(lambda trial: objective(trial, valid_name=custom_valid_name), n_trials=1)
    assert study.trials[0].state == optuna.structs.TrialState.COMPLETE
    assert study.trials[0].value == 1.

def test_lightgbm_pruning_callback_errors():
    # type: () -> None

    # "maximize" direction isn't supported yet.
    study = optuna.create_study(pruner=DeterministicPruner(False))
    with pytest.raises(ValueError):
        study.optimize(lambda trial: objective(trial, metric='auc'), n_trials=1, catch=())

    # Unknown metric
    study = optuna.create_study(pruner=DeterministicPruner(False))
    with pytest.raises(ValueError):
        study.optimize(lambda trial: objective(trial, metric='foo_metric'), n_trials=1, catch=())

    # Unknown validation name
    study = optuna.create_study(pruner=DeterministicPruner(False))
    with pytest.raises(ValueError):
        study.optimize(lambda trial: objective(trial, valid_name='valid_1',
                                               force_default_valid_names=True),
                       n_trials=1, catch=())

def objective(trial, metric='binary_error', valid_name='valid_0', force_default_valid_names=False):
    # type: (optuna.trial.Trial, str, str, bool) -> float

    dtrain = lgb.Dataset([[1.]], label=[1.])
    dtest = lgb.Dataset([[1.]], label=[1.])

    if force_default_valid_names:
        valid_names = None
    else:
        valid_names = [valid_name]

    pruning_callback = LightGBMPruningCallback(trial, metric, valid_name=valid_name)
    lgb.train({'objective': 'binary', 'metric': ['auc', 'binary_error']}, dtrain, 1,
              valid_sets=[dtest], valid_names=valid_names,
              verbose_eval=False, callbacks=[pruning_callback])
    return 1.0


# coding: utf-8

from __future__ import absolute_import
from datetime import date, datetime  # noqa: F401

from typing import List, Dict  # noqa: F401

from swagger_server.models.base_model_ import Model
from swagger_server.models.one_of_validation_issue_value import OneOfValidationIssueValue
# from swagger_server.models.object import Object  # noqa: F401,E501
from swagger_server import util

class ValidationIssue(Model):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """
    def __init__(self, issue_code: str=None, message: str=None, property_name: str=None, value: OneOfValidationIssueValue=None):  # noqa: E501
        """ValidationIssue - a model defined in Swagger

        :param issue_code: The issue_code of this ValidationIssue.  # noqa: E501
        :type issue_code: str
        :param message: The message of this ValidationIssue.  # noqa: E501
        :type message: str
        :param property_name: The property_name of this ValidationIssue.  # noqa: E501
        :type property_name: str
        :param value: The value of this ValidationIssue.  # noqa: E501
        :type value: OneOfValidationIssueValue
        """
        self.swagger_types = {
            'issue_code': str,
            'message': str,
            'property_name': str,
            'value': OneOfValidationIssueValue
        }

        self.attribute_map = {
            'issue_code': 'issue_code',
            'message': 'message',
            'property_name': 'property_name',
            'value': 'value'
        }
        self._issue_code = issue_code
        self._message = message
        self._property_name = property_name
        self._value = value

    @classmethod
    def from_dict(cls, dikt) -> 'ValidationIssue':
        """Returns the dict as a model

        :param dikt: A dict.
        :type: dict
        :return: The ValidationIssue of this ValidationIssue.  # noqa: E501
        :rtype: ValidationIssue
        """
        return util.deserialize_model(dikt, cls)

    @property
    def issue_code(self) -> str:
        """Gets the issue_code of this ValidationIssue.

        A code identifying the type of issue that occurred. This allows integrating APIs to try to resolve the issue automatically.  # noqa: E501

        :return: The issue_code of this ValidationIssue.
        :rtype: str
        """
        return self._issue_code

    @issue_code.setter
    def issue_code(self, issue_code: str):
        """Sets the issue_code of this ValidationIssue.

        A code identifying the type of issue that occurred. This allows integrating APIs to try to resolve the issue automatically.  # noqa: E501

        :param issue_code: The issue_code of this ValidationIssue.
        :type issue_code: str
        """
        if issue_code is None:
            raise ValueError("Invalid value for `issue_code`, must not be `None`")  # noqa: E501

        self._issue_code = issue_code

    @property
    def message(self) -> str:
        """Gets the message of this ValidationIssue.

        A message summarising why this property failed to validate.  # noqa: E501

        :return: The message of this ValidationIssue.
        :rtype: str
        """
        return self._message

    @message.setter
    def message(self, message: str):
        """Sets the message of this ValidationIssue.

        A message summarising why this property failed to validate.  # noqa: E501

        :param message: The message of this ValidationIssue.
        :type message: str
        """
        if message is None:
            raise ValueError("Invalid value for `message`, must not be `None`")  # noqa: E501

        self._message = message

    @property
    def property_name(self) -> str:
        """Gets the property_name of this ValidationIssue.

        The name of the property that this issue was raised for.  # noqa: E501

        :return: The property_name of this ValidationIssue.
        :rtype: str
        """
        return self._property_name

    @property_name.setter
    def property_name(self, property_name: str):
        """Sets the property_name of this ValidationIssue.

        The name of the property that this issue was raised for.  # noqa: E501

        :param property_name: The property_name of this ValidationIssue.
        :type property_name: str
        """
        if property_name is None:
            raise ValueError("Invalid value for `property_name`, must not be `None`")  # noqa: E501

        self._property_name = property_name

    @property
    def value(self) -> OneOfValidationIssueValue:
        """Gets the value of this ValidationIssue.

        The value of the property that passed validation.  # noqa: E501

        :return: The value of this ValidationIssue.
        :rtype: OneOfValidationIssueValue
        """
        return self._value

    @value.setter
    def value(self, value: OneOfValidationIssueValue):
        """Sets the value of this ValidationIssue.

        The value of the property that passed validation.  # noqa: E501

        :param value: The value of this ValidationIssue.
        :type value: OneOfValidationIssueValue
        """

        self._value = value


from app.domain.models import CreateDatasetResponse, CreateDatasetRequest

class MockBevaringClient:

    dataset_keys: CreateDatasetResponse

    def request_dataset_keys(self, payload: CreateDatasetRequest):
        self.dataset_keys = CreateDatasetResponse(
            bucket_name="mockBucketName",
            session_id="mockSessionId",
            datasett_id="mockDatasettId",
            iam_access_key_id="mockAccessKeyId",
            iam_secret_access_key="mockSecretAccessKey",
            s3_path="mockS3Path",
            s3_logfiles_path="mockS3LogfilesPath",
            status="mockStatus",
        )
        return self.dataset_keys


import json
import unittest

from ..models import SubmittedPriceList
from ..schedules.fake_schedule import FakeSchedulePriceList
from ..schedules import registry
from ..management.commands.initgroups import PRICE_LIST_UPLOAD_PERMISSION
from .common import StepTestCase, FAKE_SCHEDULE, FAKE_SCHEDULE_EXAMPLE_PATH

class PriceListStepTestCase(StepTestCase):
    url = None

    # TODO: Move individual setUp functions here if applicable
    def set_fake_gleaned_data(self, rows):
        session = self.client.session
        pricelist = FakeSchedulePriceList(rows)
        session['data_capture:price_list']['schedule'] = \
            registry.get_classname(pricelist)
        session['data_capture:price_list']['gleaned_data'] = \
            registry.serialize(pricelist)
        session.save()

    def delete_price_list_from_session(self):
        session = self.client.session
        del session['data_capture:price_list']
        session.save()

    def setUp(self):
        super().setUp()
        registry._init()

    def login(self, **kwargs):
        kwargs['permissions'] = [PRICE_LIST_UPLOAD_PERMISSION]
        return super().login(**kwargs)

    def test_login_is_required(self):
        if not self.url:
            raise unittest.SkipTest()
        self.assertRedirectsToLogin(self.url)

    def test_permission_is_required(self):
        if not self.url:
            raise unittest.SkipTest()
        super().login()
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 403)

class Step1Tests(PriceListStepTestCase):
    url = '/data-capture/step/1'

    valid_form = {
        'schedule': FAKE_SCHEDULE,
        'contract_number': 'GS-123-4567',
        'vendor_name': 'foo'
    }

    def test_get_is_ok(self):
        self.login()
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 200)

    def test_valid_post_sets_session_data(self):
        self.login()
        self.client.post(self.url, self.valid_form)
        session_pl = self.client.session['data_capture:price_list']
        session_data = session_pl['step_1_POST']
        self.assertEqual(session_data['schedule'], FAKE_SCHEDULE)
        self.assertEqual(session_data['contract_number'], 'GS-123-4567')
        self.assertEqual(session_data['vendor_name'], 'foo')

    def test_valid_post_redirects_to_step_2(self):
        self.login()
        res = self.client.post(self.url, self.valid_form)
        self.assertRedirects(res, Step2Tests.url)

    def test_invalid_post_returns_html(self):
        self.login()
        res = self.client.post(self.url, {})
        self.assertEqual(res.status_code, 200)
        self.assertContains(res, 'This field is required')
        self.assertHasMessage(
            res,
            'error',
            'Oops, please correct the errors below and try again.'
        )

class Step2Tests(PriceListStepTestCase):
    url = '/data-capture/step/2'

    valid_form = {
        'contractor_site': 'Customer',
        'is_small_business': 'False',
        'contract_year': '1',
        'contract_start_0': '1985',
        'contract_start_1': '07',
        'contract_start_2': '08',
        'contract_end_0': '1989',
        'contract_end_1': '04',
        'contract_end_2': '14'
    }

    def setUp(self):
        super().setUp()
        session = self.client.session
        session['data_capture:price_list'] = {
            'step_1_POST': Step1Tests.valid_form,
        }
        session.save()

    def test_get_is_ok(self):
        self.login()
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 200)

    def test_going_back_to_previous_step_prefills_its_form(self):
        self.login()
        res = self.client.get(Step1Tests.url)
        self.assertEqual(res.context['form'].data, Step1Tests.valid_form)

    def test_redirects_to_step_1_if_not_completed(self):
        self.login()
        self.delete_price_list_from_session()
        res = self.client.get(self.url)
        self.assertRedirects(res, Step1Tests.url)

    def test_valid_post_updates_session_data(self):
        self.login()
        self.client.post(self.url, self.valid_form)
        session_pl = self.client.session['data_capture:price_list']
        posted_data = session_pl['step_2_POST']
        self.assertEqual(posted_data['contractor_site'],
                         self.valid_form['contractor_site'])
        self.assertEqual(posted_data['is_small_business'],
                         self.valid_form['is_small_business'])

    def test_valid_post_redirects_to_step_3(self):
        self.login()
        res = self.client.post(self.url, self.valid_form)
        self.assertRedirects(res, Step3Tests.url)

    def test_invalid_post_returns_html(self):
        self.login()
        res = self.client.post(self.url, {})
        self.assertEqual(res.status_code, 200)
        self.assertContains(res, 'This field is required')
        self.assertHasMessage(
            res,
            'error',
            'Oops, please correct the errors below and try again.'
        )

    def test_cancel_clears_session_and_redirects(self):
        self.login()
        res = self.client.post(self.url, {'cancel': ''})
        self.assertEqual(res.status_code, 302)
        self.assertEqual(res['Location'], 'http://testserver/')
        session = self.client.session
        for k in list(session.keys()):
            self.assertFalse(k.startswith('data_capture:'))

class Step3Tests(PriceListStepTestCase):
    url = '/data-capture/step/3'
    csvpath = FAKE_SCHEDULE_EXAMPLE_PATH
    rows = [{
        'education': 'Bachelors',
        'price': '15.00',
        'service': 'Project Manager',
        'sin': '132-40',
        'years_experience': '7'
    }]

    def setUp(self):
        super().setUp()
        session = self.client.session
        session['data_capture:price_list'] = {
            'step_1_POST': Step1Tests.valid_form,
            'step_2_POST': Step2Tests.valid_form,
        }
        session.save()

    def ajax_post(self, data):
        res = self.client.post(self.url, data,
                               HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(res.status_code, 200)
        return res, json.loads(res.content.decode('utf-8'))

    def test_get_is_ok(self):
        self.login()
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 200)

    def test_going_back_to_previous_step_prefills_its_form(self):
        self.login()
        res = self.client.get(Step2Tests.url)
        self.assertEqual(res.context['form'].data, Step2Tests.valid_form)

    def test_redirects_to_step_2_if_not_completed(self):
        self.login()
        self.delete_price_list_from_session()
        res = self.client.get(self.url)
        self.assertRedirects(res, Step2Tests.url, target_status_code=302)

    def test_valid_post_updates_session_data(self):
        self.login()
        with open(self.csvpath) as f:
            self.client.post(self.url, {
                'file': f
            })
            session_pl = self.client.session['data_capture:price_list']
            self.assertEqual(session_pl['step_1_POST']['schedule'],
                             FAKE_SCHEDULE)
            gleaned_data = session_pl['gleaned_data']
            gleaned_data = registry.deserialize(gleaned_data)
            assert isinstance(gleaned_data, FakeSchedulePriceList)
            self.assertEqual(gleaned_data.rows, [{
                'education': 'Bachelors',
                'price': '15.00',
                'service': 'Project Manager',
                'sin': '132-40',
                'years_experience': '7'
            }])

    def test_valid_post_via_xhr_returns_json(self):
        self.login()
        with open(self.csvpath) as f:
            res, json_data = self.ajax_post({
                'file': f
            })
            self.assertEqual(json_data, {
                'redirect_url': '/data-capture/step/4'
            })

    def test_valid_post_redirects_to_step_4(self):
        self.login()
        with open(self.csvpath) as f:
            res = self.client.post(self.url, {
                'file': f
            })
            self.assertRedirects(res, Step4Tests.url)

    def test_invalid_post_returns_html(self):
        self.login()
        res = self.client.post(self.url, {})
        self.assertEqual(res.status_code, 200)
        self.assertContains(res, r'<!DOCTYPE html>')
        self.assertContains(res, r'This field is required')
        self.assertHasMessage(
            res,
            'error',
            'Oops, please correct the error below and try again.'
        )

    def test_invalid_post_via_xhr_returns_json(self):
        self.login()
        res, json_data = self.ajax_post({})
        assert '<!DOCTYPE html>' not in json_data['form_html']
        self.assertRegexpMatches(json_data['form_html'],
                                 r'This field is required')
        self.assertHasMessage(
           res,
           'error',
           'Oops, please correct the error below and try again.'
        )

    def test_cancel_clears_session_and_redirects(self):
        self.login()
        res = self.client.post(self.url, {'cancel': ''})
        self.assertEqual(res.status_code, 302)
        self.assertEqual(res['Location'], 'http://testserver/')
        session = self.client.session
        for k in list(session.keys()):
            self.assertFalse(k.startswith('data_capture:'))

class Step4Tests(PriceListStepTestCase):
    url = '/data-capture/step/4'
    rows = [{
        'education': 'Bachelors',
        'price': '15.00',
        'service': 'Project Manager',
        'sin': '132-40',
        'years_experience': '7'
    }, {
        'education': 'School of hard knocks',
        'price': '0',
        'service': 'Oil change & tune up',
        'sin': 'absolved',
        'years_experience': 'vii'
    }]
    session_data = {
        'step_1_POST': Step1Tests.valid_form,
        'step_2_POST': Step2Tests.valid_form,
    }

    def test_gleaned_data_is_required(self):
        # TODO: This login and session-setting code is repeated
        # throughout all these tests--perhaps we should just move it into
        # the test's setUp() code or consolidate in some other way?

        self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        res = self.client.get(self.url)
        self.assertRedirects(res, Step3Tests.url)

    def test_get_is_ok(self):
        self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        self.set_fake_gleaned_data(self.rows)
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 200)

    def test_gleaned_data_with_valid_rows_is_required_on_POST(self):
        self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        self.set_fake_gleaned_data([])

        res = self.client.post(self.url)
        self.assertEqual(res.status_code, 400)

    def test_valid_post_creates_models(self):
        user = self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        self.set_fake_gleaned_data(self.rows)
        self.client.post(self.url)
        p = SubmittedPriceList.objects.filter(
            contract_number='GS-123-4567'
        )[0]
        self.assertEqual(p.schedule, FAKE_SCHEDULE)
        self.assertEqual(p.vendor_name, 'foo')
        self.assertEqual(p.contractor_site, 'Customer')
        self.assertEqual(p.is_small_business, False)
        self.assertEqual(p.submitter, user)
        self.assertEqual(p.contract_year, 1)

    def test_valid_post_clears_session_and_redirects_to_step_5(self):
        self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        self.set_fake_gleaned_data(self.rows)
        res = self.client.post(self.url)
        assert 'data_capture:price_list' not in self.client.session
        self.assertRedirects(res, Step5Tests.url)

    def test_cancel_clears_session_and_redirects(self):
        self.login()
        session = self.client.session
        session['data_capture:price_list'] = self.session_data
        session.save()
        self.set_fake_gleaned_data(self.rows)
        res = self.client.post(self.url, {'cancel': ''})
        self.assertEqual(res.status_code, 302)
        self.assertEqual(res['Location'], 'http://testserver/')
        session = self.client.session
        for k in list(session.keys()):
            self.assertFalse(k.startswith('data_capture:'))

class Step5Tests(PriceListStepTestCase):
    url = '/data-capture/step/5'

    def test_get_is_ok(self):
        self.login()
        res = self.client.get(self.url)
        self.assertEqual(res.status_code, 200)


def kakko(T):
    l = len(T)
    if l%2 == 1:
        return False
    else:
        s = int(l/2)
        T1 = T[:s]
        T2 = T[s:]
        T2 = T2[::-1]
        T2 = T2.replace('(','a').replace(')','(').replace('a',')')
        if T1 == T2:
            return True
        else:
            return False

def kkakko(U):
    l = len(U)
    if l%2 == 1:
        return False
    else:
        s = int(l/2) + 1
        i = 1
        while i <= s and  l != 0:
            if kakko(U[:i*2]) == True:
                U = U[i*2:]
                i = 1
                l = len(U)
                s = int(l/2) + 1
            else:
                i += 1
        if l == 0:
            return True
        else:
            return False

S = input()
c = 0
l = len(S)
s = l + 1
for i in range(l):
    for j in range(i+1, s):
        if kkakko(S[i:j]) == True:
            print("{}""{}".format(i,j))
            c += 1
print(c)