#!/usr/bin/python

# Ensure that your YAML file use 2 white spaces for each indent. Do not mix tab and white space
# Developped by JSFonta (https://github.com/JSFonta), 2019
# This tool is designed for RCMan (https://github.com/nikolayarhangelov/rcman)
# The aim is to convert a simple and easy readable YAML file to a json which works into RCMan as configuration

import sys, re

# Define classes

# All items created by this script is based on the Entity class
# Each entity has its own and unique id, whatever the final type
class Entity:
	id = 1
	def __init__(self, name, parent):
		self.id 		= Entity.id
		self.name 		= name
		self.parent		= parent
		self.children 	= []
		Entity.id 	   += 1

# Leaves of the tree, inheritance of Entity
class Server(Entity):
	def __init__(self, name, parent, conn, protocol):
		Entity.__init__(self, name, parent)
		self.conn 		= conn
		self.protocol	= protocol
		# Keep 2 ID for each server
		Entity.id 	   += 1

# This method determine the depth of an YAML object : 2 white spaces = 1 depth
def depthOf(expression):
	return(int(len(expression)/2))

# Hydrate all items with children
def hydrateAllChildren(items):

	for item in items:
		for ite in items:

			if ite.parent == item:

				item.children.append(ite)

# Convert recursively the whole objects tree to a json file
# Must start with the tree's root
def jsonify(item):

	# Display all the JSON, with right parameters
	returnValue 	= "{\n"
	if len(item.children) == 0 :
		returnValue    += "\"$id\": \""+str(item.id)+"\",\n"
		returnValue    += "\"DisplayName\": \""+item.name+"\",\n"
		returnValue    += "\"IsExpanded\": false,\n"
		if isinstance(item, Server) :
			returnValue+= "\"ConnectionSettings\": {\n"
			returnValue+= "\"$id\": \""+str(item.id+1)+"\",\n"
			returnValue+= "\"Protocol\": \""+item.protocol+"\",\n"
			returnValue+= "\"Server\": \""+item.conn+"\"\n"
			returnValue+= "},\n"
			returnValue+= "\"Items\": []\n"
		returnValue    += "}"

		return returnValue

	returnValue    += "\"$id\": \""+str(item.id)+"\",\n"
	returnValue    += "\"DisplayName\": \""+item.name+"\",\n"
	returnValue    += "\"IsExpanded\": false,\n"
	returnValue    += "\"Items\": [\n"

	# Avoid coma after the last children
	count = 0
	for child in item.children:

		# Call the same function for every children
		returnValue += jsonify(child)
		count += 1
		if count < len(item.children):
			returnValue += ","

	returnValue    += "]\n}\n"

	return returnValue

####################################
# Welcome into the main program :) #
####################################

# Verify that basics looks okay
if len(sys.argv) != 3:
	print("Need path to the YAML file to parse.")
	print("python convert.py --path PATH/TO/THE/YAML/FILE.yaml")
	sys.exit(-1)

# Regular expression used after to define if it is category or server
regexCategory = re.compile(r"^[\s\t]*([\w\d\-]{1,}):$")
regexServer = re.compile(r"^[\t\s]*-[\s\t]*([\w\-+_\.\d]{1,})[\s\t](.+)[\s\t]([sS][sS][hH]|[rR][dD][pP])$")
regexDepth = re.compile(r"^(\s{0,}).*$")

# Read only the file in text based mode
# Aim is to create linked and defined objects
try:
	file = open(sys.argv[2], "rt")
except Exception as e:
	print(e)
	sys.exit(-1)

# Init the tree
root 			= Entity("root", "no")
previousElem 	= root
previousDepth 	= -1

allItems = []

# Read line by line until the EOF
for line in file:

	# Category case
	if regexCategory.match(line):
		# Catch category information
		rawCategory = regexCategory.search(line).groups()
		e = Entity(rawCategory[0], root)

	# Server case
	if regexServer.match(line):
		rawServer = regexServer.search(line).groups()
		e = Server(rawServer[0], root, rawServer[1], rawServer[2])

	# Keep in memory the whole list
	allItems.append(e)

	# Compute the depth
	depth = depthOf(regexDepth.search(line).groups()[0])

	if depth == previousDepth:
		# Same parent
		e.parent = previousElem.parent

	elif depth < previousDepth:
		# Shallower
		# Find the right parent
		i = previousDepth - depth + 1
		lastParent = previousElem
		while i != 0 and lastParent != root:
			lastParent = lastParent.parent
			i -= 1
		e.parent = lastParent

	else:
		# Deeper
		e.parent = previousElem

	# Update for next line
	previousElem = e
	previousDepth = depth

file.close()

allItems.insert(0, root)

# Now, construct the output, JSON file
hydrateAllChildren(allItems)

output = jsonify(root)

# Create or just write into the file if it already exists
try:
	file = open("connections.json", "w")
	file.write(output)
	file.close()
except Exception as e:
	print("Cant write the output file, let's print it !")
	print(e)
	print("--------------")
	print(output)


import asyncio
from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
from pathlib import Path
import time
from typing import Dict, Optional, Set

from cylc.flow.exceptions import WorkflowStopped
from cylc.flow.id import Tokens
from cylc.flow.network.server import PB_METHOD_MAP
from cylc.flow.network.subscriber import WorkflowSubscriber, process_delta_msg
from cylc.flow.data_store_mgr import (
    EDGES, DATA_TEMPLATE, ALL_DELTAS, DELTAS_MAP, WORKFLOW,
    apply_delta, generate_checksum, create_delta_store
)
from cylc.flow.workflow_files import (
    ContactFileFields as CFF,
    WorkflowFiles,
    get_workflow_srv_dir,
)
from cylc.flow.workflow_status import WorkflowStatus

from .utils import fmt_call
from .workflows_mgr import workflow_request

def log_call(fcn):
    """Decorator for data store methods we want to log."""
    fcn_name = f'[data-store] {fcn.__name__}'

    def _inner(*args, **kwargs):  # works for serial & async calls
        nonlocal fcn
        self = args[0]
        # log this method call
        self.log.info(fmt_call(fcn_name, args[1:], kwargs))
        # then do it
        return fcn(*args, **kwargs)

    return _inner

