#!/usr/bin/env python

from google.appengine.ext.webapp import template
from google.appengine.ext import ndb

import logging
import os.path
import webapp2
import json

from webapp2_extras import auth
from webapp2_extras import sessions

from webapp2_extras.auth import InvalidAuthIdError
from webapp2_extras.auth import InvalidPasswordError

class AccessException(Exception):
  def __init__(self, value):
    self.value = value
  def __str__(self):
    return repr(self.value)

def user_required(handler):
  """
    Decorator that checks if there's a user associated with the current session.
    Will also fail if there's no session present.
    Remember that we are usually decorating a subclass of BaseHandler
    If you try to access a user from a BaseHandler, without this decorator -> no go.
    If you try to post to a BaseHandler, decorated thusly, without an auth cookie, you will get a redirect
  """
  def check_login(self, *args, **kwargs):
    auth = self.auth
    if not auth.get_user_by_session():
      logging.warn("Permission denied.")
      # todo: this should return some json failure
      #self.redirect(self.uri_for('login'), abort=True)

      self.addAccessHeaders()
      self.response.status = 403
      response = {"status": "fail", "data": { "title": "Permission denied." } }

      self.response.out.write(json.dumps(response) + "\n\n")
    else:
      logging.info("Permission granted.")
      return handler(self, *args, **kwargs)

  return check_login

class BaseHandler(webapp2.RequestHandler):

  def addAccessHeaders(self):
    '''Add headers needed for access control'''
    self.response.headers['Content-Type'] = "application/json"

    # you have to provide this header eg. Origin: http://localhost:8080, which is added automatically by a browser
    # browsers tend to be picky about seeing a wildcard origin
    if 'Origin' in self.request.headers:
      logging.info("Origin: " + self.request.headers['Origin'])
      # todo: we need a list here
      origin = self.request.headers['Origin']
      if origin.startswith('http://localhost') or origin.startswith('https://localhost') or origin.startswith('https://stratweb1.appspot.com'):
        self.response.headers['Access-Control-Allow-Credentials'] = 'true'
        self.response.headers['Access-Control-Allow-Origin'] = origin

  def options(self,stratfileId=0,themeId=0):
    '''Convenience method to add all the required headers, when backbone requests OPTIONS'''
    logging.debug("Returning options")
    self.response.headers['Access-Control-Request-Method'] = "*"
    self.response.headers['Access-Control-Allow-Methods'] = 'GET,PUT,POST,DELETE,OPTIONS'
    self.response.headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type'
    self.response.headers["Access-Control-Max-Age"] = '1728000'
    self.addAccessHeaders()

  @webapp2.cached_property
  def auth(self):
    """Shortcut to access the auth instance as a property."""
    # http://webapp-improved.appspot.com/api/webapp2_extras/auth.html#api-webapp2-extras-auth
    return auth.get_auth()

  @webapp2.cached_property
  def user_info(self):
    """Shortcut to access a subset of the user attributes that are stored
    in the session.

    The list of attributes to store in the session is specified in
      config['webapp2_extras.auth']['user_attributes'].
    :returns
      A dictionary with most user information
    """
    return self.auth.get_user_by_session()

  @webapp2.cached_property
  def user(self):
    """Shortcut to access the current logged in user.

    Unlike user_info, it fetches information from the persistence layer and
    returns an instance of the underlying model.

    :returns
      The instance of the user model associated to the logged in user.
    """
    u = self.user_info
    return self.user_model.get_by_id(u['user_id']) if u else None

  @webapp2.cached_property
  def user_model(self):
    """Returns the implementation of the user model.

    It is consistent with config['webapp2_extras.auth']['user_model'], if set.
    """
    return self.auth.store.user_model

  @webapp2.cached_property
  def session(self):
      """Shortcut to access the current session."""
      return self.session_store.get_session(backend="datastore")

  # this is needed for webapp2 sessions to work
  def dispatch(self):
      # Get a session store for this request.
      self.session_store = sessions.get_store(request=self.request)

      try:
          # Dispatch the request.
          webapp2.RequestHandler.dispatch(self)
      finally:
          # Save all sessions.
          self.session_store.save_sessions(self.response)


# Super simple NextBus display thing (prints to console).

import time
from predict import predict
from microdotphat import write_string, scroll, clear, show

# List of bus lines/stops to predict.  Use routefinder.py to look up
# lines/stops for your location, copy & paste results here.  The 4th
# element on each line can then be edited for brevity if desired.
stops = [
  ( 'mbta', '47', '1812', 'Central Square' ), #47 stop Brookline/Putnam, towards Central Square
]

# Populate a list of predict objects from stops[].  Each then handles
# its own periodic NextBus server queries.  Can then read or extrapolate
# arrival times from each object's predictions[] list (see code later).
predictList = []
for s in stops:
    predictList.append(predict(s))

time.sleep(4) # Allow a moment for initial results

currentTime = time.time()
#print
for pl in predictList:
    #print pl.data[1] + ' ' + pl.data[3] + ':'
    if pl.predictions: # List of arrival times, in seconds
        #for p in pl.predictions:
            # Extrapolate from predicted arrival time,
            # current time and time of last query,
            # display in whole minutes.
        t = pl.predictions[0] - (currentTime - pl.lastQueryTime)
        Output='Bus:'+str(int(t/60))
        #Output.encode(errors='ignore').decode('utf-8')

    else:
        Output='No Bus'
        #Output.encode(errors='ignore').decode('utf-8')

prevTime = currentTime;
#time.sleep(5) # Refresh every ~5 seconds

while True:
    clear()
    write_string(Output, kerning=False)
    show()


from django import forms
from .models import ReflectIssues, ReflectContents, ReflectProblem

# class ReflectIssues...で使う

class ReflectIssuesForm(forms.ModelForm):
    class Meta:
        model = ReflectIssues
        fields = ('issues',)
        labels = {'issues': '論点'}

class ReflectContentsForm(forms.ModelForm):
    class Meta:
        model = ReflectContents
        fields = ('ref_issues', 'comment_type', 'comment_content')
        labels = {'ref_issues': '参照論点', 'comment_type': 'コメントタイプ', 'comment_content': 'コメント内容'}

class ReflectProblemForm(forms.ModelForm):
    class Meta:
        model = ReflectProblem
        fields = ('problem',)
        labels = {'problem': '問題点'}


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import os
import sys

from core.crawl.crawler import Crawler
from core.lib.utils import *
from core.scan.scanner import Scanner
from core.util.util import Util

def split_argv(argv):
    argvs = []
    cur = 0
    for a in argv:
        if a == ";":
            cur += 1
            continue
        if len(argvs) == cur:
            argvs.append([])
        argvs[cur].append(a)
    return argvs

def usage():
    infos = get_program_infos()
    print((
        "eye1c ver " + infos['version'] + "\n"
        "usage: eye1c <command>\n"
        "commands are chainable using '\\;' and they share the same database\n"
        "  ex: eye1c crawl http://loadlhost:80/ tmp.db \\;"
        "Commands: \n"
        "  crawl                  run crawler\n"
        "  scan                   run scanner\n"
        "  util                   run utility\n"))

if __name__ == '__main__':
    if not os.path.exists("./log/"):
        os.makedirs("./log/")
    logging.basicConfig(format='%(name)s|%(asctime)s :%(message)s',
                        level=logging.DEBUG,
                        datefmt='%m/%d/%Y %I:%M:%S %p',
                        filename='./log/app.log',
                        filemode='w+')
    logging.getLogger("requests").setLevel(logging.CRITICAL)
    logging.getLogger("urllib3.connectionpool").setLevel(logging.CRITICAL)
    logging.getLogger("urllib3.util.retry").setLevel(logging.CRITICAL)
    log = logging.Logger('eye1c')

    logging.debug("python args:%s" % " ".join(sys.argv))

    if len(sys.argv) < 2:
        usage()
        sys.exit(0)

    argvs = split_argv(sys.argv[1:])
    for argv in argvs:
        if argv[0] not in ('crawl', 'scan', 'util'):
            print("Command not found: %s" % argv[0])
            sys.exit(1)
    cr = None
    sc = None
    for argv in argvs:

        if argv[0] == "crawl":
            cr = Crawler(argv[1:])
        elif argv[0] == "scan":
            if sc:
                dbfile = sc.db_file
            else:
                dbfile = cr.db_file if cr else None
            sc = Scanner(argv[1:], dbfile)
        elif argv[0] == "util":
            dbfile = cr.db_file if cr else (sc.db_file if sc else None)
            Util(argv[1:], dbfile)
    sys.exit(0)


"""
Available commands:
 - fab release [--bump=minor] : insert new version to project settings and update Changelog file from git log
 - fab finish : commit updated ChangeLog file, update version line in project settings and commit changes with tag
 - fab check : checks code using isort, flake8, mypy, pylint, black with sensible defaults

Usage example: project release
 1. fab release --bump=major
 2. <prettify updated Changelog by hand>
 3. fab finish

Usage example to check code:
 1. fab check --path=t2f/api/v1/registration.py  # checks file `registretion.py`
 2. <fixing errors>
 3. fab check  # checks the entire project
"""
import os
import sys
from copy import copy
from dataclasses import dataclass, fields

from dateutil.utils import today
from invoke import task

file_dir_path = os.path.dirname(__file__)

CHANGELOG_FILE = "CHANGELOG.md"
VERSION_TITLE_TMPL = "## version {version} ({day})"
CHANGE_LINE_TMPL = "  - {line}"

# validate changelog file path on import
CHANGELOG_ABSPATH = os.path.abspath(os.path.join(file_dir_path, CHANGELOG_FILE))
if not os.path.isfile(CHANGELOG_ABSPATH):
    sys.stderr.write(f'Can\'t find "{CHANGELOG_FILE}" file at {CHANGELOG_ABSPATH}\n')
    sys.exit(1)

# validate that settings could be found
SETTINGS_PATH = os.path.abspath(os.path.join(file_dir_path, "t2f", "core", "config.py"))
if not os.path.isfile(SETTINGS_PATH):
    sys.stderr.write(f"Can't find settings file with VERSION constant at {SETTINGS_PATH}\n")
    sys.exit(1)

@dataclass
class VersionStructure:
    major: int
    minor: int
    patch: int

    @classmethod
    def from_str(cls, line) -> "VersionStructure":
        """
        return object from {line}, e.g. "0.8.16"
        """
        major, minor, patch = [int(item) for item in line.split(".")]
        return cls(major=major, minor=minor, patch=patch)

    @classmethod
    def from_settings(cls) -> "VersionStructure":
        """
        return last version from "settings.py" file
        :rtype: unicode
        """

        with open(SETTINGS_PATH) as f:
            for line in f.readlines():
                if line.startswith("VERSION"):
                    return cls.from_str(line.split("=", 1)[-1].strip("\n '\""))

    @classmethod
    def bump_version(cls, version, part="patch"):
        """
        increment {part} of version
        """
        resulting_version = copy(version)
        version_parts = [f.name for f in fields(resulting_version)]
        assert part in version_parts, f"{part} is not a version part"
        # setattr(self, part, (getattr(self, part, 0) + 1))
        old_version = getattr(resulting_version, part, 0)

        part_to_increment = version_parts.index(part)
        for index, value in enumerate(version_parts):
            if index == part_to_increment:
                setattr(resulting_version, value, old_version + 1)
            elif index > part_to_increment:
                setattr(resulting_version, value, 0)

        return resulting_version

    def __str__(self) -> str:
        return f"{self.major}.{self.minor}.{self.patch}"

    def to_release_brach_name(self) -> str:
        """
        Convert version for release branch name. Patch part is not used to allow release branch contain hotfixes.
        """
        return f"release/{self.major}.{self.minor}"

