# -*- coding: utf-8 -*-
from __future__ import unicode_literals, division, print_function, absolute_import
import os
import datetime
import decimal
import math

import testdata

from . import BaseTestCase, EnvironTestCase
import prom
from prom.model import Orm
from prom.config import Schema, Connection, DsnConnection, Index
from prom.config import Field
from prom.compat import *

class SchemaTest(BaseTestCase):
    def test_field_index_property(self):
        s = self.get_schema(
            foo=Field(str, index=True)
        )
        self.assertTrue("foo", s.indexes)
        self.assertFalse(s.indexes["foo"].unique)

    def test___init__(self):
        """
        I had set the class .fields and .indexes attributes to {} instead of None, so you
        could only ever create one instance of Schema, this test makes sure that's been fixed
        """
        s = Schema("foo")
        self.assertTrue(isinstance(s.fields, dict))
        self.assertTrue(isinstance(s.indexes, dict))

        s2 = Schema("bar")
        self.assertTrue(isinstance(s.fields, dict))
        self.assertTrue(isinstance(s.indexes, dict))

        s = Schema(
            "foo",
            bar=Field(int),
            che=Field(str, True),
            barche=Index("bar", "che")
        )
        self.assertTrue("bar" in s.fields)
        self.assertTrue("che" in s.fields)
        self.assertTrue("barche" in s.indexes)

    def test___getattr__(self):
        s = Schema("foo")

        with self.assertRaises(AttributeError):
            s.foo

        s.set_field("foo", Field(int, True))
        self.assertTrue(isinstance(s.foo, Field))

    def test_set_field(self):
        s = Schema("foo")

        with self.assertRaises(ValueError):
            s.set_field("", int)

        with self.assertRaises(ValueError):
            s.set_field("foo", "bogus")

        s.set_field("foo", Field(int))
        with self.assertRaises(ValueError):
            s.set_field("foo", int)

        s = Schema("foo")
        s.set_field("foo", Field(int, unique=True))
        self.assertTrue("foo" in s.fields)
        self.assertTrue("foo" in s.indexes)

        s = Schema("foo")
        s.set_field("foo", Field(int, ignore_case=True))
        self.assertTrue(s.foo.options["ignore_case"])

    def test_set_index(self):
        s = Schema("foo")
        s.set_field("bar", Field(int, True))
        s.set_field("che", Field(str))

        with self.assertRaises(ValueError):
            s.set_index("foo", Index())

        with self.assertRaises(ValueError):
            s.set_index("", Index("bar", "che"))

        s.set_index("bar_che", Index("che", "bar"))
        with self.assertRaises(ValueError):
            s.set_index("bar_che", Index("che", "bar"))

        s.set_index("testing", Index("che", unique=True))
        self.assertTrue(s.indexes["testing"].unique)

    def test_aliases_1(self):
        s = self.get_schema(
            foo=Field(int, aliases=["bar", "che"])
        )

        self.assertEqual(s.pk, s._id)
        self.assertEqual(s.foo, s.bar)
        self.assertEqual(s.foo, s.che)

        with self.assertRaises(AttributeError):
            s.faosdfjadkfljlk_does_not_exist

    def test_aliases_primary_key(self):
        s = self.get_schema()
        self.assertEqual(s._id, s.pk)

    def test_aliases_created_updated(self):
        orm_class = self.get_orm_class()
        s = orm_class.schema

        self.assertEqual(s._created, s.created)
        self.assertEqual(s._updated, s.updated)

        q = orm_class.query.lte_created(datetime.datetime.utcnow())
        self.assertTrue("_created" in q.fields_where)

        q = orm_class.query.lte_updated(datetime.datetime.utcnow())
        self.assertTrue("_updated" in q.fields_where)

    def test_create_orm_1(self):
        s = self.get_schema()
        o = s.create_orm()
        self.assertEqual(s, o.schema)
        self.assertEqual(s.table_name, o.table_name)
        self.assertEqual(s.fields.keys(), o().fields.keys())

    def test_create_orm_2(self):
        self.assertTrue(hasattr(Orm, "_id"))

        s = self.get_schema(_id=None)
        o = s.create_orm()

        self.assertEqual(None, o._id)
        self.assertTrue(hasattr(Orm, "_id"))

    def test_field_name(self):
        s = self.get_schema(_id=None)
        with self.assertRaises(AttributeError):
            s.field_name("bogus")

        r = s.field_name("bogus", None)
        self.assertIsNone(r)

    def test_field_model_name(self):
        o1_class = self.get_orm_class(
            bar=Field(str),
        )
        o2_class = self.get_orm_class(
            o1_id=Field(o1_class),
        )

        field_name = o2_class.schema.field_model_name(o1_class.model_name)
        self.assertEqual("o1_id", field_name)

class DsnConnectionTest(BaseTestCase):
    """Any general tests should go here and always use sqlite because that's
    installed with python. If you have SQLite or PostgreSQL specific connection
    config tests those should go into the appropriate insterface ConfigTest
    """
    def test_environ(self):
        os.environ['PROM_DSN'] = "prom.interface.sqlite.SQLite://:memory:#i0"
        os.environ['PROM_DSN_1'] = "SQLite://:memory:#i1"
        os.environ['PROM_DSN_2'] = "sqlite://:memory:#i2"
        os.environ['PROM_DSN_4'] = "sqlite://:memory:#i4"
        prom.configure_environ()
        self.assertTrue('i0' in prom.get_interfaces())
        self.assertTrue('i1' in prom.get_interfaces())
        self.assertTrue('i2' in prom.get_interfaces())
        self.assertTrue('i3' not in prom.get_interfaces())
        self.assertTrue('i4' not in prom.get_interfaces())

        prom.interface.interfaces.pop('i0', None)
        prom.interface.interfaces.pop('i1', None)
        prom.interface.interfaces.pop('i2', None)
        prom.interface.interfaces.pop('i3', None)
        prom.interface.interfaces.pop('i4', None)

    def test_dsn_options_type(self):
        dsn = "prom.interface.sqlite.SQLite:///tmp/sqlite.db?timeout=20.0"
        c = DsnConnection(dsn)
        self.assertTrue(isinstance(c.options["timeout"], float))

    def test_readonly(self):
        dsn = "SQLite:///tmp/sqlite.db?readonly=1"
        c = DsnConnection(dsn)
        self.assertTrue(c.readonly)

    def test_bad_classpath(self):
        dsn = 'bogus.earaskdfaksfk.Interface://host/dbname#bogus2'
        with self.assertRaises(ImportError):
            DsnConnection(dsn)

        dsn = 'bogus.earaskdfaksfk.Interface://host/dbname'
        with self.assertRaises(ImportError):
            DsnConnection(dsn)

        dsn = 'bogus.earaskdfaksfk.Interface://host/dbname#bogus1'
        with self.assertRaises(ImportError):
            DsnConnection(dsn)

class ConnectionTest(BaseTestCase):
    def test_interface_is_unique_each_time(self):
        c = Connection(
            interface_name="prom.interface.sqlite.SQLite",
            database=":memory:",
        )

        iids = set()
        inters = set()
        for x in range(10):
            inter = c.interface
            iid = id(inter)
            self.assertFalse(iid in iids)
            iids.add(iid)
            inters.add(inter)

    def test___init__(self):

        c = Connection(
            interface_name="prom.interface.sqlite.SQLite",
            database="dbname",
            port=5000,
            some_random_thing="foo"
        )

        self.assertEqual(5000, c.port)
        self.assertEqual("dbname", c.database)
        self.assertEqual({"some_random_thing": "foo"}, c.options)