class DataStoreMgr:
    """Manage the local data-store acquisition/updates for all workflows."""

    INIT_DATA_WAIT_TIME = 5.  # seconds
    INIT_DATA_RETRY_DELAY = 0.5  # seconds
    RECONCILE_TIMEOUT = 5.  # seconds
    PENDING_DELTA_CHECK_INTERVAL = 0.5

    def __init__(self, workflows_mgr, log):
        self.workflows_mgr = workflows_mgr
        self.log = log
        self.data = {}
        self.w_subs: Dict[str, WorkflowSubscriber] = {}
        self.topics = {ALL_DELTAS.encode('utf-8'), b'shutdown'}
        self.loop = None
        self.executor = ThreadPoolExecutor()
        self.delta_queues = {}

    @log_call
    async def register_workflow(self, w_id: str, is_active: bool) -> None:
        """Register a new workflow with the data store.

        Call this when a new workflow is discovered on the file system
        (e.g. installed).
        """
        self.delta_queues[w_id] = {}

        # create new entry in the data store
        data = deepcopy(DATA_TEMPLATE)
        self.data[w_id] = data

        # create new entry in the delta store
        self._update_contact(
            w_id,
            status=WorkflowStatus.STOPPED.value,
            status_msg=self._get_status_msg(w_id, is_active),
        )

    @log_call
    async def unregister_workflow(self, w_id):
        """Remove a workflow from the data store entirely.

        Call this when a workflow is deleted.
        """
        if w_id in self.data:
            self._update_contact(w_id, pruned=True)
        while any(
            not delta_queue.empty()
            for delta_queue in self.delta_queues.get(w_id, {}).values()
        ):
            await asyncio.sleep(self.PENDING_DELTA_CHECK_INTERVAL)
        self._purge_workflow(w_id)

    @log_call
    async def connect_workflow(self, w_id, contact_data):
        """Initiate workflow subscriptions.

        Call this when a workflow has started.

        Subscriptions and sync management is instantiated and run in
        a separate thread for each workflow. This is to avoid the sync loop
        blocking the main loop.

        """
        if self.loop is None:
            self.loop = asyncio.get_running_loop()

        # don't sync if subscription exists
        if w_id in self.w_subs:
            return

        self.delta_queues[w_id] = {}

        # Might be options other than threads to achieve
        # non-blocking subscriptions, but this works.
        self.executor.submit(
            self._start_subscription,
            w_id,
            contact_data['name'],
            contact_data[CFF.HOST],
            contact_data[CFF.PUBLISH_PORT]
        )
        successful_updates = await self._entire_workflow_update(ids=[w_id])

        if w_id not in successful_updates:
            # something went wrong, undo any changes to allow for subsequent
            # connection attempts
            self.log.info(f'failed to connect to {w_id}')
            self.disconnect_workflow(w_id)
            return False
        else:
            # don't update the contact data until we have successfully updated
            self._update_contact(w_id, contact_data)

    @log_call
    def disconnect_workflow(self, w_id, update_contact=True):
        """Terminate workflow subscriptions.

        Call this when a workflow has stopped.
        """
        disconnect_msg = self._get_status_msg(w_id, False)
        if (
            update_contact
            and w_id in self.data
            and (
                self.data[w_id][WORKFLOW].status != (
                    WorkflowStatus.STOPPED.value
                )
                or self.data[w_id][WORKFLOW].status_msg != disconnect_msg
            )
        ):
            self._update_contact(
                w_id,
                status=WorkflowStatus.STOPPED.value,
                status_msg=disconnect_msg,
            )
        if w_id in self.w_subs:
            self.w_subs[w_id].stop()
            del self.w_subs[w_id]

    def get_workflows(self):
        """Return all workflows the data store is currently tracking.

        Returns:
            (active, inactive)
                active: Set of active (running, paused, stopping) workflows.
                inactive: Set of (stopped) workflows.
        """
        active = set()
        inactive = set()
        for w_id, workflow in self.data.items():
            status = getattr(workflow.get('workflow'), 'status', 'stopped')
            if status == 'stopped':
                inactive.add(w_id)
            else:
                active.add(w_id)
        return active, inactive

    @log_call
    def _purge_workflow(self, w_id):
        """Purge the manager of a workflow's subscription and data."""
        # Ensure no old/new subscriptions exist on purge,
        # this shouldn't happen if disconnect is run before unregister.
        self.disconnect_workflow(w_id, update_contact=False)
        if w_id in self.data:
            del self.data[w_id]
        if w_id in self.delta_queues:
            del self.delta_queues[w_id]

    def _start_subscription(self, w_id, reg, host, port):
        """Instantiate and run subscriber data-store sync.

        Args:
            w_id (str): Workflow external ID.
            reg (str): Registered workflow name.
            host (str): Hostname of target workflow.
            port (int): Port of target workflow.

        """
        self.w_subs[w_id] = WorkflowSubscriber(
            reg,
            host=host,
            port=port,
            context=self.workflows_mgr.context,
            topics=self.topics
        )
        self.w_subs[w_id].loop.run_until_complete(
            self.w_subs[w_id].subscribe(
                process_delta_msg,
                func=self._update_workflow_data,
                w_id=w_id))

    def _update_workflow_data(self, topic, delta, w_id):
        """Manage and apply incoming data-store deltas.

        Args:
            topic (str): topic of published data.
            delta (object): Published protobuf message data container.
            w_id (str): Workflow external ID.

        """
        # wait until data-store is populated for this workflow
        if w_id not in self.data:
            loop_cnt = 0
            while loop_cnt < self.INIT_DATA_WAIT_TIME:
                if w_id in self.data:
                    break
                time.sleep(self.INIT_DATA_RETRY_DELAY)
                loop_cnt += 1
                continue
        if topic == 'shutdown':
            self._delta_store_to_queues(w_id, topic, delta)
            # close connections
            self.disconnect_workflow(w_id)
            return
        self._apply_all_delta(w_id, delta)
        self._delta_store_to_queues(w_id, topic, delta)

    def _clear_data_field(self, w_id, field_name):
        if field_name == WORKFLOW:
            self.data[w_id][field_name].Clear()
        else:
            self.data[w_id][field_name].clear()

    def _apply_all_delta(self, w_id, delta):
        """Apply the AllDeltas delta."""
        for field, sub_delta in delta.ListFields():
            delta_time = getattr(sub_delta, 'time', 0.0)
            # If the workflow has reloaded clear the data before
            # delta application.
            if sub_delta.reloaded:
                self._clear_data_field(w_id, field.name)
                self.data[w_id]['delta_times'][field.name] = 0.0
            # hard to catch errors in a threaded async app, so use try-except.
            try:
                # Apply the delta if newer than the previously applied.
                if delta_time >= self.data[w_id]['delta_times'][field.name]:
                    apply_delta(field.name, sub_delta, self.data[w_id])
                    self.data[w_id]['delta_times'][field.name] = delta_time
                    if not sub_delta.reloaded:
                        self._reconcile_update(field.name, sub_delta, w_id)
            except Exception as exc:
                self.log.exception(exc)

    def _delta_store_to_queues(self, w_id, topic, delta):
        # Queue delta for graphql subscription resolving
        if self.delta_queues[w_id]:
            delta_store = create_delta_store(delta, w_id)
            for delta_queue in self.delta_queues[w_id].values():
                delta_queue.put((w_id, topic, delta_store))

    def _reconcile_update(self, topic, delta, w_id):
        """Reconcile local with workflow data-store.

        Verify data-store is in sync by topic/element-type
        and on failure request entire set of respective data elements.

        Args:
            topic (str): topic of published data.
            delta (object): Published protobuf message data container.
            w_id (str): Workflow external ID.

        """
        if topic == WORKFLOW:
            return
        if topic == EDGES:
            s_att = 'id'
        else:
            s_att = 'stamp'
        local_checksum = generate_checksum(
            [getattr(e, s_att)
             for e in self.data[w_id][topic].values()])
        if local_checksum != delta.checksum:
            self.log.debug(
                f'Out of sync with {topic} of {w_id}... Reconciling.')
            try:
                # use threadsafe as client socket is in main loop thread.
                future = asyncio.run_coroutine_threadsafe(
                    workflow_request(
                        self.workflows_mgr.workflows[w_id]['req_client'],
                        'pb_data_elements',
                        args={'element_type': topic}
                    ),
                    self.loop
                )
                new_delta_msg = future.result(self.RECONCILE_TIMEOUT)
                new_delta = DELTAS_MAP[topic]()
                new_delta.ParseFromString(new_delta_msg)
                self._clear_data_field(w_id, topic)
                apply_delta(topic, new_delta, self.data[w_id])
                self.data[w_id]['delta_times'][topic] = new_delta.time
            except asyncio.TimeoutError:
                self.log.debug(
                    f'The reconcile update coroutine {w_id} {topic}'
                    f'took too long, cancelling the subscription/sync.'
                )
                future.cancel()
            except Exception as exc:
                self.log.exception(exc)

    async def _entire_workflow_update(
        self, ids: Optional[list] = None
    ) -> Set[str]:
        """Update entire local data-store of workflow(s).

        Args:
            ids: List of workflow external IDs.

        """
        if ids is None:
            ids = []

        # Request new data
        req_method = 'pb_entire_workflow'

        requests = {
            w_id: workflow_request(
                client=info['req_client'], command=req_method, log=self.log
            )
            for w_id, info in self.workflows_mgr.workflows.items()
            if info.get('req_client')  # skip stopped workflows
            and (not ids or w_id in ids)
        }
        results = await asyncio.gather(
            *requests.values(), return_exceptions=True
        )
        successes: Set[str] = set()
        for w_id, result in zip(requests, results):
            if isinstance(result, Exception):
                if not isinstance(result, WorkflowStopped):
                    self.log.error(
                        'Failed to update entire local data-store '
                        f'of a workflow: {result}'
                    )
                continue
            pb_data = PB_METHOD_MAP[req_method]()
            pb_data.ParseFromString(result)
            new_data = deepcopy(DATA_TEMPLATE)
            for field, value in pb_data.ListFields():
                if field.name == WORKFLOW:
                    new_data[field.name].CopyFrom(value)
                    new_data['delta_times'] = {
                        key: value.last_updated
                        for key in DATA_TEMPLATE
                    }
                    continue
                new_data[field.name] = {n.id: n for n in value}
            self.data[w_id] = new_data
            successes.add(w_id)
        return successes

    def _update_contact(
        self,
        w_id,
        contact_data=None,
        status=None,
        status_msg=None,
        pruned=False,
    ):
        """Update the data store with information from the contact file.

        Args:
            w_id: Workflow ID.
            contact_data: Contact file data dictionary.
            status: Workflow status (e.g. "running").
            status_msg: Workflow status message (e.g. "will stop at 2000").
            pruned: ?

        Returns:
            True if the contact data is successfully updated or False if
            the workflow is no longer in the store (e.g. has been removed).

        """
        if w_id not in self.data:
            # workflow has been removed - do nothing
            return False

        delta = DELTAS_MAP[ALL_DELTAS]()
        delta.workflow.time = time.time()
        flow = delta.workflow.updated
        flow.id = w_id
        flow.stamp = f'{w_id}@{delta.workflow.time}'
        if contact_data:
            # update with contact file data
            flow.name = contact_data['name']
            flow.owner = contact_data['owner']
            flow.host = contact_data[CFF.HOST]
            flow.port = int(contact_data[CFF.PORT])
            flow.api_version = int(contact_data[CFF.API])
        else:
            # wipe pre-existing contact-file data
            w_tokens = Tokens(w_id)
            flow.owner = w_tokens['user']
            flow.name = w_tokens['workflow']
            flow.host = ''
            flow.port = 0
            flow.api_version = 0

        if status is not None:
            flow.status = status
        if status_msg is not None:
            flow.status_msg = status_msg
        if pruned:
            flow.pruned = True
            delta.workflow.pruned = w_id

        # Apply to existing workflow data
        if 'delta_times' not in self.data[w_id]:
            self.data[w_id]['delta_times'] = {WORKFLOW: 0.0}
        self._apply_all_delta(w_id, delta)
        # Queue delta for subscription push
        self._delta_store_to_queues(w_id, ALL_DELTAS, delta)

        return True

    def _get_status_msg(self, w_id: str, is_active: bool) -> str:
        """Derive a status message for the workflow.

        Running schedulers provide their own status messages.

        We must derive a status message for stopped workflows.
        """
        if is_active:
            # this will get overridden when we sync with the workflow
            # set a sensible default here incase the sync takes a while
            return 'running'
        w_id = Tokens(w_id)['workflow']
        db_file = Path(get_workflow_srv_dir(w_id), WorkflowFiles.Service.DB)
        if db_file.exists():
            # the workflow has previously run
            return 'stopped'
        else:
            # the workflow has not yet run
            return 'not yet run'


import csv

with open("src/assets/unb_graduacao.csv", mode="r", encoding="utf-8") as file:
    content = csv.reader(file, delimiter=",", quotechar='"')
    header, *data = content

group_by = dict()
for row in data:
    target = row[15]
    if target not in group_by:
        group_by[target] = 0
    group_by[target] += 1

with open("src/assets/unb_result.csv", mode="w", encoding="utf-8") as new_file:
    writer = csv.writer(new_file)

    headers = ["Target", "Contagem"]
    writer.writerow(headers)

    for target, count in group_by.items():
        row = [target, count]
        writer.writerow(row)

print("Operação realizada com sucesso !!!")


from aiogram import types
from aiogram.dispatcher import FSMContext

from architecture.base import State
from architecture.handlers.base import MessageHandler
from data.questions import KEYWORDS, COMPARISONS
from db.models import Student, Comparison, Keyword
from services import AnalysisManager

class StartMessageHandler(MessageHandler):
    async def handler(self, message: types.Message, state: FSMContext = None):
        """ Обработчик, который запускает бота (по команде /start) """

        await message.delete()

        Student.query_.get(chat_id=message.chat.id)
        student = Student.query_.perform_fetch()

        if not student:
            Student.query_.create(chat_id=message.chat.id)
            Student.query_.perform_update()

        state_name = await self.states_group.first()
        state: State = getattr(self.states_group, state_name.split(':')[1])
        await message.answer(text=state.get_text(), reply_markup=state.get_markup())