def _set_settings_version(c, settings_path, version_line):
    """
    set `VERSION` constant in project settings
    """
    version_const = "VERSION"

    print(f"Adjusting {version_const} in {settings_path} to {version_line}...")
    c.run(f'sed -i .orig \'s/^{version_const} =.*$/{version_const} = "{version_line}"/\' "{settings_path}"')

@task
def release(c, bump="patch"):
    """
    fab release will insert new version to project settings and update Changelog file from git log
    """
    assert bump in [f.name for f in fields(VersionStructure)], f'"{bump}" is not a version part'

    old_version = VersionStructure.from_settings()
    new_version = VersionStructure.bump_version(old_version, part=bump)

    # collecting changelog
    print(f'Collecting changelog from the last version tag "{old_version}"...')

    result = c.run(f'git log "{old_version}"..HEAD --pretty=format:"%s"', hide="out")

    commit_messages = filter(bool, result.stdout.splitlines())
    if not commit_messages:
        sys.stderr.write("Error: no new commits from last version, sorry\n")
        sys.exit(1)

    # updating changelog
    with open(CHANGELOG_ABSPATH, "r+", encoding="utf-8") as changelog:
        old_changelog = changelog.read().strip()

        changelog.seek(0)
        print("Inserting this to changelog file:\n-----\n")
        new_version_line = (
            VERSION_TITLE_TMPL.format(version=new_version, day=today().strftime("%Y-%m-%d")) + "\n"
        )
        changelog.write(new_version_line)

        print(new_version_line)
        for line in sorted(commit_messages):  # sort commit messages for easier edition afterwards
            line: str = line.strip()
            if line.startswith("Merge"):
                continue

            message_line = CHANGE_LINE_TMPL.format(line=line) + "\n"
            print(message_line)
            changelog.write(message_line)

        changelog.write("\n")
        changelog.write(old_changelog)

        print("-----")

    _set_settings_version(c, SETTINGS_PATH, str(new_version))

@task
def finish(c):
    """
    commit updated ChangeLog file, update version line in project settings and commit changes with tag
    """
    files_to_commit = [os.path.relpath(path, start=os.curdir) for path in [CHANGELOG_ABSPATH, SETTINGS_PATH]]
    version: VersionStructure = VersionStructure.from_settings()

    c.run(f"git add %s" % " ".join(files_to_commit))
    c.run(f'git commit -m "version {version}" --no-verify')
    c.run(f"git tag {version}")

@task
def check(c, path=None, lines=110):
    """
    check code using isort, flake8 and mypy
    """
    default_env = {
        "SECRET_KEY": os.environ.get("SECRET_KEY", "fab check key"),
        "PATH": os.environ["PATH"],
        "LANG": "en_US.UTF-8",
    }

    env = os.environ
    env.update(default_env)

    commands = [
        'echo "=> Checking in \\"%s\\":"' % (path or "t2f"),
        # black
        'echo "\n\n=> running `black --version` ...\n"',
        f"black --line-length={lines} %s" % (path or "."),
        'echo "\n=> done!"',
        # mypy
        'echo "\n\n=> running `mypy --version` ...\n"',
        "mypy --config-file ./mypy.ini %s" % (path or "t2f"),
        'echo "\n=> done!"',
        # flake8
        'echo "\n\n=> running flake8 `flake8 --version` ...\n"',
        "flake8 %s" % (path or "t2f"),
        'echo "\n=> done!"',
        # pylint
        'echo "\n\n=>running `pylint --version` ...\n"',
        "python pylint-checker.py %s --fail-under=9.8" % (path or "t2f"),
        'echo "\n=> done!"',
    ]

    [c.run(cmd, env=env, warn=True) for cmd in commands]

@task(name="load-testdb")
def load_testdb(c, dbname="test_template", fpath="tests/test_db.sql"):
    """
    Load db for tests from {fpath} file to {dbname} to allow for easy changing of data
    """
    default_env = {
        "PATH": os.environ["PATH"],
        "PYTHONPATH": os.path.abspath(os.path.dirname(__file__)),
        "LANG": "en_US.UTF-8",
        "POSTGRES_DB": dbname,
        "POSTGRES_HOST": "localhost",
        "POSTGRES_USER": "postgres",
        "POSTGRES_PORT": "5432",
    }

    env = os.environ
    env.update(default_env)

    psql_command = (
        f'psql -h {default_env["POSTGRES_HOST"]} '
        f'-p {default_env["POSTGRES_PORT"]} '
        f'-U {default_env["POSTGRES_USER"]}'
    )

    c.run(f'{psql_command} postgres -c "drop database if exists {dbname}";', env=env)
    c.run(f'{psql_command} postgres -c "create database {dbname}";', env=env)
    c.run(f"{psql_command} {dbname} < {fpath}", env=env)
    # update test db to the latest migrations
    c.run(f"alembic -c ./alembic.ini upgrade head", env=env)

@task(name="dump-testdb")
def dump_testdb(c, dbname="test_template", fpath="tests/test_db.sql"):
    """
    Dump {dbname} to test db file {fpath}
    """
    default_env = {
        "PATH": os.environ["PATH"],
        "LANG": "en_US.UTF-8",
    }

    env = os.environ
    env.update(default_env)

    c.run(f"pg_dump -h localhost -p 5432 -U postgres {dbname} > {fpath}", env=env)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd

def create_ordered_toc(toc_file: str, output_file: str) -> None:
    df = pd.read_csv(toc_file)
    ordered = df.sort_values(by=['# id'])
    ordered.to_csv(output_file, index=False)

if __name__ == "__main__":
    create_ordered_toc("encoding_toc.csv", "testtt.csv")


import datetime
import logging
import warnings
from collections.abc import Iterator, Mapping
from functools import partial
from pathlib import Path
from typing import Iterable, Optional, Union, Callable, Tuple
from numbers import Number

import bw_processing as bwp
import matrix_utils as mu
import numpy as np
import pandas as pd
from fs.base import FS
from scipy import sparse

from . import PYPARDISO, __version__, factorized, prepare_lca_inputs, spsolve
from .dictionary_manager import DictionaryManager
from .errors import EmptyBiosphere, NonsquareTechnosphere, OutsideTechnosphere
from .single_value_diagonal_matrix import SingleValueDiagonalMatrix
from .utils import consistent_global_index, get_datapackage, wrap_functional_unit

try:
    from bw2data import get_node
except ImportError:
    get_node = None

logger = logging.getLogger("bw2calc")

