import random
import pygame
from pygame.locals import *
import logging
import numpy as np
import itertools

# logging.basicConfig(filename = 'Result.log', level=logging.INFO)
# copy Rohit Agrawal's work and modify for py_game version. It doesn't work really well but the concept has been applied.

pygame.init()

BLUE = (0, 0, 255)
GREEN = (0 ,255, 0)
RED = (255, 0 , 0)

width = 300
height = 300
line_width = 6
font = pygame.font.SysFont(None,20)

screen = pygame.display.set_mode((width, height))

markers = [[0,0,0],[0,0,0],[0,0,0]]
clicked = False
pos = []
player = 1
winner = 0
game_over = False
again_rect = Rect(width//2 - 80,height//2,160,50)
win = [0,0]
totalgame = 0
win_text = ''
winrateCalculated = False
states_dict = {}

def copy_game_state(state):
    new_state = [[0,0,0],[0,0,0],[0,0,0]]
    for i in range(3):
        for j in range(3):
            new_state[i][j] = state[i][j]
    return new_state

def play_move(state, player, block_num):
    if state[int((block_num-1)/3)][(block_num-1)%3] == 0:
        state[int((block_num-1)/3)][(block_num-1)%3] = player

def draw_grid():
	gr = (50,50,50)
	bg = (255,255,200)
	screen.fill(bg)
	for x in range(1,3):
		pygame.draw.line(screen,gr,(0,x*(width/3)), (width,x * (width/3)), line_width)
		pygame.draw.line(screen,gr,(x*(height/3),0), (x * (height/3),height), line_width)

def draw_marker():
	x_pos = 0
	for x in markers:
		y_pos =0
		for y in x:
			if y == 1:
				pygame.draw.line(screen,GREEN,(y_pos*100+15,x_pos*100+15),(y_pos*100+85,x_pos*100+85))
				pygame.draw.line(screen,GREEN,(y_pos*100+15,x_pos*100+85),(y_pos*100+85,x_pos*100+15))
			if y == -1:
				pygame.draw.circle(screen,RED,(y_pos*100+50,x_pos*100+50),30,line_width)
			y_pos +=1
		x_pos +=1

def check_winner():
	global winner
	global game_over

	y_pos = 0

	for x in markers:
		if sum(x) == 3:
			winner = 1
			game_over =True
		if sum(x) == -3:
			winner = 2
			game_over =True
		if markers[0][y_pos] + markers[1][y_pos] + markers[2][y_pos] == 3:
			winner = 1
			game_over = True
		if markers[0][y_pos] + markers[1][y_pos] + markers[2][y_pos] == -3:
			winner = 2
			game_over= True
		y_pos +=1

	if markers[0][0] + markers[1][1] +markers[2][2] == 3 or markers[2][0] + markers[1][1] +markers[0][2] == 3:
		winner = 1
		game_over = True
	if markers[0][0] + markers[1][1] +markers[2][2] == -3 or markers[2][0] + markers[1][1] +markers[0][2] == -3:
		winner = 2
		game_over = True

def draw_winner(winner):
	global totalgame, win_text, winrateCalculated

	if winner == 0 and winrateCalculated == False:
		totalgame += 1
		win_text = 'Draw!'
	else:
		if winner == 1 and winrateCalculated == False:
			totalgame += 1
			win[0] += 1
			winrate1 = str((win[0]/totalgame)*100)
			win_text = 'Player 1 wins!'
			logging.info(win_text)
		if winner == 2 and winrateCalculated == False:
			totalgame += 1
			win[1] += 1
			winrate2 = str((win[1]/totalgame)*100)
			win_text = 'Player 2 wins!'
			logging.info(win_text)

	win_img = font.render(win_text, True, BLUE)
	pygame.draw.rect(screen,GREEN,(width//2 -100,height//2 -60,200,50))
	screen.blit(win_img,(width//2 -100,height//2 -50))

	again_text = 'Play Again?'
	again_img = font.render(again_text, True, BLUE)
	pygame.draw.rect(screen,GREEN,again_rect)
	screen.blit(again_img,(width//2 -80,height//2 +10))
	winrateCalculated = True

def getBestMove(state, player):
    '''
    Reinforcement Learning Algorithm
    '''
    moves = []
    curr_state_values = []
    empty_cells = []

    #find all empty cells
    for i in range(3):
        for j in range(3):
            if state[i][j] == 0:
                empty_cells.append(i*3 + (j+1))

    if not empty_cells:
    	return -1

    for empty_cell in empty_cells:
        moves.append(empty_cell)
        new_state = copy_game_state(state)
        play_move(new_state, player, empty_cell)
        next_state_idx = list(states_dict.keys())[list(states_dict.values()).index(new_state)]
        curr_state_values.append(state_values_for_AI[next_state_idx])
        print('next state value', state_values_for_AI[next_state_idx])
    print('Possible moves = ' + str(moves))
    print('Move values = ' + str(curr_state_values))
    print('markers:',markers)
    best_move_idx = np.argmax(curr_state_values)
    # print('state:',states_dict[best_move_idx])

    best_move = moves[best_move_idx]
    return best_move

def print_board(game_state):
    print('----------------')
    print('| ' + str(game_state[0][0]) + ' || ' + str(game_state[0][1]) + ' || ' + str(game_state[0][2]) + ' |')
    print('----------------')
    print('| ' + str(game_state[1][0]) + ' || ' + str(game_state[1][1]) + ' || ' + str(game_state[1][2]) + ' |')
    print('----------------')
    print('| ' + str(game_state[2][0]) + ' || ' + str(game_state[2][1]) + ' || ' + str(game_state[2][2]) + ' |')
    print('----------------')

#LOAD TRAINED STATE VALUES
state_values_for_AI = np.loadtxt('trained_state_values_O.txt', dtype=np.float64)

players = [1,-1,0]
states_dict = {}
all_possible_states = [[list(i[0:3]),list(i[3:6]),list(i[6:10])] for i in itertools.product(players, repeat = 9)]
n_states = len(all_possible_states) # 2 players, 9 space values
n_actions = 9   # 9 spaces

for i in range(n_states):
    states_dict[i] = all_possible_states[i]

run = True

while run:

	draw_grid()
	draw_marker()

	draw = 0

	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			run = False
		if game_over == 0:
			if event.type == pygame.MOUSEBUTTONDOWN:
				clicked = True
			if event.type == pygame.MOUSEBUTTONUP and clicked == True:
				clicked = False
				pos = pygame.mouse.get_pos()
				cell_x = pos[1]
				cell_y = pos[0 ]
				print(cell_x//100,cell_y//100)
				if markers[cell_x//100][cell_y//100] == 0:
					markers[cell_x//100][cell_y//100] = player
					player *= -1
				check_winner()

	if player == -1 and game_over == False:
		smartMove = getBestMove(markers,-1)
		print(smartMove)
		if smartMove == -1:
			#draw
			player = 0
			game_over = True
		else:
			markers[(smartMove-1)%3][int((smartMove-1)/3)] = player
			print_board(markers)
			player *= -1
			check_winner()

	if game_over == True:
		draw_winner(winner)
		if event.type == pygame.MOUSEBUTTONDOWN:
			clicked = True
		if event.type == pygame.MOUSEBUTTONUP and clicked == True:
			pos = pygame.mouse.get_pos()
			if again_rect.collidepoint(pos):
				markers = []
				pos = []
				player = 1
				winner = 0
				game_over = False
				for x in range(3):
					row = [0]*3
					markers.append(row)

	pygame.display.update()

pygame.quit()


# -*- coding: utf-8 -*-
"""
Created on Wed Apr  1 22:37:54 2020

@author: GGX
"""

# 输出1~n的全排列(深度优先搜索)
class Solution():
    def __init__(self, x):
        self.n = x
        self.book = [1 for _ in range(x)]
        self.res = [-1 for _ in range(x)]

    def fun(self, step):

        if step == self.n:
            print(self.res)
            return

        for i in range(self.n):
            if self.book[i] == 1:
                self.res[step] = i+1
                self.book[i] = 0
                self.fun(step+1)
                self.book[i] = 1  #

Solution(4).fun(0)


import csv
f = open(r'G:\ResearchWork\G_extrac\jiyi-nowear.gcode','r')
lines = f.readlines()
#print(lines)

c = open('extract_infor_1.csv', 'w', newline="")
writer=csv.writer(c)

#删除单元间空格
def filterNan(item):
    return item != ''

#循环处理每一行
#line为字符串
#lines为总字符串列表
#items为单行字符串列表
#item为单行字符串
#item2为重组的单行字符串列表
for line in lines:
    line = line[0:]#引用字符串
    items = line.split(' ') #以空格区分拆分字符串 #将一个字符串转换为一个列表
    items = list(filter(filterNan, items))#清除空字符,提取的内容为“符号”，”字母+数字“，“单词“
    items = items[0:]
    item2 = list(range(8))

    #将头部为X，Y，Z和F的单元提出,并按序排列
    for item in items:
        if item[0] == 'X':
            item2[0]=item[0];
            item2[1]=item[1:];#不能写作item=item.qppend()

        elif item[0] == 'Y':
            item2[2] = item[0];
            item2[3] = item[1:];

        elif item[0] == 'Z':
            item2[4] = item[0];
            item2[5] = item[1:];

        elif item[0] == 'F':
            item2[6] = item[0];
            item2[7] = item[1:];

        elif item[0] == 'G':
            continue

        for i in range(8):
            if item2[i] == i:
                item2[i] = '';

    writer.writerow(item2)

f.close()
c.close()


from functools import partial

from ._derived import Derived
from . import utilities

class Operation(Derived):
    __slots__ = ('opkwargs', 'opfn')

    def __init__(self,
            *terms,
            op = None,
            **kwargs,
            ):
        if type(op) is tuple:
            sops, op = op[:-1], op[-1]
            for sop in sops:
                terms = Operation(*terms, op = sop)
                if not type(terms) is tuple:
                    terms = terms,
        self.opfn = partial(op, **kwargs)
        self.opfn.__name__ = op.__name__
        self.opkwargs = kwargs
        super().__init__(*terms, op = op, **kwargs)

    def evaluate(self):
        return self.opfn(*self._resolve_terms())

    def _titlestr(self):
        return self.opfn.__name__
    def _kwargstr(self):
        kwargs = self.kwargs.copy()
        del kwargs['op']
        if kwargs:
            return utilities.kwargstr(**kwargs)
        else:
            return ''


import cant_utils as cu
import numpy as np
import matplotlib.pyplot as plt
import glob
import bead_util as bu
import tkinter
import tkinter.filedialog
import os, sys
from scipy.optimize import curve_fit
import bead_util as bu
from scipy.optimize import minimize_scalar as minimize
import pickle as pickle
import time

####################################################
####### Input parameters for data processing #######

TESTING = True

ddict = bu.load_dir_file( "/home/charles/opt_lev_analysis/scripts/dirfiles/dir_file_june2017.txt" )
#print ddict

pow_axis = 4

cant_axis = 1           # stage control axis
straighten_axis = 2     # axis with coherent drive to straighten
fit_pows = True

load_charge_cal = True
maxfiles = 1000

plot_forward_backward = False #True
#subtract_background = True

drivefreq = 18.0
cant_volts_to_um = 8.0    # 80 um / 10 V

#fig_title = ('Force vs. Cantilever Position: %s Hz, %s - %s, ' + bead) % (drivefreq, gas, num)

#dirs = [1,2,3,4,5,6,7]
dirs = [8,9,10,11,12,13,14,15,16]

tf_path = './trans_funcs/Hout_20160808.p'

step_cal_path = './calibrations/step_cal_20160808.p'

thermal_cal_file_path = '/data/20160808/bead1/1_5mbar_zcool_final.h5'

def poly2(x, a, b, c):
    return a * (x - b)**2 + c

def proc_dir(d):
    dv = ddict[d]

    dir_obj = cu.Data_dir(dv[0], [0,0,dv[-1]], dv[1])
    dir_obj.load_dir(cu.simple_loader, maxfiles = maxfiles)

    amps = []
    for fil_obj in dir_obj.fobjs:
        fil_obj.psd()
        stagestuff = fil_obj.get_stage_settings(axis=straighten_axis)
        amp = stagestuff[2] * cant_volts_to_um
        amps.append(amp)
    uamps = np.unique(amps)
    if len(uamps) > 1:
        print('STUPIDITYERROR: Multiple dirve amplitudes in directory')

    newlist = []
    for i in [0,1,2]:
        if i == straighten_axis:
            newlist.append(uamps[0])
        else:
            newlist.append(0.0)
    dir_obj.drive_amplitude = newlist

    return dir_obj

dir_objs = list(map(proc_dir, dirs))

colors_yeay = bu.get_color_map( len(dir_objs) )

psds = {}
pows = {}
bpows = {}

for ind, obj in enumerate(dir_objs):
    psd = []

    col = colors_yeay[ind]

    amp = obj.drive_amplitude[straighten_axis]

    filcount = 0
    for fobj in obj.fobjs:
        filcount += 1
        fobj.psd()
        if not len(psd):
            freqs = fobj.other_psd_freqs
            psd = fobj.other_psds[pow_axis-3]
        else:
            psd += fobj.other_psds[pow_axis-3]

    psd = psd / float(filcount)
    psds[amp] = psd

    ind = np.argmin(np.abs(freqs - drivefreq))

    totpow = np.sum(psd[ind-1:ind+2])
    pows[amp] = totpow

    badind = int(ind*1.5)
    totbadpow = np.sum(psd[badind-1:badind+2])
    bpows[amp] = totbadpow

amps = list(pows.keys())
amps.sort()
powsarr = []
bpowsarr = []
for amp in amps:

    powsarr.append(pows[amp])
    bpowsarr.append(bpows[amp])

if fit_pows:
    p0 = [1, 0, 0]
    popt, pcov = curve_fit(poly2, amps, powsarr, p0 = p0, maxfev = 10000)

    fitpoints = np.linspace(amps[0], amps[-1], 100)
    fit = poly2(fitpoints, *popt)

    plt.plot(amps, powsarr, 'o')
    plt.plot(fitpoints, fit, color='r', linewidth=1.5)

    title = 'Best fit straightening amplitude: %0.2g um' % popt[1]
    plt.title(title)

else:
    plt.plot(amps, powsarr)
    plt.plot(amps, bpowsarr)

plt.show()


"""
HomeWork 14 - task 5
Dmytro Verovkin
robot_dreams

5. (необов'язкове виконання) Створити клас Bot та TelegramBot із першого завдання за допомогою функції type
"""

def bot_init_function(self, name):
    self.name = name

def bot_say_name_function(self):
    print(self.name)

def bot_send_message_function(self, message):
    print(message)

Bot = type(
    'Bot',
    (),
    {
        '__init__': bot_init_function,
        'say_name': bot_say_name_function,
        'send_message': bot_send_message_function,
    }
)

def tg_bot_init_function(self, name, url=None, chat_id=None):
    super(type(self), self).__init__(name)
    self.url = url
    self.chat_id = chat_id

def tg_bot_send_message_function(self, message):
    print(f"{self.name} bot says {message} to chat {self.chat_id} using {self.url}")

def tg_bot_set_url_function(self, url):
    self.url = url

def tg_bot_set_chat_id_function(self, chat_id):
    self.chat_id = chat_id

TelegramBot = type(
    'TelegramBot',
    (Bot,),
    {
        '__init__': tg_bot_init_function,
        'send_message': tg_bot_send_message_function,
        'set_url': tg_bot_set_url_function,
        'set_chat_id': tg_bot_set_chat_id_function,
    }
)

some_bot = Bot('Marvin')
some_bot.say_name()
# >> "Marvin"

some_bot.send_message("Hello")
# >> > "Hello"

telegram_bot = TelegramBot("TG")
telegram_bot.say_name()
# >> > "TG"

telegram_bot.send_message('Hello')
# >> > "TG bot says Hello to chat None using None"

telegram_bot.set_chat_id(1)
telegram_bot.send_message('Hello')
# >> > "TG bot says Hello to chat 1 using None"


import sys
sys.path.append('/usr/local/lib/python3.7/site-packages')

import mido
import time

outport = mido.open_output('VirtualDevice Bus 1')

note_sequence = [57, 59, 60, 62, 57, 59, 55, 57]

for note in note_sequence:
    time.sleep(0.25)
    outport.send(mido.Message('note_on', note=note, velocity = 100))
    time.sleep(0.25)
    outport.send(mido.Message('note_off', note=note, velocity = 100))


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

# PyArtForms - Python generative art forms paint algorithms (artificial artist)
# experimental 'smears' paint algorithms, v1.0 - core algorithm definitions
# (c)2017-2021 MoNsTeR/GDC, Noniewicz.com, Noniewicz.art.pl, Jakub Noniewicz

# #01 [...] 'cruel red smears', not only red
# #02 [tested, ok] circle worms
# #03 [tested, ok] crazy trangles --- finish: more par, opt less random?
# #04 [tested, ok] self-crossed filled polygons
# #05 [...] star flowers --- finish: a lot here
# #06 [...] circle ripples - co-centered circle groups --- finish: par + misc
# #07 [tested, ok] random rectangles - grayish and colorish rects mess --- finish: new colorer proper
# #08 [tested, ok] just rectangles, may flux --- finish: new params, more variants in defs
# #09 [tested, ok] 'Warp' effect - triangle rays from center, opt center point shifted rnd
# #10 [...] long beziers
# #11 [tested, ok] horizontal gradients with suprizes
# #12 [tested, ok/so-so] opart-like boxes/circles/triangles
# #13 [tested, ok] opart-like single big poly (like #04?)
# #14 [tested, ok/so-so] opart-like cicrles xor-cut by triangles
# #15 [tested, ok, predictable] opart-like or color circle-interference patterns
# #16 [tested, ok, predictable] opart-like circles
# #17 [tested, ok] scottish-like grid --- finish: postproc satur 75 up + light 10 up? | 0,0 missing in rnd issue
# #18 [tested, ok] slim colorful circles --- finish: more par or var th*, more with self-call
# #19 [tested, ok, predictable] opart-like grid
# #20 [tested, ok, predictable] opart-like / papercut-like / video feedback-like 'dragon' effect
# #21 [tested, ok, predictable] opart-like scaled and pasted frames
# #22 [...] pie slice effects --- finish: reduce total count, mimosrod opt?
# #23 [tested, ok, predictable] Sierpinski's triangle fractal
# #24 [tested, ok, predictable] rotated traingles --- finish: reduce total count, more par ver, mimosrod opt, a scale par
# #25 [tested, ok] waves#1 --- finish: more par
# #26 [tested, ok] waves#2 --- finish: more par, simplify code
# #27 [tested, ok] multishaped polygon mess --- finish: more par
# future fun:
# #28 [...]
# #29 [...]
# #30 [...]
# #31
# #32

# cre: 20180430
# upd: 20180501, 02, 03
# cre: 20180805, 07, 08
# upd: 20180928, 29
# upd: 20181019, 20
# upd: 20190105, 06, 12, 13, 18, 19, 21, 22
# upd: 20190306, 11, 29, 30
# upd: 20190414, 15, 17, 18, 22, 24, 26, 27
# upd: 20200507, 10
# upd: 20210106, 15, 16, 19, 20, 21, 22
# upd: 20210515, 16, 22, 23, 24, 25, 26, 27
# upd: 20210606, 07, 10, 11, 12, 13, 14, 17, 18, 19, 20

# see:
# https://pillow.readthedocs.io/en/stable/

# note: now required at least pillow version 5.3.0, tested on 7.2.0, my prev was 5.0.0

# TODO:
# - ?

from PIL import Image, ImageDraw, ImageChops, ImageOps #, ImageMorph, ImageMath # test
import random, math, string, os, sys, copy
from bezier import make_bezier
from drawtools import *
from color_defs import *

"""
import PIL
print('PIL',PIL.__version__)
"""

# ---

def mazy1(draw, params):
    """ ? """
    w, h, cnt = init_common(params)
    mar = 0
    if 'mar' in params:
        mar = params['mar']
    v = 0
    if 'v' in params:
        v = params['v']
    ts = [t/100.0 for t in range(101)] # par?
    sc = float(h) / 3507 # lame par!
    wx = int(float(params['penw']) * sc)
    if wx <= 0:
        wx = 1

    for n in range(cnt):
        po = [(random.randint(0+mar, w-mar), random.randint(0+mar, h-mar)),
              (random.randint(0+mar, w-mar), random.randint(0+mar, h-mar)),
              (random.randint(0+mar, w-mar), random.randint(0+mar, h-mar)),
              (random.randint(0+mar, w-mar), random.randint(0+mar, h-mar))]

        if 'color' in params:
            if params['color'] == 'rg':
                color = gradient2((255,255,0), (255,0,0), random.randint(0, 255), 255)
            else:
                color = new_colorer(params['color'], n, cnt)
        else:
            color = (0,0,0)
        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])
        r = color[0]
        g = color[1]
        b = color[2]

        if params['prefill'] == True:
            bezier = make_bezier(po)
            points = bezier(ts)
            draw.polygon(points, fill=color, outline=None)

        for m in range(params['m']):
            if params['keep'] == True:
                po0 = po[0]
                po3 = po[3]
            vsc = int(v*sc)
            po[:] = [(xy[0]+random.randint(0, vsc)-random.randint(0, vsc), xy[1]+random.randint(0, vsc)-random.randint(0, vsc)) for xy in po]
            if params['keep'] == True:
                po[0] = po0
                po[3] = po3
            old = False
            if params['mode'] == 'red':
                color = (r ^ random.randint(0, 48), 0, 0)
                old = True
            if params['mode'] == 'black':
                rr = random.randint(0, 48)
                color = (rr, rr, rr)
                old = True
            if old == False:
                color = new_colorer(params['mode'], n, cnt)
            if 'addblack' in params: # todo: (re)use
                if params['addblack'] == True and random.randint(0, 100) > 80:
                    color = (0,0,0)
            if 'addalpha' in params:
                color = add_alpha(color, params['addalpha'])
            bezier = make_bezier(po)
            points = bezier(ts)
            draw.line(points, fill=color, width=wx)

def mazy2(draw, params):
    """ circle worms """
    w, h, cnt = init_common(params)
    cntm = params['m']
    if cntm <= 0:
        cntm = 1
    sc = 50 # dflt
    if 'sc' in params:
        sc = params['sc']
    if sc > 0:
        v = int(h/sc)
    else:
        v = 0

    for n in range(cnt):
        r1 = random.randint(int(h*0.15), int(h*0.45))
        po = [(random.randint(-r1, w+r1), random.randint(-r1, h+r1)),
            (random.randint(-r1, w+r1), random.randint(-r1, h+r1))]
        r0 = random.randint(int(r1*0.7), int(r1*0.99))
        if r0 < cntm:
            r0 = cntm
        de = 1/cntm
        for m in range(cntm):
            #v = int((cntm-m)/cntm * h/20) # test4
            po[:] = [(xy[0]+random.randint(0, v)-random.randint(0, v), xy[1]+random.randint(0, v)-random.randint(0, v)) for xy in po]
            color = new_colorer(params['color'], m, cntm)
            if 'addalpha' in params:
                if params['addalpha'] > 0:
                    color = add_alpha(color, params['addalpha'])
            circle(draw, po[0][0], po[0][1], int(r0*(1-m*de)), fill=color, outline=None)

def mazy3(draw, params):
    """ crazy trangles """
    w, h, cnt = init_common(params)

    def r(p, d):
        return int(p/2+random.randint(int(-p/d), int(p/d)))

    d = 0.5 # par, 1.3, 2.2 ? # todo: ext par
    da = 0.06 # dflt, how quickly they get smaller in center mode, 0.5 ok too
    if 'da' in params:
        da = params['da']
    for n in range(cnt):
        if params['mode'] == 'center':
            po = [(r(w, d), r(h, d)), (r(w, d), r(h, d)), (r(w, d), r(h, d))]
            d = d + da
        if params['mode'] == 'xcenter':
            d = 2.2 # par
            po = [(int(w/2), int(h/2)), (r(w, d), r(h, d)), (r(w, d), r(h, d))]
        if params['mode'] == 'rnd':
            d = 2.2 # par
            po = [(r(w, d), r(h, d)), (r(w, d), r(h, d)), (r(w, d), r(h, d))]
        color = new_colorer(params['color'], n, cnt)
        if 'addalpha' in params:
            if params['addalpha'] > 0:
                color = add_alpha(color, params['addalpha'])
        triangle(draw, po, fill=color, outline=None)

def mazy4(draw, params):
    """ self-crossed filled polygons """
    w, h, cnt = init_common(params)
    sc = 2.1 # dflt
    if 'sc' in params:
        sc = params['sc']
    if sc <= 0:
        sc = 1
    sx = int(w/sc)
    sy = int(h/sc)
    p_cnt = 20 # dflt
    if 'pc' in params:
        p_cnt = params['pc']
    mode = 'center'
    if 'mode' in params:
        mode = params['mode']

    for n in range(cnt):
        if mode == 'center':
            w0 = w/2
            h0 = h/2
        else:
            w0 = random.randint(0, w)
            h0 = random.randint(0, h)
        po = []
        for p in range(p_cnt):
            po.extend((w0+random.randint(-sx, sx), h0+random.randint(-sy, sy)))
        color = new_colorer(params['color'], n, cnt)
        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])
        draw.polygon(po, fill=color, outline=None)

def mazy5(draw, params):
    """ star flowers """
    w, h, cnt = init_common(params) # cnt unused
    colors = params['colors']
    c = math.pi/180

    dg = h*0.037 # thickness, par
    #dg = h*0.01 # TEST interesting...
    r0 = h/2*0.93 # base radius, par
    #r0 = h/2*1.5 # TEST
    rOut = float(h)*0.77 # outer circle radius, par
    #rOut = float(h)*0.3 # TEST
    sc = float(h)/2480 # par
    step = 10 # par (?)
    n = 10 # count of all 'stars', const, par
    for i in range(n):
        a = random.randint(4, 28)  # number of 'spikes', par
        rv = random.randint(20, int(300/a*2))  # 'spike' amplitude, [todo: correlate with a - less if a big] par
        if i == 0:
            x0 = w/2
            y0 = h/2
        else:
            axy = c*(i-1)*360/8 # par
            x0 = w/2 + rOut * math.cos(axy)
            y0 = h/2 + rOut * math.sin(axy)
        bands = 16 # par r decrease steps, also related to num colors
        #bands = len(colors)*3 # test
        for m in range(bands):
            points = []
            for n in range(int(360*step)):
                angle = c*float(n)/float(step)
                r = r0 + sc * (rv * math.sin(angle*a)) - m*dg
                x = x0 + r * math.cos(angle)
                y = y0 + r * math.sin(angle)
                points.extend((x, y))

            color = colors[m%len(colors)]   # TODO: fix: not new not old
            if 'addalpha' in params:
                color = add_alpha(color, params['addalpha'])
            draw.polygon(points, fill=color, outline=params['outline'])

def mazy6(draw, params):
    """ circle ripples - co-centered circle groups """
    w, h, cnt = init_common(params)
    useblack = False
    if 'useblack' in params:
        useblack = params['useblack']
    n_r_max = 16 # par
    r_min = int(h/25) # par
    r_max = int(h/7) # par
    #r_max = int(h/3) # par
    #r_max = int(h/15) # par
    # todo: start w big r_mx then go to lower? == start with big 1st
    # todo: mix color modes maybe?

    for m in range(cnt):
        x = random.randint(int(w/2-w/3), int(w/2+w/3))
        y = random.randint(int(h/2-h/3), int(h/2+h/3))
        r = random.randint(r_min, r_max)
        n_r = random.randint(3, n_r_max)
        for n in range(n_r):
            nn = n_r - n
            ro = int(r*(1+nn*nn*0.015)) # par
            if n & 1 and useblack == True:
                color = (0, 0, 0)
            else:
                color = new_colorer(params['mode'], n, n_r)
                try:
                    color
                except NameError:
                    print('ERROR: undefined color mode, using black', params['mode'])
                    color = (0,0,0)
            #color = add_alpha(color, 100) # todo
            circle(draw, x, y, ro, fill=color, outline=None)

def mazy7(draw, params):
    """ random rectangles - grayish and colorish rects mess """
    w, h, cnt = init_common(params)
    hdiv = int(h/30) # dflt
    if 'div' in params:
        d = int(params['div'])
        if d <= 0:
            d = 1
        hdiv = int(h/d)

    for m in range(cnt):
        x1 = random.randint(int(w/2-w/3), int(w/2+w/3))
        y1 = random.randint(int(h/2-h/3), int(h/2+h/3))
        w1 = 0
        h1 = 0

        if params['mode'] == 'dec': # big2small any
            sc = (m+1)/cnt
            if sc == 0:
                sc = 1
            wm = int(w/8 * 1/sc)
            hm = int(w/8 * 1/sc)
            w1 = random.randint(int(w/35), wm)
            h1 = random.randint(int(w/35), hm)

        if params['mode'] == 'decp': # big2small rect prop
            sc = (m+1)/cnt
            if sc == 0:
                sc = 1
            wm = int(w/7 * 1/sc)
            hm = int(h/7 * 1/sc)
            w1 = random.randint(int(w/35), wm)
            h1 = random.randint(int(h/35), hm)

        if params['mode'] == 'const':   # const small sqare
            w1 = hdiv
            h1 = hdiv

        color = (0,0,0)
        # todo: new colorer proper
        if params['cmode'] == 'std':
            color = gradient2((255,255,255), (0,0,0), m, cnt)
        if params['cmode'] == 'inv':    # or inverse
            color = gradient2((0,0,0), (255,255,255), m, cnt)
        if params['cmode'] == 'rnd':    # or rnd
            ci = random.randint(0, 255)
            color = (ci,ci,ci)
        if params['cmode'] == 'color':    # color
            color = colors_happy[random.randint(0, len(colors_happy)-1)]
        if params['cmode'] == 'wryb':
            color = colors_fwd[random.randint(0, len(colors_fwd)-1)]
        if params['cmode'] == 'BeachTowels':
            color = colors_BeachTowels[random.randint(0, len(colors_BeachTowels)-1)]
        if params['cmode'] == 'MoonlightBytes6':
            color = colors_MoonlightBytes6[random.randint(0, len(colors_MoonlightBytes6)-1)]
        if params['cmode'] == 'RainbowDash':
            color = colors_RainbowDash[random.randint(0, len(colors_RainbowDash)-1)]

        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])

        rect(draw, x1, y1, w1, h1, fill=color, outline=None)

def mazy8(draw, params):
    """ Block grid with random colors """
    w, h, cnt = init_common(params) # cnt unused
    xcnt = params['xcnt']
    ycnt = params['ycnt']

    # todo: new par use ext
    alpha_flux_p = 50
    alpha_flux_p = None
    alpha_flux_vmin = 20
    alpha_flux_vmax = 90-40

    # todo: opt dodatkowe 'cienkie'

    flux_p = None
    v = 0
    if 'flux_p' in params:
        flux_p = params['flux_p']
    if 'v' in params:
        v = params['v']
    border = 0
    if 'border' in params:
        border = params['border']
    ou = None
    if 'ou' in params:
        ou = params['ou']

    w1 = int(w/xcnt)
    h1 = int(h/ycnt)
    max_c = len(get_colors(params['color']))
    for y in range(ycnt-border*2):
        for x in range(xcnt-border*2):
            x1 = x*w1 + int(w1/2) + border*w1
            y1 = y*h1 + int(h1/2) + border*h1
            ci = random.randint(0, max_c-1)
            color = new_colorer(params['color'], ci, -1)
            if alpha_flux_p != None and alpha_flux_p > 0: # rnd flux
                if random.randint(0, 100) > alpha_flux_p:
                    ar = random.randint(alpha_flux_vmin, alpha_flux_vmax)
                    color = add_alpha(color, ar)
            vx = vy = vw = vh = 0
            if flux_p != None and flux_p > 0: # rnd flux
                if random.randint(0, 100) > flux_p:
                    vx = float(w1)*(random.randint(0, v)-random.randint(0, v))/100.0
                    vy = float(h1)*(random.randint(0, v)-random.randint(0, v))/100.0
                    vw = float(w1)*(random.randint(0, v)-random.randint(0, v))/100.0
                    vh = float(h1)*(random.randint(0, v)-random.randint(0, v))/100.0
            rect(draw, x1+vx, y1+vy, w1+vw, h1+vh, fill=color, outline=ou)

def mazy9(draw, params):
    """ 'Warp' effect - triangle rays from center, opt center point shifted rnd """
    w, h, cnt = init_common(params)
    w2 = int(w/2)
    h2 = int(h/2)
    c = math.pi/180
    v = 0
    if 'v' in params:
        v = params['v']
    rndc = False
    if 'rndc' in params:
        rndc = params['rndc']

    po = [(w2, h2), (0, 0), (0, 0)]
    da = c * float(360)/cnt
    r = w
    for n in range(cnt):
        if v > 0:
            po[0] = (w2+random.randint(int(-v), int(v)), h2+random.randint(int(-v), int(v)))
        x = w2 + r * math.cos(da*n)
        y = h2 + r * math.sin(da*n)
        po[1] = (x, y)
        x = w2 + r * math.cos(da*(n+1))
        y = h2 + r * math.sin(da*(n+1))
        po[2] = (x, y)

        if params['color'] == 'red' or params['color'] == 'bw': # todo: more? + both modes as one?
            ci = random.randint(0, 255)
            color = new_colorer(params['color'], ci, 255)
        else:
            cx = get_colors(params['color'])
            if cx == None:
                raise Exception('Undefined color: '+params['color']) # todo: err only, no raise/crash
            cx_len = len(cx)
            if rndc == True:
                color = cx[random.randint(0, cx_len-1)]
            else:
                color = cx[n%cx_len]
        triangle(draw, po, fill=color, outline=None)

def mazy10(draw, params):
    """ Random bezier threads or aeas """
    w, h, cnt = init_common(params)
    mode = params['mode']

    # todo: fix make threads no-lame
    # todo: for closed make internal pts bigger while 1st+last with margin?
    # todo: 1-2 bezier stripes then rnd mutate?

    #np = 1800 #par
    np = 5000 #par
    ts = [t/float(np) for t in range(np+1)]
    sc = float(h) / 3507 # todo: not like that?
    wx = int(float(params['penw']) * sc)
    if wx <= 0:
        wx = 1

    def rwh():
        ex = 1
        if params['open'] == True:
            return (random.randint(-w*ex, w*(ex+1)), random.randint(-h*ex, h*(ex+1)))
        else:
            return (random.randint(0, w), random.randint(0, h))

    for n in range(cnt):
        po = [rwh()]
        for x in range(params['complexity']):
            po.extend([rwh()])
        if params['color'] == 'blue_const':
            color = (16,48,255)
        if params['color'] == 'happy':
            color = colors_happy[n%len(colors_happy)]
        if params['color'] == 'rg':
            color = gradient2((255,255,0), (255,0,0), random.randint(0, 255), 255)
        if params['color'] == 'red':
            color = gradient2((0,0,0), (255,0,0), random.randint(0, 255), 255)
        if params['color'] == 'wryb':
            color = colors_fwd[n%len(colors_fwd)]
        # todo: new colorer proper

        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])

        bezier = make_bezier(po)
        points = bezier(ts)
        if params['mode'] == 'line':
            draw.line(points, fill=color, width=wx)
        if params['mode'] == 'fill':
            draw.polygon(points, fill=color, outline=None)

def mazy11(draw, params):
    """ Horizontal gradients with suprizes """
    w, h, cnt = init_common(params)
    cx = get_colors(params['color'])
    csize = len(cx)

    dy = float(h)/cnt
    if dy*cnt < h:  # lame fix for small images
        cnt += 3
    steps = 256 # const, max rational limit for RGB24 gradient
    if steps > w:
        steps = w
    dx = float(w)/steps
    for n in range(cnt):
        n1 = random.randint(0, csize-1)
        n2 = n%csize
        n3 = random.randint(0, csize-1)
        color1 = cx[n1]
        color2 = cx[n2]
        color3 = cx[n3]
        for step in range(steps):
            color = gradient(color1, color2, color3, step, steps)
            x = step*dx
            y = n*dy
            xy = [(x, y), (x+dx, y+dy)]
            draw.rectangle(xy, fill=color, outline=None)

def mazy12(draw, params):
    """ Opart-like boxes/circles/triangles """
    w, h, cnt = init_common(params)
    c = math.pi/180
    o = params['o']
    v = False
    if 'v' in params:
        v = params['v']
    rc = 1.0
    if 'rc' in params:
        rc = params['rc']
    w0 = w/2
    h0 = h/2
    r = int(h/2/2 * rc)
    for i in range(cnt):
        a = c*i/cnt*360
        x = int(w0+r*math.cos(a))
        y = int(h0+r*math.sin(a))
        if v:
            va = random.randint(int(-h0/8), int(h0/8)) # par
            vx = random.randint(int(-w0/8), int(w0/8)) # par
            vy = random.randint(int(-h0/8), int(h0/8)) # par
        else:
            va = 0
            vx = 0
            vy = 0
        if i&1 == 0:
            co = (0,0,0)
            ou = (255,255,255)
        else:
            co = (255,255,255)
            ou = (0,0,0)
        if o == 'box':
            rect(draw, x+vx, y+vy, r+va, r+va, fill=co, outline=ou)
        if o == 'cir':
            circle(draw, x+vx, y+vy, r+va, fill=co, outline=ou)
        if o == 'tri':
            vx1 = random.randint(int(-w0/2), int(w0/2)) # par
            vx2 = random.randint(int(-w0/2), int(w0/2)) # par
            vx3 = random.randint(int(-w0/2), int(w0/2)) # par
            vy1 = random.randint(int(-h0/2), int(h0/2)) # par
            vy2 = random.randint(int(-h0/2), int(h0/2)) # par
            vy3 = random.randint(int(-h0/2), int(h0/2)) # par
            points = [(x+vx1, y+vy1), (x+vx2, y+vy2), (x+vx3, y+vy3)]
            triangle(draw, points, fill=co, outline=ou)

def mazy13(draw, params):
    """ Opart-like single big poly """
    w, h, cnt = init_common(params)
    w0 = w/2
    h0 = h/2
    sc = 1.0
    sx = int(w/sc)
    sy = int(h/sc)
    po = []
    for n in range(cnt):
        newp = (w0+random.randint(-sx, sx), h0+random.randint(-sy, sy))
        po.append(newp)
    color = params['color']
    draw.polygon(po, fill=color, outline=None)

def mazy14(draw, params):
    """ Opart-like cicrles xor-cut by triangles """
    w, h, cnt = init_common(params)
    c = math.pi/180
    if w > h:
        sc = w/2*1.5/cnt
    else:
        sc = h/2*1.5/cnt
    if 'm' in params:
        cnt2 = params['m']
        if cnt2 < 4:
            cnt2 = 4
    else:
        cnt2 = 4 # some min
    v = 0
    if 'div' in params:
        v = params['div']
        if v > 0:
            v = w/v

    im1 = Image.new('RGB', (params['w'], params['h']), params['Background'])
    im2 = Image.new('RGB', (params['w'], params['h']), params['color']) # note: 2nd image is reversed
    draw1 = ImageDraw.Draw(im1)
    draw2 = ImageDraw.Draw(im2)

    for n in range(cnt): # centered circles 1st
        r = int(sc*(cnt-n))
        if n&1 == 0:
            co = params['Background']
        else:
            co = params['color']
        circle(draw1, int(w/2), int(h/2), r, fill=co, outline=None)

    po = [(int(w/2), int(h/2)), (0, 0), (0, 0)]
    da = float(360)/cnt2
    r = w
    for n in range(cnt2):
        if v > 0:
            v1 = random.randint(int(-v), int(v))
            v2 = random.randint(int(-v), int(v))
            po[0] = (int(w/2)+v1, int(h/2)+v2)
        x = w/2 + r * math.cos(c*da*n)
        y = h/2 + r * math.sin(c*da*n)
        po[1] = (x, y)
        x = w/2 + r * math.cos(c*da*(n+1))
        y = h/2 + r * math.sin(c*da*(n+1))
        po[2] = (x, y)
        if n&1 == 0:
            color = params['Background']
        else:
            color = params['color']
        triangle(draw2, po, fill=color, outline=None)

    imout = ImageChops.difference(im1, im2)
    params['im'].paste(imout, (0, 0))
    draw1 = None
    draw2 = None
    im1 = None
    im2 = None
    imout = None

def mazy15(draw, params):
    """ opart-like or color circle-interference patterns, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    c = math.pi/180
    scc = 1.5 # par
    if w > h:
        sc = w/2*scc/cnt  # note: off-screen to fill all
    else:
        sc = h/2*scc/cnt
    ys1 = 0
    xs1 = 0
    if 'xs1' in params:
        xs1 = params['xs1']
    if 'ys1' in params:
        ys1 = params['ys1']
    ys2 = 0
    xs2 = 0
    if 'xs2' in params:
        xs2 = params['xs2']
    if 'ys2' in params:
        ys2 = params['ys2']

    colorer = None
    if 'colorer' in params:
        colorer = params['colorer']

    def draw_it(draw, xs, ys, r):
        if n&1 == 0:
            if colorer == None:
                co = params['Background']
            else:
                co = new_colorer(colorer, n, cnt)
        else:
            if colorer == None:
                co = params['color']
            else:
                co = new_colorer(colorer, n, cnt)
        circle(draw, int(w/2+xs), int(h/2+ys), r, fill=co, outline=None)

    im1 = Image.new('RGB', (params['w'], params['h']), params['Background'])
    im2 = Image.new('RGB', (params['w'], params['h']), params['color']) # note: 2nd image is reversed in 'polarity' for better difference effect
    draw1 = ImageDraw.Draw(im1)
    draw2 = ImageDraw.Draw(im2)

    for n in range(cnt): # circles #1
        r = int(sc*(cnt-n))
        if 'mode' in params:
            if params['mode'] == 'linear':
                if 'xs1v' in params:
                    xs1 = xs1 + params['xs1v']
                if 'ys1v' in params:
                    ys1 = ys1 + params['ys1v']
            if params['mode'] == 'circle':
                a0 = c*n/cnt*360
                if 'xs1v' in params:
                    xs1 = params['xs1v']*math.cos(a0)
                if 'ys1v' in params:
                    ys1 = params['ys1v']*math.sin(a0)
        draw_it(draw1, xs1, ys1, r)
    for n in range(cnt): # circles #2
        r = int(sc*(cnt-n))
        if 'mode' in params:
            if params['mode'] == 'linear':
                if 'xs2v' in params:
                    xs2 = xs2 + params['xs2v']
                if 'ys2v' in params:
                    ys2 = ys2 + params['ys2v']
            if params['mode'] == 'circle':
                a0 = c*n/cnt*360
                if 'xs2v' in params:
                    xs2 = params['xs2v']*math.cos(a0)
                if 'ys2v' in params:
                    ys2 = params['ys2v']*math.sin(a0)
        draw_it(draw2, xs2, ys2, r)

    if colorer == None:
        imout = ImageChops.difference(im1, im2) # only difference is cool for bw
    else:
        imout = ImageChops.blend(im1, im2, 0.5) # only blend for color now

    params['im'].paste(imout, (0, 0))
    im1 = None
    im2 = None
    imout = None

def mazy16(draw, params):
    """ Opart-like circles, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    c = math.pi/180
    if w > h:
        sc = w/2
    else:
        sc = h/2
    rcoef = params['rcoef']
    acoef = params['acoef']
    rscale = params['rscale']

    for n in range(cnt):
        r = int(sc * (cnt-n)/cnt*rcoef)
        if n&1 == 0:
            co = params['Background']
            ou = params['color']
        else:
            co = params['color']
            ou = params['Background']
        #ou = None
        a0 = c*n/cnt*360 * acoef
        xs2 = rscale*sc/2*math.cos(a0)
        ys2 = rscale*sc/2*math.sin(a0)
        circle(draw, int(w/2+xs2), int(h/2+ys2), r, fill=co, outline=ou)

def mazy17(draw, params):
    """ Scottish-like grid """
    w, h, cnt = init_common(params)
    vv = params['v']
    v = int(w*vv)

    for z in range(cnt):
        ndx = random.randint(0, cnt)
        color = new_colorer(params['color'], ndx, cnt)
        if 'addalpha' in params:
            if params['addalpha'] > 0:
                color = add_alpha(color, params['addalpha'])
        x = random.randint(0, w)
        y = random.randint(0, h)
        lw = random.randint(1, v)
        xy = [(0, y), (w, y+lw)]
        draw.rectangle(xy, fill=color, outline=None)
        xy = [(x, 0), (x+lw, h)]
        draw.rectangle(xy, fill=color, outline=None)

def mazy18(draw, params):
    """ Random circle bundles """
    w, h, cnt = init_common(params)

    if 'multi' in params:
        multi = params['multi']
        for p in multi:
            p['w'] = params['w']
            p['h'] = params['h']
            p['call'] = params['call']
            p['color'] = params['color']
            p['name'] = params['name']
            mazy18(draw, p)
        return

    v = params['v']
    r0v = w
    if 'r0v' in params:
        r0v = params['r0v']

    for n in range(cnt):
        x = random.randint(0, w)
        y = random.randint(0, h)
        r0 = random.randint(0, r0v)
        for m in range(params['m']):
            r = r0 + random.randint(-v, v)
            color = new_colorer(params['color'], n, cnt) # note: alpha for outline does not seem to work
            thn = 3 # par
            thd = 0.2 # par
            thw = 2 # par
            for th in range(thn):
                circle_w(draw, x, y, r+th*thd, fill=None, outline=color, width=thw) # note width, v 5.3.0+
# was
#            for th in range(5):
#                circle(draw, x, y, r+th*0.15, fill=None, outline=color)

def mazy19(draw, params):
    """ Chequered opart grids with x variations, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    c = math.pi/180
    nx = cnt
    ny = params['m']
    dx = int(2*w/nx)
    dy = int(2*h/ny)
    c_white = (255,255,255)
    c_black = (0,0,0)
    if 'c_white' in params:
        c_white = params['c_white']
    if 'c_black' in params:
        c_black = params['c_black']
    if params['mode'] == 'exp':
        fncx = []
        coef = 17 # par / const 17 good for 40
        for x in range(coef): # precalc
            fx = 2.0*math.exp(-x/4)
            fncx.append(fx)
    if params['mode'] == 'sin':
        fncx2 = []
        coef2 = nx # ?
        for x in range(coef2): # precalc
            fx = abs(1.1*math.sin(x/coef2*360*2*c)) #par x2
            fncx2.append(fx)
    dxmap = []
    f = 0
    x = 0
    while f < w+dx:  # fill whole width
        fx = 0
        if x > 0:
            if params['mode'] == 'grid':
                fx = dx
            if params['mode'] == 'lin':
                fx = dx*f/(w+dx)*1.01
            if params['mode'] == 'exp':
                if x < coef:
                    fx = dx * fncx[x]
                else:
                    if x < 2*coef:
                        ndx = coef-(x-coef)-1
                        fx = dx * fncx[ndx]
                    else:
                        fx = dx
            if params['mode'] == 'sin':
                if x < coef2:
                    fx = dx * fncx2[x]
                else:
                    fx = dx
        if fx < 1:
            fx = 1
        f = f + fx
        dxmap.append(f)
        x += 1
    for y in range(ny):
        for x in range(len(dxmap)-1):
            b = ((x&1) == 1 and (y&1) == 1) or ((x&1) == 0 and (y&1) == 0)
            if b == True:
                cx = c_white
            else:
                cx = c_black
            xp = dxmap[x]
            xy = [(xp, y*dy), (xp+(dxmap[x+1]-dxmap[x]), y*dy+dy)]
            draw.rectangle(xy, fill=cx, outline=None)

def mazy20(draw, params):
    """ opart-like / papercut-like / video feedback-like 'dragon' effect, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    da = params['da']
    dd = 10 # dflt
    if 'dd' in params:
        dd = params['dd']
        if dd < 1:
            dd = 1
    dx = int(w/dd)
    dy = int(h/dd)
    sc = 0.75 # dflt
    if 'sc' in params:
        sc = params['sc']
    nw = int(sc*w)
    nh = int(sc*h)

    xy = [(dx, dy), (w-dx, h-dy)]
    draw.rectangle(xy, fill=params['Foreground'], outline=None)
    xy = [(dx*2, dy*2), (w-dx*2, h-dy*2)]
    draw.rectangle(xy, fill=params['Background'], outline=None)

    for n in range(cnt):
        im1 = params['im']
        im1 = im1.resize((nw, nh), Image.BICUBIC)
        im1 = im1.rotate(da, Image.BICUBIC)
        params['im'].paste(im1, (int((w-nw)/2), int((h-nh)/2)))
    im1 = None

    if 'invert' in params:
        if params['invert'] == True:
            params['im'] = invert_image(params['im'])

def mazy21(draw, params):
    """ opart-like scaled and pasted frames, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    dx = int(w/10)
    dy = int(h/10)
    sc = 0.666
    nw = int(sc*w)
    nh = int(sc*h)
    mode = 0
    if 'mode' in params:
        mode = params['mode']

    xy = [(dx, dy), (w-dx, h-dy)]
    draw.rectangle(xy, fill=params['Foreground'], outline=None)
    xy = [(dx*2, dy*2), (w-dx*2, h-dy*2)]
    draw.rectangle(xy, fill=params['Background'], outline=None)

    for n in range(cnt):
        im1 = params['im'].resize((nw, nh), Image.BICUBIC)
        xx = int(nw/2)
        yy = int(nh/2)
        if mode == 0:
            params['im'].paste(im1, (0+int(nw/2/2), 0+int(nh/2/2))) #center
        if mode == 1:
            params['im'].paste(im1, (0, 0)) #l/u
        if mode == 2:
            params['im'].paste(im1, (xx, yy)) #r/d
        if mode == 3 or mode == 4: # l/u + r/d - extravagant
            if n&1 == 0:
                params['im'].paste(im1, (0, 0)) #l/u
            else:
                params['im'].paste(im1, (xx, yy)) #r/d
        if mode == 4 or mode == 5:
            params['im'].paste(im1, (0+int(nw/3), 0+int(nh/3))) # lame
        if mode == 6: # maxxx fract like
            nn = n&3
            if nn == 0:
                params['im'].paste(im1, (0, 0))
            if nn == 1:
                params['im'].paste(im1, (xx, 0))
            if nn == 2:
                params['im'].paste(im1, (0, yy))
            if nn == 3:
                params['im'].paste(im1, (xx, yy))
    im1 = None

    if 'invert' in params:
        if params['invert'] == True:
            params['im'] = invert_image(params['im'])

def mazy22(draw, params):
    """ pie slice effects """
    w, h, cnt = init_common(params)
    colorer = params['color']
    do_rnd = False
    if 'rnd' in params:
        do_rnd = params['rnd']

    drc = 0.97
    if 'drc' in params:
        drc = params['drc']
    a_s = 0
    a_e = 35
    if 'a_e' in params:
        a_e = params['a_e']
    da = 12
    if 'da' in params:
        da = params['da']

    #note: some nice: drc a_e da
    #0.97, 90, 12
    #0.97, 35, 12
    #0.97, 10, 12
    #0.97, 90, 45 # good for colorsets
    #0.97, 90 90 # special
    #0.97, 90 89 # special + good for colorsets
    #0.97, 90 85 # special + good for colorsets
    #0.97, 90 80 # special + good for colorsets
    #0.9, 90, 45

    radius = h/2 * 1.0 # par

    for i in range(cnt):
        if do_rnd:
            a_s = random.randint(0, 360) # par x2
            a_e = random.randint(0, 360) # par x2
            drc = random.randint(92, 98)/100 # par x2
            if i == cnt-1:
                a_s = 0
                a_e = 360
        if params['Background'] == (255,255,255) and do_rnd and params['color'] == 'bw': # rev bw color in this special case
            color = new_colorer(colorer, cnt-1-i, cnt)
        else:
            color = new_colorer(colorer, i, cnt)
        draw.pieslice((w/2-radius, h/2-radius, w/2+radius, h/2+radius), a_s, a_e, fill=color)
        radius = radius * drc
        if not do_rnd:
            a_s = a_s + da
            a_e = a_e + da

def mazy23(draw, params):
    """ Sierpinski's triangle fractal, predictable (no rnd parts) """
    # https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
    w, h, cnt = init_common(params)
    limit0 = cnt
    margin = 5/100
    if 'margin' in params:
        margin = params['margin']
    dd = h*margin
    color = (255, 255, 255)
    if 'color1' in params:
        color = params['color1']
    color2 = (0, 0, 0)
    if 'color2' in params:
        color2 = params['color2']
    colorer = None
    if 'colorer' in params:
        colorer = params['colorer']
    colorer_mode = None
    if 'colorer_mode' in params:
        colorer_mode = params['colorer_mode']

    def m23(draw, limit, a, htr, ofsx, ofsy):
        if limit <= 0:
            return
        a /= 2
        htr = 0.5 * math.sqrt(3) * a

        c2 = color2
        if colorer != None and colorer_mode == 0:
            c2 = new_colorer(colorer, limit, limit0) # mode=0

        xx1 = wo+a/4 +(0.5) # note: 0.5 'visual' fix
        xx2 = wo+a/2
        xx3 = wo+a-a/4 -(0.5)
        yy1 = h-dd-htr/2 +(0.5)
        yy2 = h-dd -(0.5)

        fix_x = ofsx
        fix_y = ofsy
        po = [(int(xx1+fix_x), int(yy1+fix_y)), (int(xx2+fix_x), int(yy2+fix_y)), (int(xx3+fix_x), int(yy1+fix_y))]
        if colorer != None and colorer_mode == 1:
            c2 = new_colorer(colorer, limit+0, limit0) # mode=1
        triangle(draw, po, fill=c2, outline=None)
        m23(draw, limit-1, a, htr, fix_x, fix_y)

        fix_x = a + ofsx
        fix_y = ofsy
        po = [(int(xx1+fix_x), int(yy1+fix_y)), (int(xx2+fix_x), int(yy2+fix_y)), (int(xx3+fix_x), int(yy1+fix_y))]
        if colorer != None and colorer_mode == 1:
            c2 = new_colorer(colorer, limit+1, limit0) # mode=1
        triangle(draw, po, fill=c2, outline=None)
        m23(draw, limit-1, a, htr, fix_x, fix_y)

        fix_x = a/2 + ofsx
        fix_y = -htr + ofsy
        po = [(int(xx1+fix_x), int(yy1+fix_y)), (int(xx2+fix_x), int(yy2+fix_y)), (int(xx3+fix_x), int(yy1+fix_y))]
        if colorer != None and colorer_mode == 1:
            c2 = new_colorer(colorer, limit+2, limit0) # mode=1
        triangle(draw, po, fill=c2, outline=None)
        m23(draw, limit-1, a, htr, fix_x, fix_y)

    a = h-dd-dd # start side len, todo: try par >> w?
    wo = (w-a)/2
    htr = 0.5 * math.sqrt(3) * a # start triangle h
    po = [(wo, h-dd), (wo+a/2, h-dd-htr), (wo+a, h-dd)]
    triangle(draw, po, fill=color, outline=None) # main
    po = [(wo+a/4, h-dd-htr/2), (wo+a/2, h-dd), (wo+a-a/4, h-dd-htr/2)]
    triangle(draw, po, fill=color2, outline=None) # 1st cut
    m23(draw, limit0-1, a, htr, 0, 0) # recurent inside

def mazy24(draw, params):
    """ rotated traingles, predictable (no rnd parts) """
    w, h, cnt = init_common(params)
    cx = w/2
    cy = h/2 + h/12 # 'y center' slightly moved down, nicer this way
    c = math.pi/180
    colorer = params['colorer']
    ou = None
    if 'ou' in params:
        ou = params['ou']

    a_sc = 0.93 # par
    a_base = 1.0
    if 'a_base' in params:
        a_base = params['a_base']
    an_sc = 1.0
    if 'an_sc' in params:
        an_sc = params['an_sc']

    a = h*a_base
    for i in range(cnt):
        htr = 0.5 * math.sqrt(3) * a
        po = [(cx-a/2, cy-htr/2), (cx, cy+htr/2), (cx+a/2, cy-htr/2)]
        ce = (1/3*(po[0][0]+po[1][0]+po[2][0]), 1/3*(po[0][1]+po[1][1]+po[2][1])) # actual triangle center is here (triangle centroid)
        an = i/cnt * 360 * c * an_sc
        po_ = [rotate_point(po[0], ce[0], ce[1], an), rotate_point(po[1], ce[0], ce[1], an), rotate_point(po[2], ce[0], ce[1], an)]
        color = new_colorer(colorer, i, cnt)
        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])
        triangle(draw, po_, fill=color, outline=ou)
        a = a * a_sc

