import random
from math import ceil
from queue import PriorityQueue

class Node(object):
	def __init__(self, label: str=None):
		self.label = label
		self.children = []

	def __lt__(self,other):
		return (self.label < other.label)

	def __gt__(self,other):
		return (self.label > other.label)

	def __repr__(self):
		return 'Node({})'.format(self.label)

	def add_child(self, node, cost=1):
		edge = Edge(self, node, cost)
		self.children.append(edge)

class Edge(object):
	def __init__(self, source: Node, destination: Node, cost: int=1):
		self.source = source
		self.destination = destination
		self.cost = cost

	def __repr__(self):
		return '{}: {}'.format(self.destination.label, self.cost)

def GenerateGrid(n, p):
	'''
	Generates undirected mesh grid with n rows and n columns
	'''
	g, c = [[] for _ in range(n*n)], {}
	for node in range(n*n):
		try:
			col = ([_ for _ in range(n*ceil((node+1)/n)-n, n*ceil((node+1)/n))])
			adj_nodes = [i for i  in col if i != node and abs(node-i)==1]
			adj_nodes += [i for i in [node+n, node-n] if i>=0 and i<n*n]
			for an in adj_nodes:
				if an >= 0 and an < n*n:
					g[node].append(an)
					if (an, node) not in c:
						c[(node, an)] = random.randint(1,20)
					else:
						c[(node, an)] = c[(an, node)]
		except IndexError:
			pass

	for _ in range(int(p/(2*n*(n-1)))):
		s = random.choice([_ for _ in range(0,n*n)])
		t = random.choice(g[s])
		print(s, t)
		g[s].remove(t)
		g[t].remove(s)
		del	c[(s,t)]
		del c[(t,s)]

	_g = []
	for _l in range(n*n):
		_g.append(Node(_l))
	for (_s,_t), _c in c.items():
		_g[_s].add_child(_g[_t], _c)

	return _g

def UniformCostSearch(s, t):
	q = PriorityQueue()
	q.put((0, [s]))
	while not q.empty():
		p = q.get()
		cur = p[1][-1]
		if cur.label == t:
			return p[1]
		for e in cur.children:
			np = list(p[1])
			np.append(e.destination)
			q.put((p[0] + e.cost, np))

def IterativeDeepeningDepthFirstSearch(_source: Node, _target: str, _limit: int=10):
	def _dls(p: list, _t: str, _l: int):
		cur = p[-1]
		if cur.label == _t:
			return p
		if _l <= 0:
			return None
		for e in cur.children:
			np = list(p)
			np.append(e.destination)
			r = _dls(np, _t, _l - 1)
			if r is not None:
				return r

	for depth in range(0, _limit):
		r = _dls([_source], _target, depth)
		if r is None:
			continue
		return r

	print('goal not in graph with depth {}'.format(_limit))
	return None

def AstarSearch(_source : Node, _target : Node, _graph : list, n: int):
	def generateHeuristicValue(_s : Node, _t : Node, _n : int):
		t = {}
		tx = ceil((int(_t.label)+1)/_n)
		ty = int(_t.label)-(tx-1)*_n+1
		for _node in _graph:
			nx = ceil((int(_node.label)+1)/_n)
			ny = int(_node.label)-(nx-1)*_n+1
			t[_node] = abs(tx-nx)+abs(ty-ny)
		return t
	h : dict = generateHeuristicValue(_source, _target, n)
	#print(f"{_source.label},{_target.label} - {h}")

	open = set([_source])
	close = set()
	g = {}
	g[_source] = 0
	parents = {}
	parents[_source] = _source

	while len(open):
		_node = None
		#print(f"g={g} and h={h}")
		for v in open:
			if _node == None or g[v]+h[v] < g[_node]+h[_node]:
				_node = v
		if _node == None:
			print("Path does not exist")
			return None
		if _node == _target:
			reconst_path = []
			while parents[_node] != _node:
				reconst_path.append(_node)
				_node = parents[_node]
			reconst_path.append(_source)

			reconst_path.reverse()

			#print('Path found: {}'.format(reconst_path))
			return reconst_path

		for _neighbor in _node.children:
			if _neighbor.destination not in open and _neighbor.destination not in close:
				open.add(_neighbor.destination)
				parents[_neighbor.destination] = _node
				g[_neighbor.destination] = g[_node] + _neighbor.cost
			else:
				if g[_neighbor.destination] > g[_node]+_neighbor.cost:
					g[_neighbor.destination] = g[_node] + _neighbor.cost
					parents[_neighbor.destination] = _node

					if _neighbor.destination in close:
						close.remove(_neighbor.destination)
						open.add(_neighbor.destination)
		open.remove(_node)
		close.add(_node)
	print('Path does not exist!')
	return None

if __name__=='__main__':
	n = int(input("Enter the number n of rows and columns of the grid: "))
	p = int(input("Enter the percentage p of edges to be removed: "))
	g = GenerateGrid(n, p)
	s : Node = random.choice(g)
	t : Node = random.choice([_ for _ in g if _ != s])

	p_ucs_path = ""
	p_ucs_cost = 0
	ucs_path = ((UniformCostSearch(s, t.label)))
	for i in range(len(ucs_path)):
		if i==len(ucs_path)-1:
			p_ucs_path+=str(ucs_path[i])
		else:
			p_ucs_path+=str(ucs_path[i])+"->"
			for child in ucs_path[i].children:
				if child.destination == ucs_path[i+1]:
					p_ucs_cost+=child.cost
	print(f"For Uniform Cost Search Search: \n\tPath is {p_ucs_path} \n\tCost is {p_ucs_cost} \n\tNumber of nodes created is 0")

	p_iddfs_path = ""
	p_iddfs_cost = 0
	iddfs_path = (IterativeDeepeningDepthFirstSearch(s, t.label, n*n))
	if iddfs_path:
		for i in range(len(iddfs_path)):
			if i==len(iddfs_path)-1:
				p_iddfs_path+=str(iddfs_path[i])
			else:
				p_iddfs_path+=str(iddfs_path[i])+"->"
				for child in iddfs_path[i].children:
					if child.destination == iddfs_path[i+1]:
						p_iddfs_cost+=child.cost
	print(f"For Iterative Deepening Depth-First Search: \n\tPath is {p_iddfs_path} \n\tCost is {p_iddfs_cost} \n\tNumber of nodes created is 0")

	p_as_path = ""
	p_as_cost = 0
	as_path = (AstarSearch(s,t,g,n))
	for i in range(len(as_path)):
		if i==len(as_path)-1:
			p_as_path+=str(as_path[i])
		else:
			p_as_path+=str(as_path[i])+"->"
			for child in as_path[i].children:
				if child.destination == as_path[i+1]:
					p_as_cost+=child.cost
	print(f"For A* Search Search: \n\tPath is {p_as_path} \n\tCost is {p_as_cost} \n\tNumber of nodes created is 0")


from functools import lru_cache
from typing import Dict

from django.contrib.postgres.aggregates import ArrayAgg
from django.db import models
from django.db.models import Value, F, Exists, OuterRef, Subquery
from django.db.models.fields.json import KeyTextTransform
from django.db.models.functions import TruncSecond, Cast
from google.protobuf.wrappers_pb2 import UInt64Value

from accounts.models import Account, get_request_account
from event.base.column import Column, AnnotatedColumn, AttributeColumn, AttributeColumnV2
from event.base.filter_token_op import LiteralArrayColumnTokenFilterOp
from event.base.literal import event_key_type_to_literal_type, literal_type_is_groupable, \
    literal_type_aggregation_functions
from event.models import AlertMonitorTransactionMapping, MonitorTransactionEventMapping, MonitorTransaction, \
    EntityInstanceEventMapping, AlertEntityInstanceMapping
from protos.event.engine_options_pb2 import AttributeOption, AttributeOptionV2
from protos.event.literal_pb2 import LiteralType, IdLiteral
from protos.event.metric_pb2 import AggregationFunction
from protos.event.monitor_pb2 import MonitorTransaction as MonitorTransactionProto

transaction_status_options = {
    MonitorTransactionProto.MonitorTransactionStatus.PRIMARY_RECEIVED: 'Active',
    MonitorTransactionProto.MonitorTransactionStatus.SECONDARY_RECEIVED: 'Finished',
}

def transaction_status_options_cb(account, obj):
    return transaction_status_options

def get_enum_id_column_option_cb(proto_enum):
    def _enum_id_options(account, obj):
        return {v: k for k, v in proto_enum.items() if v != 0}

    return _enum_id_options

def get_id_option_cb(account_scope_cb):
    def _id_options(account, obj):
        if obj is not None:
            return {obj.id: obj.name}
        return {elem['id']: elem['name'] for elem in account_scope_cb(account).values('id', 'name')}

    return _id_options

def get_event_attribute_options(path, display_name, account, obj):
    if obj:
        qs = account.eventkey_set.filter(event_type=obj)
    else:
        qs = account.eventkey_set.all()

    qs = qs.select_related(
        'event_type'
    ).values('id', 'name', 'type', 'event_type__id', 'event_type__name')

    attribute_options: [AttributeOption] = []

    for q in qs:
        literal_type = event_key_type_to_literal_type(q['type'])
        attribute_options.append(
            AttributeOption(
                name=q['name'], path=path, type=literal_type,
                column_context=[
                    AttributeOption.ColumnContext(
                        alias='event_type_id',
                        id=IdLiteral(
                            long=UInt64Value(value=q['event_type__id']),
                            type=IdLiteral.Type.LONG
                        )
                    )
                ],
                is_groupable=literal_type_is_groupable(literal_type),
                aggregation_functions=literal_type_aggregation_functions(literal_type),
            )
        )

    return attribute_options

