import math
from PIL import Image, ImageDraw

number = 50
maxImageHeight = 300
rotateFactor = 30

def GetObjectProperties(labels, areas, imagePath):
    global number
    global rotateFactor
    orientation = 0

    elements = []

    size = len(areas)

    for indexAreas in range(0, size, 1):
        area = GetObjectArea(labels, areas, indexAreas)
        if area < number:
            continue
        perimeter = GetObjectPerimeter(labels, areas, indexAreas)
        compactness = GetObjectCompactness(perimeter, area)

        CreateImage(labels, areas[indexAreas], indexAreas, "Source Images\\")

        xCenter, yCenter = GetObjectCenterOfMass(labels, areas[indexAreas], indexAreas)
        xCenter, yCenter, orientation = GetNeedCenterOfMass(xCenter, yCenter, areas[indexAreas])
        staticMoment11 = GetObjectStaticMoment(labels, areas[indexAreas], indexAreas, xCenter, yCenter, 1, 1, orientation)
        staticMoment20 = GetObjectStaticMoment(labels, areas[indexAreas], indexAreas, xCenter, yCenter, 2, 0, orientation)
        staticMoment02 = GetObjectStaticMoment(labels, areas[indexAreas], indexAreas, xCenter, yCenter, 0, 2, orientation)
        elongation = GetObjectElongation(staticMoment02, staticMoment20, staticMoment11)

        scalingFactor = GetScalingFactor(areas[indexAreas])

        scalingXCenter = scalingFactor * xCenter
        scalingYCenter = scalingFactor * yCenter

        WriteData(str(indexAreas) + ".txt", areas[indexAreas], area, perimeter, compactness, xCenter, yCenter,
                  staticMoment02, staticMoment11, staticMoment20, elongation, scalingXCenter, scalingYCenter)

        elements.append([indexAreas, scalingXCenter, scalingYCenter, compactness * 2, elongation])

    return elements

def GetObjectArea(labels, areas, indexAreas):
    area = 0

    for i in range(areas[indexAreas][0], areas[indexAreas][2] + 1, 1):
        for j in range(areas[indexAreas][1], areas[indexAreas][3] + 1, 1):
            if (labels[i][j] == indexAreas + 1):
                area += 1

    return area

def GetLabel(labels, i, j):
    try:
        return labels[i][j]
    except Exception as exc:
        return 0

def GetObjectPerimeter(labels, areas, indexAreas):
    perimeter = 0

    for i in range(areas[indexAreas][0], areas[indexAreas][2] + 1, 1):
        for j in range(areas[indexAreas][1], areas[indexAreas][3] + 1, 1):
            if labels[i][j] == indexAreas + 1:
                counter = GetLabel(labels, i - 1, j) + GetLabel(labels, i + 1, j) + GetLabel(labels, i,
                                                                                j - 1) + GetLabel(labels,
                                                                                i, j + 1)

                if counter != (indexAreas + 1) * 4:
                    perimeter += 1

    return perimeter

def GetObjectCompactness(perimeter, area):
    return perimeter ** 2 / area

def GetObjectCenterOfMass(labels, areas, indexAreas):
    xCounter = 0
    yCounter = 0
    counter = 0

    for i in range(areas[0], areas[2] + 1, 1):
        for j in range(areas[1], areas[3] + 1, 1):
            if labels[i][j] == indexAreas + 1:
                xCounter += i
                yCounter += j
                counter += 1

    return (xCounter / counter) - areas[0], (yCounter / counter) - areas[1]

def GetObjectStaticMoment(labels, areas, indexAreas, xCenter, yCenter, i, j, orientation):
    staticMoment = 0
    height = areas[2] - areas[0] + 1
    width = areas[3] - areas[1] + 1
    for x in range(areas[0], areas[2] + 1, 1):
        for y in range(areas[1], areas[3] + 1, 1):
            if labels[x][y] == indexAreas + 1:
                valueX = x - areas[0]
                valueY = y - areas[1]
                if orientation == 0:
                    staticMoment += ((valueX - xCenter) ** i) * ((valueY - yCenter) ** j)
                elif orientation == 1:
                    staticMoment += (((height - valueX) - xCenter) ** i) * (((width - valueY) - yCenter) ** j)
                elif orientation == 2:
                    staticMoment += (((width - valueY) - xCenter) ** i) * ((valueX - yCenter) ** j)
                elif orientation == 3:
                    staticMoment += ((valueY - xCenter) ** i) * (((height - valueX) - yCenter) ** j)

    return staticMoment

def GetObjectElongation(staticMoment02, staticMoment20, staticMoment11):
    try:
        part1 = staticMoment20 + staticMoment02
        part2 = math.sqrt((staticMoment20 - staticMoment02) ** 2 + 4 * staticMoment11)

        return (part1 + part2) / (part1 - part2)

    except Exception as exp:
        return math.inf

def GetObjectOrientation(staticMoment02, staticMoment20, staticMoment11):
    try:
        value = 2 * staticMoment11 / (staticMoment20 - staticMoment02)
        return 0.5 * math.atan(value) * 180 / math.pi
    except Exception as exp:
        return 45

def WriteData(fileName, diap, area, perimeter, comp, x, y, stM02, stM20, stM11, el, scalingXCenter,
              scalingYCenter):
    try:
        file = open("Data\\" + fileName, 'w')
        try:
            file.write("Площадь: " + str(area) + "\n")
            file.write("Периметр: " + str(perimeter) + "\n")
            file.write("Компактность: " + str(comp) + "\n")
            file.write("Центр масс x=" + str(x) + " y=" + str(y) + "\n")
            file.write("Статические моменты:\n")
            file.write("stM02=" + str(stM02) + "\n")
            file.write("stM11=" + str(stM11) + "\n")
            file.write("stM20=" + str(stM20) + "\n")
            file.write("Удлинненность: " + str(el) + "\n")
            file.write("Высота: " + str(diap[2] - diap[0] + 1) + "\n")
            file.write("Ширина: " + str(diap[3] - diap[1] + 1) + "\n")
            file.write("Маштабированная координата x центра масс: " + str(scalingXCenter) + "\n")
            file.write("Маштабированная координата y центра масс: " + str(scalingYCenter) + "\n")

        except Exception as ex:
            print(ex)
        finally:
            file.close()
    except Exception as ex:
        print(ex)

def CreateImage(labels, areas, indexAreas, repository):
    height = areas[2] - areas[0] + 1
    width = areas[3] - areas[1] + 1

    image = Image.new("RGB", (height, width))
    draw = ImageDraw.Draw(image)

    for i in range(0, height, 1):
        for j in range(0, width, 1):
            draw.point((i, j), (0, 0, 0))

    for i in range(0, height, 1):
        for j in range(0, width, 1):
            if labels[i + areas[0]][j + areas[1]] == indexAreas + 1:
                draw.point((i, j), (255, 255, 255))

    for i in range(0, height, 1):
        for j in range(0, width, 1):
            if labels[i + areas[0]][j + areas[1]] == 0:
                counter = GetLabel(labels, i - 1 + areas[0], j + areas[1]) + GetLabel(labels, i + 1 + areas[0],
                                                                                j + areas[1]) + GetLabel(labels,
                                                                                i +
                                                                                areas[0],
                                                                                j - 1 +
                                                                                areas[
                                                                                1]) + GetLabel(
                    labels, i + areas[0], j + 1 + areas[1])
                if counter >= 4 * (indexAreas + 1):
                    draw.point((i, j), (255, 255, 255))

    image.save("Images\\" + repository + str(indexAreas) + ".png")

def GetNeedCenterOfMass(xCenter, yCenter, newAreas):
    height = newAreas[2] - newAreas[0] + 1
    width = newAreas[3] - newAreas[1] + 1

    diapX = []
    diapY = []

    diapX.append(xCenter)
    diapX.append(height - xCenter)
    diapX.append(width - yCenter)
    diapX.append(yCenter)

    diapY.append(yCenter)
    diapY.append(width - yCenter)
    diapY.append(xCenter)
    diapY.append(height - xCenter)

    maxValue = max(diapX)
    orientation = diapX.index(maxValue)

    return diapX[orientation], diapY[orientation], orientation

def GetScalingFactor(areas):
    global maxImageHeight

    height = areas[2] - areas[0] + 1
    width = areas[3] - areas[1] + 1

    value = max(height, width)

    return maxImageHeight / value


class worker:
    def __init__(self):
        self.current_task = ''
        self.finish_time = 0

with open("/Users/DominikKloepfer/Documents/workspace/Personal_Projects/Advent of Code 2018/Day 7/day7_input1.txt") as input:
    conditions = [line.strip().split(' ') for line in input]

steps = {} # each key has value [[predecessors], [successors]]

for condition in conditions:
    if not condition[1] in steps:
        steps[condition[1]] = [[], [condition[7]]]
    else:
        steps[condition[1]][1].append(condition[7])

    if not condition[7] in steps:
        steps[condition[7]] = [[condition[1]], []]
    else:
        steps[condition[7]][0].append(condition[1])

workers = [worker() for w in range(0, 5)]

proper_time = -1
steps_to_do = len(steps)

while steps_to_do > 0:
    next_finish = 100000
    for worker in workers:
        if worker.finish_time > proper_time and worker.finish_time < next_finish:
            next_finish = worker.finish_time
    proper_time = next_finish

    for worker in workers:
        if worker.finish_time == proper_time and worker.current_task != '':

            for successor in steps[worker.current_task][1]:
                steps[successor][0].remove(worker.current_task)
            steps_to_do -= 1

    i = 0
    while i < len(steps):
        step = sorted(steps.keys())[i]
        if steps[step][0] == [] and not all(worker.finish_time > proper_time for worker in workers):
            print(step, proper_time + 60 + i +1)
            # assign step
            for worker in workers:
                if worker.finish_time <= proper_time:
                    worker.current_task = step
                    worker.finish_time = proper_time + 60 + i+1
                    break

            steps[step][0] = ['Done']
            i = -1 # returns to beginning of steps

        i += 1

print(proper_time)


import fcntl
import os
import shutil
import sys
from contextlib import suppress
from itertools import count, product
from logging import getLogger
from pathlib import Path
from uuid import uuid4

from pypika import SQLLiteQuery as Query
from pypika import Table

from marv.utils import within_pyinstaller_bundle
from marv_api.utils import find_obj
from marv_node.node import Node
from marv_node.run import run_nodes
from marv_store import Store

from .collection import Collections
from .config import Config, ConfigError
from .db import Database, DBNotInitializedError, Tortoise, create_or_ignore, scoped_session
from .model import Dataset, Group, User

log = getLogger(__name__)

class SiteError(Exception):
    pass

def make_config(siteconf):
    return Config.from_file(siteconf)

def load_sitepackages(sitepackages):
    import site  # pylint: disable=import-outside-toplevel
    site.USER_SITE = sitepackages
    sitepackages.mkdir(parents=True, exist_ok=True)
    if str(sitepackages) not in sys.path:
        sys.path.append(str(sitepackages))
    with suppress(FileNotFoundError), \
         (sitepackages / 'easy-install.pth').open('r') as f:
        for directory in f.readlines():
            if directory[0] == '#' or directory.startswith('import'):
                continue
            directory = directory.strip()
            if directory not in sys.path:
                sys.path.append(directory)

