"""Abstractions for setting up a Galaxy instance."""
from __future__ import absolute_import
from __future__ import print_function

import abc
import contextlib
import os
import random
import shutil
from string import Template
from tempfile import mkdtemp

from galaxy.containers.docker_model import DockerVolume
from galaxy.tools.deps import docker_util
from galaxy.tools.deps.commands import argv_to_str
from pkg_resources import parse_version
from six import (
    add_metaclass,
    iteritems
)
from six.moves import shlex_quote

from planemo import git
from planemo.config import OptionSource
from planemo.deps import ensure_dependency_resolvers_conf_configured
from planemo.docker import docker_host_args
from planemo.io import (
    communicate,
    kill_pid_file,
    shell,
    shell_join,
    wait_on,
    warn,
    write_file,
)
from planemo.mulled import build_involucro_context
from planemo.shed import tool_shed_url
from planemo.virtualenv import DEFAULT_PYTHON_VERSION
from .api import (
    DEFAULT_MASTER_API_KEY,
    gi,
    user_api_key,
)
from .distro_tools import (
    DISTRO_TOOLS_ID_TO_PATH
)
from .run import (
    setup_common_startup_args,
    setup_venv,
)
from .workflows import (
    find_tool_ids,
    import_workflow,
    install_shed_repos,
)

NO_TEST_DATA_MESSAGE = (
    "planemo couldn't find a target test-data directory, you should likely "
    "create a test-data directory or pass an explicit path using --test_data."
)

WEB_SERVER_CONFIG_TEMPLATE = """
[server:${server_name}]
use = egg:Paste#http
port = ${port}
host = ${host}
use_threadpool = True
threadpool_kill_thread_limit = 10800
[app:main]
paste.app_factory = galaxy.web.buildapp:app_factory
"""

TOOL_CONF_TEMPLATE = """<toolbox>
  <tool file="data_source/upload.xml" />
  ${tool_definition}
</toolbox>
"""

SHED_TOOL_CONF_TEMPLATE = """<?xml version="1.0"?>
<toolbox tool_path="${shed_tool_path}">
</toolbox>
"""

SHED_DATA_MANAGER_CONF_TEMPLATE = """<?xml version="1.0"?>
<data_managers>
</data_managers>
"""

EMPTY_JOB_METRICS_TEMPLATE = """<?xml version="1.0"?>
<job_metrics>
</job_metrics>
"""

TOOL_SHEDS_CONF = """<tool_sheds>
  <tool_shed name="Target Shed" url="${shed_target_url}" />
</tool_sheds>
"""

JOB_CONFIG_LOCAL = """<job_conf>
    <plugins>
        <plugin id="planemo_runner" type="runner" load="galaxy.jobs.runners.local:LocalJobRunner" workers="4"/>
    </plugins>
    <handlers>
        <handler id="main"/>
    </handlers>
    <destinations default="planemo_dest">
        <destination id="planemo_dest" runner="planemo_runner">
            <param id="require_container">${require_container}</param>
            <param id="docker_enabled">${docker_enable}</param>
            <param id="docker_sudo">${docker_sudo}</param>
            <param id="docker_sudo_cmd">${docker_sudo_cmd}</param>
            <param id="docker_cmd">${docker_cmd}</param>
            ${docker_host_param}
        </destination>
        <destination id="upload_dest" runner="planemo_runner">
            <param id="docker_enable">false</param>
        </destination>
    </destinations>
    <tools>
        <tool id="upload1" destination="upload_dest" />
    </tools>
</job_conf>
"""

LOGGING_TEMPLATE = """
## Configure Python loggers.
[loggers]
keys = root,paste,displayapperrors,galaxydeps,galaxymasterapikey,galaxy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_paste]
level = WARN
handlers = console
qualname = paste
propagate = 0

[logger_galaxydeps]
level = DEBUG
handlers = console
qualname = galaxy.tools.deps
propagate = 0

[logger_galaxymasterapikey]
level = WARN
handlers = console
qualname = galaxy.web.framework.webapp
propagate = 0

[logger_displayapperrors]
level = ERROR
handlers =
qualname = galaxy.datatypes.display_applications.application
propagate = 0

[logger_galaxy]
level = ${log_level}
handlers = console
qualname = galaxy
propagate = 0

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = DEBUG
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
"""

EMPTY_TOOL_CONF_TEMPLATE = """<toolbox></toolbox>"""

DEFAULT_GALAXY_BRANCH = "master"
DEFAULT_GALAXY_SOURCE = "https://github.com/galaxyproject/galaxy"
CWL_GALAXY_SOURCE = "https://github.com/common-workflow-language/galaxy"

# TODO: Mac-y curl variant of this.
DOWNLOAD_GALAXY = (
    "wget -q https://codeload.github.com/galaxyproject/galaxy/tar.gz/"
)

DOWNLOADS_URL = ("https://raw.githubusercontent.com/"
                 "jmchilton/galaxy-downloads/master/")
DOWNLOADABLE_MIGRATION_VERSIONS = [141, 127, 120, 117]
MIGRATION_PER_VERSION = {
    "dev": 145,
    "master": 142,
    "18.09": 142,
    "18.05": 141,
    "18.01": 140,
    "17.09": 135,
    "17.05": 134,
    "17.01": 133,
}
OLDEST_SUPPORTED_VERSION = 127

DATABASE_LOCATION_TEMPLATE = "sqlite:///%s?isolation_level=IMMEDIATE"

COMMAND_STARTUP_COMMAND = "./scripts/common_startup.sh ${COMMON_STARTUP_ARGS}"

CLEANUP_IGNORE_ERRORS = True
DEFAULT_GALAXY_BRAND = 'Configured by Planemo'

@contextlib.contextmanager
def galaxy_config(ctx, runnables, **kwds):
    """Set up a ``GalaxyConfig`` in an auto-cleaned context."""
    c = local_galaxy_config
    if kwds.get("dockerize", False):
        c = docker_galaxy_config
    elif kwds.get("external", False):
        c = external_galaxy_config

    with c(ctx, runnables, **kwds) as config:
        yield config

def simple_docker_volume(path):
    path = os.path.abspath(path)
    return DockerVolume("%s:%s:rw" % (path, path))

@contextlib.contextmanager
def docker_galaxy_config(ctx, runnables, for_tests=False, **kwds):
    """Set up a ``GalaxyConfig`` for Docker container."""
    test_data_dir = _find_test_data(runnables, **kwds)

    with _config_directory(ctx, **kwds) as config_directory:
        def config_join(*args):
            return os.path.join(config_directory, *args)

        ensure_dependency_resolvers_conf_configured(ctx, kwds, os.path.join(config_directory, "resolvers_conf.xml"))
        _handle_job_metrics(config_directory, kwds)

        shed_tool_conf = "config/shed_tool_conf.xml"
        all_tool_paths = _all_tool_paths(runnables, **kwds)

        tool_directories = set([])  # Things to mount...
        for tool_path in all_tool_paths:
            directory = os.path.dirname(os.path.normpath(tool_path))
            if os.path.exists(directory):
                tool_directories.add(directory)

        # TODO: remap these.
        tool_volumes = []
        for tool_directory in tool_directories:
            volume = simple_docker_volume(tool_directory)
            tool_volumes.append(volume)

        empty_tool_conf = config_join("empty_tool_conf.xml")

        tool_conf = config_join("tool_conf.xml")

        shed_tool_path = kwds.get("shed_tool_path") or config_join("shed_tools")
        _ensure_directory(shed_tool_path)

        sheds_config_path = _configure_sheds_config_file(
            ctx, config_directory, **kwds
        )
        port = _get_port(kwds)
        properties = _shared_galaxy_properties(config_directory, kwds, for_tests=for_tests)
        _handle_container_resolution(ctx, kwds, properties)
        master_api_key = _get_master_api_key(kwds)

        template_args = dict(
            shed_tool_path=shed_tool_path,
            tool_conf=tool_conf,
        )
        tool_config_file = "%s,%s" % (tool_conf, shed_tool_conf)

        _write_tool_conf(ctx, all_tool_paths, tool_conf)
        write_file(empty_tool_conf, EMPTY_TOOL_CONF_TEMPLATE)

        properties.update(dict(
            tool_config_file=tool_config_file,
            tool_sheds_config_file=sheds_config_path,
            migrated_tools_config=empty_tool_conf,
        ))

        server_name = "planemo%d" % random.randint(0, 100000)

        # Value substitutions in Galaxy properties - for consistency with
        # non-Dockerized version.
        template_args = dict(
        )
        env = _build_env_for_galaxy(properties, template_args)
        env["NONUSE"] = "nodejs,proftp,reports"
        if ctx.verbose:
            env["GALAXY_LOGGING"] = "full"

        # TODO: setup FTP upload dir and disable FTP server in container.
        _build_test_env(properties, env)

        docker_target_kwds = docker_host_args(**kwds)
        volumes = tool_volumes + [simple_docker_volume(config_directory)]
        export_directory = kwds.get("export_directory", None)
        if export_directory is not None:
            volumes.append(DockerVolume("%s:/export:rw" % export_directory))

        # TODO: Allow this to real Docker volumes and allow multiple.
        extra_volume = kwds.get("docker_extra_volume")
        if extra_volume:
            volumes.append(simple_docker_volume(extra_volume))
        yield DockerGalaxyConfig(
            ctx,
            config_directory,
            env,
            test_data_dir,
            port,
            server_name,
            master_api_key,
            runnables,
            docker_target_kwds=docker_target_kwds,
            volumes=volumes,
            export_directory=export_directory,
            kwds=kwds,
        )