class LCA(Iterator):
    matrix_labels = [
        "technosphere_mm",
        "biosphere_mm",
        "characterization_mm",
        "normalization_mm",
        "weighting_mm",
    ]

    #############
    ### Setup ###
    #############

    def __init__(
        self,
        demand: dict,
        # Brightway 2 calling convention
        method: Optional[tuple] = None,
        weighting: Optional[str] = None,
        normalization: Optional[str] = None,
        # Brightway 2.5 calling convention
        data_objs: Optional[Iterable[Union[Path, FS, bwp.DatapackageBase]]] = None,
        remapping_dicts: Optional[Iterable[dict]] = None,
        log_config: Optional[dict] = None,
        seed_override: Optional[int] = None,
        use_arrays: Optional[bool] = False,
        use_distributions: Optional[bool] = False,
        selective_use: Optional[dict] = False,
    ):
        """Create a new LCA calculation object.

        Compatible with Brightway2 and 2.5 semantics. Can be static, stochastic, or iterative (scenario-based), depending on the ``data_objs`` input data..

        This class supports both stochastic and static LCA, and can use a variety of ways to describe uncertainty. The input flags `use_arrays` and `use_distributions` control some of this stochastic behaviour. See the [documentation for `matrix_utils`](https://github.com/brightway-lca/matrix_utils) for more information on the technical implementation.

        Parameters
        ----------
        demand : dict[object: float]
            The demand for which the LCA will be calculated. The keys can be Brightway `Node` instances, `(database, code)` tuples, or integer ids.
        method : tuple
            Tuple defining the LCIA method, such as `('foo', 'bar')`. Only needed if not passing `data_objs`.
        weighting : tuple
            Tuple defining the LCIA weighting, such as `('foo', 'bar')`. Only needed if not passing `data_objs`.
        weighting : string
            String defining the LCIA normalization, such as `'foo'`. Only needed if not passing `data_objs`.
        data_objs : list[bw_processing.Datapackage]
            List of `bw_processing.Datapackage` objects. Can be loaded via `bw2data.prepare_lca_inputs` or constructed manually. Should include data for all needed matrices.
        remapping_dicts : dict[str : dict]
            Dict of remapping dictionaries that link Brightway `Node` ids to `(database, code)` tuples. `remapping_dicts` can provide such remapping for any of `activity`, `product`, `biosphere`.
        log_config : dict
            Optional arguments to pass to logging. Not yet implemented.
        seed_override : int
            RNG seed to use in place of `Datapackage` seed, if any.
        use_arrays : bool
            Use arrays instead of vectors from the given `data_objs`
        use_distributions : bool
            Use probability distributions from the given `data_objs`
        selective_use : dict[str : dict]
            Dictionary that gives more control on whether `use_arrays` or `use_distributions` should be used. Has the form `{matrix_label: {"use_arrays"|"use_distributions": bool}`. Standard matrix labels are `technosphere_matrix`, `biosphere_matrix`, and `characterization_matrix`.

        """
        if not isinstance(demand, Mapping):
            raise ValueError("Demand must be a dictionary")

        if data_objs is None:
            self.ensure_bw2data_available()
            demand, self.packages, remapping_dicts = prepare_lca_inputs(
                demand=demand,
                method=method,
                weighting=weighting,
                normalization=normalization,
            )
            self.method = method
            self.weighting = weighting
            self.normalization = normalization
        else:
            self.packages = [get_datapackage(obj) for obj in data_objs]

        self.dicts = DictionaryManager()
        self.demand = demand
        self.use_arrays = use_arrays
        self.use_distributions = use_distributions
        self.selective_use = selective_use or {}
        self.remapping_dicts = remapping_dicts or {}
        self.seed_override = seed_override

        message = """Initialized LCA object. Demand: {demand}, data_objs: {data_objs}""".format(
            demand=self.demand, data_objs=self.packages
        )
        logger.info(
            message,
            extra={
                "demand": wrap_functional_unit(self.demand),
                "data_objs": str(self.packages),
                "bw2calc": __version__,
                "pypardiso": PYPARDISO,
                "numpy": np.__version__,
                "matrix_utils": mu.__version__,
                "bw_processing": bwp.__version__,
                "utc": datetime.datetime.utcnow(),
            },
        )

    def keep_first_iteration(self):
        """Set a flag to use the current values as first element when iterating.

        When creating the class instance, we already use the first index. This method allows us to use the values for the first index.

        Note that the methods ``.lci_calculation()`` and ``.lcia_calculation()`` will be called on the current values, even if these calculations have already been done."""
        self.keep_first_iteration_flag = True

    def __next__(self) -> None:
        skip_first_iteration = hasattr(self, "keep_first_iteration_flag") and self.keep_first_iteration_flag

        for matrix in self.matrix_labels:
            if not skip_first_iteration and hasattr(self, matrix):
                obj = getattr(self, matrix)
                next(obj)
                message = """Iterating {matrix}. Indexers: {indexer_state}""".format(
                    matrix=matrix,
                    indexer_state=[(str(p), p.indexer.index) for p in obj.packages],
                )
                logger.debug(
                    message,
                    extra={
                        "matrix": matrix,
                        "indexers": [(str(p), p.indexer.index) for p in obj.packages],
                        "matrix_sum": obj.matrix.sum(),
                        "utc": datetime.datetime.utcnow(),
                    },
                )

        if not skip_first_iteration and hasattr(self, "after_matrix_iteration"):
            self.after_matrix_iteration()

        if skip_first_iteration:
            delattr(self, "keep_first_iteration_flag")

        if hasattr(self, "inventory"):
            self.lci_calculation()
        if hasattr(self, "characterized_inventory"):
            self.lcia_calculation()

    def ensure_bw2data_available(self):
        """Raises ``ImportError`` is bw2data not available or version < 4."""
        if prepare_lca_inputs is None:
            raise ImportError("bw2data version >= 4 not found")

    def build_demand_array(self, demand: Optional[dict] = None) -> None:
        """Turn the demand dictionary into a *NumPy* array of correct size.

        Args:
            * *demand* (dict, optional): Demand dictionary. Optional, defaults to ``self.demand``.

        Returns:
            A 1-dimensional NumPy array

        """
        demand = demand or self.demand
        self.demand_array = np.zeros(len(self.dicts.product))
        for key in demand:
            try:
                self.demand_array[self.dicts.product[key]] = demand[key]
            except KeyError:
                if key in self.dicts.activity:
                    raise ValueError(
                        f"LCA can only be performed on products, not activities ({key} is the wrong dimension)"
                    )
                else:
                    raise OutsideTechnosphere(
                        f"Can't find key {key} in product dictionary"
                    )

    def check_selective_use(self, matrix_label: str) -> Tuple[bool, bool]:
        return (
            self.selective_use.get(matrix_label, {}).get("use_arrays", self.use_arrays),
            self.selective_use.get(matrix_label, {}).get("use_distributions", self.use_distributions),
        )

    ######################
    ### Data retrieval ###
    ######################

    def load_lci_data(self, nonsquare_ok=False) -> None:
        """Load inventory data and create technosphere and biosphere matrices."""
        use_arrays, use_distributions = self.check_selective_use("technosphere_matrix")

        self.technosphere_mm = mu.MappedMatrix(
            packages=self.packages,
            matrix="technosphere_matrix",
            use_arrays=use_arrays,
            use_distributions=use_distributions,
            seed_override=self.seed_override,
        )
        self.technosphere_matrix = self.technosphere_mm.matrix
        self.dicts.product = partial(self.technosphere_mm.row_mapper.to_dict)
        self.dicts.activity = partial(self.technosphere_mm.col_mapper.to_dict)

        if (
            len(self.technosphere_mm.row_mapper) != len(self.technosphere_mm.col_mapper)
            and not nonsquare_ok
        ):
            raise NonsquareTechnosphere(
                (
                    "Technosphere matrix is not square: {} activities (columns) and {} products (rows). "
                    "Use LeastSquaresLCA to solve this system, or fix the input "
                    "data"
                ).format(
                    len(self.technosphere_mm.col_mapper),
                    len(self.technosphere_mm.row_mapper),
                )
            )

        use_arrays, use_distributions = self.check_selective_use("biosphere_matrix")

        self.biosphere_mm = mu.MappedMatrix(
            packages=self.packages,
            matrix="biosphere_matrix",
            use_arrays=use_arrays,
            use_distributions=use_distributions,
            seed_override=self.seed_override,
            col_mapper=self.technosphere_mm.col_mapper,
            empty_ok=True,
        )
        self.biosphere_matrix = self.biosphere_mm.matrix
        self.dicts.biosphere = partial(self.biosphere_mm.row_mapper.to_dict)

        if self.biosphere_mm.matrix.shape[0] == 0:
            warnings.warn(
                "No valid biosphere flows found. No inventory results can "
                "be calculated, `lcia` will raise an error"
            )

    def remap_inventory_dicts(self) -> None:
        """Remap ``self.dicts.activity|product|biosphere`` and ``self.demand`` from database integer IDs to keys (``(database name, code)``).

        Uses remapping dictionaries in ``self.remapping_dicts``."""
        if getattr(self, "_remapped", False):
            warnings.warn("Remapping has already been done; returning without changing data")
            return

        if "product" in self.remapping_dicts:
            self.demand = {
                self.remapping_dicts["product"][k]: v for k, v in self.demand.items()
            }

        for label in ("activity", "product", "biosphere"):
            if label in self.remapping_dicts:
                getattr(self.dicts, label).remap(self.remapping_dicts[label])

        self._remapped = True

    def load_lcia_data(
        self, data_objs: Optional[Iterable[Union[FS, bwp.DatapackageBase]]] = None
    ) -> None:
        """Load data and create characterization matrix.

        This method will filter out regionalized characterization factors.

        """
        global_index = consistent_global_index(data_objs or self.packages)
        fltr = (
            (lambda x: x["col"] == global_index) if global_index is not None else None
        )

        use_arrays, use_distributions = self.check_selective_use("characterization_matrix")

        try:
            self.characterization_mm = mu.MappedMatrix(
                packages=data_objs or self.packages,
                matrix="characterization_matrix",
                use_arrays=use_arrays,
                use_distributions=use_distributions,
                seed_override=self.seed_override,
                row_mapper=self.biosphere_mm.row_mapper,
                diagonal=True,
                custom_filter=fltr,
            )
        except mu.errors.AllArraysEmpty:
            raise ValueError("Given `method` or `data_objs` have no characterization data")
        self.characterization_matrix = self.characterization_mm.matrix
        if len(self.characterization_matrix.data) == 0:
            warnings.warn("All values in characterization matrix are zero")

    def load_normalization_data(
        self, data_objs: Optional[Iterable[Union[FS, bwp.DatapackageBase]]] = None
    ) -> None:
        """Load normalization data."""
        use_arrays, use_distributions = self.check_selective_use("normalization_matrix")

        self.normalization_mm = mu.MappedMatrix(
            packages=data_objs or self.packages,
            matrix="normalization_matrix",
            use_arrays=use_arrays,
            use_distributions=use_distributions,
            seed_override=self.seed_override,
            row_mapper=self.biosphere_mm.row_mapper,
            diagonal=True,
        )
        self.normalization_matrix = self.normalization_mm.matrix

    def load_weighting_data(
        self, data_objs: Optional[Iterable[Union[FS, bwp.DatapackageBase]]] = None
    ) -> None:
        """Load normalization data."""
        use_arrays, use_distributions = self.check_selective_use("weighting_matrix")

        self.weighting_mm = SingleValueDiagonalMatrix(
            packages=data_objs or self.packages,
            matrix="weighting_matrix",
            dimension=len(self.biosphere_mm.row_mapper),
            use_arrays=use_arrays,
            use_distributions=use_distributions,
            seed_override=self.seed_override,
        )
        self.weighting_matrix = self.weighting_mm.matrix

    ####################
    ### Calculations ###
    ####################

    def decompose_technosphere(self) -> None:
        """
        Factorize the technosphere matrix into lower and upper triangular matrices, :math:`A=LU`. Does not solve the linear system :math:`Ax=B`.

        Doesn't return anything, but creates ``self.solver``.

        .. warning:: Incorrect results could occur if a technosphere matrix was factorized, and then a new technosphere matrix was constructed, as ``self.solver`` would still be the factorized older technosphere matrix. You are responsible for deleting ``self.solver`` when doing these types of advanced calculations.

        """
        if PYPARDISO:
            warnings.warn("PARDISO installed; this is a no-op")
        else:
            self.solver = factorized(self.technosphere_matrix.tocsc())

    def solve_linear_system(self) -> None:
        """
        Master solution function for linear system :math:`Ax=B`.

            To most numerical analysts, matrix inversion is a sin.

            -- Nicolas Higham, Accuracy and Stability of Numerical Algorithms, Society for Industrial and Applied Mathematics, Philadelphia, PA, USA, 2002, p. 260.

        We use `pypardiso <https://github.com/haasad/PyPardisoProject>`_ or `UMFpack <http://www.cise.ufl.edu/research/sparse/umfpack/>`_, which is a very fast solver for sparse matrices.

        If the technosphere matrix has already been factorized, then the decomposed technosphere (``self.solver``) is reused. Otherwise the calculation is redone completely.

        """
        if hasattr(self, "solver"):
            return self.solver(self.demand_array)
        else:
            return spsolve(self.technosphere_matrix, self.demand_array)

    def lci(self, demand: Optional[dict] = None, factorize: bool = False) -> None:
        """
        Calculate a life cycle inventory.

        #. Load LCI data, and construct the technosphere and biosphere matrices.
        #. Build the demand array
        #. Solve the linear system to get the supply array and life cycle inventory.

        Args:
            * *factorize* (bool, optional): Factorize the technosphere matrix. Makes additional calculations with the same technosphere matrix much faster. Default is ``False``; not useful is only doing one LCI calculation.
            * *builder* (``MatrixBuilder`` object, optional): Default is ``bw2calc.matrices.MatrixBuilder``, which is fine for most cases. Custom matrix builders can be used to manipulate data in creative ways before building the matrices.

        Doesn't return anything, but creates ``self.supply_array`` and ``self.inventory``.

        """
        if not hasattr(self, "technosphere_matrix"):
            self.load_lci_data()
        if demand is not None:
            self.__check_demand(demand)
            self.build_demand_array(demand)
            self.demand = demand
        else:
            self.build_demand_array()
        if factorize and not PYPARDISO:
            self.decompose_technosphere()
        self.lci_calculation()

    def lci_calculation(self) -> None:
        """The actual LCI calculation.

        Separated from ``lci`` to be reusable in cases where the matrices are already built, e.g. ``redo_lci`` and Monte Carlo classes.

        """
        self.supply_array = self.solve_linear_system()
        # Turn 1-d array into diagonal matrix
        count = len(self.dicts.activity)
        self.inventory = self.biosphere_matrix * sparse.spdiags(
            [self.supply_array], [0], count, count
        )

    def lcia(self, demand: Optional[dict] = None) -> None:
        """
        Calculate the life cycle impact assessment.

        #. Load and construct the characterization matrix
        #. Multiply the characterization matrix by the life cycle inventory

        Doesn't return anything, but creates ``self.characterized_inventory``.

        """
        assert hasattr(self, "inventory"), "Must do lci first"
        if not self.dicts.biosphere:
            raise EmptyBiosphere

        if not hasattr(self, "characterization_matrix"):
            self.load_lcia_data()
        if demand is not None:
            self.__check_demand(demand)
            self.lci(demand=demand)
            self.demand = demand
        self.lcia_calculation()

    def lcia_calculation(self) -> None:
        """The actual LCIA calculation.

        Separated from ``lcia`` to be reusable in cases where the matrices are already built, e.g. ``redo_lcia`` and Monte Carlo classes.

        """
        self.characterized_inventory = self.characterization_matrix * self.inventory

    def normalize(self) -> None:
        """Multiply characterized inventory by flow-specific normalization factors."""
        assert hasattr(self, "characterized_inventory"), "Must do lcia first"
        if not hasattr(self, "normalization_matrix"):
            self.load_normalization_data()
        self.normalization_calculation()

    def normalization_calculation(self) -> None:
        """The actual normalization calculation.

        Creates ``self.normalized_inventory``."""
        self.normalized_inventory = (
            self.normalization_matrix * self.characterized_inventory
        )

    def weighting(self) -> None:
        """Backwards compatibility. Switching to verb form consistent with ``.normalize``."""
        warnings.warn('Please switch to `.weight`', DeprecationWarning)
        return self.weight()

    def weight(self) -> None:
        """Multiply characterized inventory by weighting value.

        Can be done with or without normalization."""
        assert hasattr(self, "characterized_inventory"), "Must do lcia first"
        if not hasattr(self, "weighting_value"):
            self.load_weighting_data()
        self.weighting_calculation()

    def weighting_calculation(self) -> None:
        """The actual weighting calculation.

        Multiples weighting value by normalized inventory, if available, otherwise by characterized inventory.

        Creates ``self.weighted_inventory``."""
        if hasattr(self, "normalized_inventory"):
            obj = self.normalized_inventory
        else:
            obj = self.characterized_inventory
        self.weighted_inventory = self.weighting_matrix * obj

    @property
    def score(self) -> float:
        """
        The LCIA score as a ``float``.

        Note that this is a `property <http://docs.python.org/2/library/functions.html#property>`_, so it is ``foo.lca``, not ``foo.score()``
        """
        assert hasattr(self, "characterized_inventory"), "Must do LCIA first"
        if hasattr(self, "weighted_inventory"):
            return float(self.weighted_inventory.sum())
        elif hasattr(self, "normalized_inventory"):
            return float(self.normalized_inventory.sum())
        else:
            return float(self.characterized_inventory.sum())

    #########################
    ### Redo calculations ###
    #########################

    def _switch(
        self,
        obj: Union[tuple, Iterable[Union[FS, bwp.DatapackageBase]]],
        label: str,
        matrix: str,
        func: Callable,
    ) -> None:
        """Switch a method, weighting, or normalization"""
        if isinstance(obj, tuple):
            self.ensure_bw2data_available()
            _, data_objs, _ = prepare_lca_inputs(**{label: obj})
            setattr(self, label, obj)
        else:
            data_objs = list(obj)
        self.packages = [
            pkg.exclude({"matrix": matrix}) for pkg in self.packages
        ] + data_objs
        func(data_objs=data_objs)

        logger.info(
            f"""Switched LCIA {label}. data_objs: {data_objs}""",
            extra={
                "data_objs": str(data_objs),
                "utc": datetime.datetime.utcnow(),
            },
        )

    def switch_method(
        self, method=Union[tuple, Iterable[Union[FS, bwp.DatapackageBase]]]
    ) -> None:
        """Load a new method and replace ``.characterization_mm`` and ``.characterization_matrix``.

        Does not do any new calculations or change ``.characterized_inventory``."""
        self._switch(
            obj=method,
            label="method",
            matrix="characterization_matrix",
            func=self.load_lcia_data,
        )

    def switch_normalization(
        self, normalization=Union[tuple, Iterable[Union[FS, bwp.DatapackageBase]]]
    ) -> None:
        """Load a new normalization and replace ``.normalization_mm`` and ``.normalization_matrix``.

        Does not do any new calculations or change ``.normalized_inventory``."""
        self._switch(
            obj=normalization,
            label="normalization",
            matrix="normalization_matrix",
            func=self.load_normalization_data,
        )

    def switch_weighting(
        self, weighting=Union[tuple, Iterable[Union[FS, bwp.DatapackageBase]]]
    ) -> None:
        """Load a new weighting and replace ``.weighting_mm`` and ``.weighting_matrix``.

        Does not do any new calculations or change ``.weighted_inventory``."""
        self._switch(
            obj=weighting,
            label="weighting",
            matrix="weighting_matrix",
            func=self.load_weighting_data,
        )

    def invert_technosphere_matrix(self):
        """Use one-shot approach to efficiently calculate the inverse of the
        technosphere matrix by simultaneously solving ``Ax=b`` for all ``b``.

        See `Intel forum <https://community.intel.com/t5/Intel-oneAPI-Math-Kernel-Library/How-to-find-inverse-of-a-sparse-matrix-using-pardiso/m-p/1165970#M28249>`__
        for a discussion on why we use this approach."""
        assert hasattr(self, "inventory"), "Must do lci first"

        if not PYPARDISO:
            warnings.warn("Performance is much better with pypardiso (not available on MacOS ARM machines)")

        MESSAGE = """Technosphere matrix inversion is often not the most efficient approach.
    See https://github.com/brightway-lca/brightway2-calc/issues/35"""
        warnings.warn(MESSAGE)

        self.inverted_technosphere_matrix = spsolve(
            self.technosphere_matrix, np.eye(*self.technosphere_matrix.shape)
        )
        return self.inverted_technosphere_matrix

    def __check_demand(self, demand: Optional[dict] = None):
        if demand is None:
            return
        else:
            for key in demand:
                if key not in self.dicts.product and not isinstance(key, int):
                    raise KeyError(f"Key '{key}' not in product dictionary; make sure to pass the integer id, not a key like `('foo', 'bar')` or an `Actiivity` or `Node` object.")

    def redo_lci(self, demand: Optional[dict] = None) -> None:
        """Redo LCI with same databases but different demand.

        Args:
            * *demand* (dict): A demand dictionary.

        Doesn't return anything, but overwrites ``self.demand_array``, ``self.supply_array``, and ``self.inventory``.

        .. warning:: If you want to redo the LCIA as well, use ``redo_lcia(demand)`` directly.

        """
        warnings.warn('Please use .lci(demand=demand) instead of `redo_lci`.', DeprecationWarning)
        self.lci(demand=demand)

    def redo_lcia(self, demand: Optional[dict] = None) -> None:
        """Redo LCIA, optionally with new demand.

        Args:
            * *demand* (dict, optional): New demand dictionary. Optional, defaults to ``self.demand``.

        Doesn't return anything, but overwrites ``self.characterized_inventory``. If ``demand`` is given, also overwrites ``self.demand_array``, ``self.supply_array``, and ``self.inventory``.

        """
        warnings.warn('Please use .lcia(demand=demand) instead of `redo_lci`.', DeprecationWarning)
        self.lcia(demand=demand)

    def to_dataframe(self, matrix_label: str = "characterized_inventory", row_dict: Optional[dict] = None, col_dict: Optional[dict] = None, annotate: bool = True, cutoff: Number = 200, cutoff_mode: str = "number") -> pd.DataFrame:
        """Return all nonzero elements of the given matrix as a Pandas dataframe.

        The LCA class instance must have the matrix ``matrix_label`` already; common labels are:

        * characterized_inventory
        * inventory
        * technosphere_matrix
        * biosphere_matrix
        * characterization_matrix

        For these common matrices, we already have ``row_dict`` and ``col_dict`` which link row and column indices to database ids. For other matrices, or if you have a custom mapping dictionary, override ``row_dict`` and/or ``col_dict``. They have the form ``{matrix index: identifier}``.

        If ``bw2data`` is installed, this function will try to look up metadata on the row and column objects. To turn this off, set ``annotate`` to ``False``.

        Instead of returning all possible values, you can apply a cutoff. This cutoff can be specified in two ways, controlled by ``cutoff_mode``, which should be either ``fraction`` or ``number``.

        If ``cutoff_mode`` is ``number`` (the default), then ``cutoff`` is the number of rows in the DataFrame. Data values are first sorted by their absolute value, and then the largest ``cutoff`` are taken.

        If ``cutoff_mode`` is ``fraction``, then only values whose absolute value is greater than ``cutoff * total_score`` are taken. ``cutoff`` must be between 0 and 1.

        The returned DataFrame will have the following columns:

        * amount
        * col_index
        * row_index

        If row or columns dictionaries are available, the following columns are added:

        * col_id
        * row_id

        If ``bw2data`` is available, then the following columns are added:

        * col_code
        * col_database
        * col_location
        * col_name
        * col_reference_product
        * col_type
        * col_unit
        * row_categories
        * row_code
        * row_database
        * row_location
        * row_name
        * row_type
        * row_unit
        * source_product

        Returns a pandas ``DataFrame``.

        """
        matrix = getattr(self, matrix_label).tocoo()

        dict_mapping = {
            'characterized_inventory': (self.dicts.biosphere.reversed, self.dicts.activity.reversed),
            'inventory': (self.dicts.biosphere.reversed, self.dicts.activity.reversed),
            'technosphere_matrix': (self.dicts.product.reversed, self.dicts.activity.reversed),
            'biosphere_matrix': (self.dicts.biosphere.reversed, self.dicts.activity.reversed),
            'characterization_matrix': (self.dicts.biosphere.reversed, self.dicts.biosphere.reversed),
        }
        if not row_dict:
            try:
                row_dict, _ = dict_mapping[matrix_label]
            except KeyError:
                row_dict = None
        if not col_dict:
            try:
                _, col_dict = dict_mapping[matrix_label]
            except KeyError:
                col_dict = None

        sorter = np.argsort(np.abs(matrix.data))[::-1]
        matrix.data = matrix.data[sorter]
        matrix.row = matrix.row[sorter]
        matrix.col = matrix.col[sorter]

        if cutoff is not None:
            if cutoff_mode == 'fraction':
                if not (0 < cutoff < 1):
                    raise ValueError("fraction `cutoff` value must be between 0 and 1")
                total = matrix.data.sum()
                mask = (np.abs(matrix.data) > (total * cutoff))
                matrix.data = matrix.data[mask]
                matrix.row = matrix.row[mask]
                matrix.col = matrix.col[mask]
            elif cutoff_mode == 'number':
                matrix.data = matrix.data[:int(cutoff)]
                matrix.row = matrix.row[:int(cutoff)]
                matrix.col = matrix.col[:int(cutoff)]
            else:
                raise ValueError("Can't understand cutoff mode")

        df_data = {
            'row_index': matrix.row,
            'col_index': matrix.col,
            'amount': matrix.data,
        }
        if row_dict:
            df_data['row_id'] = np.array([row_dict[i] for i in matrix.row])
        if col_dict:
            df_data['col_id'] = np.array([col_dict[i] for i in matrix.col])
        df = pd.DataFrame(df_data)

        def metadata_dataframe(objs, prefix):
            def dict_for_obj(obj, prefix):
                dct = {
                    f"{prefix}id": obj["id"],
                    f"{prefix}database": obj["database"],
                    f"{prefix}code": obj["code"],
                    f"{prefix}name": obj.get("name"),
                    f"{prefix}location": obj.get("location"),
                    f"{prefix}unit": obj.get("unit"),
                    f"{prefix}type":  obj.get("type", "process"),
                }
                if prefix == "col_":
                    dct["col_reference_product"] = obj.get("reference product")
                else:
                    dct["row_categories"] = (
                        "::".join(obj["categories"]) if obj.get("categories") else None
                    )
                    dct["row_product"] = obj.get("reference product")
                return dct

            return pd.DataFrame(
                [dict_for_obj(obj, prefix) for obj in objs]
            )

        if get_node and annotate:
            if row_dict:
                row_metadata_df = metadata_dataframe(
                    objs=[get_node(id=i) for i in np.unique(df_data['row_id'])],
                    prefix="row_",
                )
                df = df.merge(row_metadata_df, on="row_id")
            if col_dict:
                col_metadata_df = metadata_dataframe(
                    objs=[get_node(id=i) for i in np.unique(df_data['col_id'])],
                    prefix="col_",
                )
                df = df.merge(col_metadata_df, on="col_id")

        return df

    ####################
    ### Contribution ###
    ####################

    # def top_emissions(self, **kwargs):
    #     """Call ``bw2analyzer.ContributionAnalyses.annotated_top_emissions``"""
    #     try:
    #         from bw2analyzer import ContributionAnalysis
    #     except ImportError:
    #         raise ImportError("`bw2analyzer` is not installed")
    #     return ContributionAnalysis().annotated_top_emissions(self, **kwargs)

    # def top_activities(self, **kwargs):
    #     """Call ``bw2analyzer.ContributionAnalyses.annotated_top_processes``"""
    #     try:
    #         from bw2analyzer import ContributionAnalysis
    #     except ImportError:
    #         raise ImportError("`bw2analyzer` is not installed")
    #     return ContributionAnalysis().annotated_top_processes(self, **kwargs)

    def has(self, label: str) -> bool:
        """Shortcut to find out if matrix data for type ``{label}_matrix`` is present in the given data objects.

        Returns a boolean. Will return ``True`` even if data for a zero-dimensional matrix is given."""
        return any(
            True
            for package in self.packages
            for resource in package.resources
            if resource["matrix"] == f"{label}_matrix"
        )

    #####################
    ### Compatibility ###
    #####################

    @property
    def activity_dict(self):
        warnings.warn("This method is deprecated, please use `.dicts.activity` instead", DeprecationWarning)
        return self.dicts.activity

    @property
    def product_dict(self):
        warnings.warn("This method is deprecated, please use `.dicts.product` instead", DeprecationWarning)
        return self.dicts.product

    @property
    def biosphere_dict(self):
        warnings.warn("This method is deprecated, please use `.dicts.biosphere` instead", DeprecationWarning)
        return self.dicts.biosphere

    def reverse_dict(self):
        warnings.warn("This method is deprecated, please use `.dicts.X.reversed` directly", DeprecationWarning)
        return self.dicts.activity.reversed, self.dicts.product.reversed, self.dicts.biosphere.reversed