class Site:
    Database = Database
    PREFETCH_FOR_RENDER = ('files',)
    PREFETCH_FOR_RUN = ('collection', 'files')

    def __init__(self, siteconf):
        self.config = make_config(siteconf)
        self.collections = Collections(config=self.config, site=self)
        self.db = self.Database(  # pylint: disable=invalid-name
            [y for x in self.collections.values() for y in x.model],
            self.config,
        )

    @classmethod
    async def create(cls, siteconf, init=None):  # noqa: C901
        site = cls(siteconf)
        if within_pyinstaller_bundle():
            load_sitepackages(site.config.marv.sitepackages)
        site.config.marv.resourcedir.mkdir(exist_ok=True)

        site.db.check_db_version(site.config.marv.dburi, missing_ok=init)

        dbpath = Path(site.config.marv.dburi.split('sqlite://', 1)[1])
        store_db_version = not dbpath.exists()

        if init:
            site.init_directory()

        try:
            fd = os.open(
                site.config.marv.sessionkey_file,
                os.O_CREAT | os.O_EXCL | os.O_WRONLY,
                0o600,
            )
        except OSError as e:
            if e.errno != 17:
                raise
        else:
            with os.fdopen(fd, 'w') as f:
                f.write(str(uuid4()))
            log.verbose('Generated %s', site.config.marv.sessionkey_file)

        # Generate all dynamic models
        models = site.db.MODELS + site.db.listing_models

        await Tortoise.init(
            config={
                'connections': {
                    'default': {
                        'engine': 'tortoise.backends.sqlite',
                        'credentials': {
                            'file_path': dbpath,
                            'foreign_keys': 1,
                        },
                    },
                },
                'apps': {
                    'models': {
                        'models': models,
                    },
                },
            },
        )

        await site.db.initialize_connections()

        try:
            if init:
                await site.init_database(store_db_version=store_db_version)

            async with scoped_session(site.db) as txn:
                try:
                    await txn.execute_query('SELECT name FROM sqlite_master WHERE type="table"')
                except ValueError:
                    raise DBNotInitializedError
        except BaseException:
            await site.destroy()
            raise

        return site

    async def destroy(self):
        await self.db.close_connections()
        await Tortoise.close_connections()

    def load_for_web(self):
        _ = [
            getattr(x, y) and None for x, y, in product(
                self.collections.values(),
                (
                    'compare',
                    'filter_specs',
                    'listing_columns',
                    'model',
                    'sortcolumn',
                    'sortorder',
                    'summary_items',
                ),
            )
        ]

    def init_directory(self):
        try:
            os.mkdir(self.config.marv.storedir)
            log.verbose('Created %s', self.config.marv.storedir)
        except OSError as e:
            if e.errno != 17:
                raise

        try:
            dbdir = os.path.dirname(self.config.marv.dburi.replace('sqlite://', ''))
            os.mkdir(dbdir)
            log.verbose('Created %s', dbdir)
        except OSError as e:
            if e.errno != 17:
                raise

    async def store_db_version(self, txn):
        metadata = Table('metadata')
        # yapf: disable
        await txn.exq(
            Query
            .into(metadata)
            .columns(metadata.key, metadata.value)
            .insert('database_version', self.db.VERSION),
        )
        # yapf: enable

    async def drop_listings(self, txn):
        prefixes = [f'l_{col}' for col in self.collections.keys()]
        tables = {
            name for name in [
                x['name'] for x in
                (await txn.execute_query('SELECT name FROM sqlite_master WHERE type="table"'))[1]
            ] if any(name.startswith(prefix) for prefix in prefixes)
        }
        for table in sorted(tables, key=len, reverse=True):
            await txn.execute_query(f'DROP TABLE {table};')

    async def init_database(self, store_db_version=False):
        async with scoped_session(self.db) as txn:
            await self.drop_listings(txn)

        await Tortoise.generate_schemas()

        async with scoped_session(self.db) as txn:
            for name in ('marv:user:anonymous', 'marv:users', 'admin'):
                await Group.get_or_create(name=name, using_db=txn)

            for name in ('marv:anonymous',):
                user = await User.get_or_create(
                    name=name,
                    realm='marv',
                    realmuid='',
                    active=True,
                    using_db=txn,
                )
                await user[0].groups.add(
                    await Group.get(name=name.replace(':', ':user:')).using_db(txn),
                    using_db=txn,
                )

            if store_db_version:
                await self.store_db_version(txn)

            await create_or_ignore('acn', id=1, txn=txn)
            await create_or_ignore('acn', id=2, txn=txn)
            for name in self.collections:
                await create_or_ignore('collection', name=name, acn_id=1, txn=txn)

            log.verbose('Initialized database %s', self.config.marv.dburi)
            await self.render_detail_and_listing_for_all(txn=txn)
        log.info('Initialized from %s', self.config.filename)

    async def render_detail_and_listing_for_all(self, txn):
        for col, collection in self.collections.items():
            loop = count()
            batchsize = 50
            # TODO: increase verbosity and probably introduce --reinit
            while True:
                batch = await Dataset.filter(collection__name=col)\
                                     .using_db(txn)\
                                     .prefetch_related(*self.PREFETCH_FOR_RENDER)\
                                     .limit(batchsize)\
                                     .offset(batchsize * next(loop))\
                                     .all()
                for dataset in batch:
                    collection.render_detail(dataset)
                if batch:
                    await collection.update_listings(batch, txn=txn)
                if len(batch) < batchsize:
                    break

    async def cleanup_discarded(self):
        descs = {key: x.table_descriptors for key, x in self.collections.items()}
        await self.db.cleanup_discarded(descs)
        # TODO: Cleanup corresponding store paths

    async def cleanup_relations(self):
        descs = {key: x.table_descriptors for key, x in self.collections.items()}
        await self.db.delete_listing_rel_values_without_ref(descs)

    async def restore_database(self, **kw):
        await self.db.restore_database(self, kw)

    async def run(
        self,
        setid,
        selected_nodes=None,
        deps=None,
        force=None,
        keep=None,
        force_dependent=None,
        update_detail=None,
        update_listing=None,
        excluded_nodes=None,
        cachesize=None,
    ):
        # pylint: disable=too-many-arguments,too-many-locals,too-many-branches

        assert not force_dependent or selected_nodes

        excluded_nodes = set(excluded_nodes or [])
        async with scoped_session(self.db) as txn:
            dataset = await Dataset.get(setid=setid)\
                                   .prefetch_related(*self.PREFETCH_FOR_RUN)\
                                   .using_db(txn)
        collection = self.collections[dataset.collection.name]
        selected_nodes = set(selected_nodes or [])
        if not (selected_nodes or update_listing or update_detail):
            selected_nodes.update(collection.listing_deps)
            selected_nodes.update(collection.detail_deps)
        persistent = collection.nodes
        try:
            nodes = {
                persistent[name] if ':' not in name else Node.from_dag_node(find_obj(name))
                for name in selected_nodes
                if name not in excluded_nodes if name != 'dataset'
            }
        except KeyError as exc:
            raise ConfigError(f'Collection {collection.name!r} has no node {exc}')

        if force_dependent:
            nodes.update(x for name in selected_nodes for x in persistent[name].dependent)
        nodes = sorted(nodes)

        storedir = self.config.marv.storedir
        store = Store(storedir, persistent)

        changed = False
        try:
            if nodes:
                changed = await run_nodes(
                    dataset,
                    nodes,
                    store,
                    force=force,
                    persistent=persistent,
                    deps=deps,
                    cachesize=cachesize,
                    site=self,
                )
        finally:
            if not keep:
                for stream in store.pending:
                    if stream.streamfile:
                        stream.streamfile.close()
                for stream in store.readstreams:
                    if stream.streamfile:
                        stream.streamfile.close()
                for tmpdir, tmpdir_fd in store.pending.values():
                    store.logdebug('Cleaning up %r', tmpdir)
                    shutil.rmtree(tmpdir)
                    fcntl.flock(tmpdir_fd, fcntl.LOCK_UN)
                    os.close(tmpdir_fd)
                store.pending.clear()

        if changed or update_detail:
            collection.render_detail(dataset)
            log.verbose('%s detail rendered', setid)
        if changed or update_listing:
            await collection.update_listings([dataset])
            log.verbose('%s listing rendered', setid)

        return changed

    async def scan(self, dry_run=None):
        for collection in self.collections.values():
            for scanroot in collection.scanroots:
                await collection.scan(scanroot, dry_run)


import os, shutil, sys, subprocess
from numpy import *

'''

'''

DISULFIDESDISTANCE = 2.5

#
all_atoms = True
names_to_changes = ["XX ", "C2 ", "C3 ", "C4 ", "C5 ", "C6 ", "C7 ", "C8 ", "C9 ", "C10", "O1 ", "H10", "H7 "]

# Input name is key and value is the name from the MD
# parameter file
atom_name = {
    "C3 ": "C  ",
    "O3 ": "O  ",
    "N1 ": "N1 ",
    "N2 ": "N  ",
    "C4 ": "C1 ",
    "C5 ": "C4 ",
    "C2 ": "C2 ",
    "S1 ": "S  ",
    "C6 ": "C3 ",
    "C7 ": "C5 ",
    "C8 ": "C6 ",
    "C9 ": "C7 ",
    "C10": "C8 ",
    "C11": "C9 ",
    "O11": "O2 ",
    "O12": "O1 "
}

def insert_correct_histidines(tmplist, hie_numbers):
    correct_list = []

    for line in tmplist:

        if (line[17:19] == "HI" and line[23:26].strip() in hie_numbers):

            line = str(line[0:17]) + "HIE" + str(line[20:])

            correct_list.append(line)

        elif (line[17:19] == "HI"):

            line = str(line[0:17]) + "HID" + str(line[20:])

            correct_list.append(line)

        else:
            correct_list.append(line)

    return correct_list

def insert_disulfides(tmplist, residuepairs):
    # mega ugly hack
    residuenumbers = []
    for i in residuepairs:
        tmp = i.split(',')
        residuenumbers.append(tmp[0])
        residuenumbers.append(tmp[1])

    correct_list = []
    for line in tmplist:

        if (line[17:19] == "CY" and line[23:26].strip() in residuenumbers):

            line = str(line[0:17]) + "CYX" + str(line[20:])
            correct_list.append(line)

        else:
            correct_list.append(line)

    return correct_list

# add 11-02-2014
def get_sulfur_atom_coordinates(pdbfile):
    sulfur_coordinates = {}

    for line in pdbfile:

        if ( line[0:4] == 'ATOM' and line[13:14] == 'S'):
            sulfur_coordinates[line[22:26].strip()] = array(
                [float(line[31:39]), float(line[39:47]), float(line[47:55])])

    return sulfur_coordinates