class InStatesMessageHandler(MessageHandler):
    """
    Обработка входящих сообщений от пользователя во время того,
    как он находится в каком то из State
    """

    async def handler(self, message: types.Message, state: FSMContext):
        await message.delete()

class UserQuestionHandler(MessageHandler):
    async def __init_questions(self):
        for index, comparison in enumerate(COMPARISONS):
            Comparison.query_.create(pk=index + 1, answer=comparison)
            Comparison.query_.perform_update()

        for index, keywords_tuple in enumerate(KEYWORDS):
            for keyword in keywords_tuple:
                Keyword.query_.create(comparison=index + 1, source=keyword)
                Keyword.query_.perform_update()

    async def handler(self, message: types.Message, state: FSMContext):
        """ Обработка вопросов пользователя после того, как он заполнил все данные о себе """

        if message.text == '/init_questions':
            await self.__init_questions()
            return await message.answer(f'<b>Все прошло успешно!</b>', parse_mode=types.ParseMode.HTML)

        manager = AnalysisManager(message.text)
        answer_list = manager.answer()
        joined_answers = "\n\n".join(answer_list)
        if len(answer_list) > 1:
            await message.answer(
                'Я не совсем точно смог распознать твой вопрос, возможно тебе подойдут эти ответы:'
                f'\n\n{joined_answers}', parse_mode=types.ParseMode.HTML)
        elif len(answer_list) == 1:
            await message.answer(answer_list[0], parse_mode=types.ParseMode.HTML)
        else:
            await message.answer('К сожалению, я не совсем понимаю, что ты имеешь ввиду')

class SubscriptionSendHandler(MessageHandler):
    async def handler(self, message: types.Message, state: FSMContext):

        await message.answer('Ты жопошник)')


import torch
import torch.nn as nn
import torch.functional as F
import numpy as np

##
# @brief calculate iou between two boxes list
def calculate_iou(bbox1, bbox2):
    """
    @param bbox1 shape(numb_of_bbox, 4), it contains x, y, w, h
    @param bbox2 shape(numb_of_bbox, 4), it contains x, y, w, h
    @return result shape(numb_of_bbox, 1)
    """
    # bbox coordinates
    b1x1, b1y1 = (bbox1[:, :2]).split(1, 1)
    b1x2, b1y2 = (bbox1[:, :2] + (bbox1[:, 2:4])).split(1, 1)
    b2x1, b2y1 = (bbox2[:, :2]).split(1, 1)
    b2x2, b2y2 = (bbox2[:, :2] + (bbox2[:, 2:4])).split(1, 1)

    # box areas
    areas1 = (b1x2 - b1x1) * (b1y2 - b1y1)
    areas2 = (b2x2 - b2x1) * (b2y2 - b2y1)

    # intersections
    min_x_of_max_x, max_x_of_min_x = torch.min(b1x2, b2x2), torch.max(b1x1, b2x1)
    min_y_of_max_y, max_y_of_min_y = torch.min(b1y2, b2y2), torch.max(b1y1, b2y1)
    intersection_width = (min_x_of_max_x - max_x_of_min_x).clamp(min=0)
    intersection_height = (min_y_of_max_y - max_y_of_min_y).clamp(min=0)
    intersections = intersection_width * intersection_height

    # unions
    unions = (areas1 + areas2) - intersections

    result = intersections / unions
    return result

##
# @brief find best iou and its index
def find_best_ratio(anchors, bbox):
    """
    @param anchors shape(numb_of_anchors, 2), it contains w, h
    @param bbox shape(numb_of_bbox, 2), it contains w, h
    @return best_match index of best match, shape(numb_of_bbox, 1)
    """
    b1 = np.divide(anchors[:, 0], anchors[:, 1])
    b2 = np.divide(bbox[:, 0], bbox[:, 1])
    similarities = np.abs(b1.reshape(-1, 1) - b2)
    best_match = np.argmin(similarities, axis=0)
    return best_match

##
# @brief loss class for yolo
class YoloV2_LOSS(nn.Module):
    """Yolo v2 loss"""
    def __init__(self, num_classes, img_shape = (416, 416), outsize = (13, 13)):
        super().__init__()
        self.num_classes = num_classes
        self.img_shape = img_shape
        self.outsize = outsize
        self.hook = dict()

        self.anchors = torch.FloatTensor(
            [(1.3221, 1.73145),
            (3.19275, 4.00944),
            (5.05587, 8.09892),
            (9.47112, 4.84053),
            (11.2364, 10.0071)]
        )

        self.mse = nn.MSELoss()
        self.bbox_loss, self.iou_loss, self.cls_loss = None, None, None

    ##
    # @brief function to track gradients of non-leaf varibles.
    def hook_variable(self, name, var):
        """ Do not use this function when training. It is for debugging. """
        self.hook[name] = var
        self.hook[name].requires_grad_().retain_grad()

    ##
    # @brief function to print gradients of non-leaf varibles.
    def print_hook_variables(self):
        """ Do not use this function when training. It is for debugging. """
        for k, var in self.hook.items():
            print("gradients of variable {}:".format(k))
            batch, channel, height, width = var.grad.shape
            for b in range(batch):
                for c in range(channel):
                    for h in range(height):
                        for w in range(width):
                            if torch.abs(var.grad[b, c, h, w]).item() >= 1e-3:
                                print("(b: {}, c: {}, h: {}, w: {}) = {}"\
                                      .format(b, c, h, w, var.grad[b, c, h, w]))
            print("=" * 20)

    def forward(self, bbox_pred, iou_pred, prob_pred, bbox_gt, cls_gt):
        """
        @param bbox_pred shape(batch_size, cell_h x cell_w, num_anchors, 4)
        @param iou_pred shape(batch_size, cell_h x cell_w, 1)
        @param prob_pred shape(batch_size, cell_h x cell_w, num_anchors, num_classes)
        @param bbox_gt shape(batch_size, num_bbox, 4), data range(0~1)
        @param cls_gt shape(batch_size, num_bbox, 1)
        @return loss shape(1,)
        """
        self.hook_variable("bbox_pred", bbox_pred)
        bbox_pred = self.apply_anchors_to_bbox(bbox_pred)

        bbox_built, iou_built, cls_built, bbox_mask, iou_mask, cls_mask =\
            self._build_target(bbox_pred, bbox_gt, cls_gt)

        self.bbox_loss = self.mse(bbox_pred * bbox_mask,
                                        bbox_built * bbox_mask)
        self.iou_loss = self.mse(iou_pred * iou_mask,
                                       iou_built * iou_mask)
        self.cls_loss = self.mse(prob_pred * cls_mask,
                                       cls_built * cls_mask)

        return self.bbox_loss * 5 + self.iou_loss + self.cls_loss

    def apply_anchors_to_bbox(self, bbox_pred):
        """
        @param bbox_pred shape(batch_size, cell_h x cell_w, num_anchors, 4)
        @return bbox_pred shape(batch_size, cell_h x cell_w, num_anchors, 4)
        """
        anchor_w = self.anchors[:, 0].contiguous().view(-1, 1)
        anchor_h = self.anchors[:, 1].contiguous().view(-1, 1)
        bbox_pred_tmp = bbox_pred.clone()
        bbox_pred_tmp[:, :, :, 2:3] = torch.sqrt(bbox_pred[:, :, :, 2:3] * anchor_w)
        bbox_pred_tmp[:, :, :, 3:4] = torch.sqrt(bbox_pred[:, :, :, 3:4] * anchor_h)
        return bbox_pred_tmp

    def _build_target(self, bbox_pred, bbox_gt, cls_gt):
        """
        @param bbox_pred shape(batch_size, cell_h x cell_w, num_anchors, 4)
        @param bbox_gt shape(batch_size, num_bbox, 4)
        @param cls_gt shape(batch_size, num_bbox, 1)
        @return tuple of (bbox_built, iou_built, cls_built, bbox_mask, iou_mask, cls_mask)
        """
        bbox_built, bbox_mask = [], []
        iou_built, iou_mask = [], []
        cls_built, cls_mask = [], []

        batch_size = bbox_pred.shape[0]

        for i in range(batch_size):
            _bbox_built, _iou_built, _cls_built,\
                _bbox_mask, _iou_mask, _cls_mask =\
                    self._make_target_per_sample(
                        torch.FloatTensor(bbox_pred[i]),
                        torch.FloatTensor(np.array(bbox_gt[i])),
                        torch.LongTensor(cls_gt[i])
                    )

            bbox_built.append(_bbox_built)
            bbox_mask.append(_bbox_mask)
            iou_built.append(_iou_built)
            iou_mask.append(_iou_mask)
            cls_built.append(_cls_built)
            cls_mask.append(_cls_mask)

        bbox_built = torch.stack(bbox_built)
        bbox_mask = torch.stack(bbox_mask)
        iou_built = torch.stack(iou_built)
        iou_mask = torch.stack(iou_mask)
        cls_built = torch.stack(cls_built)
        cls_mask = torch.stack(cls_mask)

        return bbox_built, iou_built, cls_built, bbox_mask, iou_mask, cls_mask

    def _make_target_per_sample(self, _bbox_pred, _bbox_gt, _cls_gt):
        """
        @param _bbox_pred shape(cell_h x cell_w, num_anchors, 4)
        @param _bbox_gt shape(num_bbox, 4)
        @param _cls_gt shape(num_bbox,)
        @return tuple of (_bbox_built, _iou_built, _cls_built, _bbox_mask, _iou_mask, _cls_mask)
        """
        hw, num_anchors, _  = _bbox_pred.shape

        # set result template
        _bbox_built = torch.zeros((hw, num_anchors, 4))
        _bbox_mask = torch.zeros((hw, num_anchors, 1))

        _iou_built = torch.zeros((hw, num_anchors, 1))
        _iou_mask = torch.ones((hw, num_anchors, 1)) * 0.5

        _cls_built = torch.zeros((hw, num_anchors, self.num_classes))
        _cls_mask = torch.zeros((hw, num_anchors, 1))

        # find best anchors
        _bbox_gt_wh = _bbox_gt.clone()[:, 2:]
        best_anchors = find_best_ratio(self.anchors, _bbox_gt_wh)

        # normalize x, y pos based on cell coornindates
        cx = _bbox_gt[:, 0] * self.outsize[0]
        cy = _bbox_gt[:, 1] * self.outsize[1]
        # calculate cell pos and normalize x, y
        cell_idx = np.floor(cy) * self.outsize[0] + np.floor(cx)
        cell_idx = np.array(cell_idx, dtype=np.int16)
        cx -= np.floor(cx)
        cy -= np.floor(cy)

        # set bbox of gt
        _bbox_built[cell_idx, best_anchors, 0] = cx
        _bbox_built[cell_idx, best_anchors, 1] = cy
        _bbox_built[cell_idx, best_anchors, 2] = torch.sqrt(_bbox_gt[:, 2])
        _bbox_built[cell_idx, best_anchors, 3] = torch.sqrt(_bbox_gt[:, 3])
        _bbox_mask[cell_idx, best_anchors, :] = 1

        # set cls of gt
        _cls_built[cell_idx, best_anchors, _cls_gt] = 1
        _cls_mask[cell_idx, best_anchors, :] = 1

        # set confidence score of gt
        _iou_built = calculate_iou(_bbox_pred.reshape(-1, 4), _bbox_built.view(-1, 4)).detach()
        _iou_built = _iou_built.view(hw, num_anchors, 1)
        _iou_mask[cell_idx, best_anchors, :] = 1

        return _bbox_built, _iou_built, _cls_built,\
                _bbox_mask, _iou_mask, _cls_mask


