#!/usr/bin/env python
'''
An export method producing for GDML.

http://lcgapp.cern.ch/project/simu/framework/GDML/doc/GDMLmanual.pdf
http://gdml1.web.cern.ch/gdml1/doc/g4gdml_howto.html
http://geant4.in2p3.fr/2007/prog/GiovanniSantin/GSantin_Geant4_Paris07_Materials_v08.pdf

http://lxml.de/tutorial.html
http://lxml.de/objectify.html
http://stackoverflow.com/questions/2850823/multiple-xml-namespaces-in-tag-with-lxml

'''

import os

schema_dir = os.path.join(os.path.dirname(__file__), 'schema')
schema_file = os.path.join(schema_dir, 'gdml.xsd')

from lxml import etree
from gegede import Quantity
from gegede.iter import ascending
from gegede.export import pod

def qtus(q,unit):
    'Quantity to unit string'
    return str(q.to(unit).magnitude)

def nt_qunit2xmldict(nt, unit):
    ret = dict(unit=unit)
    for k,v in zip(nt._fields,nt):
        if Quantity == type(v):
            v = str(v.to(unit).magnitude)
        else:
            v = str(v)
        ret[k] = v
    return ret

def D(obj):
    return str(obj.density.to('g/cc').magnitude)
def Atom(obj):
    return str(obj.a.to('g/mole').magnitude)
def Symbol(obj):
    return obj.symbol or ""

# def wash(geom):
#     '''Return a new geom object with its contents "washed" of any things
#     that will tickle GDML limitations.
#     '''
#     import gegede.construct
#     newg = gegede.construct.Geometry(geom.schema)
#     for store_name in geom.store._fields:
#         store = getattr(geom.store,store_name)
#         newstore = getattr(newg.store,store_name)
#         for name, obj in store.items():
#             newobj = type(obj)(obj.name.replace(' ','_'), *obj[1:])
#             newstore[name.replace(' ','_')] = newobj
#     return newg

def make_material_node(obj):
    '''
    Return an lxml.etree.Element made from the matter object.
    '''

    typename = type(obj).__name__
    node = None

    if typename == 'Element':
        node = etree.Element('element', name=obj.name, Z=str(obj.z), formula=Symbol(obj))
        node.append(etree.Element('atom', value=Atom(obj)))

    if typename == 'Isotope':
        node = etree.Element('isotope', name=obj.name, Z=str(obj.z), N=str(obj.ia))
        node.append(etree.Element('atom', type="A", value=Atom(obj)))

    if typename == 'Composition':
        node = etree.Element('element', name=obj.name)
        for isoname, isofrac in obj.isotopes:
            node.append(etree.Element('fraction', ref=isoname, n=str(isofrac)))

    if typename == 'Amalgam':
        node = etree.Element('material', name=obj.name, Z=str(float(obj.z)))
        # fixme: units???
        node.append(etree.Element('D', value=D(obj)))
        node.append(etree.Element('atom', value=Atom(obj)))
        for propname, propvect in obj.properties:
            node.append(etree.Element('property',
                                      name=propname,
                                      ref=obj.name+'_'+propname+'_VALUE'))

    if typename == 'Molecule':
        node = etree.Element('material', name=obj.name, formula=Symbol(obj))
        node.append(etree.Element('D', value=D(obj)))
        for elename, elenum in obj.elements:
            node.append(etree.Element('composite', ref=elename, n=str(elenum)))
        for propname, propvect in obj.properties:
            node.append(etree.Element('property',
                                      name=propname,
                                      ref=obj.name+'_'+propname+'_VALUE'))

    if typename == 'Mixture':
        node = etree.Element('material', name=obj.name, formula=Symbol(obj))
        node.append(etree.Element('D', value=D(obj)))
        for compname, compfrac in obj.components:
            node.append(etree.Element('fraction', ref=compname, n=str(compfrac)))
        for propname, propvect in obj.properties:
            node.append(etree.Element('property',
                                      name=propname,
                                      ref=obj.name+'_'+propname+'_VALUE'))

    return node

def make_shape_node(shape):
    '''
    Return an lxml.etree.Element made from the <shape>
    '''
    lunit = 'cm'
    aunit = 'radian'
    typename = type(shape).__name__

    def unitify(unit, quant, scale=1.0):
        quant = quant * scale
        return str(quant.to(unit).magnitude)
    def dsize(quant):
        return unitify(lunit, quant, 2.0)
    def rsize(quant):
        return unitify(lunit, quant, 1.0)
    def ang(quant):
        return unitify(aunit, quant, 1.0)

    if typename == 'Box':
        dat = dict(name=shape.name, lunit=lunit,
                   x=dsize(shape.dx), y=dsize(shape.dy), z=dsize(shape.dz))
        return etree.Element('box', **dat)

    if typename == 'TwistedBox':
        dat = dict(name=shape.name, lunit=lunit,
                   x=dsize(shape.dx), y=dsize(shape.dy), z=dsize(shape.dz), PhiTwist=ang(shape.phitws))
        return etree.Element('twistedbox', **dat)

    if typename == 'Tubs':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                   rmin=rsize(shape.rmin), rmax=rsize(shape.rmax), z=dsize(shape.dz),
                   startphi=ang(shape.sphi), deltaphi=ang(shape.dphi))
        return etree.Element('tube', **dat)

    if typename == 'Sphere':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                   rmin=rsize(shape.rmin), rmax=rsize(shape.rmax),
                   startphi=ang(shape.sphi), deltaphi=ang(shape.dphi),
                   starttheta=ang(shape.stheta), deltatheta=ang(shape.dtheta))
        return etree.Element('sphere', **dat)

    if typename == 'Cone':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    rmin1=rsize(shape.rmin1), rmax1=rsize(shape.rmax1),
                    rmin2=rsize(shape.rmin2), rmax2=rsize(shape.rmax2), z=dsize(shape.dz),
                    startphi=ang(shape.sphi), deltaphi=ang(shape.dphi))
        return etree.Element('cone', **dat)

    if typename == 'Trapezoid':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    x1=dsize(shape.dx1), x2=dsize(shape.dx2),
                    y1=dsize(shape.dy1), y2=dsize(shape.dy2), z=dsize(shape.dz))
        return etree.Element('trd', **dat)

    if typename == 'TwistedTrap':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    x1=dsize(shape.dx1), x2=dsize(shape.dx2), x3=dsize(shape.dx3), x4=dsize(shape.dx4),
                    y1=dsize(shape.dy1), y2=dsize(shape.dy2), z=dsize(shape.dz),
                    Theta=ang(shape.dtheta), Phi=ang(shape.dphi), Alph=ang(shape.dalpha), PhiTwist=ang(shape.phitws))
        return etree.Element('twistedtrap', **dat)

    if typename == 'TwistedTrd':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    x1=dsize(shape.dx1), x2=dsize(shape.dx2),
                    y1=dsize(shape.dy1), y2=dsize(shape.dy2), z=dsize(shape.dz),
                    PhiTwist=ang(shape.phitws))
        return etree.Element('twistedtrd', **dat)

    if typename == 'Arb8':
        # print("arb8ivert",shape.ivert[0][0])
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                   v1x=dsize(shape.v1x),v1y=dsize(shape.v1y),
                   v2x=dsize(shape.v2x),v2y=dsize(shape.v2y),
                   v3x=dsize(shape.v3x),v3y=dsize(shape.v3y),
                   v4x=dsize(shape.v4x),v4y=dsize(shape.v4y),
                   v5x=dsize(shape.v5x),v5y=dsize(shape.v5y),
                   v6x=dsize(shape.v6x),v6y=dsize(shape.v6y),
                   v7x=dsize(shape.v7x),v7y=dsize(shape.v7y),
                   v8x=dsize(shape.v8x),v8y=dsize(shape.v8y),
                    dz=dsize(shape.dz))
        return etree.Element('arb8', **dat)

    if typename == 'Paraboloid':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    rlo=dsize(shape.drlo), rhi=dsize(shape.drhi),
                    dz=dsize(shape.ddz))
        return etree.Element('paraboloid', **dat)

    if typename == 'Ellipsoid':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    ax=dsize(shape.dax), by=dsize(shape.dby), cz=dsize(shape.dcz),
                    zcut1=dsize(shape.dzcut1), zcut2=dsize(shape.dzcut2))
        return etree.Element('ellipsoid', **dat)

    if typename == 'PolyhedraRegular':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    startphi=ang(shape.sphi), deltaphi=ang(shape.dphi), numsides=str(int(shape.numsides)))
        ele = etree.Element('polyhedra', **dat)
        zpos = shape.dz / 2
        zneg = - shape.dz / 2
        ele.append(etree.Element('zplane', rmin=rsize(shape.rmin), rmax=rsize(shape.rmax), z=dsize(zpos)))
        ele.append(etree.Element('zplane', rmin=rsize(shape.rmin), rmax=rsize(shape.rmax), z=dsize(zneg)))
        return ele

    if typename == 'Boolean':
        ele = etree.Element(shape.type, name=shape.name)
        # the rest are sub nodes.  why?  because, don't ask questions!
        ele.append(etree.Element('first', ref=shape.first))
        ele.append(etree.Element('second', ref=shape.second))
        ele.append(etree.Element('positionref', ref = shape.pos or 'center'))
        ele.append(etree.Element('rotationref', ref = shape.rot or 'identity'))
        return ele

    if typename == 'EllipticalTube':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    dx=dsize(0.5*shape.dx), dy=dsize(0.5*shape.dy), dz=dsize(0.5*shape.dz))
        return etree.Element('eltube', **dat)

    if typename == 'Torus':
        dat = dict(name=shape.name, lunit=lunit, aunit=aunit,
                    rmin=rsize(shape.rmin), rmax=rsize(shape.rmax), rtor=rsize(shape.rtor),
                    startphi=ang(shape.startphi), deltaphi=ang(shape.deltaphi))
        return etree.Element('torus', **dat)

    # etc....  Grow this as gegede.schema.Schema.shapes grows....

    return

def make_volume_node(vol, store):
    #print ('VOL',vol)
    node_type = 'volume'
    if vol.material is None and vol.shape is None:
        node = etree.Element('assembly', name=vol.name)
    else:
        assert vol.material and vol.shape
        node = etree.Element('volume', name=vol.name)
        node.append(etree.Element('materialref', ref=vol.material))
        node.append(etree.Element('solidref', ref=vol.shape))
    for placename in vol.placements or []:
        place = store[placename]
        if place.copynumber:
            pvol = etree.Element('physvol', copynumber=str(place.copynumber))
        else:
            pvol = etree.Element('physvol')
        node.append(pvol)
        pvol.append(etree.Element('volumeref', ref=place.volume))
        if place.pos:
            pvol.append(etree.Element('positionref', ref=place.pos))
        else:
            pvol.append(etree.Element('positionref', ref='center'))
        if place.rot:
            pvol.append(etree.Element('rotationref', ref=place.rot))
        else:
            pvol.append(etree.Element('rotationref', ref='identity'))
    for parname, parval in vol.params or []:
        pnode = etree.Element('auxiliary', auxtype=parname, auxvalue=parval)
        node.append(pnode)
    return node