def get_monitor_attribute_options_cb(key='primary_key'):
    def get_monitor_attribute_options(path, display_name, account, obj):
        if obj:
            qs = account.monitor_set.filter(id=obj.id)
        else:
            qs = account.monitor_set.exclude(is_active=False)

        key_event_type_id = f'{key}__event_type__id'
        key_event_type_name = f'{key}__event_type__name'

        qs = qs.select_related(key, f'{key}__event_type').values(
            'id', 'name', key,
            key_event_type_id,
            key_event_type_name,
        )

        attribute_options: [AttributeOption] = []
        for monitor in qs:
            event_keys_qs = account.eventkey_set.filter(
                event_type=monitor[key_event_type_id]
            ).values(
                'id',
                'name',
                'type'
            )
            path_alias = f"{monitor[key_event_type_name]} ({display_name})"

            for ek in event_keys_qs:
                literal_type = event_key_type_to_literal_type(ek['type'])
                attribute_options.append(
                    AttributeOption(
                        name=ek['name'], path=path, type=literal_type,
                        path_alias=path_alias,
                        column_context=[
                            AttributeOption.ColumnContext(
                                alias='monitor_id',
                                id=IdLiteral(
                                    long=UInt64Value(value=monitor['id']),
                                    type=IdLiteral.Type.LONG
                                )
                            )
                        ],
                        is_groupable=literal_type_is_groupable(literal_type),
                        aggregation_functions=literal_type_aggregation_functions(literal_type),
                    )
                )
        return attribute_options

    return get_monitor_attribute_options

def get_monitor_attribute_options_v2(account, obj):
    if obj:
        qs = account.monitor_set.filter(id=obj.id)
    else:
        qs = account.monitor_set.exclude(is_active=False)

    attribute_options: [AttributeOptionV2] = []
    attribute_options_dict = {}
    for key in ['primary_key', 'secondary_key']:

        key_event_type_id = f'{key}__event_type__id'
        key_event_type_name = f'{key}__event_type__name'

        eqs = qs.select_related(key, f'{key}__event_type').values(
            'id', 'name', key,
            key_event_type_id,
            key_event_type_name,
        )

        for monitor in eqs:
            event_keys_qs = account.eventkey_set.filter(
                event_type=monitor[key_event_type_id]
            ).values(
                'id',
                'name',
                'type'
            )

            path = "monitor__{}__event_type".format(key)

            for ek in event_keys_qs:
                literal_type = event_key_type_to_literal_type(ek['type'])
                if f"{ek['name']}##{literal_type}" not in attribute_options_dict:
                    attribute_options_dict[f"{ek['name']}##{literal_type}"] = []
                attribute_options_dict[f"{ek['name']}##{literal_type}"].append(path)

    for key, value in attribute_options_dict.items():
        paths = list(set(value))
        name = key.split("##")[0]
        literal_type = int(key.split("##")[1])
        attribute_options.append(
            AttributeOptionV2(
                name=name,
                path=paths,
                type=literal_type,
            )
        )
    return attribute_options

def get_entity_attribute_options_v2(account, obj):
    if obj:
        qs = account.entityeventkeymapping_set.filter(entity_id=obj.id)
    else:
        qs = account.entityeventkeymapping_set.exclude(is_active=False)

    attribute_options: [AttributeOptionV2] = []
    attribute_options_dict = {}
    qs = qs.select_related('event_key__event_type').values('event_key__event_type__id')
    for q in qs:
        event_type_id = q["event_key__event_type__id"]

        event_keys_qs = account.eventkey_set.filter(event_type=event_type_id).values('id', 'name', 'type')

        path = str(event_type_id)
        for ek in event_keys_qs:
            literal_type = event_key_type_to_literal_type(ek['type'])
            if f"{ek['name']}##{literal_type}" not in attribute_options_dict:
                attribute_options_dict[f"{ek['name']}##{literal_type}"] = []
            attribute_options_dict[f"{ek['name']}##{literal_type}"].append(path)

    for key, value in attribute_options_dict.items():
        paths = list(set(value))
        name = key.split("##")[0]
        literal_type = int(key.split("##")[1])
        attribute_options.append(
            AttributeOptionV2(
                name=name,
                path=paths,
                type=literal_type,
            )
        )
    return attribute_options

@lru_cache(maxsize=256)
def get_event_type_name_from_id(account_id, event_type_id):
    return Account(id=account_id).eventtype_set.filter(id=event_type_id).values_list('name', flat=True)[0]

@lru_cache(maxsize=256)
def get_monitor_name_from_id(account_id, monitor_id):
    return Account(id=account_id).monitor_set.filter(id=monitor_id).values_list('name', flat=True)[0]

@lru_cache(maxsize=256)
def get_entity_name_from_id(account_id, entity_id):
    return Account(id=account_id).entity_set.filter(id=entity_id).values_list('name', flat=True)[0]

def resolve_transaction_status_options(transaction_status):
    return transaction_status_options[transaction_status]

def get_resolve_column_id_cb(get_obj_name_from_id_cb):
    def _resolve_column_id(column_id):
        account = get_request_account()
        return get_obj_name_from_id_cb(account.id, column_id)

    return _resolve_column_id

event_columns = {
    'event_type_id': Column(
        name='event_type_id',
        display_name='Event Type',
        type=LiteralType.ID,
        id_options_cb=get_id_option_cb(
            lambda account: account.eventtype_set
        ),
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.COUNT],
        id_label_resolver_cb=get_resolve_column_id_cb(get_event_type_name_from_id),
    ),
    'timestamp_in_seconds': AnnotatedColumn(
        name='timestamp_in_seconds',
        annotation_relation=TruncSecond('timestamp'),
        type=LiteralType.TIMESTAMP,
        display_name='Timestamp (Seconds)',
        is_groupable=False,
        is_filterable=True,
        is_orderable=True,
        aggregation_functions=[AggregationFunction.MIN, AggregationFunction.MAX],
    ),
    'timestamp': Column(
        name='timestamp',
        type=LiteralType.TIMESTAMP,
        display_name='Timestamp',
        is_groupable=False,
        is_orderable=True,
        is_filterable=False,
        aggregation_functions=[AggregationFunction.MIN, AggregationFunction.MAX],
    ),
    'monitor_transaction': AnnotatedColumn(
        name='monitor_transaction',
        display_name='Monitor Transaction',
        type=LiteralType.STRING,
        annotation_relation=ArrayAgg(
            'monitortransactioneventmapping__monitor_transaction__transaction',
            default=Value([])
        ),
        token_filter_op=LiteralArrayColumnTokenFilterOp(),
        is_groupable=False,
        is_filterable=True,
        is_orderable=False,
    ),
    'event_attribute': AttributeColumn(
        name='event_attribute',
        annotation_relation=F('processed_kvs'),
        display_name='Event Attribute',
        attribute_options_cb=get_event_attribute_options,
        attribute_field='processed_kvs',
        is_filterable=True
    )
}

events_clickhouse_columns = {
    'event_type_id': Column(
        name='event_type_id',
        display_name='Event Type',
        type=LiteralType.ID,
        id_options_cb=get_id_option_cb(
            lambda account: account.eventtype_set
        ),
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.COUNT],
        id_label_resolver_cb=get_resolve_column_id_cb(get_event_type_name_from_id),
    ),
    'timestamp_in_seconds': AnnotatedColumn(
        name='timestamp_in_seconds',
        annotation_relation=TruncSecond('timestamp'),
        type=LiteralType.TIMESTAMP,
        display_name='Timestamp (Seconds)',
        is_groupable=False,
        is_orderable=True,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.MIN, AggregationFunction.MAX],
    ),
    'timestamp': Column(
        name='timestamp',
        type=LiteralType.TIMESTAMP,
        display_name='Timestamp',
        is_groupable=False,
        is_orderable=True,
        is_filterable=False,
        aggregation_functions=[AggregationFunction.MIN, AggregationFunction.MAX],
    ),
    'event_attribute': AttributeColumn(
        name='event_attribute',
        annotation_relation=F('processed_kvs'),
        display_name='Event Attribute',
        attribute_options_cb=get_event_attribute_options,
        attribute_field='processed_kvs',
        is_filterable=True
    )
}

monitor_transaction_columns = {
    'monitor_id': Column(
        name='monitor_id',
        type=LiteralType.ID,
        display_name='Monitor',
        id_options_cb=get_id_option_cb(
            lambda account: account.monitor_set.exclude(is_active=False)
        ),
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.COUNT],
        id_label_resolver_cb=get_resolve_column_id_cb(get_monitor_name_from_id),
    ),
    'transaction': Column(
        name='transaction',
        type=LiteralType.STRING,
        display_name='Transaction Value',
        is_groupable=False,
        is_orderable=False,
        is_filterable=True,
    ),
    'type': Column(
        name='type',
        type=LiteralType.ID,
        display_name='Transaction Status',
        id_options_cb=transaction_status_options_cb,
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.COUNT, AggregationFunction.COUNT_DISTINCT],
        id_label_resolver_cb=resolve_transaction_status_options,
    ),
    'transaction_time': AnnotatedColumn(
        name='transaction_time',
        annotation_relation=Cast(
            KeyTextTransform("transaction_time", "monitortransactionstats__stats"), models.FloatField()
        ),
        type=LiteralType.DOUBLE,
        display_name='Transaction Time',
        is_groupable=False,
        is_orderable=True,
        is_filterable=True,
        aggregation_functions=literal_type_aggregation_functions(LiteralType.DOUBLE),
    ),
    'created_at': Column(
        name='created_at',
        type=LiteralType.TIMESTAMP,
        display_name='Created At',
        is_groupable=False,
        is_orderable=True,
        is_filterable=False,
        aggregation_functions=[AggregationFunction.MIN, AggregationFunction.MAX],
    ),
    'has_alerts': AnnotatedColumn(
        name='has_alerts',
        annotation_relation=Exists(
            AlertMonitorTransactionMapping.objects.filter(
                monitor_transaction=OuterRef('pk')).filter(
                created_at__gte=OuterRef('created_at'))
        ),
        type=LiteralType.BOOLEAN,
        display_name='Alerted',
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=literal_type_aggregation_functions(LiteralType.BOOLEAN),
    ),
    'primary_event_attribute': AttributeColumn(
        name='primary_event_attribute',
        annotation_relation=Subquery(
            MonitorTransactionEventMapping.objects.filter(
                monitor_transaction=OuterRef("pk")).filter(
                event__event_type=OuterRef(
                    "monitor__primary_key__event_type__id")).values(
                'event__processed_kvs').order_by(
                'event__timestamp')[:1]
        ),
        display_name='Primary Event',
        attribute_options_cb=get_monitor_attribute_options_cb(key='primary_key'),
        is_filterable=True
    ),
    'secondary_event_attribute': AttributeColumn(
        name='secondary_event_attribute',
        annotation_relation=Subquery(
            MonitorTransactionEventMapping.objects.filter(
                monitor_transaction=OuterRef("pk")).filter(
                event__event_type=OuterRef(
                    "monitor__secondary_key__event_type")).values(
                'event__processed_kvs').order_by(
                'event__timestamp')[:1]
        ),
        display_name='Secondary Event',
        attribute_options_cb=get_monitor_attribute_options_cb(key='secondary_key'),
        is_filterable=True
    ),
    'free_attribute_search_column': AttributeColumnV2(
        name='free_attribute_search_column',
        general_annotation_relation="Subquery(MonitorTransactionEventMapping.objects.filter(monitor_transaction=OuterRef('pk')).filter(event__event_type=OuterRef('{}')).values('event__processed_kvs').order_by('event__timestamp')[:1])",
        display_name='Attribute Search',
        associated_model_name='MonitorTransactionEventMapping',
        associated_model=MonitorTransactionEventMapping,
        attribute_options_cb_v2=get_monitor_attribute_options_v2,
        is_filterable=True
    )
}