class FieldTest(EnvironTestCase):
    def test_modified_pk(self):
        orm_class = self.get_orm_class()
        o = orm_class(foo=1, bar="2")
        f = o.schema.pk

        im = f.modified(o, 100)
        self.assertTrue(im)

        im = f.modified(o, None)
        self.assertFalse(im)

        o.save()

        im = f.modified(o, None)
        self.assertTrue(im)

        im = f.modified(o, o.pk + 1)
        self.assertTrue(im)

        im = f.modified(o, o.pk)
        self.assertFalse(im)

    def test_help(self):
        help_str = "this is the foo field"
        orm_class = self.get_orm_class(
            foo=Field(int, help=help_str)
        )

        f = orm_class.schema.foo
        self.assertEqual(help_str, f.help)

    def test_type_std(self):
        std_types = (
            bool,
            long,
            int,
            float,
            bytearray,
            decimal.Decimal,
            datetime.datetime,
            datetime.date,
        )
        if is_py2:
            std_types = (basestring,) + std_types
        else:
            std_types = basestring + std_types

        for field_type in std_types:
            f = Field(field_type)
            self.assertEqual(field_type, f.type)
            self.assertEqual(field_type, f.interface_type)
            self.assertIsNone(f.schema)
            self.assertFalse(f.is_serialized())

    def test_type_dict(self):
            f = Field(dict)
            self.assertEqual(dict, f.original_type)
            self.assertEqual(dict, f.interface_type)
            self.assertEqual(dict, f.type)
            self.assertIsNone(f.schema)
            self.assertFalse(f.is_serialized())

    def test_type_pickle(self):
        class Foo(object): pass
        pickle_types = (
            list,
            set,
            Foo,
        )

        for field_type in pickle_types:
            f = Field(field_type)
            self.assertEqual(field_type, f.original_type)
            self.assertEqual(bytes, f.interface_type)
            self.assertEqual(bytes, f.type)
            self.assertIsNone(f.schema)
            self.assertTrue(f.is_serialized())

    def test_type_fk(self):
        orm_class = self.get_orm_class()

        f = Field(orm_class)
        self.assertEqual(orm_class, f.original_type)
        self.assertEqual(long, f.interface_type)
        self.assertEqual(long, f.type)
        self.assertIsNotNone(f.schema)
        self.assertFalse(f.is_serialized())

    def test_type_fk_get(self):
        """ https://github.com/Jaymon/prom/issues/145 """
        class PrimaryKey(Field):
            def __init__(self):
                super().__init__(str, pk=True)
            def iset(self, orm, v):
                return str(v)
            def iget(self, orm, v):
                return int(v)

        foo_class = self.get_orm_class(_id=PrimaryKey(), _created=None, _updated=None)
        bar_class = self.get_orm_class(foo_id=Field(foo_class), _created=None, _updated=None)

        f = foo_class.create(pk=1)
        b = bar_class.create(foo_id=f.pk)

        foo_pk = bar_class.query.select_foo_id().one_pk(b.pk)
        self.assertTrue(isinstance(foo_pk, int))

    def test_serialize_lifecycle(self):
        orm_class = self.get_orm_class(
            foo=Field(dict, False)
        )

        o = orm_class()
        self.assertIsNone(o.foo)

        o.foo = {"bar": 1, "che": "two"}
        self.assertTrue(isinstance(o.foo, dict))
        o.save()
        self.assertTrue(isinstance(o.foo, dict))

        o2 = o.query.eq_pk(o.pk).one()
        self.assertTrue(isinstance(o2.foo, dict))
        self.assertEqual(1, o2.foo["bar"])
        self.assertEqual("two", o2.foo["che"])

    def test_choices(self):
        orm_class = self.get_orm_class(
            foo=Field(int, choices=set([1, 2, 3]))
        )
        o = orm_class()

        for x in range(1, 4):
            o.foo = x
            self.assertEqual(x, o.foo)

        o.foo = 1
        with self.assertRaises(ValueError):
            o.foo = 4
        self.assertEqual(1, o.foo)

        o.foo = None
        self.assertEqual(None, o.foo)

    def test_iget(self):
        orm_class = self.get_orm_class(
            foo=Field(int, iget=lambda o, v: bool(v))
        )

        o = orm_class()

        o.from_interface({"foo": 1})
        self.assertTrue(o.foo)
        self.assertTrue(isinstance(o.foo, bool))

    def test_iget_really_big_int(self):
        """Postgres will return Decimal for a really big int, SQLite will return
        an int. I'm not sure it's worth slowing down every select statement to
        check if an int is a decimal since this is such a rare use case but this
        test is here if I ever do want to address it

        https://github.com/Jaymon/prom/issues/162
        """
        orm_class = self.get_orm_class(
            foo=Field(int, True, precision=78)
        )
        o = orm_class.create(foo=int("9" * 77))
        o2 = orm_class.query.one_pk(o.pk)
        self.assertTrue(isinstance(o2.foo, (int, decimal.Decimal)))

    def test_iset(self):
        dt = datetime.datetime.utcnow()
        orm_class = self.get_orm_class(
            foo=Field(int, iset=lambda o, v: datetime.datetime.utcnow())
        )

        o = orm_class()
        self.assertIsNone(o.foo)

        fields = o.to_interface()
        self.assertLess(dt, fields["foo"])

        fields2 = o.to_interface()
        self.assertLess(fields["foo"], fields2["foo"])

    def test_iquery(self):
        class IqueryOrm(Orm):
            foo = Field(int)

            @foo.iquerier
            def foo(query, v):
                return 10

        q = IqueryOrm.query.is_foo("foo")
        self.assertEqual(10, q.fields_where[0].value)

    def test_datetime_jsonable_1(self):
        orm_class = self.get_orm_class(
            foo=Field(datetime.datetime)
        )

        o = orm_class()
        o.foo = self.get_past_datetime()
        r = o.jsonable()
        self.assertTrue("foo" in r)

    def test_default(self):
        class FDefaultOrm(Orm):
            foo = Field(int, default=0)
            bar = Field(int)

        o = FDefaultOrm()
        foo = o.schema.foo
        self.assertEqual(0, foo.fdefault(o, None))
        self.assertEqual(0, o.foo)

        bar = o.schema.bar
        self.assertEqual(None, bar.fdefault(o, None))
        self.assertEqual(None, o.bar)

    def test_fcrud(self):

        class FCrudOrm(Orm):
            interface = self.get_interface()
            foo = Field(int)

            @foo.fsetter
            def foo(self, v):
                return 0 if v is None else v

            @foo.fgetter
            def foo(self, v):
                ret = None if v is None else v + 1
                return ret

            @foo.fdeleter
            def foo(self, val):
                return None

        o = FCrudOrm(foo=0)

        self.assertEqual(1, o.foo)
        self.assertEqual(1, o.foo)

        pk = o.save()
        self.assertEqual(2, o.foo)
        self.assertEqual(2, o.foo)

        del o.foo
        self.assertEqual(None, o.foo)
        pk = o.save()
        self.assertEqual(1, o.foo)

        o.foo = 10
        self.assertEqual(11, o.foo)
        self.assertEqual(11, o.foo)

        o.foo = None
        self.assertEqual(1, o.foo)

    def test_icrud(self):
        class ICrudOrm(Orm):
            interface = self.get_interface()
            foo = Field(int)

            @foo.isetter
            def foo(self, v):
                if self.is_update():
                    v = v - 1
                else:
                    v = 0
                return v

            @foo.igetter
            def foo(self, v):
                if v > 1:
                    v = v * 100
                return v

        o = ICrudOrm()
        self.assertEqual(None, o.foo)

        o.save()
        self.assertEqual(0, o.foo)

        o.foo = 5
        self.assertEqual(5, o.foo)

        o.save()
        self.assertEqual(400, o.foo)

        o2 = o.query.one_pk(o.pk)
        self.assertEqual(400, o2.foo)

    def test_fdel(self):
        orm_class = self.get_orm_class()

        o = orm_class()

        self.assertFalse(o.schema.fields["foo"].modified(o, o.foo))

        o.foo = 1
        self.assertTrue(o.schema.fields["foo"].modified(o, o.foo))

        del o.foo
        self.assertFalse(o.schema.fields["foo"].modified(o, o.foo))

        with self.assertRaises(KeyError):
            o.to_interface()

    def test_fdeleter(self):
        class FDOrm(Orm):
            foo = Field(int)

            @foo.fdeleter
            def foo(self, val):
                return None

        o = FDOrm()
        o.foo = 1
        del o.foo
        self.assertEqual(None, o.foo)

    def test_property(self):
        class FieldPropertyOrm(Orm):
            foo = Field(int)

            @foo.fgetter
            def foo(self, val):
                return val

            @foo.fsetter
            def foo(self, val):
                return int(val) + 10 if (val is not None) else val

        o = FieldPropertyOrm()

        o.foo = 1
        self.assertEqual(11, o.foo)

        o.foo = 2
        self.assertEqual(12, o.foo)

        o.foo = None
        self.assertEqual(None, o.foo)

    def test_ref(self):
        m = testdata.create_module([
            "import prom",
            "class Foo(prom.Orm):",
            "    che = prom.Field(str)",
            "",
            "class Bar(prom.Orm):",
            "    foo_id = prom.Field(Foo)",
            ""
        ])

        Foo = m.module().Foo
        Bar = m.module().Bar

        self.assertTrue(isinstance(Bar.schema.fields['foo_id'].schema, Schema))
        self.assertTrue(issubclass(Bar.schema.fields['foo_id'].interface_type, long))

    def test_string_ref(self):
        modname = testdata.get_module_name()
        d = testdata.create_modules({
            "foo": [
                "import prom",
                "class Foo(prom.Orm):",
                "    interface = None",
                "    bar_id = prom.Field('{}.bar.Bar')".format(modname),
                ""
            ],
            "bar": [
                "import prom",
                "class Bar(prom.Orm):",
                "    interface = None",
                "    foo_id = prom.Field('{}.foo.Foo')".format(modname),
                ""
            ],
        }, modname)

        Foo = d.module("{}.foo".format(modname)).Foo
        Bar = d.module("{}.bar".format(modname)).Bar

        self.assertTrue(isinstance(Foo.schema.fields['bar_id'].schema, Schema))
        self.assertTrue(issubclass(Foo.schema.fields['bar_id'].interface_type, long))
        self.assertTrue(isinstance(Bar.schema.fields['foo_id'].schema, Schema))
        self.assertTrue(issubclass(Bar.schema.fields['foo_id'].interface_type, long))

    def test___init__(self):
        f = Field(str, True)
        self.assertTrue(f.required)
        self.assertTrue(issubclass(f.type, str))

        with self.assertRaises(TypeError):
            f = Field()

        f = Field(int, max_length=100)
        self.assertTrue(issubclass(f.type, int))
        self.assertEqual(f.options['max_length'], 100)

    def test___set_name___instance(self):
        class FooSN(Orm):
            bar = Field(str)
            _created = None
            _updated = None
            _id = None

        o = FooSN(bar="bar")
        self.assertEqual("bar", o.bar)

    def test___set_name___class(self):
        class FooSN(Orm):
            class bar(Field):
                type = str
            _created = None
            _updated = None
            _id = None

        o = FooSN(bar="bar")
        self.assertEqual("bar", o.bar)

    def test_get_size(self):
        """Makes sure sizes get set correctly, I've evidently had a bug in this for years (1-26-2023)"""
        f = Field(int, True, max_size=100)
        self.assertEqual(100, f.options["max_size"])

        f = Field(int, True, size=100)
        self.assertEqual(100, f.options["size"])

        f = Field(int, True, size=100)
        self.assertEqual(100, f.options["size"])

        f = Field(int, True, size=100, max_size=500)
        self.assertEqual(100, f.options["size"])
        self.assertFalse("max_size" in f.options)

        f = Field(int, True, min_size=100)
        self.assertEqual(100, f.options["min_size"])

        f = Field(int, True, min_size=100, max_size=500)
        self.assertEqual(100, f.options["min_size"])
        self.assertEqual(500, f.options["max_size"])

    def test_size_info_1(self):
        # A field with precision 65, scale 30 must round to an absolute value less than 10^35
        f = Field(float, precision=65, scale=30)
        r = f.size_info()
        self.assertLessEqual(r["size"], math.pow(10, 35))

        f = Field(str, size=32)
        r = f.size_info()
        self.assertLessEqual(32, r["size"])
        self.assertLessEqual(32, r["precision"])

        f = Field(int)
        r = f.size_info()
        self.assertLessEqual(2147483647, r["size"])

        f = Field(float, size="15.6")
        r = f.size_info()
        self.assertTrue(r["has_size"])
        self.assertEqual(21, r["precision"])
        self.assertEqual(6, r["scale"])

        f = Field(float, precision=78, scale=18)
        r = f.size_info()
        self.assertFalse(r["has_size"])
        self.assertTrue(r["has_precision"])

        f = Field(int, size=100)
        r = f.size_info()
        self.assertTrue(r["has_size"])
        self.assertEqual(100, r["size"])

        f = Field(int, precision=78)
        r = f.size_info()
        self.assertEqual(int("9" * 78), r["size"])

    def test_size_info_2(self):
        f = Field(int, True, max_size=int("9" * 78))
        r = f.size_info()
        self.assertEqual(78, r["precision"])

    def test_regex(self):
        orm_class = self.get_orm_class(
            foo=Field(str, True, regex=r"^[abcd]+$")
        )

        with self.assertRaises(ValueError):
            orm_class(foo="aazabbbbbddddd")

        o = orm_class(foo="aaaabbbbbddddd")
        self.assertTrue(o.foo)