def test_disulfide(sulfur_coordinates):
    """

    :param sulfur_coordinates:
    :return: pairs of disulfides
    """
    disulfides_pairs = []

    tmpfile = open("disulfide_pairs.txt",'w')

    already_done = []

    for k,v in sulfur_coordinates.iteritems():
        for kk,vv in sulfur_coordinates.iteritems():

            if ( kk != k) and kk not in already_done:
                if linalg.norm( v - vv ) <= DISULFIDESDISTANCE:
                    tmpfile.write(k+','+kk+"\n")
                    already_done.append(k)
                    pair = k+','+kk

                    #disulfides_pairs.append(k)
                    #disulfides_pairs.append(kk)
                    disulfides_pairs.append(pair)

            else:
                continue

    tmpfile.close()
    return disulfides_pairs

def write_amber_input_file(disulfides_pair):
    # bond oxy.1.SG oxy.6.SG
    ds_string = ""
    for i in disulfides_pair:
        pair = i.split(',')
        ds_string = ds_string +"bond prt."+str(pair[0])+".SG prt."+str(pair[1])+".SG\n"
    # blabla
    template = '''
source leaprc.gaff
#loadoff q4md-forcefieldtools-cofactors.off
#loadoff phosphoaa10.lib
loadoff ions08.lib
# load protein
prt = loadpdb design1.pdb
'''+ds_string+'''

saveamberparm prt apo_vacuum.prmtop apo_vacuum.inpcrd
quit
    '''
    return template

def main():
    pdbfile = sys.argv[1]

    filename = open(pdbfile, 'r')

    tmplist = []
    # HID residues - Ndelta protonation
    hid_residue_id = []
    # HIE residue - Nepsilon protonation
    hie_residue_id = []

    residuename = "BTN"

    new_residue_name = "BTN"

    change = False

    for line in filename:

        if ( line[17:20] == residuename ):

            if (line[13:16] in names_to_changes or all_atoms):

                newline = line[0:13] + str(atom_name[str(line[13:16])]) + line[16:17] + new_residue_name + line[20:]

                tmplist.append(newline)

                # tmpfile.write(newline)

            elif ( line[13:14] == 'H'):

                continue

            elif (line[13:16] in forbidden_atom_names):

                continue

            else:

                newline = line[0:17] + new_residue_name + line[20:]

                tmplist.append(newline)

                # tmpfile.write(newline)

        else:
            # test for histidine

            if ( line[17:20] == "HIS" ):
                # HD1 - proton located on Nd1
                if ( line[13:16] == "HD1" ):
                    hid_residue_id.append(line[23:26].strip())
                    # HE2 - proton is located on Ne2
                if ( line[13:16] == "HE2" ):
                    hie_residue_id.append(line[23:26].strip())

            if (line[13:14] != 'H' and line[13:15] != "NV" and line[12:14] != "OV" and line[13:14] != 'X'):
                tmplist.append(line)

    # tmpfile.close()
    filename.close()

    # replace histidine protonations
    if ( len(hid_residue_id) > 0 or len(hie_residue_id) ):
        tmplist = insert_correct_histidines(tmplist, hie_residue_id)

    # vector with coordinates
    sulfur_coordinates = get_sulfur_atom_coordinates(tmplist)

    positions_to_change_for_sulfides = test_disulfide(sulfur_coordinates)

    if ( len(positions_to_change_for_sulfides) > 0):

        tmplist = insert_disulfides(tmplist, positions_to_change_for_sulfides)

    tmpfile = open('tmp.pdb', 'w')

    for line in tmplist:
        tmpfile.write(line)
    tmpfile.close()

    mvfl = 'mv tmp.pdb ' + str(pdbfile)

    subprocess.Popen(mvfl, shell=True).wait()

    tmp_amber = open("generate_input_parameters_disulfides.sh",'w')

    output_file = write_amber_input_file( positions_to_change_for_sulfides )

    for i in output_file:
        tmp_amber.write(i)

    tmp_amber.close()

if __name__ == "__main__":
    main()


def dstat(inarr, taxdict, mindict=1, nboots=1000, name=0):
    """ private function to perform a single D-stat test"""

    #if isinstance(inarr, str):
    #    with open(inarr, 'r') as infile:
    #        inarr = infile.read().strip().split("|\n")

    # ## get data as an array from loci file
    # ## if loci-list then parse arr from loci
    if isinstance(inarr, list):
        arr, _ = _loci_to_arr(inarr, taxdict, mindict)

    # ## if it's an array already then go ahead
    # elif isinstance(inarr, np.ndarray):
    #     arr = inarr
    # ## if it's a simulation object get freqs from array
    # elif isinstance(inarr, Sim):
    #     arr = _msp_to_arr(inarr, taxdict)

    #elif isinstance(inarr, types.GeneratorType):
    #    arr = _msp_to_arr(inarr, taxdict)
    #elif isinstance(inarr, list):
    #    arr = _msp_to_arr(inarr, taxdict)
    ## get data from Sim object, do not digest the ms generator
    #else:
    #    raise Exception("Must enter either a 'locifile' or 'arr'")

    ## run tests
    #if len(taxdict) == 4:
    if arr.shape[1] == 4:

        ## get results
        res, boots = _get_signif_4(arr, nboots)

        ## make res into a nice DataFrame
        res = pd.DataFrame(res,
            columns=[name],
            index=["Dstat", "bootmean", "bootstd", "Z", "ABBA", "BABA", "nloci"])

    else:
        ## get results
        res, boots = _get_signif_5(arr, nboots)
         ## make int a DataFrame
        res = pd.DataFrame(res,
            index=["p3", "p4", "shared"],
            columns=["Dstat", "bootmean", "bootstd", "Z", "ABxxA", "BAxxA", "nloci"]
            )

    return res.T, boots


# The sum of the squares of the first ten natural numbers is,

# The square of the sum of the first ten natural numbers is,

# Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is .

# Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
from math import pow

x = list(range(1,101))
print(x)
# resultado 1
result1 = pow(sum(x),2)
print(result1)
y = 0
#resultado2
for n in x:
  y = y + pow(n,2)
print(y)

result = result1 - y
print(result)


import sys
from itertools import takewhile

def factorization_2357(x):

    fs = [0]*10

    for p in [2, 3, 5, 7]:
        while x % p == 0:
            fs[p] += 1
            x //= p

    if x > 1:
        fs = []

    return fs

def solve(n):

    if len(n) == 1:
        return '1' + n

    fs = factorization_2357(int(n))

    if not fs:
        return 'There is no such number.'

    fs[9] = fs[3] // 2
    fs[3] %= 2

    fs[8] = fs[2] // 3
    fs[2] %= 3

    if fs[3] > 0 and fs[2] > 0:
        fs[6] = 1
        fs[2] -= 1
        fs[3] -= 1

    fs[4] = fs[2] // 2
    fs[2] %= 2

    x = 0

    for d in range(2, 10):
        while fs[d] > 0:
            x = 10*x + d
            fs[d] -= 1

    return str(x)

if __name__ == '__main__':

    ns = [x.strip() for x in sys.stdin.readlines()]
    ns = takewhile(lambda x: x != '-1', ns)
    xs = map(solve, ns)

    print('\n'.join(xs))


from flask import Flask, render_template, request
import os
import datetime
import pytesseract
from PIL import Image
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime

app = Flask(__name__)
scheduler = BackgroundScheduler()

# Define the route for the home page
@app.route('/')
def home():
    return render_template('index.html')

# Define the route to handle form submission
@app.route('/success', methods=['POST'])
def upload():
    # Get the uploaded file from the form
    uploaded_file = request.files['file']

    # Get the date and time for text extraction
    extraction_datetime_str = request.form['datetime']
    extraction_datetime = datetime.strptime(extraction_datetime_str, '%Y-%m-%dT%H:%M')

    # Schedule the text extraction
    scheduler.add_job(extract_text, 'date', run_date=extraction_datetime, args=[uploaded_file])
    text1=extract_text(uploaded_file)
    return render_template("result_data.html", result=text1)

# Function to extract text from the TIFF image using OCR
def extract_text(uploaded_file):
    pytesseract.pytesseract.tesseract_cmd = r'/var/task/pytesseract/pytesseract.py'
    image = Image.open(uploaded_file)
    text = pytesseract.image_to_string(image)
    return text

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


from typing import Any, Tuple

import numpy as np

def fill_gamut(img, dtype=None):
    """Scale image values to fill datatype range

    Sets the lowest value to 0 and the highest to whatever is the highest that
    `dtype` allows, or 1. if dtype is a floating point type.

    Parameters
    ----------
    img : array-like
        Image data
    dtype : numpy.dtype or None, optional
        dtype of the output array. Image will be scaled to fill the value range
        of the type. E.g. if ``dtype=numpy.uint8``, the resulting image will
        take values between 0 and 255. If `None`, use ``img.dtype``. Defaults
        to `None`.

    Returns
    -------
    numpy.ndarray
        Scaled image with `dtype` as data type.
    """
    if dtype is None:
        dtype = img.dtype

    scaled = img - img.min()
    scaled = scaled / scaled.max()

    if np.issubdtype(dtype, np.integer):
        scaled *= np.iinfo(dtype).max

    return scaled.astype(dtype)

def center(obj: np.ndarray, shape: Tuple[int, ...], fill_value: Any = 0
           ) -> np.ndarray:
    """Center an image in an array of different size

    If the new shape is larger, the image will be padded, otherwise it will be
    cropped.

    Parameters
    ----------
    obj
        Image array
    shape
        Output shape
    fill_value
        Value to use for padding

    Returns
    -------
    New array with `obj` centered.
    """
    ret = np.full(shape, fill_value, dtype=obj.dtype)
    ret_slices = []
    obj_slices = []
    for n, o in zip(shape, obj.shape):
        e = min(n, o)
        ret_margin = (n - e) // 2
        ret_slices.append(slice(ret_margin, ret_margin + e))
        obj_margin = (o - e) // 2
        obj_slices.append(slice(obj_margin, obj_margin + e))

    ret[tuple(ret_slices)] = obj[tuple(obj_slices)]
    return ret


# Необходимо создать функцию sumNumbers(n), которая будет считатьvсумму всех элементов от 1 до n.

def sum_numbers(n, y):
    print(y)
    summa = 0
    for i in range(1, n+1):
        summa += i
    return summa

a = sum_numbers(5, 'qwerty')
print(a)

# Функция, которая принимает неограниченное количество аргументов

def sum_str(*args):
    res = ''
    for i in args:
        res += i
    return res
print(sum_str('q', 'e', 'r'))
print(sum_str('a', 'd', 'g', 'h'))
# print(sum_str(1, 3, 9, 52)) # Ошибка типа данных

############################################### IMPORT

import modul_1
print(modul_1.max_1(5, 9))
# либо
from modul_1 import max_1
print(max_1(15, 9))

from modul_1 import * # - Для импорта всех функций из modul_1

import modul_1 as m1
print(m1.max_1(10, 25))

##########################################  RECURSION

# Пользователь вводит число n. Необходимо вывести n - первых членов последовательности Фибоначчи.

def fib(n):
    if n in [1, 2]:
        return 1
    return fib(n - 1) + fib(n - 2)

list_1 = []
for i in range(1, 10):
    list_1.append(fib(i))
print(list_1)

########################################## АЛГОРИТМЫ

# БЫСТРАЯ СОРТИРОВКА