@contextlib.contextmanager
def local_galaxy_config(ctx, runnables, for_tests=False, **kwds):
    """Set up a ``GalaxyConfig`` in an auto-cleaned context."""
    test_data_dir = _find_test_data(runnables, **kwds)
    tool_data_table = _find_tool_data_table(
        runnables,
        test_data_dir=test_data_dir,
        **kwds
    )
    data_manager_config_paths = [r.data_manager_conf_path for r in runnables if r.data_manager_conf_path]
    galaxy_root = _find_galaxy_root(ctx, **kwds)
    install_galaxy = kwds.get("install_galaxy", False)
    if galaxy_root is not None:
        if os.path.isdir(galaxy_root) and not os.listdir(galaxy_root):
            os.rmdir(galaxy_root)
        if os.path.isdir(galaxy_root) and install_galaxy:
            raise Exception("%s is an existing non-empty directory, cannot install Galaxy again" % galaxy_root)

    # Duplicate block in docker variant above.
    if kwds.get("mulled_containers", False) and not kwds.get("docker", False):
        if ctx.get_option_source("docker") != OptionSource.cli:
            kwds["docker"] = True
        else:
            raise Exception("Specified no docker and mulled containers together.")

    with _config_directory(ctx, **kwds) as config_directory:
        def config_join(*args):
            return os.path.join(config_directory, *args)

        install_env = {}
        if kwds.get('galaxy_skip_client_build', True):
            install_env['GALAXY_SKIP_CLIENT_BUILD'] = '1'
        if galaxy_root is None:
            galaxy_root = config_join("galaxy-dev")
        if not os.path.isdir(galaxy_root):
            _build_eggs_cache(ctx, install_env, kwds)
            _install_galaxy(ctx, galaxy_root, install_env, kwds)

        if parse_version(kwds.get('galaxy_python_version') or DEFAULT_PYTHON_VERSION) >= parse_version('3'):
            # on python 3 we use gunicorn,
            # which requires 'main' as server name
            server_name = 'main'
        else:
            server_name = "planemo%d" % random.randint(0, 100000)
        # Once we don't have to support earlier than 18.01 - try putting these files
        # somewhere better than with Galaxy.
        log_file = "%s.log" % server_name
        pid_file = "%s.pid" % server_name
        ensure_dependency_resolvers_conf_configured(ctx, kwds, os.path.join(config_directory, "resolvers_conf.xml"))
        _handle_job_config_file(config_directory, server_name, kwds)
        _handle_job_metrics(config_directory, kwds)
        file_path = kwds.get("file_path") or config_join("files")
        _ensure_directory(file_path)

        tool_dependency_dir = kwds.get("tool_dependency_dir") or config_join("deps")
        _ensure_directory(tool_dependency_dir)

        shed_tool_conf = kwds.get("shed_tool_conf") or config_join("shed_tools_conf.xml")
        all_tool_paths = _all_tool_paths(runnables, **kwds)
        empty_tool_conf = config_join("empty_tool_conf.xml")

        tool_conf = config_join("tool_conf.xml")

        shed_data_manager_config_file = config_join("shed_data_manager_conf.xml")

        shed_tool_path = kwds.get("shed_tool_path") or config_join("shed_tools")
        _ensure_directory(shed_tool_path)

        sheds_config_path = _configure_sheds_config_file(
            ctx, config_directory, **kwds
        )

        database_location = config_join("galaxy.sqlite")
        master_api_key = _get_master_api_key(kwds)
        dependency_dir = os.path.join(config_directory, "deps")
        preseeded_database = attempt_database_preseed(
            ctx,
            galaxy_root,
            database_location,
            **kwds
        )
        _ensure_directory(shed_tool_path)
        port = _get_port(kwds)
        template_args = dict(
            port=port,
            host=kwds.get("host", "127.0.0.1"),
            server_name=server_name,
            temp_directory=config_directory,
            shed_tool_path=shed_tool_path,
            database_location=database_location,
            tool_conf=tool_conf,
            debug=kwds.get("debug", "true"),
            id_secret=kwds.get("id_secret", "test_secret"),
            log_level="DEBUG" if ctx.verbose else "INFO",
        )
        tool_config_file = "%s,%s" % (tool_conf, shed_tool_conf)
        # Setup both galaxy_email and older test user test@bx.psu.edu
        # as admins for command_line, etc...
        properties = _shared_galaxy_properties(config_directory, kwds, for_tests=for_tests)
        properties.update(dict(
            server_name="main",
            ftp_upload_dir_template="${ftp_upload_dir}",
            ftp_upload_purge="False",
            ftp_upload_dir=test_data_dir or os.path.abspath('.'),
            ftp_upload_site="Test Data",
            check_upload_content="False",
            tool_dependency_dir=dependency_dir,
            file_path=file_path,
            new_file_path="${temp_directory}/tmp",
            tool_config_file=tool_config_file,
            tool_sheds_config_file=sheds_config_path,
            manage_dependency_relationships="False",
            job_working_directory="${temp_directory}/job_working_directory",
            template_cache_path="${temp_directory}/compiled_templates",
            citation_cache_type="file",
            citation_cache_data_dir="${temp_directory}/citations/data",
            citation_cache_lock_dir="${temp_directory}/citations/lock",
            database_auto_migrate="True",
            enable_beta_tool_formats="True",
            id_secret="${id_secret}",
            log_level="${log_level}",
            debug="${debug}",
            watch_tools="auto",
            default_job_shell="/bin/bash",  # For conda dependency resolution
            tool_data_table_config_path=tool_data_table,
            data_manager_config_file=",".join(data_manager_config_paths) or None,  # without 'or None' may raise IOError in galaxy (see #946)
            integrated_tool_panel_config=("${temp_directory}/"
                                          "integrated_tool_panel_conf.xml"),
            migrated_tools_config=empty_tool_conf,
            test_data_dir=test_data_dir,  # TODO: make gx respect this
            shed_data_manager_config_file=shed_data_manager_config_file,
        ))
        _handle_container_resolution(ctx, kwds, properties)
        write_file(config_join("logging.ini"), _sub(LOGGING_TEMPLATE, template_args))
        if not for_tests:
            properties["database_connection"] = _database_connection(database_location, **kwds)

        _handle_kwd_overrides(properties, kwds)

        # TODO: consider following property
        # watch_tool = False
        # datatypes_config_file = config/datatypes_conf.xml
        # welcome_url = /static/welcome.html
        # logo_url = /
        # sanitize_all_html = True
        # serve_xss_vulnerable_mimetypes = False
        # track_jobs_in_database = None
        # outputs_to_working_directory = False
        # retry_job_output_collection = 0

        env = _build_env_for_galaxy(properties, template_args)
        env.update(install_env)
        _build_test_env(properties, env)
        env['GALAXY_TEST_SHED_TOOL_CONF'] = shed_tool_conf

        # No need to download twice - would GALAXY_TEST_DATABASE_CONNECTION
        # work?
        if preseeded_database:
            env["GALAXY_TEST_DB_TEMPLATE"] = os.path.abspath(database_location)
        env["GALAXY_TEST_UPLOAD_ASYNC"] = "false"
        env["GALAXY_TEST_LOGGING_CONFIG"] = config_join("logging.ini")
        env["GALAXY_DEVELOPMENT_ENVIRONMENT"] = "1"
        # Following are needed in 18.01 to prevent Galaxy from changing log and pid.
        # https://github.com/galaxyproject/planemo/issues/788
        env["GALAXY_LOG"] = log_file
        env["GALAXY_PID"] = pid_file
        web_config = _sub(WEB_SERVER_CONFIG_TEMPLATE, template_args)
        write_file(config_join("galaxy.ini"), web_config)
        _write_tool_conf(ctx, all_tool_paths, tool_conf)
        write_file(empty_tool_conf, EMPTY_TOOL_CONF_TEMPLATE)

        shed_tool_conf_contents = _sub(SHED_TOOL_CONF_TEMPLATE, template_args)
        # Write a new shed_tool_conf.xml if needed.
        write_file(shed_tool_conf, shed_tool_conf_contents, force=False)

        write_file(shed_data_manager_config_file, SHED_DATA_MANAGER_CONF_TEMPLATE)

        yield LocalGalaxyConfig(
            ctx,
            config_directory,
            env,
            test_data_dir,
            port,
            server_name,
            master_api_key,
            runnables,
            galaxy_root,
            kwds,
        )

def _all_tool_paths(runnables, **kwds):
    tool_paths = [r.path for r in runnables if r.has_tools and not r.data_manager_conf_path]
    all_tool_paths = list(tool_paths) + list(kwds.get("extra_tools", []))
    for runnable in runnables:
        if runnable.type.name == "galaxy_workflow":
            tool_ids = find_tool_ids(runnable.path)
            for tool_id in tool_ids:
                if tool_id in DISTRO_TOOLS_ID_TO_PATH:
                    all_tool_paths.append(DISTRO_TOOLS_ID_TO_PATH[tool_id])

    return all_tool_paths

def _shared_galaxy_properties(config_directory, kwds, for_tests):
    """Setup properties useful for local and Docker Galaxy instances.

    Most things related to paths, etc... are very different between Galaxy
    modalities and many taken care of internally to the container in that mode.
    But this method sets up API stuff, tool, and job stuff that can be shared.
    """
    master_api_key = _get_master_api_key(kwds)
    user_email = _user_email(kwds)
    properties = {
        'master_api_key': master_api_key,
        'admin_users': "%s,test@bx.psu.edu" % user_email,
        'expose_dataset_path': "True",
        'cleanup_job': 'never',
        'collect_outputs_from': "job_working_directory",
        'allow_path_paste': "True",
        'check_migrate_tools': "False",
        'use_cached_dependency_manager': str(kwds.get("conda_auto_install", False)),
        'brand': kwds.get("galaxy_brand", DEFAULT_GALAXY_BRAND),
        'strict_cwl_validation': str(not kwds.get("non_strict_cwl", False)),
    }
    if kwds.get("galaxy_single_user", True):
        properties['single_user'] = user_email

    if for_tests:
        empty_dir = os.path.join(config_directory, "empty")
        _ensure_directory(empty_dir)
        properties["tour_config_dir"] = empty_dir
        properties["interactive_environment_plugins_directory"] = empty_dir
        properties["visualization_plugins_directory"] = empty_dir
    return properties

@contextlib.contextmanager
def external_galaxy_config(ctx, runnables, for_tests=False, **kwds):
    yield BaseGalaxyConfig(
        ctx=ctx,
        galaxy_url=kwds.get("galaxy_url", None),
        master_api_key=_get_master_api_key(kwds),
        user_api_key=kwds.get("galaxy_user_key", None),
        runnables=runnables,
        kwds=kwds
    )

def _get_master_api_key(kwds):
    master_api_key = kwds.get("galaxy_admin_key") or DEFAULT_MASTER_API_KEY
    return master_api_key

def _get_port(kwds):
    port = int(kwds.get("port", 9090))
    return port

def _user_email(kwds):
    user_email = kwds.get("galaxy_email")
    return user_email

@contextlib.contextmanager
def _config_directory(ctx, **kwds):
    config_directory = kwds.get("config_directory", None)
    created_config_directory = False
    if not config_directory:
        created_config_directory = True
        config_directory = os.path.realpath(mkdtemp())
        ctx.vlog("Created directory for Galaxy configuration [%s]" % config_directory)
    try:
        yield config_directory
    finally:
        cleanup = not kwds.get("no_cleanup", False)
        if created_config_directory and cleanup:
            shutil.rmtree(config_directory)

@add_metaclass(abc.ABCMeta)
class GalaxyInterface(object):
    """Abstraction around a Galaxy instance.

    Description of a Galaxy instance and how to interact with it - this could
    potentially be a remote, already running instance or an instance Planemo manages
    to execute some task(s).
    """

    @abc.abstractproperty
    def gi(self):
        """Return an admin bioblend Galaxy instance for API interactions."""

    @abc.abstractproperty
    def user_gi(self):
        """Return a user-backed bioblend Galaxy instance for API interactions."""

    @abc.abstractmethod
    def install_repo(self, *args, **kwds):
        """Install specified tool shed repository."""

    @abc.abstractproperty
    def tool_shed_client(self):
        """Return a admin bioblend tool shed client."""

    @abc.abstractmethod
    def wait_for_all_installed(self):
        """Wait for all queued up repositories installs to complete."""

    @abc.abstractmethod
    def install_workflows(self):
        """Install all workflows configured with these planemo arguments."""

    @abc.abstractmethod
    def workflow_id(self, path):
        """Get installed workflow API ID for input path."""

@add_metaclass(abc.ABCMeta)
class GalaxyConfig(GalaxyInterface):
    """Specialization of GalaxyInterface for Galaxy instances Planemo manages itself.

    This assumes more than an API connection is available - Planemo needs to be able to
    start and stop the Galaxy instance, recover logs, etc... There are currently two
    implementations - a locally executed Galaxy and one running inside a Docker containe
    """

    @abc.abstractproperty
    def kill(self):
        """Stop the running instance."""

    @abc.abstractmethod
    def startup_command(self, ctx, **kwds):
        """Return a shell command used to startup this instance.

        Among other common planmo kwds, this should respect the
        ``daemon`` keyword.
        """

    @abc.abstractproperty
    def log_contents(self):
        """Retrieve text of log for running Galaxy instance."""

    @abc.abstractmethod
    def cleanup(self):
        """Cleanup allocated resources to run this instance."""

    @abc.abstractproperty
    def use_path_paste(self):
        """Use path paste to upload data."""

