#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#License GPL v3
#Author Horst Knorr
from configparser import RawConfigParser
from io import StringIO
from os.path import expanduser
import atexit
import bz2
import getopt
import gzip
import inspect
import os
import random
import re
import shutil
import signal
import socket
import subprocess
import sys
import syslog
import tempfile
import time

VERSION="1.0.0"
DATE="02.09.2015"
ZIP_EMAILS=True
#################################
#Definition of general functions#
#################################

####
#log
####
def log(msg,infotype="m",ln=-1):
	global logfile,SYSLOG

	if ln==-1:
		ln=inspect.currentframe().f_back.f_lineno

	if LOGGING:
		_lftmsg=20
		prefix="Info"

		if infotype=='w':
			prefix="Warning"
		elif infotype=='e':
			prefix="Error"
		elif infotype=='d':
			prefix="Debug"

		t=time.localtime(time.time())
		_lntxt="Line %i: "%ln
		tm=("%02d.%02d.%04d %02d:%02d:%02d:" %
			(t[2],t[1],t[0],t[3],t[4],t[5])).ljust(_lftmsg)

		if (ln>0):
			msg=_lntxt+str(msg)

		if SYSLOG:
			#write to syslog
			level=syslog.LOG_INFO

			if infotype=='w':
				level=syslog.LOG_WARNING
			elif infotype=='e':
				level=syslog.LOG_ERR
				msg="ERROR "+msg
			elif infotype=='d':
				level=syslog.LOG_DEBUG
				msg="DEBUG "+msg
			syslog.syslog(level,msg)
		elif  logfile!=None:
			#write to logfile
			logfile.write("%s %s: %s\n"%(tm,prefix,msg ))
		else:
			# print to stderr if nothing else works
			sys.stdout.write("%s %s: %s\n"%(tm,prefix,msg ))

######
#debug
######

def debug(msg,ln=-1):

	if ln==-1:
		ln=inspect.currentframe().f_back.f_lineno

	if DEBUG:
		log(msg,"d",ln)
#######
#lineno
#######
def lineno():
    return inspect.currentframe().f_back.f_lineno

############
#print_usage
############
def print_usage():
	print("encryptmaildir")
	print("==============")
	print("License: GPL 3")
	print("Author:  Horst Knorr")
	print("Version: %s from %s"%(VERSION,DATE))
	print("\nUsage:\n")
	print("encryptmaildir [options] directory1 [directory2 ...]")
	print("\nOptions:\n")
	print("-c f --config f:  adds the configfile 'f'")
	print("-d --debug:       print debugging information into logfile")
	print("-h --help :       print this help")
	print("-k f --keyhome f: sets gpg key directory to 'f'")
	print("-u --user:        user email address")
	print("-v --dovecot:     uses Dovecot maildirlock")
	print("-x --example:     print example config file")
	print("-y --syslog:      log to syslog, otherwise to logfile")
	print("\n")

####################
#print_exampleconfig
####################
def print_exampleconfig():
	print("\n[default]")
	print("gpgmailencrypt = /usr/local/bin/gpgmailencrypt.py")
	print()
	print("[mail]")
	print("dovecot = no")
	print("maildirlock = /usr/lib/dovecot/maildirlock")
	print("\n")

###############
#prepare_syslog
###############
def prepare_syslog():
		global LOGGING,SYSLOG
		LOGGING=True
		SYSLOG=True
		syslog.openlog("encryptmaildir",syslog.LOG_PID,syslog.LOG_MAIL)

###############
#shellquote
###############
def shellquote(s):
	return s.replace("'", "'\''").replace(" ","\ ")

#########
#get_lock
#########
def get_lock(directory):
	global _pids

	try:
		debug ("%s %s"%(MAILDIRLOCK,directory))
		process = subprocess.Popen([MAILDIRLOCK,directory,'10'],
									stdout=subprocess.PIPE)
	except:
		log("get_lock: Couldn't call 'maildirlock'!","e",lineno())
		exit(1)

	output=process.stdout.read()
	pid=-1

	try:
		pid=int(output)
	except:
		log("get_lock: Couldn't get lock for '%s'" %directory,"e",lineno())
		pid=-1
	else:
		debug("get_lock: %s"%str(pid),ln=lineno())
		_pids.append(pid)

	return pid

##########
#free_lock
##########
def free_lock(pid):
	global _pids

	try:
		os.kill(pid,signal.SIGKILL)
	except:
		log("free_lock: Pid '%i' doesn't exist"%pid,"e",lineno())

	try:
		debug( "free_lock _pids.remove(%i)"%pid,ln=lineno())
		_pids.remove(pid)
	except:
		log( "free_lock _pids.remove(%i) wasn't possible"%pid,"e",lineno())

##################
#class maildirname
##################
class maildirname:

		def __init__(self):
			self._name=''
			self._leftpart=''
			self._middlepart=''
			self._rightpart=''
			self._flags=[]
			self._dovecotflags=dict()

		def __splitname(self,n):

			try:
				self._leftpart,self._middlepart,rp=n.split(".",2)
				rp=rp.split(":2,")
				self._flags=[]
				self._flags.extend(rp[1])
				self._flags.sort()
				rp=rp[0].split(",")
				self._rightpart=rp[0]

				if len(rp)>1:
					self._dovecotflags=dict()

					for f in rp[1:]:
						r=f.split("=")
						self._dovecotflags[r[0]]=r[1]

			except:
				log("Name '%s' does not fit name convention "
					"part1.part2.part3:2,<flags>"%n,
					"e",
					lineno())

		def set_name(self,n):
			self._name=n.strip()
			self.__splitname(self._name)

		def originalname(self):
			return self._name

		def name(self):
			n=self._leftpart+"."+self._middlepart+"."+self._rightpart
			dvflags=[]

			for f in list(self._dovecotflags.keys()):
				dvflags.append(f+"="+self._dovecotflags[f])

			dvflags=",".join(dvflags)

			if len(dvflags)>0:
				n=n+","+dvflags

			flag="".join(self._flags)
			n=n+":2,"+flag
			return n

		def set_leftpart(self,p)	:
			self._leftpart=p.strip()

		def leftpart(self):
			return self._leftpart

		def set_middlepart(self,p)	:
			self._middlepart=p.strip()

		def middlepart(self):
			return self._middlepart

		def set_rightpart(self,p)	:
			self._rightpart=p.strip()

		def rightpart(self):
			return self._rightpart

		def set_flags(self,fl):
				self._flags=[]
				self._flags.extend(fl)
				self._flags.sort()

		def flags(self):
			return self._flags

		def dovecotflags(self):
			return self._dovecotflags

		def set_dovecotflags(self,df=()):
			self._dovecotflags=dict()

			if type(df)==str:

				r=df.split("=")

				if len(r)!=2:
					log("Flag '%s' does not fit the convention name=value"%df,
						"w",
						lineno())
				else:
					self._dovecotflags[r[0]]=r[1]
			else:

				for f in df:
					r=f.split("=")

					if len(r)!=2:
						print("Flag '%s' does not fit the convention "
								"name=value"%f)
					else:
						self._dovecotflags[r[0]]=r[1]

		def debug(self):
			print("name:'%s'"%self._name)
			print("left:'%s'"%self._leftpart)
			print("middle:'%s'"%self._middlepart)
			print("right:'%s'"%self._rightpart)
			print("flags:'%s'"%self._flags)
			print("dovecotflags:'%s'"%self._dovecotflags)

			if "S" in self._dovecotflags:
				print("dovecot filesize=%s"%self._dovecotflags["S"])

			if "W" in self._dovecotflags:
				print("dovecot wflag=%s"%self._dovecotflags["W"])

			print("End debug name:'%s'"%self._name)

###########
#is_gzipped
###########
def is_gzipped(fname):
	_res=True
	debug("is_gzipped:%s"%fname,lineno())

	try:
		f = gzip.open(fname, 'rb')
	except:
		log("is_gzipped: Couldn't open file '%s'"%fname,"w",ln=lineno())
		return False

	else:

		try:
			file_content = f.read()
		except:
			_res=False
		finally:
			f.close()

	result="No"

	if _res:
		result="Yes"

	debug("is_gzipped: %s '%s'"%(result,fname),lineno())
	return _res

##########
#gzip_file
##########
def gzip_file(fname):
	_res=False
	debug("gZip '%s'"%fname,lineno())

	if is_gzipped(fname):
		log("File '%s' is already gzipped"%fname,"i",lineno())
		return True

	try:
		_times=os.stat(fname)
	except:
		log("gzip_file: File attributes for file '%s' couldn't be read"%fname,
			"e",
			ln=lineno())
		return False

	_newname=tempfile.NamedTemporaryFile(mode='wb',delete=True,prefix='mail-')
	_newname.close()
	_newname=_newname.name

	try:
		f_in = open(fname, 'rb')
	except:
		log("gzip_file: Couldn't open file '%s'"%fname,"e",ln=lineno())
		return

	else:

		try:
			f_out = gzip.open(_newname, 'wb')
			f_out.write(f_in.read())
		except:
			log("gzip_file: Couldn't zip file '%s'" %fname,"e",ln=lineno())
		else:
			_res=True
			f_out.close()
		finally:
			f_in.close()

	if _res:

		try:
			os.utime(_newname,(_times.st_atime,_times.st_mtime))
		except:
			log("gzip_file: Fileflags of file '%s' couldn't be set"%_newname,
				"w",
				ln=lineno())

		try:
			shutil.move(_newname,fname)
		except:
			log("gzip_file: Error moving temporary file from "
			"'%(NEW)s' to '%(OLD)s'"%{	"NEW":_newname,
										"OLD":fname},
										"e",lineno())
			log("'%(m1)s %(m2)s'"%{	"m1":sys.exc_info()[0],
									"m2":sys.exc_info()[1]},
									"e",lineno())
			_res=False

	debug("gZip End '%s'"%fname,lineno())
	return _res

############
#gunzip_file
############
def gunzip_file(fname):
	_res=False
	_newname=tempfile.NamedTemporaryFile(mode='wb',delete=False,prefix='mail-')
	_newname.close()
	_newname=_newname.name
	debug("gUnzip '%s'"%fname,lineno())

	try:
		_times=os.stat(fname)
	except:
		log("gunzip_file: Couldn't load file attributes of file '%s'"%fname,
													"e",
													lineno())
		return False

	try:
		f_out = open(_newname, 'wb')
	except:
		log ("gunzip_file: Couldn't open tempfile '%s'"%_newname,"e",lineno())
		return False

	try:
		f_in = gzip.open(fname, 'rb')
	except:
		log ("gunzip_file: Couldn't open file '%s'"%fname,"e",lineno())
		return False
	else:

		try:
			f_out.write(f_in.read())
		except:
			log("Couldn't gunzip '%s'"%fname,"e",ln=lineno())
			f_in.close()
			os.remove(_newname)
			return False

		_res=True
		f_out.close()
		f_in.close()

	if _res:

		try:
			os.utime(_newname,(_times.st_atime,_times.st_mtime))
		except:
			log("gzip_file: Couldn't set file flags of file '%s'"%_newname,
				"w",
				lineno())

		try:
			shutil.move(_newname,fname)
		except:
			log("gzip_file: Couldn't move temporary file '%(NEW)s' to"
			" '%(OLD)s'"%{"NEW":_newname,"OLD":fname},"e",lineno())
			log("'%(m1)s %(m2)s'"%{	"m1":sys.exc_info()[0],
									"m2":sys.exc_info()[1]},"e",lineno())
			return False

	else:

		try:
			os.remove(_newname)
		except:
			log("gunzip_file: Couldn't delete temporary file '%s'"%_newname,
				"w",lineno())

	return True

#############
#is_bz2zipped
#############
def is_bz2zipped(fname):
	_res=True
	debug("is_bz2zipped:%s"%fname,lineno())

	try:
		f = bz2.BZ2File(fname, 'rb')
	except:
		log("is_bz2ipped: Couldn't open file '%s'"%fname,"w",ln=lineno())
		return False
	else:

		try:
			file_content = f.read()
		except:
			_res=False
		finally:
			f.close()

	result="No"

	if _res:
		result="Yes"

	debug("is_bz2zipped: %s '%s'"%(result,fname),lineno())
	return _res