def convert(geom):
    '''
    Return an lxml.etree formed from the geometry
    '''

    gdml_node = etree.Element("gdml")

    # I have no idea what this means but it reproduces what other GDML
    # files have and w/out it Geant4 complains.
    gdml_node.set('{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation',
                  'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd')

    # <define>
    define_node = etree.Element('define')
    gdml_node.append(define_node)
    center = identity = None
    for name, obj in geom.store.structure.items():
        typename = type(obj).__name__.lower()
        node = None
        if typename == 'position':
            node = etree.Element('position', **nt_qunit2xmldict(obj, 'cm'))
            if obj.name == 'center':
                center = obj
        if typename == 'rotation':
            node = etree.Element('rotation', **nt_qunit2xmldict(obj, 'degree'))
            if obj.name == 'identity':
                identity = obj
        if node is not None:
            define_node.append(node)
        continue
    for name, obj in geom.store.matter.items():
        typename = type(obj).__name__.lower()
        if typename=='mixture' or typename=='molecule' or typename=='amalgam':
            for prop, val in obj.properties:
                vals = str(val[0])
                for v in val[1:]: vals += ' ' + str(v)
                define_node.append(etree.Element('matrix',
                                                 name=name+'_'+prop+'_VALUE',
                                                 coldim=str(len(val)),
                                                 values=vals))
                continue
            continue
        continue
    if center is None:
        define_node.append(etree.Element('position', name='center'))
    if identity is None:
        define_node.append(etree.Element('rotation', name='identity'))

    # <materials>
    materials_node = etree.Element('materials')
    gdml_node.append(materials_node)
    for name, obj in geom.store.matter.items():
        node = make_material_node(obj)
        if node is not None:
            materials_node.append(node)

    # <solids>
    solids_node = etree.Element('solids')
    gdml_node.append(solids_node)
    for obj in geom.store.shapes.values():
        node = make_shape_node(obj)
        if node is not None:
            solids_node.append(node)

    # <structure>
    structure_node = etree.Element('structure')
    gdml_node.append(structure_node)
    for vol in ascending(geom.store.structure, geom.world):
        assert vol
        node = make_volume_node(vol, geom.store.structure)
        if node is not None:
            structure_node.append(node)

    # <setup>
    setup_node = etree.Element('setup', name="Default", version="0")
    gdml_node.append(setup_node)

    world_node = etree.Element('world', ref=geom.world)
    setup_node.append(world_node)

    return gdml_node

def validate(text):
    try:
        from StringIO import StringIO
        sio = StringIO(text)
    except ImportError:         # python3
        from io import BytesIO
        sio = BytesIO(text)

    xsd_doc = etree.parse(schema_file)
    xsd = etree.XMLSchema(xsd_doc)
    xml = etree.parse(sio)
    okay = xsd.validate(xml)
    if not okay:
        print (xsd.error_log)
        raise ValueError('Invalid GDML')
    return True

def validate_object(obj):
    return validate(dumps(obj))

#def validate_output(obj, filename):
#    return False

def dumps(obj):
    '''
    Return a string representation of the object returned by convert.
    '''
    xml = etree.tostring(obj, pretty_print = True, xml_declaration = True)
    xml = xml.replace(b"'",b'"')  # work around ROOT GDML import bug....
    # don't validate here
    return xml

def output(obj, filename):
    '''
    Save to file
    '''
    open(filename,'wb').write(dumps(obj))


import sys # argv
import math # inf
import itertools # permutations

from typing import Tuple, List, Iterable

OP_NUM_PARAMS = {
    99: 0,
    1: 3,
    2: 3,
    3: 1,
    4: 1,
    5: 2,
    6: 2,
    7: 3,
    8: 3,
}

def parse_op_value(op_value: int) -> Tuple[int, List[int]]:
    op = op_value % 100
    if op not in OP_NUM_PARAMS:
        raise Exception(f'Invalid op: {op}')
    op_value //= 100
    param_modes = []
    for _ in range(OP_NUM_PARAMS[op]):
        mode = op_value % 10
        assert mode in [0, 1]
        param_modes.append(mode)
        op_value //= 10
    return op, param_modes

def run_program(memory: List[int], input_values: Iterable[int]) -> List[int]:
    memory = memory.copy()
    input_values = iter(input_values)

    output_values = []
    ip = 0
    while True:
        op, param_modes = parse_op_value(memory[ip])
        if op == 99:
            break

        def get_param(n: int) -> int:
            param_value = memory[ip+n]
            if param_modes[n-1] == 0:
                return memory[param_value]
            else:
                return param_value

        def set_param(n: int, value: int):
            param_value = memory[ip+n]
            if param_modes[n-1] == 0:
                memory[param_value] = value
            else:
                raise Exception('Attempted to write to immediate parameter')

        if op == 1:
            result = get_param(1) + get_param(2)
            set_param(3, result)
        elif op == 2:
            result = get_param(1) * get_param(2)
            set_param(3, result)
        elif op == 3:
            set_param(1, next(input_values))
        elif op == 4:
            output_values.append(get_param(1))
        elif op == 5:
            if get_param(1) != 0:
                ip = get_param(2)
                continue
        elif op == 6:
            if get_param(1) == 0:
                ip = get_param(2)
                continue
        elif op == 7:
            result = get_param(1) < get_param(2)
            set_param(3, int(result))
        elif op == 8:
            result = get_param(1) == get_param(2)
            set_param(3, int(result))
        else:
            raise Exception(f'Invalid op: {op}')

        ip += 1 + len(param_modes)

    try:
        next(input_values)
    except StopIteration:
        return output_values
    else:
        raise Exception("Program didn't use all input values")

with open(sys.argv[1]) as f:
    memory = [int(value) for value in f.read().split(',')]

largest_output = -math.inf
largest_output_config = None
for phase_config in itertools.permutations(range(0, 5)):
    output_value = 0
    for phase in phase_config:
        output_value, = run_program(memory, [phase, output_value])
    if output_value > largest_output:
        largest_output = output_value
        largest_output_config = phase_config
#print(largest_output_config)
print(largest_output)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math

def suma(x):
    wynik = 0
    for i in range(1,x+1):
        wynik += i
    return wynik
print(str(suma(10)) + ' ' + str(suma(123)))

liczby = np.arange(256,348)
liczby2 = [i for i in range(256,348) if i%13==0]
print(liczby2)

"""slowo = input("Podaj palindrom: ")
x = len(slowo)
i = 0
while i<x:
    if(slowo[i]!=slowo[x-1]):
        print("Slowo NIE JEST palindromem")
        break
    x -= 1
    i += 1
    if(i>=x):
        print("Slowo JEST palindromem")"""
x = np.arange(-10,11,0.1)
y = np.sin(x)
plt.plot(x,y)
plt.show()


#循环
#Python的循环有两种，一种是for...in循环，依次把list或tuple中的每个元素迭代出来，看例子：
names = ["Michael","Bob","Tracy"]
for name in names:
    print(name)
#所以for x in ...循环就是把每个元素代入变量x，然后执行缩进块的语句。
#再比如我们想计算1-10的整数之和，可以用一个sum变量做累加：

sum = 0
for x in [1,2,3,4,5,6,7,8,9,10]:
    sum += x
print(sum)

#如果要计算1-100的整数之和，从1写到100有点困难，幸好Python提供一个range()函数，可以生成一个整数序列，再通过list()函数可以转换为list。比如range(5)生成的序列是从0开始小于5的整数：
print(list(range(5)))  #打印结果 [0,1,2,3,4]

sum = 0
for x in range(100):
    sum += x
print(sum)

#第二种循环是while循环，只要条件满足，就不断循环，条件不满足时退出循环。比如我们要计算100以内所有奇数之和，可以用while循环实现：

sum = 0
n = 99
while n>0:
    sum += n
    n = n-1
print(sum)

#练习：请利用循环依次对list中的每个名字打印出Hello, xxx!：
L = ['Bart', 'Lisa', 'Adam']
for x in L:
    print('%s,%s'% ('Hello',x))

#在循环中，break语句可以提前退出循环
n = 1
while n<100:
    print(n)
    n = n+1
    if n>50:
        break
print('end')
#在循环过程中，也可以通过continue语句，跳过当前的这次循环，直接开始下一次循环。
n = 0
while n < 10:
    n = n + 1
    if n % 2 == 0: # 如果n是偶数，执行continue语句
        continue # continue语句会直接继续下一轮循环，后续的print()语句不会执行
    print(n)


import asyncio

import pygame
import socketio
from aiohttp import web

from game_socket.socketevent import SocketEvent
from util.globals import COLOR_WHITE

class Pygame:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((500, 500))

        self.server = GameServer()
        self.running = True

    async def run(self):
        cnt = 0
        while self.running:
            cnt += 1
            self.screen.fill(COLOR_WHITE)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

            if cnt == 5:
                self.server.enabled = True

            pygame.display.update()
            self.update_socket()
        pygame.quit()

    def update_socket(self):
        if self.server.enabled:
            if not self.server.is_running:
                self.server.start()
        else:
            if self.server.is_running:
                self.server.stop()

class GameServer:
    def __init__(self):
        self.sio = socketio.AsyncServer()
        self.site = None
        self.runner = None
        self.server_task = None

        self.enabled = False
        self.is_running = False

    def start(self, ip='localhost', port=8003, listener=None):
        print('[Server] start')
        self.is_running = True
        self.server_task = asyncio.create_task(self.run(ip, port, listener))

    def stop(self):
        print('[Server] stop')
        self.is_running = False
        if self.site is not None:
            asyncio.create_task(self.site.stop())

    def disconnect(self, sid):
        asyncio.create_task(self.sio.disconnect(sid))

    async def run(self, ip, port, listener):
        self.set_on_message_listener(listener)

        app = web.Application()
        self.sio.attach(app)

        self.runner = web.AppRunner(app)
        await self.runner.setup()
        self.site = web.TCPSite(self.runner, host=ip, port=port)
        await self.site.start()

    def set_on_message_listener(self, listener):
        @self.sio.on('*')
        async def catch_all(event, sid, data):
            print(event, sid, data)
            await listener(event, sid, data)

    def set_on_connect_listener(self, listener):

        @self.sio.event
        def connect(sid, environ, auth):
            print(f'[Event] {sid} connected!')

    def set_on_disconnect_listener(self, listener):
        @self.sio.event
        def disconnect(sid):
            print(f'[Event] {sid} disconnected!')
            listener(sid)

    async def post(self, event, sid, data):
        await self.sio.emit(event, data, sid)

    def emit(self, event, sid=None, data= None):
        print('[Emit]', event, sid, data)
        asyncio.create_task(self.post(event, sid, data))

async def main():
    game = Pygame()
    pygame_task = asyncio.create_task(game.run())

    await asyncio.gather(pygame_task)

if __name__ == '__main__':
    asyncio.run(main())


# -*- coding: utf-8 -*-
"""
Loop replacemnet

@author: Roberto
"""

# para correr lienas de codigo
# 1. seleccionar lineas de codigo
# 2. presioner tecla F9

import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import re # Regex
import pyreadr  # Load R dataset
import os # for usernanme y set direcotrio

# pip install pyreadr  (correr linea esta linead e codigo en la consola)

# data.Rdata

# Change directory

user = os.getlogin()   # Username

# Set directorio

os.chdir(f"C:/Users/{user}/Documents/GitHub/1ECO35_2023_1/Lectures/Lecture_3") # Set directorio

#%% Ejemplo de header

print("Hola Mundo")

#%% Funciones lambda

# Función tradicional #

def interes(C, T, R):
  i = C*T*R
  return i

interes(5000, 24, 0.02)

# forma parsimoniosa de generar funciones