class BaseGalaxyConfig(GalaxyInterface):

    def __init__(
        self,
        ctx,
        galaxy_url,
        master_api_key,
        user_api_key,
        runnables,
        kwds,
    ):
        self._ctx = ctx
        self.galaxy_url = galaxy_url
        self.master_api_key = master_api_key
        self._user_api_key = user_api_key
        self.runnables = runnables
        self._kwds = kwds
        self._workflow_ids = {}

    @property
    def gi(self):
        assert self.galaxy_url
        return gi(url=self.galaxy_url, key=self.master_api_key)

    @property
    def user_gi(self):
        user_api_key = self.user_api_key
        assert user_api_key
        return self._gi_for_key(user_api_key)

    @property
    def user_api_key(self):
        # TODO: thread-safe
        if self._user_api_key is None:
            # TODO: respect --galaxy_email - seems like a real bug
            self._user_api_key = user_api_key(self.gi)

        return self._user_api_key

    def _gi_for_key(self, key):
        assert self.galaxy_url
        return gi(url=self.galaxy_url, key=key)

    def install_repo(self, *args, **kwds):
        self.tool_shed_client.install_repository_revision(
            *args, **kwds
        )

    @property
    def tool_shed_client(self):
        return self.gi.toolShed

    def wait_for_all_installed(self):
        def status_ready(repo):
            status = repo["status"]
            if status in ["Installing", "New"]:
                return None
            if status == "Installed":
                return True
            raise Exception("Error installing repo status is %s" % status)

        def ready():
            repos = self.tool_shed_client.get_repositories()
            ready = all(map(status_ready, repos))
            return ready or None

        wait_on(ready, "galaxy tool installation", timeout=60 * 60 * 1)

    def install_workflows(self):
        for runnable in self.runnables:
            if runnable.type.name in ["galaxy_workflow", "cwl_workflow"]:
                self._install_workflow(runnable)

    def _install_workflow(self, runnable):
        if self._kwds["shed_install"]:
            install_shed_repos(runnable, self.gi, self._kwds.get("ignore_dependency_problems", False))

        default_from_path = self._kwds.get("workflows_from_path", False)
        # TODO: Allow serialization so this doesn't need to assume a
        # shared filesystem with Galaxy server.
        from_path = default_from_path or (runnable.type.name == "cwl_workflow")
        workflow = import_workflow(
            runnable.path, admin_gi=self.gi, user_gi=self.user_gi, from_path=from_path
        )
        self._workflow_ids[runnable.path] = workflow["id"]

    def workflow_id(self, path):
        return self._workflow_ids[path]

    @property
    def use_path_paste(self):
        option = self._kwds.get("paste_test_data_paths")
        if option is None:
            return self.default_use_path_paste
        else:
            return option

    @property
    def default_use_path_paste(self):
        return False

class BaseManagedGalaxyConfig(BaseGalaxyConfig):

    def __init__(
        self,
        ctx,
        config_directory,
        env,
        test_data_dir,
        port,
        server_name,
        master_api_key,
        runnables,
        kwds,
    ):
        galaxy_url = "http://localhost:%d" % port
        super(BaseManagedGalaxyConfig, self).__init__(
            ctx=ctx,
            galaxy_url=galaxy_url,
            master_api_key=master_api_key,
            user_api_key=None,
            runnables=runnables,
            kwds=kwds
        )
        self.config_directory = config_directory
        self.env = env
        self.test_data_dir = test_data_dir
        self.port = port
        self.server_name = server_name

class DockerGalaxyConfig(BaseManagedGalaxyConfig):
    """A :class:`GalaxyConfig` description of a Dockerized Galaxy instance."""

    def __init__(
        self,
        ctx,
        config_directory,
        env,
        test_data_dir,
        port,
        server_name,
        master_api_key,
        runnables,
        docker_target_kwds,
        volumes,
        export_directory,
        kwds,
    ):
        super(DockerGalaxyConfig, self).__init__(
            ctx,
            config_directory,
            env,
            test_data_dir,
            port,
            server_name,
            master_api_key,
            runnables,
            kwds,
        )
        self.docker_target_kwds = docker_target_kwds
        self.volumes = volumes
        self.export_directory = export_directory

    def kill(self):
        """Kill planemo container..."""
        kill_command = docker_util.kill_command(
            self.server_name,
            **self.docker_target_kwds
        )
        return shell(kill_command)

    def startup_command(self, ctx, **kwds):
        """Return a shell command used to startup this instance.

        Among other common planmo kwds, this should respect the
        ``daemon`` keyword.
        """
        daemon = kwds.get("daemon", False)
        daemon_str = "" if not daemon else " -d"
        docker_run_extras = "-p %s:80%s" % (self.port, daemon_str)
        env_directives = ["%s='%s'" % item for item in self.env.items()]
        image = kwds.get("docker_galaxy_image", "bgruening/galaxy-stable")
        run_command = docker_util.build_docker_run_command(
            "", image,
            interactive=False,
            env_directives=env_directives,
            working_directory=None,
            name=self.server_name,
            run_extra_arguments=docker_run_extras,
            set_user=False,
            volumes=self.volumes,
            **self.docker_target_kwds
        )
        chmod_command = [
            "chmod",
            "-R",
            "o+rwx",
            self.config_directory,
        ]
        if self.export_directory:
            chmod_command.append(self.export_directory)

        return shell_join(
            argv_to_str(chmod_command),
            run_command,
        )

    @property
    def log_contents(self):
        logs_command = docker_util.logs_command(
            self.server_name,
            **self.docker_target_kwds
        )
        output, _ = communicate(
            logs_command
        )
        return output

    def cleanup(self):
        shutil.rmtree(self.config_directory, CLEANUP_IGNORE_ERRORS)

class LocalGalaxyConfig(BaseManagedGalaxyConfig):
    """A local, non-containerized implementation of :class:`GalaxyConfig`."""

    def __init__(
        self,
        ctx,
        config_directory,
        env,
        test_data_dir,
        port,
        server_name,
        master_api_key,
        runnables,
        galaxy_root,
        kwds,
    ):
        super(LocalGalaxyConfig, self).__init__(
            ctx,
            config_directory,
            env,
            test_data_dir,
            port,
            server_name,
            master_api_key,
            runnables,
            kwds,
        )
        self.galaxy_root = galaxy_root

    def kill(self):
        kill_pid_file(self.pid_file)

    def startup_command(self, ctx, **kwds):
        """Return a shell command used to startup this instance.

        Among other common planemo kwds, this should respect the
        ``daemon`` keyword.
        """
        daemon = kwds.get("daemon", False)
        # TODO: Allow running dockerized Galaxy here instead.
        setup_venv_command = setup_venv(ctx, kwds)
        run_script = "%s $COMMON_STARTUP_ARGS" % shlex_quote(os.path.join(self.galaxy_root, "run.sh"))
        if daemon:
            run_script += " --daemon"
            self.env["GALAXY_RUN_ALL"] = "1"
        else:
            run_script += " --server-name %s" % shlex_quote(self.server_name)
        server_ini = os.path.join(self.config_directory, "galaxy.ini")
        self.env["GALAXY_CONFIG_FILE"] = server_ini
        if parse_version(kwds.get('galaxy_python_version') or DEFAULT_PYTHON_VERSION) >= parse_version('3'):
            # We need to start under gunicorn
            self.env['APP_WEBSERVER'] = 'gunicorn'
            self.env['GUNICORN_CMD_ARGS'] = "--bind={host}:{port} --name={server_name}".format(
                host=kwds.get('host', '127.0.0.1'),
                port=kwds['port'],
                server_name=self.server_name,
            )
        cd_to_galaxy_command = ['cd', self.galaxy_root]
        return shell_join(
            cd_to_galaxy_command,
            setup_venv_command,
            setup_common_startup_args(),
            run_script,
        )

    @property
    def log_file(self):
        """Log file used when planemo serves this Galaxy instance."""
        file_name = "%s.log" % self.server_name
        return os.path.join(self.galaxy_root, file_name)

    @property
    def pid_file(self):
        pid_file_name = "%s.pid" % self.server_name
        return os.path.join(self.galaxy_root, pid_file_name)

    @property
    def log_contents(self):
        if not os.path.exists(self.log_file):
            return ""
        with open(self.log_file, "r") as f:
            return f.read()

    def cleanup(self):
        shutil.rmtree(self.config_directory, CLEANUP_IGNORE_ERRORS)

    @property
    def default_use_path_paste(self):
        # If Planemo started a local, native Galaxy instance assume files URLs can be
        # pasted.
        return True

def _database_connection(database_location, **kwds):
    default_connection = DATABASE_LOCATION_TEMPLATE % database_location
    database_connection = kwds.get("database_connection") or default_connection
    return database_connection

def attempt_database_preseed(
    ctx, effective_galaxy_root, database_location, **kwds
):
    """If database location is unset, attempt to seed the database."""
    if os.path.exists(database_location):
        # Can't seed an existing database.
        return False

    if not _database_connection(database_location, **kwds).startswith("sqlite"):
        # Not going to use an sqlite database, don't preseed.
        return False

    preseeded_database = True
    galaxy_sqlite_database = kwds.get("galaxy_database_seed", None)
    galaxy_branch = kwds.get("galaxy_branch", None)
    try:
        _download_database_template(
            ctx,
            effective_galaxy_root,
            database_location,
            galaxy_sqlite_database=galaxy_sqlite_database,
            galaxy_branch=galaxy_branch
        )
    except Exception as e:
        print(e)
        # No network access - just roll forward from null.
        preseeded_database = False
    return preseeded_database

def _download_database_template(
    ctx,
    galaxy_root,
    database_location,
    galaxy_sqlite_database=None,
    galaxy_branch=None,
):

    if galaxy_sqlite_database is not None:
        shutil.copyfile(galaxy_sqlite_database, database_location)
        return True

    download_migration = None
    newest_migration = _newest_migration_version(galaxy_root, galaxy_branch)
    for migration in DOWNLOADABLE_MIGRATION_VERSIONS:
        if newest_migration >= migration:
            download_migration = migration
            break

    if download_migration:
        download_name = "db_gx_rev_0%d.sqlite" % download_migration
        download_url = DOWNLOADS_URL + download_name
        ctx.cache_download(download_url, database_location)
        return True
    else:
        return False

def _newest_migration_version(galaxy_root, galaxy_branch):
    versions_dir = galaxy_root and os.path.join(galaxy_root, "lib/galaxy/model/migrate/versions")
    if versions_dir and os.path.exists(versions_dir):
        version = max(map(_file_name_to_migration_version, os.listdir(versions_dir)))
    elif galaxy_branch:
        for branch in MIGRATION_PER_VERSION:
            if branch in galaxy_branch:
                version = MIGRATION_PER_VERSION[branch]
    else:
        version = OLDEST_SUPPORTED_VERSION
    return version

def _file_name_to_migration_version(name):
    try:
        return int(name[0:4])
    except ValueError:
        return -1

def _find_galaxy_root(ctx, **kwds):
    root_prop = "galaxy_root"
    cwl = kwds.get("cwl", False)
    if cwl:
        root_prop = "cwl_galaxy_root"
    galaxy_root = kwds.get(root_prop, None)
    if galaxy_root:
        return galaxy_root
    else:
        par_dir = os.getcwd()
        while True:
            run = os.path.join(par_dir, "run.sh")
            config = os.path.join(par_dir, "config")
            if os.path.isfile(run) and os.path.isdir(config):
                return par_dir
            new_par_dir = os.path.dirname(par_dir)
            if new_par_dir == par_dir:
                break
            par_dir = new_par_dir
    return None

def _find_test_data(runnables, **kwds):
    test_data_search_path = "."
    runnables = [r for r in runnables if r.has_tools]
    if len(runnables) > 0:
        test_data_search_path = runnables[0].test_data_search_path

    # Find test data directory associated with path.
    test_data = kwds.get("test_data", None)
    if test_data:
        return os.path.abspath(test_data)
    else:
        test_data = _search_tool_path_for(test_data_search_path, "test-data")
        if test_data:
            return test_data
    warn(NO_TEST_DATA_MESSAGE)
    return None