############
#bz2zip_file
############
def bz2zip_file(fname):
	_res=False
	debug("bz2Zip '%s'"%fname,lineno())

	if is_bz2zipped(fname):
		log("File '%s' is already bz2zipped"%fname,"i",lineno())
		return True

	try:
		_times=os.stat(fname)
	except:
		log("bz2zip_file: File attributes for file '%s' couldn't be read"%fname,
			"e",ln=lineno())
		return False

	_newname=tempfile.NamedTemporaryFile(mode='wb',delete=True,prefix='mail-')
	_newname.close()
	_newname=_newname.name

	try:
		f_in = open(fname, 'rb')
	except:
		log("bz2zip_file: Couldn't open file '%s'"%fname,"e",ln=lineno())
		return False
	else:

		try:
			f_out = bz2.BZ2File(_newname, 'wb')
			f_out.write(f_in.read())
		except:
			log("bz2zip_file: Couldn't zip file '%s'" %fname,"e",ln=lineno())
		else:
			_res=True
			f_out.close()
		finally:
			f_in.close()

	if _res:

		try:
			os.utime(_newname,(_times.st_atime,_times.st_mtime))
		except:
			log("bz2zip_file: Fileflags of file '%s' couldn't be set"%_newname,
				"w",ln=lineno())

		try:
			shutil.move(_newname,fname)
		except:
			log("bz2zip_file: Error moving temporary file from"
				" '%(NEW)s' to '%(OLD)s'"%{"NEW":_newname,"OLD":fname},
				"e",lineno())
			_res=False

	debug("bz2Zip End '%s'"%fname,lineno())
	return _res

##############
#bz2unzip_file
##############
def bz2unzip_file(fname):
	_res=False
	_newname=tempfile.NamedTemporaryFile(mode='wb',delete=False,prefix='mail-')
	_newname.close()
	_newname=_newname.name
	debug("bz2Unzip '%s'"%fname,lineno())

	try:
		_times=os.stat(fname)
	except:
		log("bz2unzip_file: Couldn't load file attributes of file '%s'"%fname,
		"e",lineno())
		return False

	try:
		f_out = open(_newname, 'wb')
	except:
		log ("bz2unzip_file: Couldn't open tempfile '%s'"%_newname,"e",lineno())
		return False

	try:
		f_in = bz2.BZ2File(fname, 'rb')
	except:
		log ("bz2unzip_file: Couldn't open file '%s'"%fname,"e",lineno())
		return False
	else:

		try:
			f_out.write(f_in.read())
		except:
			log("Couldn't unzip '%s'"%fname,"e",ln=lineno())
			f_in.close()
			os.remove(_newname)
			return False

		_res=True
		f_out.close()
		f_in.close()

	if _res:

		try:
			os.utime(_newname,(_times.st_atime,_times.st_mtime))
		except:
			log("bz2zip_file: Couldn't set file flags of file '%s'"%_newname,
			"w",lineno())

		try:
			shutil.move(_newname,fname)
		except:
			log("bz2zip_file: Couldn't move temporary file '%(NEW)s' to"
			" '%(OLD)s'"%{"NEW":_newname,"OLD":fname},"e",lineno())
			return False

	else:

		try:
			os.remove(_newname)
		except:
			log("bz2unzip_file: Couldn't delete temporary file '%s'"%_newname,
			"w",lineno())

	return True

###########
#do_finally
###########
def do_finally():
	global _pids

	while len(_pids)>0:
		free_lock(_pids[0])
		#log("free_lock: '%s'"%str(_pids[0]))

	if checked_files >0:
		plural=""

		if checked_files >1:
			plural="s"

		log("User %s: %i mail%s checked for encryption"%(	USER,
															checked_files,
															plural))

################
#read_configfile
################
def read_configfile():
	global cfg, DEBUG,DOVECOT,GPGMAILENCRYPT,MAILDIRLOCK
	cfg=dict()
	_cfg = RawConfigParser()

	try:
		_cfg.read(CONFIGFILE)
	except:
		log("Could not read config file '%s'."%CONFIGFILE,"e",ln=lineno())
		return

	for sect in _cfg.sections():
		cfg[sect] = dict()

		for (name, value) in _cfg.items(sect):
			cfg[sect][name] = value

	if 'default' in cfg:

		if 'gpgmailencrypt' in cfg['default']:
			GPGMAILENCRYPT=cfg['default']['gpgmailencrypt']

	if 'mail' in cfg:

		if 'dovecot' in cfg['mail'] and cfg['mail']['dovecot']=="yes":
			DOVECOT=True

		if 'maildirlock' in cfg['mail']:
			MAILDIRLOCK=cfg['mail']['maildirlock']

##################
#parse_commandline
##################
def parse_commandline():
	global to_addrs
	global CONFIGFILE,DEBUG,DOVECOT,DIRECTORIES,KEYHOME
	global USER,LOGFILE,LOGGING,SYSLOG

	try:
		cl=sys.argv[1:]
		_opts,_remainder=getopt.gnu_getopt(cl,'c:dhk:n:u:vxy',['config=',
																'debug',
																'dovecot',
																'example',
																'help',
																'keyhome=' ,
																'user=',
																'syslog'])
	except getopt.GetoptError as e:
		log("unknown commandline parameter '%s'"%str(e),"e",lineno())
		exit(2)

	for _opt, _arg in _opts:

		if _opt  =='-y' or  _opt == '--syslog':
		   	prepare_syslog()

	for _opt, _arg in _opts:

		if _opt  =='-d' or  _opt == '--debug':
	   		DEBUG=True

		if (_opt  =='-c' or  _opt == '--config') and _arg!=None:
	   		_arg=_arg.strip()

	   		if len(_arg)>0:
	   			CONFIGFILE=_arg
	   			break

		if _opt  =='-h' or  _opt == '--help':
	   		print_usage()
	   		exit(0)

		if _opt  =='-k' or  _opt == '--keyhome':
	   		KEYHOME=_arg

		if _opt  =='-u' or _opt == '--user':
	   		USER=_arg

		if _opt  =='-v' or _opt == '--dovecot':
	   		DOVECOT=True

		if _opt  =='-x' or  _opt == '--example':
	   		print_exampleconfig()
	   		exit(0)

		if _opt  =='-y' or  _opt == '--syslog':
		   	prepare_syslog()

	if len(_remainder)>0:
		DIRECTORIES.extend(_remainder[0:])
	else:
		log("No directories added","e",lineno())
		print_usage()
		exit(2)

#############
#encrypt_dir
#############
def encrypt_dir(arg,dirname,names):
	global mtime,newtime,checked_files
	lockdir=dirname.replace("/cur","").replace("/new","")

	if not ("/cur" in dirname.lower()) and not ("/new" in dirname.lower()):
		return

	if "courierimapkeyword" in dirname:
		return

	if DOVECOT:
		pid=get_lock(lockdir)

		if pid == -1:
			return

	mtimefile=expanduser(dirname+"/"+MTIMEFILE)

	try:
		m=open(mtimefile)
		mtime=float(m.read())
		newtime=mtime
		debug("checktime: %i"%newtime)
		m.close()
	except:
		log("Could not read Mtimefile '%s'"%mtimefile,"w",lineno())

	for n in names:

		if ((DOVECOT and "dovecot" in n) or (MTIMEFILE in n)
				or("subscriptions" in n) or ("courierimap" in n)):
			debug("Ignore '%s'"%n)
			continue

		f="%s/%s"%(dirname,n)
		filetime=os.stat(f).st_mtime
		_gzipped=False
		_bz2zipped=False
		debug("check file '%s'"%f,lineno())

		try:
			_times=os.stat(f)
		except:
			log("Couldn't load file attributes of file '%s'"%f,"e",lineno())

		if os.path.isfile(f) and filetime >mtime:
			debug( "checkfile:%s %s"%(time.ctime(os.stat(f).st_mtime),f))
			checked_files+=1

			if is_gzipped(f):
				_gzipped=True

				if not gunzip_file(f):
					log("Couldn't gunzip Mail, continue","e",lineno())
					continue

			elif is_bz2zipped(f):
				_bz2zipped=True

				if not bz2unzip_file(f):
					log("Couldn't bz2unzip Mail, continue","e",lineno())
					continue

			out=tempfile.NamedTemporaryFile(mode='wb',
											delete=False,
											prefix='mail-')
			out.close()
			cmd="%(CMD)s -l syslog  -a -k %(KEY)s -f '%(IN)s'"
			" -m %(OUT)s %(USER)s" %{	"CMD":GPGMAILENCRYPT,
										"KEY":KEYHOME,
										"IN":f,
										"OUT":out.name,
										"USER":USER}
			_result = os.system(cmd)/256

			if _result == 0:

				try:
					new=open(f,'w')
				except:
					log ("Error opening file '%s'"%f,"e",lineno())
					continue

				try:
					out=open(out.name)
				except:
					log ("Error opening file '%s'"%out.name,"e",lineno())
					os.unlink(out.name)
					continue

				new.write(out.read())
				new.close()
				nf=new.name
				del new
				fsize=str(os.stat(nf).st_size)

				if ZIP_EMAILS:

					if _gzipped:
						gzip_file(nf)
					elif _bz2zipped:
						bz2zip_file(nf)

				if DOVECOT:
					mname=maildirname()
					mname.set_name(n)
					#mname.set_rightpart(socket.gethostname())
					mname.set_dovecotflags(("S="+fsize,"W="+fsize))
					newf="%s/%s"%(dirname,mname.name())
					os.rename(nf,newf)
					nf=newf

				try:
					os.utime(nf,(_times.st_atime,_times.st_mtime))
				except:
					log("Couldn't set file flags of file '%s'"%nf,"w",lineno())

				filetime=os.stat(nf).st_mtime
				debug("filetime: %i"%filetime,lineno())

				if filetime>newtime:
					newtime=filetime
					debug("new checktime: %i"%newtime)

			else:
				debug("Encryption ended with error %i"%_result,lineno())
				filetime=os.stat(f).st_mtime
				debug("filetime: %i"%filetime)

				if filetime>newtime:
					newtime=filetime
					debug("new checktime: %i"%newtime)

			os.unlink(out.name)

	try:
		m=open(mtimefile,'w')
		m.write(str(newtime))
		m.close()
	except:
		log("Could not open Mtimefile '%s'"%mtimefile,"w",lineno())

	if DOVECOT:
		free_lock(pid)

##################
#Main routine
##################
#Internal variables
logfile=None
cfg = dict()
_pids=[]
mtime=0
newtime=0
checked_files=0
atexit.register(do_finally)

#GLOBAL CONFIG VARIABLES
DEBUG=False
LOGGING=True
LOGFILE=""
DOVECOT=False
MAILDIRLOCK='/usr/lib/dovecot/maildirlock'
SENDSTDOUT=False
SYSLOG=False
KEYHOME="~/.gnupg"
GPGMAILENCRYPT=shutil.which("gme.py")
MTIMEFILE=".encryptmaildir"
USER=''
CONFIGFILE='/etc/encryptmaildir'
DIRECTORIES=[]
#get configuration
read_configfile()
parse_commandline()
#encrypt directories

try:

	for directory in DIRECTORIES:
		debug("DIR: '%s'"%directory,lineno())
		os.walk(directory,encrypt_dir,None)

except KeyboardInterrupt:
	log("Keyboard: CTRL-C Exit ...",ln=lineno())
except:
  	log("Bug: Exception '%(m1)s %(m2)s' occured!"%{	"m1":sys.exc_info()[0],
  													"m2":sys.exc_info()[1]})


def basic_if():
    is_male = False
    is_tall = True
    if is_male and is_tall:
        print("You a tall man")
    elif is_male and not(is_tall):
        print("You are a short man")
    elif not(is_male) and is_tall:
        print("You are a tall woman")
    else:
        print("You are not a man and not tall")

def max_num(num1, num2, num3):
    if num1 >= num2 and num1 >= num3:
        return num1
    elif num2 >= num1 and num2 >= num3:
        return num2
    else:
        return num3

print(max_num(4,2,8))
basic_if()


from django.test import TestCase
from .models import Articulo