interes2 = lambda C, T, R : C*T*R

interes2(5000, 24, 0.02)

# Más ejemplos

# map permite aplicar una función que a cada elemento de un conjunto de datos  (array, listas)

genero = ['F', 'M', 'M', 'F', 'M']

list( map( lambda x: 0 if x == 'M' else 1, genero )  )

NSE = ['A', 'A', 'C', 'B', 'C']

list( map( lambda x: 3 if x == 'A' else (2 if x == 'B' else 1), NSE )  )

# Más ejemplos #

vector = np.arange(100)

map( lambda x: np.sqrt(x) - np.mean(vector), vector )

list( map( lambda x: np.sqrt(x) - np.mean(vector), vector)   )

np.sqrt(vector) - np.mean(vector)

'''
Ejemplos
'''

'''
Función 1
'''

def cube(x):

    out = x*(1/3) - 0.5*x

    return out

list( map( lambda x: cube(x) , vector)   )

'''
Función 2, de estandarización
'''

def sdv(x,mean,sd):

    out = (x-mean)/sd

    return out

list( map( lambda x, mean = np.mean(vector), sd = np.std(vector): sdv(x,mean,sd) , vector)  )

# función explicita en la función lambda

list( map( lambda x: (x - np.mean(vector))/np.std(vector), vector)  )

'''
Función 3, If statement

Valores menos a 50 asigne el numero 1 y asignar missing values para valores mayor i igual a 50
'''

vector = np.arange(100)

def function2(x):

    if x < 50:
         out = 1
    else:
         out = np.nan # Missing values

    return out

list( map( lambda x: function2(x) , vector)   )

'''
Función 4, extrae lo numeros de un texto

La función extrae los numeros de texto

'''

texto_vector = np.array(["Municipio San Luis: 12450","Municipio La victoria: 1450",
                         "Municipio La Molina: 3550","Municipio Ate: 506"])

list( map( lambda x: int(re.sub('\D',"", x)) , texto_vector)   )

# \D : todo menos numero

# import re (regular expression)

# \D: significa todo menos a los dígitos

# re.sub( patron de texto, sustitución, texto)

#%% apply_along_axis - Matrix

''' Loop replacement in Matrix '''

np.random.seed(15632)
x1 = np.random.normal(0,1,500) # normal distribution
x2 = np.random.normal(0,1,500) # normal distribution
x3 = np.random.normal(0,1,500) # normal distribution
x4 = np.random.normal(0,1,500) # normal distribution

X = np.column_stack((np.ones(500),x1,x2,x3,x4))

print(X.shape)

'''

En el caso de aplicar funciones como mean, std, y entre otros se puede aplicar pro filas o columnas

axis = 0 se aplica la función a cada columa
axis = 1 se aplica la función por filas

Numpy apply for matrix

numpy.apply_along_axis(func1d, axis, arr, *args, **kwargs)

'''

# mead y desviación estandar por columnas

np.mean(X, axis=0)   # axis = 0 (se aplica por columnas)
np.std(X, axis=0)

# mead y desviación estandar por filas

np.mean(X, axis=1)
len( np.mean(X, axis=1) )
np.std(X, axis=1)

'''

Dos formas de estandarizar una matriz

'''

XNormed = (X - np.mean(X, axis=0))/np.std(X, axis=0)

def standarize(x):
       out = (x - np.mean(x))/np.std(x)

       return out

X_std_2 = np.apply_along_axis(standarize, 0, X)

# axis = 0, se aplicará la función a los elementos de cada columna

#%% Apply - Dataframe

'''
 We use US census data from the year 2012 to analyse the effect of gender
 and interaction effects of other variables with gender on wage jointly.
 The dependent variable is the logarithm of the wage, the target variable is *female*
 (in combination with other variables). All other variables denote some other
 socio-economic characteristics, e.g. marital status, education, and experience.
 For a detailed description of the variables we refer to the help page.
 '''

cps2012_env = pyreadr.read_r("../../data/cps2012.Rdata") # output formato diccionario

cps2012_env  # es un diccionario. En la llave "data" está la base de datos
cps2012 = cps2012_env[ 'data' ] # extrae información almacenada en la llave data del diccionario cps2012_env
dt = cps2012.describe()

# Borrar variables constantes

variance_cols = cps2012.var().to_numpy() # to numpy

X = cps2012.iloc[ : ,  np.where( variance_cols != 0   )[0] ]

# np.where( variance_cols != 0   ) resulta la posición de lasa columnas con varianza != 0

#np.where( variance_cols != 0   )[0] # array

# np.where() permite obtener la posición de columnas que cumplen la condición

# Retirar la media de las variables

def demean(x):
    dif = x - np.mean( x ) # tima la media de la columna
    return dif

X = X.apply( demean, axis = 0 )  # axis :0 se aplica la función por columna

###############################################################################

# Segundo ejemplo de base de datos

datos = pd.read_csv("../../data/BDD_compras_consumidores.csv", sep = ";")

datos['Channel'].value_counts()

datos['Region'].value_counts()

datos.info()

# Convertimos a categórica el nombre de las columnas:

datos['Channel'] = datos['Channel'].astype("category")
datos['Region'] = datos['Region'].astype("category")

datos.info()

# Apply #

# Las ventas totales por tipo de producto

datos.iloc[:,2:8].apply(lambda x: sum(x), axis = 0)  # axis = 0 , operación a nivel columna

# "iloc" permite seleccionar filas o columnas usando sus posiciones.

# ventas total por cada observación

datos['ventas'] = datos.iloc[:,2:8].apply(lambda x: sum(x), axis = 1) # axis = 0 , operación a nivel fila

#datos['ventas'] = datos['milk'] + datos['fresh']+ datos['grocery'] (poco eficiente)

# promedio por tipo de producto

datos.iloc[:,2:8].apply(lambda x: np.mean(x), axis = 0)

# minimo valor de la venta por tipo de producto

datos.iloc[:,2:8].apply(lambda x: np.min(x), axis = 0)

# máximo valor de la venta por tipo de producto

datos.iloc[:,2:8].apply(lambda x: np.max(x), axis = 0)

# cambio de moneda

datos2 = datos.iloc[:,2:8].apply(lambda x: x/3.9)

#datos3 = pd.concat([datos.iloc[:,:2],datos2], axis = 1) # se une a nivel columna o de forma horizontal

#%% *args

"""
The special syntax *args in function definitions in python is used to pass a variable number
of arguments to a function. The object *args is a tuple that contains all the arguments.
 When you build your code, you should consider *args as a tuple.
"""

'''
*args : tipo tuple o array
'''

"Keyword: *args, incluir una cantidad variable de argumentos"

def calculator(x,y,w,z,a,b):

    return x+y+w+z+a+b

calculator(10,15)

def calculator( *args ):

    print( f"args is a {type( args )}" )

    vector = np.array( list(args) )  # *args : tuple

    minimo = np.min(vector)

    maximo = np.max(vector)

    prod = np.prod(vector)

    return prod, minimo, maximo, args

calculator( 8, 9, 100, 3, 5, 51,58)

'''
*args se puede usar otro nombre siempre que se use * al inicio
'''

def calculator( *list_vars ):

    print( f"args is a {type( list_vars )}" )

    vector = np.array( list_vars )  # *args : tuple

    minimo = np.min(vector)

    maximo = np.max(vector)

    result = np.prod(vector)

    return result, minimo, maximo

calculator( 8, 9, 50, 40, 10, 1)

#%%  **Kwargs

'''
**Kwargs is an acronym of keyword arguments.
It works exactly like *Args but instead of accepting a variable number of positional arguments,
it accepts a variable number of keyword or named arguments.
'''

'''
**kwargs: tipo diccionario
'''

def calculator( *list_vars, **kwargs):

    print( type( list_vars ) )
    print( type( kwargs ) )

    if ( kwargs[ 'function' ] == "media" ) :

        # Get the first value
        result = np.mean( list_vars )

    elif ( kwargs[ 'function' ] == "adicion" ) :

        result = sum(list_vars)

    elif ( kwargs['function'] == "median"):

        result = np.median(list_vars)  # *list_vars

    else:
        raise ValueError( f"The function argument {kwargs[ 'function' ]} is not supported." )

        # Mensaje de error por tipo de argumento

    return result

calculator( 4, 5, 6, 7, 8, function = "adicion" )

calculator( 4, 5, 6, function = "media" )

calculator(100,300,50, function = "adicion")

calculator(100,300,50, function = "median")

calculator(100,300,50, function = "varainza")

# calculator( 4, 5, 6, 7, 8, function = "inversa" )

calculator( np.arange(10), function = "media" )

'''
Example using dataset cps2012
'''

def transform(Data, *select, **function) -> pd.DataFrame: #output DataFrame

    select = list(select)  # se transforma a una lista
    Data_select = Data[select] # se filtra por columnas

    if function['method'] == "demean":

        X = Data_select.apply(lambda row: row - np.mean(row), axis =0)

    elif function['method'] == "estandarize":

        X = Data_select.apply(lambda row: (row - np.mean(row))/np.std(row), axis =0)

    return X

transform(cps2012, "lnw", "exp1","exp2", method = "estandarize")

transform(cps2012, "lnw", "exp1","exp2", "exp3", "exp4", method = "demean")


#
# Package: MediaComp
# Module: pictures
# Author: Paul Buis, 00pebuis@bsu.edu
#
# Derived from source code, power point slides, and media (pictures, movies, sounds) from
# http://mediacomputation.org created by Mark Guzdial and Barbara Ericson
# licensed under the Creative Commons Attribution 3.0 United States License,
# See: http://creativecommons.org/licenses/by/3.0/us/).
"""
Module docstring goes here!
"""
# module base64 is standard in Python 3: https://docs.python.org/3/library/base64.html
# using base64.b64encode in Picture.to_base64
import base64

# module io is standard in Python 3: https://docs.python.org/3/library/io.html
# using io.BytesIO in Picture.to_base64
import io

import os

import pathlib

import collections.abc

# module typing is standard in Python 3.5+: https://docs.python.org/3/library/typing.html
# used for type hints used in static type checking in PEP 484
# PEP 484 -- Type Hints: https://www.python.org/dev/peps/pep-0484/
# PEP 525 -- Syntax for Variable Annotations: https://www.python.org/dev/peps/pep-0526/
# use mypy for static type checking of Pyhton code: http://mypy-lang.org/
# note that just because a parameter is annotated to be of a specific type, doesn't mean
# that at runtime it will actually be of that type: dynamic checking or casting/conversion
# still needs to be done
import typing

# PIL refers to the Pillow library installed by default in the Anaconda distribution of Python
# PIL is the Python Image Library, Pillow is a fork of PIL
# For documentation on Pillow, see: https://pillow.readthedocs.io/en/stable/

# suppress static type checker complain "error: No library stub file for module 'PIL.Image'"
import PIL.Image  # type: ignore
# suppress static type checker complain "error: No library stub file for module 'PIL.ImageDraw'"
import PIL.ImageDraw  # type: ignore
# suppress static type checker complain "error: No library stub file for module 'PIL.ImageFont'"
import PIL.ImageFont  # type: ignore
# suppress static type checker complain "error: No library stub file for module 'PIL.PyAccess'"
from PIL.PyAccess import PyAccess as PixelAccess  # type: ignore

# suppress static type checker complain "error: No library stub file for
# module 'matplotlob.font_manager'"
# suppress static type checker complain "error: No library stub file for module 'matplotlob'"
import matplotlib.font_manager  # type: ignore