entity_instance_columns = {
    'entity_id': Column(
        name='entity_id',
        type=LiteralType.ID,
        display_name='Entity',
        id_options_cb=get_id_option_cb(
            lambda account: account.entity_set.exclude(is_active=False)
        ),
        is_groupable=True,
        is_orderable=False,
        is_filterable=True,
        aggregation_functions=[AggregationFunction.COUNT],
        id_label_resolver_cb=get_resolve_column_id_cb(get_entity_name_from_id),
    ),
    'instance': Column(
        name='instance',
        type=LiteralType.STRING,
        display_name='Entity Instance Value',
        is_groupable=False,
        is_orderable=False,
        is_filterable=True,
    ),
    'has_alerts': AnnotatedColumn(
        name='has_alerts',
        annotation_relation=Exists(
            AlertEntityInstanceMapping.objects.filter(
                entity_instance=OuterRef('pk')).filter(
                created_at__gte=OuterRef('created_at'))
        ),
        type=LiteralType.BOOLEAN,
        display_name='Alerted',
        is_groupable=True,
        is_orderable=False,
        aggregation_functions=literal_type_aggregation_functions(LiteralType.BOOLEAN),
        is_filterable=True,
    ),
    'free_attribute_search_column': AttributeColumnV2(
        name='free_attribute_search_column',
        general_annotation_relation="Subquery(EntityInstanceEventMapping.objects.filter(entity_instance=OuterRef('pk')).filter(event__event_type_id={}).values('event_processed_kvs').order_by('event_timestamp')[:1])",
        display_name='Attribute Search',
        associated_model_name='EntityInstanceEventMapping',
        associated_model=EntityInstanceEventMapping,
        attribute_options_cb_v2=get_entity_attribute_options_v2,
        is_filterable=True
    )
}

class ColumnOptions:
    def __init__(self, columns: Dict):
        self._columns = columns

    def options(self, account, obj=None):
        column_options = []
        attribute_options = []
        for column_name, column in self._columns.items():
            if column.is_filterable:
                if isinstance(column, Column):
                    column_options.append(column.get_options(account, obj))
                elif isinstance(column, AttributeColumn):
                    attribute_options.extend(column.get_options(account, obj))

        return column_options, attribute_options

    def options_v2(self, account, obj=None):
        column_options = []
        attribute_options_v2 = []
        for column_name, column in self._columns.items():
            if column.is_filterable:
                if isinstance(column, Column):
                    column_options.append(column.get_options(account, obj))
                elif isinstance(column, AttributeColumnV2):
                    attribute_options_v2.extend(column.get_options(account, obj))

        return column_options, attribute_options_v2


import numpy as np
import torch
from PIL import Image
import glob

import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor

import transforms as T
from torchvision import transforms as TT

import random
import cv2

class BubbleDataset(object):
    def __init__(self, root, transforms):
        self.root = root
        self.transforms = transforms
        self.imgs = list(sorted(glob.glob(root + "/Images/*.png")))
        self.masks = list(sorted(glob.glob(root + "/Masks/*.txt")))
        self.bbs = list(sorted(glob.glob(root + "/BoundingBoxes/*.txt")))
        self.labels = list(sorted(glob.glob(root + "/Labels/*.txt")))

    def __getitem__(self, idx):
        # load images and masks
        img_path = self.imgs[idx]
        mask_path = self.masks[idx]
        bbs_path = self.bbs[idx]
        label_path = self.labels[idx]

        #print(img_path)
        img = Image.open(img_path).convert("RGB")
        img_size = (img.width, img.height)

        labels: [str] = []
        with open(label_path) as f:
            for i, line in enumerate(f):
                labels.append(line.strip())
        num_objs = len(labels)

        boxes: [[int]] = []
        with open(bbs_path) as f:
            for i, line in enumerate(f):
                spline = line.split('\t')
                spline.pop()
                for s in spline:
                    if s == '':
                        print(bla)
                spline = [int(s) for s in spline]
                boxes.append(spline)

        masks = np.zeros((num_objs,) + (img.height, img.width))
        with open(mask_path) as f:
            for i, line in enumerate(f):
                spline = line.split('\t')
                spline.pop()
                spline = [int(s) for s in spline]
                mask = np.zeros(img_size)
                rmask = np.ravel(mask)
                rmask[spline] = 1
                mask = np.reshape(rmask, img_size)
                mask = np.swapaxes(mask, 0, 1)

                masks[i, :, :] = mask

                # Test if masks and images align
                #rgb_mask = random_color_masks(mask)
                #cv2.imwrite('test/Mask' + f"{i:06d}.jpg", rgb_mask)
                #cv2.imshow('', rgb_mask)
                #cv2.waitKey(0)

        # Test all masks
        # np_img = np.array(img)
        # for i in range(num_objs):
        #     rgb_mask = random_color_masks(np.array(masks[i, :, :]))
        #     np_img = cv2.addWeighted(np_img, 1, rgb_mask, 0.5, 0)
        #cv2.imwrite('test/' + f"{idx:06d}.jpg", np_img)

        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        labels = torch.ones((num_objs,), dtype=torch.int64)
        masks = torch.as_tensor(masks, dtype=torch.uint8)

        image_id = torch.tensor([idx])
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        # suppose all instances are not crowd
        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)

        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["masks"] = masks
        target["image_id"] = image_id
        target["area"] = area
        target["iscrowd"] = iscrowd

        if self.transforms is not None:
            img, target = self.transforms(img, target)

        return img, target

    def __len__(self):
        return len(self.imgs)

def get_model_instance_segmentation(num_classes):
    # load an instance segmentation model pre-trained pre-trained on COCO
    model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True, box_detections_per_img=500)

    # get number of input features for the classifier
    in_features = model.roi_heads.box_predictor.cls_score.in_features
    # replace the pre-trained head with a new one
    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)

    # now get the number of input features for the mask classifier
    in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels
    hidden_layer = 256
    # and replace the mask predictor with a new one
    model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask,
                                                       hidden_layer,
                                                       num_classes)

    return model

def get_transform(train):
    transforms = []
    transforms.append(T.ToTensor())
    if train:
        transforms.append(T.RandomHorizontalFlip(0.5))
    return T.Compose(transforms)

BUBBLE_CATEGORY_NAMES = ['__background__', 'bubble']

def get_prediction(img_path, model, device, threshold=0.7):
    img = Image.open(img_path)
    transform = TT.ToTensor()
    img = transform(img)
    img = img.to(device)
    pred = model([img])
    pred_score = list(pred[0]['scores'].cpu().detach().numpy())
    pred_t = [pred_score.index(x) for x in pred_score if x > threshold][-1]
    masks = (pred[0]['masks'] > 0.5).squeeze().detach().cpu().numpy()
    pred_class = [BUBBLE_CATEGORY_NAMES[i] for i in list(pred[0]['labels'].cpu().numpy())]
    pred_boxes = [[(int(i[0]), int(i[1])), (int(i[2]), int(i[3]))] for i in
                  list(pred[0]['boxes'].cpu().detach().numpy())]
    pred_scores = pred_score[:pred_t + 1]
    masks = masks[:pred_t + 1]
    pred_boxes = pred_boxes[:pred_t + 1]
    pred_class = pred_class[:pred_t + 1]
    return masks, pred_boxes, pred_class, pred_scores

def random_color_masks(image, single_color=False):
    colors = [[0, 255, 0], [0, 0, 255], [255, 0, 0], [0, 255, 255], [255, 255, 0], [255, 0, 255], [80, 70, 180],
              [250, 80, 190], [245, 145, 50], [70, 150, 250], [50, 190, 190]]
    r = np.zeros_like(image).astype(np.uint8)
    g = np.zeros_like(image).astype(np.uint8)
    b = np.zeros_like(image).astype(np.uint8)
    if single_color:
        r[image == 1], g[image == 1], b[image == 1] = colors[8]
    else:
        r[image == 1], g[image == 1], b[image == 1] = colors[random.randrange(0, 10)]

    colored_mask: np.stack = np.stack([r, g, b], axis=2)
    return colored_mask