class SerializedFieldTest(EnvironTestCase):
    def get_orm(self, field_type=dict, default=None):
        orm_class = self.get_orm_class(
            body=Field(field_type, default=default)
        )
        return orm_class()

    def test_default(self):
        o = self.get_orm(default=dict)
        o.body["foo"] = 1
        self.assertEqual(1, o.body["foo"])

    def test_imethods_pickle(self):
        o = self.get_orm()
        o.body = {"foo": 1}
        o.save()

        o2 = o.requery()
        self.assertEqual(o.body, o2.body)

    def test_modify(self):
        o = self.get_orm()
        o.body = {"bar": 1}
        o.save()

        o.body["che"] = 2
        o.save()

        o2 = o.requery()
        self.assertEqual(o.body, o2.body)

    def test_other_types(self):
        types = (
            list,
            set
        )

        for field_type in types:
            o = self.get_orm(field_type)
            o.body = field_type(range(100))
            o.save()

            o2 = o.requery()
            self.assertEqual(o.body, o2.body)


def findCircleNum(isConnected: list[list[int]]) -> int:
    n = len(isConnected)

    visited = [0] * n
    def dfs(i):
        if visited[i]:
            return 0
        visited[i] = 1

        for j, connection in enumerate(isConnected[i]):
            if connection == 1 and i != j:
                dfs(j)

        return 1

    return sum([dfs(i) for i in range(n)])


#import itertools
#import numpy as np
#import copy
import re   # r = re.compile(r'xxx'), m = r.match(str), print(m[1])
#import collections  # including deque
#import math
import time
#import pprint
#from dataclasses import dataclass, field

with open('day04.txt') as datafile:
    alldata = [list(map(int,re.split('\W+',x.strip()))) for x in datafile.readlines()]

testdata = [list(map(int,re.split('\W+',x.strip()))) for x in """2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8""".splitlines()]   #

thedata = testdata

thedata = alldata

# ------------------------------------------------------------------------------------
#  Part 1
# ------------------------------------------------------------------------------------

def rangeContained(a0,a1,b0,b1):
    a = set(range(a0,a1+1))
    b = set(range(b0,b1+1))
    #common = a.intersection(b)
    if a.issubset(b):
        return True
    if b.issubset(a):
        return True
    return False

def rangeOverlap(a0,a1,b0,b1):
    a = set(range(a0,a1+1))
    b = set(range(b0,b1+1))
    common = a.intersection(b)
    if len(common) == 0:
        return False # no overlap
    return True

if True:

    START = time.perf_counter()
    numcontained = 0

    for apair in thedata:
        if rangeContained(*apair):
            numcontained += 1

    print(f"Num contained={numcontained}")

    END = time.perf_counter()
    print(f"Time taken for part 1: {END - START} seconds")

# ------------------------------------------------------------------------------------
#  Part 2
# ------------------------------------------------------------------------------------

START = time.perf_counter()

numoverlap = 0

for apair in thedata:
    if rangeOverlap(*apair):
        numoverlap += 1

print(f"Num numoverlap={numoverlap}")

END = time.perf_counter()
print(f"Time taken for part 2: {END - START} seconds")


import pandas as pd
from sklearn.metrics import accuracy_score, f1_score
import pickle
import json

def main():
    # open saved model
    with open("model.pickle","rb") as f:
        model = pickle.load(f)

    # open test data
    data = pd.read_csv("data_test.csv")

    # do some processing
    X,y = process(data)

    # get metrics from predictions
    metrics = test(X,y,model)

    # save to JSON file
    save_result(metrics)

def process(data):
    # boring preprocessing
    X,y = data.iloc[:,:-1], data.iloc[:,-1]

    return X,y

def test(X,y,model):
    # using model to predict
    y_predicted = model.predict(X)

    # gathering metrics
    metrics = {
        'accuracy': round(accuracy_score(y,y_predicted),4),
        'f1_score': round(f1_score(y,y_predicted),4)
    }

    return metrics

def save_result(metrics):
    # save results to JSON file
    with open("metrics.json",'w') as f:
        json.dump(metrics,f)

if __name__ == "__main__":
    main()


from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError as DRFValidationError
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

from backend.school.api.serializers import (
    ClassAddSerializer,
    ClassroomSerializer,
    ClassSerializer,
    GradeSerializer,
    StudentRegistrationSerializer,
    StudentSerializer,
    StudentUpdateSerializer
)
from backend.school.models import Class, Classroom, Grade, Student

# class StudentViewSet(viewsets.ModelViewSet):
#     queryset = Student.objects.all()
#     serializer_class = StudentSerializer

class StudentViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving students.
    Uma ViewSet simples para listar ou recuperar alunos.
    """

    def get_serializer_class(self):
        # Muda o serializer dependendo da ação.
        if self.action == 'create':
            return StudentSerializer

        if self.action == 'update':
            return StudentUpdateSerializer

        return StudentSerializer

    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        return serializer_class(*args, **kwargs)

    def get_queryset(self):
        queryset = Student.objects.all()
        return queryset

    def get_object(self):
        queryset = self.get_queryset()
        pk = self.kwargs.get('pk')
        obj = get_object_or_404(queryset, pk=pk)
        return obj

    def list(self, request):
        # queryset = Student.objects.all()
        # serializer = StudentSerializer(queryset, many=True)
        # return Response(serializer.data)
        serializer = self.get_serializer(self.get_queryset(), many=True)
        # Sem paginação
        return Response(serializer.data)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk=None):
        queryset = Student.objects.all()
        student = get_object_or_404(queryset, pk=pk)
        serializer = StudentSerializer(student)
        return Response(serializer.data)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

    def destroy(self, request, pk=None):
        item = self.get_object()
        item.delete
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=['get'])
    def all_students(self, request, pk=None):
        queryset = Student.objects.all()
        serializer = StudentRegistrationSerializer(queryset, many=True)
        return Response(serializer.data)

class ClassroomViewSet(viewsets.ModelViewSet):
    queryset = Classroom.objects.all()
    serializer_class = ClassroomSerializer
    permission_classes = (AllowAny,)

class GradeViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Grade.objects.all()
    serializer_class = GradeSerializer
    permission_classes = (AllowAny,)

class ClassViewSet(viewsets.ModelViewSet):
    queryset = Class.objects.all()
    # serializer_class = ClassSerializer

    # def list(self, request, *args, **kwargs):
    #     user = self.request.user
    #     teacher = User.objects.get(username=user)

    #     if user is not None:
    #         queryset = Class.objects.filter(teacher=teacher)
    #     else:
    #         queryset = Class.objects.none()

    #     page = self.paginate_queryset(queryset)
    #     if page is not None:
    #         serializer = self.get_serializer(page, many=True)
    #         return self.get_paginated_response(serializer.data)

    #     serializer = self.get_serializer(queryset, many=True)
    #     return Response(serializer.data)

    def get_queryset(self):
        '''
        Retorna somente as aulas da pessoa logada no momento.
        '''
        user = self.request.user
        teacher = User.objects.get(username=user)

        if user is not None:
            queryset = Class.objects.filter(teacher=teacher)
        else:
            queryset = Class.objects.none()

        return queryset

    def get_serializer_class(self):
        if self.action == 'create':
            return ClassAddSerializer

        if self.action == 'update':
            return ClassSerializer

        return ClassSerializer

    def perform_create(self, serializer):
        '''
        Ao criar um objeto, define teacher com o usuário logado.
        '''
        user = self.request.user
        teacher = User.objects.get(username=user)

        if user is not None:
            serializer.save(teacher=teacher)

    def create(self, request, *args, **kwargs):
        # https://www.cdrf.co/3.12/rest_framework.viewsets/ModelViewSet.html#create
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_update(self, serializer):
        user = self.request.user
        data = self.request.data
        teacher_id = data.get('teacher')

        try:
            teacher = User.objects.get(pk=teacher_id)
        except User.DoesNotExist:
            raise DRFValidationError('Usuário não encontrado.')

        if user and user.is_authenticated:
            if user == teacher:
                serializer.save()
            else:
                raise DRFValidationError('Você não tem permissão para esta operação.')

    def retrieve(self, request, *args, **kwargs):
        '''
        Método para ver os detalhes.
        '''
        instance = self.get_object()
        teacher = instance.teacher
        user = self.request.user

        if user and user.is_authenticated:
            if user == teacher:
                serializer = self.get_serializer(instance)
            else:
                raise DRFValidationError('Você não tem acesso a esta aula.')

        return Response(serializer.data)

    def perform_destroy(self, instance):
        '''
        Método pra deletar os dados.
        '''
        # instance.delete()
        raise DRFValidationError('Nenhuma aula pode ser deletada.')


# Librerias
import random  # Importamos la librería random
import time

# Constantes
BLACK = '\033[30m'
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
WHITE = '\033[37m'
RESET = '\033[39m'
time.sleep(1)  # Espera de 1 segundo

# Variables
puntaje = random.randint(1, 5)
preguntas = ["","¿Donde se inicio el covid?","¿Cuantas dosis deberias tener si tienes más de 18 años?","¿Que es el SARS-CoV-2 ?","¿En que año se confirmo el paciente cero en el Perú?"]
alternativas = [["","","",""],["a) China", "b) EE.UU", "c) Rusia","d) Perú"],["a) Ninguna", "b) 2", "c) 3","d) 4"],["a) Proteina", "b) Bacteria", "c) Virus","d) Ninguna de las anteriores"],["a) 2021", "b) 2019", "c) 2020","d) 2022"]]
respuestas = ["","","","",""]
respuestas_correctas = ["","a","d","c","c"]
conforme = "no"
edad = 0
nombre = ""
contador = 0;

time.sleep(1)
# Mensaje de bievenida
print (CYAN + "\nBienvenido a mi trivia sobre la pandemia" + RESET)
print ("Pondremos a prueba tus conocimientos")
time.sleep(1)

while conforme=="no":        # validacion del nombre
  nombre = input(YELLOW + "\nIngrese nombre:" + RESET)
  nombre = nombre.lower()
  time.sleep(1)
  conforme = input(GREEN + "\n¿" + nombre + " es su nombre? Responda con 'si' o  'no' : " + RESET).lower()
  while conforme not in ("si", "no"):
    conforme = input(RED + "\nResponda con 'si' o  'no' por favor: " + RESET).lower()
    time.sleep(1)

conforme = "no"

while conforme=="no":        # validacion de la edad
  edad = input(YELLOW + "\nIngrese su edad:" + RESET)

  time.sleep(1)
  while edad.isnumeric() == False:
    edad = input(RED+"\nIngrese una edad numérica valida "+RESET)
  conforme = input(GREEN+"\n¿" + edad+" es su edad? Responda con 'si' o  'no' : "+RESET).lower()
  time.sleep(1)
  while conforme not in ("si", "no"):
    conforme = input(RED + "\nResponda con 'si' o  'no' por favor: " + RESET).lower()

time.sleep(1)

# Instrucciones de la trivia:
print(YELLOW + "\n Hola", nombre, "responde las siguientes preguntas escribiendo la letra de la alternativa (en mayuscula o minuscula) y presionando 'Enter' para enviar tu respuesta:\n" + RESET)
puntaje_inicial = random.randint(0, int(edad))

print(GREEN + "Nota:", nombre, ", obtendras puntos a memida que respondas correctamente "+ RESET)
conforme = input(YELLOW + "Obtuviste un puntaje inicial que esta entre 0 y "+edad+", quieres adivinar tu puntaje (si aciertas tendras puntos extras) Responda con 'si' o  'no'" + RESET)
if conforme == "x":
  puntaje = puntaje +20
  print("x se considera como si, y se te añadirá puntos extras por ser una persona con mucha suerte")

while conforme not in ("si", "no"):
  conforme = input(RED + "\nResponda con 'si' o  'no' por favor: " + RESET).lower()
  time.sleep(1)
if(conforme == 'si'):
  puntaje1 = input(RED + "\n¿Cual es su puntaje inicial?" + RESET)
  time.sleep(1)
  while puntaje1.isnumeric() == False:
    puntaje1 = input(RED+"\nIngrese un número "+RESET)
    time.sleep(1)
  if(puntaje1== puntaje_inicial):
    print(GREEN + "ACERTASTE"+ RESET)
    puntaje= puntaje_inicial + puntaje *2
  else:
    print ("El número a adivinar era: " + str(puntaje_inicial))

  print ("Tu puntaje inicial es: " + str(puntaje))
time.sleep(1)

conforme = "si"
while conforme == "si":

  print ("Comenzamos en: ")
  for contador in range (5,0,-1):
    print(contador)
    time.sleep(1)  # Espera 1 seg

  cantidad_preguntas = len(preguntas)
  for x in range (1,cantidad_preguntas):
    time.sleep(1)
    print(CYAN + "PREGUNTA " + str(x) + ":\n" + RESET)
    print(YELLOW+str(x) + ") " + preguntas[x] + RESET)
    for y in range (0,cantidad_preguntas-1):
      print(alternativas[x][y])
    respuestas[x] = input("\nTu respuesta es: ").lower()
    while respuestas[x] not in ("a", "b", "c", "d"):
      respuestas[x] = input(RED + "Debes responder a, b, c o d. Ingresa nuevamente tu respuesta: " + RESET)
      puntaje = puntaje - 1

    if (respuestas_correctas[x] == respuestas[x]):
      print (GREEN + "Muy bien " + nombre + " !" + RESET)
      puntaje = puntaje + 1
    else:
      print (RED + "Incorrecto! " + RESET)
      print (GREEN + "La respuesta correcta es : "+ respuestas_correctas[x] + RESET)
      puntaje = puntaje - 1
    ##print ("Tu puntaje es: ", puntaje)

    print("\n")
    time.sleep(1)  # Espera 1 seg

  condicion= input("\n¿Deseas ver tus respuestas?").lower()
  while condicion not in ("si", "no"):
    condicion = input("Debes responder si ó no. Ingresa nuevamente tu respuesta: ").lower()

  if condicion == "si":
    for z in range (1,len(respuestas)):
      print("PREGUNTA " + str(z) + ": " + respuestas[z])
  condicion= input("\n¿Deseas volver a realizar la trivia?").lower()
  while condicion not in ("si", "no"):
    condicion = input(RED +"Debes responder si ó no. Ingresa nuevamente tu respuesta: " + RESET).lower()

for contador in range(0,5,1):
  print(".")
  time.sleep(1) # Espera 2 segundos antes de continuar.

print ("Tu puntaje total es: ", puntaje)
print (nombre, ", muchas gracias por participar")


# 문제 링크: https://leetcode.com/problems/permutations/

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        permutations = []
        def dfs(depth: int):
            if depth == len(nums) - 1:
                permutations.append(nums[:])

            for i in range(depth, len(nums)):
                nums[depth], nums[i] = nums[i], nums[depth]
                dfs(depth + 1)
                nums[depth], nums[i] = nums[i], nums[depth]

        dfs(0)
        return permutations


import numpy as np

class LinearRegression:
    def __init__(self, lr = 0.01, n_iters = 1000):
        self.lr = lr
        self.n_iters = n_iters
        self.weights = None
        self.bias = None

    def fit(self, X, y):
        # init parameters
        n_samples, n_features = X.shape

        # here weights refers to slope and bias refers to intercept on the line
        # Y = weights * x + bias
        self.weights = np.zeros(n_features) # can also use random values
        self.bias = 0

        for _ in range(self.n_iters):
            # y = mx + c
            y_predicted = np.dot(X, self.weights) + self.bias

            # change in Error function wrt weights
            dw = (1/ n_samples) * np.dot(X.T, y_predicted - y)

            # change in Error function wrt bias
            db = (1 / n_samples) * np.sum(y_predicted - y)

            self.weights -= self.lr * dw
            self.bias -= self.lr * db

    def predict(self, X):
        y_predicted = np.dot(X, self.weights) + self.bias
        return y_predicted


import os
import sys

data_path = sys.argv[1]
os.system('python3 src/make_pickle.py '
          '{data_path} data-processor.pickle mean_std.pickle'
          .format(data_path=data_path))
os.system('mkdir -p ../model/rnncnn')
os.system('python3 src/train.py '
          'data-processor.pickle ../model/rnncnn '
          '--batch_size 32 --gpu_mem 1 --model rnncnn'
          .format(data_path=data_path))


from xml.etree import ElementTree as ET
from pygame import Rect
from pygame.sprite import Sprite
from game_asset_management.object_assets import ObjectAssets
from game_asset_management.object_assets import AttackAssets
from game_asset_management.object_assets import AssetSet

class AssetCollectionXml(object):

    def __init__(self):

        self.tree = None
        self.root = None
        self.file_name = ''

    def open(self,file_name):

        self.file_name = file_name
        self.tree = ET.parse(file_name)
        self.root = self.tree.getroot()

    def save(self, asset_sets,file_name):

        root = ET.Element('asset_collection')

        for set in asset_sets:

            self.write_asset_set_element(root, set)
        #endfor

        ET.dump(root)
        tree = ET.ElementTree(root)
        xmlstr = ET.tostring(root, encoding='utf8', method='html')
        tree.write(file_name,encoding='utf8', method='xml')

    def write_asset_set_element(self,parent_elmt,set):

        asset_set_elemt = ET.SubElement(parent_elmt, 'asset_set', {'name':set.name})

        for k in set.object_assets_dict.keys():

            object_assets = set.object_assets_dict[k]
            #print "key %s,value: %s"%(k,str(object_assets))
            self.write_player_object_asset(asset_set_elemt, object_assets, set.name)
        #endfor

        return asset_set_elemt

    def write_player_object_asset(self,parent_elmt, asset ,set_name):

        object_elmt = ET.SubElement(parent_elmt, 'player_object', {'key':asset.key,'set':set_name})

        # animation asset
        animation_elmt = self.write_animation_asset(object_elmt, asset.animation)

        # right and left sprite sets
        self.write_sprite_list(animation_elmt, direction = 'RIGHT')
        self.write_sprite_list(animation_elmt, direction = 'LEFT',flipx = True)

        # collision group
        self.write_collision(object_elmt, asset.collision)

    def write_animation_asset(self,parent_elmt,animation_asset):

        animation_elmt = ET.SubElement(parent_elmt,'animation',{'frame_rate':str(animation_asset.frame_rate),
                                                               'layer':str(animation_asset.layer_drawing_priority)
                                                               })

        return animation_elmt

    def write_sprite_list(self,parent_elmt,file = 'image.png',cols = 1,rows = 1,scale = 1,
                              direction = 'RIGHT',flipx = False,flipy = False):

        sprite_list_elmt = ET.SubElement(parent_elmt,'sprite_list',{'image_file':file,
                                                       'cols':str(cols),
                                                       'rows':str(rows),
                                                       'scale':str(scale),
                                                       'direction':direction,
                                                       'flipx':str(flipx),
                                                       'flipy':str(flipy)
                                                       })

        return sprite_list_elmt

    def write_collision(self,parent_elmt,coll_group):

        collision_elmt = ET.SubElement(parent_elmt,'collision',{'collision_type_mask':str(coll_group.collision_type_mask),
                                                               'collision_with_mask':str(coll_group.collision_with_mask)
                                                               })

        for rect in iter(coll_group.rectangles):
            self.write_rect(collision_elmt, rect)

        return collision_elmt

    def write_rect(self,parent_elmt,rect):

        rect_elmt = ET.SubElement(parent_elmt, 'rect', {'x':str(rect.x),
                                                        'y':str(rect.y),
                                                         'width':str(rect.width),
                                                         'height':str(rect.height)})

        return rect_elmt


import argparse
import re

def main():
    parser = argparse.ArgumentParser(prog="2sq.py")

    parser.add_argument(
        "input", type=str, help="Input File Name"
    )
    parser.add_argument(
        "--output", type=str, help="Output file name"
    )

    args = parser.parse_args()

    with open(args.input, "r") as file:
        filedata = file.read()

    pattern = re.compile(r"R__\S+")
    filename = pattern.findall(args.input)[0]

    filedata = filedata.replace("'", "''")

    with open(f"{filename if args.output is None else args.output}", "w", encoding="cp1252") as file:
        file.write(filedata)

if __name__ == "__main__":
    main()


import numpy as np

def count(pred_boxs, real_boxs):
    count = 0
    index = []
    for i in range(pred_boxs.shape[0]):
        ious=[]
        for j in range(real_boxs.shape[0]):
            if j in index:
                ious.append(0.)
            else:
                ious.append(iou(pred_boxs[i], real_boxs[j]))
        max_iou  = max(ious)
        if max_iou>0.4:
            index.append(ious.index(max(ious)))
            count +=1
    return count

def iou(b1, b2):
    # b1
    b1_xy = b1[:2]
    b1_wh = b1[2:4]
    b1_wh_half = b1_wh/2.
    b1_mins = b1_xy - b1_wh_half
    b1_maxes = b1_xy + b1_wh_half

    # b2
    b2_xy = b2[:2]
    b2_wh = b2[2:4]
    b2_wh_half = b2_wh/2.
    b2_mins = b2_xy - b2_wh_half
    b2_maxes = b2_xy + b2_wh_half

    intersect_mins = max(list(b1_mins), list(b2_mins))
    intersect_maxes = min(list(b1_maxes), list(b2_maxes))
    intersect_wh = max(list(np.array(intersect_maxes)-np.array(intersect_mins)),[0., 0.])
    intersect_area = intersect_wh[0] * intersect_wh[1]
    iou = intersect_area/(b2_wh[0]*b2_wh[1])

    return iou

if __name__=="__main__":
    b1 = np.array([[10,10,100,100]])
    b2 = np.array([[100, 100, 100, 100]])
    count  = count(b1, b2)
    print(count)


# -*- coding: utf-8 -*-
import re
from datetime import datetime, date
from ..WikiParser import WikiParser

class SpanishWikiParser(WikiParser):
    def is_politician(self) -> bool:
        """
        Check if page is from a politician
        """
        search_politic = re.search(
            r"pol[ií]tic[oa]|senador|diputad[oa]|congreso|alcalde|autoridad", self.text
        )
        return bool(search_politic)

    def get_birth_date(self) -> str:
        """
        Get person's birth date
        """
        # Full date from card
        parsed_date = self.get_full_date_from_authority_card(self.text.lower())

        if parsed_date:
            return parsed_date

        text = self.text.lower()
        text = re.sub(
            r"\[\[([^0-9]*?)\]\]?", "", text
        )  # remove links without numbers [[Domingo-Caudillo]]
        text = self.remove_brackets_content(text)
        text = self.remove_html_tags(text)
        text = self.remove_square_brackets(text)
        text = self.remove_double_whitespaces(text)

        # Full date from bio (formatted)
        parsed_date = self.get_full_date_from_bio_with_format(text)
        if parsed_date:
            return parsed_date

        # Full date from bio (unformatted)
        parsed_date = self.get_full_date_from_bio_without_format(text)
        if parsed_date:
            return parsed_date

        # Partial date from card
        parsed_date = self.get_partial_date_from_authority_card(self.text.lower())
        if parsed_date:
            return parsed_date

        # Partial date from bio
        parsed_date = self.get_partial_date_from_bio_with_format(text)
        if parsed_date:
            return parsed_date

        return None

    @staticmethod
    def get_full_date_from_authority_card(text: str) -> str:
        """
        Extract full birth date from "ficha autoridad"
        Matchs:
            | fecha de nacimiento = {{fecha|1|1|1962|edad}}
            | fecha de nacimiento = 18 de agosto de [[1944]]
            | fechanac = [[30 noviembre]] de [[1951]]
        """
        text = SpanishWikiParser.remove_double_whitespaces(text)
        structured_dates = re.search(r"fecha de nacimiento =(.+)", text)

        if not structured_dates:
            structured_dates = re.search(r"fechanac =(.+)", text)

        if structured_dates:
            datesrt = structured_dates.group(1).lower().strip()
            datesrt = SpanishWikiParser.clean_authority_card(datesrt)
            datesrt = re.search(r"(\d{1,2}) (\d{1,2}) (\d{4})", datesrt)
            if datesrt:
                return (
                    datetime.strptime(
                        f"{datesrt.group(1)} {datesrt.group(2)} {datesrt.group(3)}",
                        "%d %m %Y",
                    )
                    .date()
                    .strftime("%Y-%m-%d")
                )

        return None

    @staticmethod
    def get_partial_date_from_authority_card(text: str):
        """
        Extract partial birth date from "ficha autoridad"
        Matchs:
            | fecha de nacimiento = {{fecha|1937}}
            | fecha de nacimiento = {{fecha|5|1937}}
            | fechanac = [[1951]]
            | fechanac = Marzo de [[1951]]
        """
        text = SpanishWikiParser.remove_double_whitespaces(text)
        structured_dates = re.search(r"fecha de nacimiento =(.+)", text)
        if not structured_dates:
            structured_dates = re.search(r"fechanac =(.+)", text)
        if structured_dates:
            datesrt = structured_dates.group(1).lower().strip()
            datesrt = SpanishWikiParser.clean_authority_card(datesrt)
            if datesrt:
                if len(datesrt) == 4:
                    return datesrt
                if datesrt.count(" ") == 1:
                    return datetime.strptime(datesrt, "%m %Y").date().strftime("%Y-%m")

    @staticmethod
    def get_full_date_from_bio_with_format(text):
        """
        Extract full birth date (formated) from spanish wikipedia bio.
        Matchs:
            '''alberto''' (irún, guipúzcoa, país vasco (españa), 20 de mayo de 1969)
            '''maría josé lópez santana''' (gines, 12 de enero de 1970-3 de febrero de 2013)
        """
        text = text.replace("(n.", "(")
        bio_date = re.search(
            r"''' \([a-zÀ-ÿø-ÿ0-9 ,;\|\(\)]*?(\d{1,2}) de ([a-zñ]{4,10}) de (\d{4})",
            text,
            re.IGNORECASE,
        )
        if bio_date:
            day = bio_date.group(1)
            month = SpanishWikiParser.named_month_to_number(bio_date.group(2))
            year = bio_date.group(3)
            return date(int(year), int(month), int(day)).strftime("%Y-%m-%d")

        return None

    @staticmethod
    def get_full_date_from_bio_without_format(text) -> str:
        """
        Extract full birth date (unformatted) from spanish wikipedia bio.
        Matchs:
            nacido en málaga el 21 de junio de 1955
            nació el 13 de diciembre de 1954 y falleció el 12 de mayo de 1988...
        """
        bio_date = re.search(
            r"(nació|nacid[oa]) [a-zÀ-ÿø-ÿ ,;\|\(\)]+? (\d{1,2}) de ([a-zñ]{4,10}) de (\d{4})",
            text,
            re.IGNORECASE,
        )
        if bio_date:
            day = bio_date.group(2)
            month = SpanishWikiParser.named_month_to_number(bio_date.group(3))
            year = bio_date.group(4)
            return date(int(year), int(month), int(day)).strftime("%Y-%m-%d")
        return None

    @staticmethod
    def get_partial_date_from_bio_with_format(text) -> str:
        """
        Extract partial birth date (formatted) from spanish wikipedia bio.
        Matchs:
            '''alberto''' (irún, guipúzcoa, país vasco (españa), 1969)
            '''lorem ''' (laredo (cantabria)|laredo, cantabria; 1950)
        """
        bio_date = re.search(
            r"''' \([a-zÀ-ÿø-ÿ0-9 ,;\.\|\(\)]*?(\d{4})", text, re.IGNORECASE
        )

        return bio_date.group(1) if bio_date else None

    @staticmethod
    def replace_month_to_num_from_str(date_str):
        """
        Transfrom month to number from a full date string:
        23 de enero de 1998 -> 23 de 1 de 1998
        """
        months = {
            "enero": "1",
            "febrero": "2",
            "marzo": "3",
            "abril": "4",
            "mayo": "5",
            "junio": "6",
            "julio": "7",
            "agosto": "8",
            "septiembre": "9",
            "octubre": "10",
            "noviembre": "11",
            "diciembre": "12",
        }
        for month in months:
            if month in date_str:
                date_str = date_str.lower().replace(month, months.get(month))
        return date_str.strip()

    @staticmethod
    def named_month_to_number(month):
        """
        Convert string month to ordinal
        """
        months = {
            "enero": "01",
            "ene": "01",
            "febrero": "02",
            "feb": "02",
            "marzo": "03",
            "mar": "03",
            "abril": "04",
            "abr": "04",
            "mayo": "05",
            "may": "05",
            "junio": "06",
            "jun": "06",
            "julio": "07",
            "jul": "07",
            "agosto": "08",
            "ago": "08",
            "septiembre": "09",
            "sep": "09",
            "sept": "09",
            "octubre": "10",
            "oct": "10",
            "noviembre": "11",
            "nov": "11",
            "diciembre": "12",
            "dic": "12",
        }
        return months.get(month.lower(), month)

    @staticmethod
    def clean_authority_card(text):
        """
        Remove non-usable characters and strings
        from wikipedia authority card (ficha autoridad)
        """
        text = SpanishWikiParser.remove_brackets(text)
        text = SpanishWikiParser.remove_square_brackets(text)
        text = SpanishWikiParser.remove_html_tags(text)
        text = re.sub(r"fecha de inicio|fecha|edad", "", text)
        text = re.sub(r"\||,|de", " ", text)
        text = SpanishWikiParser.remove_parenthesis_content(text)
        text = SpanishWikiParser.replace_month_to_num_from_str(text)
        text = SpanishWikiParser.remove_non_numbers(text)
        text = SpanishWikiParser.remove_double_whitespaces(text)
        return text


N,K = map(int,input().split())
A = list(map(int,input().split()))

s = []
# 訪れていない
visited = [-1] * (N+1)
v = 1
while visited[v] == -1:
  visited[v] = len(s)
  s.append(v)
  # ワープさせる
  v = A[v-1]

# サイクルの長さ
c = len(s) - visited[v]
# はみ出す分の長さ
l = visited[v]

if (K < l):
  print(s[K])
else:
  K -= l
  K %= c
  print(s[l+K])

# route = [1]
# i = 0
# while True:
#   next = A[i]
#   if next not in route:
#     route.append(next)
#   else:
#     cycle = route[route.index(next):]
#     route = route[:route.index(next)]
#     break

#   i = next-1

# K -= len(route)
# print(cycle[K%len(cycle)])


import numpy as np
import torch

from PIL import Image
from abc import ABC, abstractmethod
from diffusers import (
    AutoencoderKL,
    DiffusionPipeline,
)
from tqdm.auto import tqdm
from transformers import CLIPTextModel, CLIPTokenizer
from typing import Any, List, Optional, Tuple, Union

from stablefused.typing import (
    PromptType,
    OutputType,
    Scheduler,
    SchedulerType,
    UNetType,
)
from stablefused.utils import (
    denormalize,
    load_model_from_cache,
    normalize,
    numpy_to_pil,
    numpy_to_pt,
    pil_to_numpy,
    pt_to_numpy,
    resolve_scheduler,
    save_model_to_cache,
)

class BaseDiffusion(ABC):
    def __init__(
        self,
        model_id: str = None,
        tokenizer: CLIPTokenizer = None,
        text_encoder: CLIPTextModel = None,
        vae: AutoencoderKL = None,
        unet: UNetType = None,
        scheduler: SchedulerType = None,
        torch_dtype: torch.dtype = torch.float32,
        device="cuda",
        use_cache=True,
        *args,
        **kwargs,
    ) -> None:
        self.device: str = device
        self.torch_dtype: torch.dtype = torch_dtype
        self.model_id: str = model_id

        self.tokenizer: CLIPTokenizer
        self.text_encoder: CLIPTextModel
        self.vae: AutoencoderKL
        self.unet: UNetType
        self.scheduler: SchedulerType
        self.vae_scale_factor: int

        if model_id is None:
            if (
                tokenizer is None
                or text_encoder is None
                or vae is None
                or unet is None
                or scheduler is None
            ):
                raise ValueError(
                    "Either (`model_id`) or (`tokenizer`, `text_encoder`, `vae`, `unet`, `scheduler`) must be provided."
                )

            self.tokenizer = tokenizer
            self.text_encoder = text_encoder
            self.vae = vae
            self.unet = unet
            self.scheduler = scheduler
        else:
            model = DiffusionPipeline.from_pretrained(
                model_id, torch_dtype=torch_dtype, *args, **kwargs
            )
            self.tokenizer = model.tokenizer
            self.text_encoder = model.text_encoder
            self.vae = model.vae
            self.unet = model.unet
            self.scheduler = model.scheduler

        self.to(self.device)
        self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)

        if use_cache and model_id is not None:
            model = load_model_from_cache(model_id, None)
            if model is None:
                save_model_to_cache(self)
            else:
                print("here")
                self.share_components_with(model)

    def to(self, device: str) -> "BaseDiffusion":
        """
        Move model to specified compute device.

        Parameters
        ----------
        device: str
            The device to move the model to. Must be one of `cuda` or `cpu`.
        """
        self.device = device
        self.text_encoder = self.text_encoder.to(device)
        self.vae = self.vae.to(device)
        self.unet = self.unet.to(device)
        return self

    def share_components_with(self, model: "BaseDiffusion") -> None:
        """
        Share components with another model. This allows for sharing of the
        different internal components of the model, such as the text encoder,
        VAE, and UNet. This is useful for reducing memory usage when using
        multiple diffusion pipelines with the same checkpoint at the same time.

        Parameters
        ----------
        model: BaseDiffusion
            The model to share components with.
        """
        self.device = model.device
        self.torch_dtype = model.torch_dtype
        self.tokenizer = model.tokenizer
        self.text_encoder = model.text_encoder
        self.vae = model.vae
        self.unet = model.unet
        self.scheduler = model.scheduler
        self.vae_scale_factor = model.vae_scale_factor

    def set_scheduler(self, scheduler: Scheduler) -> None:
        """
        Set the scheduler for the diffusion pipeline.

        Parameters
        ----------
        scheduler: SchedulerType
            The scheduler to use for the diffusion pipeline.
        """
        self.scheduler = resolve_scheduler(scheduler, self.scheduler.config)

    def enable_attention_slicing(self, slice_size: Optional[int] = -1) -> None:
        """
        Enable attention slicing. By default, the attention head is sliced in half.
        This is a good tradeoff between memory and performance.

        Parameters
        ----------
        slice_size: int
            The size of the attention slice. If -1, the attention head is sliced in
            half. If None, attention slicing is disabled.
        """
        if slice_size == -1:
            slice_size = self.unet.config.attention_head_dim // 2
        self.unet.set_attention_slice(slice_size)

    def disable_attention_slicing(self) -> None:
        """Disable attention slicing."""
        self.unet.set_attention_slice(None)

    def enable_slicing(self) -> None:
        """
        Allow tensor slicing for vae decode step. This will cause the vae to split
        the input tensor to compute decoding in multiple steps. This will save
        memory and allow for larger batch sizes, but will affect performance slightly.
        """
        self.vae.enable_slicing()

    def disable_slicing(self) -> None:
        """Disable tensor slicing for vae decode step."""
        self.vae.disable_slicing()

    def enable_tiling(self) -> None:
        """
        Allow tensor tiling for vae. This will cause the vae to split the input tensor
        into tiles to compute encoding/decoding in several steps. This will save a large
        amount of memory and allow processing larger images, but will affect performance.
        """
        self.vae.enable_tiling()

    def disable_tiling(self) -> None:
        """Disable tensor tiling for vae."""
        self.vae.disable_tiling()

    @staticmethod
    def validate_input(
        prompt: PromptType = None,
        negative_prompt: PromptType = None,
        image_height: int = None,
        image_width: int = None,
        start_step: int = None,
        num_inference_steps: int = None,
        strength: float = None,
    ) -> None:
        """
        Validate input parameters.
        TODO: This needs to be removed and improved. More checks need to be added.

        Parameters
        ----------
        prompt: PromptType
            The prompt(s) to condition on.
        negative_prompt: PromptType
            The negative prompt(s) to condition on.
        image_height: int
            The height of the image to generate.
        image_width: int
            The width of the image to generate.
        start_step: int
            The step to start inference from.
        num_inference_steps: int
            The number of inference steps to perform.
        strength: float
            The strength of the noise mixing when performing LatentWalkDiffusion.
        """
        if image_height is not None and image_width is not None:
            if image_height % 8 != 0 or image_width % 8 != 0:
                raise ValueError(
                    "`image_height` and `image_width` must a multiple of 8"
                )
        if negative_prompt is not None:
            if type(prompt) is not type(negative_prompt):
                raise TypeError(
                    "Type of `prompt` and `negative_prompt` must be the same"
                )
            if isinstance(prompt, list) and len(prompt) != len(negative_prompt):
                raise ValueError(
                    "Length of `prompt` list and `negative_prompt` list should match"
                )
        if start_step is not None:
            if num_inference_steps is None:
                raise ValueError(
                    "`num_inference_steps` must be provided if `start_step` is provided"
                )
            if start_step < 0 or start_step >= num_inference_steps:
                raise ValueError(
                    "`start_step` must be in the range [0, `num_inference_steps` - 1]"
                )
        if strength is not None:
            if strength < 0 or strength > 1:
                raise ValueError("`strength` must be in the range [0.0, 1.0]")

    @abstractmethod
    def embedding_to_latent(self, *args: Any, **kwargs: Any) -> Any:
        """
        Abstract method for converting an embedding to a latent vector. This method
        must be implemented by all subclasses.
        """
        pass

    @abstractmethod
    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        """
        Abstract method for performing inference. This method must be implemented
        by all subclasses.
        """
        pass

    def random_tensor(self, shape: Union[List[int], Tuple[int]]) -> torch.FloatTensor:
        """
        Generate a random tensor of the specified shape.

        Parameters
        ----------
        shape: List[int] or Tuple[int]
            The shape of the random tensor to generate.

        Returns
        -------
        torch.FloatTensor
            A random tensor of the specified shape on the same device and dtype
            as model.
        """
        rand_tensor = torch.randn(shape, device=self.device, dtype=self.torch_dtype)
        return rand_tensor

    def prompt_to_embedding(
        self,
        prompt: PromptType,
        negative_prompt: Optional[PromptType] = None,
    ) -> torch.FloatTensor:
        """
        Convert a prompt or a list of prompts into a text embedding.

        Parameters
        ----------
        prompt: PromptType
            The prompt or a list of prompts to convert into an embedding. Used
            for conditioning.
        negative_prompt: Optional[PromptType]
            A negative prompt or a list of negative prompts, by default None.
            Use for unconditioning. If not provided, an empty string ('') will
            be used to generate the unconditional embeddings.

        Returns
        -------
        torch.FloatTensor
            A text embedding generated from the given prompt(s) and, if provided,
            the negative prompt(s).
        """

        if negative_prompt is not None and type(negative_prompt) is not type(prompt):
            raise TypeError(
                f"`negative_prompt` must have the same type as `prompt` ({type(prompt)}), but found {type(negative_prompt)}"
            )

        if isinstance(prompt, str):
            batch_size = 1
            prompt = [prompt]
            if negative_prompt is not None:
                negative_prompt = [negative_prompt]
        elif isinstance(prompt, list):
            batch_size = len(prompt)
        else:
            raise TypeError("`prompt` must be a string or a list of strings")

        # Tokenize the prompt(s)
        text_input = self.tokenizer(
            prompt,
            padding="max_length",
            max_length=self.tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt",
        )

        # Enable use of attention_mask if the text_encoder supports it
        if (
            hasattr(self.text_encoder.config, "use_attention_mask")
            and self.text_encoder.config.use_attention_mask
        ):
            attention_mask = text_input.attention_mask.to(self.device)
        else:
            attention_mask = None

        # Generate text embedding
        text_embedding = self.text_encoder(
            text_input.input_ids.to(self.device), attention_mask=attention_mask
        )[0]

        # Unconditioning input is an empty string if negative_prompt is not provided
        if negative_prompt is None:
            unconditioning_input = [""] * batch_size
        else:
            unconditioning_input = negative_prompt

        # Tokenize the unconditioning input
        unconditioning_input = self.tokenizer(
            unconditioning_input,
            padding="max_length",
            max_length=self.tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt",
        )

        # Generate unconditional embedding
        unconditional_embedding = self.text_encoder(
            unconditioning_input.input_ids.to(self.device),
            attention_mask=attention_mask,
        )[0]

        # Concatenate unconditional and conditional embeddings
        embedding = torch.cat([unconditional_embedding, text_embedding])
        return embedding

    def classifier_free_guidance(
        self,
        noise_prediction: torch.FloatTensor,
        guidance_scale: float,
        guidance_rescale: float,
    ) -> torch.FloatTensor:
        """
        Apply classifier-free guidance to noise prediction.

        Parameters
        ----------
        noise_prediction: torch.FloatTensor
            The noise prediction tensor to which guidance will be applied.
        guidance_scale: float
            The scale factor for applying guidance to the noise prediction.
        guidance_rescale: float
            The rescale factor for adjusting the noise prediction based on
            guidance. Based on findings in Section 3.4  of [Common Diffusion
            Noise Schedules and Sample Steps are Flawed](https://arxiv.org/pdf/2305.08891.pdf).

        Returns
        -------
        torch.FloatTensor
            The noise prediction tensor after applying classifier-free guidance.
        """

        # Perform guidance
        noise_unconditional, noise_prompt = noise_prediction.chunk(2)
        noise_prediction = noise_unconditional + guidance_scale * (
            noise_prompt - noise_unconditional
        )

        # Skip computing std if guidance_rescale is 0
        if guidance_rescale > 0:
            std_prompt = noise_prompt.std(
                dim=list(range(1, noise_prompt.ndim)), keepdim=True
            )
            std_prediction = noise_prediction.std(
                dim=list(range(1, noise_prediction.ndim)), keepdim=True
            )
            noise_prediction_rescaled = noise_prediction * (std_prompt / std_prediction)
            noise_prediction = (
                noise_prediction * (1 - guidance_rescale)
                + noise_prediction_rescaled * guidance_rescale
            )

        return noise_prediction

    def latent_to_image(
        self, latent: torch.FloatTensor, output_type: str
    ) -> OutputType:
        """
        Convert a latent tensor to an image in the specified output format.

        Parameters
        ----------
        latent: torch.FloatTensor
            The latent tensor to convert into an image.
        output_type: str
            The desired output format for the image. Should be one of [`pt`, `np`, `pil`].

        Returns
        -------
        OutputType
            An image in the specified output format.
        """
        if output_type not in ["pt", "np", "pil"]:
            raise ValueError("`output_type` must be one of [`pt`, `np`, `pil`]")

        image = self.vae.decode(
            latent / self.vae.config.scaling_factor, return_dict=False
        )[0]
        image = denormalize(image)

        if output_type == "pt":
            return image

        image = pt_to_numpy(image)

        if output_type == "np":
            return image

        image = numpy_to_pil(image)
        return image

    def image_to_latent(
        self,
        image: Union[Image.Image, List[Image.Image], np.ndarray, torch.Tensor],
    ) -> torch.FloatTensor:
        """
        Convert an image or a list of images into a latent tensor.

        Parameters
        ----------
        image: Union[Image.Image, List[Image.Image], np.ndarray, torch.Tensor]
            The input image(s) to convert into a latent tensor. Supported types are
            `PIL.Image.Image`, `np.ndarray`, and `torch.Tensor`.

        Returns
        -------
        torch.FloatTensor
            A latent tensor representing the input image(s).
        """
        if (
            not isinstance(image, Image.Image)
            and not isinstance(image, list)
            and not isinstance(image, np.ndarray)
            and not isinstance(image, torch.Tensor)
        ):
            raise TypeError(
                "`image` type must be one of (`PIL.Image.Image`, `np.ndarray`, `torch.Tensor`). Other types are not supported yet"
            )
        if isinstance(image, Image.Image):
            image: List[Image.Image] = [image]

        if isinstance(image[0], Image.Image):
            image: np.ndarray = pil_to_numpy(image)

        if isinstance(image[0], np.ndarray):
            image: torch.FloatTensor = numpy_to_pt(image)

        image = image.to(self.device)
        latent = (
            self.vae.encode(image).latent_dist.sample() * self.vae.config.scaling_factor
        )

        return latent

    def resolve_output(
        self,
        latent: torch.FloatTensor,
        output_type: str,
        return_latent_history: bool,
    ) -> Union[OutputType, List[OutputType]]:
        """
        Resolve the output from the latent based on the provided output options.

        Parameters
        ----------
        latent: torch.FloatTensor
            The latent tensor representing the content to be resolved.
        output_type: str
            The desired output format. Should be one of [`latent`, `pt`, `np`, `pil`].
        return_latent_history: bool
            If True, it means that the input latent tensor contains a tensor of latent
            tensor for each inference step. This requires decoding each latent tensor
            and returning a list of images. If False, decoding occurs directly.

        Returns
        -------
        Union[OutputType, List[OutputType]]
            The resolved output based on the provided latent vector and options.
        """
        if output_type not in ["latent", "pt", "np", "pil"]:
            raise ValueError(
                "`output_type` must be one of [`latent`, `pt`, `np`, `pil`]"
            )

        if output_type == "latent":
            return latent

        if return_latent_history:
            # Transpose latent tensor from [num_steps, batch_size, *latent_dim] to
            # [batch_size, num_steps, *latent_dim].
            # This is done so that the history of latent vectors for each prompt
            # is returned as a row instead of a column. It is what the user would
            # intuitively expect.
            latent = torch.transpose(latent, 0, 1)
            image = [
                self.latent_to_image(l, output_type)
                for _, l in list(enumerate(tqdm(latent)))
            ]

            if output_type == "pt":
                image = torch.stack(image)
            elif output_type == "np":
                image = np.stack(image)
            else:
                # output type is "pil" so we can just return as a python list
                pass
        else:
            image = self.latent_to_image(latent, output_type)

        return image


from flask import Flask, render_template
from flask.json import JSONEncoder
from web_service.admin_panel import admin_panel
from web_service.common_api import user_api
from web_service.error_handlers import error_handler
from datetime import datetime
from enum import Enum
from pydantic import BaseModel
from db.migrations import apply_migrations

import secrets
import logging

class ServiceCustomJsonEncoder(JSONEncoder):
    def default(self, obj):
        try:
            if isinstance(obj, datetime):
                return obj.isoformat()
            if isinstance(obj, Enum):
                return obj.value
            if isinstance(obj, BaseModel):
                return obj.dict()

            iterable = iter(obj)
        except TypeError:
            pass
        else:
            return list(iterable)
        return JSONEncoder.default(self, obj)

apply_migrations()  # применение миграций

app = Flask(__name__)
app.secret_key = secrets.token_bytes(30)
app.config['MAX_CONTENT_LENGTH'] = 20 * 1000 * 1000  # in bytes
app.register_blueprint(admin_panel)
app.register_blueprint(user_api)
app.register_blueprint(error_handler)
app.logger.setLevel(logging.DEBUG)
app.json_encoder = ServiceCustomJsonEncoder

print(app.url_map)

@app.route('/')
def index():
    return render_template("user/index.html")

if __name__ == '__main__':
    app.run(debug=True)


import cx_Freeze

executables = [cx_Freeze.Executable(script="trat.py", icon="logo.png")]

cx_Freeze.setup(
    name = "Trat",
    options={"build_exe": {"packages": ["tkinter"],
                           "include_files": ["logo1.png", "logo.png"]}
            },
    executables = executables
    )


import numpy as np
#Вводим число которое необходимо отгадать программе
number = input('Введите число от 1 до 100: ')
def find_number(number, int=1) -> int:
    """Угадываем число меньше чем за 20 попыток

    Args:
        number (int, optional): Загаданное число. Defaults to 1.

    Returns:
        int: Число попыток
    """
    count = 0
#создаем границы диапазона и рандомим первое число в этих границах
    low = 1
    high = 101
    predict_number = np.random.randint(low, high)

    while predict_number != number:
        count += 1
        if predict_number > number:
            high = predict_number # сужаем верхнюю границу диапазона в котором находится угадываемое число
        else:
            low = predict_number + 1  # увеличиваем нижнюю границу диапазонав в котором находится угадываемое число
        predict_number = np.random.randint(low, high)  # выбираем новое рандомное число
    return count

def score_game(random_predic) -> int:
    """за какое количество попыток в среднем за 1000 подходов угадывает наша функция

    Args:
        random_predic (_type_): функция угадывания

    Returns:
        int: среднее количество попыток
    """
    count_ls = []
    np.random.seed(1)
    random_array = np.random.randint(1, 101, size=1000)

    for number in random_array:
        count_ls.append(random_predic(number))
    score = int(np.mean(count_ls))
    print(f'Ваш флгоритм угадывает число в среднем за: {score} попыток')
    return score
score_game(find_number)


import os
from flask import Flask, request
import json
import os
from utils import verify_signature
import logging
logging.basicConfig(level=logging.DEBUG)

app = Flask(__name__)

@app.route('/webhook/submit', methods=['POST'])
def webhook_submit():
    """
    Handles incoming webhook requests by verifying the signature and logging the payload.

    This Flask route listens for POST requests at the '/webhook/submit' path. It retrieves
    the Uplift secret key from the environment, the 'x-uplift-signature-256' header from
    the incoming request, and the request payload as bytes. The route verifies the signature
    using the provided secret key and returns an HTTP 401 response if the signature is invalid.
    If the signature is valid, the route logs the payload and returns an HTTP 200 response.

    Returns:
        Tuple[str, int]: A tuple containing a response message and an HTTP status code.
    """

    logging.info('webhook function received a request')

    # Get the Uplift secret key from your app settings
    secret_token = os.environ.get('SECRET_TOKEN')
    logging.info(secret_token)

    # Get the signature from the request headers
    signature = request.headers.get('x-uplift-signature-256')
    logging.info (signature)

    # Get the payload from the request body as bytes
    payload = request.get_data()

    # Verify the signature using the Uplift secret key
    if not verify_signature(secret_token, signature, payload):
        return 'Invalid signature', 401

    # Print the payload
    logging.info(payload)
    return 'Payload printed successfully', 200

if __name__ == '__main__':
    app.run()


from abc import ABC, abstractclassmethod
from typing import List

import torch
from torch import nn
from transformers import AutoModel

class ProfileStrategy(ABC):
    def __init__(self, module: AutoModel, device: torch.device):
        self.module = module
        self.device = device

    @abstractclassmethod
    def profile(self):
        raise NotImplementedError("Not implemented.")

class ProfileByMemory(ProfileStrategy):
    """Profiles CUDA memory usage by layer."""

    def profile(self, input: torch.Tensor) -> List[int]:
        sizes = []
        input = input.to(self.device)
        output = input

        for _, layer in self.module.named_children():
            layer.to(self.device)
            layer.train()

            # calculate the memory occupied by the layer's output
            memory_before = torch.cuda.memory_allocated(device=self.device)
            output = layer(output)
            memory_after = torch.cuda.memory_allocated(device=self.device)
            occupied_memory = memory_after - memory_before

            # now calculate the memory occupied by the layer's parameters
            param_memory = self._compute_param_memory(layer)
            total_memory = occupied_memory + param_memory

            sizes.append(total_memory)
        return sizes

    def _compute_param_memory(self, module: nn.Module) -> int:
        total_size = 0
        for p in module.parameters():
            total_size += p.storage().size() * p.storage().element_size()

        return total_size


# -*- coding: utf-8 -*-
"""Find a Supplier - Edit Company's Directory Profile page"""
import logging

from requests import Response, Session

from directory_tests_shared import PageType, Service, URLs
from tests.functional.utils.context_utils import Actor, Feedback
from tests.functional.utils.request import Method, check_response, make_request

SERVICE = Service.FAS
NAME = "Feedback"
TYPE = PageType.FORM
URL = URLs.CONTACT_US_FEEDBACK.absolute
EXPECTED_STRINGS_FORM = [
    "Get UK companies to fulfil your business needs",
    (
        "Tell us what kind of goods or services you need. We'll put you in touch "
        "with relevant UK suppliers."
    ),
    "Your name",
    "Email address",
    "Organisation name",
    "Country",
    "Describe what you need",
    "Maximum 1000 characters.",
    "I agree to the great.gov.uk terms and conditions",
    "Send",
]
EXPECTED_STRINGS_SUCCESSFUL_SUBMISSION = [
    "We have received your enquiry",
    "also sent an email with the information",
    "What happens next",
]
EXPECTED_STRINGS_ERRORS = [
    "This field is required.",
    "Tick the box to confirm you agree to the terms and conditions.",
]

def go_to(session: Session) -> Response:
    headers = {"Referer": URL}
    return make_request(Method.GET, URL, session=session, headers=headers)

def should_be_here(response):
    check_response(response, 200, body_contains=EXPECTED_STRINGS_FORM)
    logging.debug("Buyer is on FAS send Feedback page")

def should_see_feedback_submission_confirmation(response):
    check_response(response, 200, body_contains=EXPECTED_STRINGS_SUCCESSFUL_SUBMISSION)
    logging.debug("Feedback submission was confirmed.")

def should_see_errors(response):
    check_response(response, 200, body_contains=EXPECTED_STRINGS_ERRORS)
    logging.debug("Buyer was presented with Feedback submission errors.")

def submit(actor: Actor, feedback: Feedback, *, referer: str = None) -> Response:
    """Submit feedback form.

    :param feedback: a namedtuple with Feedback request details
    :param referer: (optional) Originating page. Defaults to "{FAS}/feedback"
    """
    session = actor.session
    if referer:
        headers = {"Referer": referer}
    else:
        headers = {"Referer": URL}

    data = {
        "csrfmiddlewaretoken": actor.csrfmiddlewaretoken,
        "name": feedback.name,
        "email": feedback.email,
        "comment": feedback.comment,
        "terms_agreed": feedback.terms,
        "g-recaptcha-response": feedback.g_recaptcha_response,
    }
    return make_request(
        Method.POST, URL, session=session, headers=headers, data=data, trim=False
    )


sair = 2
while sair == 2:
    print('{:-^60}\n< 1 > Somar 2 Numeros\n< 2 > Subtrair 2 Numeros\n< 3 > Multiplicar 2 Numeros\n< 4 > Dividir 2 Numeros\n'.format('-'))
    selecao = int(input('Digite a Opção desejada: \n{:-^60}\n'.format('-')))
    while selecao < 5:
        numero1 = int(input('Digite o Primeiro nuemro: '))
        numero2 = int(input('Digite o Segundo numero: '))
        if selecao == 1:
            print('A soma de {} com {} é: {}'.format(numero1, numero2, numero1 + numero2))
        if selecao == 2:
            print('A Subtração de {} com {} é {}'.format(numero1, numero2, numero1 - numero2))
        if selecao == 3:
            print('A Multiplicação de {} com {} é {}'.format(numero1, numero2, numero1 * numero2))
        if selecao == 4:
            print('A Divisão de {} com {} é {}'.format(numero1, numero2, numero1 / numero2))
        break
    sair = int(input('\n\nDigite 1 para Sair ou Digite 2 Para Reiniciar: '))
    if sair == 1:
        sair = 1
        break
    if sair == 2:
        sair = 2
    else:
        print('Digite  apenas 1 ou 2')
        sair = int(input('Digite 1 para Sair ou Digite 2 Para Reiniciar: '))


#! /usr/bin/python
# -*- coding: utf-8 -*-
import os
import math
from collections import defaultdict
import networkx as nx
import matplotlib.pyplot as plt

os.chdir("D:/work_files/pycharm_codes/nlp_assignment")

def load_data():
    beijing_subway_geo_dict = {}  # example: {"草房":[15.26,233.56],...}
    with open("homework/part2/data/beijing_subway_geo.txt", "r", encoding="utf-8") as beijing_subway_geo_file:
        for line in beijing_subway_geo_file.readlines():
            line_strip_split = line.strip().split(":")
            subway_name = line_strip_split[0]
            subway_geo = line_strip_split[1].split(",")
            beijing_subway_geo_dict[subway_name] = (float(subway_geo[0]), float(subway_geo[1]))
    beijing_subway_belong_to_line = {}  # example: {"草房":["6号线"],...}
    beijing_subway_line = {}  # example: {"6号线":["金安桥",...]}
    beijing_subway_link = {}  # example: {"朱辛庄": ["育知路",..]}
    with open("homework/part2/data/beijing_subway_line.txt", "r", encoding="utf-8") as beijing_subway_line_file:
        for line in beijing_subway_line_file.readlines():
            line_strip_split = line.strip().split(":")
            subway_line = line_strip_split[1].split(",")
            beijing_subway_line[line_strip_split[0]] = subway_line
            for beijing_subway in subway_line:
                if beijing_subway_belong_to_line.get(beijing_subway) is None:
                    beijing_subway_belong_to_line[beijing_subway] = []
                    beijing_subway_belong_to_line[beijing_subway].append(line_strip_split[0])
                else:
                    beijing_subway_belong_to_line.get(beijing_subway).append(line_strip_split[0])
            if len(subway_line) >= 2:
                for index in range(len(subway_line) - 1):
                    if beijing_subway_link.get(subway_line[index]) is None:
                        beijing_subway_link[subway_line[index]] = []
                        beijing_subway_link[subway_line[index]].append(subway_line[index + 1])
                    else:
                        beijing_subway_link[subway_line[index]].append(subway_line[index + 1])
                    if beijing_subway_link.get(subway_line[index + 1]) is None:
                        beijing_subway_link[subway_line[index + 1]] = []
                        beijing_subway_link[subway_line[index + 1]].append(subway_line[index])
                    else:
                        beijing_subway_link[subway_line[index + 1]].append(subway_line[index])
    return beijing_subway_geo_dict, beijing_subway_line, beijing_subway_belong_to_line, beijing_subway_link

def geo_distance(origin, destination):
    """
    Calculate the Haversine distance.

    Parameters
    ----------
    origin : tuple of float
        (lat, long)
    destination : tuple of float
        (lat, long)
    Returns
    -------
    distance_in_km : float

    Examples
    --------
     origin = (48.1372, 11.5756)  # Munich
     destination = (52.5186, 13.4083)  # Berlin
     round(distance(origin, destination), 1) 504.2
    """
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371  # km

    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
         math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
         math.sin(dlon / 2) * math.sin(dlon / 2))
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    d = radius * c
    return d