def _find_tool_data_table(runnables, test_data_dir, **kwds):
    tool_data_search_path = "."
    runnables = [r for r in runnables if r.has_tools]
    if len(runnables) > 0:
        tool_data_search_path = runnables[0].tool_data_search_path

    tool_data_table = kwds.get("tool_data_table", None)
    if tool_data_table:
        return os.path.abspath(tool_data_table)
    else:
        extra_paths = [test_data_dir] if test_data_dir else []
        return _search_tool_path_for(
            tool_data_search_path,
            "tool_data_table_conf.xml.test",
            extra_paths,
        ) or _search_tool_path_for(  # if all else fails just use sample
            tool_data_search_path,
            "tool_data_table_conf.xml.sample"
        )

def _search_tool_path_for(path, target, extra_paths=[]):
    """Check for presence of a target in different artifact directories."""
    if not os.path.isdir(path):
        tool_dir = os.path.dirname(path)
    else:
        tool_dir = path
    possible_dirs = [tool_dir, "."] + extra_paths
    for possible_dir in possible_dirs:
        possible_path = os.path.join(possible_dir, target)
        if os.path.exists(possible_path):
            return os.path.abspath(possible_path)
    return None

def _configure_sheds_config_file(ctx, config_directory, **kwds):
    if "shed_target" not in kwds:
        kwds = kwds.copy()
        kwds["shed_target"] = "toolshed"
    shed_target_url = tool_shed_url(ctx, **kwds)
    contents = _sub(TOOL_SHEDS_CONF, {"shed_target_url": shed_target_url})
    tool_sheds_conf = os.path.join(config_directory, "tool_sheds_conf.xml")
    write_file(tool_sheds_conf, contents)
    return tool_sheds_conf

def _tool_conf_entry_for(tool_paths):
    tool_definitions = ""
    for tool_path in tool_paths:
        if os.path.isdir(tool_path):
            tool_definitions += '''<tool_dir dir="%s" />''' % tool_path
        else:
            tool_definitions += '''<tool file="%s" />''' % tool_path
    return tool_definitions

def _install_galaxy(ctx, galaxy_root, env, kwds):
    if not kwds.get("no_cache_galaxy", False):
        _install_galaxy_via_git(ctx, galaxy_root, env, kwds)
    else:
        _install_galaxy_via_download(ctx, galaxy_root, env, kwds)

def _install_galaxy_via_download(ctx, galaxy_root, env, kwds):
    tmpdir = mkdtemp()
    branch = _galaxy_branch(kwds)
    command = DOWNLOAD_GALAXY + "%s -O - | tar -C '%s' -xvz | tail && mv '%s' '%s'" % \
        (branch, tmpdir, os.path.join(tmpdir, 'galaxy-' + branch), galaxy_root)
    _install_with_command(ctx, command, galaxy_root, env, kwds)

def _install_galaxy_via_git(ctx, galaxy_root, env, kwds):
    gx_repo = _ensure_galaxy_repository_available(ctx, kwds)
    branch = _galaxy_branch(kwds)
    command = git.command_clone(ctx, gx_repo, galaxy_root, branch=branch)
    _install_with_command(ctx, command, galaxy_root, env, kwds)

def _build_eggs_cache(ctx, env, kwds):
    if kwds.get("no_cache_galaxy", False):
        return None
    workspace = ctx.workspace
    eggs_path = os.path.join(workspace, "gx_eggs")
    if not os.path.exists(eggs_path):
        os.makedirs(eggs_path)
    env["GALAXY_EGGS_PATH"] = eggs_path

def _galaxy_branch(kwds):
    branch = kwds.get("galaxy_branch", None)
    if branch is None:
        cwl = kwds.get("cwl", False)
        branch = "cwl-1.0" if cwl else None
    if branch is None:
        branch = DEFAULT_GALAXY_BRANCH

    return branch

def _galaxy_source(kwds):
    source = kwds.get("galaxy_source", None)
    if source is None:
        cwl = kwds.get("cwl", False)
        source = CWL_GALAXY_SOURCE if cwl else None
    if source is None:
        source = DEFAULT_GALAXY_SOURCE

    return source

def _install_with_command(ctx, command, galaxy_root, env, kwds):
    setup_venv_command = setup_venv(ctx, kwds)
    env['__PYVENV_LAUNCHER__'] = ''
    install_cmd = shell_join(
        command,
        ['cd', galaxy_root],
        setup_venv_command,
        setup_common_startup_args(),
        COMMAND_STARTUP_COMMAND,
    )
    shell(install_cmd, env=env)

def _ensure_galaxy_repository_available(ctx, kwds):
    workspace = ctx.workspace
    cwl = kwds.get("cwl", False)
    galaxy_source = kwds.get('galaxy_source')
    if galaxy_source and galaxy_source != DEFAULT_GALAXY_SOURCE:
        sanitized_repo_name = "".join(c if c.isalnum() else '_' for c in kwds['galaxy_source']).rstrip()[:255]
        gx_repo = os.path.join(workspace, "gx_repo_%s" % sanitized_repo_name)
    else:
        gx_repo = os.path.join(workspace, "gx_repo")
    if cwl:
        gx_repo += "_cwl"
    if os.path.exists(gx_repo):
        # Convert the git repository from bare to mirror, if needed
        shell(['git', '--git-dir', gx_repo, 'config', 'remote.origin.fetch', '+refs/*:refs/*'])
        shell(['git', '--git-dir', gx_repo, 'config', 'remote.origin.mirror', 'true'])
        # Attempt remote update - but don't fail if not interweb, etc...
        shell("git --git-dir %s remote update >/dev/null 2>&1" % gx_repo)
    else:
        remote_repo = _galaxy_source(kwds)
        command = git.command_clone(ctx, remote_repo, gx_repo, mirror=True)
        shell(command)
    return gx_repo

def _build_env_for_galaxy(properties, template_args):
    env = {}
    for key, value in iteritems(properties):
        if value is not None:  # Do not override None with empty string
            var = "GALAXY_CONFIG_OVERRIDE_%s" % key.upper()
            value = _sub(value, template_args)
            env[var] = value
    return env

def _build_test_env(properties, env):
    # Keeping these environment variables around for a little while but
    # many are probably not needed as of the following commit.
    # https://bitbucket.org/galaxy/galaxy-central/commits/d7dd1f9
    test_property_variants = {
        'GALAXY_TEST_JOB_CONFIG_FILE': 'job_config_file',
        'GALAXY_TEST_MIGRATED_TOOL_CONF': 'migrated_tools_config',
        'GALAXY_TEST_TOOL_CONF': 'tool_config_file',
        'GALAXY_TEST_FILE_DIR': 'test_data_dir',
        'GALAXY_TOOL_DEPENDENCY_DIR': 'tool_dependency_dir',
        # Next line would be required for tool shed tests.
        # 'GALAXY_TEST_TOOL_DEPENDENCY_DIR': 'tool_dependency_dir',
    }
    for test_key, gx_key in test_property_variants.items():
        value = properties.get(gx_key, None)
        if value is not None:
            env[test_key] = value

def _handle_job_config_file(config_directory, server_name, kwds):
    job_config_file = kwds.get("job_config_file", None)
    if not job_config_file:
        template_str = JOB_CONFIG_LOCAL
        job_config_file = os.path.join(
            config_directory,
            "job_conf.xml",
        )
        docker_enable = str(kwds.get("docker", False))
        docker_host = str(kwds.get("docker_host", docker_util.DEFAULT_HOST))
        docker_host_param = ""
        if docker_host:
            docker_host_param = """<param id="docker_host">%s</param>""" % docker_host

        conf_contents = Template(template_str).safe_substitute({
            "server_name": server_name,
            "docker_enable": docker_enable,
            "require_container": "false",
            "docker_sudo": str(kwds.get("docker_sudo", False)),
            "docker_sudo_cmd": str(kwds.get("docker_sudo_cmd", docker_util.DEFAULT_SUDO_COMMAND)),
            "docker_cmd": str(kwds.get("docker_cmd", docker_util.DEFAULT_DOCKER_COMMAND)),
            "docker_host": docker_host_param,
        })
        write_file(job_config_file, conf_contents)
    kwds["job_config_file"] = job_config_file

def _write_tool_conf(ctx, tool_paths, tool_conf_path):
    tool_definition = _tool_conf_entry_for(tool_paths)
    tool_conf_template_kwds = dict(tool_definition=tool_definition)
    tool_conf_contents = _sub(TOOL_CONF_TEMPLATE, tool_conf_template_kwds)
    write_file(tool_conf_path, tool_conf_contents)
    ctx.vlog(
        "Writing tool_conf to path %s with contents [%s]",
        tool_conf_path,
        tool_conf_contents,
    )

def _handle_container_resolution(ctx, kwds, galaxy_properties):
    if kwds.get("mulled_containers", False):
        galaxy_properties["enable_beta_mulled_containers"] = "True"
        involucro_context = build_involucro_context(ctx, **kwds)
        galaxy_properties["involucro_auto_init"] = "False"  # Use planemo's
        galaxy_properties["involucro_path"] = involucro_context.involucro_bin

def _handle_job_metrics(config_directory, kwds):
    metrics_conf = os.path.join(config_directory, "job_metrics_conf.xml")
    open(metrics_conf, "w").write(EMPTY_JOB_METRICS_TEMPLATE)
    kwds["job_metrics_config_file"] = metrics_conf

def _handle_kwd_overrides(properties, kwds):
    kwds_gx_properties = [
        'job_config_file',
        'job_metrics_config_file',
        'dependency_resolvers_config_file',
    ]
    for prop in kwds_gx_properties:
        val = kwds.get(prop, None)
        if val:
            properties[prop] = val

def _sub(template, args):
    if template is None:
        return ''
    return Template(template).safe_substitute(args)

def _ensure_directory(path):
    if path is not None and not os.path.exists(path):
        os.makedirs(path)

__all__ = (
    "attempt_database_preseed",
    "DATABASE_LOCATION_TEMPLATE",
    "galaxy_config",
)


#http://hotsapi.net/api/v1/replays?game_type=QuickMatch&player={playerName} ? {#battleTag}
#http://hotsapi.net/api/v1/replays/{replay_id}
#saebu_no LhoeynJY saebu.no.mysql

import requests
import json

def callAPI():

#    url = "http://hotsapi.net/api/v1/replays?game_type=QuickMatch&player=TommyGun%232872"
    url = "http://hotsapi.net/api/v1/replays?start_date=2017-10-01&game_type=QuickMatch&player=TommyGun%232872"
    resp = requests.get(url)

    gameDict = resp.json()
    antGames = len(gameDict)
    print (antGames)
    data = {}
    data['games'] = []
#    f = open('TGhotsData.txt', 'w')
    for gameNr in range(0,3):
        game = gameDict[gameNr-1]
        gameId = game["id"]
        print (game["id"], gameNr)

        getGameData(gameId ,data)
    with open('tg.json', 'w') as outfile:
        json.dump(data, outfile)

def getGameData(gameId ,data):
    url = "http://hotsapi.net/api/v1/replays/"+str(gameId)

    print (url)
    resp = requests.get(url)
    gameDict = resp.json()
    players = gameDict["players"]
    gameDate = gameDict["game_date"]
    for player in players:
        if (player["battletag"] == "TommyGun#2872"):
            #playerData = (player["battletag"], player["hero"], player["winner"],
            #player["score"]["hero_damage"], player["score"]["siege_damage"],
            #player["score"]["time_spent_dead"], player["score"]["experience_contribution"],
            #gameDate)
            #f.write(str(playerData)+"\n")
            data['games'].append({
                'name' : player["battletag"],
                'hero' : player["hero"],
                'winner' : player["winner"],
                'hero_dmg' : player["score"]["hero_damage"],
                'siege_dmg' : player["score"]["siege_damage"],
                'time_dead' : player["score"]["time_spent_dead"],
                'exp_cont' : player["score"]["experience_contribution"],
                'game_date' : gameDate})