import math

class prime:
    primes = [2, 3]

    def getNthPrime(self, n):
        if (len(self.primes) >= n):
            return self.primes[n - 1]

        self.fillPrimesBelow(n)
        return self.primes[n - 1]

    def fillPrimesBelow(self, n):
        i = math.floor(self.primes[len(self.primes) - 1] / 6) * 6 + 5
        while (self.primes[len(self.primes) - 1] < n):
            if (self.isPrime(i)):
                self.primes.append(i)
            if (self.isPrime(i + 2)):
                self.primes.append(i + 2)
            i += 6

    def isPrime(self, n):
        if (n <= self.primes[-1]):
            return (n in self.primes)

        i = 0
        while (self.primes[i] * self.primes[i] <= n):
            if (n % self.primes[i] == 0):
                return False
            i += 1
        return True

    def outerIsPrime(self, n):
        if (n > self.primes[-1]):
            self.fillPrimesBelow(n + 2)
        return (n in self.primes)

concatPrimes = dict()
def isConcatPrime(a, b, pr):
    if ((a, b) in concatPrimes):
        return concatPrimes[(a, b)]

    c1 = int(str(pr.primes[a]) + str(pr.primes[b]))
    c2 = int(str(pr.primes[b]) + str(pr.primes[a]))
    result = (pr.outerIsPrime(c1) and pr.outerIsPrime(c2))
    concatPrimes[(a, b)] = result
    return result