def instance_segmentation(img_path, model, device, threshold=0.7, rect_th=1, text_size=1, text_th=2):
    masks, boxes, pred_cls, pred_scores = get_prediction(img_path, model, device, threshold=threshold)
    img = cv2.imread(img_path)
    for i in range(len(masks)):
        rgb_mask = random_color_masks(masks[i], single_color=False)
        img = cv2.addWeighted(img, 1, rgb_mask, 0.5, 0)
        gray = cv2.cvtColor(rgb_mask, cv2.COLOR_BGR2GRAY)
        cv2.rectangle(img, boxes[i][0], boxes[i][1], color=(0, 0, 0), thickness=rect_th)
    return img, pred_cls, pred_scores, masks


from datetime import datetime
from typing import Optional

from fastapi import Depends, Request, Response
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import update

from app.api.api_v1 import api_router_v1
from app.api.rest_util import get_failed_response
from app.database import get_db
from app.models import Guild, User
from app.models.message import GuildMessage
from app.sockets.sockets import sio
from app.util.util import check_token, get_auth_token

class SendMessageGuildRequest(BaseModel):
    guild_id: int
    message: str

@api_router_v1.post("/send/message/guild", status_code=200)
async def send_guild_message(
    send_message_guild_request: SendMessageGuildRequest,
    request: Request,
    response: Response,
    db: AsyncSession = Depends(get_db),
) -> dict:
    auth_token = get_auth_token(request.headers.get("Authorization"))
    if auth_token == "":
        return get_failed_response("an error occurred", response)

    user_send: Optional[User] = await check_token(db, auth_token)
    if not user_send:
        return get_failed_response("an error occurred", response)

    message_body = send_message_guild_request.message
    guild_id = send_message_guild_request.guild_id

    update_guild_members = (
        update(Guild)
        .values(unread_messages=Guild.unread_messages + 1)
        .where(Guild.guild_id == guild_id)
        .where(Guild.accepted == True)
    )
    await db.execute(update_guild_members)

    now = datetime.utcnow()

    guild_room = f"guild_{guild_id}"
    print(f"sending a guild message to room {guild_room}")
    socket_response = {
        "sender_name": user_send.username,
        "sender_id": user_send.id,
        "message": message_body,
        "timestamp": now.strftime("%Y-%m-%dT%H:%M:%S.%f"),
    }

    await sio.emit(
        "send_message_guild",
        socket_response,
        room=guild_room,
    )

    new_guild_message = GuildMessage(
        body=message_body,
        guild_id=guild_id,
        sender_name=user_send.username,
        sender_id=user_send.id,
        timestamp=now,
    )

    db.add(new_guild_message)
    await db.commit()

    return {
        "result": True,
    }


#!/usr/bin/env python3
"""This module contains the class RNNCell"""
import numpy as np

class RNNCell:
    """represents a cell of a simple RNN"""

    def __init__(self, i, h, o):
        """Class constructor

        Args:
        - i is the dimensionality of the data
        - h is the dimensionality of the hidden state
        - o is the dimensionality of the outputs

        Creates the public instance attributes Wh, Wy, bh, by
        that represent the weights and biases of the cell
        """

        self.Wh = np.random.normal(size=(i + h, h))
        self.Wy = np.random.normal(size=(h, o))

        self.bh = np.zeros((1, h))
        self.by = np.zeros((1, o))

    def forward(self, h_prev, x_t):
        """performs forward propagation for one time step

        Args:
        - x_t is a numpy.ndarray of shape (m, i) that contains the data input
          for the cell
        - h_prev is a numpy.ndarray of shape (m, h) containing the previous
          hidden state

        Returns: h_next, y
        - h_next is the next hidden state
        - y is the output of the cell
        """
        def softmax(z):
            return np.exp(z) / np.sum(np.exp(z), axis=1, keepdims=True)

        h_next = np.tanh(np.matmul(np.concatenate((h_prev, x_t), axis=1),
                         self.Wh) +
                         self.bh)

        y = softmax(np.matmul(h_next, self.Wy) + self.by)

        return h_next, y


from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_POST
from shop.models import Product, Category
from .cart import Cart
from django.core.cache import cache

# Create your views here.

def cart_detail(request):
    cart = Cart(request)
    quantity = len(request.session.get('cart'))
    categories = cache.get_or_set('categories', Category.objects.all())
    return render(request, 'cart/cart.html',
                  {'cart': cart,
                   'quantity': quantity,
                   'categories': categories
                   })

# отработает только при POST запросе
@require_POST
def cart_add(request, merchandise_id):
    cart = Cart(request)
    product = get_object_or_404(Product, merchandise_id=merchandise_id)
    cart.add(product=product)
    # перенаправляем на предыдущюю страничку
    # коряво как я понял но пока так )))
    referer = request.META.get('HTTP_REFERER', None)
    if referer:
        return HttpResponseRedirect(referer)
    else:
        return redirect('index')

def cart_remove(request, merchandise_id):
    cart = Cart(request)
    product = get_object_or_404(Product, merchandise_id=merchandise_id)
    cart.remove(product)
    return redirect('cart:main')


from pathlib import Path

import pytest

from lXtractor.core import GenericStructure
from lXtractor.core.exceptions import FormatError
from lXtractor.core.pocket import Pocket

DATA = Path(__file__).parent / "data"

@pytest.mark.parametrize(
    "path,definition,is_valid,mapping,expected",
    [
        (
            DATA / "4hvd.mmtf.gz",
            "c:853:CB == 1 & daa:903,904,905:CA <= 6",
            True,
            None,
            {("933", True), ("PHU", False)},
        ),
        (
            DATA / "4hvd.mmtf.gz",
            "daa:1:any < 20 | da:2:CD < 9",
            True,
            {1: 1038, 2: 871},
            {("933", True), ("PHU", True)},
        ),
        (
            DATA / "4hvd.mmtf.gz",
            "1:any < 20 | da:2:CD < 9",
            False,
            {1: 1038, 2: 871},
            {("933", True), ("PHU", True)},
        ),
(
            DATA / "4hvd.mmtf.gz",
            "cs:904,905,906:any >= 4",
            True,
            None,
            {("933", False), ("PHU", False)},
        ),
    ],
)
def test_pocket(path, definition, is_valid, mapping, expected):
    s = GenericStructure.read(path)
    p = Pocket(definition)
    if is_valid:
        res = {(lig.res_name, p.is_connected(lig)) for lig in s.ligands}
        assert res == expected
    else:
        with pytest.raises(FormatError):
            p.is_connected(s.ligands[0])


#!/bin/env python3
"""Less annoying fan, linear fan scaling.

MATCH_SENSORS: What sensors to consider when evaluating temperatures, the max
    temp sampled from these is used.

MAX_TEMP: Temps above this transition fan-speed to max.

MIN_TEMP: Temps below this transition fan-speed to 0.

 - Temps between MIN_TEMP and MAX_TEMP will transition between MIN_ACTIVE_SPEED
   and MAX_ACTIVE_SPEED linearly.

MIN_ACTIVE_SPEED: The lower limit for the fan speed if the temp is above
    MIN_TEMP.

MAX_ACTIVE_SPEED: The upper limit for the fan speed, 184 is 100% fan, do not
    exceed 184.

UP_SLEEP: How long to sleep between iterations when transitioning fan speed up.

DOWN_SLEEP: How long to sleep between iterations when transitioning the fan
    speed down.

SPEED_UP_STEP: How big a up step in fan speed is.
SPEED_DOWN_STEP: How big a down step in fan speed is.
"""
import time

import sensors

from fan_control import fan_control

MATCH_SENSORS = {
    "k10temp-pci-00c3": {"match": ["Tctl"], "bias": 1.0},
    "nvmi-pci-0200": {"match": ["Composite"], "bias": 1.0},
    "iwlwifi_1-virtual-0": {"match": ["temp1"], "bias": 0.75},
    "amdgpu-pci-7300": {"match": ["edge"], "bias": 1.0},
}

MIN_TEMP = 50
MAX_TEMP = 75

MIN_ACTIVE_SPEED = 40
MAX_ACTIVE_SPEED = 184

UP_SLEEP = 0.5
DOWN_SLEEP = 1

SPEED_UP_STEP = 4
SPEED_DOWN_STEP = 4

def do_watch():
    speed = ((MAX_ACTIVE_SPEED - MIN_ACTIVE_SPEED) / 2) + MIN_ACTIVE_SPEED
    sensors.init()

    while True:
        try:
            temp = [0]

            for chip in sensors.iter_detected_chips():
                _chip = str(chip)
                if _chip in MATCH_SENSORS:
                    for feature in chip:
                        if feature.label in MATCH_SENSORS[_chip]["match"]:
                            temp.append(feature.get_value())
                            temp[-1] *= MATCH_SENSORS[_chip]["bias"]

            sensors.cleanup

        except Exception as ex:
            # in rare cases sensors fails to init
            print(str(ex))

        temp = max(temp)

        # get normalised scale temp from 0.0 to 1.0
        scale = max(0, temp - MIN_TEMP) / (MAX_TEMP - MIN_TEMP)
        scale = min(scale, 1.0)

        # target speed for scale
        if temp < MIN_TEMP:
            target_speed = 0
        else:
            target_speed = scale * MAX_ACTIVE_SPEED
            target_speed = max(target_speed, MIN_ACTIVE_SPEED)
            target_speed = int(target_speed)

        if speed < target_speed:
            new_speed = speed + SPEED_UP_STEP
            # avoid overshoot
            new_speed = min(new_speed, target_speed)
            time.sleep(UP_SLEEP)
        else:
            new_speed = speed - SPEED_DOWN_STEP
            # avoid undershoot
            new_speed = max(new_speed, target_speed)
            time.sleep(DOWN_SLEEP)

        new_speed = min(max(0, new_speed), MAX_ACTIVE_SPEED)

        if new_speed != speed:
            fan_control(new_speed)
            speed = new_speed

            print(f"{new_speed} -> {target_speed} @ {temp}")

try:
    do_watch()
finally:
    # Set auto fan on exit, eg:
    fan_control(-1)