callAPI()


import datetime, time
from mpi4py import MPI

class configuration():

    def __init__(self):
        # Topology settings
        self.nodesPerRank = 8
        self.maxNodesPerRank = 10

        # Time settings
        self.simTime = 1000
        self.timeSpeed = 100
        self.syncTime = 5

        # Main chain settings
        self.minerSlot = 16
        self.nbPeers = 4
        self.minerRatio = 90
        self.maxBroadcast = 8
        self.maxReceive = 32

        # Beacon chain settings
        self.validatorRatio = 80
        self.epochLength = 16
        self.slotDuration = 6

        # Shards settings
        self.nbShards = 2
        self.committeeSize = 4

        # MPI settings
        self.maxOutQueue = 16

        # Post-processing setting
        self.verbosity = 1
        self.shortReport = True
        self.resultsDir = "data"
        now = datetime.datetime.now()
        simID = now.strftime("%Y-%m-%d_%H-%M-%S")
        SID = [simID] * MPI.COMM_WORLD.Get_size()
        simID = MPI.COMM_WORLD.scatter(SID, root=0)
        self.simID = simID
        self.simDir = self.resultsDir+"/"+self.simID

    def verify(self):
        if self.nodesPerRank > self.maxNodesPerRank:
            print("WARNING : nodes per rank higher than max nodes per rank")


# ps1. accurate comprehension
# ps1.1. analysis
# n*n인 체스판에 서로 공격불가하게 n개의 퀸을 배치하는 경우의 수

# ps1.2. drawing pattern, exception
# 우선 n이 4이고, '행'만 생각해보자
# 1개의 행에 2개의 이상의 퀸이 배치되면 안된다. 즉 4개의 퀸은 우선 행마다 1개씩 배치되야한다
# 여기까지만 생각하면 1행마다 퀸은 4가지의 선택지가 있고, 총 4행이므로, 4^4의 경우의 수가 존재한다.

# 문제 단순화 관점에서, 열이 겹치는 상황을 제쳐두고,
# 이제는 브루트 포스하게 퀸을 배치해보되, 다른 퀸의 공격영역에 들어간 경우 백트래킹을 한다.

# ps2. utilizing and integration of computer algorithms

# ps3. Impl

def promising(i,col):
    k=1
    flag=True

    while(k<i and flag):
        if(col[i] == col[k] or abs(col[i]-col[k]) == (i-k) ):
            flag=False
        k +=1
    return flag

def n_queens(i,col):
    global cnt_validcase
    n=len(col) - 1

    if(promising(i,col)):
        if(i==n):
            print(col[1:n+1])
            cnt_validcase+=1
        else:
            for j in range(1, n+1):
                col[i+1] =j
                n_queens(i+1,col)

if __name__=="__main__":
    n=int(input())
    global cnt_validcase
    cnt_validcase=0

    col = ['*']+[0]*n

    n_queens(0,col)

    print(cnt_validcase)


import argparse
import json

def parse_har(har_file):
    with open(har_file) as f:
        har_dict = json.load(f)

    for entry in har_dict['log']['entries']:
        url = entry['request']['url']
        if '/search_results/' in url:
            yield url

def main(har_file):
    for url in parse_har(har_file):
        print(url)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--file", default="doctolib.har")
    args = parser.parse_args()
    main(args.file)


from django.db import models
from hesab.models import User
class jamsabad(models.Model):
    jam = models.IntegerField(blank=True,null=True)
    user = models.ForeignKey(User,on_delete=models.CASCADE)

    class Meta:
        verbose_name = "جمع"
        verbose_name_plural = "جمع سبد ها"
    def __str__(self):
        return self.user.username


import math
import random

import numpy as np
import matplotlib.pyplot as plt

def random_point(a, b):
    return np.random.uniform(a, b)

def left_riemann_sum(a, b, N):
    dx = (b-a)/N
    x_l = np.linspace(a, b-dx,N)
    return np.sum(f(x_l)*dx)

def middle_riemann_sum(a, b, N):
    dx = (b-a)/N
    x_m = np.linspace(dx/2, b-dx/2, N)
    return np.sum(f(x_m)*dx)

def right_riemann_sum(a, b, N):
    dx = (b-a)/N
    x_r = np.linspace(dx, b, N)
    return np.sum(f(x_r)*dx)

def random_riemann_sum(a, b, N):
    dx = (b-a)/N
    x_rands = []
    y_rands = []
    for i in range(N):
        x_rands.append(random_point(a+i*dx, dx*(i+1)))
        y_rands.append(f(x_rands[i]))
    summ = 0
    for i in range(N):
        summ += y_rands[i]*dx

    return x_rands, y_rands, summ

def f(x):
    return pow(math.exp(1), -x)

a = 0
b = 1
N = int(input("число промежутков: "))
n = 10

x = np.linspace(a, b, N+1)
y = f(x)
X = np.linspace(a, b, n*N+1)
Y = f(X)

dx = (b - a) / N

#left points
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(X, Y, 'r')
x_left = x[:-1]
y_left = y[:-1]
plt.plot(x_left, y_left, 'r', markersize=10)
plt.bar(x_left, y_left, dx, alpha=0.3, align='edge', edgecolor='white')
plt.title("left Riemann sum, N={}".format(N))
# plt.show()
plt.savefig("figure-l")

#right points
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(X, Y, 'b')
x_right = x[1:]
y_right = y[1:]
plt.plot(x_right, y_right, 'b', markersize=10)
plt.bar(x_right, y_right, dx, alpha=0.3, align='edge', edgecolor='white')
plt.title("right Riemann sum, N={}".format(N))
# plt.show()
plt.savefig("figure-r")

#middle points
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(X, Y, 'm')
x_middle = (x[1:]+x[:-1])/2
y_middle = (y[1:]+y[:-1])/2
plt.plot(x_middle, y_middle, 'm', markersize=10)
plt.bar(x_middle, y_middle, dx, alpha=0.3, align='edge', edgecolor='white')
plt.title("middle Riemann sum, N={}".format(N))
# plt.show()
plt.savefig("figure-m")

#random points
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(X, Y, 'cyan')
x_random, y_random, summ = random_riemann_sum(a, b, N)
plt.plot(x_right, y_right, 'cyan', markersize=10)
plt.bar(x_random, y_random, dx, alpha=0.3, align='edge', edgecolor='white')
plt.title("random Riemann sum, N={}".format(N))
# plt.show()
plt.savefig("figure-random")

right = right_riemann_sum(a, b, N)
middle = middle_riemann_sum(a, b, N)
left = left_riemann_sum(a, b, N)
rand = summ

print("Правые точки: " + str(right))
print("Средние точки: " + str(middle))
print("Левые точки: " + str(left))
print("Случайные точки: " + str(rand))
print("Вычисление по формуле Ньютона-Лейбница: 1-1/e ~ 0.6321205588")


'''
Neural Style Transfer   -   Drawing images in the style of another image
'''

import IPython.display as display
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import PIL.Image
import time
import os
from datetime import datetime

import tensorflow as tf

global start_process, epochs, steps_per_epoch, image_to_use, style_to_use, generated_dir, photos_dir, paintings_dir, photos_dict, paintings_dict

# Defines the content and style variables, the functions that are used and the training procedure
def initialize():
    global start_process, epochs, steps_per_epoch, image_to_use, style_to_use, generated_dir, photos_dir, paintings_dir, photos_dict, paintings_dict
    start_process = datetime.now()
    mpl.rcParams['figure.figsize'] = (10, 10)
    mpl.rcParams['axes.grid'] = False
    epochs = 5      # Final output quality increases with epoch count (up to max ~20)
    steps_per_epoch = 50

    root_dir = os.path.dirname(os.path.abspath(__file__))  # os.getcwd()
    photos_dir = root_dir + "/images/content/"
    paintings_dir = root_dir + "/images/styles/"
    generated_dir = root_dir + "/images/generated/"
    image_extension = ".jpg"

    # Setting up Images and Styles
    photos_dict = {}
    paintings_dict = {}
    for filename in os.listdir(photos_dir):
        if filename.endswith(image_extension):
            photos_dict[filename[:-4]] = photos_dir + filename

    for filename in os.listdir(paintings_dir):
        if filename.endswith(image_extension):
            paintings_dict[filename[:-4]] = paintings_dir + filename

    print(photos_dict)
    print(paintings_dict)

'''
Functions to visualise the input
'''

# Converts Tensor Object to Image
def tensor_to_image(tensor):
    tensor = tensor * 255
    tensor = np.array(tensor, dtype=np.uint8)
    if np.ndim(tensor) > 3:
        assert tensor.shape[0] == 1
        tensor = tensor[0]
    return PIL.Image.fromarray(tensor)

# Loads the Image
def load_img(path_to_img):
    max_dim = 512
    img = tf.io.read_file(path_to_img)
    img = tf.image.decode_image(img, channels=3)
    img = tf.image.convert_image_dtype(img, tf.float32)
    shape = tf.cast(tf.shape(img)[:-1], tf.float32)
    long_dim = max(shape)
    scale = max_dim / long_dim
    new_shape = tf.cast(shape * scale, tf.int32)
    img = tf.image.resize(img, new_shape)
    img = img[tf.newaxis, :]
    return img

# Displays the Image
def show_image(image, title=None):
    if len(image.shape) > 3:
        image = tf.squeeze(image, axis=0)

    plt.imshow(image)
    if title:
        plt.title(title)

'''
Runs The ML Program Start To Finish
'''

def training(content, style):
    print("From NST", '{}-{}.jpg'.format(content, style))
    print("Training...")

    # Configuring Modules
    print("Creating TF image objects...")
    content_path = photos_dict[content]
    style_path = paintings_dict[style]
    content_image = load_img(content_path)
    style_image = load_img(style_path)

    # Define Content and Style Representations
    print("Defining photo and painting input representations for the model...")
    x = tf.keras.applications.vgg19.preprocess_input(content_image*255)
    x = tf.image.resize(x, (224, 224))
    vgg = tf.keras.applications.VGG19(include_top=True, weights='imagenet')
    prediction_probabilities = vgg(x)

    content_layers = ['block5_conv2']
    style_layers = ['block1_conv1',
                    'block2_conv1',
                    'block3_conv1',
                    'block4_conv1',
                    'block5_conv1']
    num_content_layers = len(content_layers)
    num_style_layers = len(style_layers)

    extractor = StyleContentModel(style_layers, content_layers)

    # Run Gradient Descent
    style_targets = extractor(style_image)['style']
    content_targets = extractor(content_image)['content']
    image = tf.Variable(content_image)      # This is the image object that gets passed to numerous functions

    opt = tf.optimizers.Adam(learning_rate=0.02, beta_1=0.99, epsilon=1e-1)

    style_weight = 1e-2
    content_weight = 1e4
    total_variation_weight = 30

    input_values = [style_targets, style_weight, num_style_layers,
                    content_targets, content_weight, num_content_layers,
                    extractor, opt]

    '''
    Perform a Long Optimisation
    '''
    print("Performing Long Optimisation...")
    start = time.time()
    step = 0
    for n in range(epochs):
        for m in range(steps_per_epoch):
            step += 1
            train_step(image, input_values, total_variation_weight)
            print(".", end='')
        display.clear_output(wait=True)
        # display.display(tensor_to_image(image))
        print("Train step: {}".format(step))
    end = time.time()
    print("Total time: {:.1f}".format(end - start))
    print("Finished Optimisation!")

    # Total Variational Loss
    tf.image.total_variation(image).numpy()

    '''
    Rerun Optimisation
    '''
    print("Rerunning Optimisation With New Variational Loss Calculated...")
    image = tf.Variable(content_image)     # This is the redefined image object
    start = time.time()
    step = 0
    for n in range(epochs):
        for m in range(steps_per_epoch):
            step += 1
            train_step(image, input_values, total_variation_weight)
            print(".", end='')
        display.clear_output(wait=True)
        # display.display(tensor_to_image(image))
        print("Train step: {}".format(step))
    end = time.time()
    print("Total time: {:.1f}".format(end - start))
    print("Finished rerunning optimisation!")
    save_results(image, content, style)
    gen_path = generated_dir + '/detail/' + '{}-{}.jpg'.format(content, style)
    return gen_path, image