p = prime()
p.fillPrimesBelow(15000)
done = False
a = 5

while (not done):
    for b in range(1, a):
        if (isConcatPrime(a, b, p)):
            for c in range(1, b):
                if (isConcatPrime(a, c, p) and isConcatPrime(b, c, p)):
                    for d in range(1, c):
                        if (isConcatPrime(a, d, p) and isConcatPrime(b, d, p) and isConcatPrime(c, d, p)):
                            for e in range(1, d):
                                if (isConcatPrime(a, e, p) and isConcatPrime(b, e, p) and isConcatPrime(c, e, p) and isConcatPrime(d, e, p)):
                                    keys = [a, b, c, d, e]
                                    done = True
                                    s = 0
                                    for k in keys:
                                        s += p.primes[k]
                                        print (str(k) + ' ' + str(p.primes[k]))
                                    print (s)
    a += 1
    if (a % 20 == 0):
        print (a)


"""
Module to create tables
- list of servers, storages, libraries
- list of hba fw and drivers
- list of servers, storages, libraries san connection
"""

import utilities.dataframe_operations as dfop
import utilities.report_operations as report

def portcmd_report_main(portshow_aggregated_df, storage_connection_statistics_df,
                            device_connection_statistics_df, data_names, report_headers_df, report_columns_usage_sr):
    """Function to create required report DataFrames out of aggregated DataFrame"""

    add_columns_lst = ['FW_Recommeneded', 'Driver_Recommeneded', 'FW_Supported', 'HW_Supported']
    portshow_aggregated_df = \
        portshow_aggregated_df.reindex(columns=[*portshow_aggregated_df.columns.tolist(), *add_columns_lst])
    # partition aggregated DataFrame to required tables
    servers_report_df, storage_report_df, library_report_df, hba_report_df, \
        storage_connection_df,  library_connection_df, server_connection_df = \
        report.generate_report_dataframe(portshow_aggregated_df, report_headers_df, report_columns_usage_sr, *data_names)

    # clean and sort DataFrames
    # device report
    servers_report_df = _clean_dataframe(servers_report_df, 'srv')
    hba_report_df = _clean_dataframe(hba_report_df, 'srv', duplicates = ['Идентификатор порта WWPN'])
    hba_report_df = device_name_duplicates_free_column(hba_report_df)
    storage_report_df = _clean_dataframe(storage_report_df, 'stor')
    storage_report_df = _multi_fabric(storage_report_df, report_columns_usage_sr)
    library_report_df = _clean_dataframe(library_report_df, 'lib')
    # device connection reports
    storage_connection_df = _clean_dataframe(storage_connection_df, 'stor', clean=True)
    storage_connection_df = device_name_duplicates_free_column(storage_connection_df)
    storage_connection_df = report.translate_values(storage_connection_df)
    library_connection_df = _clean_dataframe(library_connection_df, 'lib', clean=True)
    library_connection_df = device_name_duplicates_free_column(library_connection_df)
    library_connection_df = report.translate_values(library_connection_df)
    server_connection_df = _clean_dataframe(server_connection_df, 'srv', clean=True)
    server_connection_df = device_name_duplicates_free_column(server_connection_df)
    server_connection_df = report.translate_values(server_connection_df)

    storage_connection_statistics_report_df = connection_statistics_report(storage_connection_statistics_df, report_headers_df)
    device_connection_statistics_report_df = connection_statistics_report(device_connection_statistics_df, report_headers_df)
    return servers_report_df, storage_report_df, library_report_df, hba_report_df, \
            storage_connection_df,  library_connection_df, server_connection_df, \
                storage_connection_statistics_report_df, device_connection_statistics_report_df

def _clean_dataframe(df, mask_type,
                        duplicates = ['Фабрика', 'Имя устройства', 'Имя группы псевдонимов',
                                        'Класс устройства', 'Тип устройства'],
                        clean = False):
    """Auxiliary function to sort, remove duplicates and
    drop columns in cases they are not required in report DataFrame"""

    columns_empty = ['Медленное устройство', 'Подключено через AG',
                     'Real device behind AG', 'Максимальная скорость порта устройства, Гб/c']
    # list of columns to check if they are empty
    # list of columns to check if all values are equal
    columns_unique = ['Режим коммутатора', 'LSAN', 'Connected_NPIV', 'FC4s', 'FCoE']
    # list of columns to sort DataFrame on
    columns_sort = [
        'Фабрика', 'Расположение', 'Имя устройства', 'Порт устройства',
        'Подсеть', 'Имя коммутатора', 'Идентификатор порта WWPN'
        ]
    # create mask to filter required class only
    if mask_type == 'srv':
        mask = df['Класс устройства'].isin(['SRV', 'BLADE_SRV', 'SYNERGY_SRV', 'SRV_BLADE', 'SRV_SYNERGY'])
    elif mask_type == 'stor':
        mask = df['Класс устройства'] == 'STORAGE'
    elif mask_type == 'lib':
        mask = df['Класс устройства'] == 'LIB'
    elif mask_type == 'npiv':
        # to avoid warning fillna with "no"
        df['Connected_NPIV'].fillna('no', inplace=True)
        mask = df['Connected_NPIV'].str.contains('yes')
    # filter DataFrame base on hardware type
    df = df.loc[mask].copy()
    # check if columns required to sort on are in the DataFrame
    columns_sort = [column for column in columns_sort if column in df.columns]
    df.sort_values(by = columns_sort, inplace = True)

    if duplicates:
        duplicates = [column for column in duplicates if column in df.columns]

    # DataFrames are cleaned in two ways
    # by drop duplicate values in certain columns
    if duplicates and not clean:
        df.drop_duplicates(subset = duplicates, inplace = True)
    # or by drop entire column
    if clean:
        # if all values in the column are the same
        for column in columns_unique:
            if column in df.columns and df[column].nunique() < 2:
                df.drop(columns = [column], inplace = True)
        # if all values are None in the column
        for column in columns_empty:
            # if all values are None
            if column in df.columns and df[column].isna().all():
                df.drop(columns=[column], inplace = True)
            # if all non None values are 'No'
            # elif column in df.columns and pd.Series(df[column] == 'No', pd.notna(df[column])).all():
            elif column in df.columns and (df[column].dropna() == 'No').all():
                df.drop(columns = [column], inplace = True)

    # drop column if each device connected to single fabric_name only
    possible_equal_column_pairs = [
                                    ('Количество портов устройства в подсети фабрики', 'Количество портов устройства в фабриках подсети'),
                                    ('Всего портов устройства', 'Количество портов устройства в подсетях фабрики')]
    df = dfop.drop_equal_columns(df, possible_equal_column_pairs)
    return df

def _multi_fabric(df, report_columns_usage_sr):
    """
    Function to check if device ports connected to different Fabrics.
    For example, main Fabric and replication Fabric.
    If yes then join Fabric cells values in one cell
    """

    df_columns = df.columns
    if not 'Имя устройства' in df_columns:
        return df

    if report_columns_usage_sr['fabric_name_usage'] and not df['Имя устройства'].is_unique:
        df['Фабрика'].fillna('nan', inplace=True)
        # if severeal aliases for one wwnp then combine all into one alias
        identical_values = {k: 'first' for k in df.columns[2:]}
        df = df.groupby(['Имя устройства'], as_index = False).agg({**{'Фабрика': ', '.join}, **identical_values})
        df = df.reindex(columns = df_columns)
        df = dfop.remove_duplicates_from_string(df, 'Фабрика')
    return df

def device_name_duplicates_free_column(df):
    """Function to create column with duplicates free device names"""

    duplicates_subset = ['Фабрика', 'Имя устройства', 'Тип устройства']
    duplicates_subset = [column for column in duplicates_subset if column in df.columns]
    df = dfop.remove_duplicates_from_column(df, 'Имя устройства', duplicates_subset, duplicates_free_column_name='Название устройства')
    df = dfop.drop_equal_columns(df, [('Имя устройства', 'Название устройства')])
    return df

def connection_statistics_report(connection_statistics_df, report_headers_df):
    """Function to create report table out of connection_statistics_df DataFrame"""

    # translate_dct = dct_from_columns('customer_report', max_title, 'Статистика_подключения_устройств_перевод_eng',
    #                                 'Статистика_подключения_устройств_перевод_ru', init_file = 'san_automation_info.xlsx')

    connection_statistics_report_df = connection_statistics_df.copy()

    # drop FLOGI column if there is no virtual (NPIV) ports login
    if {'FLOGI', 'Group_type'}.issubset(connection_statistics_report_df.columns):
        # device_type group is always physical_virtual
        mask_not_device_type = connection_statistics_report_df['Group_type'] != 'device_type'
        if (connection_statistics_report_df.loc[mask_not_device_type, 'FLOGI'] == 'physical').all():
            connection_statistics_report_df.drop(columns='FLOGI', inplace=True)

    # translate notes
    columns = [column for column in connection_statistics_df.columns if 'note' in column and connection_statistics_df[column].notna().any()]
    columns.append('Fabric_name')

    connection_statistics_report_df = report.translate_dataframe(connection_statistics_report_df, report_headers_df,
                                                            'Статистика_подключения_устройств_перевод', translated_columns=columns)
    # drop empty columns
    connection_statistics_report_df.dropna(axis=1, how='all', inplace=True)
    # drop zeroes for clean view
    connection_statistics_report_df = dfop.drop_zero(connection_statistics_report_df)
    return connection_statistics_report_df