from matplotlib import pyplot as plt
#define slices of pie chart these slices then will convert into percentage
slices=[7,2,2,13]
activities=["working","reading","playing","sleeping"]
clr=['c','m','r','g']
plt.pie(
    slices,
    labels=activities,
    colors=clr,
    startangle=90,
    #to display shadow od chart
    shadow=True,
    #which slice have to pop
    #simillar to cake slice
    #this will pop out 3rd sound
    explode=(0,0,0.1,0),
    #to display percentage number on each slice of pie chart
    autopct='%1.1f%%'
)

plt.title("pie chart")
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Nov 4, 2020

@author: Enx
"""

#%% Importing and Variable fixing

from well_plate_project.config import data_dir, reportings_dir

# Dataset paths
raw_data_dir = data_dir / 'raw'
interm_data_dir = raw_data = data_dir / 'intermediate'
describe_data_dir = reportings_dir / 'description'

# Use KMeans clustering algorithm from sklearn.cluster to cluster pixels in image
from sklearn.cluster import KMeans

import numpy as np
import cv2
import matplotlib.pyplot as plt

image_name = 'a2_a_cropped.jpg'

image_path = raw_data_dir / image_name
assert image_path.is_file()

#%% Import image

original_image = cv2.imread(str(image_path))

img=original_image.astype('uint8')

plot_img_4hist_rgb(original_image)

plot_img_4hist_rgb(img)

#%% Convert image
# convert our image from RGB Colours Space to HSV to work ahead.
img_rgb=cv2.cvtColor(original_image.astype('uint8'),cv2.COLOR_BGR2RGB)
plot_img_4hist_rgb(img_rgb)

img_hsv=cv2.cvtColor(original_image.astype('uint8'),cv2.COLOR_BGR2HSV)
plot_img_4hist_hsv(img_hsv)
#https://raspberrypi.stackexchange.com/questions/10588/hue-saturation-intensity-histogram-plot

img_lab=cv2.cvtColor(original_image.astype('uint8'),cv2.COLOR_BGR2LAB)
plot_img_4hist_rgb(img_lab)

#%% Reshaping

# For clustering the image using k-means, we first need to convert it into a 2-dimensional array
image_2D = img.reshape(img.shape[0]*img.shape[1], img.shape[2])
reshaped_image = np.float32(original_image.reshape(-1, 3))
reshaped_image_hsv = np.float32(img_hsv.reshape(-1, 3))
reshaped_image_lab = np.float32(img_lab.reshape(-1, img_lab.shape[2]))

#%% Clustering 1
K = 10
stopCriteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)

ret, labels, clusters = cv2.kmeans(reshaped_image, K, None, stopCriteria, 10, cv2.KMEANS_RANDOM_CENTERS)
clusters = np.uint8(clusters)

intermediateImage = clusters[labels.flatten()]
clusteredImage = intermediateImage.reshape((original_image.shape))

cv2.imwrite("clusteredImage.jpg", clusteredImage)

plot_img_4hist_rgb(clusteredImage)

#%% Clustering2
# tweak the cluster size and see what happens to the Output
kmeans = KMeans(n_clusters=5, random_state=0).fit(image_2D)
clustered = kmeans.cluster_centers_[kmeans.labels_]

# Reshape back the image from 2D to 3D image
clustered_3D = clustered.reshape(img.shape[0], img.shape[1], img.shape[2])
plt.imshow(clustered_3D)
plt.title('Clustered Image')
plt.show()

plot_img_4hist_rgb(clustered_3D)

#%% Remove 1 cluster from image and apply canny edge detection
removedCluster = 1

cannyImage = np.copy(original_image).reshape((-1, 3))
cannyImage[labels.flatten() == removedCluster] = [0, 0, 0]

cannyImage = cv2.Canny(cannyImage,100,200).reshape(original_image.shape)
cv2.imwrite("cannyImage.jpg", cannyImage)
plot_img_4hist_rgb(cannyImage)

#%% Finding contours using opencv

initialContoursImage = np.copy(cannyImage)
imgray = cv2.cvtColor(initialContoursImage, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(imgray, 50, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(initialContoursImage, contours, -1, (0,0,255), cv2.CHAIN_APPROX_SIMPLE)
cv2.imwrite("initialContoursImage.jpg", initialContoursImage)

plot_img_4hist_rgb(initialContoursImage)

#DBscan
#https://stackoverflow.com/questions/40142835/image-not-segmenting-properly-using-dbscan
#https://core.ac.uk/download/pdf/79492015.pdf

#https://github.com/s4lv4ti0n/clusteringAlgorithms

# %% Define functions

def plot_img_4hist_rgb(image_to_plot):
    # Calulate various hists

    plt.figure(figsize=(10,10))

    #plt.subplot(221), plt.imshow(image_to_plot, 'gray')
    plt.subplot(221), plt.imshow(image_to_plot)

    plt.subplot(223), plt.hist(image_to_plot.ravel(),256,[0,256])
    plt.xlim([0,256])

    color = ('b','g','r')
    for i,col in enumerate(color):
        histr = cv2.calcHist([image_to_plot],[i],None,[256],[0,256])
        plt.subplot(222), plt.plot(histr,color = col)
        plt.yscale('log')
        plt.xlim([0,256])
        plt.subplot(224), plt.plot(histr,color = col)
        plt.xlim([0,256])

    plt.show()
    plt.close()
    return

# %%
def plot_img_4hist_hsv(image_to_plot):
    # Calulate various hists

    plt.figure(figsize=(10,10))

    #plt.subplot(221), plt.imshow(image_to_plot, 'gray')
    plt.subplot(221), plt.imshow(image_to_plot)

    hist = cv2.calcHist( [image_to_plot], [0, 1], None, [180, 256], [0, 180, 0, 256] )
    plt.subplot(223), plt.plot(hist)
    plt.subplot(222), plt.imshow(hist, interpolation = 'nearest')

    plt.show()
    plt.close()
    return
# %%


def insertionSort(nums):
	for i in range(1,len(nums)):
		valueToInsert = nums[i]
		holePosition = i

		#do comparisons untill finding right position
		while holePosition > 0 and nums[holePosition-1] > valueToInsert:
			nums[holePosition] = nums[holePosition -1]
			holePosition = holePosition -1

		nums[holePosition] = valueToInsert #insert element in the position found above.

	return nums

print(insertionSort([14,33,27,10,35,19,42,44]))
print(insertionSort([14,33,270,101,35,19,42,44]))

#Find median in a streaming of data, i.e, you get one element at a time. Use insertion sort in O(n^2)
# worst case.
# http://mathworld.wolfram.com/StatisticalMedian.html
def medianFinder(nums,newel):
	#nums is the set of numbers already sorted
	#newel is the new element arriving from the stream
	nums = nums+[newel]
	nums = insertionSort(nums)
	n=len(nums)

	if n%2==1:
		median = nums[((n+1)//2)-1] # if length is odd, get middle element
	else:
		median = (nums[(n//2)-1] + nums[n//2])/2 #o.w, get average of two middle.

	return nums, median

print(medianFinder([1,2,30,40],3))
print(medianFinder([1,2,30,40,20],9))
print(medianFinder([1,2,30,40,1,1,2,4,32],31))
print(medianFinder([1,2,30,40,2,1,67,12],5))


from django.db import models
from mainapp.managers.news_manager import NewsManager
from mainapp.managers.courses_manager import CoursesManager

class News(models.Model):  # Создание моделей для News
    objects = NewsManager()
    title = models.CharField(
        max_length=256,
        verbose_name="Title",
    )
    preamble = models.CharField(
        max_length=1024,
        blank=True,
        null=True,
        verbose_name="Preamble",
    )
    body = models.TextField(
        blank=True,
        null=True,
        verbose_name="Body",
    )
    body_as_markdown = models.BooleanField(
        default=False,
        verbose_name="As markdown",
    )
    created = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Created",
        editable=False,
    )
    updated = models.DateTimeField(
        auto_now=True,
        verbose_name="Edited",
        editable=False,
    )
    deleted = models.BooleanField(default=False)

    def __str__(self) -> str:
        return f"{self.pk} {self.title}"

    def delete(self, *args):
        self.deleted = True
        self.save()

class Courses(models.Model):  # Создание моделей для Courses
    objects = CoursesManager()
    name = models.CharField(
        max_length=256,
        verbose_name="Name",
    )
    description = models.TextField(
        verbose_name="Description",
        blank=True,
        null=True,
    )
    description_as_markdown = models.BooleanField(
        verbose_name="As markdown",
        default=False,
    )
    cost = models.DecimalField(
        max_digits=8,
        decimal_places=2,
        verbose_name="Cost",
        default=0,
    )
    cover = models.CharField(
        max_length=25,
        default="no_image.svg",
        verbose_name="Cover",
    )
    created = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Created",
    )
    updated = models.DateTimeField(
        auto_now=True,
        verbose_name="Edited",
    )
    deleted = models.BooleanField(default=False)

    def __str__(self) -> str:
        return f"{self.pk} {self.name}"

    def delete(self, *args):
        self.deleted = True
        self.save()

class Lesson(models.Model):  # Создание моделей для Lessons
    course = models.ForeignKey(
        Courses,
        on_delete=models.CASCADE,
    )
    num = models.PositiveIntegerField(
        verbose_name="Lesson number",
    )
    title = models.CharField(
        max_length=256,
        verbose_name="Name",
    )
    description = models.TextField(
        verbose_name="Description",
        blank=True,
        null=True,
    )
    description_as_markdown = models.BooleanField(
        verbose_name="As markdown",
        default=False,
    )
    created = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Created",
        editable=False,
    )
    updated = models.DateTimeField(
        auto_now=True,
        verbose_name="Edited",
        editable=False,
    )
    deleted = models.BooleanField(default=False)

    def __str__(self) -> str:
        return f"{self.course.name} | {self.num} | {self.title}"

    def delete(self, *args):
        self.deleted = True
        self.save()

    class Meta:  # Создание модели Meta для Lesson
        ordering = ("course", "num")

class CourseTeachers(models.Model):  # Создание моделей для Teacher
    course = models.ManyToManyField(Courses)
    name_first = models.CharField(
        max_length=128,
        verbose_name="Name",
    )
    name_second = models.CharField(
        max_length=128,
        verbose_name="Surname",
    )
    day_birth = models.DateField(
        verbose_name="Birth date",
    )
    deleted = models.BooleanField(default=False)

    def __str__(self) -> str:
        return "{0:0>3} {1} {2}".format(
            self.pk,
            self.name_second,
            self.name_first,
        )

    def delete(self, *args):
        self.deleted = True
        self.save()


import serial
import threading
import time
port="/dev/ttyUSB0"#Linux
baudrate=115200
tty=serial.Serial(port=port,baudrate=baudrate,timeout=1)

tty.close()
tty.open()
tty.write("julien\n".encode('utf-8'))

read=tty.readline().decode()#
#read=tty.read(6).decode()
tty.flush()#vide le cache
tty.close()

print(read)


from typing import TYPE_CHECKING, Generator

import pygame
from itblib.Vec import IVector2
from itblib.globals.Constants import STANDARD_UNIT_SIZE
from itblib.gridelements.status_effect import (StatusEffectBase,
                                               StatusEffectBurrowed)
from itblib.gridelements.units.IUnitObserver import IUnitObserver
from itblib.net.NetEvents import NetEvents
from itblib.ui.widgets.game_widget import HealthBar, OwnerColorRhombus
from itblib.ui.IDisplayable import IDisplayable
from itblib.ui.TextureManager import Textures

from .GridElementUI import GridElementUI

if TYPE_CHECKING:
    from itblib.gridelements.units.UnitBase import UnitBase

class UnitBaseUI(GridElementUI, IDisplayable, IUnitObserver):
    def __init__(self, unit:"UnitBase", direction="SW", framespeed=.5):
        GridElementUI.__init__(self, parentelement=unit, direction=direction, framespeed=framespeed)
        self._parentelement:"UnitBase"
        self.fromscreenpos = None
        self.toscreenpos = None
        self.movementtime = 0.0
        self.speed = 0.0
        self.old_frame = self._framenumber
        self.healthbar = HealthBar(self._parentelement)
        self.healthbar.parent = self
        barwidth = self.healthbar.get_size()[0]
        offset = IVector2(int((STANDARD_UNIT_SIZE[0]-barwidth)/2), int(STANDARD_UNIT_SIZE[1]*.7))
        self.healthbar.position = offset
        self.owner_color_rhombus = None
        if NetEvents.session:
            self.owner_color_rhombus = OwnerColorRhombus(NetEvents.session._players[self._parentelement.ownerid].color)
            self.owner_color_rhombus.attach_to_unit(self)
        self._parentelement.observer = self

    def set_interp_movement(self, fromscreenpos: IVector2, toscreenpos: IVector2, speed: float):
        self.fromscreenpos = fromscreenpos
        self.toscreenpos = toscreenpos
        self.speed = speed
        self.movementtime = self._parentelement.age

    def update(self, delta_time: float):
        super().tick(delta_time)
        if self.fromscreenpos and self.toscreenpos:
            diff = self.toscreenpos - self.fromscreenpos
            time_ratio = min((self._parentelement.age - self.movementtime) / self.speed, 1)
            interp_screenpos = self.fromscreenpos + time_ratio * diff
            self.tfc.relative_position = interp_screenpos
            if time_ratio + 0e-4 >= 1:
                self.set_interp_movement(None, None, 0.0)
                self.movementtime = 0.0

    def get_display_name(self) -> str:
        return "UnitBaseUI"

    def get_display_description(self) -> str:
        return "Another long description ------ weee------"

    def get_blits(self) -> "Generator[tuple[pygame.Surface, pygame.Rect, pygame.Rect]]":
        if self.owner_color_rhombus:
            yield from self.owner_color_rhombus.get_blits()
        yield from GridElementUI.get_blits(self)
        yield from self.healthbar.get_blits()

    def on_add_status_effect(self, added_effect: "StatusEffectBase"):
        pass

    def on_remove_status_effect(self, removed_effect: "StatusEffectBase"):
        pass

    def on_update_position(self, new_pos: tuple[int, int]):
        pass

class UnitKnightUI(UnitBaseUI):
    def __init__(self, unit: "UnitBase"):
        super().__init__(unit, framespeed=.1)

    def get_display_name(self) -> str:
        return "Knight"

class UnitBurrowerUI(UnitBaseUI):
    def get_display_name(self) -> str:
        return "Burrower"

    def on_add_status_effect(self, added_effect: "StatusEffectBase"):
        if isinstance(added_effect, StatusEffectBurrowed):
            self.set_textures(Textures.get_spritesheet("BurrowerSWBurrowed"))
            self.frametime = .15

    def on_remove_status_effect(self, removed_effect: "StatusEffectBase"):
        if isinstance(removed_effect, StatusEffectBurrowed):
            self.set_textures(Textures.get_spritesheet("BurrowerSWIdle"))
            self.frametime = .5

class UnitChipmonkUI(UnitBaseUI):
    def __init__(self, unit: "UnitBase", direction="SW", framespeed=0.5):
        super().__init__(unit, direction, framespeed)
        self.moving = False

    def get_display_name(self) -> str:
        return "Chipmonk"

    def set_interp_movement(self, fromscreenpos: "tuple[int,int]", toscreenpos: "tuple[int,int]", speed: float):
        super().set_interp_movement(fromscreenpos, toscreenpos, speed)
        new_moving = bool(fromscreenpos) and bool(toscreenpos)
        print(new_moving)
        if not self.moving and new_moving:
            self.set_textures(Textures.get_spritesheet("ChipmonkSEMove"))
        elif self.moving and not new_moving:
            self.set_textures(Textures.get_spritesheet("ChipmonkSWIdle"))
        self.moving = new_moving


"""Faça um program que leia um número inteiro e diga se ele é ou não
um número primo"""

valor = int(input("Digite um número: "))
primo = 0
for c in range(1, valor + 1):
    if valor % c == 0:
        primo = primo + 1
if primo == 2:
    print('É primo')
else:
    print('Não é primo')

Mundo 02 - Estruturas de Controle/Atividade 052 - Estrutura For.py


# boj 17242 KaKa & Bebe
import heapq

n, m = map(int, input().split())
INF = (1e20)
graph = [[] for _ in range(n)]
distance = [INF] * n

for _ in range(m) :
    u, v, c1, c2 = map(int, input().split())
    if c1 > 1000 or c2 > 1000 :
        continue
    graph[u].append((v, c1, c2))
    graph[v].append((u, c1, c2))

def dijkstra(start) :
    hq = []
    heapq.heappush(hq, (0, 0, start))
    distance[start] = 0
    dict = {i : [] for i in range(n)}
    while hq :
        kaka, bebe , now = heapq.heappop(hq)
        if (kaka, bebe) in dict[now] :
            continue
        dict[now].append((kaka, bebe))
        for i in graph[now] :
            cost_1 = kaka + i[1]
            cost_2 = bebe + i[2]
            new_stress = cost_1 * cost_2
            if cost_1 > 1000 or cost_2 > 1000 :
                continue
            if distance[i[0]] >= new_stress :
                distance[i[0]] = new_stress
                heapq.heappush(hq, (cost_1, cost_2, i[0]))

dijkstra(0)
if distance[n-1] == INF :
    print(-1)
else :
    print(distance[n-1])


from GA.ga_pid_const import MIN_POINTS_NUMBER
from math import pow

# This file contains modelisation information

# Modelisation constants

POINTS_NUMBER = MIN_POINTS_NUMBER + 2
DELTA_T = 0.1

# Transfer function constants

# M(p)

TAU_E = 0.02
TAU = 0.0022
K_0 = 0.042

# R(p)

J = 0.001
Wheel_Radius = 0.03
Mass = 5.0
K_1 = 0.000586


#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

from math import log

#import corpus
from corpus import getTextFromFile, makeFrequencyProfile, tokenize, relativizeFP

mydict = makeFrequencyProfile( tokenize( getTextFromFile("pg873.txt") ) )
relativizeFP(mydict)

#for key in mydict:
#   print(key, mydict[key], sep="\t")

mysportsdict = makeFrequencyProfile( tokenize( getTextFromFile("sports.txt") ) )
relativizeFP(mysportsdict)

unktokens = tokenize("""
The young King was eating pomegranates and talking about his soul and other emotional issues.
""")

probpomeg = 0.0
probsports = 0.0
for token in unktokens:
   probpomeg += log(mydict.get(token, 0.00000000000001))
   probsports += log(mysportsdict.get(token, 0.00000000000001))

if probpomeg > probsports:
   print("This text is probably House of Pomeg.")
else:
   print("This text is probably a sports article.")


import pandas as pd
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
import re
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--train", help="Chemin du fichier train.csv", required=True)
parser.add_argument("--test", help="Chemin du fichier test.csv", required=True)
parser.add_argument("--output", help="Chemin du fichier de soumission au format csv.", required=True)

args = parser.parse_args()

# Preprocessing with custom transformer
class CustomTransformer(BaseEstimator, TransformerMixin):
    def __init__(self):
        super(CustomTransformer, self).__init__()
        self.embarked_values = ["S", "C", "Q", "Unknown"]
        self.numerical_cols = ['Pclass', 'SibSp', 'Parch', 'Fare', 'Fare_Per_Person']

    def fit(self, data_x, data_y=None):
        return self

    def rename(self, x):
        if x in ["Capt.", "Col.", "Don.", "Dr.", "Jonkheer.", "Lady.", "Major.", "Rev.", "Sir.", "Countess."]:
            return "Aristocratic."
        if x in ["Ms.", "Mme."]:
            return "Mrs."
        if x == "Mlle.":
            return "Miss."
        return x

    def transform(self, data_x, data_y=None):
        dataset = data_x.copy()
        dataset['Family_Size'] = dataset['SibSp'] + dataset['Parch']
        dataset['Fare_Per_Person'] = dataset['Fare'] / (dataset['Family_Size'] + 1)
        dataset["Male"] = dataset["Sex"].map(lambda x: 1 if x == "male" else 0)
        dataset["Female"] = dataset["Sex"].map(lambda x: 1 if x == "female" else 0)
        dataset["Cabin"] = dataset["Cabin"].map(lambda x: 0 if x is np.nan else 1)
        dataset["Embarked_C"] = dataset["Embarked"].map(lambda x: 1 if x == "C" else 0)
        dataset["Embarked_Q"] = dataset["Embarked"].map(lambda x: 1 if x == "Q" else 0)
        dataset["Embarked_S"] = dataset["Embarked"].map(lambda x: 1 if x == "S" else 0)
        dataset["Embarked_Unknown"] = dataset["Embarked"].map(lambda x: 1 if x is np.nan else 0)
        dataset["Title"] = dataset["Name"].map(lambda x: re.findall(r"\w+\.", x)[0])
        dataset["Title"] = dataset["Title"].map(self.rename)

        for title in dataset.Title.unique().tolist():
            dataset.loc[(dataset.Title == title), 'Age'] = dataset['Age'].apply(
                lambda x: dataset.loc[(dataset.Title == title), 'Age'].median() if pd.isnull(x) else x)

        for columns in self.numerical_cols:
            dataset[columns] = dataset[columns].fillna(value=dataset[columns].median())

        dataset = dataset.drop(["Name", "Ticket", "PassengerId", "Embarked", "Sex", "Title"], axis=1)

        return dataset

def get_accuracy(data, model=RandomForestClassifier(random_state=0, n_estimators=200, max_depth=5)):
    """ Obtenir la précision du modèle (cross validation) """

    data_y = data.Survived
    data_x = data.drop(["Survived"], axis=1)

    # Evaluation with cross_val_score
    my_pipeline = Pipeline(steps=[('preprocessor', CustomTransformer()),
                                  ('model', model)])

    cv_score = cross_val_score(my_pipeline, data_x, data_y, cv=5, scoring="accuracy")

    return cv_score.mean()

def model_transformer_fit(data, model=RandomForestClassifier(random_state=0, n_estimators=200, max_depth=5)):
    """ Preparation des données d'entrainement, fit du transformer et du modèle """

    data_y = data.Survived
    data_x = data.drop(["Survived"], axis=1)
    custom_transformer = CustomTransformer()
    model.fit(custom_transformer.fit(data_x).transform(data_x), data_y)

    return model, custom_transformer