def quick_sort(array):
    if len(array) <= 1:
        return array
    else:
        pivot = array[0]
        less = [i for i in array[1:] if i <= pivot]
        greater = [i for i in array[1:] if i > pivot]
        return quick_sort(less) + [pivot] + quick_sort(greater)
print(quick_sort([14,5,9,6,8,2,3,7,45,2,1,523,235,33,25,25,64,6,5,4,12,3,6,8,9,4]))

def merge_sort(nums):
    if len(nums) > 1:
        mid = len(nums)//2
        left = nums[:mid]
        rigth = nums[mid:]
        merge_sort(left)
        merge_sort(rigth)
        i = j = k = 0
        while i < len(left) and j < len(rigth):
            if left[i] < rigth[j]:
                nums[k] = left[i]
                i += 1
            else:
                nums[k] = rigth[j]
                j += 1
            k += 1
        while i < len(left):
            nums[k] = left[i]
            i += 1
            k += 1
        while j < len(rigth):
            nums[k] = rigth[j]
            j += 1
            k += 1
list_1 = [14,5,9,6,8,2,3,7,45,2,1,523,235,33,25,25,64,6,5,4,12,3,6,8,9,4]
merge_sort(list_1)
print(list_1)


###############################
#                             #
#   SENSOR CONTROL VARIABLES  #
#                             #
###############################

max_sensor_val = 2000
min_sensor_val = 1
should_update_range = False

###############################
#                             #
#   MUSIC THEORY VARIABLES    #
#                             #
###############################

scale_type = 'minor'
scale_base_note = 'g'
should_change_scale = False

octave_start = 4
octave_nums = 2
should_change_octave = False

is_chord_mode = False
should_change_chord_mode = False

can_play_conescutive_repeating_notes = False

###############################
#                             #
#   OUTPUT TYPE VARIABLES     #
#                             #
###############################

is_sound_out_active = True
is_midi_out_active = False

###############################
#                             #
#   SOUND HANDLER VARIABLES   #
#                             #
###############################

sound_wave_type = 'sine'
sound_duration = 0.2

###############################
#                             #
#   MIDI HANDLER VARIABLES    #
#                             #
###############################

midiout_port = 2
midiout_channel = 1


n=input()
m=input()
n=list(n.lower())
m=list(m.lower())
z=[]
for i in range(97,124):
    if chr(i) in n and chr(i) not in m:
        z.append(chr(i))
    elif chr(i) in m and chr(i) not in n:
        z.append(chr(i))
for d in z:
    print(d,end='')


import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import linregress

def draw_plot():
     # Read data from file
    df = pd.read_csv("epa-sea-level.csv", float_precision='legacy')

    # Create scatter plot
    y = df["CSIRO Adjusted Sea Level"]
    x = df["Year"]
    fig, ax = plt.subplots()
    plt.scatter(x, y)

    # Create first line of best fit
    res = linregress(x, y)
    x_guess = pd.Series([i for i in range(1880, 2051)])
    y_guess = res.slope*x_guess + res.intercept
    plt.plot(x_guess, y_guess, "r")

    # Create second line of best fit
    latest_df = df.loc[df['Year'] >= 2000]
    latest_x = latest_df['Year']
    latest_y = latest_df["CSIRO Adjusted Sea Level"]
    res_2 = linregress(latest_x, latest_y)
    x_guess2 = pd.Series([i for i in range(2000, 2051)])
    y_guess2 = res_2.slope*x_guess2 + res_2.intercept
    plt.plot(x_guess2, y_guess2, 'green')

    # Add labels and title
    plt.xlabel('Year')
    plt.ylabel('Sea Level (inches)')
    plt.title("Rise in Sea Level")

    # Save plot and return data for testing (DO NOT MODIFY)
    plt.savefig('sea_level_plot.png')
    return plt.gca()


from django.conf.urls import url
from . import views

urlpatterns = [
    # /student/
    url(r'^$', views.index, name='index'),

    # /student/grace
    url(r'^grace', views.grace, name='grace'),

    # /student/face
    url(r'^face', views.face, name='face')
]


import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.ticker import MultipleLocator
from matplotlib.ticker import FixedFormatter

import copy

import numpy as np
# TODO: HAVE TO PERFORM IT FOR ALL THE COLUMNS IN SHEETS "DOWN"
# HAVE TO ACCESS ANOTHER SHEET NAMED "UP"
def excel_to_pandas(filename):
    df_dict = pd.read_excel(filename, sheet_name=['DN', 'UP'], header=None)
    down_up = dict()
    dwn_upp = dict()
    for key, df in df_dict.items():
        first_filled_row_index = df.first_valid_index()
        df = df.loc[first_filled_row_index:]
        df = df[2:]
        df = df[:-3]
        df = df.iloc[::-1]
        first_non_empty_row = df.apply(lambda row: row.notnull().any(), axis=1).idxmax()
        df = df.loc[first_non_empty_row:]
        df = df.iloc[::-1]
        df = df.loc[~(df.iloc[:, 0].isna() & df.iloc[:, 0].shift().isin(["EA", "TRT"]))]
        df = df.loc[~df.iloc[:, 0].isin(["EA", "TRT"])]
        df.iloc[:, 0].fillna(method="ffill", inplace=True)
        df = df.dropna(subset=df.columns[2:], how="all")
        df = df.reset_index(drop=True)
        df = df.drop(df.columns[1], axis=1)
        df.iloc[0, 0] = np.nan
        df.columns = df.iloc[0]
        df = df.drop(0)
        first_column_series = df.iloc[:, 0]
        df = df.iloc[:, 1:]
        first_column_series = first_column_series.rename(None)
        first_column_series = first_column_series.str.strip()
        df = df.set_index(first_column_series)
        trains_list = df.columns.tolist()
        list_2d = []
        for column_name in df.columns:
            column_df = df[column_name]
            column_df = column_df.dropna()
            column_df = column_df.astype(str)
            column_df = column_df.str.replace('1900-01-01 ', '')
            column_df = column_df.replace(r'([\s_-]+|^$|(\.))', np.nan, regex=True)
#             column_df = column_df.dropna()
#             mask = column_df.str.contains(r'\.+')
#             column_df[mask] = np.nan
            column_df = column_df.dropna()
#             column_df = column_df[column_df != "......"]
            column_df = column_df[column_df.astype(str).str.contains(r'\d', na=False)]
            column_df = pd.DataFrame(column_df)
            row_indices = column_df.index.tolist()
            datapoints = column_df.iloc[:, 0].tolist()

            # Create the 2-dimensional list
            list_2d = list_2d + [row_indices, datapoints]
        down_up[key] = list_2d
        down_up[key + key] = df.index
        dwn_upp[key] = trains_list
    y_axis = list(dict.fromkeys(down_up['DNDN'].values.tolist()))
    down_up.pop("DNDN")
    down_up.pop("UPUP")
    return down_up,y_axis, dwn_upp

def conversion(station_dict):
    # this wil multiply with ratios for plotting
    for key, value in station_dict.items():
        for i in range(len(value)):
            if i % 2 == 1:  # Check if it's an alternative column
                for j in range(len(value[i])):
                    time_string = value[i][j]
                    hours, minutes, seconds = map(int, time_string.split(':'))

                    # Convert hours, minutes, and seconds to a decimal representation of hours
                    time_in_hours = hours + (minutes / 60) + (seconds / 3600)

                    after_decimal = time_in_hours % 1
                    time_in_hours = int(time_in_hours) + after_decimal

                    # Update the value in the dictionary
                    value[i][j] = str(round(time_in_hours, 2))

                value[i] = [float(num) for num in value[i]]
    return station_dict

def plot_trains(station_dict, y_axis, trains_dict):
    y_axis.insert(0," ")
    y_axis.insert(0,"  ")
    y_axis.insert(0,"   ")
    y_axis.insert(0,"    ")
    y_axis.append("     ")
    y_axis.append("      ")
    y_axis.append("       ")
    y_axis.append("        ")
    print(" ")
    print("Trains dictionary: ", trains_dict)
    print(" ")