from bs4 import BeautifulSoup
from .base import Base
import re

class Subscene(Base):
    async def search(self, title):
        """
        search function gives a title and search for it in subscene
        results will be passed as list of dicts, sample:
        {"name": "movie/series title", "link": "link to that title", "count": "counts"}
        """
        try:
            url = f"https://subscene.com/subtitles/searchbytitle?query={title}"
            resp = await self.aiorequest(url=url)  # send request to Subscene
            if " " in title:
                title = title.replace(" ", "+")
            soup = BeautifulSoup(resp, 'lxml')
            find_ul = soup.find('div', class_='search-result').find_all('ul')  # .find('ul')

            subtitles = []  # list for all finded subs to return
            for ul in find_ul:
                find_li = ul.find_all('li')
                for li in find_li:
                    base_li = li.find('div', class_='title').a
                    name = base_li.text  # movie/show name
                    link = base_li['href']  # movie/show url
                    try:  # movie/show subtitle counts
                        sub_count = li.find('div', class_='subtle count').text
                    except:
                        sub_count = li.find('span', class_='subtle count').text
                    sub_count = re.findall(r'\d+', sub_count)[0]

                    link = "https://subscene.com" + link

                    data = {"name": name, "link": link, "count": int(sub_count)}
                    subtitles.append(data)

            return subtitles
        except Exception as e:
            print(e)
            return []

    async def subtitles(self, url, lang=None):
        try:
            resp = await self.aiorequest(url, lang)
            soup = BeautifulSoup(resp, 'lxml')
            title = soup.find('div', class_='box clearfix').find('div', class_='top left').find('div',
                                                                                class_='header').h2.text
            try:
                title = title.replace("Flag", "")
                title = title.replace("Imdb", "").strip()
            except:
                pass

            table = soup.table.tbody.find_all('tr')

            subtitles = []
            for tr in table:
                try:
                    sub_name = tr.find('td', class_='a1').a.find_all('span')[1].text.strip()  # release title
                except AttributeError:
                    continue
                sub_link = tr.find('td', class_='a1').a['href']  # release link
                try:
                    sub_owner = tr.find('td', class_='a5').a.text.strip()  # sub owner
                except:
                    sub_owner = "Anonymous"
                try:
                    comments = tr.find('td', class_='a6').text.strip()
                except:
                    comments = ""
                sub_link = "https://subscene.com" + sub_link

                sub = {"name": sub_name, "link": sub_link, "owner": sub_owner, "comments": comments}
                subtitles.append(sub)

            re_subtitles = {"title": title, "subtitles": subtitles}
            return re_subtitles
        except Exception as e:
            print(e)
            return []

    async def down_page(self, url):
        resp = await self.aiorequest(url)
        soup = BeautifulSoup(resp, 'lxml')

        maindiv = soup.body.find('div', class_='subtitle').find('div', class_='top left')
        title = maindiv.find('div', class_='header').h1.span.text.strip()
        try:
            imdb = maindiv.find('div', class_='header').h1.a['href']
        except TypeError:
            imdb = ""
        try:
            poster = maindiv.find('div', class_='poster').a['href']
        except:
            poster = ""
        try:
            author_name = maindiv.find('div', class_='header').ul.find('li', class_='author').a.text.strip()
            author_link = f"https://subscene.com{maindiv.find('div', class_='header').ul.find('li', class_='author').a['href']}"
        except:
            author_link = ""
            author_name = "Anonymous"

        download_url = f"https://subscene.com{maindiv.find('div', class_='header').ul.find('li', class_='clearfix').find('div', class_='download').a['href']}"

        try:
            comments = maindiv.find('div', class_='header').ul.find('li', class_='comment-wrapper').find('div',
                                                                                class_='comment').text
        except:
            comments = ""
        try:
            release = maindiv.find('div', class_='header').ul.find('li', class_='release').find_all('div')
            releases = ""
            for i in range(2):
                r = release[i].text.strip()
                releases = releases + f"\n{r}"
        except Exception as e:
            releases = ""

        response = {"title": title, "imdb": imdb, "poster": poster, "author_name": author_name,
                    "author_url": author_link, "download_url": download_url, "comments": comments, "releases": releases}
        return response

    async def download(self, url, file_path):
        resp = await self.download_file(url, file_path)

        return resp


# Fennell, Matthew
# CPTR 454
# HW 5 Programming Problem

# 6.3.10
# Write a program for constructing a 2-3 tree for a given list of n integers

# Basic 2-3 Tree Algorithm

# From the text: A 2-3 tree is a tree that can have 2-nodes or 3-nodes.

# 2-nodes: A 2-node contains a single key K and has two children:
# the left child serves as the root of a subtree whose keys are less than K, and
# the right child serves as the root of a subtree whose keys are greater than K.
# In other words, a 2-node is the same kind of node we have in the classical
# binary search tree.

# 3-nodes: A 3-node contains two keys K1 and K2 (K1<K2) and has three children.
# The leftmost child serves as the root of a subtree with keys less than K1.
# The middle child serves as the root of a subtree with keys between K1 and K2.
# The rightmost child serves as the root of a subtree with keys greater than K2.

# The last requirement of the 2-3 tree is that all its leaves must be on the same level.
# In other words, a 2-3 tree is always perfectly height balanced: the length of
# a path from the root to a leaf is the same for every leaf.

# On empty tree:
# Just make a node

# Otherwise:
# Search for K
# If you end on a 2 node: add as the first or second key
# If you end on a 3 node: split the leaf in two; put the smaller in one leaf, promote the middle, and put the largest in the other

import sys
import random
import math

if(len(sys.argv)==2):
    n_list_length = int(sys.argv[1])
else:
    print("Please input the number of integers to be generated: ")
    n_list_length = int(input())

print(n_list_length, "integers will be generated.")

n_list = []

for integer in range(n_list_length):
    integer = random.randint(1,50)
    n_list.append(integer)

for entry in n_list:
    print(entry)

# Node Object
# list of keys
# list of links to children
# pointer to parent
# function to quickly give degree of node
# function to explode and regroup?

class Node:
    key_list = []
    child_link_list = []
    #parent_link
    def __init__(self,key):
        self.key_list.append(key)
        print("This node has been created with ",key," as its key.")
    def NodeDegree(self):
        return len(self.key_list)
    def AddKey(self,key):
        if(self.NodeDegree()==1):
            if(key<self.key_list[0]):
                self.key_list.insert(0,key)
            else:
                self.key_list.append(key)
        elif(self.NodeDegree()==2):
            if(key<self.key_list[0]):
                self.key_list.insert(0,key)
            elif(key<self.key_list[1]):
                self.key_list.insert(1,key)
            else:
                self.key_list.append(key)
        elif(self.NodeDegree()==3):
            print("NODE IS FULL")
    def PrintKeyList(self):
        print("Printing Keys:")
        for key in self.key_list:
            print(key)

start_node = Node(n_list[0])
start_node.PrintKeyList()
start_node.AddKey(n_list[1])
start_node.PrintKeyList()
start_node.AddKey(n_list[2])
start_node.PrintKeyList()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        '''
        当前的树是否包含 p 或 q 子节点
        如果包含，返回 True，如果不包含返回 False
            如果当前的 root/左子树/右子树 包含超过 p 和 q（True 的数量超过 2 个）
            将 ans 更新为当前的根，因为当前的根必定是 lowestCommonAncestor
        '''
        self.ans = root

        def lca(root):
            if not root:
                return False
            left = lca(root.left)
            right = lca(root.right)

            mid = root == p or root == q

            if mid + left + right >= 2:
                self.ans = root

            return mid or left or right

        lca(root)
        return self.ans


from DeckShuffle import deck

def score(cards):
    count = 0
    aceCount = 0

    for i in cards:
        if (i[1] == 'T' or i[1] == 'J' or i[1] == 'Q' or  i[1] == 'K'):
            count += 10

def createCards(myDeck):
    card1 = []
    card2 = []
    card1.append(myDeck.pop())
    card2.append(myDeck.pop())
    print (card1)


'''
Split audio into segments for easier inference
'''

import math
import multiprocessing
import os
from multiprocessing import freeze_support

from pydub import AudioSegment

class SplitWavAudio:

    def __init__(self, file_path, file, dest_path):
        self.file_path = file_path
        self.file = file
        self.dest_path = dest_path
        self.filepath = os.path.join(file_path, file)
        self.audio = AudioSegment.from_wav(self.filepath)

    #  self.resample = self.audio.resample(sample_rate_Hz=22050, channels=1)

    def get_duration(self):
        return self.audio.duration_seconds

    def single_split(self, from_min, to_min, split_filename):
        t1 = from_min * 7 * 1000  # convert to milliseconds
        t2 = to_min * 7 * 1000
        split_audio = self.audio[t1:t2]
        resampled = split_audio.set_frame_rate(22050)  # change the sampling rate to 22050 Hz
        resampled.export(self.dest_path + '\\' + split_filename, format="wav")

    def multiple_split(self, min_per_split):
        total_mins = math.ceil(self.get_duration() / 7)
        for i in range(0, total_mins, min_per_split):
            split_fn = str(i) + '_' + self.file
            self.single_split(i, i + min_per_split, split_fn)
            print(str(i) + ' done')
            if i == total_mins - min_per_split:
                print('split successfully')

def split_audio_files(file_path: str, file: str, dest_path: str) -> None:
    split_wav = SplitWavAudio(file_path, file, dest_path)
    split_wav.multiple_split(1)

file_path = "E:/AlanWattsMaterialSorted/split_audio3/"
dest_path = "E:/AlanWattsMaterialSorted/split_audio4/"

# split_audio_files('E:/AlanWattsMaterialSorted/split_audio3/', '0_03_-_Myth_and_Religion_-_Not_What_Should_Be.mp3_2022-11-19_19_52_45.wav', 'E:/AlanWattsMaterialSorted/split_audio4/')

# create a list of input arguments for the function
inputs = [(file_path, file, dest_path) for file in os.listdir(file_path)]

print(inputs)
# create a Process pool with 16 worker processes
if __name__ == '__main__':
    freeze_support()
    p = multiprocessing.Pool(16)
    p.starmap(split_audio_files, inputs)

# for i, x, z in inputs:
#     split_audio_files(i, x, z)
'''With this implementation, the worker processes will execute the convert_audio_to_wav function
with each set of arguments in the inputs list, and each worker process will convert one audio file at a time.'''

# confirm sampling rate
# file_path = "E:/AlanWatts/dataset/split_audio/"
# import os
# import wave
#
# for file_name in os.listdir(file_path):
#     print(file_name)
#     with wave.open(os.path.join(file_path, file_name), "rb") as wave_file:
#         frame_rate = wave_file.getframerate()
#         print(frame_rate)
#         break


import os
import re
import subprocess
from typing import List, Optional, Set, Tuple

from bygg.common_types import CommandStatus