def mazy25(draw, params):
    """ waves#1 """
    # todo: par + more like it?
    w, h, cnt = init_common(params)
    c = math.pi/180

    fd = 100.0*params['f0']
    div = float(cnt*2+4+(-4)) # par
    if div == 0:
        div = 1
    if params['horizontal'] == True:
        rn = w
        dx = h/div
    else:
        rn = h
        dx = w/div
    mofs0 = 0 # par, was 2

    rnd_color = True # par
    rnd_color = False

    for z in range(cnt):
        if rnd_color:
            ndx = random.randint(0, cnt)
        else:
            ndx = z
        color = new_colorer(params['color'], ndx, cnt)
        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])
        aofs1 = random.randint(0, 360)
        aofs2 = random.randint(0, 360)
        aofs3 = random.randint(0, 360)
        aofs4 = random.randint(0, 360)
        fofs1 = random.randint(0, 100)/fd*1
        fofs2 = random.randint(0, 100)/fd*1
        fofs3 = random.randint(0, 100)/fd*2
        fofs4 = random.randint(0, 100)/fd*2
        mofs1 = (z+mofs0)*dx

        y = 0
        for n in range(rn):
            nsc = float(n)/float(rn)*360*10 # par 10
            x_in =  mofs1 + dx * (1 + (math.sin(c*(nsc*fofs1+aofs1))+2*math.sin(c*(nsc*fofs3+aofs3)))/3)
            x_out = mofs1 + dx * (1 + (math.sin(c*(nsc*fofs2+aofs2))+2*math.sin(c*(nsc*fofs4+aofs4)))/3)
            if params['horizontal'] == True:
                xy = [(y, x_in), (y, h - x_out)]
            else:
                xy = [(x_in, y), (w - x_out, y)]
            draw.rectangle(xy, fill=color, outline=None) # 1px rects?
            y += 1