def predict(data, model, custom_transformer, output):
    """ Prediction sur les données de test et enregistrement dans un csv """

    data_prepared = custom_transformer.transform(data)

    test_predict = model.predict(data_prepared)

    temp_dict = {"PassengerId": data.PassengerId.tolist(), "Survived": test_predict.tolist()}

    submission = pd.DataFrame.from_dict(temp_dict)
    submission.Survived = submission.Survived.astype('int')

    submission.to_csv(output, index=False)

if __name__ == "__main__":

    train_data = pd.read_csv(args.train)
    test_data = pd.read_csv(args.test)

    model_to_used, transformer_to_used = model_transformer_fit(train_data)

    score = get_accuracy(train_data, model_to_used)
    print("Le score est de {:.3f}".format(score))

    predict(test_data, model_to_used, transformer_to_used, args.output)


import requests
import json

def user_stats(name):
    s = requests.Session()
    message_str = ""
    stats = {}

    for i in range(1,4):
        r = s.get("http://api.warface.ru/user/stat/", params={'name' : name, 'server' : i})
        r_j = json.loads(r.text)

        try:
            stats["clan_name"] = r_j["clan_name"]
        except:
            stats["clan_name"] = "Нет"

        try:
            if(r_j["message"] == "Пользователь не найден"):
                message_str = "Пользователь не найден"
            elif(r_j["message"] == "Персонаж неактивен"):
                message_str = "Персонаж неактивен"
                break
            elif(r_j["message"] == "Игрок скрыл свою статистику"):
                message_str = "Игрок скрыл свою статистику"
                break
            else:
                message_str = ""
                break
        except:
            stats["nickname"] = r_j["nickname"]

            stats["server"] = i
            stats["rank_id"] = r_j["rank_id"]

            stats["playtime_h"] = r_j["playtime_h"]
            stats["playtime_m"] = r_j["playtime_m"]

            stats["kills"] = r_j["kills"]
            stats["death"] = r_j["death"]
            stats["friendly_kills"] = r_j["friendly_kills"]
            stats["pvp"] = r_j["pvp"]
            stats["pvp_wins"] = r_j["pvp_wins"]
            stats["pvp_lost"] = r_j["pvp_lost"]
            stats["pvp_all"] = r_j["pvp_all"]

            stats["pve_all"] = r_j["pve_all"]
            stats["pve_friendly_kills"] = r_j["pve_friendly_kills"]
            stats["pve_kills"] = r_j["pve_kills"]
            stats["pve_death"] = r_j["pve_death"]
            stats["pve"] = r_j["pve"]
            stats["pve_wins"] = r_j["pve_wins"]
            stats["pve_lost"] = r_j["pve_lost"]

            stats["favoritPVP"] = r_j["favoritPVP"]
            stats["favoritPVE"] = r_j["favoritPVE"]

            message_str = ""
            break

    if message_str == "":
        return stats
    else:
        return message_str