def create_shell_command(shell_command: str, message: Optional[str] = None):
    def call_shell_command(inputs: Optional[Set[str]], outputs: Optional[Set[str]]):
        # Map stderr onto stdout and return both as the output
        process = subprocess.run(
            shell_command,
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            encoding="utf-8",
        )
        return CommandStatus(process.returncode, message, process.stdout)

    return lambda ctx: call_shell_command(ctx.inputs, ctx.outputs)

def filenames_from_pattern(
    input_files: List[str], in_pattern: str, out_pattern: str
) -> List[Tuple[str, str]]:
    """
    Generate a list of tuples with the input and output file names from a a list of
    input file names and a pattern like in Makefile pattern rules. File names that don't
    match the pattern are ignored. Example:

      ["/foo/bar/baz.txt.j2"], "%.txt.j2", "out_%.txt")
        => [("/foo/bar/baz.txt.j2", "/foo/bar/out_baz.txt")]
    """

    output_files = []
    matcher = re.compile(in_pattern.replace("%", "(.+)"))
    for input_file in input_files:
        head, tail = os.path.split(input_file)
        matches = matcher.match(tail)
        if matches:
            output_file = os.path.join(head, out_pattern.replace("%", matches.group(1)))
            output_files.append((input_file, output_file))
    return output_files


from deap import base
from deap import creator
from deap import tools
from deap import algorithms

import random
import numpy

import matplotlib.pyplot as plt
import seaborn as sns

import knapsack
from utils import processing_str_lst

# Genetic Algorithm constants:
POPULATION_SIZE = 65
P_CROSSOVER = 0.9  # probability for crossover
P_MUTATION = 0.1   # probability for mutating an individual
MAX_GENERATIONS = 50
HALL_OF_FAME_SIZE = 2

def processing_data_genetic_algorithm(process_lst):
    lst_processed = processing_str_lst(process_lst)

    items = []
    for i in range(2, int(lst_processed[0]) + 2):
        items.append((f"{i - 2}", int(lst_processed[i].split()[0]), int(lst_processed[i].split()[1])))

    capacities = int(lst_processed[1])

    return items, capacities

def initData(items, capacities):
    knapsack_init = knapsack.Knapsack01Problem(items, capacities)
    return knapsack_init

def run(items, capacities):
    # set the random seed:
    knapsack_init = initData(items, capacities)
    RANDOM_SEED = 19522081
    random.seed(RANDOM_SEED)

    toolbox = base.Toolbox()

    # create an operator that randomly returns 0 or 1:
    toolbox.register("zeroOrOne", random.randint, 0, 1)

    # define a single objective, maximizing fitness strategy:
    creator.create("FitnessMax", base.Fitness, weights=(1.0,))

    # create the Individual class based on list:
    creator.create("Individual", list, fitness=creator.FitnessMax)

    # create the individual operator to fill up an Individual instance:
    toolbox.register("individualCreator", tools.initRepeat, creator.Individual, toolbox.zeroOrOne, len(knapsack_init))

    # create the population operator to generate a list of individuals:
    toolbox.register("populationCreator", tools.initRepeat, list, toolbox.individualCreator)

    # fitness calculation
    def knapsackValue(individual):
        return knapsack_init.getValue(individual), # return a tuple

    toolbox.register("evaluate", knapsackValue)

    # genetic operators:mutFlipBit

    # Tournament selection with tournament size of 3:
    toolbox.register("select", tools.selTournament, tournsize=3)

    # Single-point crossover:
    toolbox.register("mate", tools.cxTwoPoint)

    # Flip-bit mutation:
    # indpb: Independent probability for each attribute to be flipped
    toolbox.register("mutate", tools.mutFlipBit, indpb=1.0/len(knapsack_init))

    # create initial population (generation 0):
    population = toolbox.populationCreator(n=POPULATION_SIZE)

    # prepare the statistics object:
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("max", numpy.max)
    stats.register("avg", numpy.mean)

    # define the hall-of-fame object:
    hof = tools.HallOfFame(HALL_OF_FAME_SIZE)

    # perform the Genetic Algorithm flow with hof feature added:
    population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
                                              ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)

    # print best solution found:
    best = hof.items[0]
    print("-- Best Ever Individual = ", best)
    print("-- Best Ever Fitness = ", best.fitness.values[0])

    totalWeight, totalValue = knapsack_init.printItems(best)

    # extract statistics:
    # maxFitnessValues, meanFitnessValues = logbook.select("max", "avg")

    # plot statistics:
    # sns.set_style("whitegrid")
    # plt.plot(maxFitnessValues, color='red')
    # plt.plot(meanFitnessValues, color='green')
    # plt.xlabel('Generation')
    # plt.ylabel('Max / Average Fitness')
    # plt.title('Max and Average fitness over Generations')
    # plt.savefig(f'TestResults/Genetic/{figure_name}.png')
    # plt.close()

    return best.fitness.values[0], totalWeight, totalValue


from operator import index
import random

def create_list(min_num : int, max_num : int, len_num : int) :
    '''Создаёт случайную последовательность целых чисел'''
    return [random.randint(min_num, max_num) for i in range(len_num)]

def analise_list(nums : list) :
    ''' Возвращает список неповторяющихся элементов,
    из которых состоит последовательность nums'''
    out_list = nums.copy()
    out_list.sort()

    current_index = 0
    while current_index < len(out_list) - 1 :
        if out_list[current_index] == out_list[current_index + 1] :
            out_list.pop(current_index + 1)
        else :
            current_index += 1

    return out_list

lst = create_list(1, 15, 25)
print('Primary list :')
print(lst)
print('List of numbers :')
print(analise_list(lst))


import numpy as np
import math as math
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.lines import Line2D

#-------> FUNCTIONS <-------

def FSLE(timeseries,do= 0.7,num=70,r=1.1):

    GridGoals = np.zeros([num])
    GridGoals[0] = do
    FSLE = np.zeros([3,num])         #I would like to keep the second row as index of how many pairs compute that mean, you see what I mean?

    for i in range (0,num-1) :
        GridGoals[i+1] = GridGoals[i]*r

    Errors=[]
    for i in range(0,num) :
        n = 0
        Time = 0
        for t in range(0,len(timeseries)) :
            A = timeseries[t]
            for k in range(1,len(A[0][:])) :
                if A[0][k]> GridGoals[i] and A[0][k-1]< GridGoals[i]:
                    Time = Time + (np.abs(A[1][k]-A[1][0])/24)
                    n = n+1
                    Errors.append(np.abs(A[1][k]-A[1][0])/24)
                    break
        if n != 0 :
            FSLE[0,i] = math.pow(Time/n,-1)*math.log(r)
            FSLE[1,i] = n
            Var = 0
            for p in range(0,len(Errors)) :
                Var = Var + ((Time/n - Errors[p])*(Time/n - Errors[p]))/n
                FSLE[2,i] = math.pow(Var,0.5) * math.pow(Time/n,-2)*math.log(r)
        else :
            print("Warning  :",i)
        while len(Errors) > 0 : Errors.pop()
    return GridGoals,FSLE

def Kd(timeseries):
    MaxLen = 1
    for i in range(len(timeseries)):
        if timeseries[i].shape[1] > MaxLen:
            MaxLen  =  timeseries[i].shape[1]
    K = np.zeros((len(timeseries),MaxLen,2))

    for i in range(len(timeseries)):                                           # Iterate over the different pairs
        for j in range(len(timeseries[i][0])-1):                               # Iterate over time
            K[i,j,0] = ((timeseries[i][0][j+1]*1000)**2-(timeseries[i][0][j]*1000)**2)/3600/2
            K[i,j,1] = (timeseries[i][0][j]+timeseries[i][0][j+1])/2
    return K

##-------> MAIN <-------
pairs = np.genfromtxt('Data/UnPair.txt', delimiter=',')
DirecInputForward = "Data/ForwardDistances/"
DirecInputBackward = "Data/BackwardsDistances/"

PairAsy = []
PairSyFor =  []
PairSyBac =  []
ChancePairFor = []
ChancePairBac = []

for i in range (0,len(pairs)):
   A = np.genfromtxt(DirecInputBackward+'BDPair'+str(i)+".csv", delimiter=',')  #It read the file and copy in A
   Ab = np.genfromtxt(DirecInputForward+'FDPair'+str(i)+".csv", delimiter=',')
   if len(A.shape) == 1 :
      PairAsy.append(Ab)
   else :
      if A[0][-1] < 5 :
         PairSyFor.append(Ab)
         PairSyBac.append(A)
      else :
         ChancePairFor.append(Ab)
         ChancePairBac.append(A)

#############################---FSLE---###############################

#GridGoals, FSLE_Asy = FSLE(PairAsy)
#GridGoals, FSLE_SyFor = FSLE(PairSyFor)
#GridGoals, FSLE_SyBac = FSLE(PairSyBac)
GridGoals, FSLE_ChanceFor = FSLE(ChancePairFor)
GridGoals, FSLE_ChanceBac = FSLE(ChancePairBac)

xError = np.zeros(len(GridGoals)) #Error space (equal to zero)

#############################---Diffusivity---################################
#KPA = Kd(PairAsy)
#KPF = Kd(PairSyFor)
#KPB = Kd(PairSyBac)
KCF = Kd(ChancePairFor)
KCB = Kd(ChancePairBac)

#-------> PLOT <-------
font = {'family' : 'normal',
        'weight' : 'bold',
        'size'   : 13}

matplotlib.rc('font', **font)

fig, ax1 = plt.subplots()

ax1.set_yscale('log')
ax1.set_xscale('log')
ax1.set_xlabel('Distance (km)')

ax1.set_ylabel('FSLE [$day^{-1}$]')

#ax1.plot(GridGoals, FSLE_SyFor[0,:], '-o', color='pink', label='SyForw')
#ax1.fill_between(GridGoals, FSLE_SyFor[0,:]+(FSLE_SyFor[2,:]/2), FSLE_SyFor[0,:]-(FSLE_SyFor[2,:]/2), facecolor='pink', alpha=0.5)
#
#ax1.plot(GridGoals, FSLE_SyBac[0,:], '-o', color='gray', label='SyBack')
#ax1.fill_between(GridGoals, FSLE_SyBac[0,:]+(FSLE_SyBac[2,:]/2), FSLE_SyBac[0,:]-(FSLE_SyBac[2,:]/2), facecolor='gray', alpha=0.5)
#
#ax1.plot(GridGoals, FSLE_Asy[0,:], '-o', color='brown', label='Asy')
#ax1.fill_between(GridGoals, FSLE_Asy[0,:]+(FSLE_Asy[2,:]/2), FSLE_Asy[0,:]-(FSLE_Asy[2,:]/2), facecolor='brown', alpha=0.5)

ax1.plot(GridGoals, FSLE_ChanceFor[0,:], '-o', color='red', label='Forward')
ax1.fill_between(GridGoals, FSLE_ChanceFor[0,:]+(FSLE_ChanceFor[2,:]/2), FSLE_ChanceFor[0,:]-(FSLE_ChanceFor[2,:]/2), facecolor='red', alpha=0.5)

ax1.plot(GridGoals, FSLE_ChanceBac[0,:], '-o', color='blue', label='Backward')
ax1.fill_between(GridGoals, FSLE_ChanceBac[0,:]+(FSLE_ChanceBac[2,:]/2), FSLE_ChanceBac[0,:]-(FSLE_ChanceBac[2,:]/2), facecolor='blue', alpha=0.5)