# Create your tests here.
class ArticuloTests(TestCase):

    def test_creacion_de_articulo_autor(self):
        """
        Prueba crear articulo con un autor que no existe.
        """
        articulo_con_autor_invalido = Articulo.objects.create(
            titulo="titulo_A", subtitulo="subtitulo_A", cuerpo="cuerpo_A", autor_id=200
        )
        # Compruebo que el articulo fue creado
        self.assertEqual(Articulo.objects.all().count(), 1)
        self.assertIsNotNone(articulo_con_autor_invalido)

    def test_creacion_de_articulo_titulo(self):
        """
        Prueba crear articulo sin titulo.
        """
        articulo_sin_titulo = Articulo.objects.create(
            titulo="", subtitulo="subtitulo_A", cuerpo="cuerpo_A", autor_id=1
        )
        # Compruebo que el articulo fue creado
        self.assertEqual(Articulo.objects.all().count(), 1)
        self.assertIsNotNone(articulo_sin_titulo)


import streamlit as st
import pandas as pd
from PIL import Image

def app():
    st.title('ABOUT')

    st.markdown("Automation to authenticate Indihome installation evidence")

    image_back = Image.open(r"data/slide_img/background.png")
    st.image(image_back, caption='Background', use_column_width="auto")

    st.markdown("We need a system that **automatically verify** incoming installation evidence by **classifying whether** that image is accepted **(OK)** or rejected **(NOT_OK)**")

    image_obj = Image.open(r"data/slide_img/objective.png")
    st.image(image_obj, caption='Objective', use_column_width="auto")


import cv2
from pathlib import Path
import time
import sys

def mosaic(src, ratio=0.1):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

def mosaic_area(src, x, y, width, height, ratio=0.1):
    dst = src.copy()
    dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width], ratio)
    return dst

def img2mosaic(src, ratio=0.1):
    cascade_path = "".join(cv2.__path__) + "/data/haarcascade_frontalface_default.xml"
    cascade = cv2.CascadeClassifier(cascade_path)

    src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    faces = cascade.detectMultiScale(src_gray)

    for x, y, w, h in faces:
        dst = mosaic_area(src, x, y, w, h, ratio)

    return dst

def main(fullpath, filename, image_path):
    """ 与えられた画像から、モザイク処理した画像を生成する """
    src = cv2.imread(fullpath)
    dst = img2mosaic(src, ratio=0.01)
    cv2.imwrite(image_path + "/mosaic/" + filename, dst)

if __name__ == "__main__":
    """ 親プロセスのimage2mosaic2_main.pyから呼ばれ、子プロセスとして動作する """
    _, fullpath, filename, image_path = sys.argv
    main(fullpath, filename, image_path)


#Exercise : how many
# write a procedure, called how_many, which returns the sum of the number of values associated with a dictionary.

def how_many(aDict):
    val = aDict.values()
    print (val)
    make_list = list(val)
    a = 0
    #print(make_list)
    for i in make_list:
    	a += len(i)
    return a

def main():
	n=input()
	aDict={}
	for i in range(int(n)):
		s=input()
		l=s.split()
		if l[0][0] not in aDict:
			aDict[l[0][0]]=[l[1]]
		else:
			aDict[l[0][0]].append(l[1])
	print(how_many(aDict))

if __name__== "__main__":
    main()


from python_imagesearch.imagesearch import imagesearch
import configparser
from pynput.keyboard import Key, Controller as KeyboardController
from pynput.mouse import Button, Controller as MouseController
from tksleep import tksleep

keyboard = KeyboardController()
mouse = MouseController()
config = configparser.ConfigParser()

def findegg():
    pos = imagesearch(".\images\egg.png")
    if pos[0] != -1:
        print("position : ", pos[0], pos[1])
        print("Egg is ready to hatch!")
        tksleep.tksleep(1)
        keyboard.type(";egg hatch")
        keyboard.press(Key.enter)
        keyboard.release(Key.enter)
        tksleep.tksleep(7)

        #check if there's eggs in inventory
        config.read('config.ini')
        amt = config['CONFIG']['egg']
        if int(amt) >= 1:
            keyboard.type(";egg hold")
            keyboard.press(Key.enter)
            keyboard.release(Key.enter)
            tksleep.tksleep(2)


#!/usr/bin/env python
"""data_prep module
"""

import cv2
from torchvision import transforms
import torch
import os

class DataPrep:
    def __init__(self, valid_ext=['png']):
        self.valid_ext = valid_ext
        self.transform = transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.5, ), (0.5, ))
        ])
        self.save_labeled_dir = 'labeled'
        self.save_unlabeled_dir = 'unlabeled'

        if not os.path.exists(self.save_labeled_dir):
            os.makedirs(self.save_labeled_dir)
            print('directory created for labeled')
        if not os.path.exists(self.save_unlabeled_dir):
            os.makedirs(self.save_unlabeled_dir)
            print('directory created for unlabled')

    def valid_img(self, img_path):
        return img_path.split('.')[-1] in self.valid_ext

    def img_to_mnist(self, img):
        image = cv2.imdecode(img, cv2.IMREAD_GRAYSCALE)
        #_ ,image = cv2.threshold(image, 128, 0, cv2.THRESH_BINARY_INV)
        #image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        cv2.imwrite('original.jpg', image)
        print('original image shpe: ', image.shape)

        size = min(image.shape)
        size = size if size >= 28 else 28
        resized_img = cv2.resize(image, (size, size), interpolation=cv2.INTER_LINEAR)
        resized_img = cv2.resize(resized_img, (28, 28), interpolation=cv2.INTER_LINEAR)

        cv2.imwrite('resized.jpg', resized_img)
        print("img shape: ", resized_img.shape)

        resized_img = cv2.bitwise_not(resized_img)

        return resized_img

    def transform_input(self, img):

        return self.transform(img)

    def store_img(self, img, acc, label):
        print('type of label: ', type(label), label)
        pth = f'{label:03}_img.png'
        print('path first time: ', pth)
        if acc > 0.9:
            pth = os.path.join(self.save_labeled_dir, pth)
        else:
            pth = os.path.join(self.save_unlabeled_dir, pth)

        image = cv2.imdecode(img, cv2.IMREAD_GRAYSCALE)
        try:
            cv2.imwrite(pth, image)
            print('IMage saved succesfuly, at', pth)
        except Exception as e:
            print("can't save or write image")


import numpy as np

import pytest

from summer2 import CompartmentalModel
from summer2.stratification import Stratification

from summer2.population import calculate_initial_population

def build_model():
    """Returns a model for the stratification examples"""
    model = CompartmentalModel(
        times=[0, 1],
        compartments=["S", "I", "R"],
        infectious_compartments=["I"],
    )

    # Add people to the model
    model.set_initial_population(distribution={"S": 990, "I": 10})

    strata = ["young", "old"]
    age_strat = Stratification(name="age", strata=strata, compartments=["S", "I", "R"])
    age_strat.set_population_split({"young": 0.6, "old": 0.4})

    strata = ["urban", "rural"]
    loc_strat = Stratification(name="loc", strata=strata, compartments=["S", "I", "R"])
    loc_strat.set_population_split({"urban": 0.8, "rural": 0.2})

    strata = ["one_dose", "two_dose", "unvacc"]
    vacc_strat = Stratification(name="vacc", strata=strata, compartments=["S", "I", "R"])

    model.stratify_with(age_strat)
    model.stratify_with(loc_strat)
    model.stratify_with(vacc_strat)

    return model

def test_split_single_filter():
    model = build_model()

    orig_init_pop = model._get_step_test().initial_population
    s_young_orig = orig_init_pop[
        model.query_compartments({"name": "S", "age": "young"}, as_idx=True)
    ].copy()

    model = build_model()
    model.adjust_population_split(
        "vacc", {"age": "old"}, {"one_dose": 0.7, "two_dose": 0.2, "unvacc": 0.1}
    )

    init_pop = model._get_step_test().initial_population

    # Check the total population hasn't changed
    np.testing.assert_almost_equal(init_pop.sum(), 1000.0)

    # Check we haven't changed any compartments we're not meant to

    s_young_post = init_pop[model.query_compartments({"name": "S", "age": "young"}, as_idx=True)]
    np.testing.assert_array_almost_equal(s_young_orig, s_young_post)

    # Check we got the expected rebalance values
    s_old_urban_expected = 990.0 * 0.4 * 0.8 * np.array((0.7, 0.2, 0.1))
    s_old_urban_target = init_pop[
        model.query_compartments({"name": "S", "age": "old", "loc": "urban"}, as_idx=True)
    ]

    np.testing.assert_array_almost_equal(s_old_urban_expected, s_old_urban_target)

def test_split_multi_filter():
    model = build_model()

    init_pop_orig = model._get_step_test().initial_population

    s_young_orig = init_pop_orig[
        model.query_compartments({"name": "S", "age": "young"}, as_idx=True)
    ].copy()
    s_rural_orig = init_pop_orig[
        model.query_compartments({"name": "S", "loc": "rural"}, as_idx=True)
    ].copy()

    model = build_model()
    model.adjust_population_split(
        "vacc", {"age": "old", "loc": "urban"}, {"one_dose": 0.7, "two_dose": 0.2, "unvacc": 0.1}
    )

    init_pop = model._get_step_test().initial_population
    # Check the total population hasn't changed
    np.testing.assert_almost_equal(init_pop.sum(), 1000.0)

    # Check we haven't changed any compartments we're not meant to

    s_young_post = init_pop[model.query_compartments({"name": "S", "age": "young"}, as_idx=True)]
    s_rural_post = init_pop[model.query_compartments({"name": "S", "loc": "rural"}, as_idx=True)]
    np.testing.assert_array_almost_equal(s_young_orig, s_young_post)
    np.testing.assert_array_almost_equal(s_rural_orig, s_rural_post)

    # Check we got the expected rebalance values
    s_old_urban_expected = 990.0 * 0.4 * 0.8 * np.array((0.7, 0.2, 0.1))
    s_old_urban_target = init_pop[
        model.query_compartments({"name": "S", "age": "old", "loc": "urban"}, as_idx=True)
    ]

    np.testing.assert_array_almost_equal(s_old_urban_expected, s_old_urban_target)

def test_expected_failures():
    model = build_model()

    with pytest.raises(AssertionError, match="No stratification shoes found in model"):
        model.adjust_population_split(
            "shoes",
            {"age": "old", "loc": "urban"},
            {"one_dose": 0.7, "two_dose": 0.2, "unvacc": 0.1},
        )

    with pytest.raises(AssertionError, match="All strata must be specified in proportions"):
        model.adjust_population_split(
            "vacc", {"age": "old", "loc": "urban"}, {"one_dose": 0.7, "two_dose": 0.2}
        )

    with pytest.raises(AssertionError, match="Proportions must sum to 1.0"):
        model.adjust_population_split(
            "vacc",
            {"age": "old", "loc": "urban"},
            {"one_dose": 0.7, "two_dose": 0.5, "unvacc": 0.8},
        )


import os
import logging
import ckan.lib.base as base
import ckan.authz as authz
import ckan.logic.converters as converters
from ckan.logic import get_action, NotFound
from ckan.logic.schema import package_form_schema, group_form_schema
from ckan.plugins import IDatasetForm, IGroupForm, IConfigurer
from ckan.plugins import IGenshiStreamFilter
from ckan.plugins import implements, SingletonPlugin
import ckan.lib.navl.validators as validators
import ckan.plugins.toolkit as toolkit
import ckan.lib.plugins
import ckan.logic as logic

log = logging.getLogger(__name__)