# The IPython.core.display module is specific to IPython which is used in Jupyter
# See https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html
# import IPython.core.display

# import the color and file modules in this package
from . import colors
from . import files

# make the names in the color and file modules public to
# consumers of this module so they don't have to import colors module also
Colors = colors.Colors
Color = colors.Color

def set_media_path(path: typing.Optional[str] = None) -> bool:
    """
    forwards to files.set_media_path so module that imports this module
    does not have to import files module also

    :param path:
    :return:
    :rtype bool:
    """
    return files.set_media_path(path)

def media_path(filename: typing.Optional[str]) -> pathlib.Path:
    """
    forwards to files.media_path so module that imports this module
    does not have to import files module also

    :param Optional[str] filename:
    :return:
    :rtype pathlib.Path:
    """
    return files.media_path(filename)

# Type aliases
RGB = typing.Tuple[int, int, int]
ImageSize = typing.Tuple[int, int]
Point = typing.Tuple[int, int]
PointSequence = typing.Sequence[Point]
BaseRGB = colors.BaseRGB
PixelInfoTuple = typing.Tuple[Point, RGB]
Transform = typing.Callable[['PixelInfo'], Color]
Transform2 = typing.Callable[[PixelInfoTuple], PixelInfoTuple]
Predicate = typing.Callable[['PixelInfo'], bool]
Combine = typing.Callable[['PixelInfo', 'PixelInfo'], Color]

def type_error_message(fun_name: str, param_name: str, expected: str, actual: typing.Any) -> str:
    """ generates error message for TypeError """
    return f"In MediaComp.pictures.{fun_name}: {param_name} " +\
           f"expected a {expected}, actually {type(actual)}"

class PixelInfo(colors.Color):
    """
    Class level docstring goes here
    """

    def __init__(self, xy: Point, rgb: typing.Optional[RGB] = None):
        super().__init__(rgb=rgb)
        self._xy: Point = (int(xy[0]), int(xy[1]))

    # Overrides Color.__repr__
    def __repr__(self) -> str:
        return f"PixelInfo(xy = ({self.x}, {self.y}), " + \
               f"pixel_color = Color(red={self.red}, green={self.green}, blue={self.blue}))"

    # Overrides Color.__str__
    def __str__(self) -> str:
        return f"Pixel(red={self.red}, green={self.green}, " + \
               f"blue={self.blue}, x={self.x}, y={self.y})"

    @property
    def color(self) -> colors.Color:
        """
        Write better docstring

        :type: colors.Color
        """
        rgb: RGB = self.rgb
        return colors.Color(rgb[0], rgb[1], rgb[2])

    @property
    def x(self) -> int:  # pylint: disable=invalid-name
        """
        Write better docstring

        :type: int
        """
        return int(self._xy[0])

    @property
    def y(self) -> int:  # pylint: disable=invalid-name
        """
        Write better docstring

        :type: int
        """
        return int(self._xy[1])

class Pixel(PixelInfo):
    """
    Class level docstring goes here
    """

    def __init__(self, xy: Point, pixel_access: PixelAccess):
        self.__pixel_access: PixelAccess = pixel_access
        super().__init__(xy)

    # Overrides PixelInfo.__str__ method
    def __str__(self) -> str:
        return f"Pixel(xy=({self.x}, {self.y}), Color(r={self.red}, g={self.green}, b={self.blue}))"

    @property
    def color(self) -> colors.Color:
        """
        Write better docstring

        :type: colors.Color
        """
        rgb: RGB = self.__pixel_access[self._xy]
        return colors.Color(rgb[0], rgb[1], rgb[2])

    @color.setter
    def color(self, rgb: colors.BaseRGB) -> None:
        if not isinstance(rgb, colors.BaseRGB):
            raise TypeError
        self.rgb = rgb.rgb

    # Overrides BaseRGB.red property getter
    @property
    def red(self) -> int:
        """
        Write better docstring

        :type: int
        """
        return self.rgb[0]

    @red.setter
    def red(self, value: int) -> None:
        value = min(255, max(0, int(value)))
        rgb: RGB = self.__pixel_access[self._xy]
        self.__pixel_access[self._xy] = (value, rgb[1], rgb[2])

    # Overrides BaseRGB.green property getter
    @property
    def green(self) -> int:
        """
        Write better docstring
        :type: int
        """
        return self.rgb[1]

    @green.setter
    def green(self, value: int) -> None:
        value = min(255, max(0, int(value)))
        rgb: RGB = self.__pixel_access[self._xy]
        self.__pixel_access[self._xy] = (rgb[0], value, rgb[2])

    # Overrides BaseRGB.blue property getter
    @property
    def blue(self) -> int:
        """
        Write better docstring

        :type: int
        """
        return self.rgb[2]

    @blue.setter
    def blue(self, value: int) -> None:
        value = min(255, max(0, int(value)))
        rgb: RGB = self.__pixel_access[self._xy]
        self.__pixel_access[self._xy] = (rgb[0], rgb[1], value)

    # Overrides BaseRGB.rgb property getter
    @property
    def rgb(self) -> RGB:
        """
        Write better docstring

        :type: RGB
        """
        rgb: RGB = self.__pixel_access[self._xy]
        return int(rgb[0]), int(rgb[1]), int(rgb[2])

    @rgb.setter
    def rgb(self, value: RGB) -> None:
        self.__pixel_access[self._xy] = value

class TextStyle:
    """
    Class-level docstring goes here
    """

    @staticmethod
    def find_font_file(query: str) -> typing.Optional[str]:
        """
        Write better docstring

        :param str query:
        :return:
        """
        matches = list(filter(lambda path: query in os.path.basename(path),
                              matplotlib.font_manager.findSystemFonts()))
        if len(matches) == 0:
            return None
        return matches[0]

    def __init__(self, font_name: str, emphasis: str, size: float):
        """
        Write better docstring

        :param font_name:
        :param emphasis:
        :param size:
        """
        self.__font_name = str(font_name)
        font_file: typing.Optional[str] = TextStyle.find_font_file(self.__font_name)
        # TODO: emphasis still ignored in font searching
        self.__emphasis = str(emphasis)
        self.__size = float(size)
        self.__font: PIL.ImageFont.ImageFont = PIL.ImageFont.truetype(font_file, self.__size)

    @property
    def font_name(self) -> str:
        """
        name of font used to draw with

        :type: str
        """
        return self.__font_name

    @property
    def font(self) -> PIL.ImageFont.ImageFont:
        """
        Write better docstring

        :type: PIL.ImageFont.ImageFont
        """
        return self.__font

    @property
    def emphasis(self) -> str:
        """
        kind of emphasis to use, 'bold', 'italic', 'bold + italic'

        :type: str
        """
        return self.__emphasis

    @property
    def size(self) -> float:
        """
        size of font in points

        :type: float
        """
        return self.__size