def mazy26(draw, params):
    """ waves#2 """
    if 'par1' in params and 'par2' in params:
        mazy26(draw, params['par1'])
        mazy26(draw, params['par2'])
        return

    w, h, cnt = init_common(params)

    # todo: uproscic kod (czemu 2x?) | exp par
    w = params['w']
    h = params['h']
    cnt = params['n']
    random.seed()
    c = math.pi/180

    sc = 3.0  #par was 4
    if params['horizontal'] == True:
        rn = w
        dx = h/float(cnt)*sc
    else:
        rn = h
        dx = w/float(cnt)*sc

    for z in range(cnt):
        ndx = random.randint(0, cnt)
        color = new_colorer(params['color'], ndx, cnt)
        if 'addalpha' in params:
            color = add_alpha(color, params['addalpha'])
        aofs1 = random.randint(0, 360)
        aofs2 = random.randint(0, 360)
        aofs3 = random.randint(0, 360)
        aofs4 = random.randint(0, 360)
        fofs1 = random.randint(0, 100)/100.0*1 # par
        fofs2 = random.randint(0, 100)/100.0*1 # par
        fofs3 = random.randint(0, 100)/100.0*2 # par
        fofs4 = random.randint(0, 100)/100.0*2 # par
        mofs1 = float(z*dx)
        am1 = 1.0 # par
        am2 = 1.0 # par
        am3 = 3.0 # par was 2
        am4 = 3.0 # par was 2

        y = 0
        points1 = []
        points2 = []
        points1a = []
        points2a = []
        for n in range(rn):
            nsc = float(n)/float(rn)*360*10 # par 10
            x_in =  int(mofs1 + dx * (1 + (am1*math.sin(c*(nsc*fofs1+aofs1))+am3*math.sin(c*(nsc*fofs3+aofs3)))))
            x_out = int(mofs1 + dx * (1 + (am2*math.sin(c*(nsc*fofs2+aofs2))+am4*math.sin(c*(nsc*fofs4+aofs4)))))
            if params['horizontal'] == True:
                points1.extend((y, x_in))
                points2.extend((y, x_out))
            else:
                points1.extend((x_in, y))
                points2.extend((x_out, y))
            y += 1
        lw = random.randint(1, int(w/30)) #par, opt big->small?

        points1a[:] = [xy for xy in points1]
        points2a[:] = [xy for xy in points2]
        for a in range(int(len(points1a)/2)):
            ndx = int(len(points1a)/2)-1-a
            if params['horizontal'] == True:
                points1.extend((points1a[ndx*2], lw+points1a[ndx*2+1]))
            else:
                points1.extend((lw+points1a[ndx*2], points1a[ndx*2+1]))
        for a in range(int(len(points2a)/2)):
            ndx = int(len(points2a)/2)-1-a
            if params['horizontal'] == True:
                points2.extend((points2a[ndx*2], lw+points2a[ndx*2+1]))
            else:
                points2.extend((lw+points2a[ndx*2], points2a[ndx*2+1]))
        draw.polygon(points1, fill=color, outline=color)
        draw.polygon(points2, fill=color, outline=color)

