############################################################################# SOF reference=""" ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██████████████████████████████████████████████████████████████ █████████████████████████████████████████████████████████████████████▀█▀█▄█▀█▀██ ██████████████████████████████████████████████▀██████████████████████▀██▀ ▀██▀██ ██████████████████████████████████████████████ █████████████████████░▀▄▀ ▀▄▀ ██ █████████████████████████████████████████████ ░ ▐████████████████████▄ ▄▓▄ ▄██ ████████████████████████████████████████████ ▄▓ ████████████████████░▀▄ ▀ ▄▀ ██ ███████████████████████████████████████████ ▄▀ ▓███████████████████░ ▀▄▀ ▓ ██ ██████████████████████████████████████████ █▌▌ ▓███████████████████░▄▀▄ ▄ ▓ ██ ████████████████████████████████████████▀ ███ ▌ ▐███████████████████░▓▄▓ ▓▄▀ ██ ████████████████████████████████████████▀ ▓██ ▓▀ ███████████████████░▒ ▒ ▒ ▒ ██ ███████████████████████████████████████ ▌██ ▓▌▄▌ ▐██████████████████▄▀ ░ ░ ▀▄██ ██████████████████████████████████████ ▓▐█ ▓▓▓▓▌ ██████████████████▄▀▄▀ ▀▄▀▄██ █████████████████████████████████████ ▓▌█▌▐▓▓▒▓▒ ▐█████████████████▀█▄▀▄▀▄█▀██ ████████████████████████████████████ ▓▀██ ▒▓▒█▓░ █████████████████ ▀██▄█▀▄ ██ ███████████████████████████████████ ▓▌▄█ ░▓▒██▒▓░▌ ▐████████████████ █ █▀█▄█ ██ ██████████████████████████████████ ░████░▓▒▒▒▒▓▓░▌ ▐█████████████████▄ ████▀▄██ █████████████████████████████████▌ ░▓█▓▓▌▓▄▓▒▒▓▓▓▓ ▐███████████████████████████ █████████████████████████████████ ▓█▀▄█ ▀▐▒▒▓▓▓█▓▌ ▀▄██████████████████████████ ████████████████████████████████ ▒▓██▌▒ ▒▒▓▓▓██▀ ▓▄███████████████████████████ ███████████████████████████████ ▄█▓▓██▓ ▌▓▒▓▓▓██▓ ▀▌█▐█████████████████████████ ██████████████████████████████▌ ▐█░▒▒▌░▌ █▓▓▓███▓▓░ ▐█████████████████████████ █████████████████████████████▄▀▐▄▀█░░▀ ▌ ▌▓█▓███▓▓▓▒░█ █████████████████████████ ████████▀████▀████▄█▀▀▀█▄▀ ▀▓▄ ▓▄▐███▀ ▓ ▄▐██████▓▓▓▒█ ▐████████████████████████ ████▌▀█▌▀ ▀▀▀ ▀▀▀▀████▐▄ ▐▄▀███▌▄░▐▒ ▓█████▓▓▓▓▒██▐████████████████████████ ▀▀▀ ▄ ▀▀▄▄▀▀▀▀▄▄▀▀█▄▀▄▄▀▌▄▀▄▓▀▓▓▐█▄░▓▒░░▓████▓▓▓░███████████████████████████ ▀▀▀▄▐▄▀▒▄▀▄▌▄▀▓▒▄▄▄▒ ▀▄▓▀▄▀▄ ██▀▄▄▄▀▀▓▀▄ ▀▒░░▓██▀▓▓░ ███████████████████████████ ▓▓█▄▄▀███▀░▄▀▓▄▀▐░░ ▀██▀█▄▐ ▄▀▄██▀██▄▄▄▄▀▄▄ ░░▓▓▓▄ ▄▌█▐█████████████████████████ ▀▀▓▓▓██████░▒▄▓▌▄▄██▀███▄▀█▀▄█ ▄███▀█▀██▓▓█▄▄ ▀▒▒ █▀████████████████████████████ █▄▄ ▀▀▀▄▄██▀▐▄▀█▓▓▄▌██▀▌█▄▀█▐▄▀█▌███▐▌ █▐▀▀█▓▓▄█▄▀███▓██████████████████████████ █▄█▀█▄ ▄ ▀▀█▄▌▐ ██▀▀█▄█▄███▄▀█▌██████▌ ░░███▀▐▄▀▌▄▌█▀ ██████████████████████████ ▄█▀█▓▀▄▐▒▄■▄ ▀▐█▀▀▄██▀█▀▌██ ▄▌▌▀████ ▌░░▄ ▀█▓▓▀▄██ ▀████████████████████████ ░▌▀█▄▄█▓▄▀░▌▀▀▌█▓▓█▄▄███████ ▀ █▄████████████▐▀▐▀█▄▀█ ▀████▀▐██████████████████ ░▒▄▄▀█▄█▓▓░░▌▌ ▐▄ ▀▀█▀▀▄ ████ ███████████████▄█ ▀▀▐▀▓▄▌ ▀ ▄███████████████████ ▀█░░█▀███▓▓▄▀ ▄▀▀█▄▄ █▀▌████████████████████░░▌▄█▀▌▀█▄ ▄▌ ▀▐█████████████████ ▀▀▀▄▄█▓▓▀▀▄▄ █▓▓▄░░ ▀▀ ▄████████░█████████▐█▌██▐▀██▌█▀▀▓▄▀ ▀▄████████████████ ▀▀▄▄▄ ▄ ▀▀ █▄░░▀▀▄▄████████████░█████████▐▐▌░░▐█▌▀██▐▀█▀█▄ ▀█████████████████ █▄▄ ■▄▐░░▀██▄▄███▀█▄█████████░████░░██▌ ███▓ ▄▌ ▄▀▄▄█▀▓▄ ▀███▀ ▀ ▀▐██████ ███▓▓▄▄▌ ▀▐▀░░░░███▄▀▀████████████░████░░█▌█▐███▓ █▀▄■██▄█░░█▀█▄▄ ▄▄▀ ▄▌▀██████ ██████▓ ▄ █░░████████▄▄▀▀███░░█████████▀█████▄▀▄█▄▀▄██▀▀▄▌▄▄█▀ ▀▐▓▓▀▄▓▀ ▄██████ █████▓ ▐░▀▀▄▄████████████▄████░░█▄░▀████▄▄▀▄▀ ▐▄▀▌▌ ■▄▄▀▌█░░ ▄▄▀▀▀▓▄ ▀███████ ████▀ ▄▄█▀█▀▀▀ ■▄ ▀▀▄▀▀▀██████▀███▄▀█▄██▀▓▄■▐▄▓▀■▀ ■▄▄▀▀▄▌██▀▀▀▄▀▄▐▄ ▄▀▄██████ ▀▀ ▄▄▀▄▄▀▄▓▌▓▀▄▄▀▀█▄█▄▀▄ ▀▄███▄▌█▀▌▄▐▌▐▄▐ ▄▓▀▀ ▓▀▄▒░░▄▌██▄▄▓▓▀▀ ▄████████ ▄▄▄██▓▓▓█▀█▄ ▀▀▀▓▓▓▓█▓▓▓█▓▓█▄▄▀▀█▀▄▌▄█▐▄▄▌ █▓▀▄▀■ ■▄▐▀▌▀▄▌▀█▀██▀▀▄▄▄ ▀▀▄███████ ▀▓▓▄▀▀▄▀▀█▄█▓▓▄▄ ▀▀▀▄▀▄ ▄▄▀▀▀█▄ ▀▄█▌▀▌▀█ ▐▀▄■▐░▌ ▄▀▄▄▀▐▀▀█▄█▄▄█▀▀ ▄▄█████████ ▀ ▄▀▀▒▒▄▀ ░░▌▀░▀█▀█▀▄ ▀■▀▄▓▀ ▀■ ▀ ■▀▀ ▀ ▀ ▄ ▌▀▀▀█▄▄▀ ▄▄▄▄▄▀ ▀■ ▄█████████ ▄▄▄▀█▄░░█████▌▀▄▀▀▄▀▄■ ▄▄▀ ▄ ▄▄███████▄▀▄▌▄▀▄▀▄▀░▌▀▀▒░▄ ▄▀▀ ▄██▄████████████ ▀▀▓▀░░███████▄█▀▀▀▓▄▀ ▀▀▀░ ▄▓▓▄▄▄▀█▄▄▀██▄▄▓█▄▓▓▌▄▀▄▀▀▀▄▀▄▄ ▄▄█████████████████ ▌ ▄█▌▀░░█████████▄▄▀▀█▄██░▄▀▐▐▀▄▀▄▀▄▀▀█▓▓▓▀▄▐▓▓▀▄▐▄▐▄▐▀ ▄▄ ▀ ▄██████████████████ █▄ ▀ ▀█▄░░██████████████░░░▌ ▀░░▀▓▄ ▀■▄▀▓▀▄▓▓▀■ ▀▄▀▄■ ▀████▄▄██████████████████ ████▄ ■▀ ▀▀▄▄▄▀ ▀▀▐▀▄░░░▄▀▀▀▀▄▄▀▀░░▀▀▄▄▄ ▄ ▀▀▄▀ ▄▄ ▀ ▄█████████████████████████ █▓▓▀ ▄▓▓▄ ▀▀▄▀█▄▄▄▀▄▀▄▀▀▄▓▄ ▀▄▄▄ ▀▀▀▄▄▄▄▀▓▌ ▐▀▄▀▀▄▄ ▀███████████████████████ ▓▒ ▄▌▒▐ ▀█▓▓▄ ▀▓▄▀▀▄▌▄▀▓▄ ░▄░■ ▀▒▀▄▀▓▓▄▀▐▓▀ ▄▌▀░░▀▀▓▓▄ ▀█████████████████████ ▒ ▄▓▀▄▀▄█░▌▀█▓▓▄ ▄▀▀▄▀▐▓ ▀▀░░▄░▄ ▄ ▄▄▄█▀▄▓▀▄▀░░▄▀▒ ▐████████████████████ ▒▓▐▐░░ ░░▀▌█▒▌▓▄ ▀▓▀▀▀▄▄▄░▄ ▀▀ ▄▄▀█ ▓▓▓ ▀▐▄▀▀ ▄▄▄▄▄▀▀░▒ ████████████████████ ▓ ▀ ░░ ▓▓░▀█▄■▄█▄ ▐▓░ ░░▀ ▄▀▓▀▄▀▌▐▓░▓▓░▒ ▓ ▄█▓▓██▄██▄▀▌ ▐███████████████████ ▐▐ ░░░░▌▀ █▄▄▐█ ▀▄▓▄▀ ▄▀▓▀ ▒▄▐▀ ▓░ ░░▌▐▌▐█▀█████████▄ ███████████████████ ▐▌▀ ░░▀▐░ █▐▀▓▄█ ▄▄▄ ▄█▀▀▄▄▓▓ ▐▄■ ▓░░█ ▓ ▀▄░▄████████▌▄ ▐██████████████████ ▓▀▌░░ ░░░▄▀░▀█▐ ░▀▓▌▄▀▒▒▌▐▓░▀░░░░░ ▓▄▀▄ ▓░▄▒▌▐█▄██████▓███▓▌ ▄██████████████████ ▀█▀▄▄░░▌▀░▐ ▐▀░ ▀▀ ▄▓▄▄▀ █░▌░░░░ ░░▓▐▄ ▓░▀▄▓▓▌▀█████▓▓█▓▄▀ ▐██████████████████ ▒░▄▀▀▄▄▒▀▄▀▄ ▄█ ▀▌░▀▀ ░▐▐▌░▀▄▄▄░░▄█▀▀ ▄▄ ▄▀▓▀▀▓▐███▓▓▓█▓▄ ▀▄██████████████████ ▀ ▀▄▀█▀▓ ▀▄▄▀ ▄▌▀▄▄■▄▐ ▄▀▓▄▄▄▄▀▀▄▄▄▄▓▀▐▀ ▀█▀▐▒▀███▓▓▓▓█▌ ▌███████████████████ ▐▀▄ ▀▀ ▄ ▄█░░▐▒░▓██▄ ▀▀█▄█▄██▄▄▄░▒▌▄ ▄▄ █░▀▒█▓▓▄▀▓▀ ████████████████████ ▓▄ ░ ░ ▓█▐░░░░▐░▓▓▓█▓▓░▄▓█▓▄██▓▓▀▌░░▓▀ █▀▌▄▓▐██▓▓▓▓ ▄█████████████████████ ▓▓▓▐ ░░░ ▐░▌▄░░ ▄▀▀▀▀▀▀▀▀▄▀▌▐█▓▓██▀█▀▒▌░ ███▄▀░██▓▓▌▌▐▐██████████████████████ █▓▄▒ ▄▓░██▒░▐▒▀▓▄▄▄██▌▄ ▄▄▀▀ ░▀▄■▄░ ████▄▀▓█▓▓▌ ████████████████████████ ██▓ ░░░ ▓▓░▒▓▌▀▀▀▀▀ ▀▀▀▄▀▄ ▄▄▄▄ ▄▄■ ░▐▓░▐▀▓▓▓▓▓ ▐███████████████████████ ██ ░▒▒▒░ ░░░ ▓▄▄▄▄▄▄▄▌▀▀▀▒▌▀▀ ▀▀▀▄ ▄ ░ ▐▒▌█▄█▓▓▓▌ ███████████████████████ █▀ ▒▓▓▓▓▓ ░ ▐▒▒░ █░░▄██▓█▀▀██▓▌▐▓▄▄▄▄▄▀▄░ ▐█▐▓▐█▓█▓▓▄▀ ▓██████████████████████ █ ▓▓███▓▓▒ ░▐▓▌░▌▓█▀▀█████▀█▓▓▐▓▄█▓▓▄███░ ▐▌█▀███▓█▓▓▓ ░▓██████████████████████ ▌ ▓████░▓▓▌ ▒░█░▌ ██░░░░▄▄▄░░▀▌▐▐███▄█░░▌ ▓▌█▐▀▐█▓▓▓▓▀▌ ▓██████████████████████ ▐█████░▒▒ ▓ ██▀▐██░▓▓░█▓▓▓▄▌▌▐▓▌▄▀■░░█▌ ▓▌█ ▐▄██▓▓▄▐ ███████████████████████ ██████░▀▄▌ ▓▌ ▄▓█▓█ ░░░░░░░░░▌■▀▀█▀▀█▀▀▄ ▐▌█■▀ █████░ ▐███████████████████████ ▐███████▒▒ ▓░▌ ██▓▓ ░░░░░░░ ▌▒▄▄█▄▄█░▀▌ ▐▌█▄ ■▄████▌▌ ███████████████████████ ██████▀█░░ ▌▐▒▌█░▐██▀▀▀▀▀▀▀█▓▌ ▌░░▄ ░░█▓▌ ▐█▐▓▌███▄█▌█▓ ███████████████████████ ██▀█▌▄█░ ▌ ░▒▀░▄██▓▓▓█▀▄▀▀▀ ▄ ███ ▄▀▌ ▄▓█▐▒██▄▓█▓█▓▓▌▐██████████████████████ ██▄▀█░░░▀ ▒▌ ░░█░▌▓▀██▀▀█▓▓▀▄ ▄▄▄▄▄▄█▄▄▄█ ▐▐ ▐▒▒█▓▓███▐▌ ██████████████████████ ▐██▄██░▌ █▌ ▓░░█▌▓▓█░░░█▀█▀█▐█░▓▓▓▓▓░░▌█ ▐ ░▒▒▓▓▓██▄▀▌▐██████████████████████ █▄█░░█▀ █▌▌ ▓░░▐▌▀▀█████▒▒▓▀▐▓██▀█░▐▓█ ▓▒ ▐█▓▓████▌ ▄▐██████████████████████ ▌▐░░██ ▄██▄▀▄ ▀▄▄█▓▄▄▄▄▄▄█▄▄ █▓▓███▀▀▒▌ ▓ ▒▄▓▓███ ▐███████████████████████▀ ▄▐███▌ ▀▓▓ ▐▓░▀ ▀█░░░▒▓▌▓█▀▐▓▓████░▓ ▄█ ▓▒ ▄▌▒▒▒▓█▌ ██████████████████████▀██ ▀░ █░░▄▄▄▄ ▒ █░░ ██▄████▀▒▓▄▐▓██░░▀▀ ▄██▓█ ▄▄▐▓▒░▌▒ ▐████████████████████▀██▄█ ▌▄▀▄█░░▀▓▌▌ ▐▓░░▌▀█▒▒▒██░▒▒▓▄██░░▓▀▀▀ █▄ ▄▐█▀█▌▀░█▄ ▀▓▓████████████████▀██▄█▓▓ ░▄▌▀▌█▐▄▀░ ▒ ▀█░▌▓█████▒▒▄▄▀▀▄ █▄▄█▀▀█▀▄▌▐▀██▐▀█▐▄▄▄▓▄ ▄ ▀▌▀██▓▓▓▀▀▀▀▀██▄█▓▓▄█ ▐▌▄▐▀█▀▀▌▌ ░ ▐▀▌▄█▓▓███▒▒▄░▀█▀▌ █▄▄■█░░▌▐▒▒██ ▀██░░▀▀▓█▌▄███▄▄▄▄▄▄▄▀▀█▀█▀█▄███ ░▌░░█▌▌▄░█ ▓█░░▄▄▄▀▀█░░▒▒▓▌ █▌▀▀█▄███▀▀▄▀▀▄▌▄▀▀▄▄▄▀█▄█▒▄▌▐▄▀▀▓▓▓▓▀█▄▀▄█▄█████ ▌ ░▄▀█▌▐ ░▌ ▐▄ ▄▀▀▀▓▓█░░▄▄▄▀▀▌▄█ ■▄ ▄▄▌▐█▀▀▀▀▓▓▌▐▓▀ ▌▀▄██▀█▄▀▄█▄███████ ▌▄▐▄▐▀▄▀░▀▄ ▓▓ ▄▄▄▄▄▄ ▀▀▀▀ ▄▄ ▄ ▄▌▐▄▄▐▓▓█ ▀ ▄▄▀░▀▄░▀▄▒▒▀█▀█▄▀▄█▄▀█▀▌█████ █▀▌▌▄▀▐▌▀▌▀▌ ▓▓▄ ▀▀▓▓▒░░ █▀▀█▀ ▀▄▓▀▀▐▓▀▐░▒▒▀ ▀▀▄▀ ▄▄▄▄▀▀▀ ■▄▄▌▀▄▓▌█▄█████ ▀▀▀█▄▄▀ ▄▄▄ ░░▒▒▓▓▓▓▄▄▄ █▄▐▌▄▌ ▓▄▀▓▄▀▀■▀░░▌▀▄█▒▌▐▄░░▀▀ ▄▓▀ ▄▄▌▄▀▄█▄███████ ▓▓█▄▄▄▄ ▀▀ ▀ ▀▀▀ ▀▓▓▓▒▒▒▒ ▐█▓▌▐█▄ ▀▀ ▀█▄▀▀▄█▀▄ ▀▀ ████▀▐▓▓▄███▓█████ ████▓▓█▄▄ ░░░ ░░░ █▓▀ ▀▀ ▄▄ █ ████▄ █████▓████████████ ▌▀██▀█▀▀█▄▄ ▄▄ ▀▀▀▀▀ ▄▄▄▄▄▄▄█▀▀▀█▄ ▄▄▄██▄▄▀▄█▌█▒▒███▄█████░░█▐▓███████▓▓███ ▄▀█▓▓▄▌██▀▀█■█▄▄▄▄▄▄▄ ▄▄█▄ ▌▄▐▄▄▄█▄▄█▄▀▄▐█▓▓▓▓▓█▄▌█▄▓▓█████████ ██░▓████████▓▓▓█ ▌███▀▀█▐▄█▀█▄████▓▓▓▓▓▓▓▓▄▌ ▀▀▀▀▄▄▄▄▄▄▄▄▓▓▓▓██▓▓▓▌░▓▓████████░░███░████▓▓███████ █▄▌▐▄█▄█░█▄▄▓▓████████▓▓▓▓▓▓▄▄▄▄▀▄▌▄█████████▓▓▓▌█▓▀▌████████████▐▐▐████████████ ▀█▀███▌▌▐▄████████████████████████████████████▓▌▒▒▀ ███░▐████████████ ▓▄ ▀░▐█▓▌▐▐███████████████████████████████████▌▄▌▄▄▄▄ █ ████▐░▐████████▓▓██▓ █▄░██░▓█▌▐▓████████████████████████████████████▄█▓▓▓▒▒░▐▄▄█▄▄█▄▄▀▄░▐█████▓▓███▓▓ ▄▀▌████▓██░██████████████████████████████████████▓▓█▓▓▓▄▓▌▌▐▐▄▓▓▄▓▓██▀██████▓▓▓▓ ▀░█▓▄███▌█▓██████████████████████████████████████████▓▓▀▄▌▌░▓▓▓█▀▀███▒▐██████▓▓▓ ▄ ▓▓▀▌██░▌▐▒██████████████████████████████████████████▓▓▓█ ▐▓▓█████▄▄███▀█████▓▓ ▄▀ ░▄█▓█░░█████████████████████████████████████████████▓▌▐ ░█▓▓▀██████████▀▀▀▀▀▀ ▀▓▐ ▓█▄▌█▐▌▐░█████████████████████████████████████████▓▓▀▌ ▐▀▀▌▄▀▀▀▀▄▄▄▄▄▄██████ █▄▌▌ █▓▀░▐▌█▓▐█▄▄██████████████████████████████████▓▓▓▓▀ ▄▄▄ ■▀▐▄▒▄███████████▄█ █▓░▐ ▀█▓░▐▓▌▐▀▄██████████████████████▀▀█████▀▀▀▀█▀█▄▄▄▄▌▐█▄▀▌ ▐▄▀██████████████▌ ▓▓▌▐ ▓▓▐▄█▌▄█▓▓▓▓▓▓▓▓▓▓▓▓█▓███▀█▀▀▀██▀▀▄▄█▄▄▄█▀▄▄███▐██▄▄▀▀▀ ▄▒█████████████████ █▓▌▐ ▓█▄█▄▐▓▌▐▒▓▓▓▓▓▀▀▀▀▀▀▄▄▄▄▄▄█▀█▀▀██▄██▀██▌ ▐███▄ ▀ ▐▄█▀▄▀███████████████▀▀▄ ██░░ ██▀▄▐▀░▀█▀▀ ▄▄▄▀█▀ ██▐██▄▌▐███░░█▄██████▀▄█████▀ ▄██▀█░▓▌███████████████▀▄ ▓▄▓▀ ███▌█▄▄▓▄▄█▀█▌▄█▌██▀█▀██▀█▐██████▐███████████████▄▐██▌█░▓▌▀▀██████▄██████▀ ▓░░ ███▌▀▐█▓▓▄▄█▄ ▀▄█▌████▐▀█▀███░░███▄███████████████████▄██ ▓▌███▄▄██████▀▀ ▄ ▀▄███▄█ ██▓▓████▄█▄ ▀███▄█▄███ ▌███ ▄████████████████████████░▒▌▄ ▀▀▀▀▀ ▄▄▄▄▀ ▀ ▀██▄ █ ██▀▐█████████▄ ▀█▐████░ ▌███▀▄ ▐███████████████████▀▀▀▀ ░▒▌ ▀▀▀ ▓▄ ▄▄▐▄█ █▐█░▀██████▄█▄██▄ ▀▀█▐█░ ███▀██▄▀█████████████▀▀▀▀█████▄██ ░▄▀ ▀ ▄ █▀▀█ ▀▄████▀ ▀█▄▌▀███████▌█▄▌▄ ▀█▀▌█▌███▄▄▄▀████████▄▄▄▄▄███████▀███▀ ░▓▓▄░▄▀██▀▀▀▀▀ █▀▀▄▌█▄ ▀█░░▀▐██████▀▐ ▄██▄ ▀█▐ ██▀▀▀▀▀▄▄▄▄▄██▀▀███▀▀▀█▀██▄▄■▀▄▓▐▄░▄▀█▄█▄▄▄▄▄▓▓▓ ▀█████▄█▄█▀█▄▀▌████▀██▄█▌▄▀▄▄ ▀██▄▄▀█▄▄▄▀▀▀▀██▀▀████▄▄██▀▓▀▀▄▓▀▄██▄███████▓▓▓▓▓▓ ▄█████▓▓█▄█▀▄▀▓▓███████▀▄█▀▀██▀▀██▀▀▄▄ ▄▄ ▄▄▄▄▄ ▀▀▀▀▄▄▀▄▓▓███████████████████ █████████▓▓█▄ ▀█▄▀▀▀██▀▀▀▀▄▄▄▄▄▀█▀■▀▀ ░ ░░░ ░██░░░█░░█ █▄███████████▀▀▀▀▀▀▄▄▄▄▄ ▐▀▓▓██████████▄ ▀▀▀▀▀█▄▄▄█▓▀▓▄█▀▄▄▄▄░▄░▓▓░▓▓░▓▄▀▄ ██████▓▀████▀▀███████████████ ██▀▀■▀▄▀███▓▓▓█▓▓██▓▓▓▀▀▓░░▀▐▀▄▄█████▄▌▐▓▓▐▓▌▐▓▓▓█████████▓░██ ▀▀▐▐████████▄█ ▄ ▀▀█▐▌▐▓▓▓▓▓▓▄▄▄▓▓▀▀▀▀████▌▐███████▀▌▐▒▒ ▓▒▒█▓ ██████████▓░█▌▄█▌░▀█████████▀██ █ █ ▓▓▄▀▀▀▀▀███▄▄▄▄ ░░█ ▐███████▌░ ██░░░▌░▌ ███████████░█▄▓▄ ▐▄▀▀▀▀▀▀ ▀ █ ▄▄▄▄▀▀██▄▄▄▄▄████████▄█▌▐██████▓▓▀▌▐██▄▐▄█▀▄▄ ██████████ ▀▀▀▀▀▀ ▀▀▀▀▀▀▓▓▀▀▐▀▓▓█▀▀▀▀▓█████▌░░▓▓███ ▄▄▄▄▀ █▐█████▀▐▌▄ ██████ ███ █████████████ ▄▄▄▄▀▀▀▓▓▀█▀▀█▀▀▀▀░░▓████▄▄▄▓████▄▀▀▀▀░▀ ▐███▓▓▌▄▐▄ ██████ ███████ █████████ ▀▀▀▀ ▄▄▀▀ ▀ ▐▓█████████████████▀▄▌███▓▓▀▀ ▀▀▒██████ ▐▀▐█████████████████▄▓▒▀▀▄▄▄▓▌ ▒▄█████████████████▀▄▐▄▒▒▌▀▀▒▒ ▀▀████▀▀▀▀▀▀▄▄▄▄▄▄▌▐ ▀▀ ▒▒ ▒ ▒▐▄▄▄▄▄▄▓▓▓▀▀▀▀▀▀▒▒▒▒▒ ▒▀▀▀ ▒▒▒▒▒▒▒▒▒ """ ################################################################# CLASS DR1P4NS1 class dr1p4ns1: ############################################################################ commands = { 'A': 'up', 'B': 'down', 'C': 'forward', 'D': 'back', 'H': 'position', 'f': 'position', 'J': 'erase', 'K': 'erase_line', 's': 'save_cursor', 'u': 'restore_cursor', 'm': 'color', 'R': 'report_cursor_position' } ############################################################################ asc_table=""" ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒ\ áíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐\ └┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀\ αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■  """ ############################################################################ for r in (('\n',''),(' ','')): asc_table=asc_table.replace(*r) ############################################################################ asc2uni=dict(zip([i for i in range(128,256)],[ord(c) for c in asc_table])) ############################################################################ asc2chr=dict(zip([i for i in range(128,256)],[c for c in asc_table])) ############################################################################ def __init__(self,ansifile="",width=80,height=25,debug=False): self.DEBUG=debug self.width=width self.height=height self.openansi(ansifile) self.code='\x1b[0m' self.cmps=[] print("\x1bc\x1b[1;31m[ DR1P ]\x1b[0m\n") self.boot() ############################################################################ def openansi(self,s): f=open(s,'rb') self.ansifile=f.read().decode('cp437') f.close() ############################################################################ def printascii(self): for i,_ in enumerate(self.asc_table): _int=str(i+128).zfill(3) _hex=hex(i+128)[2:].upper().zfill(2) _ord=str(ord(_)).zfill(4) print(f'{_} - {_int} - {_hex} - {_ord}') ############################################################################ def printrange(self,n,nn): for index,_ in enumerate(self.ansifile): h=hex(_)[2:].upper() i=str(_).zfill(3) s='' if _>47 and _<127: s=chr(_) else: s='.' l=str(index).zfill(len(str(len(self.ansifile)))) if index >=n and index <=nn: print(f"{l} {i} {h} {s}") if index==nn: break ############################################################################ def printhex(self): theasc=[] thehex=[] buffer='' for _ in self.ansifile: buffer+=hex(ord(_)).upper()[2:].zfill(2) for _ in self.chunk(buffer,32): subchunks='' for i,__ in enumerate(self.chunk(_,2)): if i>0 and i%4==0: subchunks+=" " subchunks+=f'{__} ' thehex.append(subchunks.strip()) for __ in thehex: buffer='' for _ in __.split(): i=int(_,16) if i>47 and i<127: buffer+=chr(i) else: buffer+='.' theasc.append(buffer) for _ in range(len(thehex)): old=buffer buffer={thehex[_]} if not buffer == old: print(f"{hex(16 * _)[2:].zfill(8)} {thehex[_]} {theasc[_]}") ############################################################################ def hexdump(self): if self.DEBUG: print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n") self.printhex() self.codes=[] code_start=0 code_end=0 code_state=False for i,_ in enumerate(self.ansifile): if code_state==False: if _ == '\x1b': code_state=True code_start=i elif _ == '\x1a': code=self.ansifile[i:] self.codes.append([code,i,len(self.ansifile)]) else: if 64 <= ord(_) <= 126: if _ in self.commands: code_state=False code_end=i+1 code=self.ansifile[code_start:code_end] self.codes.append([code,code_start,code_end]) ############################################################################ def findall(self,s,w): return [i for i in range(len(s)) if s.startswith(w, i)] ############################################################################ def getsauce(self): SPASS='\x1b[1;31m[ SAUCE INFO FOUND ] - X: {} Y: {}\x1b[0m\n' SFAIL='\x1b[1;31m[ NO SAUCE INFO FOUND ]\x1b[0m\n' try: if self.ansifile[-129:][0] == '\x1a' \ and self.ansifile[-128:][:5] == 'SAUCE': self.ansifile_xwidth=ord(self.ansifile[-128:][96]) self.ansifile_yheight=ord(self.ansifile[-128:][98]) self.width=self.ansifile_xwidth self.height=self.ansifile_yheight print(SPASS.format(self.width,self.height)) else: print(SFAIL) except: print(SFAIL) ############################################################################ def cmpans(self,s1,s2,n1=0,n2=0): _s1=''; _s2=''; _sn1=''; _sn2='' _s1=self.stripcodes(s1) _s2=self.stripcodes(s2) if not n1 == n2: _sn1=_s1[n1:n2] _sn2=_s2[n1:n2] _sn3='' for i in range(self.width): try: if ord(_sn1[i]) == ord(_sn2[i]): _sn3+='\x1b[32m0\x1b[0m' else: _sn3+='\x1b[31m1\x1b[0m' except Exception as e: print(e) self.cmps.append(f'{_sn1}\n{_sn2}\n{_sn3}') n1+=self.width n2+=self.width ############################################################################ def chunk(self,s,n): return [s[i:i+n] for i in range(0,len(s),n)] ############################################################################ def stripcodes(self,s): buffer=s code_start=0 code_end=0 code_state=False for i,_ in enumerate(s): if code_state==False: if _ == '\x1b': code_state=True code_start=i else: if 64 <= ord(_) <= 126: if _ in self.commands: code_state=False code_end=i+1 code=s[code_start:code_end] buffer=buffer.replace(code,'') return buffer ############################################################################ def rgb(self,t='',r=0,g=0,b=0): """colorize text with rgb values""" return f"\033[38;2;{r};{g};{b}m{t}\033[38;2;255;255;255m" ############################################################################ def vga(self,t='',i=0): """colorize text using vga color set""" vga = [ '#000000','#aa0000','#00aa00','#aa5500', '#0000aa','#aa00aa','#00aaaa','#aaaaaa', '#555555','#ff5555','#55ff55','#ffff55', '#5555ff','#ff55ff','#55ffff','#ffffff', ] try: r=int(vga[i][1:][0:2],16) g=int(vga[i][1:][2:4],16) b=int(vga[i][1:][4:6],16) except: r,g,b=0,0,0 return f"\033[38;2;{r};{g};{b}m{t}\033[38;2;255;255;255m" ############################################################################ def invert_dict(self,d): return {v: k for k, v in d.items()} ############################################################################ def boot(self): self.getsauce() self.hexdump() op=[] fb=self.ansifile xnew=0 xold=0 for _ in self.codes: xnew=_[1] distance=xnew-xold if not distance == 0: gap=fb[xold:xold+distance] op.append(gap) op.append(_[0]) xold=_[2] optype=[] for i,_op in enumerate(op): if _op.startswith('\x1b'): if _op.endswith('m'): optype.append(2) elif _op.endswith('C'): optype.append(3) else: optype.append(0) elif _op.startswith('\x1a'): optype.append(4) else: optype.append(1) offset=0 offsets=[] processed=[] uniqued=[] uniques=[] processing='' for i,_optype in enumerate(optype): if _optype==2: processing+=op[i] offset+=len(op[i]) elif _optype==3: count=int(op[i].split('[')[1].split('C')[0]) processing+=' '*count elif _optype==1: processing+=op[i] _bseq='\r\n' _xpos=processing.find(_bseq) if not _xpos == -1: uniques.append(_bseq) uniques.append(_xpos) processing=processing.replace(_bseq,'',1) gaps=self.width-len(self.stripcodes(processing)) processing+=' '*int(gaps) if len(processing)-offset > self.width: while len(processing)-offset > self.width: deconcatenate=processing[0:self.width+offset] processed.append(deconcatenate) if len(uniques) < 2: uniqued.append('') else: uniqued.append(uniques) uniqued.append(uniques) uniques=[] offsets.append(offset) processing=processing.replace(deconcatenate,'',1) offset=0 if self.DEBUG: print("\n\x1b[1;31m[ COMPARE LINE AGAINST REFERENCE ]\x1b[0m\n") _r=reference.strip().splitlines() for i,_ in enumerate(processed): s1=_r[i] s2=_ self.cmpans(s1=s1,s2=s2,n1=0,n2=self.width) if i >= 128: break for i,_ in enumerate(self.cmps): print(_+f' - {str(i).zfill(4)}') if self.DEBUG: print("\n \x1b[1;31m[ PROCESSED ANSI ]\x1b[0m\n") for _ in processed: print(_) print('\n\x1b[1;31m[ DR0P ]\x1b[0m') ########################################################################### MAIN if __name__ == "__main__": d=dr1p4ns1(ansifile='work.ans',width=80,debug=False) ############################################################################ EOF