# функция, которая считает среднее арифметическое
# и находит максимум из 4ех чисел

def foo(first_num, second_num, third_num, fourth_num):
    return ((first_num + second_num + third_num + fourth_num) / 4,
            max(first_num, second_num, third_num, fourth_num))

current_max = 0  # текущее максимальное
count = 0  # счетчик

# бесконечный цикл
# для выхода из него
# нужно ввести больше или меньше 4ех чисел
while True:
    # ввод через лист для удобства
    print('Введите 4 числа через пробел: ')
    nums = [int(el) for el in input().split()]
    # собственно условие выхода из цикла
    if len(nums) != 4:
        break
    a = nums[0]
    b = nums[1]
    c = nums[2]
    d = nums[3]
    # считаем
    mean, maximum = foo(a, b, c, d)
    if count == 0:
        print(mean, maximum)
        current_max = maximum
    elif maximum > current_max and count > 0:
        current_max = maximum
        print(mean, current_max)
    else:
        print(mean, current_max)
    count += 1


import pytest
from freezegun import freeze_time
from opendere import game

def test_create_game_too_few():
    g = game.Game(None, None, None)
    for i in range(3):
        g.join_game(str(i), str(i))

    assert len(g.users) == 3
    with freeze_time(g.phase_end):
        with pytest.raises(ValueError):
            g.tick()

def test_create_game_success():
    g = game.Game(None, None, None)
    for i in range(4):
        g.join_game(str(i), str(i))

    assert len(g.users) == 4
    assert g.phase == None
    with freeze_time(g.phase_end):
        g.tick()
    assert g.phase == 0
    assert g.phase_name == 'day'
    assert g.num_yanderes_alive == 1

def test_create_night_game_success():
    g = game.Game(None, None, None)
    for i in range(7):
        g.join_game(str(i), str(i))

    g.user_hurry('a')
    g.user_hurry('e')

    assert len(g.users) == 7
    assert g.phase == None
    with freeze_time(g.phase_end):
        g.tick()
    assert g.phase == 0
    assert g.phase_name == 'night'
    assert g.num_yanderes_alive == 2


import unittest
import pandas as pd

from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from challenge.model import DelayModel

class TestModel(unittest.TestCase):

    FEATURES_COLS = [
        "OPERA_Latin American Wings",
        "MES_7",
        "MES_10",
        "OPERA_Grupo LATAM",
        "MES_12",
        "TIPOVUELO_I",
        "MES_4",
        "MES_11",
        "OPERA_Sky Airline",
        "OPERA_Copa Air"
    ]

    TARGET_COL = [
        "delay"
    ]

    def setUp(self) -> None:
        super().setUp()
        self.model = DelayModel()
        self.data = pd.read_csv(filepath_or_buffer="./data/data.csv")

    def test_model_preprocess_for_training(
        self
    ):
        features, target = self.model.preprocess(
            data=self.data,
            target_column="delay"
        )

        assert isinstance(features, pd.DataFrame)
        assert features.shape[1] == len(self.FEATURES_COLS)
        assert set(features.columns) == set(self.FEATURES_COLS)

        assert isinstance(target, pd.DataFrame)
        assert target.shape[1] == len(self.TARGET_COL)
        assert set(target.columns) == set(self.TARGET_COL)

    def test_model_preprocess_for_serving(
        self
    ):
        features = self.model.preprocess(
            data=self.data
        )

        assert isinstance(features, pd.DataFrame)
        assert features.shape[1] == len(self.FEATURES_COLS)
        assert set(features.columns) == set(self.FEATURES_COLS)

    def test_model_fit(
        self
    ):
        features, target = self.model.preprocess(
            data=self.data,
            target_column="delay"
        )

        _, features_validation, _, target_validation = train_test_split(features, target, test_size = 0.33, random_state = 42)

        self.model.fit(
            features=features,
            target=target
        )

        predicted_target = self.model._model.predict(
            features_validation
        )

        report = classification_report(target_validation, predicted_target, output_dict=True)

        assert report["0"]["recall"] < 0.60
        assert report["0"]["f1-score"] < 0.70
        assert report["1"]["recall"] > 0.60
        assert report["1"]["f1-score"] > 0.30

    def test_model_predict(
        self
    ):
        features = self.model.preprocess(
            data=self.data
        )

        predicted_targets = self.model.predict(
            features=features
        )

        assert isinstance(predicted_targets, list)
        assert len(predicted_targets) == features.shape[0]
        assert all(isinstance(predicted_target, int) for predicted_target in predicted_targets)


"""
Database models relating to tagging Posts and Contacts with topics of interest.
Similar to hashtags.
"""
from __future__ import absolute_import

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import joinedload, relationship
from sqlalchemy.sql import and_, not_

from pyaspora.database import db
from pyaspora.utils.models import TagParseMixin

class Interest(db.Model):
    '''
    Link between a Contact and a Tag, indicating that the Contact has an
    interest in the Tag's topic.

    Fields:
        contact_id - integer ID for the Contact
        tag_id - integer ID for the Tag
    '''

    __tablename__ = 'interests'
    contact_id = Column(Integer, ForeignKey('contacts.id'), primary_key=True)
    tag_id = Column(Integer, ForeignKey('tags.id'),
                    primary_key=True, index=True)

class PostTag(db.Model):
    '''
    Link between a Post and a Tag, indicating that the Post has the Tag as a
    topic.

    Fields:
        post_id - integer ID for the Post
        tag_id - integer ID for the Tag
    '''

    __tablename__ = 'post_tags'
    post_id = Column(Integer, ForeignKey('posts.id'), primary_key=True)
    tag_id = Column(Integer, ForeignKey('tags.id'),
                    primary_key=True, index=True)

    @classmethod
    def get_tags_for_posts(cls, post_ids):
        if not post_ids:
            return []
        return db.session.query(cls). \
            options(joinedload(cls.tag)). \
            filter(cls.post_id.in_(post_ids))

class Tag(TagParseMixin, db.Model):
    '''
    A topic that can be attached to a Post, or to a Contact (as an
    'interest'), for categorising and filtering content.

    Fields:
        id - integer ID for the tag
        name - human-readable tag description
        contacts - Contacts interested in this tag
        posts - Posts tagged with this tag
    '''

    __tablename__ = 'tags'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)

    contacts = relationship('Contact',
                            secondary='interests', backref='interests')
    posts = relationship('Post', secondary='post_tags', backref='tags')
    post_tags = relationship('PostTag', backref='tag')

    class Queries:
        @classmethod
        def public_posts_for_tags(cls, tag_ids):
            """
            All publicly-shared posts that contain a certain tag. Assumes that
            the query already contains Share.
            """
            from pyaspora.post.models import Share
            return and_(
                Tag.id.in_(tag_ids),
                not_(Share.hidden),
                Share.public,
            )

    @classmethod
    def get_by_name(cls, name, create=True):
        """
        Look up a Tag by textual name. If create is true (the default) a new
        Tag will be created if required. Returns None if the Tag name is
        invalid or the tag cannot be found. The caller will need to commit
        the session to save any created tags.
        """
        if not cls.name_is_valid(name):
            return None

        tag = db.session.query(cls).filter(cls.name == name).first()
        if create and not tag and cls.name_is_valid(name):
            tag = cls(name=name)
            db.session.add(tag)

        return tag


from flask import Flask, request, render_template, jsonify
import bms

app = Flask(__name__)

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

@app.route('/openAC', methods=['POST'])
def open_acc():
  content_type = request.headers.get('Content-Type')
  if (content_type == 'application/json'):
      data = request.json
      response = bms.OpenAcc(data['name'], data['acn'], data['dob'], data['address'], data['phone'], data['balance'])
      return jsonify(response)
  else:
      return 'Content-Type not supported!'

@app.route('/deposit', methods=['POST'])
def deposit():
  content_type = request.headers.get('Content-Type')
  if (content_type == 'application/json'):
      data = request.json
      response = bms.Deposit(data['acn'], data['amount'])
      return jsonify(response)
  else:
      return 'Content-Type not supported!'

@app.route('/withdraw', methods=['POST'])
def withdraw():
  content_type = request.headers.get('Content-Type')
  if (content_type == 'application/json'):
      data = request.json
      response = bms.Withdraw(data['acn'], data['amount'])
      return jsonify(response)
  else:
      return 'Content-Type not supported!'