def mazy27(draw, params):
    """ multishaped polygon mess """
    w, h, cnt = init_common(params)
    colorer = params['colorer']
    addalpha = 0
    if 'addalpha' in params:
        addalpha = params['addalpha']
    saturation_factor = 1.5 # dflt
    if 'saturation' in params:
        saturation_factor = params['saturation']
    minsides = 3
    maxsides = 8
    if 'minsides' in params:
        minsides = params['minsides']
    if 'maxsides' in params:
        maxsides = params['maxsides']
    if minsides < 3:
        minsides = 3
    if maxsides < 3:
        maxsides = 3
    maxangle = 90
    if 'maxangle' in params:
        maxangle = params['maxangle']

    rmin = int(h/30)
    if 'rmin' in params:
        rmin = params['rmin']
    rmax = h/4 # h h/2 # h/4
    if 'rmax' in params:
        rmax = params['rmax']
    rsc = 0.997 # 0
    if 'rsc' in params:
        rsc = params['rsc']

    ofs = int(h/4) # centers this much off-screen
    for n in range(cnt):
        color = new_colorer(colorer, n, cnt)
        if addalpha > 0:
            color = add_alpha(color, addalpha)
        r = random.randint(rmin, int(rmax))
        cx = random.randint(-ofs, w+ofs)
        cy = random.randint(-ofs, h+ofs)
        if maxangle > 0:
            a = random.randint(0, maxangle)
        else:
            a = 0
        sides = random.randint(minsides, maxsides)
        nsided(draw, sides, cx, cy, r, a, color, None)
        if rsc > 0:
            rmax = rmax * rsc
            if rmax < rmin:
                rmax = rmin
    if addalpha > 0 and saturation_factor > 0:
        params['im'] = enhace(params['im'], saturation_factor)