class OttawaDatasetForm(SingletonPlugin, ckan.lib.plugins.DefaultDatasetForm):
    implements(IDatasetForm, inherit=True)
    implements(IConfigurer, inherit=True)

    def update_config(self, config):
        """
        This IConfigurer implementation causes CKAN to look in the
        ```templates``` directory when looking for the package_form()
        """
        here = os.path.dirname(__file__)
        rootdir = os.path.dirname(os.path.dirname(here))
        template_dir = os.path.join(rootdir, 'ckanext',
                                    'ottawa', 'theme', 'templates')
        config['extra_template_paths'] = ','.join([template_dir,
                config.get('extra_template_paths', '')])

    def package_form(self):
        return 'forms/ottawa_dataset_form.html'

    def read_template(self):
        return 'package/read.html'

    def is_fallback(self):
        return True

    def package_types(self):
        return ["dataset"]

    def form_to_db_schema(self):
        """
        Returns the schema for mapping package data from a form to a format
        suitable for the database.
        """
        schema = ckan.logic.schema.form_to_db_package_schema()

        schema.update({'titre': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'organisme': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'resume': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'date_published': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'update_frequency': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'frequence_a_jour': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'accuracy': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'exactitude': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'attributes': [validators.ignore_missing, unicode, converters.convert_to_extras]})
        schema.update({'supplementaires': [validators.ignore_missing, unicode, converters.convert_to_extras]})

        schema.update({'__junk': [validators.ignore]})

        return schema

    def db_to_form_schema(self):
        """
        Returns the schema for mapping package data from the database into a
        format suitable for the form (optional)
        """
        schema = ckan.logic.schema.db_to_form_package_schema()

        schema.update({'titre': [converters.convert_from_extras, validators.ignore_missing, unicode]})
        schema.update({'organisme': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'resume': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'date_published': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'update_frequency': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'frequence_a_jour': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'accuracy': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'exactitude': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'attributes': [converters.convert_from_extras, unicode, validators.ignore_missing]})
        schema.update({'supplementaires': [converters.convert_from_extras, unicode, validators.ignore_missing]})

        # Put a few more keys into the schema so they don't get removed by
        # validation. This stops the user profile page from crashing when the
        # user has some datasets.
        schema.update({'isopen': [validators.ignore_missing]})
        schema['tags'] = {
            'name': [validators.not_missing,
                    validators.not_empty,
                    unicode,
                    ],
            'vocabulary_id': [validators.ignore_missing, unicode],
            'revision_timestamp': [validators.ignore],
            'state': [validators.ignore],
            'display_name': [validators.ignore_missing, unicode],
            }
        schema.update({'tracking_summary': [validators.ignore_missing]})

        # This fixes a crash when viewing historical versions of datasets.
        schema.update({'revision_id': [validators.ignore_missing, unicode]})
        schema.update({'revision_timestamp':
            [validators.ignore_missing, unicode]})

        return schema

    def setup_template_variables(self, context, data_dict):
        data_dict.update({'available_only': True})

        toolkit.c.groups_available = toolkit.c.userobj and \
            toolkit.c.userobj.get_groups('organization') or []
        toolkit.c.licences = [('', '')] + base.model.Package.get_license_options()
        toolkit.c.is_sysadmin = authz.Authorizer().is_sysadmin(toolkit.c.user)

        ## This is messy as auths take domain object not data_dict
        context_pkg = context.get('package', None)
        pkg = context_pkg or toolkit.c.pkg
        if pkg:
            try:
                if not context_pkg:
                    context['package'] = pkg
                logic.check_access('package_change_state', context)
                toolkit.c.auth_for_change_state = True
            except logic.NotAuthorized:
                toolkit.c.auth_for_change_state = False


import csv

def get_averages(csv):
    cpu = 0.0
    ram = 0.0
    counter = 0
    try:
        file = open(csv, 'r')
    except:
        print('não existe')
        return
    lines = file.readlines()
    for line in lines:
        if not line.count(',')==3:
            continue
        temparray = line.split(',')
        counter += 1
        cpu += float(temparray[2])
        ram += float(temparray[3])

    try:
        finalCPU = cpu/counter
        finalRAM = ram/counter
        strCPU = str(finalCPU)
        strRAM = str(finalRAM)
        strCPU=strCPU.replace('.', ',',1)
        strRAM=strRAM.replace('.', ',',1)
        print(strRAM + "" + strCPU)
    except:
        print('estourei')
        # rows_of_numbers = [map(float, line.split(',')) for line in lines]
        # sums = map(sum, zip(*rows_of_numbers))
        # averages = [sum_item / len(lines) for sum_item in sums]
        # return averages

path = "C:/Users/Rtorres/Documents/ASSO/ASSO19_Proj"
client_server = 'Server'
protocol = 'MQTTPublisher'
machine = '30%cap'

fileSize = 1024
numberMessages = 2048
csv = "".join([path, "/", client_server, "/", machine, "/",
               protocol, "-", str(fileSize), "-", str(numberMessages), ".csv"])
get_averages(csv)


def collect_grades() -> list:
    journal = [[] for i in range(18)]
    for i in range(18):
        msg = f'Введите оценки {i+1} ученика: '
        while True:
            try:
                a, b, c = [int(x) for x in input(msg).split()]
                break
            except ValueError:
                print('Используйте целые числа')
        journal[i] = [a, b, c,]
    return(journal)

# a
def calc_a_grades(my_list:list) -> int:
    a_grades = [1 for record in my_list for i in record if i == 5]
    return(len(a_grades))

# grades = collect_grades()

# print(calc_a_grades(grades))

# b
def calc_c_grades(my_list:list) -> list:
    c_grades = [record.count(3) for record in my_list]
    return(c_grades)

# c
def calc_d_grades(my_list) -> list:
    subj_one = [1 for record in my_list if record[0] == 2]
    subj_two = [1 for record in my_list if record[1] == 2]
    subj_three = [1 for record in my_list if record[2] == 2]
    return([subj_one, subj_two, subj_three,])


import boto3

s3 = boto3.client('s3')

bucket_name = "harshabucketpython134"
region = "us-west-2"

s3.create_bucket(
    Bucket=bucket_name,
    CreateBucketConfiguration={
        'LocationConstraint': region
    }
)

s3.put_object(
    Bucket=bucket_name,
    Key='index.html',
    Body=b'
Hello World!
',
    ContentType='text/html'
)

print("Static website deployed successfully on S3!")


"""Skill Mix Data Source."""
from asgiref.sync import sync_to_async
from toga.sources import Source
from roster.rosters.models import StaffRule, StaffRuleShift, DayGroup, Shift
from roster.users.models import CustomUser

class ShiftSequenceItem:
    """A class to wrap individual shift sequence rules.

    Attribute names must match table headings
    (after lower case conversion and swapping spaces for underscores)
    """

    def __init__(
        self,
        id,
        sequence_name,
        day_group,
        staff,
        invalid_sequences,
    ):
        self.id = id
        self.sequence_name = sequence_name
        self.day_group = day_group
        self.staff = staff
        self.invalid_sequences = invalid_sequences

class ShiftSequenceSource(Source):
    def __init__(self):
        super().__init__()
        self._sequences = []
        for sequence_db in StaffRule.objects.all():
            shift_positions_db = StaffRuleShift.objects.filter(
                staffrule=sequence_db
            ).order_by("position", "shift")
            invalid_sequences = []
            for shift_position in shift_positions_db:
                if shift_position.shift is not None:
                    invalid_sequences.append(
                        (
                            shift_position.position,
                            shift_position.shift.shift_type,
                        )
                    )
                else:
                    invalid_sequences.append((shift_position.position, "X"))
            sequence = ShiftSequenceItem(
                sequence_db.id,
                sequence_db.staffrule_name,
                sequence_db.daygroup.name,
                [
                    (staff_member.last_name, staff_member.first_name)
                    for staff_member in sequence_db.staff.all()
                ],
                invalid_sequences,
            )
            self._sequences.append(sequence)

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

    def __getitem__(self, index):
        return self._sequences[index]

    def index(self, entry):
        return self._sequences.index(entry)

    async def add(self, entry):
        # Using dummy id of 999 which will be updated after DB insertion
        sequence = ShiftSequenceItem(999, *entry)
        self._sequences.append(sequence)
        day_group_db = await DayGroup.objects.aget(name=sequence.day_group)
        sequence_db = await StaffRule.objects.acreate(
            staffrule_name=sequence.sequence_name,
            daygroup=day_group_db,
        )
        for invalid_sequence in sequence.invalid_sequences:
            position = invalid_sequence[0]
            if invalid_sequence[1] != "X":
                shift_db = await Shift.objects.aget(
                    shift_type=invalid_sequence[1]
                )
            else:
                shift_db = None
            await StaffRuleShift.objects.acreate(
                staffrule=sequence_db, shift=shift_db, position=position
            )
        for staff_member in sequence.staff:
            staff_member_db = await CustomUser.objects.aget(
                last_name=staff_member[0], first_name=staff_member[1]
            )
            await sync_to_async(sequence_db.staff.add)(staff_member_db)
        sequence.id = sequence_db.id

        self._sequences.sort(key=lambda s: s.sequence_name)
        self._notify(
            "insert",
            index=self._sequences.index(sequence),
            item=sequence,
        )

    async def change(self, item):
        index = self.index(item)
        sequence_db = await StaffRule.objects.aget(id=item.id)
        sequence_db.staffrule_name = item.sequence_name
        sequence_db.daygroup = await DayGroup.objects.aget(name=item.day_group)
        await sync_to_async(sequence_db.save)()
        await sync_to_async(sequence_db.staff.set)([])
        for staff_member in item.staff:
            staff_member_db = await CustomUser.objects.aget(
                last_name=staff_member[0], first_name=staff_member[1]
            )
            await sync_to_async(sequence_db.staff.add)(staff_member_db)

        staff_rule_shifts_db = StaffRuleShift.objects.filter(
            staffrule=sequence_db
        )
        await sync_to_async(staff_rule_shifts_db.delete)()
        for invalid_sequence in item.invalid_sequences:
            position = invalid_sequence[0]
            if invalid_sequence[1] != "X":
                shift_db = await Shift.objects.aget(
                    shift_type=invalid_sequence[1]
                )
            else:
                shift_db = None
            await StaffRuleShift.objects.acreate(
                staffrule=sequence_db, shift=shift_db, position=position
            )
        self._notify("insert", index=index, item=item)

    async def remove(self, item):
        index = self.index(item)
        self._notify("pre_remove", index=index, item=item)
        sequence = await StaffRule.objects.aget(id=self._sequences[index].id)
        await sync_to_async(sequence.delete)()
        del self._sequences[index]
        self._notify("remove", index=index, item=item)

    async def refresh(self):
        self.clear()
        async for sequence_db in StaffRule.objects.all():
            shift_positions_db = StaffRuleShift.objects.filter(
                staffrule=sequence_db
            ).order_by("position", "shift")
            invalid_sequences = []
            async for shift_position in shift_positions_db:
                if shift_position.shift is not None:
                    invalid_sequences.append(
                        (
                            shift_position.position,
                            shift_position.shift.shift_type,
                        )
                    )
                else:
                    invalid_sequences.append((shift_position.position, "X"))
            sequence = ShiftSequenceItem(
                sequence_db.id,
                sequence_db.staffrule_name,
                sequence_db.daygroup.name,
                [
                    (staff_member.last_name, staff_member.first_name)
                    async for staff_member in sequence_db.staff.all()
                ],
                invalid_sequences,
            )
            self._sequences.append(sequence)
            self._sequences.sort(key=lambda s: s.sequence_name)
        # Only need to notify about one change ????
        if len(self._sequences) > 0:
            self._notify(
                "insert",
                index=0,
                item=self._sequences[0],
            )

    def clear(self):
        self._sequences = []
        self._notify("clear")

shift_sequence_source = ShiftSequenceSource()


# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

# useful for handling different item types with a single interface
#from itemadapter import ItemAdapter
from sqlalchemy import create_engine, Column, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

Base = declarative_base()
class Quote(Base):
    __tablename__ ='quote'
    id = Column(Integer, primary_key=True)
    text  = Column(Text)
    author = Column(String(200))
    tags = Column(String(400))

class QuotesToDBPipeline:

    def open_spider(self, spider):
        # Создание "движка" алхимии.
        engine = create_engine('sqlite:///sqlite.db')
        # Создание всех таблиц.
        Base.metadata.create_all(engine)
        # Создание сессии как атрибута объекта.
        self.session = Session(engine)

    def process_item(self, item, spider):
        # Создание объекта цитаты.
        quote = Quote(
            text=item['text'],
            author=item['author'],
            tags=', '.join(item['tags']),
        )
        # Добавление объекта в сессию и коммит сессии.
        self.session.add(quote)
        self.session.commit()
        # Возвращаем item, чтобы обработка данных не прерывалась.
        return item

    def close_spider(self, spider):
        self.session.close()


from rest_framework.response import Response

from rest_framework import viewsets, status, generics

from fifa.serializers import CoachingStaffSerializer
from fifa.models import Team, Country, CoachingStaff, Player
from fifa.utils import (
    validate_country,
    validate_team,
    validate_team_by_id,
    to_bool,
    validate_player_create,
    validate_position_exist,
    convert_date,
    get_positions,
    validate_rol_exist,
    get_rol,
    validate_nacionality_exist,
    calculate_age,
)