from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib import messages
from django.contrib.auth import get_user_model
from dal import autocomplete
from django.contrib.auth.decorators import login_required, user_passes_test
from datetime import date

from profiles.models import User, Interests
from student.views import student_login_required
from teacher.views import teacher_login_required
from student.views import SkillsAutocomplete

from student.models import Student
from .forms import UserForm
from .forms import SearchForm

from internships.models import Internship, Application

@login_required
def index(request):
    # template = 'profiles/index.html'
    # return render(request, template, {})
    # if request.user.is_authenticated:
    return redirect('show-user', request.user.id)
    # return render(request, template, {})

def about(request):
    template = 'profiles/about.html'
    return render(request, template, {})

def edit_user(request):
    template = "edit/user.html"
    context = {}

    if request.method == "POST":
        form = UserForm(request.POST or None, request.FILES, instance=request.user)
    else:
        form = UserForm(instance=request.user)
    print(request.user.email, request.user.first_name)
    if request.method == "POST" and form.is_valid():
        form.save()
        messages.success(request, "Your data has been edited.")
    context["form"] = form
    print(form)
    return render(request, template, context)

class UsersAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return get_user_model().objects.none()

        qs = get_user_model().objects

        if self.q:
            qs = qs.filter(email__istartswith=self.q)

        return qs.all()

@login_required
def show_user(request, pk):
    u = get_object_or_404(get_user_model(), id=pk)
    # if u.is_teacher:
    #   context = dict(found_user=u, title="Teacher")
    #  return render(request, "teacher-inf.html", context)
    # else:
    context = dict(found_user=u, title="User")
    return render(request, "user.html", context)

def search(request):
    if request.method == 'POST':
        form = SearchForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)
            users = User.objects.all()
            if form.cleaned_data['current_study_year']:
                users = users.filter(
                    student__current_study_year__icontains=form.cleaned_data['current_study_year'])
            if form.cleaned_data['last_name']:
                users = users.filter(last_name__icontains=form.cleaned_data['last_name'])
            if form.cleaned_data['first_name']:
                users = users.filter(first_name__icontains=form.cleaned_data['first_name'])
            # advanced search
            if form.cleaned_data['hard_skills']:
                users = users.filter(student__hard_skills=form.cleaned_data['hard_skills'])
            if form.cleaned_data['prog_lang']:
                users = users.filter(student__programming_languages=form.cleaned_data['prog_lang'])
            if form.cleaned_data['fields_of_interests']:
                users = users.filter(fields_of_interests=form.cleaned_data['fields_of_interests'])

            return render(request, 'search.html', {'form': form, 'users': users})
    else:
        form = SearchForm()

    return render(request, 'search.html', {'form': form})

def show_internships(request):
    internships = Internship.objects.all()
    if request.user.is_teacher:
        archive = list()
        actual_interns = list()
        for i in internships:
            if i.deadline < date.today():
                archive.append(i)
            else:
                actual_interns.append(i)
        return render(request, "internships.html",
                      {'internships': actual_interns, 'archive': archive, 'user': request.user})
    elif request.user.is_student:
        my_apps = Application.objects.filter(applicant=request.user.student)

        # only available internships
        # available_interns = internships
        available_interns = [intern for intern in internships if intern.deadline > date.today()]
        my_interns = [app.internship for app in my_apps]
        available_interns = [intern for intern in available_interns if intern not in my_interns]

        # my internships with deadline overdue
        overdue_interns = list()
        for intern in my_interns:
            if intern.deadline < date.today():
                overdue_interns.append(intern)

        return render(request, "internships.html", {'internships': available_interns, 'my_internships': my_interns,
                                                    'overdue': overdue_interns})

class InterestsAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return Interests.objects.none()

        qs = Interests.objects.filter(interest_type="professional")

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs.all()

class HobbyAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return Interests.objects.none()

        qs = Interests.objects.filter(interest_type="hobby")

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs.all()


import base64
import hashlib
import hmac
import json
import re
import time

from os import environ
from urllib import parse, request

import arc.tables

SLACK_API_BASE_URL = 'https://slack.com/api/'
SLACK_OAUTH_ACCESS_TOKEN = environ['SLACK_OAUTH_ACCESS_TOKEN']
SLACK_SIGNING_SECRET = environ['SLACK_SIGNING_SECRET']

SPECIAL_KARMA = {
    -1: ':yoda: Fear is the path to the dark side. Fear leads to anger. Anger leads to hate. Hate leads to suffering. :darth_vader:',
    1: ':one: The journey of :1000: karma begins with one.',
    8: 'That\'s one byte of karma. Mazel tov!',
    20: 'Twenty karma! You\'re cooking with gas now.',
    42: 'Ah, the answer. But what is the question?',
    50: 'Look at you, you helpful person.',
    84: ':happymac: On January 24th Apple Computer will introduce Macintosh...',
    100: ':whoa_keanu: Welcome to the :100: club!',
    1000: ':1000: Lifer. You can check out anytime you want, but you can never leave.',
}