# future fun

def mazy28(draw, params):
    """ ? """
    # fin or remove
    w, h, cnt = init_common(params)
    c = math.pi/180

    cnt = 400
    sx = int(w/cnt)
    color = (0xd4,0x8a,0x3e)
    aofs1 = 0
    fofs1 = 3
    fofs3 = 1
    am1 = 3
    am3 = 1
    dx = sx/3

    po = [(w,0), (0, 0)]
    x = 0
    y = h
    for n in range(cnt):
        aofs2 = random.randint(0, 90)
        aofs3 = random.randint(0, 180)
        fofs2 = random.randint(1, 5)
        am2 = random.randint(1, 15)
        nsc = float(n)/float(cnt)*360*3 # par
        f = int(dx * (2 + (am1*math.sin(c*(nsc*fofs1+aofs1))+am2*math.sin(c*(nsc*fofs2+aofs2))+am3*math.sin(c*(nsc*fofs3+aofs3)))))
        po.extend((x, y))
        y -= f
        x += sx
    draw.polygon(po, fill=color, outline=None)

def mazy29(draw, params):
    """ ? """
    # note: hard one, probably will fail
    w, h, cnt = init_common(params)
    c = math.pi/180

    color = (255,255,255)
    hb = int(h/10)
    y0 = (hb/2)
    cnt = 300
    dx = int(w/cnt)
    bcnt = 5

    def f1(p):
        x = p[0]
        y = p[1] + hb*2
        return (x, y)

    po = [] # build one model block
    po.append((0,y0))
    for n in range(cnt):
        pn = (dx*n, y0)
        po.append(pn)
    po.append((w, y0))
    po.append((w, y0+hb))
    for n in range(cnt):
        po.append((w-dx*n, y0+hb))
    po.append((0, y0+hb))

    poall = [None] * bcnt # copy block bcnt times
    for n in range(bcnt):
        if n == 0:
            poall[n] = copy.deepcopy(po)
        else:
            po[:] = (f1(p) for p in po)
            poall[n] = copy.deepcopy(po)

    s1 = 1
    s2 = 1 + cnt + 2

    # test sin wave - remove later?
    for n in range(bcnt):
        for x in range(cnt):
            #fn = 30*math.sin(c*x/cnt*360*4
            fn = 0
            for f in range(10):
                fn += (20+f*2)*math.sin(c*x/cnt*360*(1+f*2))
            tup = poall[n][s1+x]
            tup = (tup[0], tup[1]+fn) # change y-s
            poall[n][s1+x] = tup
            tup = poall[n][s2+cnt-x]
            tup = (tup[0], tup[1]+fn) # change y-s
            poall[n][s2+cnt-x] = tup

    """
    def dist(p, sm):
        start = sm['start']
        ds = math.sqrt((start[0]-p[0])*(start[0]-p[0])+(start[1]-p[1])*(start[1]-p[1]))
        is_affecting = ds < sm['radius']
        inte = sm['intensity']*math.exp(-ds*0.05)*1000
        intex = inte*math.cos(c*sm['angle'])
        intey = inte*math.sin(c*sm['angle'])
        return ds, inte, intex, intey, is_affecting

    def apply_smear(sm):
        for m in range(cnt):
            for n in range(bcnt):
                tup = poall[n][s1+m]
                ds, inte, intex, intey, is_affecting = dist(tup, sm)
                if is_affecting:
                    tup = (tup[0]+intex, tup[1]+intey) # change
                    poall[n][s1+m] = tup
                tup = poall[n][s2+cnt-m]
                ds, inte, intex, intey, is_affecting = dist(tup, sm)
                if is_affecting:
                    tup = (tup[0]+intex, tup[1]+intey) # change
                    poall[n][s2+cnt-m] = tup

    # todo: smear with intensity ~ 1/range and params: angle + radius + strength + len
    sme1 = {'start': (w/2, h/2), 'angle': 45, 'radius': 400, 'intensity': 100, 'length': 300}
    apply_smear(sme1)
    sme2 = {'start': (w/4, h/4), 'angle': 15, 'radius': 400, 'intensity': 100, 'length': 300}
    apply_smear(sme2)
    """

    for n in range(bcnt):
        #po = poall[n]
        po = poall[bcnt-1-n] # rev order for test
        color = (255,255, int(255*n/bcnt))
        draw.polygon(po, fill=color, outline=None)
    #circle(draw, sme1['start'][0], sme1['start'][1], sme1['radius'], fill=None, outline=(0,0,255))
    #circle(draw, sme2['start'][0], sme2['start'][1], sme2['radius'], fill=None, outline=(0,0,255))