@app.route('/checkbal', methods=['GET'])
def checkbal():
    args = request.args
    response = bms.CheckBal(args.get("acn"))
    return jsonify(response)

@app.route('/getcustomer', methods=['GET'])
def getcustomer():
    args = request.args
    response = bms.GetCustomerData(args.get("acn"))
    return jsonify(response)

@app.route('/closeAC', methods=['POST'])
def closeacc():
    content_type = request.headers.get('Content-Type')
    if (content_type == 'application/json'):
        data = request.json
        response = bms.CloseAcc(data["acn"])
        return jsonify(response)
    else:
      return 'Content-Type not supported!'


'''

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.

'''
def cetak_gambar(a):
    if(a%2==0):
        print("Harus bilangan Ganjil")
    else :
        row = 0
        while row < a :
            row = row + 1
            lines = ""
            col = 0
            while col < a :
                col = col + 1
                if (col == 0) or (col == a):
                    lines += "*"
                elif(row%2!=0) and (col%3==0):
                    lines += "="
                elif(row%2==0) and (col%2==0):
                    lines += "="
                else:
                    lines+= "*"

            print(lines)

cetak_gambar(8)


import math
from functools import reduce

from django.utils.dateparse import parse_date
from django.utils.functional import cached_property

from accounting_report.helpers import QuarterParameters
from accounting_report.models import Quarter
from cabinet.base_logic.contracts.base import ContractsLogic
from cabinet.base_logic.printing_forms.helpers.base import BaseHelper
from cabinet.base_logic.scoring.base import ScoringResult, ScoringLogic
from cabinet.constants.constants import Target, FederalLaw
from cabinet.models import EgrulData
from clients.models import Bank
from conclusions_app.conclusions.common import (
    HasArrearsOnPaymentOfTaxesConclusion
)
from conclusions_app.conclusions_logic import ConclusionsLogic
from external_api.nalogru_api import NalogRu
from external_api.searchtenderhelp_api import SearchTenderhelpApi
from settings.configs.banks import BankCode