'''
Extracting Model Features Functions
'''

def vgg_layers(layer_names):
    vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
    vgg.trainable = False

    outputs = [vgg.get_layer(name).output for name in layer_names]

    model = tf.keras.Model([vgg.input], outputs)
    return model

# Calculate Style and Extracting Style and Content
def gram_matrix(input_tensor):
    result = tf.linalg.einsum('bijc,bijd->bcd', input_tensor, input_tensor)
    input_shape = tf.shape(input_tensor)
    num_locations = tf.cast(input_shape[1]*input_shape[2], tf.float32)
    return result/num_locations

def clip_0_1(image):
    return tf.clip_by_value(image, clip_value_min=0.0, clip_value_max=1.0)

def style_content_loss(outputs, input_values):
    style_targets, style_weight, num_style_layers, content_targets, content_weight, num_content_layers, extractor, opt = input_values
    style_outputs = outputs['style']
    content_outputs = outputs['content']
    style_loss = tf.add_n([tf.reduce_mean((style_outputs[name] - style_targets[name]) ** 2)
                           for name in style_outputs.keys()])
    style_loss *= style_weight / num_style_layers

    content_loss = tf.add_n([tf.reduce_mean((content_outputs[name] - content_targets[name]) ** 2)
                             for name in content_outputs.keys()])
    content_loss *= content_weight / num_content_layers
    loss = style_loss + content_loss
    return loss

'''
Training Function
'''

def train_step(image, input_values, total_variation_weight):
    extractor, opt = input_values[-2], input_values[-1]
    with tf.GradientTape() as tape:
        outputs = extractor(image)
        loss = style_content_loss(outputs, input_values)
        loss += total_variation_weight*tf.image.total_variation(image)

    grad = tape.gradient(loss, image)
    opt.apply_gradients([(grad, image)])
    image.assign(clip_0_1(image))

'''
Total Variation Loss Functions
'''

def high_pass_x_y(image):
    x_var = image[:, :, 1:, :] - image[:, :, :-1, :]
    y_var = image[:, 1:, :, :] - image[:, :-1, :, :]
    return x_var, y_var

def total_variation_loss(image):
    x_deltas, y_deltas = high_pass_x_y(image)
    return tf.reduce_sum(tf.abs(x_deltas)) + tf.reduce_sum(tf.abs(y_deltas))

'''
Saving Results Function
'''

def save_results(image, content, style):
    print("Saving Results...")
    file_name = '{}-{}.jpg'.format(content, style)
    print("Saving {}...".format(file_name))
    tensor_to_image(image).save(generated_dir + file_name)
    print("Finished Saving Stylised File")
    print("Finished ML Process In ", datetime.now() - start_process)

# Builds a model that returns the style and content tensors
class StyleContentModel(tf.keras.models.Model):
    def __init__(self, style_layers, content_layers):
        super(StyleContentModel, self).__init__()
        self.vgg = vgg_layers(style_layers + content_layers)
        self.style_layers = style_layers
        self.content_layers = content_layers
        self.num_style_layers = len(style_layers)
        self.vgg.trainable = False

    def call(self, inputs):
        # Expects float input in [0,1]
        inputs = inputs*255.0
        preprocessed_input = tf.keras.applications.vgg19.preprocess_input(inputs)
        outputs = self.vgg(preprocessed_input)
        style_outputs, content_outputs = (outputs[:self.num_style_layers],
                                          outputs[self.num_style_layers:])

        style_outputs = [gram_matrix(style_output)
                         for style_output in style_outputs]

        content_dict = {content_name: value
                        for content_name, value
                        in zip(self.content_layers, content_outputs)}

        style_dict = {style_name: value
                      for style_name, value
                      in zip(self.style_layers, style_outputs)}

        return {'content': content_dict, 'style': style_dict}

'''
Simple Command To Run The Whole Thing
'''

def run(content, style):
    initialize()
    gen_path, image = training(content, style)
    return gen_path, image

def run_all():
    initialize()
    for style in paintings_dict.keys():
        for content in photos_dict.keys():
            if not check_exists(content, style):
                training(content, style)
            else:
                print(content + '-' + style + '.jpg' + ' already has been generated!')

def check_exists(content, style):
    filename = content + '-' + style + '.jpg'
    for generated in os.listdir(generated_dir):
        if filename == generated:
            return True        # Has already been generated
    return False    #  Has not already been generated


import pandas as pd
import matplotlib.pyplot as plt

aurora = pd.read_csv("tmp/rl_test/rl_test_log0.csv")
cubic = pd.read_csv("tmp_cubic/cubic_test_log0.csv")

fig, axes = plt.subplots(2, 2, figsize=(12, 8))

axes[0, 0].plot(aurora['timestamp'],
                aurora['throughput'] * 1500 * 8 / 1000000, c='C0',
                label='{} recv rate, avg {:.3f}mbps'.format(
                    "aurora", aurora['throughput'].mean() * 1500 * 8 / 1000000))
axes[0, 0].plot(aurora['timestamp'],
                aurora['send_throughput'] * 1500 * 8 / 1000000, ls='--',
                c='C0', label='{} send rate, avg {:.3f}mbps'.format(
                    "aurora", aurora['send_throughput'].mean() * 1500 * 8 / 1000000))

axes[0, 0].plot(cubic['timestamp'],
                cubic['throughput'] * 1500 * 8 / 1000000, c='C1',
                label='{} recv rate, avg {:.3f}mbps'.format(
                    "cubic", cubic['throughput'].mean() * 1500 * 8 / 1000000))
axes[0, 0].plot(cubic['timestamp'],
                cubic['send_throughput'] * 1500 * 8 / 1000000, ls='--',
                c='C1',
                label='{} send rate, avg {:.3f}mbps'.format(
                    "cubic", cubic['send_throughput'].mean() * 1500 * 8 / 1000000))
axes[0, 0].plot(cubic['timestamp'], cubic['link0_bw'] * 1500 * 8 / 1000000,
                c='C2', label='bw, avg {}mbps'.format(cubic['link0_bw'].mean() * 1500 * 8 / 1000000))
axes[0, 0].set_title("Simulator, Rate")
axes[0, 0].set_xlabel("Time(s)")
axes[0, 0].set_ylabel("mbps")
axes[0, 0].legend()

axes[0, 1].scatter(aurora['timestamp'], aurora['latency'] * 100, c='C0',
        label='Aurora, RTT, avg {:.2f}ms'.format(aurora['latency'].mean() * 1000))
axes[0, 1].scatter(cubic['timestamp'], cubic['latency'] * 100, c='C1',
        label='Cubic, RTT, avg {:.2f}ms'.format(cubic['latency'].mean() * 1000))
axes[0, 1].set_title("Simulator(Link RTT=100ms), RTT")
axes[0, 1].set_xlabel("Time(s)")
axes[0, 1].set_ylabel("ms")
axes[0, 1].legend()

plt.tight_layout()
plt.show()


### Test scales with easy OCR
def detect_Number(List_with_Images):
  # Input Images, best case closely cropped to image
  # Output List of Numbers and letters

  import easyocr
  reader = easyocr.Reader(['ch_sim','en']) # this needs to run only once to load the model into memory

  Results = []
  for x in List_with_Images:
    try:
      result = reader.readtext(x, detail = 0) ## Predict
      Results.append(result)
    except:
      Results.append(0)

def CropImage(Images):
  # takes as list of images
  # outputs a closley cropped list of images
  # based on CvCanny structure

  counter = 0
  List_of_crops = []
  for x in l:
    try:
      img = x

      Can = cv2.Canny(img,300,400, L2gradient = False)
      # The whiskers can confuse the process we have which is we already crop the far sides

      height, width = Can.shape
      Cropped_Can = Can[:, 10:width-10]
      Cropped_img_temp = img[:, 10:width-10]

      row_scan = np.sum(Cropped_Can, axis = 0)/255 ### Scans the image in rows
      coloumn_scan = np.sum(Cropped_Can, axis = 1)/255 ### Scans it in coloumns

      # Get the standard value for the scan
      reduced_column = coloumn_scan - coloumn_scan[0]

      # Find the index of the first number greater than 3
      # This means we exclude all artifacts caused by jittery lines
      # smaller than 2 + 3 (5) Pixels
      first_index_y = np.argmax(reduced_column > 3)

      # Find the index of the last number greater than 3
      last_index_y = np.max(np.argwhere(reduced_column > 3))

      reduced_row = row_scan - row_scan[0]

      # Find the index of the first number greater than 3
      # This means we exclude all artifacts caused by jittery lines
      # smaller than 2 + 3 (5) Pixels
      first_index_x = np.argmax(reduced_row > 3)

      # Find the index of the last number greater than 3
      last_index_x = np.max(np.argwhere(reduced_row > 3))

      if first_index_y-5 < 0:
        first_index_y = 5
      if first_index_x-5 < 0:
        first_index_x = 5

      print(counter, first_index_x-5,last_index_x+5,first_index_y-5,last_index_y+5, img.shape)
      img_crop = Cropped_img_temp[first_index_y-5:last_index_y+5,first_index_x-5:last_index_x+5]
      counter += 1

      ## Very small and pixelated values have to be resized
      ## If the image is less than 100 pixels in any dimension
      ## We resize it with Inter cubic
      ## We resize according to the smaller axis

      height, width = img_crop.shape
      print(img_crop.shape)
      ## Check size
      if (height < 100) or (width < 100):
        # Calculate scaling factors
        scale_height = 100/height
        scale_width = 100/width

        # Choose the bigger factor
        if scale_height > scale_width:
          scaling_factor = scale_height
        else:
          scaling_factor = scale_width
        print(scaling_factor,height*scaling_factor)
        # Scale up
        img_crop = cv2.resize(img_crop, (int(width*scaling_factor),int(height*scaling_factor)), interpolation = cv2.INTER_CUBIC)

      List_of_crops.append(img_crop)
    except:
      List_of_crops.append(img)
      counter += 1

  return Krops

def Sortlist(String_of_numbers):
  ### Drop entrys except numbers can cope with ['2','mm'] or ['2mm'] or ['2'], [].
  ### Input list of lists.
  ### Output float values found in string
  import re

  numbers_only = [float(re.findall(r'\d+(?:\.\d+)?', entry[0])[0]) if entry and entry[0] and re.findall(r'\d+(?:\.\d+)?', entry[0]) else 0 for entry in String_of_numbers]

  return numbers_only


"""
https://leetcode.com/problems/course-schedule/

this is just cycle detection in directed graph
we can just use the direction to mean depends on
[0,1] means 0 depends on 1...

if you say its a cycle detection, where to start the traversal?
topological sort just scan every node and see if it is scanned?

yeah, so when the checked courses reaches n.. it can
"""

from collections import defaultdict, deque
from typing import List

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        adjSets  = defaultdict(set)
        for course, pre in prerequisites:
            adjSets[course].add(pre)

        visited = set()
        def dfs(course, path):
            if course in visited:
                return True
            if course in path:
                return False

            for pre in adjSets[course]:
                if not dfs(pre, path.union({course})):
                    return False

            visited.add(course)
            return True

        for course in range(numCourses):
            if not dfs(course, set()):
                return False

        return True