def mazy30(draw, params):
    """ ? """
    w, h, cnt = init_common(params)
    w2 = int(w/2)
    h2 = int(h/2)

    cnt = 100*2 # par
    r0 = h*0.3 # par
    v = 200+100 # par
    sc = 1.0 # par
    rv = 200 # par
    asc = 10 # par 6 50

    po = []
    for n in range(cnt):
        a = math.pi/180 * 360 * float(n/cnt) # par
        rv = random.randint(100,500) # test
        r = r0 + sc * (rv * math.sin(asc*a))
        #r = r0
        po.append((int(w2+r*math.cos(a)), int(h2+r*math.sin(a))))

    def fr0(p):
        # par x2
        if random.randint(0, 100) > 80:
            return (p[0]+random.randint(-v,v), p[1]+random.randint(-v,v))
            #return (p[0]+random.randint(-v,v), p[1])
        else:
            return p

    def fr(p):
        return p
        #return (p[0]+random.randint(-v,v), p[1]+random.randint(-v,v))

    po[:] = (fr(xy) for xy in po)
    draw.polygon(po, fill=(255, 255, 0), outline=None) # par
    po.append((po[0][0], po[0][1]))
    draw.line(po, fill=(255,0,0), width=3) # par

    # opt
    if False:
        ts = [t/2000.0 for t in range(2001)]
        #ts = [t/20.0 for t in range(21)]
        bezier = make_bezier(po)
        points = bezier(ts)
        draw.polygon(points, fill=(255, 0, 0), outline=(255,255,255))

def mazy31(draw, params):
    """ ? """
    w, h, cnt = init_common(params)
    # ...
    return 0

def mazy32(draw, params):
    """ ? """
    w, h, cnt = init_common(params)
    # ...
    return 0


# coding=utf-8

import pytest
from mockito import expect, mock, verify, verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed, when

# noinspection PyProtectedMember
from elib_run._run import _run

@pytest.mark.parametrize(
    'mute',
    [True, False]
)
def test_exit(mute, caplog):
    caplog.set_level(10, 'elib_run.process')
    context = mock(
        {
            'mute': mute,
            'process_output_as_str': 'dummy_output',
            'process_logger': mock(),
        }
    )
    when(context.process_logger).debug(...)
    with pytest.raises(SystemExit):
        _run._exit(context)
    if mute:
        assert 'dummy_output' in caplog.text
    else:
        assert '' == caplog.text

@pytest.mark.parametrize('return_code', (0, 1))
@pytest.mark.parametrize('mute', (True, False))
@pytest.mark.parametrize('failure_ok', (True, False))
def test_check_error(return_code, mute, failure_ok, caplog):
    caplog.set_level(10)
    context = mock(
        {
            'return_code': return_code,
            'mute': mute,
            'result_buffer': '',
            'failure_ok': failure_ok,
            'cmd_as_string': 'dummy_cmd',
            'process_logger': mock(),
        }
    )
    when(_run)._exit(context)
    result = _run.check_error(context)
    if return_code is 0:
        if mute:
            expected_buffer = f': success: {return_code}'
        else:
            expected_buffer = f'{context.cmd_as_string}: success: {context.return_code}'
        assert expected_buffer in caplog.text
        assert result is 0
    else:
        if mute:
            expected_buffer = f': command failed: {context.return_code}'
        else:
            expected_buffer = f'{context.cmd_as_string}: command failed: {context.return_code}'
        assert expected_buffer in caplog.text
        assert repr(context) in caplog.text
        if not failure_ok:
            verify(_run)._exit(context)
        else:
            verify(_run, times=0)._exit(...)

@pytest.mark.parametrize(
    'filters',
    (None, ['some'], ['some', 'string'], 'some string')
)
def test_sanitize_filters(filters):
    result = _run._sanitize_filters(filters)
    if filters is None:
        assert result is None
    elif isinstance(filters, str):
        assert [filters] == result
    else:
        assert result is filters

@pytest.mark.parametrize(
    'filters',
    ([False], [None], [True], [1], [1.1], [['list']], [{'k': 'v'}], True, False, 1.1, 1, ('tuple',), {'k': 'v'})
)
def test_sanitize_filters_wrong_value(filters):
    with pytest.raises(TypeError):
        _run._sanitize_filters(filters)

def test_parse_exe_no_args():
    when(_run).find_executable(...).thenReturn('dummy')
    result = _run._parse_cmd('cmd')
    assert 'dummy', '' == result
    verifyStubbedInvocationsAreUsed()

def test_parse_exe_with_args():
    when(_run).find_executable(...).thenReturn('dummy')
    result = _run._parse_cmd('cmd')
    assert 'dummy', ['some', 'args'] == result
    verifyStubbedInvocationsAreUsed()

def test_parse_cmd_exe_not_found():
    when(_run).find_executable(...).thenReturn(None)
    with pytest.raises(_run.ExecutableNotFoundError):
        _run._parse_cmd('dummy')
    verifyStubbedInvocationsAreUsed()

@pytest.mark.parametrize(
    'mute', (True, False)
)
@pytest.mark.windows
def test_run(mute):
    expect(_run.RunContext).start_process()
    expect(_run).monitor_running_process(...)
    expect(_run).check_error(...)
    _run.run('cmd', mute=mute)
    verifyNoUnwantedInteractions()


from pickle import TRUE
from re import A
from turtle import Turtle, penup, reset, speed
carpoints = (
    (4,0),
    (2,2),
    (1,4),
    (1,8),
    (0,8),
    (0.10),
    (1,10),
    (1,18),
    (0,18),
    (0,20),
    (1,20),
    (1,24),
    (2,26),
    (4,28),
    (7,28),
    (9,26),
    (10,24),
    (10,20),
    (11,20),
    (11,18),
    (10,18),
    (10,10),
    (11,10),
    (11,8),
    (10,8),
    (10,4),
    (9,2),
    (7.0)
)
height = 500
width = 700
distance = 10

ben = Turtle()
screen = ben.getscreen()
screen.register_shape("car", (
    (4,0),
    (2,2),
    (1,4),
    (1,8),
    (0,8),
    (0,10),
    (1,10),
    (1,18),
    (0,18),
    (0,20),
    (1,20),
    (1,24),
    (2,26),
    (4,28),
    (7,28),
    (9,26),
    (10,24),
    (10,20),
    (11,20),
    (11,18),
    (10,18),
    (10,10),
    (11,10),
    (11,8),
    (10,8),
    (10,4),
    (9,2),
    (7,0)
))
ben.shape("car")
ben.color("black", "blue")

timer = Turtle()
timer.hideturtle()
timer.penup()
timer.left(90)
timer.forward(300)

speed = 0
angle = 10
update = 0.2

screen.bgpic("nn2.gif")

def accelerate():
    global speed
    speed = speed + update

def decelerate():
    global speed
    speed = speed - update

def moveleft():
    ben.left(angle)

def moveright():
    ben.right(angle)

def stop():
    global speed
    speed = 0

def reset():
    global time, speed
    time = 0
    ben.pu()
    ben.goto(-265, 0)
    ben.setheading(90)
    ben.pd()
    speed = 0

screen.listen()
screen.onkeypress(accelerate, "w")
screen.onkeypress(decelerate, "s")
screen.onkeypress(moveright,"d")
screen.onkeypress(moveleft,"a")
screen.onkeypress(stop, "space")
screen.onkeypress(accelerate,"Up")
screen.onkeypress(decelerate, "Down")
screen.onkeypress(moveright,"Right")
screen.onkeypress(moveleft,"Left")
screen.onkeypress(reset,"q")

ben.pu()
ben.goto(-265, 0)
ben.left(90)
ben.pd()
time = 0
scoring = False

while True:

    allowedforward = True

    if ben.ycor() < -height and ben.heading == 180:
        allowedforward = False

    ben.forward(speed)

    if scoring:
        time += 0.1
        timer.clear()
        timer.write(f"{time:02.2f}", False, "center", ("Arial", 30, "bold"))
    if abs(ben.xcor() - (-265)) < 10 and ben.ycor() > 0:
        if time < 10:
            scoring = True
        else:
            scoring = False
    if allowedforward == TRUE:
        ben.forward(distance)

    screen.update()


# 완전제곱수

import sys

input = sys.stdin.readline

M = int(input())
N = int(input())
sqr = [i**2 for i in range(1, 101)]
ans = []

for s in sqr:
    if M <= s <= N:
        ans.append(s)

if len(ans) == 0:
    print(-1)
else:
    print(sum(ans))
    print(ans[0])


# TODO : TRANSFORM INTO A CLASS AND CREATE A REPORT OF REGION TRIMMED

#~~~~~~~GLOBAL IMPORTS~~~~~~~#

# Standard library packages import
from os import remove, path
import gzip
from time import time
from sys import stdout

# Third party package import
from Bio import SeqIO

# Local library packages import
from pyDNA.Utilities import import_seq, file_basename, mkdir
from Blast import Blastn

#~~~~~~~MAIN METHODS~~~~~~~#