class InbankHelper(BaseHelper):

    def get_quarters(self):
        return self.client.accounting_report.get_quarters()

    def __init__(self, *args, **kwargs):
        super(InbankHelper, self).__init__(*args, **kwargs)
        self.finance = self.get_finance()

    def get_previous_year_quarter(self):
        return self.client.accounting_report.get_previous_year_quarter()

    @cached_property
    def bank(self):
        return Bank.objects.get(code=BankCode.CODE_INBANK)

    def physical_shareholders(self):
        output = []
        for person in self.profile.profilepartnerindividual_set.all():
            person_name = person.full_name
            text = '%s доля %s %%' % (person_name, person.share)
            output.append(text)
        return ', '.join(output)

    def getPropertyStatus(self):
        address = self.profile.fact_address_properies
        if address['status']:
            return 'Собственность'
        else:
            return 'Аренда с %s по %s' % (address['from'], address['to'])

    def suggested_price_procent(self):
        result = round(100 - self.request.suggested_price_percent, 2)
        return result

    def contract_type(self):
        return Target.PARTICIPANT in self.request.targets and \
               self.request.tender.federal_law in [FederalLaw.LAW_44, FederalLaw.LAW_223]

    def sro_licences(self):
        if self.profile.has_license_sro:
            return self.profile.licensessro_set.all()
        else:
            return []

    def get_target_display(self):
        if Target.PARTICIPANT in self.request.targets:
            return 'тендер'
        if Target.EXECUTION in self.request.targets:
            return 'контракт'
        return ''

    def get_need_more_display(self):
        return 'Да' if self.request.have_additional_requirement else 'Нет'

    @cached_property
    def isSmallSubject(self):
        category = NalogRu().get_subject_size(self.client.inn)
        return category in [1, 2]

    @cached_property
    def isMiddleSubject(self):
        category = NalogRu().get_subject_size(self.client.inn)
        return category in [3]

    @cached_property
    def isUnknownSubject(self):
        category = NalogRu().get_subject_size(self.client.inn)
        return category not in [1,2,3]

    def rule_answer(self, result):
        if isinstance(result, ScoringResult):
            return 1 if result.is_success else 0
        return 1 if result else 0

    def scoring(self):
        scoring = ScoringLogic(self.bank, self.request)
        sum = 0
        count = 0
        quarters = self.client.accounting_report.get_quarters_for_fill()
        for quarter in quarters:
            value = quarter.get_value(2110)
            if value != 0 and quarter.not_empty():
                sum += value
                count += 1
        quarters = self.get_quarters()
        last_period = quarters[0]
        if count > 0:
            test_9 = float(self.request.required_amount) / (sum / count) > 10
        else:
            test_9 = False
        test_10 = last_period.get_value(1150) <= 0
        return {
            'test_1': self.rule_answer(scoring.check_rules({
                'class': 'RegexFieldsMatch',
                'fields': ["request.client.inn"],
                'pattern': '01|05|06|07|09|15|20|91|92',
                'error_message': 'Банк не работает с клиентами из данного региона'
            })),
            'test_2': self.rule_answer(scoring.check_rules({
                'class': 'RegexFieldsMatch',
                'fields': ["request.tender.inn"],
                'pattern': '01|05|06|07|09|15|20|91|92',
                'error_message': 'Банк не работает с клиентами из данного региона'
            })),
            'test_3': self.rule_answer(scoring.check_rules({
                'class': 'OgrnScoring',
                'value': 183,
                'error_message': 'Компания зарегистрирована менее 6 месяцев назад'
            })),
            'test_4': self.rule_answer(scoring.check_rules({
                'class': 'NegativeQuartersValueScoring',
                'codes': [2400],
                'error_message': 'В строке 2400 бухгалтерской отчётности за завершенный'
                                 ' квартал имеют отрицательные значения.'
            })),
            'test_5': self.rule_answer(scoring.check_rules({
                'class': 'IsUnfairSupplierScoring',
                'error_message': 'Находится в реестре недобросовестных поставщиков'
            })),
            'test_6': self.rule_answer(scoring.check_rules({
                'class': 'DecisionSuspendScoring',
                'error_message': 'Имеются решения о приостановлении по счетам'
            })),
            'test_7': self.rule_answer(scoring.check_rules({
                'class': 'NalogStatusScoring',
                'error_message': 'Задолжности по налогам и сборам с сайта '
                                 'service.nalog.ru/zd.do'
            })),
            'test_8': self.rule_answer(scoring.check_rules({
                'class': 'IsBankrotScoring',
                'error_message': 'Задолжности по налогам и сборам с сайта '
                                 'service.nalog.ru/zd.do'
            })),
            'test_9': test_9,
            'test_10': test_10
        }

    def get_finance_test_1(self, period: Quarter):
        """
        Рентабельность деятельности Клиента
        (анализируется соотношение Чистой прибыли за Последний завершенный год
        к выручке за тот же период)
            - Низкая степень риска (1 балл) – рентабельность деятельности более 3%;
            - Умеренная степень риска (2 балла) – рентабельность деятельности
            от 1% до 3%;
            - Высокая степень риска (3 балла) – рентабельность деятельности
            от 0,5% до 1%;
            - Сверхвысокая степень риска (4 балла) – рентабельность деятельности
            от 0% до 0,5%.
        (Ф.2) (Стр.2400/Стр.2110)*100
        :param period:
        :return:
        """
        prev_value = period.get_value(2110)
        if prev_value != 0:
            value = period.get_value(2400) / period.get_value(2110) * 100
            percent = round(value, 2)
        else:
            value = 0
            percent = None

        if value > 3:
            score = 1
        elif 1 < value <= 3:
            score = 2
        elif 0.5 < value <= 1:
            score = 3
        else:
            score = 4

        return {
            'value1': period.get_value(2400),
            'value2': period.get_value(2110),
            'percent': percent,
            'result': score
        }

    def get_quarter_by_params(self, params):
        return self.client.accounting_report.get_quarter_by_params(params)

    def get_finance_test_2(self, last_year: Quarter):
        """
        Сокращение/прирост выручки (осуществляется сравнение выручки за Последний
        завершенный год с выручкой за предыдущий завершенный год)
            - Низкая степень риска (1 балл) – имеется рост выручки более 10 %;
            - Умеренная степень риска (2 балла) – отсутствует рост выручки или имеется
            рост выручки до 10 % включительно;
            - Высокая степень риска (3 балла) – имеется снижение выручки в диапазоне до
            20% включительно;
            - Сверхвысокая степень риска (4 балла) – имеется снижение выручки более
            чем на 20%.
        (Ф.2) (Стр.2110 последний ЗГ/Стр.2110 предыдущий ЗГ)*100
        :param last_year:
        :return:
        """
        prev_year = self.get_quarter_by_params(QuarterParameters(
            year=int(last_year.year) - 1,
            quarter=last_year.quarter
        ))

        if prev_year.not_empty() and last_year.not_empty():
            prev_value = prev_year.get_value(2110)
            if prev_value != 0:
                value = last_year.get_value(2110) / prev_value
            else:
                value = 0
            rost = value > 1
            value = math.fmod(value, 1) * 100
            if rost and value > 10:
                score = 1
            elif rost and 0 <= value <= 10:
                score = 2
            elif not rost and 0 <= value <= 20:
                score = 3
            else:
                score = 4
        else:
            score = 4

        return {
            'value1': last_year.get_value(2110),
            'value2': prev_year.get_value(2110),
            'result': score
        }

    def get_finance_test_3(self, last_period: Quarter):
        """
        Текущая прибыль/убыток (анализируется Чистая прибыль, рассчитанная нарастающим
        итогом, за последний завершенный квартал)
            - Низкая степень риска (1 балл) – имеется чистая прибыль;
            - Умеренная степень риска (2 балла) – чистая прибыль равна 0;
            - Высокая степень риска (4 балла) – имеются убытки в размере,
            не превышающем 5 % от выручки за тот же период;
            - Сверхвысокая степень риска (8 балла) – имеются убытки в размере,
            превышающем 5 % от выручки за тот же период.
        :return:
        """
        value = last_period.get_value(2110)
        value2 = last_period.get_value(2400)
        rost = abs(value) / value2 if value2 != 0 else 0
        if value > 0:
            score = 1
        elif value == 0:
            score = 2
        elif value < 0 and rost < 5:
            score = 4
        elif value < 0 and rost >= 5:
            score = 8
        else:
            score = 3
        return {
            'value1': value,
            'value2': value2,
            'result': score
        }

    def get_finance_test_4(self, last_year):
        """
        (анализируется доля Чистых активов за Последний завершенный год в
        валюте баланса за тот же период)
            - Низкая степень риска (1 балл) – доля > 30%;
            - Умеренная степень риска (2 балла) – доля в диапазоне от 15 до 30%;
            - Высокая степень риска (3 балла) – доля в диапазоне от 5 до 15%;
            - Сверхвысокая степень риска (4 балла) – доля < 5%.
        :param last_year:
        :return:
        """
        last_year_1600 = last_year.get_value(1600)
        v = last_year.get_value(1600) - (
                last_year.get_value(1400) +
                last_year.get_value(1500) +
                last_year.get_value(1530)
        )
        value = v / last_year_1600 * 100 if last_year_1600 != 0 else 0
        if value > 30:
            score = 1
        elif 15 < value <= 30:
            score = 2
        elif 5 < value <= 15:
            score = 3
        else:
            score = 4

        if last_year.get_value(1600) != 0:
            percent = round(v / last_year_1600 * 100, 2)
        else:
            percent = None
        return {
            'value1': v,
            'value2': last_year_1600,
            'percent': percent,
            'result': score
        }

    def get_finance_test_5(self):
        """
        Соответствие Контракта профильности деятельности
            - Низкая степень риска (1 балл) – контракт, в обеспечение которого
            запрашивается Гарантия, соответствует профильности деятельности Клиента,
            а так же имеется опыт исполнения контрактов аналогичного размера;
            - меренная степень риска (2 балла) – контракт, в обеспечение которого
            запрашивается Гарантия, соответствует профильности деятельности Клиента,
            при от-сутствии опыта исполнения контрактов аналогичного размера;
            - Высокая степень риска (4 балла) – контракт, в обеспечение которого
            запрашивается Гарантия,не соответствует профильности деятельности Клиента,
            но имеется опыт исполнения контрактов  аналогичного размера;
            - Сверхвысокая степень риска (6 балла) – контракт, в обеспечение которого
            запрашивается Гарантия, не соответствует профильности деятельности Клиента,
            при отсутствии опыта исполнения контрактов аналогичного размера.
        :return:
        """
        return {
            'value1': ' ',
            'value2': ' ',
            'result': 3
        }

    def get_finance_test_6(self):
        """
        Количество исполненных контрактов:
            - Низкая степень риска (1 балл) – более 7 исполненных контрактов;
            - Умеренная степень риска (2 балла) – от 5 до 7 исполненных контрактов;
            - Высокая степень риска (3 балла) – от 2 до 4 исполненных контрактов;
            - Сверхвысокая степень риска (6 баллов) – 1 исполненный контракт.
        :return:
        """
        finished_contracts = ContractsLogic(
            self.request.client
        ).get_finished_contracts_count()

        if finished_contracts > 7:
            score = 1
        elif 5 <= finished_contracts <= 7:
            score = 2
        elif 2 <= finished_contracts <= 4:
            score = 3
        else:
            score = 6

        return {
            'value1': finished_contracts,
            'value2': ' ',
            'result': score
        }

    def get_finance_test_7(self):
        """
        Кредитная история
            - Низкая степень риска (1 балл) – кредитная история положительная
            (факты просрочек отсутствуют);
            - Умеренная степень риска (2 балла) – кредитная история отсутствует
            либо имели место просрочки
            - платежей по кредитам сроком не более 30 дней (не более 1 раза);
            - Высокая степень риска (3 балла) – имели место просрочки платежей
            по кредитам (не более 2 раз);
            -Сверхвысокая степень риска (4 балла) – имели место просрочки платежей
            по кредитам (более 2 раз).
        :return:
        """
        return {
            'value1': ' ',
            'value2': ' ',
            'result': 3
        }

    @cached_property
    def finance_data(self):
        quarters = self.get_quarters()
        if quarters[0].id != quarters[1].id:
            return {
                'last_period': quarters[0],
                'last_year': quarters[1],
                'previous_year': self.get_previous_year_quarter()
            }
        return {
            'last_year': quarters[1],
            'previous_year': self.get_previous_year_quarter()

        }

    def get_last_period_name(self):
        if len(self.finance_data) > 2:
            return '%i кв %i' % (self.finance_data['last_period'].quarter,
                                 self.finance_data['last_period'].year)
        return ''

    def get_last_period_revenues(self):
        if len(self.finance_data) > 2:
            return self.finance_data['last_period'].get_value(2110)
        return ''

    def get_last_period_profit(self):
        if len(self.finance_data) > 2:
            return self.finance_data['last_period'].get_value(2400)
        return ''

    def get_last_year_name(self):
        return self.finance_data['last_year'].year

    def get_last_year_revenues(self):
        return self.finance_data['last_year'].get_value(2110)

    def get_last_year_profit(self):
        return self.finance_data['last_year'].get_value(2400)

    def get_previous_year_name(self):
        return self.finance_data['previous_year'].year

    def get_previous_year_revenues(self):
        return self.finance_data['previous_year'].get_value(2110)

    def get_previous_year_profit(self):
        return self.finance_data['previous_year'].get_value(2400)

    def get_analise_period_name(self):
        return '%i/ %s' % (self.get_previous_year_name(), self.get_last_period_name())

    def get_finance(self):
        quarters = self.get_quarters()
        last_period = quarters[0]
        last_year = quarters[1]
        data = {
            'test_1': self.get_finance_test_1(last_year),
            'test_2': self.get_finance_test_2(last_year),
            'test_3': self.get_finance_test_3(last_period),
            'test_4': self.get_finance_test_4(last_year),
            'test_5': self.get_finance_test_5(),
            'test_6': self.get_finance_test_6(),
            'test_7': self.get_finance_test_7(),
        }
        total_score = 0
        for d in data.values():
            total_score += d['result']

        if total_score > 25:
            finance_score = 'плохое'
            raiting = ''
        elif 14 < total_score <= 25:
            finance_score = 'хорошее'
            raiting = 'B'
        else:
            finance_score = 'хорошее'
            raiting = 'A'

        data['total_score'] = total_score
        data['finance_score'] = finance_score
        data['raiting'] = raiting
        return data

    @cached_property
    def executing_contracts(self):
        contracts = ContractsLogic(self.client).get_execution_contracts()
        data = {}
        for contract in contracts:
            d = parse_date(contract.get('start_date')).year
            data.setdefault(d, [])
            data[d].append(contract)

        data = [(k, data[k]) for k in sorted(data.keys())]
        result = []
        for year, d in data:
            result.append({
                'year': year,
                'count': len(d),
                'sum': reduce(lambda sum, el: sum + el.get('price'), d, 0)
            })
        return result

    @cached_property
    def _executing_contracts(self):
        return ContractsLogic(self.client).get_execution_contracts()

    def get_executing_contracts_count(self):
        return len(self._executing_contracts) or ''

    def get_executing_contracts_max(self):
        max_price = 0
        for contract in self._executing_contracts:
            if float(contract.price) > max_price:
                max_price = float(contract.price)
        return max_price or ''

    def get_executing_contracts_sum(self):
        return reduce(
            lambda sum, el: sum + float(el.price),
            self._executing_contracts, 0) or ''

    @cached_property
    def finished_contracts(self):
        contracts = ContractsLogic(self.client).get_finished_contracts()
        data = {}
        for contract in contracts:
            d = parse_date(contract.start_date).year
            data.setdefault(d, [])
            data[d].append(contract)

        data = [(k, data[k]) for k in sorted(data.keys())]
        result = []
        for year, d in data:
            result.append({
                'year': year,
                'count': len(d),
                'sum': reduce(lambda sum, el: sum + el.price, d, 0)
            })
        return result

    @cached_property
    def _finished_contracts(self):
        return ContractsLogic(self.client).get_finished_contracts()

    def get_finished_contracts_count(self):
        return len(self._finished_contracts) or ''

    def get_finished_contracts_max(self):
        max_price = 0
        for contract in self._finished_contracts:
            if float(contract.price) > max_price:
                max_price = float(contract.price)
        return max_price or ''

    def get_finished_contracts_sum(self):
        return reduce(
            lambda sum, el: sum + float(el.price),
            self._finished_contracts, 0) or ''

    def get_join_fl_shares(self):
        data = []
        for person in self.profile.profilepartnerindividual_set.filter(share__gt=0):
            data.append(person.full_name())
        return ', '.join(data)

    def has_dolg(self):
        result = ConclusionsLogic.get_conclusion_result(
            client=self.client,
            conclusion=HasArrearsOnPaymentOfTaxesConclusion
        )
        if result.result:
            return 'Негативные сведения отсутствуют'
        return 'найдены'

    def has_sro(self):
        return 1 if self.profile.has_license_sro or self.profile.is_member_sro else 0

    def last_contr_agents(self):
        limit = 3
        contracts = ContractsLogic(self.client).get_finished_contracts()
        count = 0
        output = []
        for contract in contracts:
            str = contract.issuer_name
            if str not in output:
                count += 1
                output.append(str + '\n')
            if count == limit:
                break
        return ', '.join(output)

    @property
    def organization_form(self):
        if self.client.is_individual_entrepreneur:
            return 'ИП'
        return self.profile.get_organization_form_display()

    def get_inn(self):
        return self.profile.reg_inn

    def get_reg_state_date(self):
        return self.profile.reg_state_date

    def get_authorized_capital_paid(self):
        return self.profile.authorized_capital_paid

    def get_notification_id(self):
        return self.request.tender.notification_id

    def get_federal_law(self):
        return self.request.tender.get_federal_law_display()[:-3]

    def get_interval_from(self):
        return self.request.interval_from

    def get_interval_to(self):
        return self.request.interval_to

    def get_interval(self):
        return self.request.interval

    def get_tender_subject(self):
        return self.request.tender.subject

    def get_suggested_price_amount(self):
        return '%.2f' % self.request.suggested_price_amount

    def get_suggested_price_percent(self):
        return '%.2f %%' % self.request.suggested_price_percent

    def get_beneficiar_full_name(self):
        egrul_data = EgrulData.get_info(self.request.tender.beneficiary_inn)
        if egrul_data:
            return egrul_data.get(
                'section-ur-lico', {}
            ).get('full-name-ur-lico', '') or self.profile.full_name
        return self.request.tender.beneficiary_name

    def get_beneficiar_name(self):
        return self.request.tender.beneficiary_name

    def getBeneficiars(self):
        return self.profile.beneficiars.filter(share__gte=21.5)

    def getPPersons(self):
        return self.profile.profilepartnerindividual_set.filter(share_gt=0)

    def getJPersons(self):
        return self.profile.profilepartnerlegalentities_set.filter(share_gt=0)

    def get_company_info(self):
        search = SearchTenderhelpApi()
        search_data = search.get_company_info(self.profile.reg_inn)
        fact_address = self.profile.fact_address_properies
        if not search_data:
            return {
                'inn': self.profile.reg_inn,
                'ogrn': self.profile.reg_ogrn,
                'kpp': self.profile.reg_kpp,
                'data': {
                    'inn': self.profile.reg_inn,
                    'kpp': self.profile.reg_kpp,
                    'OKPO': self.profile.reg_okpo,
                    'regNum': '',
                    'fullName': self.profile.full_name,
                    'legalForm': {},
                    'shortName': self.profile.short_name,
                    'factAddress': fact_address['address'],
                    'postAddress': self.profile.legal_address,
                    'customerCode': '',
                    'consRegistryNum': '',
                    'registrationDate': ''
                }
            }

        if not search_data['data']['fullName']:
            search_data['data']['fullName'] = self.profile.full_name
        if not search_data['data']['factAddress']:
            search_data['data']['factAddress'] = fact_address['address']
        if not search_data['data']['postAddress']:
            search_data['data']['factAddress'] = self.profile.legal_address
        return search_data

    def get_beneficiar_info(self):
        search = SearchTenderhelpApi()
        search_data = search.get_company_info(self.request.tender.beneficiary_inn)
        if not search_data:
            return {
                'inn': self.request.tender.beneficiary_inn,
                'ogrn': self.request.tender.beneficiary_ogrn,
                'kpp': self.request.tender.beneficiary_kpp,
                'data': {
                    'inn': self.request.tender.beneficiary_inn,
                    'kpp': self.request.tender.beneficiary_kpp,
                    'OKPO': '',
                    'regNum': '',
                    'fullName': self.request.tender.beneficiary_name,
                    'legalForm': {},
                    'shortName': self.request.tender.beneficiary_name,
                    'factAddress': self.request.tender.beneficiary_address,
                    'postAddress': self.request.tender.beneficiary_address,
                    'customerCode': '',
                    'consRegistryNum': '',
                    'registrationDate': ''
                }
            }

        if not search_data['data']['fullName']:
            search_data['data']['fullName'] = self.request.tender.beneficiary_name
        if not search_data['data']['factAddress']:
            search_data['data']['factAddress'] = self.request.tender.beneficiary_address
        if not search_data['data']['postAddress']:
            search_data['data']['factAddress'] = self.request.tender.beneficiary_address
        return search_data

    def getBenAddressFromEGRUL(self):
        egrul_data = EgrulData.get_info(self.request.tender.beneficiary_inn)
        if egrul_data:
            return egrul_data.get(
                'section-ur-adress', {}
            ).get('full_address', '') or self.request.tender.beneficiary_address
        return self.request.tender.beneficiary_address

    def date_last_finished_contract(self):
        max_end_date = None
        for contract in self._finished_contracts:
            end_date = contract.get('end_date')
            end_date = parse_date(end_date)
            if not max_end_date:
                max_end_date = end_date
            if end_date > max_end_date:
                max_end_date = end_date
        if max_end_date:
            return max_end_date.strftime('%d.%m.%Y')
        return ''

    def is_execution(self):
        return Target.EXECUTION in self.request.targets

    def is_participant(self):
        return Target.PARTICIPANT in self.request.targets

    def is_warranty(self):
        return Target.WARRANTY in self.request.targets

    def get_contract_type(self):
        return self.request.get_contract_type_display()

    def get_required_amount(self):
        return self.request.required_amount