# class PILImage has no pixel-level operations and is agnostic about how many and what kind
# of channels are in the image. Such things will be found in subclasseses of PILImage
class PILImage:
    """
    Class level docstring
    """
    def __init__(self, pil_image: PIL.Image.Image):
        self._pil_image = pil_image

    @property
    def height(self) -> int:
        """
        height of image in pixels

        :type: int
        """
        image_height = self._pil_image.height
        return int(image_height)

    @property
    def width(self) -> int:
        """
        width of image in pixels

        :type: int
        """
        image_width = self._pil_image.width
        return int(image_width)

    @property
    def size(self) -> ImageSize:
        """
        (height, width) tuple

        :type: ImageSize
        """
        return self.height, self.width

    # overriden by Picture subclass
    def copy(self) -> 'PILImage':
        """
        Makes a deep copy of this object

        :return: the copy
        :rtype PILImage:
        """
        return PILImage(self._pil_image.copy())

    def set_color(self, color: colors.BaseRGB = colors.Colors.black):
        """
        Write better docstring

        :param color:
        :return:
        """
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.rectangle([(0, 0), (self.width, self.height)], fill=color)

    def copy_into(self, big_picture: 'PILImage', left: int, top: int):
        """
        Write better docstring

        :param big_picture:
        :param int left:
        :param int top:
        :return:
        """
        big_picture._pil_image.paste(self._pil_image, (left, top))  # pylint: disable=protected-access

    def add_arc(self, x: int, y: int,  # pylint: disable=invalid-name;  # pylint: disable=too-many-arguments
                width: int, height: int,
                start: float, angle: float,
                color: colors.BaseRGB = colors.Colors.black
                ) -> None:
        """
        Write better docstring

        :param int x:
        :param int y:
        :param int width:
        :param int height:
        :param float start:
        :param float angle:
        :param colors.Color color:
        :raises TypeError:
        """
        x = int(x)  # pylint: disable=invalid-name
        y = int(y)  # pylint: disable=invalid-name
        width = int(width)
        height = int(height)
        start = float(start)
        angle = float(angle)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_arc", "c", "Color", color))

        fill_color: RGB = color.rgb
        draw = PIL.ImageDraw.Draw(self._pil_image)
        bounding_box: PointSequence = [(x, y), (x + width, y + height)]
        draw.arc(bounding_box, start=start, end=start+angle, fill=fill_color, width=1)

    def add_arc_filled(self, x: int, y: int,  # pylint: disable=invalid-name;  # pylint: disable=too-many-arguments
                       width: int, height: int,
                       start: float, angle: float,
                       color: colors.BaseRGB = colors.Colors.black
                       ) -> None:
        """
        Write better docstring

        :param int x:
        :param int y:
        :param int width:
        :param int height:
        :param float start:
        :param float angle:
        :param colors.Color color:
        :raises TypeError:
        """
        x = int(x)  # pylint: disable=invalid-name
        y = int(y)  # pylint: disable=invalid-name
        width = int(width)
        height = int(height)
        start = float(start)
        angle = float(angle)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_arc_filled", "color", "Color", color))
        fill_color: RGB = color.rgb
        bounding_box: PointSequence = [(x, y), (x + width, y + height)]
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.pieslice(bounding_box, start=start, end=start+angle, fill=fill_color, width=1)

    def add_line(self, start_x: int, start_y: int,  # pylint: disable=too-many-arguments
                 width: int, height: int,
                 color: colors.BaseRGB = colors.Colors.black
                 ) -> None:
        """
        Write better docstring

        :param int start_x:
        :param int start_y:
        :param int width:
        :param int height:
        :param colors.Color color:
        :raises TypeError:
        """
        start_x = int(start_x)
        start_y = int(start_y)
        width = int(width)
        height = int(height)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_line", "color", "Color", color))
        bounding_box: PointSequence = [(start_x, start_y), (start_x + width, start_y + height)]
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.line(bounding_box, fill=color.rgb, width=1)

    def add_oval(self, center_x: int, center_y: int,  # pylint: disable=too-many-arguments
                 width: int, height: int,
                 color: colors.BaseRGB = colors.Colors.black
                 ) -> None:
        """
        Write better docstring
        :param int center_x:
        :param int center_y:
        :param int width:
        :param int height:
        :param colors.Color color:
        :raises TypeError:
        """
        center_x = int(center_x)
        center_y = int(center_y)
        width = int(width)
        height = int(height)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_oval", "color", "Color", color))
        bounding_box: PointSequence = [(center_x, center_y), (center_x + width, center_y + height)]
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.ellipse(bounding_box, outline=color.rgb, width=1)

    def add_oval_filled(self, center_x: int, center_y: int,  # pylint: disable=too-many-arguments
                        width: int, height: int,
                        color: colors.BaseRGB = colors.Colors.black
                        ) -> None:
        """
        Write better docstring

        :param int center_x:
        :param int center_y:
        :param int width:
        :param int height:
        :param colors.Color color:
        :raises TypeError:
        """
        center_x = int(center_x)
        center_y = int(center_y)
        width = int(width)
        height = int(height)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_oval_filled", "color", "Color", color))
        left_top = (center_x - width//2, center_y - height//2)
        right_bottom = (center_x + width//2, center_y + width//2)
        bounding_box = [left_top, right_bottom]
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.ellipse(bounding_box, outline=color.rgb, fill=color.rgb, width=1)

    def add_rect(self, left: int, top: int,  # pylint: disable=too-many-arguments
                 width: int, height: int,
                 color: colors.BaseRGB = colors.Colors.black
                 ) -> None:
        """
        Takes a picture, a starting (left, top) position (two numbers),
        a width and height (two more numbers, four total),
        and (optionally) a color as input. Adds a rectangular outline of the
        specified dimensions using the (left,top) as the upper left corner.
        Default color is black.

        Wrapped by for :py:func:`.jes.addRect` function.

        :param int left:
        :param int top:
        :param int width:
        :param int height:
        :param colors.Color color:
        :raises TypeError:
        """
        left = int(left)
        top = int(top)
        width = int(width)
        height = int(height)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_rect", "color", "Color", color))
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.rectangle([(left, top), (left + width, top + height)], outline=color.rgb, width=1)

    def add_rect_filled(self, left: int, top: int, width: int, height: int,  # pylint: disable=too-many-arguments
                        color: colors.BaseRGB = colors.Colors.black
                        ) -> None:
        """
        Write better docstring

        :param int left:
        :param int top:
        :param int width:
        :param int height:
        :param colors.Color color:
        :raises TypeError:
        """
        left = int(left)
        top = int(top)
        width = int(width)
        height = int(height)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_rect_filled", "color", "Color", color))
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.rectangle([(left, top), (left+width, top+height)], fill=color.rgb, width=1)

    def add_text(self, x_pos: int, y_pos: int, text: str,
                 color: colors.BaseRGB = colors.Colors.black
                 ) -> None:
        """
        Write better docstring

        :param int x_pos:
        :param int y_pos:
        :param str text:
        :param colors.Color color:
        :raises TypeError
        """
        x_pos = int(x_pos)
        y_pos = int(y_pos)
        text = str(text)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_text", "color", "Color", color))
        draw = PIL.ImageDraw.Draw(self._pil_image)
        draw.text((x_pos, y_pos), text, fill=color.rgb)

    def add_text_with_style(self, x_pos: int, y_pos: int,  # pylint: disable=too-many-arguments
                            text: str, style: TextStyle,
                            color: colors.BaseRGB = colors.Colors.black
                            ) -> None:
        """
        Write better docstring

        :param int x_pos:
        :param int y_pos:
        :param str text:
        :param str style:
        :param colors.Color color:
        :raises TypeError:
        """
        x_pos = int(x_pos)
        y_pos = int(y_pos)
        text = str(text)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("PILImage.add_text_styled",
                                               "color", "Color", color))
        if not isinstance(style, TextStyle):
            raise TypeError(type_error_message("PILImage.add_text_styled",
                                               "style",
                                               "TextStyle", style))
        draw: PIL.ImageDraw.ImageDraw = PIL.ImageDraw.Draw(self._pil_image)
        draw.text((x_pos, y_pos), text, font=style.font, fill=color.rgb)

#
# Picture operates on files containing RGB images
#
# All interactions with the filesystem should be here
# not in superclasses
#
# class Picture adds pixel-level operations to PILImage
# and works only with 3-channel 8-bit/channel images
#
class Picture(PILImage, collections.abc.Iterable):
    """
    Class-level docstrings
    """
    def __init__(self, pil_image: PIL.Image.Image):
        if pil_image.mode == "RGB":
            super().__init__(pil_image)
        else:
            super().__init__(pil_image.convert(mode="RGB"))
        self.__pixel_access: PIL.PyAccess.PyAccess = self._pil_image.load()

    @classmethod
    def from_file(cls, filename: typing.Union[str, os.PathLike]) -> 'Picture':
        """
        Write better docstring

        :param filename:
        :return:
        :rtype: Picture
        """
        if not isinstance(filename, os.PathLike):
            filename = files.media_path(str(filename))
        img = PIL.Image.open(filename)
        img.load()
        return cls(img)

    @classmethod
    def make_empty(cls, width: int, height: int,
                   color: colors.BaseRGB = colors.Colors.black) -> 'Picture':
        """
        Write better docstring

        :param int width:
        :param int height:
        :param colors.Color color:
        :return:
        :rtype: Picture
        """
        height = int(height)
        width = int(width)
        if not isinstance(color, colors.BaseRGB):
            raise TypeError(type_error_message("setAllPixelsToAColor", "color", "Color", color))
        return cls(PIL.Image.new("RGB", (width, height), color.rgb))

    def __str__(self) -> str:
        return "<image> size:" + str(self.size)

    def _repr_html_(self) -> str:
        return '<img src="' + self.to_base64() + '" />'

    # TODO: fix it so it uses IPython display mechanism for PNG rather than HTML
    # def _repr_png_(self):
    #    pass

    def __getitem__(self, key: Point) -> Pixel:
        index_x = int(key[0])
        index_y = int(key[1])

        if index_x >= self.width:
            index_x = self.width - 1
        if index_y >= self.height:
            index_y = self.height - 1
        if index_x < 0:
            index_x = 0
        if index_y < 0:
            index_y = 0
        return Pixel((index_x, index_y), self.__pixel_access)

    def __setitem__(self, key: Point, value: colors.BaseRGB) -> None:
        index_x = int(key[0])  # pylint: disable=invalid-name
        index_y = int(key[1])  # pylint: disable=invalid-name

        # silently discard value if out of range, is that really a good thing?
        if index_x < 0 or index_x >= self.width:
            return
        if index_y < 0 or index_y >= self.height:
            return

        if not isinstance(value, colors.BaseRGB):
            raise TypeError(type_error_message("Picture.setitem", "value", "Color", value))

        self.__pixel_access[index_x, index_y] = value.rgb

    def __iter__(self) -> typing.Iterator[Pixel]:
        for j in range(self.height):
            for i in range(self.width):
                yield Pixel((i, j), self.__pixel_access)

    def to_base64(self) -> str:
        """
        convert to base64 string of bytes in PNG encoding

        :return:
        """
        file_like_backed_by_byte_buffer = io.BytesIO()
        self._pil_image.save(file_like_backed_by_byte_buffer, format='PNG', optimize=True)
        unencoded_byte_buffer = file_like_backed_by_byte_buffer.getvalue()
        encoded_byte_buffer = base64.b64encode(unencoded_byte_buffer)
        base64_string = str(encoded_byte_buffer)[2:-1]  # discard "b'" and beginning and "'" at end
        return 'data:image/png;base64,' + base64_string

    # TODO test this
    def save(self, file_name: str) -> None:
        """
        save image to file
        :param file_name: name of file to save
        """
        self._pil_image.save(file_name)

    def copy(self) -> 'Picture':
        """
        Makes a copy of the picture

        :return: The copy
        :rtype: Picture
        """
        return Picture(self._pil_image.copy())

    def resize(self, height: int, width: int) -> 'Picture':
        """
        Write better docstring

        :param int height:
        :param int width:
        :return:
        """
        height = int(height)
        width = int(width)
        new_image = self._pil_image.resize((width, height))
        return Picture(new_image)

    def map(self, transform: Transform, left_top: Point = (0, 0),
            right_bottom: Point = (1000000, 1000000)) -> 'Picture':
        """
        Write better docstring

        :param transform:
        :param Point left_top:
        :param Point right_bottom:
        :return:
        """
        left: int = int(left_top[0])
        top: int = int(left_top[1])
        right: int = int(right_bottom[0])
        bottom: int = int(right_bottom[1])
        if left > right:
            (right, left) = (left, right)
        if top > bottom:
            (top, bottom) = (bottom, top)
        if left < 0:
            left = 0
        if right > self.width:
            right = self.width
        if top < 0:
            top = 0
        if bottom > self.height:
            bottom = self.height
        copy = self.copy()
        pixel_access: PixelAccess = copy.__pixel_access  # pylint: disable=protected-access
        for j in range(top, bottom):
            for i in range(left, right):
                index: Point = (i, j)
                pixel_info = PixelInfo(index, rgb=pixel_access[index])
                color_out: colors.Color = transform(pixel_info)
                pixel_access[index] = color_out.rgb
        return copy

    def remap(self, transform: Transform2, color: Color = Colors.black) -> 'Picture':
        """
        Write better docstring

        :param transform:
        :param Color color:
        :return:
        """
        width = self.width
        height = self.height
        target = Picture.make_empty(width, height, color)
        target_pixel_access: PixelAccess = target.__pixel_access  # pylint: disable=protected-access
        self_pixel_access: PixelAccess = self.__pixel_access
        for j in range(0, height):
            for i in range(0, width):
                index_in: Point = (i, j)
                tuple_in: PixelInfoTuple = (index_in, Color.unpack(self_pixel_access[index_in]))
                tuple_out: PixelInfoTuple = transform(tuple_in)
                ((target_x, target_y), rgb_out) = tuple_out
                target_pixel_access[target_x % width, target_y % height] = Color.clamp(rgb_out)
        return target

    def combine(self, pixel_combine: Combine, other: 'Picture', resize=False) -> 'Picture':
        """
        Writie better docstring

        :param pixel_combine:
        :param Picture other:
        :param bool resize:
        :return:
        :rtype: Picture
        """
        copy = self.copy()
        if resize:
            if (not copy.height == other.height) or (not copy.width == other.width):
                other = other.resize(copy.height, copy.width)
        pixel_access: PixelAccess = copy.__pixel_access  # pylint: disable=protected-access
        other_pixel_access: PixelAccess = other.__pixel_access  # pylint: disable=protected-access
        for j in range(copy.height):
            for i in range(copy.width):
                index: Point = (i, j)
                pixel_info = PixelInfo(index, rgb=pixel_access[index])
                other_pixel_info = PixelInfo(index, rgb=other_pixel_access[index])
                color_out: colors.Color = pixel_combine(pixel_info, other_pixel_info)
                pixel_access[index] = color_out.rgb
        return copy

    def map_if(self, predicate: Predicate, transform: Transform) -> 'Picture':
        """
        Write better docstring

        :param predicate:
        :param transform:
        :return:
        :rtype: Picture
        """
        copy = self.copy()
        pixel_access: PixelAccess = copy.__pixel_access  # pylint: disable=protected-access
        for j in range(copy.height):
            for i in range(copy.width):
                index: Point = (i, j)
                pixel_info = PixelInfo(index, rgb=pixel_access[index])
                if predicate(pixel_info):
                    color_out: colors.Color = transform(pixel_info)
                    pixel_access[index] = color_out.rgb
        return copy

    def replace_if(self, predicate: Predicate, other: 'Picture',
                   resize=False) -> 'Picture':
        """
        Write better docstring

        :param predicate:
        :param other:
        :param bool resize:
        :return:
        :rtype: Picture
        """
        copy = self.copy()
        if resize:
            if (not copy.height == other.height) or (not copy.width == other.width):
                other = other.resize(copy.height, copy.width)
        pixel_access: PixelAccess = copy.__pixel_access  # pylint: disable=protected-access
        other_pixel_access: PixelAccess = other.__pixel_access  # pylint: disable=protected-access
        for j in range(copy.height):
            for i in range(copy.width):
                index: Point = (i, j)
                pixel_info = PixelInfo(index, rgb=pixel_access[index])
                if predicate(pixel_info):
                    pixel_access[index] = other_pixel_access[index]
        return copy


from __future__ import annotations

from typing import Optional

from sqlalchemy import ForeignKey
from sqlalchemy.inspection import inspect
from sqlalchemy.orm import relationship
from sqlmodel import Field, Relationship, SQLModel, create_engine

class Base(SQLModel):
    __repr_exclude__ = None
    __args_memo__ = None

    def __repr_args__(self) -> list[Tuple[str, Any]]:
        cls = type(self)
        if cls.__args_memo__ is None:
            if cls.__repr_exclude__ is None:
                rels = inspect(cls).relationships.keys()
                fks = [fk.parent.name.rstrip("_id") for fk in cls.__table__.foreign_keys]
                cls.__repr_exclude__ = [k for k in rels if k in fks]
            cls.__args_memo__ = [(k, v) for k, v in super().__repr_args__() if k not in cls.__repr_exclude__]
        return cls.__args_memo__

class Caca(Base, table=True):
    __tablename__ = "cacas"
    id: Optional[int] = Field(default=None, primary_key=True, index=True)
    description: str = Field(index=True)
    shengbing_id: int = Field(default=None, foreign_key="shengbings.id")
    shengbing: ShengBing = Relationship(
        back_populates="cacas", sa_relationship_kwargs={"uselist": False}
    )

class ShengBing(Base, table=True):
    __tablename__ = "shengbings"
    id: Optional[int] = Field(default=None, primary_key=True, index=True)
    severity: str = Field(index=True)
    cacas: list[Caca] = Relationship(back_populates="shengbing")
    erzi: ErZi = Relationship(
        back_populates="shengbing", sa_relationship_kwargs={"uselist": False}
    )

class ErZi(Base, table=True):
    __tablename__ = "erzis"
    id: Optional[int] = Field(default=None, primary_key=True, index=True)
    name: str = Field(index=True)
    shengbing_id: int = Field(default=None, foreign_key="shengbings.id")
    shengbing: ShengBing = Relationship(
        back_populates="erzi", sa_relationship_kwargs={"uselist": False}
    )

engine = create_engine("sqlite:///example.db")

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument("-c", "--create", action="store_true")
    args = parser.parse_args()

    if args.create:
        Base.metadata.create_all(engine)


import sys
sys.stdin = open("input.txt", "r")
input = sys.stdin.readline

stack=[]
point=-1

def cal(fun, n):
    global point
    global stack
    if fun=='push':
        stack.append(n)
        point= point+1
    elif fun=='pop':
        if len(stack)==0:
            print(-1)
        else:
            print(stack.pop())
            point=point-1
    elif fun=='size':
        print(len(stack))
    elif fun=='empty':
        if len(stack) == 0:
            print(1)
        else:
            print(0)
    elif fun=='top':
        if len(stack)==0:
            print(-1)
        else:
            print(stack[len(stack)-1])
c=int(input())

for i in range(c):
    sentence = input().split()
    if len(sentence)==2:
        cal(sentence[0], int(sentence[1]))
    elif len(sentence)==1:
        cal(sentence[0], 0)


import random

# creating deck of cards and shuffling it
card_categories = ['Hearts', 'Clubs', 'Diamonds', 'Spades']
card_list = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']

def start_game():
    # shuffles the deck
    deck = [(card, category) for category in card_categories for card in card_list]
    random.shuffle(deck)

    # while loop to get all players
    sign_up_list = []
    add_player = True

    while add_player:
        name = input('Enter your name: ')
        sign_up_list.append(name)

        answer = input('\nIs there another player (y/n)? ')
        if answer.lower().startswith('y'):
            print()
            continue
        else:
            add_player = False
    print(f'\nNumber of players: {len(sign_up_list)}')

    # creating dict objects for each player
    players = []
    for player in sign_up_list:
            players.append(
                {
                    "Name": player,
                    "Hand": [],
                    "Hand2": [],
                    "Natural": False,
                    "Natural2": False,
                    "Insurance": False,
                    "Split": False,
                    "DoubleDown": False,
                    "Surrender": False
                }
            )

    # creating a dealer object
    players.append(
        {
            "Name": "Dealer",
            "Hand": [],
            "Natural": False
        }
    )

    # dealing two cards to each player and dealer
    for i in range(2):
        for person in players:
            person["Hand"].append(deck.pop(0))

    return players, deck

# checks dealer's up card for possible insurance or natural blackjack
def check_face_up(player):
    if player["Hand"][0][0] == "A":
        return "A"
    elif player["Hand"][0][0] in ['10', 'J', 'Q', 'K']:
        return "ten-card"
    else:
        return False

# checks if the current player is a dealer
def isDealer(player):
    if player["Name"] == 'Dealer':
        return True
    else:
        return False

# revealing deals
def display_hand(player, reveal=False):
    if not isDealer(player):
        for card in player['Hand']:
            print(card)
    else:
        if reveal:
            print('\nDealer\'s cards are: ')
            for card in player['Hand']:
                print(card)
        else:
            print(f"\nDealer's cards:\n{player['Hand'][0]}\nUnknown")

# creates list to iterate through each hand if player chose to split
def split_creation(player):
    if player["Split"]:
        both_hands = [{"Which Hand": k, "Hand": player[k]} for k in player if k == "Hand" or k == "Hand2"]
        return both_hands
    else:
        return

# deals extra card
def hit(player_hand, deck: list):
    player_hand.append(deck.pop(0))

# get total value of deal
def get_total(player):
    card_list = [card[0] for card in player["Hand"]]
    # ace moved to last to better sum total of deal and determine soft value
    if 'A' in card_list:
        card_list.append(card_list.pop(card_list.index('A')))
    total = 0
    for card in card_list:
        # A = 1 or 11
        if card == 'A':
            # for dealers if an 11 Ace gets them a bust deal, then Ace becomes 1
            if isDealer(player) and total + 11 > 21:
                total += 1
            elif isDealer(player) and 17 <= total + 11 <= 21:
                total += 11
            # ace will always be 11 unless the total value is over 21,
            # then treated as 1
            elif not isDealer(player) and total + 11 > 21:
                total += 1
            else:
                total+= 11
        # 2-9
        elif '2' <= card <= '9':
            total += int(card)
        # 10-K
        else:
            total += 10
    return total

# player takes their turn
def player_turn(player, deck):
    # checks if player chose the option to split their pair
    if player["Split"]:
        both_hands = split_creation(player)
        # if player chose to split pair and both pairs were Aces, player is dealt one card for each hand
        if both_hands[0]["Hand"][0][0] == "A" and both_hands[1]["Hand"][0][0] == "A":
            print(f'\n{player["Name"]}, you drew two aces and decided to split. You will be dealt only one extra card.')
            for hand in both_hands:
                print(f'\n{player["Name"]}, dealer is now dealing to {hand["Which Hand"]}')
                hit(hand["Hand"], deck)
                print(f'\n{player["Name"]}, here is your new hand:')
                for card in hand["Hand"]:
                    print(card)
                if get_total(hand) == 21:
                    print('\nWow you got a blackjack! Lucky Lucky.')
        # if pairs aren't Aces, dealer will deal to each hand normally
        else:
            for hand in both_hands:
                print(f'\n{player["Name"]}, dealer is now dealing to {hand["Which Hand"]}')
                hit(hand["Hand"], deck)
                print(f'\n{player["Name"]}, here is your new hand:')
                for card in hand["Hand"]:
                    print(card)
                # Automatically end the player's turn if they draw a natural hand without splitting Aces
                if get_total(hand) == 21:
                    print('\nYou got blackjack!')
                    continue
                while True:
                    option = input('\nDo you want to stand or hit? ')
                    # ends player's turn if they decide to stand
                    if option.lower() == 'stand':
                        break
                    # draws another card if player decides to hit
                    elif option.lower() == 'hit':
                        hit(hand["Hand"], deck)
                        print(f'\n{player["Name"]}, here is your new hand:')
                        for card in hand["Hand"]:
                            print(card)
                        # Automatically end the player's turn if they draw a blackjack or bust
                        if get_total(hand) == 21:
                            print('\nYou got blackjack!')
                            break
                        elif get_total(hand) > 21:
                            print('\nBusted. You lose.')
                            break
                        else:
                            continue
                    else:
                        print('\nThat is not one of the options. Please try again.')
        # updates players hands after their turn is over
        player["Hand"] = both_hands[0]["Hand"]
        player["Hand2"] = both_hands[1]["Hand"]
    elif player["DoubleDown"]:
        print(f'\n{player["Name"]} the dealer will add one card, faced down, to your hand')
        hit(player["Hand"], deck)
    # if player didn't split pair or double down, play their turn normally
    else:
        while True:
            option = input('\nDo you want to stand or hit? ')
            # ends player's turn if they decide to stand
            if option.lower() == 'stand':
                break
            # draws another card if player decides to hit
            elif option.lower() == 'hit':
                hit(player["Hand"], deck)
                print(f'\n{player["Name"]}, here is your new hand:')
                display_hand(player)
                # Automatically end the player's turn if they draw a blackjack or bust
                if get_total(player) == 21:
                    print('\nYou got blackjack!')
                    break
                elif get_total(player) > 21:
                    print('\nBusted. You lose.')
                    break
                else:
                    continue
            else:
                print('\nThat is not one of the options. Please try again.')

# dealer takes his turn
def dealer_turn(dealer, deck:list):
    if dealer["Natural"]:
        return
    else:
        while True:
            if get_total(dealer) < 17:
                hit(dealer["Hand"], deck)
            elif 17<= get_total(dealer) <= 21:
                if get_total(dealer) == 21:
                    print('\nDealer drew a blackjack!')
                    break
                else:
                    break
            else:
                break
        display_hand(dealer, reveal=True)

# shows the results of the cards dealt to each person
def get_result(players):
    for player in players:
        if isDealer(player):
            break
        # if the dealer has a natural blackjack
        elif players[-1]["Natural"]:
            continue
        # if dealer doesn't have natural blackjack
        elif not players[-1]["Natural"]:
            # checks if player decided to split their hand
            if player["Split"]:
                both_hands = split_creation(player)
                # if both player's split hands are naturals skip
                if player["Natural"] and player["Natural2"]:
                    continue
                # if the first split hand is a natural but the second isn't
                elif player["Natural"] and not player["Natural2"]:
                    print(f'\n{player["Name"]}, your first hand turned out to be a natural hand, but your second didn\'t.')
                    print(f'\nLet\'s see how your second hand performed.')
                    if get_total(both_hands[1]) > 21:
                        continue
                    if get_total(players[-1]) > 21:
                        print(f'\n{player["Name"]}, you won! The dealer dealt a bust.')
                    elif get_total(both_hands[1]) > get_total(players[-1]):
                        print(f'\n{player["Name"]}, you won! Your second hand dealt higher than the dealer.')
                    elif get_total(both_hands[1]) == get_total(players[-1]):
                        print(f'\n{player["Name"]}, your second hand drawed with the dealer.')
                    elif get_total(both_hands[1]) < get_total(players[-1]):
                        print(f'\n{player["Name"]}, you lose. Your second hand dealt lower than the dealer.')

                    print(f'Your deal total: {get_total(both_hands[1])}')
                    print(f'Dealer\'s deal total: {get_total(players[-1])}')
                # if the first split hand is not a natural but the second is
                elif not player["Natural"] and player["Natural2"]:
                    print(f'\n{player["Name"]}, your second hand turned out to be a natural hand, but your first didn\'t.')
                    print(f'\nLet\'s see how your first hand performed.')
                    if get_total(both_hands[0]) > 21:
                        continue
                    if get_total(players[-1]) > 21:
                        print(f'\n{player["Name"]}, you won! The dealer dealt a bust.')
                    elif get_total(both_hands[0]) > get_total(players[-1]):
                        print(f'\n{player["Name"]}, you won! Your first hand dealt higher than the dealer.')
                    elif get_total(both_hands[0]) == get_total(players[-1]):
                        print(f'\n{player["Name"]}, your first hand drawed with the dealer.')
                    elif get_total(both_hands[0]) < get_total(players[-1]):
                        print(f'\n{player["Name"]}, you lose. Your first hand dealt lower than the dealer.')

                    print(f'Your deal total: {get_total(both_hands[0])}')
                    print(f'Dealer\'s deal total: {get_total(players[-1])}')
                # if neither hand is a natural hand
                else:
                    print(f'\n{player["Name"]}, Let\'s see how each of your hands performed...')
                    for hand in both_hands:
                        if get_total(hand) > 21:
                            continue
                        if get_total(players[-1]) > 21:
                            print(f'\n{player["Name"]}, you won! The dealer dealt a bust.')
                        elif get_total(hand) > get_total(players[-1]):
                            print(f'\n{player["Name"]}, you won! {hand["Which Hand"]} dealt higher than the dealer.')
                        elif get_total(hand) == get_total(players[-1]):
                            print(f'\n{player["Name"]}, {hand["Which Hand"]} drawed with the dealer.')
                        elif get_total(hand) < get_total(players[-1]):
                            print(f'\n{player["Name"]}, you lose. {hand["Which Hand"]} dealt lower than the dealer.')

                        print(f'Your deal total: {get_total(hand)}')
                        print(f'Dealer\'s deal total: {get_total(players[-1])}')
            # rewards player if they have a natural blackjack
            elif player["Natural"]:
                continue
            # if player chooses to surrender their hand
            elif player["Surrender"]:
                print(f'{player["Name"]} surrendered.')
            # if the current player already lost by drawing a bust
            elif get_total(player) > 21:
                continue
            # compares results of player's hand vs dealer's hand
            else:
                if get_total(players[-1]) > 21:
                    print(f'\n{player["Name"]}, you won! The dealer dealt a bust.')
                elif get_total(player) > get_total(players[-1]):
                    print(f'\n{player["Name"]}, you won! You dealt higher than the dealer.')
                elif get_total(player) == get_total(players[-1]):
                    print(f'\n{player["Name"]}, you drawed with the dealer.')
                elif get_total(player) < get_total(players[-1]):
                    print(f'\n{player["Name"]}, you lose. You dealt lower than the dealer.')

                print(f'Your deal total: {get_total(player)}')
                print(f'Dealer\'s deal total: {get_total(players[-1])}')


from __future__ import division
import math
import numpy as np
import numpy.random
#from scipy.stats import geom
from cryptorandom.cryptorandom import SHA256

def geometric_skipping(population, p, seed):
    if isinstance(seed, int):
        ss = SHA256(seed)
    else:
        raise ValueError('%r cannot be used to seed SHA256 instance' % seed)

    n = len(population)
    sample = []
    m = int(n*p)
#    rvs = geom.rvs(p=p, size=m) # this is what we'd do if we were using numpy.random
    runifs = ss.random(m)
    rvs = list(map(lambda u: int(1 + np.log(u)/np.log(1-p)), runifs))
    val = np.cumsum(rvs)-1
    for i in range(m):
        if val[i] < n:
            sample.append(population[val[i]])
        else:
            return sample
    index = val[-1]
    while index < (n-1):
        index += int(1 + np.log(ss.random())/np.log(1-p))
        if index < n:
            sample.append(population[index])
    return sample

def test_transformation():
    u = np.array(range(100))
    runifs = u/len(u)
    np.testing.assert_equal(runifs[0], 0)
    p = 0.5
    rvs = list(map(lambda u: int(1 + np.log(u)/np.log(1-p)), runifs[1:]))
    np.testing.assert_equal(rvs[0], 7) # floor( 1 + ln(0.01)/ln(0.5) )
    np.testing.assert_equal(rvs[-1], 1) # floor( 1 + ln(0.99)/ln(0.5) )

def test_geometric_generation():
    ss = SHA256(12345)
    runifs = ss.random(10000)
    p = 0.5
    rvs = list(map(lambda u: int(1 + np.log(u)/np.log(1-p)), runifs))
    np.testing.assert_almost_equal(np.mean(rvs), 1/p, 1) # expected value of geometric(p)

def test_geometric_skipping():
    population = list(range(100))
    rvs = [5, 5, 10, 10, 20, 20, 30, 40]
    val = np.cumsum(rvs)-1 # indices to be chosen. array([  4,   9,  19,  29,  49,  69,  99, 139])
    n = len(population)
    m = len(val)
    sample = []
    for i in range(m):
        if val[i] < n:
            sample.append(population[val[i]])
        else:
            break
    np.testing.assert_equal(sample, val[:-1])

    sample = []
    rvs = [5, 5, 10, 10, 20, 20]
    p = 0.5
    val = np.cumsum(rvs)-1 # indices to be chosen. array([  4,   9,  19,  29,  49,  69])
    m = len(val)
    for i in range(m):
        if val[i] < n:
            sample.append(population[val[i]])
        else:
            break
    index = val[-1]
    while index < (n-1):
        index += int(1 + np.log(0.5)/np.log(1-p)) # add 2 to index
        if index < n:
            sample.append(population[index])
    np.testing.assert_equal(sample, list(val) + list(range(71, 100, 2)))

if __name__ == "__main__":
    test_transformation()
    test_geometric_generation()
    test_geometric_skipping()


"""Sphinx configuration file for an LSST stack package.

This configuration only affects single-package Sphinx documentation builds.
For more information, see:
https://developer.lsst.io/stack/building-single-package-docs.html
"""

import lsst.ts.utils  # noqa
from documenteer.conf.pipelinespkg import *  # type: ignore # noqa

project = "ts_utils"
html_theme_options["logotext"] = project  # type: ignore # noqa
html_title = project
html_short_title = project
# Avoid warning: Could not find tag file _doxygen/doxygen.tag
doxylink = {}  # type: ignore


import requests
import time

url = "https://api.covid19tracker.ca/summary/split"
response = requests.get(url)
js = response.json()

file = open('provincecodes.txt')
codes = file.read()
file.close()
print(codes)

province = input("enter a province code: ").upper()

while True:
    if province in codes:
        for i in js['data']:
            if i['province'] == province:
                province_data = i
        t = time.localtime()
        current_time = time.strftime("%H:%M:%S", t)
        result_date = province_data['date']
        cases = province_data['total_cases']
        deaths = province_data['total_fatalities']
        tests = province_data['total_tests']
        vaccinations = province_data['total_vaccinations']
        vaccinated = province_data['total_vaccinated']
        result = f'{province} covid data:\ndate: {result_date}\ntime: {current_time}\ntotal cases: {cases}\ntotal deaths: {deaths}\ntotal tests : {tests} \ntotal vaccines administered: {vaccinations}\nnumber of fully vaccinated: {vaccinated}\n'
        print(result)
        with open(f"./province covid data/{province}coviddata.txt", "a") as f:
            f.write(result)
        break

    else:
        print('enter a valid province code')
        province = input("enter the province code: ").upper()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This script is a simple wrapper which prefixes each i3status line with custom
# information. It is a python reimplementation of:
# http://code.stapelberg.de/git/i3status/tree/contrib/wrapper.pl
#
# To use it, ensure your ~/.i3status.conf contains this line:
#     output_format = "i3bar"
# in the 'general' section.
# Then, in your ~/.i3/config, use:
#     status_command i3status | ~/.i3/contrib/mplayer-wrapper.py
# In the 'bar' section.
#
# In its previous version it would display the cpu frequency governor, but you
# are free to change it to display whatever you like, see the comment in the
# source code below.
#
# © 2012 Valentin Haenel <valentin.haenel@gmx.de>
#
# In its current version, it will display what mplayer is playing by extracting
# song title from ICY Info lines written to a specific file stored whose path
# is stored in METADATA_FILE variable.
# To use it, ensure to output mplayer's ICY Info line to METADATA_FILE (see below).
# I used the following script to launch mplayer:
#     METADATA_FILE=/tmp/mplayer.data
#     [ -f $METADATA_FILE ] && rm -f $METADATA_FILE
#     mplayer -playlist foo.m3u | stdbuf -o L grep ICY > $METADATA_FILE
#     [ -f $METADATA_FILE ] && rm -f $METADATA_FILE
#
# © 2015 Mathieu Soula aka rid  <msoula@gmx.com>
#
# This program is free software. It comes without any warranty, to the extent
# permitted by applicable law. You can redistribute it and/or modify it under
# the terms of the Do What The Fuck You Want To Public License (WTFPL), Version
# 2, as published by Sam Hocevar. See http://sam.zoy.org/wtfpl/COPYING for more
# details.

import re
import os.path
import sys
import json

METADATA_FILE='/tmp/mplayer.data'
SONG_COLOR='#6780fb'
NOSONG_COLOR='#ffffff'
NOSONG_MSG='No Song Played'

def get_song(f):
    """ Read last line of given file which contains Mplayer's ICY Info data
        This line contains dictionary entry StreamTitle that is returned if found """
    try:
        with open(METADATA_FILE) as fp:
            line = fp.readlines()[-1].strip()
            info = line.split(':', 1)[1].strip()
            attrs = dict(re.findall("(\w+)='([^']*)'", info))
            return attrs.get('StreamTitle', None)
    except IndexError:
        return None
    except IOError:
        return None

def print_line(message):
    """ Non-buffered printing to stdout. """
    sys.stdout.write(message + '\n')
    sys.stdout.flush()

def read_line():
    """ Interrupted respecting reader for stdin. """
    # try reading a line, removing any extra whitespace
    try:
        line = sys.stdin.readline().strip()
        # i3status sends EOF, or an empty line
        if not line:
            sys.exit(3)
        return line
    # exit on ctrl-c
    except KeyboardInterrupt:
        sys.exit()

if __name__ == '__main__':
    # Skip the first line which contains the version header.
    print_line(read_line())

    # The second line contains the start of the infinite array.
    print_line(read_line())

    while True:
        line, prefix = read_line(), ''
        # ignore comma at start of lines
        if line.startswith(','):
            line, prefix = line[1:], ','

        j = json.loads(line)

        # insert information into the start of the json, but could be anywhere
        if os.path.exists(METADATA_FILE):
            song = get_song(METADATA_FILE)
            if song is not None:
                j.insert(0, {'full_text' : '%s' % song, 'name' : 'song', 'color' : SONG_COLOR})
            else:
                j.insert(0, {'full_text' : NOSONG_MSG, 'name' : 'song', 'color' : NOSONG_COLOR})
        else:
            j.insert(0, {'full_text' : NOSONG_MSG, 'name' : 'song', 'color' : NOSONG_COLOR})

        # and echo back new encoded json
        print_line(prefix+json.dumps(j))


import flask

from app import app, db
from models import Image
from plot import plot_data

@app.route("/images")
def list_images():
    return {
        "result": "success",
        "images": Image.query.all(),
    }

@app.route("/images/<image_id>/meta")
def get_image_metadata(image_id):
    image = Image.query.filter_by(id=image_id).first()
    if not image:
        return {
            "result": "error",
            "message": f"can't find image with ID {image_id}"
        }, 404
    else:
        return {
            "result": "success",
            "image": image,
        }

@app.route("/images/<image_id>/meta", methods=["POST"])
def update_image_metadata(image_id):
    cell_width = flask.request.json.get("cell_width")
    if not cell_width:
        return {
            "result": "error",
            "message": "cell_width is a required parameter",
        }, 400

    num_updated_rows = (
        Image.query
            .filter_by(id=image_id)
            .update({Image.cell_width: cell_width}))
    db.session.commit()
    if num_updated_rows == 0:
        return {
            "result": "error",
            "message": f"could not find image with ID {image_id}"
        }, 404

    return {"result": "success"}

@app.route("/images/<image_id>", methods=["GET"])
def get_image(image_id):
    return flask.send_from_directory(app.config["IMAGE_DIR"], image_id)

@app.route("/plot", methods=["POST"])
def launch_plot():
    plot_data(flask.request.json)
    return {"result": "success"}


# You have k lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of the k lists.
#
# We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-a == d-c.
#
# Example 1:
# Input:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
# Output: [20,24]
# Explanation:
# List 1: [4, 10, 15, 24,26], 24 is in range [20,24].
# List 2: [0, 9, 12, 20], 20 is in range [20,24].
# List 3: [5, 18, 22, 30], 22 is in range [20,24].

# TLE
import heapq
class Solution(object):
    def smallestRange(self, nums):
        """
        :type nums: List[List[int]]
        :rtype: List[int]
        """
        h = []
        m = 0
        for i in range(len(nums)):
            x = nums[i][0]
            m = max(m,x)
            heapq.heappush(h,[x,i,1])
        mini = h[0][0]
        maxi = m
        diff = maxi - mini
        ans = [mini,maxi]
        while True:
            value,index,pos = heapq.heappop(h)
            if pos == len(nums[index]):
                break
            x = nums[index][pos]

            heapq.heappush(h,[x,index,pos+1])
            mini= h[0][0]
            maxi = max(maxi,x)
            if maxi - mini < diff:
                ans = [mini,maxi]
                diff = maxi - mini
        return ans

################3
class Solution1:
    def smallestRange(self, nums):
        three_ele_heap = []
        maxi = float('-inf')
        for i in range(len(nums)):
            ele = Element(nums[i][0], i, 0)
            heapq.heappush(three_ele_heap, ele)
            maxi = max(maxi, nums[i][0])
        # base case
        start = three_ele_heap[0].val
        end = maxi
        distance = end - start
        # general case
        while len(three_ele_heap) > 0:
            ele = heapq.heappop(three_ele_heap)
            index = ele.index
            if ele.pos == len(nums[index]) - 1:
                break
            val = nums[index][ele.pos + 1]
            pos = ele.pos + 1

            heapq.heappush(three_ele_heap, Element(val, index, pos))
            maxi = max(maxi, val)
            new_distance = maxi - three_ele_heap[0].val
            if new_distance < distance:
                start = three_ele_heap[0].val
                end = maxi
                distance = new_distance

        return [start, end]

class Element:
    def __init__(self, val, index, pos):
        self.val = val
        self.index = index
        self.pos = pos

    def __lt__(a, b):
        return a.val < b.val

if __name__ == "__main__":
    nums = [[1,2,3],[1,2,3],[1,2,3]]
    nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
    nums = [[-5,-4,-3,-2,-1,1],[1,2,3,4,5]]
    x = Solution1()
    print(x.smallestRange(nums))


#HW5P2
#By: Jacob Buurman
#I pledge my honor that I have abided by the Stevens Honor System.

def sum():
    list = eval(input("Enter a list of numbers separated by commas: "))
    sum = 0
    for num in list:
        sum += int(num)
    print(sum)

sum()


import gi
gi.require_version('Gtk', '3.0')
import requests
import json
import threading
import os
from gi.repository import Gtk, GdkPixbuf, GLib, Pango
# Import the modularized components
from ACDcomponents import ThumbnailBox, ImageButton, AmiiboFilterBox
from ACDutils import fetch_amiibo_data, load_image_data

class AmiiboApp(Gtk.Box):
    def __init__(self):
        super(AmiiboApp, self).__init__(orientation=Gtk.Orientation.VERTICAL)

        self.amiibo_images = []
        self.selected_images = []
        self.image_thumbnail_size = 100

        main_box = self  # Now, AmiiboApp itself is the main box

        # Start - Logo and Label code
        logo_label_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        main_box.pack_start(logo_label_box, False, False, 10)

        logo_pixbuf = GdkPixbuf.Pixbuf.new_from_file("Amiibo_logo.png")
        logo_image = Gtk.Image.new_from_pixbuf(logo_pixbuf)
        logo_label_box.pack_start(logo_image, False, False, 0)

        title_label = Gtk.Label("Cards Downloader")
        title_label.set_size_request(300, 0)

        font_desc = title_label.get_pango_context().get_font_description()
        font_desc.set_size(18 * Pango.SCALE)
        title_label.modify_font(font_desc)

        logo_label_box.pack_start(title_label, False, False, 0)

        filter_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        main_box.pack_start(filter_box, False, False, 5)

        self.search_entry = Gtk.Entry()
        self.search_entry.set_placeholder_text("Search")
        self.search_entry.connect("changed", self.apply_filters)
        filter_box.pack_start(self.search_entry, False, False, 5)

        self.amiibo_series_filter = Gtk.ComboBoxText()
        self.amiibo_series_filter.connect("changed", self.apply_filters)
        filter_box.pack_start(self.amiibo_series_filter, False, False, 5)

        content_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        main_box.pack_start(content_box, True, True, 0)

        scrolled_window = Gtk.ScrolledWindow()
        self.image_listbox = Gtk.ListBox()
        scrolled_window.add(self.image_listbox)
        content_box.pack_start(scrolled_window, True, True, 5)

        details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.large_image = Gtk.Image()

        details_box.pack_start(self.large_image, True, True, 5)
        self.info_label = Gtk.Label.new("0/9 images selected")
        details_box.pack_start(self.info_label, False, False, 5)
        self.download_button = Gtk.Button(label="Download")
        self.download_button.connect("clicked", self.download_selected_images)
        details_box.pack_start(self.download_button, False, False, 5)
        self.deselect_button = Gtk.Button(label="Deselect All")
        self.deselect_button.connect("clicked", self.deselect_all_images)
        details_box.pack_start(self.deselect_button, False, False, 5)

        content_box.pack_start(details_box, False, False, 5)
        self.show_all()

        threading.Thread(target=self.load_images, daemon=True).start()

    def load_images(self):
        response = requests.get('https://www.amiiboapi.com/api/amiibo/')
        amiibo_data = json.loads(response.text)
        self.amiibo_images = amiibo_data['amiibo']

        amiibo_series = set()
        for amiibo in self.amiibo_images:
            amiibo_series.add(amiibo.get('amiiboSeries', 'Unknown'))

        GLib.idle_add(self.amiibo_series_filter.append_text, "Select Amiibo Series")
        for series in sorted(amiibo_series):
            GLib.idle_add(self.amiibo_series_filter.append_text, series)

        GLib.idle_add(self.amiibo_series_filter.set_active, 0)

    def apply_filters(self, *args):
        search_query = self.search_entry.get_text().strip().lower()
        amiibo_series_filter = self.amiibo_series_filter.get_active_text()

        if amiibo_series_filter == "Select Amiibo Series":
            amiibo_series_filter = None

        for row in self.image_listbox.get_children():
            row.destroy()

        for index, amiibo in enumerate(self.amiibo_images):
            if search_query and search_query not in amiibo['name'].lower():
                continue

            if amiibo_series_filter and amiibo_series_filter not in amiibo['amiiboSeries']:
                continue

            thumbnail_url = amiibo['image']
            name = amiibo['name']
            series = amiibo['amiiboSeries']
            character = amiibo['character']
            amiibo_type = amiibo['type']

            def create_row(image_data, name, series, character, amiibo_type, url):
                thumbnail = ThumbnailBox(image_data, name, series, character, amiibo_type)
                image_button = ImageButton(thumbnail, url)
                image_button.connect("clicked", self.select_image, amiibo)
                self.image_listbox.add(image_button)
                image_button.show_all()

            threading.Thread(target=self.load_image_thumbnail, args=(thumbnail_url, name, series, character, amiibo_type, create_row), daemon=True).start()

    def load_image_thumbnail(self, url, name, series, character, amiibo_type, callback):
        image_data = self.load_image_data(url, self.image_thumbnail_size)
        GLib.idle_add(callback, image_data, name, series, character, amiibo_type, url)

    def load_image_data(self, url, size=None):
        response = requests.get(url)
        loader = GdkPixbuf.PixbufLoader()
        loader.write(response.content)
        loader.close()

        pixbuf = loader.get_pixbuf()
        if size:
            aspect_ratio = pixbuf.get_height() / pixbuf.get_width()
            new_height = size * aspect_ratio
            pixbuf = pixbuf.scale_simple(size, int(new_height), GdkPixbuf.InterpType.BILINEAR)

        return pixbuf

    def select_image(self, button, amiibo):
        thumbnail_box = button.get_thumbnail_widget()
        image_widget = thumbnail_box.get_image()
        url = button.get_url()

        if len(self.selected_images) >= 9 and image_widget.get_opacity() == 1:
            return

        if image_widget.get_opacity() < 1:
            image_widget.set_opacity(1)
            self.selected_images.remove(url)
        else:
            image_widget.set_opacity(0.3)
            self.selected_images.append(url)
            large_image_data = self.load_image_data(url)
            self.large_image.set_from_pixbuf(large_image_data)
            self.large_image.set_size_request(300, -1)
            self.large_image.props.icon_size = Gtk.IconSize.DIALOG

        self.update_info_label()
        self.download_button.set_sensitive(len(self.selected_images) == 9)

    def deselect_all_images(self, button):
        for row in self.image_listbox.get_children():
            image_button = row.get_children()[0]
            thumbnail_box = image_button.get_thumbnail_widget()
            image_widget = thumbnail_box.get_image()
            image_widget.set_opacity(1)

        self.selected_images.clear()
        self.update_info_label()
        self.download_button.set_sensitive(False)

    def download_selected_images(self, button):
        amiibo_folder = "amiibo"
        if not os.path.exists(amiibo_folder):
            os.makedirs(amiibo_folder)

        for index, url in enumerate(self.selected_images):
            image_data = self.load_image_data(url)
            file_path = os.path.join(amiibo_folder, f"image{index+1}.png")
            image_data.savev(file_path, 'png', [], [])

        print(f"{len(self.selected_images)} images downloaded to {amiibo_folder}")

    def update_info_label(self):
        self.info_label.set_text(f"{len(self.selected_images)}/9 images selected")