def mask (  subject_fasta,
            hit_list,
            ref_outdir="./references/",
            ref_outname="masked_ref.fa",
            compress_ouput=True ):
    """
    Import a reference fasta sequence, Mask positions indicated by hits from a hit_list and write
    the modified fasta sequence in a new file.
    @param subject_fasta Fasta sequence of the subject to edit (can be gzipped)
    @param hit_list List of hit objects. Hits need at least 3 fields named s_id, s_start and s_end
    coresponding to the name of the sequence matched, and the hit start/end (0 based).
    @param ref_outdir Directory where the masked reference will be created
    @param ref_outname Name of the masked reference
    @param compress_ouput If true the output will be gzipped
    @return A path to the modified sequence if the hit list was valid.
    """

    # Test if object the first object of hit_list have the require s_id, s_start and s_end fields
    try:
        a = hit_list[0].s_id
        a = hit_list[0].s_start
        a = hit_list[0].s_end

    except IndexError:
        print ("No hit found, The subject fasta file will not be edited")
        return subject_fasta
    except AttributeError as E:
        print ("The list provided does not contain suitable hit object, The subject fasta file will not be edited")
        return subject_fasta

    # Initialize output folder
    mkdir(ref_outdir)

    # Initialize input fasta file
    if subject_fasta[-2:].lower() == "gz":
        in_handle = gzip.open(subject_fasta, "r")
    else:
        in_handle = open(subject_fasta, "r")

    # Initialize output fasta file
    if compress_ouput:
        ref_path = path.join (ref_outdir, ref_outname+".gz")
        out_handle = gzip.open(ref_path, 'w')
    else:
        ref_path = path.join (ref_outdir, ref_outname)
        out_handle = open(ref_path, 'w')

    # Generate a list of ref that will need to be modified
    id_list = {hit.s_id:0 for hit in hit_list}.keys()

    # Iterate over record in the subject fasta file
    print ("Masking hit positions and writting a new reference for {} ".format(ref_outname))
    i=j=0
    start_time = time()
    for record in SeqIO.parse(in_handle, "fasta"):
        # Progress Marker
        stdout.write("*")
        stdout.flush()

        # Check if the record is in the list of record to modify
        if record.id in id_list:
            i+=1
            #~print ("Hit found in {}. Editing the sequence".format(record.id))
            # Casting Seq type to MutableSeq Type to allow string editing
            record.seq = record.seq.tomutable()

            # For each hit in the list of hit found
            for hit in hit_list:
                if record.id == hit.s_id:

                    # For all position between start and end coordinates modify the base by N
                    for position in range (hit.s_start, hit.s_end):
                        record.seq[position]= 'n'
        else:
            j+=1
            #~print ("No hit found in {}".format(record.id))

        # Finally write the sequence modified or not
        out_handle.write(record.format("fasta"))
    print("")
    # Report informations
    print("{} sequence(s) from {} modified in {}s".format(i,ref_outname, round(time()-start_time),2))

    # Close files and return the masked ref path
    in_handle.close()
    out_handle.close()
    return ref_path


import gzip
import sys
from SPARQLWrapper import SPARQLWrapper, JSON
import gzip
from bs4 import BeautifulSoup
import re
import spacy
from spacy import displacy
from collections import Counter
import en_core_web_md
import difflib
import requests
import json
from elasticsearch import Elasticsearch
nlp = en_core_web_md.load()

KEYNAME = "WARC-TREC-ID"
KEYHTML= "<!DOCTYPE html"
NER_type = ["DATE","TIME","CARDINAL","ORDINAL","QUANTITY","PERCENT","MONEY"] # ruled type list avoid

## format function for output
def label_process(label):
    if len(label.split(" "))>1:
        return label.title()
    return label

## rule format function in NER
def entity_process(entity):
    l = []
    for X,Y in entity:
        if "cancer" in X:
            X = X.lower()
        l.append((X,Y))
    return l

## retrieve the text from HTML pages
## including text cleaning
def html_to_text(record):
    html = ''
    flag = 0
    for line in record.splitlines():
        if line.startswith(KEYHTML):
            flag = 1
        if flag == 1 :
            html += line

    realHTML = html.replace('\n', '<br>')
    soup = BeautifulSoup(realHTML,features="html.parser")
    for script in soup(["script", "style","aside"]):
        script.extract()

    ## text cleaning
    text = " ".join(re.split(r'[\n\t]+', soup.get_text()))
    text = re.sub(r"\s+", " ", text)
    text = re.sub("[^\u4e00-\u9fa5^\s\.\!\:\-\@\#\$\(\)\_\,\;\?^a-z^A-Z^0-9]","",text)
    return text

## NER function using spaCy
def ner(text):
    doc = nlp(text)
    entity = [(X.text, X.label_) for X in doc.ents if X.label_ not in NER_type]
    entity = list(set(entity))
    entity = entity_process(entity)
    return entity

## funtion of entity linking
## link the query result (wikidata url) with each entity
def entity_linking(entity):
    entity_list = []
    for e,_ in entity:
        if es_search(e):
            entity_list.append((e,es_search(e)))
    return entity_list

## function that finds a most similar entity
def get_closest_word(es_query, es_dictionary):
    try:
        wl = difflib.get_close_matches(es_query, list(es_dictionary.keys()))
        return wl[0]
    except:
        return list(es_dictionary.keys())[0]

### function that requests elasticsearch to get the candidate
def es_search(es_query):

    def search(query):
        e = Elasticsearch(["http://fs0.das5.cs.vu.nl:10010/"])
        p = { "from" : 0, "size" : 20, "query" : { "query_string" : { "query" : query }}}
        response = e.search(index="wikidata_en", body=json.dumps(p))
        id_labels = {}
        if response:
            for hit in response['hits']['hits']:
                label = hit['_source']['schema_name']
                id = hit['_id']
                id_labels.setdefault(id, set()).add(label)
        return id_labels

    d = {}
    try:
        for entity, labels in search(es_query.lower()).items():
            d[list(labels)[0]] = entity
        res = get_closest_word(es_query,d)
        return d[res]
    except Exception as e:
        print(e)
        return d

# The goal of this function process the webpage and returns a list of labels -> entity ID
def find_labels(payload):
    if payload == '':
        return

    # The variable payload contains the source code of a webpage and some additional meta-data.
    # We firt retrieve the ID of the webpage, which is indicated in a line that starts with KEYNAME.
    # The ID is contained in the variable 'key'
    # cheats = dict((line.split('\t', 2) for line in open('data/sample-labels-cheat.txt').read().splitlines()))
    key = None
    for line in payload.splitlines():
        if line.startswith(KEYNAME):
            key = line.split(': ')[1]
            break

    try:
    # Problem 1: The webpage is typically encoded in HTML format.
    # We should get rid of the HTML tags and retrieve the text. How can we do it?
        text = html_to_text(payload)

    # Problem 2: Let's assume that we found a way to retrieve the text from a webpage. How can we recognize the
    # entities in the text?
        entity = ner(text)

    # Problem 3: We now have to disambiguate the entities in the text. For instance, let's assugme that we identified
    # the entity "Michael Jordan". Which entity in Wikidata is the one that is referred to in the text?
        result = entity_linking(entity)

        for label, wikidata_id in result:
            if key and label and wikidata_id:
                yield key, label, wikidata_id

    except:
        pass

def split_records(stream):
    payload = ''
    for line in stream:
        if line.strip() == "WARC/1.0":
            yield payload
            payload = ''
        else:
            payload += line
    yield payload

if __name__ == '__main__':
    import sys
    try:
        _, INPUT = sys.argv
    except Exception as e:
        print('Usage: python starter-code.py INPUT')
        sys.exit(0)

    with gzip.open(INPUT, 'rt', errors='ignore') as fo:
        for record in split_records(fo):
            for key, label, wikidata_id in find_labels(record):
                # print(key + '\t' + label + '\t' + wikidata_id)
                print(key + '\t' + label_process(label) + '\t' + f"{wikidata_id}")


from ruamel.yaml import YAML
from datetime import datetime
from common import *
import sys

def main():
    fn = 'data/races.yaml'
    if len(sys.argv) > 1:
        fn = sys.argv[1]

    yaml = YAML(typ='safe')
    with open(fn, 'r') as fi:
        ydat = yaml.load(fi)

    prev_date = None
    for race in ydat['races']:
        dt = datetime.fromisoformat(race['datetime']).replace(tzinfo=RACETZ)
        ts = int(dt.timestamp())
        desc = race['desc']

        if prev_date != dt.date():
            day = dt.strftime('%A')
            print('')
            print(f'{day} <t:{ts}:d>')
        prev_date = dt.date()

        print(f'<t:{ts}:t> (<t:{ts}:R>) - {desc}')

if __name__ == '__main__':
    main()


# coding: utf-8

# Credits : https://gist.github.com/jason-w/4969476

from typing import List, Dict, Any
from mongoengine import (
    Document,
    ListField,
    EmbeddedDocumentField,
    DictField,
    EmbeddedDocument,
    FloatField,
    DateTimeField,
    ComplexDateTimeField,
    IntField,
    BooleanField,
    ObjectIdField,
    DecimalField,
    StringField,
    QuerySet
)

def query_to_dict(query_set: QuerySet) -> List[Dict[str, str]]:
    """Convert a query result into a list of each ouput document as dict.

    Args:
        query_set (QuerySet): the query result.

    Returns:
        List[Dict[str, str]]: output list of documents as dicts.
    """
    return [mongo_to_dict(document) for document in query_set]

def mongo_to_dict(obj, exclude_fields: List[str] = []) -> Dict[str, str]:
    """Returns the Dict format of the Document instance given in parameter.

    Args:
        obj (Deferred): the document queried from database to convert into dict.
        exclude_fields (List[str], optional): list of fields to exclude in the
            output dict. Defaults to [].

    Returns:
        Dict[str, str]: output dict.
    """
    return_data = list()

    if obj is None:
        return None

    if isinstance(obj, Document):
        return_data.append(("id",str(obj.id)))

    for field_name in obj._fields:

        if field_name in exclude_fields:
            continue

        if field_name in ("id",):
            continue

        data = obj._data[field_name]

        if isinstance(obj._fields[field_name], ListField):
            return_data.append((field_name, list_field_to_dict(data)))
        elif isinstance(obj._fields[field_name], EmbeddedDocumentField):
            return_data.append((field_name, mongo_to_dict(data,[])))
        elif isinstance(obj._fields[field_name], DictField):
            return_data.append((field_name, data))
        else:
            return_data.append(
                (field_name, mongo_to_python_type(obj._fields[field_name],data))
            )

    return dict(return_data)

def list_field_to_dict(list_field: List) -> List[str]:
    """Converts mongo db output list fields as a list of str.

    Args:
        list_field (List): list to convert.

    Returns:
        List[str]: output list.
    """
    return_data = []

    for item in list_field:
        if isinstance(item, EmbeddedDocument):
            return_data.append(mongo_to_dict(item,[]))
        else:
            return_data.append(mongo_to_python_type(item,item))

    return return_data

def mongo_to_python_type(field: str, data: Any):
    """Convert the field into str depending on the field type.

    Args:
        field (str): field type.
        data (Any): Associated data to convert.

    Returns:
        str: data converted.
    """
    if isinstance(field, DateTimeField):
        return str(data.isoformat())
    elif isinstance(field, ComplexDateTimeField):
        return field.to_python(data).isoformat()
    elif isinstance(field, StringField):
        return str(data)
    elif isinstance(field, FloatField):
        return float(data)
    elif isinstance(field, IntField):
        return int(data)
    elif isinstance(field, BooleanField):
        return bool(data)
    elif isinstance(field, ObjectIdField):
        return str(data)
    elif isinstance(field, DecimalField):
        return data
    else:
        return str(data)


import os
from hashlib import md5
from bson.objectid import ObjectId
import datetime as dt
import re

def all_files(path):
    files = []

    with os.scandir(path) as entries:
        for entry in entries:
            entry_path = os.path.abspath(entry)
            if entry.is_file() and os.path.splitext(entry_path)[1] == '.xlsx':
                file_hash = md5(entry_path.encode()).hexdigest()[:24]
                files.append({'_id': ObjectId(file_hash), 'path': entry_path})
            elif entry.is_dir():
                files += all_files(entry_path)

    return files

def week_dates(string):
    dates = [date.split('-') for date in re.findall(r'\d+-\d+-\d+', string)]

    week_start = [int(numeric_string) for numeric_string in dates[0]]
    week_start = dt.datetime(year=week_start[2], month=week_start[0], day=week_start[1])
    week_end = [int(numeric_string) for numeric_string in dates[1]]
    week_end = dt.datetime(year=week_end[2], month=week_end[0], day=week_end[1])

    return week_start, week_end

def test_week_dates():
    week_start, week_end = week_dates('Week 31 (Q3) From: 07-31-2016 To: 08-06-2016')
    assert week_start == dt.datetime(year=2016, month=7, day=31)
    assert week_end == dt.datetime(year=2016, month=8, day=6)

if __name__ == '__main__':
    test_week_dates()


import sys
import math

# 파이썬에선 해시맵을 딕셔너리라고 부릅니다.
# 해시맵생성 방법 변수이름 = {key1 : value1, key2 : value2, key3 : value3}