class CoachingStaffViewSet(viewsets.ModelViewSet):
    serializer_class = CoachingStaffSerializer
    queryset = CoachingStaff.own_manager.get_all_coaching()

    def list(self, request):
        id_coaching = request.GET.get("id")
        if id_coaching:
            get_coaching = CoachingStaff.own_manager.get_coaching_by_id(id_coaching)
            if get_coaching:
                serializer_context = {
                    "request": request,
                }
                serializer = CoachingStaffSerializer(
                    get_coaching.get(), many=False, context=serializer_context
                )
                if serializer:
                    return Response(serializer.data, status=status.HTTP_200_OK)
            else:
                return Response(
                    {
                        "response": f"No existe el coaching {id_coaching} en la base de datos"
                    }
                )

        else:
            all_coaching = CoachingStaff.own_manager.get_all_coaching()
            if not all_coaching:
                return Response(
                    {"respuesta": "No hay cuerpo tecnico en la base de datos!"}
                )
            return Response(all_coaching)

    def create(self, request, *args, **kwargs):
        data = request.data
        res = {}
        try:
            if (
                data["name"]
                and data["last_name"]
                and data["birth_date"]
                and data["nacionality_id"]
                and data["rol"]
                and data["team_id"]
            ):
                country = validate_nacionality_exist(data["nacionality_id"])
                if not country:
                    res[
                        "respuesta"
                    ] = f"El pais con el id {data['nacionality_id']} no existe en la base de datos"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                # Validate team_id

                team = Team.own_manager.get_team_by_id(data["team_id"])
                if not team:
                    res[
                        "respuesta"
                    ] = f"El equipo con el id {data['team_id']} no existe en la base de datos"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                # Validate birth date
                date = convert_date(data["birth_date"])
                if not date:
                    res[
                        "respuesta"
                    ] = "Recuerde el formato fecha YYYY-MM-DD (AÑO-MES-DIA)"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)

                age = calculate_age(date)
                if age < 15:
                    res[
                        "respuesta"
                    ] = "El coach que desea inscribir no puede tener menos de 15 años"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)

                rol = validate_rol_exist(data["rol"])
                if not rol:
                    res[
                        "respuesta"
                    ] = f"Recuerde que los roles permitidos son {get_rol()}"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                new_coach = CoachingStaff.own_manager.create_coach(
                    data, country.get().id, rol, team.get().id
                )
                new_coach.save()
                return Response({"respuesta": "Cuerpo tecnico creado correctamente!"})
        except KeyError as e:
            res[str(e)] = "Este campo es requerido"
        return Response(res, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        coaching = CoachingStaff.own_manager.get_coaching_by_id(kwargs["pk"]).first()
        res = {}
        if coaching:
            data = request.data

            # Validamos birth_date
            if "birth_date" in data:
                date = convert_date(data["birth_date"])
                if not date:
                    res[
                        "respuesta"
                    ] = "Recuerde el formato fecha YYYY-MM-DD (AÑO-MES-DIA)"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                age = calculate_age(date)

                if age < 15:
                    res[
                        "respuesta"
                    ] = "El coach que desea inscribir no puede tener menos de 15 años"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)

                if date != coaching.birth_date:
                    coaching.birth_date = date

            if "nacionality_id" in data:
                if data["nacionality_id"] != coaching.nacionality_id:
                    # Validar si la nacionalidad existe
                    country = validate_nacionality_exist(data["nacionality_id"])
                    if not country:
                        res[
                            "respuesta"
                        ] = f"El pais con el id {data['nacionality_id']} no existe en la base de datos"
                        return Response(res, status=status.HTTP_400_BAD_REQUEST)
                    coaching.nacionality_id = country.get().id
                else:
                    pass
            # Validamos el rol
            if "rol" in data:
                rol = validate_rol_exist(data["rol"])
                if not rol:
                    res[
                        "respuesta"
                    ] = f"Recuerde que los roles permitidos son {get_rol()}"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                coaching.rol = rol

            # Validamos si el equipo existe
            if "team_id" in data:
                team = Team.own_manager.get_team_by_id(data["team_id"])
                if not team:
                    res[
                        "respuesta"
                    ] = f"El equipo con el id {data['team_id']} no existe en la base de datos"
                    return Response(res, status=status.HTTP_400_BAD_REQUEST)
                coaching.team_id = team.get().id
            coaching.name = data.get("name", coaching.name)
            coaching.last_name = data.get("last_name", coaching.last_name)
            coaching.save()
            serializer = CoachingStaffSerializer(coaching)
            return Response(serializer.data)
        return Response(
            {"respuesta": f"No se encuentra el coaching con el id {kwargs['pk']}"}
        )

    def destroy(self, request, *args, **kwargs):
        coaching = CoachingStaff.own_manager.get_coaching_by_id(kwargs["pk"]).first()
        if coaching:
            coaching.delete()
            return Response({"respuesta": "Cuerpo tecnico eliminado correctamente"})
        return Response(
            {"respuesta": f"No se encuentra el cuerpo tecnico con el id {kwargs['pk']}"}
        )


import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.gridspec as gridspec

def sim_kf_predict(sim_opt, KalmanFilter, light_state):
    start = time.perf_counter()
    # Simulator Options
    ALLOW_SPEEDING = sim_opt['ALLOW_SPEEDING']
    FIG_SIZE = sim_opt['FIG_SIZE']  # [Width, Height]

    kalman_filter = KalmanFilter()

    def motion(t0, dt, state, u_pedal):
        if len(state) == 0:
            x0 = 55
            y0 = 3
            v0 = 5
            theta0 = 0
            theta_dot0 = 0
        else:
            x0 = state[-1][0]
            y0 = state[-1][1]
            v0 = state[-1][2]
            theta0 = state[-1][3]
            theta_dot0 = state[-1][4]

        u_steer = 0

        x1 = x0 + v0*np.cos(theta0)*dt
        y1 = y0 + v0*np.sin(theta0)*dt
        v1 = (-v0 + 1.0*u_pedal)/0.8*dt + v0
        theta1 = theta_dot0*dt + theta0
        theta_dot1 = u_steer

        return [x1, y1, v1, theta1, theta_dot1]

    state = []
    est_data_t = []
    x_est_data = []
    noise_data = []
    u_pedal = 5
    predict_x = []
    light_time = [4.5,4.7,4.8,5.0,5.2]
    light_time = light_time[light_state]
    print(light_time)
    first_prediction = True

    t = np.linspace(0.0,100,1001)
    dt = 0.1
    for t0 in t:
        state += [motion(t0,dt,state,u_pedal)]
        if True:#t0%1.0 == 0.0:
            est_data_t += [t0]
            # Measure car location.
            state_with_noise = []
            state_with_noise += [state[-1][0]+(np.random.rand(1)[0]-0.5)*0.5]
            state_with_noise += [state[-1][1]+(np.random.rand(1)[0]-0.5)*0.5]
            noise_data += [state_with_noise]

            if t0 == 0.0:
                x_est_data += [[0,0]]
                continue
            kalman_filter.predict(t0)
            x_est_data += [kalman_filter.measure_update(state_with_noise, t0)]
            if t0 >= light_time and first_prediction:
                if not ALLOW_SPEEDING:
                    predict_x = kalman_filter.predict_light(95)
                else:
                    predict_x = kalman_filter.predict_light_speeding(95)
                if not predict_x[0]:
                    u_pedal = 0
                elif ALLOW_SPEEDING:
                    u_pedal = 6
                first_prediction = False

    ###################
    # DISPLAY

    # Total Figure
    fig = plt.figure(figsize=(FIG_SIZE[0], FIG_SIZE[1]))
    gs = gridspec.GridSpec(10,10)

    # Elevator plot settings.
    ax = fig.add_subplot(gs[:10, :10])

    plt.xlim(60, 110)
    ax.set_ylim([-20, 30])
    plt.xticks([])
    plt.yticks([])
    plt.title('Kalman 2D')

    # Main plot info.
    car, = ax.plot([], [], 'b-', linewidth = 5)
    light, = ax.plot([94,94], [4,2] , 'g-', linewidth = 3)
    est, = ax.plot([], [], 'ks', markersize=5, fillstyle='full', linewidth=4)
    est_light, = ax.plot([], [], 'g--', linewidth=1)
    meas, = ax.plot([], [], 'gs', markersize=30, fillstyle='none', linewidth=4)

    # First section.
    ax.plot([1,1], [9,1], 'k-')
    ax.plot([1,87], [9, 9], 'k-')
    ax.plot([1,85], [5,5], 'k--')
    ax.plot([1,95], [1,1], 'k-')
    ax.plot([87,87], [9,1], 'k--')

    # First intersection.
    ax.plot([95,110], [9, 9], 'k-')
    ax.plot([97,110], [5,5], 'k--')
    ax.plot([95,110], [1,1], 'k-')
    ax.plot([95,95], [9,1], 'k--')

    # Second section.
    ax.plot([87,87], [9, 87], 'k-')
    ax.plot([91,91], [11, 85], 'k--')
    ax.plot([95,95], [9, 87], 'k-')
    ax.plot([87,95], [9,9], 'k--')

    #second intersection.
    ax.plot([87,95], [87,87], 'k--')
    ax.plot([87,87], [87,95], 'k--')
    ax.plot([87,95], [95,95], 'k--')

    ax.plot([87,87], [95, 110], 'k-')
    ax.plot([91,91], [97, 110], 'k--')
    ax.plot([95,95], [87, 110], 'k-')
    ax.plot([92,94], [94,94] , 'g-', linewidth = 3)

    # Final Section.
    ax.plot([87,2], [87,87], 'k-')
    ax.plot([87,2], [91,91], 'k--')
    ax.plot([87,2], [95,95], 'k-')
    ax.plot([2,2], [95,87], 'k-')

    def update_plot(num):
        t_loc = int(t[num])

        # Car.
        car_loc = [state[num][0], state[num][1]]
        car_ang = state[num][3]
        car_cos = np.cos(car_ang)
        car_sin = np.sin(car_ang)
        car.set_data([car_loc[0], car_loc[0]+2*car_cos],
                        [car_loc[1], car_loc[1]+2*car_sin])
        # car_zoom.set_data([car_loc[0], car_loc[0]+2*car_cos],
        #                 [car_loc[1], car_loc[1]+2*car_sin])
        # axins.set_xlim(car_loc[0]-5, car_loc[0]+5)
        # axins.set_ylim(car_loc[1]-5, car_loc[1]+5)

        est.set_data([x_est_data[num][0]],[x_est_data[num][1]])

        #meas.set_data([noise_data[num][0]],[noise_data[num][1]])
        # est_zoom.set_data([x_est_data[num][0]],[x_est_data[num][1]])
        # meas_zoom.set_data([noise_data[num][0]],[noise_data[num][1]])
        if t_loc >= light_time:
            light.set_color('orange')
            est_light.set_data([predict_x[1], predict_x[1]],[1,9])
        if t_loc >= light_time+3:
            light.set_color('red')

        return car, light

    print("Compute Time: ", round(time.perf_counter() - start, 3), "seconds.")
    # Animation.
    car_ani = animation.FuncAnimation(fig, update_plot,
                                      frames=len(t),
                                      interval=100,
                                      repeat=False,
                                      blit=False)
    # car_ani.save('kf_2d_predict.mp4')

    plt.show()


# Problem: Binary Search

# Function - Search (Iterative)
def search(array, target):
    if not array:
        print("Empty array")

    high = len(array) - 1
    low = 0

    while low <= high:
        mid = int(low + (high - low) / 2)
        if array[mid] == target:
            return mid
        elif array[mid] > target:
            high = mid - 1
        else:
            low = mid + 1
    return -1

# Main Program

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print("Searching 2 in array found at index: %d" % (search(array, 2)))  # random
print("Searching 5 in array found at index: %d" % (search(array, 5)))  # mid
print("Searching 10 in array found at index: %d" % (search(array, 10)))  # last
print("Searching 14 in array found at index: %d" % (search(array, 14)))  # max
print("Searching 1 in array found at index: %d" % (search(array, 1)))  # first
print("Searching 0 in array found at index: %d" % (search(array, 0)))  # min


# -*- coding: utf-8 -*-
import socket

UDP_IP = ""
UDP_PORT = 9000

print("Listening on port ", UDP_PORT )