import sys
from itertools import permutations
n=int(input())
num=list(sys.stdin.readline().split())
a=list(map(int,sys.stdin.readline().split()))
b=[]
b+=['+']*a[0]+['-']*a[1]+['*']*a[2]+['//']*a[3]
b1=list(permutations(b,n-1))
b1=list(set(b1))
ma=0
mi=0
s=''
ma=-1e9
mi=1e9
for j in range(len(b1)):
    s=''
    s+=num[0]
    for i in range(n-1):
        if b1[j][i]=='//' and int(s)<0 and int(num[i+1])>0:
            s=(-int(s))//int(num[i+1])
            s='-'+str(s)
        else:
            s+=b1[j][i]
            s+=num[i+1]
            s=str(eval(s))
    s=int(s)
    ma=max(ma,s)
    mi=min(mi,s)
print(ma)
print(mi)

ma=-1e9
mi=1e9
m=int(input())
num=list(map(int,input().split()))
a1,a2,a3,a4=map(int,sys.stdin.readline().split())
def find(n,i,a1,a2,a3,a4):
    global ma,mi
    if i==m:
        ma=max(ma,n)
        mi=min(mi,n)
    else:
        if a1:find(n+num[i],i+1,a1-1,a2,a3,a4)
        if a2:find(n-num[i],i+1,a1,a2-1,a3,a4)
        if a3:find(n*num[i],i+1,a1,a2,a3-1,a4)
        if a4:find(int(n/num[i]),i+1,a1,a2,a3,a4-1)
find(num[0],1,a1,a2,a3,a4)
print(ma)
print(mi)


import asyncio
import contextlib
import datetime
import hashlib
import mmap
import os
import os.path
import random
import subprocess
import sys
import tempfile
import time
from typing import IO, Callable
from zoneinfo import ZoneInfo

import humanize
import structlog
import tzlocal

from .ext_deps import CP
from .fallocate import punch_hole

log = structlog.stdlib.get_logger(subsystem="utils")

log_data: str  # for pytest

Bytes = 1
kiB = Bytes * 1024
MiB = kiB * 1024
GiB = MiB * 1024
TiB = GiB * 1024

# 64 kiB blocks are a good compromise between sparsiness and fragmentation.
PUNCH_SIZE = 4 * MiB
CHUNK_SIZE = 4 * MiB

END = object()

def report_status(f):
    def wrapped(*args, **kw):
        generator = iter(f(*args, **kw))
        steps = next(generator)
        step = 0
        start = time.time()
        while True:
            status = next(generator)
            if status is END:
                break
            step += 1
            now = time.time()
            time_elapsed = now - start
            per_chunk = time_elapsed / step
            remaining = steps - step
            time_remaining = remaining * per_chunk
            eta = datetime.datetime.now() + datetime.timedelta(
                seconds=int(time_remaining)
            )
            if step == 5 or not step % 100:  # pragma: nocover
                log.info(
                    "progress-report",
                    step=step,
                    steps=steps,
                    percent=round(step / steps * 100, 2),
                    elapsed=round(time_elapsed),
                    remaining=humanize.naturaldelta(time_remaining),
                    eta=str(eta),
                )

        result = next(generator)
        return result

    return wrapped

class SafeFile(object):
    """A context manager for handling files in our
    scenarios more safely:

    - manage use of temporary files and os.rename for committing
    - ensure files are flushed to disk when closing
    - ensure files are write-protected (and maybe temporarily not)

    Use this as a context manager and then call the various open_*
    methods or use_write_protection() to enable the safety belts.

    use_write_protection() has to be called before opening.
    """

    protected_mode = 0o440

    def __init__(self, filename, encoding=None, sync=True):
        self.filename = filename
        self.encoding = encoding
        self.sync = sync
        self.f = None

    def __enter__(self):
        assert self.f is None
        self.rename = False
        self.write_protected = False
        self.commit_callbacks = []
        return self

    def __exit__(self, exc_type=None, exc_value=None, exc_tb=None):
        # Error handling:
        # - if we're based on temporary files, we simply unlink
        #   and haven't changed the original
        # - if we're working with the original, we at least have
        #   synced by now and will restore write-protection
        if self.f is None:
            return
        if self.sync:
            self.f.flush()
            os.fsync(self.f)
        self.f.close()

        if self.use_write_protection:
            os.chmod(self.f.name, self.protected_mode)
            if os.path.exists(self.filename):
                os.chmod(self.filename, self.protected_mode)

        if self.rename:
            if exc_type is None:
                os.rename(self.f.name, self.filename)
            else:
                os.unlink(self.f.name)

        self.f = None

    # Activate the different safety features

    def open_new(self, mode):
        """Open this as a new (temporary) file that will be renamed on close."""
        assert not self.f
        self.f = tempfile.NamedTemporaryFile(
            mode, dir=os.path.dirname(self.filename), delete=False
        )
        self.rename = True

    def open_copy(self, mode):
        """Open an existing file, make a copy first, rename on close."""
        assert not self.f

        if os.path.exists(self.filename):
            self.open_new("wb")
            cp_reflink(self.filename, self.f.name)
            self.f.close()

        self.f = open(self.f.name, mode)

    def open_inplace(self, mode):
        """Open as an existing file, in-place."""
        assert not self.f
        if self.use_write_protection and os.path.exists(self.filename):
            # This is kinda dangerous, but this is a tool that only protects
            # you so far and doesn't try to get in your way if you really need
            # to do this.
            os.chmod(self.filename, 0o640)
        self.f = open(self.filename, mode)

    def use_write_protection(self):
        """Enable write-protection handling.

        Ensures you can do your work (non-write-protected) and ensures to
        (re-)enable write protection on close.

        """
        assert not self.f
        self.write_protected = True

    # File API shim

    @property
    def name(self):
        return self.f.name

    def read(self, *args, **kw):
        data = self.f.read(*args, **kw)
        if self.encoding:
            data = data.decode(self.encoding)
        return data

    def write(self, data):
        if self.encoding:
            data = data.encode(self.encoding)
        self.f.write(data)

    def seek(self, offset, whence=0):
        return self.f.seek(offset, whence)

    def tell(self):
        return self.f.tell()

    def truncate(self, size=None):
        return self.f.truncate(size)

    def fileno(self):
        return self.f.fileno()