ax1.plot(np.logspace(-0.2,0.5),[1.5]*50,':',color='black',linewidth=3.0,label = 'Exponential')
ax1.plot(GridGoals,GridGoals**(-2/3)*1.4,'-',dashes=[5, 5],color='black',linewidth=2.5,label = 'Richardson')
ax1.plot(GridGoals,GridGoals**(-1),'-',color='black',linewidth=2.5,label = 'Shear')
ax1.plot(np.logspace(2,3),np.logspace(2,3)**(-2)*500,':',color='black',label = 'Diffusive')
ax1.axvline(4.513,10**(-3),1,color='green',label='Rossby radius')

#ax2 = ax1.twinx()
#ax2.set_ylabel('Components')
#ax2.plot(GridGoals, FSLE_SyFor[1,:], color='pink')
#ax2.plot(GridGoals, FSLE_SyBac[1,:], color='gray')
#ax2.plot(GridGoals, FSLE_Asy[1,:], color='brown')
#ax2.plot(GridGoals, FSLE_ChanceFor[1,:], color='red')
#ax2.plot(GridGoals, FSLE_ChanceBac[1,:], color='blue')

fig.tight_layout()  # otherwise the right y-label is slightly clipped
legend = ax1.legend(loc='upper right', shadow=True, fontsize='x-large')
plt.show()

fig, ax5 = plt.subplots()
ax5.set_yscale('log')
ax5.set_xscale('log')
ax5.set_ylabel('Diffusivity K [$m^2$/s]')
ax5.set_xlabel('Distance (km)')
#ax5.plot(KPA[:,:,1],KPA[:,:,0],'o',color='brown',alpha=0.3)
#ax5.plot(KPB[:,:,1],KPB[:,:,0],'o',color='gray',alpha=0.3)
#ax5.plot(KPF[:,:,1],KPF[:,:,0],'o',color='pink',alpha=0.3)
ax5.plot(KCF[:,:,1],KCF[:,:,0],'o',color='red',alpha=0.1,label='Forward')
ax5.plot(KCB[:,:,1],KCB[:,:,0],'o',color='blue',alpha=0.1,label='Backward')
ax5.plot(np.logspace(0,1),np.logspace(0,1)**2*30,':',color='black',linewidth=3.0,label = 'Exponential')
ax5.plot(np.logspace(0,3),np.logspace(0,3)**1*400,'-',color='black',linewidth=2.5,label = 'Shear')
ax5.plot(np.logspace(0,3),np.logspace(0,3)**(4/3)*60,'-',dashes=[5, 5],color='black',linewidth=2.5,label = 'Richardson')
ax5.plot(np.logspace(2.6,3),[4.5*10**5]*50,':',color='black',linewidth=2.0,label = 'Diffusive')
ax5.axvline(4.513,10**(-3),1,color='green',label='Rossby radius')
custom_lines = [Line2D([0], [0],marker='o', color='r'), Line2D([0], [0],marker='o', color='b'),Line2D([0], [0],linestyle=':', color='k',linewidth=4),Line2D([0], [0],linestyle='-',color='black',linewidth=3.5),Line2D([0], [0],linestyle='-',dashes=[5,5],color='black',linewidth=3.5),Line2D([0], [0],linestyle=':',color='black',linewidth=2.0),Line2D([0], [0],color='green')]
plt.legend(custom_lines, ['Forward','Backward','Exponential','Shear','Richardson','Diffusive','Rossby radius'])
plt.show()

# backward and forward timeseries
b = []
f = []
f6 = plt.figure(6)
ax6 = plt.axes()
plt.ylabel('Drifter dispersion $D^2$ [$km^2$]')
plt.xlabel('Time since minimum [h]')
for i in range(len(ChancePairFor)):
    b += [np.square(ChancePairBac[i][0])]
    f += [np.square(ChancePairFor[i][0])]
    ax6.loglog(np.linspace(1,len(b[i])-1,len(b[i])-1),b[i][1:],color='b')
    ax6.loglog(np.linspace(1,len(f[i])-1,len(f[i])-1),f[i][1:],color='r')
custom_lines = [Line2D([0], [0], color='r'), Line2D([0], [0], color='b'),Line2D([0], [0],linestyle=':', color='k',linewidth=4),Line2D([0], [0],linestyle='-',color='black',linewidth=3.5),Line2D([0], [0],linestyle='-',dashes=[5,5],color='black',linewidth=3.5),Line2D([0], [0],linestyle=':',color='black',linewidth=2),Line2D([0], [0],color='green')]
ax6.plot(np.logspace(0,0.75),np.exp(np.logspace(0,0.75))*0.1,':',color='black',linewidth=4.0,label = 'Exponential')
ax6.plot(np.logspace(1,3),np.logspace(1,3)**(2)*0.1,'-',color='black',linewidth=3.5,label = 'Shear')
ax6.plot(np.logspace(1.4,3),np.logspace(1.4,3)**(3)*0.001,'-',dashes=[5,5],color='black',linewidth=3.5,label = 'Richardson')
ax6.plot(np.logspace(3,4),np.logspace(3,4)*100,':',color='black',linewidth=2.0,label = 'Diffusive')
ax6.axhline(4.513**2,color='green')
plt.legend(custom_lines, ['Forward','Backward','Exponential','Shear','Richardson','Diffusive','Rossby radius'])


import cv2
import webbrowser

cap = cv2.VideoCapture(0)

detector = cv2.QRCodeDetector()

while True:
    ret, frame = cap.read()
    data = detector.detectAndDecode(frame)

    if data[0] != "":
        print(data[0])
        idata = str(data[0])
        webbrowser.open(idata, new=0, autoraise=True)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.releasse()
cv2.destroyAllWindows()


import re

# Regex pattern to match the Event logs
regex_pattern = r'\d{2}/\d{2} \d{2}:\d{2}:\d{2} (EVENT|TRACE)\s+:(.*)'

# Open the input file
with open('input.log', 'r') as input_file:
    # Open the output file for writing
    with open('output.log', 'w') as output_file:
        # Iterate over each line in the input file
        for line in input_file:
            # print(line)  # Print the line for debugging
            # Apply the regex pattern to each line
            match = re.search(regex_pattern, line)
            if match:
                # Write the matched Event log to the output file
                output_file.write(match.group().strip() + '\n')


from telebot.types import CallbackQuery
from telebot.types import InlineQuery, InlineQueryResultCachedDocument, InlineQueryResultArticle, \
    InputTextMessageContent

from app.models import User
from app.services.files import get_file
from app.utils.helper import generate_inline_id
from ...base import callback_query_base, inline_base
from ...helpers import mark_user
from ...keyboards.inline import get_edit_inline_markup
from ...loader import bot, bot_username

@bot.inline_handler(lambda q: q.query.startswith('file'))
@inline_base()
def inline_file(inline_query: InlineQuery):
    id = inline_query.query[4:]

    results = [InlineQueryResultArticle(
        id=generate_inline_id('not_found'),
        title='Файл не найден',
        thumb_url='https://images.emojiterra.com/google/android-11/512px/274c.png',
        input_message_content=InputTextMessageContent('Файл не найден ❌')
    )]

    if not id or not id.isdigit():
        return bot.answer_inline_query(inline_query.id, results=results, cache_time=1)

    file = get_file(int(id))

    if not file:
        return bot.answer_inline_query(inline_query.id, results=results, cache_time=1)

    file_available = True

    try:
        bot.get_file(file.file_id)
    except Exception as e:
        file_available = e.result_json['description'] == 'Bad Request: file is too big'

    if file_available:
        results = [InlineQueryResultCachedDocument(
            id=generate_inline_id(file.id),
            title=file.title,
            caption=file.title,
            document_file_id=file.file_id
        )]
    else:
        results = [InlineQueryResultArticle(
            id=generate_inline_id('error'),
            title=file.title,
            description='Похоже файл был удален',
            thumb_url='https://images.emojiterra.com/google/android-11/512px/274c.png',
            input_message_content=InputTextMessageContent(f'Файл "{file.title.lower()}" не найден ❌',
                                                          parse_mode='HTML')
        )]

    bot.answer_inline_query(inline_query.id, results=results, cache_time=1)

@bot.callback_query_handler(func=lambda call: call.data.startswith('file'))
@callback_query_base()
def inline_file_handler(call: CallbackQuery, current_user: User):
    deep_link = f'tg://resolve?domain={bot_username}&start=file'

    file_id = int(call.data[5:])

    file = get_file(file_id)
    if not file:
        return bot.answer_callback_query(call.id, 'Файл не найден', show_alert=True)

    text = f'{file.title}⠀'

    if call.message.chat.type != 'private':
        text = mark_user(text, call.from_user.id)

    markup = get_edit_inline_markup('edit_file', file.id) if current_user.is_admin() else None

    try:
        bot.send_document(call.message.chat.id, file.file_id, caption=text, reply_markup=markup)
        return bot.answer_callback_query(call.id, file.title)
    except Exception as e:
        if e.error_code == 400:
            return bot.answer_callback_query(call.id, 'Похоже файл был удален', show_alert=True)


import random
population = 1000

BIRTH_LOWER_RATE = 10
BIRTH_UPPER_RATE = 20

DEATH_LOWER_RATE = 5
DEATH_UPPER_RATE = 25

year = 1

print()
print('Welcome to the Gopher Population Simulator!')
print('Starting population: {}'.format(population))

while year <= 10:

    birth_rate = random.randint(BIRTH_LOWER_RATE, BIRTH_UPPER_RATE)
    death_rate = random.randint(DEATH_LOWER_RATE, DEATH_UPPER_RATE)

    current_year_birth_count = round(population * birth_rate / 100)
    current_year_death_count = round(population * death_rate / 100)

    population = population + current_year_birth_count - current_year_death_count

    print('Year {}'.format(year))
    print('****')
    print('{} gophers born. {} died.'.format(current_year_birth_count, current_year_death_count))
    print('Population: {}'.format(population), end='\n')

    year += 1


from tkinter import *

def hello():
    print("Hello!")

root = Tk()

menuBar = Menu(root, fg="white", bg="black")#main menu
root.config(menu=menuBar)

subMenu = Menu(menuBar, fg="white", bg="black")
menuBar.add_cascade(label="File", menu=subMenu)#funcionality

subMenu.add_command(label="New", command=hello)
subMenu.add_command(label="Save", command=hello)
subMenu.add_separator()
subMenu.add_command(label="Exit", command=root.quit)

editMenu = Menu(menuBar, fg="white", bg="black")
menuBar.add_cascade(label="Edit", menu=editMenu)

editMenu.add_command(label="Cut", command=hello)

root.mainloop()


#!/usr/bin/env python
import rospy

from std_msgs.msg import Int32 # Messages used in the node must be imported.
'''
"my_callback" is the callback method of the subscriber. Argument "msg" contains the published data.
'''
def my_callback(msg):
	rospy.loginfo("received data from topic_py: %d", msg.data)

rospy.init_node('subscriber_py') #initialzing the node with name "subscriber_py"

'''
A subscriber is registered in the below line.
First argument is the name of the topic.
Second argument is the message type of the subscribed topic.
Thrird argument is the name of the callback method. Whenever data is published on topic "topic_py", my_callback is called.
queue_size is the optional argument which is used to buffer up a maximum of 10 messages before beginning to throw away old ones if we are publishing too quickly.
'''
rospy.Subscriber("topic_py", Int32, my_callback, queue_size=10)

rospy.loginfo("subscriber_py node started and subscribed to topic_py") #debug statement

'''
rospy.spin() simply keeps your node from exiting until the node has been shutdown. Unlike roscpp::spin(), rospy.spin() does not affect the subscriber callback functions, as those have their own threads.
'''
rospy.spin()