# Arrow:
#     eg. axes[2].arrow(20, 25, 0, 1, width = 0.01, head_width=0.1, head_length=0.1, color = 'blue')
#     20---> x axis
#     25 --> y axis
#     1 --> size of line segment

    fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(10, 50))
    for key, arr_2d in station_dict.items():
        for i in range(0, len(arr_2d), 2):
            for j in range(len(arr_2d[i])):
                arr_2d[i][j] = y_axis.index(arr_2d[i][j])
    # Subplot 1: 0-8
    axes[0].minorticks_on()

    # print('station_dict : ', station_dict)
    # xa_0 = np.linspace(0, 8, 200)
    xa_0 = np.arange(0, 8, 0.03333)
    for key, arr_2d in station_dict.items():
        for i in range(0, len(arr_2d), 2):
            axes[0].plot(arr_2d[i+1], arr_2d[i], color='red')
    for i in range(len(y_axis)):
        y_index = y_axis[i]
        ya = [y_index] * len(xa_0)
        axes[0].scatter(xa_0, ya, marker=',',color='blue', s=0.3)

    ### ARROW DowN
    k = 1
    for i in range(len(station_dict['DN']) // 2):
        if 0 <= station_dict['DN'][k][0] <= 8:
            axes[0].text(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 2.3, trains_dict['DN'][i], rotation = 'vertical', fontsize=9)
            axes[0].arrow(station_dict['DN'][k][0], station_dict['DN'][k - 1][0], 0, 1, width = 0.005)
        k += 2

    ### ARROW UP
    k = 1
    for i in range(len(station_dict['UP']) // 2):
        if 0 <= station_dict['UP'][k][0] <= 8:
            axes[0].text(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1.3, trains_dict['UP'][i], rotation = 'vertical', fontsize=9)
            axes[0].arrow(station_dict['UP'][k][0], station_dict['UP'][k - 1][0], 0, -1, width = 0.005)
        k += 2

    axes[0].xaxis.grid(True, which='major', linestyle='-', color='black')
    axes[0].xaxis.grid(True, which='minor', linestyle='-')
    axes[0].xaxis.set_minor_locator(MultipleLocator(10 / 60))
    axes[0].set_xticks([0, 1, 2, 3, 4, 5, 6, 7, 8])
    axes[0].set_xticklabels([0, 1, 2, 3, 4, 5, 6, 7, 8])
    axes[0].set_yticks(range(len(y_axis)))
    axes[0].set_yticklabels(y_axis)
    axes[0].tick_params(axis='x', which='minor', labelbottom=True)
    axes[0].tick_params(labeltop=True, labelright=True)
    minor_labels = ["10", "20", "30", "40", "50"] * 8
    minor_labels.insert(0, "")
    formatter = FixedFormatter(minor_labels)
    axes[0].xaxis.set_minor_formatter(formatter)
    axes[0].tick_params(axis='x', which='minor', labelsize=6)
    axes[0].set_xlim(0, 8)
    axes[0].set_ylim(0, len(y_axis))

    # Subplot 2: 8-16
    axes[1].minorticks_on()
    xa_1 =np.arange(8, 16, 0.03333)
    for key, arr_2d in station_dict.items():
        for i in range(0, len(arr_2d), 2):
            axes[1].plot(arr_2d[i+1], arr_2d[i], color='red')
    for i in range(len(y_axis)):
        y_index = y_axis[i]
        ya = [y_index] * len(xa_1)
        axes[1].scatter(xa_1, ya, marker=',',color='blue', s=0.3)

    ### ARROW DowN
    k = 1
    for i in range(len(station_dict['DN']) // 2):
        if 8 <= station_dict['DN'][k][0] <= 16:
            axes[1].text(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 2.3, trains_dict['DN'][i], rotation = 'vertical', fontsize=9)
            axes[1].arrow(station_dict['DN'][k][0], station_dict['DN'][k - 1][0], 0, 1, width = 0.005)
        k += 2

    ### ARROW UP
    k = 1
    for i in range(len(station_dict['UP']) // 2):
        if 8 <= station_dict['UP'][k][0] <= 16:
            axes[1].text(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1.3, trains_dict['UP'][i], rotation = 'vertical', fontsize=9)
            axes[1].arrow(station_dict['UP'][k][0], station_dict['UP'][k - 1][0], 0, -1, width = 0.005)
        k += 2

    axes[1].xaxis.grid(True, which='major', linestyle='-', color='black')
    axes[1].xaxis.grid(True, which='minor', linestyle='-')
    axes[1].xaxis.set_minor_locator(MultipleLocator(10 / 60))
    axes[1].set_xticks([8, 9, 10, 11, 12, 13, 14, 15, 16])
    axes[1].set_xticklabels([8, 9, 10, 11, 12, 13, 14, 15, 16])
    axes[1].set_yticks(range(len(y_axis)))
    axes[1].set_yticklabels(y_axis)
    axes[1].tick_params(axis='x', which='minor', labelbottom=True)
    axes[1].tick_params(labeltop=True, labelright=True)
    minor_labels = ["10", "20", "30", "40", "50"] * 8
    minor_labels.insert(0, "")
    formatter = FixedFormatter(minor_labels)
    axes[1].xaxis.set_minor_formatter(formatter)
    axes[1].tick_params(axis='x', which='minor', labelsize=6)
    axes[1].set_xlim(8, 16)
    axes[1].set_ylim(0, len(y_axis))

    # Subplot 3: 16-24

    axes[2].minorticks_on()
    xa_2 = np.arange(16, 24, 0.03333)
    for key, arr_2d in station_dict.items():
        for i in range(0, len(arr_2d), 2):
            axes[2].plot(arr_2d[i+1], arr_2d[i], color='red')
    for i in range(len(y_axis)):
        y_index = y_axis[i]
        ya = [y_index] * len(xa_2)
        axes[2].scatter(xa_2, ya, marker=',',color='blue', s=0.3)

    ### ARROW DowN
####################### dummy area ####################################################################
# station_dict = {'DN': [[8, 8, 10, 11], [20.58, 20.67, 20.93, 21.0],
#                        [8, 8, 9, 9, 10,10, 11, 11], [20.83, 20.92, 21.05, 21.07, 21.17, 21.18, 21.32],
#                        [4, 5, 5, 6, 6, 7, 8, 10], [19.67, 19.97, 20.02, 20.32, 20.4, 20.62, 20.77, 21.0]],
#                'UP': [[37, 37, 36, 36, 35 ], [23.2, 23.28, 23.43, 23.47, 23.52],
#                       [37, 37, 36, 35, 34, 33, 32, 31], [23.58, 23.67, 23.8, 23.85, 23.9, 24.02, 24.08, 24.15],
#                       [37, 37, 36, 35, 34, 33], [23.82, 23.9, 24.03, 24.1, 24.15, 24.22]]}
# train_dictionary = {'DN': [20919, 69161, 22927], 'UP': [19034, 19038, 19042]}

####################### Add labels in dictionary #####################################################
    new_dict = copy.deepcopy(station_dict)
    def add_lables(new_dict, train_dictionary):
        """add lables in dictionary"""
        for key in new_dict:
            k = 0
            range_ = (2 * len(new_dict[key]) - int(1/2 * len(new_dict[key]))) // 3
            for i in range(range_):
                new_dict[key].insert(k, str(train_dictionary[key][i]))
                k += 3
        return new_dict
    new_dict = add_lables(new_dict, trains_dict)
############################ new ascending array #####################################################

    def sorting_array(new_dict):
        for key in new_dict:
            pairs = []
            k = 1
            for i in range(len(new_dict[key]) // 3):
                x = new_dict[key][k]
                y = new_dict[key][k+1]
                z = new_dict[key][k - 1]
                pairs.append([z, x, y])
                k += 3
            pairs.sort(key=lambda pair: pair[1][0])

            sorted_list = [elem for pair in pairs for elem in pair]
            new_dict[key] = sorted_list

        return new_dict
    new_dict = sorting_array(new_dict)

########################## collision array ###########################################################

    def extract_first_elem(new_dict):
        """still only done for "DN" """
        collision_xy = [[], []]      ### contatins 1st elemtnts of x and y
        # collision_xy = []      ### contatins 1st elemtnts of x and y
        # collision_x = []
        # collision_y = []
        k = 1
        for i in range(len(new_dict["DN"]) // 3):
            if 16 <= new_dict['DN'][k + 1][0] <= 24:
                # collision_xy.append([station_dict['DN'][k][0],new_dict['DN'][k - 1][0]])
                collision_xy[0].append(new_dict['DN'][k + 1][0])
                collision_xy[1].append(new_dict['DN'][k][0])
                # collision_x.append(new_dict['DN'][k][0])
                # collision_y.append(new_dict['DN'][k - 1][0])
            k += 3
        # Collision x and y:  [[19.67, 20.58, 20.83, 21.25, 21.25, 21.25, 21.33], [4, 8, 8, 8, 8, 8, 10]]
        return collision_xy
    collision_xy = extract_first_elem(new_dict)

############################## collision text function ##########################################

    def collision_text(collision_xy, new_dict):
        """still only done for "DN" """
        k = 1
        last_y = 0
        dup_x = np.array(collision_xy[0])
        dup_y = np.array(collision_xy[1])
        for i in range(len(new_dict['DN']) // 3):
            # print("dup x and y are: ", dup_x, dup_y)
            dup_x = np.delete(dup_x, 0)
            dup_y = np.delete(dup_y, 0)
            y = new_dict['DN'][k][0]
            x = new_dict['DN'][k + 1][0]            #19.67 + 0.7 = 20.37
            # print("x and y are in all i : ",i , x, y)
            print(collision_xy)
            ## Define the range to check
            range_of_x = x + 0.12            # 0.7 is x size of labels
            range_of_y = y + 0.9

            if i == 0:
                overlap_increment = i

            if len(dup_x[dup_x < range_of_x]) == 0 or len(dup_y[dup_y < range_of_y]) == 0:
                if y == last_y :
                    # axes[2].text(x + overlap_increment, y - 2.5, trains_dict['DN'][i], rotation = 'vertical', fontsize=9)
                    axes[2].text(x + overlap_increment, y - 2.5, new_dict['DN'][k - 1], rotation = 'vertical', fontsize=9)
                    print("I am in FIRST shifting plot ", new_dict['DN'][k - 1], x)
                else:
                #     ## normal text
                    axes[2].text(x, y - 2.5, new_dict['DN'][k - 1], rotation = 'vertical', fontsize=9)
                    overlap_increment = 0
                    print("I am in normal plot ", new_dict['DN'][k - 1], x)
            else:
                ## perform shifting
                axes[2].text(x + overlap_increment, y - 2.5, new_dict['DN'][k - 1], rotation = 'vertical', fontsize=9)
                print("I am in shifting plot ", new_dict['DN'][k - 1], x)
                overlap_increment += 0.12
                last_y = y
            k += 3

    collision_text(collision_xy, new_dict)
#######################################################################################################
    # print("new_dict: ", new_dict)
    ## ARROW UP
    k = 1
    # print(station_dict)
    for i in range(len(station_dict['UP']) // 2):
        if 16 <= station_dict['UP'][k][0] <= 24:
            axes[2].text(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1.3, trains_dict['UP'][i], rotation = 'vertical', fontsize=9)
            axes[2].arrow(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1, 0, -1, width = 0.005)
        k += 2

    ## ARROW DOWN
    # fontsize = 7
    # offset = 2.3
    k = 1
    # texts = []
    # i = 0
    for i in range(len(station_dict['UP']) // 2):
        if 16 <= station_dict['UP'][k][0] <= 24:
            axes[2].arrow(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 1, 0, 1, width = 0.005)
            # axes[2].text(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 2.5, trains_dict['DN'][i], rotation = 'vertical', fontsize=9)
        #     axes[2].arrow(station_dict['DN'][k][-1], station_dict['DN'][k - 1][-1] , 0, 1, width = 0.005)
        #     texts.append(axes[2].text(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - offset, trains_dict['DN'][i], rotation='vertical', fontsize=fontsize))

        #     # x_positions = [station_dict['DN'][k][0], station_dict['DN'][k][0]]
        #     # y_positions = [station_dict['DN'][k - 1][0] - offset, station_dict['DN'][k - 1][0] - offset - 0.5]
            k += 2

    # adjust_text(texts, ax=axes[2], expand=(0.5, 0.5), time_lim=1, force_text=(1,0))

    axes[2].xaxis.grid(True, which='major', linestyle='-', color='black')
    axes[2].xaxis.grid(True, which='minor', linestyle='-')
    axes[2].xaxis.set_minor_locator(MultipleLocator(10 / 60))
    axes[2].set_xticks([16, 17, 18, 19, 20, 21, 22, 23, 24])
    axes[2].set_xticklabels([16, 17, 18, 19, 20, 21, 22, 23, 24])
    axes[2].set_yticks(range(len(y_axis)))
    axes[2].set_yticklabels(y_axis)
    axes[2].tick_params(axis='x', which='minor', labelbottom=True)
    axes[2].tick_params(labeltop=True, labelright=True)
    minor_labels = ["10", "20", "30", "40", "50"] * 8
    minor_labels.insert(0, "")
    formatter = FixedFormatter(minor_labels)
    axes[2].xaxis.set_minor_formatter(formatter)
    axes[2].tick_params(axis='x', which='minor', labelsize=6)
    axes[2].set_xlim(16, 24)
    axes[2].set_ylim(0, len(y_axis))

    # Subplot 4: 24-31

    axes[3].minorticks_on()
    xa_3 = np.arange(24, 32, 0.03333)
    for key, arr_2d in station_dict.items():
        for i in range(0, len(arr_2d), 2):
            axes[3].plot(arr_2d[i+1], arr_2d[i], color='red')
    for i in range(len(y_axis)):
        y_index = y_axis[i]
        ya = [y_index] * len(xa_3)
        axes[3].scatter(xa_3, ya, marker=',',color='blue', s=0.3)

    ### ARROW DowN
    k = 1
    for i in range(len(station_dict['DN']) // 2):
        if 24 <= station_dict['DN'][k][0] <= 32:
            axes[3].text(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 2.3, trains_dict['DN'][i], rotation = 'vertical', fontsize=9)
            axes[3].arrow(station_dict['DN'][k][0], station_dict['DN'][k - 1][0] - 1, 0, 1, width = 0.005)
        k += 2

    ### ARROW UP
    k = 1
    for i in range(len(station_dict['UP']) // 2):
        if 24 <= station_dict['UP'][k][0] <= 32:
            axes[3].text(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1.3, trains_dict['UP'][i], rotation = 'vertical', fontsize=9)
            axes[3].arrow(station_dict['UP'][k][0], station_dict['UP'][k - 1][0] + 1, 0, -1, width = 0.005)
        k += 2

    axes[3].xaxis.grid(True, which='major', linestyle='-', color='black')
    axes[3].xaxis.grid(True, which='minor', linestyle='-')
    axes[3].xaxis.set_minor_locator(MultipleLocator(10 / 60))
    axes[3].set_xticks([24,25,26,27,28,29,30,31,32])
    axes[3].set_xticklabels([0, 1, 2, 3, 4, 5, 6, 7, 8])
    axes[3].set_yticks(range(len(y_axis)))
    axes[3].set_yticklabels(y_axis)
    axes[3].tick_params(axis='x', which='minor', labelbottom=True)
    axes[3].tick_params(labeltop=True, labelright=True)
    minor_labels = ["10", "20", "30", "40", "50"] * 8
    minor_labels.insert(0, "")
    formatter = FixedFormatter(minor_labels)
    axes[3].xaxis.set_minor_formatter(formatter)
    axes[3].tick_params(axis='x', which='minor', labelsize=6)
    axes[3].set_xlim(24, 32)
    axes[3].set_ylim(0, len(y_axis))

    plt.tight_layout()
#     for me, ax in enumerate(axes):
#         ax.set_title(f"Subplot {me+1}")
#         # Save each subplot as a separate PDF
#         plt.savefig(f"subplot_{me+1}.pdf")
    plt.savefig("myImagePDF.pdf", format="pdf")
    # plt.show()

def add_24_down_up(down_up):
    arr_2= down_up['DN']
    for hi in range(1, len(arr_2),2):
        arr_2[hi] = [x + 24 if x < 1 else x for x in arr_2[hi]]
    down_up['DN'] = arr_2
    arr_2 = down_up['UP']
    # Add 24 to each element  the arrayin
    for h in range(1, len(arr_2),2):
        arr_2[h] = [x + 24 if x < 23 else x for x in arr_2[h]]
    down_up['UP'] = arr_2
#     print(down_up)
    return down_up

down_up, y_labes, dwn_upp =  excel_to_pandas('HIREN_OLD.xlsx')
for key in dwn_upp:
    dwn_upp[key] = [int(value) for value in dwn_upp[key]]

down_up = conversion(down_up)
down_up = add_24_down_up(down_up)
print(down_up)
plot_trains(down_up, y_labes, dwn_upp)


#изменить баланс белого, сделать более "теплую" картинку
from __future__ import (division, absolute_import, print_function, unicode_literals)
import cv2 as cv
import numpy as np

def show(final):
    cv.imshow('Теплый', final)
    cv.waitKey(0)
    cv.destroyAllWindows()

# Поиск изображения по источнику
img = cv.imread('download.jpg')

#Функция создания баланса белого для создания теплой фотографии
def white_balance_loops(img):
    result = cv.cvtColor(img, cv.COLOR_BGR2LAB)
    avg_a = np.average(result[:, :, 1])
    avg_b = np.average(result[:, :, 2])
    for x in range(result.shape[0]):
        for y in range(result.shape[1]):
            l, a, b = result[x, y, :]
            l *= 100 / 255.0
            result[x, y, 1] = a - ((avg_a - 128) * (l / 100.0) * 1.1)
            result[x, y, 2] = b - ((avg_b - 195) * (l / 100.0) * 1.1)
    result = cv.cvtColor(result, cv.COLOR_LAB2BGR)
    return result

final = np.hstack((img, white_balance_loops(img)))
show(final)
cv.imwrite('task15-image/warm_photo.jpg', final)


import turtle, threading
from random import randint, uniform

p = turtle.Turtle()
p.speed(0)
p.width(4)
p.ht()

DirectionVecLength = 10000
TeakLength = 10

def PrintLine(Line):  ####
    # Рисуем отрезок
    p.goto(Line[0][0], Line[0][1])
    p.down()
    p.color(uniform(0.1, 1), uniform(0.1, 1), uniform(0.1, 1))
    p.goto(Line[1][0], Line[1][1])
    p.up()

def Paint(ListLines):  ####
    # Отрисовываем все отрезки
    p.up()
    for Line in ListLines:
        PrintLine(Line)
    p.up()

def Cross(A, B):  ####
    # находит точку пересечения двух отрезков А и В
    # если пересечение найдено, то возращает TRUE, координаты точки пересечения
    # если пересечение не найдено, то возращает FALSE

    tmp = (A[0][0] - A[1][0]) * (B[0][1] - B[1][1]) - (A[0][1] - A[1][1]) * (B[0][0] - B[1][0])

    if tmp == 0:
        return False, 0
    else:
        xp = ((A[0][0] * A[1][1] - A[0][1] * A[1][0]) * (B[0][0] - B[1][0]) - (A[0][0] - A[1][0]) * (
                    B[0][0] * B[1][1] - B[0][1] * B[1][0])) / tmp
        yp = ((A[0][0] * A[1][1] - A[0][1] * A[1][0]) * (B[0][1] - B[1][1]) - (A[0][1] - A[1][1]) * (
                    B[0][0] * B[1][1] - B[0][1] * B[1][0])) / tmp

        xp = round(xp, 5)
        yp = round(yp, 5)

        if ((A[0][0] <= xp <= A[1][0] or A[0][0] >= xp >= A[1][0]) and (
                A[0][1] <= yp <= A[1][1] or A[0][1] >= yp >= A[1][1])) and (
                ((B[0][0] <= xp <= B[1][0] or B[0][0] >= xp >= B[1][0]) and (
                        B[0][1] <= yp <= B[1][1] or B[0][1] >= yp >= B[1][1]))):
            return True, xp, yp
        else:
            return False, 0

def CrossAll(ListLines, Obj):
    # находит ближайшую точку пересечения среди всех прямых, кроме ExeptLine
    # если пересечение найдено, то возращает TRUE, координаты точки пересечения и прямую
    # если пересечение не найдено, то возращает FALSE

    bRes = False
    Per = []
    min = 1e9
    mx, my = 0, 0
    lineRes = []

    # Определяем координаты завершения отрезка
    EndPos = Obj.EndPoint()

    for line in ListLines:
        if line != Obj.ExeptLine:
            Per = list(Cross(line, [[Obj.Pos[0], Obj.Pos[1]], [EndPos[0], EndPos[1]]]))
            if Per[0]:
                tmp1 = ((Obj.Pos[0] - Per[1]) ** 2 + (Obj.Pos[1] - Per[2]) ** 2) ** 0.5
                if tmp1 < min:
                    min = tmp1
                    bRes = True
                    mx, my = Per[1], Per[2]
                    lineRes = line
    return bRes, mx, my, lineRes

def Reflex(B, Line):
    # Возвращает координаты точки отражения точки В относительно прямой Line
    m = Line[1][0] - Line[0][0]
    p = Line[1][1] - Line[0][1]
    t = (m * B[0] + p * B[1] - m * Line[0][0] - p * Line[0][1]) / (m ** 2 + p ** 2)
    xm = m * t + Line[0][0]
    ym = p * t + Line[0][1]
    return 2 * xm - B[0], 2 * ym - B[1]

class Ball():
    def __init__(self, Pos, Vec, Length):
        self.Pos = Pos  # Координаты точки
        self.Vec = Vec  # Вектор движения длиной DirectionVecLength
        self.Length = Length  # Длина перемещения в такте

        k = DirectionVecLength / (self.Vec[0] ** 2 + self.Vec[1] ** 2) ** 0.5
        self.Vec[0] *= k
        self.Vec[1] *= k

        self.move = turtle.Turtle()
        self.move.speed(0)
        # self.move.up()
        self.move.shape("circle")
        self.move.color(uniform(0.2, 1), uniform(0.2, 1), uniform(0.2, 1))

    ExeptLine = [[0, 0], [0, 0]]  # Последня прямая пересечения

    def EndPoint(self):
        # Возвращает координату последней точки отрезка перемещения
        k = self.Length / DirectionVecLength
        return [self.Pos[0] + self.Vec[0] * k, self.Pos[1] + self.Vec[1] * k]

def RefEnd(Obj, ListLines):
    global DirectionVecLength, TeakLength

    # Ищем ближйшую точку пересечения объекта и прямых из ListLines
    Confluence = list(CrossAll(ListLines, Obj))  # Определяем отрезок точку пересечения

    if Confluence[0]:  # Если пересечение есть:
        # Устанавливаем последнюю линию пересечени в объект
        Obj.ExeptLine = Confluence[3]

        # Рассчитываем расстояние от точки объекта до точки перечечения
        Distance = ((Obj.Pos[0] - Confluence[1]) ** 2 + (Obj.Pos[1] - Confluence[2]) ** 2) ** 0.5

        # Строим отражение вектора направления
        RefPos = Reflex([Obj.Pos[0] + Obj.Vec[0], Obj.Pos[1] + Obj.Vec[1]], Obj.ExeptLine)

        # Формируем новый вектор направления
        Obj.Vec[0] = RefPos[0] - Confluence[1]
        Obj.Vec[1] = RefPos[1] - Confluence[2]

        # Масштабируем вектор направлени до длины DirectionVecLength
        k = DirectionVecLength / (Obj.Vec[0] ** 2 + Obj.Vec[1] ** 2) ** 0.5
        Obj.Vec[0] *= k
        Obj.Vec[1] *= k

        # Устанавливаем новую координату объекта
        Obj.Pos[0] = Confluence[1]
        Obj.Pos[1] = Confluence[2]

        # Рисуем объект
        Obj.move.goto(Obj.Pos[0], Obj.Pos[1])

        # Проверяем, находится ли конечная точка на пересекаемой прямой
        if Obj.Length == Distance:
            # Конечная точка лежит на прямой
            # Устанавливаем в объекте полную длину перемещения за такт
            Obj.Length = TeakLength

        else:
            # Конечная точка лежит за прямой
            # Уменьшаем оставшуюся длину до конца тика
            Obj.Length -= Distance

            # Рекурсивно вызываем функцию для посторения следующего отрезка
            Obj = RefEnd(Obj, ListLines)
    else:
        # Пересечения не было
        # Обнуляем последнюю линию пересечения
        Obj.ExeptLine = [[0, 0], [0, 0]]

        # Вектор движения не изменяется
        # Определяем координаты завершения отрезка
        EndPos = Obj.EndPoint()

        # Устанавливаем новую координату объекта
        Obj.Pos[0] = EndPos[0]
        Obj.Pos[1] = EndPos[1]

        # Устанавливаем в объекте полную длину перемещения за такт
        Obj.Length = TeakLength

        # Рисуем объект
        Obj.move.goto(Obj.Pos[0], Obj.Pos[1])

    return Obj

def Printer(n):
    # Создаем массив линий
    xRect, yRect = 600, 300  # Координаты вершины прямоуголбника

    ListLines = [[[randint(-xRect, xRect), randint(-yRect, yRect)] for i in range(2)] for i in range(n)]
    ListLines.append([[xRect, yRect], [xRect, -yRect]])
    ListLines.append([[xRect, -yRect], [-xRect, -yRect]])
    ListLines.append([[-xRect, -yRect], [-xRect, yRect]])
    ListLines.append([[-xRect, yRect], [xRect, yRect]])

    # Избражаем все линии
    Paint(ListLines)
    return ListLines

def Fly(ObjNum):
    global LisLines
    Object = [Ball([0, 0], [randint(-100, 100), randint(-100, 100)], 1) for i in range(ObjNum)]

    while True:
        for i in range(ObjNum):
            Object[i] = RefEnd(Object[i], ListLines)

ThreadNum = 1  # Количество потоков
ObjNum = 20  # Количество обьектов в одном потоке
LineNum = 10  # Количество отрезков

ListLines = Printer(LineNum)
ListThreads = []
for i in range(ThreadNum):
    ListThreads.append(threading.Thread(target=Fly, args=(ObjNum,), daemon=True))
    ListThreads[i].start()

turtle.done()


class Lagrange:
    def __init__(self, pointlist):
        self.arPoints = pointlist

    def polinom(self):
        result = ''

        for i in range(len(self.arPoints)):
            p = str(self.arPoints[i][1]) + ' * '

            for j in range(i):
                p += '(x-' + str(self.arPoints[j][0]) + ')'
            for j in range(i+1, len(self.arPoints)):
                p += '(x-' + str(self.arPoints[j][0]) + ')'

            p += ' / '

            for j in range(i):
                p += '(' + str(self.arPoints[i][0]) + '-' + str(self.arPoints[j][0]) + ')'
            for j in range(i+1, len(self.arPoints)):
                p += '(' + str(self.arPoints[i][0]) + '-' + str(self.arPoints[j][0]) + ')'

            result += p + ' + '

        return result

    def getValue(self, x):
        result = 0
        for i in range(len(self.arPoints)):
            p = 1
            for j in range(i):
                p *= (x - self.arPoints[j][0]) / (self.arPoints[i][0] - self.arPoints[j][0])
            for j in range(i+1, len(self.arPoints)):
                p *= (x - self.arPoints[j][0]) / (self.arPoints[i][0] - self.arPoints[j][0])
            result += p * self.arPoints[i][1]

        return result
class Chebyshev:
    def __init__(self, rank):
        self.rank = rank + 1
        self.koefs = self.__findkoefs()

    def koeficients(self):
        return self.koefs

    def roots(self):
        return np.roots(self.koefs)

    def Value(self, x):
        result = 0
        for i in len(self.koefs):
            result += x**(self.rank-i) * self.koefs[i]
        return result

    def __findkoefs(self):
        Tprev = [0] * self.rank
        Tprev[-1] = 1
        Tcurr = [0] * self.rank
        Tcurr[-2]  = 1
        for _ in range(2, self.rank):
            Ti = self.__Tnext(Tcurr, Tprev)
            Tprev = Tcurr
            Tcurr = Ti
        return Tcurr

    def __Tnext(self, Tcurr, Tprev):
        result = []
        buff = self.__slide(Tcurr)
        for i in range(self.rank):
            result.append(2 * buff[i] - Tprev[i])
        return result

    def __slide(self, array):
        result = []
        for i in range(len(array) - 1):
            result.append(array[i + 1])
        result.append(0)
        return result
import numpy as np
import math
import matplotlib.pyplot as plt
import random

def randNums(Xarray, lowerlim, upperlim):
    result = []
    for _ in Xarray:
        result.append(random.uniform(lowerlim, upperlim))
    return result

def optValuesX(start, end, count):
    polinom = Chebyshev(count)
    result = polinom.roots()
    for i in range(len(result)):
        result[i] = result[i] * (end-start)/2 + (start+end)/2
    return result

def equidistantValuesX(start, end, count):
    result = []
    step = (float)(end - start) / count
    for i in np.arange(start, end, step):
        result.append(i)
    return result

start = -1
end = 2
count = 8

X = optValuesX(start, end, count)
Y = randNums(X, -2, 4)

points = []
for i in range(count):
    points.append([X[i], Y[i]])

print(points)

polinom = Lagrange(points)

Xgraph = []
Ygraph = []
for i in np.arange(start, end, 0.005):
    Xgraph.append(i)
for x in Xgraph:
    Ygraph.append(polinom.getValue(x))

plt.plot(Xgraph, Ygraph)
plt.grid(True)
plt.show()


import base64
import requests
import saml2

from saml2 import saml, BINDING_HTTP_POST

from django.test.client import RequestFactory
from djangosaml2.conf import get_config
from djangosaml2.overrides import Saml2Client
from djangosaml2.utils import available_idps

# SP init
#########
conf = get_config(None)
client = Saml2Client(conf)
# just needed to initialize the MetadataStore - it automatically fetches remote idp's metadata
configured_idps = available_idps(conf)

# Arguments needed to create an Attribute query
###############################################
message_id = 'MSG_ID1'
entityid = "http://idp1.testunical.it:9000/idp/aa/metadata"
destination = "http://idp1.testunical.it:9000/aap"
subject_id = "E8042FB4-4D5B-48C3-8E14-8EDD852790DD"
attributes = {
    ('urn:oasis:names:tc:SAML:attribute:pairwise-id',
     "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"): "spidCode-3242342342@idp.spid.it",
    ("fiscalCode",
     "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"): "TIN-SDF7SD89F7SD98F",
    ("email",
     "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
     "email"): None,
}

# Create an Authoritative, signed, Attribute Query -> xml
req_id, saml_req = client.create_attribute_query(
            destination,
            subject_id,

            # if I use attribute as argument using the official pysaml2 release
            # a saml2.response.IncorrectlySigned Exception will raise
            # use pplnx's pysaml2-aa fork instead, it will correctly validate signature idp-aa-side
            attribute=attributes,

            consent=True,
            format=saml.NAMEID_FORMAT_TRANSIENT,
            message_id=message_id,
            # sign=True,
            # sign_alg=saml2.xmldsig.SIG_RSA_SHA256,
            # digest_alg=saml2.xmldsig.DIGEST_SHA256
)

data = {'SAMLRequest' : base64.b64encode(saml_req.encode())}
headers = {'User-Agent': 'Mozilla/5.0'}
req = requests.post('http://idp1.testunical.it:9000/aap/', data=data, headers=headers)

# create request with html form in HTTP-POST
request = client.do_attribute_query(
        entityid,
        subject_id,
        attribute=attributes,
        # sp_name_qualifier=None,
        # name_qualifier=None,
        nameid_format=saml.NAMEID_FORMAT_TRANSIENT,
        # real_id=None,
        # consent=None,
        # extensions=None,
        sign=True,
        binding=BINDING_HTTP_POST,
        # nsprefix=None,
        # sign_alg=None,
        # digest_alg=None,
)


import os

def pickingNumbers(a):
    # Write your code here
    buckets = []
    for i in range(100):
        buckets.append(0)
    for num in a:
        buckets[num] += 1
    answer = -1
    for i in range(99):
        answer = max(answer, buckets[i]+buckets[i+1])
    return answer

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input().strip())

    a = list(map(int, input().rstrip().split()))

    result = pickingNumbers(a)

    fptr.write(str(result) + '\n')

    fptr.close()


import models.basicblock as B
import numpy as np
import torch.nn.functional as F
from .layers import *
from models import utv_model

"""
# --------------------------------------------
# basic functions
# --------------------------------------------
"""
def splits(a, sf):
    '''split a into sfxsf distinct blocks

    Args:
        a: NxCxWxHx2
        sf: split factor

    Returns:
        b: NxCx(W/sf)x(H/sf)x2x(sf^2)
    '''
    b = torch.stack(torch.chunk(a, sf, dim=2), dim=5)
    b = torch.cat(torch.chunk(b, sf, dim=3), dim=5)
    return b

def c2c(x):
    return torch.from_numpy(np.stack([np.float32(x.real), np.float32(x.imag)], axis=-1))

def r2c(x):
    # convert real to complex
    return torch.stack([x, torch.zeros_like(x)], -1)

def cdiv(x, y):
    # complex division
    a, b = x[..., 0], x[..., 1]
    c, d = y[..., 0], y[..., 1]
    cd2 = c**2 + d**2
    return torch.stack([(a*c+b*d)/cd2, (b*c-a*d)/cd2], -1)

def crdiv(x, y):
    # complex/real division
    a, b = x[..., 0], x[..., 1]
    return torch.stack([a/y, b/y], -1)

def csum(x, y):
    # complex + real
    return torch.stack([x[..., 0] + y, x[..., 1]], -1)

def cabs(x):
    # modulus of a complex number
    return torch.pow(x[..., 0]**2+x[..., 1]**2, 0.5)

def cabs2(x):
    return x[..., 0]**2+x[..., 1]**2

def cmul(t1, t2):
    '''complex multiplication

    Args:
        t1: NxCxHxWx2, complex tensor
        t2: NxCxHxWx2

    Returns:
        output: NxCxHxWx2
    '''
    real1, imag1 = t1[..., 0], t1[..., 1]
    real2, imag2 = t2[..., 0], t2[..., 1]
    return torch.stack([real1 * real2 - imag1 * imag2, real1 * imag2 + imag1 * real2], dim=-1)

def cconj(t, inplace=False):
    '''complex's conjugation

    Args:
        t: NxCxHxWx2

    Returns:
        output: NxCxHxWx2
    '''
    c = t.clone() if not inplace else t
    c[..., 1] *= -1
    return c

def rfft(t):
    # Real-to-complex Discrete Fourier Transform
    return torch.rfft(t, 2, onesided=False)

def irfft(t):
    # Complex-to-real Inverse Discrete Fourier Transform
    return torch.irfft(t, 2, onesided=False)

def fft(t):
    # Complex-to-complex Discrete Fourier Transform
    return torch.fft(t, 2)

def ifft(t):
    # Complex-to-complex Inverse Discrete Fourier Transform
    return torch.ifft(t, 2)

def p2o(psf, shape):
    '''
    Convert point-spread function to optical transfer function.
    otf = p2o(psf) computes the Fast Fourier Transform (FFT) of the
    point-spread function (PSF) array and creates the optical transfer
    function (OTF) array that is not influenced by the PSF off-centering.

    Args:
        psf: NxCxhxw
        shape: [H, W]

    Returns:
        otf: NxCxHxWx2
    '''
    otf = torch.zeros(psf.shape[:-2] + shape).type_as(psf)
    otf[...,:psf.shape[2],:psf.shape[3]].copy_(psf)
    for axis, axis_size in enumerate(psf.shape[2:]):
        otf = torch.roll(otf, -int(axis_size / 2), dims=axis+2)
    otf = torch.rfft(otf, 2, onesided=False)
    n_ops = torch.sum(torch.tensor(psf.shape).type_as(psf) * torch.log2(torch.tensor(psf.shape).type_as(psf)))
    otf[..., 1][torch.abs(otf[..., 1]) < n_ops*2.22e-16] = torch.tensor(0).type_as(psf)
    return otf

def upsample(x, sf=3):
    '''s-fold upsampler

    Upsampling the spatial size by filling the new entries with zeros

    x: tensor image, NxCxWxH
    '''
    st = 0
    z = torch.zeros((x.shape[0], x.shape[1], x.shape[2]*sf, x.shape[3]*sf)).type_as(x)
    z[..., st::sf, st::sf].copy_(x)
    return z

def downsample(x, sf=3):
    '''s-fold downsampler

    Keeping the upper-left pixel for each distinct sfxsf patch and discarding the others

    x: tensor image, NxCxWxH
    '''
    st = 0
    return x[..., st::sf, st::sf]

def downsample_np(x, sf=3):
    st = 0
    return x[st::sf, st::sf, ...]

"""
# --------------------------------------------
# (1) Prior module: CTD Module
# --------------------------------------------
"""
class EBlock(nn.Module):
    def __init__(self, in_channel, out_channel, num_res=8, norm=False, first=False):
        super(EBlock, self).__init__()
        if first:
            layers = [Basic(in_channel, out_channel, kernel_size=3, norm=norm, relu=True, stride=1)]  # 步幅1卷积
        else:
            layers = [Basic(in_channel, out_channel, kernel_size=3, norm=norm, relu=True, stride=2)]  # 步幅2卷积

        layers += [ResBlock(out_channel, out_channel, norm) for _ in range(num_res)]
        self.layers = nn.Sequential(*layers)

    def forward(self, x):
        return self.layers(x)

class DBlock(nn.Module):
    def __init__(self, channel, num_res=8, norm=False, last=False, feature_ensemble=False):
        super(DBlock, self).__init__()

        layers = [ResBlock(channel, channel, norm) for _ in range(num_res)]

        if last:
            if feature_ensemble == False:
                layers.append(Basic(channel, 1, kernel_size=3, norm=norm, relu=False, stride=1))
        else:
            layers.append(
                Basic(channel, channel // 2, kernel_size=4, norm=norm, relu=True, stride=2, transpose=True))

        self.layers = nn.Sequential(*layers)

    def forward(self, x):
        return self.layers(x)

class FOrD_v1(nn.Module):
    def __init__(self, channel, rot_opt=False):
        super(FOrD_v1, self).__init__()

        self.decomp = Basic(channel, channel, kernel_size=1, relu=False, stride=1)

    def forward(self, x):
        x_decomp1 = self.decomp(x)
        x_decomp1_norm = F.normalize(x_decomp1, p=2, dim=1)
        x_decomp2 = x - torch.unsqueeze(torch.sum(x * x_decomp1_norm, dim=1), 1) * x_decomp1_norm
        return x_decomp1, x_decomp2

class TexNet(nn.Module):
    def __init__(self):
        super(TexNet, self).__init__()

        in_channel = 1
        base_channel = 32

        num_res_ENC = 4

        self.Encoder1 = EBlock(in_channel, base_channel, num_res_ENC, first=True)
        self.Encoder2 = EBlock(base_channel, base_channel * 2, num_res_ENC, norm=False)
        self.Encoder3 = EBlock(base_channel * 2, base_channel * 4, num_res_ENC, norm=False)

        self.Convs1_1 = Basic(base_channel * 4, base_channel * 2, kernel_size=1, relu=True, stride=1)
        self.Convs1_2 = Basic(base_channel * 2, base_channel, kernel_size=1, relu=True, stride=1)

        num_res_DEC = 4

        self.Decoder1_1 = DBlock(base_channel * 4, num_res_DEC, norm=False)
        self.Decoder1_2 = DBlock(base_channel * 2, num_res_DEC, norm=False)
        self.Decoder1_3 = DBlock(base_channel, num_res_DEC, last=True, feature_ensemble=True)
        self.Decoder1_4 = Basic(base_channel, 1, kernel_size=3, relu=False, stride=1)

    def forward(self, x):
        output = list()

        # Common encoder
        x_e1 = self.Encoder1(x)
        x_e2 = self.Encoder2(x_e1)
        x_decomp = self.Encoder3(x_e2)

        # Resultant image reconstruction
        x_decomp1 = self.Decoder1_1(x_decomp)
        x_decomp1 = self.Convs1_1(torch.cat([x_decomp1, x_e2], dim=1))
        x_decomp1 = self.Decoder1_2(x_decomp1)
        x_decomp1 = self.Convs1_2(torch.cat([x_decomp1, x_e1], dim=1))
        x_decomp1 = self.Decoder1_3(x_decomp1)
        x_decomp1 = self.Decoder1_4(x_decomp1)
        return x_decomp1

class CarNet(nn.Module):
    def __init__(self):
        super(CarNet, self).__init__()
        self.TV = utv_model.ADMM(1, 6, 1)
        self.device = torch.device('cuda')
        self.hyp = B.HyPaNet()
    def forward(self, x):
        r = x[:, 0, :, :]
        smoothr = self.TV(r).unsqueeze(1)
        return smoothr

"""
# --------------------------------------------
# (2) Data module, closed-form solution
# It is a trainable-parameter-free module  ^_^
# z_k = D(x_{k-1}, s, k, y, alpha_k)
# some can be pre-calculated
# --------------------------------------------
"""
class DataNet(nn.Module):
    def __init__(self):
        super(DataNet, self).__init__()

    def forward(self, x, FB, FBC, F2B, FBFy, alpha, sf):
        FR = FBFy + torch.rfft(alpha*x, 2, onesided=False)
        x1 = cmul(FB, FR)
        FBR = torch.mean(splits(x1, sf), dim=-1, keepdim=False)
        invW = torch.mean(splits(F2B, sf), dim=-1, keepdim=False)
        invWBR = cdiv(FBR, csum(invW, alpha))
        FCBinvWBR = cmul(FBC, invWBR.repeat(1, 1, sf, sf, 1))
        FX = (FR-FCBinvWBR)/alpha.unsqueeze(-1)
        Xest = torch.irfft(FX, 2, onesided=False)
        return Xest

"""
# --------------------------------------------
# (3) Hyper-parameter module
# --------------------------------------------
"""
class HyPaNet(nn.Module):
    def __init__(self, in_nc=2, out_nc=8, channel=64):
        super(HyPaNet, self).__init__()
        self.mlp = nn.Sequential(
                nn.Conv2d(in_nc, channel, 1, padding=0, bias=True),
                nn.ReLU(inplace=True),
                nn.Conv2d(channel, channel, 1, padding=0, bias=True),
                nn.ReLU(inplace=True),
                nn.Conv2d(channel, out_nc, 1, padding=0, bias=True),
                nn.Softplus())
    def forward(self, x):
        x = self.mlp(x) + 1e-6
        return x

"""
# --------------------------------------------
# main CTDNet
# deep unfolding super-resolution network
# --------------------------------------------
"""
class CTDNet(nn.Module):
    def __init__(self, n_iter=8, h_nc=64, in_nc=4, out_nc=3, nc=[64, 128, 256, 512], nb=2, act_mode='R', downsample_mode='strideconv', upsample_mode='convtranspose'):
        super(CTDNet, self).__init__()
        self.d = DataNet()
        self.h = HyPaNet(in_nc=2, out_nc=n_iter*2, channel=h_nc)
        self.n = n_iter
        self.xy = TexNet()
        self.u = CarNet()

    def forward(self, x, k, sf, sigma):
        '''
        x: tensor, NxCxWxH
        k: tensor, Nx(1,3)xwxh
        sf: integer, 1
        sigma: tensor, Nx1x1x1
        '''

        # initialization & pre-calculation
        w, h = x.shape[-2:]
        FB = p2o(k, (w*sf, h*sf))
        FBC = cconj(FB, inplace=False)
        F2B = r2c(cabs2(FB))
        STy = upsample(x, sf=sf)
        FBFy = cmul(FBC, torch.rfft(STy, 2, onesided=False))
        x = nn.functional.interpolate(x, scale_factor=sf, mode='nearest')

        # hyper-parameter
        ab = self.h(torch.cat((sigma, torch.tensor(sf).type_as(sigma).expand_as(sigma)), dim=1))

        # unfolding
        for i in range(self.n):
            x = self.d(x, FB, FBC, F2B, FBFy, ab[:, i:i+1, ...], sf)
            cartoon = self.u(x)
            texture = self.xy(x)
            x = cartoon + texture
        return cartoon, texture, x


for test_case in range(1, 11):
    n = int(input())
    stack = []

    flag = False
    for word in list(map(str, input())):
        idx = '([{<)]}>'.index(word)

        # 열린 괄호
        if idx < 4:
            stack.append(idx)

        # 닫힌 괄호
        elif 4 <= idx < 8:
            # 열린 괄호가 없거나 짝이 안 맞는 경우
            if len(stack) == 0 or idx - stack.pop() != 4:
                flag = True
                break

    result = 1
    # 열린 괄호가 남아있는 경우
    if flag or len(stack) > 0:
        result = 0

    print('#{} {}'.format(test_case, result))


from collections import defaultdict
class Graph:
    def __init__(self,vertics):
        self.V = vertics
        self.graph = defaultdict(list)

    def addEdge(self,src,dest):
        self.graph[src].append(dest)
        self.graph[dest].append(src)

    def addEdgeOD(self,src,dest):
        self.graph[src].append(dest)

    #bfs edited
    def BFS (self,start, end ):
        visited = [False] * self.V
        dist = [None]*self.V

        counter = 0

        queue = []

        queue.append(start)
        visited[start] = True
        dist[start] = 0

        while queue :
            start = queue.pop(0)
            # From queue we alwast dequeue the first
            print(start,end="->")
            child_counter = 0

            for i in self.graph[start] :
                if not visited[i]:
                    queue.append(i)
                    visited[i] = True
                    dist[i]=dist[start]+1

        print()
        return dist[end]

    def DFSUtil(self,ver,end, explored,counter):
        explored.add(ver)
        counter = counter+1
        print(ver,end='->')

        for nb in self.graph[ver]:
            if nb not in explored:
                self.DFSUtil(nb, end, explored, counter)
            if end in explored:
                break

    def DFS(self,start,end):
        counter = 0
        explored = set()
        self.DFSUtil(start,end,explored,counter)

    def printGraph(self):
        for i in range(self.V):
            print("[",i,"]",end='=>')
            for j in self.graph[i]:
                print('{',j,'}', end="->")
            print()

    def BFSLevelThree(self,start,end):
        visited = [False] * self.V
        dist = [None] * self.V

        counter = 0

        queue = []

        queue.append(start)
        visited[start] = True
        dist[start] = 0

        while queue:
            start = queue.pop(0)
            # From queue we alwast dequeue the first
            print(start, end="->")
            child_counter = 0

            for i in self.graph[start]:
                if not visited[i]:
                    queue.append(i)
                    visited[i] = True
                    dist[i] = dist[start] + 1

        print()
        return dist[end]


import cv2
import matplotlib.pyplot as plt
# %matplotlib inline

# read images
# img1 = cv2.imread('eye_2.jpg')
# img2 = cv2.imread('eye_1.jpg')

img1 = cv2.imread('odcisk2.jpg')
img2 = cv2.imread('odcisk2.jpg')

img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

figure, ax = plt.subplots(1, 2, figsize=(16, 8))

ax[0].imshow(img1, cmap='gray')
ax[1].imshow(img2, cmap='gray')