"""
Runtime: 156 ms, faster than 36.92% of Python3 online submissions for Course Schedule.
Memory Usage: 102.5 MB, less than 5.14% of Python3 online submissions for Course Schedule.

okay.. it was all by memeory
I of course can use =1 to mean in path, =2 to mean processed
"""

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        adjSets = defaultdict(set)
        for course, pre in prerequisites:
            adjSets[course].add(pre)

        # 0: non-visited
        # 1: in path
        # 2: visited
        status = [0] * numCourses

        def dfs(course):
            if status[course] == 2:
                return True
            if status[course] == 1:
                return False

            # add to path
            status[course] = 1
            for pre in adjSets[course]:
                if not dfs(pre):
                    return False

            status[course] = 2
            return True

        for course in range(numCourses):
            if not dfs(course):
                return False

        return True

"""
Runtime: 108 ms, faster than 57.26% of Python3 online submissions for Course Schedule.
Memory Usage: 17.6 MB, less than 9.56% of Python3 online submissions for Course Schedule

let me also do this in bfs way
"""

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        adjSets = defaultdict(set)
        incomingLinks = [0] * numCourses
        for course, pre in prerequisites:
            adjSets[course].add(pre)
            incomingLinks[pre] += 1

        bfsQ = deque()
        for c in range(numCourses):
            if incomingLinks[c] == 0:
                bfsQ.append(c)

        sorted = []
        while bfsQ:
            l = len(bfsQ)
            while l:
                c = bfsQ.popleft()
                sorted.append(c)

                for pre in adjSets[c]:
                    incomingLinks[pre] -= 1
                    if incomingLinks[pre] == 0:
                        bfsQ.append(pre)
                l-=1
        return len(sorted) == numCourses

"""
Runtime: 96 ms, faster than 91.65% of Python3 online submissions for Course Schedule.
Memory Usage: 15.4 MB, less than 87.29% of Python3 online submissions for Course Schedule.
"""

if __name__ == '__main__':
    s = Solution()
    print(s.canFinish(numCourses=2, prerequisites=[[1, 0]]))
    print(s.canFinish(numCourses=2, prerequisites=[[1, 0], [0, 1]]))
    print(s.canFinish(numCourses=6, prerequisites=[[1, 0], [0, 2], [3,4], [5,3]]))


# Projeto Lava rápido - fase 1

# Mostrar serviços do lava-rápido
print('Tipo de serviços')
serviços = ['ducha simples' , 'ducha completa' , 'lavagem de motor', 'polimento', 'ducha com cera', 'ducha completa com cera']
for item in serviços:
    print(item)

# Valores dos Serviços
ducha_simples = 15
ducha_completa = 30
lavagem_de_motor = 80 # sem ducha
polimento = 350
ducha_com_cera = 20
ducha_completa_com_cera = 35

print('Valores dos Serviços')
# Preços = 'Ducha simples' ducha_simples, 'Ducha completa' ducha_completa, 'Lavagem de Motor' lavagem_de_motor, 'Polimento' polimento, 'Ducha com cera'ducha_com_cera, 'Ducha completa com cera' ducha_completa_com_cera
# for item in Preços:
#     print(item)

# Faturamento médio do Lava rápido
faturamento = 5000
Produtos = 700
Funcionários = 1500
Despesas=(Produtos + Funcionários)
Lucros=(faturamento - Produtos - Funcionários)
Porcentagem_de_Lucro=(Lucros / Despesas * 100)

print('Débitos', Despesas)
print('Lucros', Lucros)
print('Porcentagem de Lucro', Porcentagem_de_Lucro)


from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler
import IDL
import Comands
# Restrict to a particular path.
class RequestHandler(SimpleXMLRPCRequestHandler):
    rpc_paths = ('/RPC2',)

# Create server
with SimpleXMLRPCServer(('localhost', 8080),
                        requestHandler=RequestHandler) as server:
    server.register_introspection_functions()

    # Register an instance; all the methods of the instance are
    # published as XML-RPC methods

    #if automatico
        #pasar el reporte en el idl -> crear una lista de comandos -> ejecutar onecmd(list_cmd[i])
    #if manual

    server.register_instance(IDL)
    server.register_instance(Comands)
    # Run the server's main loop
    #server.serve_forever()
    if __name__ == "__main__":
        try:
            print("Sending...")
            server.serve_forever()
        except KeyboardInterrupt:
            print("Exiting")


from classes.menu import *
from classes.rangos import *
from classes.obtención import *
from classes.reporte import *
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation

global pause
pause = False
global y_data
y_data = []

def onclick(event):
    global pause
    print("pausa")
    pause=True

fig, ax=plt.subplots()
fig.canvas.mpl_connect("button_press_event", onclick)

def update_data(i):
    if not pause:

        dato=int(puerto.readline().decode().strip())
        print(dato)
        y_data.append(dato)
        ax.clear()
        ax.plot(y_data)
        time.sleep(1)

def main():
    menu = Menu("Escuela de Ingeniería")
    op=menu.ver()

    if op == "1":
        menu2=Captura()
        op2=menu2.ver()
        if op2=="1":
            obtencion()
            main()
        elif op2=="2":
            ani= animation.FuncAnimation(fig,update_data)
            plt.show()
            save_dato(y_data)
            main()

    elif op =="2":
        eq=definir_rangos()
        eq.save_parametros()
        main()

    elif op=="3":
        menu2=Reportes()
        op2=menu2.ver()
        if op2==1:
            grafica()
            main()
        elif op2==2:
            valor_max()
            main()
        elif op2==3:
            valor_min()
            main()
        elif op2==4:
            prom_temp()
            main()

    elif op=="4":
        exit()
    else:
            print("Opción inválida")
            main()

if __name__=='__main__':
    main()


#fazer programa de progressao aritmetica com primeiro termo e a razão

print('GERADOR DE PA')
termo = int(input('Digite o primeiro termo: '))#inicio
razao = int(input('Digite a razão de PA: '))#salto

contador = 0
limite = 11
acumulador = 0
acrescimo = 10

while acrescimo != 0:
    while contador < limite:
        if contador < limite - 1:
            print('{} ->'.format(termo), end=' ')
            termo += razao
        else:

            print('{} ->'.format(termo), end=' ')

            # limite do while receber ele mais acrescimo para mostrar mais termos
            limite += acrescimo
            # termo recebe ele mais razao para pular de termo em termo
            termo += razao
            # acumulador faz a contagem de termos mostrados no programa
            acumulador = limite + acrescimo
    contador += 1

#variavel acrescimo para receber quantos termos a mais vão ser mostrados
acrescimo = int(input('\nQuer mostrar mais quantos termos: '))
print('Foram mostrados {} termos '.format(acumulador))
print('PAUSA')


#!/usr/bin/env python
import os, sys
import struct
import template
from nds.fmt import *
from nds.files import *

allowed_games = ["diamond", "platinum", "heartgold", "black", "black2"]
EXT = "php"
DATA_DIR = "local/data/"
STATIC_DIR = "static/"
FORMAT_SUBDIR = "formats/"
genindex = False
games = []

args = sys.argv[1:]
while args:
    a = args.pop(0)
    if a == "--help":
        print("""Usage: %s [Options] [Game1 [Game2 [...]]]
If game is left blank, all games will be processed.

Options:
--gen-index         Generate index files.
--ext <extension>   Use <extension> for newly created files.
--help              Show this help, then exit.

Valid Games:
%s
"""%(sys.argv[0], ", ".join(allowed_games)))
        exit()
    if a == "--gen-index":
        genindex = True
        continue
    if a == "--ext":
        EXT = args.pop(0)
        continue
    if a in allowed_games:
        games.append(a)
if not games:
    games = allowed_games
FEXT = "."+EXT

struct_name = {"B": "UInt8", "H":"UInt16", "I":"UInt32"}

fs = getFSHTML(FEXT)

for game in games:
    if not os.path.exists(STATIC_DIR+game):
        os.mkdir(STATIC_DIR+game)
    if not os.path.exists(STATIC_DIR+game+"/formats"):
        os.mkdir(STATIC_DIR+game+"/formats")
    if genindex:
        template.idxfile(STATIC_DIR+game+"/index"+FEXT, "w", "Pokemon "+game.title()).close()
        template.idxfile(STATIC_DIR+game+"/formats/index"+FEXT, "w", "Pokemon "+game.title()+" Formats").close()