n = int(input())
dictionary = []
for i in range(n):
    word = input()
    dictionary.append(word)
letters = input()
max_score = 0
max_score_word = ""

def is_word_fessible(word, letters):
    for char in word:
        # 단어에 쓰인 각 글자의 개수가 알파벳 꾸러미의 글자 개수보다 많은 경우
        # 단어를 조합할 수 없습니다.
        if word.count(char) > letters.count(char):
            return False
    return True

def get_char_score(char):
    score = 0
    letters_scores = {'a': 1, 'b' : 3, 'c' : 3, 'd' : 2, 'e' : 1,
                      'f' : 4, 'g' : 2, 'h' : 4, 'i' : 1, 'j' : 8,
                      'k' : 5, 'l' : 1, 'm' : 3, 'n' : 1, 'o' : 1,
                      'p' : 3, 'q' : 10, 'r' : 1, 's' : 1, 't' : 1,
                      'u' : 1, 'v' : 4, 'w' : 4, 'x' : 8, 'y' : 4, 'z' : 10}
    return letters_scores[char]

def get_word_score(word):
    score = 0
    for char in word:
        score += get_char_score(char)
    return score

for word in dictionary:
    if is_word_fessible(word, letters):
        score = get_word_score(word)
        if score > max_score:
            max_score = score
            max_score_word = word
print(max_score_word)


from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from application.chart.models.chart import TopPosts_MH, TopPosts_WH, TopPosts_PVN, TopPosts_RW, TopPosts_BI, TopPosts_ROL, TopPosts_WE

class GetTopPosts(View):
    def get(self, request):
        models_map = {
            "WH": TopPosts_WH,
            "MH": TopPosts_MH,
            "PVN": TopPosts_PVN,
            "RW": TopPosts_RW,
            "BI": TopPosts_BI,
            "ROL": TopPosts_ROL,
            "WE": TopPosts_WE
        }
        response = []
        for brand, TopPosts in models_map.items():
            for model in TopPosts.objects.all():
                response.append(
    				dict(viral_unique = model.viral_unique,
                        unique = model.unique,
                        link = model.link))
        response.sort(key = lambda post: post['viral_unique']/post['unique'])
        response.reverse()
        return JsonResponse(response[:3], safe=False)


import re

import nltk
import spacy
from nltk import Tree
from nltk.corpus import brown

sentence = "A solution of piperidin-4-ol (100 mg, 0.989 mmol) and 3-((phenylsulfonyl)methylene)oxetane (prepared according to a published literature procedure: Wuitschik et al. J. Med. Chem. 53(8) 3227-3246, 2010, 416 mg, 1.977 mmol) in methanol (5 mL) was heated at 50Â° C. for 20 h. Solvent was evaporated in vacuo and the crude product was purified by flash chromatography on silica gel using an automated ISCO system (40 g column, eluting with 0-8% 2 N ammonia in methanol/dichloromethane). 1-(3-((phenylsulfonyl)methyl)oxetan-3-yl)piperidin-4-ol (300 mg) was obtained as a colorless oil.  If the temperature exceed 64 degrees when heating methanol it will result in 3% decrease in the final products."

def clean_sentence(example):
    cleaned_sentence = example
    mmole_qnuatities = re.findall("(\d+\.\d* mmol)", cleaned_sentence)
    for x in mmole_qnuatities:
        cleaned_sentence = cleaned_sentence.replace(x, '')
    return cleaned_sentence

sentence = clean_sentence(sentence)

def tok_format(tok, is_quantity=False, is_unit=False):
    if is_quantity:
        return "_".join([tok.orth_, "QNTTY"])
    if is_unit:
        return "_".join([tok.orth_, "UNIT"])

    return "_".join([tok.orth_, tok.tag_])

def to_nltk_tree(node, is_quantity=False, is_unit=False):
    if node.n_lefts + node.n_rights > 0:
        if is_quantity:
            return Tree(tok_format(node, is_quantity=True),
                        [to_nltk_tree(child) for child in node.children])
        if node.text in units_list:
            return Tree(tok_format(node, is_unit=True), [to_nltk_tree(child, is_quantity=True) for child in node.children])
        return Tree(tok_format(node), [to_nltk_tree(child) for child in node.children])
    else:
        if is_quantity and node.text.isnumeric():
            return Tree(tok_format(node, is_quantity=True),
                        [to_nltk_tree(child) for child in node.children])

        return tok_format(node)

parser = spacy.load("en_core_web_sm")
doc = parser(' '.join(sentence.split()))
units_list = ['mg', 'g', 'gr', 'gram', 'grams', 'kg', 'milligrams', 'milligram', 'mmol', 'ml', 'mL', 'L', 'millilitre']

uni_tags = []
for sent in doc.sents:
    for idx, token in enumerate(sent):
        if token.text in units_list:
            uni_tags.append((token.text, 'UNT'))
        elif token.text.isnumeric() and idx < len(sent) - 1 and sent[idx + 1].text in units_list:
            uni_tags.append((token.text, 'QNTY'))
        else:
            uni_tags.append((token.text, token.tag_))

# t0 = nltk.DefaultTagger('NN')
# t1 = nltk.UnigramTagger(uni_tags, backoff=t0)

[to_nltk_tree(sent.root).pretty_print() for sent in doc.sents]

# def tag_sentence(sentence):
#     for word in se


class Solution:

    def __init__(self,nums):
        self.nums =nums

    def lomuto_partition(self,low,high):
        pivot = self.nums[high]

        i = (low - 1)
        for j in range(low, high):
            if (self.nums[j] <= pivot):
                i += 1
                self.nums[i],self.nums[j] = self.nums[j],self.nums[i]
            self.nums[i+1],self.nums[high] = self.nums[high],self.nums[i+1]
            return (i+1)

    def quickSort3(self,low,high):
        if( low < high):
            pi = self.lomuto_partition(low,high)

            self.quickSort3(low, pi-1)
            self.quickSort3(pi+1 ,high)

            print(self.nums)

    def quickSort2(self,nums):
        if len(nums)<=1: return nums

        smaller,equal,lager = [],[],[]
        pivot = nums[0]

        for x in nums:
            if x < pivot: smaller.append(x)
            elif x == pivot: equal.append(x)
            else: lager.append(x)
        return self.quickSort2(smaller) + equal + self.quickSort2(lager)

    def quickSort(self,nums,left,right):
        if (left >= right):
            return
        p = nums[left]
        i = left
        j = right
        while (i != j):
            while (j > i) and nums[j] > p:
                j -= 1
            nums[i],nums[j] = nums[j],nums[i]
            while (i < j) and nums[i] <= p:
                i += 1
            nums[i],nums[j] = nums[j],nums[i]
        self.quickSort(nums,left,i-1)
        self.quickSort(nums,i+1,right)
        # print(nums)

    def quickArraySort(self,nums):
        left = 0
        right = len(nums) - 1
        self.quickSort(nums,left,right)

if __name__ == "__main__":
    arr = [21,38,29,17,4,25,11,32,9]
    solution = Solution(arr)
    solution.quickSort3(0,len(arr)-1)


import unittest

# @param {Integer[]} nums
# @param {Integer} target
# @return {Integer[]}

class Solution:
    def twoSum1(self, nums, target):
        """
            Time: O(n)
            Space: O(n)
        """
        map = {}
        for i in range(len(nums)):
            compliment = target - nums[i]
            if compliment in map:
                return [map[compliment], i]
            else:
                map[nums[i]] = i
        return [-1, -1]

    def twoSum2(self, nums, target):
        """
            Time: O(n^2)
            Space: O(1)
        """
        for i in range(len(nums)):
            for j in range(1, len(nums)):
                if nums[i] + nums[j] == target:
                    return [i, j]
        return [-1, -1]

class Test(unittest.TestCase):

    def setUp(self):
        self.s1 = Solution()
        self.s2 = Solution()

    def tearDown(self):
        pass

    def test_twoSum(self):
        self.assertEqual(self.s1.twoSum1([2, 7, 11, 15, 9], 9), [0, 1])
        self.assertEqual(self.s1.twoSum1([3, 2, 4], 6), [1, 2])
        self.assertEqual(self.s2.twoSum2([3, 3], 6), [0, 1])
        self.assertEqual(self.s2.twoSum2([3, 3, 4, 1, 0, 6], 100), [-1, -1])

if __name__ == '__main__':
    unittest.main()


'''
o/ Iae pessoal, Tudo bem?
Espero que sim :)
Bom este é o exercício 1018 do URI, modulo iniciante

Leia um valor inteiro. A seguir, calcule o menor número de notas possíveis (cédulas) no qual o valor pode ser decomposto.
As notas consideradas são de 100, 50, 20, 10, 5, 2 e 1. A seguir mostre o valor lido e a relação de notas necessárias.

<-- Entrada
O arquivo de entrada contém um valor inteiro N (0 < N < 1000000).

--> Saída
Imprima o valor lido e, em seguida, a quantidade mínima de notas de cada tipo necessárias, conforme o exemplo fornecido.
Não esqueça de imprimir o fim de linha após cada linha, caso contrário seu programa apresentará a mensagem: “Presentation Error”.

'''

valor = int(input())
cedula = [100, 50, 20, 10, 5, 2, 1]           #lista usada para os tipos de cedula 100,50,20 e por ai
ncedula = [0, 0, 0, 0, 0, 0, 0]               #lista usada para receber as quantidades de cada tipo de cedula

valor_pre_calculado = 0                       #variavel para ajudar no calculo da quantidade das cedulas
print(valor)

for index in range(7):                        #laço de repeticão que roda enquanto a variavel index não chegar em 7
                                              #variável de indexação = Usada para rodar as listas e laços de maneira ordenada e sincrona
                                              #Em cada loop, a variável index somará mais 1 no seu valor, até chegar no valor estimado no range
                                              #EX: for index in range(5) -> index = 0; index = 1; index = 2; ...; index = 5

    ncedula[index] = int((valor - valor_pre_calculado) / cedula[index])         #calcula a quantidade de cada cedula, pegando somente o primeiro valor inteiro

    valor_pre_calculado = valor_pre_calculado + ncedula[index] * cedula[index]  #auxilia a calcular somente o dinheiro que já n foi calculado (tranformado em inteiro na ncedula)

    print("{} nota(s) de R$ {},00".format(ncedula[index], cedula[index]))

'''
Caso ainda esteja dificil de entender o laço, tenho outro código fonte que não uso for
mas é mais complicado de entender hehe XD
tae para quem quiser ver

valor = int(input())

n100 = int(valor/100)
n50 = int((valor - n100*100)/50)
n20 = int((valor - (n100*100 + n50*50))/20)
n10 = int((valor - (n100*100 + n50*50 + n20*20))/10)
n5 = int((valor - (n100*100 + n50*50 + n20*20 + n10*10))/5)
n2 = int((valor - (n100*100 + n50*50 + n20*20 + n10*10 + n5*5))/2)
n1 = int((valor - (n100*100 + n50*50 + n10*20 + n10*10 + n5*5 + n2*2))/1)

print(valor)
print("%i nota(s) de R$ 100,00" %n100)
print("%i nota(s) de R$ 50,00" %n50)
print("%i nota(s) de R$ 20,00" %n20)
print("%i nota(s) de R$ 10,00" %n10)
print("%i nota(s) de R$ 5,00" %n5)
print("%i nota(s) de R$ 2,00" %n2)
print("%i nota(s) de R$ 1,00" %n1)

no fim, da no msm, mais consome mais memória '-'

Bons estudos e até o/

'''


from typing import Any, Dict, List, TypedDict

import torch as th
from tango.integrations.torch import DataCollator
from tango.integrations.transformers import Tokenizer

from dreambooth.steps.transform_data import PreprocessedExample

class BatchExample(TypedDict):
    input_ids: th.Tensor
    pixel_values: th.Tensor

@DataCollator.register("custom_collator")
class CustomCollator(DataCollator[PreprocessedExample]):
    def __init__(self, tokenizer: Tokenizer, is_prior_preservation: bool) -> None:
        super().__init__()
        self.tokenizer = tokenizer
        self.is_prior_preservation = is_prior_preservation

    def __call__(self, items: List[PreprocessedExample]) -> BatchExample:
        input_ids = [item["instance_prompt_ids"] for item in items]
        pixel_values_list = [item["instance_images"] for item in items]

        if self.is_prior_preservation:
            input_ids += [item["class_prompt_ids"] for item in items]  # type: ignore
            pixel_values_list += [item["class_images"] for item in items]  # type: ignore

        pixel_values = th.stack(pixel_values_list)
        pixel_values = pixel_values.to(memory_format=th.contiguous_format).float()

        input_ids = self.tokenizer.pad(
            {"input_ids": input_ids},
            padding="max_length",
            return_tensors="pt",
            max_length=self.tokenizer.model_max_length,
        ).input_ids

        batch: BatchExample = {
            "input_ids": input_ids,
            "pixel_values": pixel_values,
        }
        return batch