# https://api.slack.com/authentication/verifying-requests-from-slack#a_recipe_for_security
def validate_slack_request(headers, body):
    if 'x-slack-request-timestamp' not in headers or 'x-slack-signature' not in headers:
        return False
    timestamp = headers['x-slack-request-timestamp']
    if abs(time.time() - int(timestamp)) > 60 * 5:
        return False
    sig_basestring = 'v0:' + timestamp + ':' + body
    req_hash = 'v0=' + hmac.new(str.encode(
        SLACK_SIGNING_SECRET),
        str.encode(sig_basestring), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(req_hash, headers['x-slack-signature']):
        return False
    return True

# https://api.slack.com/web#basics
def _slack_api_call(url, data):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    data['token'] = SLACK_OAUTH_ACCESS_TOKEN
    data = parse.urlencode(data).encode('utf-8')
    slack_req = request.Request(
            url,
            data=data,
            method='POST',
            headers=headers,
    )
    return request.urlopen(slack_req).read()

def post_slack_message(channel, text):
    data = {
        'channel': channel,
        'text': text,
    }
    _slack_api_call('{}{}'.format(SLACK_API_BASE_URL, 'chat.postMessage'), data)

def get_slack_users_list(cursor=None):
    users = []
    data = {}
    if cursor:
        data['cursor'] = cursor
    res = json.loads(_slack_api_call('{}{}'.format(SLACK_API_BASE_URL, 'users.list'), data).decode('utf-8'))
    if res.get('members'):
        users += res['members']
    if res.get('response_metadata', {}).get('next_cursor', None):
        users += get_slack_users_list(res['response_metadata']['next_cursor'])
    return users

def is_slack_user_id(s):
    return re.match('<@((U|W)\w+)>', s)

def handler(req, context):
    body = req.get('body', '')
    if not body:
        body = '{}'
    if req.get('isBase64Encoded'):
        # decode but don't parse to json before validating the signature
        body = base64.b64decode(body).decode('utf-8')

    # validate signature
    if not validate_slack_request(req.get('headers'), body):
        return {'statusCode': 401}

    body = json.loads(body)

    # https://api.slack.com/events/url_verification
    if body and 'challenge' in body:
        return {
            'headers': {
                'cache-control': 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0',
                'content-type': 'text/json; charset=utf8'
            },
            'statusCode': 200,
            'body': json.dumps({'challenge': body['challenge']})
        }

    event = body.get('event', {})
    event_bot_id = event.get('bot_id', None)
    event_channel = event.get('channel', None)
    event_type = event.get('type', None)
    event_subtype = event.get('subtype', None)
    event_text = event.get('text', None)
    event_user = '<@{}>'.format(event.get('user', None))
    event_timestamp = event.get('ts', None)
    event_id = f'{event_channel}-{event_timestamp}'

    # only respond to messages, that also aren't from bots, and that do contains ++ or --
    if event_type == 'message' and (event_subtype != 'bot_message' and not event_bot_id):
        events_table = arc.tables.table(tablename='events')
        ddb_event = events_table.get_item(Key={'id': event_id})
        if 'Item' not in ddb_event:
            item = {
                'id': event_id,
                'ttl': int(time.time()) + 86400
            }
            events_table.put_item(Item=item)

            event_text_matches = [re.sub('\"|“|”', '', m[0]) for m in re.findall(r'((\S+|".*"|“.*”)[ ]?(\+\+|--))', str(event_text))]
            if event_text_matches:
                for i in event_text_matches:
                    delta = 1
                    if i.endswith('--'):
                        delta = -1
                    i = re.sub(' ?((\+\+)|(\-\-))', '', i)

                    # look up potential users
                    if is_slack_user_id(i):
                        user_id = i
                        users_table = arc.tables.table(tablename='users')
                        ddb_item = users_table.get_item(Key={'id': i})
                        if 'Item' in ddb_item:
                            item = ddb_item['Item']
                            i = item['name']
                    else:
                        i = i.lower()
                        user_id = None
                        userids_table = arc.tables.table(tablename='userids')
                        ddb_item = userids_table.get_item(Key={'name': i})
                        if 'Item' in ddb_item:
                            item = ddb_item['Item']
                            user_id = item['id']

                    # don't allow for modification of self-karma
                    if user_id and user_id == event_user:
                        response_text = '{}, {}'.format('Let go of your ego' if delta>0 else 'Hang on to your ego', event_user)
                    # get and modify karma
                    else:
                        karma_table = arc.tables.table(tablename='karma')
                        ddb_item = karma_table.get_item(Key={'entity': i})
                        item = {}
                        if 'Item' in ddb_item:
                            item = ddb_item['Item']
                            item['karma'] += delta
                        else:
                            item = {
                                'entity': i,
                                'karma': delta
                            }
                        karma_table.put_item(Item=item)
                        response_text = ':karmabot: _New karma for_ *{}* `{}`'.format(i, item['karma'])
                        if SPECIAL_KARMA.get(item['karma']):
                            response_text += f"\n{SPECIAL_KARMA[item['karma']]}"
                    # post to channel
                    post_slack_message(event_channel, response_text)
            # display karma
            elif event_text.startswith('karma '):
                entity = event_text[len('karma '):]
                karma_table = arc.tables.table(tablename='karma')
                ddb_item = karma_table.get_item(Key={'entity': entity})
                if 'Item' in ddb_item:
                    item = ddb_item['Item']
                    karma = item['karma']
                    response_text = f':karmabot: _Karma for_ *{entity}* `{karma}`'
                else:
                    response_text = f':karmabot: _No karma for_ *{entity}*'
                post_slack_message(event_channel, response_text)
            # reload all users
            elif event_text == 'shibboleth reload':
                users = get_slack_users_list()
                users_table = arc.tables.table(tablename='users')
                userids_table = arc.tables.table(tablename='userids')
                for t in (users_table, userids_table):
                    with t.batch_writer() as batch:
                        for i in users:
                            if i.get('name') and i.get('id'):
                                item = {
                                    'name': i['name'],
                                    'id': '<@{}>'.format(i['id']),
                                }
                                batch.put_item(Item=item)
                post_slack_message(event_channel, 'Reloaded {} users'.format(len(users)))
    return {'statusCode': 200}


from collections import Counter

#
# Complete the 'isValid' function below.
#
# The function is expected to return a STRING.
# The function accepts STRING s as parameter.
#

def is_valid_old(s):
    freq = [s.count(letter) for letter in set(s)]
    if max(freq) - min(freq) == 0:
        return 'YES'
    elif freq.count(max(freq)) == 1 and max(freq) - min(freq) == 1:
        return 'YES'
    elif freq.count(min(freq)) == 1:
        freq.remove(min(freq))
        if max(freq) - min(freq) == 0:
            return 'YES'
        else:
            return 'NO'
    else:
        return 'NO'

def is_valid(s):
    c = Counter(s)
    print(c)
    freq = Counter(c.values())
    print(freq)
    if len(freq) == 1:
        return "YES"
    elif len(freq) == 2:
        key_max = max(freq.keys())
        key_min = min(freq.keys())
        if key_max - key_min == 1 and freq[key_max] == 1:
            return "YES"
        elif key_min == 1 and freq[key_min] == 1:
            return "YES"
    return "NO"

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

    # s = input()
    # s = 'AAABBBCC'
    s = 'abcdefghhgfedecba'

    result = is_valid(s)

    # Expected Output YES
    print(result)


"""
process DNA sequence using naive methods
"""
from typing import Iterable
from .seq import Seq

class DNA(Seq):
    nt_pair = {'A':'T', 'T':'A', 'G':'C', 'C':'G',}

    def __init__(self, seq:str=None):
        super(DNA, self).__init__(seq)

    def complement(self)->str:
        return DNA.replace(self.seq)

    def reverse_complement(self)->str:
        return DNA.replace(self.seq[::-1])

    @staticmethod
    def replace(seq:str):
        if len(seq)==0:
            return ''
        nt = DNA.nt_pair.get(seq[0], seq[0])
        return nt + DNA.replace(seq[1:])

    def calculate_gc(self):
        '''
        GC percentage
        '''
        if self.length() == 0:
            return 0
        g = self.count_sub_seq('G')
        c = self.count_sub_seq('C')
        return (g + c)/self.length()

    def detect_similarity(self, seq2:str)->tuple:
        '''
        Note: length of seq2<= self.seq
        '''
        len_seq = len(seq2)
        min_dist, pool = len_seq, []
        S = Seq(seq2)
        for seq1, start, end in self.k_mers(len_seq):
            dist = S.calculate_hamming_distance(seq1)
            if dist < min_dist:
                min_dist = dist
                pool = [(start, end)]
            elif dist == min_dist:
                pool.append((start, end))
        max_same = len_seq - min_dist
        return max_same, pool

    def detect_overlap(self, seq2:str)->tuple:
        '''
        3-end of seq1 is overlapped with 5-end of seq2
        '''
        olen = 0
        while self.seq[-(olen+1):] == seq2[:(olen+1)]:
            olen +=1
        return olen

    def detect_target_repeat(self, repeat:str=None)->list:
        if repeat is None: repeat = 'N'

        pool = []
        start = self.seq.index(repeat)
        end = start + len(repeat)
        while 0 <= start < self.length():
            next_seq = self.seq[start+1:]
            pos = next_seq.index(repeat)
            if pos == 0:
                end += len(repeat)
            elif pos > 0:
                pool.append((start, end))
                start = pos
                end = start + len(repeat)
            else:
                break
        return pool

    def detect_longest_target_repeat(self, repeat:str=None)->tuple:
        pool = self.detect_target_repeat(repeat)
        repeat_start, repeat_end = 0, 0
        for start, end in pool:
            if (end - start) > (repeat_end - repeat_start):
                repeat_start, repeat_end = start, end
        return repeat_start, repeat_end