def writefmt(ofile, fmt, datafmt):
    ofs = 0
    padding = 0
    i = 0
    fmt = list(fmt)
    while fmt:
        padding = 0
        while fmt[0] in ('X', 'x'):
            fmt = fmt[1:]
            if not fmt:
                break
            padding += 1
        if padding:
            ofile.write("
%d	%d	[padding]
\n"%(ofs, padding))
            ofs += padding
        if not fmt:
            break
        ofile.write("
%d	%d	%s
\n"%(ofs, struct.calcsize(fmt[0]), datafmt[i]))
        ofs += struct.calcsize(fmt[0])
        fmt = fmt[1:]
        i += 1

if __name__ == "__main__":
    import genbaseevo, genenc, genevo, genexprate, genmoves, genpokedex, gentrdata, gentxt, gensearch
    import gennarc, gennclr
    import genfilelist


#Get data for Hurricane Michael (2018)
from tropycal import tracks
basin = tracks.TrackDataset()
storm = basin.get_storm(('michael',2018))

#Get all recon data for this storm
storm.recon.get_vdms()
#Save pickle file of VDM data (list of dictionaries)
storm.recon.vdms.to_pickle(f'{storm.name}{storm.year}_vdms.pickle')

storm.recon.get_dropsondes()
#Save pickle file of Dropsonde data (list of dictionaries)
storm.recon.dropsondes.to_pickle(f'{storm.name}{storm.year}_dropsondes.pickle')

storm.recon.get_hdobs()
#Save pickle file of HDOB data (Pandas dataframe)
storm.recon.hdobs.to_pickle(f'{storm.name}{storm.year}_hdobs.pickle')

storm.recon.get_vdms(f'{storm.name}{storm.year}_vdms.pickle')
storm.recon.get_dropsondes(f'{storm.name}{storm.year}_dropsondes.pickle')
storm.recon.get_hdobs(f'{storm.name}{storm.year}_hdobs.pickle')


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

import math
import sys
from typing import Dict

import maths.lib as mlib
from maths.parser import *
from util.log import Logger
from util.math import *

DEBUG = False

class Evaluator:
    def __init__(self, strict=False):
        self.frames = [{}]
        self.arguments = None
        self.beautified = None
        self.node_tree = None

        for name, item in mlib.__dict__.items():
            if isinstance(item, types.ModuleType):
                for member_name, member in item.__dict__.items():
                    if callable(member):  # if function
                        doc_func = mlib.find_function(member_name)

                        if doc_func:
                            member.doc_spec = doc_func

                        self.frames[0][member_name] = member
                    elif member_name.startswith("c_"):  # if constant
                        self.frames[0][member_name[2:]] = member

        for alias, func in mlib.docs.ext_aliases:
            self.frames[0][alias] = self.frames[0][func]

        self.log = Logger("Eval")
        self.strict_typing = strict

    def enter_frame(self, value: Dict[str, Any] = None):
        """Pushes the a new frame / the specified frame to the stack.

        value -- Frame (optional)"""
        self.frames.append(value or {})

    def exit_frame(self):
        """Pops the last frame from the stack."""
        return self.frames.pop()

    def set_variable(self, variable: str, value: Any, local=False):
        """Sets the value of the specified variable.

        variable -- Variable name
        value -- Variable value
        local -- If true, forces the creation of a new variable in the current frame. Otherwise, sets the value in the nearest frame containing the variable."""
        if not local:
            for frame in reversed(self.frames):
                if variable in frame:
                    frame[variable] = value
                    return

        self.frames[-1][variable] = value

    def get_variable(self, variable: str) -> Optional[Any]:
        """Returns the value of the specified variable.

        variable -- Variable name"""
        for frame in reversed(self.frames):
            if variable in frame:
                return frame[variable]

        self.log.error(translate("Evaluator", "Cannot find variable or function {name}").format(name=variable))
        return None

    def evaluate(self, expr: str) -> Optional[Any]:
        """Evaluates the specified expression.
        If an error occurs during the parsing, the result will be None.
        If an error occurs during the evaluation, the result will be undefined."""
        parser = Parser(expr)
        parser.log = self.log
        node = None

        try:
            node = parser.parse()
        except:
            if DEBUG:
                raise
            self.log.error(translate("Evaluator", "Parser: ") + str(sys.exc_info()[1]))

        self.beautified = parser.beautify()

        if not node:
            return None

        return self.evaluate_parsed(node)

    def evaluate_parsed(self, node: nodes.AstNode):
        """Evaluates the specified root node.

        node -- Node to be evaluated"""
        self.node_tree = node
        self.beautified = self.node_tree.code()

        result = None

        try:
            result = self.eval_node(self.node_tree)
        except:
            if DEBUG:
                raise
            self.log.error(str(sys.exc_info()[1]))

        return result

    def eval_node(self, node: nodes.AstNode):
        """Evaluates the specified node.
        Basically just a wrapper for eval_node_real that handles all the IEEE754 floating point rounding fuckery."""
        value = self.eval_node_real(node)

        if value is not None and is_num(value) and not isinstance(value, bool):
            if isinstance(value, complex):
                # if real, convert to float directly
                if is_real(value):
                    value = value.real

            # only convert to int if it fits well
            if is_int(value) and 1 <= abs(value) <= 1e15:
                value = int(round(value))

            # if zero, use zero directly
            if is_zero(value):
                value = 0
            else:
                if not (type(value) == int and value != int(float(value))):
                    value = close_round(value, 12)

        return value

    def call_lambda(self, node: nodes.LambdaNode, *args):
        """Calls the specified lambda function.

        node -- Function node
        args -- Argument list"""
        args = list(args)

        if len(args) != len(node.args):
            self.log.error(
                translate("Evaluator", "Argument count mismatch (expected {exp}, got {act})").format(exp=len(node.args),
                                                                                act=len(args)))
            return None

        frame = {node.args[idx]: arg for idx, arg in enumerate(args)}

        self.enter_frame(frame)

        result = self.eval_node(node.expr)

        if callable(result):
            if not hasattr(result, "frames"):
                result.frames = []

            result.frames.append(frame.copy())

        # pop arguments after use
        self.exit_frame()

        return result

    def eval_node_real(self, node: nodes.AstNode):
        """Evaluates the specified node.

        node -- Node to be evaluated"""
        if isinstance(node, nodes.ListNode):
            return [self.eval_node(x) for x in node.value]

        if isinstance(node, (nodes.NumberNode, nodes.StringNode)):
            return node.value

        if isinstance(node, nodes.IdentifierNode):
            return self.get_variable(node.value)

        if isinstance(node, nodes.UnaryOpNode):
            return self.eval_unary(node)

        if isinstance(node, nodes.BinOpNode):
            return self.eval_binary(node)

        if isinstance(node, nodes.CallNode):
            return self.eval_call(node)

        if isinstance(node, nodes.ArrayAccessNode):
            return self.eval_array_access(node)

        if isinstance(node, nodes.LambdaNode):
            return self.eval_lambda(node)

        # if the object is not a node, it must be a remnant of an already-parsed value
        # return it directly
        if not isinstance(node, nodes.AstNode):
            return node

        # if it's an unknown descendant of AstNode
        # this should never happen, but we put a message just in case
        self.log.error(translate("Evaluator", "Unknown node type: {type}").format(type=type(node)))
        return None

    def eval_lambda(self, node: nodes.LambdaNode):
        """Evaluates the specified lambda function node."""
        return lambda *args: self.call_lambda(node, *list(args))

    def eval_array_access(self, node: nodes.ArrayAccessNode):
        """Evaluates the specified array access node."""
        array = self.eval_node(node.array)
        index = int(self.eval_node(node.index))

        if not isinstance(array, (list, str)):
            self.log.error(translate("Evaluator", "Array access target must be of array type"))
            return None

        if index < len(array):
            return array[index]
        else:
            self.log.error(translate("Evaluator", "Index '{idx}' too big for array").format(idx=index))
            return None

    def eval_call(self, node: nodes.CallNode):
        """Evaluates the specified function call node."""
        function = self.eval_node(node.func)

        if function is None:
            self.log.error(translate("Evaluator", "Callee is None"))
            return None

        if (len(node.args) == 1
                and isinstance(node.args[0], nodes.UnaryOpNode)
                and node.args[0].operator == "*"):
            # expand list of arguments
            arg_list = self.eval_node(node.args[0].value)

            if type(arg_list) != list:
                self.log.error(translate("Evaluator", "Only lists can be expanded"))
                return None

            args = arg_list
        else:
            args = [self.eval_node(x) for x in node.args]

        if hasattr(function, "doc_spec") and not hasattr(function, "listfunc"):
            arg_spec = function.doc_spec[1][1]
            num_opt = sum(1 for arg in arg_spec if len(arg) >= 4)

            if not (len(arg_spec) - num_opt <= len(args) <= len(arg_spec)):
                self.log.error(translate("Evaluator", "Argument count mismatch (expected {exp}, got {act})").format(
                    exp=len(arg_spec) - num_opt, act=len(args)))
                return None

            for idx, (arg, spec) in enumerate(zip(args, arg_spec)):
                if not check_type(arg, spec[1]):
                    self.log.error(
                        translate("Evaluator", "Type mismatch for argument #{idx} '{arg}' (expected {exp})").format(
                            idx=idx + 1, arg=spec[0], exp=spec[1]))
                    return None

        if hasattr(function, "frames"):
            for f in function.frames:
                self.enter_frame(f)

        result = function.__call__(*args)

        if hasattr(function, "frames"):
            for _ in function.frames:
                self.exit_frame()

        return result

    def eval_unary(self, node: nodes.UnaryOpNode):
        """Evaluates the specified unary operation node."""
        value = self.eval_node(node.value)
        value_type = ValueType.get_type(value)

        if node.operator == "+":
            return value

        if node.operator == "-" and (is_num(value) and (not self.strict_typing or not is_bool(value))):
            return -value

        if node.operator == "-" and value_type == ValueType.LIST:
            return value[::-1]

        if node.operator == "NOT" and (is_bool(value) or (not self.strict_typing and is_num(value))):
            return not value

        self.log.error(translate("Evaluator", "Invalid unary operator '{op}'").format(op=node.operator))
        return None

    def eval_binary(self, node: nodes.BinOpNode):
        """Evaluates the specified binary operation node.
        Wrapper for binary_operation."""
        return self.binary_operation(self.eval_node(node.left), self.eval_node(node.right), node.operator)

    def binary_operation(self, left, right, operator):
        """Evaluates the specified binary operation."""
        left_type = ValueType.get_type(left)
        right_type = ValueType.get_type(right)

        if left is None or right is None:
            self.log.error(translate("Evaluator", "Trying to use None"))
            return None

        if operator == "+" and ValueType.STRING in [left_type, right_type]:
            # if one of the operands is a string
            return str(left) + str(right)

        if operator in ["*"] and right_type == ValueType.LIST and left_type != ValueType.LIST:
            # if one operand is list and not the other, then put the list at left
            # so we don't have to handle both cases afterwards
            (left, left_type, right, right_type) = (right, right_type, left, left_type)

        result = None

        if self.strict_typing:
            if left_type != right_type:
                self.log.error(
                    translate("Evaluator", "Type mismatch: operands have different types ({left} and {right})").format(
                        left=ValueType.get_name(left_type), right=ValueType.get_name(right_type)))
                return None

            if left_type == ValueType.BOOLEAN:
                allowed = Operators.boolean
            elif left_type == ValueType.NUMBER:
                allowed = Operators.math + Operators.comp
            elif left_type == ValueType.STRING:
                allowed = Operators.eq + ["+"]
            elif left_type == ValueType.LIST:
                allowed = Operators.eq + ["+", "-", "&", "|"]
            else:
                error_pos = []

                if left_type is None:
                    error_pos.append(translate("Evaluator", "left"))

                if right_type is None:
                    error_pos.append(translate("Evaluator", "right"))

                self.log.error(translate("Evaluator", "Invalid value type for {val} and operator '{op}'").format(
                    val=translate("Evaluator", " and ").join(error_pos), op=operator))
                return None

            if operator not in allowed:
                self.log.error(
                    translate("Evaluator", "Operator '{op}' not allowed for value type {type}").format(
                        op=operator, type=ValueType.get_name(left_type)))
                return None

        # arithmetic
        if operator == "+":
            result = left + right
        elif operator == "-":
            if left_type == right_type == ValueType.LIST:
                result = [x for x in left if x not in right]
            else:
                result = left - right
        elif operator == "*":
            if left_type == ValueType.LIST:
                if not is_int(right):
                    self.log.error(
                        translate("Evaluator", "Trying to multiply List by non-integer ({val})").format(val=right))
                    return None
                else:
                    result = left * int(right)
            else:
                result = left * right
        elif operator == "/":
            if right == 0:
                self.log.error(translate("Evaluator", "Trying to divide by zero"))
                return None
            result = left / right
        elif operator == "%":
            result = math.fmod(left, right)
        elif operator in ["^", "**"]:
            result = left ** right

        # comparison
        elif operator == "<=":
            result = left <= right or is_close(left, right)
        elif operator == "<":
            result = left < right
        elif operator == ">":
            result = left > right
        elif operator == ">=":
            result = left >= right or is_close(left, right)

        # equality
        elif operator == "==":
            result = is_close(left, right)
        elif operator == "!=":
            result = not is_close(left, right)

        # logic / bitwise
        elif operator == "&":
            if left_type == right_type == ValueType.LIST:
                result = [x for x in left if x in right]
            else:
                result = int(left) & int(right)
        elif operator == "|":
            if left_type == right_type == ValueType.LIST:
                result = list(set(left + right))
            else:
                result = int(left) | int(right)
        elif operator == "XOR":
            if left_type == right_type == ValueType.LIST:
                result = list(set(x for x in left + right if x not in left or x not in right))
            else:
                result = int(left) ^ int(right)

        if result is None:
            self.log.error(
                translate("Evaluator", "Invalid binary operator '{op}' for '{left}' and '{right}'").format(op=operator,
                                                                                left=left,
                                                                                right=right))
        else:
            if is_bool(left) and is_bool(right):
                # if both operands are bool, then cast the whole thing to bool so it looks like we're professional
                result = bool(result)

        return result


from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from variaveis import DATABASE

app = Flask(__name__)

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = DATABASE

db = SQLAlchemy(app)

db.init_app

class Awa_Foto(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    file_id = db.Column(db.String(255))
    chat_id = db.Column(db.String(255))


import sqlite3
from flask import current_app

def get_db():
    return current_app._get_current_object().get_db()

# Database function
def insert_user(firstname, lastname, emailuser):
    db = get_db()
    cursor = db.cursor()
    cursor.execute("INSERT INTO users (first_name, last_name, email) VALUES (?, ?, ? )", (firstname, lastname, emailuser))
    db.commit()
    return cursor.lastrowid

def insert_feedback(user_id, messageuser):
    db = get_db()
    cursor = db.cursor()
    cursor.execute("INSERT INTO feedback (user_id, message) VALUES (?, ?)", (user_id, messageuser))
    db.commit()

def get_user_by_email(emailuser):
    db = get_db()
    cursor = db.cursor()
    cursor.execute("SELECT * FROM users WHERE email = ?", (emailuser,))
    return cursor.fetchone()