sock = socket.socket(socket.AF_INET,
                     socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print(data)
    sock.sendto("OK", addr)


import numpy as np
import pandas as pd

#LO_IN_ORDER = ["mcanalysis", "mcmodeling", "interpretresults", "professionalism", "pythonimplementation","caanalysis", "camodeling", "networkanalysis","networkmodeling"]
#CO_IN_ORDER = ["MonteCarlo","MonteCarlo","Simulations","Simulations","Simulations","Cellular Automata","Cellular Automata","Networks","Networks"]
#ASSIGNMENT_TITLES =  ["Elevator simulation",
#                        "Traffic simulation",
#                        "Network simulation",
#                        'Final project proposal',
#                        "Final project"]
#ASSIGNMENT_WEIGHTS = [2, 6, 6, 0, 10]
#DEFAULT_LO_TO_DISPLAY_IN_EVOLUTION = ['networkanalysis', 'networkmodeling']

def process_df(df, params):
    globals().update(params)
    # replace space in header with "_"
    df.rename(columns=lambda x: x.replace(' ', '_'), inplace=True)
    # change HC column to LO and vice versa, due to error in the data
    df.rename(columns={'Learning_Outcome_Name':'HC','HC_Name':'LO' }, inplace=True)
    # removing incomplete instances with no Score data
    # data_simplified <- data_simplified[complete.cases(data_simplified$Score),]
    df.dropna(subset=['Score'], inplace=True)
    def map_CO(row, LO_IN_ORDER, CO_IN_ORDER):
        mapping = dict(zip(LO_IN_ORDER, CO_IN_ORDER))
    #     print(mapping)
        if not pd.isnull(row['LO']):
            return mapping[row['LO']]
        return np.nan
    df['CO'] = df.apply(lambda row: map_CO(row, LO_IN_ORDER, CO_IN_ORDER), axis=1)
    # Add weight column. Current data set does not have weights for scores.
    def map_weight(row, ASSIGNMENT_TITLES, ASSIGNMENT_WEIGHTS):
        mapping = dict(zip(ASSIGNMENT_TITLES, ASSIGNMENT_WEIGHTS))
        if row['Assessment_Type'] != 'assignment':
            return 1
        else:
            return mapping[row['Assignment_Title']]
    df['weight'] = df.apply(lambda row: map_weight(row, ASSIGNMENT_TITLES, ASSIGNMENT_WEIGHTS), axis=1)
    # Add weighted score column
    # data <- mutate(data, weighted_score = Score * weight)
    df['weighted_score'] = df['Score'] * df['weight']
    # drop null in LO column
    df.dropna(subset=['LO'], inplace=True)
    # get data only for a student (student 1 for example)
    list_of_students = df['Student_Name'].unique()
    num_students = len(list_of_students)
    def match_color(val):
        # SET COLOR TO MATCH MINERVA SCHEME
        if 0 < val and val < 2:
            color = '#C83F31'
        elif 2 <= val and val < 3:
            color = '#DB883A'
        elif 3 <= val and val < 4:
            color = '#56A371'
        elif 4 <= val and val < 5:
            color = '#3473B6'
        elif 5 <= val:
            color = '#573F88'
        return color
    def set_color(row, col_name):
        return match_color(row[col_name])

    def split_date_func(df):
        # truncate the Updated Date column so that it contains only the date information
        df['Updated_Date'] = df['Updated_Date'].str.slice(stop=10)

        # convert to DateTime
        df['Updated_Date']= pd.to_datetime(df['Updated_Date'])
        df = df.sort_values(by=['Updated_Date'])
        # summarize the grouped Updated_Date into new columns: 'sum_weighted' and 'tot_weights'
        df = df.groupby('Updated_Date').apply(lambda x: pd.DataFrame({'sum_weighted': x['weighted_score'].sum(),
                                                                 'tot_weights': x['weight'].sum()},
                                                                index=['Updated_Date'])).reset_index()
        df = df.drop(['level_1'], axis=1)
        ###### By this point we have a dataframe with:
          # * date
          # * total weighted scores
          # * total weights
          # What we want to do is taking the running average up to a certain date
          # For date #2, it equals:
          # A/B where
          # A is (total weighted scores of date 1 + total weighted scores of date 2)
          # and B is (total weights of date1 + total weights of date 2)

          ## Idea: we can create
          # * a new column (B) that is the cumsum of the vector column total weights
          # * a new column (A) that is the cumsum of the total weighted scores
          # * the quantity of interest would be A/B
        df['cumsum_tot_weights'] = df['tot_weights'].cumsum(axis=0)
        df['cumsum_sum_weighted'] = df['sum_weighted'].cumsum(axis=0)
        df['running_avg'] = df['cumsum_sum_weighted'] / df['cumsum_tot_weights']
        return df

    def group_by_student(col_name_to_group_by, evolution=True):
        """
        return a list of df, each df corresponds to a student.
        - col_name_to_group_by: 'LO' or 'CO'
        """
        df_list = []

        for i in range(num_students):
            student_name = list_of_students[i]
            student_df = df[df['Student_Name'] == student_name]
            # group by LO or CO
            data_with_avg = student_df.groupby(col_name_to_group_by).apply(func=split_date_func)
            if not evolution: # obtain only the latest average score
                data_with_avg = data_with_avg.groupby(col_name_to_group_by).tail(1)
            data_with_avg.reset_index(inplace=True)

            # map LO to CO
            if col_name_to_group_by == 'LO':
                data_with_avg['CO'] = data_with_avg.apply(lambda row: map_CO(row, LO_IN_ORDER, CO_IN_ORDER), axis=1)
            # set color
            data_with_avg['color'] = data_with_avg.apply (lambda row: set_color(row, 'running_avg'), axis=1)
            df_list.append(data_with_avg)

        return df_list

    # LO Evolution
    LO_evolution_list = group_by_student('LO')
    LO_evolution_data = []
    for i, student_df in enumerate(LO_evolution_list):
        out = {'student_name': list_of_students[i]}
        out['series'] = []
        """
        out['series'] is of str type
        out['series'] = [{'name': 'caanalysis',
                          'data': [[Date.UTC(2020, 0, 28), 4.0], [Date.UTC(2020, 1, 3), 3.5]],
                          'visible': False},
                          {...}]
        """
        for LO, group_df in student_df.groupby('LO'):
            series_info = {'name': LO,
                           'visible': LO in DEFAULT_LO_TO_DISPLAY_IN_EVOLUTION}
            series_info['data'] = []
            for index, row in group_df.iterrows():
                datetime = row['Updated_Date']
                series_info['data'].append(['Date.UTC',(datetime.year, datetime.month-1, datetime.day), row['running_avg']])
            out['series'].append(series_info)
        out['series'] = str(out['series']).replace("'Date.UTC', ", "Date.UTC").replace("False", "false").replace("True", "true")
        LO_evolution_data.append(out)

    # LO average
    def get_average_data(category_col, average_list, data_col='running_avg', color_col='color'):
    #     average_list = group_by_student(col_name_to_group_by, evolution=False)
        average_data = []
        for i, student_df in enumerate(average_list):
            out = {'student_name': list_of_students[i],
                    'categories': list(student_df[category_col]),
                   'mean_of_avg': [np.mean(student_df[data_col])]*student_df.shape[0]}
            """
            out['avg'] = [{'y': 3.5, 'color': '#56A371'},
                          {...},
                          ...]
            """
            out['data'] = []
            for index, row in student_df.iterrows():
                if color_col is None:
                    color = 'black'
                else:
                    color = row[color_col]

                out['data'].append({'y': row[data_col],
                                   'color': color})
            average_data.append(out)
        return average_data
    LO_average_df_list = group_by_student(col_name_to_group_by='LO', evolution=False)
    LO_average_data = get_average_data('LO', LO_average_df_list)
    # LO mean and range for whole class
    def get_summary_stat_data(df_list, val_col):
        summary_stat_data = {'LO': [LO for LO in df['LO'].unique()],
                             'mean': [],
                             'range': []}
        for i, student_df in enumerate(df_list):
            student_df = student_df[['LO', val_col]]
            if i == 0:
                merged_df = student_df
            else:
                merged_df = merged_df.merge(student_df, on='LO')
        merged_df['mean'] = merged_df.loc[:, merged_df.columns != 'LO'].mean(axis=1)
        merged_df['min'] = merged_df.loc[:, merged_df.columns != 'LO'].min(axis=1)
        merged_df['max'] = merged_df.loc[:, merged_df.columns != 'LO'].max(axis=1)
        merged_df['range'] = merged_df.apply(lambda x: [x['min'], x['max']], axis=1)
        summary_stat_data = {'LO': list(merged_df['LO']),
                             'mean': list(merged_df['mean']),
                             'range': list(merged_df['range'])}
        return summary_stat_data
    LO_summary_stat_data = get_summary_stat_data(df_list=LO_average_df_list,
                                                 val_col='running_avg')

    # CO average
    CO_average_df_list = group_by_student(col_name_to_group_by='CO', evolution=False)
    CO_average_data = get_average_data('CO', CO_average_df_list)

    # LO contribution
    ## for indvidual student
    contrib_df_list = []
    for i, m in enumerate(zip(LO_average_df_list, CO_average_df_list)):
        # lookup CO table from LO table
        LO_df, CO_df = m
        num_CO = CO_df.shape[0]
        contrib_df = LO_df.merge(CO_df, on="CO")
        contrib_df['LO_contrib'] = contrib_df['cumsum_sum_weighted_x']/contrib_df['cumsum_tot_weights_y']/num_CO/np.mean(CO_df['running_avg'])
        contrib_df = contrib_df[['LO', 'LO_contrib']]
        contrib_df_list.append(contrib_df)
    # print(contrib_df_list[0])
    LO_contrib_data = get_average_data('LO', contrib_df_list, data_col='LO_contrib', color_col=None)

    ## summary stats for whole class
    contrib_summary_stat_data = get_summary_stat_data(df_list=contrib_df_list,
                                                 val_col='LO_contrib')
    return LO_evolution_data, LO_summary_stat_data, LO_average_data, CO_average_data, contrib_summary_stat_data, LO_contrib_data
#    i = 0
#    lo_evolution_data = []
#    intermediate_whole_class_lo_data = {LO: [] for LO in df['LO'].unique()}
#    # data for plotting LO averages
#    LO_avg_data = []
#
#    def match_color(val):
#        # SET COLOR TO MATCH MINERVA SCHEME
#        if 0 < val and val < 2:
#            color = '#C83F31'
#        elif 2 <= val and val < 3:
#            color = '#DB883A'
#        elif 3 <= val and val < 4:
#            color = '#56A371'
#        elif 4 <= val and val < 5:
#            color = '#3473B6'
#        elif 5 <= val:
#            color = '#573F88'
#        return color
#    def split_date_func(df):
#        # truncate the Updated Date column so that it contains only the date information
#        df['Updated_Date'] = df['Updated_Date'].str.slice(stop=10)
#
#        # convert to DateTime
#        df['Updated_Date']= pd.to_datetime(df['Updated_Date'])
#    #     print(df[['Updated_Date','LO']])
#        df = df.sort_values(by=['Updated_Date'])
#    #     print(df[['Updated_Date','LO']])
#    #         print('-'*10)
#    #     print(df['Updated_Date'])
#        # summarize the grouped Updated_Date into new columns: 'sum_weighted' and 'tot_weights'
#        df = df.groupby('Updated_Date').apply(lambda x: pd.DataFrame({'sum_weighted': x['weighted_score'].sum(),
#                                                                 'tot_weights': x['weight'].sum()},
#                                                                index=['Updated_Date'])).reset_index()
#        df = df.drop(['level_1'], axis=1)
#    #     print(df)
#        ###### By this point we have a dataframe with:
#          # * date
#          # * total weighted scores
#          # * total weights
#          # What we want to do is taking the running average up to a certain date
#          # For date #2, it equals:
#          # A/B where
#          # A is (total weighted scores of date 1 + total weighted scores of date 2)
#          # and B is (total weights of date1 + total weights of date 2)
#
#          ## Idea: we can create
#          # * a new column (B) that is the cumsum of the vector column total weights
#          # * a new column (A) that is the cumsum of the total weighted scores
#          # * the quantity of interest would be A/B
#        df['cumsum_tot_weights'] = df['tot_weights'].cumsum(axis=0)
#        df['cumsum_sum_weighted'] = df['sum_weighted'].cumsum(axis=0)
#        df['running_avg'] = df['cumsum_sum_weighted'] / df['cumsum_tot_weights']
#    #        print(df)
#        return df
#
#
#    for i in range(num_students):
#        student_name = list_of_students[i]
#        student_df = df[df['Student_Name'] == student_name]
#        # group by LO
#        col_name_to_group_by = 'LO'
#
#        data_with_avg_LO = student_df.groupby(col_name_to_group_by).apply(func=split_date_func)
#        # map LO to CO
#        data_with_avg_LO.reset_index(inplace=True)
#        data_with_avg_LO['CO'] = data_with_avg_LO.apply(lambda row: map_CO(row, LO_IN_ORDER, CO_IN_ORDER), axis=1)
#        agg = {LO: {'visible': False, 'content': []} for LO in data_with_avg_LO['LO'].unique()}
#        for index, row in data_with_avg_LO.iterrows():
#            time_info = (row['Updated_Date'].year, row['Updated_Date'].month-1, row['Updated_Date'].day)
#            if row['LO'] in DEFAULT_LO_TO_DISPLAY_IN_EVOLUTION:
#                visible = True
#            else:
#                visible = False
#            agg[row['LO']]['visible'] = visible
#            agg[row['LO']]['content'].append(['mark',time_info, row['running_avg']])
#
#        series = []
#        for k, v in agg.items():
#            series.append({'name':k,
#                           'data': v['content'],
#                           'visible': v['visible']})
#            intermediate_whole_class_lo_data[k].append(v['content'][-1][-1])
#        LO_avg_this_student = {}
#        LO_avg_this_student['student_name'] = student_name
#        LO_avg_this_student['LO'] = []
#        LO_avg_this_student['LO_avg'] = []
#        LO_avg_this_student['color'] = []
#        for LO in series:
#            LO_avg_this_student['LO'].append(LO['name'])
#
#            # SET COLOR TO MATCH MINERVA SCHEME
#            color = match_color(LO['data'][-1][-1])
#            LO_avg_this_student['LO_avg'].append({'y': LO['data'][-1][-1],
#                                                  'color': color})
#    #         LO_avg_this_student['color'].append(color)
#
#
#        LO_avg_data.append(LO_avg_this_student)
#
#        series = str(series).replace("'mark', ", "Date.UTC")
#        series = series.replace("True", 'true')
#        series = series.replace("False", 'false')
#        # add this student's data to data for plotting LO evolution
#        lo_evolution_data.append({'student_name': student_name, 'series': series})
#    # print(lo_evolution_data)
#    # compute summary stats for LO averages for the whole class
#    whole_class_lo_data = {'LO': [], 'mean': [], 'range':[]}
#    # print(len(intermediate_whole_class_lo_data['pythonimplementation']))
#    for k, v in intermediate_whole_class_lo_data.items():
#        whole_class_lo_data['LO'].append(k)
#        # compute mean
#        mean = np.mean(v)
#        whole_class_lo_data['mean'].append(mean)
#        # compute range
#        min_val = np.min(v)
#        max_val = np.max(v)
#        whole_class_lo_data['range'].append([min_val, max_val])
#
#
#    CO_avg_data = []
#    for i in range(num_students):
#        student_name = list_of_students[i]
#        student_df = df[df['Student_Name'] == student_name]
#        # group by CO
#        col_name_to_group_by = 'CO'
#
#        data_CO_evolution = student_df.groupby(col_name_to_group_by).apply(func=split_date_func)
#        data_CO_avg = data_CO_evolution.groupby(col_name_to_group_by).tail(1)
#        data_CO_avg.reset_index(inplace=True)
#    #     data_with_avg_CO.reset_index(inplace=True)
#    #     data_with_avg_LO['CO'] = data_with_avg_LO.apply(lambda row: map_CO(row, LO_IN_ORDER, CO_IN_ORDER), axis=1)
#    # data_with_avg_CO.head()
#
#        CO_avg_this_student = {}
#        CO_avg_this_student['student_name'] = student_name
#        CO_avg_this_student['CO'] = []
#        CO_avg_this_student['CO_avg'] = []
#        CO_avg_this_student['color'] = []
#        CO_avg_this_student['course_avg'] = [np.mean(data_CO_avg['running_avg'])]*data_CO_avg.shape[0]
#        for index, row in data_CO_avg.iterrows():
#            CO_avg_this_student['CO'].append(row['CO'])
#            # SET COLOR TO MATCH MINERVA SCHEME
#            color = match_color(row['running_avg'])
#            CO_avg_this_student['CO_avg'].append({'y': row['running_avg'],
#                                                  'color': color})
#        CO_avg_data.append(CO_avg_this_student)
#
#    # LO contribution
#    intermediate_data_whole_class_LO_contrib = {LO: [] for LO in df['LO'].unique()}
#    LO_contrib_data = []
#    # print(intermediate_data_whole_class_LO_contrib)
#    for i in range(num_students):
#        student_name = list_of_students[i]
#        student_df = df[df['Student_Name'] == student_name]
#        # group by CO
#        col_name_to_group_by = 'CO'
#        data_with_avg_CO = student_df.groupby(col_name_to_group_by).apply(func=split_date_func)
#        data_with_avg_CO = data_with_avg_CO.groupby(col_name_to_group_by).tail(1)
#        data_with_avg_CO.reset_index(inplace=True)
#        num_CO = data_with_avg_CO.shape[0]
#
#        # group by LO
#        col_name_to_group_by = 'LO'
#        data_with_avg_LO = student_df.groupby(col_name_to_group_by).apply(func=split_date_func)
#        data_with_avg_LO = data_with_avg_LO.groupby(col_name_to_group_by).tail(1)
#        data_with_avg_LO.reset_index(inplace=True)
#        # map LO to CO
#        data_with_avg_LO['CO'] = data_with_avg_LO.apply(lambda row: map_CO(row, LO_IN_ORDER, CO_IN_ORDER), axis=1)
#
#        # lookup CO table from LO table
#        data_with_avg_LO = data_with_avg_LO.merge(data_with_avg_CO, on="CO")
#        data_with_avg_LO['LO_contrib'] = data_with_avg_LO['cumsum_sum_weighted_x']/data_with_avg_LO['cumsum_tot_weights_y']/num_CO/np.mean(data_with_avg_CO['running_avg'])
#        for k,v in data_with_avg_LO.iterrows():
#            intermediate_data_whole_class_LO_contrib[v['LO']].append(v['LO_contrib'])
#
#        LO_contrib_data_this_student = {}
#        LO_contrib_data_this_student['LO'] = list(data_with_avg_LO['LO'])
#        LO_contrib_data_this_student['LO_avg'] = list(data_with_avg_LO['LO_contrib'])
#        LO_contrib_data_this_student['student_name'] = student_name
#        LO_contrib_data.append(LO_contrib_data_this_student)
#
#    # compute summary stats for LO averages for the whole class
#    whole_class_lo_contrib_data = {'LO': [], 'mean': [], 'range':[]}
#    for k, v in intermediate_data_whole_class_LO_contrib.items():
#        whole_class_lo_contrib_data['LO'].append(k)
#        # compute mean
#        mean = np.mean(v)
#        whole_class_lo_contrib_data['mean'].append(mean)
#        # compute range
#        min_val = np.min(v)
#        max_val = np.max(v)
#        whole_class_lo_contrib_data['range'].append([min_val, max_val])

#    return lo_evolution_data, whole_class_lo_data, LO_avg_data, CO_avg_data, whole_class_lo_contrib_data, LO_contrib_data


import logging
import utils

class IcuStay(object):
    """
    class that reads information from the icu_stay.csv file. a patient might have multiple icu stays
    The hospital and ICU databases are not intrinsically linked and so do not have any concept of an ICU encounter
     identifier.
        Attributes:
            - ICUSTAY_ID: unique to a patient ICU stay
            - DBSOURCE : DBSOURCE contains the original ICU database the data was sourced from.
            - FIRST_CAREUNIT :  the first  ICU type in which the patient was cared for. As an ICUSTAY_ID groups
             all ICU admissions within 24 hours of each other, it is possible for a patient to be transferred from one
             type of ICU to another and have the same ICUSTAY_ID.
            - LAST_CAREUNIT : the last  ICU type in which the patient was cared for.
            - FIRST_WARDID : contain the first ICU unit in which the patient stayed. Note the grouping of
            physical locations in the hospital database is referred to as ward. Though in practice ICUs are not
            referred to as wards, the hospital database technically tracks ICUs as "wards with an ICU cost center".
            As a result, each ICU is associated with a WARDID
            - contain the last ICU unit in which the patient stayed.
            - INTIME: provides the date and time the patient was transferred into the ICU.
            - OUTTIME: provides the date and time the patient was transferred out of the ICU.
            - LOS: is the length of stay for the patient for the given ICU stay, which may include one or more ICU units
            - was_tranferd : boolean indecating if the patient was transfered during his icu stay.

            - time_series : dictionary that each key is a time and the value is a doctionay of events that happend at
            that time.

    """
    def __init__(self, icu_stay_id, db_source, first_care_u, last_care_u, first_ward_id, last_ward_id, in_time,
                 out_time, len_of_stay):
        """Init Patient with all the attributes defined in the patients.csv file."""
        self.icu_stay_id = int(icu_stay_id)
        self.db_source = db_source
        self.first_care_u = first_care_u
        self.last_care_u = last_care_u
        self.first_ward_id = first_ward_id
        self.last_ward_id = last_ward_id
        self.in_time = utils.convert_to_date_time_object(in_time)
        self.out_time = utils.convert_to_date_time_object(out_time)
        self.len_of_stay = len_of_stay
        if self.len_of_stay != '':
            self.len_of_stay = float(len_of_stay)

        self.was_tranferd = ((self.first_ward_id != self.last_ward_id) or (self.first_care_u != self.last_care_u))

        self.time_series = {}

    def add_event(self, event):
        """
        adds an event object to a patient.
        :param event:
        :return:
        """
        event_time = event.chart_time
        if event_time in self.time_series.keys():
            if event.item_id in self.time_series[event_time].keys():
                logging.warning("item_id %d was already inserted in the current time %s", event.item_id, str(event_time))
                # raise ValueError("item_id %d was already inserted in the current time %s", event.item_id,
                #                 str(event_time))

            self.time_series[event_time][event.item_id] = event

        else:
            self.time_series[event_time] = {}
            self.time_series[event_time][event.item_id] = event

        return


from service.MapResources import Service_MapResources
from service.Town import Service_Town
import helpers.MapCoordinate

class AbstractResourceController(object):
    def _getParamsAclJsonPackMapResources(self):
        return Service_MapResources().decorate(Service_MapResources.JSONPACK_ACL)

class ModelController(AbstractResourceController):
    def get(self, transfer, data):
        result = {}
        result['done'] = True
        result['data'] = self._getParamsAclJsonPackMapResources().getResourceByPosition(
            helpers.MapCoordinate.MapCoordinate(posId=data['posId']),
            transfer.getUser()
        )

        transfer.send('/model/map_resources/get', result)

class DeliveryController(AbstractResourceController):
    def resourcesUpdate(self, town, resources):
        town.getUser().getTransfer().forceSend('/delivery/mapResourcesUpdate', {
            'done': True,
            'resources': resources
        })

class CeleryPrivateController(AbstractResourceController):
    def resourceDown(self):
        serviceTown = Service_Town()
        serviceMapResources = Service_MapResources()
        serviceMapResourcesJsonPack = Service_MapResources().getDecorateClass(Service_MapResources.JSONPACK)
        deliveryController = DeliveryController()

        townCollection = serviceTown.getAllTownsCollection()
        for town in townCollection:
            resources = serviceMapResources.getResourceByTown(town)
            townBonus = town.getBonus()
            sendResources = []

            for resource in resources:
                serviceMapResources.resourceDown(resource)
                sendResources.append(
                    serviceMapResourcesJsonPack.packDomainToJson(resource)
                )

            deliveryController.resourcesUpdate(town, sendResources)


import os
import re
import shutil
from pathlib import Path
import pydicom
import glob

def move_file(curr_dir,des_dir,new_file_name = None):
    if (new_file_name is None):
        shutil.move(curr_dir,des_dir)
    else:
        des_dir = os.path.normpath(des_dir)
        des_dir_split = os.path.split(des_dir)
        des_dir = "/".join(des_dir_split[:-1]) + f"/{new_file_name}"
        shutil.move(curr_dir,des_dir)

def move_file_3d(curr_dirs):

    for curr_dir in curr_dirs:
        #filter our the proceesed dataset
        print(f"current directory: {curr_dir}")

        for root, dirs, files in os.walk(curr_dir):
            for file in files:
                if (file.endswith(".dcm") and os.path.split(os.path.normpath(root))[-1].startswith("Loc")):
                    file_path = os.path.join(root, file)
                    des_path = f"{os.path.dirname(root)}/{file}"
                    move_file(file_path, des_path)
                    shutil.rmtree(root)

        for root, dirs, files in os.walk(curr_dir):
            if (len(files) != 0):
                file_name = files[0]
                phase_dir = root
                study_dir = os.path.dirname(phase_dir)
                dicom_image = pydicom.filereader.dcmread(os.path.join(phase_dir, file_name))
                seriesInstanceUID = dicom_image.SeriesInstanceUID
                image_number = dicom_image.InstanceNumber
                shutil.move(phase_dir, f"{study_dir}/{seriesInstanceUID}.{image_number}")

def move_file_2d(curr_dirs):
    for curr_dir in curr_dirs:
        # filter our the proceesed dataset
        print(f"current directory: {curr_dir}")
        # dest_dir = DEST_DIRS[index]
        for root, dirs, files in os.walk(curr_dir):
            for file in files:
                if (file.endswith(".dcm") and os.path.split(os.path.normpath(root))[-1].startswith("Loc")):
                    file_path = os.path.join(root, file)
                    des_path = f"{os.path.dirname(root)}/{file}"
                    move_file(file_path, des_path)
                    shutil.rmtree(root)

        for root, dirs, files in os.walk(curr_dir):
            if (len(files) != 0):
                file_name = files[0]
                phase_dir = root
                study_dir = os.path.dirname(phase_dir)
                dicom_image = pydicom.filereader.dcmread(os.path.join(phase_dir, file_name))
                seriesInstanceUID = dicom_image.SeriesInstanceUID
                shutil.move(phase_dir, f"{study_dir}/{seriesInstanceUID}")

#move dicom files to it's parent directorie!
if __name__ == "__main__":
    studies_2d = []
    studies_3d =[]
    for study in glob.glob(r"D:\DATA\CTA_CINE\original_CTA_CINE\CT*P"):
        if(len(re.split(r"[_-]",os.path.basename(study))) < 3):
            continue
        else:
            print(study)
            locs_path = glob.glob(f"D:/DATA/CTA_CINE/original_CTA_CINE/{os.path.basename(study)}/*")
            print(locs_path[0])
            if(len(os.listdir(locs_path[0])) == 1):
                studies_3d.append(study)
            else:
                studies_2d.append(study)

    print(studies_2d)
    print(studies_3d)
    move_file_2d(studies_2d)
    #move_file_3d(studies_3d)


from functools import wraps
import requests
import json

from smoothnlp import logger
from smoothnlp import MODE
from smoothnlp import set_mode
import re

########################
## attribute function ##
########################
def localSupportCatch(func):
    @wraps(func)
    def trycatch(text):
        if MODE !="server":
            logger.error("This function does not support local mode : %s " % func.__name__)
            raise AttributeError("This function does not support local mode : %s ")
        return func(text)
    return trycatch

def requestTimeout(func):
    @wraps(func)
    def trycatch(text):
        try:
            return func(text)
        except requests.exceptions.Timeout:
            set_mode('local')
            return func(text)
    return trycatch

def convert(func):
    @wraps(func)
    def toJson(text):
        res = func(text)
        if(isinstance(res, list)):
            return res
        else:
            return json.loads(res)
    return toJson

def to_sql_update(df, engine, schema, table, id_cols = None, chunksize=100):
    """
    将 pandas.DataFrame
    :param df:
    :param engine:
    :param schema:
    :param table:
    :param id_cols:
    :param chunksize:
    :return:
    """
    if id_cols is None:
        sql = ''' SELECT column_name from information_schema.columns
                  WHERE table_schema = '{schema}' AND table_name = '{table}' AND
                        COLUMN_KEY = 'PRI';
              '''.format(schema=schema, table=table)
        id_cols = [x[0] for x in engine.execute(sql).fetchall()]
    else:
        id_cols = id_cols
    id_vals = [df[col_name].tolist() for col_name in id_cols]
    counter=0
    sql = ''' DELETE FROM {schema}.{table} WHERE 0 '''.format(schema=schema, table=table)
    for row in zip(*id_vals):
        sql_row = ' AND '.join([''' {}='{}' '''.format(n, v) for n, v in zip(id_cols, row)])
        sql += ' OR ({}) '.format(sql_row)
        counter+=1
        if counter>=chunksize:
            engine.execute(sql)
            sql = ''' DELETE FROM {schema}.{table} WHERE 0 '''.format(schema=schema, table=table)
            counter = 0
    engine.execute(sql)
    df.to_sql(table, engine, schema=schema, if_exists='append', index=False)

def remove_nonchinese(text):
    return " ".join(re.findall(r'[\u4e00-\u9fff]+', text))


# -*- coding: utf-8 -*-
"""
Created on Fri Jul 20 16:34:51 2018

@author:
"""
import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import math
np.random.seed(100)
pd.set_option('display.max_columns',10)
pd.set_option('display.width',None)
## Betas, Bootstraps are variable
bvec=[-0.1,0,0.1,0.2]
T=100
nsim = 1000
b0 = 1
boots=[10,20,30,50]
sig=0.5
mu_x=1
outp =np.zeros((len(bvec),len(boots),6))
outp.shape
for bdx,b1 in enumerate(bvec):
    for btx,boot in enumerate(boots):
        reject_boot = 0
        reject_both = 0
        reject_orig=0
        for isim in range(nsim):
            count+=1
            e = np.random.normal(0,sig,size=(T,1))
            x = np.random.normal(mu_x,sig,size=(T,1))
            y=b0+(b1*x)+e
            x = sm.add_constant(x)
            model_orig=smf.OLS(y,x).fit()
            # Create confindence interval for b1
            ci=np.zeros(int(boot))
            for b in range(boot):  ## Bootstrapping to find CI
                # Create a resample index
                resamp=np.random.randint(T, size=int(0.5*T)) #Re-sampling with replacement
                model = smf.OLS(y[resamp],x[resamp]).fit()
                ci[b] = model.params[1]
                #print(model.params[1])
            ci.sort()
            ci_lower = ci[int(boot*0.025)]
            ci_upper = ci[int(boot*0.975)]
            ## Empirical t-tests - Reject Null when CI follows a trend
            if not(0>=ci_lower and 0<=ci_upper): reject_boot+=1
            if not(0>=ci_lower and 0<=ci_upper) and model_orig.pvalues[1]<0.05: reject_both+=1
            if model_orig.pvalues[1]<0.05: reject_orig+=1
        outp[bdx,btx] = np.array((b1,boot,nsim,reject_orig,reject_boot,reject_both))
## Convert to Dataframe for analysis
df=pd.DataFrame(np.vstack(outp))
df.columns=['Betas','Bootstraps','No_of_Simulation','Reject_Actual','Reject_Bootstrap','Reject_Both']
df['Power of the Test(when Beta=0, its Size of Test)']=(df['Reject_Both']/df['No_of_Simulation'])*100


import logging

from django.conf import settings

from alarm_backends.core.cache.key import CONST_MINUTES, STRATEGY_TOKEN_BUCKET_KEY

__doc__ = """
描述：
    access模块令牌桶：对数据拉取耗时超预期的数据源进行降级。
实现方案：
    利用redis的key过期特性及decr的原子性，实现的滑动窗口令牌桶模型。
背景：
    access模块根据用户配置的监控策略，将数据源进行分组。每个strategy_group_key代表一个数据拉取任务。
    后台将周期发起数据拉起任务并给到celery worker执行。
    access下的时序数据源包含：监控自采数据（influxdb，ES），日志平台（ES），计算平台（tspider）。
    当其中某类数据源底层存储出现问题导致查询耗时过长时，会影响整个集群的worker的处理速度，
    导致任务队列堵塞，影响其他数据源的数据获取。同时没有降级能力，将加大问题存储的负载，出现雪崩效应。
实现：
    每个数据拉取任务都公平的被分配一定数量的token（值可配置）其中一个token表示1秒的时间，默认为每10分钟30s。
    token被记录在一个有着初始10分钟过期的key里。当token余额为正时，才能开启数据拉取任务，拉取结束后扣除对应拉取耗时的token。
    当token余额为负数时，后续在key有效期内，将被禁止再次执行拉取任务，同时追加对应比例的key过期时间补偿。
    例如：当前设置10分钟30s的滑动窗口。当token余额为-10的时候，将追加 600 / 30 * 10 = 200s 的过期时间。
管理工具：
    alarm_backends/management/commands/token.py
    后台执行./bin/manage.sh token
    将展示当前被降级的策略、表名及被限制时间
"""

from core.prometheus import metrics

logger = logging.getLogger("access.data")

class TokenBucket(object):
    def __init__(self, strategy_group_key, interval=60):
        self.strategy_group_key = strategy_group_key
        self.client = STRATEGY_TOKEN_BUCKET_KEY.client
        self.token_key = STRATEGY_TOKEN_BUCKET_KEY.get_key(strategy_group_key=strategy_group_key)
        # 每个access data task 在一个时间窗口的时间资源，单位：秒
        self.token_per_window = int(getattr(settings, "ACCESS_TIME_PER_WINDOW", 30))
        if interval < 60:
            # 按周期1分钟来分配token，当周期小于一分钟，等比例放大token
            self.token_per_window = int(self.token_per_window * (60 / interval))

    def touch(self):
        # 如果没有令牌：新的时间窗口或者新的策略组，申请新的令牌
        self.client.set(self.token_key, self.token_per_window, nx=True, ex=STRATEGY_TOKEN_BUCKET_KEY.ttl)
        return self.token_per_window

    def acquire(self):
        # 获取令牌
        token_remain = int(self.client.get(self.token_key) or self.touch())
        succeed = token_remain > 0
        if not succeed:
            # 没有令牌了
            remain_ttl = self.client.ttl(self.token_key) or 0
            logger.warning(
                f"strategy_group_key({self.strategy_group_key}):"
                f" no more token available, Recovery in {remain_ttl} seconds"
            )
            metrics.ACCESS_TOKEN_FORBIDDEN_COUNT.inc()
        return succeed

    def release(self, decrement):
        self.touch()
        token_remain = self.client.decr(self.token_key, int(decrement))
        logger.info(f"strategy_group_key({self.strategy_group_key}): token remain {token_remain}")
        if token_remain <= 0:
            # 令牌用完，根据令牌使用情况限制时间
            remain_ttl = self.client.ttl(self.token_key)
            if remain_ttl is None or remain_ttl < 0:
                # 申请新的令牌
                self.client.expire(self.token_key, 0)
                return
            # 欠的token，按比例补齐降级时间
            new_ttl = int(remain_ttl + abs(token_remain) * (STRATEGY_TOKEN_BUCKET_KEY.ttl / self.token_per_window))
            # 最大限制30 min
            new_ttl = min(new_ttl, 30 * CONST_MINUTES)
            self.client.expire(self.token_key, new_ttl)
            logger.warning(f"strategy_group_key({self.strategy_group_key}): token forbidden for {new_ttl} seconds")


# MAJORITY ELEMENT
"""
Given an array A of N elements. Find the majority element in the array. A majority element in an array A of size N is an element that appears more than N/2 times in the array.

Example 1:

Input:
N = 3
A[] = {1,2,3}
Output:
-1
Explanation:
Since, each element in
{1,2,3} appears only once so there
is no majority element.
"""

def majorityElement( A, N):
        #Your code here
    result = list()
    val = N // 2
    dic = dict()
    for i in A:
        if i in dic:
            dic[i] += 1
        else:
            dic[i] = 1
    for keys,vals in dic.items():
        if vals > val:
            result.append(keys)
    if(result):
        ans = max(result)
        return ans
    return -1


def plusMinus(array):
    array_length = len(array)
    i = 0
    counts = {
        'positive': 0,
        'negative':0 ,
        'zero': 0
    }
    quotient = None
    while array_length > 1:
        element = array[i]
        if element > 0:
            counts["positive"] = counts["positive"] + 1
        if element == 0:
            counts["zero"] = counts["zero"] + 1
        if element < 0:
            counts["negative"] = counts["negative"] + 1
        i = i + 1
        if i == array_length:
            break
    for item in counts.values():
        quotient = item / array_length
        print(f"{quotient:6f}")
    return
arr = plusMinus([-4,3,-9,0,4,1])