if hasattr(os, "posix_fadvise"):
    posix_fadvise = os.posix_fadvise
else:  # pragma: no cover
    os.POSIX_FADV_RANDOM = None  # type: ignore
    os.POSIX_FADV_SEQUENTIAL = None  # type: ignore
    os.POSIX_FADV_WILLNEED = None  # type: ignore
    os.POSIX_FADV_DONTNEED = None  # type: ignore

    def posix_fadvise(*args, **kw):
        log.debug("posix_fadivse-unavailable")
        return

if sys.platform == "darwin":  # pragma: no cover

    @contextlib.contextmanager
    def zeroes(size):
        yield "\00" * size

else:

    @contextlib.contextmanager
    def zeroes(size):
        with open("/dev/zero", "rb", buffering=0) as f:
            z = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ)
            yield z[0:size]
            z.close()

@report_status
def copy_overwrite(source, target):
    """Efficiently overwrites `target` with a copy of `source`.

    Identical regions won't be touched so this is COW-friendly. Assumes
    that `target` is a shallow copy of a previous version of `source`.

    Assumes that `target` exists and is open in read-write mode.
    """
    punch_size = PUNCH_SIZE
    source.seek(0, 2)
    size = source.tell()
    if size > 500 * GiB:
        punch_size *= 10
    source.seek(0)
    yield size / punch_size
    try:
        posix_fadvise(source.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)
        posix_fadvise(target.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)
    except Exception:
        pass
    with zeroes(punch_size) as z:
        while True:
            startpos = source.tell()
            chunk = source.read(punch_size)
            if not chunk:
                break
            target.seek(startpos)
            compare = target.read(len(chunk))
            if not compare or chunk != compare:
                if chunk == z:
                    target.flush()
                    punch_hole(target, startpos, len(chunk))
                else:
                    target.seek(startpos)
                    target.write(chunk)
            yield

    size = source.tell()
    target.flush()
    try:
        target.truncate(size)
    except OSError:
        pass  # truncate may not be supported, i.e. on special files
    try:
        os.fsync(target)
    except OSError:
        pass  # fsync may not be supported, i.e. on special files
    yield END
    yield size

@report_status
def copy(source, target):
    """Efficiently overwrites `target` with a copy of `source`.

    Identical regions will be touched - so this is not CoW-friendly.

    Assumes that `target` exists and is open in read-write mode.
    """

    chunk_size = 4 * 1024 * 1024
    source.seek(0, 2)
    yield source.tell() / chunk_size
    source.seek(0)

    try:
        posix_fadvise(source.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)
        posix_fadvise(target.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)
    except Exception:
        pass
    while True:
        chunk = source.read(chunk_size)
        if not chunk:
            break
        target.write(chunk)
        yield

    size = source.tell()
    target.flush()
    try:
        target.truncate(size)
    except OSError:
        pass  # truncate may not be supported, i.e. on special files
    try:
        os.fsync(target)
    except OSError:
        pass  # fsync may not be supported, i.e. on special files
    yield END
    yield size

def cp_reflink(source, target):
    """Makes as COW copy of `source` if COW is supported."""
    # We can't tell if reflink is really supported. It depends on the
    # filesystem.
    try:
        subprocess.check_call(
            [CP, "--reflink=always", source, target], stderr=subprocess.PIPE
        )
    except subprocess.CalledProcessError:
        log.warning("cp_reflink-no-cow", source=source, target=target)
        if os.path.exists(target):
            os.unlink(target)
        subprocess.check_call([CP, source, target])

def files_are_equal(
    a: IO,
    b: IO,
    report: Callable[[bytes, bytes, int], None] = lambda a, b, c: None,
) -> bool:
    try:
        posix_fadvise(a.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)  # type: ignore
        posix_fadvise(b.fileno(), 0, 0, os.POSIX_FADV_SEQUENTIAL)  # type: ignore
    except Exception:
        pass
    position = 0
    errors = 0
    while True:
        chunk_a = a.read(CHUNK_SIZE)
        chunk_b = b.read(CHUNK_SIZE)
        if chunk_a != chunk_b:
            log.error(
                "files-not-equal",
                hash_a=hashlib.md5(chunk_a).hexdigest(),
                hash_b=hashlib.md5(chunk_b).hexdigest(),
                pos=position,
            )
            report(chunk_a, chunk_b, position)
            errors += 1
        if not chunk_a:
            break
        position += CHUNK_SIZE
    return not errors

def files_are_roughly_equal(
    a: IO,
    b: IO,
    samplesize=0.01,
    blocksize=CHUNK_SIZE,
    timeout=5 * 60,
    report: Callable[[bytes, bytes, int], None] = lambda a, b, c: None,
) -> bool:
    a.seek(0, os.SEEK_END)
    size = a.tell()
    blocks = size // blocksize
    blocklist = range(0, max(blocks, 1))
    sample = random.sample(blocklist, max(int(samplesize * blocks), 1))

    # turn off readahead
    try:
        for fdesc in a.fileno(), b.fileno():
            posix_fadvise(fdesc, 0, 0, os.POSIX_FADV_RANDOM)  # type: ignore
    except Exception:
        pass

    # We limit this to a 5 minute operation to avoid clogging the storage
    # infinitely.
    started = now()
    max_duration = datetime.timedelta(seconds=timeout)

    for block in sample:
        log.debug("files-roughly-equal-verifying", offset=block * blocksize)
        duration = now() - started
        if duration > max_duration:
            log.info("files-roughly-equal-stopped", duration=duration)
            return True

        a.seek(block * blocksize)
        b.seek(block * blocksize)
        chunk_a = a.read(blocksize)
        chunk_b = b.read(blocksize)
        if chunk_a != chunk_b:
            log.error(
                "files-not-roughly-equal",
                hash_a=hashlib.md5(chunk_a).hexdigest(),
                hash_b=hashlib.md5(chunk_b).hexdigest(),
                pos=block * blocksize,
            )
            report(chunk_a, chunk_b, block * blocksize)
            return False
    return True

def now():
    """A monkey-patchable version of 'datetime.datetime.now()' to
    support unit testing.

    Also, ensure that we'll always use timezone-aware objects.
    """
    return datetime.datetime.now(ZoneInfo("UTC"))

def min_date():
    return datetime.datetime.min.replace(tzinfo=ZoneInfo("UTC"))

def has_recent_changes(entry, reference_time):
    # This is not efficient on a first look as we may stat things twice, but it
    # makes the recursion easier to read and the VFS will be caching this
    # anyway.
    # However, I want to perform a breadth-first analysis as the theory is that
    # higher levels will propagate changed mtimes do to new/deleted files
    # instead of just modified files in our case and looking at stats when
    # traversing a directory level is faster than going depth first.
    st = entry.stat(follow_symlinks=False)
    if st.st_mtime >= reference_time:
        return True
    if not entry.is_dir(follow_symlinks=False):
        return False
    candidates = list(os.scandir(entry.path))
    # First pass: stat all direct entries
    for candidate in candidates:
        if candidate.stat(follow_symlinks=False).st_mtime >= reference_time:
            return True
    # Second pass: start traversing
    for candidate in os.scandir(entry.path):
        if has_recent_changes(candidate, reference_time):
            return True
    return False

async def time_or_event(deadline, event):
    remaining_time = (deadline - now()).total_seconds()
    return await next(
        asyncio.as_completed([asyncio.sleep(remaining_time), event.wait()])
    )

def format_datetime_local(dt):
    tz = tzlocal.get_localzone()
    if dt is None:
        return "-", tz
    return (
        dt.astimezone(tz).replace(tzinfo=None).strftime("%Y-%m-%d %H:%M:%S"),
        tz,
    )


import os

import template_select

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db

from myapp.Alert import Alert
from myapp.Bbs import Bbs
from myapp.OwnerCheck import OwnerCheck
from myapp.BbsConst import BbsConst
from myapp.AppCode import AppCode
from myapp.CssDesign import CssDesign

class EditBbs(webapp.RequestHandler):
	def get(self):
		try:
			bbs = db.get(self.request.get("bbs_key"))
		except:
			Alert.alert_msg_with_write(self,"掲示板の編集画面のURLが変更されています。掲示板からログインし、デザインの編集ボタンをクリックして下さい。")
			return

		user = users.get_current_user()
		is_admin=0
		if(user and OwnerCheck.is_admin(user)):
			is_admin=1
		if(bbs.short!="sample" and OwnerCheck.check(bbs,user) and not is_admin):
			Alert.alert_msg_with_write(self,"デザインの編集の権限がありません。")
			return

		error_str=""
		if self.request.get("error_str"):
			error_str=self.request.get("error_str")

		is_css_enable=OwnerCheck.is_admin(user)

		my_app_list=None
		if(user):
			my_app_list=AppCode.all().filter("user_id =",user.user_id()).filter("mode =",2).fetch(limit=100,offset=0)

		tab="all"
		if(self.request.get("tab")):
			tab=self.request.get("tab")

		bbs_css=None
		try:
			bbs_css=bbs.css
		except:
			bbs_css=None

		template_values = {
			'host': './',
			'bbs': bbs,
			'error_str': error_str,
			'is_css_enable': is_css_enable,
			'is_admin': is_admin,
			'is_iphone': CssDesign.is_iphone(self),
			'is_tablet': CssDesign.is_tablet(self),
			'my_app_list': my_app_list,
			'user': user,
			'tab': tab,
			'redirect_url': self.request.path,
			'bbs_css': bbs_css,
			'is_english': CssDesign.is_english(self)
		}

		path = '/html/edit_bbs.html'
		self.response.out.write(template_select.render(path, template_values))