def plt_beijing_subway_line():
    """
    绘制北京地铁路线图
    :return: 无返回值
    """
    beijing_subway_geo_dict, beijing_subway_line, beijing_subway_belong_to_line, beijing_subway_link_src = load_data()
    beijing_subway_link = defaultdict(list)
    beijing_subway_link.update(beijing_subway_link_src)
    beijing_subway_graph = nx.Graph(beijing_subway_link)
    nx.draw(beijing_subway_graph, beijing_subway_geo_dict, with_labels=False, node_size=10,font_size=6)
    plt.show()

def first_search(graph, start, rule="depth_first"):
    """
    用深度优先或者广度优先的搜索策略搜索整个图
    :param graph: dict,图结构，形如 {"北京":["太原","沈阳"],...}
    :param start: string,开始地名
    :param rule: string,规则,比如depth_first,breath_first
    :return: 遍历后的元素
    """
    visited = [start]
    seen = set()
    while visited:
        froninter = visited.pop()  # 删除列表中最后一个值,并返回最后一个值
        if froninter in seen: continue
        for successor in graph[froninter]:
            if successor in seen: continue
            print(successor)
            if rule == "depth_first":
                visited = visited + [successor]  # 我们每次扩展都扩展最新发现的点 -> depth first
            else:
                visited = [successor] + visited  # 我们每次扩展都先考虑已经发现的 老的点 -> breath first
            # 所以说，这个扩展顺序其实是决定了我们的深度优先还是广度优先
        seen.add(froninter)
    return seen

def search(start, destination, connection_graph, sort_candidate):
    """
    给定初始位置和结束位置，以及图结构和排序规则，利用排序规则获取最优分布路径。
    :param start: string,开始位置
    :param destination: string,结束位置
    :param connection_graph: dict,图结构,形如{"a":["b","c"]}
    :param sort_candidate: 排序函数
    :return: path, [], 最优路径
    """
    pathes = [[start]]

    visited = set()

    while pathes:
        path = pathes.pop(0)
        froninter = path[-1]

        if froninter in visited: continue

        successors = connection_graph[froninter]

        for node in successors:
            if node in path: continue
            new_path = path + [node]
            pathes.append(new_path)
            if node == destination: return new_path
        visited.add(froninter)
        pathes = sort_candidate(pathes)  # 我们可以加一个排序函数 对我们的搜索策略进行控制

def transfer_station_first(pathes):
    """
    经过站数最少
    :param pathes: [] 路径列表,[path1,path2]
    :return: function
    """
    return sorted(pathes, key=len)  # 升序

def transfer_as_much_possible(pathes):
    """
    经过站数最多
    :param pathes:  [] 路径列表,[path1,path2]
    :return: function
    """
    return sorted(pathes, key=len, reverse=True)

def get_path_distance(path):
    """
    获取路径距离
    :param path:[] 整个路径
    :return: 距离和
    """
    distance = 0.0
    for i in range(len(path) - 1):
        distance += geo_distance(path[i], path[i + 1])
    return distance

def shortest_path_first(pathes):
    """
    最短路径距离
    :param pathes:  [] 路径列表,[path1,path2]
    :return: function
    """
    if len(pathes) <= 1: return pathes
    return sorted(pathes, key=get_path_distance)

def main():
    plt_beijing_subway_line()

if __name__ == "__main__":
    main()