commit 1edfd60dbdd294a4258801e43b1e76b42b3ddcef Author: Uyanide Date: Sat Jun 14 20:26:14 2025 +0200 first commit diff --git a/.clang-format b/.clang-format new file mode 100755 index 0000000..619bea6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,64 @@ +BasedOnStyle: Google + +AccessModifierOffset: -2 + +AlignConsecutiveAssignments: true + +AllowAllArgumentsOnNextLine: false + +AllowAllParametersOfDeclarationOnNextLine: false + +AllowShortBlocksOnASingleLine: Empty + +AllowShortCaseLabelsOnASingleLine: true + +AllowShortFunctionsOnASingleLine: Inline + +AllowShortLambdasOnASingleLine: All + +BreakAfterReturnType: Automatic + +BinPackArguments: false + +BinPackParameters: false + +ColumnLimit: 0 + +CompactNamespaces: false + +ContinuationIndentWidth: 4 + +Cpp11BracedListStyle: true + +EmptyLineBeforeAccessModifier: LogicalBlock + +FixNamespaceComments: true + +IncludeBlocks: Regroup +SortIncludes: true +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 + +IndentWidth: 4 + +KeepEmptyLines: + AtEndOfFile: true + AtStartOfBlock: true + AtStartOfFile: false + +MaxEmptyLinesToKeep: 1 + +TabWidth: 4 + +UseTab: Never + +SeparateDefinitionBlocks: Always + +QualifierAlignment: Left diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07107ca --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +sync_cachy.sh \ No newline at end of file diff --git a/.memo/fish-keybindings b/.memo/fish-keybindings new file mode 100644 index 0000000..810e78b --- /dev/null +++ b/.memo/fish-keybindings @@ -0,0 +1,14 @@ +C a 移动行首 +C e 移动行末 + +C f 字符前移 +C b 字符后移 +A f 单词前移 +A b 单词后移 + +C u 从光标位置到行首删除 +C k 从光标位置到行末删除 + +A c 大小写切换 + +A s sudo diff --git a/.memo/git-msg b/.memo/git-msg new file mode 100644 index 0000000..ee7cb81 --- /dev/null +++ b/.memo/git-msg @@ -0,0 +1,17 @@ +✨ feat: ✨ 新功能 +🐛 fix: 🐛 修复 bug +📝 docs: 📝 文档更新 +🎨 style: 🎨 代码格式(不影响功能) +♻️ refactor: ♻️ 代码重构 +🚀 perf: 🚀 性能优化 +✅ test: ✅ 添加测试 +🔧 chore: 🔧 杂务(构建过程或辅助工具的变动) +🔒 security: 🔒 安全性改进 +⬆️ upgrade: ⬆️ 升级依赖 +⬇️ downgrade: ⬇️ 降级依赖 +🚨 lint: 🚨 修复 linter 警告 +💄 ui: 💄 更新 UI 和样式文件 +🚧 wip: 🚧 工作进行中 +🔥 remove: 🔥 删除代码或文件 +🔀 merge: 🔀 合并分支 +🔖 release: 🔖 发布/版本标签 diff --git a/.memo/hyprland-ricing b/.memo/hyprland-ricing new file mode 100644 index 0000000..cb94e0c --- /dev/null +++ b/.memo/hyprland-ricing @@ -0,0 +1,40 @@ +安装的东西: + +hyprland +hyprpaper +hypridle +hyprlock +hyprshot +hyprland-plugin-hyprexpo # 类似监控室老大爷视角 :/ + +xdg-desktop-portal-hyprland +xdg-desktop-portal-gnome +xdg-desktop-portal-gtk + +mako # notification daemon +gnome-keyring +wl-clipboard +network-manager-applet # nm-applet +slurp # region selector +wf-recorder # screen recorder +brightnessctl + +waybar +wlogout +fuzzel +hyprpicker +cliphist +blueman # bluetooth GUI & applet +pavucontrol +easyeffects +nautilus # dolphin doesn't look nice in Hyprland +gnome-text-editor # neither does kwrite, even with Kvantum +btop # system monitor + +ttf-font-awesome +nwg-look # theme of GTK apps +catppuccin-gtk-theme-mocha # theme of GTK apps +polkit-gnome + +kitty # normal terminal +ghostty # floating terminal, for btop for example \ No newline at end of file diff --git a/.memo/nvidia-prime-offload b/.memo/nvidia-prime-offload new file mode 100644 index 0000000..4bee9f4 --- /dev/null +++ b/.memo/nvidia-prime-offload @@ -0,0 +1,3 @@ +__NV_PRIME_RENDER_OFFLOAD=1 +__GLX_VENDOR_LIBRARY_NAME=nvidia +__VK_LAYER_NV_optimus=NVIDIA_only diff --git a/.memo/shell.md b/.memo/shell.md new file mode 100644 index 0000000..2bb6805 --- /dev/null +++ b/.memo/shell.md @@ -0,0 +1,32 @@ +## 登陆 shell + +登陆 shell 是指用户通过终端登录系统时启动的 shell,通常是用户登录时执行的第一个 shell,可以通过`grep "^$(whoami):" /etc/passwd`查看。 + +登陆 shell 为 bash 时,在登陆时会检索 + +- `/etc/profile` + +并加载,并会加载以下第一个存在的用户配置文件: + +- `~/.bash_profile` +- `~/.bash_login` +- `~/.profile` + +所有全局环境变量以及其他非交互配置(如 ssh-agent)都可以写进这些文件。 + +## 非登陆 shell + +非登陆 shell 是指用户在已经登录的情况下启动的 shell,通常是通过终端仿真器或其他方式打开的 shell。 + +非登陆 shell 为 bash 时,会先加载`/etc/bash.bashrc`,然后加载用户的`~/.bashrc`文件。 + +对于非登陆 shell 为 fish 的情况,则会先加载`/etc/fish/conf.d`以及`/etc/fish/config.fish`, +然后加载用户的`~/.config/fish/conf.d`以及`~/.config/fish/config.fish`。 + +非登陆 shell 会继承登陆 shell 的环境变量,但不会加载登陆 shell 的配置文件。 + +## 当前做法 + +桌面端将登陆 shell 设置为 bash,对于终端模拟器显式指定 shell 为 fish,并禁用 conf.d 目录下的配置文件。 + +服务器端同样将登陆 shell 设置为 bash,并在.bashrc 中启动 fish,同样不使用 conf.d 目录下的配置文件。 diff --git a/.memo/swapfile-btrfs.md b/.memo/swapfile-btrfs.md new file mode 100644 index 0000000..47622d3 --- /dev/null +++ b/.memo/swapfile-btrfs.md @@ -0,0 +1,52 @@ +在 btrfs 分区下使用 swapfile 创建虚拟内存: + +1. 创建 swap 子卷 (假定已经挂载到 /mnt): + +```bash +btrfs subvolume create /mnt/@swap +``` + +2. 创建 swap 文件: + +```bash +touch /mnt/@swap/swapfile +``` + +3. 设置 COW 禁用属性: + +```bash +chattr +C /mnt/@swap/swapfile +``` + +4. 设置 swap 文件大小(例如 16GB): + +```bash +dd if=/dev/zero of=/mnt/@swap/swapfile bs=1M count=16384 oflag=direct +# 可检查属性,确保有 C: +lsattr /mnt/@swap/swapfile +``` + +5. 设置 swap 文件权限: + +```bash +chmod 600 /mnt/@swap/swapfile +``` + +6. 启用 swap 文件: + +```bash +mkswap /mnt/@swap/swapfile +swapon /mnt/@swap/swapfile +# 可检查 swap 状态 +swapon --show +``` + +7. 修改 `/etc/fstab` 以自动挂载 swap 文件: + +```conf +# Btrfs @swap subvolume +UUID={btrfs-uuid} /swap btrfs subvol=@swap,defaults,noatime 0 0 + +# Swap file +/swap/swapfile none swap sw 0 0 +``` diff --git a/.memo/tailscale-nfs b/.memo/tailscale-nfs new file mode 100644 index 0000000..6227feb --- /dev/null +++ b/.memo/tailscale-nfs @@ -0,0 +1,33 @@ +1. tailscale + +Tailscale 基于 WireGuard 实现 NAT 穿透。 + +安装: + 1) General: curl -fsSL https://tailscale.com/install.sh | sh + 2) Archlinux: yay -S tailscale + +安装后: + 1) systemctl 启动 tailscaled 服务; + 2) sudo tailscale up 启动 tailscale; + 3) sudo tailscale status 查看状态 / 网站 https://login.tailscale.com/admin/machines。 + + +2. nfs + +NFS 允许将文件系统挂载到远程主机上。 + +安装: + 1) 服务端: nfs-utils (Archlinux) + 2) 客户端: nfs-common (ubuntu) + +安装后: + 1) 服务端: + a)echo "/path/to/share *(rw,no_subtree_check,async)" | sudo tee -a /etc/exports + b) systemctl 启动 nfs-server 服务 + 2) 客户端 + a) sudo mount -t nfs -o vers=4,noatime,async 100.x.y.z:/path/to/share /path/to/mount + + +3. 解除 + 1) umount即可; + 2) sudo tailscale down 关闭 tailscale。 diff --git a/.scripts/change_wallpaper.fish b/.scripts/change_wallpaper.fish new file mode 100755 index 0000000..91ffcdf --- /dev/null +++ b/.scripts/change_wallpaper.fish @@ -0,0 +1,26 @@ +#!/bin/fish + +# if the path is given as an argument, use that +if test (count $argv) -eq 1 + set image $argv[1] +else + set image (zenity --file-selection --title="Open File" --file-filter="*.jpg *.jpeg *.png") +end + +if test -z "$image" + exit 1 +end +if not test -f "$image" + notify-send "Error" "Selected file does not exist." + exit 1 +end +if string match -q "* *" "$image" + notify-send "Error" "Selected file path contains white spaces, please select a file without white spaces." + exit 1 +end + +hyprctl hyprpaper reload ,"$image" +echo "preload = $image" > ~/.config/hypr/hyprpaper.conf +echo "wallpaper = , $image" >> ~/.config/hypr/hyprpaper.conf + +notify-send "Wallpaper Changed" "Wallpaper changed to \"$image\" successfully." \ No newline at end of file diff --git a/.scripts/fuzzel-emoji b/.scripts/fuzzel-emoji new file mode 100755 index 0000000..5471269 --- /dev/null +++ b/.scripts/fuzzel-emoji @@ -0,0 +1,1874 @@ +#!/bin/bash +# https://github.com/end-4/dots-hyprland/blob/main/.local/bin/fuzzel-emoji + +if [ $? -eq 0 ] +then + sed '1,/^### DATA ###$/d' $0 | fuzzel --match-mode fzf --dmenu | cut -d ' ' -f 1 | tr -d '\n' | wl-copy +else + sed '1,/^### DATA ###$/d' $0 | fuzzel --match-mode fzf --dmenu | cut -d ' ' -f 1 | tr -d '\n' | wl-copy +fi +exit +### DATA ### +😀 grinning face face smile happy joy :D grin +😃 grinning face with big eyes face happy joy haha :D :) smile funny +😄 grinning face with smiling eyes face happy joy funny haha laugh like :D :) smile +😁 beaming face with smiling eyes face happy smile joy kawaii +😆 grinning squinting face happy joy lol satisfied haha face glad XD laugh +😅 grinning face with sweat face hot happy laugh sweat smile relief +🤣 rolling on the floor laughing face rolling floor laughing lol haha rofl +😂 face with tears of joy face cry tears weep happy happytears haha +🙂 slightly smiling face face smile +🙃 upside down face face flipped silly smile +😉 winking face face happy mischievous secret ;) smile eye +😊 smiling face with smiling eyes face smile happy flushed crush embarrassed shy joy +😇 smiling face with halo face angel heaven halo +🥰 smiling face with hearts face love like affection valentines infatuation crush hearts adore +😍 smiling face with heart eyes face love like affection valentines infatuation crush heart +🤩 star struck face smile starry eyes grinning +😘 face blowing a kiss face love like affection valentines infatuation kiss +😗 kissing face love like face 3 valentines infatuation kiss +☺️ smiling face face blush massage happiness +😚 kissing face with closed eyes face love like affection valentines infatuation kiss +😙 kissing face with smiling eyes face affection valentines infatuation kiss +😋 face savoring food happy joy tongue smile face silly yummy nom delicious savouring +😛 face with tongue face prank childish playful mischievous smile tongue +😜 winking face with tongue face prank childish playful mischievous smile wink tongue +🤪 zany face face goofy crazy +😝 squinting face with tongue face prank playful mischievous smile tongue +🤑 money mouth face face rich dollar money +🤗 hugging face face smile hug +🤭 face with hand over mouth face whoops shock surprise +🤫 shushing face face quiet shhh +🤔 thinking face face hmmm think consider +🤐 zipper mouth face face sealed zipper secret +🤨 face with raised eyebrow face distrust scepticism disapproval disbelief surprise +😐 neutral face indifference meh :| neutral +😑 expressionless face face indifferent - - meh deadpan +😶 face without mouth face hellokitty +😏 smirking face face smile mean prank smug sarcasm +😒 unamused face indifference bored straight face serious sarcasm unimpressed skeptical dubious side eye +🙄 face with rolling eyes face eyeroll frustrated +😬 grimacing face face grimace teeth +🤥 lying face face lie pinocchio +😌 relieved face face relaxed phew massage happiness +😔 pensive face face sad depressed upset +😪 sleepy face face tired rest nap +🤤 drooling face face +😴 sleeping face face tired sleepy night zzz +😷 face with medical mask face sick ill disease +🤒 face with thermometer sick temperature thermometer cold fever +🤕 face with head bandage injured clumsy bandage hurt +🤢 nauseated face face vomit gross green sick throw up ill +🤮 face vomiting face sick +🤧 sneezing face face gesundheit sneeze sick allergy +🥵 hot face face feverish heat red sweating +🥶 cold face face blue freezing frozen frostbite icicles +🥴 woozy face face dizzy intoxicated tipsy wavy +😵 dizzy face spent unconscious xox dizzy +🤯 exploding head face shocked mind blown +🤠 cowboy hat face face cowgirl hat +🥳 partying face face celebration woohoo +😎 smiling face with sunglasses face cool smile summer beach sunglass +🤓 nerd face face nerdy geek dork +🧐 face with monocle face stuffy wealthy +😕 confused face face indifference huh weird hmmm :/ +😟 worried face face concern nervous :( +🙁 slightly frowning face face frowning disappointed sad upset +☹️ frowning face face sad upset frown +😮 face with open mouth face surprise impressed wow whoa :O +😯 hushed face face woo shh +😲 astonished face face xox surprised poisoned +😳 flushed face face blush shy flattered sex +🥺 pleading face face begging mercy +😦 frowning face with open mouth face aw what +😧 anguished face face stunned nervous +😨 fearful face face scared terrified nervous oops huh +😰 anxious face with sweat face nervous sweat +😥 sad but relieved face face phew sweat nervous +😢 crying face face tears sad depressed upset :'( +😭 loudly crying face face cry tears sad upset depressed sob +😱 face screaming in fear face munch scared omg +😖 confounded face face confused sick unwell oops :S +😣 persevering face face sick no upset oops +😞 disappointed face face sad upset depressed :( +😓 downcast face with sweat face hot sad tired exercise +😩 weary face face tired sleepy sad frustrated upset +😫 tired face sick whine upset frustrated +🥱 yawning face tired sleepy +😤 face with steam from nose face gas phew proud pride +😡 pouting face angry mad hate despise +😠 angry face mad face annoyed frustrated +🤬 face with symbols on mouth face swearing cursing cussing profanity expletive +😈 smiling face with horns devil horns +👿 angry face with horns devil angry horns +💀 skull dead skeleton creepy death +☠️ skull and crossbones poison danger deadly scary death pirate evil +💩 pile of poo hankey shitface fail turd shit +🤡 clown face face +👹 ogre monster red mask halloween scary creepy devil demon japanese ogre +👺 goblin red evil mask monster scary creepy japanese goblin +👻 ghost halloween spooky scary +👽 alien UFO paul weird outer space +👾 alien monster game arcade play +🤖 robot computer machine bot +😺 grinning cat animal cats happy smile +😸 grinning cat with smiling eyes animal cats smile +😹 cat with tears of joy animal cats haha happy tears +😻 smiling cat with heart eyes animal love like affection cats valentines heart +😼 cat with wry smile animal cats smirk +😽 kissing cat animal cats kiss +🙀 weary cat animal cats munch scared scream +😿 crying cat animal tears weep sad cats upset cry +😾 pouting cat animal cats +🙈 see no evil monkey monkey animal nature haha +🙉 hear no evil monkey animal monkey nature +🙊 speak no evil monkey monkey animal nature omg +💋 kiss mark face lips love like affection valentines +💌 love letter email like affection envelope valentines +💘 heart with arrow love like heart affection valentines +💝 heart with ribbon love valentines +💖 sparkling heart love like affection valentines +💗 growing heart like love affection valentines pink +💓 beating heart love like affection valentines pink heart +💞 revolving hearts love like affection valentines +💕 two hearts love like affection valentines heart +💟 heart decoration purple-square love like +❣️ heart exclamation decoration love +💔 broken heart sad sorry break heart heartbreak +❤️ red heart love like valentines +🧡 orange heart love like affection valentines +💛 yellow heart love like affection valentines +💚 green heart love like affection valentines +💙 blue heart love like affection valentines +💜 purple heart love like affection valentines +🤎 brown heart coffee +🖤 black heart evil +🤍 white heart pure +💯 hundred points score perfect numbers century exam quiz test pass hundred +💢 anger symbol angry mad +💥 collision bomb explode explosion collision blown +💫 dizzy star sparkle shoot magic +💦 sweat droplets water drip oops +💨 dashing away wind air fast shoo fart smoke puff +🕳️ hole embarrassing +💣 bomb boom explode explosion terrorism +💬 speech balloon bubble words message talk chatting +👁️‍🗨️ eye in speech bubble info +🗨️ left speech bubble words message talk chatting +🗯️ right anger bubble caption speech thinking mad +💭 thought balloon bubble cloud speech thinking dream +💤 zzz sleepy tired dream +👋 waving hand hands gesture goodbye solong farewell hello hi palm +🤚 raised back of hand fingers raised backhand +🖐️ hand with fingers splayed hand fingers palm +✋ raised hand fingers stop highfive palm ban +🖖 vulcan salute hand fingers spock star trek +👌 ok hand fingers limbs perfect ok okay +🤏 pinching hand tiny small size +✌️ victory hand fingers ohyeah hand peace victory two +🤞 crossed fingers good lucky +🤟 love you gesture hand fingers gesture +🤘 sign of the horns hand fingers evil eye sign of horns rock on +🤙 call me hand hands gesture shaka +👈 backhand index pointing left direction fingers hand left +👉 backhand index pointing right fingers hand direction right +👆 backhand index pointing up fingers hand direction up +🖕 middle finger hand fingers rude middle flipping +👇 backhand index pointing down fingers hand direction down +☝️ index pointing up hand fingers direction up +👍 thumbs up thumbsup yes awesome good agree accept cool hand like +1 +👎 thumbs down thumbsdown no dislike hand -1 +✊ raised fist fingers hand grasp +👊 oncoming fist angry violence fist hit attack hand +🤛 left facing fist hand fistbump +🤜 right facing fist hand fistbump +👏 clapping hands hands praise applause congrats yay +🙌 raising hands gesture hooray yea celebration hands +👐 open hands fingers butterfly hands open +🤲 palms up together hands gesture cupped prayer +🤝 handshake agreement shake +🙏 folded hands please hope wish namaste highfive pray +✍️ writing hand lower left ballpoint pen stationery write compose +💅 nail polish beauty manicure finger fashion nail +🤳 selfie camera phone +💪 flexed biceps arm flex hand summer strong biceps +🦾 mechanical arm accessibility +🦿 mechanical leg accessibility +🦵 leg kick limb +🦶 foot kick stomp +👂 ear face hear sound listen +🦻 ear with hearing aid accessibility +👃 nose smell sniff +🧠 brain smart intelligent +🦷 tooth teeth dentist +🦴 bone skeleton +👀 eyes look watch stalk peek see +👁️ eye face look see watch stare +👅 tongue mouth playful +👄 mouth mouth kiss +👶 baby child boy girl toddler +🧒 child gender-neutral young +👦 boy man male guy teenager +👧 girl female woman teenager +🧑 person gender-neutral person +👱 person blond hair hairstyle +👨 man mustache father dad guy classy sir moustache +🧔 man beard person bewhiskered +👨‍🦰 man red hair hairstyle +👨‍🦱 man curly hair hairstyle +👨‍🦳 man white hair old elder +👨‍🦲 man bald hairless +👩 woman female girls lady +👩‍🦰 woman red hair hairstyle +🧑‍🦰 person red hair hairstyle +👩‍🦱 woman curly hair hairstyle +🧑‍🦱 person curly hair hairstyle +👩‍🦳 woman white hair old elder +🧑‍🦳 person white hair elder old +👩‍🦲 woman bald hairless +🧑‍🦲 person bald hairless +👱‍♀️ woman blond hair woman female girl blonde person +👱‍♂️ man blond hair man male boy blonde guy person +🧓 older person human elder senior gender-neutral +👴 old man human male men old elder senior +👵 old woman human female women lady old elder senior +🙍 person frowning worried +🙍‍♂️ man frowning male boy man sad depressed discouraged unhappy +🙍‍♀️ woman frowning female girl woman sad depressed discouraged unhappy +🙎 person pouting upset +🙎‍♂️ man pouting male boy man +🙎‍♀️ woman pouting female girl woman +🙅 person gesturing no decline +🙅‍♂️ man gesturing no male boy man nope +🙅‍♀️ woman gesturing no female girl woman nope +🙆 person gesturing ok agree +🙆‍♂️ man gesturing ok men boy male blue human man +🙆‍♀️ woman gesturing ok women girl female pink human woman +💁 person tipping hand information +💁‍♂️ man tipping hand male boy man human information +💁‍♀️ woman tipping hand female girl woman human information +🙋 person raising hand question +🙋‍♂️ man raising hand male boy man +🙋‍♀️ woman raising hand female girl woman +🧏 deaf person accessibility +🧏‍♂️ deaf man accessibility +🧏‍♀️ deaf woman accessibility +🙇 person bowing respectiful +🙇‍♂️ man bowing man male boy +🙇‍♀️ woman bowing woman female girl +🤦 person facepalming disappointed +🤦‍♂️ man facepalming man male boy disbelief +🤦‍♀️ woman facepalming woman female girl disbelief +🤷 person shrugging regardless +🤷‍♂️ man shrugging man male boy confused indifferent doubt +🤷‍♀️ woman shrugging woman female girl confused indifferent doubt +🧑‍⚕️ health worker hospital +👨‍⚕️ man health worker doctor nurse therapist healthcare man human +👩‍⚕️ woman health worker doctor nurse therapist healthcare woman human +🧑‍🎓 student learn +👨‍🎓 man student graduate man human +👩‍🎓 woman student graduate woman human +🧑‍🏫 teacher professor +👨‍🏫 man teacher instructor professor man human +👩‍🏫 woman teacher instructor professor woman human +🧑‍⚖️ judge law +👨‍⚖️ man judge justice court man human +👩‍⚖️ woman judge justice court woman human +🧑‍🌾 farmer crops +👨‍🌾 man farmer rancher gardener man human +👩‍🌾 woman farmer rancher gardener woman human +🧑‍🍳 cook food kitchen culinary +👨‍🍳 man cook chef man human +👩‍🍳 woman cook chef woman human +🧑‍🔧 mechanic worker technician +👨‍🔧 man mechanic plumber man human wrench +👩‍🔧 woman mechanic plumber woman human wrench +🧑‍🏭 factory worker labor +👨‍🏭 man factory worker assembly industrial man human +👩‍🏭 woman factory worker assembly industrial woman human +🧑‍💼 office worker business +👨‍💼 man office worker business manager man human +👩‍💼 woman office worker business manager woman human +🧑‍🔬 scientist chemistry +👨‍🔬 man scientist biologist chemist engineer physicist man human +👩‍🔬 woman scientist biologist chemist engineer physicist woman human +🧑‍💻 technologist computer +👨‍💻 man technologist coder developer engineer programmer software man human laptop computer +👩‍💻 woman technologist coder developer engineer programmer software woman human laptop computer +🧑‍🎤 singer song artist performer +👨‍🎤 man singer rockstar entertainer man human +👩‍🎤 woman singer rockstar entertainer woman human +🧑‍🎨 artist painting draw creativity +👨‍🎨 man artist painter man human +👩‍🎨 woman artist painter woman human +🧑‍✈️ pilot fly plane airplane +👨‍✈️ man pilot aviator plane man human +👩‍✈️ woman pilot aviator plane woman human +🧑‍🚀 astronaut outerspace +👨‍🚀 man astronaut space rocket man human +👩‍🚀 woman astronaut space rocket woman human +🧑‍🚒 firefighter fire +👨‍🚒 man firefighter fireman man human +👩‍🚒 woman firefighter fireman woman human +👮 police officer cop +👮‍♂️ man police officer man police law legal enforcement arrest 911 +👮‍♀️ woman police officer woman police law legal enforcement arrest 911 female +🕵️ detective human spy detective +🕵️‍♂️ man detective crime +🕵️‍♀️ woman detective human spy detective female woman +💂 guard protect +💂‍♂️ man guard uk gb british male guy royal +💂‍♀️ woman guard uk gb british female royal woman +👷 construction worker labor build +👷‍♂️ man construction worker male human wip guy build construction worker labor +👷‍♀️ woman construction worker female human wip build construction worker labor woman +🤴 prince boy man male crown royal king +👸 princess girl woman female blond crown royal queen +👳 person wearing turban headdress +👳‍♂️ man wearing turban male indian hinduism arabs +👳‍♀️ woman wearing turban female indian hinduism arabs woman +👲 man with skullcap male boy chinese +🧕 woman with headscarf female hijab mantilla tichel +🤵 man in tuxedo couple marriage wedding groom +👰 bride with veil couple marriage wedding woman bride +🤰 pregnant woman baby +🤱 breast feeding nursing baby +👼 baby angel heaven wings halo +🎅 santa claus festival man male xmas father christmas +🤶 mrs claus woman female xmas mother christmas +🦸 superhero marvel +🦸‍♂️ man superhero man male good hero superpowers +🦸‍♀️ woman superhero woman female good heroine superpowers +🦹 supervillain marvel +🦹‍♂️ man supervillain man male evil bad criminal hero superpowers +🦹‍♀️ woman supervillain woman female evil bad criminal heroine superpowers +🧙 mage magic +🧙‍♂️ man mage man male mage sorcerer +🧙‍♀️ woman mage woman female mage witch +🧚 fairy wings magical +🧚‍♂️ man fairy man male +🧚‍♀️ woman fairy woman female +🧛 vampire blood twilight +🧛‍♂️ man vampire man male dracula +🧛‍♀️ woman vampire woman female +🧜 merperson sea +🧜‍♂️ merman man male triton +🧜‍♀️ mermaid woman female merwoman ariel +🧝 elf magical +🧝‍♂️ man elf man male +🧝‍♀️ woman elf woman female +🧞 genie magical wishes +🧞‍♂️ man genie man male +🧞‍♀️ woman genie woman female +🧟 zombie dead +🧟‍♂️ man zombie man male dracula undead walking dead +🧟‍♀️ woman zombie woman female undead walking dead +💆 person getting massage relax +💆‍♂️ man getting massage male boy man head +💆‍♀️ woman getting massage female girl woman head +💇 person getting haircut hairstyle +💇‍♂️ man getting haircut male boy man +💇‍♀️ woman getting haircut female girl woman +🚶 person walking move +🚶‍♂️ man walking human feet steps +🚶‍♀️ woman walking human feet steps woman female +🧍 person standing still +🧍‍♂️ man standing still +🧍‍♀️ woman standing still +🧎 person kneeling pray respectful +🧎‍♂️ man kneeling pray respectful +🧎‍♀️ woman kneeling respectful pray +🧑‍🦯 person with probing cane blind +👨‍🦯 man with probing cane blind +👩‍🦯 woman with probing cane blind +🧑‍🦼 person in motorized wheelchair disability accessibility +👨‍🦼 man in motorized wheelchair disability accessibility +👩‍🦼 woman in motorized wheelchair disability accessibility +🧑‍🦽 person in manual wheelchair disability accessibility +👨‍🦽 man in manual wheelchair disability accessibility +👩‍🦽 woman in manual wheelchair disability accessibility +🏃 person running move +🏃‍♂️ man running man walking exercise race running +🏃‍♀️ woman running woman walking exercise race running female +💃 woman dancing female girl woman fun +🕺 man dancing male boy fun dancer +🕴️ man in suit levitating suit business levitate hover jump +👯 people with bunny ears perform costume +👯‍♂️ men with bunny ears male bunny men boys +👯‍♀️ women with bunny ears female bunny women girls +🧖 person in steamy room relax spa +🧖‍♂️ man in steamy room male man spa steamroom sauna +🧖‍♀️ woman in steamy room female woman spa steamroom sauna +🧗 person climbing sport +🧗‍♂️ man climbing sports hobby man male rock +🧗‍♀️ woman climbing sports hobby woman female rock +🤺 person fencing sports fencing sword +🏇 horse racing animal betting competition gambling luck +⛷️ skier sports winter snow +🏂 snowboarder sports winter +🏌️ person golfing sports business +🏌️‍♂️ man golfing sport +🏌️‍♀️ woman golfing sports business woman female +🏄 person surfing sport sea +🏄‍♂️ man surfing sports ocean sea summer beach +🏄‍♀️ woman surfing sports ocean sea summer beach woman female +🚣 person rowing boat sport move +🚣‍♂️ man rowing boat sports hobby water ship +🚣‍♀️ woman rowing boat sports hobby water ship woman female +🏊 person swimming sport pool +🏊‍♂️ man swimming sports exercise human athlete water summer +🏊‍♀️ woman swimming sports exercise human athlete water summer woman female +⛹️ person bouncing ball sports human +⛹️‍♂️ man bouncing ball sport +⛹️‍♀️ woman bouncing ball sports human woman female +🏋️ person lifting weights sports training exercise +🏋️‍♂️ man lifting weights sport +🏋️‍♀️ woman lifting weights sports training exercise woman female +🚴 person biking sport move +🚴‍♂️ man biking sports bike exercise hipster +🚴‍♀️ woman biking sports bike exercise hipster woman female +🚵 person mountain biking sport move +🚵‍♂️ man mountain biking transportation sports human race bike +🚵‍♀️ woman mountain biking transportation sports human race bike woman female +🤸 person cartwheeling sport gymnastic +🤸‍♂️ man cartwheeling gymnastics +🤸‍♀️ woman cartwheeling gymnastics +🤼 people wrestling sport +🤼‍♂️ men wrestling sports wrestlers +🤼‍♀️ women wrestling sports wrestlers +🤽 person playing water polo sport +🤽‍♂️ man playing water polo sports pool +🤽‍♀️ woman playing water polo sports pool +🤾 person playing handball sport +🤾‍♂️ man playing handball sports +🤾‍♀️ woman playing handball sports +🤹 person juggling performance balance +🤹‍♂️ man juggling juggle balance skill multitask +🤹‍♀️ woman juggling juggle balance skill multitask +🧘 person in lotus position meditate +🧘‍♂️ man in lotus position man male meditation yoga serenity zen mindfulness +🧘‍♀️ woman in lotus position woman female meditation yoga serenity zen mindfulness +🛀 person taking bath clean shower bathroom +🛌 person in bed bed rest +🧑‍🤝‍🧑 people holding hands friendship +👭 women holding hands pair friendship couple love like female people human +👫 woman and man holding hands pair people human love date dating like affection valentines marriage +👬 men holding hands pair couple love like bromance friendship people human +💏 kiss pair valentines love like dating marriage +👩‍❤️‍💋‍👨 kiss woman man love +👨‍❤️‍💋‍👨 kiss man man pair valentines love like dating marriage +👩‍❤️‍💋‍👩 kiss woman woman pair valentines love like dating marriage +💑 couple with heart pair love like affection human dating valentines marriage +👩‍❤️‍👨 couple with heart woman man love +👨‍❤️‍👨 couple with heart man man pair love like affection human dating valentines marriage +👩‍❤️‍👩 couple with heart woman woman pair love like affection human dating valentines marriage +👪 family home parents child mom dad father mother people human +👨‍👩‍👦 family man woman boy love +👨‍👩‍👧 family man woman girl home parents people human child +👨‍👩‍👧‍👦 family man woman girl boy home parents people human children +👨‍👩‍👦‍👦 family man woman boy boy home parents people human children +👨‍👩‍👧‍👧 family man woman girl girl home parents people human children +👨‍👨‍👦 family man man boy home parents people human children +👨‍👨‍👧 family man man girl home parents people human children +👨‍👨‍👧‍👦 family man man girl boy home parents people human children +👨‍👨‍👦‍👦 family man man boy boy home parents people human children +👨‍👨‍👧‍👧 family man man girl girl home parents people human children +👩‍👩‍👦 family woman woman boy home parents people human children +👩‍👩‍👧 family woman woman girl home parents people human children +👩‍👩‍👧‍👦 family woman woman girl boy home parents people human children +👩‍👩‍👦‍👦 family woman woman boy boy home parents people human children +👩‍👩‍👧‍👧 family woman woman girl girl home parents people human children +👨‍👦 family man boy home parent people human child +👨‍👦‍👦 family man boy boy home parent people human children +👨‍👧 family man girl home parent people human child +👨‍👧‍👦 family man girl boy home parent people human children +👨‍👧‍👧 family man girl girl home parent people human children +👩‍👦 family woman boy home parent people human child +👩‍👦‍👦 family woman boy boy home parent people human children +👩‍👧 family woman girl home parent people human child +👩‍👧‍👦 family woman girl boy home parent people human children +👩‍👧‍👧 family woman girl girl home parent people human children +🗣️ speaking head user person human sing say talk +👤 bust in silhouette user person human +👥 busts in silhouette user person human group team +👣 footprints feet tracking walking beach +🐵 monkey face animal nature circus +🐒 monkey animal nature banana circus +🦍 gorilla animal nature circus +🦧 orangutan animal +🐶 dog face animal friend nature woof puppy pet faithful +🐕 dog animal nature friend doge pet faithful +🦮 guide dog animal blind +🐕‍🦺 service dog blind animal +🐩 poodle dog animal 101 nature pet +🐺 wolf animal nature wild +🦊 fox animal nature face +🦝 raccoon animal nature +🐱 cat face animal meow nature pet kitten +🐈 cat animal meow pet cats +🦁 lion animal nature +🐯 tiger face animal cat danger wild nature roar +🐅 tiger animal nature roar +🐆 leopard animal nature +🐴 horse face animal brown nature +🐎 horse animal gamble luck +🦄 unicorn animal nature mystical +🦓 zebra animal nature stripes safari +🦌 deer animal nature horns venison +🐮 cow face beef ox animal nature moo milk +🐂 ox animal cow beef +🐃 water buffalo animal nature ox cow +🐄 cow beef ox animal nature moo milk +🐷 pig face animal oink nature +🐖 pig animal nature +🐗 boar animal nature +🐽 pig nose animal oink +🐏 ram animal sheep nature +🐑 ewe animal nature wool shipit +🐐 goat animal nature +🐪 camel animal hot desert hump +🐫 two hump camel animal nature hot desert hump +🦙 llama animal nature alpaca +🦒 giraffe animal nature spots safari +🐘 elephant animal nature nose th circus +🦏 rhinoceros animal nature horn +🦛 hippopotamus animal nature +🐭 mouse face animal nature cheese wedge rodent +🐁 mouse animal nature rodent +🐀 rat animal mouse rodent +🐹 hamster animal nature +🐰 rabbit face animal nature pet spring magic bunny +🐇 rabbit animal nature pet magic spring +🐿️ chipmunk animal nature rodent squirrel +🦔 hedgehog animal nature spiny +🦇 bat animal nature blind vampire +🐻 bear animal nature wild +🐨 koala animal nature +🐼 panda animal nature panda +🦥 sloth animal +🦦 otter animal +🦨 skunk animal +🦘 kangaroo animal nature australia joey hop marsupial +🦡 badger animal nature honey +🐾 paw prints animal tracking footprints dog cat pet feet +🦃 turkey animal bird +🐔 chicken animal cluck nature bird +🐓 rooster animal nature chicken +🐣 hatching chick animal chicken egg born baby bird +🐤 baby chick animal chicken bird +🐥 front facing baby chick animal chicken baby bird +🐦 bird animal nature fly tweet spring +🐧 penguin animal nature +🕊️ dove animal bird +🦅 eagle animal nature bird +🦆 duck animal nature bird mallard +🦢 swan animal nature bird +🦉 owl animal nature bird hoot +🦩 flamingo animal +🦚 peacock animal nature peahen bird +🦜 parrot animal nature bird pirate talk +🐸 frog animal nature croak toad +🐊 crocodile animal nature reptile lizard alligator +🐢 turtle animal slow nature tortoise +🦎 lizard animal nature reptile +🐍 snake animal evil nature hiss python +🐲 dragon face animal myth nature chinese green +🐉 dragon animal myth nature chinese green +🦕 sauropod animal nature dinosaur brachiosaurus brontosaurus diplodocus extinct +🦖 t rex animal nature dinosaur tyrannosaurus extinct +🐳 spouting whale animal nature sea ocean +🐋 whale animal nature sea ocean +🐬 dolphin animal nature fish sea ocean flipper fins beach +🐟 fish animal food nature +🐠 tropical fish animal swim ocean beach nemo +🐡 blowfish animal nature food sea ocean +🦈 shark animal nature fish sea ocean jaws fins beach +🐙 octopus animal creature ocean sea nature beach +🐚 spiral shell nature sea beach +🐌 snail slow animal shell +🦋 butterfly animal insect nature caterpillar +🐛 bug animal insect nature worm +🐜 ant animal insect nature bug +🐝 honeybee animal insect nature bug spring honey +🐞 lady beetle animal insect nature ladybug +🦗 cricket animal cricket chirp +🕷️ spider animal arachnid +🕸️ spider web animal insect arachnid silk +🦂 scorpion animal arachnid +🦟 mosquito animal nature insect malaria +🦠 microbe amoeba bacteria germs virus +💐 bouquet flowers nature spring +🌸 cherry blossom nature plant spring flower +💮 white flower japanese spring +🏵️ rosette flower decoration military +🌹 rose flowers valentines love spring +🥀 wilted flower plant nature flower +🌺 hibiscus plant vegetable flowers beach +🌻 sunflower nature plant fall +🌼 blossom nature flowers yellow +🌷 tulip flowers plant nature summer spring +🌱 seedling plant nature grass lawn spring +🌲 evergreen tree plant nature +🌳 deciduous tree plant nature +🌴 palm tree plant vegetable nature summer beach mojito tropical +🌵 cactus vegetable plant nature +🌾 sheaf of rice nature plant +🌿 herb vegetable plant medicine weed grass lawn +☘️ shamrock vegetable plant nature irish clover +🍀 four leaf clover vegetable plant nature lucky irish +🍁 maple leaf nature plant vegetable ca fall +🍂 fallen leaf nature plant vegetable leaves +🍃 leaf fluttering in wind nature plant tree vegetable grass lawn spring +🍇 grapes fruit food wine +🍈 melon fruit nature food +🍉 watermelon fruit food picnic summer +🍊 tangerine food fruit nature orange +🍋 lemon fruit nature +🍌 banana fruit food monkey +🍍 pineapple fruit nature food +🥭 mango fruit food tropical +🍎 red apple fruit mac school +🍏 green apple fruit nature +🍐 pear fruit nature food +🍑 peach fruit nature food +🍒 cherries food fruit +🍓 strawberry fruit food nature +🥝 kiwi fruit fruit food +🍅 tomato fruit vegetable nature food +🥥 coconut fruit nature food palm +🥑 avocado fruit food +🍆 eggplant vegetable nature food aubergine +🥔 potato food tuber vegatable starch +🥕 carrot vegetable food orange +🌽 ear of corn food vegetable plant +🌶️ hot pepper food spicy chilli chili +🥒 cucumber fruit food pickle +🥬 leafy green food vegetable plant bok choy cabbage kale lettuce +🥦 broccoli fruit food vegetable +🧄 garlic food spice cook +🧅 onion cook food spice +🍄 mushroom plant vegetable +🥜 peanuts food nut +🌰 chestnut food squirrel +🍞 bread food wheat breakfast toast +🥐 croissant food bread french +🥖 baguette bread food bread french +🥨 pretzel food bread twisted +🥯 bagel food bread bakery schmear +🥞 pancakes food breakfast flapjacks hotcakes +🧇 waffle food breakfast +🧀 cheese wedge food chadder +🍖 meat on bone good food drumstick +🍗 poultry leg food meat drumstick bird chicken turkey +🥩 cut of meat food cow meat cut chop lambchop porkchop +🥓 bacon food breakfast pork pig meat +🍔 hamburger meat fast food beef cheeseburger mcdonalds burger king +🍟 french fries chips snack fast food +🍕 pizza food party +🌭 hot dog food frankfurter +🥪 sandwich food lunch bread +🌮 taco food mexican +🌯 burrito food mexican +🥙 stuffed flatbread food flatbread stuffed gyro +🧆 falafel food +🥚 egg food chicken breakfast +🍳 cooking food breakfast kitchen egg +🥘 shallow pan of food food cooking casserole paella +🍲 pot of food food meat soup +🥣 bowl with spoon food breakfast cereal oatmeal porridge +🥗 green salad food healthy lettuce +🍿 popcorn food movie theater films snack +🧈 butter food cook +🧂 salt condiment shaker +🥫 canned food food soup +🍱 bento box food japanese box +🍘 rice cracker food japanese +🍙 rice ball food japanese +🍚 cooked rice food china asian +🍛 curry rice food spicy hot indian +🍜 steaming bowl food japanese noodle chopsticks +🍝 spaghetti food italian noodle +🍠 roasted sweet potato food nature +🍢 oden food japanese +🍣 sushi food fish japanese rice +🍤 fried shrimp food animal appetizer summer +🍥 fish cake with swirl food japan sea beach narutomaki pink swirl kamaboko surimi ramen +🥮 moon cake food autumn +🍡 dango food dessert sweet japanese barbecue meat +🥟 dumpling food empanada pierogi potsticker +🥠 fortune cookie food prophecy +🥡 takeout box food leftovers +🦀 crab animal crustacean +🦞 lobster animal nature bisque claws seafood +🦐 shrimp animal ocean nature seafood +🦑 squid animal nature ocean sea +🦪 oyster food +🍦 soft ice cream food hot dessert summer +🍧 shaved ice hot dessert summer +🍨 ice cream food hot dessert +🍩 doughnut food dessert snack sweet donut +🍪 cookie food snack oreo chocolate sweet dessert +🎂 birthday cake food dessert cake +🍰 shortcake food dessert +🧁 cupcake food dessert bakery sweet +🥧 pie food dessert pastry +🍫 chocolate bar food snack dessert sweet +🍬 candy snack dessert sweet lolly +🍭 lollipop food snack candy sweet +🍮 custard dessert food +🍯 honey pot bees sweet kitchen +🍼 baby bottle food container milk +🥛 glass of milk beverage drink cow +☕ hot beverage beverage caffeine latte espresso coffee +🍵 teacup without handle drink bowl breakfast green british +🍶 sake wine drink drunk beverage japanese alcohol booze +🍾 bottle with popping cork drink wine bottle celebration +🍷 wine glass drink beverage drunk alcohol booze +🍸 cocktail glass drink drunk alcohol beverage booze mojito +🍹 tropical drink beverage cocktail summer beach alcohol booze mojito +🍺 beer mug relax beverage drink drunk party pub summer alcohol booze +🍻 clinking beer mugs relax beverage drink drunk party pub summer alcohol booze +🥂 clinking glasses beverage drink party alcohol celebrate cheers wine champagne toast +🥃 tumbler glass drink beverage drunk alcohol liquor booze bourbon scotch whisky glass shot +🥤 cup with straw drink soda +🧃 beverage box drink +🧉 mate drink tea beverage +🧊 ice water cold +🥢 chopsticks food +🍽️ fork and knife with plate food eat meal lunch dinner restaurant +🍴 fork and knife cutlery kitchen +🥄 spoon cutlery kitchen tableware +🔪 kitchen knife knife blade cutlery kitchen weapon +🏺 amphora vase jar +🌍 globe showing europe africa globe world international +🌎 globe showing americas globe world USA international +🌏 globe showing asia australia globe world east international +🌐 globe with meridians earth international world internet interweb i18n +🗺️ world map location direction +🗾 map of japan nation country japanese asia +🧭 compass magnetic navigation orienteering +🏔️ snow capped mountain photo nature environment winter cold +⛰️ mountain photo nature environment +🌋 volcano photo nature disaster +🗻 mount fuji photo mountain nature japanese +🏕️ camping photo outdoors tent +🏖️ beach with umbrella weather summer sunny sand mojito +🏜️ desert photo warm saharah +🏝️ desert island photo tropical mojito +🏞️ national park photo environment nature +🏟️ stadium photo place sports concert venue +🏛️ classical building art culture history +🏗️ building construction wip working progress +🧱 brick bricks +🏘️ houses buildings photo +🏚️ derelict house abandon evict broken building +🏠 house building home +🏡 house with garden home plant nature +🏢 office building building bureau work +🏣 japanese post office building envelope communication +🏤 post office building email +🏥 hospital building health surgery doctor +🏦 bank building money sales cash business enterprise +🏨 hotel building accomodation checkin +🏩 love hotel like affection dating +🏪 convenience store building shopping groceries +🏫 school building student education learn teach +🏬 department store building shopping mall +🏭 factory building industry pollution smoke +🏯 japanese castle photo building +🏰 castle building royalty history +💒 wedding love like affection couple marriage bride groom +🗼 tokyo tower photo japanese +🗽 statue of liberty american newyork +⛪ church building religion christ +🕌 mosque islam worship minaret +🛕 hindu temple religion +🕍 synagogue judaism worship temple jewish +⛩️ shinto shrine temple japan kyoto +🕋 kaaba mecca mosque islam +⛲ fountain photo summer water fresh +⛺ tent photo camping outdoors +🌁 foggy photo mountain +🌃 night with stars evening city downtown +🏙️ cityscape photo night life urban +🌄 sunrise over mountains view vacation photo +🌅 sunrise morning view vacation photo +🌆 cityscape at dusk photo evening sky buildings +🌇 sunset photo good morning dawn +🌉 bridge at night photo sanfrancisco +♨️ hot springs bath warm relax +🎠 carousel horse photo carnival +🎡 ferris wheel photo carnival londoneye +🎢 roller coaster carnival playground photo fun +💈 barber pole hair salon style +🎪 circus tent festival carnival party +🚂 locomotive transportation vehicle train +🚃 railway car transportation vehicle +🚄 high speed train transportation vehicle +🚅 bullet train transportation vehicle speed fast public travel +🚆 train transportation vehicle +🚇 metro transportation blue-square mrt underground tube +🚈 light rail transportation vehicle +🚉 station transportation vehicle public +🚊 tram transportation vehicle +🚝 monorail transportation vehicle +🚞 mountain railway transportation vehicle +🚋 tram car transportation vehicle carriage public travel +🚌 bus car vehicle transportation +🚍 oncoming bus vehicle transportation +🚎 trolleybus bart transportation vehicle +🚐 minibus vehicle car transportation +🚑 ambulance health 911 hospital +🚒 fire engine transportation cars vehicle +🚓 police car vehicle cars transportation law legal enforcement +🚔 oncoming police car vehicle law legal enforcement 911 +🚕 taxi uber vehicle cars transportation +🚖 oncoming taxi vehicle cars uber +🚗 automobile red transportation vehicle +🚘 oncoming automobile car vehicle transportation +🚙 sport utility vehicle transportation vehicle +🚚 delivery truck cars transportation +🚛 articulated lorry vehicle cars transportation express +🚜 tractor vehicle car farming agriculture +🏎️ racing car sports race fast formula f1 +🏍️ motorcycle race sports fast +🛵 motor scooter vehicle vespa sasha +🦽 manual wheelchair accessibility +🦼 motorized wheelchair accessibility +🛺 auto rickshaw move transportation +🚲 bicycle sports bicycle exercise hipster +🛴 kick scooter vehicle kick razor +🛹 skateboard board +🚏 bus stop transportation wait +🛣️ motorway road cupertino interstate highway +🛤️ railway track train transportation +🛢️ oil drum barrell +⛽ fuel pump gas station petroleum +🚨 police car light police ambulance 911 emergency alert error pinged law legal +🚥 horizontal traffic light transportation signal +🚦 vertical traffic light transportation driving +🛑 stop sign stop +🚧 construction wip progress caution warning +⚓ anchor ship ferry sea boat +⛵ sailboat ship summer transportation water sailing +🛶 canoe boat paddle water ship +🚤 speedboat ship transportation vehicle summer +🛳️ passenger ship yacht cruise ferry +⛴️ ferry boat ship yacht +🛥️ motor boat ship +🚢 ship transportation titanic deploy +✈️ airplane vehicle transportation flight fly +🛩️ small airplane flight transportation fly vehicle +🛫 airplane departure airport flight landing +🛬 airplane arrival airport flight boarding +🪂 parachute fly glide +💺 seat sit airplane transport bus flight fly +🚁 helicopter transportation vehicle fly +🚟 suspension railway vehicle transportation +🚠 mountain cableway transportation vehicle ski +🚡 aerial tramway transportation vehicle ski +🛰️ satellite communication gps orbit spaceflight NASA ISS +🚀 rocket launch ship staffmode NASA outer space outer space fly +🛸 flying saucer transportation vehicle ufo +🛎️ bellhop bell service +🧳 luggage packing travel +⌛ hourglass done time clock oldschool limit exam quiz test +⏳ hourglass not done oldschool time countdown +⌚ watch time accessories +⏰ alarm clock time wake +⏱️ stopwatch time deadline +⏲️ timer clock alarm +🕰️ mantelpiece clock time +🕛 twelve o clock time noon midnight midday late early schedule +🕧 twelve thirty time late early schedule +🕐 one o clock time late early schedule +🕜 one thirty time late early schedule +🕑 two o clock time late early schedule +🕝 two thirty time late early schedule +🕒 three o clock time late early schedule +🕞 three thirty time late early schedule +🕓 four o clock time late early schedule +🕟 four thirty time late early schedule +🕔 five o clock time late early schedule +🕠 five thirty time late early schedule +🕕 six o clock time late early schedule dawn dusk +🕡 six thirty time late early schedule +🕖 seven o clock time late early schedule +🕢 seven thirty time late early schedule +🕗 eight o clock time late early schedule +🕣 eight thirty time late early schedule +🕘 nine o clock time late early schedule +🕤 nine thirty time late early schedule +🕙 ten o clock time late early schedule +🕥 ten thirty time late early schedule +🕚 eleven o clock time late early schedule +🕦 eleven thirty time late early schedule +🌑 new moon nature twilight planet space night evening sleep +🌒 waxing crescent moon nature twilight planet space night evening sleep +🌓 first quarter moon nature twilight planet space night evening sleep +🌔 waxing gibbous moon nature night sky gray twilight planet space evening sleep +🌕 full moon nature yellow twilight planet space night evening sleep +🌖 waning gibbous moon nature twilight planet space night evening sleep waxing gibbous moon +🌗 last quarter moon nature twilight planet space night evening sleep +🌘 waning crescent moon nature twilight planet space night evening sleep +🌙 crescent moon night sleep sky evening magic +🌚 new moon face nature twilight planet space night evening sleep +🌛 first quarter moon face nature twilight planet space night evening sleep +🌜 last quarter moon face nature twilight planet space night evening sleep +🌡️ thermometer weather temperature hot cold +☀️ sun weather nature brightness summer beach spring +🌝 full moon face nature twilight planet space night evening sleep +🌞 sun with face nature morning sky +🪐 ringed planet outerspace +⭐ star night yellow +🌟 glowing star night sparkle awesome good magic +🌠 shooting star night photo +🌌 milky way photo space stars +☁️ cloud weather sky +⛅ sun behind cloud weather nature cloudy morning fall spring +⛈️ cloud with lightning and rain weather lightning +🌤️ sun behind small cloud weather +🌥️ sun behind large cloud weather +🌦️ sun behind rain cloud weather +🌧️ cloud with rain weather +🌨️ cloud with snow weather +🌩️ cloud with lightning weather thunder +🌪️ tornado weather cyclone twister +🌫️ fog weather +🌬️ wind face gust air +🌀 cyclone weather swirl blue cloud vortex spiral whirlpool spin tornado hurricane typhoon +🌈 rainbow nature happy unicorn face photo sky spring +🌂 closed umbrella weather rain drizzle +☂️ umbrella weather spring +☔ umbrella with rain drops rainy weather spring +⛱️ umbrella on ground weather summer +⚡ high voltage thunder weather lightning bolt fast +❄️ snowflake winter season cold weather christmas xmas +☃️ snowman winter season cold weather christmas xmas frozen +⛄ snowman without snow winter season cold weather christmas xmas frozen without snow +☄️ comet space +🔥 fire hot cook flame +💧 droplet water drip faucet spring +🌊 water wave sea water wave nature tsunami disaster +🎃 jack o lantern halloween light pumpkin creepy fall +🎄 christmas tree festival vacation december xmas celebration +🎆 fireworks photo festival carnival congratulations +🎇 sparkler stars night shine +🧨 firecracker dynamite boom explode explosion explosive +✨ sparkles stars shine shiny cool awesome good magic +🎈 balloon party celebration birthday circus +🎉 party popper party congratulations birthday magic circus celebration tada +🎊 confetti ball festival party birthday circus +🎋 tanabata tree plant nature branch summer +🎍 pine decoration plant nature vegetable panda pine decoration +🎎 japanese dolls japanese toy kimono +🎏 carp streamer fish japanese koinobori carp banner +🎐 wind chime nature ding spring bell +🎑 moon viewing ceremony photo japan asia tsukimi +🧧 red envelope gift +🎀 ribbon decoration pink girl bowtie +🎁 wrapped gift present birthday christmas xmas +🎗️ reminder ribbon sports cause support awareness +🎟️ admission tickets sports concert entrance +🎫 ticket event concert pass +🎖️ military medal award winning army +🏆 trophy win award contest place ftw ceremony +🏅 sports medal award winning +🥇 1st place medal award winning first +🥈 2nd place medal award second +🥉 3rd place medal award third +⚽ soccer ball sports football +⚾ baseball sports balls +🥎 softball sports balls +🏀 basketball sports balls NBA +🏐 volleyball sports balls +🏈 american football sports balls NFL +🏉 rugby football sports team +🎾 tennis sports balls green +🥏 flying disc sports frisbee ultimate +🎳 bowling sports fun play +🏏 cricket game sports +🏑 field hockey sports +🏒 ice hockey sports +🥍 lacrosse sports ball stick +🏓 ping pong sports pingpong +🏸 badminton sports +🥊 boxing glove sports fighting +🥋 martial arts uniform judo karate taekwondo +🥅 goal net sports +⛳ flag in hole sports business flag hole summer +⛸️ ice skate sports +🎣 fishing pole food hobby summer +🤿 diving mask sport ocean +🎽 running shirt play pageant +🎿 skis sports winter cold snow +🛷 sled sleigh luge toboggan +🥌 curling stone sports +🎯 direct hit game play bar target bullseye +🪀 yo yo toy +🪁 kite wind fly +🎱 pool 8 ball pool hobby game luck magic +🔮 crystal ball disco party magic circus fortune teller +🧿 nazar amulet bead charm +🎮 video game play console PS4 Wii GameCube controller +🕹️ joystick game play +🎰 slot machine bet gamble vegas fruit machine luck casino +🎲 game die dice random tabletop play luck +🧩 puzzle piece interlocking puzzle piece +🧸 teddy bear plush stuffed +♠️ spade suit poker cards suits magic +♥️ heart suit poker cards magic suits +♦️ diamond suit poker cards magic suits +♣️ club suit poker cards magic suits +♟️ chess pawn expendable +🃏 joker poker cards game play magic +🀄 mahjong red dragon game play chinese kanji +🎴 flower playing cards game sunset red +🎭 performing arts acting theater drama +🖼️ framed picture photography +🎨 artist palette design paint draw colors +🧵 thread needle sewing spool string +🧶 yarn ball crochet knit +👓 glasses fashion accessories eyesight nerdy dork geek +🕶️ sunglasses face cool accessories +🥽 goggles eyes protection safety +🥼 lab coat doctor experiment scientist chemist +🦺 safety vest protection +👔 necktie shirt suitup formal fashion cloth business +👕 t shirt fashion cloth casual shirt tee +👖 jeans fashion shopping +🧣 scarf neck winter clothes +🧤 gloves hands winter clothes +🧥 coat jacket +🧦 socks stockings clothes +👗 dress clothes fashion shopping +👘 kimono dress fashion women female japanese +🥻 sari dress +🩱 one piece swimsuit fashion +🩲 briefs clothing +🩳 shorts clothing +👙 bikini swimming female woman girl fashion beach summer +👚 woman s clothes fashion shopping bags female +👛 purse fashion accessories money sales shopping +👜 handbag fashion accessory accessories shopping +👝 clutch bag bag accessories shopping +🛍️ shopping bags mall buy purchase +🎒 backpack student education bag backpack +👞 man s shoe fashion male +👟 running shoe shoes sports sneakers +🥾 hiking boot backpacking camping hiking +🥿 flat shoe ballet slip-on slipper +👠 high heeled shoe fashion shoes female pumps stiletto +👡 woman s sandal shoes fashion flip flops +🩰 ballet shoes dance +👢 woman s boot shoes fashion +👑 crown king kod leader royalty lord +👒 woman s hat fashion accessories female lady spring +🎩 top hat magic gentleman classy circus +🎓 graduation cap school college degree university graduation cap hat legal learn education +🧢 billed cap cap baseball +⛑️ rescue worker s helmet construction build +📿 prayer beads dhikr religious +💄 lipstick female girl fashion woman +💍 ring wedding propose marriage valentines diamond fashion jewelry gem engagement +💎 gem stone blue ruby diamond jewelry +🔇 muted speaker sound volume silence quiet +🔈 speaker low volume sound volume silence broadcast +🔉 speaker medium volume volume speaker broadcast +🔊 speaker high volume volume noise noisy speaker broadcast +📢 loudspeaker volume sound +📣 megaphone sound speaker volume +📯 postal horn instrument music +🔔 bell sound notification christmas xmas chime +🔕 bell with slash sound volume mute quiet silent +🎼 musical score treble clef compose +🎵 musical note score tone sound +🎶 musical notes music score +🎙️ studio microphone sing recording artist talkshow +🎚️ level slider scale +🎛️ control knobs dial +🎤 microphone sound music PA sing talkshow +🎧 headphone music score gadgets +📻 radio communication music podcast program +🎷 saxophone music instrument jazz blues +🎸 guitar music instrument +🎹 musical keyboard piano instrument compose +🎺 trumpet music brass +🎻 violin music instrument orchestra symphony +🪕 banjo music instructment +🥁 drum music instrument drumsticks snare +📱 mobile phone technology apple gadgets dial +📲 mobile phone with arrow iphone incoming +☎️ telephone technology communication dial telephone +📞 telephone receiver technology communication dial +📟 pager bbcall oldschool 90s +📠 fax machine communication technology +🔋 battery power energy sustain +🔌 electric plug charger power +💻 laptop technology laptop screen display monitor +🖥️ desktop computer technology computing screen +🖨️ printer paper ink +⌨️ keyboard technology computer type input text +🖱️ computer mouse click +🖲️ trackball technology trackpad +💽 computer disk technology record data disk 90s +💾 floppy disk oldschool technology save 90s 80s +💿 optical disk technology dvd disk disc 90s +📀 dvd cd disk disc +🧮 abacus calculation +🎥 movie camera film record +🎞️ film frames movie +📽️ film projector video tape record movie +🎬 clapper board movie film record +📺 television technology program oldschool show television +📷 camera gadgets photography +📸 camera with flash photography gadgets +📹 video camera film record +📼 videocassette record video oldschool 90s 80s +🔍 magnifying glass tilted left search zoom find detective +🔎 magnifying glass tilted right search zoom find detective +🕯️ candle fire wax +💡 light bulb light electricity idea +🔦 flashlight dark camping sight night +🏮 red paper lantern light paper halloween spooky +🪔 diya lamp lighting +📔 notebook with decorative cover classroom notes record paper study +📕 closed book read library knowledge textbook learn +📖 open book book read library knowledge literature learn study +📗 green book read library knowledge study +📘 blue book read library knowledge learn study +📙 orange book read library knowledge textbook study +📚 books literature library study +📓 notebook stationery record notes paper study +📒 ledger notes paper +📃 page with curl documents office paper +📜 scroll documents ancient history paper +📄 page facing up documents office paper information +📰 newspaper press headline +🗞️ rolled up newspaper press headline +📑 bookmark tabs favorite save order tidy +🔖 bookmark favorite label save +🏷️ label sale tag +💰 money bag dollar payment coins sale +💴 yen banknote money sales japanese dollar currency +💵 dollar banknote money sales bill currency +💶 euro banknote money sales dollar currency +💷 pound banknote british sterling money sales bills uk england currency +💸 money with wings dollar bills payment sale +💳 credit card money sales dollar bill payment shopping +🧾 receipt accounting expenses +💹 chart increasing with yen green-square graph presentation stats +💱 currency exchange money sales dollar travel +💲 heavy dollar sign money sales payment currency buck +✉️ envelope letter postal inbox communication +📧 e mail communication inbox +📨 incoming envelope email inbox +📩 envelope with arrow email communication +📤 outbox tray inbox email +📥 inbox tray email documents +📦 package mail gift cardboard box moving +📫 closed mailbox with raised flag email inbox communication +📪 closed mailbox with lowered flag email communication inbox +📬 open mailbox with raised flag email inbox communication +📭 open mailbox with lowered flag email inbox +📮 postbox email letter envelope +🗳️ ballot box with ballot election vote +✏️ pencil stationery write paper writing school study +✒️ black nib pen stationery writing write +🖋️ fountain pen stationery writing write +🖊️ pen stationery writing write +🖌️ paintbrush drawing creativity art +🖍️ crayon drawing creativity +📝 memo write documents stationery pencil paper writing legal exam quiz test study compose +💼 briefcase business documents work law legal job career +📁 file folder documents business office +📂 open file folder documents load +🗂️ card index dividers organizing business stationery +📅 calendar calendar schedule +📆 tear off calendar schedule date planning +🗒️ spiral notepad memo stationery +🗓️ spiral calendar date schedule planning +📇 card index business stationery +📈 chart increasing graph presentation stats recovery business economics money sales good success +📉 chart decreasing graph presentation stats recession business economics money sales bad failure +📊 bar chart graph presentation stats +📋 clipboard stationery documents +📌 pushpin stationery mark here +📍 round pushpin stationery location map here +📎 paperclip documents stationery +🖇️ linked paperclips documents stationery +📏 straight ruler stationery calculate length math school drawing architect sketch +📐 triangular ruler stationery math architect sketch +✂️ scissors stationery cut +🗃️ card file box business stationery +🗄️ file cabinet filing organizing +🗑️ wastebasket bin trash rubbish garbage toss +🔒 locked security password padlock +🔓 unlocked privacy security +🔏 locked with pen security secret +🔐 locked with key security privacy +🔑 key lock door password +🗝️ old key lock door password +🔨 hammer tools build create +🪓 axe tool chop cut +⛏️ pick tools dig +⚒️ hammer and pick tools build create +🛠️ hammer and wrench tools build create +🗡️ dagger weapon +⚔️ crossed swords weapon +🔫 pistol violence weapon pistol revolver +🏹 bow and arrow sports +🛡️ shield protection security +🔧 wrench tools diy ikea fix maintainer +🔩 nut and bolt handy tools fix +⚙️ gear cog +🗜️ clamp tool +⚖️ balance scale law fairness weight +🦯 probing cane accessibility +🔗 link rings url +⛓️ chains lock arrest +🧰 toolbox tools diy fix maintainer mechanic +🧲 magnet attraction magnetic +⚗️ alembic distilling science experiment chemistry +🧪 test tube chemistry experiment lab science +🧫 petri dish bacteria biology culture lab +🧬 dna biologist genetics life +🔬 microscope laboratory experiment zoomin science study +🔭 telescope stars space zoom science astronomy +📡 satellite antenna communication future radio space +💉 syringe health hospital drugs blood medicine needle doctor nurse +🩸 drop of blood period hurt harm wound +💊 pill health medicine doctor pharmacy drug +🩹 adhesive bandage heal +🩺 stethoscope health +🚪 door house entry exit +🛏️ bed sleep rest +🛋️ couch and lamp read chill +🪑 chair sit furniture +🚽 toilet restroom wc washroom bathroom potty +🚿 shower clean water bathroom +🛁 bathtub clean shower bathroom +🪒 razor cut +🧴 lotion bottle moisturizer sunscreen +🧷 safety pin diaper +🧹 broom cleaning sweeping witch +🧺 basket laundry +🧻 roll of paper roll +🧼 soap bar bathing cleaning lather +🧽 sponge absorbing cleaning porous +🧯 fire extinguisher quench +🛒 shopping cart trolley +🚬 cigarette kills tobacco cigarette joint smoke +⚰️ coffin vampire dead die death rip graveyard cemetery casket funeral box +⚱️ funeral urn dead die death rip ashes +🗿 moai rock easter island moai +🏧 atm sign money sales cash blue-square payment bank +🚮 litter in bin sign blue-square sign human info +🚰 potable water blue-square liquid restroom cleaning faucet +♿ wheelchair symbol blue-square disabled accessibility +🚹 men s room toilet restroom wc blue-square gender male +🚺 women s room purple-square woman female toilet loo restroom gender +🚻 restroom blue-square toilet refresh wc gender +🚼 baby symbol orange-square child +🚾 water closet toilet restroom blue-square +🛂 passport control custom blue-square +🛃 customs passport border blue-square +🛄 baggage claim blue-square airport transport +🛅 left luggage blue-square travel +⚠️ warning exclamation wip alert error problem issue +🚸 children crossing school warning danger sign driving yellow-diamond +⛔ no entry limit security privacy bad denied stop circle +🚫 prohibited forbid stop limit denied disallow circle +🚳 no bicycles cyclist prohibited circle +🚭 no smoking cigarette blue-square smell smoke +🚯 no littering trash bin garbage circle +🚱 non potable water drink faucet tap circle +🚷 no pedestrians rules crossing walking circle +📵 no mobile phones iphone mute circle +🔞 no one under eighteen 18 drink pub night minor circle +☢️ radioactive nuclear danger +☣️ biohazard danger +⬆️ up arrow blue-square continue top direction +↗️ up right arrow blue-square point direction diagonal northeast +➡️ right arrow blue-square next +↘️ down right arrow blue-square direction diagonal southeast +⬇️ down arrow blue-square direction bottom +↙️ down left arrow blue-square direction diagonal southwest +⬅️ left arrow blue-square previous back +↖️ up left arrow blue-square point direction diagonal northwest +↕️ up down arrow blue-square direction way vertical +↔️ left right arrow shape direction horizontal sideways +↩️ right arrow curving left back return blue-square undo enter +↪️ left arrow curving right blue-square return rotate direction +⤴️ right arrow curving up blue-square direction top +⤵️ right arrow curving down blue-square direction bottom +🔃 clockwise vertical arrows sync cycle round repeat +🔄 counterclockwise arrows button blue-square sync cycle +🔙 back arrow arrow words return +🔚 end arrow words arrow +🔛 on arrow arrow words +🔜 soon arrow arrow words +🔝 top arrow words blue-square +🛐 place of worship religion church temple prayer +⚛️ atom symbol science physics chemistry +🕉️ om hinduism buddhism sikhism jainism +✡️ star of david judaism +☸️ wheel of dharma hinduism buddhism sikhism jainism +☯️ yin yang balance +✝️ latin cross christianity +☦️ orthodox cross suppedaneum religion +☪️ star and crescent islam +☮️ peace symbol hippie +🕎 menorah hanukkah candles jewish +🔯 dotted six pointed star purple-square religion jewish hexagram +♈ aries sign purple-square zodiac astrology +♉ taurus purple-square sign zodiac astrology +♊ gemini sign zodiac purple-square astrology +♋ cancer sign zodiac purple-square astrology +♌ leo sign purple-square zodiac astrology +♍ virgo sign zodiac purple-square astrology +♎ libra sign purple-square zodiac astrology +♏ scorpio sign zodiac purple-square astrology scorpio +♐ sagittarius sign zodiac purple-square astrology +♑ capricorn sign zodiac purple-square astrology +♒ aquarius sign purple-square zodiac astrology +♓ pisces purple-square sign zodiac astrology +⛎ ophiuchus sign purple-square constellation astrology +🔀 shuffle tracks button blue-square shuffle music random +🔁 repeat button loop record +🔂 repeat single button blue-square loop +▶️ play button blue-square right direction play +⏩ fast forward button blue-square play speed continue +⏭️ next track button forward next blue-square +⏯️ play or pause button blue-square play pause +◀️ reverse button blue-square left direction +⏪ fast reverse button play blue-square +⏮️ last track button backward +🔼 upwards button blue-square triangle direction point forward top +⏫ fast up button blue-square direction top +🔽 downwards button blue-square direction bottom +⏬ fast down button blue-square direction bottom +⏸️ pause button pause blue-square +⏹️ stop button blue-square +⏺️ record button blue-square +⏏️ eject button blue-square +🎦 cinema blue-square record film movie curtain stage theater +🔅 dim button sun afternoon warm summer +🔆 bright button sun light +📶 antenna bars blue-square reception phone internet connection wifi bluetooth bars +📳 vibration mode orange-square phone +📴 mobile phone off mute orange-square silence quiet +♀️ female sign woman women lady girl +♂️ male sign man boy men +⚕️ medical symbol health hospital +♾️ infinity forever +♻️ recycling symbol arrow environment garbage trash +⚜️ fleur de lis decorative scout +🔱 trident emblem weapon spear +📛 name badge fire forbid +🔰 japanese symbol for beginner badge shield +⭕ hollow red circle circle round +✅ check mark button green-square ok agree vote election answer tick +☑️ check box with check ok agree confirm black-square vote election yes tick +✔️ check mark ok nike answer yes tick +✖️ multiplication sign math calculation +❌ cross mark no delete remove cancel red +❎ cross mark button x green-square no deny +➕ plus sign math calculation addition more increase +➖ minus sign math calculation subtract less +➗ division sign divide math calculation +➰ curly loop scribble draw shape squiggle +➿ double curly loop tape cassette +〽️ part alternation mark graph presentation stats business economics bad +✳️ eight spoked asterisk star sparkle green-square +✴️ eight pointed star orange-square shape polygon +❇️ sparkle stars green-square awesome good fireworks +‼️ double exclamation mark exclamation surprise +⁉️ exclamation question mark wat punctuation surprise +❓ question mark doubt confused +❔ white question mark doubts gray huh confused +❕ white exclamation mark surprise punctuation gray wow warning +❗ exclamation mark heavy exclamation mark danger surprise punctuation wow warning +〰️ wavy dash draw line moustache mustache squiggle scribble +©️ copyright ip license circle law legal +®️ registered alphabet circle +™️ trade mark trademark brand law legal +#️⃣ keycap symbol blue-square twitter +*️⃣ keycap star keycap +0️⃣ keycap 0 0 numbers blue-square null +1️⃣ keycap 1 blue-square numbers 1 +2️⃣ keycap 2 numbers 2 prime blue-square +3️⃣ keycap 3 3 numbers prime blue-square +4️⃣ keycap 4 4 numbers blue-square +5️⃣ keycap 5 5 numbers blue-square prime +6️⃣ keycap 6 6 numbers blue-square +7️⃣ keycap 7 7 numbers blue-square prime +8️⃣ keycap 8 8 blue-square numbers +9️⃣ keycap 9 blue-square numbers 9 +🔟 keycap 10 numbers 10 blue-square +🔠 input latin uppercase alphabet words blue-square +🔡 input latin lowercase blue-square alphabet +🔢 input numbers numbers blue-square +🔣 input symbols blue-square music note ampersand percent glyphs characters +🔤 input latin letters blue-square alphabet +🅰️ a button red-square alphabet letter +🆎 ab button red-square alphabet +🅱️ b button red-square alphabet letter +🆑 cl button alphabet words red-square +🆒 cool button words blue-square +🆓 free button blue-square words +ℹ️ information blue-square alphabet letter +🆔 id button purple-square words +Ⓜ️ circled m alphabet blue-circle letter +🆕 new button blue-square words start +🆖 ng button blue-square words shape icon +🅾️ o button alphabet red-square letter +🆗 ok button good agree yes blue-square +🅿️ p button cars blue-square alphabet letter +🆘 sos button help red-square words emergency 911 +🆙 up button blue-square above high +🆚 vs button words orange-square +🈁 japanese here button blue-square here katakana japanese destination +🈂️ japanese service charge button japanese blue-square katakana +🈷️ japanese monthly amount button chinese month moon japanese orange-square kanji +🈶 japanese not free of charge button orange-square chinese have kanji +🈯 japanese reserved button chinese point green-square kanji +🉐 japanese bargain button chinese kanji obtain get circle +🈹 japanese discount button cut divide chinese kanji pink-square +🈚 japanese free of charge button nothing chinese kanji japanese orange-square +🈲 japanese prohibited button kanji japanese chinese forbidden limit restricted red-square +🉑 japanese acceptable button ok good chinese kanji agree yes orange-circle +🈸 japanese application button chinese japanese kanji orange-square +🈴 japanese passing grade button japanese chinese join kanji red-square +🈳 japanese vacancy button kanji japanese chinese empty sky blue-square +㊗️ japanese congratulations button chinese kanji japanese red-circle +㊙️ japanese secret button privacy chinese sshh kanji red-circle +🈺 japanese open for business button japanese opening hours orange-square +🈵 japanese no vacancy button full chinese japanese red-square kanji +🔴 red circle shape error danger +🟠 orange circle round +🟡 yellow circle round +🟢 green circle round +🔵 blue circle shape icon button +🟣 purple circle round +🟤 brown circle round +⚫ black circle shape button round +⚪ white circle shape round +🟥 red square +🟧 orange square +🟨 yellow square +🟩 green square +🟦 blue square +🟪 purple square +🟫 brown square +⬛ black large square shape icon button +⬜ white large square shape icon stone button +◼️ black medium square shape button icon +◻️ white medium square shape stone icon +◾ black medium small square icon shape button +◽ white medium small square shape stone icon button +▪️ black small square shape icon +▫️ white small square shape icon +🔶 large orange diamond shape jewel gem +🔷 large blue diamond shape jewel gem +🔸 small orange diamond shape jewel gem +🔹 small blue diamond shape jewel gem +🔺 red triangle pointed up shape direction up top +🔻 red triangle pointed down shape direction bottom +💠 diamond with a dot jewel blue gem crystal fancy +🔘 radio button input old music circle +🔳 white square button shape input +🔲 black square button shape input frame +🏁 chequered flag contest finishline race gokart +🚩 triangular flag mark milestone place +🎌 crossed flags japanese nation country border +🏴 black flag pirate +🏳️ white flag losing loser lost surrender give up fail +🏳️‍🌈 rainbow flag flag rainbow pride gay lgbt glbt queer homosexual lesbian bisexual transgender +🏴‍☠️ pirate flag skull crossbones flag banner +🇦🇨 flag ascension island +🇦🇩 flag andorra ad flag nation country banner andorra +🇦🇪 flag united arab emirates united arab emirates flag nation country banner united arab emirates +🇦🇫 flag afghanistan af flag nation country banner afghanistan +🇦🇬 flag antigua barbuda antigua barbuda flag nation country banner antigua barbuda +🇦🇮 flag anguilla ai flag nation country banner anguilla +🇦🇱 flag albania al flag nation country banner albania +🇦🇲 flag armenia am flag nation country banner armenia +🇦🇴 flag angola ao flag nation country banner angola +🇦🇶 flag antarctica aq flag nation country banner antarctica +🇦🇷 flag argentina ar flag nation country banner argentina +🇦🇸 flag american samoa american ws flag nation country banner american samoa +🇦🇹 flag austria at flag nation country banner austria +🇦🇺 flag australia au flag nation country banner australia +🇦🇼 flag aruba aw flag nation country banner aruba +🇦🇽 flag aland islands Åland islands flag nation country banner aland islands +🇦🇿 flag azerbaijan az flag nation country banner azerbaijan +🇧🇦 flag bosnia herzegovina bosnia herzegovina flag nation country banner bosnia herzegovina +🇧🇧 flag barbados bb flag nation country banner barbados +🇧🇩 flag bangladesh bd flag nation country banner bangladesh +🇧🇪 flag belgium be flag nation country banner belgium +🇧🇫 flag burkina faso burkina faso flag nation country banner burkina faso +🇧🇬 flag bulgaria bg flag nation country banner bulgaria +🇧🇭 flag bahrain bh flag nation country banner bahrain +🇧🇮 flag burundi bi flag nation country banner burundi +🇧🇯 flag benin bj flag nation country banner benin +🇧🇱 flag st barthelemy saint barthélemy flag nation country banner st barthelemy +🇧🇲 flag bermuda bm flag nation country banner bermuda +🇧🇳 flag brunei bn darussalam flag nation country banner brunei +🇧🇴 flag bolivia bo flag nation country banner bolivia +🇧🇶 flag caribbean netherlands bonaire flag nation country banner caribbean netherlands +🇧🇷 flag brazil br flag nation country banner brazil +🇧🇸 flag bahamas bs flag nation country banner bahamas +🇧🇹 flag bhutan bt flag nation country banner bhutan +🇧🇻 flag bouvet island norway +🇧🇼 flag botswana bw flag nation country banner botswana +🇧🇾 flag belarus by flag nation country banner belarus +🇧🇿 flag belize bz flag nation country banner belize +🇨🇦 flag canada ca flag nation country banner canada +🇨🇨 flag cocos islands cocos keeling islands flag nation country banner cocos islands +🇨🇩 flag congo kinshasa congo democratic republic flag nation country banner congo kinshasa +🇨🇫 flag central african republic central african republic flag nation country banner central african republic +🇨🇬 flag congo brazzaville congo flag nation country banner congo brazzaville +🇨🇭 flag switzerland ch flag nation country banner switzerland +🇨🇮 flag cote d ivoire ivory coast flag nation country banner cote d ivoire +🇨🇰 flag cook islands cook islands flag nation country banner cook islands +🇨🇱 flag chile flag nation country banner chile +🇨🇲 flag cameroon cm flag nation country banner cameroon +🇨🇳 flag china china chinese prc flag country nation banner china +🇨🇴 flag colombia co flag nation country banner colombia +🇨🇵 flag clipperton island +🇨🇷 flag costa rica costa rica flag nation country banner costa rica +🇨🇺 flag cuba cu flag nation country banner cuba +🇨🇻 flag cape verde cabo verde flag nation country banner cape verde +🇨🇼 flag curacao curaçao flag nation country banner curacao +🇨🇽 flag christmas island christmas island flag nation country banner christmas island +🇨🇾 flag cyprus cy flag nation country banner cyprus +🇨🇿 flag czechia cz flag nation country banner czechia +🇩🇪 flag germany german nation flag country banner germany +🇩🇬 flag diego garcia +🇩🇯 flag djibouti dj flag nation country banner djibouti +🇩🇰 flag denmark dk flag nation country banner denmark +🇩🇲 flag dominica dm flag nation country banner dominica +🇩🇴 flag dominican republic dominican republic flag nation country banner dominican republic +🇩🇿 flag algeria dz flag nation country banner algeria +🇪🇦 flag ceuta melilla +🇪🇨 flag ecuador ec flag nation country banner ecuador +🇪🇪 flag estonia ee flag nation country banner estonia +🇪🇬 flag egypt eg flag nation country banner egypt +🇪🇭 flag western sahara western sahara flag nation country banner western sahara +🇪🇷 flag eritrea er flag nation country banner eritrea +🇪🇸 flag spain spain flag nation country banner spain +🇪🇹 flag ethiopia et flag nation country banner ethiopia +🇪🇺 flag european union european union flag banner +🇫🇮 flag finland fi flag nation country banner finland +🇫🇯 flag fiji fj flag nation country banner fiji +🇫🇰 flag falkland islands falkland islands malvinas flag nation country banner falkland islands +🇫🇲 flag micronesia micronesia federated states flag nation country banner micronesia +🇫🇴 flag faroe islands faroe islands flag nation country banner faroe islands +🇫🇷 flag france banner flag nation france french country france +🇬🇦 flag gabon ga flag nation country banner gabon +🇬🇧 flag united kingdom united kingdom great britain northern ireland flag nation country banner british UK english england union jack united kingdom +🇬🇩 flag grenada gd flag nation country banner grenada +🇬🇪 flag georgia ge flag nation country banner georgia +🇬🇫 flag french guiana french guiana flag nation country banner french guiana +🇬🇬 flag guernsey gg flag nation country banner guernsey +🇬🇭 flag ghana gh flag nation country banner ghana +🇬🇮 flag gibraltar gi flag nation country banner gibraltar +🇬🇱 flag greenland gl flag nation country banner greenland +🇬🇲 flag gambia gm flag nation country banner gambia +🇬🇳 flag guinea gn flag nation country banner guinea +🇬🇵 flag guadeloupe gp flag nation country banner guadeloupe +🇬🇶 flag equatorial guinea equatorial gn flag nation country banner equatorial guinea +🇬🇷 flag greece gr flag nation country banner greece +🇬🇸 flag south georgia south sandwich islands south georgia sandwich islands flag nation country banner south georgia south sandwich islands +🇬🇹 flag guatemala gt flag nation country banner guatemala +🇬🇺 flag guam gu flag nation country banner guam +🇬🇼 flag guinea bissau gw bissau flag nation country banner guinea bissau +🇬🇾 flag guyana gy flag nation country banner guyana +🇭🇰 flag hong kong sar china hong kong flag nation country banner hong kong sar china +🇭🇲 flag heard mcdonald islands +🇭🇳 flag honduras hn flag nation country banner honduras +🇭🇷 flag croatia hr flag nation country banner croatia +🇭🇹 flag haiti ht flag nation country banner haiti +🇭🇺 flag hungary hu flag nation country banner hungary +🇮🇨 flag canary islands canary islands flag nation country banner canary islands +🇮🇩 flag indonesia flag nation country banner indonesia +🇮🇪 flag ireland ie flag nation country banner ireland +🇮🇱 flag israel il flag nation country banner israel +🇮🇲 flag isle of man isle man flag nation country banner isle of man +🇮🇳 flag india in flag nation country banner india +🇮🇴 flag british indian ocean territory british indian ocean territory flag nation country banner british indian ocean territory +🇮🇶 flag iraq iq flag nation country banner iraq +🇮🇷 flag iran iran islamic republic flag nation country banner iran +🇮🇸 flag iceland is flag nation country banner iceland +🇮🇹 flag italy italy flag nation country banner italy +🇯🇪 flag jersey je flag nation country banner jersey +🇯🇲 flag jamaica jm flag nation country banner jamaica +🇯🇴 flag jordan jo flag nation country banner jordan +🇯🇵 flag japan japanese nation flag country banner japan +🇰🇪 flag kenya ke flag nation country banner kenya +🇰🇬 flag kyrgyzstan kg flag nation country banner kyrgyzstan +🇰🇭 flag cambodia kh flag nation country banner cambodia +🇰🇮 flag kiribati ki flag nation country banner kiribati +🇰🇲 flag comoros km flag nation country banner comoros +🇰🇳 flag st kitts nevis saint kitts nevis flag nation country banner st kitts nevis +🇰🇵 flag north korea north korea nation flag country banner north korea +🇰🇷 flag south korea south korea nation flag country banner south korea +🇰🇼 flag kuwait kw flag nation country banner kuwait +🇰🇾 flag cayman islands cayman islands flag nation country banner cayman islands +🇰🇿 flag kazakhstan kz flag nation country banner kazakhstan +🇱🇦 flag laos lao democratic republic flag nation country banner laos +🇱🇧 flag lebanon lb flag nation country banner lebanon +🇱🇨 flag st lucia saint lucia flag nation country banner st lucia +🇱🇮 flag liechtenstein li flag nation country banner liechtenstein +🇱🇰 flag sri lanka sri lanka flag nation country banner sri lanka +🇱🇷 flag liberia lr flag nation country banner liberia +🇱🇸 flag lesotho ls flag nation country banner lesotho +🇱🇹 flag lithuania lt flag nation country banner lithuania +🇱🇺 flag luxembourg lu flag nation country banner luxembourg +🇱🇻 flag latvia lv flag nation country banner latvia +🇱🇾 flag libya ly flag nation country banner libya +🇲🇦 flag morocco ma flag nation country banner morocco +🇲🇨 flag monaco mc flag nation country banner monaco +🇲🇩 flag moldova moldova republic flag nation country banner moldova +🇲🇪 flag montenegro me flag nation country banner montenegro +🇲🇫 flag st martin +🇲🇬 flag madagascar mg flag nation country banner madagascar +🇲🇭 flag marshall islands marshall islands flag nation country banner marshall islands +🇲🇰 flag north macedonia macedonia flag nation country banner north macedonia +🇲🇱 flag mali ml flag nation country banner mali +🇲🇲 flag myanmar mm flag nation country banner myanmar +🇲🇳 flag mongolia mn flag nation country banner mongolia +🇲🇴 flag macao sar china macao flag nation country banner macao sar china +🇲🇵 flag northern mariana islands northern mariana islands flag nation country banner northern mariana islands +🇲🇶 flag martinique mq flag nation country banner martinique +🇲🇷 flag mauritania mr flag nation country banner mauritania +🇲🇸 flag montserrat ms flag nation country banner montserrat +🇲🇹 flag malta mt flag nation country banner malta +🇲🇺 flag mauritius mu flag nation country banner mauritius +🇲🇻 flag maldives mv flag nation country banner maldives +🇲🇼 flag malawi mw flag nation country banner malawi +🇲🇽 flag mexico mx flag nation country banner mexico +🇲🇾 flag malaysia my flag nation country banner malaysia +🇲🇿 flag mozambique mz flag nation country banner mozambique +🇳🇦 flag namibia na flag nation country banner namibia +🇳🇨 flag new caledonia new caledonia flag nation country banner new caledonia +🇳🇪 flag niger ne flag nation country banner niger +🇳🇫 flag norfolk island norfolk island flag nation country banner norfolk island +🇳🇬 flag nigeria flag nation country banner nigeria +🇳🇮 flag nicaragua ni flag nation country banner nicaragua +🇳🇱 flag netherlands nl flag nation country banner netherlands +🇳🇴 flag norway no flag nation country banner norway +🇳🇵 flag nepal np flag nation country banner nepal +🇳🇷 flag nauru nr flag nation country banner nauru +🇳🇺 flag niue nu flag nation country banner niue +🇳🇿 flag new zealand new zealand flag nation country banner new zealand +🇴🇲 flag oman om symbol flag nation country banner oman +🇵🇦 flag panama pa flag nation country banner panama +🇵🇪 flag peru pe flag nation country banner peru +🇵🇫 flag french polynesia french polynesia flag nation country banner french polynesia +🇵🇬 flag papua new guinea papua new guinea flag nation country banner papua new guinea +🇵🇭 flag philippines ph flag nation country banner philippines +🇵🇰 flag pakistan pk flag nation country banner pakistan +🇵🇱 flag poland pl flag nation country banner poland +🇵🇲 flag st pierre miquelon saint pierre miquelon flag nation country banner st pierre miquelon +🇵🇳 flag pitcairn islands pitcairn flag nation country banner pitcairn islands +🇵🇷 flag puerto rico puerto rico flag nation country banner puerto rico +🇵🇸 flag palestinian territories palestine palestinian territories flag nation country banner palestinian territories +🇵🇹 flag portugal pt flag nation country banner portugal +🇵🇼 flag palau pw flag nation country banner palau +🇵🇾 flag paraguay py flag nation country banner paraguay +🇶🇦 flag qatar qa flag nation country banner qatar +🇷🇪 flag reunion réunion flag nation country banner reunion +🇷🇴 flag romania ro flag nation country banner romania +🇷🇸 flag serbia rs flag nation country banner serbia +🇷🇺 flag russia russian federation flag nation country banner russia +🇷🇼 flag rwanda rw flag nation country banner rwanda +🇸🇦 flag saudi arabia flag nation country banner saudi arabia +🇸🇧 flag solomon islands solomon islands flag nation country banner solomon islands +🇸🇨 flag seychelles sc flag nation country banner seychelles +🇸🇩 flag sudan sd flag nation country banner sudan +🇸🇪 flag sweden se flag nation country banner sweden +🇸🇬 flag singapore sg flag nation country banner singapore +🇸🇭 flag st helena saint helena ascension tristan cunha flag nation country banner st helena +🇸🇮 flag slovenia si flag nation country banner slovenia +🇸🇯 flag svalbard jan mayen +🇸🇰 flag slovakia sk flag nation country banner slovakia +🇸🇱 flag sierra leone sierra leone flag nation country banner sierra leone +🇸🇲 flag san marino san marino flag nation country banner san marino +🇸🇳 flag senegal sn flag nation country banner senegal +🇸🇴 flag somalia so flag nation country banner somalia +🇸🇷 flag suriname sr flag nation country banner suriname +🇸🇸 flag south sudan south sd flag nation country banner south sudan +🇸🇹 flag sao tome principe sao tome principe flag nation country banner sao tome principe +🇸🇻 flag el salvador el salvador flag nation country banner el salvador +🇸🇽 flag sint maarten sint maarten dutch flag nation country banner sint maarten +🇸🇾 flag syria syrian arab republic flag nation country banner syria +🇸🇿 flag eswatini sz flag nation country banner eswatini +🇹🇦 flag tristan da cunha +🇹🇨 flag turks caicos islands turks caicos islands flag nation country banner turks caicos islands +🇹🇩 flag chad td flag nation country banner chad +🇹🇫 flag french southern territories french southern territories flag nation country banner french southern territories +🇹🇬 flag togo tg flag nation country banner togo +🇹🇭 flag thailand th flag nation country banner thailand +🇹🇯 flag tajikistan tj flag nation country banner tajikistan +🇹🇰 flag tokelau tk flag nation country banner tokelau +🇹🇱 flag timor leste timor leste flag nation country banner timor leste +🇹🇲 flag turkmenistan flag nation country banner turkmenistan +🇹🇳 flag tunisia tn flag nation country banner tunisia +🇹🇴 flag tonga to flag nation country banner tonga +🇹🇷 flag turkey turkey flag nation country banner turkey +🇹🇹 flag trinidad tobago trinidad tobago flag nation country banner trinidad tobago +🇹🇻 flag tuvalu flag nation country banner tuvalu +🇹🇼 flag taiwan tw flag nation country banner taiwan +🇹🇿 flag tanzania tanzania united republic flag nation country banner tanzania +🇺🇦 flag ukraine ua flag nation country banner ukraine +🇺🇬 flag uganda ug flag nation country banner uganda +🇺🇲 flag u s outlying islands +🇺🇳 flag united nations un flag banner +🇺🇸 flag united states united states america flag nation country banner united states +🇺🇾 flag uruguay uy flag nation country banner uruguay +🇺🇿 flag uzbekistan uz flag nation country banner uzbekistan +🇻🇦 flag vatican city vatican city flag nation country banner vatican city +🇻🇨 flag st vincent grenadines saint vincent grenadines flag nation country banner st vincent grenadines +🇻🇪 flag venezuela ve bolivarian republic flag nation country banner venezuela +🇻🇬 flag british virgin islands british virgin islands bvi flag nation country banner british virgin islands +🇻🇮 flag u s virgin islands virgin islands us flag nation country banner u s virgin islands +🇻🇳 flag vietnam viet nam flag nation country banner vietnam +🇻🇺 flag vanuatu vu flag nation country banner vanuatu +🇼🇫 flag wallis futuna wallis futuna flag nation country banner wallis futuna +🇼🇸 flag samoa ws flag nation country banner samoa +🇽🇰 flag kosovo xk flag nation country banner kosovo +🇾🇪 flag yemen ye flag nation country banner yemen +🇾🇹 flag mayotte yt flag nation country banner mayotte +🇿🇦 flag south africa south africa flag nation country banner south africa +🇿🇲 flag zambia zm flag nation country banner zambia +🇿🇼 flag zimbabwe zw flag nation country banner zimbabwe +🏴󠁧󠁢󠁥󠁮󠁧󠁿 flag england flag english +🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag scotland flag scottish +🏴󠁧󠁢󠁷󠁬󠁳󠁿 flag wales flag welsh +🥲 smiling face with tear sad cry pretend +🥸 disguised face pretent brows glasses moustache +🤌 pinched fingers size tiny small +🫀 anatomical heart health heartbeat +🫁 lungs breathe +🥷 ninja ninjutsu skills japanese +🤵‍♂️ man in tuxedo formal fashion +🤵‍♀️ woman in tuxedo formal fashion +👰‍♂️ man with veil wedding marriage +👰‍♀️ woman with veil wedding marriage +👩‍🍼 woman feeding baby birth food +👨‍🍼 man feeding baby birth food +🧑‍🍼 person feeding baby birth food +🧑‍🎄 mx claus christmas +🫂 people hugging care +🐈‍⬛ black cat superstition luck +🦬 bison ox +🦣 mammoth elephant tusks +🦫 beaver animal rodent +🐻‍❄️ polar bear animal arctic +🦤 dodo animal bird +🪶 feather bird fly +🦭 seal animal creature sea +🪲 beetle insect +🪳 cockroach insect pests +🪰 fly insect +🪱 worm animal +🪴 potted plant greenery house +🫐 blueberries fruit +🫒 olive fruit +🫑 bell pepper fruit plant +🫓 flatbread flour food +🫔 tamale food masa +🫕 fondue cheese pot food +🫖 teapot drink hot +🧋 bubble tea taiwan boba milk tea straw +🪨 rock stone +🪵 wood nature timber trunk +🛖 hut house structure +🛻 pickup truck car transportation +🛼 roller skate footwear sports +🪄 magic wand supernature power +🪅 pinata mexico candy celebration +🪆 nesting dolls matryoshka toy +🪡 sewing needle stitches +🪢 knot rope scout +🩴 thong sandal footwear summer +🪖 military helmet army protection +🪗 accordion music +🪘 long drum music +🪙 coin money currency +🪃 boomerang weapon +🪚 carpentry saw cut chop +🪛 screwdriver tools +🪝 hook tools +🪜 ladder tools +🛗 elevator lift +🪞 mirror reflection +🪟 window scenery +🪠 plunger toilet +🪤 mouse trap cheese +🪣 bucket water container +🪥 toothbrush hygiene dental +🪦 headstone death rip grave +🪧 placard announcement +⚧️ transgender symbol lgbtq +🏳️‍⚧️ transgender flag lgbtq +😶‍🌫️ face in clouds shower steam dream +😮‍💨 face exhaling relieve relief tired sigh +😵‍💫 face with spiral eyes sick ill confused nauseous nausea +❤️‍🔥 heart on fire passionate enthusiastic +❤️‍🩹 mending heart broken heart bandage wounded +🧔‍♂️ man beard facial hair +🧔‍♀️ woman beard facial hair +🫠 melting face hot heat +🫢 face with open eyes and hand over mouth silence secret shock surprise +🫣 face with peeking eye scared frightening embarrassing +🫡 saluting face respect salute +🫥 dotted line face invisible lonely isolation depression +🫤 face with diagonal mouth skeptic confuse frustrated indifferent +🥹 face holding back tears touched gratitude +🫱 rightwards hand palm offer +🫲 leftwards hand palm offer +🫳 palm down hand palm drop +🫴 palm up hand lift offer demand +🫰 hand with index finger and thumb crossed heart love money expensive +🫵 index pointing at the viewer you recruit +🫶 heart hands love appreciation support +🫦 biting lip flirt sexy pain worry +🫅 person with crown royalty power +🫃 pregnant man baby belly +🫄 pregnant person baby belly +🧌 troll mystical monster +🪸 coral ocean sea reef +🪷 lotus flower calm meditation +🪹 empty nest bird +🪺 nest with eggs bird +🫘 beans food +🫗 pouring liquid cup water +🫙 jar container sauce +🛝 playground slide fun park +🛞 wheel car transport +🛟 ring buoy life saver life preserver +🪬 hamsa religion protection +🪩 mirror ball disco dance party +🪫 low battery drained dead +🩼 crutch accessibility assist +🩻 x-ray skeleton medicine +🫧 bubbles soap fun carbonation sparkling +🪪 identification card document +🟰 heavy equals sign math +¿? question upside down reversed spanish +← left arrow +↑ up arrow +→ right arrow +↓ down arrow +←↑→↓ all directions up down left right arrows +AH↗️HA↘️HA↗️HA↘️HA↗️HA↘️HA↗️HA↘️ pekora arrows hahaha rabbit +• dot circle separator +「」 japanese quote square bracket +¯\_(ツ)_/¯ shrug idk i dont know +↵ enter key return +𝕏 twitter x logo +👉👈 etou ughhhhhhh shy +👉👌 put it in imagination perv \ No newline at end of file diff --git a/.scripts/hyprland_workspace_action.sh b/.scripts/hyprland_workspace_action.sh new file mode 100755 index 0000000..4eca733 --- /dev/null +++ b/.scripts/hyprland_workspace_action.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# https://github.com/end-4/dots-hyprland/blob/main/.config/ags/scripts/hyprland/workspace_action.sh + +hyprctl dispatch "$1" $(((($(hyprctl activeworkspace -j | jq -r .id) - 1) / 10) * 10 + $2)) \ No newline at end of file diff --git a/.scripts/record-script.sh b/.scripts/record-script.sh new file mode 100755 index 0000000..332e5aa --- /dev/null +++ b/.scripts/record-script.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# https://github.com/end-4/dots-hyprland/blob/main/.config/ags/scripts/record-script.sh + +getdate() { + date '+%Y-%m-%d_%H.%M.%S' +} +getaudiooutput() { + pactl list sources | grep 'Name' | grep 'monitor' | cut -d ' ' -f2 +} +getactivemonitor() { + hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .name' +} + +mkdir -p "$(xdg-user-dir VIDEOS)" +cd "$(xdg-user-dir VIDEOS)" || exit +if pgrep wf-recorder > /dev/null; then + notify-send "Recording Stopped" "Stopped" -a 'record-script.sh' & + pkill wf-recorder & +else + notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'record-script.sh' + if [[ "$1" == "--sound" ]]; then + wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$(slurp)" --audio="$(getaudiooutput)" & disown + elif [[ "$1" == "--fullscreen-sound" ]]; then + wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)" & disown + elif [[ "$1" == "--fullscreen" ]]; then + wf-recorder -o $(getactivemonitor) --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t & disown + else + wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$(slurp)" & disown + fi +fi \ No newline at end of file diff --git a/.scripts/set_nv_env.sh b/.scripts/set_nv_env.sh new file mode 100755 index 0000000..6056aa6 --- /dev/null +++ b/.scripts/set_nv_env.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export __NV_PRIME_RENDER_OFFLOAD=1 +export __GLX_VENDOR_LIBRARY_NAME=nvidia +export __VK_LAYER_NV_optimus=NVIDIA_only diff --git a/.scripts/unset_nv_env.sh b/.scripts/unset_nv_env.sh new file mode 100755 index 0000000..a4e4c72 --- /dev/null +++ b/.scripts/unset_nv_env.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# __NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia __VK_LAYER_NV_optimus=NVIDIA_only +unset __NV_PRIME_RENDER_OFFLOAD +unset __GLX_VENDOR_LIBRARY_NAME +unset __VK_LAYER_NV_optimus diff --git a/.utils/live_mount.sh b/.utils/live_mount.sh new file mode 100755 index 0000000..c85f7a7 --- /dev/null +++ b/.utils/live_mount.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +device="/dev/nvme0n1" +efi_part="${device}p3" +boot_part="${device}p4" +btrfs_part="${device}p5" + +umount /mnt -R + +mount $btrfs_part -o subvol=@ /mnt +mount $btrfs_part -o subvol=@home /mnt/home +mount $btrfs_part -o subvol=@log /mnt/var/log +mount $btrfs_part -o subvol=@cache /mnt/var/cache +mount $btrfs_part -o subvol=@tmp /mnt/tmp +mount $btrfs_part -o subvol=@swap /mnt/swap +mount $boot_part /mnt/boot +mount $efi_part /mnt/boot/efi +swapon /mnt/swap/swapfile \ No newline at end of file diff --git a/.utils/truecolor-test.sh b/.utils/truecolor-test.sh new file mode 100755 index 0000000..9735442 --- /dev/null +++ b/.utils/truecolor-test.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Based on: https://gist.github.com/XVilka/8346728 + +awk -v term_cols="${width:-$(tput cols || echo 80)}" 'BEGIN{ + s="/\\"; + for (colnum = 0; colnum255) g = 510-g; + printf "\033[48;2;%d;%d;%dm", r,g,b; + printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b; + printf "%s\033[0m", substr(s,colnum%2+1,1); + } + printf "\n"; +}' diff --git a/alacritty/alacritty.toml b/alacritty/alacritty.toml new file mode 100644 index 0000000..3c80388 --- /dev/null +++ b/alacritty/alacritty.toml @@ -0,0 +1,167 @@ +[env] +TERM = "xterm-256color" +WINIT_X11_SCALE_FACTOR = "1" + +[window] +dynamic_padding = true +decorations = "full" +title = "Alacritty@CachyOS" +opacity = 0.75 +decorations_theme_variant = "Dark" +blur = true + +[window.dimensions] +columns = 100 +lines = 30 + +[window.class] +instance = "Alacritty" +general = "Alacritty" + +[scrolling] +history = 10000 +multiplier = 3 + +[colors] +draw_bold_text_with_bright_colors = true + + +# [colors.primary] +# background = "0x2E3440" +# foreground = "0xD8DEE9" + +# [colors.normal] +# black = "0x3B4252" +# red = "0xBF616A" +# green = "0xA3BE8C" +# yellow = "0xEBCB8B" +# blue = "0x81A1C1" +# magenta = "0xB48EAD" +# cyan = "0x88C0D0" +# white = "0xE5E9F0" + +# [colors.bright] +# black = "0x4C566A" +# red = "0xBF616A" +# green = "0xA3BE8C" +# yellow = "0xEBCB8B" +# blue = "0x81A1C1" +# magenta = "0xB48EAD" +# cyan = "0x8FBCBB" +# white = "0xECEFF4" + +[font] +size = 12 + +[font.normal] +family = "Meslo LGM Nerd Font" +style = "Regular" + +[font.bold] +family = "Meslo LGM Nerd Font" +style = "Bold" + +[font.italic] +family = "Meslo LGM Nerd Font" +style = "Italic" + +[font.bold_italic] +family = "Meslo LGM Nerd Font" +style = "Bold Italic" + +[selection] +semantic_escape_chars = ",│`|:\"' ()[]{}<>\t" +save_to_clipboard = true + +[cursor] +style = "Underline" +vi_mode_style = "None" +unfocused_hollow = true +thickness = 0.15 + +[mouse] +hide_when_typing = true + +[[mouse.bindings]] +mouse = "Middle" +action = "PasteSelection" + +[keyboard] +[[keyboard.bindings]] +key = "Paste" +action = "Paste" + +[[keyboard.bindings]] +key = "Copy" +action = "Copy" + +[[keyboard.bindings]] +key = "L" +mods = "Control" +action = "ClearLogNotice" + +[[keyboard.bindings]] +key = "L" +mods = "Control" +mode = "~Vi" +chars = "\f" + +[[keyboard.bindings]] +key = "PageUp" +mods = "Shift" +mode = "~Alt" +action = "ScrollPageUp" + +[[keyboard.bindings]] +key = "PageDown" +mods = "Shift" +mode = "~Alt" +action = "ScrollPageDown" + +[[keyboard.bindings]] +key = "Home" +mods = "Shift" +mode = "~Alt" +action = "ScrollToTop" + +[[keyboard.bindings]] +key = "End" +mods = "Shift" +mode = "~Alt" +action = "ScrollToBottom" + +[[keyboard.bindings]] +key = "V" +mods = "Control|Shift" +action = "Paste" + +[[keyboard.bindings]] +key = "C" +mods = "Control|Shift" +action = "Copy" + +[[keyboard.bindings]] +key = "F" +mods = "Control|Shift" +action = "SearchForward" + +[[keyboard.bindings]] +key = "B" +mods = "Control|Shift" +action = "SearchBackward" + +[[keyboard.bindings]] +key = "C" +mods = "Control|Shift" +mode = "Vi" +action = "ClearSelection" + +[[keyboard.bindings]] +key = "Key0" +mods = "Control" +action = "ResetFontSize" + +[general] +live_config_reload = true +working_directory = "None" +import = ["~/.config/alacritty/catppuccin-mocha.toml"] diff --git a/alacritty/catppuccin-macchiato.toml b/alacritty/catppuccin-macchiato.toml new file mode 100644 index 0000000..64b6214 --- /dev/null +++ b/alacritty/catppuccin-macchiato.toml @@ -0,0 +1,65 @@ +[colors.primary] +background = "#24273a" +foreground = "#cad3f5" +dim_foreground = "#8087a2" +bright_foreground = "#cad3f5" + +[colors.cursor] +text = "#24273a" +cursor = "#f4dbd6" + +[colors.vi_mode_cursor] +text = "#24273a" +cursor = "#b7bdf8" + +[colors.search.matches] +foreground = "#24273a" +background = "#a5adcb" + +[colors.search.focused_match] +foreground = "#24273a" +background = "#a6da95" + +[colors.footer_bar] +foreground = "#24273a" +background = "#a5adcb" + +[colors.hints.start] +foreground = "#24273a" +background = "#eed49f" + +[colors.hints.end] +foreground = "#24273a" +background = "#a5adcb" + +[colors.selection] +text = "#24273a" +background = "#f4dbd6" + +[colors.normal] +black = "#494d64" +red = "#ed8796" +green = "#a6da95" +yellow = "#eed49f" +blue = "#8aadf4" +magenta = "#f5bde6" +cyan = "#8bd5ca" +white = "#b8c0e0" + +[colors.bright] +black = "#5b6078" +red = "#ed8796" +green = "#a6da95" +yellow = "#eed49f" +blue = "#8aadf4" +magenta = "#f5bde6" +cyan = "#8bd5ca" +white = "#a5adcb" + +[[colors.indexed_colors]] +index = 16 +color = "#f5a97f" + +[[colors.indexed_colors]] +index = 17 +color = "#f4dbd6" diff --git a/alacritty/catppuccin-mocha.toml b/alacritty/catppuccin-mocha.toml new file mode 100644 index 0000000..de33f2d --- /dev/null +++ b/alacritty/catppuccin-mocha.toml @@ -0,0 +1,65 @@ +[colors.primary] +background = "#1e1e2e" +foreground = "#cdd6f4" +dim_foreground = "#7f849c" +bright_foreground = "#cdd6f4" + +[colors.cursor] +text = "#1e1e2e" +cursor = "#f5e0dc" + +[colors.vi_mode_cursor] +text = "#1e1e2e" +cursor = "#b4befe" + +[colors.search.matches] +foreground = "#1e1e2e" +background = "#a6adc8" + +[colors.search.focused_match] +foreground = "#1e1e2e" +background = "#a6e3a1" + +[colors.footer_bar] +foreground = "#1e1e2e" +background = "#a6adc8" + +[colors.hints.start] +foreground = "#1e1e2e" +background = "#f9e2af" + +[colors.hints.end] +foreground = "#1e1e2e" +background = "#a6adc8" + +[colors.selection] +text = "#1e1e2e" +background = "#f5e0dc" + +[colors.normal] +black = "#45475a" +red = "#f38ba8" +green = "#a6e3a1" +yellow = "#f9e2af" +blue = "#89b4fa" +magenta = "#f5c2e7" +cyan = "#94e2d5" +white = "#bac2de" + +[colors.bright] +black = "#585b70" +red = "#f38ba8" +green = "#a6e3a1" +yellow = "#f9e2af" +blue = "#89b4fa" +magenta = "#f5c2e7" +cyan = "#94e2d5" +white = "#a6adc8" + +[[colors.indexed_colors]] +index = 16 +color = "#fab387" + +[[colors.indexed_colors]] +index = 17 +color = "#f5e0dc" diff --git a/cava/config b/cava/config new file mode 100644 index 0000000..fd54a3f --- /dev/null +++ b/cava/config @@ -0,0 +1,280 @@ +## Configuration file for CAVA. +# Remove the ; to change parameters. + + +[general] + +# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0 +; mode = normal + +# Accepts only non-negative values. +; framerate = 60 + +# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off +# new as of 0.6.0 autosens of low values (dynamic range) +# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0 +; autosens = 1 +; overshoot = 20 + +# Manual sensitivity in %. If autosens is enabled, this will only be the initial value. +# 200 means double height. Accepts only non-negative values. +; sensitivity = 100 + +# The number of bars (0-512). 0 sets it to auto (fill up console). +# Bars' width and space between bars in number of characters. +; bars = 0 +; bar_width = 2 +; bar_spacing = 1 +# bar_height is only used for output in "noritake" format +; bar_height = 32 + +# For SDL width and space between bars is in pixels, defaults are: +; bar_width = 20 +; bar_spacing = 5 + +# sdl_glsl have these default values, they are only used to calculate max number of bars. +; bar_width = 1 +; bar_spacing = 0 + + +# Lower and higher cutoff frequencies for lowest and highest bars +# the bandwidth of the visualizer. +# Note: there is a minimum total bandwidth of 43Mhz x number of bars. +# Cava will automatically increase the higher cutoff if a too low band is specified. +; lower_cutoff_freq = 50 +; higher_cutoff_freq = 10000 + + +# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and +# only check for input once per second. Cava will wake up once input is detected. 0 = disable. +; sleep_timer = 0 + + +[input] + +# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem' +# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with. +# On Mac it defaults to 'portaudio' or 'fifo' +# On windows this is automatic and no input settings are needed. +# +# All input methods uses the same config variable 'source' +# to define where it should get the audio. +# +# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink +# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them). +# +# For pipewire 'source' will be the object name or object.serial of the device to capture from. +# Both input and output devices are supported. +# +# For alsa 'source' will be the capture device. +# For fifo 'source' will be the path to fifo-file. +# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address +# +# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'. +# README.md contains further information on how to setup CAVA for sndio. +# +# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device. +# README.md contains further information on how to setup CAVA for OSS on FreeBSD. +# +# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'. +# README.md contains further information on how to setup CAVA for JACK. +# +; method = pulse +; source = auto + +method = pipewire +source = auto + +; method = alsa +; source = hw:Loopback,1 + +; method = fifo +; source = /tmp/mpd.fifo + +; method = shmem +; source = /squeezelite-AA:BB:CC:DD:EE:FF + +; method = portaudio +; source = auto + +; method = sndio +; source = default + +; method = oss +; source = /dev/dsp + +; method = jack +; source = default + +# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods: +# sample_rate: fifo, pipewire, sndio, oss +# sample_bits: fifo, pipewire, sndio, oss +# channels: sndio, oss, jack +# autoconnect: jack +# Other methods ignore these settings. +# +# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported +# by the chosen audio device, the device will use other supported values instead. +# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it +# will use 44100, 16 and 1. +# +; sample_rate = 44100 +; sample_bits = 16 +; channels = 2 +; autoconnect = 2 + + +[output] + +# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl' +# or 'sdl_glsl'. +# 'noncurses' (default) uses a buffer and cursor movements to only print +# changes from frame to frame in the terminal. Uses less resources and is less +# prone to tearing (vsync issues) than 'ncurses'. +# +# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data +# stream of the bar heights that can be used to send to other applications. +# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above. +# +# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display +# in graphic mode. It only support the 3000 series graphical VFDs for now. +# +# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context. +# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or +# use one of the predefined ones. +; method = noncurses + +# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or +# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl +# and ncruses output. 'horizontal' (bars go up and down from center) is only supported +# on noncurses output. +# Note: many fonts have weird or missing glyphs for characters used in orientations +# other than 'bottom', which can make output not look right. +; orientation = bottom + +# Visual channels. Can be 'stereo' or 'mono'. +# 'stereo' mirrors both channels with low frequencies in center. +# 'mono' outputs left to right lowest to highest frequencies. +# 'mono_option' set mono to either take input from 'left', 'right' or 'average'. +# set 'reverse' to 1 to display frequencies the other way around. +channels = mono +mono_option = average +; reverse = 0 + +# Raw output target. A fifo will be created if target does not exist. +; raw_target = /dev/stdout + +# Raw data format. Can be 'binary' or 'ascii'. +; data_format = binary + +# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530). +; bit_format = 16bit + +# Ascii max value. In 'ascii' mode range will run from 0 to value specified here +; ascii_max_range = 1000 + +# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters. +# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)). +; bar_delimiter = 59 +; frame_delimiter = 10 + +# sdl window size and position. -1,-1 is centered. +; sdl_width = 1000 +; sdl_height = 500 +; sdl_x = -1 +; sdl_y= -1 +; sdl_full_screen = 0 + +# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none' +# 'frequency' displays the lower cut off frequency of the bar above. +# Only supported on ncurses and noncurses output. +; xaxis = none + +# enable synchronized sync. 1 = on, 0 = off +# removes flickering in alacritty terminal emulator. +# defaults to off since the behaviour in other terminal emulators is unknown +; synchronized_sync = 0 + +# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders +; vertex_shader = pass_through.vert +; fragment_shader = bar_spectrum.frag + +; for glsl output mode, keep rendering even if no audio +; continuous_rendering = 0 + +# disable console blank (screen saver) in tty +# (Not supported on FreeBSD) +; disable_blanking = 0 + +# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off +; show_idle_bar_heads = 1 + +# show waveform instead of frequency spectrum, 1 = on, 0 = off +; waveform = 0 + +[color] + +# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow. +# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires +# a terminal that can change color definitions such as Gnome-terminal or rxvt. +# default is to keep current terminal color +; background = default +foreground = '#b4befe' + +# SDL and sdl_glsl only support hex code colors, these are the default: +; background = '#111111' +; foreground = '#33ffff' + + +# Gradient mode, only hex defined colors are supported, +# background must also be defined in hex or remain commented out. 1 = on, 0 = off. +# You can define as many as 8 different colors. They range from bottom to top of screen +; gradient = 0 +; gradient_color_1 = '#59cc33' +; gradient_color_2 = '#80cc33' +; gradient_color_3 = '#a6cc33' +; gradient_color_4 = '#cccc33' +; gradient_color_5 = '#cca633' +; gradient_color_6 = '#cc8033' +; gradient_color_7 = '#cc5933' +; gradient_color_8 = '#cc3333' + + + +[smoothing] + +# Percentage value for integral smoothing. Takes values from 0 - 100. +# Higher values means smoother, but less precise. 0 to disable. +# DEPRECATED as of 0.8.0, use noise_reduction instead +; integral = 77 + +# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable. +; monstercat = 0 +; waves = 0 + +# Set gravity percentage for "drop off". Higher values means bars will drop faster. +# Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off". +# DEPRECATED as of 0.8.0, use noise_reduction instead +; gravity = 100 + + +# In bar height, bars that would have been lower that this will not be drawn. +# DEPRECATED as of 0.8.0 +; ignore = 0 + +# Noise reduction, int 0 - 100. default 77 +# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth +# 100 will be very slow and smooth, 0 will be fast but noisy. +; noise_reduction = 77 + + +[eq] + +# This one is tricky. You can have as much keys as you want. +# Remember to uncomment more than one key! More keys = more precision. +# Look at readme.md on github for further explanations and examples. +1 = 2 # bass +2 = 1.5 +3 = 1 # midtone +4 = 1 +5 = 0.5 # treble diff --git a/cava/shaders/bar_spectrum.frag b/cava/shaders/bar_spectrum.frag new file mode 100644 index 0000000..b078913 --- /dev/null +++ b/cava/shaders/bar_spectrum.frag @@ -0,0 +1,79 @@ +#version 330 + +in vec2 fragCoord; +out vec4 fragColor; + +// bar values. defaults to left channels first (low to high), then right (high to low). +uniform float bars[512]; + +uniform int bars_count; // number of bars (left + right) (configurable) +uniform int bar_width; // bar width (configurable), not used here +uniform int bar_spacing; // space bewteen bars (configurable) + +uniform vec3 u_resolution; // window resolution + +//colors, configurable in cava config file (r,g,b) (0.0 - 1.0) +uniform vec3 bg_color; // background color +uniform vec3 fg_color; // foreground color + +uniform int gradient_count; +uniform vec3 gradient_colors[8]; // gradient colors + +vec3 normalize_C(float y,vec3 col_1, vec3 col_2, float y_min, float y_max) +{ + //create color based on fraction of this color and next color + float yr = (y - y_min) / (y_max - y_min); + return col_1 * (1.0 - yr) + col_2 * yr; +} + +void main() +{ + // find which bar to use based on where we are on the x axis + float x = u_resolution.x * fragCoord.x; + int bar = int(bars_count * fragCoord.x); + + //calculate a bar size + float bar_size = u_resolution.x / bars_count; + + //the y coordinate and bar values are the same + float y = bars[bar]; + + // make sure there is a thin line at bottom + if (y * u_resolution.y < 1.0) + { + y = 1.0 / u_resolution.y; + } + + //draw the bar up to current height + if (y > fragCoord.y) + { + //make some space between bars basen on settings + if (x > (bar + 1) * (bar_size) - bar_spacing) + { + fragColor = vec4(bg_color,1.0); + } + else + { + if (gradient_count == 0) + { + fragColor = vec4(fg_color,1.0); + } + else + { + //find which color in the configured gradient we are at + int color = int((gradient_count - 1) * fragCoord.y); + + //find where on y this and next color is supposed to be + float y_min = color / (gradient_count - 1.0); + float y_max = (color + 1.0) / (gradient_count - 1.0); + + //make color + fragColor = vec4(normalize_C(fragCoord.y, gradient_colors[color], gradient_colors[color + 1], y_min, y_max), 1.0); + } + } + } + else + { + fragColor = vec4(bg_color,1.0); + } +} \ No newline at end of file diff --git a/cava/shaders/northern_lights.frag b/cava/shaders/northern_lights.frag new file mode 100644 index 0000000..ecd859a --- /dev/null +++ b/cava/shaders/northern_lights.frag @@ -0,0 +1,34 @@ +#version 330 + +in vec2 fragCoord; +out vec4 fragColor; + +// bar values. defaults to left channels first (low to high), then right (high to low). +uniform float bars[512]; + +uniform int bars_count; // number of bars (left + right) (configurable) + +uniform vec3 u_resolution; // window resolution, not used here + +//colors, configurable in cava config file +uniform vec3 bg_color; // background color(r,g,b) (0.0 - 1.0), not used here +uniform vec3 fg_color; // foreground color, not used here + +void main() +{ + // find which bar to use based on where we are on the x axis + int bar = int(bars_count * fragCoord.x); + + float bar_y = 1.0 - abs((fragCoord.y - 0.5)) * 2.0; + float y = (bars[bar]) * bar_y; + + float bar_x = (fragCoord.x - float(bar) / float(bars_count)) * bars_count; + float bar_r = 1.0 - abs((bar_x - 0.5)) * 2; + + bar_r = bar_r * bar_r * 2; + + // set color + fragColor.r = fg_color.x * y * bar_r; + fragColor.g = fg_color.y * y * bar_r; + fragColor.b = fg_color.z * y * bar_r; +} diff --git a/cava/shaders/pass_through.vert b/cava/shaders/pass_through.vert new file mode 100644 index 0000000..a4f20e5 --- /dev/null +++ b/cava/shaders/pass_through.vert @@ -0,0 +1,14 @@ +#version 330 + + +// Input vertex data, different for all executions of this shader. +layout(location = 0) in vec3 vertexPosition_modelspace; + +// Output data ; will be interpolated for each fragment. +out vec2 fragCoord; + +void main() +{ + gl_Position = vec4(vertexPosition_modelspace,1); + fragCoord = (vertexPosition_modelspace.xy+vec2(1,1))/2.0; +} diff --git a/cava/shaders/spectrogram.frag b/cava/shaders/spectrogram.frag new file mode 100644 index 0000000..ccb79ae --- /dev/null +++ b/cava/shaders/spectrogram.frag @@ -0,0 +1,53 @@ +#version 330 + +in vec2 fragCoord; +out vec4 fragColor; + +// bar values. defaults to left channels first (low to high), then right (high +// to low). +uniform float bars[512]; + +uniform int bars_count; // number of bars (left + right) (configurable) +uniform int bar_width; // bar width (configurable), not used here +uniform int bar_spacing; // space bewteen bars (configurable) + +uniform vec3 u_resolution; // window resolution + +// colors, configurable in cava config file (r,g,b) (0.0 - 1.0) +uniform vec3 bg_color; // background color +uniform vec3 fg_color; // foreground color + +uniform int gradient_count; +uniform vec3 gradient_colors[8]; // gradient colors + +uniform sampler2D inputTexture; // Texture from the first render pass + +vec3 normalize_C(float y, vec3 col_1, vec3 col_2, float y_min, float y_max) { + // create color based on fraction of this color and next color + float yr = (y - y_min) / (y_max - y_min); + return col_1 * (1.0 - yr) + col_2 * yr; +} + +void main() { + // find which bar to use based on where we are on the y axis + int bar = int(bars_count * fragCoord.y); + float y = bars[bar]; + float band_size = 1.0 / float(bars_count); + float current_band_min = bar * band_size; + float current_band_max = (bar + 1) * band_size; + + int hist_length = 512; + float win_size = 1.0 / hist_length; + + if (fragCoord.x > 1.0 - win_size) { + + if (fragCoord.y > current_band_min && fragCoord.y < current_band_max) { + + fragColor = vec4(fg_color * y, 1.0); + } + } else { + vec2 offsetCoord = fragCoord; + offsetCoord.x += float(win_size); + fragColor = texture(inputTexture, offsetCoord); + } +} \ No newline at end of file diff --git a/cava/shaders/winamp_line_style_spectrum.frag b/cava/shaders/winamp_line_style_spectrum.frag new file mode 100644 index 0000000..375ff27 --- /dev/null +++ b/cava/shaders/winamp_line_style_spectrum.frag @@ -0,0 +1,112 @@ +#version 330 + +// Emulate the "line style" spectrum analyzer from Winamp 2. +// Try this config for a demonstration: + +/* +[general] +bar_width = 2 +bar_spacing = 0 +higher_cutoff_freq = 22000 + +[output] +method = sdl_glsl +channels = mono +fragment_shader = winamp_line_style_spectrum.frag + +[color] +background = '#000000' +gradient = 1 +gradient_color_1 = '#319C08' +gradient_color_2 = '#29CE10' +gradient_color_3 = '#BDDE29' +gradient_color_4 = '#DEA518' +gradient_color_5 = '#D66600' +gradient_color_6 = '#CE2910' + +[smoothing] +noise_reduction = 10 +*/ + +in vec2 fragCoord; +out vec4 fragColor; + +// bar values. defaults to left channels first (low to high), then right (high to low). +uniform float bars[512]; + +uniform int bars_count; // number of bars (left + right) (configurable) +uniform int bar_width; // bar width (configurable), not used here +uniform int bar_spacing; // space bewteen bars (configurable) + +uniform vec3 u_resolution; // window resolution + +//colors, configurable in cava config file (r,g,b) (0.0 - 1.0) +uniform vec3 bg_color; // background color +uniform vec3 fg_color; // foreground color + +uniform int gradient_count; +uniform vec3 gradient_colors[8]; // gradient colors + +vec3 normalize_C(float y,vec3 col_1, vec3 col_2, float y_min, float y_max) +{ + //create color based on fraction of this color and next color + float yr = (y - y_min) / (y_max - y_min); + return col_1 * (1.0 - yr) + col_2 * yr; +} + +void main() +{ + // find which bar to use based on where we are on the x axis + float x = u_resolution.x * fragCoord.x; + int bar = int(bars_count * fragCoord.x); + + //calculate a bar size + float bar_size = u_resolution.x / bars_count; + + //the y coordinate is stretched by 4X to resemble Winamp + float y = min(bars[bar] * 4.0, 1.0); + + // make sure there is a thin line at bottom + if (y * u_resolution.y < 1.0) + { + y = 1.0 / u_resolution.y; + } + + vec4 bar_color; + + if (gradient_count == 0) + { + bar_color = vec4(fg_color,1.0); + } + else + { + //find color in the configured gradient for the top of the bar + int color = int((gradient_count - 1) * y); + + //find where on y this and next color is supposed to be + float y_min = float(color) / (gradient_count - 1.0); + float y_max = float(color + 1) / (gradient_count - 1.0); + + //make a solid color for the entire bar + bar_color = vec4(normalize_C(y, gradient_colors[color], gradient_colors[color + 1], y_min, y_max), 1.0); + } + + + //draw the bar up to current height + if (y > fragCoord.y) + { + //make some space between bars based on settings + if (x > (bar + 1) * (bar_size) - bar_spacing) + { + fragColor = vec4(bg_color,1.0); + } + else + { + fragColor = bar_color; + } + } + else + { + fragColor = vec4(bg_color,1.0); + } +} \ No newline at end of file diff --git a/fastfetch/brief.jsonc b/fastfetch/brief.jsonc new file mode 100644 index 0000000..daa4c37 --- /dev/null +++ b/fastfetch/brief.jsonc @@ -0,0 +1,24 @@ +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "display": { + "key": { + // "width": 14 + } + }, + "modules": [ + { "type": "title" }, + { "type": "separator" }, + { "key": " os", "type": "os" }, + { "key": "┠ host", "type": "host" }, + { "key": "┠ cpu", "type": "cpu" }, + { "key": "┠ gpu", "type": "gpu" }, + { "key": "┖ uptime", "type": "uptime" }, + { "type": "break" }, + { "key": " display", "type": "display" }, + { "key": "┠ wm", "type": "wm" }, + { "key": "┠ de", "type": "de" }, + { "key": "┠ shell", "type": "shell" }, + { "key": "┖ terminal", "type": "terminal" }, + { "type": "break" } + ] +} diff --git a/fastfetch/config.jsonc b/fastfetch/config.jsonc new file mode 100755 index 0000000..2b9b235 --- /dev/null +++ b/fastfetch/config.jsonc @@ -0,0 +1,31 @@ +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "display": { + "key": { + // "width": 14 + } + }, + "modules": [ + { "type": "title" }, + { "type": "separator" }, + { "key": " os", "type": "os" }, + { "key": "┠ host", "type": "host" }, + { "key": "┠ kernel", "type": "kernel" }, + { "key": "┠ uptime", "type": "uptime" }, + { "key": "┖ packages", "type": "packages" }, + { "type": "break" }, + { "key": " display", "type": "display" }, + { "key": "┠ de", "type": "de" }, + { "key": "┠ wm", "type": "wm" }, + { "key": "┠ font", "type": "terminalfont" }, + { "key": "┠ shell", "type": "shell" }, + { "key": "┖ terminal", "type": "terminal" }, + { "type": "break" }, + { "key": " cpu", "type": "cpu" }, + { "key": "┠ gpu", "type": "gpu" }, + { "key": "┠ memory", "type": "memory" }, + { "key": "┠ disk", "type": "disk" }, + { "key": "┠ localip", "type": "localip" }, + { "key": "┖ publicip", "type": "publicip" } + ] +} diff --git a/fastfetch/logo_gg/24x.sixel b/fastfetch/logo_gg/24x.sixel new file mode 100644 index 0000000..2a400e9 --- /dev/null +++ b/fastfetch/logo_gg/24x.sixel @@ -0,0 +1,2 @@ +[?25l[?80l[?8452lP0;1;0q"1;1;240;360#0;2;14;12;14#1;2;14;16;20#2;2;15;18;22#3;2;16;18;23#4;2;16;19;23#5;2;16;20;23#6;2;23;11;12#7;2;23;15;16#8;2;21;19;21#9;2;24;25;29#10;2;34;15;16#11;2;37;23;23#12;2;45;21;17#13;2;61;23;22#14;2;31;32;35#15;2;43;34;34#16;2;57;32;14#17;2;56;37;32#18;2;45;39;39#19;2;59;41;29#20;2;51;45;46#21;2;56;53;55#22;2;65;39;20#23;2;72;47;23#24;2;68;51;41#25;2;80;51;16#26;2;72;56;51#27;2;81;56;25#28;2;87;56;58#29;2;87;58;60#30;2;70;61;55#31;2;67;64;70#32;2;81;62;41#33;2;80;67;71#34;2;87;62;30#35;2;89;63;65#36;2;88;63;69#37;2;89;66;70#38;2;78;68;71#39;2;80;68;70#40;2;75;70;74#41;2;76;76;83#42;2;90;69;40#43;2;92;75;32#44;2;87;72;76#45;2;87;76;79#46;2;95;71;43#47;2;96;74;32#48;2;96;76;31#49;2;98;76;81#50;2;96;76;31#51;2;99;77;80#52;2;98;77;81#53;2;99;77;80#54;2;97;78;45#55;2;99;77;80#56;2;98;78;81#57;2;99;77;82#58;2;99;78;83#59;2;99;78;83#60;2;90;80;56#61;2;96;81;41#62;2;89;82;85#63;2;97;83;85#64;2;98;82;61#65;2;98;84;84#66;2;98;85;86#67;2;98;86;87#68;2;99;81;83#69;2;99;87;87#70;2;99;87;87#71;2;91;85;89#72;2;98;86;88#73;2;99;87;87#74;2;97;88;53#75;2;97;88;88#76;2;97;88;89#77;2;100;89;89#78;2;98;88;90#79;2;99;88;90#80;2;100;88;90#81;2;96;88;91#82;2;99;88;91#83;2;99;88;91#84;2;100;89;90#85;2;99;90;57#86;2;98;91;89#87;2;98;91;90#88;2;99;92;90#89;2;94;91;94#90;2;98;92;93#91;2;99;92;93#92;2;99;93;93#93;2;98;93;93#94;2;99;93;91#95;2;98;95;95#96;2;98;96;97#97;2;98;97;97#98;2;99;98;99#99;2;99;99;99#100;2;100;100;100#101;2;93;93;93#102;2;71;22;37#103;2;33;33;36#104;2;50;22;19#105;2;62;24;21#106;2;37;20;17#107;2;34;26;27#108;2;77;50;49#109;2;81;52;56#110;2;35;15;17#111;2;36;17;18#112;2;42;31;30#113;2;44;36;35#114;2;81;56;20#115;2;82;56;62#116;2;65;46;31#117;2;74;47;15#118;2;63;38;17#119;2;65;43;23#120;2;23;21;23#121;2;25;26;29#122;2;81;67;70#123;2;80;67;70#124;2;73;61;61#125;2;76;61;50#126;2;92;80;47#127;2;87;80;82#128;2;55;50;50#129;2;57;55;56#130;2;89;69;36#131;2;87;69;72#132;2;20;11;12#133;2;22;12;13#134;2;59;41;23#135;2;59;41;44#136;2;87;56;59#137;2;88;57;56#138;2;86;58;58#139;2;88;58;59#140;2;87;63;27#141;2;88;61;61#142;2;77;73;76#143;2;77;76;81#144;2;70;50;33#145;2;67;51;54#146;2;96;81;39#147;2;96;81;82#148;2;87;62;68#149;2;89;65;69#150;2;13;16;20#151;2;16;16;19#152;2;14;11;13#153;2;13;13;16#154;2;16;18;22#155;2;16;18;23#156;2;50;45;47#157;2;60;45;43#158;2;88;61;65#159;2;90;65;65#160;2;58;31;10#161;2;55;33;38#162;2;65;61;69#163;2;71;65;70#164;2;19;18;23#165;2;23;19;20#166;2;81;61;35#167;2;81;63;66#168;2;85;76;79#169;2;91;76;78#170;2;71;56;45#171;2;70;56;60#172;2;87;66;70#173;2;90;66;70#174;2;45;20;21#175;2;46;25;18#176;2;45;40;41#177;2;54;40;39#178;2;92;75;30#179;2;88;72;72#180;2;95;72;40#181;2;97;72;76#182;2;16;20;23#183;2;56;37;23#184;2;56;37;39#185;2;96;82;85#186;2;97;85;85#187;2;15;19;23#188;2;16;19;23#189;2;80;66;70#190;2;80;67;71#191;2;80;68;70#192;2;80;68;71#193;2;94;92;93#194;2;96;91;93#195;2;14;18;22#196;2;15;18;23#197;2;90;70;75#198;2;87;73;77#199;2;96;74;30#200;2;98;74;79#201;2;87;82;85#202;2;94;82;85#203;2;97;88;51#204;2;99;88;86#205;2;98;94;95#206;2;99;95;95#207;2;99;87;87#208;2;96;88;89#209;2;99;89;89#210;2;99;89;54#211;2;99;90;87#212;2;98;90;92#213;2;98;92;93#214;2;98;76;81#215;2;99;77;81#216;2;99;77;81#217;2;99;78;83#218;2;98;82;53#219;2;98;82;82#220;2;98;84;86#221;2;98;86;86#222;2;99;87;89#223;2;99;87;87#224;2;100;89;89#225;2;100;88;90#226;2;16;19;23#227;2;98;83;84#228;2;98;85;84#229;2;98;90;89#230;2;99;91;89#231;2;98;97;96#232;2;98;98;98#233;2;20;15;16#234;2;26;15;15#235;2;98;76;75#236;2;98;76;78#237;2;97;78;81#238;2;98;78;81#239;2;98;85;88#240;2;98;87;88#241;2;96;88;88#242;2;99;88;88#243;2;99;88;91#244;2;99;89;91#245;2;99;89;91#0!240?$#21!46?_$#129!44?__?__-#18!31?_!18?C$#20!58?O?_$#21!35?O!18?@$#38!33?G!6?AG$#40!51?G$#62!30?O???_!14?G!7?C!5?_$#71!38?A!9?G$#76!46?@$#81!29?O?G???A!18?A!5?G$#87!42?@!6?@$#96!39?O$#97!36?_!13?OO$#98!40?O??_!12?__$#99!37?!4_o_Oo___oo__o___$#124!41?A!10?G$#127!37?O!12?G$#128!34?G!4?G???A!5?A!4?G!5?O$#129!33?A!24?A???G!20?__$#135!32?O!5?G??C??A???A$#142!32?C!26?G$#143!29?G!7?@$#145!37?C!12?A!4?C??G???_$#156!36?@$#161!53?C$#163!27?O???C??A?S!16?@???A?_!5?_$#168!35?C???A??G!10?A??O???C$#171!31?O?_!6?G?A!8?A?G???O$#176!43?C!5?C!9?O?_$#177!30?_?_OOGGGCCC?C?CEEEC??CC?CGGG$#189!29?_!22?A$#190!56?C$#192!61?O$#193!26?_!11?P@!15?O??_$#194!27?_O!12?@???GGG!7?AA??C?G?O_$#201!43?G$#202!32?G$#205!35?_$#208!28?_?G??C??A???@???H@??@???@$#212!50?@@!6?C$#232!42?O??OOO!5?OO$#241!34?C??A$#245!43?@???@!14?O-#18!90?CCC$#20!27?C??@!31?@@?C!4?CC???CCC!9?CC!12?G$#21!16?CC??A!78?@!5?AAA!6?CC!5?O??_$#38!13?_!58?A!16?A!4?O?G!4?C!4?G?_!5?O???_$#40!28?C!38?O$#44!71?A$#62!15?O!48?G??G??A!24?A!23?_$#66!37?CCGK!4C$#71!12?_!5?G!6?A?G??A?@!58?G!9?O?C??_???G!5?O$#72!31?_??_???O$#73!43?I?A$#77!43?!4owooo?G??ooo$#78!33?G!4?A!9?A!14?O_!4?_!7?!4_$#79!36?___?o!7?C!14?_$#81!17?G?CC_?A!6?O?G!4?A!4?@@@!7?A!8?G???O??_!4?_!9?_!13?AAA?AA?C!13?OO___$#82!50?C!19?___?_!6?_$#84!39?_!10?GG!4?G?o$#86!53?_$#87!54?G?C!17?!4@!8?___?_$#88!51?_$#89!15?G$#90!58?C!5?O!27?__$#91!55?C$#93!36?A!18?AA???C!32?O$#96!25?_?_GC???@?A??@!12?@@!4?A???A!9?G!7?G???O!4?G!11?O???_$#97!26?_!4?C???@?@!34?GGG!10?GG!5?O$#98!28?O!5?A!18?@@!5?A!14?GG???!5GOOO?OO!7?_O$#99!27?O!5?A??@!18?@@?@!40?__$#101!96?@@$#113!19?O??GG!4?A@$#124!23?C?OA!4?@!42?!6A!6?AAA!6?G?G!11?_???O$#127!27?@!65?AA_!11?_?G$#128!28?@!34?AC?G??C??CCC???!9C!10?C??G!4?O!6?_$#129!29?A!65?O???G$#135!23?OO!39?A!30?CC!5?GG??O??OO??!4_$#142!68?C!33?O!4?G!12?O$#143!21?A!76?@!14?C$#145!14?_??O?_G?_?C?G!38?G!27?G!4?CC!4?W!6?_O!4?_$#157!21?O!72?G!16?O$#161!16?__$#163!8?_??O??G!9?_!41?P!6?A!22?_!6?O!14?G$#168!20?_?C!39?AC@!27?I!9?C!5?G!6?O$#171!22?O!38?@!18?!6A!12?G?C!4?G!4?_$#177!15?_??o??G?_?CCA!61?C???CC!12?OO$#184!20?O???GG$#186!34?G?C$#189!16?O$#190!19?G$#191!90?A$#192!65?AC!24?A$#193!9?_??OO!46?@!29?G???@@O!7?A!12?G$#194!10?__??O?G?C???A?@@!40?AEA?@?@@!4?@!6?_?!7@!6?A??A???!5CK?GGG!6?_$#202!67?_$#205!26?O!4?G!16?@@@!17?WG!5?O!13?G!4?_$#206!29?O???C!5?@!21?CCG!5?OW!4O?O!5?O!22?_$#208!31?O???C!15?A!17?A?@!24?A!14?G$#209!45?G$#212!24?A?@?_!5?C!6?@???@@@!5?MC??KGww_???`!13?!4@?`@@??_?_!13?CC!6?G???O$#213!40?@!13?A!4?C??G!14?!5O?@$#220!36?GGG??G$#221!42?G$#222!32?O??_???OA!5?CC$#223!45?C$#225!49?C$#229!46?G!6?OoG$#230!51?Oo$#232!29?GKAE?@!22?@AB!17?GG!5?O??GO??O!5?oO??___$#239!32?_oOWOO?E?AA?A?AA$#241!21?C!7?__!18?AA!15?_$#242!44?G$#243!75?__$#244!41?oo!6?G?CC!8?O_$#245!48?G!13?O!19?_-#18!7?C??E!11?@$#20!9?A!6?@!105?A$#38!7?O!7?A!89?G!9?@$#40!119?C$#45!106?O?G$#62!10?G!10?C!74?@!9?_!6?G$#71GGG!10?C???O@!78?@!15?@!12?A$#72!30?@@!59?@!12?__!6?_$#75!94?AA$#77!43?FFNFF^^^}}}!4~}wwoowoowow}{{sss!5{}{{w{!5oO!5?owoow$#78!26?A@!39?@@!30?CC!6?_Cc???_$#79!24?_??G?CK?@@??@?@@AA???_?_!21?@@@??!4@!12?@??A!16?_$#81??C??A!11?G??@_!91?O!9?@@??AA?G$#82!26?_!19?_!54?C?_$#83!28?GG!15?O?O!32?@$#84!42?@!4?G!10?@!5?G!20?C??GG!11?_$#86!51?@$#87!10?_$#89!7?@!113?C!10?OO$#90!91?C$#93!15?_!10?@!72?A!4?A$#95!9?_!10?_??C!82?A$#96!6?_!4?W??C?C?A!4?AB!74?!4@!7?A@???IA???_!4?G???_$#97!8?_?O??G?C__?O!5?@!77?@!4?@??A!4?O$#98!12?G!4?A??O!91?AAA?GGO??_??GOOO_??_$#99!118?!6G??__$#100!119?OOOooo_$#113??_!10?@$#124!8?A!8?@!89?O?G?G!4?@$#127!5?_?A!96?O!14?A??@??A$#128!4?G?O!4?C!8?C!99?@??A?C!9?O$#129!114?CC!5?A!6?G$#135_?O!115?@$#142!6?@???@!7?O!4?@!96?C!8?GC?G$#143!126?@$#145!6?C!4?@??A!5?A@!88?G!6?@!8?C$#161?_?oOG!8?@$#162!18?G!98?C!6?C$#163?C?A!8?C!99?C!5?C?A@??A$#168!5?C!16?A!83?C!4?CG?@!8?C??G??O$#171!4?_!4?G!9?K!93?C??C!10?G$#176!5?O$#177!6?GGKC?ABA!7?A!97?@$#184!15?@$#186!23?_$#189?O!106?O$#192???G$#193!8?O!122?G??o__$#194!4?A?A?@!6?GQ!86?A!10?G!14?C?O$#198!127?C$#201!130?O$#202O!103?GOG??O$#205!20?G?G!75?@!6?A???A??@??O???_??C!5?O!4?_$#206!14?G!4?@?O!78?A!6?AA!8?A$#208???CC!4?@?_?o_?G!6?GC!68?@?@!18?_??_!7?@??C$#209!34?@!13?___!19?AAIII!5A?AAE!14?GG$#212!18?CA!5?A!33?FFF!7E!17?CCEEKw{{wo??A??OA!15?a$#213!12?O!4?C!83?A!12?O$#220!25?G$#222!27?C??A!61?@???C!14?O$#224!43?G!18?G??G?G!17?GGG??_!5?G$#225!27?!4ow}}}~}~}}{{}ow!27?@@!4?@@!4?A$#229!53?@$#230!52?@$#232!7?_?O!8?__?GC!81?!4@?@@!6?O!12?_?_$#239!23?OWCKABB!66?AA!9?K???_$#240!97?CC!11?O$#241!12?_?OO!6?o!71?@!10?C!4?C!4?__$#243!25?oO?C??A!8?@!5?O!41?@@?AA$#244!41?@!4?G!15?@@@!16?@@?@?AA??A???CG!6?s[!4?_$#245!31?C!29?G???@@!16?@?B@@!7?C!5?GG?C!7?O-#15!50?G$#20?@!137?G?O$#36!49?_$#44!50?O$#45!46?_!4?C!90?G$#71!4?C?G!130?G$#72!11?@!7?G!31?O$#75!115?@@!10?O?_$#76!121?A$#77!59?!7BA!13B!6Z^^!13ZzZ~zz!6w}}wwywwywwwg!5_$#78!18?C???A@!22?O??C??O!65?@@A?A?CC!4?_$#79!18?_?_o?C!4?__!13?O_S@@?@@`@O!22?!4O$#81!8?@!120?O?_!8?C!8?_$#82!17?gO!26?G?E??A!7?C!18?G_!33?@$#83!19?_?GCA!20?G!6?A?G??CC$#84!88?__?_??_!4?_!6?B$#86!123?O$#87!20?@$#89?O$#90!15?O$#93!128?G???_$#95!122?@$#96?ACO?O@!7?@???A@!103?@?A!7?_?@$#97!10?C_!4?C!112?G!6?G?O$#98?C??P@?G_?_??O?H!108?@?A!5?O?@$#99!7_?WwW[[KKEB@@!106?@@BFFNNN^}}qo_$#101!136?@$#122!47?O$#124!141?G$#127!5?CC!43?C!88?C$#128???G!139?o??G$#129??G?G!133?G??A!8?_$#131!48?G$#135!48?_O!95?_$#142G!137?@$#143O$#157!140?G$#161!47?_O??G$#162?G!146?O$#163??@??G!136?_$#169!50?_$#171!52?G!87?O$#176@$#177!142?O?_$#184!49?G$#186!22?@$#189!146?_$#192!144?O$#193???@!132?C@AAA$#194???C??ACC??A?@!127?CCC$#201A!136?CCO$#202!145?O?_$#205??O!4?@!129?A$#206!5?A???C??a?O??C!109?C???O$#208!12?@!107?@!6?G!13?_?GGGOO_$#209!53?_!5?C?C?CC?@!10?C??!6_?_!23?C?@B?C?C???C?G$#211!115?C$#212!14?__O!37?@@B@!49?!5B!9?@$#213!13?_??G!107?A?C???O$#222!18?G??C!23?_!71?@!5?C$#224!60?C?C??!12C?!8C??!15C?CCC!10?A?C?C$#225!19?O??ww!4~^^!13~nVBE?@!5?!22wg_?_!6?_!31?A$#229!102?_!14?C??C???OO$#232C?AAA?Oo!5?AA??A!121?__$#239!10?@!8?CEA$#241!7?AABA!10?@!104?G?O$#242!114?CA!9?GO$#243!20?W!25?GGCA??EC$#244!53?BAA?AB!19?GG!10?_?__??___?_!6?!4C$#245!16?_O?A!28?A???_?CC!39?_!27?A-#15!85?_$#18!80?_$#20!78?__$#21!89?_$#36!46?O?aB$#38!96?__!54?O$#40!144?@$#45!104?_$#62!106?_!42?@???C$#71!107?_$#76!98?O!46?_$#77!12?@!70?OO!17?!18@!8|~!7{ww_?_$#78!5?A??A!34?C!20?__?O!24?OO!21?OO?_!12?@$#79?GG!7?AAA??A!5?GAA??aA?GAI!7?O??S!8?KBA!5?G?_OO??G?WOG?WO?OG?G@GKK?GG?O!13?I??GG??W???OOO!4?C!18?G$#81!67?___!38?_!23?@?A!11?_???@@A?C!4?_$#82???CC!33?_!30?C?G!11?CC?G!4?G!14?GC???_?_?_?o?_$#83!66?O???S???K??O?O@@??@@!15?CCC???OC!9?[$#84!13?@$#86!91?O!38?A$#87!11?@!119?A$#90!8?@!123?A!5?C$#93!5?@!139?O$#95!142?G$#96?A??@!130?@!4?C?@???OC?G$#97!137?A!5?GG!4?_?__$#98A??@!137?C???GC?G$#99@@@!133?@@!4B!4CGWO$#108!46?GC$#109!45?_?AOG$#112!83?__$#113!81?__$#115!48?C$#124!43?_!48?___!53?@?A?C?_$#127!71?_!33?_!52?_$#128!76?__!9?__!56?@?A?C?G$#135!45?O@G?O!97?@!5?GOo_$#142!72?_!73?A???G!6?G?O$#145!90?_!66?_$#148!48?@$#149!47?o?C$#157!153?O$#161!44?oGE@$#162!156?C$#163!73?_!21?_$#167!49?_!104?G$#168!148?C$#169!50?o$#171!44?G!29?__!15?_$#173!46?_$#177!86?_!59?@?AAC?G$#179!103?_$#184!45?C??G!102?C$#185!50?C$#189!45?A$#191!98?___$#192!101?__!53?O$#194!153?a??G???_$#197!50?B$#202!43?OC!25?_!80?A???G$#205!143?@?A!5?O$#206??A!131?@?A??C!8?_$#208!66?_!88?C?OO$#209!6OAA?A???A!8?!4_?!5_!53?O??OOO!5?OO?OOO!17AY!8A?B@!7?OoO_$#212!10?@!80?@@@L!17?!4KC!16?B?A!4?G???O$#213???A??@@?@!131?G!5?_$#222!42?g!8?B!22?O!69?_$#224!101?@$#225g__ggk!8{}{!5~rPPRRPPRRPP!6~^N~~BBB!6?o{|!5~v~^NN^^FNFJBRBBBNVNVMC??G??O!15?!5OG!34?__$#229!136?CC$#232!142?AAA!4?Oo$#239!45?@!4?G$#241!114?_$#243CCC!19?!7G?G!12?G!29?G!8?@@?C@@?G??G???!5G?GG$#244!14?@!7?!8C?C!7?_!22?_!8?CCC!6?!6AEEFFFEEMQEFFFDD???CC???S{[!4?G!26?O$#245!4?A!10?@!5?C!8?C!32?_!16?OOO!4?GG?G!4?X???AA!5?C??g??_???_K!21?G?OO-#5!62?Oo!5O$#7!60?C!4?A??A!4?@???@??@!9?@?!11@???@AA?A???A???CC!6?G!4?O$#8!51?___!8?!4C!9?A?G?o!6?CKCU_ggO$#9!63?G??!4G!31?G!13?O$#14!73?!4C??C!5?C!13?!7CKKKGG!4?G!4?OO_$#18!56?G!60?A!21?_$#20!52?O!82?O!35?GG???CCC??ECC!7?OO$#21!68?@!55?C!45?Q$#36!43?_o]NM$#37!48?A$#38!170?G???G!15?C$#39!131?G$#40!159?C!37?_$#45!120?A$#62!50?O!14?@!49?@!11?C!33?A!29?C$#63!19?O???G??G?GG!4?O_$#65!14?_O$#66!14?O??GCGG?!13CGO?_$#67!145?A??A?GG?_$#69!11?_?O!9?AA?ABBA?A!7?_!109?C$#71!82?WWWw!69?@!15?C!4?G!7?G???A!4?G$#72?O!7?O?GGG!26?O!103?@?@$#73__!12?GGC??CC!129?C$#75!59?A!92?CG$#76!53?G!68?A??AA??AA?C!8?O_O!6?A_???O$#77!120?!7@BB!9@BNNFNNs{{wo__$#78!50?GG???CAA???@@@!53?@!13?A?CGC!18?G$#79HHG?HH@@HH?CCAA?@@!14?!5@A?A?@!9?@HA!80?C$#81!169?G!7?@@!5?`@!9?O$#82??AA!6?AAA!25?@!110?@$#83!8?A$#84!132?AA??AA$#87!123?A!6?CC!11?_!7?A?C!24?__$#89!81?G??_?O$#90!156?O!20?_$#93!176?_$#95!152?A$#96!86?_!67?@??O!14?O??_??G??G!6?O$#97!153?A??A??G!20?OOO!7?_$#98!156?G!5?___!8?Oo!4?GG!5?OO$#99!152?@??ECGOooo???___???___?!4O!6?O?__$#101!80?C??C???_$#103!86?GO_!22?!4G!8?!5_$#107!53?O!5?C!19?A!28?@!7?A!5?SO!4?_!5?O$#112!41?_GE!65?@!18?G$#113!63?A!5?@!53?C$#115!43?O$#120!50?_!5?OO?WG???IGCC??HG?G??A?GGo!7?O?CCCK[[KIIWGOOQ!5?OOOsso_?ggg_!4?OO??_?_?O??_?_$#121!58?O??GG!5?!5C!4?EE!5?A!12?CC???!4G???CCC!4?WOOO?_??O!5?_$#122!42?A$#124!61?A!5?@!72?_!18?@!25?A!6?G$#127!54?G!5?A!71?G!8?_!15?A!4?CG!10?AG$#128!62?A!48?@!48?CCG!6?O???C!5?EC?AA!5?C$#129!80?G??A!34?A!75?C$#131!48?[$#132!57?G!8?A!37?@$#133!105?@$#135!42?CG!113?@@A!20?A!4?CC?C!4?O$#142!66?@!13?AA!32?@!22?O!24?ACG??G???O???A!9?G!9?G$#143!81?O??C$#145!41?O??A!85?G!27?A?A!17?A!13?_$#147!20?!4_Ooo!6_$#149!45?@?@@$#151!56?_!20?_$#154!57?__?_$#156!81?_!91?@!18?A$#157!188?G$#161!42?_$#162!82?A!91?@!14?@$#163!51?O???G!57?@!5?A!5?C!35?G!10?C???A!9?G$#164!54?__???_Oo??!5_ooowowwwOo!9?GgWOO___ooo_o___!5o___!4?_$#165!54?OO??G!15?B@@!8?!4A??!6A??!4A?AAA@???AA?!4C??GK!4G?WOOO?!4_?_$#167!44?C??_$#168!57?C!68?C!36?O!23?A$#169!24?_$#171!49?_!8?C!53?@!23?O!19?@!16?G???A!6?A??G??O$#172!44?G_oO$#174!42?O$#176!110?@!18?G$#177!174?CC!8?C??C?GGG?_$#184!43?@@!149?_$#185!16?_???!4O???WOOWWOO$#186!12?_!29?@!90?G$#188!62?_$#190!48?_$#192!186?A!8?_$#193!160?G!8?_?AAA?@?G!10?@A?a!4?O$#194!161?@!7?C!6?@!6?H??@@??A??CG$#197!49?@$#198!41?G!152?O$#201!189?O$#202!17?___!13?__!5?_!8?O!71?A!16?O$#204!24?@@@??@@!120?C$#205!81?CC_!74?C???O?O??O_$#206!150?@???CG??_!6?OO!15?G???_$#208!56?C!103?@!7?O!11?__!14?_$#209!15?A!5?@!36?B@@!73?AA???O??O?A??CGOO$#212!136?KK!19?_!21?!4@!9?C$#213!168?G?C!14?_$#220!16?OOW??GG?GG!6?GGGO__$#221!10?_?O!4?C???C!13?CG!115?OO$#222??OWOOWW??G??CCC!6A!10?!5AK][G!9?@!94?@?B@??O_?O__$#223!11?O!4?G!5?A??A!4?A$#224!141?G??G$#225??@@!6?!6@??@@@!16?@??@!12?!5@$#227!15?_$#228!13?_$#229!124?A!4?C!10?O$#232!82?_!68?@?@A??CG!11?_!8?O???OO!4?_$#233!61?C!5?A?AABBA!4?@@?!9@A@!17?A!10?C$#234!103?@!9?A?A!16?O$#239!41?C!7?M$#240O?!6_o_O!25?CO!108?A??I!4?_$#241!54?C!9?@!51?@!11?C!53?__$#242!22?@@!7?@!116?C???G$#243EECC!4ECEC!29?EA!8?EEECAA$#244!39?@!98?K$#245!118?@@!15?G-#0!41?oO$#1!73?O$#3!51?@???C@??CCCG?GGG!24?OO?oo___ooO??!8o!11?_$#5!54?_!59?@B@?ooo__$#7!40?O???C$#8!119?B??@??C$#9!51?CGO!21?A!47?@?A?C?G$#11!41?F$#14!74?_?@!13?G!33?@@BB?B$#18!136?A???_?@$#20!133?@$#21!45?G!28?O!55?O$#31!47?O!154?O$#36!43?@$#38!154?_$#40!48?C??GO!24?@!59?G$#41!47?_y{wo_$#62!146?A!53?O$#63GGCCC!32?AA$#65!8?@?@@$#66CAAABA@@$#67?@!179?A???@?A$#69B??@!174?AA??AA@AEC$#70!177?B??A???A$#71!88?@!41?E?O!4o__!62?_$#73!180?@???CC$#75!174?AA!10?@$#76!148?AC!22?A?@!14?C??_$#77!146?!4@?@!8?oow!7ow{{w{{!8wooo_o$#78!155?W!4?C!28?GGO$#79!153?@??ACC!30?O_$#81!191?G!5?@?C$#82!158?@$#84!152?@??A!4?GG$#86!163?G$#87!150?B!5?_???AC!8?C!18?a!10?G$#88!164?!5G$#89!76?O?_!9?_!42?@!5?O$#90!171?A!20?O$#91!162?C$#93!188?@$#95!193?_$#96!77?OO?OO!6?G!44?KK?G!23?@!6?C??A!22?AC$#97!89?G!100?@?GO$#98!78?G]mm~~!4}!43?EM!36?A!21?A!4?_$#99!78?A!82?@@!4BAA@@!20?@A?wO$#100!167?@@$#101!79?@!9?C$#103!128?B?_!6?CMK]{{wwoo__$#107!39?O!7?@!88?@@@!5?AG?O?_$#111!40?C$#113!137?A?A!13?_$#120!46?A!27?C!15?C!26?@??FFECMWww_!10?@?A??CCK?O??_$#121!89?@!38?CC!4?@@!7?C!6?_$#122!16?__OO!7?OOO__!7?C!5?@!151?A$#124!42?C???@!146?@A$#127!148?C?G!48?G$#128!147?C?G!48?_?_$#129!43?_O?CA?A!24?G!122?O$#131!14?__?O?!10G?O?_$#132!43?G$#133!42?G$#135!45?A!150?ACG_$#142!131?_!20?O$#143!75?c__!52?G?_!5?O_$#145!42?@$#147_ooOWWGKGKCCABB!5@!11?@?BBFMK[$#148!44?@$#151!44?G!4?@!9?@@@!10?E!17?_$#154!43?O!6?@AECCG??@???DD???KKGGH?G$#155!56?{{{wwG??!8o?_!19?_!7?_oo$#156!48?@!86?A$#157!39?G???C!155?O$#161!40?A$#162!44?_owK??C??_!82?C$#163!89?A!42?@!10?@!57?G$#164!42?_!7?A?@BBB!8AFFFBBFFEXFB@!14?RNN^NN^^^!13N~~}{}]NKGGGYo_C?Wo$#165!140?@?AA???GGOO?_$#167!18?!12_!8?_!5?A$#169???__?__oooOGGKCCEEABBA!7BFEFK[Woo$#171!40?@?A!102?A!49?CG$#172!43?A$#176!89?_!49?O!11?O$#177!194?@ACGO$#179!11?___OOWGG!10CKGWWo__$#184!195?@$#185O?GG!6?A?@!23?@$#186!38?@B$#188!57?@!5?G!53?_???OO$#189!196?@$#191!20?!7O$#193!198?@AC$#194!197?_???O_$#195!53?GWo!5?___!8?_!18?__$#196!61?OOO$#198!12?OO?G!182?C$#201!75?OA?@!10?O!40?@O??A$#204!176?A$#205!75?GK???@!54?K!25?A!30?@??GO$#206!163?!4C?C???@!17?AC$#208!153?O?_???A!27?@??C!7?A$#209!173?C??!8CGG?O$#212!150?CGCCS??www$#213!159?@!9?C???@$#219!8?C??A$#220?C!4?A??@!27?@$#221??@??@!175?@@@$#222!154?@@@BA!29?K?O_$#223!176?@?@@$#225!156?C$#227!5?CCAAA$#229!145?@?A?A$#231!189?@$#232!77?MC_?@??!4@U!42?G?A!28?A!8?@!20?CK?_$#233!40?_!4?C$#234!39?_GG!99?@$#237!5?_OO??GGCC?AA!5?@$#240!187?G$#241!144?@!28?A?@!12?A$#242!186?G$#243!159?C$#244!152?IIAC$#245!151?E??G?W!12?G-#0!38?_W@$#2!56?__$#3!55?_!38?AA!5?@BB@@B!19?O$#4!64?GG?__$#5!61?AA!22?CKC?@!28?AABBA?XJ$#7!39?@$#8!147?_$#9!41?_!46?@!38?C$#11!38?A$#14!85?G!43?A!13?A?C?GOooO$#20!157?A$#21!54?`!22?G!52?A!73?O?G$#24!16?___??!4O?_$#26!10?___OOOGKK!5CKKK[WWwo_$#30!8?__OOO?GGC??!6A???C$#31!44?G?@!28?@!9?_$#38!156?@???G$#40!45?C$#41!44?ow}!7~]!21?BFN]{{wwo$#62!158?A$#71!83?C!44?GK?C?A!64?@???_?G$#72!193?A$#76!157?@???G$#77!165?B!4FB!5?!5^!11~G_$#78!164?__!27?@C$#79!160?DCGOOO??_?O?W!19?A???_$#81!158?@!35?A!7?@??O_$#82!193?C$#83!162?E!7?__$#84!165?C!4?C!5?!5_!12?O_$#89!80?@!46?_OOGGKKNF!4@??G$#96!83?A!48?OOOWW]EA??O!52?AC???G$#97!200?O$#98!82?@@!44?!4_?!5_ww{w__!51?@?GA$#99!196?BCKw$#101!85?@$#103!75?A!65?@@HBBFFNNNn}}{wwo__$#107!37?G!117?C?GS$#112!36?_$#113!155?@$#120!85?A!41?@?@!13?COwoO_!4?@BAEC?WO$#121!55?A!86?A?C?G!5?@!7?_$#122__OO?GG?CC?A?@@!17?@@AC$#124!5?__oOOGGKKCEAAB!6@!4BFEM[wo!166?G???_$#127!199?A$#128!162?_!36?@??O$#129!41?G@!12?G!28?A??@!39?G!16?_$#131?O?GG?CC?AA?@!22?A$#132!37?oGA$#133!38?C$#135!200?BACg$#142!132?B!67?C???A$#143!80?A?C?G?@!53?@$#145!13?___OOOWWGGG?OO___!7?C!163?@$#147@$#152!38?OC$#153!39?_y$#154!40?C!17?_!27?o_!16?!12C!10?G$#155!56?^^^~|WwWpp~^^!5~iCO!11?WWX~~~{{[]~~~}{[w!7W!4w{_!7?_$#156!41?A!13?C!20?C?O!6?O!45?@!10?C$#157!19?!7_$#162!41?C}~FB!82?C??A!9?A!63?C?_$#163!84?C!76?O!40?A$#164!41?@!65?!10B@!8?fAB?@!13?G$#165!158?G??_$#167??__oOOGGGCCAAA@@@!12?@@AEKO$#168!159?C!43?C$#169EBBB@@@!30?@$#171!36?O$#176!41?O!13?O!23?_$#177!38?@!162?CGO_$#179WKKCEEABB@@@!22?@`NA$#182!60?ACDf!23?AA!7?b`!7?!7_!7?CKKK^e$#187!61?@!27?A!27?CCGOOO_$#188!64?EE!28?@@!7?_!13?A@@??@??S$#191!35?G$#194!195?C!5?O?@CGO$#195!55?@!18?TwGo_!7?AO_cA!13?AA!11?GWo___$#196!61?_!14?_!10?GC?c!26?O_$#201!79?@?A!45?O??C??@!9?O$#205!82?A?@!45?OO!4?E???AC!56?_$#206!194?@$#208!162?O!32?G?_$#209!166?!4G!22?o$#212!163?AA!6?BBN~}!27?A$#213!196?GO$#222!192?@$#225!160?AB@GGG!4?GW!20?C$#232!81?@!50?_!6?C!57?BOC__$#241!163?_$#243!159?@!6?_O?_!24?GOO$#244!163?DD?O_OO?Cco?@!17?GO_$#245!159?A-#0!34?_WG!21?A$#1!50?KS!10?O!24?E?G$#2!62?CC!19?O!38?C?OO$#3!64?_!26?OO!15?__!6?G!9?Q$#5!43?W!19?AMMKKK!15?CC!9?GN~Gwwow{abb!5B!13?A__$#6!36?@$#7!35?C$#8!146?MNNK[W$#9!44?O_!7?@!7?C!24?B!63?A??_$#14!59?C!20?@!10?_!38?_!19?@BF^~~}{oowww{wo_$#18!35?A$#20!34?G$#21!42?@!6?C!91?O!65?_$#24??_O?GGC???A?@@!12?@@@ACK$#26WGKCCABB@@@!20?@@F$#30!4?A@$#31!44?GO?_??@!30?@?A$#36!172?oO_$#40!90?_!37?C!11?O!62?@$#41!43?BFN^^N@!32?@@B@$#44!169?_$#45!206?@$#62!164?@???O$#71!86?OO!42?O_$#72!169?O???A!4?O!19?A?OO$#77!180?G!6@\LL!5\][wo_$#78!168?G?C!6?CKO!17?@@C$#79!168?@L@?A???E?__??cc__!11?A$#81!165?@?C!31?A!8?CO$#82!166?@B!9?AAA?O!18?C$#83!182?G???O$#84!180?A!5?C!8?@$#96!89?_!39?C??_!11?C!55?ACG$#97!54?O???G!144?O?O$#98!86?__!42?BL^^!4~FNBBBF$#99!54?___o_OO!68?A?A!68?@BEGO$#100!128?B@$#101!57?G!81?O!4?@$#103!42?A!6?A???G!6?C!28?O!52?O!13?@BNNFEC$#107!161?@A?ACGO_$#112!173?C$#113!163?@$#115!173?G$#120!34?O!15?_!7?C!69?G!11?__!4?@??B??O!11?CGO_$#121!129?O!13?O?@!5?CG$#124CEBB@!29?@!141?G!30?C$#127!54?G!74?G!35?AC$#128!33?_!27?O!77?_!65?CA?O?G$#129!46?_??G!11?G!22?_$#131!171?G???C$#132!36?A$#135!8?_??O??GGG?G??GG?G!149?C$#142!56?G!28?A!58?G!66?_$#143!48?O??_???G!71?@$#145_oOGGCC?AAA@@!17?@AQ!142?_$#148!173?_$#149!171?_$#150!36?_OOwC@!8?O??AB!7?G!22?GC?C$#151!57?@@???_$#152!36?CB!18?C$#153!35?_OknFB!8?_?GKCCEAE?A$#154!52?A???@??@B??o!18?__??G@GCG?_!33?D[$#155!40?_a___!6?A!13?___`!9oqoqc!10?G??_!8?KK!4W!4wzwo_!4w___???__$#156!48?_O??@!8?_!20?A??O!41?A!17?E$#157???_ooow[[[KMME!8FNFN^]}}{w!140?C$#158!174?O$#161!175?G_$#162!43?C!7?@O!155?@$#163!88?O!117?O??_$#164!87?G??O!37?O!13?__ow!4o___$#165!162?@A$#167B@!30?_G?@!141?_$#168!205?G??G$#169!170?O!6?O$#171!204?A$#172!170?_OG$#177!9?___!5owoww!5o__!176?@BKW_$#182!41?C!21?@!32?o?o??G!22?B@$#184!174?GOO$#186!201?__$#187!41?WW!19?B?@OQQQK!23?K[S??FCCCF?PO?_!4?B!4?[!5?B?g$#188!64?O!28?_!9?B$#191!33?OE$#193!204?C??@?CO$#194!208?A?_$#195!40?W?C!7?A!4?@!5?A!15?A@B?ASKG!5?C??O!28?W[KCG$#196!61?@?G!13?@CCGOG?O???@B@K??_$#201!167?G$#202!171?C$#205!143?G!59?A??_$#206!199?@$#208!207?A$#209!179?KSK!6?OO!6?@CGO_$#212!176?@@?@@!4?K!4?!7_!4?GO_!5?G$#222!198?C?G$#224!181?!14A?A$#225!168?!4A!14?___$#226!65?@@@?B!7NKGGCG!6?A?ABFBBB???BBB!4?!7CFCFFB!4FB$#232!52?_o?OO?Ogg!24?_??_!41?KO?_!4?w?KKK?A!57?@Cg_$#239!170?G$#240!199?G$#243!172?@?AA?G???_OWOO$#244!166?A!8?@??@?_???K?G??_$#245!168?C??@?@@-#0!32?_?D!8?O???@$#1!43?G?A!34?_?oD$#2!98?G!29?C?G$#3!41?C!40?A!25?NN!20?A?C!17?__??G$#4!39?G$#5!43?A!52?@@@`AANKFFF!19?@@!4?G!9?A$#8!61?_$#9!133?C!20?@C?_$#14!49?@!11?G!32?A!36?@A!22?BF^!10~}{wo_$#17???___ooo!7w!5{w{!5w$#20!208?@??G$#21!97?O!42?A!72?C?_$#24@$#26!30?C$#30!28?_$#31!134?C$#36!171?@$#40!211?_$#41!138?oo__$#45!49?G!5?A$#62!48?G!5?O!155?@??_$#66!203?A$#67!202?@$#71!45?O!4?@!81?@!4?C!69?@!4?G$#77!197?!4NMK$#78!178?D!25?G?_$#79!178?wF?C!6?LCIA??OO$#81!211?B$#82!180?G$#83!192?cg___$#89!138?C?G$#95!208?O$#96!47?GO_?@@?_?C???_!29?@!4?G!43?A!69?_$#97!60?B$#98!56?WW?@!25?LN~~~}}}{wo!38?AA!70?AE$#99!45?_oo!8?_f~a!25?qo!46?@@@BB@$#101!94?C??_$#103!61?C!36?_$#107!31?OC!136?@ACGO$#112!174?_$#120!33?@!9?_??C!46?@!60?A!13?@ACGO$#121!44?OG!15?O!94?G$#127!84?A$#128!30?_!53?O!125?G$#129!84?G!7?@???G!39?O_!76?O$#135!6?@!23?A!145?o$#142!47?C!36?C!123?A??CA?_$#143!136?GWG@$#145!31?HA!143?C^!32?A$#147!55?C$#148!172?BD@A$#150!36?n]E$#151!41?_O???AA!14?~$#152!31?_WMA$#153!33?ow~O@@???_?GC??@!34?A$#154!40?_OGCC?@!16?^!17?_?W!10?@A??O!4?o!24?GG!13?___!4o!4?Oo$#155!39?CNJB@B@!18?!16~NN!17?KK???owwooo!15~}{oa`___G?o_!5?sR$#156!48?A!46?C$#157]NFB@@!23?G@!145?G_$#158!173?AE\$#161!176?@$#162!135?G!5?O$#164!130?@A??G!5?@F?C^^!4N^^~~cGo$#165!173?_$#167!29?O!140?@ACGW_$#169!52?A?A$#171!209?C??O$#176!61?B!22?_!56?G!67?ACO_$#177_ow[MMMBNB!6F@B!4@!6BVF!179?@$#179!32?@$#181!52?GKK$#182!99?A@@?B$#184!4?OO?K?C!6?A?AAAE?!5CG!147?A$#186!203?@$#187!96?AAA??Ko!4?N!17?@AA$#188!42?C!54?G!44?HG$#191!29?_WE$#193!50?__!157?G$#194!205?A!6?CG$#195!37?_WR!40?OOD_!13?C?Ooo!26?@A?G??O$#196!38?__O!22?_!18?G!12?@C?C!5?G!22?KOSSSOo_$#200!50?KKC$#201!44?_?G!37?@!8?A!39?A?CC??GS!69?O$#202!53?O$#205!49?AO?_?@@!35?@!47?C!66?C$#206!53?`?OA!150?G$#208!52?O??G!150?GO_$#212!192?BBFNN?OOoo_oo!8?O$#213!48?COAO!152?@$#214!53?A$#222!178?A!24?C$#225!179?wow!6NAICKWO$#232!48?_!6?_@??[[!35?o!41?A!66?@@?KO_$#239!49?C?A!152?CGO_$#240!202?A$#241!204?AC$#242!201?@$#243!181?BooO_ooo___!4?O!8?O$#244!180?F???_O???P@@?CG??o__??O??_$#245!190?OO!11?G-#0!28?_?GC!6?O??@???oOGA?@!10?c$#1!35?O???A@!101?C$#2!37?@?@!60?@C!46?GG??A@?G??_$#3!38?A!64?@!33?@!16?E?G$#4!65?Go!90?G$#5!99?@!44?oo!13?_$#7!175?C$#8!42?@!9?GA$#9!158?CO$#11!175?A$#14!53?G!104?BN~^NFDFFN^~^~~}w_$#15!53?@!122?G_$#17{{{!16~vv~fNFB@$#18!47?A$#20!29?A$#21!60?_!37?_!39?@!74?A$#26!23?_$#30!24?O???C$#31!79?K!82?_$#38!29?@$#40!51?O!8?G!102?G!52?C$#41!80?!4}mC!53?@B@$#62!214?G$#63!182?__???___$#66!178?_???OO???O???OooO$#67!180?WW?G!4?G$#69!182?CC$#71!84?O!11?o?G!67?O_!45?C!5?_$#72!208?@A$#73!179?O?C!14?O$#78!179?@???@!26?C??_$#79!197?@@@!7?@I$#82!207?G???Go$#83!203?WG!4?Kw$#87!214?_$#89!50?OG!43?O?G!117?A$#93!210?@$#96!47?@!11?O!25?PWM!7?_G!120?_$#97!41?GwOH@!118?_!50?O$#98!55?_???C!27?@~~z~~~^NEE!65?_??_$#99!40?_o?EC?@!7?G^~~~@!105?O$#101!40?O!5?A??CKC??B!31?_!129?G$#103!46?C!121?_$#107!27?O!145?@C?_$#112!26?_!149?O$#120!28?G?@!8?O!12?@C!103?@!16?AG$#121!48?O@!30?@!80?_??A!5?_!4?O$#122!28?@$#124!25?GOG$#127!43?@!54?@$#128!48?C???A$#129!41?C!11?_!45?K!62?O!50?@C$#132!29?C$#135!176?BM$#142!39?_???_!6?A!33?@!129?AH?OO$#143!48?G??A!8?C!24?a!79?G$#145!27?@$#150!34?aKB!40?OA!21?G$#151!37?OC??A??_??_!14?~!92?@$#152!28?OGEB!29?Z$#153!29?oow~~\B?_gKE!5?gS!4?_$#154!35?__K@!60?_o!39?CC?B@@!8?@EE$#155!36?OA!26?~FN!10~B?@!22?r}!31~r{oq{!4oEEArrr~~ooo_o$#156!45?G???A?_!27?A?@@!56?A!79?G?_$#157!26?A!150?@$#161!177?O$#162!44?O???@?_!9?O!18?O!61?A!76?_?O$#163!42?A$#164!49?_!92?B!13?@AG$#167!25?_C$#171!212?@$#176!40?G!11?CO!25?_???@!15?Q!66?GO$#177B@!17?GG?GOGC$#184?AB!19?O!152?@C$#186!184?OO???O?_$#187!101?I!42?GG{K!5?M$#188!65?o!86?C!5?O$#191!24?_OGEA$#193!60?@!151?A??C?G??_$#194!218?GO$#195!36?C!11?_!14?o!13?k{!21?Ep!36?C???GK??@?CC!7?_$#196!36?G!26?N!14?@!23?K!32?KBMG?GG!10?H?GO?S$#201!49?O!10?A!24?GE!10?oO$#202!184?___???_$#204!189?CC$#205!45?C???G!114?G!46?B??O$#206!212?CG$#208!209?@AC$#209!184?!8A!5?O$#212!214?@$#220!186?O?O!5?_$#221!179?___??!4G?GO!4?__$#222!178?FEEA!10?!4G$#223!182?G?!5C?GG???O$#225!180?@@AA!8@!4FNM]]}}}!5eoo$#231!215?_O$#232!42?CGAA!8?s!4?i!26?@o??C???_?@@E!64?OO_!50?_$#233!27?_!23?@O$#234!174?@$#239!178?WG$#242!191?C!5?___$#243!182?@!21?O?G$#244!200?!5@X@OC$#245!206?O!4?oGO-#0!34?_G?@???oKEA@!5?M!9?F$#1!45?A!4?C!110?G$#2!44?G[?@AC!13?@!33?_W_?_$#3!62?O!31?A$#4!66?@$#5!47?O!19?}}!49?!4W!41?_$#6!5?_$#8!26?A!149?W$#9!24?_??@!132?@AC!10?_$#11??OO_?_$#14!25?_!4?_!6?A!46?_!12?@!71?@@FFFN^$#15!25?@$#17BBBFFFDDDHL!5^NFFBB$#18!42?A$#21!36?G!126?G$#26???_$#30!8?_$#31!85?_$#36__$#38!18?_$#40!54?_!25?@!14?@!128?C$#41!81?BFN^^~}{wwo_!71?_$#62!38?_O!186?_$#63!179?A!17?E???WO$#65!200?C$#66!178?@!16?@!8?GG_o$#67!198?@?@??CC!5?O_$#69!201?A???C?C$#71!42?@!9?__!33?@???G!76?@!53?OG?G$#73!199?B?@!7?G$#78!214?AA?_$#79!206?@!6?C??_$#81!216?GO$#82!214?_$#83!210?@$#84!208?@$#87!216?C$#89!90?C??OO_!68?G!55?@$#90!215?@$#96!36?_OA??A!14?O!32?A???K!69?A@?O!49?@?OCG$#97!38?K!124?@!7?_!45?C$#98!53?GO!4?@!29?@BFB!71?AEFN{wo!47?K_o?_$#99!37?G?EA!12?C!4NFA!105?@GO!49?BAG$#101!53?A!40?G$#103!28?A!31?A!19?A!14?G!67?O$#107!40?O!11?C!123?BA$#112!177?@$#113!24?A$#120!43?@!16?C!101?G!13?C$#121!35?O!125?@!8?A?WWo_$#122!6?O!10?O$#124C?GG!4?O??_!166?_$#127!37?C!181?A$#128!23?C??C!196?Q__$#129!22?G!4?ACO!8?@??C!54?`!130?O$#135!5?G!14?C$#142!35?_!4?G!12?@!5?O!161?C$#143!57?_!30?AC???a@!68?CO_???A?O!50?G$#145G???G!10?_O$#147!179?KCCEEAABBBAEEAACKGGWo$#150!28?@AF_f^@A!7?G!116?_Oo$#151!34?K!7?_???@???G!10?_N$#152!22?_OW!15?_!10?o@!7?o$#153!29?@G^W_OCB!5?O?D!5?o@A!8?W$#154!34?A@C!12?gB!11?_!17?__!13?C?A@!61?KC$#155!72?__!8?O!15?_$#156!52?G!7?@!20?CG!11?C!77?_!49?@$#157?C??O!4?O??_!8?A@$#161!6?AAIEA$#162!26?w{w_!29?_!102?@!7?C!49?C!7?_$#163!19?_!32?O??__!163?AG??O$#164!23?_!72?W!79?_$#165!177?C$#167O!4?O?O!10?O$#169!178?C__oWW!6KGWK[Wooo_$#171?W!19?O!17?_!179?@$#172??_$#176!20?_!4?W???G!53?O!78?A!8?G$#177!7?_??O??__??GGG$#179!178?G???__!7o_o_$#182!49?@!17?@@A$#184??C???GG!11?C?@$#185!182?@@!5?!5@??C???W??_$#186!196?@@EC$#187!44?O?ACLA!19?{!47?W!4_W!29?___$#188!46?Wg!17?~}!12?@!15?AEO$#191!9?__!5?__?OGCEB@!153?O$#192!20?OG$#193!59?G!161?@?C$#194!221?AE_G$#195!29?CO!12?O??CA?O!13?w!16?SG_!14?KCWwW!58?O_$#196!48?_!14?E!13?@@CG??_!14?A?D@!55?@@@A$#198!194?_$#201!92?O?_O!69?O_$#202!178?A!5?@@!8?AAA??G___$#204!202?A???C!4?O$#205!36?O??G!53?@!71?G!4?G!46?G@$#206!216?A$#208!214?@!10?O$#209!205?@?ACCGKgo?_$#212!218?_!8?_$#213!37?_O!187?O$#220!179?@!14?@!7?GWoo$#221!201?CC???OGoO$#223!200?A!5?G?G__$#225!208?AAEBF$#226!43?!4_?O!15?~!4?@~~^^~~~}}y?O!17?FAE!15~f!4Ff!29~^^^~~}}}$#227!180?BB$#232!39?@D@!11?O?O?OwC!28?@???K!71?C??_AC!49?O?o$#233!21?_OGCE@!14?G!18?G!116?w$#237!179?OWG$#242!202?@BBAA!5?O$#243!207?@!5?I[SO$#244!209?@!5?G$#245!213?@-#0!20?_G@!6?_??C@???_?G@!9?@!8?oB!12?_!14?OO!7?OOO$#1!22?O!17?G!7?_A!19?_!12?Q!6?G$#2!40?_!23?K??SS!15?G!13?@??CG!10?G_??O$#3!101?G??GK!20?CC!28?c$#4!42?O!41?@!38?_!30?O$#5!30?A!36?BB???CC!11?@??C!8?@?B!23?Gw?!6_!6w!8_?GW???BB!5?@$#6!8?@!7?A!75?_$#7!20?@$#8!33?A!143?o$#9!26?G!133?@@!11?O_om$#11!9?A$#14!31?_!18?O!46?A!59?C!13?_?A$#15!6?@!11?@$#18!19?A!208?O$#20!225?@$#21!22?GH!65?C?G!65?g!9?_$#26!187?___$#30!185?__OOOo__$#31!53?__!37?GG!66?!4C??_$#36?@B@AGCGKC$#37C!15?GG$#38!19?O$#40!51?C??AAA?O!29?A!6?G!65?GGG!65?A$#41!87?@@B!5FE!62?{}wooo~~^]$#44!10?O!8?C$#62!35?G!191?@??_$#63!208?CCGG$#66!209?@??CGG$#67!216?o$#69!213?A$#71!34?A!23?G!36?@!71?@??OO!57?G$#72!218?O$#73!4?O!209?AAA]_$#76!220?O$#78!219?C?_$#79??O!4?_?__$#81!224?@???A$#82!218?@$#89!96?@!71?A$#96!33?OC@!15?OR!118?KC!54?_$#97!32?_!25?A!162?G$#98!52?C[[[CK!110?@@D!49?A???G$#99!56?W!112?AA!49?@FN^o__$#101!33?G!62?A!75?I$#103!25?G??C!8?O!49?A!85?G$#107!10?@!10?A!156?G$#112!20?G$#113!59?A!118?C$#120!38?C@!19?C!116?@$#121!22?A!9?G!18?@!38?G!81?_`^NO$#122!182?CAAA!5@AAECKWO__$#124!5?@!175?__ooW[KKKGWOo__$#128!12?@!4?@!41?@!167?I??C$#129!25?@?C?A???C!24?_!27?@!70?O!5?@!64?_??_$#131???G!8?OO?_??G!161?C?A?@@!5?@@?A??GO?_$#132!12?A!74?__?__???!8_!75?_$#133!11?A?AAA?A?@!69?_???__$#135!13?C!164?A!47?@$#142!56?_!39?G$#143!52?_B???@!110?[O$#145!13?!4@C!20?A!139?@_$#147!36?C!163?@@BFEMK[w___$#148??CECEIC$#149BA$#150!23?o??OGG!11?C!42?O$#151!39?O?A!18?_J!8?_???!8O!21?OOO?!5_$#152!20?OC!16?WE!10?E!8?GG!13?!13_???!7O!6?___$#153!21?o_?oo_ooW{^B!5?_?A@!7?{!10?S!10?__!11?!4O!12?OOO???_$#154!39?_OC@!6?@!11?s~C!5_C??OO!6?NNCG??GGG!9?G?G!5?O!5?__!41?c$#155!41?__!27?WO!6?CC!6?A!17?C!9?C!37?CCG?W$#156!34?@!15?_A!45?C!70?__??OC$#157!8?A???C$#162!23?EFEFBB@!25?_!104?!4A!66?G$#163!32?O!4?G!16?@@@!37?G!77?@!53?C?C$#165!21?@$#167!7?A??CGG!166?OoWWKKC!4AECKGWO__$#168!227?O$#169!8?OO!4?_?_!21?@!140?B@!15?@@BFEM[Wwoo_$#171!11?C!8?C!208?O$#172?C??H!4?GG??GWWOOC!161?GC$#176!19?_??C?G!5?@!66?G!60?A???@!7?_!56?C$#177!11?@??C?C!209?A?G_$#179!179?KAB@@!9?@@BECKWOo__$#182!131?W!12?O$#184!15?C$#185G!5?O!10?_!19?D!166?@@A??GOOo_$#186!208?BA$#187!41?G!22?BWWGGB??IAK!25?F!18?_??WSCw!4OW!7CW!5O?OwsCG$#188!65?FF!6?G!8?@!15?C!16?__!37?F$#191!20?A$#193!34?O!16?G$#194!228?@CO$#195!29?C!12?C!5?K!14?RO!17?GFEECC!10?A???CK!8?[SOSS!39?AB@$#196!41?OA!5?P!14?_!5?OC!4?!5G!5?G!13?G!6?G!5OAAIIIA??C!33?_Y$#197!11?O$#198??G!194?A??G$#201!36?_!20?A!38?C!72?G!55?A$#202!7?O!27?CA!172?O$#205!35?AO!132?C!50?C?_???G$#206!219?@$#208!34?G$#209!219?O$#212!36?@!182?AG$#213!221?O$#220!5?O!7?_!192?@B??CCGOo_$#221!210?A?AC?O?_$#222O??O!210?@@??MG$#223!210?@B??CKK$#225_o!5_$#226!42?G!5~A!14?G!5?GBN@@BFFFBB!19?C?!5BF!5N!5@l~^z~fBBFJJNNF!7BF!7NFBbv~~ww?@@$#231!58?C$#232!33?__o!15?_G!4?o@!111?GB!50?O_E[O$#233!50?G!126?NO$#234!7?@?@A!7?A$#237?G!16?OG!17?A$#239!11?__$#240!213?@$#241!36?G$#242!212?@???@@?__$#243!18?_$#244!8?_-#0!19?A!9?D@!5?w@!9?C?@!9?B!7?@@@!56?G???O!4?_$#1!119?A?A$#2!40?C!82?A!13?OO!10?A!7?O$#3!46?A!78?A!7?G!17?_$#4!128?CC!24?@$#5!127?@?@B!5@B@@@HH@@@!24?C$#6!75?@!35?A$#7!63?C$#8!37?O!140?K$#9!157?AO!8?COAWoRdLjr`_$#11!60?G!18?@!23?@!5?A!4?C!9?O!4?_$#14!166?@??@F$#15!17?O!23?O??O!36?@!20?@!5?A$#18!37?_!141?@!49?@$#20!39?O!6?O!183?a$#21!33?gg!123?G!8?G$#24!184?_oO??GGG?GWOO_$#26!182?KEEFBB@@@BBFEEKKWoo__$#30!183?@@!9?@@A??G?O?_$#31!31?@!126?C_$#37!64?WG?GG!35?C$#38!8?_??A$#40!30?G!23?o?A_$#41!158?BFF^!4~{o$#44!71?G!12?A???A$#45!9?_A!7?@!41?_!170?C$#62!13?@$#63!215?@?C?_$#66!217?@G?g?o__$#67!220?A??OO$#69!219?A??GG$#71!49?_C!108?O_!71?G$#72!221?CC$#73!221?A?CG$#75!225?O$#76!226?O$#78!8?SC_!4?@]!66?G!25?_!112?@AC$#79???A???K??OO?G!52?__???O?O!5?O??GCK?C??GG?OW??G!5?O$#81!12?A!218?A_$#82!12?G??o!52?__!8?O?G!4?!4G$#83!14?AA$#87!227?_$#89!50?O$#90!225?CG$#93!223?@???O$#96!50?G$#97!30?_!195?CA?_$#99!31?GD@@@!188?@@B?K$#101!30?OAG!18?@!4?_$#103!35?_A!12?G!8?A$#107!38?O!20?O!4?C!5?A!48?G!59?A$#111!78?@$#112!42?OO!36?@$#113!59?_!53?C!66?O$#120!18?C!10?O!17?O!130?O?_$#121!58?C!112?NkYqSK]$#122!76?!4A!101?G!18?@@AAC?GGO__$#124!17?G!49?C!19?@!10?@!12?C!4?G!63?BDP!13?@BECKGWOo__!23?@$#127!11?@!216?@$#128!18?A!16?G!4?O!5?_!60?A!121?A$#129!32?_OO?@!13?@?NFFF!176?C$#131!60?OO!7?G!4C!8?AA!5?A!8?C!8?G!7?O???_?_!80?@??C??GO?_$#132!42?GG?G?_O!10?GCCC???AA!5?@@!30?@???@@?AAA?ECC??GGG??OOO??___$#133!68?A!110?C$#135!83?@!17?@!129?_$#142!9?G!22?O!18?C!4?C$#143!33?C!21?o!103?GW_$#145!66?C!17?@@!13?@@!16?G!4?O!4?_!52?G??wWG?KMEECK??G?O_$#147!73?G!5?C!23?G!6?O!4?_!94?@@BAEWO__$#150!20?O@@B?_?O!20?@!120?o$#151!30?A!7?IGG??CC!15?@A??@@!47?!4@???A???CCCGGG???OOO?_$#152!17?_wKB!8?G!14?G?GGKA!8?o!4?AAA!4?@@@!33?@@@??@???A???CCC??GG???O!4?_$#153!19?ok}}{~^^n~A!7?M@!6?CC?A!13?A???@!45?@!4?AA???CC!12?_$#154!26?_!11?C???C!4?A!13?@@@!53?@@???A?A??C??GGG???O?__!16?@$#155!41?@A!108?O!15?@C$#156!29?_C!27?@!107?A$#157!72?A!39?C!73?_!7o___$#161!45?O!82?_$#162!34?CC!15?OOWGG!112?_$#163!50?Ag__??@!172?C$#164!36?C$#167!39?!7_!28?AA!12?!10@!7?A!4?C!4?G!5?O!4?_!71?@BAECGGOOo_$#168!16?_$#169!66?O!5?G!5?C!6?AAA!6?CC!8?GG!5?O!4?_!90?@BBECK[w__$#170!186?K$#171!9?OC!38?O!12?G!10?A!12?@!19?A!74?AA!48?O$#172!62?OW!4?CC!4?CC!4?AA!8?!9A!5EACCCKK!4GW?!4Oo?!4_$#173!66?G$#176!35?O!121?@$#177!61?G???C!5?A!46?G!111?[$#179!181?O!21?@BBEECGWWo_$#182!126?@?@!5?AAK??G???E?@$#184!82?@!40?O$#185!62?_!5?O!5?G!5?C!11?C!9?G!6?O!4?_!98?@@EEGO$#186!17?C!201?C$#187!125?@A?AA?CCEKK?KKEEUEOAA@??_!7?G!12?_$#188!131?AA!4?AAO??WG!24?@$#189!38?_!192?G$#191!180?C__!20?C?G$#192!10?G$#193!57?G$#194!229?O?@$#195!39?FBE@!101?_???B@!4?{~{C_!8?AI$#196!44?A!100?C!11?_!11?G$#197!65?O!4?G!5?CC!18?CC!8?G!5?OO!4?_$#198!117?_!88?@??C$#201!50?_A!4?GO!171?G$#202!12?@?@!201?GO$#204!219?@@$#205!56?O!171?A$#206!224?A$#208!8?G$#209!106?__$#212!232?O$#220!63?_!5?O!21?C!8?GG!6?O!107?@ACW?o$#221!218?B!6?_$#222!13?C!51?_!6?O!4?GGG??C!9?g___ow!4o__??O???___!109?A$#223!220?SG$#225!7{o???_oo{K!54?!4_!4o__!11ow??OO!7?Ooo??_$#226!43?B@B@@!71?!6@??A??C!9?o___[w}~{[~N~~A?A$#232!31?s!4A!21?F!167?A?Lo$#233!19?@!21?G!6?_C!8?GCA!70?OO!45?Bw$#234!69?A!6?@@!26?@!5?A!4?C!4?G!4?O!4?_$#237!61?_!5?O!25?C!117?A$#239!64?_!5?O!4?GG!4?C!8?C!7?GG!7?O!5?_$#240!226?_$#241!11?C!213?G$#242!221?@$#243AAB@AABBA??GC???@@!67?C?CCC!4?GG$#244@@??@@??@B@$#245!13?A???A!63?G-#0!16?Oe?OO??G???@@!8?_!100?@??A??C!4?O?_$#1!22?C!130?_!6?G!10?O$#2!24?A!118?@!16?OO$#3!150?C!5?O$#4!148?A$#5!162?O?_!7?G_$#6!146?O$#7!36?_!21?A!122?W$#8!44?O??A!132?_$#9!171?@COGm~~KC$#11!20?_!55?_!63?C$#14!35?@!127?O!14?o_$#15!58?O$#18!15?G$#20!16?@!20?@!19?A!123?A$#21!28?_!8?C!5?_!12?_$#24!200?AACCGWO_$#26!201?@@@BEEKWo_$#30!205?@??CGO_$#31!47?C!6?M?O!107?O$#36!23?_!103?@!16?_$#37!125?@?AA?AEIA?C?_ggg?O??_$#38!5?_!28?G!147?G$#40!31?w!16?o_`_?_!112?_??A$#41!162?@?N^^~~{$#44!128?C!53?C$#62!76?C$#63!120?@!100?B@G$#65!224?GL$#66!223?B?AJ$#71!30?_@!14?_O!7?gH!175?A$#72!134?_$#76!227?E$#78!5?]?OKBN??Y?@!43?W?i?O!4@?!5@}A@`@G!28?@@??@?@??A!15?_$#79!5?@!6?@?@!46?OO!12?@???@@!10?@!15A!5?ABAAAC!5A??SGWoo_$#81!13?_!61?K?AAC!152?G$#82!6?A_!5?C!46?_!7?@!9?__!39?C???C$#83!132?_$#84!9?G!107?G!5?G$#89!48?C@!5?O!106?C$#96!56?E!171?WC$#97!228?_$#98!228?E$#99!29?SB$#101!29?AW!129?@$#103!57?C!112?_$#107!28?C!6?M!7?G?A!99?O$#112!23?O??o!14?O??C!88?@???A!43?C$#113!35?O?O!144?_!47?_$#120!16?A!41?G$#121!159?@!12?BNvP??BW$#122!183?o!27?@ACGO$#124!39?O!5?@!85?@!51?A_!21?@BBEKWo_$#127!14?O!44?C!169?_$#128!37?A!20?_!17?G!62?C$#129!32?@@@!11?G!10?@!103?C$#131!124?@?A??C!4?O??C!74?@ACG_$#132!15?_!5?O??G?CG!8?O??_!4?GC!12?@!76?@!5?C??G??O?_!31?_$#133!58?C!79?A$#135!147?_!37?_O???!4CG???O!31?BL$#142!31?E!15?_?C!4?O$#143!55?C!107?F$#145!14?_!6?_??O!12?G??O!18?@!76?A!7?O!37?O@O!14?@@?AAC?GO_!22?o$#147!121?@!5?C!7?_!81?@?BKKw__$#148!25?_!104?@$#149!126?@!7?CG!5?__$#150!18?GK@??A@!145?@?O$#151!24?C?@!113?@??A?CC?G??O!27?@$#152!16?k@__!7?C!8?N?_?__?O??E@!88?@@?AA?CC?GG?O?_$#153!17?WVBMNJ@!115?@??A!4?G??O?_$#154!23?C?@!115?@@?AA?CCGGGA!5?__CG!9?c$#155!144?@@@B@@@B@FE]MMMW!10?A$#156!28?O!19?@!111?A?G$#157!132?@!51?N^N^FF!4BF!4N][{wwo__$#158!24?_$#162!32?AA?_!9?O!124?W$#163!6?GA!7?C!13?@??{{u!14?W]^~^@B???A!17?C$#164!25?A!153?A$#165!26?G!15?_$#167!22?_??O!12?!4NFFB!90?A??C??G!4?_!62?@BEKWo_$#168!8?A!68?O$#169!122?@??A!7?O!81?@BEN[oo$#171!6?OC@!29?O???G!32?_?G!103?@$#172!128?@@C???AOC!6?O$#173!129?A??CKG?WW!4O?_$#176!28?G!136?_???@C$#177!142?G!43?__!6w!4o___!29?[A$#179!182?BG!29?@BE[wo$#185!124?A!7?O!87?B?CO$#186!222?AC$#188!149?CAC!19?A$#191!183?C$#192!6?_$#195!152?KWX!4@?__!9?G_$#196!146?A??A??O?___oOE??__$#197!123?@!7?G!4?_$#198!7?G!211?_$#201!44?__OGIA!4?_!106?@AG$#205!161?A!67?G$#208!15?A!211?x?O??D$#212!14?A!61?A?CA!152?o$#219!224?O$#220!226?o$#222!7?@!53?@@!29?!16@??@@???@?@!10?G?O$#225!5~?@?ooo~}@!47?Cmn!10}@!5?}!10~}!15{!5}!5{ooo{{{ow_o_$#227!225?o$#228!224?F$#232!29?gC!197?@B$#233!15?O!9?CAqA!13?O??G!11?w!122?^$#234!22?O??G!20?@!29?O!57?@!8?G!4?_$#237!130?G$#239!116?@?@@!6?C??G?O!94?C$#241!6?C!68?O$#243!60?B!17?OO!43?ACG$#244!9?C!108?KG!11?_$#245!14?K!44?_[!17?G-#0!55?O!99?A??GG?O$#1!155?@???C???O??_$#2!159?A?CCA!4?_!4?O$#3!167?o$#5!165?@@!7?AG_$#6!14?CA$#7!28?G!46?_!106?A$#8!55?GA!124?K$#9!174?@CO???B_$#11!14?G!168?Ko$#14!167?@$#15!26?A!155?O$#17!188?ow!5{}}}{{o$#18!16?A!57?C?@!151?_$#20!55?_!17?O!155?C$#21!28?@!7?C?GKKC!13?C$#24!208?@CGo$#26!210?@BN{o$#30!213?AGo$#31!33?GWWw!4opOOO_!7?O$#36!15?oOCG!6?C!124?G$#37!23?G!117?@AACCD!5?OgG?O_$#38!33?@@!23?@!15?A?G!152?`$#40!31?^MEE`!6?GKMMnNNZLDB?G$#41!32?___!12?_$#45!12?O!63?O!148?O$#62!226?G$#63!137?@$#71!54?@@?G!168?OQ$#72!12?G!128?C$#78__AD?KB??SGw!46?K!10?OOGE!4?~C!57?EC?CC???!4_$#79E?H??O??E?S?C!47?@@!6?_?KE!6?ggF!47?@@?@@BEEoo[W?Oww$#81!73?C!157?G$#82!7?E!63?O@@!4?B$#83!79?C$#87!72?O$#89!29?CF$#103!29?O!139?@$#107!18?@!38?A!17?@!76?A!5?O$#108!19?G$#109!20?C$#111!13?o!136?@!9?_$#112!13?G@!11?@O!126?C?G$#113!56?@!125?G!46?WB$#115!14?_???OS$#120!54?O?G!124?O_$#121!175?BN~~~{$#122!151?_!32?C!31?@EGO_$#124!4?G!12?A!9?_!28?O!96?C?G?O!27?CO!26?@FKo!12?A$#127!72?_!152?_!4?O$#128!28?A!8?C??@!35?A!150?_$#129!36?A!4?AE!14?C!174?E$#131!25?O!113?@?A!6?O???C!5?_!26?G_!30?@C$#132!15?@@@!36?_?C!18?G!75?@?A?CCG?O?_$#133!14?A!12?EO!44?_$#135!15?C!10?C!156?O!20?GW$#142!73?G!154?G$#143!29?GO_!10?!4@!4?Og?@$#145???O?@!6?_C!4?_@A@!127?@?A!7?_!49?BEKo$#147!149?_!72?@@FN$#148!16?G?C_o]NFEB!122?@?A$#149!16?_w!124?@??@AAKC?KGO?_$#150!165?C$#151!156?BAC??GO?_$#152!152?@@A??C??O?_!18?@$#153!154?@!5?G??_$#154!157?@@?C?G??_$#155!160?@?A?@??G[WO~}_$#156!37?@C!129?@$#157!184?GAG_!14?@BFF~~}wo$#158!20?G???@$#162!32?OO?E?IAAAG_a_!4O$#163!32?@???@!12?CAA!179?@$#165!182?D$#167!15?G!167?_@O!29?BMw_$#168???G!9?A!217?A$#169!138?@!6?G?O!72?@BM]W$#171???_C!21?G!49?C!153?GO@$#172!16?C?AA@!4?Go!113?@!5?GH?OOO_$#173!143?@BA?CAIC???oO_$#176!28?C?_!7?@@!12?_$#177!150?_!32?A?@FZB@??@@!5?@BF}[o_!22?O?C$#179!184?A!33?BN]{o_$#184!14?O!170?_?CKEBBAAB@@@BAKw?_$#185!24?O!201?@$#187!174?__$#189!5?A$#191!183?@!34?O_$#192!4?A$#194!227?G$#195!159?@??@L[GAEAEB??AKO$#196!158?A?AB??AQ[??_k?@LO$#197!22?O!120?C$#198!25?_!198?_$#200!24?G$#201!30?G!17?___O[MEA$#202??_?O!137?C!83?E$#205!29?A!198?C$#208!56?_O!169?C??_C$#209!58?_$#220!144?G?O$#222!4?@!18?__!109?@@@AA$#225X^S??_wwxjbFB!46?~}}!6~^NB@!6?OOw!47~}}~}}{wwGG__wg$#232!29?@!198?B$#233!27?@?_!23?_???@!16?WU!105?A$#234!27?G_!45?_$#237!21?_!118?A$#239!22?_O!115?A!8?_$#241!4?_!53?A!17?_!149?_@$#243???A??C@!62?_!73?OO$#244!69?_?_!7?B$#245!13?@!43?_O!13?GA@-#0!164?@??C???_!10?@$#1!170?C?_$#2!169?A?G?_??EO$#5!173?GNN?AG_$#6!48?C!25?_$#7!38?CCC!12?@$#8!183?_$#9!177?@CO??o$#10!71?O$#11!11?oE!25?GGG!33?G@!93?_$#14!180?_o$#15!12?@!18?C!43?A!74?@$#17!189?BN^~~vvv~~~|~~}[$#18!151?_$#20!71?C@??C!74?CO!71?_O$#21!32?@$#24!212?M{$#26!187?C!25?@F]WO$#30!215?@eG$#31!46?A$#36!13?gDD!19?O_oO?_o_$#37!45?O?O!24?_O!80?@B?C?H?AsC??o$#38!70?G$#40!36?A!12?@!175?_??C$#41!33?!14@$#44!18?C!166?_$#45??C!8?A!42?A!163?_O?O$#62!224?_O$#63!51?O!100?A$#71!226?GCA@$#72!25?A$#78??OAR@??__C@!38?_!4?A??@!7?_O@!7?ef!12?_!31?_?__!26?CC?G$#79!5?o_?OOI!10?GGGWW_!24?_!4?EE!8?O!11?wZ!9?OO!31?OO?O!22?P!7?_$#81!67?__?E@!80?_!31?_$#82D`g!15?O!35?OK!13?C!19?_!33?_!25?x???W_O$#84!7?_!44?_!99?G$#103!34?A!148?O$#107!49?C!20?O$#109!15?O?@$#111!74?O!90?C$#112!13?@!16?O??C???G!112?A!34?BCW_!33?_$#113!163?A!57?_?O?C$#115!12?_C!4?@!12?O!157?_$#120!31?@!150?K$#121!48?A!129?BN^N$#122!29?C!154?G!32?_??bAA$#124OC!28?C!16?G!27?O!75?B!32?A?@@C!27?@FM!9?@$#127???@!6?O!60?A$#128!150?GG!31?C!39?GCI$#129!35?A!114?oC$#131!26?@AC!19?OW!23?G!78?@?A!4?O?_!5?_!53?D$#132!32?A!12?C???A??@!111?A?CG??_$#133!31?A??C!35?_G!96?O$#135!29?_gG!4?G!6?GGG!6?A!18?_??A!110?C!22?O!13?O$#142!45?A$#143!37?!8A$#145?G!9?C!4?KA!17?G!10?G???C???@!20?G!91?O!15?A??O!25?@Aw_!10?C$#147!48?_$#148!13?OyIB?A!13?oWo_!150?_??O$#149!36?O?__O!5?O!110?AEEACGOg$#151!165?@?AC?G$#152!35?CC!9?CC??A!112?@?A??GO$#153!166?A??GO$#154!166?@@AC?O$#155!171?BN??_G$#156!47?A$#157!12?OA!18?C!128?@!26?QG!17?BN~~~o!13?@$#161!11?GG!28?G!32?C!91?G!19?I_!38?A@$#162!227?G?A$#163!226?O???@$#165!29?@$#167!16?OC?@!9?Q?_G_G!13?G??CCA!18?OC!88?A!5?_!14?@CG!4?_!27?PNC$#168?O!221?A@$#169!19?A@!29?O?G!100?A!4?O?_!58?_O$#171_?B!7?_!4?_!12?@!40?_!94?C!62?A$#172!17?G!9?@A!10?O??Ooo_!4?GG!21?_!79?@??C?G?PO???G!19?O?AG$#173!156?B@@?KG?gOo$#176!50?@!132?G$#177!30?A!11?G!29?GA@!113?@??_??GGG!7?_x~{_!15?G$#179!220?G?@@$#184!184?@!4?CO!9?A??@BE$#185!17?O!7?@??G!125?C?G$#187!173?VOO__o$#192!75?_$#195!177?G$#196!168?@@BCO?_?PC$#197!29?G!16?__!107?C?G$#198!16?_!36?C$#201!47?@@$#202GA!53?@!128?O!36?GK?A@$#208!69?W$#209!66?FF$#212!19?O$#222!19?CA!4FC!27?G!22?WWFC$#225???{kM^^NN@!8?__ooo__!27?___xx}!7~GG]!10?_!8~^NN!31~NN^N!22~m!6?_$#233!30?@??A???C???!4C!6?@!130?A$#234!51?A!20?E@!88?@$#237!26?AC$#239!18?G!7?C?_!20?_!107?O?_$#241!149?C!73?C$#243!17?__!7?WWO!23?OOK!14?A!83?_G?O__$#244A!18?G[!34?O!20?@!11?_!63?O?O$#245!27?_!41?@@!78?A-#0!172?@$#2!178?GEC$#5!177?A??A$#6!67?o!6?B$#7!68?C!108?_$#9!182?_$#10!212?_$#11!9?_C!57?O!82?_!21?C!39?O?G?CC$#14!181?BN$#15!87?_!63?@$#17!193?@BFFNN^NBBB@$#18!212?O$#20!216?_$#21!150?_$#26!195?G!11?O?G$#35!69?_C?M$#36!11?OiA!174?A$#37!163?@???H@Oo??O!14?C$#38!66?O!60?O$#39!212?G$#40!219?O$#44!8?_!4?O!15?_C!11?@!109?C!33?A$#45!217?@@$#62!67?C!20?@!34?@!95?G???@$#63!14?G$#71!220?GCA$#72A!15?@!171?_$#78?@@!5?G@!8?_?_???O!39?o!10?Q^!9?WC?\[!33?R?OC$#79GMQwoFZX!7?GuNRwOO?o??E!5?SS!4OKKK!5CKCEF^NKK!10?BHI!8?C_|?O!5?kB@??`!26?_??OO???@A?o??o!13?O?oo!5?oBFFCCIIC?Oo!20?g_$#81!67?@!117?C$#82!8?B!5?_!32?A!18?@!8?g!49?eKA!26?G???A!26?W$#83?O_!23?@!93?_?@!7?_!28?A$#84!17?_$#87!65?O$#90!149?O$#106!211?_$#107!66?_??@!81?]!32?_!30?O???AA$#108!193?_$#111!69?C!146?GG$#112!9?OI!62?_G!141?O??C@@$#113!74?O!99?G!43?A$#115!11?C!61?@$#120!181?G?_$#121!180?@CO$#122!27?C!184?C??@$#124!30?@!92?a???_!62?@!14?_???_???A$#127!87?G!39?G!56?@$#128!88?K!129?G??G@$#129!68?A!81?Z!33?C!39?@$#131!29?G!7?@@?@!121?@???G?O_!17?AG!5?GO!12?O?G$#132!69?A!101?@?ACG$#133!68?G$#135!10?PA!16?AA!145?O!13?A?A?GO!12?KEA$#141!70?_o$#142!214?_!5?C$#145!10?_!15?_?OC!43?A!13?O!88?_!14?GO!5?_!12?C??@$#147!13?_?A!14?G!130?@??C!20?@?G$#148!11?GDD@!13?_!164?C$#149!11?_O!152?@BC??CKG!16?COo_$#151!173?@AAGO_!4?A$#153!183?@$#154!174?@@CGO_?O$#156!184?G!37?CA$#157!9?G!17?G!41?G???C!116?C?@AC??O!6?_?O?HDFBB@$#159!70?WMp$#161!11?@!15?oK@!43?O!114?@@ACGO_$#162!218?_$#163!184?A$#164!183?[$#165!214?O$#167!9?C!4?A!13?@!42?@!16?O!33?_!49?C!14?@???@!21?G$#168!217?O$#169!14?C!19?@@!7?@!108?A_!9?A???O_!19?O_!18?_O$#171!68?_!19?A!34?[!26?C!20?A!47?@?A$#172!13?G?@!14?A!8?@!29?O!82?w!11?AEC??@A??GO_!10?@??O_?A???o$#173!164?@??AMMGoo__!14?GG$#176!184?O$#177!67?G??A???_!95?@!25?G!8?O@B??_??_G?C$#179!197?_!8?__??OG?CEAA$#182!176?@@$#184!73?G!118?C??_??O_o{{{]NM$#185!30?_A@!11?@!120?G!20?C$#186!122?C$#187!177?CB$#188!176?A$#191!211?O???C?A$#192@$#194!215?_$#195!179?XW_$#196!178?C?_$#197!29?O?@!4?@!4?@!145?C$#198!26?O!95?O!93?@$#202!9?A!65?@!10?_?_A!32?G$#208!67?A@!149?O$#209!17?O???_!30?A!93?o$#212!149?N$#213!149?_$#220!8?O!21?O!14?@!107?G!8?A$#222!15?C!9?OGA???w?A!4E??A??A!109?A!10?G?__!18?OO$#225C?KFNwce!8?G?KFNN~NNN!6?!6_ooo!5wowww_opr!10~KEC!10?A~n!5~B!5?!26~^~~NNA???@@!4N!13~nNNN!6?{!4wssww_$#233!175?CO$#234!70?@???C!97?A$#237!33?@!119?O$#239!31?CA!5?AA!6?@!116?C??O!18?A$#241!65?_!151?_$#243O!7?C!5?OO!8?__?@!4?!6G???AA?AAA@@!36?O?A?_A!30?_??k?_???O!21?@D@!4?@@$#244__!84?C!38?W???o!28?@$#245!15?_!138?E!30?_-#0!184?C$#1!182?C$#3!181?@$#6!63?_OC!7?M$#7!151?A!26?@AC?O_$#8!180?A??O$#10!66?A$#11!65?G$#15!26?B!36?O$#18!150?G$#20!217?G$#21!219?C$#35!66?O$#36!11?@!196?CC$#37!153?_!17?@AACHO?_G?_!11?AE!5?O!9?CGG$#44!10?_!51?O!21?G!38?@??G!73?___!10?G$#45!63?C!63?O!77?@$#63!11?O!180?C$#71!185?A$#72!85?@!37?C??A!45?G!20?G$#78!5?C[A???_!9?@!6?OG!29?__C?A@!18?GA??W!32?w??WOE@!40?@@!16?@!4?A$#79???XoxB@!5?A!8?BB!7?Aw!25?o?@??@!11?O@??c__O@@???EEC!16?o!4?oo?_?pdt@??_!4?F??@!12?[[`D@!6?|?W?W!5?@B?CCCGo!13?FxEI??GOo_!13?_$#81!22?_!193?C?A_$#82??_!9?oC@!13?_?C!28?OOA!13?@G!43?C!4?@!4?@!15?O$#83!59?GG!14?EoO!4?G!7?@!33?@!22?AE!19?G!21?GG$#84!169?G$#87!20?@!127?O$#90??I!11?C!6?A!126?_$#92??C$#93!15?A?@!11?_!184?G$#95!31?_!117?C$#96?a!12?G!5?AC!127?W!64?OBG$#97!15?C!5?_!127?_$#98E[!12?O?!4A!10?O!185?O$#99w!13?_g!5CW!8?_!184?o_$#100!15?O!5w$#103!150?O$#106!73?@$#107!150?_O$#108!72?G!138?@$#109!72?C!121?@$#111!73?_!131?C$#112!8?K@!15?G!38?_!20?O!65?_!46?C$#113!204?C?C!10?C$#115!9?G!17?A!39?A!127?A??G$#120!151?G!31?@$#122!83?_!116?A$#124!74?C!11?G!34?_!4?OC!24?A!44?@!10?@$#127!62?G?A!9?O!142?_$#128!74?@!12?@!62?@!65?@$#129!218?O?_$#131!10?OC@!11?G?_?@!58?A!88?_!14?@A!6?A???!4O?O$#132!66?@$#135!25?_C!37?C?C!5?O!11?_!97?_!14?C!4?G$#137!68?_oO$#138!72?A$#139!66?__WGg$#141!65?_G[EFF~$#142!74?G!143?GG$#145!7?O?C!14?O?G!35?_??O!8?A!10?_!36?Q???_!25?K!28?O!16?A@??@G!13?A$#147!25?@???@!161?A??G???_!6?_!7?@$#148!9?O!16?O!182?A$#149!10?E!162?@@EAY!17?C!14?AEE$#151!179?@??G$#154!180?@AAM$#156!150?A$#157!27?@!94?K!29?o!46?K!7?A$#158!196?C!15?@$#159!68?@???@$#161!7?_OA!14?_O!41?@!17?GA!108?@BA!11?@$#162!217?O$#163!185?O!30?A$#164!181?C$#165!151?@!29?G??@$#167!7?G??@!111?_!80?C???C$#168!185?C!31?@$#169!11?G!73?AO!67?o!17?CG!16?@!5?O??_?C??_!4?O???A$#171!8?@!16?A!39?@!18?OC@!35?@!4?B!49?@ACG!4?_!18?G?A?A$#172!9?_GA!15?C!124?@]!19?CGO@_C!17?G???COO??GGWGGG$#173!172?@?A?KCWoo!11?@@???G$#176!150?C!67?_$#177!200?@@$#179!198?@??AEABA@@$#184!8?a!16?C!46?_!13?C!113?GG!8?@$#185!23?_!4?C!125?C!14?@!36?_!4?OO$#186!84?C!42?_$#188!182?@$#189!63?G$#191!203?@$#192!127?G!57?G$#194!219?O$#197!27?GA!124?@!16?@A!21?C?G?OOO!13?C$#198!61?_!59?O!81?_$#201!218?@$#202!7?C!75?O!39?A??C$#205!30?G!183?E$#206@!12?_!17?O!117?A!64?`$#208!218?C$#209???E!71?_!94?G$#212??O!10?O??@!5?W!6?O$#213?@!16?@@!11?G!117?@$#220!30?@!139?AC$#222!13?@!9?K@!5?A@!50?_!71?@!14?A???_!14?@$#225???_N!27?F!25~NFE@@!12?G?n~Z^^F!5?wwy!16~N!4~NN~^~MYI!8?w}}}!12~bbM!8?A~f~f!5~}{}!4o!15?Ew!4o_$#232!215?K$#233!151?C!32?y$#234!64?GA!7?O$#237!12?A!14?O!126?G!19?O_!34?O$#239!6?_!5?C!10?OE??_GE!31?O!12?_!11?_C@!32?G!32?A!18?O_!14?@!5?O?_!9?__!4?O$#243!5?A!6?G!48?GC!13?E!6?E???_?@!31?F??gw!21?G!20?A!17?w??CCC!4?_!13?!4_$#244??@!28?C!88?A???E!4?@!17?o$#245!13?GA@!6?C!39?A!85?G-#10!63?@$#11!61?OC!121?@$#15!22?_!162?_$#18!219?G$#20!219?C_$#21!185?@$#26!151?_$#29!63?_$#35!63?C$#37!154?G!24?BCUac$#39!193?G$#40!218?C$#44!6?@?GA!66?C!4?@!111?C$#45!74?A!49?_$#49!67?_o$#52!41?_!7?_$#56!37?___??_$#57!46?__??__$#59!52?_!30?_$#63!8?O!70?C$#68!33?!4_!48?_$#72!36?O!37?G!102?C$#76!115?O$#78!9?GG?@!6?__!6?C!78?_??O_!4?G!4?@?GW???A_!18?C!44?@b???_!16?_$#79OGGnKD??__EB!13?_?@??OOXGKOK!5?@???G?KGGGKNKGKJ!22?C!7?@FBS!6CccCcccCCSA??SFB@F@[{~???O@@@_L[C?G?W?G{WKO[WOOo{F!8?F_K!12?BB?AAEwwO_!6?C`!4?o?AK?T@D@DB?!4F@@?@B_O$#81!21?C$#82??@!8?W!15?A!12?@@!33?@!11?B!17?_??A??G!7?_!7?o?OG?G!5?OG!6?_A!8?B!29?`!5?A?DO_$#83!28?OO!8?GG!55?G!8?_!4?A!32?G!14?A!20?_!18?G$#84!143?G$#87!28?B??C!106?_!8?G$#89!218?G$#90!28?C??@!100?_!15?@!66?_$#91!129?_$#93!12?_!17?C!80?_??O!33?A!66?O$#95!12?O!16?@$#96A!18?GC!9?A!77?G$#97!13?@!15?C!118?O!66?C$#98@!12?A???OW?A!91?O_!101?A_?O$#99!13?[~~^NFF@!91?_O!101?@]w_$#108!64?OOC!4?E!80?o_$#109!61?_???C!4?A!82?O$#110!60?_!11?O$#111!60?G?@!9?g$#112!6?wF!15?C@!48?B!8?OC@!99?A$#113!151?@!31?@?O$#115!24?G!37?_?_!5?wG!7?_$#120!150?@$#122!59?G?@!12?CEA???A$#124!8?A!49?_?C!12?O!6?O?A!38?G!4?C!67?_!24?AO$#127!78?@!70?G!43?O$#128!121?@!97?O$#131!25?C!31?OO?A!23?C@!68?C!22?@AC$#132!150?_$#135!6?C!16?_C!38?O???C??C!49?_A???O!26?F!31?wC$#137!68?@$#138!64?@@???A$#139!65?AA@?@@$#141!64?E?@AA??@!81?G$#142!149?O$#145!5?_?O@!62?o?G!8?c!37?OC???GB!24?O$#147!5?G!20?A!33?@!116?A?G$#148!25?A!30?_!8?_???G$#149!180?B@?G$#152!150?W$#157!22?OA!38?GI???G!13?O?GA!40?_!25?GG!32?A$#158!68?G$#161!23?OA!40?GG?CC??@!8?_G!101?C$#163!149?_!69?_$#165!150?A$#167!5?O?_!14?G@!56?_!44?C$#168!219?@G$#169!25?G!30?O?G!18?C??G!41?@!31?@!26?_$#171!6?A!18?@!55?G?@!134?A$#172!8?C@!14?O!30?_?_!96?o!23?@?G?@A$#173!66?O!86?F!27?G[O$#174!23?G!48?E$#176!218?@$#177!61?A!11?C!77?E!33?G$#179!80?@$#181!69?O$#184!7?G!51?O??O?G!18?A$#185!55?O!25?C!4?__$#189!73?_???AAA??@!37?G$#192!194?O$#193!149?C$#194!21?A!198?Ew$#197!24?_?@!42?_!8?_!75?A$#198!59?C!19?P?A?O!37?O!4?G$#200!54?_!11?_O$#201!220?@$#202!9?C@!10?_C!54?@C!41?C!4?A!68?G$#205C@!19?@!127?A!67?@$#206!12?K!4?_!89?oO???G!17?__!8?___!5?C!66?G$#208!22?@$#209!40?CCC?GG?G!8?B!31?E!27?_!17?W!75?EE$#212?A!10?A!5?_?G!10?A!75?G???O?C!29?_???o!66?A$#213!19?O!8?GG!78?c!5?g!24?_!74?@$#214!180?O$#215!40?_$#217!43?___??_!4?_$#220!28?!4_!8?!13O!25?O!9?___!33?O$#222_ooOoA!16?A???_!6?OO!23?C!16?GGG?G!6?@!8?___!12?G!9?A?cEM!4?G!25?G!17?@@?E?G$#224!40?GG$#225!4?B!6?C!20?EFBFBNFFAAIN!4FBFFFB?BF?C!33?!9Bb!6B@@@B!4?EBB?^!8?BB!4FfvBFBFBFFFNBW!10?p!12~{{~{{w!10?A]!4~???BVA}y}y{~!4w}}xw{W$#227!32?_!20?OO!29?_$#229!115?_$#231!29?A!118?G$#232!13?_??_!13?@!82?G!34?_@!66?@E$#233!150?C$#234!59?_OKA$#237!77?_!98?@?C$#239!25?OC_!9?OOO!19?A!14?oopOG!5?WA!5?!4_!26?_A???O!28?o!19?@???O_$#243??E!6?Oo_!8?OW!4?WO!30?B@!25?SUO??S?!14O!17?_!23?@!8?[!35?G!20?F$#244G!26?G!58?GGOW!5G?!10G???K!86?G$#245?C!28?GG???G!38?@!10?G?CG!17?GC?_??CA!16?OOO_???_!48?W!5?C??_!18?K-#6!55?_O$#10!57?G!14?[$#11!56?g?D!12?G@!77?C!34?s$#18!220?@$#20!220?A$#26!57?_???_$#35!152?K$#36!51?G?O!22?A$#37!52?O!66?_!34?_$#38!194?G$#44!186?O$#45!120?C!65?C!7?O$#49!6?O_!12?C??_A??__??_!8?GG?A!4@O?@?_!11?CAB!9?O!39?_$#51!35?AA!60?A!4?KC$#52!18?C!10?[?O!67?A!6?C!6?GGG$#53!12?O???CC!7?C?CC!4?C!7?BA?O!22?CB!14?AAA!4?A!5?A?A??[??CC??o??_!4?O$#55!8?!4o_!6w!5?{w{YY???ww{{{~~~b__o__oo__!16?CB!18?AA]][[[!9?O!5WGo?Oooo_$#56!9?G!5?C!59?_!5?WA!10?E$#57!11?GG!6?K!5?A!17?@!4?@!34?CCDDD@@???WACw!4?_!14?GO$#58!117?_$#59!20?A!7?@??@!49?__wwgg_???@@@x!22?G??O$#62!119?@!101?@$#63!55?E!62?C!36?~$#66!100?@$#68!12?C!4?AAA!7?@!24?C!21?_!20?@@@!6?A$#71!222?G$#72??@!16?@!114?_!46?@$#77!213?_$#78???A!101?@@!10?AB!4?A!4?@!6?[@!9?@!34?O!11?A?AcO!13?O???E$#79KCC!5?@@@!106?@!4?B!4?O!6?O!21?~!19?@@??@ESo???F!5?G???@!8?OO??o?O?@$#81!135?_!57?@!28?C$#82!12?@!4?@$#83!181?_!11?O???e!7?_$#84!214?k$#87!133?B???@!7?@A$#92!216?O$#93!13?@?@!95?C!32?@??@$#95!137?A$#96!111?A!20?@???O!8?CGCK!67?E???_$#97!129?A?_G!10?@A!74?C$#98!113?@!15?{_@E???_??@??@!4?wB!67?@_?G$#99!112?@!17?^]!6?E?BB?ACGo!70?P|_$#100!137?ww}{{}{wo!71?MA$#107!149?G!35?G$#108!22?G!35?___!6?GO!11?@$#109!20?O??@!21?CCC!14?G???G??O!52?_!29?@$#111!72?a$#112!5?M!16?@!34?O!13?o!6?_G?@!68?G!34?B$#113!55?O!93?C$#115!22?O!7?O!12?CC!5?AA!7?KKHfB@!5?B!8?_!44?_!26?@$#122!73?@!112?_$#124!6?C!66?E!46?A!63?o!9?CO!26?_$#127!125?C$#128!57?A!61?C@!28?A!73?G$#129!149?@!72?@O$#131!53?A!10?_!9?A!50?A!28?[!28?@$#132!149?_$#133!149?O$#135!6?A!13?_?C!45?G??B!6?OC!38?_G!4?A!28?E$#141!70?O!81?A$#142!195?G!24?G?O$#143!148?_$#145!4?G_!15?A!32?_???G?@!9?C!9?GA!37?O???GG!28?@!30?F!36?c$#147!7?@!49?@!17?@!107?C$#148!22?_!27?G!18?C!8?HA$#149!151?C$#157!150?_$#158!23?A!37?E???G$#159!69?__!80?wo$#161!4?_P@!14?SA!36?QOOO?OOO!4?C!7?OE!42?O$#163!221?A$#167!4?C!24?_?C!10?C!5?IM??A@P@!4?A??c!11?A?`!40?OA!31?A$#169!4?A!49?GG@$#171!48?C!75?P@!58?G!9?B_!24?C$#172!30?G?A!19?H!20?GC!79?B$#173!20?G??C!17?C!5?A???O!12?I??__!6?C?A???C$#174!21?G$#177!221?W$#181!23?G!6?_!14?GIG?O?@!13?@!8?O?KCE$#184!4?O!16?_!36?O!4?O???O?GG!52?_C!25?O??w$#185??OO!7?C!14?@!26?CC!58?CCC!4?G!6?_$#186!56?A$#189!21?@$#192!56?C$#193!148?O$#194!146?C!73?O?A$#197???_??G!24?G!18?S??G!9?G?_???B???OGG@??@??@!39?O!59?@A$#198!123?C!62?G$#200!23?O!8?CA!8?GGIA!7?_!21?O?W??O$#201!219?@$#202!110?C!75?A!8?C$#205!14?@!204?A$#206!111?@!17?@??O???G?@!8?A!68?G$#208???C$#209!213?AA$#212!16?@!96?A!14?a???_C!73?_!4?_??`$#213!107?@!20?[!7?C!8?A!70?_!6?_$#214!7?O!11?O!4?@!51?_!5?C!38?_???_$#215!41?OO??O!5?_!13?C!18?@!25?O!4?O$#216!26?A!13?O!56?{___!6?_$#217___???_GG!4?CC!4?_!9?@@!18?@!30?_?W??OOW__`___Cw!6?!5_?C!11?_O!4?_$#220?O!7?CC!4?A!9?@!80?A?AA!7?C???G!60?A$#222BJA?@??!7A!4?@!85?@!9?AAA!4?D$#225!115?@@!17?NB!21?!19~}}~~}G!5?w!4~__???G!7~^NN~~NNN[$#227!16?A!56?_!24?@@!5?A!5?G!4?C$#232!112?A!24?C!81?O$#234!57?CA@!90?B$#236!34?A!5?C!9?_!15?_?C!41?_$#237!30?EA@@!17?C??A!52?C?CG?G!5?G!6?O$#238!10?G!18?A!4?@@@!5?@!40?@!7?AA??AC?[[]AAA!5?G$#239O?GG???CC!5?A!5?@!53?@!26?@@@???A??A!11?G@?GO!6?_!49?G??@!7?_$#243???@!7?@!97?@@!10?AC???NA!5?O!48?G!9?DC!19?@$#244!114?@!12?L!8?A!45?_!13?B!9?_!4?_$#245!108?@???C!20?G!58?Y??@W!17?OW-#6!51?_OCA@!93?A$#7!148?O$#10!72?w$#11!54?C!17?C$#17!71?C$#18!148?C$#20!222?E$#21!148?A$#24!123?@$#36!26?O!23?G!69?G!33?A$#37!53?_??A!21?A!71?W$#38!184?_!36?@$#40!146?o!73?_?O$#49!5?C?@!8?o!5?o|!4?wK??O!12?_o_GC?@!26?KG!34?S??__[@@!9?O$#51!49?@!28?_!32?B!14?_$#52!6?A!10?O!7?O?@?A!4?WAA!56?_!21?O!8?_??A?GG_$#53!18?@!10?o!7?A!7?O?O!33?K!23?_??@?A!15?QO?O$#55!6?{}^^!6~NNM!5?NNL???}{NNB@@@!7~NNN@!29?O_{!25?_o}}|{~~B@!9?@@k___$#56!33?_!39?GC$#57!74?G??_???A!14?B!4AB!5?F!7?G??G!6?G?@$#58_!82?A??A!8?Bc_?cCCBpGGG$#59?o@!71?@!5?@@~|~~|!5~MYZ[!4WwwwIFF$#62!139?_!70?C!12?C$#63!128?ACC!24?F!40?C!5?G!4?AA$#65!61?A@?@?E$#66!209?A$#68!73?E$#71!145?_!75?A_$#72!134?@!66?G???A$#77!213?@C$#78!177?OO!13?_?O?A??O!12?C$#79!156?@G!18?C!6?B???]!4?XYm??q__MEAAA@!4?@$#81!131?A!73?G!5?G??__!7?A$#83!181?@!6?AA!7?@$#84!157?C!39?C!15?EB$#87!216?C$#96!130?A!9?_!62?_!5?G!7?G???C$#97!136?C!76?_???E$#98!129?@!6?BG???_!5?D!60?G!8?@?@A_$#99!130?@!6?FNPP@ptNF@!58?_OO??oo!6?^A@G$#100!139?MM]MI!62?__oo??_!6?KK$#101!219?_$#108!20?O@!99?_G$#109!19?C?A!5?GA!94?A!8?O$#111!54?@!17?B!76?C$#112???wA!46?O!19?B!5?A!71?G!35?~$#115??O@O@!14?_K!7?@!92?oC!8?_!21?O$#120!148?G$#122!133?AO!51?@$#124!34?_!16?G!4?@!19?A!56?KGO?_!46?F?g!8?O$#127!137?O!58?G!23?O$#129!224?[$#131!35?_!13?O!146?O$#132!149?@$#133!148?_$#135!19?GG!34?A!18?_???@!37?o???OCD!30?N$#142!223?G$#145??_AG!30?O!17?O!21?G?C!39?I!31?_???_!41?F!26?@$#147!61?@!72?C!70?CCC$#148!21?_!97?_?A??@$#157!52?C!18?_???_!77?O$#158!19?A?O!101?G$#159!55?CKNFB!8?AB^!79?_to$#161???CD!14?oB!32?A!21?OK!43?_WA$#162!223?_$#163!148?@!74?O$#167!18?_!8?OC!7?G!12?_OCA@G!21?O!38?_G!15?A@??O!13?A???k!31?S!8?__$#168!147?O$#169!35?G!20?_??C!7?o!5?_?C!59?_$#171!26?_!91?A!13?K!14?_??@!44?G!26?G$#172!27?C!46?O!42?O!32?C???@$#173!22?@!31?owO???@!6?@|{_!52?OA!26?IN$#177!149?O$#181!4?_!13?O@??E!5?@!28?O!9?G!9?G$#184!20?C!29?_?_!18?W!5?@!39?C@$#185!131?C??_!69?C$#186!213?G$#189!135?G_?_!45?W?A$#193!224?_$#194!136?G!86?@$#197??G??A!42?_!18?E!49?@C!14?o$#200!22?GA???_!6?C?O!12?GEA@!23?@??@!43?_C$#201!146?G$#202!132?@!67?_oOGG???CC?CG$#204!58?_!7o$#205!138?O!8?G!58?G???G?O!6?O$#206!129?A!74?O$#209!176?O$#212!135?B!76?@??BY$#213!216?`$#214??C!14?_!6?__?A??@@_???_!11?O!27?_O?A!35?CC?OBE???W$#215!5?w??__!14?O!6?A?O???{!10?CA@!28?C?o!12?__!8?oOO!7?gAB!8?aK?O$#216!80?A!16?@?@!7?G!17?O$#217^NA???@!67?AB!16?pDC??Cc???CC??F!18?C??G??G$#219!65?@@$#220!206?A$#221!60?G!5?_$#222!194?@!5?O?C!7?A$#225!157?r!18~jnn~~}{{???``p~~Ed???GNN!5@???@@$#227!73?@$#228!57?_OGCKMNMMW$#232!131?@!12?oWEA!56?_O?G!9?o_??O$#234!52?GG$#235!58?G$#236!26?A!52?O!29?@!20?O$#237!35?CC!23?A!12?O!54?C$#238!48?A!49?@?@$#239!128?@!5?A!20?w!47?C!10?O$#241!202?_O!9?O$#243!156?y!39?@!14?A??GO$#244!135?C!46?@!5?KK!21?@A??G$#245!156?C!25?A!5?O!9?O!7?@@!7?C-#6!46?_O?C@$#7!146?o$#10!71?_H$#11!47?g???@!19?O$#21!220?A$#26!71?@$#29!20?S!99?C$#35!149?{_`{$#36!23?OC!91?@$#37!71?A!44?O$#38!140?@??E$#40!223?A$#44!137?@$#45!141?C$#49???O!12?CA!4?HB??G?@!12?_?K!39?_o!26?GA?_?EB!5?@!9?O$#51!43?A!34?@$#52!22?cG???@?IC???A!9?C?@!27?_??@!6?E!19?G!5?O!13?@!6?E$#53!29?@!4?oAA??A??A?A!32?O??A!14?@!13?OG!12?o?@@?@??GG$#55!6?@@???!5~!10?o}}?@@???{{}~|NNL@@!30?}}MEFD!5?!5oww}~}}}{ww___oooxxnF@@@!8?kM}EEFE~~oo_$#56!16?G!14?A!41?O??@$#57???_?_??@@}!11?AC?_!6?o!7?_!37?O!11?CAA!6?A?CO???EAA!19?O$#58!9?}!80?A!7?@@AA?@@!21?oo_$#59^???OI{{}!73?@@@B!4F@@@!7?@@FEAE!91?_$#62!142?C?G?B$#63!139?K??O!54?GA$#68!137?Ooo$#71!223?Oo$#72!141?G$#75!53?G$#78!143?O!13?@!9?O??_G??_?@@@!4?C!8?C??G$#79!155?@!4?__w__??A!4?eaO!4?AwMa_???w!4?bbD??@@$#81!144?o$#82!179?C$#84!155?}!14?C!18?E??G?a$#86!53?O?G!4?G??GW$#87!179?w$#88!53?_!4?Ggo_?___$#89!215?@!5?C$#90!169?_!5?C??A$#92!175?G$#93!175?O$#95!175?_!26?@$#96!177?A!43?A_$#97!178?G!22?G!14?A!5?G$#98!143?@!32?C!24?O!12?@??@@_?@O$#99!176?GK!23?_M@@!7?@@A?G?K$#100!176?oo!24?o}}!7~}}{{s}q$#101!223?_M$#108!17?_aC!100?A!32?E$#109!18?@!55?A!44?G!33?W$#111!48?C!23?A$#112??C!43?O?O!97?GOA!36?~$#113!147?@$#115!17?O?wg??_G!19?_WK!33?_?g!31?A???aOGB!11?CG!18?_$#124!30?_O??@!12?C!23?G?@!66?A?A?A!41?G!9?@$#127!140?C@???C!49?A!24?_$#128!220?C_$#129!146?C!73?G$#131!32?G@!14?_?OG!18?O!124?@$#132!48?G$#133!147?C$#135?OO@!15?A!92?_??@_?OD$#142!221?G?C$#143!223?G$#145?G_A!29?A!15?@!31?_O!30?GGA?G!35?@!42?{$#147!67?A!130?K}$#148!21?@???D!55?O!52?O!13?O$#149!121?C$#157!49?G!97?_C$#158!20?B!22?_O!74?_$#159!54?@!95?^]B$#161?_I!15?[@!52?OE@!42?oKA@$#162!220?@O?@$#163!139?@!5?B!74?O$#167?C?C!22?@!4?G!15?A@??A!21?G!39?_!18?@A?o_?@??A!6?G!5?~!29?W$#169?A!28?O??C!18?GC?@!11?@o!66?G??A$#171!25?A!6?C!15?A?C!93?C_!40?v!9?A$#172!24?O!27?@!59?O!20?@C!14?@$#173!17?G???M!20?_O!9?B!14?FNN!49?O?@!10?G!14?_A$#174!72?C$#179!49?o_O??A!13?G???_$#181_??G!17?_!23?C!68?O!7?A$#184??@!42?_!24?_!42?OC$#185!136?@!60?O?@$#186!51?_$#189!184?f$#191!139?A$#194!143?G!57?A!22?@$#197!21?O!22?G?A@??GCE!16?o?C???@!7?G!31?C!16?A$#200!17?C!7?OA!10?@!41?_???S!27?_?C?_?C@?_G!10?C?_$#201!145?O$#202!195?C!4?F@$#204!52?O??AA@?@@@BBBFN$#205!142?@?@G!30?A!39?@??@??@$#206!178?C!21?_C$#208!200?G$#209!54?GC!112?AAA$#211!56?CEFEEECC?GO$#212!142?G!26?GWO!28?O$#213!169?O$#214!4?@@!10?r@!4?O?bGC??oA?@?K?@!8?A!27?_S!4?OWGCAG!25?_OCA?WG!20?_$#215!45?@!31?_gG?D???o!4?GCC@!4?ACCO!4?GCC??E??@!10?!4G$#216!10?@!22?o!6?O!44?!5G!11?G?O?G@!18?o!5?@$#217?@??mSAA!73?AA??C!10?@@!4?GGC@!6?G$#219!67?C$#220!134?@B?AC?Go_$#221!54?C$#222!180?E!16?C$#225!158?~~^^F^^~~l@@@F!4@???@@p\Z???@@x~~?C???A$#227!135?CMKG?o$#228!56?@!10?W$#229!67?_$#230!52?_?oowwoO?WwO?O_$#232!178?o!36?A???]??E$#234!49?AA!96?I@$#236!29?C!11?OO!78?O$#237!30?GcAG?@!38?G!59?A?O!61?o$#238!121?_O$#239!143?_$#242!64?C$#243!156?@}!15?O!13?E!6?GO$#244!156?}!11?KC!4?E!13?o!4?WO$#245!168?o??_WKGA!12?M???O??_-#6!41?_?GC!22?O??@$#7!145?A$#10!44?A!21?_??C$#11!43?C!101?G!26?W$#15!145?@!26?C$#21!144?C$#24!17?G!60?C$#29!18?C@@!20?C$#35!150?@@B$#36!40?A!39?_!27?O$#37!75?G!62?C$#38!66?O$#40!143?O$#45!68?A!73?G$#49??G!11?_!6?A!11?GgWGA??@!29?_O??KFB@!4?c!22?_O?G???CA@??o!19?C??_!14?w_$#51!6?O!23?O$#52!26?C`?g!76?_G?A!48?O$#53!5?w!20?@!5?@P???D!34?A!10?@@!35?@@!11?@@$#55???y??gw???F~^^^!8?FF!4?GWEEFFF!35?CE!8?A}}~~~wwwxx!11~^^FFF!9?ww}}~~~www}!4~}MEwwwO!18?!4_$#56???@W!20?G!134?O$#57??o?@A!4?@O!10?__!9?_!47?O!8?A!19?@!5?_!10?E!7?gC!19?W$#58!6?EAopO!77?EECCC!33?F@$#59!6?@?FE!145?C!41?@$#62!142?O$#63!49?A!149?K$#67!163?O$#68!139?@!18?G??O$#71!220?@_$#72!191?@$#75!58?O$#77!57?O!4?O!100?CG!15?C$#78!171?C!7?C$#79!158?C??C!6?C?E!10?RGo???_?G!4?C$#81!174?A!20?G!27?O$#82!164?A!13?_!10?C!4?B$#83!159?@!10?G!17?@?B$#84!180?@$#86!49?C!13?OAG$#87!55?O!8?WOKB!111?A!9?O$#88!47?_OgkGXC?G?@@FMKLL@C$#90!189?_$#93!178?G$#94!49?OO?_GSCG$#96!175?@??E!11?O!9?~!19?A??A$#97!175?]??@$#98!175?_oO!12?_O!27?C$#99!176?GN!13?_!9?~f!16~zw$#100!176?F!25?W$#101!224?@$#107!144?G$#108!17?O@!57?OG!38?A@!28?_$#109!17?_?O_O!53?_???@!30?G@?_OH!37?HK$#111!46?@!22?A$#112!42?G!25?C?A!75?A!25?_!12?~$#113!67?_!154?_$#115?O@!15?__?GC!14?___?GE@!30?O???OC?C!32?_OKA@!22?G!4?W{w{KwwEA$#124!45?C!101?@!25?G!22?O$#127!51?_!92?A$#128!67?G!104?A!49?G$#129!221?C??[$#131!43?__!25?C!68?A!33?@!23?_$#132!42?O$#133!144?oC$#135C!15?O@!22?_!33?_?GC_??A!28?C_OG?C$#136!18?IM$#142!221?O??A$#145AG!14?G!27?H!28?_!4?AIR!27?_W??@!33?C!6?oO!41?B$#147!45?_OGC!6?_!8?_???@!124?Ko$#148@!19?C?@!6?@!7?OGC!71?C??A??C!22?G!7?@$#149!20?G!116?A$#156!143?_!77?A$#157!43?O!24?O??@$#158!18?O?Q_?@!12?_?OW[A@!33?_oG!69?EA?C$#159!151?A$#161wB!14?_A!57?O???oK!31?_OGA@!28?O!8?_$#163!221?GC$#167!16?C!10?GCA!16?A@!88?@@AC!7?A??o???@!29?i!11?_$#168!222?A_$#169!56?_???!4_?_??_!69?@!34?_!23?O$#171!22?A!20?A!25?H!101?_?E!12?~!9?K$#172!26?o???@!79?A!29?C$#173!21?CG!18?@!76?A!30?@A?C$#176!221?@O$#177!42?_$#179!44?O?KCB@!7?___$#181??A!12?_A!55?_???CA!4?@!24?_?__OG??_O??@$#184?C!15?C!23?O!39?@!29?A??C!30?_$#185!140?A?A@!12?C!37?G$#186!50?@$#189!172?@!11?T$#192!171?O?O$#193!224?_$#194!222?@$#197?_!23?_?OA???_!12?W?A!33?G!30?AC!25?G?O$#200!21?@OA???C???_???_OGCA!31?_??@???@!30?COG!5?GC!16?@A???O!16?O!39?G$#202!171?G!20?EO?_???r$#204!54?_$#205!223?L$#206!177?_$#208!67?C!124?G$#209!60?OO!100?G?CO!13?wAC$#212!142?_!31?|???O@!10?G!4?A$#213!143?G@!46?G$#214!23?SoO??xOEC!38?OGWW!7?_!25?O!5?@!27?C$#215??C!10?_??@!13?_?W?O???B@!42?W!8?A!12?_!4?@!9?C!8?@!5?o$#216!10?Eg!11?G!64?@@@?A!26?A!5?F$#217!5?@?DGGg!124?O!27?_!33?A$#220!141?BD!16?G??O??_!27?A$#222!155?A!5?G!4?_???_!22?@$#225!160?C?CG?L^~w}O!9?wgvN???^}@$#227!140?@!23?_$#229!46?_!6?_??O!9?A$#230!47?Og?AVERJBFMMG@BAACB@$#231!192?O$#232!192?_!27?C$#234!45?B!22?G!77?@$#236!24?G?A!47?A!31?G!50?_$#237!26?GA?C?B!37?oGE!69?_!15?G!39?C~$#238???CeC!66?@@!65?_!19?O??_$#239!143?A!13?C??G!30?A@$#240!164?O$#241!191?C?_?O$#242!59?O$#243!155?@ABB?!4B@A!4?@B$#244!159?E!8?B@!25?D$#245!143?C!12?@!32?AC-#6!36?OGCA@!31?A!69?OC$#7!37?___!10?O!90?_$#11!34?_!16?C???@???AA??CCA$#12!72?G$#13!69?C$#15!38?G!7?_!16?G!66?_!40?A$#17!68?G!75?A$#18!51?W!89?O$#20!52?_!170?O_$#24!58?@!18?O!66?C??A???G$#29!16?_o?O!54?_$#35!148?O$#36!15?@!8?A!83?A!53?_??_$#37!21?_?C!8?C!131?_$#38!52?@$#40!141?G$#45!53?O!5?_C!135?C$#49?OA!10?TD!6?G???_???A??A@!45?O?A@!19?G?@?_???OW?KE@@@!12?G!24?KE@CK!6?C$#52??@!21?_!103?O!9?O!16?@$#53?_!110?G$#55??_bbBBB!4?~!11?W[W^V!50?G{{}!10~NFF^^^~~RBB???!5_oow{{{!10~BBF^^~{w^^N@!17?EJB^^]]][W$#56!11?@!11?O!104?G!11?@!24?@??O$#57?AK???CC???}!10?B@!55?_?@!13?O!6?OG!28?_??B?_!18?H!6?@@?AC?G$#58???GWW??F?O!83?O_!71?Q$#59!6?oow^n!83?_!74?AA$#62!196?G$#63!40?O!17?_!6?_!74?C@!31?@!26?O$#66!169?@$#68!166?@$#71!142?@!50?O!30?C$#75!59?C$#77!55?GCKC$#78!189?_!10?G$#79!173?[][!5O?_b???B[$#81!60?O!163?A_$#83!176?C?A$#84!54?G$#86!42?OCOOO?G???G$#87!43?O!5?K???K?C???WG$#88!44?GANME!9?G$#91!189?C$#92!189?B$#93!192?_$#94!47?@!4?C$#96!140?O!34?@!14?_!9?@!20?@$#97!190?O!10?O$#98!192?K!8?N!19?I_$#99!190?Bx!10?~???_!14?c$#100!191?E!11?~~~^!14~$#106!142?_?@$#107!42?___!97?C$#108!16?C!15?WO!36?A??_?O!30?GG?C!33?_o\E??C?C$#109!15?A???C@!10?O??W!31?G?SG_!5?C@!34?@!31?GA??@?I?C$#110!72?C$#111!72?@$#112!30?_!4?O???CA!4?_!5?_??@?@!4?_C??@@O!5?@!79?O!16?_O@!12?~$#113!41?@!5?__!11?_!162?G$#115!14?_?WN\JA!7?_?CI?KENFB@!38?_GA!27?CG?CA?@!35?@@BB!4?!4_$#120!40?__!7?_?B$#122!39?G!24?_!132?@$#124!54?_!7?A!107?G!13?N?E!10?K$#128!61?Og!162?C$#129!142?A!79?A_?G$#131!39?OKCA@!152?A$#132!35?_!14?_$#133!36?_!105?GA$#135!15?_A!13?O!7?A!23?O?O!8?Y?_GAC@!28?CAB@!31?O??@@AA???C]!15?O@A$#136!18?a$#137!145?_G$#138!148?C???O$#139!149?WOO$#141!59?@!88?!5_$#142!52?O!171?G$#145C!14?C!13?_G??_!19?_???A!5?_!89?B_!17?C!50?A$#147!41?GCA!10?O??_!82?A!53?OH???E$#148!104?OGA??G?C!44?_O$#149!20?O!84?O!57?_$#157A!38?@$#158!19?_K!53?^NB!35?A!48?_$#159!70?WG!74?OCG$#161!15?O@!14?_!4?G!30?G?_?A_???OKB!50?_!23?G@$#163!50?C!171?C@$#165!143?@$#167G!24?@???O?@!31?O!91?OO!15?G!13?w!10?A$#168!49?O???A!86?_$#169!44?@!11?_!10?@!104?O!25?C$#171!32?_!23?A!4?C!45?@!76?o?@!10?o!26?O$#172!22?O!18?A@!22?C!5?@$#173!20?_!10?C!29?@!5?C?O?o!6?O!27?OO!47?_??O$#174!70?C?O!80?_!17?K$#175!143?G$#176!50?G!171?@$#177!37?O!15?@???@A!9?_!154?C$#179!54?A_!6?@A@??_$#181!21?A??C!7?@?@!32?AAA!31?_?_???AO???CA@!15?O$#184@!14?G!21?C!23?A??AOO!4?C?C??_!73?C?G!18?_$#185!194?N?O?_?_$#189!196?@$#191!38?O!16?A$#194!224?@$#197O!13?O!6?PGG!6?A??A!26?@??@GGE!12?C!22?_O?CC?@@G!18?O!36?_???C$#200_@!11?AG!6?C??@A_??G!39?@@!7?_?@!23?G_@??O!49?O$#201!222?G$#202!50?@!88?O!53?_!5?@$#204!55?O!10?_$#205!141?C!80?O$#206!201?_$#208!193?L$#209!61?G$#211!42?G$#212!177?@!11?W!10?C!24?O$#213!139?_GA!34?@!23?A$#214?GOC?_!7?gA!8?A??A_??@!37?@!35?EB!23?K!6?_?_!16?A!12?C$#215!22?__!5?D!50?A!13?GG!5?KCC_!10?AAA!16?BC???A!17?G!4?@??A$#216!4?CC!87?o???_!30?C$#217?C?O??GG?_!118?_!38?GIs$#220!168?@$#222!187?[_$#225!176?GKKNN^^[!4?B$#227!167?@$#229!41?O??A@??O!7?O?O$#230!43?GCK?O@B!7?O$#232!190?K?R!28?O$#235!146?_w$#236!26?C?G$#237!22?C???@!104?_!7?K!28?_!25?_u??Zw$#238!96?_?_!68?_$#239!170?@?_A!13?_!8?_$#241!50?A?A!140?A$#242!56?G$#243!173?___?A??__$#244!54?C!119?@Aa_`_-#6!29?owo_oh___!15?@oq_!69?_OCf!8?_?C@!27?w$#7!41?G??KKC??CC?CK$#10!28?_!28?M}!68?G$#11!33?@!21?@!71?_?OF!10?A!27?C$#12!60?OkG$#13!62?OOg_o$#15!32?@!192?G$#17!139?_$#18!224?A$#20!225?C$#24!21?O!41?C?G!75?C!10?G$#29!15?wZ!56?A?G$#35!149?CGo$#36!171?W$#37!64?C!7?C!81?C!17?_$#40!223?@$#44!126?G!59?C$#45!186?W!39?G$#49?@!10?[!8?A!55?sB!26?A@???OO!12?O!7?NE??@!19?A??A?AAA??O!6?s$#51!175?Oo!4?_$#52!103?A!19?_!10?_$#53?A!10?A@!65?A!24?B?A???__!5?o!4?OO!8?O@?G!19?I!4?A!4?QG!8?G?O?O$#55}{~~NK!5?_@!65?{{!5~FFF~~r``!10?s{{{~~~!5N~~N^~~~NNN@@@!5?o^F!8?GC!9?s!9{KE!6?Gw?G_o__$#56!101?A!65?W$#57!4?_OQ???OD!12?@@!50?o??@!7?W!5?Q??OQOOQO}!11?_!63?G!15?@$#58!7?[??C!75?W!4?KKC?F???_?_$#59!6?@`~}@!82?G~g__??_!11?_!70?_$#63!190?A!8?CO$#65!143?__OO$#67!69?OO$#68!127?A!45?A??C??G!12?C$#71!220?G???O??_$#75!63?@??C$#76!66?A@$#77!188?A$#78!65?@??A!118?G?C!4?G???[O$#79!176?@B??DBJ!4?CGIG?oO?cU$#81!202?G!16?G!6?C$#82!178?@@!19?G$#83!182?C$#84!69?GG$#87!66?@A?C!131?@$#89!223?A$#93!137?G$#95!202?C$#96!138?C!65?_$#98!203?GO!12?_G??HPK$#99!204?!12GwWCB?EKo$#100!202?@FF!11vFFB?@$#104!61?OcgOO?_$#106!28?O!30?A!69?G!23?@$#107!138?O$#108!14?p@!51?O!4?@?H!65?O?A@$#109!15?A?OGC!4?C?A?@!32?A!9?@?_??@!64?GKA@!7?C$#110!59?wC!109?B$#111!27?_!31?Cg$#112!24?G!4?GCB!24?@!13?@!55?O???G!9?G!29?c!14?~$#113!224?@O$#115!13?_?C!4?A?G!4?@!43?_G?OC$#120!47?CCG$#122!60?@!125?B$#124!58?@!10?@!57?C!97?A$#127!226?@?_$#128!224?C_?CO$#131!154?G$#132!34?UN\^~v~vv!5a!4rRA$#133!32?[M?O!7?C!8?_oA!73?G!10?G$#135!14?I!10?_?Q!29?@!15?SAA!66?@!9?O!16?A$#136!16?_NFa!53?@$#137!141?O?C$#138!140?_!11?A$#141!72?A!68?_??A???B@FN@$#142!138?G$#145!28?GC!41?A!56?_?O!39?O@!12?{!12?G$#147!65?C!5?G!64?GA!30?C!17?_!6?@!6?CW_$#148!20?@!48?_!101?c$#152!36?A$#157!29?@$#158!13?O??C_oX!54?_?A$#159!142?O!5?{yo$#161!21?_oooW[KEAB!29?A!11?_G?@!76?__$#163!224?G$#165!42?GG??G?G?GGG$#167!154?@!13?G@$#168!139?A!85?@$#169!68?O??O!53?O!41?_!4?A$#171!59?@!77?_!33?A!12?B!12?v!28?O$#172!154?A$#173!13?G!6?O!45?G!8?OC@!67?@!15?@@@!8?[$#174!153?]$#176!139?C@$#177!125?_??Q!39?O?G!55?_$#179!128?@?_$#181!13?C!6?K!54?_G!77?_!4?@!5?@$#184!14?C!5?_??G?C_!41?_???O?C$#185!191?C?C?A???@G_!18?_$#186!137?C!63?A$#193!220?C$#194!137?O!89?W$#197!25?A@!35?A!91?O!5?@???@$#200!12?_A!7?H?C!53?A!22?@@!31?G!23?@@$#202!70?A!64?_!55?A@!6?A?CO!16?oO$#204!62?@$#205!136?_!66?O!15?C!4?_$#206!139?@!51?@!26?O??O$#208!136?O!52?@!28?_$#209!64?A??C!119?A@$#212!190?@!30?_!4?A$#213!138?A$#214!23?A!78?@@!32?E@$#215@???OAK!4?Q!10?F@A!52?G!7?___??KQO!10?G?@!12?_!36?@@AA!5?A_$#216!5?@!4?_G!73?W!6?A`!18?OOO$#217!5?__A?@I!84?O??`??K!11?_!61?C!5?O_!10?A$#219!63?A???G???C!71?OOGK$#220!172?@??A?C??G??O!10?C???@$#222!173?@??A??C?G?M???@??C?GG??G???_$#225!178?AAAC?@!4?C!4?_oO_$#227!61?@!112?A!7?O$#228!145?__$#229!65?A!4?C$#232!202?A!17?A?a$#233!39?G???!5P???C$#234!31?KA!14?G!6?LK]o!81?OA!27?_$#235!143?GCAB~$#236!21?C!100?_??A!40?`A$#237!70?_!53?_KE!4?N???O!32?B!23?A?A@!4?B$#238!96?NLMNK!30?o_!9?_!24?D!6?C_?G??O$#239!138?@!39?C!17?@?a$#240!64?@$#241!68?@!134?_$#242!68?G$#243!174?@@!11?ooo?G!7?_$#244!68?C!121?O_$#245!69?A!120?_O???G-#6!30?A?@B!9@!11?ELG!71?A!8?A!28?_KB$#7!137?@$#10!26?@FBB??MKCAA!5?A?OO???A??C??O?cF!62?_!4?p!11?@!13?K!16?@B$#11!28?C!5?G!8?A!4?A!78?C!8?g_!29?O$#12!20?owwC!36?G^[W$#13!63?@AFLYu$#15!29?C!5?G!8?AAA!4?C!81?_!18?_!74?G$#17!42?_!25?@!69?_$#21!29?_!197?A$#24!138?A!12?O$#26!140?_!12?A!14?G$#29!13?_MBA!54?GA$#35!137?OO!12?C$#37!140?O??_!28?@$#38!134?G$#40!227?`$#44!26?_oOW$#49!173?@!7?o{G???G!4?__$#51!175?_$#52!75?@!41?G!10?O?G$#53!5?G???GCE!82?_!9?GG!13?C!11?A!30?_!10?EGNN!10?o!6?_$#55!4~}!5oi@!61?_s}}}!14~poO!7?E!6F!5?opP?EA@@!10?C!22?!7~^FF@@!7?F?o!4~NA!4?CwwwoO$#56!120?A!10?G!57?C???O$#57!92?C@?O!13?G???G@??@!45?O!18?@a??C$#58!7?@!85?C??__`N?O!4?O???EG??A!71?o$#59!6?FE@@!84?BE^^]o~!6_o__ouEF?CA!88?G?O$#63!207?G!6?G$#65!141?A$#68!188?A???G!26?A$#69!141?C!4?O$#71!33?O!183?A@$#72!133?G$#78!200?WOW!18?@$#79!189?@??A@!5?A?GC_!17?_$#81!206?C?G!19?@$#83!191?@!7?C$#89!225?A$#96!207?C!15?G$#97!32?__$#98!206?A!6?CEA!6?@?aK_$#99!206?@B!5FB@@@!6?F[o$#102!69?o$#104!18?_o??C??@!36?BE\wqdGLC$#106!26?G!16?_g___$#107!30?_!103?O!31?GA$#108!13?B!4?GG??A?@!45?W_@$#109!13?K@?OO@!51?`O!67?@!11?G$#110!24?KEE!10?A!20?GNP!91?A$#111!23?WOG!5?Y???C!7?C!16?E!9?A!64?O!16?O$#112!30?O!7?A!4?G?G?A!7?_??O??_!57?_!8?@!36?_??C$#113!41?A!11?G!74?C!7?A!89?BC_$#115!71?CC!56?_!9?A$#122!28?G!30?_$#124!30?G!91?_??CA_???_!4?O!28?OC!62?_$#127!31?_!194?G$#128!36?O!190?O?A$#129!135?C!90?C!4?_$#131!126?C??A!23?G$#132!43?!8@BBE$#133!50?A??@@!68?C!12?C$#135!16?GkCCEF@@!12?GW!4{W??CCK[[wwwo_!14?A!83?@!15?A!14?Fo$#136!13?OOKCA$#138!140?@$#141!137?GC$#142!35?O$#145!30?CCO!25?_?_!106?@?{$#147!129?C@??A@!7?O??_!20?A!35?@ACO?_!5?Ooo_O?@$#148!125?O??_!39?_??pM$#149!12?G$#157!27?G!93?GCA@?G!12?_!27?_$#158!12?o?_o`@!54?GB!98?o$#159!138?GO??_!5?~~~@$#161!18?A@H??A?O!18?C??O!77?_?O!9?C!13?_!32?wF!42?O$#162!230?G$#163!225?@$#167!26?O!100?@G??OO!8?_!11?C!17?M$#169!119?O!44?_$#171!24?_!12?_!85?OG??A??_!66?~!30?G$#172!168?O$#173!12?C!60?C@!50?G!4?O!8?C!7?o???A$#174!23?_A!11?C!6?O??O!12?O??___!87?@$#175!48?_$#177!50?C$#179!118?_!22?O??_$#181!12?B!59?O?A!48?_!5?O$#184!18?OA!17?C?AA?C???G??_!4?O!16?B!48?O!8?@!55?G$#185!133?C!68?ACG?g?!5O???GgSGFC$#186!222?_$#192!133?O$#193!36?_$#194!215?C!6?C!5?AKO$#197!124?o!15?A!6?G$#198!25?_??_!103?_$#200!72?_$#201!136?@!91?C$#202!198?}!4?@AC!9?GCCA??AO!6?O$#204!141?GKK][G$#205!135?A!81?@$#206!210?GG!10?A$#208!34?O!187?G_$#212!134?C@!68?@A!7?G!16?_$#213!209?G??G???A!6?O$#214!154?@!8?_$#215!4?@E!5?_!64?@@!14?I?G_!5?MHG??GG!5?o??gC?@??@!40?GG$#216!6?GGGE@!82?G!14?GF!4?GG!67?S$#217!5?@??E!84?ACH!5?@!4O??OOH@x?CAC?@!64?@??J???C???O__!11?!4_$#219!140?K?@@??_$#220!189?A???G$#222!188?@?AAC??G!4?___O!15?_?O$#225!190?@?@EFFN??@F???_!15?o$#227!191?C???O$#228!142?AQ@BF$#232!34?__!169?@!18?@?O$#234!30?@@??A!19?GAvZ!62?_OWGEB?G!6?_g!30?O???{$#235!139?G?@!5?F$#236!11?W!61?WG!42?O?G!33?Oy!18?w$#237!117?_O?KEA@!6?E??@!30?OG!21?A!18?O!5?__??O?GC$#238!10?O!106?AG!10?G?DJ!20?_C!10?E!8?oO!12?C??G$#239!187?@!6?G?O?@??@?GO_!12?_OGG$#241!134?A$#243!199?_?A$#244!201?C$#245!199?W-#6!112?_??G??A!31?oE!10?_W$#10!57?FK!55?O!10?@???!5_!36?@$#11!57?GA!57?G?@!11?OC??@!5?_@@!7?GH!9?_!4?@???E$#12!40?AA!4BFBFFE?CG!12?@$#13!17?E@!50?BC$#15!126?@!14?_!87?AG$#16!38?_$#17!17?@!34?A!4?_$#18!231?O$#19!38?G$#20!229?CO$#21!123?G$#24!15?G$#26!26?_!110?O$#30!28?O!109?@$#35!14?@_A!129?_!21?_$#36!172?A!12?O$#37!145?@???G!15?_!6?G$#38!131?A$#40!229?G!4?_$#44!24?@?GA!31?A!4?A!50?_!47?A$#45!18?_OG?C!40?A!57?_$#49!76?W!4?_!27?O!49?G!21?@N???[!9?g??G$#51!98?O!76?F!18?C$#52!10?a!72?_??_!21?_!44?C!4?_!46?O$#53?w???_!67?A?G???O!6?G?wg?_??GG`xI!9?O!48?_??C!12?W!7?O!5?F!11?C??Owo?__$#55~!5F!4~C@!61?@DFF^^N^^~^^^V^FV~^~~vv]E!56?J~~^^VBF!12?ww!5~G!5?w!4~zzy{!4?wwg$#56!87?_!11?W?G!4?_!7?@!84?_??C$#57!107?GG!4?@!39?G_!27?_!21?G$#58!4?G!94?F@@!10?A!69?O???B$#59???o!97?A!5B!5F!91?C!5?_@$#62!21?_???O$#63!17?_!111?C!93?A$#68!205?G?O$#71!29?C!37?_$#72!222?@?_$#73!207?G$#75!68?O!61?A???CEC!7?C$#77!219?C$#79!203?@!4?G???_??_?@B@D@E$#81!37?@!186?A?_!4?C$#83!213?G!7?_$#86!137?EEC??C$#87!121?OG!18?C$#88!140?A$#93!25?_$#94!37?O!101?A$#96!23?_!201?CO$#97!37?C$#98!33?AA?A!188?A??G$#99!30?ww}||~\!188?@BWo$#102!68?@$#104!18?A@@!29?@!16?@ACG$#106!58?_!65?C$#107!29?@$#108!12?cA?S!54?@G!54?_$#109!13?C?A!55?@!125?]$#110!56?@$#111!58?O!54?O???A??@!7?_!4?@!5?_!24?A$#112!27?O!28?AO!8?A!46?_G!4?A!4?G!6?GCA!31?C!4?w!13?~$#113!27?G!30?@!12?_!58?G!9?@!90?_$#115!21?A!122?_!4?OA!14?G!17?O!13?_$#120!28?C$#122!69?O!54?O!11?@???O!20?O$#124!11?_!15?C_!30?G!8?G!43?O?_?AG???@!13?@??O!4?A$#127!20?_???O!5?@!98?GC!11?A$#128!132?@!6?@$#129!29?A$#131!23?@!42?C!49?O@!11?@$#133!119?@$#135!12?W!39?@BFNG!6?@!7?O!39?_???S!35?O@$#136!71?C$#138!16?O$#141!16?G$#142!122?O!107?_$#145!17?O!41?O!5?A!57?_?C!5?OOO??O!6?_!20?P?A??@!13?_?F$#147!112?G!13?CE!15?O??C!5?G!60?@$#148!124?@!20?_!25?N@$#149!168?@???C!10?C$#157!22?@!15?F@!16?O??_!7?C!50?C!5?A!9?OO!8?AA!17?_!5?E$#158!12?B@$#159!13?G??D!54?A!75?~~F@!15?w}]$#160!39?w{{!9wooo_$#161!19?C!50?A!56?_!35?C!5?_$#163!228?A?AG$#167!62?@!64?PW???G!4?@?O!11?_!19?o!11?G?G$#168!19?_OWW[MNF!33?Y}}{{ww!165?C$#169!16?_?O!97?_?O?G?C??G!4?@!5?GG!4?O???W!13?_???_!33?@$#171!144?@!7?A!9?G!34?@!34?_$#172!20?C!99?A!7?@!36?OC@$#173!13?o}@!56?B!52?_O!45?O$#174!17?GCAA@!42?@@?ACGO$#175!39?E??!4C?C???MG?O_$#176!28?A!199?@@$#177!28?G!100?O!12?_!87?C$#179!26?O!86?G???O!5?A_?A!6?GGG!5?O!4?B!5?C$#181!11?G!60?[O?__!45?@!75?A$#183!27?_!10?O??@!11?CGO_$#184!18?G!21?@!10?@!4?C!86?@!5?_C!18?W$#185!199?@!8?@@!4?@@$#186!67?O!49?_!5?C!20?O!79?S$#190!28?@!30?C$#191!37?_!32?_!63?A$#193!22?_!205?C$#194!231?B?O$#197!11?S!61?__!43?GKCEA@?OGG!44?_!10?A?_$#198!19?G?CAA???@!31?@d@???C!67?C$#200!11?A!61?GWO?_!105?@!14?C$#202!67?G!70?G!84?@Go$#204!145?O$#205!227?@?O$#206!224?@$#208!225?G!4?@?O$#209!119?_O!19?G!78?A$#211!69?_!72?G?GK$#212!232?G_$#214!107?_?GO!49?G!37?G$#215!5?W!4?X!87?D!8?O??G!51?@!10?_!7?E!14?F??O!5?_$#216!102?!5G!47?O!41?O$#217??wGo!95?E!6C!5?DEA!37?Oo!7?G!36?_?A!7?_???@$#219!119?O$#220!129?A!72?A?C?G???_$#222!201?@@AABFEAAAaA!8?C?G$#225!204?@???CC???owW!4wyI$#227!128?E!72?A$#229!68?_!51?_!15?A???CA?K$#231!24?_!4?w!6?_G$#232!30?EF@!4?A!188?Ke?_$#234!116?CC!4?_O?A!6?A?!5_!23?O?KB$#236!73?CA???_!74?AC!7?A!10?F!7?_!12?@B$#237!72?_!36?__W??CB@!35?_!7?O??@!34?O!7?O!4?@$#238!79?__???__!12?__w!5oO!46?@!5?_??C!11?F!11?_!5?CC!5?ACC$#239!200?@!4?C?@OO!6?@!6?C$#241!121?G!9?@$#242!118?_!20?G?G$#243!209?GOOOEEA?A!4?_O$#244!210?GGG??CCC!4?W_$#245!210?CCC???A?C??O-#6!82?A!28?@!19?WWwoQEUEAEEEC!5?E!5?O???C?@$#10!95?G!12?CA!17?B~~|FD!12?A?A?@@?_!16?O$#11!96?G!24?@!26?_G!6?O?GA@!8?G$#12!120?_{{{M$#13!120?C$#15!84?C!13?GGG!69?B$#16!26?sF!30?o$#17!101?GG!19?A$#18!232?A$#19!59?A$#20!79?A!154?W$#21!231?@$#23!31?__!4?A$#24!37?@!21?W$#25!33?__oww]EAAA@BM}}{{wo_$#26!99?O!22?@$#27!34?O$#30!87?G$#36!171?_!25?_$#37!103?OO!48?A!11?B$#38!111?A!47?G!72?C$#40!236?_$#43!41?C$#44!82?@$#45!60?C!30?O$#47!42?C?_$#48!39?O$#49!172?o!9?@??q!9?_???C!8?@!5?W$#50!39?_$#52!10?@!95?A!47?A??@!40?OG$#53?@G??F!149?AA!16?_!7?U!4?A!6?EGF!6?{G?E@?EEAA$#55r!4ow~~^^C!141?C??@@!16?V!7~G!4?o!6~xv?@??ArrB@HH]^WW[{{!6_$#56!10?A!79?@???AA!5?C!4?@!105?AC$#57??CC!84?@@?@@!60?@!31?C!10?G?H!11?_$#58??AAC$#59???@!199?___!8?C$#60!36?A$#62!18?@!214?@$#63!74?@!150?@C[$#65!162?Q$#66!221?_$#67!73?@$#68!99?CC?C!113?G$#71!62?G???O!164?A???G$#72!216?C$#75!160?O$#76!17?@!100?A$#77!116?@??@$#78!115?@$#79!215?BACACOPBrFCO$#81!19?@!207?A!6?A?O$#83!223?GG_$#84!224?O$#86!15?A!54?BA?CAA!4?C!4?O!28?_??B$#87!68?O!14?WO!4?O!18?_?O??A$#88!13?_ww{!51?`a??CAC{{{Ss?GG???__o___!17?O__Kg?KK$#89!234?_$#91!73?Go!7?O!31?A$#92!18?[!49?GWwwwo!7?!4_$#93!60?G!6?_!161?O$#94!17?}!6?G!4?CG??G??@!31?ECCC??G!5?oO??G_!24?GK?CCA$#95!24?C!10?A!24?o_$#96!19?U@!40?O?oo_!163?G_CG$#97!20?C?B!10?C$#98!20?W!207?B$#99!20?_?{K!6?FFBBB!194?A[w__$#104!118?woW$#106!58?@!47?OG$#107!84?A!4?G!17?O??A$#108!121?A$#109!117?_!29?@@!33?_$#110!124?oy~{??A!13?@$#111!125?C$#112!80?A!8?C!7?G!12?@!6?O??A!24?@??A!5?O?G!12?A$#113!85?A!19?_??G!123?@C$#114!37?C?GC??A$#115!12?@!139?I!18?F!10?O?O!12?@$#116!25?G!33?C$#117!38?!5@??p@?A?CGO_$#118!27?Wo__!16?@?A$#119!29?O$#120!85?C!20?_!48?_$#122!79?@@!12?C!13?C$#124!78?A!8?A!12?O???G?G!11?CA!29?_O!6?C$#125!25?C??A!4?O$#127!24?_!39?G!12?A!29?_$#128!83?C??A!148?_$#129!156?_!76?I??C$#131!81?@$#132!86?CC!48?!5_oo!4_!10?G??A$#133!92?G!42?_WGOSO?G!4WoG!4?__$#134!28?G$#135!11?A!112?@!21?@!23?W!12?AE$#140!38?_$#142!234?C$#143!235?A??_$#144!36?C$#145!11?@!79?C??O???O!17?_!33?KG?O???O??C!9?_!12?@G!50?O$#146!40?www{W$#147!14?A@!18?G!50?@@!8?CCcC!63?GF_$#157!59?@!35?OOO!14?@!48?A@$#158!171?W!25?A$#159!102?O!64?Ff$#160!27?_!20?@@BFN^~~}{$#161!11?W!137?O!19?@C!12?{@$#165!90?G$#166!35?G$#167!76?@@@!13?O!8?O!21?@!27?PO??G!41?[$#168!61?!4FNN!19?G!150?O$#169!12?OC!18?O!42?@!7?@???@A!5?C???___!51?@!6?@!4?@!20?@$#170!28?C!30?_$#171!92?CO!56?_$#172!108?A!75?_$#173!12?AA!151?{~wW$#174!119?K???A?@!43?C$#175!56?@BM$#177!88?G?C!18?C!40?A_$#179!12?G?@!14?GO!29?A!40?!4_W???@!7?G??@!30?C!6?A$#181!13?@!158?E$#183!25?oJ$#184!11?c!91?G$#185!211?@!6?O$#186!81?C!14?_!20?C!42?_[!64?@$#191!25?A??@!53?C!33?O$#194!61?G???O!168?@CG_$#197!10?_?C!138?A?K!18?@!9?G$#198!60?@!52?@$#199!44?C$#200!154?C!17?G!9?C???K!9?_$#201!63?G$#202!114?@!42?_!68?A?o$#204!13?G$#205!227?@C?@??O$#206!18?_!43?o???_$#208!67?G!42?C?A$#209!72?@$#211!14?C!9?O@!5?O$#212!67?O$#213!18?A$#214!108?@!87?O$#215KM?GG!4?_!144?@!27?A!12?WE?EPKK???O???@???G??O$#216!8?_!84?@!104?_!4?E!9?O?W$#217??@?B!180?G!17?OO?!4_@!6?O$#219!162?Cw$#220!215?C?G$#222!213?@A???G???_!4?_$#225!214?@?@B@BBA!4?_$#227!213?A!6?_$#228!35?C!126?_$#229!86?OO!5?_!17?O???O??@$#230!13?O?CB!52?@??A!5?gGG!11?_!16?_??oOW?A$#231!19?gAf?_B!4?B?GG?C$#232!21?W?R!8?C??@!193?DA?O$#234!81?A?A!4?C??G?GG!36?_aFNL@@!4H@BECEKS!9?C!10?_$#235!10?O!153?I$#236!10?G!93?CC!58?S!8?G!7?`$#237!84?@!4?AA!15?CB!46?GCCA@!60?_$#238!91?AAA@@!7BFBB!80?@!12?_!4?E$#239!212?@!6?O!5?AG$#241!67?F???@!4?A!8?G!4?O!17?OG!5?_!42?ooG_!66?G_$#242!12?_!81?__$#243!218?C?GGW$#244!223?C_$#245!219?GCCC??W-#6!137?@?A!13?G!4?C!10?B$#7!147?G???OG$#10!128?!4@!23?_???_oo$#11!132?@@!7?CG!10?O???@?A?G@$#12!120?DBB@@???_w_w_o?_$#15!136?A!11?@$#16!26?@!31?N$#17!131?C!36?O$#19!126?_$#20!145?G$#24!24?_!99?C_!42?C$#25!27?w{]^NFBB@@B!5?_?CBBFFN^~~}{W$#26!24?G$#30!24?C!138?@$#37!181?C$#38!104?A?@!51?@$#40!146?OO$#43!42?A?@$#45!11?G$#47!38?w$#48!38?C!4?G$#49!8?O!163?Z@!11?A$#50!31?__G!5?~}[[!4?O_$#51!214?@$#52!9?o$#53!171?O$#55!5~b``_!162?__s!4~nN@@???{{~NNB!4@o_??@NN!9?@@B}!6~}{{_$#56!9?C!211?@?A??OO_?_$#57!9?G!169?_C???[@??_?OK??w??S??O?O!7?B$#58!6?KK!181?__oCc!9?^!4?BB??{$#59!192?_W???G{__??_~}}~{{{w!12?CG$#62!104?C$#63!229?A$#66!230?O$#68!231?_$#71!159?@$#72!223?@!6?G$#75!115?G$#76!12?C$#78!229?C$#79!224?@@?C$#81!230?@??O$#82!228?A$#84!226?BBC$#86!13?O??OO!77?@BBB@?@@@$#87!103?AG$#88!12?GI]^NK_!49?f!9?@!7?BB?@BFEMxmGK[W][[[!4?!4@BRt$#90!104?OOW$#91!71?}??B!5?A@???E!4?_!6?o!14?g$#92!19?_!50?~@~~!7{}~~~www{{!8?!6_??_!5{S$#93!18?B!41?C!43?__E$#94!17?B[!41?B!6?~W~!5?BBBAB@!4?@CCAA[wwo?Oo!4?AA??G?B!4A?kA$#95!19?W???w!36?G!59?O?O$#96!20?_{W!37?_cov?~!52?_!4?_!109?GO_???C$#97!21?AB!39?C!56?_$#98!22?C!40?G~!171?_$#99!20?@!99?___!109?@FM][{{w$#104!117?BDBA???A???O!7?_!31?_$#106!129?AW?O?_!27?_$#107!138?C!12?_O?_$#109!168?A!12?G$#110!123?A?@@!42?C$#111!121?C!5?@!9?A$#112!116?aO?G!10?E???O!4?GO!4?_G??@!32?G$#113!139?C??O!19?C$#114!29?_!5?AQ!7?CG?C?GO_$#115!170?C$#117!27?CA@!7?{!6?wB!8?@Ac$#118!26?}@!29?o$#120!151?G$#121!149?O$#124!10?AA!12?A!93?O!43?O_$#125!24?O!34?E$#127!59?_!44?@$#128!105?A!15?G!26?O$#129!150?_$#132!138?@@BBBN^FBFEE]Cc?A$#133!105?@!30?@!5?CO_!6?BBF\BB?A$#134!25?{!32?_$#135!126?EEK???AEMC[WWo_W_!25?G!12?o@A$#140!32?GC??k!6?OAO$#141!168?@$#142!146?!4_$#145!10?w!113?oG!44?@!12?C$#146!40?@b`F$#147!163?CF$#148!170?G!12?O$#149!117?C$#152!149?G$#156!145?O$#157!11?@!104?O!6?GGSWW!33?@$#158!180?_$#159!166?g[$#160!27?A@!26?@BN$#161!117?GA!6?A!14?K_!27?o!12?u@$#162!236?@??@$#163!123?O$#165!153?_$#167!116?@$#168!117?_$#169!116?G!45?G$#170!59?@$#171!10?C!104?_!54?A!12?G$#172!10?@$#173!165?~Vb??O@$#174!118?GC??C!6?C!39?G$#175!127?_$#177!120?G?G!12?A?C$#178!33?_!14?G$#179!24?@!34?O!100?@$#181!171?A!9?A??@!11?C$#183!25?B!32?O!73?G$#184!123?C!4?A??ACG?W?__$#185!225?C!5?WO$#186!115?O!115?C$#191!59?G!56?C!46?A$#192!11?C$#193!237?A@A$#197!170?_!9?O!15?B@$#199!30?_OOO{{??B!6?_{gOo_$#200!171?K!8?G??_!11?BGA$#201!237?@$#202!11?O!103?A!113?@E$#205!235?@??A$#206!19?C!40?OYB???~!165?C$#208!232?G$#211!11?__???_$#212!119?O$#213!231?A$#214!8?K$#215!5?OQQAB!162?CA!5?OA!5?B?O?KAAA?G??BA??N!8?AA{!10?OO$#216!5?K??@!175?_!4?O!4?A??_???O$#217!184?A!7?W?CC???[?__??@@!4?C!12?G?G?O$#219!164?W!64?O$#220!224?A$#222!225?A???G$#227!222?@!4?G$#228!163?W$#229!12?R`__!84?@!13?G@$#230!13?C@!73?@???@@E?C??E$#231!19?B[@_F!37?@G!58?O$#232!20?A!210?@A?@?A$#233!146?C?G$#234!134?@@??A!4?_!6?@!4?[{}w[MEA$#236!173?G!4?O!17?O$#237!164?_!67?__$#238!222?A??___?_$#239!226?C?H!5?_$#241!105?C!9?C$#242!17?_-#6!144?W$#7!144?@A!7?@$#10!144?_!12?CD@$#11!155?@@$#12!128?!5@BBBENM[o___!16?{}wO$#13!164?sI$#15!143?A$#16!125?C$#17!138?@A??OO!22?A$#19!124?O$#20!146?_$#21!152?@$#24!58?A!65?K!41?GD$#25!37?GSG?OGC@!8?BFF$#26!124?A$#30!24?C!89?O$#37!179?A$#38!146?A$#40!150?@??A$#44!156?O$#47!27?K!11?CC???C$#49!169?G$#50!29?A?@??o{?_?BB???O?yo}??ww_$#52!169?_C!12?G$#53!218?_OO!8?_$#55!8~!161?O?FFN~~^^E!5?A@@@!7?@@!15?oo!4~^NNN^Nzpooo$#56!8?G!174?_??]!34?_?_!5?CC?A_???_$#57!8?@!161?_!11?OC@???@!5?@!16?w!14?AAI!6?G$#58!171?oo!14?K?@@@!4?AA!13?EF!13?CCC$#59!9?A!178?{}}}]]]{ww!13~@!20?@QW?GOO$#62!24?_$#63!9?O$#65!18?_$#68!233?K!4?_o$#69!12?_o$#72!239?C$#75!11?GI!6?O$#77!18?A$#86!11?A$#87!112?_$#88!68?H!25?@@!17?`@$#90!109?_??A$#91!71?@!18?@!5?@@??@@??@@!6?@$#92!19?@!46?F???~}!18~!8}~~}}~~}}~~~^~~K$#93!20?O!38?C!5?_$#94!19?A_!38?A!6?w~u~!21?@@@!19?]E$#95!20?K??F!41?O!49?_!7?O$#96!20?@AMG!36?~D~@N@!51?@!5?@$#97!116?K$#98!61?y!56?@$#99!116?_}}}~~~!115?@@$#104!125?@!37?cIo?O$#106!136?@!20?A?_?@@@$#107!10?O!132?@!10?A$#108!165?@C$#109!166?@$#110!157?GWK$#111!157?@?O@$#112!10?G!170?E$#113!10?C$#114!27?A!10?A?G?A!9?@?G$#115!168?OA!8?OC@$#116!57?_$#117!26?K@!9?FGOOGCB!11?WB!68?!6_$#118!26?r!28?_[@!73?_$#119!25?A!98?_$#120!10?_$#124!58?G!57?@$#125!24?A$#127!58?O!56?@$#128!114?_!31?O$#133!144?AC!9?A$#134!25?|!30?_U@$#135!140?BFN!13?GO!6?@COA!11?GCO@$#140!27?_@!7?B?@?_C??A!8?CO$#142!115?E!30?@^EBABE?C$#143!148?x{{{WKG$#145!10?@!135?G!33?A?A$#146!41?B$#147!9?G$#157!10?A$#160!125?W!6]{{{wwo__$#161!166?_g!10?_owH$#165!145?@$#167!182?C$#168!114?GG!31?_!4?_oow_$#169!237?C$#170!24?@!33?C$#171!124?@!21?C!34?_$#173!168?_$#174!158?AAA?EI!4?F$#175!125?A@@!4?A??C??O?GO$#176!155?C$#178!27?O?{}}}~N!4?_??@___?N@?MCA?_$#179!24?O$#181!169?C!7?_G$#183!57?G$#184!139?@CG?K!14?_!9?G@$#186!9?_$#191!24?G$#193!115?OA$#197!182?G$#198!157?_$#199!28?}@@?@??B{O_??_oWG^D??~pBCW$#200!170?@!8?@!55?A$#202!11?o!223?@??C$#204!12?OGKMNNK_$#205!236?@$#206!20?A_!41?}?M!172?A$#208!237?A$#211!12?@FA!43?_$#213!112?O$#214!8?A!224?@A?C$#215!171?GGo!4?@!5?C!28?L!10?CMG$#216!8?C!175?oO_!10?@!14?GA!7?O?O???H??y{_???_$#217!182?_B?_?qA???``_ACC!24?_!11?CSOG?G$#221!18?O$#228!14?!4o!105?_$#229!11?D!7?G$#230!18?@C!39?@$#231!21?\@!36?w!4?o!58?M$#232!22?oo!92?O??@!117?@?A$#234!144?Cw!8?@?E$#236!170?A!5?_$#237!8?oD!224?@?A?G$#238!170?W!12?OGM!33?__!5?@?@Z@B[?__$#241!12?C$#242!14?@@-#12!144?A!16?@$#13!164?OH$#15!159?@!66?O$#16!114?O!29?w$#17!114?A!50?C$#19!26?G!29?C$#20!146?@$#21!226?_$#23!121?O??@$#24!19?_$#25!54?A!60?___??__WKA@???`z~}}{wo_$#27!28?_$#30!146?C$#32!119?O$#34!28?O$#36!181?@$#37!180?G$#38!226?G$#43!31?__??O!4?OO??_!6?_!73?oWK$#44!158?@!70?_$#45!11?@!13?G!89?C$#47!28?Eo!22?G!71?w???_$#48!28?@!8?G!14?CA!71?CEqA$#49!7?_U!159?W??_o_??@!4?A!12?_!31?A??G$#50!29?MzXAABBBFEECCEEEV~}J]UFB@!71?G_?S$#51!17?o$#52!169?C!11?_@!45?GO??_$#53!6?DE!181?G!5?w!10?_??W!18?B!5?W$#55^!4~vwP!158?__?AEEEFF@!11?__o{{}}W!12?ww!18?FC?WOWW_$#56!180?_$#57!168?_woGG!7?O??`??O??AA!5?w!15?@___?GV!10?A?H@@E$#58!183?G__?GG!6?FFF!15?E??G???]$#59!184?W[CEF!9?!8~!4B}}}GM]?A???W!9?CAA$#60!117?OO$#61!34?_!7?_$#63!9?@!213?@$#65!12?W??@?@@E$#68!14?__!222?@B$#71!149?C?G$#81!153?O!68?C$#88!20?@G?_!83?A?CC[$#89!155?_$#91!21?C!42?O?x!39?z$#92!21?A!42?msE}}}!36~$#93!25?_!37?o?J$#94!22?WO@O!30?_G@!8?@@@!36?C|~zzBB??@?G?G$#95!23?G}!33?A?AE??@!51?C!5?@!24?w$#96!22?@A!34?_?`hx!84?CwwOO__!70?W$#97!23?@!34?WC!60?@$#98!59?GG!58?C!103?{$#99!117?@FA$#104!162?N^n?B$#106!144?@@$#108!167?A!8?_$#109!166?GC!9?p?_$#111!11?_$#112!10?A!168?G@$#113!11?O!216?_$#114!27?A!24?_G!64?__???O??@??O$#115!165?_??C$#116!25?@O$#117!27?C!94?_!7?C?@?ACGO$#118!53?o[F!58?_!18?@!4?_$#119!26?Fw!87?O$#120!10?@$#124!25?C_!85?_A!32?G$#125!56?G!66?@$#127!113?@!32?_!5?G!5?_$#128!10?GG!213?G?_$#129!225?o$#130!52?O$#131!218?_$#134!54?_WB$#135!162?_!4?@!9?G?B$#140!27?@!26?@!68?_CA?@@I$#143!147?@B@$#144!115?GO???O?CA$#145!146?A!13?C!13?_?C?K?C!46?O$#146!33?_??!4O???_!84?G$#147!13?_!4?WW!100?G!106?GO$#148!168?@!6?G$#158!168?A$#160!134?@BFN^~~~}}$#161!161?G???QC!8?_WE`CA$#166!121?G$#167!20?_!140?O$#168!149?AFFFNN^^~]w_$#169!21?_!34?O!55?O!9?A!37?G_$#170!25?A!29?_?@!55?C$#171!10?OC$#174!160?BEO_$#175!142?@@C]$#176!10?C$#177!114?@$#178!32?\\[KK?HGGHXXX_???__O?C!75?C$#179!20?O!125?O$#180!28?G$#181!166?OG!6?O$#183!113?wK!30?_$#184!175?O??QO$#185!9?C$#186!12?_!7?G$#190!159?A$#191!11?A!45?A$#192!10?_$#197!176?A$#198!159?CO$#199!29?@CE!7?@BA???G?@s@HG$#200!8?g$#201!147?A!6?O?_$#202!9?A!214?AC$#203!35?!7_$#204!12?@!7?C?_$#205!148?C?G!73?_$#206!21?@EC!38?EN!86?__O?_$#208!224?C$#209!21?O$#211!20?A!91?G$#213!223?A$#214!8?@_!171?C!34?_$#215!167?O??@P@W?E!6?EE???OOC?A@@E!11?W??_!4?@@??GG!5?@$#216!182?_???_!7?@!18?@??@@??@!8?C$#217!170?G!10?WWOFBJ@?@@@!5?w!8?!4C@@?OO?US??_d!8?FACC$#219!13?WWW[ME$#228!12?EFFEB??@!37?C!58?G!4?C$#230!111?_C??A$#231!57?oCBCO!56?G?CA$#232!59?oO!55?BE?@A@$#235!18?_$#236_!4?G?G!218?@$#237!9?W!164?G!42?_?_?A??@AC???__$#238!6?A!9?_!152?@!49?V!9?@???_@~~~}{$#239!222?@$#244!222?A$#245!222?w-#0!226?O$#7!11?@!219?A!5?G$#11!163?A!53?G!16?C$#14!226?A$#16!143?wB$#18!230?A?A$#19!50?_O!60?C$#20!230?@?C??C$#23!28?@C$#24!27?A!84?A$#25!115?FBB@@?KK!4?OkG???@@BF^}{o$#30!29?_!115?G$#31!234?G$#34!47?_$#36!178?C$#37!21?A!150?A$#38!11?G$#40!225?A$#42!31?O$#43!45?@?O!66?_!10?@@$#44!237?C$#45!161?@$#47!29?@@!17?G?A!73?@$#48!123?A$#49F^]M]??@!157?O??G?A!6?_g!15?G$#50!47?A!67?_???_C??{}{[F!4?K$#51!15?@$#52!164?C!15?@!10?G$#53!6?@!158?I???@!9?GGH?@???@`@@@?c!12?C`@CO???@!20?@?@@@$#55??@@@JAA!6?CC?A?C!145?C^^FE!9?sou~!5}]]]UBACY!10?w]}w!4?EB!20?@?AA$#56!193?O!26?G!18?C$#57!162?_o!8?@!12?@!10?^!8?c!4?C!4?W!4?C$#58!197?[!12?AKL$#59!196?_a!6~r@!4?@BA!7?Qo$#61!30?A!13?@AW$#62!159?AG$#63!10?A!211?_$#68!14?@!177?_$#71!160?C!57?O!6?_?G!5?G???O$#74!31?GO?_!8?oO$#75!23?@$#77!25?C$#81!157?@$#88!61?OWW!38?!5_KKJ@$#91!103?GKKA$#92!59?_o_?Bf!36~NNFBB@@$#93!58?_?GCB!83?G$#94!24?@A!29?A!5?GccW!36?o!4O[qroE!35?E$#95!25?@!26?_O?C!90?O$#96!53?___EZZE@@!84?_mwG_?_?^pf]KG!63?_$#97!54?OO!101?__!64?G_$#98!57?CC@!87?O!7?MW!66?BE$#99!224?O$#107!11?AG!223?G??G$#108!171?_???O$#109!7?_!164?OG??_$#112!162?C!54?_$#113!12?_!204?C$#114!50?C!69?@Ao!7?@?@?AC$#115!8?_!159?_???_?cMB$#116!27?@KO_!21?G$#117!51?A!62?N!6?oB!4?_OF!8?@AG_$#118!48?_OWCB@!59?w!26?COG$#119!28?AGO_$#120!217?O!8?C!11?G$#124!12?A_!40?A!163?C_!16?C$#127!145?_!12?@!66?G!4?CC$#128!11?CC!147?O!55?_$#129!231?G$#130!32?_$#131!7?G!154?I!68?@$#134!49?_?GCA@!57?_F$#135!175?@?H$#140!29?A!18?OG?@!62?OGC?A??@!5?GAOA@!4?G$#142!218?G!6?C?_A???G$#143!227?C!11?O$#145!7?O!168?C?A!38?AA$#146!31?@!14?C!78?AA$#147!11?_?M_!7?@EGO_!25?O??@!163?F!12?@??A$#149!177?O$#153!226?G$#157!20?A@!123?C!72?@$#158!173?oW$#160!139?@BNvF$#161!169?_oOKEB_WE@$#162!159?O!65?@???C!4?OO$#163!228?@$#165!12?O!216?@???C$#166!30?G$#167!162?@C!9?@!42?O??O!13?A$#168!159?@BA$#169!10?K?@O!12?@!24?_!109?O!54?G??G!14?A$#170!53?C!58?@$#174!163?@$#176!226?@!8?G$#177!161?G$#178!46?BKE@@!66?s{]???@!4?@??OooO$#179!19?@@!90?O$#181o!23?_$#183!112?W!31?{B$#184!164?@!6?G$#185!160?_!30?_O$#189!217?@$#191!27?CO!82?_!33?O$#193!227?@!8?O$#197!164?A!4?OGC!7?@!36?F$#198!161?C$#199!47?@@E!65?OwG??y!5?_??_{mAMkwo_$#200G__??O??P`_!167?O$#201!158?O!66?O?O?A!8?O$#202!10?@O$#203!31?EB~^~|~~~^^^Lm{_$#204!26?O$#205!158?AC!58?_!8?A$#206!56?w_?WEA!86?FV^~^~_$#210!32?K???A???___A$#211!27?W_!25?C!55?WC$#212!159?_$#214!10?O!151?O?w___?GD@!12?@$#215!168?O!17?@!7?O!11?B??Bg??@$#216!205?W!7?A$#217!161?_!9?A!21?G__?@!6?KA!5?oo!7?`N$#218!30?C$#219!13?@$#221!24?C$#227!192?G$#228!25?G?_!83?G$#229!26?K$#230!24?A?A!82?C_B$#231!54?GG@!90?@?_$#232!223?SH$#233!226?_$#235!15?y{{{w{{}wO_$#236???o_c{CM]!4?W?A?B!146?@!13?AC!8?_???@BD$#237!163?G!51?_!17?@@?AAC$#238!14?A?@@?A!160?A!9?_?C!20?{wC$#239!222?]$#241!53?G!92?@$#243!222?@-#6!216?W$#7!216?_$#10!13?A!150?O!51?C$#11!163?_$#16!142?C$#19!143?G$#20!227?W$#21!227?C$#23!41?GC?CA$#24!48?A$#25!121?C??CG@A!11?B^B$#26!31?A$#29_!167?_a?K$#30!111?C$#32!41?C$#36A$#40!219?G$#42!35?A??C$#43!114?A$#44!162?G$#45!220?C$#47!114?|!8?AA$#48!125?@$#49?@G!171?OgAB@$#50!115?~v{[F???@@_OO?csc_o|}$#53!178?G!9?W@!16?A@!6?C$#55!25?!4_?g!145?{{s!5f!4~f???_!13?@$#56!162?@@!25?_??@!20?B_C$#57!13?_!169?G!21?@!7?S$#58!181?GG!23?[[$#59!192?CEm}||!7~{__}}ww{!7?@B$#63!222?F$#64!43?O$#68!32?__!156?G$#71!218?G$#74!37?A$#75!46?_!115?O$#81!219?_$#88!54?ooGG!44?!5~_?g!35?@$#91!56?_$#92!57?_`v!41~$#93!48?O???O??GCA!160?@$#94!46?OG!5?O??OS]G!41?~!5?^~F!34?O!14?_$#95!47?OGOQP??G?A@!86?_A$#96!50?G?JFF!90?WF?S{bovoqQwpB!64?B?o$#97!49?GCA!94?G`bB$#98!51?GC!102?_$#99!224?_$#101!225?C$#108!9?O!157?W!5?C@$#109!8?CCO!155?O?MC??g$#110!166?A$#111!14?O!149?_$#112!13?C!149?C!4?@!47?AC$#113!217?B$#114!122?BC?A??@!9?@C$#115O!164?_??O?rPCB?A$#116!32?A?C?GGG!4?G??C!97?@$#117!121?BKGGCE@!12?_K$#118!47?@@!64?~!27?oI@$#119!31?@@A?CC??GG?GC?C$#120!217?G!8?O$#121!226?_$#124!14?C!96?_!103?O???D$#125!34?G!5?O!4?G?C!63?W!31?OA$#126!39?CC??A$#127!49?A!110?C!58?O$#128!220?_$#129!228?}$#131!161?E?A!51?G$#134!46?AA?@!62?~!29?oA$#135!8?AG_!151?C???g@?@?_OG?@$#138!38?OO$#140!121?G?OO!14?G$#141!41?OO$#144!33?CAG!8?G$#145!13?G?_!150?C!7?C!40?_$#147!14?@?C!12?C?GOO!126?A!30?W$#148!9?_$#149!8?G$#157!8?@$#158K!166?c?WKABO$#159!37?O$#160!142?@$#161!14?g!149?C??A$#163!218?_?G!6?@$#165!217?O!8?M$#166!33?@???C!6?A?@$#167!32?C!78?A$#168!218?O$#169!14?A?A!144?GAG$#170!30?@$#171!12?@!151?I!54?AO!6?A$#173@_!5?@?A!12?OM@$#174!165?G$#176!217?_!9?_$#177!13?@!202?@$#178!117?@@!7?gcWOG?BN??!4_$#179!15?O!20?O!13?@!92?_C$#181?W!5?AO?GH!12?A$#183!143?C$#184!165?U!8?A$#185!160?@!30?C!28?A[$#186!17?A!144?_$#191!111?@$#192!163?O$#193!218?C!6?B$#194!218?A$#197!11?_?O!8?_!8?_!134?@!7?G?@$#198!12?A$#199!116?GAaw~oo__O?GeJBZ[?A@^^]O$#200?Eu!5?_@FU{!160?_?C$#203!34?!5@B@@B@?@$#204!18?E!9?@AAC!13?_$#205!223?O?G$#206!53?G?F@!88?_?O??[NGNLLFM{W!63?k$#210!38?A?AA??@$#211!44?O???C?___!57?O!33?G$#213!159?F$#215!174?_O??AWWOOO!5?]???o!13?A@@@$#216!192?O@!20?B$#217!192?IGP@AA!7?A!4?EFBg$#218!36?A$#219!20?AC!5?@A!7?!5_$#220!190?_!31?G$#221!17?C?A$#227!190?OB$#228!19?CC!8?@C?G!8?!4_$#229!47?_!112?o_$#230!45?O??__???_!55?On$#231!49?C!95?CoM$#232!51?C!96?G!75?^$#233!226?@$#235!5?o!9?NxxwwxxNP{^^]WwOO?GOO$#236??@~~N~{!10?@@?A?_!4?C$#237!161?@??@@!24?F_!22?WB$#238!34?__$#239!221?_o$#241!46?G!113?GO-#6!13?O!201?G$#10!14?_!145?_GE@$#11!215?_$#15!227?@$#18!216?A$#19!141?C$#21!221?_$#27!114?G$#29!164?o?KD@$#34!114?E$#35G$#37!12?A$#43!116?G!4?AA??C???O!8?C@$#44!16?O$#47!114?@M!20?_$#48!137?GA$#49!8?C!159?_OGCE???o!9?w???oW$#50!115?@FCC!9?DFf@@DFfCE$#51!27?O$#52!14?G!176?A$#53!170?O!21?@$#55!23?Oo~~F~E!141?wo|~}NNN~fn!4~FA@???E$#56!213?C$#57!191?_!21?A$#59!190?A?oo!16~^^^O$#61!120?C??C??G?O$#63!188?OG$#65!36?o?MN??A!115?_$#66!189?C$#68!31?C@@@?@!152?@$#71!219?Y$#75!160?@@$#78!222?G$#81!217?O!4?O$#86!110?G!47?A@$#88!51?_op~|j}!12?OoooOoowww_}}}qENNMMMU}Gww!6?!5@zopo!44?OG$#91!57?@o!21?C???@@!7?A!4?_!58?C$#92!58?N!10~!9FBBA!7?@@@?@@FF^^^~~o!4_$#93!157?A@$#94!69?w!7G?CCX@@@!7?@?C??__???N!4]}CNM!31?_G!11?_$#95!143?A!10?OG$#96!145?B?A!4~^NJB@@!65?k$#97!144?o!80?j$#98!143?o$#99!224?~$#103!218?C!8?A$#104!161?_G$#107!216?@!9?O{$#108!10?@!151?OsK`pGCA@$#109!11?CO!149?_G$#110!15?@!145?O!53?C$#111!16?CO$#112!15?A!145?C!53?A$#113!16?G$#114!114?O!23?G$#115!164?AC??A$#116!140?O?@$#117!114?_!22?_?C$#118!113?^!24?oWF@$#120!218?O$#121!218?g!7?n$#124!111?@!30?A!73?O!4?O$#125!112?_!28?G$#127!219?_?C$#128!216?C???C$#129!218?@!9?u$#131!214?G$#134!112?J_!25?_GA$#135!13?G!150?@A?OGCA$#136!169?@$#140!139?A$#142!217?C??_!7?@$#144!112?O$#145!14?O?Ag!141?_!11?@!44?G$#146!115?O?G?C!4?C??G$#147!31?O!127?O$#148?@!9?G$#149o!168?G$#156!218?A?B$#157!11?@!150?@!51?_$#158F}_!7?A?_!152?WAA$#159??O$#161!12?C!5?_!196?@$#162!228?G$#163!217?A??O$#167!14?@C$#169!13?C???E!22?|!70?C$#171!15?_!144?G!53?O??@??G$#173??G!7?C!9?C!147?O?C$#174!11?A?_!146?O??A$#178!119?AA??AAADFGGWmm_??@P@$#179!18?O!121?_!20?A$#181??Co!5?@!9?GGB!8?A!140?A$#183!112?C$#184!12?G$#185!188?GA@$#186!160?C$#189!216?_$#190!221?G$#191!111?A$#194!219?@$#197!11?O!7?O!9?_K!136?_!10?_$#199!117?BB!7@A?A??OOYwWY$#200??B!5?AEG??A!158?@!4?_!36?C$#201!217?G$#203!116?oowww{{wwwoo__$#204!42?_w{~PO!107?_O$#205!217?_!5?O$#206!146?}{!4?_o?CE!66?B$#208!219?C$#211!46?gh~~~NF!32?!5o_!19?E!30?OC@$#212!222?_$#214!12?@@!173?W??G!22?@$#215!170?_??A???O!9?C???CGN$#216!169?_$#217!210?___gB$#218!115?_$#219!31?_}}}~MN@$#221!42?O!116?C$#227!189?O$#228!37?ooo?~LFB!66?G!44?_oWG$#230!51?OGM?AS!13?_???_!9?KG!4?Og?o!16?@o$#231!142?oKN{@@!6?C!70?C$#232!225?O$#234!215?O$#235!5?N!10?@@BfrK@HN!4?WP@$#236???N~o~~xwo_!6?C??o}e???G?@?A!140?G??@??O?WO!5?@$#237!14?EW_?G!21?A!146?_E_C$#238!27?_??_G!159?@$#239!221?AF$#240!188?_$#242!46?EE!109?GCAA$#243!221?@-#10!15?@AC!140?GE!54?S$#11!20?GG$#14!218?@!8?O$#15!22?G!196?_$#18!221?_$#19!116?_$#20!221?G$#21!218?G$#23!132?_$#24!18?G!94?A!21?O??A!19?A???C$#27!116?G!14?_$#29?oGw$#31!228?A$#32!117?O$#34!133?GC$#35???C!10?E?GO?_$#36@???_!155?O!16?@$#37!12?@?_!5?_$#38!95?O$#42!120?_!9?_$#43!131?@A$#44!216?D$#45!95?_$#47!133?CA@$#48!133?A$#49!165?AEBOWG!4?@??o@!4?G!4?WF$#50!134?@$#51!26?@!136?_$#52!186?A!26?C$#53!164?O???@!12?W??_?@?_!20?_?_$#55!25?@?@!135?Wgww[EEFFFB@!4?}~f~~FF???_w_ww!15?WwEM$#56!156?G!29?C??A$#57!185?G???C?F!16?_?FG?@$#58!195?w!12?G$#59!192?BBBF!11~^FF$#61!130?@AG$#62!94?_$#65!31?_ooGE?BAA!114?A?@$#66!188?@$#68!26?G$#71!217?_??A$#72!186?OC$#74!116?A??O$#75!151?G$#76!152?C$#77!92?W$#81!217?[??w$#86!112?G!34?_??G$#87!93?W!18?O$#88!50?O!5~FF!12?Vt{Y}~fBBB@@@?@!8?D??P}~}U!5W[z~F~}$#90!153?@$#91!58?x!42?B$#92!58?E!10~!33?BBBA!42?O??CA$#93!146?_$#94!57?w!11?~gIB@!20?@@E??@@!4CDB!5?__!26?@!8?G$#95!94?A!42?OG?A!6?O$#96!139?gC?_e_OC?CBA@!70?w$#97!94?C!43?_??A@??C!78?J@$#98!139?OWW[WWG!4?@!72?P$#99!224?_$#101!225?o$#103!227?_$#107!227?G$#108!13?A!144?_??IB??@!5?_$#109!157?G!5?@A$#110!160?@$#112!13?_!4?DI!194?a@$#113!13?O$#114!136?@$#115!170?_?O_$#116!114?G!18?_??GC$#117!133?OG$#118!114?@!20?CA@$#119!115?C!18?O$#120!226?N$#121!227?F$#124!16?@$#125!134?_$#126!115?@C!4?_!7?_$#127!94?O!125?@$#128!219?G?D$#129!219?C!8?[$#131!216?a$#134!113?@EWO_!17?GCA@$#135!157?O?O?@?A@!50?C$#136??o$#140!135?A$#141!16?__o$#142!218?_@$#144!118?_$#145!13?D???A!137?_!57?O?w$#146!132?C$#147!12?G!8?QcCC??A!12?o!110?OG?C!30?_?PC$#148!171?O??C??G$#149!169?_$#156!218?C??A$#157!16?C???C??G!126?_!62?_$#158?NF!169?_Ww{}E$#159!14?G{OG?O$#161!14?@A!140?_?O?K$#162!218?OA!8?@$#163!228?_$#165!226?O$#166!115?A???_!12?O$#167!19?CA!128?_!4?_$#169!18?A?O!7?A!11?N!110?_$#170!139?@$#171!19?@$#172!213?G$#173}??AO!9?O!148?C!8?G!4?O@$#174!158?CHA$#176!218?AO?O$#178!132?@@$#179!21?C!90?@?O_$#181???@G!154?_!6?@?_?O!5?@_C$#184!13?G!143?_???C!52?@A$#185!186?G?A$#186!12?_!174?G$#191!113?C$#194!222?@$#197!12?A!16?@!123?_!21?A??A!37?W$#200!5?O!6?C!148?OG?C??_???G?C!4?G$#202!137?G!11?OO??C$#203!116?@F!4N!7~^][$#204!36?_!4?}[NDL!35?_gggwww_Gw_$#205!94?GG!121?@!4?C??G$#206!138?O?__???_WNJCCA@$#208!220?C$#209!153?A$#210!120?OO$#211!42?_oyq~~~FF!26?www{[UUUFFF^vF^e!20?W_!20?_???A$#213!217?A!4?A$#214!188?O$#215!165?C??G!5?A!9?O!9?w!16?@p$#216!191?G!19?O$#217!185?O!6?CCC!12?_O$#218!117?GO$#219!12?O!9?O__[s{w{~^NNF@!119?AEB$#220!187?A$#227!23?OO_$#228!34?ow^{||?@B!93?O?C!9?_!6?@$#229!79?C!13?_!60?@$#230!49?wg!5?w!16?c@?WCC?AA?@!8?@A??g@??g!6_C?w?@E$#231!95?A!40?_??C?@??FBB!78?E$#232!95?C!41?_???CA@!79?mS$#233!226?_$#234!214?G$#235!8?KwwC!11?@!4?D!123?_$#236!4?Fn~~rFFz!9?@BA?A!127?O!6?__o!6?@$#237!17?@??@_??G!127?OGWOOC@!28?_G@$#238!24?B?A??A!125?K!35?O!21?A$#239!186?_-#6!156?OG$#10!156?_$#11!68?!5O??!6G?G!8?!5O!6?__!109?C$#15!80?O?!4O!13?_!114?@$#17!155?_$#18!219?_?H!5?@$#20!66?O$#21!227?G$#23!119?@@@?!5A@?@@$#24!124?C!5?A$#26!14?A!131?A!7?EO?C$#27!123?!5@$#29?Dc?AO!165?_?_$#35?_!13?w!148?A!11?@???_$#37!147?A!68?B$#38!65?O??_!33?O$#40!92?_$#44!217?_$#45!97?G!119?C$#49!8?G?G!166?EF?K?G!25?K???@$#51!138?_???_!6?OGKoo$#52!184?@!27?A$#53!162?@!16?B???@!4?@!19?oC$#55!9?G?O!7?@!119?_???_OC!6?G!8?@?@!12?WWWOB@@!4?}}!4~??!4_!9?Bba$#56!211?C$#57!186?w!7?_!12?_??G$#58!194?@BA?O!8?G??O$#59!194?MKLNN^~v!5~$#60!119?A$#62!89?_!127?A$#63!144?A!39?O$#65!17?K??C?!5A!4@?@!99?__?O$#66!12?w!7?O$#67!12?D!15?__?_!105?G$#68!20?@$#69!19?W!112?O$#71!71?_!16?_!136?@$#75!74?C!17?C!34?_!8?G$#77!73?C?BB!17?DB!27?__$#78!99?GG$#81!72?_!14?_$#82!184?G$#86!71?CC?B!25?C!15?k_???OOO??_???G$#87!53?_??_!4?_??G?G!8?__!8?_!15?GGG!5?_??_?__!15?G!11?A$#88!48?ww{~~^~vM???!4W!5?CC?AA!27?B@C?CK[[K{CCmW[Q[wW__!11?GG!4?C!5?@$#90!58?__!18?__!52?G!9?A$#91!57?gB?_!4?!4C!69?C??A$#92!57?O?@B@!7B!71?A$#93!80?__$#94!56?OF[]CECCCG???BB!32?BJJRBBRBbXP!20?@$#95!131?C?A$#96!135?AAA@@@!77?W???u$#97!136?@!86?GS$#98!137?@!85?A$#106!213?O$#107!67?O!28?OOO??_!117?N$#108!153?A!9?KGGCAA@@$#109!158?!4OC???A!47?_K$#110!156?G$#111!213?G$#112!13?@!59?OW!5O!5?G!5W!8?O_???_!48?@!59?A$#113!13?A!50?_!154?O$#114!122?@$#115!161?CO??O??@!46?o$#116!129?A$#117!129?@$#119!128?A$#124!94?G!11?_!39?@!4?@???H!56?O$#125!120?A??C!4?C$#127!62?_!27?_!12?O!114?@?O!4?A$#128!66?_!29?_!8?_!115?_!6?_$#129!225?_?OF$#135!14?w!77?G!7?O!56?_!4?G?S!49?K$#136?AZ~{_$#142!225?K$#144!118?@??AA!9?@$#145!70?G!22?G?_!116?_?O$#147!77?CCC!4?CCC!29?@!20?OWG??C!6?_!4?o!28?GAG$#148!167?@!6?O$#149!158?C$#156!97?_!129?C$#157!13?OC!56?G$#158?W??@G!152?__c__o?aw{{}}^~^NF$#159!15?C_!133?@?A$#161!73?G!7?O!9?G!63?CC?!4G??_!48?@$#163!93?_!131?O$#167!14?@!80?G!35?A$#168!68?G_!21?_!15?_$#169!80?!4C!45?C!13?C$#170!117?@!7?CCC$#171!63?_???_!26?_!6?O!113?B!11?_$#172!212?G$#173@!4?C_!9?O!142?C???A??@!14?W!34?W$#174!81?G?GG!67?@!4?O!55?_$#176!65?_!32?_!122?U!5?A$#177!13?k$#179!96?G!49?C@!5?C?A$#181}!4?BO__!147?@!5?A!18?C$#184!72?G!81?@!10?C!48?A$#185!185?C@$#186!19?_!7?_!60?CC!51?C!42?C$#191!69?G!63?@$#192!220?_$#193!218?A$#197!154?G!19?_GA???O_!30?C???c$#198!217?W$#200!6?GWO_?A!152?@@!9?OC@???AE$#201!70?_$#202!75?CC!10?C!10?G!9?_!108?@??G$#204!22?_?___OO?_?!4{~~FEAE!36?AA!9BACCB!35?_oOO$#205!143?@@!73?C???@$#206!134?CCC?AA?@@!75?_???G$#208!104?O!115?@$#211!38?ww{x!5~FB!28?B@@!9?@BB?F??EA?A!15?@?A?CCG?!4GWW???A!7?C$#212!73?__??_!27?O$#213!82?___!52?C$#214!182?O!28?w$#215!179?K!13?~!15?WC$#216!211?@$#217!182?_??o!8?!4O?_?G!5?V$#219!16?EQAAAB!5@!107?__o$#220!20?G$#221!20?__!108?_$#222!185?A$#223!12?A$#228!18?{C?[[{[[[MM]]^ABBB???@@!77?A??C!9?_?OO$#229!97?CCC?CC!19?G?OOO!8?G$#230!47?wCFB!4?G@!14?B@@!22?@@B@B?A?C!6?WA?FA??C_W?_!6?GC$#231!132?CCA@!88?g$#232!223?tB$#233!226?~$#235!8?AB!5?BH`@!103?C!16?OgwWW__w{]NAAC???A@?A?A$#236!6?FFDSvl!128?O???KW??`?C!6?AB@B!14?!5_???A!26?@$#237!145?A!4?_!32?C_?E$#238!137?_!12?Oo?G!33?@!23?A$#239!183?O?@$#241!64?O??G!57?_!94?E$#242!94?AC$#243!183?_$#245!86?_-#0!226?@$#7!226?C$#10!13?GG??C!15?G!121?}@$#11!13?C??C???A!7?A???C???OO!14?G?C??A!49?@!4?AA??CC??G?OO!30?_$#15!13?A!21?G!15?G!58?A???A???C!5?O$#17!154?O$#18!22?C!196?C$#20!23?C??C!4?G!18?O!58?A@!108?@!5?A_$#21!25?C!199?@$#26!154?C$#29??W???E!150?u}|\[?_g]OOqq^F@$#30!36?G$#35!173?@!5?A$#36!215?O$#38!30?G!71?@!13?I$#44!128?_!88?FG$#45!27?@!9?G!14?O$#49!184?C?B!23?_$#51!139?E??FC!8?_B!32?G$#53!183?GG?C!11?`!11?K$#55!140?_??@}cK??__OO!23?G!5?_oowo~~~rb~{{~~b!8?o{~~Q$#56!11?C!199?A$#57!184?AB!8?@???O!6?O?@$#58!198?Go???EG$#59!199?K~r~xFN@$#62!17?O!29?_?O!10?@@!39?@!11?@!106?_$#63!124?G!4?_!50?G$#65!133?g{K$#66!59?!5O!35?O?!5_!24?_$#67!12?A!11?__??_`!28?O???g_GWK??CCC!8?!8CKK!4G??GGg_O?G??O_oO??_???_$#68!137?N?o$#69!60?__!30?_!15?___$#71!29?G!18?_!57?A!8?G!105?C??O$#75!27?_!9?C?G!17?O!33?C!7?G!11?O!11?C@??O$#76!56?O!124?G$#78!24?OO!68?CC!83?_$#81!100?@$#84!80?AA???A$#86!32?O!15?K?CA?o?O!59?@!4?AA$#87!26?OO???_!13?__OOG???@P@@?G!9?A!18?A!11?C!7?GG!7?@?_???C$#88!20?_!25?GC!5@!56?G!7?!5@$#90!18?Oo?O!4?GGWO??__?_!25?CC!4?A!22?A!9?C!9?GG?OOO???__!97?@$#92!18?_?O??G!10?_!24?C!14?@?@??@??@!5?@???A?AA!5?C??!5C$#93!50?__!17?@??@??@!4?@@???@???@!6?A??A???A?A!6?G?G$#94!30?OO!20?_!49?CC$#95!49?_!12?A!34?AA?A$#96!94?@@!5?A!119?O??G$#97!224?A$#98!222?KCC$#99!222?ow$#107!12?_?_!5?C!18?_!18?A!49?@??A!13?_$#108!156?G!5?GHA!14?C$#109!156?O@???_!15?_!33?_?G?@$#110!14?C$#111!34?G!120?@$#112!28?C???G!5?_!16?C!50?@??@!5?C???G?G!4?_!85?S@!5?WC$#113!21?C!5?C?A!5?O!4?_!12?G!51?@!8?C???G??O??_!100?CO$#115!178?G!34?O^E$#120!29?C$#121!225?GG$#124!112?C!107?O$#127!33?O!20?A???@?A!56?A?O$#128!24?C!12?_!75?C???G!101?A$#129!221?@$#131!11?_$#135!19?A!134?G!7?_A@!13?O!33?@!7?G$#136??F~r~wo!149?G?Aa?COS___$#138!15?A!140?_$#139!4?K$#142!15?_!43?@!167?A$#143!224?_$#145!33?CO!16?O!51?@!11?A!4?O?G_?O!52?_!39?O$#147!11?O!6?@?@!111?cA!15?C???O!27?Q$#148!215?G$#149!215?_$#157!127?_!51?G!33?C$#158??_???@G!150?@??BB??@NNLL?GA!4?O??@!32?__$#159!15?@B@!136?A!21?_$#161!14?A!141?C!6?C!48?a!5?__$#163!57?C!163?A!5?@$#165!225?O$#167!17?A!161?O!31?O$#168!19?G!11?A!4?_!25?@!57?C?_$#169!21?@!104?O!5?W$#171!18?A!11?A!23?GA!52?A??@!7?C!100?@$#172!217?_$#173?F!5?C_!139?_!21?_?C!5?C?A!30?G!4?K$#174!15?C!140?A!55?G$#176!16?O?G!40?A$#177!13?@!24?O!14?C??E!47?@!115?A$#179!22?@??@@!7?C!15?G!72?G!23?C$#181~w!5?B^rA!136?GO!22?O?A???G?@$#184!14?@!147?O!50?A$#185!180?_?C@$#186!12?C!6?@!8?@!80?OO!13?E@$#191!23?@@!14?O?_!10?C$#192!107?A!4?@$#193!63?@!163?O$#197!180?C!35?rW$#198!12?O$#200!10?w!170?@$#201!227?c$#202!12?G!42?G!55?C$#204!30?@@@!4B!17?__?_!45?G!21?ACK^^!18?AAA$#205!16?_!49?@???@!22?@!8?A$#206!61?A??A@??@??@!11?@@?@@??@@@???@@@!5?A!116?G$#208!58?C!53?O!8?C!105?G$#209!21?_!8?_!38?AA!11?AAA$#211!37?BFF!4^NNB!76?@??AA$#212!22?O!33?GG!30?AA!20?C!107?A$#213!17?_??GGG?GG!34?C??A@AA@!5?@???@@!12?A?A!5?@!9?C???G??OOO??_$#214!183?C!27?C$#215!185?C!4?KO?BA??OA!7?K???@$#216!191?K!5?K!7?_?A$#217!183?A@!13?CB?K??o?A$#219!132?BD@p~oo!8?B??@?@$#221!59?_!4?O!31?ooO?_!4O?O!5?_$#222!22?_!42?C!34?G!15?_!64?C$#223!58?_!5?___!5w!8{!8w!4oOOoo$#227!134?AA$#228!32?A!97?^~?O!14?@@CE$#229!36?C!6?__OO??C???A!17?A!24?CCC!19?A!4?A$#230!44?O?CJAAA?A!66?A??B$#231!224?@$#232!221?_BB$#233!225?_A$#234!13?oOWGGCC?!7A??CC$#235!139?@^~wy@ZROGOO?CC@!20?_$#236!9?KDB!134?__?GG?G!18?_w{~^VFB$#237!11?G!136?C??H?_!27?_G!28?@$#238!138?NG!11?_AG!28?O$#239!12?@!169?@$#240!23?_??_!33?GG?G??OCC!4?AA??AAA!10?C?CcGG!5?G!11?__$#241!35?C??G???_!8?C!5?@!56?@$#242!56?_!7?C!7?A??AA!27?GGG!18?KH@$#243!182?A!35?C$#244!23?O$#245!59?G???C!22?A!30?_!62?O-#7!225?@$#10!11?@!125?_!16?V$#11!5?_O!34?@!85?@@?A?C?GO$#12!153?O$#14!225?G$#18!40?@?@?A$#20!13?@!28?A$#21!225?O$#24!161?A$#26!153?C!63?G$#29???KG!150?_GT@b@?GmO@!48?A$#35??@!165?A$#36!215?@$#37!26?!5_$#40!225?_$#44!45?G!86?A!42?G$#45!47?C!128?G$#49!208?_$#51!140?C?DFC!5?M$#53!179?C?A!16?AA!4?A$#55!140?B?A?@DHI??@A!27?wc{!16~|{___o{}~~NNB$#57!200?OOGC!5?_$#58!200?MMEA$#59!200?!4@!13?_$#62!47?@!81?C!5?_!39?O$#63!32?O!16?G!81?@?A?C!42?A$#65!29?O!103?@@$#66!13?_!7?_??O???@!4?O??_O?OOO$#67!12?O!4?GWQIXHHA!4?C!5?AAC!4?G??O?_??AAA!5?AA!49?A??A???@!5?AK??GG$#68!136?ECK!4?o??___$#69!18?_g_?AA???GI?AA???G!23?@@@!42?@!20?g$#72!118?@$#73!18?C!4?O!9?KC?O_??G_!7?CK!45?!5@!18?AAA$#75!44?G!7?@!70?A?CC$#76!37?A!5?G!4?A$#77!12?G??C!108?A$#78!33?@!5?CC!6?A!80?G$#81!9?_!4?@!19?@!6?C!4?A!77?@!9?_!85?@$#83!17?A$#87!10?OG!23?@!14?@@!70?@!8?O?_$#88!14?C???@$#90!8?_!4?E???@!18?@?A!10?@$#92!15?A$#93!48?@$#96!220?C$#97!221?G$#98!220?w$#99!221?REA$#100!222?@@$#104!154?_$#106!155?@$#107!10?C!32?A?C!83?A???G!89?_$#108!155?O??_OC!51?A?O$#109!6?GC!151?GI?@!13?A!34?_C_$#110!153?_G$#112!8?C!38?GO!82?C!4?O$#113!49?O$#115!4?oW??A!162?_OWKe?O!32?O??AK$#120!11?A$#121!224?S$#122!137?O!34?_!4?A$#124!47?O?_!85?G$#127!11?C!36?_!128?C@$#128!130?C$#129!226?P@$#131!153?A!20?_$#133!6?_$#135!46?C!81?A!4?C!21?G!5?@!14?O!34?O@??g$#136???BFFFB!149?_S?o{sPNMFB@!7?@$#139!156?_?IC$#141!156?FI!4?A$#142!39?@!6?@!179?G$#145!10?@!123?O!42?H!32?_@!5?@?@$#147!23?_!108?@???G?O?o$#148!210?G?o??C??C$#149!169?@!45?A$#156!224?A$#157!152?_!63?O$#158???O!4?@!147?O!7?_OGC!44?G\@$#159??A$#161!9?A!145?C!20?_!34?K??_OGE@$#162!223?O@$#163!7?_!4?A!213?A$#165!224?g$#167!216?A$#168!41?A?C!83?A$#169!24?_!7?_!101?C!6?o!11?@!20?O$#171!8?O!39?G!83?G$#173??C_!144?@!26?@?_$#174!7?G!147?A$#177!9?G!34?C?G!79?@??@?A!4?_?_$#179!130?@!8?_!12?O$#181~~w!6?@!138?AK!15?_OGKa@@GC!36?C$#184!153?G!57?A!4?C?A$#185!34?_!183?_C$#186!31?@!14?O?C!63?@!11?C!54?@$#189!176?C$#192!43?@?A!79?@$#193!222?_$#194!15?@!24?A$#197!25?_!5?_!138?_O??A!41?@$#200!166?_oOOQGC!5?O$#201!223?G??C$#202!50?O!122?_$#204!20?@!25?_!6?@@@!68?G$#205!220?A$#206!219?_$#208!44?@@!74?@$#209!13?G!5?@!110?O$#212!9?O??C???A!25?C!83?ACC???O!86?O$#213!14?A?@!20?@@A!83?@$#214!208?O!7?_??A$#215!178?_??@!20?O??@???O$#216!203?G$#217!199?@!4?@!13?G$#219!135?B@JB\??w?__!6?C$#220!22?_??!4O??O$#221!11?__??_G!4?A!4?G@?@G??A??GGo?_G_o?_!11?@!53?@?@@!7?C!5?_$#222!10?_???G?C!102?@$#223!13?OoOooA!5CLNFECIDKA?ASC?Gg??O?o!6?{{}}}~}|{}}!34~!5}~~~}!4~|~}{}}~}}}{{{wooOoo?___$#227!30?O!4?_!98?A$#232!221?cWC$#233!225?E$#234!7?OGCA?@$#235!141?N??AAA?Cqo?I!18?A$#236!146?CDG@!18?_KKCBB@!5?W$#237!33?_!144?KA@!36?OO$#238!139?AG??GWWOOO??|@!27?A$#239!219?G$#240!15?G?C??O?O!9?L?W???C!10?A_!66?@!10?O???_$#241!10?G!120?G?O$#242!11?O!117?O$#244!129?GG$#245!121?@???A-#6??G$#8!221?O?A$#10!147?_$#11!139?@A?C??O?O_?!6_$#12!150?G??@$#17!152?C$#18!222?A$#20!144?O$#24!149?C?G$#26!151?@$#28!152?GKK?@?A$#29!26?G!128?GGC@?A?PoO?OOGG?C$#35!22?!4O!132?C??A?@$#36!166?A!8?_!26?_$#37!168?C!41?C$#39!137?@$#40!221?C$#44!38?@$#49!167?@!8?oyw{}E!8?OO!8?_g??}Y??PPG!4?A$#52!208?E!4?C$#53!205?C???_$#55!179?B@@!5F^!4N!8~FFF@@`~~???Cww$#56!43?_$#57!200?WO!8?OO??_C$#59!215?O$#65!4?__$#66!11?@??o??A@!21?@??A$#67!8?GHG??x?G@@!30?@?@!77?@???@M?_?CW?o$#68!43?O!101?C$#69!7?G_?C_`!31?BQmg!86_a?gg$#71!143?O!81?@$#73!14?G!27?@$#75!7?A@$#76!137?A$#77!140?G$#78!6?A!128?@$#81!143?_$#87!7?@!131?C?G$#90!217?O$#93!217?_$#96!218?K??A$#97!218?_O$#98!219?FF$#103!224?@$#104!29?@!4?AA$#106!150?CA$#107!143?G$#108!18?_OGGK!11CKK!4G!114?@!4?_!13?oKPA!35?@?@$#109!23?GG!6?GGG!6?G!109?O??O???@?O!12?_?A!36?A$#110!151?CA$#111!149?G??@$#112!4?@!11?_oGC!4?@!5?@@BA!5?A!98?@??A??G?_?G_!6?__$#113!141?C$#115!27?!4G!119?AO???!4O?o__!4?G?C!4?@!37?A$#120!222?G$#121!221?G$#124!5?A!13?A$#127!140?C!81?_$#128!220?O$#131!142?A??G$#135??C!32?@CC!136?OA!37?@$#136!155?@C??A@@??!4_ooww[M$#138!19?_O!4?G!126?O?O!4?@?O???O$#139!154?AEAA$#141!20?_O!4_$#142!224?E$#145O??GC!11?O?C!17?@???A!98?A@??C!66?A$#147!20?@!18?@!103?BCAG!22?A$#148!165?C!5?A$#149!30?O!127?G$#156!223?S$#157?gO!14?G!4?@!187?@$#158!157?G!5?G??G???C?A???C!34?@$#159!21?_!4?!4o_!8o!123?G$#161???A!14?OGA??BA?!6A?@@!4?CCC!104?O??O!24?_K@$#163!6?@!135?G!76?_??P$#165!220?_??@$#167!21?@!15?@!109?G!21?@???@$#168!145?_$#169G!140?@!26?A???@$#171!15?_$#172!167?A??@$#173!39?oowo!116?KGG??KG!36?O!10?A$#174!20?CAA??!4@!7?AAA!109?O$#176!221?_$#179!42?C$#181BFB!39?G!117?CCEEBBC!35?GC$#184!21?C???A!12?C!114?A!4?_$#185!16?GCA!197?G$#186??_oW?CC!8?A!25?A$#193!220?G$#197???@!166?A!32?w!5?K$#198!41?A$#200C!165?@C@!7?G@!31?A!4?A@$#201!223?G$#202!5?C$#204!139?G$#212!142?O?_$#213!218?A$#214!212?C?C$#215!208?g??_??W$#216!210?_G$#217!215?GF$#219!142?@?B@FBB$#220!15?O!201?C$#221!8?Ecr???@@???@!23?@Oh@D!82?@@!6?_o$#222!136?C$#223!8?OO?]]EEE!28?CCOO]]]!73^]]^^]^]]]O[]OO$#227!43?G!171?_$#228!5?Wwo?A!33?Cg??A$#232!218?OG?@$#233!222?C$#234_O?CA@$#235!149?@@!31?!5_$#236!148?C!28?CF??w!5W_oo__!11?A$#237!171?@!45?B$#238!147?C?A$#239!16?C!199?O$#240!41?@!7?@!74?@@!7?@??A?C??_!74?_$#241!134?@???A??O_$#243!217?G@$#245!136?@-#6!162?A??C??G?OO??__$#10!176?_$#11!169?O??_!42?G?C$#15!163?CA$#18!221?O$#20!221?B$#24!15?G$#29!167?@!34?_$#35!17?CA?_???B@$#36!201?A!7?o$#37!207?_$#38!150?C$#45!153?G$#49!176?BB@@B!14?GGGOGB???^GWK$#52!209?CC$#53!194?@FFBKF!5?@FB??B$#55!193?@WOOOB!5?_E??BB?B$#59!217?oO$#62!158?A$#63?@!9?G!142?_!58?CC$#65A?e_pooO?OWEA!146?O$#66!47?G!108?O!57?A$#67!47?_!93?A?A!17?GG$#68!214?@$#69!43?__d|D!93@!5?o?_!6?O$#70!44?O$#71!152?@!69?Q$#72!153?C$#75!145?AAC?GO???OCC!6?G$#76!144?@???CCG?_!63?@$#78!145?@?A!71?O$#81!151?B$#87!159?CC$#88!158?C$#89!222?C$#90!153?A!66?_$#93!155?AA!60?@$#104!14?G$#107!157?@!8?G!6?O$#108!14?_?C!155?A@$#109!15?O?A!153?C@$#110!163?A$#111!158?@?@$#112!12?O??@!144?A!6?C??G!6?_$#113!156?@$#115!18?@!144?@@?AAACC???A!33?G$#120!218?A$#122!11?O!201?G$#124!150?A?G!9?C$#127!148?A@??C!62?C$#128!149?A?C???@!12?O$#135!13?CO??@!155?A!39?OG?K$#136!165?@@?@@BB$#138!16?G!152?A$#141!15?_oww}MBEB$#142!218?@$#145!12?G!149?@??A!7?GO!35?OO??O$#147!12?C!29?_$#148!179?_!34?__$#149!199?_$#157@!147?@!19?C??_C!5?_!33?O$#158!200?o{^!7?!4_$#159!18?C@P{x{{}!12~_$#161!11?_?_AC!145?@!46?o$#163!154?@!62?A$#165!219?@$#167!14?@!200?O??C$#168!153?@$#169!10?_??A!141?_!8?G!47?G!4?G$#171!147?@!11?A!5?G!53?A@$#172!175?O$#173!38?^~~~F!157?G??F$#174!12?_WCA@$#176!221?k$#179!170?_$#181!42?G!131?C?O??Gg[Kkkkw??_!10?C@?_$#184!16?A!154?GGC@$#185!213?A!5?G$#186!13?@!140?G?_Wgg!5?OO??_$#193!222?G$#194!150?@!6?A!64?@$#197!203?W!6?G$#198!167?O$#200!175?NG?O??_oOOO?_!11?O!7?OCG?G$#201!222?_$#202!151?G!9?C!58?A$#204!44?G!102?GWO__!8?G$#209!144?A!12?C$#212!152?A!66?_G$#213!154?A!65?O$#214!205?O_!4?C!4?O$#215!197?C!7?_$#217!213?@??_?G$#219?C!41?C$#220!9?_!33?GB!110?GG!4?_!56?_$#221!11?@!31?O?Y!103?_!18?_$#223!46?AA!93}|}{w{K_$#227!7?__$#228{yX^MNNN^NF?@!31?C??O!110?O?oOooo___$#229!151?OO_$#234!159?@?A??C?CG?G??O_$#235!42?O!139?!5@EQM]][$#236!43?@!132?C[MUSB!4AEXlP``b}e!4_$#237!43?A!130?G!37?C!6?C$#238!212?B$#239!215?B!4?C$#240!142?@@C??O!6?C$#241!146?@!6?O???_!58?A-#6!178?@@??A?A!5?CCC$#10!186?A$#11!176?@???A!6?A!6?C$#15!155?@$#18!175?@$#20!221?B$#21!223?C$#24!13?@!185?A$#29!11?_??@!184?OA?E$#36!206?_!8?@$#49!204?__!10?o$#53!204?BM$#55!204?CO$#57!206?G!9?M$#59!217?@$#63!8?B!153?_!13?A$#65G?JN^P!35?C!122?G?`?]Y?CEsQQG?C!7?G$#66C!40?oa!106?KO[!8?F?O$#67!43?B!105?@A??Kg$#68?_!5?G!168?__o_oow!4o_ooo_$#69!41?G!109?AW$#71!221?_?_$#76!152?@??O$#77!156?_$#78!155?C$#84!219?[$#87!153?@?G?O$#88!219?_$#90!157?_!62?@$#103!222?O$#104!198?C$#108!10?_OC!186?@$#109!13?A!195?O$#111!180?@!6?C$#112!7?_oOA@!144?AC!23?@!4?C!20?O?_$#113!185?C??A$#115!12?G!186?K!7?@??G$#121!222?_$#122!184?@!6?G$#124!178?A!4?D!7?AG$#128!184?C!37?C$#129!221?C?G$#131!190?G$#132!183?A$#133!185?A???C!4?G$#135!8?G?OGA!144?ACgO!37?O!8?CC$#136!199?_{~@$#141!12?o{}~~~b~~!181?G$#142!222?@O$#145!156?@?O??_!28?A??O_??GA!8?A$#147!158?A??O!19?K?G???G???O$#148!209?J$#149!215?A$#157!10?@!171?@!12?G??_$#158!200?@?O!6?CV!4~$#159!18?[??!8~^^frA?``xN$#161!9?cGC@!145?GO_!37?G!8?GX$#162!222?A$#163!221?G$#167!7?O?A!144?@!40?C!12?_?_$#168!182?C!38?O$#169!8?C!164?@???A!10?G$#171!155?ACG!16?@$#172!192?A??O$#173!29?__WK|~]]EONB!155?O!5?_!12?C$#174!9?GCA!185?o!9?_$#176!222?G$#177!179?A!9?A???G$#179!6?_$#181!40?C@!144?@@!7?_?C@!4?F!11?W$#184!196?_!11?A$#185!9?@!147?@??G$#186!158?@!12?@@!6?CC$#191!192?_$#197!185?@!7?A$#198!189?G$#200!188?@@?@!4?K!7?O?O$#202!159?C!32?O$#204!155?_$#208!158?_$#209!153?AC$#212!156?W!62?B}$#214!206?F!10?o$#215!205?@$#217!216?@M$#219oOo!174?OGWG???G$#220!7?B!32?O!109?K!10?J!12?__!42?B$#221!40?_?O?O!104?Q@?C?O!4?@!11?A$#223!42?K{n!104~__`_o$#227?GCo_m^C!34?@!133?OK!7?G$#228BF!37?_!121?CN~v~]~`d~wwIKKC$#234!177?@???A!6?C!4?cO$#235!38?_O$#236!41?A!148?@?@@!4B!5?wG!10?_$#238!40?G!146?O$#239!159?A!58?{$#240!152?A$#244!154?A-#7!212?O$#10!188?_???@$#11???_o__!183?CE$#15!161?AA?_!22?_!25?_$#20!210?C$#24!9?_!184?_$#26!189?_$#29!199?M_D$#31!209?_$#35!14?__ooaM@$#40!223?_$#44!160?A???C$#49!203?M!11?EF$#53!204?AA$#55!204?L@!11?O$#56!187?A$#62!159?@!48?@$#65!166?FG??E?w~$#66!156?E!10?O_$#67!39?AB?A!113?@!7?A$#68JGJ!173?Nn~F~!5NB@B@$#69!36?_o!4?K!111?HG$#71!162?O!60?@$#75!218?O$#76!160?_$#77!219?C$#84!219?A$#87!157?@?G$#88!219?@$#90!158?A!60?_Q$#92!159?E?o$#93!160?C!47?C$#96!208?o$#103!222?W$#107!222?C$#108!8?OC@!184?OC?_$#109!9?G_!184?`w$#111!189?OG$#112!4?G??a!153?@CG!24?OG!4?O!11?O@??AC$#113!209?@!12?_$#115!9?O!155?O!24?O!21?CM$#120!212?_!9?@$#121!222?A$#122!4?C!161?_$#124!161?C!49?A?O$#127!223?C$#128!162?G!48?O$#129!209?E$#135???O??OCA!155?G_!31?]^!6?_a???@$#136!11?_!187?@^A$#138!10?A$#141!10?[^~~^XBB@$#142!223?W$#143!221?_$#145??_??A?WC!183?_?C!12?C$#147?O??A@!29?GC!148?__[?A@$#149!193?G!7?G???G!8?@$#157!8?GB!202?G$#158!199?o!11?@B@$#159!15?EKK[p}!4~z~xwO?GNA$#161!6?G?`!151?@??CO!28?P?IA_!8?CA$#162!209?GW$#163!209?O_$#167!163?A!43?G$#168!163?_$#169???G!184?GCA!16?_!6?_$#171!162?@!42?O@$#172!191?G$#173!25?C?EFn~vOLFFB@!163?O@!11?A$#174!5?[E@!184?A_GC@!9?G$#177!163?O$#179!191?@$#181!33?OG!156?OGAB!6?_A!11?Gwo$#184!6?@!190?@$#185o_OE!163?_$#186!163?@$#194!221?@$#197!190?_?C!14?O!6?C$#200!191?_OC!8?CooC!8?O@G$#201!211?_!11?A$#204!39?@$#205!160?G!60?[$#206!162?_$#208!220?_$#209!158?C$#212!160?O!47?A!10?OL$#213!158?@??G!46?G!12?A$#214!217?N$#219?B!32?O??A@!126?@!11?O?w?__o_OO$#220!168?Oo!4?~~$#221!34?__GCMKKN@!111?EFGKOO!4?@?G$#222!218?M$#223!38?!5o!111~!4o__!5?C$#227CCC@@!171?o$#228!33?_?OO!128?A?FNNx~F$#233!211?G$#236!32?_!169?w@!13?_$#237!165?GO!19?G?C$#238!181?OO?O?C$#239!218?@$#240!37?G!120?G$#242!157?A!60?_$#245!219?G-#6!180?_$#7!214?AC$#10!181?_??G?A??OGC$#11?A!177?_!12?A$#15C!14?C!168?C!35?C$#18!219?O??E$#20???A$#21!213?A!7?@$#24!192?C$#26!187?A@$#33!6?A!162?O$#35!200?@$#36!18?@@@!184?G$#38!4?OC!161?CG$#39!6?!6o___$#40!4?G!205?@!12?F$#44A!171?_$#45!22?_$#49!201?OW$#52!217?@$#55!202?C$#62!219?G$#63!169?A??O???O??O$#65!170?BBHVOO?O[$#66!173?__$#67!26?GG??G?AAA$#68!178?@?@?@$#69!24?_?_!5?@@!126?F??_$#71!168?_!41?C!12?_$#72!218?C$#73!24?O$#81!164?A!42?A$#87!162?AC$#89!208?G!8?__??_$#91!165?O$#92!166?o$#93!165?GGo$#96!207?OF!12?W$#103!219?_G?G$#106!192?@$#107OG!216?O???o$#108!14?@!5?AA!5?A!165?A??K?B!6?C$#109!22?A???A!160?_??_ow{~~B?K!5?A$#110!188?_$#111??@@!179?G$#112!7?@??AAA?A?E!8C!156?O!7?_?A!13?@$#113??C!162?@!56?@$#115!15?@!7?AAA!157?_OG!18?_?@$#120G!215?G$#121!208?_$#122!8?CK???G!5?O?o!145?@AC$#123!8?G???OO$#124!11?C!6?GG!7?C!136?@?A??_$#127!207?@??A!5?O$#128!165?A!43?G!4?D$#129!208?OCG!9?Q$#131!170?GO!34?A$#135!13?C!12?C!155?_!13?o!7?O$#142??gO!216?@A$#143?_$#145!8?A???C!175?OG!25?AC$#147!170?C!8?GGGC?B@!19?_G$#148!17?@!173?@!11?G$#156!217?O$#157!28?A!174?O$#158!16?@!181?OF$#159!21?!7@$#161!9?A??@?C??AAA!5?C!164?S??@???~!5?_KA$#162_!208?B!5?G_$#163?O???@!203?O?@BCGO$#167?@!5?A??C!6?G!4?G!6?A!136?@A$#168??OKEA!160?CGO!54?G$#169!28?C!148?_!5?C!33?C$#171!4?@!15?GG!156?_???G???C$#173!28?@@!159?@!8?_GA?_$#174!8?!4@?A?A!167?O$#176!217?G$#177!6?@!178?A@$#181!184?_ow[KE@!8?OC$#184!13?@!177?G$#185!24?G!143?@??G$#186!34?C!140?_$#189!5?_?C??GGG?GGG?O_!148?CGo_$#190???__WC!9?o__?o$#191!180?O$#192!6?GG!6?Oo?O$#193!221?C$#194!165?C$#197!30?@!157?A?A!13?@O$#198!22?O!183?C$#200!203?F!12?@$#201!207?_?_!8?G?_??O$#202!23?G!152?_$#204!161?E$#206!207?G$#209!164?O$#212!164?G!41?_!12?F$#213!162?@BC!42?C$#217@$#219!31?@!144?GG?FEFAB$#220!25?G!143?@!4?BB$#221!25?_??GCCCKKH!127?W?_$#222!23?o!194?A$#223!26?O!4owooo!125~ow$#227!173?GKKFFA$#228!30?AA!139?CE$#229!161?@???_$#233!213?@$#234?CA!179?O??C?@$#235!199?_$#236!200?wnB$#237!215?@AA$#240!25?O???G!130?G?cO!54?@$#242!163?G$#243!206?O-#6!178?@$#7!205?O$#8!215?_$#11!170?A?Aq$#15!174?@!32?@$#18!169?@??O!46?O?C$#21!171?G!36?@!5?O$#24!183?_$#28!175?Gww$#29!178?_$#33!21?D$#35!182?A$#36!200?G$#38!5?o!4_o$#39?_oww?!5F!4~{w!4o$#40!205?_!9?OG$#63!22?G!179?O$#66!75?_$#67!23?O!50?_???_!86?G$#69!25?G!139?AOG$#71!207?O!11?G_O$#72!23?e!48?__!5?_!123?G$#73!24?N!144?_$#75!167?C?O$#78!204?C$#81!204?G$#87!168?CG_$#88!166?@$#89!223?@$#92!167?@$#93!169?C?_$#94!167?A??W$#96!219?CB$#101!207?G!10?W???C$#103!206?G!11?A??A$#104!184?G$#108!173?G!4?A!5?cqgkAc?o?O?C?@!4?@$#109!174?G!5?_B!4?PO{Z^NNN~B???_$#111!171?EG???@??@!7?@$#112!175?@$#113!170?@!34?G!13?@$#115!173?CO_!20?OA!5?A$#120!216?O$#121!217?G??G$#122!21?O$#123?G?C?!6G!6?!4G$#127!169?A??_!32?C$#128!204?O??C!10?_$#129!208?G@!4?_!8?A$#131!202?G$#132!204?_$#135!177?A??@??GOG!4?_?O??GG???O?C$#136!175?SCC[ME?@!9?__$#138!174?C$#142?A@!205?E!9?@A??A$#143B!215?_O???G$#145!200?_S$#147!22?A!180?CA$#149!181?O$#152!207?A$#156!216?C!5?@$#157!172?C$#158!179?OGC$#161!172?@?_?A!4?__O??CA@!6?oE!4?GA$#162!213?_???D??O$#163!170?C!49?C@G$#168C@$#169!22?@$#171!203?_??A$#173!183?@!12?_$#174!174?AA!9?CA$#176!218?C_$#177!171?@?@$#181!179?_OGCEB@!12?`O$#184!182?O!13?@!6?@$#186!76?_!91?O!33?_$#189!4?@?!4O$#190?CEB!12?!5FA$#191oOG?EF!15?G$#192G!14?B!5?_$#193!217?A$#194!168?B??O!34?@$#197!182?G!14?C???A$#200!197?w]KC@??@$#201!206?O$#202!22?C$#204!165?@$#221!77?_!87?O??_$#222!23?@$#223!24?ov!46~!8^!85~cko$#229!168?G$#232!217?_$#233!206?C$#234!177?@$#235!199?@@$#236!199?AA$#237!201?_$#239!22?oG!181?@$#241!203?O$#242!166?A$#245!205?A-#6!138?O!37?G$#7!202?A$#10!59?__??O!72?O??O??__!31?A$#11!66?G!4?CG???C!53?G??OO!5?O_!58?G$#15!65?G!110?O$#18!211?A$#20!202?C???C$#21!208?C$#24!177?A$#28!183?o$#29!189?AA?@@$#31!217?@$#33?_$#35!190?__$#36!192?_$#38!4?{!5~B!190?A!4?G$#39BF@CA!6?|~N~~FNNN@$#40!211?_???CQ???@$#44!21?K!180?G$#45!139?G$#49!198?C$#62!174?C!34?A$#63!78?G!50?C!10?G!7?_!52?O?_$#66!58?O!69?C$#67!53?O???OG??AC?A?AA?A??@!6?A??_!39?MC?CAAA??!4A?A??C?A?CESC??O?O!16?@?cO$#69!59?KC!19?GG!47?A!8?A!30?A?G$#71!206?@AG!5?_`?G?@$#72!22?@W!30?OoO!18?@!73?_?_!18?A?_!34?_$#73!23?f$#75!141?G!31?_$#79!22?O$#81!208?o$#82!170?@$#87!173?K$#89!209?G??O$#90!171?@$#93!172?@??O$#94!172?C$#96!211?G???A@$#102!179?A???A?@$#103!210?C??@P???@$#106!61?__??O?G??GGC?CC!52?O__?O$#107!207?C!9?A$#108!176?A?SCa]BD@AB@!4?OOC@???@$#109!178?Gw[_GGS??A?@???M???A$#110!67?O$#111!62?O_o_o_WW???C!52?OO?OOWGGGO!8?_!31?C$#112!58?_??O!8?C_?G???OO!46?O???G??___g_???_O???_!32?_$#113!77?C$#115!126?_!67?GA??B$#120!175?C!36?A$#121!212?_??GC$#122???B!17?A!104?G!20?_$#123KOE!8?A!8?M$#124!73?O!5?C!93?@?G!22?O???@$#127!208?A!8?C$#128!204?G!5?@$#129!199?_!13?_$#133!177?_$#135!79?O!97?C?@!4?A???@!5?B$#136!176?@!5?o?g{{[][\^M$#141!177?@$#142!201?_!10?@$#143!176?_!39?G$#145!60?O???G???C??O??O!52?G!9?G!61?O$#147!62?G???C!4?A!58?C??CC!9?O!52?_$#156!213?O$#157!74?GA!4?_!61?O???_!28?@$#158!178?@!8?_$#161!70?_!5?O!50?_G!8?_?_!37?GA?@@$#162!203?C!9?AG$#163!203?AD!5?AD$#165!209?C$#167!72?OA!126?C$#168!207?G$#169!59?O!12?A!7?O!43?_!6?CC$#171!57?_!16?A!49?O!73?_G_??G?K$#173!188?__!4?O?C$#174!68?_?O?!8_!48?_??_$#176!174?A$#177!69?C!6?AAC!57?G$#179!67?C$#181!193?__KB@$#184!69?_!5?O!62?_!43?C$#185!199?CA@OO_$#186!61?C??CC!4?A!6?G?G?_!42?GGCC!7?CCC!5?G$#190o!9?_!5?o___o$#191?Gww!9?o??G!46?G!11?G??A!59?G!4?O$#192!4?@!5?[!6?OOO?@!179?G$#193!173?A$#194!174?G!29?AAA???_?C$#197!125?_!71?C$#198!21?o$#200!195?owG?A@$#201!207?@!7?O??EA$#202!56?_!19?G!123?O?_$#204!60?G!80?C??G$#205!209?OWOGKE$#206!172?A??_!29?@$#208!207?O$#212!171?A??_!34?_$#213!174?O$#221!53?_!7?G?C!58?__!14?C?C?K???O???_$#222!22?m$#223!24?!29~!5NFBB@BB@B@@B@@@!8?FF^!39~PRBB!4@B!4@B@B@BB@BB@JJNNN^N!16~{|W?O$#229!173?O$#233!203?@$#234!137?O!36?@??O!23?C$#237!197?OG$#239!54?_!18?@!130?Ooo$#240!74?@?!4@?O!41?GC!22?OO!19?A??_$#242!171?CG-#6!178?@C$#10!53?CCA?kk?QSB@!69?@AAA@DBB??B$#11!50?G?C?A?B?A_@!5?G!67?C!7?@!36?AG_$#12!150?KG$#14!196?O$#21!198?O??@$#24!95?_$#28!181?AA@ooG]MA$#29!182?O_$#33_$#35!99?_!84?A??_$#36!190?O?G@$#38?KM]!6~$#39WO@!8?[^?~^$#40!200?A!4?A!6?A$#45!21?}!175?@$#62!197?A$#63!45?_!20?O!79?_!9?G$#65!70?G!53?C$#66!22?G!20?Aa!26?G!5?GCA!25?A!4?A???G???_!53?@$#67!23?M!18?osOCG?CC!17?O??__?gg!7?@???G???CC?A!5?A!7?A!5?C??KGGg__h?G_o_?___oo__?o!17?A?C?G!13?C?W$#69!42?KGG??GA!23?G!13?A??A??A!21?A??A!4?EA!4?G!9?_oo_!11?@?C!14?MMA?G$#71!177?A!20?G@???ACC$#72!50?A??@!21?GK!7?_o!7?C!10?A!7?C!4?O!55?A!19?O$#73!23?@!96?O!50?@??C$#75!95?A$#78!193?_$#81!208?B$#88!177?_$#89!202?A???C??C?A$#90!175?AK$#92!177?O$#93!175?@??o$#101!201?A$#103!195?_!6?@$#104!92?_$#106!49?O_?G!15?AE!59?BA?@??C!6?G???BOWW$#107!179?G!23?@$#108!180?B$#109!96?_!11?__!71?D!7?@?@@$#110!53?___g??ECAC!4A!74?AA??C$#111!50?OwoWW[C?@O?@OKLLDFC?A!59?@BAA@@DEACCDCKNJKL$#112!56?O??@GG!8?C???A!14?__oOO?O?WWGW!5GWWWO?O?___!17?C!7?G!6?@?A???G!25?_!23?@!5?@$#115!97?_!84?_!5?__$#122!61?_!15?A!28?C!10?_$#123Cao_!11?_$#124!47?O!28?A!22?C???CCC!38?O???_$#127!196?A!7?A!7?@$#128!198?B!7?@$#129!178?C!20?C!7?o!6?@$#131!97?C!57?G!37?G?A$#135!75?A!34?_??O??_!13?CC!8?G!4?O!34?C$#136!182?DGLME?@KFAA$#137!186?O$#138!181?G$#139!182?GU??_$#142!196?G?C?@$#143!196?_$#145!49?G?C?A?@!4?_!10?C!15?_!5?G!6?CCC!7?G!14?@C!24?A?C$#147!48?G?C?A?@!14?G!4?C!13?O!7?C!45?O!11?C$#149!106?_$#156!177?@!19?K$#157!46?_!20?G!59?CCC!49?@?O$#158!98?_!8?_!79?@O??C$#159!185?@$#161!57?O!5?O!15?@!8?_!4?_gGW!4?!5O!4?O_o!19?C!23?O_$#162!206?A$#163!179?O!14?_??_!11?B$#165!178?A$#167!68?G???C!16?O??G!5?C!39?G!52?O$#168!207?A$#169!78?A!12?G!15?C!7?O!8?A!11?G!10?_!4?A!4?O$#171!64?O!49?O!10?C!13?G!9?@!57?@$#172!111?G!82?C$#173!100?!6_!80?@???G$#174!47?_o_!7?AOG??G!5?@@@BBB!5@!15?O!4?O!25?ABBB!17?OAEEos{woo_$#176!205?@!5?@$#179!65?O!14?@!56?G!5?O$#181!189?O?GCAB@$#184!90?O!18?G!39?_$#185!62?_!32?C!12?C???G!78?_$#186!46?O!18?__!8?C!5?@!12?C???A!9?A!14?L!8?GGG!6?O_!8?@?A???GoO$#190@@!8?@!5?!5~$#191???@!7?b_~$#192A!9?}$#193!199?A!13?@$#194!179?_!15?G!11?Cg$#197!193?C??@$#198!21?@!51?C!116?_$#201!195?O?O!4?CC!6?A$#202!86?_!48?G!14?@$#204!94?A!32?O!48?_$#205!176?BK$#208!178?G$#209!175?CO$#212!194?O!13?S$#213!196?C$#219!124?@$#220!90?G!18?C!82?_$#221!23?o!18?A??Y???A!14?_!4?_??_!7?A!8?G!19?A!4?CI!9?GGG_G?G!4?_?O!4?___!8?A???G_!13?@$#222!22?@!95?O$#223!22?C?!18~@@D@FF!5@!14?_o!6O!4ow{}}~^NDNNDBB!5@B!14@BB@D@DFFN^OooO??!4O??OOO!15?@?@@FBFF!10~po{wo_$#228!51?A!64?A!13?G$#234!57?@!122?O$#237!192?O$#239!22?A!40?_!22?OO!4?C!17?CC?G??O!77?G$#240!22?o!54?CGC!16?A!4?AAA??A!4?A!7?O$#241!195?C$#242!100?A!73?A$#245!174?@-#10!54?@!129?_$#15!190?C$#20!191?O$#21!193?C!12?G$#24!85?G$#26!45?O!109?A$#28!88?GG!9?O[$#29!85?O???C!20?A???C!5?G!66?__$#35!112?A$#38!4?!4~l@!182?@$#39??}}!6?c}$#40!180?@!11?_???@!8?O?@$#45!21?~$#49!184?C?C$#59!188?A$#63!77?_!6?@!42?_!28?C$#66!77?G!5?@$#67!23?w!18?I@???_oo???GKK?AG?@??!4@!4?@??@?O?GC?B!42?CDG?_?_?@??@??@!10?@??G?CG???G???__?_!10?O_$#69!42?_!9?oO?OG!17?_oG!49?@@?_?___!15?K_IOW??GwGO!8?!4_?__?GGW_$#72!122?@$#73!22?~?O!32?G!69?O$#75!159?C!17?@$#76!179?O$#84!180?_$#86!178?A$#87!179?G$#88!178?@$#89!193?O$#91!179?CO$#93!179?BCW$#103!182?G$#104!80?_?O??C?A?@$#106!50?A??@!103?A$#107!183?_!9?@$#108!82?_!4?C???@!24?A!6?O!61?OOGG$#109!84?O!4?A!23?@!4?C!68?O$#111!52?@??@!126?A$#112!49?C!29?_?OGGCA?@!28?@@AA?CGGO!28?@!27?A!9?A$#115!44?G!138?B?_G$#122!48?G!72?A$#123}~@@!6?Z?}$#124!50?C??A!31?@!38?G!33?A!31?G$#129!193?G!12?CaB$#131!83?A$#132!181?@?O$#133!182?C$#135!45?H?G!4?A!30?O!30?@!6?GC$#136!86?G!97?@@`$#137!87?_ooo!5w{{[k_w!4oww!4o$#138!83?__?OWC?GCDCCCAAaAAE!4MEEMMKK{{wwo_o___$#139!85?__!30?O?O$#141!90?C!4?A!15?A???CGGG?O?_$#142!191?C???_$#145!44?A!33?_???C$#147!150?@??A!4?D$#149!112?@$#156!192?A?@$#157!125?o!26?@!29?@C$#158!184?A??@O_$#159!94?A!21?C??G?OO$#161!44?O?C!33?O_?CG?F?B?@!24?@?A??C!35?A$#162!191?G??O!13?G$#163!181?CO!7?A???A!9?_$#167!79?O!39?@!31?@!36?C$#168!193?A$#169!43?S??O!4?C!71?C!60?G$#171!57?@!133?_$#173!90?A?AB@!4?!10@!4?A?A?C!5?__!60?A???O$#174!44?CAJFFB@B!102?!4@$#177!184?O$#179!154?A??C$#181!91?A???!4@!10?@@@??A!70?G$#184!45?C!10?@!24?G??A!33?@CA!5?_$#185!44?_!4?G!76?O!62?@@$#186!43?a?_?O!4?CC??A??@!63?AAG!26?AC!5?B$#189@!7?Q!4?}$#190!14?]!6~$#191!9?}?@@@$#192!14?`!174?C$#193!180?A!11?O!15?C$#194!182?_!9?K$#197!188?@$#198!54?A???@!21?G$#200!185?CA$#201!193?__@$#202!43?G!11?A!25?C!107?A$#204!46?_!5?G!21?GG!100?@AC$#213!180?G_$#214!187?C$#217!187?A$#220!78?O!79?_$#221!23?F!18?S!7?w!10?@!7?@@?@@???CC?A?@!45?!4@?@@?@@!7?@@@!7?C??O!17?o_$#223!24?n!17~@!8?w?_o_ooo!8}~~!5}UFFBBB@!42?@@AEE!6]!5}!6~}}}~q]s__ooo???~~~^^~^~!4^~^^~EC$#227!44?@$#228!159?_$#234!183?G$#237!189?G_$#239!56?CC!19?O?GC?A!37?@@A!67?O@$#240!58?E???@!13?_!50?G!24?C?G-#6!184?@$#7!193?C$#8!194?A_??G$#11!185?A$#14!195?S??O$#21!192?A!13?O$#24!91?A?A!18?WC@$#26!187?O$#29!79?GAA!6?WG!33?@ACCG!58?@BIMw$#38!4?!4~^^$#39!4~!6?^!4~_$#44!21?W!106?A$#52!155?O$#56!157?_!8?GCG$#62!192?C$#63!172?C$#65!43?_??O_!109?G!8?O?C$#66!28?_!45?O!55?GOG!25?_!4?@A@!6?G??C$#67!29?O!5?_!7?GG!29?A@!52?@AE@__!18?KCB!4?g??A???_@!7?AC?_b$#68!169?O$#69!29?GWW!4?_?_?_?G???C!27?@!55?@GFF!15?G@!5?@@KS??@!7?A?O?@@??S[$#71!196?@A???O_$#72!22?_!158?C$#73!22?EJ!20?@???_!131?[O$#75!192?G$#78!182?O$#87!181?A?_$#89!200?G!6?@$#90!182?C$#93!182?BS$#95!183?G$#103!196?wo__$#104!78?A!11?OK!37?_$#107!194?C$#108!77?O!12?C!21?C@??@!10?C$#109!89?_!4?{!16?_A!15?_$#112!75?_WE@@!34?o_!12?C!57?G$#113!185?O$#115!187?Ko?C$#120!192?@?H!5?_$#121!197?K$#124!75?GA$#127!184?G!13?AC??O_??G$#128!184?C!11?A???O$#131!21?_!168?@$#133!185?K_$#135!75?O??CA!12?w{!18?__A?o!11?O!56?@$#136!77?_W!47?G!61?Do$#137!79?O_!6?@@BB@???!16~^!11?C$#138!79?c[||~~[Z}eS??@@B!17?@!4?!6~Y{woo$#139!78?_???A??ac!36?_$#141!85?@!39?A$#142!201?G$#145!77?@!35?G!16?_!55?C$#147!43?Oo?_!80?@!26?K!11?A!6?GC$#148!190?A$#149!191?O$#151!195?AC$#156!203?@$#157!113?Q!13?A?G$#158!189?@?_$#159!124?@$#161!76?cG!13?oE!21?G@E!11?G$#162!199?GC???@??A$#163!185?_!7?O?@!9?_$#164!199?O$#165!184?A!8?A_$#167!186?A$#168!198?C$#169!74?_!54?C!35?A!7?CG!16?C$#171!183?@!13?@$#174!90?_!24?]!13?O$#176!193?G?G!5?_$#181!125?@$#184!80?@!9?G!23?C?G!70?_$#185!45?O$#186!76?@!55?O!20?G!11?G!25?A$#190!8?__!6?!5~$#192!10?_!4?^$#194!184?_$#197!126?B???O!60?G$#198!21?F$#200!156?O!9?CG!6?O_$#202!75?C!116?O_$#204!34?_!10?@@@!122?K$#205!184?O$#208!183?A$#212!181?@$#219!155?_!9?C?_$#220!31?_!15?O!107?A!10?@??GO@$#221!37?_!4?O??KGK???___!79?W!19?O?@?E!7?o??B@@}Aa??W_$#222!22?@S!51?A!53?@!34?@!15?@G_$#223!24?!4~^FFF~~!5^~^~fFEAAA^~~^^^!18~^^!57?E??!15~v}~rb_???RB~~{{{!4?E??`@A?B^J?__$#227!29?__!123?O?CO!9?A??_??O?G_$#228!156?A$#233!193?@O$#234!186?O$#235!168?__$#236!155?G_!10?OO$#237!45?_!109?CG!17?_O!16?_$#239!22?O!108?_$#240!22?G_!48?__K!88?A!16?A$#241!191?@$#244!182?G-#0!195?C$#1!206?O$#9!201?@$#10!187?@$#14!196?@?Go!4?GO_$#21!195?_$#24!116?B!12?C$#28!128?Q$#29!77?|!10?U!100?ADF$#33!21?W$#38!4?!4~$#39~~~N!6?Cv~~NN$#44!131?C$#45!22?_$#55!32?G$#56!38?C!118?@$#62!194?C$#63!22?C!27?_$#65!32?OA?G!8?@??GO??O!119?A??@?GE$#66!28?B??G!17?_?G@@!18?_C!84?@!18?@$#67!31?O??@!10?O??_!4?_!18?YX!58?_@!24?G!6?O!8?OO?OWW?OO$#68!29?@!7?A$#69!26?o???G?_!6?@A?S?CC???@??A!18?@!61?A!20?Q^???B!12?DE!4?A!4?_$#71!203?@BA??O$#72!22?@O!49?_!110?O$#73!23?@p!27?o!19?D!59?@!32?AQC!14?A]$#78!184?C$#89!206?CGGO!4?_$#91!185?G_$#92!185?C$#103!197?FFNM?Poo_?O$#104!113?__$#107!186?@G$#108!76?E!12?@!4?{!16?w!4?[!12?w$#109!94?B!16?F!4?_$#112!75?B!37?O!16?q!57?C_$#115!188?@K$#120!196?A_??_?_$#121!195?G??_???AA!4?_$#122!74?@$#123???O!5?C!4?O!6?C$#124!74?A!56?o$#127!22?O!187?O$#128!186?AO!18?G$#129!211?O$#133!187?C_$#135!76?G!12?E?}~~!18?o@?{!13?A$#136!128?k!61?A$#137!82?!4o}s!7?J!14~B!6?_!4o_o_$#138!77?A~~~rNNNM?JH!6?s!14?{!6?^NNBN[K^~~~@$#139!81?K???@@?_!31?K?BB$#141!191?G$#142!187?_$#143!202?G???A$#145!74?{$#147!34?G!10?@?@AOG!106?A!11?C!5?A@!16?[$#150!207?_$#151!196?{O???_???G$#153!198?O$#156!195?O!5?G?G$#157!112?N!75?AO$#158!189?@wo$#161!75?{_!12?ww!22?M?@!13?@$#162!201?O???C???G_$#163!200?O??C!11?_$#164!197?G$#167!131?G$#168!186?C!18?@$#169!31?A?O!141?@E$#171!194?A$#174!90?F!23?^!15?K$#176!194?@!5?@EC?C!4?_$#181!30?@!161?}$#184!76?P!14?@!23?A!14?@$#185!131?A!61?a$#186!177?G$#189!8?{$#190!9?B@!4?_!5~_$#191!9?wwG$#192???_!4?B?A???_O!5?B$#193!212?__$#194!185?@$#200!34?_$#201!207?C???_$#202!22?G$#204!40?@?_!113?OW!14?A!6?B$#205!185?A$#209!183?@?_$#212!184?A!9?W$#213!184?@?W!7?_$#214!192?@$#219!37?_??_!127?A??C$#220!29?AC???C?@@@?O!5?C?@?C@!104?A!13?OO???K$#221!27?O?K!4?A?_??E?O?BA??O???AKW!78?O!21?@??CE!6?@?@[??@WXA?O?@??LK?_$#222!165?CKW!16?G$#223!24?M~Nn{oo_?@!6?KNJ{wgw_??BC?E!17~}!61?{!20~k_c_o{!5~_`__o!4_k___cc~a`$#227!32?@_?UO?AG!129?G?G$#228!41?_???A???A!117?A$#233!195?B$#234!187?AW$#235!32?CG???Ow_!128?@BE$#236!34?O?CK?O!6?@ACG$#237!30?ADAC?_A!9?ACGCO!105?@!13?G$#238!36?G!133?@$#239!22?Aa!107?@G!60?@$#240!23?K!11?@!15?_!21?A!58?E!32?G$#242!156?G$#244!185?O-#0!194?O!15?@??A?A?CC???GO?_$#1!197?@$#3!201?A_O$#5!198?ssww@G_$#7!190?O?_$#9!203?E$#11!190?G$#14!203?@O!5?A???C!6?O$#17!77?G$#21!195?@!27?A$#24!92?GA!21?B$#28!94?C!17?_$#29!80?_!7?H!37?cAE$#31!222?A$#33!4?O???A!13?O$#38!4?N~~~$#39~Nb!5?ooq~ppo$#40!188?C$#44!22?A!108?A$#45!23?_!51?O$#59!192?C$#63!23?G!12?@!93?_!62?A$#65!35?A$#66!33?@??A??C?@!31?@$#67!26?B!10?A?GGC@!8?AA!19?AAg!56?_QB!52?o$#68!38?@$#69!26?_!10?LC??IG!89?_$#71!193?CA!32?_$#72!23?C!48?@?O$#73!24?N!7?@!16?A?@!80?G!52?E$#76!186?A$#78!186?C$#89!223?C?G??_$#93!187?No$#103!204?N~~~}}{{{|!4wo?O??g$#104!77?O!11?A!23?B$#107!188?@!31?C$#108!77?A?_!9?_?_?C!17?BGG?C!11?_?@$#109!92?O?@!16?C??G?@!11?G$#112!75?B]__!10?@!38?_WF$#113!191?_$#115!190?@$#120!208?@???@??C!6?O$#121!195?A!15?A!4?A?G$#122!22?C$#123?o?o!5?@K?MA$#127!218?@!5?C?G$#128!188?A!4?G$#129!214?@!10?O$#133!189?C$#135!78?O!12?VF@!18?F!16?A$#136!128?@$#137!82?BNNFr`_!4?Ow}!14~wo!5?n!7~$#138!77?@JJN~{oowK]A???_gA@!14?FGOoow}!8?~Z@$#139!88?O!28?O$#141!78?CSO!7?C!38?[$#142!224?G$#145!75?G_!113?A$#147!39?AA!150?G$#148!191?A$#150!194?_OM$#151!196?@!14?@!7?G$#152!214?A!5?GG$#153!193?_?K!13?@!6?C$#154!197?ABAB@$#156!221?C!4?_$#157!91?G!38?G$#158!191?@$#161!75?C@!12?[~!22?CF!14?C!60?C$#162!218?A$#163!219?@$#164!199?@!12?A$#165!189?G$#167!74?@!55?O@$#168!227?O$#169!35?@!155?C$#171!189?_??O$#176!189?O!4?C!22?A?o___$#179!74?A$#182!198?GG$#184!77?C!50?O_$#185!192?G@$#187!195?__w!4?O$#188!200?CCM_$#189!8?@!4?K!8?g$#190!4?_???CK!4?KN!6~$#191??[!7?@$#192???N!4?GA!4?Bo!175?O$#193!188?G!27?@@??AA!4?O$#196!197?C$#198!22?@$#200!192?@$#201!215?@???A??C$#202!23?O!107?C$#212!186?@$#213!194?@$#217!192?A$#220!38?A!35?C$#221!32?AAA!5?C?A$#222!23?@!25?@@$#223!24?o~[!5~!5{owooos!5~}{}{{!19~{{!59?{!51~w$#226!196?O$#227!34?@$#229!187?o$#233!190?_??OG!24?C!4?o$#234!189?B$#236!39?@$#237!40?@$#239!75?_!55?G@$#240!23?A!24?@???@!78?OC!52?@$#241!186?G-#0!191?O`!35?CGO$#1!193?B$#2!194?E?@!6?@??C!8?C?C$#3!196?{!25?_?_$#5!195?_??!4~{{sqw{!4oww{ooo?!4A??_$#8!227?C$#9!205?@A?C??CCC!4?A$#14!209?CC!5?A!7?C?O$#18!190?C!36?@??_$#24!90?P!5?G$#28!89?A!17?CC?@!12?A@$#29!80?@@A!10?G???CC?C???CCC!11?KCCC$#31!231?ACGO_$#38!4?w~~~$#39~~ww!4?FF!5~w!7?_$#40!227?_$#44!23?@!54?G!50?@$#66!25?_o!52?_!45?_G?C$#67!25?C!48?@??_!49?_?GF$#69!75?g!50?_!4?BBB$#71!228?@??CGO_$#72!24?AW!52?_!50?E$#73!24?@BG!47?A@!51?O!58?C$#75!187?@$#86!188?w$#87!188?C$#89!229?@A$#91!188?A$#93!188?@O$#95!189?g$#103!207?!9B!4@???A@AC?A$#104!101?GG!24?@$#107!229?C?O_$#108!83?G??OOO!6?G!14?G!9?G??C??@$#109!89?@A???G!7?CC!7?GGG$#112!77?@BEKGO__!6?___oo!7OW!10O!5_OOO?G?CAA@$#115!81?AC$#120!190?A$#121!217?A!7?G!4?G$#122!22?GA_!103?A$#123???@!5?g!12?oO$#124!80?O!19?_!4?_$#127!228?_$#129!190?G$#135!85?O???O?O!5?_!10?GG__!8?_G$#136!109?C!9?G$#137!85?FFFB!4C@@B!7@B@@!4B?@!6?@@?@@@$#138!82?@BNGGGKGGJJEE?!5AEA?AA!4?EA!6FAABAE?A@$#139!111?C$#141!83?C!11?CC??C!14?!4G$#142!190?O$#143!229?_$#145!78?C???_!15?_!8?___!11?_?O$#147!124?O$#150!219?C$#151!192?EG!31?@B$#154!193?sW$#156!226?_$#157!126?C$#161!79?@?CG?O!8?O??_??GG???GGG!5?__!5O_??W?K$#163!230?@$#164!228?G$#165!191?@!37?O$#167!81?_!19?!4_!17?_??G$#168!189?@$#169!76?@C??_!46?C$#171!77?A?G!19?_!6?_$#174!83?O?!6_$#176!206?@!13?!4@ACGWO$#182!195?L?B!5?A!15?OO??KG$#184!80?AO!10?O!4?GG!8?G!17?A$#186!24?C!51?AW$#187!195?QAo!6?IK??GG?G!6?o__?GO$#188!194?_??K!4?B?@!10?GGG!5?_OO$#189!8?w$#190!16?!6~F$#191??FE!19?K$#192!4?F!4?O!5?F$#194!189?A$#195!194?@!21?C?CGK?C$#196!210?G!7?G??K$#198!24?O!54?O$#201!229?ACGO_$#202!24?G!53?O$#204!75?C!111?A$#205!189?C$#208!190?_$#221!76?K!53?GC!54?@$#223!26?F!47~{Qo!51?woow{{!52~y{$#226!221?oO$#233!190?@mW!34?A???_$#237!123?_$#239!124?_$#240!125?OOG-#0!233?A??O$#1!208?_!8?C$#2!206?_???GK??K!12?_$#3!194?O?L!25?_!6?_$#5!195?P??!4~BBRBBbNBBBFBBF@??@!5?OG??C?O_$#14!218?C!6?G!5?KSH$#15!236?GO$#21!191?C!29?A$#31!237?A$#33!92?_AAA!5?@$#38!4?F^FF$#39~zrr???oq}!6~!6?w~!73?GOSS[SOKKWWO$#40!226?C$#44!87?_!21?_$#45!25?@!60?_!23?_???O$#63!81?C$#66!123?@@$#67!28?Wo!50?A_?_!31?_??_???CC?@$#69!30?Cc!48?_!42?AEE!60?__$#71!215?O!18?@ACGO_$#72!28?_!51?GW!34?O??W!68?_$#73!44?!4_!32?D!35?__O$#81!235?@$#90!189?O$#92!189?C$#93!189?B$#94!189?G$#95!190?G$#96!213?_???O!5?AAA$#97!229?@$#98!215?_$#99!222?C!5?@$#101!220?CO???@!4?@$#103!191?@!31?@???C??A?Goq_$#107!235?C$#113!238?_$#121!213?O!7?_?O!6?CA$#122!24?AA_!55?BEMC!4?A??_?!4_???@?!4@`!5@KMAEFB@@$#123!4?w_w?L@!12?F?_C!64?__!4?[OC?_aabQAEEM]WW$#124!84?@$#128!231?@!6?C$#129!191?G!22?O!7?O$#131!26?G!55?CG!4?AA!26?G???A$#135!88?@@@$#142!191?_$#143!212?_!4?G!4?A!5?A$#145!85?@@@???@@$#147!111?_!9?A@$#150!212?W$#151!192?@M!28?@!10?C$#152!192?o!41?CG?_$#153!193?_!38?A$#154!193?@k?A!13?_O???GC?AA@@??O???c$#155!230?__$#156!211?_!4?G!12?A$#162!219?C_???G$#163!191?O!32?@!11?@$#164!220?A$#167!94?@!20?@@$#169!26?CO!89?G?C$#171!93?@$#176!191?A$#179!27?_!53?@!31?O$#182!195?g!6?SS!5?K!20?G$#185!82?G$#186!26?AG!54?OO!28?_!5?G?C$#187!195?E_B!4?gGCSCCOO???K???@!8?_??OO$#188!194?B?O{!5?_g_WW?_S!5?AA@!4?__??GG$#189!24?Ww!57?@?AAA???AA??@!16?AAB??@$#190!16?!5~F!63?GW!8[KBBB@@$#191?CKK!20?D?O!71?GgG?GK_o__??EE[K$#192!7?G!13?w!63?OC?__!4?_O?C?AA!15?C$#193!238?GO$#195!225?_OOOG$#196!205?G$#198!81?A??O$#202!85?_!29?O$#205!190?s!27?G_???G$#206!190?B$#208!236?AC$#209!188?B$#212!189?_$#221!27?C???O!81?_!7?CA$#222!26?@!161?S$#223!27?BFNrB!12~!4^!32~??_!31?_!4?_!6w!60~^^$#228!30?GG$#232!214?_?o_oWWKGCCCBB$#233!192?MO!38?@?GO_$#239!117?O$#240!80?O???_!103?G-#0!193?A!26?_?OOG$#1!194?Ac!9?A?@!10?_$#2!199?CC??AA!11?C?A?G!5?@$#3!210?_!10?G$#5!197?aJBBB!13?G$#6!228?O??_$#7!227?A@$#8!232?@!6?C$#10!229?O$#13!228?G?AO?_$#14!201?G!15?A?@!16?@A$#15!43?_!148?_$#18!238?G$#20!229?_$#21!209?@!15?_$#26!48?_$#31!207?A!6?C?A!6?_$#39~B??!4{~~f~BBB!6?_~~A}$#40!208?_?O?G$#44!28?A$#63!90?@!15?@@$#65!39?_!7?O$#67!30?CS??___???CC!4?AA!39?@@?!4A?!9A!4?BBA$#69!31?B??OO?O?S?O!4C!4?S?OC!6?_!23?@A?A!23?A!6?@!67?FN$#71!191?A!34?__$#73!43?B!15?O!28?A$#82!189?O$#96!190?BO!9?_??GOC???CG?C???@$#97!205?G???A$#98!203?oo_OOKK!4?@@$#99!212?@$#101!203?G!4?A$#102!228?CKKK[[wwooo_$#103!206?A??_?O?G?C!18?@AA?C@$#106!44?_$#107!192?O!33?O$#110!232?aA?C$#111!45?__!181?A$#112!47?_$#113!236?CC?G$#120!192?G!15?@!12?_!11?@A$#121!225?O$#122!26?B@?O$#123?{?{?BB!6?!6_?_O??@$#128!204?C$#129!198?_$#132!192?@$#142!228?_$#143!199?_O!4?C$#145!42?_$#147!30?_!9?_???O!4?_!44?!12@$#150!195?GwOO$#151!220?O?G?C??@$#152!193?{!31?G!12?@A$#153!193?@{O!23?_?O?G$#154!194?@!7?C??@!6?O!4?_??@??C$#156!222?_$#161!227?C!9?G?O$#162!202?G!15?@!5?_$#164!203?C!15?O!6?A$#165!192?C!31?O!6?@$#169!46?O$#174!227?G?AOA??C?G$#176!199?O!35?@$#179!41?_$#182!196?CC!15?o?oWS$#185!29?C!61?@$#186!30?O!54?@???@$#187!195?BB!17?w?_GKM?EBB?@$#188!197?@?GGC!4?@!4?__!5?O??@??BA$#189??{$#190!13?[[[!5^!5?K}{$#191??BB???B??W?_!11?{@???_$#192!4?B!7?[??B???_?N!4?o$#194!191?C$#195!197?GC!21?E$#198!29?G$#201!191?@!18?@$#202!28?@!63?@@$#204!31?_!6?GGW!7G!4?_!6w$#205!201?O$#206!190?[g$#212!189?B$#213!190?_$#220!43?O$#221!37?_S!9?OO_sK!33?A!7?A!9?!4A$#222!29?AG!13?!4@!140?N_$#223!30?B?~~NN^N!4BR???CCNNJJBB!5FN^!23~}!27{!6~}!67~wo_$#226!202?B@@!17?C$#228!38?_$#231!216?@$#232!200?_?o???gkOOIFEBAA$#233!192?A!32?C!11?@A$#234!226?KO?@`$#237!45?O$#240!29?@?G!12?AA!13?_!26?@??A!20?@@!76?O$#244!189?K-#0!193?FA!11?_??OG?C??A?@$#1!205?_???G!6?@$#2!210?@A@$#3!208?@C$#5!198?_!7?GA?@$#6!233?@$#7!239?G$#8!194?C!32?A?G$#9!196?@!4?G$#10!36?C?A??@!6?@??A??C??G!176?@?A??C$#11!15?__!14?__?G??C!21?O$#13!236?@?A$#14!194?OA???O???C!26?_$#15!43?@!188?@$#17!44?@??@$#18!14?_!219?A$#20!192?A!43?C$#21!192?o!27?@!7?G$#30!36?G$#31!195?CAN!12?__oooWW[KEEB@$#33!20?O!9?C$#38!33?_$#39B??MnNFF@N@@?@@B@?!4@n~{~$#40!195?w{ONNE???A!11?_!8?@A$#44!30?@C$#63!31?A!4?@$#66!61?_$#67!35?@!24?GACK$#69!32?@!27?@?@$#71!200?@!16?_??G!7?O_@Aa$#72!32?A$#73!31?@$#75!57?_$#86!36?O??GO_$#87!34?_$#88!35?_?O?__$#89!218?_OOGKA??Gg_@A??C??G$#92!190?{$#94!36?__oO$#96!202?AA!28?GG!4?_$#97!236?O$#98!202?@@@!32?_$#99!234?Oo_$#101!201?A!17?__oo{}}sO!5?_?G?O?_$#102!237?@@B$#103!194?_!12?@??O!6?A$#106!39?A!16?K?G$#110!55?C!181?A$#111!35?G!14?A??C$#112!40?@?@$#120!230?O$#121!194?G!17?G!6?@!6?@!4?_$#122!19?e!7?Sc{QGK$#123CNCP!8?@?A??P???[O???A???G$#124!13?_!24?C!7?@!4?C??G$#127!237?G$#128!192?K$#129!197?_!13?O!6?A$#135!35?C!9?@!9?G$#142!206?@!12?G!13?A$#143!201?C!16?O???A@???@AC$#145!30?_!8?@!14?A???O?_$#147!37?@!15?G!6?O$#150!199?_!4o_!11?A$#151!207?_???C?A$#152!208?O??G?C$#153!194?@@!11?O!6?A???@$#154!204?SOQ?G?C?A?@@$#156!200?G!12?G?C!22?G$#157!34?O!5?A!16?C$#161!52?C!6?_$#162!198?O???C!6?_!4?G_C!10?C???@$#164!214?C!13?C$#167!31?O??C?A!14?@$#168!235?C$#169!50?C!4?A??C$#171!33?G$#174!49?@??A!182?@$#176!192?@!12?A??_!20?O$#177!17?_!14?O!16?A$#179!35?A??@!18?O$#182!207?C???@$#184!37?A!12?@??A$#186!42?A!16?C$#187!205?G?GAAA$#188!202?G??CC!6?@$#189??p!5?O!11?__!5?_OB???C$#190oo???ooo_ok}}M??MM]WG!6?BB$#191??I_O???M!9?_?AA??B?{GG!12?A!6?A!10?G$#192G!5?GG??Q??O[[O???C!5?@$#193!228?@AC?S?C???O$#195!204?G$#196!203?G!4?C$#201!221?C??@!5?GO!7?O$#202!34?AO???C!16?O$#204!43?AA??AKKGWW?`p`BBBE$#205!231?K??G$#206!191?~$#211!41?CK{{}}{ooo__oO$#213!190?B$#219!52?@$#221!53?@!4?_??G$#222!189?~$#223!33?@!27?Tyr!125~$#228!56?A$#229!38?G?KW$#230!42?o$#232!201?@???@!27?O_$#233!193?w$#234!33?O!201?A?CC$#239!33?A$#240!34?@$#241!37?G-#0!193?D!9?A$#1!199?_O??@$#6!12?A!4?@$#8!234?G$#10!18?@A!47?_$#11!10?C!12?_!4?AA!30?A???C$#14!195?A!39?_$#15!24?O!4?@!36?O$#18!5?_??G!8?A$#20!10?O?@$#21!192?@!7?_O$#26!63?GG$#30!9?_!47?_$#31!205?A?AfNJFBA!18?C$#38!7?G!22?A$#40!195?@!10?A??O!25?G$#41!212?C$#44!189?_$#45!12?G??A$#65!61?_?_$#67!63?B???A?D!100?O!10?C!4?OGW$#69!61?@@?@!112?C$#71!190?G!20?G??A!15?_??@AC?_$#73!69?A!95?_!13?G?G$#75!189?@$#86!40?@@@??_!7?O$#87!27?OO?CA$#88!32?wbbabBa_aikGW?[G???OO$#89!209?_oow{{}~!4}!8~xO!5?G$#90!27?_?W?G$#91!30?G$#92!30?oo!158?@$#93!28?__?C$#94!26?_!5?E!5[\^[SOo$#96!239?_$#98!235?@$#99!236?@FN^$#101!217?!4@!8?EM[G$#103!192?O?B!8?C!28?@???_$#107!7?O???G!180?_$#110!66?G$#112!21?w!38?@??C?C$#113!11?A$#120!231?@???O$#121!204?A$#122!18?C??Ba[KCA@!31?G$#123!6?G!16?@?@$#124!13?C??A???O!7?@!30?@C!5?_$#127!231?_?_$#128!14?A!44?O$#129!233?G$#131!22?O$#132!9?O$#133!8?OGG??A@$#135!26?C!40?O$#142!190?o$#143!191?o!23?@!15?A_$#145!9?C!9?@iC!5?I$#147!58?_A!4?AO$#150!195?[}]^^@D$#151!194?s!37?A$#152!193?o!8?C$#153!194?G_?__?MIB?@@$#156!192?E???@!5?G!30?A$#157!56?_?O???K$#161!65?G$#162!201?_ow{{{|W?C??@@$#163!10?A!15?O$#167!61?C!4?C$#168!191?G$#169!68?_$#171!6?O!227?C$#176!192?G!13?@!27?O$#177!19?C!8?C??@$#179!57?O??OA!5?G$#184!25?G!34?GG$#186!13?GGG?G!41?_!4?_?A?KG!118?_$#189!22?@???@$#190~~}^~NFFBB!15?A$#191!20?@!4?_!29?_$#192??@_?O??C?@@!10?KAB$#193!232?OO@ACO_$#194!191?A$#195!197?@$#201!191?C!38?@???_?O$#202!11?O???CC!12?C??@!156?O$#204!11?_ooOOosWW!27?__!4?@`H\MF???A!124?O$#205!237?GO$#206!191?@$#208!28?G$#211!14?__??_!26?@`@FfnFFE]UA$#213!190?E$#220!68?O$#221!60?_!4?A@C?_$#222!166?!5_!8?CG$#223!65?@?@?O!95~^^^NNN!6~zzrrr!4~nfF$#228!58?GC?OoOO_$#229!53?_$#230!35?@?_!4?AFf]AUWWOggG$#232!236?A$#233!193?I!39?C$#234!6?___??CC@?@@?A?C???_OGC??@$#240!168?OO!8?C?C!8?K$#241!10?_???C?G!51?A$#242!19?_!37?@!10?@!120?A-#0!193?O$#1!194?B@$#5!211?_$#8!237?A$#9!197?A!12?_$#10O!20?A!21?O!115?_OGGG!4?CC!4?G???O?O??_$#11??CC!11?__?GK??B!48?_!98?C?G!4?O!9?_$#12!47?G???A$#13!45?GC$#14!193?_OGC$#15!18?O!163?O$#17!43?G?E?CE!122?C$#18!7?@$#21!224?A!4?@!4?@?GO$#24!47?A$#26!51?C!115?I?G$#30!49?G???A$#31!218?C!7?@$#35!48?@@!114?O$#37?_??O!41?@$#38G??@$#40!191?A!18?C$#44!188?GG$#45!19?O!19?_!133?O$#65!63?_?OKg__$#66!73?_$#67!71?CC?c!75?__??OWC??C?@?@?@?@???@@!9?@G$#69!70?B?J!81?G?BB??B?A!15?C??@$#70!71?@!110?A$#71!210?A!10?A$#72!185?@?@$#73!180?@$#75!19?@!32?O!111?@!4?@OO!5?@$#76!9?A!29?O$#77!176?__$#86!6?[e??C??_!32?_!123?__$#87!9?D!4?O!28?A@$#88!7?WGgWO_?C!6?_WOOLS_??__NFFFfaDFNF!5?_!124?__$#89!210?@FJBAB?@BBB!4@!13?@$#90!12?OO$#91!27?GO$#92!27?FN^NN$#93!43?@$#94!9?O?_!8?_?_kiajO__OOowwgWGWG??B$#101!212?!4CBA$#103!212?_$#104!46?G??A!110?_O???G$#106!17?O??C!23?O!25?O!95?CC!7?G$#107???A@A$#108!68?@$#111!165?C!7?G!12?_$#112_!15?O???A!27?GCC?A!111?C!11?G!5?_$#113!191?G$#115!163?O!21?O$#116!46?A$#120!236?@$#122!52?@!17?GO!86?O???C!24?C$#124!4?C!13?C?G!23?A!8?@?@!118?O$#127!8?@!146?_!34?G$#128?G!173?O!55?G!4?A?A$#129!191?C!6?A@!8?_?O???G!5?C!7?@!6?BC?_C$#131!186?GWSO$#132!4?A@!186?_$#133!6?@!184?_$#135!158?_!24?O$#142C!189?B!22?G$#143!191?@!25?C!4?A$#145?O!15?_??@!46?A??_!102?C!4?G?_???O$#147!5?O!34?O?G!7?G!21?_!84?O?G!18?_$#151!193?E!44?CG$#153!193?HKEB@$#156!211?OO__wgOwgw!4{!5}~v~~}{oc$#157??G!14?G!28?O!7?@!14?O!90?G?OC!6?G?C!8?_!8?_$#159!47?@??@@!109?_$#161!188?__$#162!194?_ow{{}!8~^]G!8?C???A???@!9?GO_$#163!6?A$#164!198?@$#165!191?O@$#167??A!11?_!151?A?I!10?G$#168!15?O!7?A!166?S$#169!41?_???@!22?O!92?C???A?O!7?C$#171!43?_$#172!42?O!114?_!28?O$#173???_!158?___o_$#174!21?@!22?KO!4?A!16?@C!95?G!16?O$#176!209?_???OO?Og?O!17?@GO$#177!21?C!137?O!16?OG$#179???Wg_!13?A!20?_O?C!23?C!88?_!11?_A$#181!166?O$#184!68?IG!96?G!4?G$#186!5?G_!11?_!19?_!6?_!8?A?@!99?O?G!4?A!4?@!12?G???C$#189?C$#190BB@!185?AF$#191!44?_??O!126?C!4?_$#192!24?@$#193!214?@!24?B$#197??o!66?C!97?_$#198!180?G!4?GCA@$#201!209?@?G!4?C!8?@$#202!16?G!35?C!117?A!13?G$#204!18?A!22?G!11?KSUK~f@!11?A!88?C!8?_?A?A!5?C?C?E$#211!11?!5BFF@!31?Oggoggo$#219!42?_!23?@!101?O$#220!176?CC$#221!73?FB!74?_!8?C???@?A$#222!185?A@$#223!72?OWW!74~!5^FF??BB?A!21?@$#227!69?@C$#228!58?W}~~~^~nqO$#229!8?E?B??KGK!4?OG!20?C!6?o?O!122?__$#230!8?o?_KK!6?_?O??CO!9?O?TA!9?_?_$#233!192?]$#234!23?@!155?O!4?__$#237!69?A$#239!186?A$#240!152?___?GK!8?@???@?O@@@!8?F$#241!5?C!16?C!25?O!22?G$#242!56?A!112?O??A?AABABBEAK-#5!206?CEEFFFE$#6!190?@@$#9!205?C??@???@$#11!14?@!56?@$#15!187?@$#21!194?C!9?C!34?A$#26!61?C!123?@$#29!160?@$#44!154?@$#45!16?@!21?@$#63!7?A!65?C!75?C$#65!66?@A$#66!73?@$#67!73?AE!74?AA@$#75!40?@!146?A$#86!7?@!34?@!127?@!10?@??A$#87!17?@!18?@!4?@!139?A$#88!8?BAB@B!5?!10AB???AEAA??AAEAABEDEEBB!121?EFDAB@F??C??AC$#90!178?@$#91!176?C??@@$#94!9?@!6CEE!6D@DDDCFFF@@DD!4C?CC?@!133?EE?CE$#103!206?A!6?C$#106!72?C!115?@$#107!192?AC$#108!158?CA$#111!158?@$#115@$#122!151?C?AAA!28?@$#123!152?CC$#124!60?C$#127!13?@!23?@$#128!228?A!9?@$#129!205?A$#131!61?A!9?C$#135!156?A@$#145!62?A!8?A@!82?C!35?A$#147!59?C??C!7?@!118?A$#156!207?@!5?@FFE!11FD!9FEC$#157!186?@$#161!72?A$#162!193?@B!9FB@@!32?@$#165!192?@$#168!14?A!177?C$#169!6?@C!54?@$#172!156?@$#173AFBB!155?CEFFFBBB$#174!156?CAA@$#176!193?A!19?A??@$#177!15?@$#179!63?B$#181!4?EE!158?!4C$#184!157?C$#185!169?A$#186!70?A!98?@$#189!154?C$#191!190?A$#192!155?@$#197C?CC@@E!160?BF$#198!150?C?A$#202!39?@!111?A?@!15?C!13?@$#204!58?F!129?A??C$#211!8?C!28?A!12?C!7F!127?EE!4C$#212!174?CC$#219!60?A@$#221!59?@@???C!5?C???@!74?@@$#223!75?!74F$#228!59?A???CBFEDFF$#229!15?A!154?A!9?A?@$#230!9?C?A!12?C!7?C!10?C?A@@CCB!119?C@?A@?A!6?C$#234!189?@$#240!152?@$#241!13?A!22?A-#0!240?\ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_gg/24x.symbols b/fastfetch/logo_gg/24x.symbols new file mode 100644 index 0000000..cf0b5b6 --- /dev/null +++ b/fastfetch/logo_gg/24x.symbols @@ -0,0 +1,19 @@ +[?25l ▂▃▅▆▅▃▃▃▃▃▂▁  +▆▇┈▁┎┊▁▁▁▁▁▁▁▇▅▃ ▁▁   +▃▄▄▗▎▌┈▝▗╴▇▇▉▆▗▄▂▁┈▇▄   +▁▁╷▁▚╱▏╶▍▋▏ ▆▏▝▗▊▂▂┊▝▂  +▇▗▁▋▄▉▄▅▅▉▅▄▄▃▁▊▁▆▂▅▄▃┈▎ +┊╴┈▇▘╵▗╹╷ ┊ ▇▇▅▂▍▂▂▁▄  +╻┊╹▅─┌╹┊╴▄▄┈╱▁▉▏ ▇╿╷▇┊▍  +╴┌▏▁╱╴▂▂╸▇╶╱┊╵╻▌▃╴│└▏╵▌  +▝▊▃▄▅▉━▏▁┗┈╷╌▁▁╸╶▏┃▊▝▅▉▖ +╴▏▌▇▝▉▇▇▇▆╵▝▖▃▗┻▖▁╸╴▆▇▅▇ +╶╴▝▃▃▘▇▁▂▁▘▎╺▆▌▇╏╱┈▘▝┌▉▅ +▝╻▂▂▏╷┌───┊┋▁▅▅┌╴╸╴▝▊╹▉  +╴┎╸╍▇ ┈┈╶┹╲▁▁┊┊▅▍  +╼╴╷▄┈ ┈╶▁▂▉╶▖▍  +▍▗▏ ╷┎━━▂╷╷▃╺━╾╷ ▝▆▂▃▄   +▍▌▎╌╺╴ ┍▉▍▊┃▉▏ ╵┈╵┕╴▅▃▂  +▝▋▝┈▁┊ ┊▅▅▄▄▆ ▉▎▂╶╸▝ +╺┊┙▇╷▇╶╴ ▁╷┈▂▎▅▂▃▄ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_gg/ButaNeko.png b/fastfetch/logo_gg/ButaNeko.png new file mode 100644 index 0000000..ced264c Binary files /dev/null and b/fastfetch/logo_gg/ButaNeko.png differ diff --git a/fastfetch/logo_mugi/24x.sixel b/fastfetch/logo_mugi/24x.sixel new file mode 100644 index 0000000..643397f --- /dev/null +++ b/fastfetch/logo_mugi/24x.sixel @@ -0,0 +1,2 @@ +[?25l[?80l[?8452lP0;1;0q"1;1;200;258#0;2;0;0;0#1;2;0;7;20#2;2;18;8;4#3;2;7;22;36#4;2;26;23;21#5;2;40;22;7#6;2;43;27;10#7;2;28;37;43#8;2;47;33;17#9;2;50;33;16#10;2;52;43;33#11;2;57;39;24#12;2;59;43;28#13;2;61;46;30#14;2;65;47;32#15;2;53;50;46#16;2;66;50;34#17;2;67;49;34#18;2;67;51;35#19;2;69;50;34#20;2;69;51;35#21;2;69;52;35#22;2;69;52;37#23;2;71;52;36#24;2;71;53;36#25;2;72;52;36#26;2;71;53;36#27;2;57;53;49#28;2;70;53;36#29;2;70;54;36#30;2;70;54;37#31;2;70;53;36#32;2;70;54;37#33;2;71;53;36#34;2;70;54;36#35;2;71;54;36#36;2;71;54;37#37;2;71;53;36#38;2;71;54;36#39;2;72;53;36#40;2;71;54;37#41;2;71;54;37#42;2;72;53;36#43;2;72;53;36#44;2;72;54;37#45;2;72;53;36#46;2;72;54;37#47;2;49;54;58#48;2;58;66;73#49;2;71;54;37#50;2;71;62;52#51;2;72;55;38#52;2;72;56;39#53;2;73;71;71#54;2;74;74;75#55;2;76;58;43#56;2;80;63;46#57;2;82;69;52#58;2;90;70;56#59;2;74;74;74#60;2;75;75;74#61;2;82;75;63#62;2;94;74;58#63;2;96;73;59#64;2;98;75;61#65;2;99;76;61#66;2;98;76;61#67;2;99;76;61#68;2;99;76;61#69;2;99;76;62#70;2;99;76;61#71;2;100;76;62#72;2;76;80;82#73;2;93;81;58#74;2;96;79;61#75;2;95;82;59#76;2;100;76;62#77;2;86;88;88#78;2;96;86;70#79;2;98;87;68#80;2;99;91;67#81;2;100;92;68#82;2;100;92;68#83;2;100;92;68#84;2;100;92;67#85;2;100;92;67#86;2;96;92;77#87;2;100;92;69#88;2;100;93;67#89;2;97;93;76#90;2;100;93;67#91;2;99;94;74#92;2;93;93;93#93;2;57;74;93#94;2;71;54;37#95;2;53;57;61#96;2;54;68;82#97;2;5;9;16#98;2;27;11;3#99;2;47;30;13#100;2;47;39;31#101;2;73;57;40#102;2;73;63;47#103;2;49;36;25#104;2;51;34;17#105;2;0;0;0#106;2;0;8;22#107;2;74;74;73#108;2;76;59;41#109;2;76;75;75#110;2;79;75;70#111;2;92;72;61#112;2;74;74;74#113;2;24;18;15#114;2;21;26;32#115;2;52;36;19#116;2;52;41;27#117;2;40;27;16#118;2;45;27;10#119;2;82;66;50#120;2;82;69;54#121;2;10;21;32#122;2;9;27;43#123;2;87;69;53#124;2;92;71;57#125;2;39;20;5#126;2;41;24;9#127;2;21;35;47#128;2;43;36;27#129;2;94;74;58#130;2;96;73;59#131;2;57;38;23#132;2;57;40;25#133;2;77;79;83#134;2;91;80;58#135;2;92;73;57#136;2;94;74;59#137;2;96;80;65#138;2;93;85;71#139;2;57;43;26#140;2;60;43;26#141;2;98;79;63#142;2;100;76;62#143;2;78;62;44#144;2;82;63;50#145;2;0;0;0#146;2;70;52;36#147;2;69;52;37#148;2;65;47;31#149;2;65;48;33#150;2;66;49;34#151;2;66;50;34#152;2;71;52;36#153;2;71;52;36#154;2;74;73;74#155;2;74;74;75#156;2;95;83;60#157;2;96;85;66#158;2;72;53;36#159;2;72;53;37#160;2;70;53;36#161;2;70;54;36#162;2;67;49;34#163;2;67;50;34#164;2;69;52;35#165;2;70;52;35#166;2;52;53;54#167;2;70;53;36#168;2;99;91;68#169;2;60;46;31#170;2;62;47;32#171;2;67;50;35#172;2;67;52;35#173;2;71;53;36#174;2;42;54;64#175;2;70;54;37#176;2;98;90;69#177;2;99;91;68#178;2;51;51;50#179;2;65;50;34#180;2;71;52;36#181;2;71;52;36#182;2;70;53;36#183;2;70;54;37#184;2;71;54;36#185;2;71;54;37#186;2;72;53;36#187;2;72;53;36#188;2;72;55;39#189;2;73;56;39#190;2;99;76;61#191;2;99;76;62#192;2;94;81;57#193;2;94;82;58#194;2;97;87;74#195;2;98;88;65#196;2;69;50;34#197;2;69;50;34#198;2;71;53;36#199;2;72;52;36#200;2;71;53;36#201;2;70;53;36#202;2;70;53;36#203;2;70;54;37#204;2;71;53;36#205;2;71;54;37#206;2;72;54;36#207;2;72;54;37#208;2;72;53;36#209;2;72;54;37#210;2;71;54;37#211;2;71;55;37#212;2;71;65;58#213;2;72;55;38#214;2;75;74;75#215;2;75;75;74#216;2;97;75;61#217;2;98;75;61#218;2;99;76;61#219;2;99;76;62#220;2;93;80;56#221;2;93;81;56#222;2;100;92;67#223;2;100;92;67#224;2;100;92;67#225;2;99;93;69#226;2;93;95;97#227;2;69;51;34#228;2;69;51;36#229;2;72;53;36#230;2;96;80;60#231;2;96;79;61#232;2;100;92;67#233;2;100;92;68#234;2;100;93;67#235;2;96;93;81#236;2;96;93;81#0!200?$#4!45?_!6?O!37?OO$#10!47?_!9?!4O!24?_!13?_$#13!87?_$#15!48?_!19?O$#50!66?OO$#57!91?__?_$#82!60?!5_$#100!56?O$#101!51?_!36?_!8?_$#102!63?O!6?_!18?_!5?__$#113!92?OOO!6?_$#117!53?O!18?_!11?_!15?_$#119!52?_!11?OO!24?_$#120!93?_$#128!46?_!7?OO!13?O$#134!53?_!15?_$#147!98?_$#156!55?_!12?_$#169!61?O!24?_$#175!49?__!11?O$#177!67?_$#179!71?_$#195!56?_$#221!54?_$#222!58?__$#223!57?_$#225!65?__-#4!38?A??@!32?@!35?A!11?_$#10!30?_???G!74?A$#57!33?O!73?A$#75!78?C$#80!48?@!55?A!7?G???O??_$#81!43?_$#82!39?G_??G???OGgw???@!5?D??@@!4?@!5?O??Oo_?WAaqSSE?`@ACBQAA?__aqE??C!5?O??O$#87!34?___o???c[O[W[?OO?C!10?@!17?C?E[[CGGGB!6?[OQW[O$#88!48?A??A???_``p!4_?CC?D!7?G!5?O!14?@!10?CK?W$#90!35?OO??OO!16?O?O!4?O!15?O!30?G??O$#100!75?A!5?@$#102!35?G!8?@!31?CC?A???@!19?@!4?A??C???G??O$#113!29?_?O!74?@$#116!116?G??O$#117!78?A$#119!74?A$#120!38?C??A???@!34?A!21?@!11?G$#123!72?@$#128!36?C??A??@!62?@!7?C$#134!31?_!4?G!9?@!37?@!16?@!4?A???C!6?O??_$#156!42?A!32?C!24?@!12?G$#157!34?O!4?C!7?@!57?A$#169!32?O!7?A??@!60?@$#172!37?C$#175!82?@!38?_$#176!109?C$#177!32?_!7?C!38?C!6?@$#179!73?@!38?C$#195!43?A!27?@?A!7?A???@!13?@$#222!38?o_???C_a_KcDFx\|[CCCANADECaqqOw{}}{{w_oog??_?_???ao{[{|z{k__`AA??WW[G??!4_O??__$#223!44?A??a!4?AAaAAIK??A???@LGAA??A!7?GG_!4?@!9?@!8?owoW?O$#225!33?_???GG$#232!63?A!6?@!10?C!6?@!15?C$#233!42?_??C!22?@!16?G!4?AA!5?KKC?KK$#234!40?GW!4?A??A??_??XW???WWWwGG?aC!5?C?GG?G!6?a!8?@!7?___!7?___??_-#4!24?C$#8!131?O$#10!26?A?@$#15!22?O$#56!88?A$#57!83?C$#61!29?@$#73!57?___!29?A$#75!56?_???__$#80!51?_!27?G!10?C!12?_$#81!28?C!10?C$#82!25?_gC?C???@??@@B?CCCb??A_?@@???O!5?G!6?S!8?Gwk_O?O?OO?@!7?_???@@@?OoO??_OCcGCCC{GGW?A$#83!23?_?OOw_!10?ABBB?___?_!6?!5O!20?_O!7?@B!18?_oWoWWo!6?A$#87!34?@@!49?GG!4?AAA!11?A!14?GG?A??G$#88!33?{w{wG!6?GGG]G??GG??NNFBBBJLG!28?G[C!4?_o!5?[J!16?C???O$#90!51?O!13?_!31?o!9?O!13?OOOooo??_$#100!23?G$#101!86?AA!35?@?A!6?_$#102!24?G$#113!20?_!6?@!102?G??_$#116!129?G$#117!124?@?A$#119!80?C???A!45?O$#120!27?A!60?C$#123!83?A!5?C$#126!128?C$#134!23?O!60?!4C!34?@???C?G$#143!81?CC??A$#156!55?_!6?_!19?A!41?A!6?_$#157!22?_???C!26?__!74?O$#168!24?_$#175!127?C$#176!25?G$#177!50?_!30?G!20?_!24?G$#179!21?_???C$#195!28?A?@!21?_!10?_!15?CGA$#222!29?O!10?O__??B!25?CCfB!12?_!13?CC$#223!30?{|{?C?Cso!4?GOOO@O?G??GN??GKCCCAOwO!4?B!4?w??BR@!11?o?WI???O!7?CK!13?C!4?O$#224!66?!7_?_?_!8?__?!4_?__???_$#225!60?OO!5?G!13?_GGH???@!13?O??_!4?G??__!15?_$#232!24?O!4?iAA???AAAKxgWWSFCD?@WO@OP!5?G???EFNV?[^[ZZW[FVFO?A@!4?OOOWOP@@BTCN^MMYJNNG??QNBBFB?@Bvueu`_c???__$#233!28?W!20?_!65?G$#234!32?BAA!13?!4EFE!8?O@??GBB!13?`p_@@GG?GKC???z!4?_???Db_@!5?BA??@@@CGGGK-#4!17?CA@!120?O$#6!60?_O??GG$#10!14?_$#11!61?_$#13!103?@$#25!83?_?K$#29!104?@$#36!55?_??O!7?_O$#38!64?AA!12?_$#40!63?__$#41!42?__???_!5?_WG?O!15?_o_???__O?G???o$#42!81?_!4?K$#43!39?_!44?OOO$#46!38?_?_??OwWw???__wW???GG!26?__$#49!55?OO!4?C?A!4?O!7?__?OO?G!4?G_$#51!47?C!5?CA?A$#52!36?O!4?G!19?AA!5?G!4O?G??CCC?CC!6?O$#55!67?A$#56!36?G!5?A!8?@!16?CG!7?A!10?C?G$#57!19?A!13?O!59?_!10?A?C?C!27?C$#73!30?_!41?C!7?@@@!8?G$#75!32?O!13?@!32?@???@!17?_$#79!21?@!72?_$#80!42?@!28?C!15?@!11?c!6?@???G!21?@??C$#81!26?H?GG???G!42?@$#82!17?_???w?ghG?G?FC!7?A!33?@@@!15?BB@G@`HyMA?OOG_?G!5?WE???xlLHG?N!6?@C??o??O$#83!18?O???@C??CFF!63?AFEMo!13?BAF!4?E??EC!13?o$#87!18?_!82?G!5?O?CCC?_$#88!33?@B?BB@@@!64?G!28?C$#94!63?C!6?_$#99!63?O??G$#101!34?_O??G??!4C?!5A!6?@@??@!11?G?CC???!4A???CGGO?_!7?C!9?_$#102!17?GC?@$#103!134?@$#108!32?__O??G??C??AAA!8?@@@??@@?@@!8?G?C???AA!11?O$#113!136?A$#115!58?_!4?G$#116!138?G$#117!16?G!124?_$#119!31?_!17?@@!13?@!6?G?C??A!63?_$#120!16?O!116?@$#123!35?G??C??A!6?@!26?A!13?C??O!7?A?A??@$#125!59?_??O$#128!15?O!121?C$#131!60?O$#134!15?_!49?@!35?@?A???I!29?G$#135!47?@!22?G!16?A$#139!64?O$#140!101?A!4?ACG$#143!39?C!12?@@!32?A!22?G$#148!105?A!5?_$#150!66?CG$#151!57?_!44?@!6?O$#156!34?G!5?A!25?@?A!15?@!15?_C!6?O???_!21?A$#157!45?@!23?C!4?A???@!6?@!16?_$#158!84?G$#161!61?G$#162!62?_$#168!20?A!115?G$#170!62?G$#171!65?C$#172!65?O!69?A$#175!65?_O!4?__??OWWWGG!58?O$#176!31?O!45?@!25?_$#177!18?G!49?@!4?A!18?G$#179!59?O$#183!64?C$#185!56?_$#188!35?_!12?CC!5?A!4?G!6?C?_!19?_$#189!39?GG!4?CC!4?AAA!30?AA!5?_$#193!37?C$#195!29?_!6?C??A???@@!22?@!18?@?A?C??O!6?G!4?C???_?O!26?O$#199!82?_$#207!36?__!13?W??_?G??G$#208!45?_!36?OOc$#210!40?O!21?C!5?_!4?O!6?CG!6?O$#211!37?OOO?OW!4?!4W!7?AAA!5?A_!7?G!7?C!6?_!19?O$#213!41?_?G!4?__CCC?CCCECCC$#222!19?OG!5?_???OKKCC!36?A!17?A!6?EC!5?CC_???A!4?EAE!12?EC$#223!19?G?A!11?A?B!63?@!4?G?o!8?C!16?EC?G??__$#224!19?_o?o!4OooO!64?WO??_GO??OOO?__!5?GwW?OOo_!4o__?wG???G$#225!16?_O?CCC!48?C!31?C!15?AA$#232!22?IBAB!4?JBB!8?@!27?BB@A??@!12?@!8?@@!8?@@@???!4@!5?G!4?@?@AA$#233!22?C?CcA!8?C!53?@?CC!15?A??@!4?_??_?BF!13?o_$#234!98?OO@?G!8?G?Wo!6?O??NN^]~?oxwy-#5!56?A$#6!31?_O!18?O?C!4?@$#8!53?G!88?@???GO$#9!49?_!65?G$#10!10?C$#11!55?C$#13!31?O$#22!117?O$#23!78?__$#25!78?OWEFB@$#29!114?AO$#30!51?C$#34!47?_!18?_$#36!54?O$#37!56?W!4?A??_$#38!27?o!24?A!11?!5O!6?_$#40!35?C!17?O!35?@@!10?_$#41!28?O???A!4?A!6?oowFQKC??@___WwW]XMGGgGgm!4{~~^~]BB@OWwz}~~~oa___???__$#42!42?@@!13?_!4?OO?C!11?_?C??CA!20?OOo$#43!40?AA!5?O!9?C!6?EAA!13?__!12?o_!8?G$#46!34?@???ABDDu[HJFGHBB@@!5?CE??@E??@F!14?_CC!4?K[[WWG?oOOOSM]W?G?__$#49!36?A!31?@!4A!20?C$#51!35?@!5?W!51?A???GC$#52!25?O?GC?A!61?@!24?G$#55!40?_!63?A$#56!29?@!65?A!15?@!8?O$#57!27?A!118?O$#58!40?O$#73!25?C??@!8?O!78?A$#75!96?A?@!5?@$#80!9?O???A!6?_!6?@!86?O_!28?G$#82!19?!4@!97?@!13?@??@??@$#83!12?o?oO!5GWGC@A!82?C!15?C?CG!7?@@??@$#87!13?_ABFFECCAA@!14?_!72?OO???@!8?AA!6?A$#88!9?_O!98?AAKGo_!16?ooo!11?o$#90!12?KC?C!94?G??G$#94!29?G??C!36?@$#99!33?G$#101!13?@!9?_O??C?A?@_?O?G!56?@A?C??A@!5?G!12?O_!24?G$#102!7?_OG$#104!34?G!15?O!5?@!57?C?O$#108!22?_??G??A?@!6?GGG!58?A???@??C??O_!6?C?G$#113!12?@!131?AC$#115!30?_!20?G!61?A$#116!148?_$#117!11?A$#118!50?_$#119!23?O!11?O!58?@!4?@???@??C!7?GA?C$#120!12?A!128?@$#123!24?G!72?A!7?A!7?D!5?G$#125!52?G?CA?@$#131!33?O$#134!11?C!9?_!11?_!75?O!37?_$#135!36?O!73?_!11?_$#139!54?A!88?A$#140!57?A?@!52?@!4?_$#143!26?C!80?G!4?A!8?_$#146!56?C$#147!29?_???C!15?O???A!62?G$#148!34?C!81?_$#151!115?C$#156!107?CG!5?@???C??O$#157!14?@!7?O!16?o!55?@$#164!48?_$#167!50?G$#168!105?@!15?CS!4?C$#170!52?S$#172!51?_???@!88?C$#175!26?o?_?[K!20?_!18?@@!45?_$#176!24?C!90?@$#177!8?_!88?@!13?_!11?_$#179!32?G!21?G$#180!58?A!21?G$#185!54?@G!4?@$#188!29?C?A@??G!4C!51?@!4?G???_?__C!13?O_$#189!26?G!13?G!54?C?C??A@?A$#193!142?A$#195!10?G!12?G??A!7?_!71?A!10?A??G!22?C$#204!78?K$#206!33?AAA!15?A!51?C__$#207!38?@!9?C!4?_!37?AC!6?_$#208!43?aEC!9?O???__c__??C!13?OG!7?A!5?O!5?O$#210!25?_??GO!7?@!32?@$#211!24?_!11?@!40?@!7?@$#213!33?@!7?_G!20?@@@!26?A?CG??GKG!6?O$#222!14?G!4?O!6?@!83?O!11?G!6?G!8?C?Oc?W$#223!11?G??C!4?_!86?@BB?@AC!10?G?__???]!10?W{_o$#224!13?G?G?_o!16?__!72?D!13?P@P@@PP@C??SE]]Z[MA$#231!38?O$#232!123?C_??_ae_???_??!4_$#233!11?O?O?_oO?AQCCAA@!11?_!58?@!12?G!7?@BFEIAAYKWQK??AE?Aw_??A$#234!10?__!6?@!91?C?_!8?@@!8?HHLG!11?_-#5!25?O?CA$#6!29?@!18?A!29?_$#9!47?A!30?OG$#13!24?OGC!51?G!23?G$#16!79?_$#20!45?_!57?G$#22!103?C$#23!76?AB@$#29!23?C!20?C$#30!100?G$#34!23?G!19?W?A$#36!44?G??OO[!30?G!20?O$#37!25?C!28?C!20?C$#38!43?C?@!6?AB!17?{{!20?A{{A}s!5?DF!18?_$#40!51?@!28?o!21?O$#41!19?O??G!16?k{}~aB?@??_??@?w!6{???B!6~BB~b!4?AFL@?@!7B~|BA??Gwo_??GGB?A?G_$#42!52?CCB??@???K!13?O???@???B__!22?@$#43!25?A$#46!37?O??B@!9?GO!29?e!12?@!9?Oo~{!14?_$#49!20?OwQ@@?@!54?O!15?@?C!4?A!5?SW!12?O$#51!109?@??O!7?AA$#52!19?GC!15?GC!83?KG$#55!112?C!9?@A$#56!18?C!16?GC!82?C!6?GO$#57!31?@!5?A!79?A$#73!113?C!5?G$#80???_!27?_P!4?@!79?C?O!14?O??!4O???O!7?O_$#81!17?@!94?@!25?__$#82!5?GgGIcca?wGA!16?G!82?CO_O_!6?A?G?O!4?B???Ee!5?wwO_$#83!6?COOWW[BBBG!99?G!11?C!20?_$#87!116?AO$#88!30?O???@@!78?@!14?GKBBB!11?@@!5?_$#94!19?__!14?_O?GO!82?O$#99!30?@!17?@@$#101!5?A!10?_??CA!4?_!87?O!6?C@A??GO!24?CG$#102!153?O$#103??O$#104!45?OC$#108!21?@!11?_O!4?@!70?@A??_!5?G???C$#115!128?_$#116???G$#118!24?_!21?GC!52?AAC$#119!19?A@!93?O!10?C???_$#123!32?_!87?O???A$#125!26?G$#128?_$#131!101?C!15?@$#132!79?O$#134??_!30?O!4?@!73?A!5?C!9?O!19?@$#135!111?@???_!7?@$#140!29?A!15?G!53?A!18?A$#143!15?_OG!95?G!7?_$#146!44?O!33?C!21?C$#147!101?@$#148!28?C!50?C!19?@$#149!100?@?A$#156!4?G!9?_OG!13?A!85?@$#157!5?CA!10?C!17?C!78?G!11?CG$#159!50?G$#161!127?_$#162!46?O$#164!118?@$#165!46?A$#170!149?@$#171!47?G!29?_$#172!6?@!20?G!19?@!106?_$#173!44?_!5?_!24?g$#175!22?cO??A@!20?G!47?G!4?G@$#176!28?G!86?O!8?@$#177!26?_O!85?A??_!34?G$#179!4?C!18?_???A@!19?C!101?A$#180!24?C!51?{KA$#181!77?O$#183!24?G!71?s$#188!17?_!32?A!52?B!15?@!6?_$#189!17?OG??A@!11?_O??A!71?ACG_!5?A?O_CGO$#193???O!30?G$#195!7?@!10?A@!9?C!6?A!83?_!4?A!23?AC$#200!76?@$#201!45?C$#202!98?B$#204!50?O!10?___{!9?K@!13?___$#206!24?A$#207!18?_!19?O!11?CA!29?a!21?o!8?_!10?O$#208!37?_!5?@???_???CGw?BBABBBR^^!10?OA!7?[][{{{WWO!12?o!4?A$#209!36?_?_!7?_?_??o_!29?W_!5?CCK!10?_??_K??{_$#210!20?G??A$#211!26?O!95?CG?_$#213!18?O??C???@!11?GCA!56?@!23?@$#222!33?G!101?G!8?GG$#223!7?A@B??_!17?_A??EA@!89?@@!4?_!8?!4BAAA?Ww_$#225!118?G!11?_$#228!49?A@$#232!4?OoOCC?B?[CCCF!12?W??EE!84?_!6?@?ABBB?W{ns~nKHH{s{cs!4C?O$#233!4?_??__??@??O@?A@!14?@!80?C!14?O$#234!27?_o_K[!81?@ABKG!10?CC?{C!5?B???G!4?@I-#5!77?C$#6!19?_??A$#8!18?_$#9!76?O!53?ACG$#11!77?O$#17!16?_$#18!38?_$#30!32?O!5?O!33?GG!5?C$#34!32?_o??oo??A!34?@!4?G$#37!50?O!55?G$#38!38?GG!87?A$#40!15?_!15?w!97?wG$#41!17?O?A!10?_?GK}~MNFFDF!4?C{{E?wgw~!5F!4~@???@~~FVRoE???_?GWK!5?!7~@@@FF??CCCO[Www{wwwo!10?@$#42!17?G!29?@@?@!33?BB$#43!113?A?G$#46!16?O!29?G!34?C!23?_??FFFAF@ACO$#49!18?G!54?CN!41?_!8?F?C???_$#51!12?_?G!13?__??E!83?G$#52!15?A@!107?G$#55!10?_!104?@$#56!14?@!103?O!4?O$#57!30?A!99?@$#79!119?O$#80?A!9?C!13?_?G$#81!8?F!108?@???C!24?@??@??C$#82?C@??EC???F@!9?_???[!92?@B?W!9?@?C??AW???F??w!7?A$#83???@@@BF!20?A!90?Cg!15?OF~^voww?FCFF?CC$#87!25?@??@!90?GE!11?A$#88!5?wW!16?_??A!105?@!21?A$#90!22?O!129?O?O$#94!19?@@!12?A@!73?_!8?_!6?@?A$#99!19?OOC?@!53?G@!54?_$#101!11?_GCA@!14?CA@!81?@?CO_!4?Eo$#102?@$#103!159?O$#104!129?@??OO$#108!11?O!15?_OG!87?G!4?@G$#115!21?G!112?_$#116!158?G$#117@$#118!20?G!55?_A$#119!12?CA!103?C!16?O$#120!131?A$#123!11?G!8?_!5?_O?C?@!89?@C_$#126!160?_$#132!77?@!53?G$#134!116?@?G!13?CG??_!22?_$#135!10?O!17?G!90?_$#139!76?G?A$#140!22?CA$#143!116?A!5?A!12?_$#146!75?_$#147!39?_!36?A??@$#150!77?_$#151!78?C!49?@$#156!9?_!11?O!100?G!35?O$#157C!155?CG$#159!80?A$#160!79?G$#161!127?H$#164!132?_$#169!157?C$#170!130?C$#172!17?_O?CA$#173!47?A??E$#175A!19?A@!53?G??GA!45?Gwo]C?O!23?@$#176!26?O!91?C!35?@$#177!24?A???C!108?_$#179!19?G??@!53?C!52?A!26?A$#183!78?_$#184!48?A$#185!19?C!19?O!35?O??O$#188!14?c[EDC!10?O!51?@!42?A$#189!12?OG!16?GC?@!81?A!7?@$#195!10?G?A@!8?GC!5?A@!86?A???AO!12?O!19?A$#199!76?@$#202!52?O!18?w!7?OO!26?_$#204!50?g!4?w???w!4?}???}???_!8?O_o$#207!14?O??A@!11?O!49?@AF$#208!40?ww|{~~r??x?EFF??www!6?~~~!5?_!6?c_?B{{~~~!7?}}}ww{KGzWE!4?@?CC$#209!36?@!5?AB!7?@!49?BBB?B@B$#210!13?_!112?C$#211!24?@!99?Co??_$#213!13?O??G?A!111?o$#222!9?K!112?_!23?wo??WW???O$#223?G!4?_w!4?@!13?G!106?BNG!16?@A?cw_$#224?o{{s???w!13?_Ow!96?_!13?CK!5?CCCw?Gww__?[CG?O$#227!106?_$#229!102?oo$#232??AAA!4?B?A!14?@B!92?@!14?B@!5?BBB!5?@@?@$#233w!8?O!108?A?O!18?_GG!4?A??EAA$#234!4?G!18?GCACC?@!122?g_g???_-#5!11?_!6?@!16?O!71?A!26?@?C$#6!14?_!122?O$#8!15?G$#9!10?_!27?@!68?C$#11!12?G$#12!14?O!20?_$#13!137?_$#17!36?A$#29!32?OY$#30!30?ABC!4?O!77?L~o!10?_CC$#34!31?CGDB!69?AA???AK?Oo!17?@$#36!12?C!64?C$#38!110?O!6?@!12?A?@$#40!12?A!64?A!29?_!31?O$#41!8?_?G!15?O?CND!4?@??_?[N!9?!4Boo!5?^^!4E!11?poo!5}oo~!5F?!6o?A?@W???BnNN~q??_!10?woWGG_$#43!26?GG!11?G??O$#46!11?C!13?oCC!13?O!89?_$#49!9?OC!119?G???O$#51!8?OC!14?_G?@!92?_!14?o$#52!7?_!18?A!92?C!5?@!12?CG?_$#55!121?O$#56!9?@!114?C$#57!120?AG$#58!141?G$#73!23?C!99?@$#80!4?_??A!16?@!136?C?_$#81a!18?_!102?@!21?A@@?O$#82??AAE!15?PAB!98?@?G!18?D@SGG@HPTVK?K?AND$#83!19?A?C!101?O!17?A???a!4EIG$#87!16?_!4?GC!99?C_!16?AC!7?G!10?A$#88!18?G!141?G$#90!23?@$#94!13?@!13?A!91?W!6?A$#99!16?G!18?GC!100?G$#101!6?_OKA@!4?_!7?O??@!92?AG_??@g!10?@!24?A$#103!16?A@$#104!37?C!38?A!59?G$#108!7?G!14?_?CA!94?C???A!14?CGO_$#113!161?@??O$#115!75?K$#116!15?C$#117!163?G$#118!16?@!19?GA!38?@!31?W_$#119!6?O?A!13?O!120?_!19?O$#120!19?@$#123!21?_???@!96?_?W!12?@!4?O$#125!12?OGCQ?A!16?_!100?A??_$#126!16?C$#131!11?O!95?@C!26?@??O$#132!13?CA@!119?C$#134!7?C!8?O!7?A!99?_!15?C!21?G$#135!5?_$#139!17?C!16?O!73?_!53?C$#140!38?A!36?QC!29?@??O!24?A$#143!23?G!95?@!18?A!21?@$#146!37?G$#147!39?@!37?@!31?G!28?G$#148!37?@!69?G$#149!36?O!38?@!30?A$#150!108?A!28?C$#156!6?G!114?C!17?A$#157!17?G!4?G!97?@?OA$#160!31?G??C!71?C$#161!32?b!77?_!6?A!9?_$#167!34?G$#169!13?OG!149?_$#170!12?_!20?_!102?A$#172!13?_!62?G!56?@$#173!55?B!15?D!31?@@K???@$#175!9?_O??A@!61?OW!29?O?C!7?KK!7?@^^B?EECKG!4?_$#176!20?_!102?C!18?G?_$#177!121?A$#179!139?_$#181!71?W??O$#183!36?@!41?@$#185!31?O!6?C$#188!11?B@!11?O!14?A!96?_A$#189!23?_GC!92?@?O!4?U!14?O$#195!5?O??@!9?C??O!116?@!4?O$#199!50?o$#200!40?_!30?_?O!4?_!33?_$#202!30?__!76?@$#203!47?_!30?O$#204!35?A??O!8?^n_B___{KGw?@@~__xHHHn``!4?_?_MGGG!5@MG?w!4G~!6?o$#205!74?G$#207!28?B!10?C!34?F!30?_!13?_$#208!11?G!14?_owOW!8?o?_n{{}x?O^K[[[??CF~}}!4?oooO]]A~H_?_??EFF!5?@F??!4o?NMMMNNMKK!6?O!20?oo$#209!38?G!7?E!26?E!29?ooO$#210!36?__??B!65?_!11?O!7?K???@$#211!18?A!99?A!7?o!6?A$#213!9?GA$#223?w?_OFB@!9?o_K!123?E!11?@!4?coo$#224?F|DHG!12?O?M@!124?O_!4?rrbq\OoCOG$#225!159?@$#228!35?C!100?O$#229!29?_!13?BB@!10?B!16?_!23?@@@??@$#232O??W??C!12?O!127?O_!6?K__$#233L!22?A!98?I!16?@@@?GHC_G?___?K$#234!142?A??O!8?O???Iy-#5!8?C!22?O!77?@G$#6!11?OC!18?G!78?C!28?ACO_$#8!73?_!91?@$#9!9?@???@!18?G?@!37?_!36?A!28?@?G$#12!33?C!75?C$#13!4?_??O??O!99?@!28?C$#18!10?AC!96?@$#22!8?@$#24!28?_!82?C$#29???_!7?_!14?o??ODB!38?_?G!13?_!25?_!25?__$#30!47?@B!67?@@!10?F$#34!27?O?M!38?_!8?A@!38?C@$#36!6?C!25?_!43?_$#37!27?_!79?G$#38!9?G!117?GG$#40!77?_!29?@!4?O$#41!24?CDCEE!7?C@!10?CECFFF@@@!19?EC?!9@B@???C??!5@!7?C!5?@@??EBC!8?FF???FBA$#42!8?o!24?_!48?___!22?_!12?o$#43!20?_?_!44?_!45?_!24?G$#46!7?_!11?_?_K[@!49?@!39?_!4?CGC_!8?NNN??@$#49!116?__!17?[sC??_???O$#51!22?AB!119?EG$#52???O??@!13?G!105?E$#56???G!119?C?G$#57!125?_!39?A$#73???C$#79?_$#80???A!11?@_?@!127?A!18?C$#81@?C!15?A$#82?G!148?O!11?__$#83!146?@?DD@@$#87!147?A?O$#88!15?AA!142?!4]^$#90!13?oO?@!141?G`_???WW$#94!9?O!11?C!115?A!4?AG__$#99!8?A?_!63?_!36?_!27?@?G$#101!5?A!12?_GC!100?@EO?B!15?_?@?G?_!20?_$#103!167?G$#104!7?C???G!98?A$#108??_?C!8?C!6?A@!101?G?C!18?ACGO$#113!166?A?O$#115!30?O?A$#118!9?A@??A!96?O$#119!17?_?C!104?_O!41?O$#123!4?A!7?O!131?@A$#125!5?_OG!22?_?CA!39?OW$#126!33?@$#131!6?G!5?G!18?_!78?_$#132!6?_!104?O$#134??O!144?GO$#135!18?G?@!102?AO!21?C$#137!124?G$#139!12?A!127?A$#140!5?O!8?@!59?C!67?O$#143!5?@!12?O!103?@!25?_$#147!5?G?A!25?G!37?_?C!69?_$#148!31?C!43?G$#149!11?@$#151!9?C!62?O!68?C$#156!14?A??O?A!104?@!24?_!16?G$#157!4?@!119?A$#159!103?OOO$#161!9?_!117?@$#162!75?C$#165!30?A!76?O$#168!17?G$#169!73?G$#170!8?G$#171!30?G$#172!32?@?A!74?G!28?A!27?C$#173!33?OO!17?O!13?O!28?O$#175!10?G?@!21?CB!73?O!17?E!12?@@?O$#176??G!142?@??G$#177!167?_$#179!29?_!81?G$#180!35?O!33?G??E!22?G!12?O???EG$#183!75?_!66?G$#184!26?GGW!8?_!10?!6G?_!13?_!6?WW!15?G!6?GG?___!7?@?_?Ww!9?OWW___o_GwO?O$#185!6?A!27?GC!43?CCC!55?@$#186!23?___!9?gWWWw??!5w!5_?_?GGGwww__wwwgO?OW!7?G???GGG??Ggwww!5_ww___!6?_!4?O?OW??w$#188!4?WC?@???A!8?O!100?AW!19?@???_$#189!19?O?A@!100?_!20?C?O$#195!13?G!4?C!104?@C!39?@$#199!54?C?OO!13?A!14?C?O$#200!26?A!7?_!17?_!14?GG??H!13?_?_!6?G!13?G??A!4?A$#202!40?@!34?A?@A!22?B!4?O!10?A$#203!47?A!38?O!6?O!12?G$#204!36?a?`B}}!5?[OPRO?OyQef???]]!5?P@@O!6?C!6AYIUCAB?]AUBAAAYQOz???_!5?GAAA$#205!80?GG$#206!74?A!45?A!18?O$#207!78?Ogoo!21?JJGF?A!29?C$#208!24?A?@@@!8?EEC?@!5F!8?C??FFF@@!5FEEE??B!8?!4C???CCF@@@!8C!8?@?CCC$#209!22?O?WW!81?A?_!4?O!6?_!6?___OOOG$#210!36?@!102?G?AC$#211!126?XO$#213!10?C!10?W!56?_O!23?CCF!14?@W!4?__!17?O$#222}!14?w!134?kGwwowwwo!5?__$#223??A@!12?[F!133?o??G!6?@@???_$#224?E!13?C!132?AA?EFFBFFFB?@???C$#227!75?O$#228!32?O$#229!25?A???@!41?C@??@@!5?OOO!11?W!10?C!4?@?GGC$#232?@@!9?_!137?A$#233?O!17?@!127?C?G$#234!14?k!132?@!6?C???C??_??A?O-#5!4?@!25?@!80?B$#6???C!4?GA!101?C$#9!7?O!21?@!39?G???G!68?@C$#12!30?A!42?`$#13?G!26?_!39?G!42?_!32?C$#14!7?G!104?A$#18!31?@!42?C$#21??_!107?C$#22?C!24?O$#24!5?A!14?CC!63?C??C!6?!5C!9?C$#25!66?BB!10?G$#29!26?BB!40?@!12?O!4?RWW!7?WWW!17?G!8?WWO!11?@$#30!7?C!67?A$#34!23?__K???__?[!53?_!26?C?c??A$#36!66?G!8?@B$#37!83?F$#38!114?WWC!21?B$#40!65?O!79?B$#42!6?C@!10?G?GG!11?K!45?G??M?M???A!5MK!5?G!8?J!6?o!21?CE$#43!6?G!131?G$#46!4?O!12?G?@@@!92?B!7?BA?A?A!10?Oww_$#49!7?A!10?A!97?BN!19?B???G$#51!16?O?@!104?@??A@!13?O$#52!146?O??C$#55!72?O$#56!69?O!55?@!16?G??O_??@?G$#57!143?G$#58!72?E$#66!69?_o_$#70!71?O$#73!14?OC$#79!150?@$#80!10?C!4?A!137?O!17?_$#81!14?C$#82!11?c???@!136?C?O!5?wS@^!5?o_$#87!10?w$#88!166?A???O$#90!12?C@!145?@@$#94!141?C$#99!4?A!22?OCC!37?_O!4?C$#101!15?o?@!124?_??G??@A?o!18?C$#103??C!168?G$#104!8?C!64?A!37?G$#108C!15?C!51?_!55?@!16?AO!7?C?_$#113!170?A?O$#115!5?@???@@!63?@!37?G$#116!169?@$#118?_?A???_!20?O!83?O!30?A$#119!14?_GA!124?@A??_$#120!10?A!160?O$#123!70?G!71?C?_!5?A?O$#125!27?_GA!82?_$#126?OG$#131_!69?C@@O!37?O$#132??O$#134!8?_G!6?@!126?_!7?C!17?A$#135A!70?C!81?_$#140!9?C!59?CAA!40?C!30?@G$#143?@$#144!72?G$#147W?A?C!23?@OC!37?C?@???G$#148!72?_!71?O$#149!66?_$#150???@$#151!110?A$#157!11?@!131?O!26?G$#159!32?_!41?o!5?@$#161!114?_$#164!112?@$#165???_!22?K$#167!27?C$#170???G!4?O!18?GAG!37?O!6?A!35?@$#172!113?_$#173!80?G??G!11?G???G!20?C$#175!8?@!21?W!35?O!46?O!30?A!27?_$#176!14?G$#177!9?O!141?A!16?@$#179!6?_?A!17?_$#181!61?_!4?C$#182!25?_!5?_!8?O!20?C!7?A!5?K$#184??@???@!15?E[[O!5?]B!4?B!17?~~!5G??o???A@!15?GK!16?NNN!4?_??G?B?o|ww{w{{c_gw{[N~rr~~{??@$#185!65?_?G$#186!5?C!13?G__XBBB!7?bmmkwwf??JZ!7^~}~!4?!4B?KFB!9?OWGCC?C!6?!6@BAAABBFN???__~~!4?@!5?BAA!6?A??o?K!4?_$#188!4?G?O!137?@CL]I?o$#189!16?GE!129?`??G$#195@!12?_!138?G$#199???O!37?ccc!31?_$#200!19?_??_!13?P!15?@!6?__?bB!12?_O!5?O?r?B!7?p@@?o??O$#201?A$#202!63?_!13?_ooo_!5?c_!7?___$#204!19?C!16?ACFWnZO?!7_???~??vsSSO[O???C!12?C!21?NOOO^??oO!8?C!10?_???K$#207!5?W!59?K!11?FBBAB!40?C!5?C!17?A$#208!4?_!12?ooOOO!11?OOO!46?o_o!4?!6o!5?oo___$#209!5?_A!11?CAAA!42?G!16?G!31?AC!6?@??A?CC@BB$#210!76?C!33?G!37?C$#211!148?ow$#213!16?_!109?@!13?E$#218!71?G$#222!14?B!137?!7@!5?FB$#223!12?GG!139?C!11?{|~}K$#224!11?WoS!138?AIm!5}Ea}_w$#225!9?_?A$#229!34?@@!46?@?@!35?@$#233!151?@$#234!12?BA!147?H-#5!26?A!85?A$#6!26?C$#9A!4?G!57?G!8?E!39?G$#11!26?G!35?OC!8?O$#12!5?C$#13!59?_!5?@$#16!60?O$#18!4?O$#19!25?_O$#22!28?@$#24o!17?oo__o__???OO!62?_O!24?O$#25!76?CKC!15?_o$#29!23?@!6?F!79?C$#32???O!46?oo!6?_$#34???_!13?_!4?@!6?@?F!29?C!20?!4o~oo{{{O!7?CC!8?G!4?@$#36!27?O!45?o_!39?CC$#37!116?o$#38!15?ooO??OO!4?_??_!7?!6o!5?oo??o!58?O!5?o_!4o!5?ooo???!8o$#40!27?G!46?K$#42!5?@!51?O!19?!5o!14?!6o???_oOOO!5?_$#44!115?O$#46!15?AA!122?BFF$#49!27?__!113?o$#51!15?@@!126?_$#52!13?O!128?C!5?@A?@$#55!67?@!87?_$#56!66?A!82?_$#57!7?A!4?G!141?AG_$#58!63?O$#62!71?A$#63!68?@$#66!66?CE}f^$#70!65?G?W?G$#73!13?@!158?@$#80!10?_GA!131?@$#82!11?A@!133?C!8?@@?@^^W[SWW$#87!6?_G?@@@!133?E?o!8?CVU!4?G!7?O$#88!166?FFN???CWo$#90!8?o_!159?W?GG$#94!14?O!135?_o_$#99!64?C$#101!12?_G!128?@K_???A???@EO$#102!173?A$#103!26?@$#104!6?C!18?G!35?O$#108!6?G!5?OC@!128?A???@CO!4?KO$#115!5?O@!18?O!46?H!40?O$#117!175?G$#118!6?A!20?@!32?_!4?A@!45?C$#119!13?A!129?@G!30?O$#123!11?_!52?G!6?C!75?AG$#125@!111?@$#128!173?@$#131!62?G!49?O_$#132!113?G$#134!144?C$#135!145?_$#136!62?_$#139!174?C$#140!25?C?A!36?A!6?_!41?C$#143!71?G!72?O!8?@$#144!65?C$#146!5?A!105?A$#147!27?C!35?A$#148?@??_??@!104?_$#149!73?@$#150C$#151!111?@$#152!61?_$#156!6?OC???OC!133?@?O!6?CO!17?G$#157!144?AO?C!6?@$#161??_!108?C$#164!61?G$#165?O!21?OO!46?O$#167!64?@$#168!145?G?G!7?AA$#170!72?_!40?A$#171!25?A$#172!176?_$#175!4?G!9?_!58?G!40?I$#177!145?@!10?G_$#179!113?@$#180?G!55?_?G!15?GG!20?GG???ww_$#181??C!72?C!21?EE!4?EA$#182!115?A$#183!25?@!33?O$#184???NC!10?G???@NN!10?F!8?MME!4FNN!5?!4F?G??@!10?A!36?G??@?GNF!4N@@@B?GG???F!4NGG$#185!73?C!40?O$#186!15?CCFF!9?A?!4o~~!4F!4?ooo!4?FFFO__?G?E!43?GO?h`G!6?C!7?{{{CFFF~wo!4?B$#188!13?_G!135?@?OW$#189!5?_!8?E!127?AO!5?K!4?_$#190!63?_oow_$#195!173?C$#200!18?G!10?K?G!22?_WW??B@!13?@oo?@???GGGF?FGAAAE_W!4?MIIA?S?AAE_o_!4?A$#201?eO!20?G@!36?B!48?A$#202G?J!16?G??MEM!4?AG!31?B!12?@@@!7?G?G!4?GG!8?C!7?@!7?G$#203!50?GG!10?C$#204!16?GG?E!8?G???GN??wGGGN@@xGGGw??F?GwN??G?C!15?A!33?B!13?}AA?z??G?FG$#206!58?O$#207!4?@!69?O!39?_G!37?_$#208!28?C!47?AAINNNFFF???F!4@FFNN!8@FLC!8?@$#209!105?G??GC!28?CCGG$#210!4?A$#211!149?@EEM$#213!142?G!7?WG$#216!70?_@$#218!69?O$#222!171?A$#223!9?WW!151?@@BFWWo$#224!11?C!134?G!14?FAAC!5?MC$#225!7?oA$#228!73?A$#232!146?O!12?!4_?!4_?_@@$#233!8?@!137?a?_!9?_!4?_$#234!8?KEE!146?GG!10?Fo_q_?_-#6!53?O??C$#8!151?G$#9!52?_!6?@!11?G!78?E$#11!58?@!12?@$#13!82?OO!67?C$#21?U!52?C$#24!4?@!13?@oBB!28?Q!4?A!26?@?A???!4@$#25!26?A?GG!15?o!42?_!4?@@B@$#28!43?o!40?CG$#29?G?@!49?C$#32??S!10?AFE!35?B!21?@_O!10?o!34?wo_!19?w$#34??A!10?C???@!29?_??@??AA!18?A???___??A@@bNN!15?___?MM!5?KK$#36!74?N!9?_!67?@$#37!11?_!14?@@!88?@$#38??_!8?OowwxNAA!22?__?M!29?O!39?AA?!4@FN]}}}___!4?!4~NN^~~C$#42!51?K!25?BNNKB!7?!6][]!5^?MNN!4?\\[?@??YW$#43!32?OO!21?@!25?G!61?A$#44!24?@@!49?M!5?C!25?@@$#49!12?G!131?_!9?oo$#51!10?O!143?ME$#52!145?_!10?O$#55!70?O$#56!4?O!48?_??G???@!88?A!7?C$#57!10?A!168?O$#58!55?O$#65!60?!4_?_$#66!55?_O???C!4?E??^~$#68!62?IM$#70!56?_!8?G$#73!5?A!141?_!10?G$#75!146?C$#80!8?GA!148?CO!17?C?_$#83!6?WSC!138?C[!9?A!7?[G$#87!6?ea!150?@!7?AEM$#88!149?W!13?E!8?@MMe_w$#94??GE!7?GA@!129?@K!8?U??_$#99!51?_??GG?A!13?C!79?O$#101!4?A!4?_?A!132?@K_???G!5?EO$#103!180?_$#104!58?A!12?A$#108!4?C!4?OC@!144?@G_$#117!177?@?G$#119!4?_!4?G!135?@!12?O$#120!177?A$#123!5?@!53?A!10?C!75?G!10?A$#124!58?C!11?A$#126!49?_$#129!54?_$#131!71?O$#132!48?_???O!18?_!80?_$#135!8?_$#136!70?@$#139!55?C!95?_$#140!54?O!27?__$#143!4?G!140?AO$#144!70?G$#146!57?@$#147!51?O!20?K$#148!49?O!7?C!24?GG$#149!150?@$#150!83?C$#156!8?OC@!139?O!6?@?_$#157!5?C!143?C!26?@?G$#159!23?@!78?M$#160}_!18?_!52?W?__$#161??@!70?c!11?O!65?AG$#162!82?C$#165!18?GNOOF!60?A!29?@!35?@$#167@$#168!147?G$#169!50?_$#171!72?@$#172!72?A!79?O$#173!24?E?CCDCC!15?!5C!25?C???B!7?E???@!13?F!6?C??AC$#175!12?C!59?o!78?@E$#176!5?o$#177!146?@???_$#179!53?G??A!121?C$#180!22?oU???A!18?wGG!39?O!13?@@!27?O$#185!44?_???O!35?W$#186!24?w}__oor~nn~~!4}MMM???BAAI!4?@?@!18?@BK???o!27?@AAB!5?E]!8?MMMN~~!4?___$#188???w!66?_!73?A!8?`@$#189!10?GC!133?O!9?@G_$#190!57?oGGYNSPNPXx_$#195!5?G!140?AO$#200!23?G???G??G!19?G!25?GOOOo!6?_G!13?_OOOwOOO???WOOO???_!9?o_$#201?@$#202!16?o{s?KKG!24?O!28?O!8?C?O!21?K!6?K$#204!26?WOAB!6?!4@pPPNPN?@@@??H@!48?O!6?A???A!6?]??!4@^PP@!7?OO$#206!115?@$#207!52?A!100?G$#208!52?C$#211!10?_?@!131?O$#213!155?G$#216!57?G$#217!58?os?O??o?_$#218!62?@???EE$#222!7?G!139?AA!10?EKA??EF??@@!4?@?E$#223!149?_!10?Oo^XH!8?ooXW?_$#225!6?@@$#227!21?_$#229!23?_!65?!13_!5?!13_$#232!8?@!150?HbL__ow_o?_?w$#233!8?A@!156?@@$#234!147?@`!19?o]~F}@!4?O-#4!183?_$#5!46?C???@!63?o$#8!45?G$#9!20?G!25?G!67?C$#11!21?A!48?O!11?@!31?A$#12!48?C!22?A$#13!18?_?O!92?C$#16!45?C$#18!18?O$#19!113?@$#21!17?O!25?O$#24B!17?C!67?_!8?!15_!10?_$#29!22?_$#32??E!6?WYOO!27?WW!31?[WC]]!8?@!25?O!9?@BMWO!16?^^$#34!21?_!20?O???@!30?@@@!6?EC!5?EEC[CCK[[[^^^[[[??oK!8?~}{o$#36!21?GA??C!46?O!43?W$#37!11?@!10?O!13?AAA!41?A!11?A???!7A!4?AA??AA!7?A!18?A$#38??@!7?D??^^@!5?OG@XB!4?OK!5?WW[CCC!44?Z!36?@FN^^^!4?@BB@[[[^^!13?G__$#40??_!81?@!56?_$#41!23?___!4?_!6?_!74?_!14?___$#42!11?A!20?E!47?C!8?EEE!25?EEE!20?A$#43!27?PP!126?G$#44!26?@!54?@$#46!27?__!126?C$#49!23?EE!5?K!114?A!9?@T$#51!159?_$#52!7?_?@!136?E!11?K$#56!7?C!39?G??A!108?A!20?@C$#57!4?@!146?@$#58!49?C$#64!57?BbbbjnFF$#65!55?[hcCCC!4?`o$#66!47?O?OSA?@@B!12?{F$#69!56?C$#70!46?__???Ccw$#80!5?A!145?C_$#83!149?@OO!9?AIY!12?WWWO$#87!5?G@!142?E`G!10?cc!14?_$#88!166?GG!5?!5BABKO$#90!167?O_?!6o$#94!154?B?_^$#98!47?CA$#99!152?BG$#101???_???OA!137?@K_!9?AG_$#102!182?O$#103!181?A$#108!6?_G!150?@C$#115!20?A!23?O!37?G!71?_$#117!49?@$#118!19?oC!93?G!38?O$#119!160?G$#123!4?M?O!140?@G!10?@$#124!52?@$#125!47?A@$#126!49?A$#128!182?G$#129!46?O$#131!19?G?@!22?_!25?_!11?U!70?C$#132!153?_$#134!7?A!140?C_!10?C_$#135!4?o!40?_$#136!69?_$#139!43?_!108?C$#140!45?O!24?G@!11?^!29?A$#143!8?@!138?AO???G!7?O$#146{!17?GB$#147!72?N!42?[!37?@G$#148!70?CG!41?W$#149!51?@$#150!71?O$#151!19?C!51?_!41?_$#152!70?@$#153!117?_$#156!6?G!144?AO$#157!7?@!153?O!20?_$#159!84?A!30?AE$#160?c!10?___??E!23?_!31?__x@!33?_$#161!73?BFA!69?{$#162!70?A$#163!21?C$#165?W!13?Owg!25?G!39?_$#167!16?C$#168!5?O!156?O$#170!46?A@!23?C!81?A$#172!115?_$#173!12?J!23?C!41?K?@G??O[??D???LGGO!6?@???@???W!9?\$#175!9?E!136?w$#176!5?@C!154?G$#179!20?@!133?O$#180!43?A?@!38?_a!6?__!15?AF@!5?W$#183!40?_?_!34?_$#184!9?___!10?CW!48?_???_!8?@!39?__!16?__$#185??W!5?_!16?W!90?_$#186!11?C!15?MM@@@O^~~!4@!39?{o???G???GO_!25?@!14?^^^[{{{B@@$#188???@$#189???]!4?C!138?O!11?O$#190!48?__?_AA{_!10?B~$#195!5?_!142?AO!10?A!19?AG$#196!114?@$#201!15?_!28?A$#202?B!13?MB@B???@!14?CC???GCC!33?AA!6?W?A!4?@@J?WWO!6?A??[?K$#204!11?GC!18?q__??w?_aBBB@@A!32?o??O!33?@!14?~___a??A$#206!155?QA$#207!138?___$#209!26?}??}A!50?e??C??_o_$#210!8?O!133?_!4?_$#211!145?@!8?C_??O$#213!8?G$#216!48?G!5?A!8?__!4?W$#217!50?_!5?O!4WSOWW]K$#218!48?OGGWWC!14?B$#219!56?A$#222!164?`!4?_!6?_??_$#223!150?E!14?_sc!8?CCDCo$#225!161?C$#227!82?_$#228!20?_!23?G$#229!32?H!47?G!8?HXxOOo?!6@!5?@@@??@!4?@xx$#232!5?C!144?G!10?@@@]^BB[P?B!7?G$#233!6?A!141?@G?_!8?@!16?_$#234!168?BMNKNKKK!5?_-#2!185?O$#5!17?_!96?N$#6!18?A!135?A$#9!41?GA!82?_!28?C$#12!155?C$#13!17?CO!63?_$#18!16?OA$#20!19?C$#22!16?G!109?_$#24!22?_??@B!9?_?AA!38?_!27?_??@!10?`$#25!21?K?CEA!11?O$#28!126?O$#29!8?C!149?@$#34?O_???_wAB!5?_!21?C!42?G!26?www~DA!5?ww?!5BK!17?A???_!9?o$#36!116?o$#38!148?O!8?@G$#40??E!17?@!95?G$#41!20?q!9?~~~www?B!35?CE?~w!50?BN!4~G!6?}{??w}w!9?W$#42!22?@!17?@$#46!81?A$#49!5?_!66?AA$#51!149?_$#52!148?A!11?E$#55!4?_$#56???O!39?A!118?O$#57!149?@G???O$#58!44?@!24?o$#62!69?@$#63!43?C$#64!58?xxxX@@E$#65!46?C!9?~~EEE?WWW^rr$#66!41?_?OAC!22?N$#68!53?G$#70!42?__?bb~~w_??F!14?_$#75!5?@!145?_!10?C$#81!151?@$#83!153?O!9?E!14?B?A$#87!151?CwG!9?@$#88!166?C??O!10?wAA_$#90!152?@!15?B??@!4B!5?@$#99!39?_!114?@_$#101???A?G@!141?@K???@!6?@W$#104!17?GG!51?u!84?G$#108???K!146?_!10?C_$#115!18?@@!21?C?@!26?H$#117!185?_$#118!40?O!114?O$#119???_!157?@$#120!183?AO$#123!4?OA!156?G$#124!42?G!26?M$#125!114?o$#126!17?OC$#128!184?C$#131!81?_$#134!4?@!145?C??A$#137!4?K$#139!40?G$#143!5?C!143?AO!10?A$#144!41?O$#146r!70?_$#147!40?C!115?O$#148!19?A!61?OO!30?W$#149!113?C!11?O$#150!113?A!10?_$#151!113?@?x$#153!40?_$#156!154?_!29?_$#157!150?A!12?_!19?C$#159!84?__$#160KM!6?wsI}Kz~@???_!16?GG!37?J!4?O!30?y{!4?w???!4CK?O$#161!145?@$#162!82?G$#164!71?E$#165?_!7?Gs?qC?MF@$#168!151?GC$#169!183?@$#170!16?_!25?@!70?_!40?G$#172!184?G$#175!155?@MCEC$#176!162?@O$#177!150?@$#179!39?O?A!73?E!39?A_$#180!21?BE_!16?A!47?C???BB!8?KKO!12?@!5?O$#182!127?_!8?_$#183?@!39?@!92?__!10?@$#184!6?OC@?@@@!6?W!19?G!32?D@@C??GG!32?@!13?BN{o!4?OO!5?@BF@A?C!9?A?w$#185!38?O!41?_??_!32?F!40?_$#186!20?Co?I`w{~~!5?BB!36?woo???@DBCC???@CAA@!44?FN^~~~??__$#188!7?@$#189???@??A!142?O!11?_$#190!42?O?wWW??FK}v_~~!12?O$#191!62?__$#195!151?O?C!8?A$#197!38?_$#199!25?C$#200!22?GOW!11?S?K!39?UO!26?[CCE!7?CCC]???G!18?GK$#201!15?O$#204!22?O!6?~???FCCB?@C!35?o?F!45?_!10?FGO_$#207??H!80?WWG$#209!20?G??@!49?GG!4?_C@AEEU}z`@!53?OOC$#210??O???G!140?@!8?@???o$#211!5?OCA!139?AK!10?BG$#216!61?EEE@$#217!50?B@!9?_??__KK$#218!43?GC!5?O?GO$#222!153?_!10?NGOOOFn}C_??FF???W@$#223!152?A!12?FJNKg!11?C$#227!42?C!28?@!9?G!42?O$#228!18?_!52?W$#229!37?_?@!39?A??!4@??W{}~{{!8~rrn~BBB!8?ABB?wwG$#230!4?A$#233!151?A!11?Goo___???w!5?CF@$#234!170?O??[{{!4wC_{W-#2!114?_$#5!16?C$#6!16?G!53?_!55?_$#9!16?O!18?_G!44?@!43?CG$#11!155?@$#12!82?_!30?C$#13!15?G!66?\!30?B!11?_A!29?_!28?@$#16!115?E$#21C!9?AA$#22!15?A?G!53?C$#24!19?@?@@@F??GG!5?@@!37?GG???L!7?GGG???CGGK???BNG!4?N!4?B!7?CGKAA$#25!102?N!7?o{!10?KK$#34??@?c`a!5_!61?O!12?Ooowww!4o!4wo!6?~~F@!7?BBA!22?@@?@!11?D$#36!18?D$#37!18?oo!7?oo!4?_G!39?O!26?O!4?O!5?O!11?O$#38!75?_!82?G$#41??A!33?A!39?BB!60?AABBBAAB!12?A$#42!29?{s?_!46?C!6?CCC!4?CC!6?Co{{{!13?w!39?C$#43!124?G$#46!160?C$#49!159?WY$#51!4?@!156?Ew$#52!151?_!9?@$#56!49?_?__$#57!152?G??C$#58!47?_!10?_!10?B$#63!37?O$#64!56?OW@HHM$#65!39?___??O???GGG?O??ONFEAE??WYizH$#66!37?__GMP?O!14?O??O$#68!45?BAA$#70!38?O??EB???@@OOOE!16?b$#71!62?O!4?s$#75!164?G$#76!44?_$#80!173?_$#81!152?@??_!11?`!6?O$#83!166?_]pAH!14?_$#87!165?W??A??C$#88!183?_E$#94!158?_??_$#98!81?o!32?W$#99!15?_A@!19?C!32?K!55?O!29?K$#101!150?@K!10?B_$#103!80?_$#104!38?@!31?B$#108???A!33?G!114?_!10?W!8?O$#111!60?_$#113!186?C$#115!35?O??A!74?_!42?O$#116!186?O$#117!186?G$#118!70?O!10?A!43?B$#119???@!159?A_$#123!38?C!18?_!11?{!81?@!12?O!20?C$#124!36?_!22?_$#125!81?K!32?F$#129!40?@$#131!15?O@!20?A!75?O!11?GC!29?A$#132!17?A!139?_$#134!163?@!7?OG$#135!39?A$#136!46?_!14?_$#139!16?_!17?_!78?G!11?O$#140!39?@$#142!51?W?O!11?O$#143!151?AO!10?C!21?A$#144!48?_?_??!4_$#146z!13?O$#147!14?_!56?o!8?A!46?_$#148!36?S$#149!17?C!97?O$#151!115?@$#152!71?B$#156!153?_!17?g$#157!185?G$#160!6?@@BFCC???@!21?@!74?@!4?@??!4@$#161!134?N!14?K$#163!126?@$#165?xGG??G?C?@@NN!18?OW$#167!157?C$#169!80?O!34?_!40?@$#170!82?A!74?O$#171!15?C$#172!35?G!121?G!14?_!13?_$#175!149?OW!6?A?@@$#176!164?A_$#177!153?G@!30?O$#179!80?G!34?G$#180!13?O!16?G{KCS?@!73?G?K!4?{{?ooo?_$#182!19?GCGGG!49?@@@!7?K?G!26?A!11?A!12?G$#183!133?N?N!12?[$#184??CC!17?CCo!48?[AAA???_!4?oo_!44?NNOOO^O!8?MNb_$#185!17?oG!16?C!36?__?OwC?O@??p!32?r!10?WOOOoO??___!8{oo??_$#186!20?rq???o~FF!6?A!42?_!5?F!39?C???EE$#189!150?AO!10?C$#190!38?G?OGCNHKKS@@C?FFNN???O!8?[$#191!53?G!8?G?_$#193!155?G$#195!152?AO?O!8?C$#199!25?N$#200!101?_!4?_$#201?EooW]S]!4W__N!4?CG!54?CC!12?CCCG???!4C!9?wE!6?A??CA$#204!12?O!9?qEw!4?!5@!38?BCCG?wQ!5?GF!26?_???C!6?O???@HHN?___??F@@$#207!127?C?__$#209!74?_!4?G!36?G!6?_???A_!30?A$#210!4?A!13?A!64?A!65?A!7?@O$#211!150?C!4?A$#213!149?@!9?__W$#216!42?O!18?@_$#217!42?G!4?GCC??G!6?CO?FFDDC$#218!39?S!4?EOO?AAB@$#219!42?__?_!8?O???G!4?_???A$#220!152?C$#222!153?D!15?CC?EFm?C!6?@$#223!153?AC!14?O_??W??o!6?MH$#228!71?G!8?C!43?@$#229!19?A!9?!6A!44?B!6?!13B??B?BBB$#232!154?O!10?A???gO!4?GG_?GGG$#233!154?i!9?@D^?K@A@@??o!8?o$#234!171?A??@FB^~vvv~O-#2!114?B$#4!187?A$#5!14?_!18?A!79?G?O!10?B$#6!15?@!20?G!29?_???C!9?@A!44?G!30?E$#8!49?@@!7?@@!53?@?A!10?_$#9!15?C!15?O!9?OA!10?@!9?A!18?_!32?_!41?H_$#10!187?O$#11!65?O!14?O?C!75?O$#12!39?C??_??@_!15?A!64?C$#13!116?_!41?G$#14!37?O!33?O$#16!16?@$#17!64?G$#18!71?C$#22!116?C!8?C!32?A$#24E!21?E?AAE???C!22?C!30?A???A!48?A???A$#25!111?@!7?][$#28!116?@$#29!26?_!56?G_!43?_!30?E!12?G$#34?`~vVv~~!4N@!33?C?C???C!30?QO???@D@@@!8`!6?~~!19?OW$#36!43?G!5?_!11?O!10?B!44?O$#37_!16?A?@!9?@?@!53?_!7?!8Oo!4?o!17?B!5?O$#38!83?C!75?@??O$#40!73?@!54?A$#41!18?{{!33?G!20?[?OB_!13?CC!28?O`!7?!4Oo!13?BDI!8?AE$#42!11?_!5?@!12?@!31?G!13?_?A!12?C?G!8K!4~!4?@!6?@F`?KC?o!5?M$#43!61?G!13?{Ko???O!54?__!22?C$#44!17?{B!6?[!18?KCG?O[??O!9?OO!9?}!4?G!5?D!7?aA!30?C!4?E?__?_???^~~ppH!4@___O!9?_$#46!63?g!13?K$#49!43?C!28?W?_B@!82?G??G$#52!152?G!11?_$#55!35?G!45?_$#56!67?_!97?O!7?_!12?@$#57!66?G!89?A!16?G$#58!34?C!34?F$#63!35?A$#66!33?o??@@!29?GG$#67!66?A$#69!38?@@$#70!68?T$#73!156?C!8?A!7?A$#79!154?C$#80!156?O!29?o$#81!167?_C??C$#83!154?@C!10?@@@?_!5?___$#87!155?h!10?C!18?@$#88!156?_$#94!64?O!86?@!8?@XC$#98!81?@$#99!14?G!17?G!4?C!6?_???@??@@?!4@??@@??C!5?w!9?G!45?O$#101!63?@!88?Bo??@!6?@W$#103!37?G$#104!41?A?_?_?@$#108!35?@!117?G!10?E_$#111!69?o$#113!114?C$#115!32?C?A???C?A??A!18?@!16?_??O!44?o$#117!113?E!73?C$#118!15?A!17?C!5?OO!24?G$#119!153?A!11?G!6?_O$#123!33?G!6?_@!72?_!50?C!7?C$#124!39?_!29?G$#125!34?@!45?A!32?o?K$#126!14?O!55?B!9?C!45?C$#128!187?G$#129!32?_$#131!14?C!16?_!6?O!7?@!19?O!15?G$#132!15?G!23?A??O!39?A!32?@!11?G$#134!153?@O!31?A$#135!154?_$#136!36?A???@!24?A$#139!30?_!48?O?C@$#140!44?A!19?A!92?O$#143!42?@!71?O!38?C!10?@!7?O$#144!35?O?A$#147!31?CA!7?GC??O!13?A!12?@!7?A!32?o$#148!15?O!45?A!9?_!100?C$#149!45?A!79?@!46?A$#150!13?_!57?G$#151!172?@$#152!87?C$#156!154?G$#157!165?@_!19?C$#159!30?A!87?O$#160!109?_$#161!29?_!21?O!27?@!5?W$#164!30?O$#165!13?W!16?G!56?G!22?O!6?A$#167!47?A!62?_$#169!36?C?G!148?_$#170!14?A!16?G?@!4?A!40?G$#171!14?@!45?A??C$#172!46?A!18?_!13?C!45?A$#173!26?O??O!76?G!25?G???GG$#175!41?GK!5?_??_!31?_!28?K!39?_!4?_@o$#176!171?A$#179!39?GC??O???_!66?G?O!10?A!30?C$#180!12?O!18?A!55?A!22?EE!8?AAA?G$#181@!11?_!105?G?@@@$#182!88?W?O!20?_!5?G$#183!50?AM!78?_$#184!4?_!11?{!6?~{_!19?G?SIA{?i!31?G@@@?w__!33?W??G_!21?_!8?_$#185!45?O!7?!5A!25?@!28?A!15?C$#186!9?__!9?r~???@@NN!32?C_!15?@!7?__c??GG!25?_??og]!7?N@nNNV!5?Eee}}}][Y$#188!41?_?@!12?W???_!56?_!44?@M$#189!32?O!119?C$#190!34?O$#191!36?_$#195!156?G!9?O!4?@?@!12?G$#196!65?C!14?_G$#200!19?AK!8?M!48?C!12?A??!7AB!4?F!25?E$#201!12?AF??A!69?[O!22?G!5?AC$#202?]?GGG??oOOOK!15?_!18?G!37?EA??AM!18?^?W$#204W!21?x?@?GoO!62?OO!19?@!7?_!16?T_??KGOW???@$#207!36?O!16?ooKCssKC_C?_!9?B?A?O!46?_??@@@!20?C!10?A$#209!32?@!21?K$#210!46?O!25?c!89?__$#211!152?O$#213!55?o_GGoW!99?W??O$#216!35?C??_!25?@?CO$#218!34?g!33?A$#219!35?_?_!27?@@F_$#222!167?]WQK???GBD^^]{wo]QI$#223!168?_k@???v_A!6?@?O$#225!155?O$#227!15?_$#228!44?@!14?A!11?A!44?G!10?@$#232!184?__$#233!154?AA!10?I?A@Q_???C???_???_@$#234!171?W???WW??@BFN?KC-#4!188?_$#6!67?AG??_!10?C!30?A!13?w$#8!64?O$#9!13?CA!33?@!4?C!7?O!8?AO!7?@!47?@$#11!14?C!12?O!21?A!10?O!5?_!15?O!33?O$#12!61?G!4?@!45?C!4?O!8?W!32?O$#13!12?_!15?C!42?@!6?_!33?A??@$#16!12?O$#18!67?G$#19!14?O$#21!14?_!113?w$#25!137?A!5?CG$#29!26?@!83?A!17?F?W$#34?B!4~BB!8?B@?W!6?G?@!55?@!8?@!4BbBB!6?^N!15?o!5?c!19?CC$#36!54?@@???C??C!15?A!5?W!33?C!41?O$#37B!26?A!37?A!19?@@@!13?@!4?@???_$#38!65?C!9?C!48?C!36?K$#40!61?C??A$#41!9?C!8?A!54?w?P!37?O!7?_GN@!6?KGG?B$#42!7?GWyDf!5?W?BBK???O!49?A~E!7?K!11?GGGWW!4^!13?B??O!14?@$#43!124?A!11?K$#44!17?A!7?A!27?@!19?F?G!8?C!4?NMKHO!24?A!6?C!5?BB?@!4?^^Rr!5?^^JOO!8?O$#46!63?@!10?O???@$#49!74?B!86?AA$#51!175?o$#52!153?E$#55!80?@!34?A$#56!48?A??C!16?AG!10?A@$#57!166?O!5?K$#58!47?A??C!11?_!18?C!32?@$#62!115?G$#64!52?G$#65!45?A?C!5?OO$#66!30?GM@B!80?W_$#67!31?OG?C!9?A$#70!32?C?A$#71!58?_$#73!176?O$#74!68?@$#75!166?@$#80!155?A!19?AG_$#81!155?@!12?C!8?G$#83!156?C!11?A?B!6?RB$#87!156?__!9?A$#88!156?@!29?C$#99!27?_G?@!16?@???A??C!4?G??OO!6?@!8?G??H!29?O???A!10?A!30?@$#101!153?H_!10?}!7?@C!12?C$#103!68?O$#104!56?G!8?O!13?O!33?C!44?G$#108!154?W!10?@$#113!188?W$#115!55?C!4?G!6?@C??G!40?G???@_!8?@!32?_$#118!13?w@!14?C!20?A!6?GG!8?_!11?E??A!29?_???G!10?C!30?E$#119!54?G!99?A??@!8?_!5?r??G!11?o$#123!28?_?C!13?@!12?O!5?_!16?C!73?@!11?K!7?A$#124!53?G!26?G$#125!113?@$#126!68?__!46?C$#129!80?O$#130!29?O!84?A$#131!13?A!14?OA!16?@!23?CC!11?_!42?A$#132!52?A!13?O??OG!55?C$#134!155?_?A$#135!166?A$#136!43?@!12?O!4?_!7?@!11?G$#139!49?@!17?C!90?O$#140!13?@!38?C!18?A!7?_???O!29?G!59?_$#142!34?www}}}!8woo$#143!58?O!5?_!89?C!21?_!10?G$#144!31?@!49?A!31?_?C$#146!15?@$#147!27?GA!22?@!5?C!5?G!14?C!4?A!27?O!5?A!41?A$#148!14?G!15?A!39?O$#149!83?G!89?K$#150!78?O$#151!158?_!14?A$#152!12?C$#153!55?G$#156!155?O!19?C$#157!155?G?C$#159K$#160!8?@!6?C!94?C$#161!83?@$#162!70?_$#163!26?_$#165!12?G!97?@$#167!15?A$#169!126?_$#170!56?C!10?O!91?G!13?O$#171!159?C$#172!29?@!20?@!32?C!27?_!5?C$#175!52?@?AA??C!5?G@!18?a!32?@o!33?N!6?@_?C_!23?A$#176!174?@$#177!157?O!9?_$#179!53?A!8?G!49?@!4?G!69?@$#180!7?O??wWB!8?_??W??@!58?AE!49?C$#181!9?@$#182!95?wO!22?O!9?B!14?_$#183!111?G!18?@$#184!8?A!6?G!7?BB@?C!38?G!5?{??_!14?@BEM[?__!13?F!7?G!4?Gw!4?A!10?K?_!5?__J!8?@@xO$#185!15?o!10?C!38?GC!51?G_$#186!10?A!10?BWW!38?@!14?X!7?Qw?^___!4?G!23?r^F!8?OSV?[RO!5?JF~~~!4?_$#188!45?@!107?o$#191!29?_?__???E!9?C!4?G__$#195!155?C?G$#196!82?_$#197!29?G!29?O!5?_!50?_$#200O_!5?cc!7?Wc???O___G!60?Cw!8?CCCSce!4_}???O!8?CK?_o!7?__?W__g__!4?O!6?_$#201_C!4?C!9?C?CCC!5?A!68?C!13?F!19?C!8?F$#202?W!4?w!9?_?w_w!5?O!70?OO_!7?_owG!18?W!8?W!11?O$#204!18?@???FCCc!59?_??_OOOo__!23?@!10?_???_e!5?__KO!4?_$#207!56?B@BACBACD!9?g??_!47?B!35?_$#209!74?C$#210!72?B!87?M??N{$#211!174?G$#213!57?A?@B??A!100?B!9?o$#216!42?@???A??C!10?_!8?E!10?_O!32?CO$#218!32?AC@!46?_!32?_$#219!30?o?Ow?F!4@FFEECC??KGwoO?_o__?_$#222!168?@y?g???@??_oPtHCCE@$#223!169?D!6?C??K_?C???A$#225!156?O$#228!66?A!11?G$#232!168?w!9?O?GG??B@$#233!156?G!10?\??{@!4?BCKBC?oB$#234!156?A!14?U!8?AAA!4w-#4!188?@$#5!12?o!58?A$#6!71?@$#8!159?@$#9!13?@!10?O!53?[!32?C!15?O!31?_$#11!12?@!65?_!33?A!60?_$#12!72?O$#13!23?_!48?G$#16!126?G$#18!72?A$#19!79?@$#20!11?O$#21!128?F$#22!72?@!4?G!7?O$#23!125?_$#25!123?C$#29!75?XO!85?A$#34??~!5F!8?VV^!5?@!50?_!23?@B!5F?OO?C!9?CF??@!6?FFE!16?OO?_$#36!73?@???A!41?O!41?@$#37!23?G$#38!75?E_!99?A$#41!76?@$#42!4?o_oo?@?@!7?_oG!54?G!8?@??o!18?@@@!11?oo!8?o!6?@@!9?@$#44!8?O!12?O?A!50?N?A!8?AC_?!16O?__!24?!5O?o_o?VVF~~~ww_g~O$#46!112?C!37?A!24?G$#49!74?O?C!97?c?{G$#51!174?@P$#52!165?^$#55!25?O!44?@!11?@!34?_$#56!116?@!38?G!10?A$#57!155?A!31?~$#58!70?C!8?G$#62!25?_GA!54?C_$#63!79?_!32?_$#65!28?C!39?w$#66!70?_!11?w!30?CFF$#67!80?@$#69!27?_oo~~~!36?E$#70!80?E~!32?G$#71!67?}$#75!158?G$#80!156?G!21?CO$#83!156?@!24?oGo$#87!157?@!24?o$#88!169?w$#90!171?A$#94!153?M_!22?O$#99!12?C!58?G!11?EO!26?W@!4?D_!8?G!31?Q$#101!26?C!127?B!17?_!5?_$#104!12?A!11?_G!58?_!33?O$#108!79?A!75?o!10?w!5?[!4?C$#115!13?A!11?CB!51?A!4?@G!26?_!61?M$#118!12?G!58?C!45?A!9?F!31?K$#119!79?C??A!72?C!10?@$#123!116?A!38?@??A!18?A$#124!67?@!44?O@$#128!188?}$#129!79?O$#130!70?G$#131!71?O_!44?GG!54?P$#132!78?@!32?A$#134!158?C!19?G$#136!116?C$#139!13?C!96?_$#140!83?G$#142!33?!28~}{{{}}$#143!158?@!7?C!5?B!5?O$#144!68?@?A!12?O!28?G$#146!11?G!98?G$#147!13?_!105?_$#148!71?_!12?C!42?_$#149!72?C$#150!11?_!98?O!6?O$#151!160?_$#152!126?_$#156!156?_?O!18?@$#157!158?_!8?_$#159!69?@!54?CG$#161!14?G!8?OA!60?Cw!73?A?D$#164!160?C$#167!24?C$#169!24?G$#170!13?G!63?_!7?_!32?C!7?B$#171!126?O$#172!13?O!104?A!41?W$#173?w?OG?GG?_!5?E???]MA!66?G!13?GGG?E??G!11?GMAAC!5?GGG??AGGG!8?E$#175!14?U!10?@!47?o???C!7?G!32?@M!40?@ww~~$#176!167?B$#179!25?A!51?O!33?@!14?C$#180!5?G!4?FE!96?E$#181!5?O!117?G?O$#182|!98?A!20?X$#183A!13?@!104?@$#184!74?_!12?O@!7?@@@?C!8?oA!9?_!4?@!7?@!27?E$#185!84?@!44?F$#186!8?_!8?__???I!63?@?C!6n!4k!7_!26?___nl@??F?__!5?CD@$#188!175?_$#189!154?[!21?@$#191!26?o[IA!86?_$#195!156?O!10?[!11?_$#197!27?@$#200???_!11?@???@@`!84?@???@!11?@p!24?@$#201!10?O!113?_$#202???G!4?F?g!4?GGG!5?@!63?G!19?Gg!11?A???WA??ww~!8?O!10?G$#204?F!6?GW!5?O!6?p!63?AFA!6?BAAAKGG!4?G!27?N??o??G~GGw$#207!77?@$#209!15?__!5?CC!81?WO!42?A?E!22?G$#210!73?M$#211!153?@!11?_$#213!14?_!159?QE?_$#216!28?@!37?@???O!42?A??G$#218!68?E!11?w!32?wowO$#219!29?L!31?@BBB@???w$#222!156?C!13?@!7?@?B@@$#223!168?WB?G!13?G$#228!84?A$#229!9?E!11?C!85?E?E!27?EEE$#232!157?C!10?_?yC!7?K{E???C$#233!156?Ay!10?F?C!7?AB?GCG$#234!169?C?p!10?AF~r~-#0!39?!5_?___$#2!37?_!10?_$#4!188?E$#5!119?_$#6!72?G!45?@$#8!35?_$#9!11?G!10?C!49?@!12?C!24?D!56?_$#10!44?O$#11!108?_$#12!54?C!22?@$#13!76?_!82?wK!6?G$#16!108?O$#18!20?_!66?O$#22!10?_!10?C!98?_$#28@$#29!5?Kk!69?@!31?A!43?_g$#34??~]MA?GG!7?_!91?@!12?E!6M}NM]}}!17?o?B$#36!161?_$#37!162?o$#38!179?_$#42!8?@!9?o_A@!66?P?CCC!30?_?__$#43!74?K$#44!15?_!4?GA!53?B!11?@!12?MMMm{}P@!12?EWo!14?E~~~!4M^^^?cC@B!9?GCC$#46!74?O!88?_wo!8?CO$#51!78?A!75?A!19?__?ACO$#52!166?C$#55!23?C@!22?O!5?C!17?A$#56!78?C!100?G$#58!22?_!32?C$#62!111?C$#63!54?O$#64!35?O$#65!53?o??C???O!7?@!11?A!32?_B$#66!79?po?F\G!26?wIK???o$#67!34?O$#69!25?_a~~NN^n???FBBBFCCK??C???C?A??@!13?]E$#70!81?~w__$#71!67?@$#73!156?A!23?O$#80!171?C!8?G$#83!158?_!22?_kw$#87!182?B$#88!169?H?A!12?B@$#90!186?A$#94!166?G!9?FC$#99!11?oA!8?_!50?a!4?W!7?A!23?O!62?O$#101!155?}!10?@$#102!187?F$#104!12?C!9?G@!53?c!8?_!22?G!8?C!40?@$#105!38?_$#108!155?@!22?@$#111!49?O$#113!36?_!12?_$#115!11?C!9?O!63?@G!32?G!47?O!4?G$#118!12?@!59?S!13?O!23?A!7?AO!52?_$#120!33?_$#123!37?O!33?G!6?G!5?AO!24?O!56?A!12?_$#124!56?G!14?o!6?O!38?A$#128!188?@$#129!78?_$#130!24?A!28?A?_$#131!12?G!10?A!53?A!81?A$#132!11?Ao$#134!156?{!11?[??_!7?C$#136!23?G!12?O!20?O!26?C$#139!119?C$#140!55?G!31?_!21?c!8?G!40?Co!11?C@$#142!33?BBB!5?JJ!7B@@!4?@?!4N!5~}o$#143!38?O$#144!48?O!22?C!39?A!5?@_$#145!44?_$#146!4?_??o!159?C$#147!13?@!25?O!31?@?K??G!8?GA!100?G$#148!22?A!33?_!103?@!12?E$#149!21?G!56?@$#150!55?O!117?G$#151!172?A$#156!156?@!10?@_$#157!171?O!7?A$#159!14?C!87?O!15?O$#160!109?@$#161!4?OoO!145?WO!9?@@$#162!56?O!54?@$#163!73?_$#164!173?_$#165!127?@$#169!43?O!143?_$#170!11?@!29?OO??O!40?C!32?A!40?A$#172!109?A$#173?@!7?@$#175!13?o!59?@??C!9?@!33?O!33?w!6?NB??@$#179!34?_!5?O!9?_!25?O!110?O$#180!19?O!55?O$#181!7?@!9?O!4?@!102?@@$#182o_!8?O!88?O!8?G$#184!14?_!5?O!53?@!25?O???A?mMC!11?@!13?}}}w!10?WXxKCC!8?CAA$#185M!14?M!57?A!87?O!4?_$#186!9?_!4?AO!72?M~zzz!6~!6?@?O!34?__!4?AAA$#188!22?O!23?O!10?_!117?@?G$#189!166?A!11?A$#190!24?G!5?_??O!81?CC$#191!23?os^???_???KKK?CGG!4?C??CCCOCC?_A?C?_!10?G!43?g_@G$#195!158?B!9?A??G!7?@$#197!54?G!29?@$#200?M?_@@@?q]K!6?_!57?_!45?@@PoOO_?oo@@@!14?@$#201?O!4?AEC?A!5?O???C!103?@??O???_$#202???@!6?@!117?@?@$#204!13?AO!84?n`p`P@!29?!4@???pPPp___c??A$#205!13?C!5?G$#207!13?GH?NKGE!54?a!12?K!19?_$#209!15?@?!4@!66?A!75?W$#210!75?KA!11?_!31?G_!43?CO$#211!165?A!6?@$#213!17?AE!135?D!10?G!8?ZMwpw$#216!51?_?GA???_!26?_!24?_?@!4?C$#217!113?OOWo$#218!29?OO_O!18?O_!4?G!21?ML??AO!27?sBCBI$#219!26?\!9?GGCCG???GK!4GIIX@@?ABOO_o!6?M`p$#222!157?oC!10?O$#223!169?Cq!14?u$#224!186?_$#227!110?G!62?O$#228!73?O!45?@$#232!157?K!11?_L!9?BM??oGO$#233!158?W!9?@!11?CPOF$#234!157?B!11?A?@!12?K?L-#0!30?C?A?@!16?A$#2!27?OG??A?@!20?O$#4!35?O!10?O?_!6?_$#5!119?D$#6!11?G!7?O!100?_$#7!33?_??O$#8!30?A!88?OW$#9!72?A???O!11?O_!18?@!6?GG!10?o!44?C$#10!187?B$#11!59?_!54?G$#12!57?@!14?_A?_!30?O!13?A$#13!89?O!69?OC!11?_$#22!10?B!104?O$#23!77?A$#28[!14?O!113?{!6?__!23?G$#29!16?CO$#30!18?G!97?O_???O$#34!5?@TTW{!4?O?B?C!71?CGG!9?EE!17?C@!9?@@!17?@$#36!122?_!38?A$#37!8?@!6?A!90?@!17?_!5?_!31?B$#40!161?@$#42!18?@!106?B$#43!104?_$#44!9?A!5?@!73?A!13?@@@!15?B!16?@BB!8?@???A!19?A$#46!89?@!74?F$#47!45?O$#48!47?_$#49!74?C!41?_!56?_c!4?B$#51!174?@$#55!86?@!21?G!8?C$#56!57?A!19?C!31?@!6?C!63?O$#57!171?A!8?@$#58!25?_???A!78?_???G$#63!57?C!51?C$#64!59?A!52?C$#65!22?A!33?C!27?@G!27?@?A@$#66!71?G!6?@???_???C!22?WEA!5?@$#67!27?C!32?G!25?__$#68!61?O$#69!23?NFB@!29?A!27?uQ$#70!78?C~~~B@!26?@@$#72!38?O$#75!186?_$#77!35?_!5?O!4?_$#80!158?o!11?_!10?O!4?A$#82!157?[!11?C!12?WGC_$#83!181?C?F$#87!181?BF$#88!170?C$#90!157?_!10?O$#95!37?O$#97!32?_!5?GGG?GG$#98!119?G$#99!11?@!8?A!51?@???K!11?G!19?A?_?O!4?G!49?@!4?A$#100!187?G$#101!21?C!133?^$#103!32?@$#104!19?G!53?_??A!50?K!38?_A$#105!31?_??O??G!6?G??O??@?CG$#111!52?@???@!61?A$#113!26?_??C!11?G$#115!72?CO??_!42?_!7?A$#116!18?_!34?C!66?C!66?C$#117!19?_!167?_$#118!11?u!8?_!66?B!18?_W!10?GA!52?@$#119!180?G$#123!21?G!36?P!18?G!37?C??@!37?]!23?E$#124!21?O!36?_C!26?A!22?AO$#125!20?[$#128!51?@A!134?O$#129!77?O!30?O$#131!21?@!36?C!13?GG??@!11?C!19?C??_?O!52?O!5?G$#132!59?O!12?OC!33?C!18?_!40?C$#133!39?OO?OO$#134!171?@$#135!156?`$#136!21?_!31?A??_???_!10?B!15?O$#139!12?@!7?@$#140!12?}!6?C!57?@!48?O!32?_B!5?G!4?_O$#141!55?G$#142!61?B!7~{~$#143!26?O!140?_???C!8?_$#144!27?GC??@!23?O!31?G$#145!27?_oww[[]MNN!8FNNN^~}{wo_$#146!10?w!6?_$#147!88?@!17?G@!5?_$#148!21?A!65?C!19?_!18?G!40?G$#149!88?a!25?O!11?C!33?O$#150!127?@$#152!58?A!30?G$#154!34?_!9?O$#156!186?O$#157!168?@$#159???A!88?C!6?A???_?C!20?@$#161!75?E!29?_!12?O??_$#163!118?C$#164!19?A$#165!17?G!110?{!5?_$#167!10?C??G??_$#168!158?C$#170!73?@!35?_!49?GG!5?C$#172!18?O!56?G!90?@$#173!123?F!6?CC???C$#175!13?B!60?W!14?C_!23?_??O$#177!158?G!9?C!12?G$#179!54?G!20?O!31?A!4?_!7?@!38?F_!5?A$#180?[!14?O!86?G!20?B!9?[$#181???@$#182B@!134?AA!12?AA$#183_!12?o$#184!5?C?AE!5?NK!59?@!14?Woowwo_???[[@!12?_!5?G!12?!4@}C{!9?@?[\!7?C$#185!13?C!91?O!12?_!42?O$#186??O[A!85?BBBFFF^^~``_??O!17?C??[!6?[[??[!5?VV!4^[{{{_!9?gy$#188!59?G!14?_!38?G$#189!155?_!15?G!7?w$#190!22?O???C!28?@!22?_!35?A$#191!25?KA@@@!24?B?GO??Bk!21?[GC!28?@@$#195!168?A!12?_!4?K$#197!58?G$#200?_G?@a___!5?_??@A!83?W?G!19?O!4?BZW???W!5?GGG$#201?AB???A!10?E!104?A!5?B??B!4A!16?@!20?@$#202!5?WGG!7?_G!107?K!6?___?_???w$#204!19?@!75?G?_?[AB_?EIA!16?W!13?[???v!6_bA??A!9?O$#205!91?C$#207!106?C!15?W??_!28?_!10?b$#209!4?C!4?@!152?CDG$#210!74?A!79?@!6?_!14?G?o$#211!154?[!12?O!5?[W}s{K$#213!74?@!79?A!10?[!8?A@BBBC$#216!22?@!7?@!23?C!5?O!10?C!5?_!36?C$#217!22?_!90?A$#218!27?A!25?@!5?@!18?Y???[A??W!23?GCB$#219!22?KowOG?A!26?EOg??C!8?B?o!11?_?`!25?G?C??AA$#223!169?wZ!11?_??N@$#224!168?G$#226!36?!10_$#227!171?O$#228!111?O!14?A$#229??c_w!98?O!19?_!29?_!10?o$#232!157?@!25?ozO$#233!157?AB!10?B$#234!168?_-#0!24?C!30?@?_$#2!17?G$#4!16?_!5?G!34?G!129?@$#5!18?@J!84?OC!20?G$#6!19?_!100?w$#7!29?A!4?G!4?A!9?@A_$#9!11?G_!60?@!30?G?A!4?CCG?O!10?A!32?_!6?F!4?K$#11!12?E!77?O!68?C$#12!59?@$#13!72?@!92?O$#14!20?A!51?_$#18!119?O!40?G$#21!125?G!40?_$#22C!159?_$#24!8?_!114?_$#28!15?_!113?B!35?A$#29!128?C$#34!9?~!114?G???ogw~~~$#36!13?A!78?G!20?@B$#38?_!99?o!22?O$#42!16?C!146?G$#46!99?AA!53?B!7?AAA$#47!37?C$#48!28?C??_O!4?A!4?@!8?OO$#49!101?G!59?CG!13?@@?wW$#50!58?O$#53!35?_!9?@$#55!75?_!13?C_!19?C?G$#56!76?A!104?_$#57!106?C$#58!24?@!51?C!36?O$#62!20?G$#63!58?@!55?_$#64!21?@!37?G!47?CC$#65!60?O!10?K!13?E?B$#66!76?OwO~??B???A?Co$#67!22?@@!47?@!38?OO$#68!85?w$#69!58?Co!24?F?w!21?o$#70!71?A!4?_BG?~~C???@?G$#72!30?A!18?A$#73!181?A$#77!26?O!7?C?A??@!7?@@$#80!158?B!8?O!17?_$#82!168?GC!12?AB?F$#87!182?[$#88!168?aO$#90!157?B!10?OG!13?G$#92!25?_???C!8?@!13?_$#94!13?C$#95!35?C!7?@@$#97!28?A?@?_OO!7?A???A??C??G$#98!17?O$#99!11?F!63?E!14?K!14?A??A?A!15?C$#101!155?h!24?A$#102!186?G$#103!58?_$#104!11?O!5?_!55?u?G!13?A!69?O!11?A$#105!21?_?_OG@!6?__!7?CQAA!4?P??O??CO$#108!180?@$#109!40?C?O$#111!20?O?CA!33?A!51?C$#113!21?O???@?C!28?A!130?E$#114!26?G!8?G!4?AA!5?A??GC?_$#115!11?_O!60?GO@!15?O!15?A!18?@@!31?G!6?G!4?P$#116!16?O$#117!17?CC!4?CA!84?@$#118!74?_!16?_!24?_$#119!88?@!97?C$#120!20?_G!164?A$#123!60?@!106?@??O!10?O$#124!60?G$#125!18?AC!86?@?@!11?E!5?o$#126!19?O!69?@!19?A!10?@$#129!76?G$#131!12?G!7?@!82?__!9?O!12?A$#132!114?G$#133!27?G!4?@G??G??C@!5?@???CG$#134!158?_!8?A??G!10?C!4?@$#135!89?G!66?~!24?G$#136!88?A$#139!12?@!5?G!71?A!28?@!7?C!37?_$#140!75?O!29?G!9?_?_!9?G!31?B!6?O$#142!61?A!9~!11?www!22?w$#144!20?C!38?C!45?O$#145!22?oWGEEB@@!13?k!5{w_BFN~}w$#146!10?F!154?C$#147!57?C!16?A!16?C!12?A!7?A??GG!4?G!64?O$#148!72?E!54?O!44?@$#149!72?W???@!42?C$#151!160?E$#154!38?C$#155!41?@$#156!158?O!8?C!13?@$#157!170?A$#159G!58?AC$#161!92?_!28?@$#162!127?_$#164!119?_!51?_$#165!128?B!5?B$#166!25?O!9?O!6?_$#169!17?A_!55?G!36?A!13?_!60?_$#170!18?O!72?G!12?C@?@!5?C!5?A$#172!17?@!38?@!64?U!38?O$#173?O!6?W!6?G!83?WG!48?OO$#175!91?B!10?_G!8?@?C$#177!182?_$#178!24?_!6?@!4?C?A??CG!5?A$#179!74?C!15?@!12?O!6?@!5?O??G?_???O!34?@!4?G$#180?K?O??BB!8?A!82?_o!22?E$#183B!12?`!108?B$#184!14?wO!76?BxXH~~w???W!12?ECN|???_O!10?__!7~!5B!4?ww!7?B???@!6?O!7?_$#185!13?W!78?O!20?A???O$#186??_!89?CCCo??F@DB?A!12?B!27?!4wonnJFF!8?@$#188!60?A!13?@!36?@$#189!155?U!24?C$#191!21?A!38?_|!9?o!15?w!18?O??__??_$#193!170?C$#195!158?K!8?G??@$#199o$#200?B!6?F!5?C@@!86?@!20?C!5?F!17?K$#201!15?C!108?_!9?K!37?C$#202!10?w!4?A!102?A!9?GS!4?O^!36?G$#204!93?AAE!6?C!19?WG?E!17?{!4CB??o$#205!103?C$#207!104?@!20?@!36?C_O!7?_$#209!94?_!6?C!13?@!35?C??C!8?TK$#210!122?C!31?G!6?wo!15?@E$#211!154?o!18?~~~}}}@$#213!164?_$#216!58?G!46?_!5?G$#218!77?Cf!9?o$#219!21?CA!34?@A!24?F?@CC!18?g?GWG_o$#220!170?_$#222!185?O$#223!157?C!10?C`!12?@Oo$#226!26?_oww{]MFBBpx!4w$#227!172?A$#228!16?G$#229??^n~~{{!6?B!84?C??B!20?@B!39?@$#232!169?A!14?NG$#234!157?w!9?_@!14?c-#0!20?G!7?_o!16wo_owwW$#4!21?G!32?A!131?G$#5!12?W!88?OC!22?G$#6!12?a!5?W!101?A$#7!23?@!5?C!16?G?G$#8!15?C??c@!53?@!52?G$#9!92?W!66?@$#10!19?W@!165?@$#11!11?A!157?_$#12!15?A???C!52?O!19?A$#13!13?_!110?_!33?OO!4?G$#14!72?G$#18!93?O!76?_$#21!158?G$#22!163?_A$#24???C!4GC!118?A!23?K$#25F!93?GG$#27!55?O$#28!123?CC!4?A!4?@$#29?o!7?N$#34??w!5o?O!91?@!28?@BB@$#36!14?C!107?O!37?G$#37!163?O$#38??E!93?B???C!27?C??CCE!4?FFF!21?B!8?W!6?A?A$#40!99?_!22?G$#41!149?oo!11?G!9?O!5?_$#42!127?_$#43!94?C???CA$#46!94?a???OO!53?E!23?O$#48!35?@!11?A!5?@$#49!178?@[D$#51!154?o$#52!180?O$#53!52?a$#55!74?G!41?@$#56!102?OC@!76?w$#57!185?O$#62!56?O!62?o$#63!75?A!26?_GA$#64!56?_$#65!88?@!16?B!10?C$#66!57?G!17?{BAB@!9?NK!26?sO$#67!71?B!8?G!35?O$#68!68?F!7?oO??C!4?@???o!13?__!10?K$#69!61?A!19?U!4?@!18?C???BFEEEB$#70!76?KLC}B!9?O!13?O!13?_$#71!60?GG!6?G?G$#72!23?A!23?G$#77!22?G?@?_?C!8?AA!13?@A_$#82!168?C!14?N$#87!166?w?G$#88!167?@@!15?^$#92!54?O$#94!93?A!66?O!12?ooo$#95!21?O!14?A!15?[?C$#97!22?A!5?O??@???A??C??A@!8?@$#98!16?@!39?@@!15?W!51?o@$#99!12?@!61?@!42?@??o!4?C!38?_C$#101!155?F!15?C$#102!185?_$#103!14?_???A$#104!16?C!57?A!26?G!16?AA!39?A!5?@$#105!20?SC!7?GC?@?@??C?CC!4?C?O?C?e??@A$#108!155?W!25?A$#111!55?_!63?G$#113!20?a!9?A!24?C!130?O$#114!27?_!18?A$#115!15?_???A!38?A!32?Ac!9?GA!21?A!33?C$#116!17?_@$#117!58?@!14?A!112?C$#118!91?@!11?@!16?@!44?A$#119!158?A!12?@$#121!48?A$#123!56?G!17?O@!82?@!6?_$#124!58?CA!30?@O$#125!15?WA!56?C!46?C!5?A$#126!12?C!60?_!46?G!5?C$#128!55?G!130?A$#129!118?C$#131!11?@!60?_!27?__A!61?O$#132!118?@!6?@!33?G$#133!21?_!7?A!9?A?@!12?G$#134!156?E!9?A!18?G$#135!156?@!13?G$#136!59?@!14?_$#139!126?O!31?_$#140!11?C!153?G$#141!57?C$#142!57?_ooos!6~o~r!9?og~~~}}E}!16?oo~~{www?oo$#143!155?_??C!6?O@!4?A!9?D$#144!56?CA!33?G!25?A$#145!21?B@!8?EEFECC!4?CEFFB@@@BF!4?@$#146!10?_!82?G$#147!13?E!105?@!4?G$#148!11?G!4?G!55?@?C!18?_!25?C$#149!17?@!54?A!18?C$#150!100?O!20?B$#151!11?O?O!87?C$#153!5?@$#154!27?O$#155!30?@!15?C$#156!156?W!12?G!15?C$#157!170?C!14?A$#159!17?C!104?A$#160!123?_$#161!9?_!4?@$#165!10?O!5?O!106?O$#166!22?C!17?A$#168!168?O?@$#169!14?O$#170!17?O!103?o!4?_$#171!72?C$#172!13?GG!87?@!21?O$#173?A?B??@?A!86?@!4?@!50?B@$#174!48?C$#175!13?@!79?@!28?_$#176!170?A!11?~$#177!157?_$#178!28?G$#179!15?@???_!72?@!28?K!37?_!4?C$#180!5?A??@!7?_!79?O???A$#181G!122?G!6?G$#182!131?G??G!17?G$#183o!99?GA!58?B?_$#184?@@!5?o!88?@@@!27?GG??oww!4owww!10?OQ!9?CA$#185!160?C$#186!95?A?CA!23?@!12?EE!5?EE!7F??@$#188!56?A$#189!180?_$#190!71?W!6?O!24?O!12?_$#191!60?@@!8?C!10?@!5?@!25?@C$#195!156?_!9?C?_!16?@$#197!127?@$#199!145?OOO$#201?K!8?F!6?A!105?BB??C?@A$#202???G!4?G?G!140?__$#204!96?CA?G!28?BKs???EHHN???~@@!4?wGG?C$#205!14?A!146?g??@!7?_$#207!160?_OOG!7?_K???G_W$#208!94?OogwG!29?_o!12?wwwggg!5?_$#209!98?_C!27?OO!24?W!9?@!8?B???o$#210!93?C!67?F?C!15?bG$#211!154?B!15?O??!5FC$#213!122?C!31?K!18?GGG?G$#216!59?C!30?A_!23?@$#217!115?A$#218!71?C!6?G!11?_!25?GGG$#219!57?OGGE!10?_!5?__!8?w!16?KGN!4?@@wG?A$#223!167?}AB!13?_$#224!169?C$#225!157?]$#226!22?o{}~^NB@!6?!5@!6?C!5?{$#227!169?O$#228!11?_!5?G$#229!4?FCEF!86?@C$#232!183?O$#234!157?@!26?_-#0!27?{~~^NFB@|!8~^!5~N$#1!31?O?GO$#3!31?_OO$#4!185?O$#5!13?C???O!81?C$#6!12?@?E!105?s???G$#8!12?AAG??A!106?A$#9!72?A!53?W!36?S!4?O@$#10!20?@!164?C$#11!73?@$#12!105?_?O!18?A!36?A$#13!12?G!108?M!4?@!31?G???O$#18!15?A!146?G$#22!16?C$#24!11?K!117?_O!6?_!13?oO$#29?@!94?KC$#34??!6~}{__!84?A!41?_!39?A$#36!94?C?O!62?K?_@$#38?_!150?_!16?_$#40!161?@$#41!95?C!32?W!20?NB??a!16?[?^[O$#42!97?A!29?A$#46!94?@$#49!176?B$#50!20?A$#52!154?@!25?O$#53!20?O!30?O$#55!106?_!6?O!11?O$#56!18?GC!72?C!18?G??O!66?C$#57!105?O!49?C$#58!92?O!14?_!11?o$#62!71?G!36?G$#63!71?C!28?G$#64!18?_!52?@!29?A!7?_$#65!102?O!13?G$#66!74?@!16?L!7?_!17?@@$#67!57?A!46?G?C?C?AA?ECc_M$#68!56?G!32?G_!9?_?K?C!11?C$#69!53?_GD@!55?C$#70!55?OO!17?Q^N!12?fBA!11?CB??AA$#71!68?o!6?_O!11?A!14?G??!4@$#72!52?@$#75!184?G$#77!25?C!25?_E$#80!156?@!9?_!15?C?C$#82!165?OLB$#87!165?_OC!14?o_A$#90!183?W$#92!21?@!30?GE$#94!159?o!13?BN^[@$#95!25?O$#97!27?@!22?_A$#98!13?G!111?B$#99!14?@!78?s!4?G?@!19?@??_??_!37?@$#101!154?w!25?_!4?@$#102!19?@!164?_$#103!16?O@$#104!17?_!54?@!20?A!64?A!9?GA$#105!26?wA??_?GCMA!8?_!5?O@$#106!34?_$#108!157?G$#110!20?_$#111!104?O$#114!26?C!24?C$#115!72?C!24?_?A!24?P!33?@???_$#117!16?_!103?A$#118!93?G!4?O!64?G$#119!100?C!54?A!12?A!12?G$#120!167?O!16?O$#122!32?__$#123!73?C!18?G!8?@!7?G!4?G!40?G?C!23?O$#124!18?O_!72?_!22?O???G$#125!13?O???G!107?C$#126!17?C!102?G???C$#128!185?G$#129!71?O$#130!73?G$#131!12?C!86?G!4?_!20?G!32?C!5?A$#132!18?@!74?@!14?O!14?O??C$#134!164?G???@$#135!155?O!25?_$#136!102?_!5?_!10?F$#137!53?OC$#138!52?_?A$#139!13?@O$#140!13?_!86?A!67?_C$#141!55?A$#142!55?__{!10~N~~!5?_{!10~|!12?G???@!4?@@B?@@$#143!19?A!92?G!42?@!25?B$#144!19?W!52?O!26?O!10?G??G!11?_$#147!94?G!11?O!15?_C???o!31?@??C$#148!92?@!5?_!22?O!35?_!9?_C$#149!18?A!53?G$#151!158?O!4?_!5?G$#154!26?@$#155!25?G$#156!157?A$#157!165?@?G$#159!11?@!80?A!18?O$#161A!8?B!148?_!11?@$#162!99?@$#165!15?C!108?_$#167[$#168!156?A!25?G$#170!15?@G!81?C!10?O!11?@?G$#171!14?_$#172!12?O!81?_$#175!96?_G!24?JB???G!31?A!18?W^$#176!165?A$#177!156?O$#178!25?_A!24?G$#179!97?O!23?_!41?@!21?A$#180?A!8?@!4?G$#181?K!129?A$#182!12?_!118?xQCA!6?AA?_!24?O$#183@!97?A$#184!8?@!86?G!36?`b!4@^~~{{_!18?A!7?A!7?D$#185!127?C_$#188!18?C!54?A!21?_!7?_!8?O!9?S$#189!154?E!25?N$#190!71?_??_!15?O!12?B!5?A!4?A??o$#191!101?O!8?__$#194!53?G@$#195!156?_@!6?O!17?B$#199!129?EE!16?_$#200!11?A!84?@$#201_!9?WO!4?A!133?GGG$#202!10?E!139?CFF$#204?O!13?_!112?CWHCKOsAA]???@?]RbbB^OO??C$#205!171?@$#207!94?A!65?{]$#208!15?O@!78?B?@!29?@B@_??GG{{!5?@@K[[[___??H$#209!98?@!54?O!6?B$#210!95?O!74?_}!5_}__$#211!164?C$#212!20?K$#216!71?A_!34?G!7?G$#218!73?oK!15?Ko!8?O?B!15?}$#219!54?oGE@!19?B!11?O!11?c?O?MIC?CCC_`_AR$#223!183?@$#225!156?K!7?_C!18?@$#226!21?}~~~B!27?@$#227!157?O$#228!94?O!15?O$#230!155?_$#232!166?A!16?A$#233!165?G$#234!183?C$#235!52?O-#0!26?FFFB!6?@BB@@B@??CFfN@!61?_$#1!30?@!4?A!5?C??O$#2!48?O!53?_$#3!30?E???@!7?C_A$#4!105?O$#5!122?G@$#6!120?D$#7!25?B$#8!95?G!26?C$#9!93?G??A!23?O!5?A!35?A??_?A$#10!94?G!5?_$#12!15?G!105?OA$#13!95?C$#14!119?_$#22!15?@$#24C!10?_?o!115?@!7?B!10?c??B!16?A$#25!13?A!115?C$#30!14?_!113?O$#34?W~!7^NF!123?o??N~}}{wo_$#37_???!6_!120?_!5?_$#38!152?F$#40!158?G$#41!128?C!40?D???@E$#42!96?G!63?A$#48!25?O$#49!159?C!9?o][WoO$#50!49?G$#52!158?A!20?N$#55!17?A!101?O!6?O$#56!154?G?_!23?C$#57!119?C!6?_!36?@?G$#58!17?O!80?@!20?@!5?@$#63!17?_!74?G$#64!19?@!105?C$#66!97?WAA!4?G!4?@!8?x!4?_c_$#67!49?_!50?B!4?CCC@A?G?@@@$#68!89?oCE!6?C$#69!19?K{?_!29?A!46?O!13?O???A$#70!71?BB!26?@!18?E$#71!68?F??CC!15?F!10?CC$#77!31?O!8?G_$#78!51?A$#79!165?C$#80!163?O!17?GOA$#82!163?C!18?A@$#83!164?G!17?_$#87!155?O!9?A!16?@$#92!22?EGO???_$#93!31?_oOWwooo$#95!28?O?G$#96!34?_?G$#97!26?O!12?A$#98!16?E$#99!93?F?O?@!22?G??A??@o!33?G!4?G@$#101!153?_???W!21?o$#103!161?C$#104!16?_!103?_!6?G!33?O$#105!27?OGC!5?@ACC?A?A@_B???A!53?_$#106!36?C!6?AL$#108!95?_!58?B??@!8?A!13?B$#111!101?O!4?GGG???O$#113!49?C!51?_!4?!4O!74?O$#114!29?G!10?C!9?@$#115!15?_!77?O!66?_!5?C$#116!15?O!168?A$#117!110?O?_!8?_!62?G$#118!96?C!23?A?O!39?@$#119!124?@!29?O??A!22?G??_$#120!99?_??O$#121!26?__$#122!31?FFFEC!5?Gw[$#123!17?G!84?A?@!8?_!5?A!34?_!25?O$#124!49?O!42?@!4?C???A$#125!16?G!77?_$#126!16?P!77?O$#127!32?G!5?G$#128!104?O!79?C$#129!124?A$#130!92?A!30?O$#131!126?C!38?O$#132!93?_$#133!25?_$#134!166?@!13?_@?O$#135!96?O!59?O!5?G$#136!92?C!8?@!7?G!15?A$#137!20?AGO_!26?C?@$#138!20?@C$#139!127?C$#140!123?C!42?OC$#141!50?G$#142!18?C??O!30?OAA!13~w~~ww{!14~w!10?G!6?@???AB@?EEE$#143!154?C??C$#144!17?C!101?G???G$#145!26?GG!17?wwW!56?!7_$#146!167?G$#147!95?A!15?O!48?G$#148!103?@!18?_$#149!126?G$#154!39?C$#156!156?G!26?G$#157!155?B!7?AO!16?A$#158!129?G!21?O$#159!13?C!116?Kwww!15?Wwg$#160?_?_!6?_W??O!119?o?GGo$#162!102?@$#164!162?C$#165!12?O!148?_!4?_$#166!25?G$#168!162?_$#169!15?C!32?_$#170!17?@!76?C!32?A!32?OA$#172!121?M!62?@$#173!12?_$#174!31?G?g???G???O$#175!95?@!63?_$#176!155?gF$#177!163?_$#178!25?C$#179!15?A!78?B?@!24?@@!4?@$#180!12?@@D!136?C$#181!12?A?A!122?_$#182!131?B!14?@A$#184!128?B_??BB!6?@@BFFFAK!11?G!8?_G_?_?_?_?F$#188!103?O!49?A!4?P$#189!153?[???_$#190!53?C!19?@!15?LA@!4?_!6?G!7?CG!4?s!6?W$#191!18?G??_!28?ooGow!46?KK!5?CC???G$#195!155?C!6?O!18?C?C$#196!97?A$#199!13?G!120?C$#200W!13?G!114?OO???GGOO!10?W$#201BF!10?K!123?CC!8?C$#203!10?O!117?G!15?GWwo!11?O$#204!129?A?CCCB!12?@A$#205!160?C$#207!152?O!5?_!9?C!6?_$#208!130?B!4?FB!11?@FF!9?@$#209!149?_??G!6?B!7?oWA?_$#210!170?@BFMH^^~w$#211!153?@!10?_$#212!50?A$#213!152?_!5?C$#216!92?o!5?_!4?A?H!4?G$#217!104?C!12?@$#218!18?o!34?G!35?Axw!5?_W!18?G!7?W$#219!18?Bq!31?Kc@D!18?A!26?W??CAAABA?D?EEwwx$#222!182?K$#223!163?GA$#224!181?o$#225!164?@@$#226!21?@@FN!4?oo!8?wo$#227!168?@$#228!128?_!32?@$#232!164?C$#235!24?_$#236!21?AGO!27?@-#0!29?GO__!11?O!55?@!11?@$#1!43?A$#2!43?_!54?I@$#3!43?@$#4!27?C$#5!28?G!90?c$#6!15?A!112?O$#7!26?@???@?C!69?_!6?O?_$#8!120?@$#9!14?_!106?A$#11!96?O!65?G?A$#12!45?O!82?A$#13!159?A$#15!99?O$#22!129?O$#24EEGE!4?wG???A!116?CW???GGE!5?!7GMA!20?@??a$#25!137?o!24?_$#29?o$#30_!129?W$#34??F??oO!5?E!122?F??F!4~!5FEC$#36!129?D!27?CA$#37@@?@!133?@!27?C$#38!12?@C!142?o!12?!4O???}$#40!129?A$#42!13?G$#43!163?_$#46!150?_C$#48!42?A!59?O$#49!156?G!9?KKNB???@$#51!151?OA$#52!156?C!20?oA$#54!100?_$#55!15?_!30?G!71?O!8?G$#56!16?A!135?_C?C!6?C!15?_A??O$#58!114?@!5?_!5?@$#63!118?A???A$#64!125?G$#65!23?C$#66!94?CA!21?C@??o_pf@$#67!126?G$#68!24?o!64?E@??W$#69!17?F!5?@A!21?O??C$#70!25?_!65?@$#71!23?o!4?_!19?A!40?HA??_$#72!110?_$#73!154?@$#77!97?_$#79!154?C$#80!181?_$#83!180?O$#87!162?@!17?G?B$#92!41?G!56?__$#93!32?BBFCEFFG$#94!177?C$#95!101?O?OOO???_$#96!31?@?C?@HGG$#97!27?@???C?G??!4O!65?___??O$#98!119?WC$#99!15?@!103?A!7?@g!31?@$#100!98?O$#101!121?C!30?O@?G???_C!17?K!4?@$#103!98?@$#104!127?A!31?C???C$#105!27?A??A?G??O???_??_C@GA!55?G!13?O$#108!153?A_?@!21?O@$#111!28?O_!18?@!47?_!19?C$#113!41?O!4?C@!60?_!4?@???_!65?G$#114!34?G!7?G!60?__$#115!128?C!30?O$#116!97?G$#117!29?O_!67?C!15?AC$#118!15?C!142?_G!4?@$#119!122?@!31?O!6?O$#121!40?O$#123!27?G!66?A!23?G!8?O!33?_!17?C$#124!16?C!78?OK!18?A!11?_$#125!97?A!23?@$#126!120?I$#128!28?@!68?O!18?G!66?C$#131!14?OG!103?@!38?O?A$#134!160?G@?@!15?G??G$#135!118?C??G!31?G?A$#136!47?C!45?C$#137!24?@AC$#140!94?@!67?OA$#142!18?oo{oo!24?Gwoo!38~ooo$#143!93?A$#144!97?D$#145!28?EEKWOoo!4_?__OWMF@!52?MMNF!8N^}}{w_$#147!14?B!32?A!69?O!12?_!26?_C!5?C$#148!127?C!37?@$#149!44?_$#153???wG!5?W!126?G$#156!153?oG!25?@$#157!154?A@!5?G!17?O$#158!4?@FFB@!127?_!7?oooO$#159!7?CEff~w!117?Bf~~??O!11?OOP@!13?A!5?@$#160G!4?GG!127?N?F?g!31?C???CS$#161!171?CC{W$#166!106?O$#169!118?_!64?A$#170!14?G?@!76?@$#171!14?C$#172!159?@$#173!13?O!120?__!7?_$#174!31?A???I!6?D$#175!157?W!14?G$#176!160?OAA$#178!29?@!70?O_!5?OO$#179!128?@_!28?G!23?_$#180!4?o$#181!4?E$#182O!6?G!121?G$#184!163?OW_rrokB!5?@$#188!96?A$#189!151?_K??OA$#190!25?Go!65?@?G!22?B!4?WMWs$#191!16?__GKBKFI!22?_o?HL!39?KM{$#195!179?_A?C$#196!15?O!104?O$#200??o!6?O!124?OO!7?O$#201?G!11?_!124?O!36?G$#203!6?_o!140?@B!8?@!11?giaAa$#206!13?@!141?_$#209!147?___!14?_W!8?@$#210!157?A!19?B$#211!178?@$#212!26?A$#213!151?G@!4?@!17?@?G$#216!16?G!28?_!49?`@!20?G!8?A$#217!26?G$#218!18?C!5?KO?o!20?C?A!41?A?oK!19?@B!8?Ac$#219!16?OWBB?BG??C!23?A!72?C???O$#222!180?C$#223!181?B$#224!181?K$#225!160?_C$#226!39?FNF$#227!163?G$#232!181?O$#234!180?_$#236!25?@-#0!117?@A$#2!35?!4@!80?O$#4!98?K!7?A!75?A$#6!157?S$#7!94?_???AA@!9?@?G$#9!13?o!115?c$#13!13?C!144?A$#16!12?_$#18!130?O$#24!5?G??N!122?G!35?@!4?M??@$#25???@!140?M$#29!154?C$#34!131?O!6?M^^N!12?G!21?@$#36!130?B$#42??oO!131?oo!5?_ooo!8?O@$#46!148?OC!18?GAA$#48!113?_?_$#49!152?_G!20?_OA$#51!150?F??C@!21?G$#52!160?C$#53!104?@$#56!150?O$#57!153?@!4?O!22?C$#58!14?_A!22?A!4?@!84?O!22?G$#63!15?C?G_!4?_!103?@$#64!17?OG!21?A$#65!22?O!18?O!79?Osoo$#66!33?C??G!83?!5@??E$#67!27?@@@!7?G?C???A@$#68!25?@!10?O_??O??C!45?M??_@$#69!15?G!76?E?A@!24?C$#70!26?@!7?C???C$#71!24?@!10?C_?___???M!44?P$#75!158?G!19?C$#77!94?OG!7?_!7?@AC$#82!179?o$#87!178?_LG$#88!180?A$#92!96?A@??a!4?A!7?GO$#94!175?_$#95!101?@??_!9?G$#97!105?_O!4?CO$#98!34?@!4?@!116?_$#100!106?C!74?O$#101!150?G_GA!23?F$#104!14?C!113?@$#105!95?_?G_!7?@??@!5?G_$#108!159?G!17?G$#109!103?@$#113!40?@!57?O!15?C???@G$#114!95?OGC!7?@G!5?@A?O$#115!13?G!143?A$#117!33?@!7?@!114?O!24?_$#118!14?B!114?W!28?@$#119!151?OC!24?O$#120!158?C$#123!15?@!19?AAA!112?_C!8?A!16?_@$#124!34?A$#125!157?G$#128!182?@$#130!17?C$#131!32?@$#132!129?A$#133!98?@C!5?O!7?O$#134!152?@!25?A?_A$#136!30?@!8?A!80?G!7?_$#137!93?OC$#138!93?_?A$#139!156?G_$#140!128?A$#142!15?OH?@NNNCCm}ooO_woq___!5?__oo}oo!41~_~o!33?oo$#143!119?A!31?A!9?@$#144!14?O!105?O!7?G$#145!96?oo!8?_~~}}w_@BF^}{_$#146!161?_$#147F!129?K$#149!13?A!116?_$#150!14?G$#154!112?C$#155!96?CA!4?@$#156!159?@$#157!178?G$#158??MMA!126?@???MN!6?M@NJFM!21?C$#159G$#160!5?@!132?@???@!12?C!14?@???E$#161?@$#165!12?O!146?O$#166!99?_$#167?E$#169!119?C$#170!42?@!86?@!25?_?@$#172!13?@!106?_!35?C$#173??@?@!126?AB?@@?A!4?A@!4?@!6?A$#175!159?_!13?_!7?G$#176!160?@!17?O$#178!99?@!11?A$#180!12?B!119?OOo!11?o$#181!137?@$#182?w???E!165?@@$#184!6?KN!4?C!118?_!6?o!14?_??@???O[}}MN@?@PoooMWM$#185!155?O!4?_$#186???_{!4_~n~!116?C???KNM!12?g_@!4?_!7?@@@o}]UKGM$#188!31?@!87?@!38?_$#189!151?@!24?o$#190!33?GG???!5G!81?INDG$#191!16?E@A???JJ??!4KEGG!12?@MN!43?NHC!27?GGG$#194!94?G?@$#195!180?O@$#199o$#200!10?O!120?C__???{???_[???C!20?__$#202!140?_O!27?_$#203!6?B!5?G!142?GA!4?A!11?@@$#204!5?!4O!130?_!24?O$#205!160?G$#207!149?A$#209!147?O!5?O!10?_!8?O$#210!176?C$#211!152?O?A$#213!149?w$#216!17?AO!14?A$#217!17?_!4?_O!99?C$#218!35?GCSOOCCCG!49?A!26?!4AC?Io$#219!15?_o?Cooo??O?AAaQ?ECOOO!5?AQ???@!45?OG@!26?c$#225!159?A!19?A$#226!99?W[}}]]K!8?_$#230!152?A$#231!159?C$#234!180?D$#236!95?C-#1!96?OO$#2!92?GA!26?w$#4!180?G$#5!159?oA$#6!160?C$#7!101?@!15?O$#8!153?O?@A$#9!12?G!142?G$#10!92?C!86?_$#11!129?@$#12!11?_!146?_?O$#21!156?G$#25O$#27!93?@$#29!149?_$#34!148?_!13?@$#36!154?@??_$#37??A!5?C!124?CA!18?@!19?_$#38!174?@$#40!132?O$#42_O@!7?K!124?~~^]?OWzzZZJ!4?S@$#43!8?_$#46!6?__???@$#48!109?G$#49!173?CC$#51!150?A!23?O@$#55!129?C$#56!176?C$#58!121?G$#61!92?A$#62!13?O$#63!18?BG???_!5?c??_???G$#64!13?_!5?A!11?G???G!92?@$#65!14?AB???@O???_!5?]_G_?oCO!53?A!35?@a$#68!14?_!7?]!67?G!31?H!5?[$#69!91?C$#71!14?OC$#77!108?CE!4?[@G$#80!177?C?A$#82!178?@$#87!177?_?@$#90!178?G$#92!114?A?O$#93!108?A$#95!117?_$#96!110?C$#97!103?@???A@!4?o??@C$#98!153?_GE@$#99!130?s!28?G$#101!175?G@??O$#102!180?@$#103!120?@!33?C$#104!12?O!147?G$#105!92?O?@_?_!9?G?O@!6?A_$#106!96?_$#108!175?oA$#111!91?G!37?O$#113!100?@!12?G???G??C$#114!102?@!7?G??E$#115!12?C@!116?A!28?C@$#117!91?_!28?A$#118!130?G$#119!150?@$#120!179?G$#121!107?C?@$#123!121?O!7?G!46?G$#124!121?C$#125!154?O$#128!180?C$#130!23?^!5?W!6?o$#131!154?_$#132!12?A$#133!114?_$#134!176?O$#136!129?_$#139!130?@$#140!12?_$#141!92?@$#142!14?KW_C??EC??K~b|??_DFN~@@N~~^^!47~P@@!31?{~~~C$#143!149?@$#144!13?G!107?_$#145!92?_{}^NN~~!4}~~~po_o~~!4?@^~$#146!11?G!143?_?C$#147!131?G!25?O@@$#148!13?A$#149!152?_???C@???A$#150!11?O!149?@$#155!116?C$#156!176?_@?C$#159A?__!128?`@!19?C$#160!9?C!128?___!4?___!13?_A!6?B$#161!152?O!17?CMJB$#165!10?_!150?C$#169!159?A!20?A$#170!12?@$#171!157?G$#172!131?O!24?O?O$#174!108?G?A$#175!131?E!26?M!13?C$#178!113?@??A$#179!131?_!21?GAO$#180!9?wO!123?@!11?OO??oGMA$#182?B!160?W!6?_$#184?C[!145?^[!12?c~!4?[KzpOWA$#185!131?@$#186?g?@^vV^P@BE!121?_!4?@P@FCCC??H???`!12?Ov~@@$#188!13?C$#189!149?A$#190!122?E$#191!24?Q!97?_$#195!177?A_$#196!129?A$#199G$#200!5?GG?G!123?GGw??_???_??_!5?G!10?G???G!6?_$#201!132?C!23?_A$#204@??]!4?AA!122?AQC!26?O??G??}aO$#207C???_$#209!139?MM!4?CCE??CA!12?f$#211!174?GE$#213!174?_$#216!14?@???CS!8?oA??O!57?_!30?A$#217!17?@G???@!5?G@?O???C?_???_$#218!89?_$#219!15?_^yo_hz_?@?[AF?@A?O?AA???_!48?MU!30?@OB???y$#222!177?GO$#223!177?OE$#226!114?@}_$#227!160?_$#228!91?O-#0!90?oA$#1!93?C??@C!5?_???O$#2!90?G@!28?Z$#3!93?OE?E?O!6?_O$#4!91?_!21?A!4?c!59?_A$#5!150?O$#6!158?C$#9!10?_C!118?@O!20?@!6?@$#11!130?C$#12!10?G!139?G$#13!131?@$#18!149?O$#19!151?_$#21!152?_?C!4?C$#22!155?C$#24!153?_!11?_$#29!10?@!137?G!13?A$#34!138?^~~wwwWNN~?K@!4?_!4?@wwe??wwG$#36!151?@!5?@$#37!9?C!139?B!23?@$#40W!131?V!17?A$#42B?!4_???@!125?JJ!5?BB!21?A!4?W$#43!8?@$#46!6?@B$#48!92?_$#51!173?O$#52!174?@$#55!12?A!108?E$#56!11?_$#57!89?G$#58!12?C$#63!36?@G???NO!46?C$#64!42?_!86?C$#65!13?A!22?C?C?@OA!86?w$#68!12?_?@!74?@!32?O!4?_$#69!13?_$#75!175?G$#76!14?o$#77!113?_F??m$#80!175?_$#81!176?A$#82!176?O$#83!176?_$#87!176?KB$#92!117?O$#93!96?__$#95!101?_$#96!95?_??_$#97!102?_!10?@!4?A$#99!151?C$#100!178?G$#102!177?_$#104!11?A!119?G!24?_$#105!92?OA@??AGOOO???GCG!4?O!5?@?C$#106!93?G?@?G!6?_OG_$#108!174?W$#113!112?_!7?_$#114!113?C!4?W$#115!10?O!119?A!18?_?O!6?G$#117!89?_C!67?@$#118!131?_!18?_?C!4?_$#119!175?A??A$#120!177?O$#121!100?_$#122!94?WMG!9?_$#123!90?@!30?O!53?C$#124!121?_$#125!151?GA!4?OA$#126!153?@???G$#127!95?O???_$#128!178?O@$#130!37?E$#131!11?H!119?C!25?C$#134!178?@$#139!131?A$#140!153?A!5?A$#142!13?OKz!7~}}~wfww~{{w~}w_`~{_@!44~nB!34?b~~~B$#143!174?_@$#144!121?H$#145!91?[N@???@FNNN^^^FBF!4~N!6?~$#147!130?O$#148!152?G!5?O$#149!151?A$#154!113?O$#155!117?@$#157!177?G$#160!141?C???OO?F!10?WWE@WW!4?C?C$#161!156?G$#164!152?O??A$#165!153?WI@!6?C$#167!154?_$#168!177?C$#170!89?OA!39?G!25?O$#172!10?C$#174!93?__?OO$#175!155?G$#178!113?G$#179!157?A!20?C$#180!148?O!15?A$#182!161?@!7?B$#183!150?C$#184C!137?_!16?OF!6?@!4?o?BB$#185_!8?_A!121?_!15?_$#186?EOOO]][!125?F?OO!28?@BBB???G$#188!12?@!117?_$#189!173?_E$#190!122?_$#191!13?G!108?F$#195!175?O@$#196!11?O$#200!8?C!125?KCCN???BCCF!15?E???D[CCCWCW@$#201!144?___!7?O???___???_$#204!8?GG!124?R!36?_E$#206!169?_$#207?XNLL!4?O!123?w!4_!34?oE$#208!6?__$#209?_!6?qA!122?G!4?O!32?_$#213???AA@!167?G$#216!12?G!15?B@??@???A@W???G!45?_!40?B$#217!23?@!4?CA!7?O!4?C$#219!12?ODAC!8?@?FW?C?BAF?@??A?A!46?O[A!32?G[???[~$#226!114?w~~$#227!153?C@-#0!90?KO$#1!107?C$#2!118?G$#3!106?G$#4!116?_!60?C$#5!131?]$#6!131?@!24?A$#7!110?OC$#9!10?A!135?G!7?O$#10!117?_!10?_!47?OB$#11!155?a?@$#12!8?_A!138?@$#13!150?@!5?G$#16!132?O$#18!8?O@!109?G!24?_$#20!150?A$#21!147?_?WC?A$#24?o!5?C!129?{!4?_G?A@!7?@!10?o???A$#29!145?C!10?_$#34!138?}~~^FF!9?O!6?@vFF^F~^~W[$#36!132?@_$#40!133?W$#42?G!5?A!127?ow!14?_?G$#43!8?@$#46!4?CK!166?@$#47!93?A$#48!92?A$#50!129?G$#52!172?K$#54!117?A$#55!130?@$#56!10?G!119?A!42?G$#58!89?O!30?C$#64!88?G!39?C$#65!87?A?_!30?_GG!4?K$#66!120?G!7?H$#68!11?G!75?G!33?C?G$#69!11?o!75?Oo!32?oo??O$#72!99?C??A$#77!99?w@?c!13?G$#80!175?@$#83!174?_A$#87!175?G$#92!91?@!10?O!8?OC$#93!95?AH^~B$#94!6?_$#95!116?O$#96!94?AGO_$#97!90?A??C!15?_?A!6?E$#98!89?E!29?C$#99!10?@!137?C$#100!118?O$#101!172?oB??G$#103!89?G!30?@$#104!9?c!146?C$#105!94?O!11?_G?OG!8?A$#106!105?_OB$#108!173?C$#113!89?@@_!25?O@$#114!117?G$#115!149?A$#116!130?O$#117!129?O!25?C$#118!9?W!135?_OK!7?O$#119!174?@$#120!128?O!46?_C$#121!94?G?_$#122!103?F~^F$#123!10?O@!76?C?_!82?O$#124!88?@$#125!130?G_!16?A@!4?_G$#126!90?O!65?@$#127!95?O!7?w$#128!176?_$#130!11?A!107?O$#132!129?_$#133!115?_?@$#134!174?A$#136!10?_!107?_$#140!145?O_$#142!12?|!73~oc!35?CNNFB$#144!88?A$#145!91?K{w__!11?o~NF@!7?@$#147!8?G!111?A!11?E$#148!10?C$#149!147?Q!5?_$#150!132?_!15?G$#152!151?@$#155!110?_GA$#156!173?_??A$#157!174?CO$#159!157?C$#161!162?ow$#164!145?G??o_$#165!150?_M\!6?I$#167!156?O!5?G$#170!154?G$#171!132?G$#172!146?C!8?@$#174!94?DDE!5?@$#175!7?_$#176!174?G$#178!112?@!4?C$#179!130?c$#180!151?O?E$#181!142?O!14?G$#182!147?@$#184!138?@!14?@!17?{$#185@??o???OC!134?_O?A!7?C???@$#190!11?C!107?_??@!4?OA$#191!87?@!32?OAE??_o??B$#195!176?@$#199?E!141?O$#201!141?_G?N!7?_!4?oMt}G??_G?_?c_$#203E!157?o$#204G!6?G!126?_!10?@!8?A!14?@A$#207??wGwo!127?F^BBB$#208o@FFBB^@A!126?GC!33?@@$#209!135?C!35?A$#212!91?A$#213!172?A$#216!121?@!5?_$#219!12?A!73?N!36?ro?G??C$#225!175?C$#226!92?@@!6?}~G!8?_w~~^F$#227!149?CW$#228!157?A$#233!174?O-#0!94?A?G$#2!93?AC$#4!99?_?_$#5!131?@!12?A!9?@$#6!131?]!10?oK!8?G$#7!107?C$#8!128?@$#9!8?E!135?@@$#10!175?A$#11!144?C$#12!151?O$#16!132?P$#18!7?C!122?_!10?OC$#19!143?_$#21!144?oOIAA@$#24?F!135?@?A?C!4?O!4?@$#29!151?A!4?@@$#30!140?_?A$#34??O!125?O!9?B!9?O]!5?_}GGKMNM}mKA@F?@$#37?W!125?O!9?__OO!6?GG_!4?_??!5O$#40!5?@!127?`$#42??M!132?N~???M!17?!4_$#43???_$#46!4?o$#48!99?@$#49!169?C$#50!127?@$#52!169?_$#55!171?C$#56!9?A!83?C$#57!94?G!77?A$#58!9?C!85?O$#64!119?@?O???@$#65!9?O?@!70?__!8?GGo_!18?W?GA??_?WM@A$#66!124?A?@$#68!10?AC!79?CCO!18?_!10?@$#69!9?_[WW!46?o???GG!25?E!20?_!4?O?AAANF$#71!12?F$#77!100?A?@!5?C??C$#78!109?_$#80!173?A$#81!174?@$#83!173?G$#87!172?_$#92!104?_??g?OG?A$#94!6?G$#95!102?A!6?@???A$#97!97?@?A??CQ?G$#98!92?@!59?O$#99!7?O!143?_?G$#100!113?C$#101!170?OA??G$#103!174?O$#104!127?C!26?A$#105!96?@OA!6?@CA@$#106!104?@$#108!170?_$#110!111?G$#111!113?G!10?GC$#113!100?c!74?G@$#114!98?@!5?O$#115!8?@!144?@$#116!124?O$#117!95?GO?_!26?OKA!46?_$#118!7?_!123?_$#120!114?C!11?A!46?_C$#122!103?@$#123!60?_GO!28?@!79?O$#125!153?C$#126!124?_!27?_A$#128!114?A@!9?G!49?C$#130!117?@$#131!8?G!132?_$#134!172?C$#136!123?O$#137!110?_O$#139!142?GA!8?C$#140!7?G!135?O!9?O$#142!10?___!46~NNBBvv!17~^^!5~}wy__!20?___{{{K$#143!171?G@$#144!8?_!53?G!29?A!19?G$#145!93?@@FEM[[WWWKMEB@$#146!145?_!7?_$#147!6?_A!135?@$#149!9?@!135?A!8?C$#150!132?M$#151!132?_$#153!61?o$#154!114?@$#155!103?_?O$#156!171?_$#157!173?O$#159!137?G$#161!152?@!9?@???wow$#163!130?A$#164!129?@!15?KC?@$#165!128?CC!17?C$#167!151?G!6?@!4?@???G$#170!128?A$#172!152?A$#175!7?@!142?_!18?O!5?@$#178!101?C_???G?A???C$#179!116?@!6?_?_!4?@$#180!126?_?GA!9?_?A!12?O$#181!146?_$#184!5?A@!121?_!4?M!7?G@!8?C!13?B@??I$#185M!136?E$#188!97?_!17?A$#189!170?G$#190!11?A!78?@!21?OO?GC!7?C$#191!115?C??@?@$#194!110?O$#195!172?G@A$#199!8?O$#201!127?_?W!8?[L@@!6?c?N???G]?EEB@?O?PoCE?@$#202??_!126?_!32?_$#203o!149?O$#204@_!135?O$#206!134?M$#207??@^NKU$#208!135?O!11?o!9?_$#209!5?O!128?p_$#210!5?_!127?O!36?A$#211!170?C@$#216!9?G!50?O?_!33?_!19?A$#218!121?_$#219!10?@!50?CC!26?@??O!20?_?O!4?O?_$#222!172?O$#226!100?@B???_oOWMFB@@$#227!127?G!16?G?@@!7?@$#228!126?O???[$#234!173?C$#236!108?_-#4!173?G@$#5!149?_$#6!138?_$#8!119?_!30?A$#9!6?A!132?_$#10!172?OA$#11!142?@!9?@$#12!149?C$#13!6?@!117?@$#18!132?B$#21!122?GC!18?CA@!7?A$#22!132?G$#24???K!122?C?AM!17?@!7?BA$#25!135?_!12?@$#29!121?_?o???@!25?B$#30!4?_!133?G!4?GCB?_$#34???O!120?_@???@!24?A?@$#37???_!123?A$#40!133?B!11?CCC$#42!134?C???C!26?C$#43???@$#44!134?B!10?O!5?OkC_!8?[[?AAA$#46!167?G$#51!168?C$#55!7?A$#58!7?C$#63!87?o!4?o$#64!82?@}???GA$#65!8?w!77?_A!4?C_??B!10?A?AB?AA___WA$#69!8?E!4_!46?BA!24?_]@`?}c!5?E???ACA?AE?@@?A@???G$#71!95?CC!6?C!8?CC??A$#76!9?!4^!46~{{}!20~??~^@??^@BB^x!15w{{wW^^!4@$#79!171?O$#87!171?K$#90!170?_$#92!102?@@$#98!6?o!142?OC@$#99!140?G$#101!168?_E???@$#102!122?@!49?G$#103!121?G$#104!140?A$#108!169?G$#111!117?_OGC$#115!7?@!114?C!16?G!8?_$#117!120?OCA!26?G$#118!131?~!9?A$#119!169?OA$#120!121?A$#123!7?_$#124!7?W!53?@$#125!6?G!132?OC@!8?G$#126!5?_C!116?@!27?A$#128!118?_OG!51?_C$#132!130?_$#134!169?_C_C$#136!60?@$#137!107?@$#138!99?@$#139!5?O!117?A$#140!130?O!10?C!8?OC$#141!102?A$#143!170?@$#147!5?C!126?O!4?_!6?A???GA$#148!130?G!9?O$#149!130?C$#150!130?A$#152!142?O!8?G$#153!142?_$#159!137?G!18?OO?EMMC$#160!125?M$#161!122?OG]!41?@@@$#163!148?O$#164!121?O!20?G$#165!126?@!14?o!8?_$#167!132?_!10?C$#168!171?A$#171!130?@$#172!120?_!19?@$#175!5?B!116?_$#176!172?A$#179!5?G!132?OC!10?@$#180!134?_?G!18?CG!5?@$#182B!124?O!20?@?C$#183!129?_!9?A!7?A!17?@$#184!128?@O!24?@$#185!137?O!5?OG?IG$#186[??A!123?W!5?_??_C!5?__?O!6?wOO?GB@@@?A?_[C$#188!167?_G$#189!168?O$#190!97?@!10?A!10?C@$#191!111?@$#194!100?@!5?@$#195!170?G@$#199!162?A$#200_]}!123?I_{!8?B@!9?A!8?B!5?@??_$#202?_$#204?@!123?_oC!21?@$#206!139?@!11?_!12?BA$#207!4?@!139?O!7?O??___wwoow__$#210!4?]!128?[!11?G$#211!169?@$#213!167?O$#216!8?@!73?}!5?K???G$#217!83?@???CO??W$#218!99?A$#219!89?_!4?EB??FCEC??EC?CCC???`??SEKAA@$#223!170?O$#225!172?@$#227!140?_GA@$#228!132?C$#229??@!131?W^V?A!6?__O!6?KGCCC!6?W$#236!101?@??@@-#2!5?AB$#4!170?_C$#5!6?G!111?@!18?E$#6!135?O!11?C$#8!4?C$#9!130?C$#10!117?@$#11!9?_!121?C!16?C$#12!137?@$#13!115?O?CA!28?O$#14!139?@$#18!4?@!131?A!12?A$#21!138?WG!8?G$#24!129?O!4?C!5?CA$#25ES!139?_$#27!115?CA$#29!115?__???C!38?W$#30!116?O!12?A$#34O!144?A???Wooo!6w_$#36???A$#37??_!124?C!18?@!4?C!14?@$#40!133?O!12?A$#44!133?G!7?G??@!18?wW$#55!9?G$#56!8?O!159?A$#58!8?A$#61!113?OG$#63!87?@!4?F??[!4?_$#64!82?@???AA!5?[??O$#65!8?@?G!72?@??@C!4?_B??g!4?_??_!5?_O$#69!9?BDNF!73?GG??oa??{!14?KC??A$#71!109?O?C$#76!13?!69~}}~zoo~wNL??@@F~N~BBn^^~^~~!4B$#78!113?G$#82!169?C$#87!168?_?@$#98!4?ODC$#99!130?W@$#100!171?A$#101!166?OC$#102!169?_?@$#103!7?C$#104!6?_!123?A!7?A$#108!166?_?@$#113!115?GC!55?@$#115!131?A!4?C!8?_???@$#116!5?O$#117!5?G?AC$#118!6?O!129?O!10?G$#119!170?C$#123!7?G!159?O$#124!7?O_$#125!4?g!109?O??A!17?_G?@!7?O?B$#126!146?_$#128!170?O$#130!7?_$#131!130?@???_!11?GA$#132!9?O!120?_!6?G$#134!169?O$#135!168?C$#136!9?C$#137!112?O?C$#140!131?G$#141!111?_$#143!167?G$#144!10?_$#146???G$#147!7?@!126?O$#148!136?_$#149!119?@$#150!138?C$#151!131?O$#153!134?@$#156!167?_$#157!170?A$#159?GJ!152?!4@AAWK$#160!119?A$#161!117?ww{zFFF$#164!118?C!20?A@$#165!129?_!5?A?__CA@$#167!131?_???C$#169!4?A_??G!104?_!56?G$#170???_!110?_?G!18?G$#172???O$#173!134?G$#177!169?I$#179!145?O?@$#180!134?A!7?qw$#182???C!119?GC!4?K!14?_$#183!124?B!7?@$#184_!120?ww!9?W!15?ocGGG$#185!129?@???_??@!8?G?_!12?C$#186!124?oow!6?F!6?OO!8?A??BBA??A???O$#188!165?_G@$#189!167?A$#190!11?o!80?O!17?OG?CB$#191!10?A!99?G$#194!112?_$#195!168?G@$#199?AC!137?_$#200@!124?GEOv???_!6?O??@?A@!4?DACC?!4C?w$#202G@!123?E?b!12?G$#204??O@!119?oG?@!14?C!12?C!4?C$#206!125?@$#207!144?OC!13?@@FBFFNC$#210!132?E!33?A$#213!164?_O$#216!10?O!75?C!5?G??a!19?A@$#217!93?_!6?O!14?@$#219!12?w!72?C???F?O??A???o?K[O_??_??_??K@$#227!137?O$#228!146?C$#229?_!125?GG!6?@???_??KFK!6?@B???AA???__$#233!168?O-#4!169?C$#5!132?O$#6???A@!124?_$#8!131?O$#10!168?G$#11!6?@???@!135?@?G$#12!5?A!6?O!95?_!23?_$#13??G?C!129?C!13?C$#14!10?A$#18!112?@!17?C!4?A$#20!135?G$#21!110?o??@!21?OC$#22??A!106?_!22?A$#24!137?_$#25!140?@!9?_$#29!113?UH!26?_$#34!112?g!18?A!16?@@@$#36CO!114?_!32?G$#37?@$#38!117?Ow??E!5?AM!10?_O!8?_?C!11?I$#42!146?G$#51!164?C$#55!6?O??@?G?O$#56!11?A!130?_!22?G$#58!10?C?C$#61!107?_$#63!100?@??WA$#64!14?O!80?@!7?_$#65!14?K!86?G??_??F@@$#69!12?AC?_!78?@!10?P@$#71!13?@?@!86?O$#76!14?@?!78@???@@@??@$#78!106?_$#80!166?G?@$#83!166?O$#88!167?E$#98???G!127?_!12?G$#99???_!125?O???A!11?C$#101!142?O!22?A$#102!168?C$#103!130?_$#104!4?A!8?_!119?G!9?O$#108!164?_C$#115??O??_!109?_$#118??_!131?A!9?O??_$#120!167?O$#123!12?_?_!151?A$#124!11?O$#125???S!128?GC@!8?_CB$#128!168?OA$#129!8?wK$#130!7?{Fow`$#131???@?W!108?_!20?@!8?A??O$#132!11?C$#134!168?A$#135!165?O$#136!7?B?A$#137!110?@$#138!111?@$#139!5?C!126?C$#140!109?O!19?G!18?O$#141!109?A$#142!14?AM]]!76}{{{}}yoom??MA$#143!166?@$#146!137?@$#147?_??O!103?OGC??_!29?G!5?C$#148!6?A!5?G!131?_G??_$#149!110?G?A!31?@$#150!147?G$#151!133?O!9?C$#152!6?C!123?@$#153!136?O$#156!166?C$#160!117?_??C!6?O!7?_?Ao!4?A??C!4?A!10?M$#161!113?GUNNNFF@!10?C$#164!134?OCB!9?A$#165??@!131?_??G???O$#167!147?C$#169!5?@!105?A!18?O!36?_$#170!6?_!123?G$#172!4?G!110?O$#175!4?_!111?O$#176!166?_$#179??C!108?C!19?G?@!35?@$#180?A!134?gSB@?@B@?oO!5?_a?K$#182@$#183!112?O!7?A!18?O!9?AE$#184!121?@!5?C!4?@!7?_!6?B???G!10?OD$#185!150?G$#186!119?wooq}~P}??@!10?G!9?O?K!7?oO$#188G!162?_$#189!6?G!157?W@$#190!106?O?A$#194!107?OGCA$#195!165?_?G$#199?C$#200!125?m@h@!9?GG?KC!8?_!9@?@$#201!111?wC!15?O!19?A$#202!122?@!28?@$#203A$#204!120?GGK@!5?AA!15?_!4?O!10?_$#205!149?O$#207oG!162?B$#209!159?o$#210!131?@$#211!142?G!20?O$#216!13?G!86?AE?CD$#217!96?@???C@?BG$#219!12?@A?O__!76?AAA??CG???O_KGC$#223!167?@$#227!133?_G$#228!128?_C$#229!138?CEEA!10?Q[}q}}}MMn-#2!129?A$#4!7?W!159?A$#5??C!111?B!26?OC???G@$#6??G!104?@!5?O$#9!106?_!35?G$#10!166?C$#11???@$#12!16?G!33?O!77?A$#13!115?@!29?O$#14!105?_$#15!6?G_$#18!4?C!102?C!37?G$#21!108?A!14?_???C???GCA$#22!115?_$#24!110?_!49?O$#25!108?_o!11?GGGKKM?_!4?OO!15?@C???ooO_$#27!105?C$#29!144?@$#34!111?@!32?A!14?K$#36!112?C$#38!112?@???C?@!18?A?@@??_O@???F$#40@??G!108?A!23?_$#42!143?O$#46!161?O$#49!139?G$#50!103?_$#52!163?@$#53!6?_$#55!8?O!4?@?A$#56!164?@$#58!8?G!5?C?_$#61!104?G?@$#63!8?Co!40?_$#64!19?_$#65!18?C?_!79?_$#66!103?A$#70!48?W???G$#71!19?A?O!25?G$#76!104?A$#80!164?G$#86!104?C$#87!164?O$#98!130?@$#99!5?C!107?C!27?_!4?c$#100!165?_$#101!162?OA?O$#102!166?A$#103!5?B@C_$#104?G!129?@$#108!139?OC@$#113!5?_$#115??O!14?_!96?C!27?A??_?C$#116!104?O$#117!5?WA!98?GM!60?@$#118!112?_!30?@???A$#119!163?G$#120!141?C$#123!16?C!34?G!88?W$#124!7?@!5?A???G!31?O$#125?_B!110?G!15?D$#126?O!104?O!23?A!15?O$#128!6?C!159?G$#129!13?GO_$#130!8?BN~~~sgO!35?_$#131!112?O!15?C!17?A$#132!113?a!27?G$#134!141?A!21?O?G@$#135!139?_!24?A$#136!18?O$#137!102?O??@$#139?C!105?A$#140??_!12?C!91?G!20?GG!13?A$#141!101?_$#142!16?@@@HNNN!24~fffDBr|!45~xXF@$#143!7?A!134?@!19?_C$#144!15?G!34?G$#146C!108?A!5?O_!26?C$#147???CB!13?_!92?_??O!32?_$#148_!13?B$#149???A!13?O!124?O$#150!146?@$#151?@!111?@!17?A$#152!120?_?_?_!4?OO$#153!110?O!9?OOO??OOo!20?__oo_!4?_$#157!164?_$#159A!107?O!22?___$#160G!109?@!6?@???A!14?@@!21?Q$#161!115?A!32?A$#162!104?_??O$#163!16?O$#164!132?@$#165!127?I!5?@B$#167!109?@!32?_??C$#169!4?_$#170?A??O!125?C!16?G$#172!148?@$#175!115?C!21?oK$#177!165?@$#179!4?G!100?O!6?G?G!13?@!11?_$#180!110?G!5?OoooG??OO__@O??OWKKB!8?G???OWKGWw!4?R__$#182!107?_!27?_$#183!148?C$#184!138?@!9?G$#185!114?_!21?KK$#186!116?GKKN!5@!34?@?K$#188!139?E!22?C$#189!161?_G$#190!17?C???_!82?@$#191!17?A$#194!103?G?A$#195!163?_CC$#199???_!47?O!57?G!14?AA???__???_$#200!117?A??A?AC?@@!8?O!7?G!6?AB!6?K?M$#201!121?_$#203!108?C?A!25?A!8?A$#204!116?A?A?CCCA$#205!108?G?CO???G!20?O?Q!23?@$#207???O!105?C?G!4?@!45?A$#208!144?C$#209!111?E$#211!138?_$#212!6?O$#213!140?A$#216!15?@$#217!49?G$#219!16?A?ISO?o!24?O??ACCA!45?EEWMD$#225!165?A$#227O!107?@!21?GCA$#228!147?O$#229!135?K!8?_!7?FF~NNN??@B$#235!102?_O-#4!164?C$#5!145?E$#6GC!102?_!6?C@!26?GB!4?G$#8C!8?A!90?_??@?A$#9!139?O$#10!9?GO!91?A!60?O$#12?O??@!97?O??G!4?G!35?A$#13!106?@!4?`$#15!5?C$#21???C!109?G!27?A!4?g$#22??o!103?O$#23!115?[{{{w!8_d_W!17?_ww{{w{[{$#24!113?o!33?C!10?o$#25!108?@B!5?AA!11?A!22?AA?BBB?B$#27!5?w$#29!141?O?K$#32!141?G$#34!141?c$#36!134?O$#37!140?O?_$#38!135?E!6?A@$#40!136?@$#42!140?_$#49!135?G$#52!137?@$#53!7?@$#55!19?C$#56!161?C$#57!139?A$#58!21?CG!81?@$#60!7?A$#61!101?C$#63!11?G$#65!97?K$#67!20?@!4?_!70?C$#68!23?C?O_!68?oO$#69!21?A??O!72?O$#71!26?O_!67?K$#78!98?O$#79!137?O$#80!138?C$#82!162?G$#86!101?@$#92!99?OC$#94!134?_$#98!103?GG!33?_$#99!20?C!89?O?A!31?_P$#100!5?A??A?_$#101!137?A!22?G$#102!10?G!89?O!62?G$#104!18?@??G!79?O???@!5?Q!28?C$#107!6?@??_$#108!136?G!23?OA$#109!6?{{w$#110!102?@$#111!11?O$#113!163?_?@$#115AG??{!100?C!38?O_@$#116!101?G$#117!5?@??@C!92?GO$#119!137?C$#120!10?C_!125?_!26?@$#123!9?@!94?A!31?O!23?_?@$#124!10?A!8?GO_$#125oB!102?O!5?_$#126!111?G$#128!102?C$#129!12?A$#130!10?@F|!4~}wo_$#131!19?A$#132!4?A!98?_C!34?_$#134!138?G@!21?G_C$#136!18?C$#137!99?C$#138!99?_$#139!138?OC!4?G$#140@!20?O_!89?C!28?@$#141!97?_$#142!22?BJNNN^!67~!4B$#143!135?_??@$#144!17?@A@A$#146!115?@!28?@$#147??K!100?A?_$#148!20?G?O$#149!101?_$#150??@!102?O???_!30?G$#152???B!104?_!4?CA!17?G?@$#153!114?{_???C\\\[[\^^WW_oo!14?w\DD@@F?_?~K$#156!138?A!23?A$#159!106?_?[!20?ABFBEC!24?A$#160!113?A!10?B!22?A$#163!146?C$#164???w$#165!102?_!9?o!20?o!9?o$#167!147?@$#168!163?@$#169!164?A$#170?_!142?C$#171!112?G!31?A$#172!113?@$#176!162?CA$#177!161?_$#180!118?BBAAAB?A!8?A!13?AAA!8?@$#181!133?G$#183!106?K??O$#184!142?\$#188!103?C!32?C!22?OE$#189!135?O!23?_?@$#191!22?C!73?g?C$#194!100?A$#195!136?_G!23?OO$#196!23?_$#199!107?wAC!6?@!12?DCGC@$#200!117?B$#203!110?B???@!28?A$#204!135?@$#205!107?F!26?G$#207!109?G!49?G@$#211!136?A$#212!8?CO$#215!6?A$#216!23?O_$#219!21?@!76?GB@$#228??A!103?A???C!35?O$#229!159?C$#235!98?_GGA-#2!137?C@$#4!161?GA$#5@!108?K@!26?G!5?_D$#6!103?G!32?G$#8!137?O!22?_$#9C!109?A$#10!11?C$#11!135?_$#12O!23?A!84?_$#13!97?_!41?@$#14!145?A$#15!10?@?O$#16!98?O$#18!102?A$#19!108?C!33?_$#20!115?!4_!6?_??_!17?_$#21?G!96?_?_@!4?G!6?_G?!9O?W??_!19?O???_$#22?A!102?_???B?_!34?G$#23!121?@@!5?@!19?!7@?FA$#24!105?A@!40?G$#27!5?~$#34!132?A$#36!132?G$#37!140?B$#38!132?C@!6?C$#42!139?_!17?C$#49!131?_$#50!97?G$#51!157?O$#52!134?@!23?A$#53!12?_$#55!24?@A?G$#56!26?C!132?A$#58!14?_!8?A$#61!98?A$#62!12?A??G$#63!14?O$#64!25?@$#65!26?@!66?M$#66!96?@$#68!28?GC?_!58?_?G??@$#69!27?C@!63?_OC$#70!92?C$#71!92?A$#80!134?_?@$#81!134?O$#86!95?G$#92!94?_OGE@$#94!133?A$#98!138?E$#99!97?O!4?O@!5?A!34?G$#100!11?AG$#101!157?_C$#102!12?C!147?OC$#103!4?A!131?_$#104!99?A!9?O!33?GO$#108!158?G@$#109!6?N~~~wo$#110!96?O$#111!13?G$#113!161?o$#115!4?@!21?G!69?_?G???GO!4?O$#116!4?{$#117!137?_$#118A!107?_!29?_!4?O$#123!24?CG!108?C@!22?O$#124!22?@$#125!102?_E!33?AG!5?A$#126!136?O?O$#128!13?_$#129!26?_$#130!13?BNv!6~}{wo$#131G!24?C?O_!75?@!38?C_$#132!100?@!8?@C!34?@$#134!136?A!22?CGA$#135!133?O$#136!12?@$#137!95?CA$#138!95?_$#139!103?_$#140!23?@!75?C$#142!27?ACP^^!57~v^^P@B$#143!132?_GAO$#144!26?O_O_$#146??@@!97?G!5?O!31?C?G???O$#147!102?@??@!4?OA!50?@$#148!108?G!34?A$#149!104?A$#150!110?G!28?A$#151!101?_$#152!106?EC???[g!14?C!18?DvC?GK$#153!107?@!4?C?DD!5@EE!4FBEFF!11?C!5?AEEACCC@W@$#156!158?_$#157!135?G!23?_@$#164?s]w!95?_?O??W_?_!6?oO!5?!4_O_!21?___?_$#165!99?W[E???KOI!4?BFAAE!4M!5G?GGGwN!9?OG???A?WGOoOOws$#168!135?C$#169!98?C!38?@$#170!102?C$#172?@!97?@A???C!31?C$#173!156?_$#176!161?@$#177!159?OC$#179_!10?@?O$#180!142?B!9?!4A$#182!140?_C$#184!139?W!18?@$#189!132?OC$#191!26?A@?G!61?_$#194!93?_O??@$#195!133?_GA!23?GA$#197!112?OG!28?O!9?GG?G$#201!132?@$#202!131?O$#203!141?B$#204!140?G$#205!140?O$#209!157?G$#212!10?AG$#214!10?C$#215!6?o$#216!13?C$#219!28?AA_!58?G!4?GA$#227??_!102?O_!6?O?GG??__!6?oOO!11?_?@$#228???E!107?`!33?cW$#235!96?C-#2!160?_$#5!101?_!5?O!29?`!5?G$#6!90?GG!9?O!5?C@!26?@!22?O$#8!88?O???C?A!48?_!15?A$#9!101?G!5?_!26?CA!6?O$#10!5?_!8?@?G$#11!32?G?_$#12!95?A@!5?_!41?@$#13!89?O!11?A!4?O?G!49?G$#14!92?G!8?@$#15!5?^!9?G!68?_$#16!138?O$#17!100?_$#18_??O!102?C!8?@!12?A!15?O?@$#19!123?G$#20???C!88?_!11?GG!6?_!27?O!5?C?@C?@$#21!92?Og?WAB?GG!11?@AG!26?O$#22!103?_?O???G!34?_$#24!94?O$#29!139?C$#34!130?@!23?C$#41!128?_$#42!139?@$#49!130?A$#50!89?G?C?A$#52!156?@$#53!13?A?O$#56!33?G!95?_G!23?_$#58!33?_$#63!18?C??_$#66!86?C$#67!37?_!37?_$#68!34?C??OO!35?O!4?OO?G??CAA@$#69!32?A!32?!4_??_!9?O??A$#70!65?OOO!6?_?O$#71!59?Oo___O???OOO$#75!157?O$#76!37?!4G!18wgGWWW!5Ggg!4GW!6G$#78!80?_$#80!132?CB!22?OC$#81!132?G$#98!137?C!22?O$#99!91?O!10?G!31?G$#100!14?A$#101!130?C$#102!17?O_!114?G!25?o$#104!93?C!44?@$#108!156?A_$#109!7?!6~ww_$#110!82?_???O$#111!15?@?G$#113!160?B$#115!30?AC!70?O???_!26?O??_!5?G$#116!4?^!81?_!8?@$#117!15?C!144?K$#118!91?_!16?A!24?_!8?_O$#119!157?@$#120!158?C@$#123!16?C!14?AO!55?_?_!41?`$#125!102?B!4?G!29?Y!5?F!14?_$#126!102?C!56?C$#128!16?O_!67?_$#129!26?C$#130!16?@BJ^~^!4~z~{{wo_$#131!29?@!78?C!29?A$#132!101?C!5?A!26?O!7?C$#134!131?C!23?O$#135!134?@!21?C$#136!16?A??_!8?A$#137!79?_???O?G?C$#138!81?_!12?@$#139!4?_!28?O!102?O$#140!135?C??C$#141!82?O!6?A?@$#142!32?@B@FB!47FD?@@$#143!87?_!43?A!23?G$#144!28?@ADGC$#146!95?C??@!13?A!15?GA!9?_@$#147O!14?A!18?O!70?_??_$#148!94?C!43?G$#149!142?@$#151B?O!103?G@O!12?`@_$#152!154?B$#153!155?@$#156!157?A$#157!133?C!24?A$#159!128?O$#164???b!100?_F!4?fF?\BMG!11?C@!10?A!4?_??kx?G|M$#165!94?G?C??CV!5?A!7?C!24?WC$#166!13?@$#167!99?B!29?C!23?O$#169!87?O!54?A!16?G$#170!35?_!67?@!32?@!7?A$#172K?_!87?O!12?[!5?E!6?DBFBJQ!13?wE!7?GB?AAA??A$#175!134?A!19?G$#176!156?_$#179!103?A!5?@!24?_?G!7?C$#184!139?A$#185!129?G$#189!129?O?@!22?OC$#191!31?@?CAG???oo!23?_!6?OOO!11?A$#193!89?_$#194!84?O?G?C?A?@$#195!130?_wQ!22?_GG@$#197!146?G$#201!93?O__w{}o$#207!155?A$#210!153?_$#212!14?C?_!66?_$#215!6?~!6?C$#216!17?CO!16?O_$#218!36?O?_!37?__$#219!34?G?K!35?__???Oo!4?GG@??A@@$#220!130?O$#226!93?@$#227?~NG!100?O?@???Ww!4?A{w{sK}V!4~@!11?GN???OooO?~u?@$#228!104?F!4?o??[_ooo!21?_?__???KAL$#235!87?G?C?A$#236!85?O??G?C?A-#2!157?A$#4!159?_$#5!101?O!4?Q!35?_$#6!106?_!24?O!10?@$#7!60?_$#8!49?GG!6?C!47?_$#9!92?_!38?_$#10!5?B!63?C!5?_?C??@@!77?G$#11!35?@$#12!36?@!70?A!33?O$#13!55?C!22?A!13?A!9?@??G!24?_?@!8?G$#14!44?O!9?C$#15!19?C!50?C$#16!110?O$#17??_$#18B!101?Og?A??C???E!7C!4?o!7?_?G!6?@??oAROG$#19??OG!107?G!8?g!18?__$#20!103?C!9?G??G???O$#21!93?W?_C??A!24?CGC!22?O?C@$#22!138?@!5?J??C$#24!138?O$#27!17?@??G???_!46?CC??OC$#29!91?G!7?@!52?A$#34!99?C!50?_$#38!151?G$#50!23?O!46?A!7?@@$#53!60?OG$#54!17?A??O$#55!37?C!7?G?O!6?G$#56!42?G!12?G!24?GOO!45?A!24?A$#57!77?G$#58!21?C!12?@!14?OO!11?AAA$#59!17?G?_!48?G$#60!7?AENWKO?o!4?O_!42?oO$#61!156?A$#62!27?GG!7?CG??C$#63!21?AC!9?@$#64!58?A$#67!46?C!21?@@?@$#68!46?A!19?@$#69!39?A?C??CC???A!6?AA??@?@@$#71!47?A$#73!153?C$#76!41?@@@BB!6@!4B@@$#80!130?E@$#95!22?_!39?O$#98!136?o$#99!100?_!31?C???@@$#100!5?K!14?C!37?_?GcCC!4?C!4?A$#101!79?A!11?O!60?C$#102!57?O!13?A$#103!155?_$#104!91?@O!7?O$#107!62?!6G!7?G$#108!91?_!34?_$#109!7?|xOfrfFN~~cg!45?_!4o!5wW$#111!24?O_!34?AA!14?@@$#113!57?_O!99?A$#115!37?A!10?G!84?@???A!5?@$#116!4?F$#117!18?@!39?C!97?G@[$#118!106?@!25?A$#119!80?A!71?G$#120!19?@A?G!42?!4A$#123!38?A!11?C!33?@!42?O$#124!35?A?@?O!9?C!5?_$#125!59?G!41?N!4?K!29?K!5?]!15?@$#126!101?_!34?A$#128!5?o!13?A?GO_!35?SC???!4C!6?AAIA!80?_O$#129!26?_$#130!21?@BBNNVvv~~~}\]{WOo!12_!4oO$#131!38?CGG!51?G!7?G!30?G$#132!4?w!51?C!48?O?@!27?_!5?_?A$#134!76?_!4?A!70?O?@G$#135!128?C@O$#136!20?@??K?OG!6?a_?__!10?C!7?O$#139!47?G???G!48?C!31?G$#140!91?AC!7?A!34?O?C!5?C$#143!52?C!30?@!43?G???C!19?_$#144!38?G?O??GG???O??C!4?GG!11?A$#146!138?A@$#147!41?G!14?_?G!49?B!35?CC$#148!43?O!47?C!8?@!34?G?G???C$#149!102?A!29?O??C!5?A$#150!42?O!49?@$#151?BFA!117?@A!12?A!14?@$#152!138?_$#156!77?_okccc}{s}ppp}!36?_$#157!154?_?@$#159!46?O$#161!127?A$#162!137?O$#163K!108?G!12?_!22?_$#164!104?B!6?@!5?B!5?CAC!19?@??CGGA$#165!81?G!11?DvU__!29?@!12?C$#166!18?A!40?_$#167!94?GG!29?O!24?O$#169!76?O!56?A!25?C$#170!107?C!35?G$#171?K!101?O!4?WOGOG!8?oOo!9?_!12?__$#172!82?@!19?_?_!5?CE!4?A!6?@@AA!6?KD@!12?@DC@$#175!125?_!29?O???@$#176!154?C@$#178!21?O$#179!36?A!15?G!19?A!29?K??C?G!35?o!12?C??A$#180!138?K$#184!98?C!27?G$#188!39?C?O!11?K$#189!128?@!22?O$#191!38?@?BAAA!7?A!6?@@!5?@?@$#192!86?@???@$#193!77?OGO??A?AI?MMM!41?A$#195!128?w}H!21?_wYE$#196__?o!105?__!23?_$#197?O!109?_!5owww!17?_?]W$#201!93?A?@JNjg$#202!96?!4O$#211!127?C!25?@$#212!61?O_!10?CcC$#213!126?O$#214!12?Gw!5?G?_$#215!6?~??_!7?OS$#216!47?C!11?A!15?@$#219!39?@??CC!4?A?A!10?@??@!5?@?@@@$#220!78?C?O?G$#221!85?@$#227??GD!89?_!10?[!5?B???GG??BBFMLIG@@!7?O!13?qAA$#228O!44?OG!56?B?@?o_F??@BBB@!16?OA!5?B!4?WKJ?_-#2!55?AB$#4!48?OO!4?C??@@!95?G@??h$#5!95?A??G!36?G!6?@$#6!97?C??@@!28?A!4?C!5?oC$#8!76?O!19?C!4?C!4?@!28?A!6?_$#9!93?@!35?O@!5?O!4?A$#10!25?@!16?_!4?_!25?C!79?O$#11!129?_$#12!4?E!99?O?K$#13!134?_$#14!104?C!26?A??O$#15!29?O!17?O??G!7?A$#17AG?V!99?_$#18!102?@!4?@!15?A!8?@!10?O@GM$#19!103?O???oHckK{?_BK[K{_o!9?_GG???OC?@$#21!96?@!40?C!11?@$#22!123?G!24?G$#24!98?@$#27!56?C!16?A$#29!75?G??_$#32!148?O$#48!23?@$#49!150?@$#50!27?A!18?O$#52!29?C!93?_$#53!6?W!17?A??G!24?O!4?C!11?_OG?@$#54!10?_??_!14?O$#55!52?C$#56!124?O$#57!39?_!86?@??A$#58!45?O$#59!13?A???WWOOQQ{OO?_!31?A$#60!8?]???F@GGO???_`??K??O!23?_???o!4?C??ooO$#62!29?@??oF??cc?CKKKC!9?A@$#63!42?O$#73!79?_$#75!77?C!11?AA$#95!51?O$#97!158?E}$#98!100?O!4?O!29?_$#99!101?y!34?G!4?KW$#100!27?C!18?_!6?K!16?_???@!78?_C$#101!124?G$#102!40?_!32?G???O!75?G$#103!43?_$#104!129?G$#107!6?E!12?GGGK!27?_!10?@$#108!125?A!23?GA$#109!7?~@w^|!4?G?@?@!5?G!26?OOGGGK???@GHhHH@BFF@$#111!28?A!15?O???G$#112!12?WW!8?_!29?__$#113!57?A!101?@$#114!59?@!98?O$#115!77?_!15?A!12?A!23?C!4?@_!4?@$#117!5?w!23?G$#118!92?@$#119!30?G!45?_!72?O$#120!26?@!22?G!104?@$#123!74?G!16?@A!32?C!24?C@$#124!38?_!12?C$#125!99?O_!4?m!29?O@$#126!94?A!5?M!4?@!30?E!5?A$#128!5?F!18?@AA?K!15?__!5?GG??C!15?OG$#129!28?@$#130!29?ABnNwww?O^ZRRBJNNNFFFEAA@$#131!96?A!31?_$#132!94?@!4?G$#134!74?C?G!17?C?G!27?_!24?_??_$#136!27?@??CO??FFZJ!9?G??@@@$#139!4?@!92?G!6?_$#140!98?C!30?C?@$#143!75?@!22?O!29?O$#146!99?C$#147!30?_!23?A$#148!138?__$#149??_!103?_!27?G???OW$#150?uO!92?@!36?o_!4?GCo$#151!130?oW!13?__$#155!8?_???_?_$#156!73?_?EFJ^^~^!4~NHN\\M[[GWO!28?GA?G!21?GA$#157!129?@!23?C$#161!124?A$#162{@N!131?C!5?G$#163???G!118?A!21?_@$#164!147?_A$#165!98?A@!11?@@!24?B$#166!26?C??_$#169!4?G!50?@!18?A$#170!4?O!99?G?O!23?G$#171!102?_D???C!12?ABX!11?A!9?]UP@$#172!97?A!6?@!19?@!18?N!10?A$#175!72?O!50?O$#178!48?_?O!9?@$#179!4?_!36?_!29?_!32?A!38?_$#188!30?O$#189!99?_!48?_$#192!73?O$#193!72?_?__!5?_!4?ouo__o__o__o_$#195!125?o{~F!21?o{^B$#196@??_!99?G???GuWOo?_?oo_o?[K!11?O???_?BE$#197!109?BBAA^^K!4B@!12?@@???A$#201!97?@?A!49?A$#211!75?O!19?C!28?C@!23?C$#212!6?_!42?_!4?G!17?C$#214!11?A??Oo!4_??@??K??_!25?_!4?C!6?___$#215!6?@??F???C!4FEFEC?A__o!29?ooowy}}FEEUU][G?A$#216!43?O$#221!74?O$#227!122?C@!7?CEE???G!10?@$#228!102?]A???A!14?_C!14?@!8?]C-#4!36?C!116?@$#5!105?A$#6!101?_!39?W$#7!159?_$#8!5?M!63?A!35?O!28?_$#9!100?@???C_!21?G!14?@$#10!6?G!23?{!4?G!4?@!29?@$#11!136?@$#12!134?A?A$#13!127?CG$#14!138?@o@$#15!6?C!26?_!4?A??@!27?@$#16!129?A$#17LMA!104?G?A!7?KCCC!8?C???_$#18!102?D???U!39?@$#19!4?o!102?`?G@@@?AAFAABP@!9?PPE???A$#21!79?@$#22!146?G@$#27!6?A$#36!122?A$#52!122?C$#53!18?__!9?{!6?G??AA!4?@@$#54!7?E??C?Kn~~__?[K?X__?OW}!10?GCKKEC??G!20?@$#56!127?A!19?G$#57!69?C!53?A??O$#58!32?O??A$#59!23?JMKK!10?gS??AA?A?CC?{miYwvxxsCCS?HFNG$#60!17?AAA!28?A$#62!31?ABD$#73!71?@!6?A!20?B!23?C$#75!77?o??_!66?_$#79!126?C$#95!6?@!22?@!13?@!20?_$#97!159?B$#98!135?N$#99!101?N??W!22?O@$#100!6?O!25?_?O$#101!146?_$#102!37?@!28?_OG!82?G@$#103!33?O!4?@!95?W$#104!5?O!122?A$#107!7?O!8?W!6?OP?BB!6?_O?O!12?OO_?GEEG???}E$#109!7?@!12?r~???___!11?C!7?!4@!15?C$#111!36?@$#112!7?g!4?oO??E\[!6?O?C!7?_o?_!5?GKG?w!14?G?E$#113!152?G!5?B$#114!159?O$#115!5?_!94?A???A!37?E$#117!5?@!28?G??A?@!65?G$#118!101?O??_!36?_$#119!122?O$#120!34?C$#121!159?K$#123!122?_!24?OA$#124!31?[?A$#125!105?@!29?o$#126!105?C!35?F$#128!6?_!28?C!29?_OGC!82?_C$#129!31?@???@$#131!104?@!22?_$#132!134?C!7?g$#134!70?A!6?@?A!47?@!22?_C$#135!34?@$#136!32?K?A$#139!100?C!27?C!13?O$#140!134?@$#143!100?_!21?G@!24?@$#144!33?G$#147!30?@!90?G@$#148!100?G!37?oN$#149!136?G?M?]$#150O``BA!105?__!6?G!11?AG_!4?o??_???_$#151!117?oog!9?G@!12?LKR$#155!8?~~z~B!9?_!16?owoow!4o!18?AA$#156!67?_owssM|~C?C??E}FEEEKEE!6A!31?G$#157!151?A$#162_OO_!99?_!4?GCSS!7?O!10?CCK$#163A???C!97?GN???O!21?o!13?OB$#164!145?_$#166!42?@!25?A$#169!151?OA$#170!129?@!6?C$#171!4?G!97?aO??gE!12?GA!21?a?K$#172!126?_?_$#175!147?A$#179!4?@!25?A!5?A!69?@!21?O$#185!121?O$#189!100?O!46?C$#192!99?_$#193!70?GIpA?z~I{{X@wxxxrxx!6|!4~[$#195!123?w~~B!21?w~^@$#196??K[!104?voII}~||w@@?A!9?waAX??oL!6?O$#211!121?_!24?O$#212!29?A?_!5?C!6?@!20?OGC$#214!16?@?@@??EC!4?@!16?AAACA?DDF!4?wwg?ooO@@@$#215!25?B!12?G!18?!4B@$#227!78?@!30?@$#228!102?O!17?_C!24?E$#231!148?C-#1!13?_O?G$#3!18?G?O!4?_$#4!22?C!136?A$#5!104?E!29?G$#6!101?F!33?A!5?M_$#7!15?A?@@C!9?GGO!128?O$#8!102?_!32?O!6?K$#9!125?G$#10!31?@$#12!102?G??W!20?G$#13!65?_!35?_!23?C?@$#14!5?G!132?_N_$#15!30?@?@$#16!103?@!23?w$#17!106?OC??@??!6_!11?I?G$#18!133?E!10?C$#19!107?B??AAB???@??W!16?_$#21!145?@$#22!120?C$#27!7?O!54?O$#36!120?_$#47!10?_$#48!13?C!6?C!6?G_???_$#53!7?A!6?A???AA?@O??G???O_GA@!26?_C$#54!8?EKLBA!10?AC???@d???C?GMEeeO!4?OBX___$#56!121?C$#57!100?A!20?G??O$#59!33?A@!14?@BhgwBFFDU]KB$#60!62?@$#73!64?C!30?@!26?@$#75!63?_!5?_a!6?@???@!63?_???C$#95!7?G!4?G!8?GA!8?A!29?G$#97!12?_?GG?C!6?O??o$#99!101?G!23?OA!8?K!5?oO$#100!19?@A!40?oK$#101!145?C???O$#102!64?A@!84?@$#104!125?_!9?_$#105!11?_O??CC$#106!13?O?O!5?_??_$#107!7?@?Q!25?C!11?AN]WABB{wwyg_O$#108!121?A$#109!27?@!4?C!13?G$#112!10?AC@@!11?CC!7?EA???@!7?CO?C$#113!16?A!6?G!126?G@$#114!13?GC???C??Q_!8?_!127?@g$#115!105?@!20?D!15?B$#116!149?_$#117!6?k!127?B$#118!141?@$#119!66?_!33?@!24?A!19?G$#120!149?G$#121!14?_??G?GG??_?Oo!133?C$#122!15?_!4o_$#123!62?_??G!34?C!20?O$#125!104?w!29?o$#126!6?O!97?@!29?C@$#128!6?B_!55?A@!85?C$#131!101?OO??A$#132!105?C$#134!63?G??O!33?G!20?_!23?O$#135!64?O!81?A$#139!5?@$#140!65?O$#143!146?@$#146!120?B$#147!120?W!23?O$#148!138?^o$#149!103?O!33?O??^$#150?``M}o!102?!4o!19?oA!4?h!6?@$#151!128?][?E@$#154!15?@!10?G???C!9?_$#155!8?x`OGCA@!7?@@BBAEEA?CWwwpowPOF!4~ns_$#156!63?O?A!5@AA@@!8?AADBCC??C!5?@!24?A?G@!20?C?_$#157!147?@$#162bY]o@!102?W!4?_!17?o?o!4?E$#163[C!104?__!9?@!10?_aCH$#166!16?@!4?CGC!6?O$#169!5?A!99?_$#170!5?C!96?C_$#171!106?N!12?_!8?@!4?H!9?NA$#175!144?_A$#178!11?O!5?A??@??OG???W$#179!63?C!38?BM!22?oE!5?o!9?o!6?A$#189!121?@??_$#192!66?C?OOO?ooOwoaWG!7?__!5w}m?gFE$#193!65?CI}mMK|LMmFFCfv~}~||y{ZZFFBFF@?FE$#195!122?{~F!21?w}^B$#196???@!104?NNKL[^^^]]^F!9?@@?C$#197!136?^$#212!7?C!22?A!31?A@$#214!26?@!9?@@GGG!10?SSC!4?@@B$#220!64?g!35?O$#221!76?GW!17?OwOwx_$#228!144?G-#1!10?A@@!4?_!9?GA$#2!7?K!96?o$#3!10?CA!4?_??S?@!5?_WC??O$#4!7?@!51?_!89?@$#5!102?C!39?K$#7!28?@!4?O!127?O$#8!102?GG!37?B$#9!124?A$#10!61?@$#11!141?O$#12!6?C!96?A!21?A$#13_!65?@!36?@?K$#14E?W!134?_@Py$#15!60?A$#16!109?g!5_?_!9?w[???_$#17!106?S!10?C$#19!136?B$#20!119?O$#22!119?G$#47!33?G$#48!8?A@!19?@$#53!33?C_!20?GWwwC$#54!34?W_C{~My^{q_??P}fA[SW$#56!120?G$#57!101?C!42?A$#59!49?W@!8?@$#73!61?O??@???A!75?G$#75!69?@@!50?@?C!23?G$#95!30?@!28?G@$#97!8?OE@$#98!7?O!95?_M!29?~$#99!124?K$#100!59?O$#101!120?@??O!19?_$#102!60?_A$#103!6?A$#104!124?O$#105!8?G$#106!18?WG??@!4?SCA?A$#107!51?BBB~vfFF$#108!101?A!18?A!23?@$#113!7?a$#114!31?@A!127?@k$#115!102?O!32?B!5?K$#116!103?C$#117!6?@!95?@!45?G$#119!67?A!52?o!27?A$#120!123?G!23?O$#121!8?cG???@???O_!4?@???B??A?K_$#122!9?ow{}}~~^NFb~}}}~~~?_w{{_$#125!104?@!37?o$#126!102?AO!38?B$#128!60?K$#131!124?_!10?C$#132!125?@!9?W$#134!61?K@???CD!33?G!46?@$#135!144?C$#139!124?@!10?_!5?_$#143!65?@!54?C$#147!143?O$#148W{_??_!60?A!70?[}mD$#149?ACw_U_!116?_!9?O???B$#150@@BF^H!111?`!12?z^}$#151!102?_$#154!39?@D!9?{_gc$#155!8?@!24?BF^zB?o?_BL^~~m@$#156!121?]!22?O@_$#157!123?A!20?_$#162!106?Ggl!4@???PW!8?C_c~C?@$#163!106?bVQU]]]^^~MA@!6?o?AZ$#165!119?_$#169!105?q!42?C$#170!6?G!98?@!19?C!7?_$#171!118?m$#175!101?@$#178!32?@$#179!6?O!53?O!64?GB@!5?N!9?N???_$#192!61?_wb{[O??AEE^^^|||{lllLLL|||x~^^MKLKCN}$#193!68?@??@$#195!121?_~@!21?}^F$#196!136?_$#197!136?[$#215!59?A$#221!62?E[Aagw{{ww___AAABQQQqqqAAAE?__prqrzo@~~o$#228!118?OF-#0!200?$#1!13?_WCB@?_O$#2!8?W!95?N$#3!9?Koo_G?P?A?KCO?_Oo_!6?Co$#5!103?A!38?@$#6?A!102?_!18?c!18?C$#7!34?A$#8!103?C!38?_$#9???_!119?A$#12!124?A!10?@$#13?@!5?G!116?[!8?C?C!5?@$#14???BEFC!130?SOwz_$#16!106?A!7?@?B$#17!136?A$#27!57?G$#53!35?C!11?_??_W??~{[A$#54!36?IW]K~~f~~~}B@@$#55?G$#56!143?B$#57!58?_!63?_$#58?O$#59!35?@$#73!62?@@!37?@$#75!146?@$#94!119?_$#95!34?@G!22?@$#97!8?B$#98!103?@!30?~$#99?C!140?W$#100!58?A@$#101!102?_!40?C$#102!59?A!86?C$#103!7?A$#105!8?C!11?_$#106!9?_???OcI???OG???_!9?G$#107!55?BA@$#113!8?_!137?_A!14?_$#114!35?_!126?F$#115A$#116!143?_$#117!7?@!138?O@$#118??W$#119!102?@$#120!145?_A$#121!9?O!6?C!4?_!11?BC!127?W$#122!9?BNN^FB_w{~BBN~^NN^!6~w$#123C!58?C!41?_?O!16?F?O$#124w_$#125@!103?O$#126!123?W!18?A$#128!57?oK$#131??C!102?_!17?@$#132!7?C!97?O$#134!59?G@!41?A!17?_?K!22?O$#135!120?W$#139!124?@$#140??_O!131?A$#143!103?_$#148??BKwwW_!101?_!14?_!10?o??NFC$#149!4?@?`!99?Oo_!4?ooo!9?W__?oo?w!4?j???W$#150!6?A!99?_@X^~~~FMK{o!7?_WWwGN}F$#154!36?_!10?[}}^f~~??@$#155!35?ASf`r??W???@$#156!121?XA!21?_$#157!122?@!21?OG$#162!106?GIA!8?NG!8?FFF?@$#163!106?CCC!6?B??v!6?@F$#165!119?N$#169!105?N!27?w!9?O??G$#170!7?O!125?B?G??_??E$#171!136?`$#172!143?G$#175!58?O!44?G$#178!35?O$#179!106?@!6?G!11?E$#192!61?@???G???!7@BBBF@B!5?@@!4?!6F???O$#195!121?e!22?NF$#202!119?O$#212!56?_C$#214!36?@$#220!59?OE[W[??AAC??GO???OOooo___???goaqQO!4?OO]sCC$#221!59?_waea~v||z}}um}}}kkKGM[^^~~~UM\Lln!4wgg`JYG$#227!136?[\ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_mugi/24x.symbols b/fastfetch/logo_mugi/24x.symbols new file mode 100644 index 0000000..3633311 --- /dev/null +++ b/fastfetch/logo_mugi/24x.symbols @@ -0,0 +1,14 @@ +[?25l ▂▄▆▆▆▅▆▆▅▄▃▁  +▄▆▖╼┌┊┊▇┊▆▅▖▃┈▅▖  +▄┏▘╴▎┫┊╈╴▘┈▇▘▇▄┈▝   +▌▘╵▏╶▃▆▏┈╻┎┊▝┊▋▝┈▝   +┈╻┊▂▄▄▄▏▎▅▋╹╵╹╴╻▌╴▋  +┖┊╴▂▂▁▇▏▖▖╴▊┊▝▂▌▊▏▊  +▄▚▗▅▇╹┈╹╴▎▘▅▏▏▍▋▌▏▋  +▏▋▇╾▄ ▃▇▉▁▇▆▊╴┊▗▘▊▍  +┊▎ ┈ ┈ ╶▅╴▘▏▎╶╷┊▗   +╽┊▉ ┈ ╴╴┊▅▇┉╻╴┈▘  +▋╴╴┈ ┈ ┊▗▘╴┈▗╽╴▘  +▋┊╶▁▂╺┈╴▆▃╷▅┏▘▉▗   +▗▆▆▖▉╴╵▅▅▆┃▉▍┇▗   +[?25h \ No newline at end of file diff --git a/fastfetch/logo_mugi/32x.sixel b/fastfetch/logo_mugi/32x.sixel new file mode 100644 index 0000000..b531331 --- /dev/null +++ b/fastfetch/logo_mugi/32x.sixel @@ -0,0 +1,2 @@ +[?25l[?80l[?8452lP0;1;0q"1;1;280;420#0;2;0;0;0#1;2;0;1;6#2;2;17;7;7#3;2;15;16;18#4;2;10;24;37#5;2;33;18;6#6;2;33;23;14#7;2;7;28;43#8;2;34;30;22#9;2;43;28;10#10;2;43;36;26#11;2;51;33;18#12;2;53;38;18#13;2;53;42;28#14;2;61;44;29#15;2;47;49;50#16;2;63;47;32#17;2;64;47;32#18;2;65;49;34#19;2;67;49;34#20;2;67;50;34#21;2;67;51;34#22;2;67;51;36#23;2;69;51;35#24;2;70;52;35#25;2;70;52;36#26;2;72;52;36#27;2;70;53;36#28;2;72;53;36#29;2;52;54;55#30;2;70;54;36#31;2;70;53;36#32;2;70;54;37#33;2;71;53;36#34;2;70;54;36#35;2;71;54;36#36;2;71;54;36#37;2;71;54;37#38;2;72;53;36#39;2;71;53;36#40;2;71;54;37#41;2;72;53;36#42;2;72;54;37#43;2;72;54;37#44;2;72;54;38#45;2;72;54;39#46;2;53;55;56#47;2;71;55;37#48;2;72;55;37#49;2;72;56;39#50;2;63;61;54#51;2;72;59;41#52;2;58;73;89#53;2;72;73;74#54;2;75;57;41#55;2;79;61;46#56;2;81;65;49#57;2;83;69;53#58;2;74;74;74#59;2;74;75;75#60;2;76;75;75#61;2;86;75;58#62;2;94;72;58#63;2;96;73;59#64;2;96;75;60#65;2;99;75;61#66;2;98;76;61#67;2;99;76;61#68;2;100;76;62#69;2;98;76;61#70;2;99;76;62#71;2;73;78;82#72;2;91;78;56#73;2;92;79;56#74;2;92;80;56#75;2;100;76;62#76;2;99;76;62#77;2;96;79;62#78;2;100;77;63#79;2;84;87;89#80;2;94;83;59#81;2;96;83;62#82;2;98;88;72#83;2;100;90;67#84;2;100;92;68#85;2;100;92;68#86;2;100;92;67#87;2;100;92;67#88;2;94;92;83#89;2;100;92;69#90;2;100;93;67#91;2;97;93;77#92;2;100;93;67#93;2;99;94;75#94;2;93;93;93#95;2;39;25;11#96;2;10;27;41#97;2;26;20;18#98;2;37;18;3#99;2;74;58;41#100;2;74;57;40#101;2;1;2;5#102;2;14;7;5#103;2;100;93;68#104;2;91;94;96#105;2;54;63;74#106;2;67;60;44#107;2;35;38;40#108;2;43;28;12#109;2;44;31;14#110;2;43;37;31#111;2;15;20;24#112;2;12;25;36#113;2;82;74;59#114;2;87;75;57#115;2;45;39;32#116;2;51;34;19#117;2;0;0;0#118;2;0;1;9#119;2;77;72;70#120;2;74;74;74#121;2;14;16;23#122;2;16;18;19#123;2;28;27;22#124;2;27;31;36#125;2;79;63;46#126;2;81;65;47#127;2;56;41;23#128;2;54;42;29#129;2;70;79;90#130;2;80;78;73#131;2;76;58;43#132;2;77;61;43#133;2;90;73;55#134;2;94;71;58#135;2;100;77;63#136;2;84;88;90#137;2;93;80;57#138;2;99;76;62#139;2;96;79;60#140;2;94;81;59#141;2;100;77;63#142;2;55;43;32#143;2;61;45;30#144;2;96;83;62#145;2;98;86;71#146;2;34;22;9#147;2;41;23;7#148;2;51;38;21#149;2;55;38;21#150;2;71;70;71#151;2;73;72;73#152;2;63;47;33#153;2;64;47;32#154;2;67;51;36#155;2;67;52;36#156;2;49;53;60#157;2;69;53;36#158;2;98;89;74#159;2;100;89;67#160;2;0;0;0#161;2;75;75;75#162;2;76;75;74#163;2;65;48;33#164;2;65;49;34#165;2;70;52;34#166;2;70;52;36#167;2;72;55;38#168;2;72;55;39#169;2;62;46;31#170;2;63;47;32#171;2;69;50;35#172;2;69;51;35#173;2;82;68;54#174;2;85;69;53#175;2;74;74;74#176;2;74;74;75#177;2;94;82;58#178;2;94;82;58#179;2;67;50;34#180;2;67;52;33#181;2;70;54;36#182;2;94;74;58#183;2;96;75;61#184;2;55;47;36#185;2;61;47;32#186;2;66;49;35#187;2;67;49;34#188;2;71;54;37#189;2;72;53;36#190;2;72;54;38#191;2;72;54;38#192;2;50;55;60#193;2;69;55;37#194;2;70;55;37#195;2;71;54;37#196;2;56;73;93#197;2;70;70;70#198;2;98;75;61#199;2;99;76;61#200;2;92;79;56#201;2;92;80;55#202;2;100;92;69#203;2;100;92;67#204;2;100;92;69#205;2;100;93;67#206;2;69;52;36#207;2;71;52;36#208;2;71;54;37#209;2;71;54;37#210;2;71;54;37#211;2;72;53;36#212;2;99;76;62#213;2;98;76;61#214;2;90;78;56#215;2;91;78;56#216;2;100;92;68#217;2;67;49;33#218;2;67;50;34#219;2;71;52;36#220;2;72;52;36#221;2;70;53;36#222;2;72;53;36#223;2;72;53;36#224;2;70;53;36#225;2;70;54;36#226;2;70;54;37#227;2;70;54;36#228;2;72;53;36#229;2;71;55;37#230;2;72;58;41#231;2;70;67;64#232;2;94;72;59#233;2;96;73;59#234;2;98;76;61#235;2;98;76;61#236;2;99;76;62#237;2;91;79;57#238;2;92;78;56#239;2;94;83;59#240;2;94;83;59#0!255?!25?-#8!62?O???G!6?C!15?AA!14?G?O!19?C!12?C!10?O!4?_$#10!74?C!16?A!24?_??O!12?!8C!5?G!9?_$#13!120?O!4?G!24?O???_$#14!126?G$#18!99?C!49?O$#29!98?A$#51!84?CCC!18?O!46?_$#56!63?_!24?C!33?O!6?G$#57!76?G!12?C!40?GG!5?G!13?_$#61!90?C!44?GG$#81!65?_!4?O!8?G!20?G??O!16?_$#83!71?O!33?_!19?O!14?OOO!6?_$#84!66?_!6?!6O_!5?O!5?_oo??OO?__???_!17?_!5?_!9?o$#85!99?O??O!28?__$#86!69?__!11?WO!13?_!41?__$#87!78?_OOO??O!7?G!5?O$#89!72?O!13?O??GWW??WO!4?OO!28?_??oO$#92!83?G!57?_??_$#97!65?G!18?A!36?G!4?C!19?G!5?O$#103!84?GG!51?_!4?_$#106!67?O!4?GG!7?CCC!56?GGG!4?OO$#110!59?_!39?A!22?G$#113!97?C!20?_$#114!106?_!25?GGG!10?O$#115!60?_??O???GGG!22?A!35?C?CC$#123!72?C!12?!4A!26?_??O$#125!102?G!25?G!10?G!6?O$#126!75?G$#128!75?CC!31?_!20?C$#132!74?G!12?C!10?C$#140!96?C!47?O$#142!64?O!35?C!23?G!19?G$#144!94?CC!54?_$#155!62?_!8?G!8?C!22?G!17?O$#159!80?G!18?G!21?_??O?OO!15?O$#164!107?_$#173!68?O!69?G$#174!104?O$#184!61?_!8?G!6?CCC!13?!5A???CC?G?O!16?G!19?G$#185!65?O!87?_$#193!66?O!50?_!9?G$#202!98?G!30?_$#203!71?__?!4_???g!8_!4?___?_???__!21?___!6?__$#204!67?__!17?GWW!6?GGG!25?__!4?!4O??OOO!7?!4_$#205!73?_!6?_!8?O_??G!7?_!37?O???_$#214!69?O!7?G!13?C!31?O$#216!128?O!7?_$#237!64?_!27?C!8?G$#239!93?C!25?_$#240!78?G-#6!170?G$#8!51?C!4?@!56?@$#10!47?O!6?A??@!108?C$#13!109?@!59?G??O$#18!158?@??A$#51!168?G??O$#56!108?@!64?_$#57!113?A?@!47?C!6?O$#61!57?A??@!98?A$#81!111?C!42?@!17?_$#83!112?C!4?@!43?C$#84!51?O!12?!4_MKkKkk!10?@@@F@!4?@!15?OO?OOSO?A?k``_?AQqaA?W_cdEE@XX!9_`CAOOA!12?___$#85!66?A!56?C!7?@@!8?CC@??DKK$#86!52?OO!5?O!10?@???@@?@!6?oo_!7?CC?AA?@!8?K!6?GOO!35?O??GGOOO!7?_$#87!58?O_O?@!11?OO?_??wkks??W__cc_C{O?___aCA!5?CC?G??G??O__!35?A!7?_??O$#89!53?___!5?_OW]][]!6O!40?___??Q]]FwKkKKK@@!8?\^ZZ[]]WPO!14?___!4?_$#92!63?@@!6?@!26?@!26?@!29?AA??C$#97!44?_?O!6?A!106?@!6?C!5?O$#103!51?__???OWGGg]EC!8?@@ME!4?COO!4?!5Ww!4?@?CA?@??GHA???GG??KC!7?@!25?@@!5?AC?C!5?O$#106!46?_!6?C??A!107?C$#109!175?_$#110!49?G!109?@$#114!156?@!10?G$#115!45?_!12?@!104?A$#123!110?@$#125!51?G!105?@??A$#128!52?C$#132!110?A$#144!50?O!63?A$#145!58?A$#155!48?O!10?@$#159!53?G?C!5?@!45?@!45?@!4?A!5?GG??O$#173!49?O$#177!155?@!6?C$#184!50?G!4?A!106?A??C$#185!111?A??@!59?_$#193!112?A$#202!48?_!13?__!88?@!10?G$#203!57?__!7?@??B!4A_?@?@`!4@MME??@!4?AAECC@?@??@!5?C_!5?KK!30?@?CC?g{{SOgg_??O$#204!49?__???WWKCCCE?G!50?C?AA?@@??WB!4?@!10?A!22?GO???O???_$#205!56?_!6?A?@?@@_!5?g}]}]AAAI!4?EABFBAhxXWWWw{}~wvUwy??O?_G!9?o?@POye]YYwx}ee!6?@???y{g_sC??__??GO$#214!47?_$#216!59?A!8?_??_!32?E?_??__?_!5?A!9?_C!4?@!8?A@?AAA??AIG$#237!52?G?C!54?A$#240!116?@!49?G??O-#5!180?A$#6!182?C$#8!37?G!149?_$#10!39?C?A$#13!179?A$#18!42?A$#57!41?C!84?C!58?_$#61!45?@$#81!37?_??G?C!72?O_!4?C!5O???W$#83!120?C!55?A$#84!44?C?C?A!4?A?CBA!5?@!4?C???F!32?A!25?BCC!9?!4FBB!10?BB??@!9?C$#85!42?WW!12?GO?!4OG!23?_!20?_??__O!29?G!15?OOOoOOOooO_o__wGGG?G???O$#86!69?C!9?CFFB!6Fff???_!20?C???A!4?@@!8?!4_!16?ffc$#87!44?GGGA???CC??Wo!7_WWOWW?C?__CCC?C!7?_?_??RwZGwwK?fwwwogw?wWWwWW??GC???A???_??_??@??_??HGgFWWWOWW??WXxB!4?A]\!5GFFDDDOIZY?A?___gg_$#89!40?_!7?C!5?ABC?C!4FE!8?OZ!24?_!22?_`@!6?E[G!26?___?___??_!5?@??G$#92!47?GG!5w__!9?!4_w__??___??Www{w??GGG?G!43?OOO!17?WO!23?OO$#97!42?@!141?G$#100!117?O$#103!40?O??C!5?EEAAC!16?WWG?WYZ^W!11?O?B?O?Br^W!13?K!7?A???__?___?oWKK?OOW!11?W^^!10?!6G@?@Boq!5?O__$#106!36?_$#109!177?@!7?O$#110!36?O!6?@$#113!38?O$#114!120?O???C??C$#115!35?_$#123!34?_$#125!119?G!58?A$#126!116?O??O$#128!37?O$#132!118?O!10?G$#133!118?G!10?O$#140!179?C$#142!38?G$#144!128?C$#148!181?C?G$#153!126?G$#159!44?A!70?_G_!11?C!54?_$#170!127?G$#173!39?G$#174!125?C$#177!117?G???O!5?O!47?@!5?G$#180!124?GG??G$#184!40?C???@$#185!186?_$#193!122?GG!52?@???C?G?O$#194!120?G$#202!39?o?g_!14?!6G!50?_O???_$#203!44?oqqoo!5?W!9?_!4?B!7?_bb!4?wwOOOW?k?_!13?C?_!4?MAA??@!6?@@!10?C!8?O!7?GX!19?OOO$#204!38?_!8?D!7@??C!15?C!43?CCc_?Aa!6A!46?CCC$#205!45?C!8?C??@B!5?FF?FA?BF??B@!16?CCFFC???FFFEFDBB!5FB@@@BB?@@!6?@@?_BABBEFB_fff!4_cceEc__???`aCCFFE??AAAFCCC$#214!43?A!133?A$#216!41?O?_??@!11?O!4?O??N?@!34?HO?{!7?_!18?@!12?WG!26?CC$#225!121?G$#237!123?C!4?O!54?O$#239!122?C-#3!28?O$#6!189?@??C??O$#8!32?A@$#10!31?C!164?_$#12!146?_?O?O??_$#13!29?O!163?GO$#34!94?_$#35!96?_$#38!93?_$#45!97?_$#48!92?o!30?__$#49!76?__!5?!4O???_!30?_$#51!187?@!4?G??_$#54!65?_!4?__O!5?OO?OO!31?_$#55!98?_$#56!61?_!6?O!9?G!16?O!14?_!7?OO$#57!117?O??O!28?G?_$#61!30?O!4?@$#81!33?C!28?O!7?G!11?!8C!18?_???O!36?_!36?@!7?_$#83!68?G!7?C!15?C!14?_??O???G!9?G??O!24?G?O!34?C$#85!32?OO???Aco??A{?o__!9?_?OO?HGCCC!5?A??AAA!9?@@!9?EGW??OGGO@C?GHFB?DF!7?A???OWgwoO??GCA?O___!4?@!4?A???I@??C???GHGGHHHJJ_G_gG!5?K??AO_$#86!49?O?_ooo!9?!5@A@!63?BA!8?UA!39?A$#87!33?___oo!6?o?OO_!20?C!25?C!6?o??o!14?CC?C!4?G_??GG!5?o?[WS??C!8?GGOo!5?W!4o!5?CCDCD!5|ooww_O$#89!30?_??G?K???F~~{!21?G??CC?CC?AA???A!12?A!6?@!4?A??_OO!4?C???EE@B@BB!6?O??_wwow{Ii???_??EA!4ECG?AcM~~RvvfFEFFo??OOOo??o??AAA$#92!49?n~^FN@xWG!11?@A???@@@???!4@!5?!5@?@!28?!5@?@??@?@@!4?@???K!4?@???@@@!32?G?O$#97!27?_$#100!63?__?!4_??_oooOO!9?!5O!23?!6_$#103!34?OO!20?_!39?@@!24?C!16?DD!13?CCC!17?@@?@!6?@G?CG?G$#106!31?GCA$#109!190?A$#114!146?O?G?G$#125!70?O!10?G!8?G!20?_$#126!69?O!9?GG!10?G$#127!147?O?O?O$#128!30?G$#132!62?_!8?O!8?O?!8G!4?O!17?__!11?_$#133!67?O!7?GG!20?O!11?_!4?O!7?OO$#140!64?OO!5?GGG!19?G!19?O!34?_$#142!34?@$#144!34?A!24?_???O!34?O_!25?O?_!19?G!43?G$#148!188?@$#159!32?G!25?_??O!7?G!7?!5C!8?CC??G!4?O!11?O!14?O?_$#167!84?!6_???O!28?_$#169!152?_$#174!77?G!14?G???O!18?OO!4?O!4?_!18?_$#180!154?_$#181!95?_$#184!28?_$#185!191?C$#190!78?!6_$#193!152?O!36?A$#202!36?G!5?@!31?CC!24?_!11?GG???G?!5G$#203!31?__?G?A!7?FFNN^!5?MEE!4?G!4?A?A??@@!4?@@!5?@@!6?AAF??G???o??o!4?N!4?A!12?G!6?C??@!5?HH!39?A?C???o_$#204!31?O??CA?@B!26?GGG!4?CC!5?!12A!26?@H!26?OG?C!4?G?O_!4?_?G!6?oo__!11?@??C???O_$#205!38?G!5?GG!6?G???@V^LNBEFAA?A???A?@!5?@!6?@!6?C?AEEGFFNNLFFBMJ?FE??DA???E?A??C!4EFEFFE?CEA@??AFA?@B@?@?@@@AA?@!11?EEECC!7A!4?CA!5?_$#214!153?O!36?C??O$#215!60?_!13?G$#216!36?DKOG???B!15?A?C!33?GG!6?_??K??O!5?GG!8?GG!29?O!4?GG!11?G?WO$#229!91?_!55?_$#237!29?_$#238!66?O!57?O$#239!151?G???_$#240!150?_!37?A-#6!24?C!177?G$#8!23?G!175?A???O$#10!22?O??CA$#11!89?G???G$#12!84?_!11?A!59?ACG$#13!201?G$#14!88?G!5?I$#18!198?A$#22!85?O?G$#26!123?@A$#28!124?@@$#30!113?O$#36!99?G!9?O??O!14?G$#37!80?_!12?O__OW$#38!84?G!4?A!35?A$#40!55?_!6?_!14?__GGSW!5?@!29?OGCA@???]$#41!84?C!36?CC?C$#42!61?_??os[{?_!13?A!4?A!36?_$#43!60?_!13?OG!4?O!4?G@@!5?_??_$#44!53?_!25?_$#45!52?_!33?GC???__??O!34?_$#47!104?O$#48!79?CC!4?C!4?B$#49!52?OOG??C???!4A!4?!5@!23?@???G???G!4?A???@@??@@@!8?G?O_$#51!199?C???_$#54!47?__oO!13?@@@!66?O$#56!22?_!77?A!6?@$#57!45?_!53?@!57?A!38?@$#61!27?A$#81!50?C!5?@!48?@!25?A??GO!8?`!7?@?A!5?G$#83!47?G!82?@!16?@$#84!26?o?Gagg{_!4C_?S__!4A!88?G?O?CCFbF??G??U@!11?CG!4?O[[FBKCC?CC!8?@???E??C?A??O$#85!37?_!5?@PH@??@!88?_!12?_!5?O!9?__!4?_??BB!19?WO$#87!28?COSO?[W?!4WgWGG?CCFFA!4@!81?CCCOBBOGGCK??AHMOGKO!7?G?NF^\N??WWO_!4w~~~!4n~mnkggikACC$#89!28?A??B??BBAA!5B!60?@!28?!7@???C!5?C??@??C???@??C?@?__??@@???@@??@$#92!136?GG!4?OO!8?C?G??_!36?@A$#97!20?_!5?@!171?@$#98!86?_?OO?GG?C$#99!54?C!44?A!4?C?AA?@@!17?ACC???_$#100!50?_WGG?CC!4A@@@???@@!31?C?GGGCC?AA?@@@!12?@AC?GGO_$#103!31?C???W!102?G??G??W!5?OG???O!5?G?OOW!8?W!7?!4O?OOQUOSO$#106!23?O$#108!90?O$#109!92?C???C!103?C???_$#114!156?@?O$#115!21?_$#123!25?A$#125!50?G!7?@!68?@???C!26?C$#126!52?C??A!45?C?C?A!28?O_!9?A!7?@$#127!88?_??S!5?E!56?@@???O?_$#128!27?@$#131!98?@$#132!46?_?O!4?C??A??@@!47?@!20?A??G!13?@!10?G$#133!49?G?C!5?@!88?__$#140!44?_?O!6?A!94?_$#142!197?@$#144!25?G??@!19?G!87?_!7?A$#145!24?O$#147!85?_?o??G??C?C$#149!86?O!8?A$#155!202?O$#159!23?_!19?_?O!6?A??@!44?@A?A!29?C!12?A??_!5?CG??C!35?@??C???_$#163!89?_$#164!83?_!6?C$#167!54?oWGGKSS[[!6?!5[L!6?G??@@???@!4?@?@__CW!11?!4A@@A?A@!4?_C?OO_$#168!51?_!36?C!9?A?_oo!4?CC!20?_$#173!26?C$#174!47?O!6?A!47?C!25?@?A??G$#177!161?O!39?O$#180!145?@!14?o$#185!24?G$#186!92?O$#190!56?ooO_???[KIAA}A!5av~^^RBBFDAAEA!35?o_$#193!84?O!4?C!4?O?G?C!5?_!4?!5G!42?C??G$#194!81?_!23?_???CSSCCKCC$#195!59?GG!30?B@@!4?W_???o??G!4?A__?GAECA!8?W$#202!24?__?WO!4?A?__!9?G??C?A!49?@A!28?@AAEAQaEoo_!5?GG?_!11?A!6?aa__?AA??A!10?@!4?wwwcgG$#203!29?C!12?OO!10?@!96?Eqo___?_!8?A!23?@@B!5?___$#204!25?OGc_@B?B@_!15?A!51?@!36?GG!4?OSUP!4?A?GO@ABFBPe_!8?B$#205!200?O$#206!90?_$#208!63?_!43?oo_!4?__oO$#211!66?_!50?__OWw_$#214!159?_??_!34?A??G$#215!106?@$#216!29?G!6?@@Cc?CCCK!59?@!38?_!28?C???C!13?@$#218!93?A?G$#223!58?_!60?__?YMW[$#225!155?A$#226!82?_!9?A$#229!83?W!11?@???O!5?OoGG?__??OOGGGC!7?o_$#237!132?C$#238!104?A!40?_$#239!129?@-#6!212?_$#8!14?O???A$#9!48?_!29?O!86?GO_!42?O$#10!13?_???C$#11!80?G$#12!74?_??G!4?@!80?AC!41?A$#13!80?A$#14!75?O???O!85?CG$#18!81?@$#26!114?o_w?@A$#33!89?A$#34!63?@$#35!98?_$#36!41?_!10?C!16?K!30?!4C!30?G$#37!46?GC?G!25?G??A@_!7?@!40?@@$#38!59?CC!15?A!73?___$#39!89?@$#40!48?EC?C?C?AA!5?AA???_K?A_??CC!8?_!5o|o__OO?OO!9?B!5AKA@?Oooor_??BBB$#41!61?@$#42!49?A?A!6?EIJMK[Lvv@q@@B!4A!7?O??GK??AAO[!4?E!21?GKK[!5?{o!14?G?oKSOO$#43!52?A???@!14?O?G!12?AA!35?@!6?AAA!20?_$#44!82?G!46?A?@$#45!47?A?@??WG!4?G!20?_!12?@!40?A$#48!98?@!46?@@$#49!38?_?OG??CA?@!4?_OG??G??_!72?@BACGGOOGG??C??A$#51!19?A$#54!54?OOO!78?@!8?A!4?A?CGOO$#55!136?@$#56!14?_???C$#57!163?@$#73!153?C$#81!16?O!20?G??A!111?A???O???@A???_?A!6?_$#83!15?_!5?O!13?O??C!99?@!14?A!12?@?A?C!37?O$#84!28?!6B!4?@A@!111?@??C!18?!11A!9?!5A?@$#85!22?__!7?GGG???@!101?@!17?G?O!11?@B??K_GGC!4?Gw!4?GG!5?_???@??G??O$#86!163?O$#87!18?G_g?GW!132?C?H!15?@@@`P!6@F~n@J!4@!4[{v{{{oCG$#89!23?!5@!6?@!169?A$#92!16?_??W!139?BEGO__!24?!5_!11?_$#97!15?G!190?@!4?O$#98!75?_?OGGC?A@@$#99!38?O!6?@!124?O$#100!37?_?OGCCE??@!9?GOO!77?AC?GG?CCCA?@??CG???_!9?O$#103!20?!4C!135?k___!26?OQQYY___!5?AA?C??_$#106!15?O$#109!79?C!125?@???G$#114!21?@!144?A!38?A$#123!19?@$#125!55?__!108?A!38?@!4?O$#126!37?O!5?@!13?__!83?A?@!4?@!5?O_!14?O$#127!50?_!26?_!8?@!75?@???_!44?_$#131!53?_$#132!36?_??GC?A?@!9?_!4?_!77?AC??C?A!4?@?A?CG!10?G??C?G??_$#133!35?_??G!131?G$#140!36?O!5?@!98?A!30?O$#144!20?A!136?_!4?C$#146!207?AC$#147!49?_O!25?o!4?E?A?@$#149!49?O!32?C?A$#152!78?C!88?O$#153!50?G!111?A$#154!76?G!10?@$#155!78?_A$#157!48?O!24?_O??C??O$#159!34?_!6?@!97?AA?@!8?@??CG!7?G?@!5?G?O!29?@???G$#164!168?_$#167!41?OO_o??G??C!9?O!9?K!29?@A!10?@@!20?CCG!6?G$#168!42?GW?KE?H!52?@!30?@!37?_$#169!47?_???O$#171!51?G$#174!41?A!97?CC!10?A??G!13?C!4?_$#179!85?A$#180!161?@?C!43?CG$#181!82?_$#184!16?G$#185!20?@$#187!81?G$#189!50?A!11?@!84?A?G$#190!50?@@@BCKCF@P?oo_o??]@ooKLD@@@!6?G?KC!4?LM!4BJG!24?A!6?K{{{!5o__ooOwo}Ko_G?O?_$#191!143?_$#193!45?_oO!56?@!59?A!4?_$#194!44?GO!30?C???@??_!19?@A@$#195!42?_!11?@!44?AA?BA?AA!7?A!20?G$#202!18?_???@?}uw!4{sssMBBAA!101?@!15?G?o!10?@@C?JK?KCCg{kk{s!4?CC???!5@?A$#203!17?oOCOGO!16?@!113?@BBBF!20?_!9?}!15?oOO??_$#204!21?AAA?GEA!6?OKKC!103?@!15?O!9?@@???KCOo!15?CCC!7?A@???G$#205!158?E?WSG$#206!51?_$#208!55?@!13?A??oOG??B???O!12?!4_?{!4w{{{~{|||{{@@??_!5?~~{{{$#211!64?AGG!17?[???MK!5?GW!18?C?`??CA$#214!17?G!188?C???_$#215!39?C!98?A!4?@!6?@$#216!21?_!142?O!4?AAA!4?OO?O?OO!4?O!11?G???K??__$#217!83?C$#219!81?_!35?O$#223!82?O!11?KCCC!17?WEMMLB@$#229!39?__!13?A!23?@!20?@!6?@$#230!44?A!121?CGWO?_$#238!137?@$#239!164?@!4?C-#6!213?@$#8!214?A$#9!44?C!123?@$#10!10?C$#11!42?_O???A!21?O_C???@!68?O?_!22?C$#12!46?C!21?_??O?@A!92?@AAG!47?_$#14!49?@!95?G$#18!44?A$#21!169?@$#26!111?WWwF@$#30!171?G$#33!65?_GO?A!44?O$#35!35?_!28?_?_??C!6?owW!4?@!10?@@!8?__???A!24?WO??_ooOO$#36!33?_!5?C!111?owo$#37!68?G??@!4?C$#38!36?__!113?@$#39!88?_$#40!36?C$#41!38?O!30?@!81?AB?CCA$#42!37?O!25?@!53?@?@_!4?!4_```bb@@EC?!4B!7?B??Bwy{C__$#43!38?_!20?_ow{Y!5@?@???oo?CEAEEE?FF!4B@?@O!18?B???GOP?^F^^!5W]]][[?A?GOC?CC!4?@??C??C?@$#44!80?@!65?@$#45!39?OG!17?O!13?_?G?AB@!65?!4EM~!21?AM$#47!38?@!132?C$#48!32?_??CG!137?O$#49!31?_?GC??@!12?@!4?_!4?@!96?A??_!11?OScW?_$#54!172?@B??G$#56!13?@!154?C!10?O$#57!178?G!38?_$#81!9?_O!19?C!24?@@!122?G!34?G$#83!12?C!14?OG??A!16?C???_O!105?@ACGO!12?@!5?_!32?O$#84!13?_?___?___???_!21?__!135?_???O!5?oO!4?_ooo!10?_$#85!15?G?W?@???]FV?CC?@!17?O!4?A?E!107?G!15?B?G@A@F??E!5?GKCEE?C$#86!50?G!113?CGG!22?!5L!15?FEC$#87!11?Ow?_O]!5?__GGEBA@!15?_OW?o?CCC!109?F???g!10?@?D@?OUov~h__??_E_xxxjBN??!4_`G__?g?_$#89!13?O!4?}]^^^@!6?A@!18?C!109?@BF??`A??_!7?@A!4?@!10?@@!20?_$#92!164?@!24?OOoOO!16?WGG$#98!41?_OG?C!23?_OGCA@!72?_$#99!29?_!145?C$#100!30?oWGCAA@!19?O!99?@?CGO_!11?_A?OO_$#103!13?C?F?F!26?_!4?G??A?A!109?GOsO_!13?O!12?AA??SW!9?@AC$#106!8?_OGC$#109!48?@!21?G!144?C$#110!9?G$#115!7?_O??A@$#116!72?A$#125!28?_O???A!17?@!105?@!22?_!34?G$#126!30?G!13?O!10?O!118?@!41?O$#127!41?OG??A!26?G!71?G??O_!21?O!41?@$#131!177?GO_$#132!32?C??@!12?A!5?_??GCA!98?ACGO_!8?__??AC$#133!49?A??@???G??@!101?G!14?A$#140!27?_O!24?@P!114?O!5?@$#143!46?@$#144!46?G!11?A!121?O!31?A$#145!58?@$#147!44?G?A@!97?OO$#148!216?GO$#149!40?_!32?C$#153!143?O!26?CO$#154!69?G$#155!39?_!31?a!141?A$#157!40?O!31?@?C!69?_???O!21?A$#159!11?G??@!18?@!11?O!5?A???G?@!110?G!8?AC!34?C$#167!32?O???A!19?_OG!100?O!15?__$#168!43?A!126?@@$#169!143?G?_$#172!68?O!46?_$#173!12?A$#174!31?C??@!135?_!6?C$#179!70?C$#180!169?G$#185!43?C$#186!76?@$#189!36?O!41?_!14?@!57?CC$#190!37?GG!20?[MFB!16?C!13?G!23?MG}!18?K!4?B@@??@!8?_G!14?GG$#191!72?Ow!5?@$#193!41?KC??H!29?A!71?G!66?C$#194!34?_!4?BBAA?@!30?C$#195!33?OWW?EEGC??@!13?__!16?G!18?W!23?_!20?GKG?c!6?wG?G$#202!13?A!12?oG!4?@!16?C!6?C!110?C!11?C$#203!11?_?G]?@!7?o!4?E!16?_?G?owWGC!109?AC!14?AEMK!8?_!11?!4^]o?OOO$#204!10?_!7?@!37?AA!106?O???O!11?GO?_!30?O$#205!165?A!23?!5A$#206!67?_$#208!42?@!20?_]]UME?A!5?G??___`!5_!6?c}|~}!5~^^~~~lFB???Oo_!6?!5F!5?ekwo!4?G$#211!81?@?A!7?@?A!60?B$#214!43?_???C!5?_!113?A!43?@$#215!159?AC?O$#216!26?H?@!25?G!109?_!19?GGG!15?NN!8?_$#218!146?G$#219!111?__E$#222!83?C!26?_??@GC!5?w$#223!63?C!15?!7W[[[{}}}c!15?OWCC??IF?E???___!11?@BB!18?WO$#225!41?@!52?A?A?@!42?__$#227!114?_$#237!166?@$#238!32?A!24?C!100?@!4?_!17?_$#239!29?G!20?A-#6!5?A$#8!6?@$#9!35?_!77?O!34?@$#10??_O$#11!37?CA!27?CC?@!44?QA!70?_$#12!36?G??@?@!105?@!37?O$#13!4?GC!213?@?C??_$#14!36?_?GC!26?A!47?_C!32?A!37?O_$#17!113?C$#19!149?A$#20!67?G!117?_$#22!37?A!74?O$#26!111?W$#27!66?@$#28!69?___?__!35?w!11?oo$#30!139?O$#32!148?C$#33!65?O!7?O!35?O$#35!63?@C@!22?B!15?^^???B!26?[^^?^^L?A!8?A!28?_$#36!29?CCEQJAA!81?KK!25?@C!7?@!5?NKK!17?W$#37!70?A!45?A!28?A$#38!35?@@!73?BB@$#39!61?_!4?OO!5?G!19?O!14?@!4?@$#40!53?G!64?@$#41!153?K$#42!52?_o??O!6?oo___?OO???K?OK!12?A!28?KCo!6?@@@BBB!12?_o__{G{o!5~ooO__$#43!54?CCC!12?GG!77?OO!12?O$#44!28?G!88?OO$#45!26?_!42?CCDF!42?_k__!27?EC$#47!145?@!38?G$#48!28?CwWXKC!17?_???AAK!85?@!4?G!11?@AK!14?CECG!4?G$#49!26?WEAA!19?_OGCA@!106?@AW!11?A?O@?C?G$#54!162?@AKO_!6?@??_$#55!181?@$#56!4?O$#57!51?A$#73!173?C$#81!8?@!30?G!127?O_???A$#83!23?CA@!20?O!4?@!114?C!7?_!8?@$#84!8?GA[Q?AOoooN?\AAA!18?G?A??@A!118?A?O`w_O!11?A!7?R??@B!6RB?BBBOOU]\?G?A$#85!184?A$#86!19?O!171?_$#87!7?C?O?@@?_???o@?!4@!14?__G???W!123?@O?G!13?B?CKGJKGWwwwG?G??GwwgggGGG??D?_??G$#89!5?o__q_bkkK!4N??AC!18?O?OW@?JE!118?@DGMMCO_!10?@@C?GOB!7?!6_?@???!5_Oo??CC$#92!41?O!126?@!18?BB?O!23?A$#97???GC$#98!37?GCA@!26?A@!44?_$#99!51?C?@!126?@$#100!23?_OWC?@@!18?_OG!112?CO_!8?BKO_?@AECG$#103!41?___?EC!121?E!18?C?b!15?A!7?A!6?G$#106???_$#109!222?GO$#114!222?O$#125!49?G!113?@!9?A$#126!50?C!113?A?O_$#127!34?_O!4?A!179?A$#132!22?_OGCA@!19?_O???A!112?G!8?CO!6?AC$#133!22?OG!141?C!6?@!10?A$#140!7?A!39?O!116?@!21?GO!30?@A$#143!112?_$#144!40?CA!7?C!124?O!13?_$#147!36?O!77?K$#149!66?G@A!44?G?@$#153!37?O$#154!38?@$#155!36?C!33?@$#157!33?_WG!33?A!114?_$#159!4?_!16?OG!14?_O!6?_!4?A!114?A!5?@?G!11?C$#166!113?A$#167!27?G??@!20?O?CA!13?G!107?NB?A$#168!25?_!24?_?G??@!119?@!5?GOO$#169!114?@$#174!174?G_$#177!6?C!214?G$#180!184?O$#181!64?G$#185!6?A@$#186!115?G$#190!54?GGG!17?A}K!42?Rz!43?_!12?Gw$#191!27?oo!44?@!42?O??_!29?G$#193!139?N$#194!32?_??CA$#195!30?a_@!19?O???@@!7?A!41?__!38?G??A!28?__??_$#202!12?O!152?@?GO???C$#203!6?WGCG???@!5?G!23?C{???@?@!140?Oo__!20?FM{oo__$#204!9?@!11?GC!15?_OGCA@?@??C!117?A!4?A!15?GO!25?G??@A??O_$#205!9?C??A!6?e!22?CA!5?B!140?cCB?FDE!4C??!6CBF@@???@???O$#206!65?C??C!46?O!30?@$#208!37?@!16?___q~~~^^A!4?O??WW!6?!9~{!4o_!5^!5~__~^O!8?BA!10?!5o~~b!5_q}{wW???@BB!7?A!20?_$#209!73?E!38?C$#214!5?G!46?@!129?@?C!35?C??_$#215!21?_??CA$#216!7?O!5?o!6?_!26?G!121?_!23?C?A???G?KK???OOOC!4?_?O?G$#217!65?G!83?@$#219!111?CA$#221!112?G$#222!89?B!20?C$#223!54?OO!6?_!5?_???_?P@br~!10?KLNNN!5_!9?MK?_!9?NNN!4~}MMKKK!17?s!9?_$#225!33?OC!28?KB!44?_$#226!71?A!75?A$#227!34?@!81?@$#228!149?C$#229!180?OO$#230!24?_$#237!42?@$#238!26?@!19?_?G!117?G-#8!228?GO$#9!111?O!76?AC?o_$#10?@!224?AC$#11!33?C!77?GPA!73?@??O$#13C!188?G$#14!29?OGCA@!77?C_C!74?@$#18!186?@$#21!113?G$#22!110?O!79?_$#27!104?G$#28!68?!4@?`F!47?NN!27?GG!12?KG$#30!28?O$#31!104?O!10?OO$#33!76?_!27?_!10?__$#35!29?A!19?C!7?GG!14?E!31?WO??H!5?K!65?@@$#36!48?_$#37!29?C!79?o???o!72?_?G_$#39!61?@!9?o??G!6?o!4Gw!6?}!23?_???o$#41!26?O$#42!25?og!17?_???K???EF!5?GGE?B???C{!48?K??G!26?BBFFEFVHNJG?@!4NBqS_$#43!47?G!27?G!43?G!38?GG$#44!26?@!89?A$#45!22?WwO@?@C?A@@!13?w!63?M!4?B!71?oo$#47!180?O$#48!19?_!30?@!118?_$#49!21?KC!20?_?GCA@!117?AC!11?M$#51G!191?O$#54!18?O!24?OC!121?@@C!8?AE$#56!17?O!152?G!54?AC$#57!32?O$#81!16?O!19?@!133?C!19?AC$#83?G!13?_!16?_!9?C!128?G!56?_$#84???C!4?E???GM_N@@!18?_sO??A!129?@@?X?_!19?BF_!5?GGGIIGG?!4G?@@?C??C???_$#85?O!209?@??@?@$#86!8?O?o!28?G!184?C$#87???Gy}}}G?GGooP?EE@!16?WW??OG!152?G?FKG!6?FFFDDoo?!4oOO_oywxo??O$#89??C?!5@!4F??OG!17?G??Gk??DA@!126?@?ENaWO!13?@?C!4?_N!4~f!5oFFEFFEF???A???GA$#92!9?o!28?@@@!184?G$#95!29?_$#98!30?_??A@!77?C$#99!178?W_$#100!17?__WKAB@!18?_?WCA@!119?AGW_!6?@@$#103!34?O_?A??A!134?_!19?!4O!20?@$#109!32?G?A$#110A$#114?C!32?C!159?_!29?@$#125!20?A@!147?C!8?_!48?G$#126!18?GC!151?_!5?G$#127!35?@$#132!31?_!9?_OG?A@!121?A?O!5?@C!50?O$#133!16?_!27?A@$#137!42?G$#140??A!168?O$#142?A$#144???@!14?CA!155?@?_!11?@???O$#146!230?_$#147!30?OWC!78?_I@!76?G$#148!225?@$#152!187?A$#153!110?_$#157!29?G!84?K!74?O???_$#159O!16?G!25?A@!124?@??_???G!15?G??_!30?GO$#164??@$#167!20?O?_??G??A!16?o!4?AA!128?@$#168!23?ENEEE???A!17?@!129?@_$#169!188?CA$#174!33?G!134?@!7?A$#180!190?C$#181!74?_!39?_$#185!28?_$#187!111?A$#189!52?@!20?G$#190!21?O??_!22?CA!13?A!4?w!7?F!42?C?F!35?CFFE!5?@?Go$#191!28?@!87?@BBF$#193!30?C!83?A!68?Ox@EC!41?_$#194!27?_!20?O!131?GwwgAyGG$#195!20?_!6?WG!20?A!56?EFF!9?G!61?EEEFCCO$#202!39?_!131?A!44?EIIC$#203???o!4?_G?o??M!19?_!157?BFNG!25?FE?Go_$#204_?o!30?O?CA@!4?@!127?ACWoCC!15?A!4?_!20?CC!4?@$#205???AC!28?_??C?AEC!150?@!28?@??A$#208!21?_!25?o?w{|ww~~~VTDF!8?}}MM?OoWww~~N!5F!6~@!5?!5~FfhwwE!6?GOOoo!8?!10~!5@NNF!7?!10ow$#209!57?__$#214!35?A$#215!43?C!133?O$#216?_G!10?@!4?A@!20?OG!133?A!18?O!8?W!7?w!4?g_OG!4?oC$#218!114?@$#221!111?@$#223!59?oow|{~~~BA???pO??FFF???!4o!8?!5~!11?@!5?C?_??Noo!5~!10?!5}oow{{wwpogE!9?C?_O$#225!58?AA!54?O$#229!29?@@$#230!179?O!11?G$#238!40?_O!127?A$#240!20?@!155?C-#5!26?GC?@$#9!27?I@!24?_??C!53?S!43?C?_!35?@@?O_$#11!55?O!54?A!83?GC$#12!110?_C!43?_O$#13!25?G$#14!22?G?A!29?G!54?O?G!42?A!42?O$#16!26?A$#17!53?O$#18!27?@$#21!194?@$#22!195?A$#24!153?C$#27!156?C$#28!63?!4C!15?C!58?CCC!5?B$#30!47?KW!120?W!17?O$#32!113?G$#33!81?G!22?p!46?OO$#34!46?o??wW!100?GG!5?Go$#35!44?CC?B!66?@!52?EC!20?C$#36!41?O??WwGo_??WG!6?oo!8?ww???!5Gww!8?!10w!20?!7w???!10w!10?WW??W_??GOG!4wWwwwG!19?O?E$#37!19?OEE!4?@!19?C!4?_O???`?W!53?oq!68?W???BC$#39!61?o!9?~??!5O??r!4?FC{!4?F!10C?@!13?E?F!4Cw!26?_$#42!17?_!25?CB!14?AA!45?@BA!43?D!11?F!24?A$#43!16?_?_!6?@!15?_ww_B!13?CCG!46?C$#44!24?@!32?_!10?w!37?w$#45!17?GKKG??@!22?B!10?WC!53?KC!73?B!9?GO$#47!193?_$#48!15?_$#49!14?_O?C?@!19?GC?@!128?GO!7?@o!18?_$#51!26?_!206?O$#54!16?AB!155?_$#55!196?A$#56!27?O!146?O???@!16?@??C???_$#57!231?CG$#81!11?_?CA!15?A!4?O!137?A!4?G!24?_!29?_$#83!178?O!18?@???G$#84!4?GGGw??_G!18?GoEI!141?F!29?GC?g?C?!4Cscc_!5?Gs[O$#85!176?G!24?A!19?_$#86!206?OO$#87`C?{vvvFw?O??@!15?OoI??CBB!139?C!29?_g?BB??!6B^^N^^Hs??A?_O$#89!29?G??G!4?@!136?@!24?@B@BBFVBFV!17?G?GG$#92O!8?@!220?G$#95!25?O!207?G$#98!21?_OGC_O?A!126?G!38?CG$#99!173?O!5?A!20?O$#100!13?oWKC?@!17?_oWCA@!128?@FK!6?@}!16?C???_$#103G!31?@??C!191?_c_C?_$#108!22?_?G$#109!24?_?C!84?A!82?A!37?C$#125!15?A!21?G$#126!12?_?C!20?_O!142?O$#127!20?_O?C!31?C!54?@!82?C??G!34?A??_$#132!16?@!21?CA@!131?AG_!4?K!19?G$#133!172?@C!5?_$#140!175?_??C$#142!24?O$#144!29?C!6?G!137?G!21?@??C$#146!234?O$#147!23?O!30?oG!54?G@!43?O!37?A??O_$#148!25?C$#149!56?G!52?_!44?GC$#153!29?A!168?_$#154!157?_!37?_$#155!109?C!84?O?C$#157!112?A!80?G$#159!12?G!14?_???@??_??A@!136?O?@!20?A???O!26?@$#163!55?_?C!96?O$#164!52?_!56?G??@!78?@$#165!155?A$#167!16?WO!21?OWI?@!126?A!11?_!16?O$#168!19?A??B!148?O_!8?K!8?@!7?G_$#169!25?A!30?A!99?G$#170!192?A!37?@$#174!13?G!187?O$#180!30?@$#181!48?BCC??BB!99?@@$#185!23?_!4?C$#186!57?A$#190!18?A!19?___?EA!63?C!44?A@!34?A$#191!18?O!39?B!48?ww!79?@$#193!19?_??C!135?_!10?_o!12?B~[[G?WOQ$#194!168?A?G_!9?BF[?b??G_gk{O_$#195!20?@@!19?C!17?GG!54?@!40?@BB!5?_???pB!13?_!4?C@$#202??s!8?O!22?O!142?e_!20?A?CCC!28?O$#203?w?A!4?E}MFF!15?__?C??A!141?B!29?G!17?EB@@??O_$#204E?J!27?C?osGG!137?@AGoW!20?@???GWw_???g!6wGWW?_?__!5?U?G$#205???@!4?@?@!22?@@!193?@$#206!54?C?O$#208!49?BBFFC!15?FF???!7F!6?BB!4F!6?!5B!4?@!5?EE@??@F!8?!10F!11?C!5?ACC!5F?FF@!18?___$#209!53?G$#211!58?_???!6w!4?ww!5_???!6w!11?!5wGw!8?!5w!8?ww!10?!10w!4_$#214!197?A$#215!12?O!24?CA!139?A!21?G$#216?B!11?A@!13?O!7?C!137?C!25?C!8?S?FB!8?O??o?AA$#218!111?O$#219!153?A$#222!81?C!22?E!44?C?C$#223!59?@@FF!4BFF???FF!8?BFFF!8?!5B!6?EE!9?EFF???!4BFFF!10?FFBBB!5F?BB$#224!50?_!4?B$#225!48?C!120?C$#226!20?OG?A!33?@!51?B?_?@!43?O$#229!170?C$#237!28?G!201?A$#238!15?@!23?@-#3!238?G$#5!49?_$#6!239?_$#8!236?A$#9!20?_?C!28?G@!104?IG!41?_$#11!18?G!31?_?C!106?_$#12!21?_??A!84?B$#14!16?_???O?O!27?C???@!55?@!45?C?C!42?O$#16!49?G$#18!21?C$#22!14?O!141?G$#24!108?E$#30!48?G!110?G$#32!46?C!66?A$#33!46?@!11?_w!51?_oO!32?__!15?G$#34!44?oOO?@!64?_!45?@!11?_$#35!46?G$#36!13?G!28?@B???J??@???KC???F@!8?xpo??_!4o~~{{!6?!4F!6@!15?!5{!7~{{{~~!8@!7{[[{!5?H!5?J@BB}~~~}}{Wo!10?@?wB~`!5@w!8?O$#37!15?C!30?A!5?Og?@!52?@??CF@!40?oGO???o!9?AAB$#38!43?wG!13?W!45?G?G??_?O?G!47?_wO$#39!45?@!10?c_???@!6?oEI@ooWGGGN??BA}!4?N!4GM!5A!5W!5?G?GG?!5A!7?BAA??}!17A???A$#40!14?C!139?A$#41!17?@!22?A!16?A!4?Co!45?O!86?_$#42!13?C??@!20?EEA!17?@???C!45?W_?O!78?{{oow$#43!37?_GCG!15?W???EA!46?G?G!42?@C_!4?CO!10?G!13?[??!5A?O$#44!68?@!37?@!42?GGw?G??_$#45!52?_!58?@!43?O!15?@!24?E!4?C$#47!203?_$#48!14?A!159?o!19?C???_$#49!11?GCA@!17?__!139?@?_!5?Mo!18?@?C$#51!235?A$#54!31?_OGEB!138?BKo!25?@ACGO$#56!11?@$#57!9?G!165?@$#81!31?G!145?G_C$#83!9?A!14?G!4?_?CA!144?C?O!26?A??O_!24?C$#84!28?E!149?@!29?AAAI??U[YI?AA?AA??@AA!4?@$#85!29?G!178?@!5?G?_!4?@???_$#86!230?@@??C$#87A??p\NDBF!16?_A???B!180?CKW!5?{{}wwc^e{{~w_?Ao$#89!212?o?__?__$#92G!22?_oG!196?CC!6?EE??A?_$#97!237?C$#98!15?_OGCA@?GE@!25?OCA@!103?Co!39?AKO$#99!12?@$#100!9?oWCA@!19?OGCB!137?CO!4?@p!20?A???__$#103D!8?@!17?@!181?CC??_!13?@@!6?G$#108!15?O!4?A!28?O$#109!14?_?G??C?@!134?A!41?D?G!34?@??O$#114!237?O$#116!17?O???G$#125!177?_!26?A$#126!8?_!23?G!147?W!22?@$#127!157?@!41?A$#132!10?CA!21?C!141?AG???E!24?CGO_$#133!30?_??A!143?O!28?CG$#137!209?_$#140!25?A!150?A!27?@$#142!22?A$#143!51?O$#144!179?A$#147!21?O!28?G!105?@!40?@???_$#148!23?@!27?A!185?G$#149!17?CA@!28?_!4?A!103?O!39?A?O$#152!196?@$#153!13?_$#154!48?O$#155!18?OGCA!136?A!38?C?_?G!34?C$#157!15?G!31?_?CA???A$#159!7?_G?@!12?O??@???O??@!142?@??G!27?C$#163!155?@!42?G$#164!157?_!44?_$#167!12?G??AA!19?C!136?A!8?F!12?K?O!4?C??_$#168!10?_o!7?O!135?C!39?@GG??@A??GO$#169!25?@!83?C!49?O$#170!200?C$#174!31?O??@!141?C???_$#180!238?_$#181!45?g?C!111?A??C$#185!22?@$#186!19?_$#189!110?_$#190!34?owwX@@@???@!62?_!42?O?OS!19?{G!18?C??O_$#191!56?@!50?@!41?o_?g_$#193!17?__?G??G!27?_!59?A!43?A??@!10?@@!13?|!15?A?W$#194!14?G!169?AF!8?@!8?G_$#195!15?@!38?OY!108?@???@??CC!22?A??O$#202??~!25?_O!148?O_!28?G$#203o~?MAooC!18?[]@@!201?W~{GoO$#204!25?C!4?KB@!144?BM!26?@@@CHXp@@@BDT^@@?@@!13?_$#205!25?O$#206!16?CA!35?C!145?@$#208!53?O!134?Y$#209!45?C!67?C!38?C!8?A$#211!18?@!19?ows|}CE!9?__A[F?wwzL||~~M?CMNB!4F!4?@@!4~!6o!5{!5dO~uEO!5?!5@!8?@@???!7{!10@BBB!9?G?_!27?KK$#214!24?C!209?@$#215!8?O?A$#216!4?_?IW!18?__WE!177?A!4?AE!10?Z?W$#218!51?@G!57?A$#219!104?_$#222!41?A!21?AAA!38?F!47?@$#223!45?A!27?K!25?!5A!45?CCC?A!7?C$#225!46?_?EB!113?C$#226!47?O!62?C$#228!186?_!8?_$#229!12?oO!145?C!22?G}!4?C!5?A!9?O$#237!22?_!213?G$#238!32?C!146?@!25?A??O$#239!9?C-#5!107?o$#6!241?C$#9!17?o?C!25?O?G!60?S!50?G!45?_$#10!240?A$#11!12?G!33?_!61?_!50?O$#12!11?C!6?O$#14!15?@!29?G???A!57?C!51?_?_!41?A?O$#16!18?A!28?@$#18!12?@!37?@!55?G!54?O$#21!44?O!64?O$#22!17?C$#26!82?OO!13?_!27?A?O$#30!14?C$#32!42?_!68?_$#33!38?@!5?G!4?O?O!44?O!12?@???@!25?O!6?@@!7?g!13?B$#34!14?_!24?_???N!66?GC@!41?W$#35!40?_??O!57?_!23?o!73?_??_$#36!10?@???W!24?!4^!16?~}!8?!9^Oo??@!6?]]!9?_??_O?A???VZ]!11?o??@B!5?]]!8?!4WX!8?G!11?{~~!13?F?^~_!4?_@D$#37!10?A!32?_!4?_GGCA!54?A??_???!5E!38?Co??C?A!39?@??G$#38!13?O!23?@???_??C!4?_o_!24?__!26?KF!14?___!16?_!14?_C{_???BF?KKK!7?_!25?_o$#39!38?_!14?@___@@?@~!6?~!7_??nGw`ef!4?~``F!7?_!4?@!9?!10@GG`EC@@@??``r??!4@?``!8_!9?!6@$#41!13?_!19?_!129?o!35?K$#42!33?W??A!17?A!37?W!47?G??A!4?A!6?@!8?__!8?[!14?!5^$#43!32?W!15?O!63?_!43?@!5?G!36?A$#44!8?G!22?_!20?C!63?ggg!30?WWXW?B$#45!7?gS?C!4?AC!14?[!15?_???A@!51?_!52?A!4?O!13?[_!21?@!6?O_??_$#47!15?C!167?@!10?BAAA!7?C$#48!9?A!173?__!13?B?W!5?A?oO$#49!6?O!22?O[A@!144?O!4?^!24?@??O_$#51!19?G$#54!7?CA!18?_!149?LW!29?@ACGO_$#55!7?A$#56!6?C!172?O!33?O!27?O$#57!18?_!195?_!24?A$#81!21?A!4?O?A!151?G!31?CG!24?@$#83!6?@!18?_$#85K?YO?A!17?A!4?@!182?@A?AAGW@!18?_$#86!229?!7A$#87Q??MB@!17?{??CA!186?@@F?]!4~t~}~~~!5?__sMkG_$#89!213?ACC$#92!21?o?@!205?K!6LH$#95!242?O$#97!240?@?G$#98!10?OGCA@???GA@!24?_WCB!57?_!52?Eo!40?@AGO$#99!6?G$#100!28?oKA@!144?BA_??F!26?ACGO_$#103!20?OG}!189?@@!9?A?@!11?OQ$#108!11?OA@!4?C!139?@$#109!16?_!30?A!58?O!53?G!41?D?G!34?@$#114!4?_$#116!13?C!5?@!28?C!155?_$#125!21?@!7?A!149?_?_!21?_!5?@A$#126!5?O!21?O!150?A!32?CG$#127!9?O!7?G??A!23?_?C!111?A!42?A?O$#132!8?@!19?G?@!147?C??W$#133!7?@!18?_!151?@GA$#137!29?@$#140!27?G!152?C!29?@$#143!8?_!38?O$#144!6?A!12?O!159?C$#145!180?o$#146!243?_$#147!9?__!38?@!57?GG!50?@!43?C$#148!241?G$#149!10?G???A!90?_!54?C$#153!108?AK$#154!11?_?G!91?O!54?@$#155!15?_!190?_$#157!45?CA!62?_!51?G!38?AC???G$#159!4?OC!14?G!6?C!151?A!34?O_!25?_$#163!158?C!45?C$#165!109?A!45?O$#167!16?A!12?_??E!142?@!6?_O!17?GO???CKGG$#168!7?O???@???O?A!32?A$#169!200?@?G$#170!160?A$#171!12?O$#174!20?C!7?C!151?@$#177!240?G$#180!240?C$#181!44?A@$#185!16?O$#189!108?@!48?O!16?@$#190!12?_!17?_?_F^~WW!75?o!58?A^?U_!23?C!5?@AC$#191!9?C!104?wwOOO!30?FFEFF!21?G$#193!16?G?@!30?CC@!53?G!78?N$#194!5?_!10?@!167?OG!18?A$#195!6?_!8?G!167?E?O!8?[{w{{O!5?A?O?_$#202!4?C!174?@!35?GO$#203@~?@!15?_!4?}NB!190?__!4?G!5?@!6?A??o$#204??__G!16?C@!190?CGO!21?@??O$#205_!19?_???@!204?!5oOO$#206!9?G?A!146?G$#209!51?G!101?W$#211!36?dcC!13?gw\^V}}???!6~!11?CC]GG!4~???_f~~~N^r^RRF^A?@!6?M!5?}]]]}CC]gg}}}~~???RRAe}}{AAEE!7?A!7?CQQQ]]???w_$#216??D!22?OG@!188?_F!21?C$#218!48?G$#219!100?G!62?G$#220!52?O!26?@@!15?_!27?@@$#222!98?K?CK!34?!4K!14?C$#223!79?AA!43?A???O$#224!46?@$#225!44?@A$#226!106?C!50?@!4?_$#228!34?_??AY!14?E??G!34?W!10?w!4?@!29?__?O??@CC??C!7?A!9?___???D?A_!9?_~_??!4_???@$#229!9?@!7?@!165?G!20?@@$#230!242?_$#237!5?G$#239!211?A-#6!245?C$#9!14?OA!90?o!54?A!44?AG$#10!244?A$#11!6?C!35?G??A!55?_GC!57?@_$#12!16?A!84?O!4?G!98?A??_$#14!8?CA!5?H!87?GDA?O!99?_$#16!160?O$#17!10?@$#18!6?A$#19!101?G$#21!160?_?A$#22!44?O!54?_O$#24??O$#26!96?KMG$#30!4?A!35?O!121?@_$#32!97?_!10?_?C$#33!31?O!9?A!6?o!48?O!18?_!4?}!4?SOO!10?!5O!29?O$#34!28?G!10?N!84?NN!42?o!31?J$#35!38?M?N!6?o!51?DA!65?O!4?C!27?@$#36!5?B@??C?G!16?O!4GW!4o@!7?_IF!5?NN???NN!18?!4~!8_!9?D@!8?O!13?oo_!22?!5~!9?O?__o???qo!5_!4o!5_oo~~^NN~~}{wM$#37!4?C!93?_GGE@@!5?BJN!97?Em$#38!10?OE!16?C!22?@!47?A!20?@@@!51?@!25?CNA$#39!29?OO?O!21?OO^?{ooN!16?}!4?^!5O?Oo!6?O!11?_!5?O!57?O$#40!28?A!173?C$#41!10?__!17?@?@?@!59?O!69?@$#42!10?K?@!17?AA!20?@!111?NB!15?G???@??G!11?__$#43!9?_!101?O!51?C!12?OO!6?O$#44!95?O!16?O?MNLNN$#45!8?o!35?__?@!51?O??A!10?@!94?AGPm$#48!10?A!16?C!155?@?O!16?g_!4?@$#49??G!23?O!176?A!8?ICCW_$#51!246?_$#54?_!177?@!23?@G!8?@A$#56!102?_??_!74?A$#57!15?OC!200?G$#62!105?G$#64!180?@$#81_?A@!213?C?_!23?A$#82O$#83?C!214?@$#85C!17?O??GA!196?CO??_!7?_??B~??@??@$#87AA!15?o_GOoKB@!192?@@BNn~N~~|{|}{[K{{?~`!5?o$#89!16?O?K!201?_$#92!240?G$#97!247?_$#98!5?OGCB!33?oKE@!61?A!53?[!43?@$#99???A!210?@?G$#100!24?_wM@!150?@!33?@A?CO_$#103!16?_??BL?@!196?G!9?@??rB!11?_$#108!4?_?O!36?O!116?A$#109!13?O$#114!245?O$#115!246?O$#116!7?G!33?_!65?G!52?C$#125!204?@!39?C$#126!25?A!155?@!22?CCO!9?C?_$#127!108?@!53?O!43?HC$#128!43?_!116?G$#131!106?A$#132!4?@!19?OC@!154?A!23?_!9?A?O$#133!103?OGC!98?A!10?@$#140!23?O?@!179?G!10?A$#143!106?D!55?G$#144?G!204?_$#147!5?_?A?@???_GC@!27?@!59?A@?D!52?@_!44?CO$#148!14?C$#149!5?G!37?AG!55?_?O$#152!6?_!7?A!30?C$#153!108?A$#154!43?@$#155!5?C!6?OC$#157???O!36?_!5?A!112?A!47?AG$#159!16?G!5?_GA!193?G!23?@?G$#163!42?C!60?A!58?C$#164!159?@$#165???C!35?o$#166???G!37?G$#167!26?_I@!149?CA??BA!19?[!5?@???O__$#168!7?_!199?@C??PsgG$#169!7?@!4?_!33?@!60?_!100?O$#170!41?O$#171!108?C$#174?OC!20?_G!80?O!99?O$#177!17?A$#180!14?_??@!225?@$#181!38?_!7?O!80?__!10?!5_$#185!4?O!8?G!231?G$#187!102?C$#189!13?@!105?GG?GG???!10G!36?G!25?OOO$#190!11?@!17?EDCF??@!58?O!18?O!51?K!10?NNA?CCKKN$#191!48?G!45?___!15?NM@$#193!4?G$#194!12?GA@!30?O!163?O$#195!12?E!33?CC!115?G???NN^^!25?@BF!5?O$#202!15?_!202?A$#203?@!17?__!200?O!16?w}v{{Ko$#204G?@!14?KA!198?AC!23?A$#205@!18?SAF!208?BB!7?@?A$#206??_!4?OG$#208!164?_!4?__!33?_!9?O$#209!116?A$#211!9?G?O!16?!5_aLMNN!11?~}{}|___~B???NN!12~{{@!5?!7N@xnNNB?D!12?__?oo?oOvo?or???BBrrr!5v~~LLLNN!5~!5?!4~o_!12?NFKK???GG!11?Oo!5?_$#213!103?_o$#215!218?O$#216!18?@???OC!195?O???O??ABA!8?]E$#218???_$#219!41?@!8?@!25?@@!13?CC!33?@$#220!96?O$#222!34?A!16?A?A!22?AA!13?IA!5?A!21?E?EC??I!5C!7?AAA!32?A$#223!61?ooo!33?@!15?_$#225!38?O!7?G!112?[!42?@$#226!41?CB??G!43?O!18?W{$#228!9?O!17?o!5?C!84?_!39?N!4?AOON!4?H???R??GC??OO?M^NF??__!9?O$#230!209?_$#239!24?C-#8!250?O$#9!10?_WC@!84?CA@!4?o@$#11_!10?C!93?GA!54?A?_$#12!4?A!94?@!63?O!44?@$#13!39?G!209?G$#14!38?_!67?G!54?G?C!45?C$#16!106?O$#17!5?@$#18!39?C$#19!105?A$#22?C@!6?_!28?O???C@!50?O$#23!97?O$#24!36?O!52?o$#25!5?A$#26!61?CCC!25?C!20?C$#30!43?C!116?A!4?G$#31???_oo!27?_??_!6?o!115?_$#32!37?G!8?G!112?G$#33!4?GCG!24?G!6?A!9?@!37?gGwGGG?G!14?GGWWSO!4HG??@!4?wGG!5_!5?!5G!5_??_??!4_!9?_$#34!34?O!9?OO$#35!35?_??C!7?C@!42?o!58?!5@!13?O$#36!6?o!22?wwow?!4F!6?__@q!11?!14o!6?!4~ooo!6?AA!14?_O!14?@@!34?[!4?BFB?w!9~^^]}}!5F@@{}y!5~$#37!7?_!29?_!4?W?BB?CC!43?oOE?@!11?B!50?C$#38!6?AC!18?EFCBBD???WG!14?BB@!59?@!5?FFEFF!5?!10F!5?FFFEECC!9?_!7?F!30?@$#39?@!46?A!9?FCCB!16?F!4?F!7@F@!17?@!48?A$#40!9?G$#41!8?W!16?G!142?G!30?E@@xp_$#42!7?G!85?@!24?@!71?AB@@$#43!7?O!17?C$#44!159?@$#45C!6?@?B!86?AB!113?@@???W_$#47!12?G!206?_$#48!24?E$#49!22?_G!76?A!104?_!6?CGOo_@?O_$#51!248?C$#54!22?G$#56!21?GA!226?O$#57!20?_$#64!97?_???Q$#69!103?O$#81!208?_!13?G$#83!12?_GA!206?A!24?G$#84!17?A??A!201?BD??GGG_mnEEEF!7?ECkC$#85!18?oO!204?O_???OOO!13?O$#87!17?@NM!202?CY!5FN@?wxpgFFF!5?w???_$#89!244?@$#97!251?_$#98?oGA@!7?A!26?_GB!120?]$#99!218?BCGo$#100!21?_OE@!180?^w!5?GO_$#103!14?__`_!214?@$#108??C!9?@!26?O$#109??O!158?@!86?A$#114!207?@!39?A$#116???@!6?O!29?A!53?_$#123!249?C$#125A!205?C??@$#126!210?A?O!8?G$#127?G?G!7?_!30?A!53?GC!7?C!57?G$#131!104?_@$#132!21?OC@!77?@!105?_???C?_!5?AC?_$#133@!103?G!106?G!10?O$#137!207?G!13?C$#140!12?OC!6?OC@!183?@$#143??A!8?A$#144!223?_$#147???C!36?SC@!52?_OG!64?`$#149!40?_G!53?O??A!7?C!54?C$#152!40?@$#154!11?@!94?_!54?_$#155!163?@$#157!39?A???A!116?@$#159!19?_GA!185?EG?GO!8?@!26?C?_$#163!161?O$#164!163?A$#165!5?GC$#167!25?@!178?B!6?AA?MFB$#168!10?A??A!199?F@?C]w$#169??_$#172???O$#173!104?O$#174!14?@!191?AOC!10?@$#179!107?@$#180!208?A$#181!33?Wg???@@???GGGo!65?GK!5E!5?}}FFF!10?!5F!22?G!14?@@@$#182!99?GC$#183!104?A$#185!10?G!236?@??_$#186O$#187!41?O$#189!26?@!140?K$#190!7?A?C!13?owq!174?}}EM[$#191?A!4?@?@?@!30?_!52?@F!11?oC$#193G!163?{C$#194!164?B_$#195!8?_!160?F$#198!102?C?@$#202!16?G[??C@!188?_!10?@??_Oooo!15?A??G$#203!19?@@!213?GOwwwFFNNG??AOO$#204!13?o[^U!192?oO_$#205!239?wwooo?B$#206!38?G!54?_GGC?@!8?E$#209!47?Gw!9?w!14Gw!4?w!4?GGGO!20?G!71?___??!5G$#211!8?C!17?wwzCCAFF!8?_!6?~~{{{!4~!4?BB!10F!4~!6?EEEuEAE!18?baf`_!5o!5w???oo!5W!5wooOOoWWWXXyY]}}!4^~!9?o!15?!5o}{!8?w$#213!98?_owkzn$#214!210?C$#215!209?G!10?A$#216!208?O!15?GG!17?@??o_$#217!4?C!93?GC$#219!141?__!7?_$#221!37?O!121?O$#222!53?A!58?AA$#223!8?A!87?_!12?C$#224!92?G$#225!108?O$#226!10?C$#227!9?O!34?CCA!12?BB!30?oCC!71?Oo!26?C$#229!209?A!5?G$#230!210?@!7?CGO$#232!104?C$#233!98?O$#238!212?_$#239!246?@?G-#2!253?C$#8!254?O$#9!10?@!76?__OGCAA@!9?W@!56?@B$#11?@!7?A!28?G!49?O???C@!10?C!57?A$#12C!9?A!152?_$#13!251?@$#14!8?G@!27?SO!50?G!15?C!56?G?o$#17!39?C$#18!8?C!78?O$#19!104?@$#21G!6?_$#22!164?C$#24?oC@!30?WK?_!51?@$#25!4?@$#26!109?AAA$#30O???_$#31?GA?KD!20?_ow?ooo~BR\!5?GGC!81?C!7?CSG!33?GG$#33!5?A!22?C!13?CF?CC!31?OO?OG???@C!21?W?W!7?!5C??BCC!7?S!7?!5C!5?!4@?SO$#35!89?A!69?AG!7?W$#36!6?B@!15?wW[WK?~NNN!6?__ooo???B!6?!5w!4~!6B!4~???w??!6BR??C?@!16?g@!51?CO!6?_~vv!7~!5?w!4{??BBB!5~{{{www$#37!6?K?@!11?_Oo!16?GO!46?G???@!14?Q!54?K???BB!51?__$#38!84?o!75?B$#39??G!50?w!9?w!4?w!8?w!106?C!7?CC$#41!25?A?B!54?_?G!71?C!43?@!4B$#42!23?C!17?A!43?G??A!30?@!31?CKK_c?CF!8?GC!30?BA?CCC$#43!41?@!42?C!22?Cg!58?C!50?O$#44!107?AO!112?_$#45!22?G!17?E!65?G!110?_@S[O$#48!216?KK$#49!19?_?C@!182?@Co!7?@O$#51!10?C!243?_$#54!89?_!5?@!111?BO!13?Co_$#55!94?A$#56!93?C$#64!90?_!5?@$#69!98?W$#81!17?O?@!190?_$#83!10?O!5?_!193?O!13?@C$#84!15?_O?@!191?A@K?_!11?G??N~^USD`CCS_$#85!12?@!199?A!12?@$#86!249?{Kw$#87!12?Aoo??C!193?I!20?@BO?rqaWo_??o?EB$#89!12?GB!212?CKK!18?G$#92!13?CA!229?N{wsn?Q$#95!252?A$#98B!38?@$#99!18?_$#100!20?MB!184?BK_!5?@M!5?@J$#103!12?C?!4@!194?oo!13?OO!6?O!9?B??O?_??_$#109!9?G!28?@!65?_$#114!9?_!240?@??O$#116!39?A$#125!18?OC!189?_$#126!103?O!104?C!4?@CO$#127!104?A!57?C$#131!103?_!119?K$#132!11?@!8?@!187?G!5?A!8?AW_!25?A$#133!17?_G!196?_$#134!91?O$#137!213?A$#140!225?G_$#143!105?G$#144!18?C!205?A$#147!9?C!28?E!124?[$#148!253?G$#149!8?o!28?G!53?G!13?A$#152!86?_$#153!91?A!70?O$#155!8?A$#157!88?GC!15?_!55?A??B$#159!18?A!190?C??@CO!11?O!24?C$#163?A!35?A$#164!40?@!51?@!71?G$#165???]!30?C$#167!22?C!183?G!10?AMA_$#168!7?K!12?Og!198?BMo$#169!90?C$#174!92?G!10?G!104?AO!13?@CO$#177!252?G$#181!5?O!38?B?B!72?!5w~~www!5~WG!8?!5B!10?@$#182!103?C$#183!103?A$#187!105?O$#189!79?_???o!28?!7w!18?GG!10w?g___W!4Og_!6?o$#190!22?AB?@!142?A!36?A$#191!40?G!65?C?E!56?OCA!51?G$#193!9?O!155?K!86?C$#195!5?_!18?__!139?_!39?{o!9?`O$#198!91?_OooqUs!4?K$#199!92?_??K$#202!11?CO!4?G!192?L_?G!11?ABbb???GGIMGGG$#203!13?GK[MA!219?@@CK[{{!5?B??o$#204!10?_w_!196?@$#205!15?A!223?!5B$#206??@!4?O!29?@!68?@!54?@_$#209!24?C?C!14?C!5?CF!4?!5CF!4?!6C!4?B?CCCF!5C??A!79?G@$#211!24?B?B?B!13?B?!5w!4~!5B!6?!4w!6?!4BGGw_OG?C?B@!20?`|@??!5FA!4B???BB!5?BBB!4F??F!5?@EIRREIiig!7?o?@!10?!5~!5B~~{ww$#213!93?GC??BF~~~R@$#215!19?A!194?G$#216!209?A?S!17?o?!4_!11?@$#217!90?O$#219!4?A!29?___?_!42?G!4?C!22?C?C!29?FF!6?}PP$#220!112?FE!22?_oo$#221?Co!33?A!4?G!32?C!11?G$#222!78?_!32?_!22?__!25?_$#223!107?@!5?@$#224???_O$#225!6?_!38?B$#226!85?_O$#227_!4?GOA!65?{ww!14?A$#229!39?O!66?_O!108?A@?@$#230!19?W$#234!102?_$#235!94?G?gG_$#237!10?GA$#238!208?@G-#9!80?O??C??@!16?w!112?A$#11!83?G$#12!103?C@!111?CC$#13!255?@?G$#14!85?@A!16?AG$#17!82?O$#19!119?_$#22!77?_??G??A$#23!163?@$#24?@!31?W$#26!42?__$#30!219?A$#31!26?Owg!4w_!88?KG???{$#33!7?@!18?@BF@!4F??G??GGIGGG!22?GG??GGMG!36?G!4?A???A!6?!7A!35?C$#35!5?A!13?GKEKK!49?@@@!30?A!47?AA!18?o_!30?_$#36!20?ooop}}MC!11?_@@B!11?!9@?{{???!4@???@E?A!26?C~!11?C???C!32?ACC!5?EECEF!5@N^~~~!5{!5@!5?!11~}G$#37??@!18?@@!52?A!6?A!23?@!110?@?@$#38!39?@!35?OGGG$#39!38?oO_?CF!9?B!9A~AA}?B!4A???_P!84?@!6?A!9?!10A$#41!36?@@!41?@B?@!83?@$#42!109?~E!7?K!35?@@@BB???A??@A???EAAA!32?E$#43!108?F!98?A$#44!108?w!39?{!72?w$#45!220?!4@$#47!4?O!14?O$#48!224?_$#49!6?sA!8?_O!190?Aw!15?G$#51!216?G!39?C?_$#54!7?_!201?AO!13?@B{_$#55!84?G!17?_$#56!102?O$#57!15?G!199?A$#62!86?C$#64!102?A$#65!85?OO$#67!85?_$#81!9?A!6?@!194?G!15?A!26?@$#83!14?G!197?O!15?G!28?_$#84!10?_OWMC!197?CK{G!12?C^!9?~@aAA!10?CC$#86!235?[O!12?~{{~[?O$#87!11?__PB!199?A!15?{?cc???ss??@@?@?__!6?G$#89!212?AA!36?@@!4?O$#92!214?@O!21?II!5?}~ZRb?AA?@?_$#95!218?_!37?A$#98!79?_??G$#99!17?E$#100!7?[!7?_WG@!189?@C_!14?C$#103!212?@@!32?CK[!5?AG$#109!80?_!136?OO$#114!255?A?O$#116!84?A$#125!16?C@!208?A$#126!8?C!201?C_???@!11?G$#127!79?O!24?C!15?O!95?@$#132!8?A!6?O!65?_!127?@G!16?O$#133!8?O!7?A!66?O!18?G!107?A$#134!87?A$#139!8?_$#140!9?@!200?@$#143!82?C$#144!14?OC!199?C!12?O$#146!255????O$#147!81?O??CA!131?G$#148!78?_??G$#149!87?@!16?A!15?_$#155!78?O!138?_$#157k?}c@!76?C!23?R!113?O$#159!9?C???_!197?C_!14?@$#163!217?A?_$#164!104?_$#165?}??C???@!17?_?OE!54?@!21?o!12?GCK!42?@$#166!85?C$#167!5?wG!11?G!202?A???o$#168!18?E$#169!104?O!15?G$#171!103?@!17?_$#174!8?G!5?_!73?@!137?@?_$#181@???G?A!16?A!50?C???EKC!38?B@BBB~~~!7@!20?{{{ww!5?!5w$#182!82?_$#183!85?G!16?@$#185!218?G$#188!75?C$#189!37?AB!35?_gO!35?B^~~|FB!9?!6{~!4{}!7~B@{!4~!5?xxzww???@?o_$#190!76?C!41?o!88?CC!13?}}]$#193!105?C!112?CK$#194!5?@!13?@!187?__!11?s$#195!4?_!12?___!4?@@!179?@PHG!12?C$#198!84?O?GCWx@?@?ABq@A$#199!84?_?__?Euu{@??@oo$#202!9?_XKC??@!195?@Go!26?q$#203!215?_!15?G??~bn@@!4?@!9?a_?_$#204!9?OEBB!203?_!11?B!11?K[{{$#206!121?O$#207!34?@$#208!19?C!198?A$#209!76?A$#211!35?~e{K?OC??F!8~!10{?@@@FCKKCc!5?@??B?@!26?xF{_???w!29?{A!10?EECCE!6?W{{{!5?!5@!5{!5~$#213!83?_!4?c??@??{{KMK~~~$#215!211?O!15?C$#216!9?G!5?A!195?A!17?_BvZZ!20?O$#217!119?O$#219!34?]!4?AE!4O!23?O!4?OO!74?B!19?G$#220!39?C!95?!4B@$#221!122?oo$#222!34?_?O!4?_??_!22?o_oooO_!37?o$#224Q??ZA!16?G$#225!6?@!12?A!54?A!31?G$#226!105?g$#227!22?A$#229!5?C!12?O?B!186?OO!9?@?I$#232!102?C$#235!87?WA?GGA}@???@$#239!255??G$#240!216?O-#2!69?_!191?G$#5!70?oS$#9!31?O!88?w!97?@?O$#10!255?!4?@$#11!30?_!41?C!4?A!25?E!16?C!44?_!94?C$#12!103?G!16?A!43?_!55?G$#14!30?O!48?@!22?_!16?W!99?@?_$#17!32?C!40?O$#18!73?AA!146?O$#19!102?G$#20!31?C$#22!30?G$#24!32?A!40?@$#25!29?D$#26!66?DB!59?AF$#30!106?ECC!15?@!84?_$#31???k!19?_?^]~~???@_!29?_!5?@!41?D!11?@_??_!35?_$#32!63?CA$#33???O!13?C!15?@!33?GC!43?!4@H!11?G!20?!10@!4?G!5@!21?@!35?C$#35!4?_!11?O!46?B@!42?BArrqso!10?CF!48?BFFSoo!26?Dso$#36!4?B!11?G?@ED!4F!9?_!24?!4A!45?@!4G!10?C??E!49?GJN!5F!5E!5?!5F???@?FFAGG[$#37!15?O!48?C!57?F$#38!18?w!44?OOoO!49?Ow!5?O!5?!5w!5?!10W!5?!5WGO?WO!5?!5w!27?OO!21?OO$#39??W!32?CC?@@@!5?_!10?_f!4dGGH_!99?O!17?!5@!5?!5_@@@$#40!5?[!11?_!20?C!5?__!72?{???_!44?CC!34?[$#41!39?!4C!4?!4B!67?B$#42!17?BA!20?wWWWOOO!156?AB!20?__$#43!168?G$#44!5?b!68?@!47?O!44?OO$#45!102?A!119?O_$#47!208?@$#48!15?CA!205?BNMK__$#49!6?B!6?_K!57?_!137?K_!14?@K_$#51!218?C_!40?G$#56!13?C!61?G!136?C!46?A$#57!12?O$#61!217?@$#64!73?_??G!24?W$#65!83?GCDF@?@_??be_c$#67!96?A$#69!81?G$#72!12?G$#76!82?w$#81!8?K!4?@!199?G???A!11?@!28?@$#83!11?O!218?A$#84!9?_?@!202?@?G!13?@CGWwo_??@@$#86!215?B!33?FF?FE$#87!216?SO!15?DEMU~~]]Xww}w~xg!5_?_$#89!215?G?G!14?O_$#92!214?AC!25?EEE@F?EF!8OPe$#95!68?_O??G$#97!255?!7?_$#98!70?G?OG??A!143?_$#99!14?A!196?A!16?Mo!31?_$#100!6?o!6?O?B!194?BKo!14?BO$#103!216?B!25?@@!4?O!11?_$#108!31?_$#109!77?@!25?@!115?I$#116!74?G$#125!7?[!4?_$#126!7?_!205?_!15?C$#127!32?G!86?_!45?O$#128!73?C$#131!78?A!23?@$#132!7?B!5?G@!196?@G!15?@G_$#133!74?O??C!134?AO!15?A$#139!8?@$#140!212?@!17?G$#143!76?@!25?O$#144!8?A??_!219?_$#146!71?G??C$#147!71?_A??C??@!140?C$#148!75?A!142?A!42?O$#149!31?G!38?CA!31?o!16?@!43?O$#153!72?@!46?B$#154!29?_!74?A!16?]$#155!104?C$#157F?B@!26?C!38?C!5?@!29?EG!114?G$#159!8?o???C!200?C_???O!11?CO!27?C$#165G~?A!22?@???BB$#166!29?G$#167!6?C!9?@!192?@!11?AGO?BQ$#168!14?O!195?O!9?@C!5?O$#169!119?C$#170!32?O$#171!102?C!18?`$#174!80?@!149?O$#177!218?G$#181!112?AM]]!7?AWo`?O!5?!5w!10?!5}!20?{wo_!28?w$#182!79?A$#183!101?E$#185!67?_OG!149?OC$#189!17?WC!14?C!14?C!67?CF!5?G???C?!19FE!5?!5EFBBFF!5AFFFEC$#190!6?G$#191!122?G!45?_$#193!105?@?WW!15?A!95?A$#194!14?__!191?@??_!11?_$#195!19?@A!12?OWwww_!182?@C?@$#198!76?o_c!4?A!9?C@?X|`$#199!80?__??aa_e!5E?W]?AW$#202!9?NvI@!200?AO$#203!216?___!12?BFA@@@??___!9?F?@fFneOw$#204!10?GCA!200?@Ko?C!13?G_$#205!249?!7G?GG$#206!29?O??_!37?A!33?W!61?_$#208!4?[!11?c??!4wWW!8?G!4?W!86?GWW!51?G!9w!5?!5W__??_ww?AC!17?G$#209!65?C$#211!35?@@@??_``hHHXWwwwxx!5X!5W!85?@!12?O!5?G!4?@@!15?wwxxx!5?WWGG$#213!74?_o?WW{]VB@!15?~~@$#216!9?O!226?G$#217!76?C!87?GG$#218!104?@$#219!29?A???A@!31?GC@!54?_???@!31?oKK??CC!23?B$#220!166?G$#221??c!67?@@!95?_$#222!34?A!12?_!5?!4_!11?A!45?__a!11?_!10?!10_!5?!5_?___!27?A!10?__$#223!66?A$#224o!23?___!79?@??CC$#225!64?_!4?A$#226!67?OG!35?_wo__$#228!34?CAAE!5A!4EC?CC!7E!7?A!100?C!6?A!15?CCEEE!5?EEEC$#229!15?G!192?AA$#230!211?O$#232!101?_$#234!83?o!4WwwWwwW$#235!82?CC@???@?@@@??@??E$#238!13?A$#239!255?!5?O-#3!255?!8?A$#5!68?@$#6!255?!9?O$#9!28?OO!34?O?C@!52?F!44?@!54?@IO$#10!255?!8?C$#11!29?A!33?_!38?w$#12!28?G?C!37?A!33?C!17?G!100?O$#13!255?!7?@?_$#14!31?@!32?_!38?E!15?G!44?o?_$#17!29?@$#18!166?C$#22!31?A!30?_??A!100?@$#23!120?O$#24?E?O!20?_K!37?AA!56?@!47?O$#25!121?C??O$#31???_!14?OOooov???@!26?@?@???OOA@@!59?@M?@!6?!5A??EEG!16?^B$#32!58?OO?_!50?O!8?G$#33!23?G!94?C??O???O!13?!21O!9?K$#34!227?_$#35!4?F!8?w{~}wg_!38?!4MG!41?oonnn@~^NN!29?C!18?kB!14?@F^}w_!20?__s~~$#36!32?GB]!9?AA!181?Oo$#37!31?C!72?KK$#38!32?o{$#39!17?A@!18?__!7?WOo!4?{??oO!54?_O!75?!5O$#40!34?___!6?[!73?wX???@???oo{ww!69?!4_!21?Bo$#42!39?^[[[$#43!224?@G$#44!199?!5O$#45!5?B!26?@!134?AC$#47!211?AO!12?_$#48!6?E!6?C!20?@@!167?GGG!18?GCKB?G$#49!5?_@!4?_?@!198?FO!15?Aw$#54!12?@$#56!214?C_$#57!10?G$#64!69?CA$#65!73?__!7?{}MMME!5NJQ^B$#67!72?O$#69!68?_!4?G$#76!83?@$#81!255?!8?_$#83!8?U$#84!216?A?B!17?B!17?AA?A$#85!216?CCO!15?C?{!17?KSsCO_$#86!240?C?o!17?K$#87!216?@A?_!17?~N???BNzb!4B?@@@p`A?@C$#89!219?G_!37?K$#92!239?ABMKOC[!5{www!6?Bk$#98!29?G!37?A?@!95?{!56?_$#99!213?A!16?@$#100!6?w???_WE!200?Ko!5?C!8?@Eo$#103!9?@!209?O!23?_!6?BEEE!4?A??O_$#106!255?!8?G$#114!255?!8?O$#125!11?A$#126!7?F!61?A!161?AO$#127!29?_!34?GC!36?@@!15?F!44?K!55?A$#131!231?G$#132!10?OC!201?@G!16?C_!29?A$#133!7?_!60?C!32?C!113?O!15?@G$#134!101?A$#140!10?C!204?G!45?@$#143!103?G$#144!9?O!204?@!17?C_$#147!28?_CB!34?G!99?A!55?C$#148!66?A!154?@G$#149!102?A!61?B$#152!63?O!102?G$#153!28?C?G!39?@!32?_$#154!66?@$#155!27?O!194?A$#157!209?B!13?O$#159!8?@GA!204?C_??AO!11?AO$#163!27?_$#165ow?A!20?[os$#166??I!25?@!92?A$#167!13?A!199?_!9?@?O?K?C$#168!5?[!6?w!154?K!55?A!4?N$#169!103?O$#172!119?O$#174!7?W???@!59?@!29?w$#181!31?O!93?@@!7?!5@NNHHB!15N__{B!11?!4~}w_$#182!65?_$#183!67?G!4?@!18?O$#185!166?O!55?C_$#186!166?A$#189!53?@!4?___!56?F!4?C!6?!5F!5C!20?F!9?@@FFF$#190!66?G!51?_!105?E$#191!4?_!25?_!7?N!128?@J$#193!209?{~o!9?_@G$#194!14?B!148?K???O!43?K!12?_$#195!4?O!27?A???@N!6?DD!117?o???_!31?!4G?OO!6?G$#198!70?GYA@Oo??LGo!13?@???N$#199!72?GO??_??FN~A?@@@H!6?__{~o$#202!8?_?@!204?BWGKC!12?@MBN!19?GGG!4?G$#203!217?@!20?o|wp!14?@@?ZoA$#204!9?E!207?o_!14?@oo!21?o_???O$#206??t!24?CA?O!32?GC$#208!4?G!11?@CC!4N!8?gC??]]OO!5?wwf_!6?}~MN!5@!48?_!6?A!7?MM!34?O!18?@F^!5~!5_!5?!7FJ!5?_!13?B$#209!67?C!100?o$#212!82?@$#213!66?_oWwscCENN^~qo!19?~~$#214!219?@G$#215!9?_!204?A$#216!8?G!225?G$#217!65?O$#219!122?WO_!9?oo!33?_]$#220!123?K$#222!18?A!28?B!66?B!5?_?__!8?wwGGwww!20_G!9?A_www$#224N@?D!20?BBJA!34?CC!42?OOO}!14?M$#225???G$#226!27?G!34?O??@!38?BB$#228!17?@!21?_!4b???KN!4~A???_!55?_{~~??_?_AB?_??B??w!57?!5N!5~_$#229!211?@!11?CO!4?o$#232!101?@$#233!66?O$#234!84?!7o_osK$#236!72?_$#237!255?!7?C-#9!26?OQA!31?OC!161?C_$#10!255?!11?O$#11!62?A!39?N$#12!62?@!160?_O$#13!223?@!42?_$#14!58?_!59?_!45?N?~!55?C?G$#17!26?C!92?O$#22!25?O$#24?O!21?x@!93?G$#31???G!12?C^||rr~?_!28?W!55?O!6?_!44?rj!18?O$#32!4?A!54?C@$#33!55?GMMA!55?G??G!36?!5G!11?!9GgG?__!22?GGG$#34!114?OO?O!96?_!12?@$#35!11?GG??O!13?_!74?KC@@@MN!6?_!45?a???E?o!12?B^}w_!7?__!8?!8@KK$#36!228?PC$#37!4?D!7?@!17?@!195?O$#38!33?@!25?@$#39!29?C?@?_!9?~!4?N!4GF??@!48?G!6?NG!55?G!24?GG__$#40!30?M???O!21?_!58?GMF?!5E~~~B@BB!76?__C$#42!34?@@!70?OOO$#43!30?O$#44!120?GWWW!44?A$#45!5?E!220?_$#47!214?O!14?BC$#49!5?@???GA@!202?@O!15?Bo$#54!6?E$#55!61?O!39?K$#56!6?_!94?@!115?_!47?G$#57!9?@!211?@!11?A$#64!63?cE$#65!73?@!8?NN!4?Coo_oob?GGG$#67!68?O!7?OW$#69!67?C$#77!7?c$#81!8?A!225?C$#83!8?@!208?A!17?O!29?_$#85!218?@!17?Z__?__?_!4?G!6?CCGG$#86!220?A!18?ECCF?_O!13?ooAB?_$#87!219?A!17?^WoOOoVFf~~F!5~zzwooGGp{AG$#89!255?!8?G$#92!255?!9?O$#97!255?!10?@G$#98!26?_K!137?~!57?G$#99!215?AO!15?Do$#100!6?@?_C@!204?K_!15?I$#103!220?@!39?C??o$#109!60?G!41?o!119?AA!41?A$#125!6?O?O!207?C!16?C!30?@$#126!63?A!37?A!132?_$#127!26?G@!33?A!102?o$#131!101?o$#132!6?G??A!205?@G!5?G!10?G$#133!7?@!54?G!154?O$#140!216?@G???A!12?G!29?A$#144!255?!10?O$#145!7?W$#147!28?@!30?_!162?@O$#148!59?O$#149!27?_C!32?G?@$#153!29?@!88?O$#154!26?A$#155!59?GA@!162?A_$#159!217?C_??C_!11?A_!28?C$#163!103?F$#164!224?C$#165Nn!12?O!9?M@!155?_$#166!119?G$#167!5?o???_KA!201?@?_!14?BO$#168!9?O!204?E!16?K$#169!25?_??G!90?_$#171!28?O$#172!29?A$#174!8?G!55?@!151?A!17?O$#181!13?!4B!142?BB!13?!8B!27?A$#183!61?_!27?CCEE$#185!60?C!204?C$#190!118?F$#191!4?WG!114?o___!44?w$#193!57?_O!165?@]$#194!12?C!154?_!46?G!10?@KEE$#195!4?_!99?A!106?AAA!12?B$#198!63?G??w_!4?Gwo@??NN@!18?O$#199!67?W!4?FEN}n_oo}~oo!4EA!5?[~vvv$#202!218?WW!15?A$#203!219?@C!17?FHJJGGWG!15?K?@$#204!217?@Ecww!12?@L_!11?o!8?FFFB??C$#206??~!22?C$#208!12?A!16?G_??O!10?!4~!5o?FF!48?@BMMM_o~oo!49?@!20?@F^!7~OO!8?}}uEEw}{po!13?wG?w$#209!168?D$#213!62?oOw~FBb~~~o!4?F!21?n~$#214!222?O$#215!233?@$#216!236?C!17?C?B$#217!60?_!119?_$#218!103?w$#219!24?O!7?BI!22?O!57?A!13?K!5?@@!13?G__!27?O$#220!32?KCCCK$#222!35?_o?@!14?_oo??@A??C!51?`_!11?Ko{{{~~}}!13~v^^~~!5F!11?!4F!5o$#223!31?W??IA?CC$#224o??F!9?wggw_AAKK?E?A@!82?@!53?K$#225???o!7?ooCCC!38?G!61?O!37?!5o{{KSO!6?!4o!7CK[!45?_w$#226!25?G??_!28?O!109?@$#228!31?eo?_WBzy!4~!6?!4F!4?@C!45?oo___!4?FCF@??!5@???oA??B!37?F!10?O!13?FF^^!6~???OO$#229!10?oC!17?O!28?G!108?W!63?_$#234!84?!5xJJXHN$#236!68?K$#238!7?AC-#3!255?!13?G$#5!165?o!101?@$#6!255?!13?O$#9!25?_A!27?_?GE!44?_!15?E!62?a!42?BO$#10!255?!12?A$#11!26?C!31?A!43?K!121?CG$#12!56?C!123?A?O$#13!166?O$#14!24?G!92?O?r!46?D!13?C@G!41?G$#18!26?O!198?@O$#20!53?_$#22!26?_!90?A$#23!182?A$#24???w$#26!178?_$#30!192?wCAE$#31!8?O??c{?!4_AAMAEC!85?ooo!47?_KAM_!6?!4O?OG?C$#33!18?!4@X!5?OO???C?C[!14?_C!61?O!14?!5O!5?!5OC[!14?ODP!11?CCSKG!29?C$#34!51?C!154?C!21?O$#35!4?P?__?A@!12?O!4?_B!4_o!72?[[!54?[???B?^!14?@BBA??{{CA@@~}!13?w{{G!12?`??B$#36!214?B!12?C_$#37!116?_???\!47?[!14?o$#38!28?K??C!14?OowwGG?CE!59?FK!8?!5K!15NBBNBB!5N!7?G!12?BBB$#39!22?_G!4?@?OOOWC!8?F!5C!55?O[C__!5?G!6?c!56?A!6?!4C!8?@|CCC$#40!8?A!21?E!22?G!61?BG!8?!4B!50?O!4?w!22?B@!19?GO$#42!52?G!177?o_$#43!53?O!62?C$#44!56?@!64?B!45?_!15?A$#45!27?s!73?_!124?A$#47!232?C$#48!5?O??@!206?A!15?O$#49!5?IOC!208?K!15?BW$#51!224?O!41?@$#54!57?G!43?[!115?A$#55!58?C$#56!59?A!158?C!48?O$#57!224?_!10?C$#64!59?K$#65!71?___!12?o?O@\|{~pua$#67!63?A__KGG!5?F$#69!100?B$#72!235?A$#76!98?[?[$#80!219?G$#81!218?@!16?@G!29?C$#83!223?G!12?C_$#84!221?_G!15?CC{???O??Cc$#85!221?@!15?!4@F@@$#86!244?@!14?FB!4?C$#87!220?OAAo!15?_!4?_prBW^!9~wcfNOMOo$#89!220?C!42?B?@$#92!255?!10?a$#95!255?!13?_$#98!25?G@!91?o!46?N$#99!218?o!15?G_$#100!5?C!210?B[!15?Fu$#103!220?G!26?w!12?WWok$#108!24?_$#109!25?A!76?R!79?_$#114!255?!12?_$#126!6?G!212?_$#127!26?G!28?G!108?B?I!58?C!41?C$#128!166?_$#131!7?A!93?B$#132!217?@G!15?@W$#133!56?_!161?AO$#134!60?@$#138!97?GA$#143!119?K!106?_$#144!223?C$#147!25?S!29?O??@!59?G!62?[!43?_$#148!164?_$#149!24?O@!29?_???@!57?_@!45?[!15?@$#152!117?G$#153!182?C$#154!24?C!78?o$#155!27?A$#157!24?A$#159!219?C_$#163!57?@$#165Ev!14?GGG$#167!5?@?G!207?@!15?AG$#168!27?G!188?O_!8?D$#169!54?O!125?G$#170!27?@$#171!103?M$#174!6?F@!215?A!12?_$#181!8?_wwW!17?_!99?!5_!5?!5_w!9?!5wW!10?!4GwG!51?O$#182!57?O$#185!225?A$#186!117?C$#187!180?O$#189!43?ooo!4?oO!63?o!9?Oooo!5?!5o!7?o??!5o!17?___!55?_$#190!52?O!179?o_$#191!122?@B!43?GB$#193!193?w{w!18?__!10?G$#194!215?O_!6?@!5?@?C!35?G$#195!52?_!63?Q!50?C!11?G???G$#198!58?G??p?G!7?KK[??gGg$#199!62?os^^!5oOO??!4F!5~wwGw_?_???MH\v@$#202!219?AA!15?ACo???o?C$#203!221?[o!21?AA???_!14?pGG$#204!219?@@?C!13?@YAAAwM}GKK?B$#206??o!20?_@!30?C!61?@??_!58?B_$#208!4?g_?OK!20?C@???G!9?!5BFFBB!51?__w??NNN~~??@!4?W!41?B!20?C??@B~BBB@!4?Awww{{~~z{w~~BBBC!12?AEA$#209!120?A??{!43?O_!14?D$#213!57?_oo}MN@??BFFNNBBBwwOoO!20?~$#214!255?!11?A$#216!222?@!15?GW$#217!56?Q$#218!103?@$#219!32?C?B!11?_!7?@!105?_?_!6?__$#220!147?{{!12?o!14?_oO$#221!182?@$#222!28?A???AB?@@!16?B!60?_!30?_!29?_$#223!31?B!6?w!16?@!66?A!56?_$#224xGND!9?~^^VVs{o{!32?G$#225???AE!4?CEBB!10?B!130?!6FB!9?!4F!10?A!26?C??O!13?@C$#226!179?C$#227!230?C$#228!29?GGGH??ya~F!4~!5G!7?A!48?N!4B!13?{?r_!51?B@!6?!4w!10?!5B!4?A$#229!9?@!205?K!11?G?GGH$#234!84?!4FN}AAB!7?_$#236!98?_$#238!236?O-#2!50?_!114?F$#5!117?{~!45?_!104?C$#6!255?!14?G$#9!24?G!27?CA!48?@!79?@!42?@c$#10!73?O!195?O$#11!54?@!14?_??O!4?O?OOO?___!31?@!63?@!44?A$#12!24?O@!26?G@!27?__!98?A!43?A?_$#13!49?_!23?_!42?O??O!46?B!101?@$#14!23?A?A!26?A!9?_!56?H!61?G?O!43?O!20?G$#16!86?O$#18!22?O!80?_!77?_?C!43?G!40?A$#19!23?@$#20!163?_$#21!163?[$#22!88?O!12?K?C!12?C!50?_!15?A$#24oK?PAAA!4?B!151?@$#26!177?@$#27!4?KKL!4FC!6FMI@@!6?G!116?A$#30!22?A!92?O!76?@AAA!18?A$#32!105?W!17?A$#33!22?@!5?C!12?S?_???O!60?C!5?A!10?!4A!5?!5A!7?}!12?A??w!5?_!5?AA???WG$#35!21?_!4?K?O?!4@~{!68?AFNC?@@N@@?C!5?}!4{o_!40?O!20?NNFECKKNNM!15~[WWO$#36!230?_$#37!25?OA?`!19?_??A!52?K?O!16?@!43?GG!59?A$#38!20?C!23?FFNLLHF!96?!7C!5?C!11?CCC???C?__$#39??O!16?C!7?AA??AA}?A}!75?MAC!6?@A?A!43?C!9?CC!6?A!4?GGG!4OP$#40!229?BBB$#41!113?o?@!99?__$#42!27?o!79?GG???o??A!62?w?C!8?O!28?_$#43!47?_!59?Oo!5?_$#44!114?O!65?A???@WOWW$#45!104?O_!10?B!63?@!47?g$#48!229?K[k_$#49!218?Ao!13?@_w$#51!248?A!19?C$#54!235?@w$#55!60?_$#56!66?O!201?G$#57!225?O!21?A?O$#64!55?A??@!10?G$#65!69?AA???A?B?B!9?C!5?@?O$#66!60?C???A!19?A!4?C$#68!74?@@?B!14?@$#69!57?C?CH!11?CC!10?C!5?C!9?o$#75!59?G!5?G!8?CCC??CC!13?Cccc$#76!55?_!6?O?G??G!10?C!5?@@???@?GA?_$#77!89?GG$#81!221?G??A!22?O?C$#83!238?G$#84!222?NMW!14?BB??K`?G!18?WO$#85!241?W$#87!244?WE_???o@pN!8~v~??G_$#89!223?@!41?C$#92!250?K!13?K@$#95!164?G$#98!24?A!26?O!50?o!79?W$#99!219?A$#100!219?K_!14?E$#102!165?w!103?A$#103!224?_!21?O!15?G??A_O$#108!117?A!46?C$#109!23?G!27?G!19?O??OOO?O!7?__???_!72?A?O$#116!66?___!47?_!47?@?G$#125!220?G!28?_$#126!220?C!15?@O$#127!63?_!8?_???___!4?OO!34?_!61?C!44?@$#128!255?!14?_$#131!67?O!22?O$#132!52?O?A!164?@O!4?G!10?E_$#133!53?G!5?_!11?GG?!4G!15?_!126?A_$#134!65?O!7?G!4?GGG$#138!90?@A!5?B$#139!53?_$#140!220?@O???_!12?_!8?G$#141!56?__!8?G!10?C!15?O$#143!22?_?_!44?O!15?O!33?E!61?O?G$#144!237?A!10?@!18?@_$#146!164?O?_$#147!23?oD!63?___!11?M!79?e!43?W$#148!23?C!26?O!19?o!11?O!83?C$#149!51?_!12?__!5?_??__???__!102?_$#152!51?C!40?_$#153!248?C$#154!103?@$#155!22?G!27?G?@!174?C!20?_$#157!22?C!92?_!4?O$#159!221?C??C!12?@O!8?`?A!17?A$#164!25?C$#165M!20?M!25?AAC$#167!25?_!192?W!9?CO?OVuI$#168!104?_!112?@C!9?O!5?@$#170!248?O$#171!61?_$#172!163?A$#173!91?O$#174!55?@!181?G!9?C$#180!225?C$#181???_ooo!11wooO!8?@!21?@!74?K[{!5~!5{!6~{!8?!5~!15?@$#182!52?_!17?G$#183!58?_!5?O!18?GG!7?O$#185!116?G$#186!87?O!15?Y$#189!26?o??w!13?Rww??O!65?@!11?@@@!5?!5@!7?@ww!5z!15?ooxxx!6?O$#190!234?S$#191!26?@@!73?_!4?__!59?F!16?{_gcc$#193!120?m!72?@@@!18?@BA!10?B$#194!115?G!99?CDE$#195!217?G!11?_??GG$#198!53?O??@A???@AA??AAEC$#199!57?GIO?O@@DFDD@@DF@B!5?BBDDD?CCC?A?@?AQZJGB?N$#202!222?o!16?GKFNA?@F!5?I$#203!244?Ew???@Bw?o!10?r?@$#204!221?@?o!14?Foo_op!8?C!12?_?K$#206??M!22?G!42?O!32?R!81?@$#208!104?@!4?]]O$#212!57?OO!34?H$#213!54?w[M@?BAA!37?~$#214!249?G!18?O$#215!237?C$#216!221?A!17?C!11?E!14?E$#217!53?C$#219?o!18?I!20?G!4?O!67?G!44?w?AE!6?NN???{{}o?A$#220??_!144?BB!11?N|@!13?@AA$#222!29?AA!10?A!65?AA!36?@!13?@!11?AAA?@$#223!38?@!121?o!7?B!9?@@!4?ACC$#224@B@M@@!12?@@?O!27?A$#225!20?_!207?@$#226!49?O!70?@!46?O$#228!27?K?C{{{??@@~}~~`~K??_!60?@@!4?K!8?@?@@!51?G!7?B@BB_!4o!5_!15?_??_$#229!109?___$#230!89?O!128?@$#232!81?GG$#233!54?C$#234!56?O!4?KK[!4?G!12?AAA?IJJJ$#236!58?C?O!11?A??A!14?ACKCG??O{$#237!224?@-#2!164?SAE$#5!49?B!67?@!46?b?@o$#8!255?!15?G$#9!46?_!8?O?A??_!31?@A?O!86?AA!43?O$#10!255?!15?o$#11!21?_!24?OO!6?W???AO???@!52?_??o!62?G@!42?@__$#12!64?@!28?@A!133?O$#13!55?G!7?_!103?A$#14!23?G!21?_!12?@!6?@!24?@??C?c!7?O!14?_!44?G!62?A?G!20?a$#16!48?@!118?@$#17!49?C!39?@!76?_$#18!46?G!10?G!7?_!37?@!11?C!153?@$#21!23?_$#22!47?A!8?C?G??AO!4?@!19?@!80?_$#24_!43?G!81?E!33?G$#25!126?@$#26!179?W$#30!19?B!25?G!28?]!154?@$#31??_???KKK!4?_!4?[!20?_??_?O!22?C?G!54?aa_??A!5?!11_!15?g!6?A!18?W$#32??]!17?_@!19?_???C!85?__!26?_$#33@W!16?B!7?@!16?G!26?A!6?C!43?@?@@@?C?@?D!14?_!12?C?C!8?C!16?D???C!4?CCC$#34!19?G!101?E?A!37?O!18?B!6?A$#35!7?_!16?Wy}!7?~~}}!26?K[[GQbo_M]_]YI!13?OO!13?f__!18?WO{w??``@!45?o!4?B_?__???_!4?^!4~wwWWW!5?!5_$#36!76?_!153?F???o_$#37!47?@!15?A!6?@!6?@@@???@!5?OOAC?_!9?`@!8?g!7?[!39?^!6?G!9?@?G??@$#38!20?A!93?@!6?G!38?A!19?{!7?F$#39??@!25?@!4?~??@@^!4?O!49?G!28?@!4?_g??W!38?GO!27?_!4?@@`!7@$#40!109?@$#41!89?KK!17?]}}]__!63?Y!16?OO_!21?A!12?A$#42!27?~}}w!58?A?_?_!13?]!4?@!20?A]A!40?O_y!10?OOoOO?_!19?@F]\!12?@B$#43!77?OO!28?@???@!119?[???O$#44!77?_?waACeCc?Cs_??_$#45!63?O!4?_!9?_??WWW?A?AA?A!10?B!15?C!50?Wo!15?A!48?@A$#47!63?C!156?_$#48!110?@!119?W__PG$#49!220?O!15?W$#51!226?C!21?A!20?A$#54!47?_??A!185?@U$#55!56?_!44?o!15?G$#56!53?A?@!40?G!125?o???G$#57!248?G!20?G$#62!51?O$#63!52?_$#64!96?C$#69!97?A$#76!96?A?_?M$#77!52?A@!41?@?G$#81!222?A!16?G!10?C$#83!223?O!23?@$#84!224?@!15?@_?O?Q`!5?E?__!8?__$#85!242?@$#87!241?WO_PGQ!6?eE!4^~~~vf]FFV$#89!247?_!4?W$#97!255?!15?F$#98!22?W!25?C?@!51?B!13?K!66?o$#99!221?w$#100!220?N!15?Eg$#102!164?G@$#103!247?[!5?W!14?]$#108!48?A!9?O!57?@!50?G$#109!22?AA!30?C!5?@@`!55?A!63?C!44?@$#114!248?O$#116!54?A!4?`!57?ACG!47?C$#125!255?!14?C$#126!51?@!113?O!55?@!16?C$#127!21?O!25?C!10?_AO!30?@??G!8?_!11?O??O@!43?O!85?[$#128!165?C$#131!97?_???K$#132!221?E!15?@w!9?C$#133!48?O???C??_!39?A!126?G!15?@_$#134!54?_!42?O!19?_$#135!98?O$#138!100?O$#140!222?C!46?_$#141!100?_$#143!48?G???O???G@!34?A!10?G$#144!250?G$#147!22?c@!23?G!5?G?AQO???_!32?CG_!5?{!13?Q?@!47?G!15?@K!43?M$#148!53?C!61?_!47?_$#149!22?@C!29?O!42?O!21?GE!46?O!15?o$#152!60?A!42?A$#153!23?O!42?@!117?O$#154!94?O!86?@!46?A$#155!57?C!8?_!48?A!65?A??A$#157!44?_O!16?A!5?@!46?@!4?_???O!35?_!67?@_$#159!222?@_?@!13?C!10?A$#164!163?@$#165!20?D!148?@@$#167!93?O!125?@!12?W??G_$#168!59?CGG!173?@$#169!21?G!30?G!8?O!122?_$#170!103?C!59?A!64?C$#171!57?_$#174!94?@!22?O!47?_!72?A$#177!250?O$#181???}~~rRr!4~!5^?CO!4?C!12?_!29?KSKM???_C!43?[O_c!6?F!23?!5~GO!7?@E!15?o{$#182!49?G$#183!51?G$#184!55?C$#185!64?_!50?G!47?C$#186!56?@$#187!184?G$#189!29?@!42?__!61?!19O!20?O$#190!88?G???G!15?@???]N!118?C??C$#191!45?A!33?E\db?yW}w!25?O!56?o!8?A!5?D$#193!58?CGCC!12?@@!86?_!66?W!18?@@$#194!62?K!8?@?@??@!37?O!5?@!98?_!10?_$#195!25?@!37?GO??O???OO!31?[!114?W!13?mE$#198!48?_OG_!47?@$#199!96?@@@_@$#202!225?E!13?A_??B?_?A$#203!225?_!15?E_?mCK!4?v_@@!9?@??G_$#204!223?N}W!13?@]!4?@$#205!251?G??W!7?GW?WW$#206!46?C!39?@$#208!24?_!39?A!40?{W!78?G$#209!40?_!81?A$#211!111?_!35?!7_!20?_!4?_$#213!49?_oE@!46?]$#214!226?O!42?O$#216!241?@MK!6?@?@???___!7?__@$#217!24?@$#218!21?C!66?@!95?C$#219?b!13?__?_o!23?BF?B!80?@!4?@???!11@!12?@C!9?AC??!4@!13?@$#220!128?@!30?A!11?g~~$#221!21?A$#222?C!12?_??_!12?EC!11?C!34?C!12?K!35?A???AA??GK!10M!7N!6?@B!9?B??MMC!11?G??A!4?GGG$#223!45?@!151?__$#224]!23?E!89?E!9?K[W$#225???@!16?G!22?_!77?_?W!35?O!28?_!40?E$#226!67?_!16?@@!82?C!12?C$#227!120?A$#228!30?@z~!6?!4^!35?I!11?_!37?E???[[?CA!38?oiCDC!8?ONNGnnNNRRR!5?EEEee!5}^]W@$#229!65?AAA!4?@!31?AA!113?E$#230!165?G$#232!53?_@$#233!50?C$#234!97?CM$#237!239?O!8?_?_$#239!226?_-#5!164?@$#9!21?@!22?CB!18?@?@??A?CC!4?OO??__!19?G!12?A???B!108?P$#11!43?_G!22?A??A??K!9?_!15?O???G!59?@!20?_!43?__$#12!20?O!59?_!22?C!80?O$#13!71?A!25?GC!171?B$#14!22?C!19?O!38?O!16?_!15?_?A???O!61?A?B!42?@?G!19?}$#16!75?C!106?C$#17!66?A!12?_!38?@!48?O$#18!41?_??@!27?A!5?G!8?_!26?G!5?C!41?O!5?@!13?W$#22!120?A!41?C!6?O$#23!45?C!72?A$#24!19?A!139?M!13?O!12?O$#25!19?O$#26?_$#27!28?OOO!7?G!160?[$#30!23?O!17?O!146?A!30?_$#32!23?M!14?OG!119?o?P!25?o$#33O?J_!7?OOV!5?G!5?OOO???O!6?C?HA!104?L!52?a$#34!95?o!13?O!70?_!50?B@$#35!7?B!16?B@L!7?!4N??OG!35?A!16?A!9?EoF??_!12?O!6?!6~wwo_!33?_!6?p?_!7?^NH??N!5?!6~!8?~~~nN!12?C?AA$#36!76?@!17?@C!10?o@@!123?s?s$#37!39?__!32?@!4?CEEG??OO!4?_O??[?O!7?@!56?m!8?A_!9?O!5?N$#38GNC!16?C!21?C!53?G!14?oo!11?A?AA!19?A$#39_!26?A!5?^!4O_??@!80?_C!47?O?@!25?@!6?N$#41!77?@!9?O!21?FF?@F!63?__?M!15?p_$#42!14?XP@!10?L@@@!47?A!7?O?O??BO!14?O!5?G!9?G!47?K???__^^A!9?_oecdO^$#43!93?__?G!84?G$#44!78?@??ACBCJG?KMKK_V!14?o!4?_!67?F$#45!77?C!4?G!5?BOO_?G!68?@!6?@@!59?O$#47!220?@$#48!179?K!71?o$#49!221?w!15?A$#51!250?C$#54!75?O??_!21?_!63?_?@!72?_!12?_$#55!68?C!153?A$#56!46?A!24?G!29?B!14?_!49?A$#57!223?_!26?A$#63!62?A!102?C$#64!45?OC!70?@$#65!65?CGG$#66!64?G$#67!51?K!18?O???_$#69!50?K$#76!58?CCCECC?O!9?_$#77!99?A$#81!223?A???_!24?G_!15?E$#83!224?O!15?@!10?A$#84!224?C!17?Cs??F!6?@K??o?_o???ENS[$#87!226?q!15?AB??o!4?@AI?O???BBVFFo???O$#89!225?G!21?j!16?H$#95!163?CA$#97!255?!16?{$#98!21?K!21?O!55?_!15?W???O!47?@_!14?~$#99!222?o!15?~$#100!237?@$#103!226?K!20?S!11?KKGGG?o___$#108!96?@C!5?_!64?G$#109!20?__@!53?G??O!18?O???OO!11?@!47?AC??C$#114!227?G$#116!43?G!19?@!33?@!4?_!65?C$#125!222?@!4?C!11?C$#126!118?O!120?A!11?G$#127!20?G!23?A?@!27?C?O!7?_!18?@!60?G!17?@?C$#128!168?A$#131!61?@???A!52?G!48?_!54?G$#132!116?O!105?C!16?W$#133!44?_G!52?@!66?@$#134!63?A???C!5?O??_!88?AC$#138!50?!4_|~{{!8_o!4_O$#140!223?C!16?o!7?w$#141!100?N$#142!77?G!192?C$#143!62?@!5?@!16?_!76?_$#144!240?G!10?C!17?@$#147!21?Q!20?_!22?@??A!5?GG!21?AG???F!12?c???k!43?w???AO!59?M$#148!67?@!12?O$#149!22?A!47?C!32?A!12?@???_!46?G!16?G!44?O$#152!22?G$#154!104?_!57?G!66?@$#155!42?G!33?C!11?_!6?@?OA!5?O!64?G$#157!43?A!35?G!40?@!39?B!66?A$#159!223?@_?@!13?E!28?w$#163!229?A$#164!43?C!226?O$#165F!21?_!21?O!140?_M$#167!237?K$#168!169?A!60?K$#169!20?C!93?O!5?G!128?@$#172!20?@$#174!60?@???A!9?O??_!23?K!16?_!104?O!15?@!12?O$#177!227?O$#179!22?O$#180!164?O!105?_$#181???^~~~{~~~NNG!10?kMA?___!7?B@!56?_!25?F!12?FFN^!7N!8?!5~?O!12?_!12?@?o!28?Oo!13?A$#182!47?@$#183!72?O!28?_!15?A!47?G$#185!86?_!9?A!72?_!59?C!40?G$#186!69?@!12?O!99?_$#187!69?C$#189!180?P$#190!89?@??B!14?_!8?G!79?G$#191!79?@@@BKJCFN!4?K!6?G!13?O!4?C$#193!70?@@?AAA!4?G??O!5?_!5?AC!24?}!47?C{!48?O!10?_!19?w$#194!42?C!29?@?@?A!111?K!30?N}!9?A$#195!97?_!7?N?EE!122?w?D?~~o$#198!46?gG_OB@!14?C??G!96?_$#199!49?_?A??A?ABA!4?WCG???O??_$#202!241?E$#203!224?GF!16?@?~!7?@Co_??o???oo!4?E$#204!224?Bo!15?wGG?~G!7?BN~NN$#205!255?!13?H$#206!19?_???@!90?C!44?@??A$#207??O$#208!106?GGG!13?G!109?GGH$#209??_!78?C!32?B$#212!52?^^!13?OG!4?_$#213!45?_Ou^N!67?G!47?o$#215!223?G$#216!241?@o!9?CO!5?O?_!4?JB$#217!20?A!51?G!43?C$#219!15?A??K@!20?E!82?@?K{!59?_!11?O$#220?O!16?o!179?G!7?OO$#222!11?___EK_pB!6?___?KKm!4?__!71?GGJ!13?O!13?OO!6o!7~!17?B@?N?M!17?_???_$#223!123?o!73?^F!9?o$#224!23?_O!79?G!55?K$#225!39?E??B@!77?@!38?_!24?^??@!44?o$#226!39?O$#227!75?@!154?@$#228!14?__]M!10?MAA@~___!54?B!20?C}!11?~`@~~!10?__!31?]Mo^P!14?OZY?_E!9?_nN!5~$#230!221?F$#232!59?@!10?G!28?COO!64?G$#234!58?@!5?O!34?@!17?s!48?O$#236!50?OO!4?@?WYYWW!5?O??_$#237!248?F?@-#5!100?C$#6!255?!16?@$#8!255?!16?A$#9!19?_X!18?OG?@!40?@!4?@?A?A!21?o!5?]!41?_A!5?c!13?C!45?]$#10!255?!16?C$#11!19?O_!18?_C!48?B!5?C???G@!13?C@???@`!128?_$#12!19?G?@!19?C!46?A!26?A!47?C!4?AA!60?_!18?O$#13!96?A!65?@!67?O!18?@$#14!19?C?A!16?_G!42?@!8?@!10?A?O!10?C???A!43?G!4?C@!80?O$#16!101?C!11?_$#17!40?O!46?A!5?C$#18!230?C$#20!21?G$#22!92?@!5?A!83?G$#23!18?_$#24?A$#27!179?_!8?_$#30!160?_!73?o$#31!13?_!14?_!159?O$#32!172?EW!13?M$#33?g?j!7?GGW!9?_MGGGW!4G??WG?@!71?G!12?W!20?!10G??F??`!13?@GGo??@`!7?G?GG!4?_??@!14?_!39?_$#35!22?A!86?D!24?!5FEEC!18?A!11?@!8?F!5?@!11?E!6FECC!5?FFCCF@!12?E?FBA$#36!106?@?wG!78?E!43?@$#37!37?O!84?BC!36?O!26?o!44?OC$#38!110?DF!47?G$#39!22?C!10?OO!90?_og_!5@!5G`@!45?o!16?G??@AAGGG!7?G$#40!106?E??A!144?O$#41!124?O!71?@@$#42!33?__???A!73?C!11?_!49?EE!13?F!26?OOO$#43!38?C!67?o!113?M!30?C$#44!107?G@???G!60?C!59?G$#45!38?G!47?A!20?o!4?o!9?C!98?E!9?E!20?C$#47!105?O!114?@$#48!107?A!129?A!13?J@_$#49!221?@o!15?G$#51!228?C!41?M$#54!239?@$#55!41?G?@!37?@???A!15?OO!16?G!43?O$#56!100?OA_!16?O$#63!94?G$#64!116?C?A!45?G??C$#65!42?o$#67!48?C!25?@@!41?G$#69!44?A$#70!83?GGG!12?__!17?o$#76!75?E???CC$#81!224?A???_$#83!227?A!13?o!14?O$#84!243?f?_!9?@E?s??AfQ$#85!242?GW?W!12?G$#87!226?_!17?F?vW!8?GfAwz|W@Jo~?N[$#98!85?@@!10?C??I??[$#99!222?@!16?W$#100!222?M!15?F_!13?AG$#103!247?f!15?_sN?~o_$#108!98?C@!62?C!20?G!45?@$#109!93?AA!4?C!14?G!68?o~!44?_$#110!255?!16?G$#114!224?O!23?_$#115!255?!16?o$#116!95?A!66?A$#125!223?A$#126!90?C!24?_!48?@???O!54?@!4?G!25?C$#127!98?G!15?@!6?_!106?@!20?E$#128!99?A$#131!91?C!131?o$#132!115?O!107?K!15?E!15?_!14?o$#133!116?@??_!43?_!4?_!71?K$#134!42?C!37?@??A!4?C!6?G???O?@!65?A$#138!49?!22~}~q!14oggwG_O?__o$#140!248?F!5?AG$#141!100?__$#143!40?A!63?G!16?O!39?O!8?O$#147!20?E!20?A!42?@??@???A!4?C!6?b!58?W@!4?@W!13?B$#148!90?@!158?G$#149!41?@!52?C!6?G@?_!9?A!46?_!8?_$#153!21?C!82?C!145?G$#154!39?C!81?C$#155!21?O!16?O!54?@!4?@!22?A!39?C!8?C!11?o!47?A$#157E!20?_!15?_!56?@!155?A$#159!224?@??@!26?@C_$#163!121?G!106?A$#165?C!183?~$#166!18?O$#167!221?G!29?OOW$#168!97?@!73?O!59?G!6?o$#169!250?_$#170!19?A$#174!40?_!43?A!4?C!6?G!67?A??@!56?_!15?o!12?@?O$#179!19?@!84?@$#180!250?C$#181!4?!7~oo!11?poooFFF!5?O??@!83?_!17?AEMO!9oFF?FF?D!13?oo???]]!7?@woo!24?BB!14?_`$#182!116?A!47?C$#183!41?O?A!38?A!4?C!10?O!68?G$#185!97?A!132?G$#186!102?C!10?O!47?G!8?G!11?F$#187!104?A$#189!27?A???A!4?A!73?A!30?@@@!10E!5?E!17?EE!15?A???@!20?A$#190!107?D!108?___!33?iC$#191!92?C!15?E!4?B!5?C??WA!108?G$#193!95?@!65?B!8?Bmo!57?@o???ooo!12?@!19?@$#194!109?o!124?!4G$#195!105?F!114?oo!9?@?A??@@!13?_$#198!48?@!68?EC!47?X$#199!44?CAA@!26?C?!6AC?C?C$#202!225?_?C!13?G$#203!244?w?G!10?W@FC!8?B$#204!225?^^w!13?Fo??F!9?A@!6?C$#206G!101?G!10?G!8?_$#207O!112?C$#208!105?G!129?CC$#209_?@!32?_?G!68?G???o!16?O!11?O!64?www!5oww!5?o!13?O$#211!32?o!91?GW???!5w!5o!55?wwOww???wo!10?Go?GG$#212!41?_?Co{{{w!24?GGGLKKG?GG???GGOO?_WgoOO$#213!44?@@@!69?w@w!45?o~eo$#214!228?O!19?O$#215!240?A$#216!242?F!20?G$#219?@!9?EE???h@B!12?c?G??@!78?G!10?F!29?_!17?@!11?F!7?@$#220!42?A!165?@$#221@$#222?OCS!7?@@F~~U}C???@O?FFD?ooPC???C@!73?w!14?G!17?!10@wwWwwO!16?Gww!7?G!9?K??www!12?OGG??C$#223!97?G!70?G$#224!39?A$#226??w!15?G???_N!10?G!5?@!55?@!24?@!6?G!11?!4_!27?@G_!7?_!10?GG$#227!22?W!13?_!68?_!22?O!10?GWWWO_!15?G!20?W!10?oo!13?GG$#228??A!29?BFFF?E!74?B!10?@FF?FF!5E!39?A?@F@@!11?!4FCFAEE!8?@?!5F$#229!237?C$#232!118?@$#234!42?GwG!29?A!4?@G!10?O$#236!47?AA!22?@?D???@@??C?C?C$#237!224?G!23?G$#238!240?@$#239!224?C-#9!36?OC!65?@u!8?O@!6?@_!38?G!68?o!18?w$#11!18?_!17?_?A!64?A@!9?A!45?OO!8?`_!11?FE!45?@$#12!18?O?@!162?GW!44?@$#14!18?C!86?_!7?@!57?G!11?O!66?F$#15!255?!16?w$#16!112?_!47?C!10?C$#17!18?A!86?O$#18!20?G$#19!103?G$#21!160?A$#22!122?@!48?A$#24!39?@$#25!182?O$#27?A!11?B?C!8?CCC?F!97?C!28?CCC!28?C?F!10?C!16?C$#30!22?C!100?@!110?@$#31!16?_!140?_!28?_$#33?D?B??[C??CCC???[@!5?E??OOW??V!95?K!21?CCC??C??OC!15?CCF???G!4?WY??!4C!7?CS!12?@??CO$#34!110?O$#35!24?OO!7?O?A!71?C!17?B?_!24?CCwo??wB!25?_!13?wwgww!5B!5~{{ogknwW_$#36!108?b??M!15?O!31?K!94?G?W$#37!21?OO!83?c!66?H!8?C!4?B$#38!110?K!143?CE$#39!13?C!9?X!9?G!92?B!17?!5C!25?W!6?B!4?@!6?C!8?!7C$#42!23?!5_!4?GBB!71?@!45?Gw!20?_!41?@!34?_?K$#43!253?O$#44!14?K!7?_!156?A$#45!21?_!81?O???B!4?@?O!5?A!52?O!78?O$#47!109?BB@!12?B$#48!251?^?Br@?_$#49!222?B_!14?@$#51!255?!15?^$#54!121?O!101?@!32?C$#55!103?_!10?_!47?C$#56!169?G$#57!240?@!15?A$#64!102?C!12?C???_!42?_@?B$#65!39?CAE$#66!102?O!14?w$#67!99?w!63?O??_$#69!117?C$#70!98?~??G!15?B!50?_$#76!100?@$#77!168?A$#81!225?G!15?o!15?Co$#83!228?{$#84!226?H{!14?bB?B!12?F?{DAAC!4?_$#86!255?!11?[$#87!226?CA!14?O_BczE!11?@BA???[A}?O$#89!226?O$#98!19?M!150?K$#99!224?_!14?_$#100!223?]!15?^!17?O$#103!247?x!14?@@Bb@@~N$#108!113?_!8?G!38?@$#109!38?@!74?G!70?@!45?M!18?F$#114!248?~$#115!255?!16?B$#116!37?G!131?@$#125!224?C!15?K$#126!224?A!15?A$#127!18?G?A!82?C!9?AC!7?C_!105?E$#128!160?G$#132!224?W!15?o!29?_$#133!37?_!77?A$#134!38?GA!62?A!59?O!6?_$#138!40?G!7?}!49~???@$#140!225?O!30?@$#143!161?_!7?A$#147!19?p!84?G!16?EO!37?_E!8?Q$#148!35?_G!76?C$#149!37?A!82?@G!40?@!8?O$#152!35?O!87?O$#153!184?_!65?O$#154!105?C$#155!20?O!13?_!77?G!10?G!47?@!10?@!48?{$#157!34?OGA!87?_!35?@!70?B$#159!225?E??B!12?N$#164!159?_$#167!222?[!30?_?w_$#168!238?A!13?_$#169!20?C!101?A!106?G!20?G$#171!162?A$#174!102?@!12?@!4?C_!40?G!6?O!54?@!32?G$#180!229?o$#181!4?~~!7B??w!8?JJJN!7?C!69?@???o_!36?@!6B?GwG!16?BB???w!5?C?ww!4B!23?GO?O?_!10?@@$#182!120?G!47?@$#183!102?G$#184!255?!16?C$#185!36?C$#186!37?@!74?O$#190!217?@B!33?N$#191!37?O!131?C??OC$#193!21?N!90?E!10?E[!47?B!59?{?}~~~$#194!111?_!121?}!4?{$#195!106?Q?G!64?A!46?FF$#198!116?c!47?OW$#199!163?K__WG$#202!255???A!4?C$#203!226?A!15?K[{WC!12?{!6?_$#204!226?_@!29?@???ww{w$#206!17?_!141?O!12?_!9?I$#207B!180?G$#208!107?wS??O!14?_$#209!35?@!145?C$#211!32?FC!93?B@!15B!35?@!14?!5B???BB!10?AB?A$#212!38?o__px|!4~@!50?C}E$#213!99?@??_!12?wZ?~[o!42?aNCFVC$#216!225?@!32?GA$#217!18?@!95?G!68?_!66?_$#218!105?G$#219{w?{??_?[[!6?B!139?B!23?S?_$#220!38?C!142?o$#222!7?w__ww??rB?A!11?^^_??C!93?{!25?BB?BB!16?ww~~?`!8?ww!8?BBB!14?A$#223!128?A!51?A$#224!105?A!79?B$#225!109?K$#226??~!14?[??_?H!11?G?@!69?G!65?K_!5?C!7?C!44?A$#227!22?A!102?{W!17?BBBA!45?B$#228!12?ww!14?___Go_!95?!15{!8wo!38?www!5{!5?!5w$#232!119?@$#234!39?WTGEA!57?O!17?A$#235!99?A?_!65?_W$#238!225?_-#9!18?@!15?C!69?@!7?o!10?AG!33?_SA!10?P_!57?N$#11!19?A!13?G!45?O_!23?CC!6?GB!9?C_!46?_O!76?~$#12!33?_G!89?C!34?A$#14!17?O?G!84?O!7?@G!8?@G!35?`!12?C!68?_!6?_$#15!255?!16?@$#16!125?O!105?C$#17!34?@!45?O$#18!111?_!158?G$#19!19?_$#21!158?C$#22!17?@!88?_!4?O!60?@$#24!250?C$#25!13?G!19?A$#30!157?E!61?_$#31!11?CG???g!233?O$#33?~?{??!5A?CC}?V!13?G!124?}g!18?!4A?!4A?@???!5A!20?AAA$#35!30?o!77?AF!16?A@!16?!7{w}}@@@?@!15?]__!21?[!5~!5{!5~!4XHFF?B!11?wKG$#36!108?@?E!128?_$#37??_!17?K??_!85?G!63?Q$#38!14?@{!140?E$#39!29?_!79?_!34?!7A!47?A!5?!5A$#41!21?o!86?_!51?G$#42!23?!7@F?A!74?A!45?@??O!17?@!60?oo!14?C$#43!108?G!142?y{$#44!20?_?~?!5}]??C!75?C!17?K!46?C$#45!20?O@!84?@!4?A!14?O!129?_$#48!251?@A?_??K$#49!36?@!133?C!52?X!15?@!18?_$#51!229?@!18?G$#54!79?_!33?_!47?@$#55!78?O!43?AO$#56!161?A!8?G$#57!225?o???C!11?C!6?A$#64!114?W!4?@?@$#65!36?oK!40?A!87?OO$#66!102?@!14?@???A!47?C$#67!81?CGa!15?@!16?Co!46?MN@??O$#69!99?A?@!13?A?Ko???o$#70!98?@$#76!54?_?___qQQQAAAQqa!5?aa!4?C?AC!15?{$#81!255????B$#83!226?o!16?w???O$#84!255?!4?AC?G?[!4?B$#85!226?K!35?C?_$#86!227?KC!15?U?g!18?E??Y$#87!227?QA!14?@?F@K!12?A}_?A??`$#89!255?!5?O!4?_$#92!228?w!16?w?A!17?Go?c$#98!18?W!140?G!11?C$#99!224?F!15?A$#100!223?Ew!15?K?o!14?A$#103!227?@!19?@!11?@H!4?P??@$#106!255?!15?B$#107!255?!16?G$#108!104?AG$#109!19?@!15?@!87?@!106?o$#114!229?G$#115!255?!16?E$#116!104?G$#123!255?!16?_$#124!255?!16?O$#125!242?G!5?C$#126!255????O$#127!17?_!14?_!45?G!26?@!6?AC!56?@$#131!35?C$#132!229?A!10?@!16?@$#133!34?_!79?A!7?C!47?O!54?E!32?G$#134!35?GA!43?GO!21?C!19?_$#138!48?fffF~pP@@P@!10DFfFfb@@D!7@^!13~}!69?@$#140!241?A$#141!60?!7_!35?[$#142!255?!15?_$#143!17?G!86?_!53?G$#144!241?@C$#147!18?e!14?O!71?o!18?O!35?@!10?I$#149!19?C!14?AA!69?A!6?C!12?_!32?O?C!11?G$#152!17?C!154?A$#154!17?A!139?_$#155!124?@G!47?_!96?C$#157!9?o_!147?A!62?_$#159!247?_!11?O!9?o$#163!32?O!48?_$#164!231?B$#165!113?O!136?A$#167!238?GE_G!11?~^~^o$#168!110?_!112?_!15?GO!11?@$#169!19?O!13?C!90?A!45?A$#173!103?@$#174!77?G!25?A!10?@!45?O!64?G!22?@$#180!248?O?@$#181!4?~~{{{C[Woo?@!15?G!78?@!46?@!17?[[{{~!4{}}~~~!5{!27?F!14?C$#182!114?C!45?_C$#183!79?C!23?G!18?G!46?A$#184!255?!15?O$#185!231?w$#189!31?C$#190!107?K?O!127?oo$#191!20?@??E!10?O!72?o???C!14?_!46?G$#193!106?E!4?@!13?E!94?_?_!9?~w!4@$#194!110?O!14?@!47?@!59?FE??A@$#195!31?o!75?@!18?@!47?_!47?[!14?GEO!10?_$#198!37?@!39?C???G!33?@@!45?G!4?GG$#199!79?A!36?A!47?@!4?_$#202!243?C!15?G_?A_$#203!227?_!16?h?U!19?N]$#204!226?B!15?BA!15?C?@P^@$#206!32?G!46?G!26?W!4?G$#209!20?A$#211!127?!4{sss!10{!70?!5C$#212!35?oGq}!9~!5?MMe]MM!10GwWgG[[[yA???ACG_!15?~}a$#213!114?_G?AN}~{!39?wv~???CC$#214!229?o$#215!225?@!33?_$#216!228?@!40?K$#218!241?O$#219~??B!7?A???A!162?@?@?@@$#220!21?G$#222!6?!6@A!18?B!76?O!19?B??GGG!41?@@@!11?@@$#223!21?E!159?@$#224!184?@!65?G$#225!9?G?_$#226??^!20?W!127?A!5?O!36?!4A$#227!110?G!40?C??}??G!36?!4{_!15?!4_oWWW!13?AAC$#228!12?@B!18?@@!93?A?!15B!9@!38?!8@!5?!5@!8?AA$#232!78?C???_!86?@_$#234!36?C?@!9?WWWw???W??O!4?OOO??O??OO!4?o_?A?OO!19?o!60?oo_`_$#235!115?sw!49?MAQG$#238!255????C-#0!45?__ooo!4w!10{}}!6{wwo_$#2!57?A!9?AA$#5!46?O!4?C!4?A!12?A$#6!44?_???G!21?A??C$#8!71?A$#9!30?_gB!78?G@!12?@S_!29?K!83?[!6?K$#10!50?C!219?w$#11!17?o!93?C!13?C!31?A!15?G!74?A$#12!112?C!14?O!29?O!83?A!6?@F$#13!54?A$#14!111?@G!13?a!29?G@!13?@!11?O!47?v!8?_!8?O$#17!84?G!39?@$#20!19?F$#21!19?W!90?G$#22!106?@$#23!183?G$#30!16?u!4?{!7?O!80?A$#31!5?AACG_o??D!12?_!149?W!8?O@??[!29?G$#32!16?@???@!9?A!76?_?O!17?@!59?_!44?_P!6?A$#33??@?_KCG?O!4?`@!10?]_!148?_P@`!4@??u@@!5_?_!38?_$#34!255?!4?G$#35!12?OO?]!6?[W!6?@!114?A?GG[!4^J!20?@FM!8?G!12?!5^!5?!5B]]!4?O!13?F!23?A$#36!175?_!83?O$#37!20?A!8?G!78?_!19?O!45?MM!57?M!6?@$#38!28?_A!148?_Oo$#39?`?@!29?@!109?Bcc~DCB?__?C!22?_!18?___!5?!5@!5C_?!5_$#40!254?@$#42!14?W!7?AE!104?A!105?W^p??@!11?_$#44!107?GE!23?__!19?__A!26?GC$#45!64?@@!14?@A!26?W!46?G$#47!250?A$#48!242?@!8?\GD!5?E$#49!223?G!35?_$#54!104?C!53?C$#55!52?A!30?O!20?O!7?_!46?@!11?C$#56!32?_!24?@!9?@!16?C!19?_!120?A!16?G$#57!225?@$#61!70?@$#63!81?C$#64!33?C!79?G!46?A$#65!36?@!6?GE!35?G!83?BbRVF$#67!45?A!27?@??AAB!9?@!33?C$#68!34?wwy}]]]EEC!34?C!21?@!20?_ogo!39?GG??O$#69!50?@@!62?!5_?_?A$#75!89?!12_?__$#76!53?@!21?A@??G!5?@B?W!14?E$#77!75?CGO$#81!247?@!21?B$#83!226?B!19?_$#84!227?wO!32?@A?@^$#86!245?_!22?`$#87!227?C!16?E?F!15?@???N$#89!228?e!14?gW$#92!255?!13?]$#95!55?A$#98!126?G!45?E$#100!224?~!17?A$#101!66?A$#102!49?G??CC!4?!6A!8?C?GO_$#103!228?@!14?O$#106!49?C!24?CGO_$#108!112?A!60?O$#109!31?C!124?O!15?O!57?N!10?_$#114!242?O!26?_$#115!255?!15?E$#116!17?K!63?@A$#123!255?!16?B$#125!255?!4?@$#126!113?@!10?A!100?{!21?O$#127!17?@!13?A!52?O!21?O!66?C!10?O!46?G!17?G$#128!45?O!37?C!186?@$#131!32?O!10?_!14?!6@??@!15?@A!20?G$#132!242?C!4?_$#133!113?A$#134!171?O$#138!34?A!12?A!39?EC!11^]?W!66?O$#140!247?A!21?G$#141!48?A???@!29?O!20?W!19?O!44?___$#142!47?G$#143!83?G!22?G$#144!255?!14?C$#147!18?~!12?O!73?~!5?o!13?A!30?_?@!13?H_!74?o$#148!30?O!75?_!123?o$#149!17?A!14?C!78?A!46?A!13?_!10?__!56?@$#152!106?C!48?_$#153!249?_$#154!128?_$#155!19?_!10?C!209?C$#157!8?BFB!99?C!108?BBB@$#159!226?{!33?@$#163!29?_!210?G$#164!110?O!45?C$#165N$#167!174?@!48?o!26?{?oG}~~~|$#168!223?F!15?O$#169!127?G!112?O$#171!104?@$#173!46?G!21?@$#174!33?A!10?O???C??A!4?@!12?@???A!11?O!39?O!32?G!12?G!75?G$#179!31?@$#181??_?^@@??GGgNG?_!8?]}!123?__!33?FN???B!4^!25?CK$#182!113?C!45?A$#183!45?G!4?A???@!25?A??`?G_!38?_!44?@_$#185!30?G!79?_!62?A$#186!53?A!18?A!9?C!23?A!19?@!46?@_$#189!29?C!148?E$#190!107?U@!19?C[[!90?OO!13?M~~A!11?AFA$#191?]!102?A??@!17?G?AG!26?C!15?A!10?o!49?]!6?K$#193!20?{!201?A$#194!110?@$#195!175?O!74?@??o$#198!34?@!10?C??@@!24?@???O!82?b@?_$#199!40?_!35?CC!35?_$#202!255?!7?w\[$#203!227?B!16?@FW!20?~$#204!228?G!14?E_!16?}?aa_$#205!245?W!20?o$#206!127?C!27?OA!17?O$#207_!31?G!115?@$#208!22?__!106?__!68?!4_!17?__!10?_$#209???]$#211!6?_oo!5?E!7?@@???@!101?BB^^^!9~{GW?AA!32?o!22?!5}!5w?_$#212!33?O?@?!6@AG@@!32?Usw_?@?SxA!12?~F@!18?G!41?SSkgG$#213!46?C!66?O!5^~^N@B!34?_{|[!7?N]$#214!229?c!17?C!12?W$#216!243?@!18?C$#217!84?__!71?_!26?G$#219O!28?@!79?@!69?K$#220???_?oG!6?A!12?@?C!165?_$#222!27?]Z!80?E!18?@!26?@!22?WAMMEA???]}!46?_$#223!6?O!105?O!31?O$#224!11?F$#225??]!4?BC?C!13?_!84?_!75?_$#226!16?G!4?@??@@!128?O?@!62?O!12?@$#227!11?O__!7?A!87?G!19?_!14?B@?oo!45?!5^_!14?@@^^^??KK$#229!239?_$#232!55?@!15?@!10?G!41?C!33?O$#233!79?@$#234!33?gCEC?__?WwP??AC?A!22?@?A??Hg_!4?AE??_!32?O??G!38?}$#235!44?@??@!27?@!10?G!36?C!38?}@$#236!41?_$#237!229?Z!12?_!26?O$#238!255?!5?c$#239!255?!5?A-#0!44?@$#2!43?@!33?@A$#3!46?_?O!21?O$#5!28?_!9?_!134?^$#6!79?C?_!188?G$#8!255?!15?C$#9!18?_!11?_!74?Bw???G@!16?C!26?I!4?O?G!4?AA!14?C!46?o!9?W!6?_B$#10!255?!15?B$#11!17?^!13?@!73?wA???C!17?O!24?_!5?O???G!19?@!46?C!9?C@$#12!85?B!70?A!83?A!6?OC$#13!27?_!144?G$#14!31?A!77?_!45?O!18?C!9?_!56?C!5?C$#15!47?_!9?CCC?CC!4?G$#16!167?C!14?_$#17!111?G$#18!109?O!50?_!7?C???_!58?G$#21!19?o!149?C!79?@$#22!27?O!14?@!42?C!41?C!26?A???O!72?_$#24!194?O$#29!60?C!8?O$#30!109?@!58?G?G$#31_!10?A!12?A?@?@!150?G!6?K$#32!16?g!4?O??O_!126?C!42?!4O!34?E$#33O~?w!4?M!4?_!9?w_G!123?AAA!26?BOF!8?^OOOR?B!5?]??AAA$#35!150?@!25?@$#36!175?@!73?OOO!5?O$#37??_!17?H!111?__!33?G?_?_???Co!10?~!44?{!6?C$#38!151?O!26?_$#39!21?_??C!112?AA?Oo!6?O_?DA!25?K??E!22?!10O!5?F$#41!149?G_$#42!5?wH@@!141?GG!15?_!36?GG!11?Gw_!13?_?bFC_$#44!133?O!42?C@???w!51?O$#45!27?C???G!121?C!9?_??G!10?g$#46!53?G$#47!108?@$#48!168?_!80?_nk~~|v~N_$#49!223?@!34?K$#51!241?O!27?O$#53!48?_$#54!86?A!82?@$#55!31?O!5?_!43?O??@!41?@!28?_$#56!79?A!7?O!16?@!59?A??@!73?_$#57!255?!14?A$#61!80?C$#62!157?A$#65!33?{??O??@!41?@$#66!158?G$#67!32?G??o??A!43?K!6?{!23?@!5N?N?A|D$#68!82?@G$#71!51?O!16?O?_$#75!36?G!52?B!13~N!18?|$#76!33?BM?CG@!42?A!21?o!56?CA$#77!37?O!42?AG$#79!55?G!8?GG$#81!242?A???G!14?O$#83!226?_!15?G???@!14?C$#84!227?B!16?@!17?KCCA?OG$#87!243?oA!17?_Gg{~K$#92!227?o!15?K!24?F$#95!29?g!142?@$#97!255?!15?o$#98!30?^!98?_!24?oC!14?AAA_!9?_$#100!156?C!67?~!22?@!11?~$#101!47?O??G??CC???!4A!4?C??G??_!6?G$#102!39?OGCA!37?O$#103!227?Ko!14?A$#104!50?___!4o!5wWOOOoo__$#107!52?G!10?C!7?_$#108!28?O!125?G??_!6?C!7?C$#109!29?Q!75?CC!4?A!17?O!35?C!17?A!46?G$#111!65?C??G$#114!229?M!39?@$#116!17?_!68?W!19?@!20?AA!45?_!55?A$#117!52?C!4?A!4?AA$#122!51?G???C$#124!49?O!6?C!7?C$#125!255?!14?C$#126!111?_!45?@!67?~!34?W$#127!129?G!25?@!18?G!9?^!55?@!6?Go$#128!110?@$#131!38?O!39?@!8?_!72?G!7?@$#132!255?!5?_!8?G$#133!84?A?@!25?A!43?G!103?A$#134!32?@!49?_??_?C!16?W!21?A!30?O?G?C?A??@$#136!49?_??O???G!5?_g__$#138!80?@???w!41?G$#141!36?_!44?CO`!40?G$#142!39?G!40?G$#143!128?@!25?C!16?@??A!56?@$#147!18?^!10?C!80?o!16?@G!27?@?_!10?A!13?W!56?_$#148!110?A!119?@$#149!28?G@!56?c!24?C!47?_?W?C??E!7?O!66?A!6?G$#152!40?C!121?O!11?@!56?C$#154!19?G$#155!19?E!8?A!80?G!20?O!108?O!29?_$#157!19?@!6?_!80?G?E$#159!226?^!15?C???E!14?G!6?_$#160!39?_ow{}}~^NNNFF!5B!7@BBBFFFN^^!4~}{o_$#163!164?G!5?C$#164!239?_$#165!186?o$#167!223?]!15?B!15?G??R$#168!108?w!52?__$#169!171?C$#170!153?O$#171!31?C!150?C$#173!85?G!41?G$#174!31?_!53?O?G!16?E!7?@!116?o!30?C$#180!241?G!5?A$#181!9?NNLNM~~!6?G??B?@!102?@BEC!15?@!29?F!5?S???!5_$#182!104?_$#183!32?A!5?GCA@!114?O$#185!28?C!101?_!41?O!58?A$#186!41?A!140?O!48?O$#189!180?w$#190!111?O!38?O!72?_!13?B^$#191!133?@!15?O???B@!7?C??_!4?@!5?GU!55?G$#192!50?O$#193!27?G!79?EE!22?_!32?OO???G!5?o$#194!130?GO!39?G???I$#195!130?C!21?G!13?_!84?A??A$#197!54?G!11?G$#198!112?GA!5?N!5?C!36?@$#199!34?_!4?A@!47?p!34?AAWo!30?G$#202!255?!6?@??A$#203!244?{~!16?Oo???B$#204!228?N!13?o@!18?BB@@?_$#206!107?o!44?_G!9?O?I!16?B!56?G$#208!22?FF!106?AKO?EEECCo_???!5N!18?O!8?A!23?F`~~!10_!5?GNNN!10?@!15?G?@$#209N!131?@$#211!4?GCEM!126?!5@NNN~~!4o_?C_@!28?@!8?NNNK?KNNN!5?DDL!7N~~~vFOo_o!11?~[$#212!32?s?@NBFC!43?AU???B!33?~??o!37?A@$#213!88?M!23?o{!7o!4?b!31?CFFB@$#214!229?@$#215!255?!5?@$#216!255?!6?A??O???O$#217!129?C$#218!128?_!53?G$#219???FE!124?A!64?N$#221!16?U???A$#222!4?pB!7oO!8?o!109?GG!15?C!28?O_!8?~!32?O!14?ww$#223!24?G$#224!25?OO!167?_!54?A$#225!24?@CM!158?jB$#226??^!10?@??@???sN!5?A!79?@!21?@???A!5w!13?O!11?_?O??OoO!23?!4_~w!31?B!16?C$#229!168?O!88?_$#230!156?_$#232!127?O$#233!112?C$#234!34?O!44?@!4?C!41?C_!36?@@$#237!246?_$#239!242?@???O!14?_-#0!35?GCA@$#1!63?A?AA$#2!26?gE$#3!49?__!10?C!6?A!4?O??O$#5!29?N!7?@!118?@@$#6!25?_!10?A$#8!82?AG$#9!106?~??S@!48?AC??GO__!7?}!7?O_!46?H!9?A!6?N$#10!84?_$#11!30?@!99?GG!30?G!10?O@!7?G!47?o!8?OC!6?O$#12!17?B!91?@!42?O!87?G!6?_$#13!155?@$#14!17?_!136?A!4?C!4?G!17?@!56?AO!7?@$#15!50?O!5?E??C?H!4?@!5?DAC$#16!151?C@!14?_$#17!86?@$#18!108?C!23?O!17?O!8?@?A$#21!248?C$#22!25?G?_!79?b!58?O!5?A!58?@$#24!248?O$#30!167?G!11?O$#31^??w!11?G!7?G!121?_!40?F$#32!16?A!164?G$#33?V?F!9?z?ow!6?BW!120?G???@!21?C!6?GF!6?_GG!59?_$#34!185?C$#35!23?O!117?G???O!24?G$#36!170?A!61?A!27?o$#37??F!17?_!112?A!15?g!15?AC??_!6?tF!9?F!44?w?_???G$#38!25?F!118?w!25?C!7?F?W$#39!21?B!112?!5A$#41!168?@!67?G$#42!143?AFFCCC!18?@!10?_!38?CKC?AE!10?B@wp?@$#44??o!130?C!16?@!15?B!14?B!77?K$#45!20?W!112?O!16?M@!12?@!94?A$#46!42?C!8?G!5?CC?@!15?_$#48!223?G!9?C!15?v!4~}}}~~?G$#49!255?!4?@$#50!62?_$#51!229?O!16?G$#54!30?C!229?A$#55!31?_O???@!116?G!4?C$#56!130?_!29?G?O!62?o$#57!229?E!16?A!21?_$#59!52?C!22?O$#63!31?A!56?@!15?W!58?_$#64!104?_!6?A!16?A!30?G$#65!31?C?@!122?G$#67!32?C!56?_!13?~!8?AE???ooGG??NqG?oO!26?G!5?_$#69!125?@!33?O$#71!49?O!4?A!19?O$#75!31?G!57?^!13~!16?ooo~o!31?_$#76!84?D!40?C???O!26?OW???O$#77!32?G$#79!40?O??C!6?G??O?G?@??G!8?@??ACG$#81!241?G!26?A$#83!228?_!33?_$#84!244?E!17?@EBB?B$#87!228?C!14?NgB!19?_Lg$#92!227?F!14?Eo!20?W$#94!61?O$#95!27?G?O!5?C$#97!33?OG!235?B$#98!18?o!111?C!20?_KB???AA!14?@!9?B$#100!224?~!35?C$#101!26?O!11?OG??A?@!17?C!4?A???CG@A??_!4?C$#102!32?_!48?@?O$#103!227?wB!13?@!22?[$#104!40?_oww{{}~^NFFBbpp!4wo_!8?@!4?_$#105!48?_!6?A!17?G$#106!83?C$#107!39?OG!11?WGCC?A??C?@@?@!4?A$#108!28?o_!124?@AA!16?C$#109!26?C?I!79?_A!63?G!56?E!8?_$#110!255?!14?_$#111!51?o!8?AA!7?A$#114!241?@!4?@$#115!255?!14?O$#116!28?C!76?B!46?AC!4?@???C!10?_$#117!40?C??@!18?G_A!10?C$#118!62?A$#122!37?_???C$#123!62?O$#124!43?A?@!12?AA!4?@!9?_G$#125!229?G!16?C$#126!110?G!114?N!35?_$#127!17?W!69?C!22?A!52?O?O!16?A!56?C$#128!25?O!243?G$#131!84?O?A!42?C!22?_!11?_$#132!255?!5?@$#133!83?A!4?A!22?@!42?C!106?C$#134!31?@!97?G!25?CCC$#136!39?_!5?A!10?@!14?@$#137!255?!6?@$#138!84?A??_!72?O$#140!255?!13?G$#141!33?CA@!49?S_!71?G$#142!26?AO!80?G!22?C!137?E$#143!87?@$#144!255?!13?C$#146!27?@@$#147!18?N!90?G!19?@Ao!19?O!9?C!11?A!8?_[!56?@$#148!108?O!21?@!20?G$#149!17?C!12?A!56?A!17?{???_!19?A??_!17?_!9?A!21?C!56?G$#150!68?@$#152!19?O$#153!248?A$#154!231?E!6?_$#155!26?@!55?@!24?[A!22?A!19?A!11?C!8?C??w!55?g$#157!24?_!137?A!12?B!55?O!6?O$#159!226?~!14?O???o!22?@$#160!33?_oow[MFBB@!20?[!7{wo_@BN^~~~}w_$#163!19?E!164?C$#164!19?H$#165!246?O$#167!165?C!57?v$#168!20?C!87?@!23?C!28?@$#169!19?_!164?@$#170!184?A!54?@$#171!87?G!73?G$#172!184?_!63?G$#173!33?GC!93?@$#174!30?G!4?A!50?C?K!21?O!118?@!31?W$#176!41?G!16?@$#179!184?O$#180!175?C!70?_$#181!14?~F!8?C!121?_!23?@A!7?_!5?WWoo!5~!38?C$#182!30?O!73?F!5?_$#183!30?_O!53?`?O$#185!255?!14?@$#186!172?@!8?_$#189!180?_$#190!110?C!56?A!66?EFEEE$#191!20?A!112?G!15?O!14?A@$#192!53?C!13?@$#193!131?@J_!26?@?@BCGGO_$#194!240?_$#195!134?o!35?oO!50?_!10?w!15?G!4?@@@??_$#197!44?A?@!7?G!4?@!11?A$#198!88?O!24?@!14?_$#199!88?_!23?C!4?GG!5?K?BK!32?_$#202!255?!7?M$#203!244?@G!17?@??q$#204!228?G!13?w!20?wC??C$#205!244?O!19?_??O$#206!130?O!50?O$#207??G$#208!22?w_!110?HXxxX~~vww??Www!18?CKE?g!13?_!15?@N~~~!8F!5?WooW!11?W??w!21?O$#209!177?wO??C!24?w!7G!5?_GG$#211!5?@!15?C!112?!5C???FD??BBB!19?A!38?!7OV^^ZRBFD@!14?@$#212!32?B!52?IO!34?N??@o{B!25?_oO__o???_$#213!34?@!76?{xw~~~!4F!4?A??K_!29?_$#214!255?!13?O$#215!255?!6?A$#216!228?O!12?_???C!16?O$#217!184?G$#219?g!4?_!4?B?C!10?B!189?G$#221!16?D!6?C$#222!4?~}^!4~{~!9?F!126?E!30?F!7?F!27?_$#224_!178?G!14?~$#225!185?B!43?_$#226!20?@w!111?@?_!32?OX?@w???I!18?!6~}o!29?@$#228!138?_!68?!9_?__$#231!38?_!13?_$#232!84?G?G!66?O$#234!33?A!49?@!70?G$#237!241?A$#239!241?C-#0!33?G!47?C?A$#1!49?@!21?O$#2!24?W@!56?C?@!97?[$#3!35?A!9?G!5?@!23?G!4?_$#5!24?_C??W!153?a$#6!24?C$#8!81?_$#9!106?@?C!39?OO@!19?G!58?_!8?OE$#10!31?@$#11!19?O!5?G???@!55?G!46?G!17?C@!14?@??AC!12?@$#12!19?G!153?@!9?A!45?KB!7?GG$#13!24?A!82?C$#14!17?@?A!7?O!57?O!62?GA!23?G!9?G!46?O!7?C!8?@$#15!33?_!33?_$#16!172?G$#17!131?A!36?C$#18!23?G@!82?@!67?a!62?@$#20!17?O$#22!82?G!49?_!14?O!27?@$#23!26?C!145?_$#24!144?B!39?@$#29!35?C!16?G!8?C!17?_$#30!22?G!149?A!7?C$#31???_!10?C?O!162?C$#32!178?o!8?OO!42?O!5?K$#33G??W??o!6?B?Bf!119?C!8?FK!31?CO!4?A?@!32?s$#34???F$#35!22?AA!112?A??!5A!27?@!13?@!17?@@@!14?@@!37?@@$#36!234?[!21?G??GO$#37!20?R?O!147?@!5?B???G!53?@_$#38?w!24?G!110?_!6?OO$#39!139?_O?C?C!33?A!5?OSw!7?!5C!5?CCF!12?JK$#41!136?_!5?_O$#42!4?A!131?WR!5?Cg_!31?B@!41?oW!13?CE!11?G@$#44!177?_!44?C!12?BG@!10?Bw$#45!85?A!86?C???_!59?_!10?A$#46!54?O???O?G!14?A_$#48!247?_!13?G$#49!223?~!37?O$#50!62?@$#51!255?!13?A$#52!68?O$#53!34?O!9?G!10?O$#54!255?!6?a$#55!84?O!24?A!59?G$#56!30?C!134?@A???O!54?@!42?@$#57!225?G!14?A!5?A$#64!104?{!5?@$#65!88?C!75?A$#66!131?_$#67!87?@?@!9?{{_o[!13?FB!5?F??Fw!24?A!7?@??C?__$#68!153?@$#69!116?{$#71!43?O!31?@G$#75!89?}!9~BBNNB!13?w?!5~!4w!26?{~}{o_$#77!83?o$#79!35?G!6?_!9?@!25?O$#81!228?A!17?G!15?A!4?_$#83!226?J!40?C$#84!241?@@??C!19?A?A$#85!226?O!15?_??G!18?_$#86!243?K!22?K$#87!241?C]_O!19?\L$#92!243?B!22?_$#94!52?EG!5?G?A$#95!28?B!77?[$#97!30?OA$#98!18?^!9?_!79?A!39?_!19?A!13?@$#99!224?G$#100!151?A!72?v!22?O!13?C$#101!31?C_?C!9?_?C?@???O??___??OG!8?G???Bo??AGO???A$#102!25?A!4?_!50?G?CC$#103!227?B!12?_???_!19?Ao?@$#104!34?_ow}!4~^NFB@!6?F!5NFF@!14?Aw_$#105!45?C!32?G$#107!43?_$#108!106?A!25?@O$#109!19?_???_??@!80?G!23?@!17?C!23?O!7?O!47?O!9?@!28?_$#110!255?!14?F$#111!51?A!15?O!11?O$#114!228?_$#116!105?E!27?G$#117!46?GC??AG!10?C@???G!11?CG$#118!47?A??@!17?G$#121!69?G?_$#122!33?O??@!14?C$#123!59?O??A!206?O$#124!34?G!9?O!8?O!21?C?@C!190?G$#125!108?_!131?@!6?C!13?@$#126!131?C!93?E$#127!19?C!9?C!75?o!26?O!14?_!20?@??O?C!7?C!47?AK$#128!23?O???_??G!54?C!95?A$#129!69?O_$#132!239?_!7?G$#133!130?@G!19?C!94?_$#134!82?_??_W!65?@!14?C$#136!36?C!31?__!6?DC$#137!240?C$#138!153?_$#140!228?G!17?O!15?{$#141!86?@!78?A$#142!133?C$#143!19?@!5?OA??G!77?A$#144!228?C$#146!28?C!52?O??G!21?_$#147!18?_!88?o@!23?E_!15?GA!16?@?C?GO_~!6?_!56?_$#148!29?A!151?G!86?O$#149!105?H??G!58?A!5?A!9?C$#150!37?@$#153!17?C!91?@!119?@!9?O$#154!237?O$#155!23?C???B?_!118?C@!81?@!36?C$#156!46?A!23?O$#157!133?@O!96?A$#159!226?C?@!11?G!4?BC!15?@!4?W$#160!31?w^FB@!9?oow}}{o___???___ow}~~~!4FN~~{???@BFBB@$#161!56?O$#163!17?G!9?C!106?_!48?_!53?_$#164!133?A$#165!149?_$#167!146?_!85?B$#169!17?A!9?G!155?O!46?_!7?A$#173!85?@$#174!82?O!26?C!40?O!74?o$#179!25?_!144?A$#180!246?@$#181!4?_[!8?B!131?B!31?G@!5?AANN^^^N@$#182!109?G!61?_$#183!84?_?C!17?B!25?AO!18?_$#185!83?G!97?@!86?G$#186!29?O!141?C???[$#189!150?G$#190!143?g!32?[!44?_w!13?@!11?s$#191??B!23?_!204?_{?A?OA$#192!47?@$#193!20?G?c!111?M!12?G$#194!20?C!127?A$#195!135?{!12?@!73?B!10?~_!14?E!6~f~~sk$#197!57?O!18?OA$#198!86?_!41?B!22?G!17?_$#199!88?B!39?C!22?O[!6?@@!7?_$#202!226?_!18?_$#203!241?o?ON!21?@$#204!227?{!13?A???O!17?~$#205!241?G!24?Q$#206!108?O!60?@!9?__$#208!22?@@!112?@??!5@???B!23?A!8?@!23?AA!14?AA!37?AA$#209!4?K!134?OGK!4?O!88?W!20?O$#212!86?A}w!12?O!16?{!6?FF!24?__[B?@BN]}}~~w{[WO$#213!103?_!5?o}!5~B!12?~{!21?A!17?_$#214!228?O$#216!240?O$#218!17?_$#219?F!6?KK???C$#220??o$#221!231?G$#222!4?@BN~rr~~~w??G!9?O!110?KC!6?G!31?C!8?C$#223!21?o$#224F!14?O!163?I$#225!14?wk$#226o???O_!14?_N!112?@B???KC!6?C!24?@!7?Q???__???___o}!5B!4~}!27?C$#228??K!135?z?_oW!34?W!6?KG?__!5?!5w!5?www!12~??C$#231!36?A$#232!30?A$#234!30?@!133?@???GO-#0!30?C$#2!30?G!150?{$#3!42?A!28?@???_$#5!23?F!82?N!73?_B@$#8!255?!13?K$#9!18?@@!87?@!26?g!10?o!83?B!7?W@!5?_!23?@$#10!22?C$#11!106?_A!25?AC!45?G!56?c!6?O$#12!18?C!209?_!7?_?A!5?G$#13!21?_!4?G!153?C?_$#14!18?O?O??OA!108?C?_!9?G!27?@!8?G!53?O!7?C$#15!31?G!10?@!26?A!10?A$#16!175?C!4?A$#17!18?_$#18!21?O!153?@!54?A!36?_$#21!20?A$#22!22?@???A?C!106?G!8?O!28?A$#24A!15?G!161?C$#27!24?O$#29!40?G!35?B$#30!14?w!164?G$#31???@$#32??A!176?@!9?@!4?!5A$#33@A!4?!8A?w!9?O!113?_!79?z!27?@$#35!7?G!181?W!14w!5?!5_!5w?w!28?w!4?_??w$#36!183?O!51?G!12?A!10?A$#37??C!14?O???@!113?A!40?CG!56?W@$#38?@?{!21?N!110?B@?C!107?A$#39?[!141?_!42?B!27?E!4A$#40!248?C$#41!138?@??@@@$#42!136?Gg???SwGA!39?{}!34?@FB!31?K$#44!135?@!41?@!5?c!47?w]?E!14?@!7?E$#45!136?_!7?G!28?C??@!53?g?__??B!9?OWO$#46!32?A!43?C$#47!255?!4?G$#48!183?G$#49!223?Z!36?G$#51!255?!12?O$#52!70?@$#54!224?@$#55!132?@O$#56!28?O!78?O!120?@!16?A@$#57!244?A!22?C$#59!79?@$#63!104?A$#64!82?A!21?@???C!23?C!16?A$#66!131?@!38?w$#67!88?B!10?BB?BC!7?}??[]A@!8?E?AoC!19?wu??!5_!5?E@@Ba??@$#68!83?O!19?O!8?oO???WO!43?Ww?wwG$#69!116?@!32?C!19?A$#71!32?C@!5?O!36?_$#75!84?o{{~{!10~{{~{G!10?__{__x!6~p~{!23?{{!5^~{w_!4?o$#76!84?@!85?C$#77!80?o??B!48?G$#79!31?_!8?C!38?A$#81!225?O!12?_A$#83!227?G!11?C$#85!226?A!13?[oGA$#87!242?E!21?E$#88!79?O$#89!226?C!37?@$#92!255?!10?BB$#93!227?@$#94!32?G!45?_K$#95!22?G!4?A!154?A$#97!30?O!237?_$#98!19?w!7?[!78?O!40?A!26?n$#99!224?A$#100!223?c!22?C!13?s$#101!31?A!8?_G?@!31?W$#103!226?w!38?_K$#104!32?o}!5~NB@!35?~^$#108!27?_@!76?G!27?@$#109!18?A!4?G@?_!78?C!41?C@!80?C!38?A$#110!29?E$#111!40?OC!28?A$#114!238?O@!27?A$#115!29?G_!50?@$#116!105?A!76?C$#117!67?A???A$#123!31?C@!47?@!187?O$#124!67?@A$#125!146?_!77?_!42?G$#127!18?G?_!7?A!76?@!28?A!9?_?A!81?OO!7?A$#128!182?O$#130!80?G$#131!28?G!78?G!65?O$#132!224?[???A!9?G!4?_??A!14?~$#133!28?_!52?G!22?O!27?A!15?C@!75?@$#134!104?G??_!39?O$#136!68?@@$#137!225?C!36?_$#138!103?_!49?B$#140!243?G!18?^$#141!81?__!30?_???CE$#142!22?A$#143!107?C!26?@!94?_!7?@$#144!227?_$#147!19?E??o!82?o!28?O!11?K@!26?O!5?O$#148!26?O@$#149!146?O!82?G$#150!76?O$#152!175?A$#153!236?G!8?C$#154!145?C$#155!21?G!208?C$#157!17?E!159?O?O???@$#158!79?_$#159!225?_?O!15?C?@$#160!30?B@!9?o{}!23~!5{~~~F$#163!135?O!94?@$#164!179?_!65?O$#165???A!20?G$#167!222?_!25?_?!4_?_!4?A$#168!81?C!91?G!56?O$#169!245?G$#170!20?G!207?G$#174!104?_???@!24?_!109?O$#177!255?!12?@$#180!20?C???C!213?C!6?_$#181!4?~}{sw!5{AC$#182!108?A$#183!172?X$#184!29?P$#185!26?C!54?A!93?w$#186!23?_!5?_$#189!136?C!4?_!93?E$#190!136?O!5?CCC??G!106?AME$#191!17?_!115?G!42?AE!5?A!47?@@]_!11?G?H$#192!39?_$#193!21?E!123?A!30?__o!49?C!6?_$#194!145?@!89?O!22?_o$#195!222?[!8?E?@!12?__??!4^PPx@^?@$#197!31?O!9?A!34?G$#198!148?_!20?@??C$#199!83?_!19?B!6?s?EEA!14?EW!17?OwE!17?L$#203!241?N!22?w$#204!226?@E!11?wB?p@!19?~??o$#205!240?_!24?[$#206!17?@??@!5?@!209?C$#208!255?!4?@$#209!5?@!172?@!5?A!30?!4C?E!13?@!12?C?E$#211!138?C!47?CCC!15?!5C$#212!81?OWGEAB!30?AHE!8?@!21?@@B!7?BFFF@EEC$#213!108?w~J!5@!13?@b}o!14?_G!20?{B}$#215!225?A$#216!244?@$#217!146?@$#218!180?@$#219{!15?o!7?_!153?A$#220??@$#221?_!133?C!53?_$#222!6?!8@??@!120?UAY}I!6?A$#223!25?_!112?G!49?@!20?!5E$#224!16?E!161?G$#225!14?@B!163?C$#226??w!5?C!5?C??G!126?@!31?W??A!4?@@???E!4F!5C!5F!15?C$#228!138?o@@?AQ!42?wzy!5?!5@!5?!5z!5X!5@??w$#229!255?!4?C$#230!173?_$#231!80?C$#232!82?@!21?C$#234!82?CC?@!86?a$#236!84?G!27?GG!12?G??G!21?G!12?w???O$#239!225?G-#1!48?G?K@$#2!181?@$#4!48?O?_$#5!20?[K???_K!153?@A$#7!47?__o$#8!255?!12?O$#9!19?A_?@!112?G!8?@!91?@!5?_K$#10!25?G!241?G$#11!19?C@?A!82?C!28?AA!45?GA!61?@$#12!143?OC!83?C!7?G!5?OA$#14!22?G!4?C!78?@!27?C!18?_??_O??O?OO!14?O?G!46?OG!8?@!5?_$#15!75?C$#16!141?O$#18!24?OA!110?_!41?G!4?_$#19!18?@!162?O$#21!228?_$#22!29?B!113?@!29?G!9?O!51?@$#23!27?G$#27?_$#29!30?A$#30!234?@$#32!18?G$#33_@?_!11?@|}_!119?B!48?_!28?C?Cw_!24?@$#35??_!15?O!5?C!158?@C[o??Ww?BB!5?!5~}}!8?N^Z^Z?Bb!12?A!9?_Q^??l__??@?@E$#37!141?C!41?AG!48?_$#38!23?[!116?BB$#39U??O!13?@!5?A!162?GOOCD]??!5@!7?^??`!4@o!4_?W$#42!184?BB$#44!137?F!93?J]$#45!29?C!104?O???_?_!11?_!20?A??]A!51?WU$#47!140?G!118?B$#49!222?G!37?w$#50!30?[$#54!106?A!74?_$#55!27?O?_!74?[!40?A!5?_!6?_$#56!104?A!54?_!4G??O!99?G$#57!224?A??A!8?_!4?_$#62!28?@!76?_G!59?_$#63!28?A!128?G$#64!107?@!64?_$#65!146?_@!20?G$#66!172?C$#67!81?__!16?_???_!5?}~~!16?BKo!18?MBFA?@C?C?BBB!4?C?_@o$#68!82?E[!28?@@!15?O!16?O[!5?@!9?B!4?O$#69!132?@$#71!37?_A!36?O$#75!80?G???!15~^^^~]!8?}}!14~{!24?A!4?C???B$#76!82?O!68?OKK!10?C??@??N$#77!77?_?A@$#79!37?O!37?_@$#81!237?G!4?A!19?G???A$#83!237?O@???@!22?O@$#85!238?_cCA$#88!76?_GA$#89!240?O!24?C$#94!31?N!44?OE@$#95!20?AA???O$#97!255?!12?_$#98!19?@!6?O!116?K!30?~!4?OAC$#99!223?G$#100!144?G!77?oF!13?A!22?FB$#101!39?C!34?C$#102!74?G$#103!238?O?_!23?}B$#104!31?o!5~F!38?K@$#107!38?G@!34?_A$#108!26?@!107?@!44?CC$#109!21?_!4?_@!107?C!46?C!45?B!6?G$#111!38?OA$#115!255?!12?C$#116!21?@!120?G$#117!39?G@!4?_O??C@_!22?A$#118!46?_O?GQA$#121!38?_$#123!74?O@$#126!105?O!118?@!36?o$#127!19?G??C!122?@!13?O?O!65?_!6?_C$#128!158?O!108?A$#131!29?O!104?_!20?O!24?O!42?O$#132!143?_!79?_???C!33?K$#133!144?OC!17?__!59?G$#134!27?_!105?@!16?_!7?G!6?g$#136!37?G@!37?A$#137!255?!7?@$#138!82?@A!19?@!46?O???!5A$#140!224?_!37?A$#141!28?O!49?oKEB!77?!5C$#142!179?@$#143!105?G!69?G$#144!226?O!14?O!20?C$#145!77?OG@$#146!21?O!4?A!152?G$#147!105?B!29?o!6?o?A!34?_??w!52?oE$#148!141?_?A!34?_A??@$#149!27?A!107?@!18?__!87?OA$#152!175?_!59?A$#153!244?C$#154!136?G!92?A$#155!19?_!158?C!4?G!50?G$#157!24?G!116?GA$#158!78?C$#159!225?@G!35?o??_$#160!39?o}!4~^NNFB?[!22~@$#163!229?@$#165!24?B!211?O$#167!137?_!84?F!36?_$#168!140?O!35?_[$#169!142?C!30?_?S$#170!228?O$#171!18?A!138?_$#173!104?@!49?O$#174!104?_?C!52?G___?G!15?_!43?C!17?C$#179!244?G$#180!227?G!15?@$#181?A??!10~}}A!121?C@C!116?@$#183!28?K!104?C!32?G!5?W$#184!30?@!236?@$#185!19?O!4?_C!149?B!90?_$#186!22?O!111?G!21?O!7?O!8?O!60?O$#187!136?O$#190!137?G!93?O$#191!136?@O?_!25?O!7?C!56?hc`^$#192!38?C$#193!177?`B!4?C_!73?F$#194!138?O!37?@!7?O!57?G!15?w$#195!185?_!43?_!15?k_~~Q^^~~}~}w?O$#198!107?wC!62?]$#199!80?OG!27?@!19?BK!14?_A?{?C!4?@@!7?BB?CCo$#202!225?A!12?G!24?B$#203!240?@$#204!225?{F!10?_EBGK!21?{$#205!239?WA@!23?G$#206!22?_@?@!110?C!97?C$#207@$#208!142?@$#209G$#212!28?_!54?_!16?__!45?A???G??GG!9?CBIA$#213!81?O!24?oEz!21?B~}w!10?_W??B@!7?@@!12?`$#214!226?_@!9?C!28?C$#215!224?O$#216!255?!9?@$#219???@$#220???E$#221!18?C!170?_?`cc!10?@@___!11?C$#222!23?_!164?_$#223!186?BFFB???O!18?__$#224?[!217?F$#225!14?@!123?GM$#226??^!133?A??O!89?C!14?O$#228???G!182?CGG?A?WG!5}!8?^^]}}]]!7?[$#229!255?!4?K$#230!29?G!143?@!92?O$#231!30?_!44?G$#232!133?A!19?O$#233!146?@$#234!83?@!65?_??O???G!10?o@???B$#236!79?o_CG!46?_!16?K_?OG?@?C?C!12?M-#1!42?_OC!9?OO!7?C$#3!38?@!227?_$#4!44?Oc@???@GO?_!5?_?O?C$#5!24?oN$#6!255?!11?G$#7!45?W}~~~]O!9?__ow$#8!255?!11?C$#9!135?_???_GB!32?C???@???@!50?_A!5?o$#10!255?!11?A$#11!138?_G!9?A?@!21?__!4?@!54?H@!6?@$#13!24?A!111?o!39?_!89?@$#14!136?G!5?@!30?B!53?@!5?C$#15!53?_$#17!141?C!8?A$#18!23?G!115?C!35?AO!7?O!80?_$#19!26?A!155?O$#21!227?A$#22!177?@$#25G$#27???W$#29!74?@$#31??O!15?V???@!163?N!10?OO!12?O?O$#32!22?G$#33??_@!15?_??_!173?o!21?O?@$#35??@!14?_!167?o!4?!4N!5?@@BFFN^~~~}}kw_!6?M@!22?r!4?E?W!4?]]$#36!230?_$#37!242?O$#38?~?C!215?_!10?WG$#39!22?OA!165?^!4O!16?@AA$#40!220?O$#42!230?EO!11?eK$#44!20?O!167?o!41?@$#45!137?F@!14?@!77?_$#49!221?O!37?@$#50!72?_G$#53!37?_!19?_$#54!255?!4?O$#55!26?C!107?A!14?D!28?_C$#56!134?G!7?A!8?A!71?G??@$#57!234?_!4?O!20?_$#63!172?G!8?G$#64!172?E!6?O$#65!29?C!121?O_???O!12?A$#66!29?G!114?G!12?C!4?O$#67!99?^???^WW???@!18?[@@?_w!9?QOQG!5?OO__?A??O???AAA?@?D!10?_$#68!27?s!48?_KGB!20?^O!5?KIC!36?_oo???C??AGwwxBBBA_?\~}C$#69!158?A!12?O$#75!79?{!19~___~___wooy!18~b!14?_!15?CKKCCL|_$#76!28?G!113?G??G!10?C!6?O$#77!30?C!42?oo?A$#81!224?@?G!12?G!21?O???@$#82!224?G$#83!224?O!10?O!26?B?O$#84!255?!8?_$#85!237?_!25?MK$#88!31?CO!41?CA$#89!236?GEB!25?A$#94!31?AG_!41?@$#95!25?O$#97!72?O!193?O$#98!139?O!37?oE!4?_$#99!227?O!32?A$#100!221?_~!4?_!31?m@$#101!38?[!18?G?O!11?_G$#102!38?_!19?G!14?A$#103!255?!9?@$#104!31?@F^~~~!21?_$#105!37?M!13?_$#106!137?_!127?O$#107!57?O$#108!174?G??GG???AG$#109!24?C_!148?O!58?O!7?I$#113!30?@$#116!173?O!8?CC$#117!44?A!7?CG??O!7?@!8?@$#118!38?A!4?_G@!5?BGO??_???OOG?Ap$#119!74?A$#120!58?O$#121!44?_A!5?C???_!7?G?M$#124!73?C$#125!223?A!41?G$#126!134?C!46?@!41?C!11?C!24?O$#127!26?@!113?A!11?@!25?O???GA!56?GOA$#128!173?C$#131!134?@!12?C!34?_!44?C$#132!223?@???G!12?C!19?K$#133!26?_!152?G!43?_??A!34?A$#134!147?GG???A!28?C$#138!145?C!8?KC!6?GG$#140!226?O!9?@$#141!28?C_wo!43?WCB!23?M!6?C!35?__?@!5?CA$#142!232?_$#143!23?_!112?C!11?C!34?@$#144!226?C!8?G!25?G$#145!30?AG_!42?C@!147?C$#146!24?G$#147!135?^!4?C!33?B!8?O!50?C!6?C$#148!233?G$#149!150?@!22?G???C$#152!23?O!112?@$#153!184?_!54?_??C$#155!140?@!34?GG!7?K$#156!50?_?_$#157_!183?A$#158!74?G$#159!224?A!11?A?_?@!20?_??_$#160!39?~~~^N@!7?BFNNNFFNNNFB??!5~^F$#164!175?@$#165!242?G$#167!221?G!6?oG!28?}$#168!137?WA!37?@!51?M$#169!20?@@!116?O!96?A$#171!148?A$#174!26?W??@!104?o!5?_G!12?@!26?A!41?O??_!34?@???C$#180!175?C!58?O!6?@?@$#181???_!13~^_!178?__}}{wwo_$#182!143?@!36?@$#183!27?@!114?C???C?@!7?@!15?@!7?A$#185!24?@!111?A!40?A$#186!232?OA$#189!187?G!10?G!20?G$#190!220?_!22?O$#191!20?_!118?@!89?o?@B!9?_$#192!59?_$#193!138?KA!35?oE!7?@$#195!185?@!35?E!7?F!15?!4~x~f!4~``@$#197!37?P$#198!104?@A!23?KK?@!8?O!7?___!28?G$#199!77?oq!26?C@@@!20?QqxW!8?_OCA@!5?G?_!6?_o_!6?@$#202!239?C!22?C$#203!236?_G!24?_$#204!224?_~!9?_C@[B!22?G@$#205!236?OO$#206!23?C!209?@$#209!19?G$#212!27?IrO!46?G!24?@!44?A!4?C?IOWA@@A???`O!4?GG$#213!104?E@A!22?_?EEB!9?GD!13?C!11?on!7?_s$#214!240?A$#216!255?!7?OO$#217!140?O!38?A!61?_$#219E!20?AC!196?O$#220!19?C?o$#221!18?GP!189?@??CG$#222@??A!15?AA?A!163?OFN!30?F$#223!20?KK!164?_o!6?O!17?@@!29?G$#224O?M$#226!185?M!42?@???K$#228!23?@!165?!5_n~NNF!12?@?E!4~n!12?E$#232!147?A??C!4?@!16?o$#234!29?A!45?_!70?@??WO!19?A!10?O$#236!76?O?D!27?CA!25?C!8?_???O???G?G???_!12?o$#237!255?!10?A$#238!255?!6?C-#0!69?GA!73?O??GG!9?CCC???_$#1!65?A$#2!69?OC!72?O!5?C!11?C$#3!38?@??A???_!25?@$#4!63?OA$#5!24?@!111?C!4?_???G!10?A$#6!148?C!8?AA$#7!47?@!13?B^N@$#9!135?@!37?A??@!54?oA???_?KB$#10!136?@!5?O!4?C???A!11?G!10?O$#11!135?C??A!45?C!46?G@$#12!232?G@???G$#13!71?A!68?_!21?C??_$#14!25?A!109?O!36?_!4?A!5?G@_!52?O$#15!39?_???O?O!14?@?_$#18!175?A!54?O$#19!172?O???O$#21!239?G$#22!22?_??C!124?A!34?G$#27!18?A@?E$#30O$#31!16?C@@!177?Gw?C$#33??@G??!8G??G!169?A!6?G@@B@@!15?@$#34!18?C!167?C?C!65?_$#35!15?FBEG!168?G!20?@BFNN^wwO!10?_O!10?oWgGA@?_ccw__!4?B$#36!19?W!223?GII!4AI???G??G$#37!21?G!165?o!40?g@A!10?@!11?C$#38?F!17?E?@!117?@$#39??M!11?GG!4?@!167?A!27?_$#42!18?O?G!167?O!27?G?@!22?CF???W!4?Wo$#43!241?A!10?G$#44!21?o!197?O!9?C$#45!136?_!48?Ao!41?E?C$#49!220?}B!4?GC!29?_F$#50!38?G??G$#51!255?!9?O$#52!56?A???A$#53!44?@$#54!172?G$#55!25?G!115?O?G!33?C!5?_$#56!71?C!89?A!20?@!81?G$#61!72?@!191?C$#62!138?G$#63!26?A$#64!177?O???WW$#66!137?_!33?O!6?GW?C_$#67!28?Hs??o_!38?C!56?E}O?b!4?_!25?A@FN?O!8?C??B$#68!26?g!4?IC??_!37?MMM?KKE!63?A!4?@!15?@?G?F$#69!142?C$#70!129?g?__!13?@$#71!37?@$#75!30?G?GG!38?G???J??H!49N!14?@!21?E$#76!27?O!42?_?_!66?G!6?A??@@!10?@$#77!33?A???_!113?@$#79!37?A!7?@$#81!223?COA!7?G@!25?G???@$#83!224?G!9?A!25?_$#84!234?GC!25?M?B$#87!236?A!25?_$#88!34?ACGO$#94!34?@ACG$#95!136?A!37?_G$#97!153?AAA!109?O$#98!24?M!111?GC!35?{?oE!6?@$#100!221?{B??_SB!30?wB$#101!39?A_!27?_!73?_!7?C!12?O$#102!41?O!104?G!15?G$#104!35?@B!5?KMMEA!10?}~~{_$#105!46?`?@CC_?O!7?G$#107!38?C???O!13?@!4?C$#108!23?OO!151?G@!5?AG$#109!135?AO!22?A!13?@$#110!255?!10?C$#111!38?AO$#114!232?_??_??@$#115!144?G!120?A$#116!23?G!159?C$#117!39?@A???_!19?_C$#118!39?C[?@!21?W@$#121!39?G!23?_C$#123!152?A!112?G$#124!43?@O$#125!237?C$#126!172?C!49?G??G@!32?O$#127!137?G!36?@!62?_?C$#128!23?A!206?_C$#129!45?GC!9?[!4?O$#130!38?O$#132!222?C??OA!32?K$#133!134?A!4?A!14?@!8?CG!12?G@!43?_@_!34?_@$#134!134?K!13?A!9?@!7?_!5?@$#135!26?O???oo?O!40?!55oO$#136!37?C!19?@$#138!27?_!48?C!68?A!18?C$#140!223?A!40?A$#141!30?FDBCWO_!34?OQ@@!64?O!25?G$#142!23?@!113?@!36?I!90?@$#145!34?CGO$#147!23?_!113?A@!45?o!47?C!4?O$#148!23?C?@!138?O!10?C$#149!24?_!110?G!48?A!55?@$#150!42?A$#152!69?_$#155!22?O!123?C!117?_$#156!49?G??o??@$#157G!21?K!162?C$#158!33?@!4?_$#159!223?G?@!11?A!22?O$#160!40?@`__!21?w~~^F@!72?__!4oww!7{!4wo_$#163!185?O!52?A$#165!233?A$#167!138?C!87?_G!29?O$#171!183?O$#173!149?A$#174!25?O!44?O!63?@??O?_!5?C!9?@@@!14?A???_!5?A!39?O!10?C$#179!240?A$#181?w?F~~!9F!4?_!174?}}o??z!8~}{woo_$#182!134?O$#183!25?_C!44?G!68?@???C??A!4?@!18?_!6?A$#185!70?G!89?A!13?C$#186!231?A$#189!20?O!166?C!5?C??C!46?@$#190!220?@!32?w$#191!135?_!50?G!41?@$#193!175?@!54?G?O???O$#194!185?@$#195!227?O??@!9?_Oooop!4@PBFBV~cF$#196!46?W}}rz^Nn~}_$#198!27?C!105?G_!5?G!22?@???_??_!8?A$#199!27?IA!44?_???@@!51?@N^S!4?O???B!19?@!4?Ooj!7?__$#202!223?_!9?O?OC!26?_$#203!235?@@!24?o^$#204!223?OF!8?_sG?@!25?[$#208!240?C??!4C??CCC$#209!229?A!8?_$#211??O!9?_!4ow??E!165?@?h!4~B???Ey!15?EFF~]k!27?WW$#212!29?B!45?@!67?C!19?A$#213!28?C!100?@!9?CEN!27?C^N!6?Od~_$#215!225?C$#216!235?A!25?@$#219???o??o__!9?_?_!172?o!24?_$#220!187?@$#221!22?@$#223??_!4?OOoooO!174?A!10?C!20?B$#225f$#226!22?A!206?w?@!24?W$#231!41?C$#232!26?@!113?O?G!10?@!5?@??A??O!16?C$#234!160?@!7?G$#236!27?@oG!4?_!36?_?O???AA!65?B@?@!18?O$#237!236?G$#238!255?!5?A$#239!255?!5?C-#0!41?BBFN~{{ww!4o___??__OW{^NF@!75?!16FNN^!4~{wo_$#1!54?OO?__$#2!65?OG!75?G!25?G???WC$#3!62?C!83?G!5?_?G?_!4?_$#5!141?G@!29?cIB$#6!68?@!100?O$#8!255?!9?C$#9!22?o!161?@_!43?GC!4?A$#10!255?!9?A$#11!22?G!149?@!12?A!42?_?@!5?@$#12!23?C!206?G???C$#13!140?O!30?_!14?_$#14!228?O!6?C$#15!58?G???@!78?O!5?_$#16!43?O$#18!171?O!14?G!41?G$#22!68?A!101?_!15?C$#24!6?o$#25!4?o$#29!142?O$#30J!246?A?aoG$#32??_!185?C!47?C$#33??KCK???{CCC!4?G!178?k?B?k!6?k!44?AQA$#34!19?@O!218?A!14?`$#35?O!8?owW!202?@!10?[!18?_dD@@Bp_K$#36!20?_!204?o!28?G$#37!21?A!164?@?w!37?_CA$#38!20?K!217?A$#39!13?w!174?A[!62?@@$#40!255?C$#41!19?_$#42!187?G!25?O?__??@!16?__X$#43!235?O$#45!227?G!28?@$#46!143?O!14?O$#48!220?C??_o!30?w$#49!219?o!4?G!31?M@$#51!230?OA??A!28?G$#52!47?@!4?CC???C$#53!145?O???O!8?_$#54!233?_!23?G$#55!23?_!115?G$#56!24?A!42?G!67?@!33?G!14?O!39?@$#57!255?!8?C$#64!135?A!40?@$#65!33?BF!4?G$#66!175?G$#67!26?w?F???FGG~~__c?_!28?A@?E!55?B!5?KO@!30?@!8?B$#68!29?B!38?_???C!58?EDFA$#69!67?_$#70!134?Go_O$#71!61?C!83?_OOO$#75!27?ww{~~woo!7?_!26?G{{ww!55~wwxww$#76!27?B!10?A?GO!30?@!65?A!31?G!12?G$#77!39?A$#79!141?_$#81!232?o!25?_A??O$#83!223?@!9?A!25?C@?G$#85!255?!4?wOoD$#89!255?!5?k$#95!141?@!30?A$#98!23?@!205?O$#100!220?J??OCB!7?G!22?oE$#101!59?OO!92?__??G??O!5?AC$#102!40?@?CGO!22?A!74?CGGG!9?gG$#104!58?FFFB!80?___$#105!49?A?D!94?_!13?_$#107!50?C???G??G!90?_$#108!174?C$#109!41?C!25?C!72?G$#110!142?A$#111!47?A!103?_$#112!49?C$#113!39?@$#114!231?C!30?_$#115!40?A!100?C!121?_$#116!184?A$#117!46?A???G!10?__A!94?G$#118!48?C??G!4?OOO!4?@$#121!52?G$#122!147?!7G$#123!61?G$#124!46?@!6?G!8?A!86?__!6?_?O$#125!222?_!34?_$#126!221?A!36?A$#127!231?@???@$#128!42?G!124?A$#129!57?A$#130!140?_$#131!65?_!105?G!12?G$#132!139?@!35?A!44?O@?GA!32?O@$#133!40?CG!27?@!101?A??O!45?_??C!34?G$#134!24?C!43?C!70?_!30?O!4?C$#136!57?@!101?_$#138!26?A$#140!221?G@!10?C!24?O@???A$#141!25?A!42?WC!62?A$#142!44?_!121?@$#143!21?_AG!162?O$#144!223?A!10?@$#145!38?@$#146!64?_!108?@$#147!23?A!149?O!11?[!43?_A$#148!229?C$#149!22?C!116?O@!34?@!9?@!48?G$#152!229?A!6?A$#153!233?O$#154!237?@$#155!229?@$#156!48?A!6?GG$#157!227?_C!21?CC$#159!221?oI!8?G@!30?@$#167!219?K!6?@$#169!184?C$#173!140?CA!29?C$#174!136?@?O!44?@_!36?C!36?C$#181?N?WBB???wG!8?A!174?~BB??B!6~!9BA!38?E$#183!24?G!17?O_!94?`A!27?@AC$#184!255?!9?@$#185!255?!8?O$#186!22?@!145?C$#189!20?A!217?C$#190!24?@!41?O!146?__??_}A!15?_$#191!21?C?O!163?O!39?A@!8?A$#193s!226?O!20?A[G$#194!248?G$#195!226?A!9?G??_NNN~xWWwo!5?OB$#196!48?@@BABBFFF$#197!59?GG!89?OOO!4?O$#198!37?C[O!26?_!69?MMG!30?@!6?}o@[ZV?_$#199!24?oKC!6?C???W??o!32?@!60?@??_!39?K??C?_$#202!222?C$#203!255?!6?B$#204!231?oM@!28?A$#205!255?!5?AK$#206!186?A$#209!12?_!174?B!39?@!8?O[_\ooo?EF!7?o$#211!19?G!187?!6G$#212!25?p@!40?O?q??A!61?o!4?C$#213!169?AF???_o??qb__@$#214!230?_$#215!222?O$#217!173?_!60?O$#218!21?O$#219???B?CN~B!6?[??B?@!172?B!22?B$#220!5?W!168?G!23?{!35?_$#221??O!9?CC!7?H$#222??B!6?BB@!4?S??C!167?C!7?OCC?O!6?O!10C$#223!19?O!177?_!9?!5oO$#224???_!231?G!10?A!5?K$#226?_!185?_$#227!248?C$#228!5?_!5?ABB~bb~{!169?@b~~~{??wWB!13?_GWWW^@$#229!225?K$#231!144?O!8?!4O$#232!140?A!30?@!11?A$#234!37?B!144?KS$#235!178?K??GQ$#236!27?C!42?@A!57?CF???C???C-#0!49?!12@!93?B~~~}{w_?@BFN~~~}{$#2!47?@!94?_$#3!141?OO!9?@AO$#5!171?A$#8!255?!8?@$#9!21?c@!163?c$#10!255?!7?W$#11!21?AE!34?A!114?@!14?_$#12!228?C$#13!227?A$#14!22?G!36?A$#15!148?@@@!9?A?O$#22!20?C!166?C!38?C$#25!4?@$#30???G!15?_@$#32?A!222?_!8?A$#33!8?B!10?G!171?E??AA???@!5?uA!16?O!7?O!13?OA!4?KK?@$#34!222?o?G!7?GO$#35???o!5?NF@!212?O!5?_!16?@@BB$#36!222?G??C!7?_$#37C?W!185?P$#38!18?A!171?G!14?G!5?G!12?FB$#39!8?{!4?~!175?_!49?OAAA!4?AA{??BB$#41!235?@@$#42!18?o!172?o!21?_?C!21?@?e___mEe$#43!188?E!45?A$#45!48?A!139?G$#46!144?DA!13?@!4?G$#48!218?A??s?@!8?C!22?@$#49!217?O@?o?A!32?M$#50!153?C!9?C$#53!139?O??A!22?_$#54!185?G!33?@$#55!61?A$#56!47?A!137?O!33?A!42?@$#57!255??_$#61!228?O$#63!44?@$#64!50?C!133?A$#65!27?O!150?O$#67!25?BBK!5?eC!5@?W?_MKSO_!6?GG??ooOooG?@!62?}!4?_CC!36?CG??O??G??_$#68!38?ooo_oO!23?{{!63?{??G!38?oO___$#69!43?@!10?O?OGG!116?C?CA$#70!35?!4A?@@!9?G???_!8?uW!64?}!4?@@$#71!138?_!14?W!8?G_$#75!24?~??B!5~XX{{{KGK?GGoo_c!4?GG!11?e{@?}!59~@@~@@$#76!39?EACD!7?!4O_O?OOC??KK?@??@$#77!135?_OC$#79!143?`??A!4?A$#81!219?GB!8?C!27?W$#83!230?@$#85!255?!4?_$#88!137?OGA@$#89!255?!4?A?@$#92!255?!5?@$#93!230?A$#94!137?_OCE???G??A??A$#95!46?@!5?A??A!171?_$#97!62?@!107?@?O!89?_A$#99!255??C$#100!218?C???@!8?G!23?oB$#101!140?_!12?@c???@AC???CG_$#102!48?@!12?@!79?_!12?G!7?@A!8?_$#103!255?!4?@G$#104!139?G?B@?o{{{}}{{{!7?@?CWo$#107!143?I???@!17?O$#108!56?A!170?C$#109!51?A!119?@!13?@A$#111!141?G$#114!255?!6?O$#116!226?O$#117!161?O!4?O$#121!140?O!21?_$#122!142?G$#123!143?C!17?G$#124!139?_??C?A@@!4?@$#125!221?A!8?O!25?O$#126!218?G!10?A??A!24?@$#127!20?_@!165?O!41?@$#128!172?G$#131!22?O!150?_$#132!217?_?_G!35?G!4?_$#133!52?C?C!7?A?@!108?@!44?OOC!10?C!25?A$#134!23?E!22?A!8?CC!116?O!10?@_$#136!161?A$#140!230?G?@!24?C$#141!23?_!24?C!11?CC!76?A!34?G$#143!49?A!137?G!38?G$#144!228?_!32?G$#145!136?_GC@!89?O$#146!53?AA$#147!21?W!164?W!39?_WB$#148!186?@$#149!50?A!7?A!126?A$#150!153?_$#153!185?C$#155!20?A!166?A$#157???F$#158!229?GC$#159!231?A!25?_@??C$#164!225?_?@$#167!221?GCA!30?_$#169!20?O$#171!45?@!14?A!111?C$#174!22?_@!29?C!175?_$#181!194?@!4?}!5~@!17?g!30?A$#182!218?_$#183!23?G!33?C$#185!63?@!198?C$#186!20?G$#189!214?_$#190!172?A!42?w~N!14?_@!9?O$#191??_!228?_$#193@!186?@_!36?O$#194!225?G!28?G$#195!223?C??@!16?@@!8?o$#197!141?C?O!17?D$#198!25?GC!22?_??_???___??_!74?A!37?B!4?sC}^Xw$#199!25?s!8?a!8?C?AGGO?__??G!4?GGG!72?OA!40?O!6?A$#202!255????o?_$#203!255?!5?C$#204!231?@!26?M?O$#205!255?!4?[A$#209?[!7?ow}~!6?O!212?OK{}}}~!4@!7?{roKC$#212!23?O!42?AAA@!62?A}NOGB@!36?_$#213!49?GG??_!119?A?BBB!4@??C$#215!221?@$#216!255?!6?A$#219!4?A?@@!11?E!170?E!4?@!10?@!7?A$#220!198?@!9?A$#222!4?wwW!11?G!176?_www!7?ww?wwowGW!30?G$#223!4?CFe}!6?!4~D@!169?^pH~~{[FFE!7?CF|!4FVDB!18?@!4?G[[[?w?{{{$#224!245?@@$#226y@F!223?A$#228?_$#229!254?O$#230!228?G!33?A$#231!140?G!11?A!9?A$#232!51?C$#233!26?w_$#234!41?AAA!5?S!13?A$#235!48?G!9?C!115?CGKGKIq?_C$#238!219?C-#0!136?ow}}~~{wooo_oooww{~NNFFNN~{!5?FN~~~o$#2!224?_GB$#3!143?C!23?A$#5!224?OSC$#6!173?A$#9!20?K$#10!255?!5?_C$#11!20?O!166?__!41?_$#12!186?@$#13!174?_!86?A$#14!19?G_!167?G!37?O!5?_$#15!136?C!10?G!11?O!4?_??C$#18!188?C$#19!186?A$#20!19?A$#24!18?_!214?G$#26!221?_$#30!246?__W_?O$#32!18?O!171?G!31?O$#33?O?~_!186?_!12?@@!15?O@!4?O??@??CO!9?K$#34!190?@$#35!189?CC!54?_?WC?__$#36!189?B!59?CC$#37!189?G!43?@$#38!219?Oo$#39?@!4?_?!5@p?_!177?w!7?C!20?C!14?@???__wA$#40!221?@$#41!214?A$#42!17?O!182?WwwwW!7?o|!5?KCK!14?C}z@@??@!6?@$#43!236?G$#44!18?K!202?A??@$#45!189?O!38?C??A$#46!152?A!10?@!4?_$#48!254?D$#49!218?C!34?wI$#50!144?C$#52!157?OO$#53!164?G$#55!21?C!152?G!42?G$#56!186?G!30?@$#57!255?!5?C$#63!22?@$#64!185?@$#65!26?K?C_!146?O!7?O$#67!22?S??@O??N?L~~?@P!4?o{@G_??!4@``ABAAABBA@!68?_?C!42?G{@?@!4?_$#68!22?_!5?@!7?m~~!4@!19?A@???@@!62?OPA!42?ABA{}{ww$#70!22?G!30?E!5C!70?@@!52?@$#71!137?@!28?A$#75!23?B?}_???~q!7?]}MAEF^~~!4}]W!5w!4{}~~~}}!60~]]NMG!47?AFE?O$#76!24?~!14?_!89?_!45?C!9?K$#77!133?_?@$#79!136?A!6?@?C???C!14?C??O$#81!255?!4?O$#85!255??WGf$#88!136?@$#94!151?A$#97!135?O!9?G!115?G$#98!231?_$#99!254?_$#100!215?OA!37?O@$#101!135?_G!5?A?G!5?G?CA!6?O??o!5?_$#102!142?@!20?G!9?K$#104!144?BBFFFBB@@!11?B~{_$#106!255?!5?G$#107!146?G?G!4?@!12?@$#108!187?P!37?_G$#109!19?_A!203?GA$#111!138?@$#113!134?O$#114!255?!4?_$#116!20?@!206?@$#117!137?C?@!7?O!7?O!6?A!4?@GO$#118!157?GG???@$#121!155?_!4?_$#122!149?G!13?C$#123!168?O$#124!137?A!13?C!4?O!6?A$#125!218?A!9?A$#126!216?S!38?C$#127!21?@!166?O!43?O$#128!255?!5?O$#129!156?_??_$#131!186?C$#132!255?A$#133!186?O!29?GE@$#134!21?O!152?A$#136!157?__$#139!228?@$#140!255?_A$#141!133?OG$#142!173?@!51?@$#143!230?O?G$#145!135?E$#147!187?M!43?O$#148!19?O!203?_$#149!231?G$#154!232?C$#155!188?A!40?G$#157!188?@!35?A??CO$#159!255??C???@$#163!223?O$#164!227?A$#165!233?o$#167!215?g`??@B!8?@!15?@!7?E$#168!229?_C$#169!19?C$#171!21?A$#172!226?_$#174!21?G!152?C!80?G$#181!201?@BB!10?W!19?_$#183!21?_A!5?G!5?Ao!7?_!130?@_$#184!134?_$#185!224?C!36?@$#186!174?O$#189?C??N@!10?@?@!172?@bCB!4~_??CCe}~~~^^GK?CC!4?G?A$#190!213?A@B?Oo$#191??_!187?O$#192!164?O$#193!189?_!38?_OG!17?_WW$#194F$#195!219?A!12?@!14?!5A~@$#197!143?A!23?G$#198!26?B_!6?@K!7?Oo!131?_!7?C$#199!23?o!5?O!13?G!12?@@@??@!72?C!40?BD??B?@??G$#202!255???B$#203!255???_$#204!255???CWK$#205!255??_O?B$#206!19?@!203?G???G?C$#208!245?GG!4?K$#209?_^!187?A!8?FFA!12?_!7?GC!7?@?AN~r!7?@UVD@??@$#212!23?K!4?A!6?A!94?_?_@!41?G??k!5?_$#213!184?BA$#215!255?O@$#219?G!191?@{!16?F$#220!191?A$#222?A!191?A!47?AA$#223!4?O]^~!5}M^^}nA!172?CC!6?W_!8?__oB!4?_G!4?B!14?C}}\\E!5?@$#224!229?A!14?o$#226w!4?_!8?_!207?_!4?_G?ACA$#227!190?_!28?_$#228!191?WW$#231!135?G!14?C$#232!186?_$#233!27?^o!5?{$#234!134?B!40?O??O$#235!54?@$#237!255?!5?A-#0!133?OC!20FC!4?CFFC!6?!4F$#1!138?O?_G$#2!134?@!39?_!48?A$#3!169?@O$#5!132?_!41?W!46?oGC@!4?_E$#6!133?C!40?A$#8!255?!4?_$#9!19?B!168?`!41?O$#10!255?!4?K@$#11!19?C!201?G?G$#12!229?G$#13!255????_$#14!187?@?O!34?C@??_$#15!169?C$#18!222?@$#21!227?E$#22!17?O!210?OA$#24!223?_$#30!246?@ECC$#31G!13?E!184?oO?OO!5?!5O!20?C$#32!233?G$#33?a!6?!4A?A!177?AAKB!21?GOAG!12?K!5?AA$#34!219?@$#35!4?BF!8?@!219?G!7?KG@bEWGI$#36!214?O$#38?O?G!10?wE[!177?!5wG??GG!5wGG!6?_?C!29?oO$#39!6?N!6?@!179?r!7?O!14?C!24?^OOG$#41!13?o$#42??_!6?ooowG!187?FFF!5?@@@BB??B@P!17?OPp$#44???_?__Oo!8?A!173?w!26?_$#45!132?G!57?G!36?o$#49!252?c@$#50!169?G$#51!255?!4?@$#55!19?_$#56!175?o!11?G$#57!255????G$#59!168?@O$#61!133?@$#65!27?@?@!12?@!5?G???p?C!76?G$#67!21?G?@??EE??CE?N!17?A!78?CF!44?EB!7?@$#68!36?G^^!9?C!5?AOW?QQAQo!67?_!45?o{!6~_$#69!129?_$#75!22?FE?F@???B@F!7?FF???F@@BFFD??@FFF!4D!67FE$#76!20?_C??N!14?N!9?o!79?@!55?_$#79!165?{??A_$#81!254?O@??C$#83!255?C??A$#84!255??_$#86!255??G$#89!255?o?G$#95!230?@$#97!255?!5?C$#98!222?S!7?G$#99!253?C$#100!252?WA$#101!156?C!6?@!6?G$#102!133?G$#103!255???C$#104!166?~~{$#105!159?A$#106!255????O$#107!164?B$#108!231?A$#109!18?o!155?@!45?_???A$#110!255?!4?O$#111!157?C??@???o$#112!158?C$#116!18?G!113?O!89?A$#117!134?A??_???O!13?A!7?A$#118!138?_gW!18?CA$#121!139?O!15?@$#123!170?_!89?A$#124!164?K!4?A$#126!253?_A$#127!18?C!203?_!7?_$#129!156?@??@$#131!20?A!166?C$#132!253?W@$#133!175?A!11?_$#135!22?G?ow!6_w_???__owG???w_??Gwg???G_wg!4Gg!65wG$#136!157?BB!6?B$#137!254?G$#141!23?G!108?B!53?G$#142!255?!4?A$#143!229?C$#144!255???_$#146!174?C!48?@$#147!188?]!40?O?@$#148!231?C$#149!19?G!169?_$#152!17?_$#154!189?A$#155!226?G$#156!156?A$#157!189?@!30?G???GM??@$#159!254?_A?O$#160!133?_wwwWG??_!22w!7?www$#163!223?O$#164!189?C$#165o!14?w!200?O!15?A$#167!251?kA$#168!228?A$#169!18?A!170?G$#171!19?O@!166?A$#174!20?C!110?_C!42?K!11?O!66?C$#179!18?@$#180!226?C!4?O$#181!200?!4_!5?!6_!10?_A!6?pQ!13?O$#183!28?CG!5?F!11?_!4?E!78?O$#185!220?OC!9?G$#186!133?A$#189???E!12?A!175?@?C!5F!4?!10C???E??B!29?_$#191??@?o??_$#193!227?GK@!17?@B$#194!190?A$#195!226?_!23?KQ@$#198!29?A!4?O_!6?A?N?C?o???G?G$#199!21?oo!23?AA!5?@!76?Q!45?@!8?M$#203!255??EB$#205!255??P$#206!17?G!201?_?A??_??@$#208!219?O!30?B@$#209?@?@COO!10?C!173?C!22?FF!4?C!12?E@FF!5?BFEC$#210!4?GG!208?GG!18?_wg!8?Ww__$#212!21?A!6?G?G???_?F!7?O?W!12?_O_!67?O@!53?^Ou$#216!255?G??@$#217!232?@$#219?K!189?@C!18?GGG???GCA$#223??K!4?F!4DFC?@@@!182?F???!5BAAA!25?ECDF$#224E!223?OO$#225!16?_!198?o_!14?_$#226@!189?s!35?@$#227!190?@!35?O!5?o!11?o!4?@$#228??QO???!5G!180?w!7?GG!16?G??@!15?gGww___$#232!20?G!154?@$#233!28?BC!4?NW!6?{~???[!5?}o!5?_$#234!20?O@!164?@$#236!23?o??WWOOOW?O??o!4?o??_!6?O???_!7?O!66?G!45?G-#0!131?OA$#1!135?C@???@G?_$#2!174?Z$#3!163?O!7?o$#4!135?OC?@!14?__$#5!130?_C!42?_!52?OC@$#7!135?_w}}}o_$#8!255????E$#9!189?C!28?g?C!7?O$#10!130?O!126?O@$#11!16?_CB!169?A@!29?A$#12!219?O$#13!16?O!240?G$#14!17?@C!169?G!29?C?GA$#16!219?@$#17!188?O$#18!16?G!209?OA$#20!190?O$#21!229?G$#22!130?G!86?G$#24!222?a$#30!223?_$#31!204?!5G?_???@!10?A!4?GxG?@?bw?w!4G$#32!15?_$#35!15?G@!206?O!19?_?FFEC$#37??w!12?C!208?_?@$#38gN!7?E??GGD@!177?W!5^!5?!5F!5?_B@!19?CC]C!4?wWo??P$#39!14?W!178?F!21?C!15?EC!14?GGE$#40!215?_$#42??F`!5?@BBFFA!176?O?_???__!51?@$#44!4?OTZY^!182?bW!55?o$#45!16?A?G!169?_???_!25?@!7?E$#46!170?A$#49!250?_N$#53!170?O$#54!251?O$#55!175?P$#56!18?O!110?_!122?O!4?A$#57!253?@??O$#59!170?_$#63!187?G$#65!21?@!34?G!129?_$#68!20?GW]JC!9?@!6?K!4?KKK??wAG??AwwC??F!63?_?Q!47?@FF!5~F$#76!20?@!28?F!78?_!56?~?_$#79!164?_$#81!253?G$#83!253?O$#84!254?A$#87!254?_$#89!254?SFB$#98!189?_!27?_OKB!6?_A$#100!251?_B$#101!163?K!7?E$#102!131?G@!38?G??C$#104!165?w!4~$#107!164?E!5?@$#108!17?W!203?@!5?G$#109!131?A!56?@A$#114!255???@$#115!255???_$#116!17?_!210?@$#117!133?_O!6?CO!10?GGO!7?A!7?@$#118!134?_GA???EO_!9?_OO_$#121!137?@?@G$#123!163?_!94?G$#124!164?@$#127!17?A!210?_C$#131!175?M$#132!252?K$#133!19?A!232?_A$#134!18?_!168?B$#135!19?O??_oz!9~}}~~oo^Ooo}~qoow~F{o??@FFw???!63~^~@$#136!165?F$#137!253?C$#141!21?_$#144!255??G$#147!189?W!38?GA$#149!188?C!28?O!8?_C$#153!190?_!39?@$#155!16?C!173?K!66?C$#156!164?G$#157!224?G_G$#159!254?@?C$#160!131?_{^NB!5?BN^!8~^FFN!7~@!8?~~$#163!219?_$#165F!219?Ow[BF$#167!250?Q$#170!216?_$#173!130?C!44?_$#174!19?@$#180!230?A$#181!199?!5~!5o~^~~~!11?D???o_?owu~W???oooO$#183!187?O$#186!131?@$#189?o!236?_!6?_$#190!249?_G$#191!4?NICD!242?C$#193!224?OO?@!28?_$#194!217?C$#195!14?_A!175?C!24?GA$#197!164?O!5?G$#198!19?G!23?A???@@!4?AOAO???O@o$#199!129?G!46?o!9?O$#202!255?_$#204!253?_GW$#206!190?A!27?A!4?C$#207!214?E!22?A!8?G$#209!15?O$#210!191?G!24?E@!29?@B$#212!20?q??C!11?@!7?C!4?A!5?_@???@_?G!113?M!9?N$#217!221?C$#218!222?@$#219!237?@$#221!232?A$#224!220?_??G!6?O???G$#225!214?WW!9?G!4?C??F$#226!190?@!25?O$#227!232?@!11?F$#228O??]!5_w{{oo!178?F?___!41?@B!4F???o?G$#231!170?C$#232!19?C!109?OA!56?C$#233!42?F@!9?@N{_???N}$#234!130?@$#236!19?_CE@!15?NN_bGG@?@A!4?@C??C??A!68?KF!47?ww!5?w-#0!130?{@!41?A$#1!151?@$#3!171?@$#4!145?A!5?A$#5!129?w!96?A$#6!129?C!43?O$#7!135?@@D?_!4?A!4?{{{}~~$#9!15?OH!197?g!12?@$#10!129?A!44?A!81?E$#11!213?O??@A!8?G$#12!215?O!11?A$#14!17?@!172?K!21?_???G?@!8?C$#15!131?GO!14?A!13?_G@!6?G$#18!129?@$#19!215?_$#20!213?G$#21!228?@$#22!225?@$#23!218?A$#24!218?C?H@$#25!212?C!31?O$#31!209?f?@B!7?C!7?QJBRO!4?FCF!4?_$#32!211?OG!14?OG$#33?{$#37??^!220?O$#38BA!207?O!11?_?C$#39w!213?@!6?A!5?_$#41???G!12?_$#42???B???!4_??I!180?__!14?WC!32?CFOG$#44!13?@!179?F!5P!48?OC$#45!191?{B!21?A$#48!249?C$#49!249?o@$#50!133?O!36?C$#52!136?C!11?O$#53!170?@$#54!250?O@$#55!128?_!45?G!13?C$#56!128?G!59?G!62?G$#61!254?_$#65!176?G!9?`$#68!20?F!32?BBAABB!65?{?AE!47?O?_b!5~[??G$#71!134?A!10?C!16?O$#75!19?!105_$#76!18?s!42?A!63?{OO@!46?G??[!6?B?B$#79!132?C!14?C!15?C!5?O$#81!251?_C$#84!253?G@$#89!253?QA$#95!174?@!49?_$#96!148?C$#97!131?CA!37?_$#98!189?~!23?_OGA@!7?WC$#100!250?M$#101!146?@!15?A!8?{$#102!130?BO!39?A_K$#104!132?GKKC!9?w{w!14?_w!5~N$#105!136?QAF!4?A$#107!134?O!35?O$#110!255??G@$#115!255?_$#116!224?OC$#117!134?_!10?@?@!8?K???_G@!9?W$#118!135?_!8?@???AAA!4?r$#120!133?A$#121!134?@!8?@!8?@??K!5?O$#123!162?C!93?O$#124!135?O$#125!250?_C$#127!16?O!173?O!24?A$#129!135?G!8?O$#131!128?O!59?b$#132!17?C!233?A$#133!128?C!46?@$#134!174?O$#135!19?^W[!31^!6[^^[[!61^BB@@$#136!144?_???_$#137!252?@$#140!252?A??A$#141!18?G??B!165?_$#142!255?O@$#143!190?A$#144!254?O$#145!255?@$#147!15?_E!198?CC!8?_@$#149!15?G!174?_$#152!214?C$#153!217?C!8?O$#154!216?O$#155!212?O??@$#156!135?AgG_O??@!5?G$#157!223?B$#159!252?G?G$#160!131?a``!14?@@@!5?r~~~^F!10?F@$#161!169?_$#165!216?_ow~q!8?O$#167!249?G$#168!248?_$#169!14?_C!174?@$#173!188?O!66?C$#174!17?G$#179!226?_$#180!227?G$#181!199?_!9p?@!19?GGG!11w?_$#183!18?@!109?A!46?C$#185!173?_!50?GA$#186!174?C$#189?@??!5F??__C!195?G!11?Gg!15?B!5?JOF$#190!248?W$#191!17?A!174?{w!5M!49?B$#193!224?C!30?G$#195!13?_@!176?@!51?F???_?B$#196!137?oWN~~}{K$#197!146?A!16?A!6?A$#198!17?_!37?@@!4?@A!113?A!9?G$#199!176?DK!7?oS$#202!252?O$#204!252?_`$#205!253?C$#206!14?G@!201?G!5?_$#209??_!188?A!21?C$#210!14?C!184?^!10?C??B!7?CCG!18?F???_$#212!18?A!108?g!48?oO!8?AS$#213!185?K$#215!251?O$#216!254?C$#218!14?OA$#219!221?OO$#221!211?G!16?CC$#222C$#223???o$#224!222?B!6?_o__$#225!200?!9M?aA!12?B???_?CC!5F???FF$#226!211?_$#228???CwwwWW!4^O!182?___!46?GGF$#229!14?A$#232!175?A$#233!17?O!44?@$#234!174?_$#236!126?k!48?_?B!6?b-#0!130?@ACO_$#1!136?A?GO$#2!130?A!39?CB$#3!157?_?C@!9?B$#4!150?_??C@$#5!224?@$#6!188?@$#7!149?|^^NB$#8!187?A!67?A$#9!189?_!19?OOA$#10!186?O$#11!14?_!175?E!17?_?C!14?@$#12!13?_!176?@!30?_G$#13!253?_$#14!187?G!21?G_@C$#15!143?_!15?G$#21!212?G$#22!13?C!154?_???A!15?O$#24!218?A$#26!206?A$#29!169?@$#30!221?G!11?G$#31!187?_!17?A@@!8?_!7?_??C@[!8?AM?G??WW$#32w!227?W$#33?_?_$#34!219?O$#36!221?C$#37E!8?o??A!179?}}!13?O!20?_$#38?@!219?B$#39@?A!8?C!215?@C$#41!222?@$#42!4?!6@D!183?~@!22?o!19?_$#43!10?G$#44!4?}}qEMM$#45!12?{!195?G$#49!248?GA$#50!168?C!16?G$#51!249?C$#52!138?AC??OO$#53!158?_$#55!15?O$#56!16?@!237?@$#57!249?O$#64!169?_$#65!171?O!11?GC$#66!182?_??@$#67!17?@$#68!127?@!42?_??k!7?GKC$#69!174?@$#71!161?@!4?OG$#75!19?!105~{}w{c!45?O$#76!16?O?`!106?@???_O!41?_OA@A??W_??Q$#77!185?C$#79!159?O!8?A$#81!250?G$#82!253?A$#83!250?O$#84!251?o$#89!251?GC$#95!129?@!55?_$#97!168?OG!84?_$#98!188?A@!32?_KA$#99!248?_$#100!249?@$#101!158?G$#102!131?CG$#104!144?^~~~!11?_o}~~~^NF@$#105!137?@?@GO$#106!184?_$#107!137?AC!21?A!5?_O$#108!15?A!207?A$#109!14?C!175?w!33?C$#110!254?O@$#111!142?_!26?C$#112!140?O$#113!186?A$#115!185?O!68?K$#116!132?O_$#117!140?_!12?OGA??C$#118!137?C???_!9?_OGC@$#120!165?_$#121!136?@!17?A$#123!167?_$#124!139?G!18?O!9?GA$#125!249?G$#126!250?@$#127!13?O@!209?G$#129!143?F!4?_$#131!129?A$#132!253?G$#134!15?_A!111?@???_!38?G$#136!144?_???^!11?G$#140!252?_$#141!17?M!110?A$#142!131?G!39?C!14?C$#143!223?@?A$#146!172?@!13?GC$#147!14?W@!173?]!19?_GCB@!8?OO$#148!14?A$#149!15?C!195?G!11?_$#152!13?G!208?C$#153!214?@!9?O$#154!208?O$#155!188?g!20?C!12?A!31?A$#156!138?@!10?A$#157!209?@@!14?C!8?}}$#159!251?@O$#160!131?@BN^~{wo_!12?__o{~^BB$#163!210?A$#164!186?_$#165!187?O!23?__{{~^F@?N!4?_@$#168!247?_F$#169!213?A$#170!221?O$#171!15?G$#172!214?A$#173!187?@$#174!173?@!76?A$#180!212?O$#181!199?!6B@??@!23?@??!12@$#183!16?G!112?C!53?_$#184!170?G$#185!130?C!57?C!64?O$#186!169?O$#189?]?]!7?@!183?}}~~!6?C?AA!10?C!18?K$#191!7?oo!4?@!178?@@!12?_$#193!13?A!195?A!10?_$#195!10?O$#196!139?AFNNG$#197!160?C$#199!130?_!53?H$#202!250?_EJ$#204!253?@$#206!191?}!15?_$#207!227?A$#208!10?_O$#209??@???KG!198?OG$#210!11?G!193?_??C!29?Oo_!6?@$#212!17?OY!105?B?CAWG!41?_??k}|~{F^VR@$#213!172?OA!11?A$#214!250?C??C$#217!211?O$#219!218?CG$#220!206?K!21?A$#223???@$#224!204?G!12?G?BO!5?I??bF^WB@?w$#225!199?!5{sW!11?o?_!5?Osw??w_es??E}??]u}}eeA$#226!191?@$#227!11?_!213?G!20?{]$#228??{!7?AA@!183?@!10?C!10?G$#230!248?O$#232!16?C!113?GO!38?O?C!11?O$#234!181?_??A?@$#236!16?__C!107?B??O?_!40?G!5?B_$#237!249?_-#0!135?@BC??O$#3!147?C!5?G$#5!180?_OGC!35?_OA$#6!183?A$#8!166?@!15?C!69?W$#9!13?A!176?[!16?GA!11?C?A$#10!181?G!69?_C$#11!12?G@!175?o!16?_!12?O$#12!209?@$#13!183?G?@$#14!11?_C?@!192?OC!11?A?C$#15!144?@!10?CA!5?C$#16!218?_G$#17!89?_$#18!251?O$#19!13?O$#21!208?GC$#22!188?@!17?A$#24!213?A!9?_$#27!204?C!11?G$#30!4?_!181?@!52?O!4_$#32??~!184?O!4?^!10?_GA!8?GCO_K!4?C!20?O$#33???E!178?_???on!11?wCF@@!7?OO??@EA!6?}?_??A@???_?@???AAA$#35!184?__!14?_!17?@!26?@$#36!245?C$#37!192?__!50?G$#38__?w^!179?O[A!8?NNN???GmE@!8?G!13?!7_$#39?P!199?O!9?__!10?G$#42!8?B!185?_!18?O??_$#43!5?O??_AE$#44!7?_!190?O$#45!10?_F!234?@$#46!154?G!8?A$#48!245?I$#49!14?A!230?_C$#50!183?@$#53!153?O$#54!89?O!156?OE$#55!90?g$#56!247?O$#57!252?@$#61!180?G$#64!138?_!39?_$#65!167?K!8?_O???@$#66!166?O!12?A$#67!15?_@B!101?__!9?@?A?Co_!25?_!7?@!7?@?C$#68!14?_?qoo!68?_???_!41?G!27?_??o???o!6?G?_$#69!18?A$#71!161?C$#75!15?O?C?!67~^^FBBFff!25~^^!8~}}y{s_!30?_???{!4}]$#76!18?C!70?CC!44?G!29?W_oG@!6?WGOG$#79!147?A!4?_$#81!249?@$#85!248?_$#87!249?OB$#88!160?O$#94!158?_OG$#95!135?A!4?_$#97!252?_$#98!206?OC@!11?gC@$#100!246?G@$#101!141?_??AC???_?O???A@$#102!138?GO$#103!250?C$#104!145?@B@!5?_oww}^NFB@$#105!148?@!8?@$#106!162?G$#107!152?O$#108!13?C!120?@!49?A!36?H$#109!136?C!52?Nb$#110!163?C!89?B$#111!148?A$#113!181?C$#114!250?_$#115!180?O$#116!221?O$#117!142?@!5?_???G$#118!143?@!6?@???C$#119!161?G$#121!149?@$#123!164?A!88?C$#124!146?C???_!14?@$#126!14?C!233?A$#127!182?O!24?@$#128!137?G$#131!13?_!153?@!79?G$#132!246?_?@$#133!248?C$#134!14?G!73?_G!43?@A?G!28?C!13?O$#136!156?C!5?A@$#140!251?C$#141!15?M!72?G???WW!38?@A!26?_O!5?A!13?A$#142!165?A$#146!184?@$#147!12?o!192?_GA$#148!181?_$#149!13?G!191?OC$#152!138?O$#153!209?A!11?_$#154!205?G$#155!185?A!5?^!28?@!31?A$#157!191?_!27?C!18?_?!4O$#158!159?_$#159!248?OAOA$#160!137?BFNN^}}{www[]]NFFB@$#163!223?@$#164!204?_$#165!186?K!21?OW^NF@@!7?O!6?@$#166!183?O!24?_$#167!10?O!234?O$#168!246?A$#169!184?C$#172!218?O???GA$#173!163?G??A!15?A!68?G$#174!135?C$#179!207?_$#181!199?FZ!13?Sw?XA@!4?@~\\Y[]!4^~}]]E@@@F@$#183!91?W!45?O!26?G$#184!179?_$#186!12?A$#187!11?O$#189!194?^$#190!5?M??O[@$#191!6?^^$#192!151?_!12?@$#193!12?@!151?C!41?@$#195!10?G!233?C$#197!145?A$#198!14?O!151?G!13?A$#203!249?C?@$#204!250?G$#205!249?g$#206!139?_!48?m!20?__$#209\M$#210!5?_???@!183?^!11?@!9?A@!20?@@@!4?A$#212!16?KGG!67?_!42?@?D!5?_!28?C?AA?@@@`VFFM$#213!18?@!144?o!15?@$#217!90?O$#219???@!180?G!19?A!8?C!8?_$#220!223?O$#221!188?O$#222!9?_!185?Ooo_??_O$#224!212?G?a??C!8?AAD!8?_?_CKC$#225!219?A!19?GG?GG$#226!11?G!192?OC$#227!244?_$#228A!4?@_?K!174?_!11?_??N!4?W!9?_$#234!15?@!72?O!45?O!27?O!5?@!6?_???C@?@$#235!134?G!33?C$#236!136?O$#238!247?_$#239!248?G-#2!144?@!74?@$#3!143?@$#5!10?_!164?_OG?@!36?_oMA$#6!177?CA$#8!251?@$#9!10?OA@!176?{!12?O??A$#10!250?G$#11!189?@M!12?cG!13?OC$#12!10?G!179?O$#13!176?_!40?C!31?_C$#14!10?C?A!165?G!23?G??C@$#18!216?GA$#21!205?G$#22!10?A$#25A$#30!178?_!59?@?DD@$#31!178?O??C!4?O!27?@$#32??N!177?KA!4?@`!13?GB!4?__?BKG??G!5?A!14?@A?C??C$#33?C!4?_!175?w@??MO!11?A!12?CC!10?A!9?@$#34!220?G$#35!184?FN_G!12?@A!21?B$#37!7?GO!183?oN!7?C!6?Oo{ooo??A$#38Lb?xU!178?OWo!13?s!12?A??D!6?OO?O^!8?A$#39??O!180?_!35?O!12?_$#41!200?G!41?O$#42!193?_N@!23?_oo!6?K!7?wo??WgG$#43!235?_$#44!7?C!190?_!30?w{{[{o$#45!8?k?@_!180?N!7?_!15?C$#47!244?A$#49!243?oD$#54!244?W$#55!88?A$#56!13?@$#61!174?O!74?G$#62!90?@$#63!141?A$#65!88?CC!29?E!8?g!12?C!13?G!18?A$#67!16?B!104?Y!4?_C!4?_Oo?PA?CA??!11O?OOOWCE@XC!8?G?@$#68!86?KKG!32?_??ooQ?C??o!6?A?O?W!10?GO!4?A?EE$#75!14?~~{!69~ooow{!28~??D~~NNLBB~~N^NN~m{c!21_oo__f~~~n!4FB$#76!13?K!76?A!28?@@!16?@@@G!5?G!4?G!4?C!6?@!5?_gG?GG?@$#77!175?CA$#79!147?A??@$#81!247?@?C$#82!145?C$#83!247?AOA$#87!249?@$#88!148?C!5?A?@$#91!147?C$#94!148?!6A?@$#95!178?C$#97!142?@!108?C$#98!202?_WE@$#100!244?_E$#102!145?@@$#104!151?!4@$#106!178?@!70?O$#107!148?@$#109!189?A@$#110!176?G!73?OA$#113!143?A!31?G$#115!175?O$#116!216?O$#119!144?AAA$#122!147?@$#123!250?_$#125!177?A!68?@$#126!12?C!76?A!155?O$#127!177?O$#128!141?@$#131!88?@$#132!245?G!4?@$#133!140?@?A!102?_$#140!246?G$#141!12?O!73?B!56?C!4?GG!4?CC?AA@@!9?O??O$#143!201?_$#144!248?_$#145!144?C!7?CC??A?@$#147!11?C!167?A!37?G$#148!180?@!23?@!13?@$#149!11?H!178?_!29?@$#152!203?A$#153!204?O$#154!188?W$#155!9?O!171?@!19?O$#157!179?OO!10?B!10?C@!35?BAA$#158!146?C??CCC???A?@$#159!246?O$#163!219?G$#164!9?_$#165!182?A!22?o[NF!5?OO$#167!243?G$#170!179?C!35?_!4?A$#171!11?O$#172!188?C!15?_$#173!176?C$#174!246?A$#179!188?_!17?A$#180!220?C$#181!4?H!174?G???A!15?@!22?K?LN!9?@?@A$#183!120?C!6?G!45?_???@$#184!174?_$#185!250?A$#186!180?A$#189!194?o!5?C!37?o$#190!6?BB@!233?_$#191!8?A$#193!9?K!169?__!28?G!4?_??@!24?A$#194!9?A!233?F$#195!7?o$#197!149?@$#198!119?wA!7?O!4?_!5?GC??G!12?GG!5?G!7?_O$#202!247?K$#203!246?_$#204!247?oN$#206!188?B!17?_??@?A$#207!211?@$#210!5?oO??@!177?E!5?O!6?O!12?G??@!6?K!12?EKKG$#212!12?_o!73?B!53?WC!4?G!4?G?G??CC??G?A$#213!144?G!30?@$#215!246?C$#217!89?@$#218!218?_$#219?W!180?DC!17?@!12?I!7?A?O!9?A$#220!234?K$#222???E_!178?G!11?{}~NGA!12?A?A!6?@!4_}O!5B?C???_$#223!5?MC$#224o!176?_???w$#225!221?K$#226!191?{!15?OGE!11?@$#228??_??@G!177?_!10?A@?O!13?@@C!7?_!4?@bC!5?W???O_O$#230!245?@$#232!12?GA$#233!120?w!6?o$#234!139?A!10?G!9?G!11?_$#235!145?G!23?O?O??CA$#236!138?WO!19?W???OW???OG???C-#2!9?GM!205?@$#5!10?@_!158?_GCA@!24?O!14?oE$#8!169?_!78?WA$#9!200?CC!11?_?O$#10!247?_C@$#14!9?@!161?_!16?K?G!9?A!13?C_$#17!217?A$#18!11?G!187?C$#21!175?A!26?GG!12?O$#22!197?_!16?A$#23!204?A$#24!194?O!9?[I$#26!183?E!9?W$#30!173?oGG??GAB!18?@$#31!184?w!54?G$#32!179?o{!6?A!21?_$#33???W??@!174?`_???_@!17?_$#34!185?oO!24?O!27?O$#35!181?A!4?BC!8?_!9?@$#36!210?__!27?_$#37!7?S!179?G!4?F!4?GC!10?@@!5?_?C$#38?B?FG!177?@??NG!18?O!4?GG$#39??W_OG!175?KYw!9?C!12?A??O?@$#42!192?GB!14?oEE!7?IFpS[C!12?FF??E$#43!7?G!204?@!11?K???@@!5?NGGW$#44!6?_!191?B!8?D@???G@!9?_QQQA?__`@@$#45!187?O???C!5?O!10?A!14?W?KK[]]^]}}~ooo_??G$#48!240?_$#49!241?oM$#54!243?C$#55!11?B$#57!248?@$#61!246?_$#65!119?O!5?OBGB!5?@!30?oO?G$#67!127?_!8?__!26?W???C$#68!12?F??!4w!102?N??NF??K??NC!33?C$#75!14?!5F!100~??o~~o???oF~og??~^^^!25~FFBFB$#76!13?f!105?__!4?G?O!4?B!5?_!26?G?W?FA$#77!170?C$#81!245?@?C$#83!246?OA$#92!246?D$#95!8?_C!204?G$#97!248?_$#98!189?}!9?_GA!13?GA$#100!242?oB$#102!9?oo$#106!170?G??@!73?O$#109!11?O!160?GCA!23?_??@!15?@$#113!168?_!78?G$#116!8?O!206?@C$#123!249?C$#126!243?OA$#127!188?O?F!9?_G!11?O$#128!8?G$#131!11?C_!156?O$#132!243?G@$#138!14?G!114?w$#140!244?G$#141!14?O!117?O!34?_O$#146!170?OO$#147!189?@!10?O?@$#148!9?A!165?@!23?G$#149!188?_!13?A$#152!198?O$#153!188?A!14?@$#155!7?_!204?_!35?A$#157!176?KA@$#159!244?OA$#163!188?@?_$#164!174?C!27?C$#165o!174?C!18?_!7?oS@$#166!172?_$#168!212?O$#169!172?O!17?O!25?G$#172!201?_???@$#174!243?_C$#180!173?G$#181I!5?A!170?@$#183!133?@!35?G??@$#184!171?CA$#186!213?G$#187!8?C!192?O$#189!217?W!20?F$#190!220?E!20?F@$#191!4?_o!201?AC$#193!8?A!165?ooo{o@!18?GA@!13?@$#194!8?@$#195!7?B!183?w!48?O$#198!119?NO!4?_!7?wE!31?_$#202!244?_$#203!245?CA$#204!245?oG@$#206!176?@!26?A$#207!194?G!31?@$#210!5?F!175?O!58?G$#212!12?G!151?_?G$#213!13?O$#216!245?G$#219?{!4?W!188?_@!7?_C!11?C@$#220!193?_?WG$#222!4?F!189?FFEF!8?ww??O?A!4?__wG?_@!15?F$#224@!175?A!26?_$#225C!5?C!171?EK!6?C$#226!187?_???B$#228??f!179?C@F!7?o???O!9?C?GG?ECE!4?O??jBA``_`_!11?@$#232!12?O!158?A$#233!120?N!5?{F!5?Ew$#234!14?_!156?@$#235!13?G!156?@-#2!8?E?B?A!154?C$#5!7?oHAC!154?OG??@!25?_$#6!245?_$#8!9?C?@!155?A!78?CA$#9!10?_!177?[A!5?O?A?@!10?_???@$#10!9?G!158?@!76?OG@$#11!188?@!23?A$#12!188?_G!8?C$#13!9?o!157?G!78?A$#14!15?_!149?_O?C!20?O!7?@!16?A$#18!6?O@!157?G$#19!213?G$#21!199?C@$#22!14?C!175?@$#24!201?GA$#26??BSP$#30!166?_?_?C?@DEC?AA$#31!202?C!26?CC$#32!6?@!172?BB!11?_$#33!181?D@?OCC!4?C!8?O!13?C???@@!9C??C$#34!184?ABB!31?A$#35??[!171?www!13?_!4?A!18?GOG??O$#36!181?A!27?A!6?FCCC$#37!5?O!184?O?OG??@!16?O!25?B$#38~z??_!204?C$#39!4?KC!173?CC?Eb!17?O?C!4?_$#42!183?C??W!5?G!9?OGK???WG???_!21?{[{K$#44!5?A!197?A!6?A!12?B!5?!4BRFBB??C$#45!12?CG!179?o!15?O?@!25?BBG$#49!239?_C$#54!241?C$#55!11?C?P?O$#56!11?G$#57!241?O$#61!163?_??A$#65!17?OW!114?A?k?C!7?O!15?O?C$#67!17?_C!105?DC!19?CC!13?WG?A$#68!15?AABB!107?C!9?C$#69!159?O$#75!19?!105~www~~{~NFw??B??B^NN~~JJnN~^^~^!4~n!4B@$#76!124?A?A!6?C?B???C!19?_C???@$#77!165?A@$#81!242?GA?A$#83!244?G$#85!244?B$#87!242?_$#88!165?C$#89!243?_$#91!162?_OG$#95!13?A$#97!168?A$#98!7?G??W!185?WCB!12?oK@$#100!240?WB@$#102!9?@$#106!11?A!234?@$#108!8?O???@?O!149?_$#109!7?C!180?AC!6?_!14?G$#110!166?C$#114!245?C$#116!13?CG$#123!246?O$#126!242?A$#127!7?A!189?O!12?O?OC$#128!169?A$#132!240?_G$#134!13?_$#138!129?B!28?O$#140!244?O$#141!136?w???_!20?_O$#143!14?_!196?C$#145!163?GC$#147!189?@!7?G!15?A$#148!8?_!161?@!23?_?C$#153!198?G$#154!187?G!8?A$#155!6?G!183?A???O!14?_G!4?@!29?G$#157!6?C!162?C?F!15?@??C!4?C$#159!242?O$#165!194?D@??ooEF@$#166!194?A$#168!210?C!28?OB$#169!199?A!12?@$#172!187?C$#173!167?@!76?_$#174!11?o??A$#178!241?_$#180!170?A$#181!167?_!16?`!17?G!6?@!5?Gooo_!11w$#183!125?A!8?O$#184!164?O$#185!6?_!188?G$#189???_!180?KG!19?G?G!24?___$#190!236?_?o$#191!5?@!227?K$#193!168?Gwww}w@BB@@!15?G$#194!5?_$#195!191?B!18?@!7?G$#198!125?@@!6?@_O?B?w!6?_$#202!243?C?@$#204!243?WC$#206!187?A!23?A$#209??_??G!171?ww!12?o!22?o_?G?G$#212!15?@LK_!112?o_!4?g!8?O!12?C$#213!161?C??A$#215!242?C$#217!187?o!9?_$#218!189?_!22?_$#219?C!202?`pw_!11?A$#220???HA!188?B$#221!203?@$#222!181?G???o_!4?G!8?_!4?EFFC!8?B??BBB?!5B??w$#223???A!199?_!28?K$#224!6?A!192?GG$#225!173?A$#226!167?OO!7?CCC!11?G!24?E$#228!179?wwowW!8?FC!7?__OQ??OB!23?O?W$#232!12?G??G_$#233!12?o!121?N???~!6?_$#234!14?@?O!145?G??@$#235!15?C!144?_?C$#236!132?W!4?O???oo!4?Oo?__?_!5?G$#238!243?@-#2!208?_G$#5!6?_@!183?_!16?OC@$#8!244?G@$#9!7?C!184?_$#10!243?O$#11!5?O???w@!4?@!171?_???O!19?@$#12!10?A!182?O$#13!9?@!180?_$#14!159?O??A!44?o$#16!188?_$#17!10?G!4?A!172?@$#18!8?A!151?G!82?G$#22!5?A!157?@$#24!160?__!34?O@?@!6?G?@!25?A$#26???G!197?@@@$#30!164?M@?@@_?IQG$#32??C!183?O!5?@!14?C$#33!174?W!9?o!13?G!5?OO?A??_GK!21?{W$#35??A!166?Aa???B@@!9?G???D!23?C?KCC$#36!4?C$#37??G?G!186?A!24?o!19?A$#38@@?E@!193?O!6?EE!4?_$#39!176?o!6?@??C??C$#42!176?CCC@!22?__!9?@!6?{O!13?@$#44!189?A$#45??o?O!210?_!21?A$#49!237?OA$#51!242?_$#54!238?[A$#55!14?@?@$#56!17?_G!224?C$#57!240?A$#61!161?A@$#63!13?FC?_$#65!17?@!127?O???W?H!4?C$#66!157?CA$#67!19?A?o?A!131?E?A$#68!18?A?G?GWo!119?G!4?E??MMKG$#70!19?C!136?@$#75!19?@FFFDN!109~}~w~ww}~~~f??B}@??po@@?@@$#77!158?CAC$#81!240?G$#82!160?A$#83!241?_G@$#89!242?C$#92!241?O$#95!209?A$#97!245?A$#98!6?[A!184?OKB!15?A$#100!237?_?@$#103!240?_$#108!6?A!201?G$#109!193?AC!15?C$#110!243?_C$#116!9?C!8?_$#125!206?_$#126!239?G@$#127!5?G@???C!181?C??A!13?@G??_o$#128!17?G$#131!16?GC$#132!238?_C$#133!11?@!227?O$#134!11?M??A?OA$#140!239?_$#141!19?G???_!112?@???@!19?@$#142!8?@!235?A$#143!17?OO!141?OG$#144!242?OA$#145!156?_o?G$#147!5?_!186?G??@!13?O$#148!7?G?A!151?C$#149!16?E!192?_$#152!191?G?@$#153!159?_!27?O!8?@$#154!163?A!31?C!12?A$#155!7?_c!177?_???O?A$#157!5?@!157?_!6?WOG!16?O!23?G$#158!158?WC?@$#159!241?@$#163!214?G$#164!213?O$#165!4?A!189?_oK[_!6?_$#166!196?_?@$#167!237?G$#169!162?C!31?G!13?C??A$#171!10?O$#172!187?@!7?G?A$#173!15?C$#180!164?@!29?O?A$#181!162?_G!20?@@!18?_!8?AACBBB!12@!4?A$#182!14?_$#183!138?@!6?CA$#185!5?C?O!150?_$#186!188?O$#189???@!182?@A!11?ox[]]G!7?A!7?AGwCE!7}~~@$#190!236?@@@$#191oo!8?_!8?_$#193!8?W!155?o}~}}\DDDF!15?_GC$#195!173?O!62?cC$#198!138?AB!5?G@??_@E$#199!156?A$#200!240?C$#203!240?OMB$#206!4?_!156?OG!24?GG@!8?A!16?W$#209?G@!160?C!7?_??c}G@@!5?M}!4?A!22?C@@?ww!16?cW$#212!18?D?O!125?_o???O??Q?G$#217!193?_!16?O$#218!207?G$#219!183?A!13?_?MEA??!4@!11?A?EEww$#220G??O$#221!198?C!12?Cp$#222?E!174?AA???{I!8?@!13?G!5?O!7?s!11?@$#223???_!169?_!14?A$#224!162?O$#225!163?O!25?G!25?A$#228E!171?_!4?wy}~Bt{??ACC!12?_??E!14?G?_?A$#229!206?O$#230!244?@$#232!11?OM??G???O$#233!11?_pwWo!129?B[???}$#234!20?_!134?_OG?@$#235!134?@$#236!21?Go!113?E?CC!4?O_?K@??_?@_O-#2!187?oO$#5!4?_@!148?_!31?_?GKA!16?A$#8!10?o!230?W?@$#9!4?G!152?A!8?G!20?@??C!15?_!6?C$#10!9?oG!178?A!52?A$#11!5?_???A!10?CG!185?GA!4?@$#12!4?C!186?A!13?_!6?C$#13!10?C!177?C!53?@$#14!6?G?_!13?O!133?C?@!7?O!19?A???G?@!14?O!4?A?@$#17!19?A$#18!6?O!182?@$#19!21?C$#21!8?@!181?_?A$#22!211?G$#24!157?O!34?__K@B!12?a$#26!195?O??@!18?[$#32!159?_!37?_$#33!160?KK!7?W!4?___!7?A!10?A?KKCD??C!5?C!5?C!13?_$#34!208?O$#35!162?BFA!4?@!28?O?GC?B!11?g_!17?B$#36!208?GG$#37???A???_!154?_!4?O@!29?_???O!7?o???_@!18?W$#38!185?@!24?BB$#39!171?[!6?_!17?_$#42!161?_!9?@@@!25?_!30?NN?b$#44?@!158?_!7?O$#45??x!165?K!31?___$#48!203?O!30?_$#49!235?_F$#51!204?G$#55!156?A$#56!19?C??G!182?O@!34?A$#61!155?C$#63!11?A?_???EC$#65!25?_$#66!149?C_$#67!23?@???_!122?WCC$#68!23?AW?o!120?__???AA$#70!72?_!4?_!73?A$#75!24?BZJ^^!43~^^~!4^!65~^^~^^$#76!78?_$#77!154?A@$#81!239?_$#89!239?C$#91!152?_?CA$#97!154?O$#98!4?OM!159?oC!23?@@!14?GC@???o$#100!236?WB$#108!164?_!23?_!17?C@$#109!6?A??L!145?O!30?G!26?G$#110!242?C$#113!154?G!85?G$#116!19?@$#123!241?_$#125!203?_$#126!237?G@$#127!6?C!179?C!26?O$#128!11?_!228?_$#130!153?O$#131!11?O!8?G!184?A$#132!236?_C$#133!237?O$#134!11?C_!5?A!4?O$#138!21?@!122?__???W??G$#141!22?AK!51?__!75?@C$#143!4?A!16?O$#144!204?_!32?_???@$#145!151?_OG??@$#146!6?@!179?OG$#147!5?O!149?G!9?G!21?E!18?O!5?GA$#148!189?O$#149!20?A?_!141?OC!45?_$#152!167?C$#153!155?_!30?@$#154???G!153?CA$#155!165?A_!23?O!15?A_!32?O$#157!158?[!4?_??@@!17?K!18?C$#159!238?K@C$#163!164?G$#164???O!4?E!180?_?C$#165!156?o??E!24?_!6?_[LB!9?A$#166!158?_O!39?@$#167!163?O!71?C$#168!10?@!157?A!66?W$#169!156?G!54?O?_$#170!166?A$#171!23?_$#172!212?@$#173!11?G$#174!20?@a!182?OC$#180!191?W?A$#181!162?K!7?C!14?A!11?O?I?@?G!5?O!20?_$#182!13?C$#183!22?C$#184!153?_!87?C$#185???_!4?W!148?@!27?_??B$#186!185?O$#189!183?G!11?g!14?C!7?__zz!7~G?O~G$#191n?E@!207?C$#193!7?^$#194!214?O$#195!163?G!5?A@!30?O!33?B$#198!150?B???@$#199!151?G$#202!238?O$#204!238?_WB$#206???C??_???A!146?_!6?C??G!25?O!20?C$#208!167?_$#209!160?OOO!7?YA!28?AIN!7?G!4?A??B!15?C$#210!168?_!8?_!21?OO!7?_!6?O$#212!22?@!128?@?@$#213!28?_!44?_!75?_$#215!238?A$#216!239?A$#217!208?C@!4?A$#218!4?@!162?A$#219!183?_W!9?o??BA!5?@!14?CCC!7?O$#220?w!16?@!160?_$#221!159?G!9?C$#222!174?OOO!4?K[OC!10?C[!20?_[Z!11?_$#223OE!178?___!33?A$#224!157?G?@BB!22?@!20?@$#225!164?@@$#226!214?G$#228!169?___}}NNN!4^RBF!32?\B!11?FO??S$#232!12?OH??A@??O$#233!11?@NQ~~|www_???_!124?B$#235!151?O$#236!24?CCC!123?C$#237!205?G-#2!11?BO!140?@$#5???_B???_!143?C?C!31?@$#6!12?G$#8!9?w???_!139?A$#9!162?_?C!38?O!7?P$#10!12?C!139?A!85?_G$#11!25?G?_!46?G!75?_!12?_?@!44?G_A$#12!8?A$#13??O??@!147?G$#14!73?G!81?E!29?B?A!15?G!6?C$#15!10?A$#16!5?A$#17!152?_$#18!161?_!51?@$#21!189?@$#22!7?G!18?G!135?C$#23!209?O$#24_D!165?G!6?O?oooO!6?G??CE@!21?O??oo?o!6?o$#25!174?__!13?G$#26!157?osCK!16?CCFNFEoOo!6?KC!22?GG}!5?oo?ooO$#27!166?G!24?A@!16?A!5?A!13?N?B$#30!209?C$#31?_!177?_$#32!155?_!9?o!31?@!7?_??G!4?G$#33!160?O!52?_!17?K$#35!167?C!31?@!6?o!7?A$#36!200?G$#37!7?@!149?@!8?C!35?@!4?@!5?C@$#38!200?O!7?B$#39!156?A??_!14?!5@!17?N!17?C?@$#42!161?@!6?A!64?@$#44!158?@?@A$#45!6?@!18?O!126?G!9?A??GA!31?OG@$#48!201?C$#49!234?A$#50!10?CO$#54!235?A$#55!24?@!49?O!77?O$#56!12?@G!10?G???_!46?G$#57!203?C!35?@$#61!237?_$#62!21?G$#63!17?O?G??CG_$#65!26?@!47?A!70?O$#66!28?G!46?A!71?GC@$#67!27?A??_o!113?_$#68!28?A!43?O!71?{KG@@$#70!69?CAA!4?@?@$#75!29?!5N!35~rpp@?__oro!65~AA@A$#76!27?C?_??OO!37?K?@@@CK!68?_$#77!147?O??@$#81!201?_G!35?C$#82!149?C$#83!238?A$#84!236?O$#87!237?A$#88!148?oWC@$#89!237?C$#91!147?_??AA$#95!8?OC!144?G$#97!240?C$#98???WC!158?WB!38?_GB!4?_C$#99!202?A$#100!201?G!31?oK@$#106!149?_$#107!11?G$#108!9?A!16?O$#109???CO???G@!194?OC$#110!10?@!229?B$#113!152?@!51?@$#115!12?_!226?C$#116??_!5?C!145?A$#123!11?C!227?O$#125!235?C$#127???@_!19?AC_!123?O???O!49?_?@!5?C$#130!150?G$#131!22?@!4?O!45?C$#132!200?_!33?o$#133!202?C@$#134!13?C_!8?C!49?O?O!75?_$#138!144?@@???A$#141!29?O!42?A???G?M$#142!151?C$#143!165?A$#144!236?C$#145!148?G!88?O$#147!4?G!146?G?o!9?C!22?A@!16?C!5?OI@$#148???A!150?@!7?O$#149!8?@!14?@!139?AG$#150!10?O$#151!10?_$#152!24?C!163?@$#153??G!161?O!20?C!20?A??_$#154!155?G$#155??C??G?C!157?C!46?OA!25?A$#157??A!152?@!49?O!4?@?_$#159!235?_G@$#161!11?_$#163!151?O!11?@$#164!154?_!55?A?G$#165OW!173?O!8?B??CEA@!15?C$#166!187?GG$#167!201?A!32?@$#168!198?_??@$#169!162?G!23?C$#170!205?G$#171!23?A!50?C$#173!238?G$#174!25?a!46?G??C!125?O!33?G@$#181!230?N$#183!14?O!12?GO$#184!13?O!139?C!84?O$#185!204?A$#186!7?o!4?A$#189!169?C!24?CF!10?G}s!9?@@@B!7F$#190!232?oM$#191B!5?E!150?M?@?K@!33?O{N$#193!166?@!32?U??_$#194!199?_A$#195!160?_$#199!27?@!118?O$#204!236?_G@$#206!5?O!158?_?Oo!41?G$#208!167?@$#209!155?O!39?O_A$#210!167?A@!46?@$#212!28?C!4?_!39?A!72?CC$#213!26?A!43?K!5?A$#214!202?O$#218!5?C$#219?A!156?GG!8?G!5wKKKGGGowwNkG!4?GKAAB!19?osEE?M{k_!6?_?O$#220G!5?o!149?w?AA!26?oOOO???_O$#221!5?_!160?_?o!25?__$#222!156?@!13?!4C!19?@GG!13?@!4?GG?@??AOWw!5G?o_$#223C!181?@!4?___oooW$#226??@!4?A!153?O$#228!6?G!149?C??OA!7?C!5B!5A!53?N$#229!200?C$#231!10?G$#232!21?@A?O?C!45?C$#233!13?BN~~n~v~uwo$#234!25?@$#236!28?@?O?_!36?G??__!72?A?A$#237!203?A$#238!236?A$#239!235?O-#2!14?C$#5??K@!145?ooo$#6!13?@!222?_$#8!14?AO!132?C!88?C@$#9??@!148?G!9?O!39?_G@!6?C$#10!15?G!131?GWA!86?O$#11?_!160?C!39?@!7?G$#12!200?_!8?AO$#13!147?_!4?O!83?G$#14???_???w!21?A?_!130?G@!44?_@$#15!13?C$#16?G!5?A!22?O!121?_!55?O$#18!4?A!155?C!47?G$#22_???C!146?C!7?O$#24!163?CCA!50?@@?@@@$#25!5?@F!147?_!37?O!18?O$#27@!161?_?A!14?F!27?A!4?CF$#29!9?A$#32!155?F!37?G!9?O$#35!204?Y?B$#36!204?C$#37!158?_?@???@!28?O_!10?O$#38!195?W!10?w$#39!155?O!36?G$#44!155?GwgG!28?EE]EE?C$#45!230?CA$#46!12?@$#49!196?OCA!32?WA$#50!9?K!4?O$#51!201?C$#54!197?GC!33?G$#55!14?@$#56!15?A!11?AC!204?C$#57!235?_$#58!10?@$#60!10?{yco$#61!16?O!184?A$#63!18?_$#64!15?@$#66!145?@$#67!31?@?GGG?_!102?wW$#68!32?@DS?_?G!104?A$#69!139?W$#75!34?BV^^v!100~!4F@$#76!30?@!108?_??GC$#77!142?_GC!5?C$#81!198?O??@!32?AOA$#82!235?G$#83!234?C@$#85!233?_O$#87!199?O!34?_$#88!143?_OCIA$#91!144?G$#94!144?_WC@$#95!8?W!139?_$#97!237?G$#98??qA!143?O!12?_GB!38?OC!6?oB$#100!196?_??@!31?_C@$#106!16?_!132?C!87?@$#108!8?_!143?E!7?OA$#109???G!142?_!6?@!47?G!7?C$#110!13?AG_$#115!9?@$#116!27?@!124?G$#119!148?@$#125!197?O??O!35?C$#126!199?A!32?O$#127!28?@?C!122?A!7?`!40?OA!6?_@$#128?O!158?G$#130!145?_$#131!33?_$#132!233?A$#133!29?P_!166?_$#134!16?G!13?AC!118?A$#138!34?_$#140!199?_$#141!31?A???_$#142!237?A$#143!7?C!203?A$#144!200?G$#145!143?O?A@$#146!8?F!140?@$#147???C!26?GO_!128?C!40?A!6?G$#148!29?C$#149???O!24?A!123?@$#150!12?A$#152!7?@$#153!203?C$#154?A!161?A!39?G!4?C$#157!4?w!149?@$#159!200?A!32?O$#161!11?@$#162!10?ACW$#165!6?w!157?O$#166C!162?_!27?o_!18?_$#167!195?_?B$#168!29?G!120?@!45?G?@!31?_C$#169!4?@!154?_$#171!153?C$#172!5?W$#173!146?O!4?A$#174!26?@!171?G!35?@$#179!204?@$#180!202?_$#181!204?_?CG$#182!18?C$#183!17?o!15?O$#184!148?AGG$#185!15?C$#186!31?GO$#187?C!160?O$#190!232?@$#191!157?OO!70?_Q@$#193!153?G!6?A$#195!196?D!6?_?G$#197!13?G_$#202!198?_$#203!199?GC$#204!235?E@$#206W!4?_!148?O!8?W!44?A??G@$#207!155?_!34?O$#208!195?CA!8?F?@$#209!159?@!6?@@!27?B!9?_??@$#212!32?EA!107?_??@$#215!200?@!31?_$#216!234?G$#218!211?C$#219!5?E!153?E!4?g{]??!5F!4z~w~~~}c__???_???B!17?wwFFE!4?E@???w}w^$#220!157?FF!7?_}}!5w!4C!5?@ZZ^ww_GGEB!20?www}~}}w}}~~F@F$#221!159?G!5?@!27?_!13?C$#222!194?C!28?@$#223!156?F!11?@!16?C?!6@?W!35?H$#224A@$#225!207?o$#226!153?oM!57?A$#231!9?o!137?C$#232!16?C!8?@ACG???G!118?@$#233!16?BNZ!6~}{wo_$#234!142?O?A$#238!233?G$#239!199?C-#2!198?_o$#5?O!196?O?E$#6!199?A$#9!143?_??@??G!58?C$#10!8?_!8?W!217?A$#11O!36?_!120?G!48?_A$#12G!33?AC!109?C!13?@!41?@$#13!197?_G$#14C?G!4?O!28?G!107?O?A!4?C!6?C!51?@$#15!15?@G$#16???@!206?A$#17A$#18???A!144?@$#19!37?O_$#20!207?C$#22!148?O!11?O$#24!147?AA???_?osk!4?_[E?!4_!4?O!10_!5?{{?B!13?O!4?G_!6?_!7?@$#25!152?G!8?O!49?@?_$#26!226?_$#27!193?@$#31!191?C$#34!204?@$#35!203?Y$#36!205?A$#38!202?u??{B$#39!153?@$#44!154?A@@@!71?@$#45!194?B$#47!192?OK$#49!228?_G@$#51!233?O$#53!16?_$#55!18?O!176?C$#56!17?A!18?_$#57!231?A$#58!14?@$#59!14?_$#60!10?~~~nSw$#63!19?AC!14?_$#64!19?W$#67!37?DCC!93?_Ooo??B$#68!37?A?GO_MMC!89?C??KK?B$#69!38?@!4?_$#75!38?GBBB@@z!88~^JNNBB$#76!40?KKOO!93?O?G$#77!138?_?C$#81!196?CH!34?_$#82!198?@!34?C$#83!196?G$#85!195?_!35?_?@$#88!140?OGAC@$#91!139?_$#94!140?_oKB$#97!234?OC$#98?m!147?oC!7?_K@!39?@!7?wB$#99!231?@$#100!193?_GA!33?OA$#102!199?K$#106!142?_!56?@$#108_!199?O$#109??A!5?^!134?OKA!4?OA!7?_!40?_!8?G$#110!16?E$#125!143?GA!49?O??OC!31?G???C$#126!196?@$#127!7?B!24?@ACG!113?C!57?O@$#128!7?K!226?G$#132!229?_C$#133!19?_!11?@A!161?_!35?O$#134!17?@!18?CGO$#138!138?O$#140!198?A$#141!35?@!4?_!96?_?O?B$#142!16?@?_!130?@!83?_$#143!7?_!193?A$#144!230?_$#145!140?G?@!53?_$#146!150?@!49?G$#147?@@!147?I@!6?OQA!48?C$#148??C$#149!33?@??O!113?_!9?C!48?O$#150!15?C$#152!145?G$#153!201?C!5?G$#154!151?G!9?A!48?G$#155???C@!152?O$#157???O!141?O!5?O$#158!141?CO$#159!195?O!35?WA?@$#161!14?G$#162!13?OA$#163!157?_$#164??_$#165???_?w@!139?oG!15?woOO??!4o_!32?KB???s!12?_$#166!152?O?K?O!44?O!4?_!4?A$#167!192?_OC!33?OC$#168!195?@$#169??O!157?G@!47?_$#170!148?_$#172!5?B$#174!18?G!14?CHQ$#180!6?A!137?_?K$#181!191?GKA!10?A!23?C$#183!18?B?_$#184!17?c!127?@$#185!235?@$#186@!146?@?A??@$#187!210?C$#189!202?G$#191!153?A$#193???G$#195!229?A$#204!196?OE!34?[A$#206!4?qC{!140?_G???A!5?@?_C!48?O$#207!153?{@??A!55?O$#208!203?_$#209!203?@[@$#210!191?o!11?C!24?G$#212!36?B??O?O_$#213!38?A!95?_$#214!234?A$#218!158?A!42?G$#219!155?G!6?b?NNKWWGKKGG!5O!5Wo?wow?BB!10?@!9?^B!5oO!4o[?F]B$#220!155?AA!9?BFFFBBFF!5N!5FN~FNFB!23?K!10NB~W$#221!152?C!48?_??_!5?_$#223!227?_$#224!147?O???_!11?@$#225!145?_?C$#226!4?K!143?C!8?K???G$#231!9?~!5?AO$#232!18?CC?C!17?_$#233!19?@Zz!9~}{wo$#235!139?C$#237!233?G$#238!195?GA$#239!231?C@-#2!199?M$#5!148?_!48?B@o!7?G!23?_$#6!231?OK$#8!21?_$#9?A!137?O!8?C!8?_!38?C!10?@A$#10!8?~!9?@?G!117?_!59?K$#11!39?ACGO_!98?A!6?G!58?G$#12!156?O?C$#14?O!5?A!132?OG?@!6?@!5?G@!42?G!5?G$#15!19?G$#18!21?O!128?C!7?O!38?O$#21??AG?qa!134?O!27?oowWWw!6?G??Oo_!32?_$#22??C!147?G!5?A?_$#23!162?G?!7G!33?C!6?G!4?oo_$#24!143?C??C!4?G?C?B@!5?_G!19?A@?@O?D@!13?AO!5?@@!10?O?A$#25!153?@!59?@$#26!226?@$#27!188?O!36?O$#31!143?G!60?@$#32!203?M$#37!203?@$#38!201?w@$#42!227?A$#43!226?G$#44!202?M$#45!43?O$#48!190?O!35?O$#49!191?C!35?C@$#50!9?o!10?_!118?G$#54!41?SG?_!183?A$#55!19?@!17?@A$#56!193?@$#57!194?_!34?@$#60!10?F~~}}~~{o_$#63!21?@?W!16?_A$#64!23?_$#65!22?G$#67!42?A@??o!86?@EB@$#68!41?@@!4?wwo!76?__?W[MEM$#75!44?FNNFFN!79^D@@@$#76!43?EGO!83?Aao?O$#81!193?CO!34?C?A$#83!193?W?A!33?g?@$#88!134?_O??AC$#89!195?@$#91!136?GC$#94!135?_oWKB@$#95!198?O$#98[@!146?WB!7?W@!37?W!10?s$#100!190?_?B!33?_G$#102!199?@$#106!230?_$#108!149?C$#109?C!139?C!6?A!7?_!39?_CA!9?C$#110!19?CO!211?A$#113!20?A!116?_O!91?OC$#114!196?@$#115!19?A$#116!38?@!103?@!4?_!9?A!48?_$#123!232?o@$#125!228?C???@$#126!191?OC$#127!139?_!7?O@O!45?O!4?E!5?O?O$#128!141?A!66?_$#130!141?@$#131!22?_!16?CG$#132!191?G???G!31?O$#133!191?_!36?G$#134!40?O$#135!50?!76_??__$#140!192?G$#141!134?WGCA$#142!140?C!56?G$#143!7?D!31?@A!108?_!8?G$#144!228?O$#145!133?_!4?@!91?G$#146!198?_$#147b!139?G!16?CA!36?_!11?A@$#148?G!198?@$#149!159?@$#152!150?A$#153!206?C$#154!147?C!12?o!49?Oo$#155!147?A??O!8?K!36?A_!7?_???A_?_$#157??G??K!138?o!10?w???o!49?_!10?_$#158!140?A$#159!192?o_@!33?_?@$#161!14?@$#162!10?w??@$#163!156?C$#164!142?C$#165???FE@O!134?_o?@xH!4?ENy}!6?@EEF!10E!6]U][EM]MEA!14?WM!8?}}MMYNN~}MZ$#166!144?A!9?@!5?@EO!48?CKA!10?_$#167!189?_G!34?_$#168!191?A$#169?_!198?O$#171!206?@$#172??_!137?_??A!17?w?oOOooo!34?O!6?G?Oo$#174!21?G!205?_$#175!17?AG$#179???O!199?_$#180???_w!167?__?!9_g!19?_$#181!188?_W$#182!23?A!15?G$#183!20?@A!20?C$#184!18?A?C!210?G$#185!7?w!139?G$#186??@!156?A!49?@$#191!42?_$#195!201?@$#197!19?O$#202!194?G!35?C$#203!230?A$#204!229?O$#206??O?@?@!140?@??_oo!7?M???__!24?A!18?[FAA!6?OO$#207!213?K$#209!190?C!10?Co$#210!191?@!9?A$#212!132?W??C$#213!134?@$#215!229?A$#216!194?E$#217!200?_$#218!206?A$#219!145?EA!15?@@?!19@?@?@H!16?@!8?!4@D???@`CK$#220!225?@A$#221!146?_$#223!226?C@$#224!6?K!135?GOK?O!4?@!35?_$#226!143?_!11?C$#231!9?N!7?@C$#232!21?CO!11?@???C?@_$#233!22?FD!10~}~~}wo$#234!43?GO_!86?_???A@$#237!195?C$#238!193?A-#5!198?^!7?_!23?A`$#6!23?C!207?O$#8!8?v!15?O_!205?K$#9B!130?O_???A!11?C!7?C!37?G!4?A!7?C!21?G$#10!8?G!13?B!106?O???C$#11C!43?@A!86?O!14?@G!45?AA?_?G!29?C$#12!148?O!5?_?G$#13!24?G!25?_!97?_$#14_!130?_!5?A!8?O!7?O!42?G?_!5?O$#15!22?C?_$#16!197?C!10?A$#18!149?A!42?_?_??A!10?C$#21??GW_[W!126?O!17?_!8?O!5?@BAj~zGW?W[ienZRvvB!29?@@MeeO?G$#22??_!44?CG!104?_!51?@$#23!152?@!6?S!17?OW?C???C!26?W!9?@$#24!135?O?O?C@!20?_!60?A$#27!139?AEBF$#32!200?_$#33!134?!5_wwwgG_$#34!188?@$#35!142?Oo!43?K$#37!186?O$#38!201?B$#39!145?_!39?_$#43!186?_$#45!45?C$#48!189?@$#49!187?O!37?@$#50!9?~!11?A!106?O$#51!229?_$#54!45?@$#55!24?C?_!21?_$#56!193?C$#57!130?_!57?OC!35?C$#58!21?C$#60!11?^~~F!5~wgo$#61!229?@$#63!25?@BY]!13?A???__$#64!29?__$#65!116?_$#66!125?C???@$#67!47?@?EEE?@!70?EB?@$#68!52?DA!65?@CEAA??A$#69!53?O!57?_!16?@$#76!50?@@?K!35?!4_!19?_?_!7?@@@$#77!122?O?GGCC?A@@$#81!189?G???A!33?P$#83!190?GCF!33?_AA$#85!191?G!36?@$#88!123?_?OO??CCE?B?@$#91!122?_?O?G?C$#94!127?GG???A?@$#95!127?_???G!5?@$#97!231?A$#98!147?w@!6?wA!36?_!4?_@!6?[@!20?_$#99!224?G$#100!188?CA!34?CA$#106!130?G?C?A?@!93?O$#108!46?C!88?A!11?A!58?@!23?C$#109!130?O!68?C!7?G!22?@$#110!21?@$#114!227?_$#115!23?G$#116!207?O$#123!232?@$#125!228?G$#126!190?@!35?@$#127G!48?_!106?O!37?OC?O?O!5?_?_!20?OO$#128O$#130!124?_??O$#131!46?IO$#132!187?_G!34?_$#133!24?A$#134!26?O!15?@ACG!4?O$#135!52?A?!5^!25~^~!7^~!15^~!9^EJ@$#137!190?A!34?G$#141!48?A?G!33?_!28?_!4?___GCK$#142!25?O!100?_$#143!157?A$#144!192?G!31?_???C$#145!121?_?O!5?G$#147!128?_???G?C!12?CA!6?C@!36?OC@!10?AA$#148!23?A!24?O!84?G?C!10?_!8?A!37?G$#149!47?G!90?@!18?@$#151!22?G$#152!134?G!11?G??@!4?G?_$#153!129?_$#154?CO!143?C???O???C!8?_!47?@BO$#155?g???_!132?A!10?[@!6?_C!4?O!30?@O_@!10?wFB??F$#157?O???BB!128?G!8?B!13?B@!7?W!27?_Q!22?GYO$#158!130?A?@$#159!189?osb?@!31?oSG$#161!11?_??w!6?O$#162!10?~!9?E??_$#164?A!193?G!9?C$#165??E???C!129?GKW!5?WV!6?AB@??O?igO??XX]C?O?Co_!7?GGGw!15?EW?[]!4?!5_}}oWWcdE@$#166!185?G!16?@?_$#167!222?_?A$#168!223?G$#169!49?O!155?G$#170?@!134?C!59?@$#171!151?XW!49?O!7?WE[$#172!6?_!144?ECG???G???JsC!21?@!15?_k_@!5?C??G$#173!23?@?G!25?_!140?O$#174!224?O$#178!188?_$#179???_!129?_!23?C!21?O__$#180??@F^!163?\C??FF~fbD@??C!18?@??B!12?@@@B$#181!134?O!52?A$#182!39?C$#183!24?@EKc???_!14?@AC$#184!230?G$#185!7?~!147?@!52?@!20?A$#186!205?A$#191!43?@A$#193!196?K!25?O!7?_$#195!223?C$#197!20?@$#199!53?_!41?_!23?O$#200!226?A$#203!226?G$#206!139?@!6?A??_m?_SA???w?FCJJaa___!16?UF!15?A!6?W!11?_$#207!136?O!9?@$#209!224?@$#212!48?@@?W_?_???_!45?___!15?G???@$#216!191?O!35?C$#219!201?C!21?B$#221!138?C!47?G$#224!141?C?FC!19?CC!21?@!34?C$#225!145?G!54?W$#227!222?G$#229!188?A$#230!223?O$#231!23?O!101?_$#232!39?G!4?O!4?G$#233!27?@`^^^!7~r~~{{goO$#234!117?_??OO!5?AA$#236!52?W??___!28?___!5?_?!8_???__?_!4?_???G-#2!228?U??B$#5!83?___!141?C$#6!8?W!77?_$#8!8?F!18?AGO!58?_!21?GG!114?O$#9!79?__!65?A!7?@@!34?_OA!5?C!6?C$#10!26?@???_!62?!5O?O!7?GG???G???CC!5?@!106?W$#11!51?@?C?O?_!75?O!12?@!6?O!38?@!5?G!6?A$#12!132?CG!19?G?A!40?O!8?@$#13!77?_!43?A!108?A$#14@!55?O!75?G!12?W!9?C!34?O??A!13?B$#15!91?!9_!7?O???o$#16!7?{!147?O$#17!133?A$#18!53?G!21?_!72?E!4?@?_!40?@!28?_$#19!58?_$#20?_???G!127?@!11?A!61?_$#21???MB?N!127?_!25?KG!8?@NNN__?_?@DF]B!11?o!14?@B@?YigXN$#22GNH!71?_!12?O!17?G!46?c!39?_C$#23!145?@!15?@@!38?o$#24!134?N?K??O!44?B!15?_??O$#29!9?_!19?_!70?_$#31!135?O!4?_O$#32!200?D$#33!135?K@NF!4N?@$#35!141?_oP!41?@$#36!183?_GA!33?_G$#37!200?A$#38!200?O$#47!184?O$#48!220?OC$#49!186?@$#50!9?^!16?CGO!72?_$#51!116?G!6?A???@$#55!27?@A!43?_!30?G$#56!50?A?@??_!15?_!11?O!40?A!60?OC$#57!113?O???G$#58!28?_$#60!10?gM~NG~nNN!5~}{oO!79?__$#61!31?O!67?G!10?C!114?O$#62!41?_$#63!30?BEENRoO!9?MHHIC$#64!29?@$#65!67?O!45?@$#67!69?O$#69!70?O!35?AAA$#70!87?@@AA!19?A$#76!55?A??E?O??ooO?_???O?G!24?@DD@@D!6@!4?@$#77!114?A$#80!118?OG__ooww}eaE}$#81!130?@w!55?C?O!31?_$#83!225?A$#88!119?@@$#95!54?G!92?A$#97!226?_?_$#98!82?_!63?w@!6?[!42?{@!6?oN$#99!184?_$#100!131?@!54?A!35?@$#102!227?GH$#106!85?OO!26?C?G??A???@!103?C??{$#108!147?C!5?_!38?C!4?@!8?_$#109!125?@!7?_!13?W!43?C?@??_!30?A$#110!26?A?C!69?O?OOO?O!4?G!120?_$#113!29?C!87?A$#114!120?C!4?A!63?_?@$#115!25?@???G!59?_??O!10?O?O???OO!9?A$#116!52?A???_!21?_!68?_$#120!26?G$#123!27?C!59?_$#125!229?B$#126!190?G!29?_$#127!133?C!11?_!7?C!42?G?O$#128!91?O!14?G!8?C!114?@$#130!116?A!4?@$#131!53?AO!18?_!10?O!19?G$#132!119?C!65?G!35?GA$#133!70?_!8?O!141?O$#134!52?GO??G!21?O$#135!54?@!4?!14NFFNNFFNNJFFC@@?A!5@$#137!118?G!10?@?C$#138!61?_!4?_!38?C$#140!186?G$#141!53?@??CG?O??_??_!6?OO???GG???GGHGG??!5C!4@!4?C!8?AAA?@@$#142!30?O!59?O!21?O!113?G$#143!155?G!42?_$#144!115?OOO???G!68?C!31?GA$#145!115?A?@!107?G$#146!8?_!115?@$#147!81?_!50?B!13?C!7?a!36?G!5?AA!6?GO$#148!50?@!62?G!77?_G!37?C$#149!51?AC$#151!105?_$#152C!6?B!47?G!136?O???A!10?G$#153!132?O!12?C!58?G$#154o?E??C!142?G_B!5?`??__oO?a_??_o___o!20?_!9?A!4?GAKA$#155!5?B!142?o???O???MN?OOCK?!5O?OOO!20?o^E!12?O??oo!14?@$#157!183?W!9?G?H!12?A!5?_???o$#158!118?@$#159!186?ow~NB!31?o{~@@$#161!11?p??v?Ooo$#162!10?V??o!13?_!78?_??_$#163!199?A$#164!207?O$#165!134?O???G!5?G!5?w~!7?NBA!7?NM!7?!5_C!18?o!6?B???B@@@??N$#166!203?_$#167!185?C$#169!153?A!42?C??@!4?o$#171???o!153?__???_!39?A$#172!158?O???AvGAa_!31?G?GDB$#173!30?G!51?O!18?GG!8?CC$#174!32?_!16?@?C!5?O?_!20?OO!18?G!27?@??A!55?@!34?C@$#178!122?KKCC?WWo$#179???@_?_!175?@$#180!4?Ko!126?_!41?^^~^^]YW!32?CSUe$#181!143?M!40?C!35?C$#183!29?ACGO_!13?EA!5?A!5?_!7?_!7?O!12?G!16?!4C$#184!31?_!57?O_!15?O?O???_?C???CA$#185A!75?_!37?G!7?A???@!21?@!58?C$#186??o!85?O$#193!191?A$#195!221?@$#197!24?@A!78?_!5?_$#199!55?@@!11?O!30?A!9?A?@@$#200!113?_$#202!225?C$#206!149?^C?J???OON!4?GDLLNN!32?FGK@???ls{?K{$#212!57?EH??OO???O!7?G!6?C??AEEMC!5?EECEE$#217!6?O$#218?O??O!194?C!4?C$#219!199?o$#221!200?G$#224!135?Bqoo_O!79?@$#225!135?_!7?_u!74?OA$#229!221?A$#230!54?C$#231!102?__$#232!28?@!5?_!19?_C!13?_!7?O!12?!9G$#233!31?@HOKNn!4~^!4~posswwo_$#234!58?O!15?OO!12?G!12?C??C$#236!56?A@!33?AAA??A???!6A!4?@$#237!185?_!40?A$#238!117?_???C!65?A$#239!114?o_??_oWO!6?CG$#240!116?_-#2!82?OGCC!110?_!31?A$#3!86?O!138?C??__W$#5!8?E!77?A@!48?_!9?~!6?_!42?W!8?_$#6!31?@!53?A$#8!32?ACC???_!45?G!23?O??@!112?G$#9!133?R!56?A!5?@$#10!110?A$#11!145?C!8?A!42?_!6?O?@$#12!154?C!34?_$#13!109?G!28?_!15?O!40?_$#14!57?@??A!7?A!78?G!56?@$#15!9?_!79?K!20?@$#16!7?r!75?C!63?_!4?A!38?@!14?_$#17!69?A$#18!111?A!40?@!38?A$#19!4?o!154?A$#20w???GA!151?B??E?@!15?C!15?G$#21!4?C!145?D!23?!5@W!15?B!11?w!4?GW^?@@$#22??E!56?A!88?O??W???v!35?CE$#23!159?OW??c{~NN~yyy][!26?OB@$#24!141?AA!16?__!54?aA$#25!198?GO$#29!9?^!21?A!4?_!48?GK?@!19?G$#31!137?G?ABD\A!38?@$#32!144?C$#33!141?O_$#34!139?CC$#36!216?_G$#38!138?O$#39!199?G$#45!67?@!9?@!103?G$#46!88?O$#47!182?C$#48!119?A!97?O$#49!182?G!35?A$#50!30?@?C!53?_?C?G$#51!132?@!91?A$#55!65?@!6?AA!5?@$#56!56?@?A???@CD!15?@!106?_!30?O$#57!133?_!50?@$#58!20?_oo???@!64?G$#60!10?B~~A?E{}]NNKNN^^[\@EOGG!56?aPOEH[]^^^Xx~~~T~^FB@$#61!33?@???G!41?_!30?G$#62!39?C?R?G??___!6?C??GC!8?_!6?_G?O$#63!37?AG?WG!22?ooO??g???o??A??C??A$#64!34?@!45?G$#80!111?_[RCF!4?@FFFffv~~u^$#81!110?o??C??G[W??GGO!7?N!52?C???A!31?A$#95!72?@@!6?_!64?_$#97!35?GO!191?T?C$#98!135?_!17?^!42?CB!7?^$#100!118?@!64?A!33?_C@$#102!81?!4_$#106!35?C???_!189?@$#107!34?GO!51?G??C$#108!58?@!12?@!73?O!8?@!42?O$#109!70?@???@!6?O!63?G!6?O!35?OO!14?_!20?@$#110!33?A!196?@$#113!112?@$#114!223?G$#115!84?O!22?_!121?G$#116!63?AA!80?A$#119!108?C$#120!107?G$#123!37?_!45?O?O?OG!135?O???GOA$#124!85?_$#125!132?C!50?C$#126!132?G!55?C$#127!61?A!55?@!16?gO!11?A!6?G!33?GA!14?E$#128!32?@!75?_!38?C!4?C!53?C!16?_$#131!61?@!4?@!4?A!6?@!5?A$#132!117?A!14?A!49?O!6?@!28?GA$#133!116?@!15?O!49?_G$#134!36?C!20?A??C!6?CC!6?A!6?C$#137!116?A?C@$#140!224?@$#142!75?@!6?G$#143!68?@!78?O!6?_!40?O!10?G$#144!111?G??Wws__wW??g!63?O$#146!8?x!77?@!138?A$#147!133?KO??_!14?_!35?_K@!5?AK$#148!69?@!77?@!4?G!37?C!13?G?A!17?C$#149!59?@??A??AAA!77?@$#150!89?OA$#151!35?_!51?CA??A$#152!7?K$#153!118?A!15?A!63?@$#154BE@!146?nGC!4?B!21?_CA!9?OoWFO???A!9?wccceE$#155!148?J?o!29?S!9?_G@!14?FFBBB$#157!179?_g$#159!183?_w~~N@!30?o{~^B$#161!14?F@B@@o?@!7?@C??O!59?E!5?EE???a$#162!10?{??|ww??_?O??o__aa}wgoo_!54?_@_`wob`!4_!4?G$#163!136?O!58?C$#164!151?_!43?G$#165!135?G??GWGG??W!19?A!14?@@@!32?_S$#166!198?o_M$#167!183?@$#168!181?O$#169!134?C!55?G$#171??WF??E!142?O!6?[wwG?CE???oo?DDD`b}}AAA!13?_w_!5?_[]K!9?_$#172!144?_???C??B!9?wwZ@!29?@!8?A$#173!34?A???O!24?@!16?OG$#174!61?CC??CC!7?A!6?!4@!134?C$#175!21?A!70?@$#176!30?AC??_$#177!222?_$#178!114?B!5?A!8?@_$#179!4?B?@!143?A!6?C?@@B!14?{{WA!30?WW$#180!5?@!133?_!54?E$#181!141?_?L$#182!39?G?_OO!14?C$#183!83?A$#184!36?GO!49?A!21?CC!118?E$#185!206?O$#186!60?@!15?@$#191!70?A$#193!109?O$#194!218?@$#195!182?A$#197!34?O!52?_!18?_$#206!148?_!6?G!42?C!4?@!8?@@?G$#214!111?C$#215!119?C!64?A!35?@$#217?w?w?Co!127?@??O!18?_??C!41?__o$#218C@_??wG!151?F!50?W??O$#219!143?o!55?F@$#224!135?FNFF@o!40?A!33?@KA$#226!144?A!36?C$#227!144?@!71?OC$#230!85?@!95?_!41?O$#231!33?G!57?C!15?O?A$#232!35?BACEP`?@!6?!5w{x!18?oOO??O$#233!36?@@@AECmf~~^^^!5FBA}{o!5wGGgwWS{{{KKKc}mIEE$#237!109?_$#238!218?_$#239!111?O_g_!5?coo?WWG??G?o_!86?G???C$#240!112?A!70?O-#2!71?O!5?C!4?@!58?C!54?F$#3!74?G!153?@_$#5!138?@!5?OO@!5?{!42?_W$#6!8?@!34?C!34?C$#8!9?_!29?@A??G!29?G??C$#9!111?O!27?@??G!43?OA$#10!8?OO!31?A!26?_!37?C@!115?@$#11!143?O!9?G!41?A$#12!110?O__!23?@!4?A!46?A$#13!151?G$#14!135?@!15?C!35?@!6?_??w$#15!39?A??GO!35?C$#17!147?O!55?o$#18!7?E!146?A!51?y$#19???vro!186?_!8?o$#20C!148?O!4?G!19?[?G!32?_$#21w!149?_!37?GiMA?_!13?B??__$#22!144?C???k!6?@!56?IA$#23!150?[!5?MAABB@@bw~NMNL!4@!19?[!4?O$#24!143?@!54?@@$#29!37?@!34?_?O$#30!213?_G$#37!178?o$#46!43?_!33?G$#47!214?OC@$#48!108?G$#49!179?OA!34?G$#50!72?G!9?A!22?A@$#51!104?_!36?G$#53!42?O$#55!44?C!17?_!123?C$#56!105?O$#57!142?O!42?O!29?_!6?@$#58!10?A!8?[[!5?!5W[\\Moo!50?C!16?A$#59!13?o!62?_$#60!11?^^?KKNNA@!4?K[!10?CE??G!34?_?OOowcCCKM@@!4?!4{KKG??RBF?@$#61!70?G??C!37?G!108?_$#62!44?A?@Bv!5?QE!4C?KEA$#63!43?@?EWC!7?G!4?OO!4?G??BF???A?@$#74!108?O$#80!108?__!7?oo!5?~~{|~A?oo_!4oOOo_$#81!105?_!6?G!22?A!44?_C@??G@!29?_C@?O$#95!8?E!128?@!7?F!49?G!8?C$#97!70?o!4?G???A$#98!140?A??G?_}!5?B!43?_!8?F$#100!216?A$#102!42?C!37?@@$#106!64?_!12?A!29?A!114?A$#107!73?O??G!7?@$#108!139?A!13?A!41?C!8?@$#109!8?G!94?_OG???G!43?C!33?G$#110!9?G!28?@??C!39?A!21?O?CA!115?G$#111!228?E$#113!71?G??C$#114!186?A!34?C$#115!9?E!34?o!22?_!10?A!25?G!116?_C$#116!144?G$#118!229?^$#119!34?@?@$#123!69?_?_O!7?A??@!138?OA!4?G$#124!228?o$#125!43?A!62?G?@???O_!65?_C@!34?C$#126!110?_!106?@$#127!138?A?D!10?O?_!33?O!9?E$#128!221?O$#131!63?_!4?O$#132!109?O!33?_!71?O$#133!59?_!74?@!45?G$#134!66?O!8?A$#140!107?C!6?_!65?O$#142!44?G!34?@$#143!151?A$#144!109?@??AWO@FF@@AC!10?CD!4?C!77?O$#146!145?G!49?O$#147!142?C?_!8?@!32?_C@!15?yw$#148!8?_!142?_?O$#149!195?@?@$#150!10?G!72?A!17?_$#151!10?C!65?O??G!23?G$#152!7?@!139?G!6?@!51?@$#153!142?AC!50?G!5?_??G$#154!144?B!4?AA???_!22?E@!9?O?@???@!12?{~MNND@$#155!150?@!70?G$#157!141?@?A!35?@$#159!181?w}~~F!31?w}~NB$#161!11?__?ooOo{??wG!6?!4_???G?KKOo_!31?_!11?AA!12?_???@$#162!10?@??NBB??@ABFFNRB!5FBAaOJAooo!37?__??Wwwqo{w!4~!4BRRV~^KK$#163!147?F!46?C!8?C$#164!185?_!20?C$#165!198?A!15?B$#167!214?_$#169!147?_!38?G_C@!4?O$#170!151?@$#171!6?k!141?Q!6?EOl@kkM}?C??`_qMM}}?@_!23?B!11?O$#172!163?[B!33?CA$#173!41?@!19?_!5?O!8?A$#174!45?o!14?_!17?@!58?A!43?A$#175!22?oo!5_!5?_C?G??_!55?___$#176!16?_??__$#177!107?GA!10?C!9?__!5?A?_c$#178!106?ooC!17?BA!13?O$#179!149?C!4?Ow??K!15?b}V@!10?_??DBB!4?G!10?OOO_$#180!189?S$#182!54?c$#183!62?OOO??GGG?CC!4?@$#184!9?@!30?@?A!23?_??O!32?_$#186!7?w!57?_!9?C$#187!4?GG!148?C!39?A$#193!110?G!68?E$#194!179?G@$#197!10?O!27?A?CG!31?_!4?G?C!21?O?C$#206!148?@@!27?wM!34?[C$#214!140?G$#215!216?GA$#217?|?G??B!142?g!6?`OoOOo!4?oOO?oo!18?ow[!5?_{[N~B$#218BA~?CFO!202?@$#224!142?@!72?@$#227!215?A$#231!10?_!64?O!9?@$#232!42?@??G?o?!5BH@__aIIAGG?O$#233!44?@@eGG!5{?oZZXPD@@DNNFFFC?BBB@@$#237!109?C$#239!109?AFFDFN}wGMq|z~~!5?\^NJYMKKKGG$#240!119?G!22?_-#2!195?w$#3!229?@}$#5!52?O!99?^!42?F$#6!9?C!45?C?A!4?@@$#8!9?B!43?WG?A???@@!37?OKA$#9!151?G!32?oA!19?B$#10!54?C!164?_K$#11!145?C!59?O$#12!114?A!70?@$#13!101?C$#14!8?C!138?_!5?@!30?G_$#15!52?_!6?A!7?@!30?O$#16!8?O$#17!197?@??}~A$#18!153?G!52?F$#19???@?AEG!142?G!20?_!27?}$#20_??]???O!141?[!5?_!13?o!16?O_!21?_$#21!158?A!28?GB!4?@!13?ooG?@@$#22!7?@!140?B!5?[G!55?E$#23!156?A??___w@JHH??AAA?E!17?K!5?_$#29!10?C!44?G!45?@$#37!176?G$#45!177?A$#46!60?A$#49!212?_C$#50!10?B!32?@!10?O??C???AA!5?@!31?A$#51!220?@$#53!63?OO$#55!45?G$#56!45?E???_???C!90?@!33?C!34?O$#57!101?G!11?AC!62?_!40?_C$#58!25?AA!7?EG]w[LDA!12?_??_??C!12?C!4?w!4}w!4?w{}}]?I_$#59!11?Acv_aE]K!45?__!33?A$#60!42?@!14?G!7?C?AEEEF!4B!4?@@!10?!4@P@@$#61!54?A$#62!46?KGMKCBB@$#80!102?_CFEM??NNykG_o}BA!5?DDDBBFFFMMCCC?C?W}gx$#81!101?O!76?O!4?G!31?A??G$#95!9?W!92?@$#97!51?_!12?@!155?O$#98!146?~!49?@!7?~$#99!213?G$#100!177?G@!35?@$#106!99?_O??@!115?G$#107!99?G$#108!151?C!44?C$#109!113?@!31?A!5?A!33?C@!7?_?G!8?K$#110!44?o!11?C?A!7?@$#111!228?@G$#112!229?O$#114!102?C!41?A!39?A$#115!10?_!33?N!14?@!161?@$#116!50?_!100?@!42?O$#120!11?C!10?[{o???Oo_???`__?_??o!17?OOoW?G?GWoOO??wGGG!17?_$#121!229?E$#123!65?@!155?A$#124!229?_$#125!177?O!5?_!30?A$#127!145?O!39?O!8?F?_$#128!8?B!211?A$#131!45?o$#132!178?A$#133!179?@!33?_$#134!46?o?OQ?G???@$#137!144?_$#140!214?G@??O$#142!219?O$#143!8?G!138?K!5?A!49?}$#144!179?A!4?@!34?A$#146!98?_!53?_$#147!9?_!135?@!5?o!44?A$#148!185?G!8?G?O!8?_$#149!145?G!40?A$#150!43?O!12?G??C!5?A!30?_O$#151!11?w!31?_!22?A???@$#152!8?_!144?C$#153!150?o!46?A?@@?@$#154??M!145?K!4?_b!32?A!19?E??c$#155!102?A$#159!178?_{~~~F!30?o{~~F@$#161!12?B?@??@@???@?AKCeeFN~~!9?E!14?OG!4?_C!12?@@@!15?E?IA?@$#162!35?F@FBAA!14?oo??G!12?C!9?@F!4NFB@@??C$#163!202?{$#164!186?G$#168!177?C$#169!112?@!34?R!38?C!16?@$#171!4?_?@!149?K@@!4FECEEMNCCCF@!14?_!4?]!4?o$#172!175?G@$#173!50?O!5?@$#174!45?@!69?C!98?C$#175!24?LowWG!5?WO???OWK!18?GK???WscGggww?ssu}E!5?!4o!4?_]OG$#176!11?@WG]\x_q~~~aB?!4@GO??~!5?__@w!15?o__?cK!12?@!16?_?OMCC@$#177!103?a!8?A!11?AAA!5?@@!4?_NF?R$#178!108?@??C!6?@!15?!5B$#179N!147?o?B!4?B!11?ooGGG?__F!11?C!4?W!4?WA!8?G?OW$#180!114?@!43?_!27?_@??@$#182!50?A$#184!10?W!40?OG??A??@!38?_$#185!145?_$#186!153?O$#187??@?E??C$#193!176?_$#195!213?A$#197!43?K!9?_!44?G$#200!111?@$#206!175?oA!34?WE$#214!144?K!33?G!4?O$#217O~?_@|w!142?B!6?puSWWW?wooo@?@pPwW^!12?O[~}rf!4?CD!10?F@$#218??o?W??a!141?_C!4?S?GG!34?_!4?G!7?w@N?A$#224!212?G$#225!115?A!97?@$#226!176?S@$#227!211?_O$#230!57?@!126?C$#231!43?A!14?C!4?AA!4?@!29?C$#232!47?v`@HCCA@$#233!46?B$#237!115?@!28?O$#239!100?_?GWwxp~yoo?OsGG@w{]]^\\www[[OO!6?C!5?E$#240!101?_O!5?C!5?O??C?``_aa???__ggwoo!4wWo_@C-#2!195?@$#3!24?_!194?A$#5!151?_!42?o]$#6!10?W!38?A!44?G$#8!10?c!36?GC!43?_!125?G$#9!182?_K@$#10!10?A!38?@!43?O?CA!121?C$#11!9?G!195?G$#12!182?OO$#14!147?B??W!32?@!12?@$#15!24?O??O?G!14?C???GC?@!39?_OG$#16!196?C$#17!199?_^~$#18!184?G!8?_$#19?M?WWO?_C!150?C!42?F$#20!4?@??O!148?@!12?NNFEA!12?[B?g??G$#21!174?A!34?C$#22!45?A??A!99?]!4?S$#23!157?WW???F???KF??__?o!23?V$#29!28?O?_!16?O$#37!175?E$#46!26?G!6?_$#47!210?O$#49!211?E$#50!11?_!10?_???_!17?G?_$#51!93?_?G!49?A!35?_$#53!12?@@!10?I??C!6?_!8?@_$#56!145?G!30?G!5?C!28?OA$#57!217?C$#58!14?_!11?@!22?O!4?BAA!15?Q^~v!8~___?C~$#59!12?AE?__bc[[oW??CC@!5?O[wWOo!4_!9?KG?OWWWs~nXX^zX$#60!28?_!21?G?A@G!37?C$#61!48?@$#74!95?O$#80!96?__K_!6?___NWNOOq!25?OCB?_$#81!177?G!4?@!29?O???O$#95!9?B!184?E$#97!218?O$#98!146?C!4?^!43?_!8?r$#99!211?G$#100!175?_!34?_$#106!45?@G!49?CA!120?@$#107!25?_?GGO?O!12?@!185?O$#108!9?C!142?E!52?_$#109!97?@!54?G!30?A!10?@!10?O$#110!45?OO$#111!25?O!203?CA$#115!10?@!33?A!49?C?@!120?_$#116!152?o!52?C$#119!49?GC!41?G??@$#120!13?_!8?AFD@??@@!4?@BB!4?@?A!6?O??_!14?oo_~`!14?_???CA@@$#121!230?@$#123!23?_!6?O__!186?@$#124!26?O!202?Bk$#125!94?O???@!46?C!30?C$#127!147?K!36?A!20?@$#128!9?_$#131!176?A$#132!212?@$#133!47?A!128?O@!34?C$#134!46?@$#137!143?O@$#140!118?W!57?_A!34?G@$#142!150?_!66?O$#143!150?C!45?A!6?F$#144!96?GC!119?A$#146!50?@!143?G$#147!146?z!5?@!51?K$#148!9?O!137?_!57?A$#149!147?O$#150!11?F!11?O!4?C_!18?O!41?_O??A$#151!31?G!15?_!4?@$#152!150?@!45?G$#153!199?^$#154!148?_{!4?@!29?_wA!5?_!13?M???@$#155!153?j!31?E!23?_$#157!145?@$#159!177?o~~~N!30?_}~~N@$#161!26?!4AEFFE??_mM][OOo!7?WOO?G?CCG??___!28?A$#162!51?C???D@!18?G!15?G$#163!8?A!193?w$#164E!7?@!176?@$#167!175?O$#168!176?@$#169!200?_??w$#170!150?A!33?C$#171!148?@A!5?A!37?@???G$#172!174?C!22?_$#173!46?C$#174!145?o$#175!19?BB!13?A??@!10?!5_EC?C!13?X?K_!10?^^[[z?^$#176!12?{W^^^[Z__NDG?A?_?C@?GH?CC?@@BMNK!10?o__bbB?OEE?Ce~NNE!15?BB???B@$#177!98?A@?_!7?O?O??L[O??_!4?_?!13_pbBkbE$#178!96?O?_!10?!5_!28?OKW$#179@!153?wwW__poowwOORW^OOO?L@!12?S??OO!6?_!8?]_$#180!182?G!25?@W$#184!45?K?C??A!44?A!122?A$#185!183?_$#186??_?__!187?[??O!9?o$#187_o[_??_?o!187?_$#194!211?@$#195!175?G$#197!11?G!13?G!25?A!41?C$#206!174?w!35?A$#214!181?OA$#217?@AFEN^M!148?_FFINN?Fnn!4_?Gx!14?G^FnnF!5?^!8?@]B$#218W?@!4?@G!140?@!4?EDE!27?O?`__O??OA!12?@_$#224!210?C$#225!210?G$#226!175?@$#230!217?G$#231!11?O!18?G?O!11?O_$#232!46?A@$#237!216?_$#238!211?_$#239!95?_?WO[^^^}__^^^?F!5?CEF?!4_WW!15?O!35?C$#240!94?_!4?A_?_@^^!6?NN?bjx_!5^Ff!13^MKg-#1!24?A$#2!194?o$#3!22?@??@!8?AC$#4!23?OGC???CGO!4?_$#5!151?B!42?N!10?_$#8!10?@G!78?G$#9!146?@A!32?_I@!12?C!9?@$#10!89?O!126?G@$#11!150?_!30?OA$#12!146?A!33?O$#13!148?O?A?A$#14!9?@!136?C?G$#15!32?G?@A!5?OG??O?_!41?G$#16!182?G!10?@!12?_$#17!199?~~~|s$#18!9?_!139?C!32?o{H!21?NO!8?A$#19OO?__??B{!148?GWOw!8?_!19?g?o!6?{$#20_!157?_??Oo!26?@D!7?B$#22!153?A$#23!157?!4EDN!7?@N?B!23?H$#29!11?@!22?O!53?_$#37!209?A$#45!174?G$#46!20?A@!7?@$#50!12?_!18?@!11?AA_!42?OC@$#51!96?_$#53!12?ACwg???A@!9?@!10?AO!15?_$#56!96?O!78?C!33?O!6?@$#57!95?C!50?_!32?_$#58!78?p!5~nn?O$#59!13?O?O!4@!16?@BB!4@P?@BCWm[woOwqII?@?RVUqB@$#60!40?A!47?E$#61!91?G$#72!96?G$#74!145?o$#80!91?_C_???AN@pove@!4B!5?PPxxxO!4XEETDD???BB$#81!176?F???@!29?G@_?OA$#95!10?M!193?_$#96!22?__oww{wwo$#97!11?O!204?OA$#98!147?o???{!52?BW$#100!174?_!34?C$#101!11?_!12?@$#102!21?A$#107!19?C!8?@?A!5?C!4?C???CG!43?A!140?K$#108!10?O!184?W$#109!10?_!136?@!47?_$#110!11?C!77?_$#111!17?OG!7?@!8?G??GG?G!188?@?_$#112!26?C?C??_!5?___$#114!92?A!52?@!69?G$#115!11?A!79?A$#116!150?O$#117!17?_OG???@$#118!18?_o_OIMCAA??A??!4_W???O$#120!12?@@!37?B?E@??@?o!11?~~{{_kkM!5?OO~H$#121!20?[kS!4?AA?CGO??O?WOOg!190?@$#122!33?@$#123!43?CC!45?C@$#124!16?_!10?@???C@AC!6?_C??Go!184?q$#125!146?O!28?A!4?C!28?G@$#126!94?C$#127!95?o!54?C!30?`C$#128!150?@?C!63?C$#132!94?O!80?@$#133!175?O$#137!111?CC!26?CwG{CEG!29?_$#139!210?C$#140!92?o!121?_C$#142!152?G!40?o!21?_$#143!9?A!142?o!40?K$#144!179?G$#146!204?C$#147!147?K!33?C!13?B!8?WE$#148!148?_?G?@$#150!12?G!23?A?CC??_!45?G$#151!12?C!22?@!51?C$#152!206?O$#153!9?G!170?G!21?AG$#154!149?Z???{!31?OA!5?F!14?NF$#155!149?_???@!54?W$#156!33?O$#157!94?G$#159!176?w~~F!30?o}^~N@$#161!47?@@?_!4?KCCEEF??@@??E]$#162!39?A$#163K$#164!148?A!34?BA$#166!173?C$#168!174?O$#169!9?C!85?G!107?B$#171!197?E$#172!173?W$#173!90?_C$#174!94?_!80?G!33?_A$#175!49?@@?@@!15?NN??BBRRR!9?a@@$#176!13?iFFMEA!14?G!9?_p??IeOACMgE@poXGwkggK{}x`oo!4?K$#177!93?MBBA[ouAF!12?g_!5?_??oO???@@@??!5B!5@$#178!93?O??@@?GKGGG}!4{~~zz~EMEEEfeEeeGggww}}}!7{AEuAA@$#179!154?FB?!4@!11?}!16?AA?O???_$#185!92?@!55?C!44?A$#186??^?NN!201?_$#187BN_YOon{BO!146?oo?_?_!25?HO?o!5?B$#193!90?O!55?G!61?_$#197!12?O???OGC!12?AC!4?C!4?AG?AC!42?A$#201!139?w???ww$#206!173?_A$#214!145?A!34?A$#217?_!152?GKN??G?I?N!5~^}o@!16?OGN!4?Oo$#218???D??O!141?@!5?oo!7?o!20?sn|unC??g???K$#221!174?@$#226!174?C!34?@$#230!215?O$#231!32?ACG!5?C???G??O$#237!93?@!51?C$#238!179?O$#239!92?G!10?P!15?G!4?@@AAA$#240!91?O!4?C_-#0!11?@_$#2!11?G!139?_!42?~$#4!14?_??AAA@!6?OGW??@?A@!4?D?G??CCO$#5!148?G??]!53?N$#6!11?O!202?O$#8!87?_C$#9!179?_C$#10!88?G!126?@$#11!180?G!14?E$#12!96?@!83?O$#13!10?A!138?G!43?M!12?_!7?G$#14!96?A!82?C_$#15!87?G@$#16!181?A!24?B$#17?CC!196?^~~~X$#18!149?@!31?OB@!6?_$#19@@GB?WfFIQ!159?@!12?C!6?~?N!6?B$#20!159?@??@?!5@?@!21?C$#22!172?G$#23!196?w$#29!12?@!29?@$#37!173?S$#46!48?C!37?_$#47!97?C$#50!87?C$#51!208?@!4?_$#53!14?@!33?@G!8?BG!16?OOW!5?G$#56!174?G???_!35?A$#57!97?@!110?C!4?O$#58!78?@!4FBABB$#59!49?Bk~yOM__!5?Ew~]]}O$#72!146?C$#74!99?__!13?!7C?CC??C!12?C???A?`$#80!102?@@$#81!175?{{?C!30?A?x`C$#95!147?@_?O!53?@$#96!15?_w{{{}}!4~^NFf~~}{{}!4~??_o_wo_$#97!215?A$#98!151?@!53?o$#101!15?A$#102!11?E$#106!88?_A$#107!12?E??@!32?G$#108!148?A_M!53?A$#109!11?_!135?A@?@!28?O!15?@!8?[$#110!87?OA$#111!12?G!30?AEA!185?@$#112!15?O!5?@!4?_!6?A!6?A?OGW?G?O$#114!90?@!55?B_!66?@$#116!149?O!45?G!8?_$#117!12?OOG?@$#118!13?_SCA@@@!13?@@!5?o]E!4?E_$#119!84?@$#120!50?O??GoWWXWrgww!6?_??w}{|nna!8?@$#121!13?G?GC!10?_o!11?G`?C??AG$#124!46?@@!184?~_$#125!96?C!50?O!26?A!4?@!28?A$#126!174?C$#127!179?G$#128!193?@!12?O$#132!174?@$#133!174?_$#137!90?_y}}g_owgWWw__!5?!5E!5oqqryyw}yyyww_o{gghhhw~wtw?W_$#140!89?O!4?A!80?@!32?_!4?G$#142!10?C!77?O@!116?G$#143!152?[$#144!175?A??G$#146!148?S?_$#147!180?B$#148!10?@!136?C!45?o?o$#151!78?C!4w{s{G$#152!149?A$#153}yq{w???@!189?{!4?A$#154!153?z!4?C!11?_}!11?A?A!6?o!14?H$#155!172?E$#156!14?A$#157!207?O$#159!176?B~B!30?{~E]B$#161!50?B!17?C$#162!86?C$#163!5?_???_!171?K!21?c$#164!9?@$#169!97?A!101?_$#172!172?_!23?C$#173!89?C$#174!174?O$#175!74?BA$#176!13?B!35?C??Df@FFecCVF@F?``@j^~~F@$#177!89?_E!7?PFF?AE!42?W$#178!90?WD@@S[G!4?F[W!5~!5x!5JHHG@@F!4@FF^NBPPOOO??FI$#179!153?C!18?@!23?B$#180!147?G$#185!10?G!138?C??b!28?@!24?C$#186!7?w_?o!172?C!6?W$#187??@?FFW?O!145?ooXgp?@@!22?LKwvo?F$#192!13?C!35?_$#193!95?@!83?A!34?C$#197!43?@@???AO!37?A$#200!98?E$#201!121?C!5?CC!5?!5EB???D~E$#206!172?O@$#214!95?A!82?O!29?G$#217!8?CK!159?W!21?o!5?~$#218!154?NNeVI!4}~!5}e]@!9?_wwqpFGN???J!14?E$#221!173?G$#226!173?A$#229!173?_$#230!207?_$#231!45?@!40?O$#237!89?G!4?@!113?O$#238!209?@-#2!12?C!137?A~!42?~$#3!213?C$#4!14?o!8?GCbOC@_!10?AB!6?A_$#5CK!10?G!136?E@$#6!212?_$#8!85?oC@!125?A$#9!178?OB!25?O_$#10!11?@!200?O$#11!178?GC!26?O$#12!179?w$#14A?CG!7?G!183?o!8?K$#15!84?_$#16G$#17!4?Kg!193?~b~b$#18!153?o!26?c!9?B$#19??A??CR?A?Q!153?o!24?v?v!6?{!4?]$#22?O!151?B!17?@$#23!172?Y!23?^$#46!85?C$#47!148?C$#49!173?A!4?@$#50!84?O$#53!69?__wok!4}f$#56!207?A$#57!86?_!61?G!28?_!34?A$#59!50?@GON}{K~b?A???@?AB$#74!87?o?O?!5ogog?OoBB_??!4_!6?_?wwwWW{woow__gkc!10?[|o?_$#81!175?~~B!30?B^mF$#95!12?_$#96!14?F!7~NFB?_oW^!10~{{!6~{$#98??O_!201?B$#100!173?{$#101!12?@_$#102!12?A!137?{$#106!86?O$#107!49?@G!35?@$#108!205?_$#109???O!83?A!60?@O!43?{$#111!13?@!36?O!182?G$#112!13?AG!7?O!4?Ge!20?A$#113!87?G$#114!88?@!88?O!29?C$#115!85?GG$#116!193?B!12?M$#118!13?W!9?_w[E@!21?G$#120!51?CC?@Bb?W~|[Fn?@__oPWCNR!4@$#121!13?C!8?_O??HA!12?@!7?@S_!182?O$#123!86?A!145?@$#124!233?F{$#125!207?@???_$#127!148?A_!28?C!16?M!8?A$#128!11?C!200?G$#133!174?@$#134o_$#137!88?_K~NJNLLDLD|LK{{]}}]][[{{{|||^~DDFffBFNNFNNFBZ!5{!5~BAKg!26?G$#140!88?C!58?C!26?O??C!29?W!4?@$#143!152?_$#146!12?O!136?H$#147??G!175?_!26?K$#148!11?A!183?@!8?@$#149!4?_!201?@$#150!50?AO!30?_?@$#151!78?W~~~^~E$#152??_!177?A$#153@@@FBOg?K~!168?A!19?B???[$#154!153?C!16?@A!25?C$#159!208?{_P$#161!52?_$#163!5?BC{o?__!191?`$#165!196?_$#169?A??O!6?O!188?[???O$#170!180?@!23?_$#172!172?d$#175!51?BG$#176!52?Bo??O?C??bwO}}\[NMFB$#177!88?GB!29?AA!26?O!26?_$#178!92?C?!5A??B??!5@!5BAAA!17?!5B$#179!197?_$#184!213?@$#185!87?C!64?^$#186!7?B@?L!142?G!15?A!10?W{w{!6?{?y$#187!155?[[!7{K{_}}|!14?}}~~~$#192!50?C$#193!212?C$#197!84?G@$#201!88?O_!6?O?OAa!28?!4O!11?_?B$#214!147?@O!58?_???O$#215!147?A!26?A$#217!189?G?G!5?@$#218!154?~bb!9B^@@?}{!9?BFB@@!6?D!4?Y$#229!173?@$#231!51?_!33?A$#237!88?A!88?G$#238!174?C$#239!211?G-#1!31?_$#2!13?G!137?F!42?N$#4!14?@{O{oWC@OCB?G?WB@FO_?OCso!5?__!4?M_$#5!13?O!137?G!42?o!11?_$#6!84?C$#7!16?g?M$#8!83?OA$#10!83?_?@!125?C$#11!4?C!200?@$#12!6?O!141?_$#13!84?G!67?C!52?O$#14!6?G!170?_?W!15?F$#15!51?@!31?C$#17!4?G@F}O!190?^|v~x_$#18!8?@!144?a!26?@!23?C$#19!10?Sx!141?!4Css}]}oO???A{w!11?ow{}w}[[~?~!6?X$#23!172?A!23?W$#24!172?C$#37!172?_$#50!82?OA$#51!149?O!27?C!29?G??G$#53!53?O!14?~F^VF!6@$#55!4?O$#56!173?_$#57!149?A!60?C$#58!53?A$#59!54?xrq}W?ocs$#74!86?GAK!4owoo~~~}pyyy|u}ww{|zzzEEFNNMME!4~LNBNNFVU[[[!4{uuuhHEEG$#81!174?_~N!31?]W$#95!13?_!136?A!42?}$#96!15?BFB@F@??wKNF~E???BFNNBBN!5~^^!4~o$#98!5?W!145?o!26?N!27?]$#101!13?B_$#102!13?C!136?@$#105!53?_$#108!5?c_!186?@$#109!12?@!137?_$#110!83?G$#111!234?M}$#112!20?A?_?ooo?@???KWO!16?A$#114!84?_G!121?@$#115!82?_?@$#116???@!148?_!52?A$#117!30?O$#118!14?W!4?_w]F@!5?wmO_??_O$#120!54?EKL@f~NZHzo~~~$#121!14?E!6?_GA!4?_C?G??_?gG!12?@[_!181?O$#124!52?O!181?@$#125!147?_!25?W!33?C$#126!177?@$#127!5?A!144?C!28?F$#128!12?C!197?_A$#131???A$#132!85?C!61?O!25?F???A$#134~~}w$#137!86?C|p?@??ANN!4?MDDD?@@FFBA???@@???@@@!11?@!7B@@@O???EG$#140!174?A?_!32?_$#142!12?G!72?A!66?B!52?_$#143!195?w$#144!174?[?O!31?_?@$#146!211?G$#147!4?B!144?_!28?o!27?@$#148!12?A!139?W!52?K$#150!52?A!26?OM@$#151!69?w_gw!6}np]F$#152!12?_!168?E$#153!8?m~J!146?G!9?o!30?_!5?O$#154!171?w$#155!149?@O!56?O??O@$#156!52?G$#159!208?@F$#163!7?@!146?GGG?G?_??_{{{K!13?G!5?__?}!7?E!4?EI$#164!153?@!10?A!12?O??M!23?@$#165!196?f$#166!172?G$#169!12?O!166?_!19?_AG$#172!172?@$#173!207?A$#174??@C_$#176!52?@L!8?ACN$#179!197?@$#180!148?O$#185!207?_$#186!10?_!142?O!27?@@@!6?@?~$#187!154?AAABB@@@NN@BB@BFwA!8?o?EA@F@BB$#193!84?O!65?G!26?G$#197!52?C!28?_G@$#201!85?oo?ANMNND!5?@!4?AG!5?CCCwww!4ow!4?qo{oowgg___!4?GGGEuHH@$#214!86?@$#215!146?o$#217!11?E!141?Gooo$#218!154?@@@!13?FD!25?}$#221!172?O$#237!86?A!62?C!60?A$#239!174?@-#1!32?@$#2!14?G!179?O!12?W$#3!15?O$#4!15?@NB_wur?OC?_[??H]??{a^AL{???F_BOCMC?@C_$#5!14?O!137?_!28?_o!11?n!12?c$#6!208?_?C$#7!24?_$#8!80?OC@!126?_A$#9!7?G!143?CC!24?G@!27?A$#10!81?GA!127?@$#12!151?G$#13!13?A!136?@O!26?o?_!25?O$#14!5?@?A_!4?G!168?G?_!10?@!10?_$#15!53?@G!24?_$#16!153?O!51?A$#17!8?K???O!186?BW~~~n$#18!12?@!141?_!24?o[!4?_$#19!11?BG!141?FN}}}~N^_!5?~~!12?BEBFc{}N?^!5?C~$#20!197?B$#22!171?@$#23!171?o$#45!5?A$#49!172?O$#50!80?C@$#53!55?O!8?~~NN$#56!5?C!170?O$#57!81?_GA!66?G!22?@$#59!55?NBBN^^A$#61!208?A$#73!82?O!4?_!61?O$#74!82?_gOOo?FFNFF?A??oW!5b!8B@@!4?_FF?HNFO???___!5?^^~~JBB!4_$#81!174?~~$#95!14?_!168?O!9?~!13?A$#96!20?GKr_Y~B@!8?_??B^v~_???B`z~oo$#97!210?G$#98!6?Eo!143?@O!24?_$#100!172?_$#101!14?@$#102!14?E_!194?O$#105!54?C_$#106!208?GC$#107!236?G$#108!6?G$#109!80?_!71?B!24?CA!27?C$#112!22?KN@?[A??u!4?[?@A?_G?W??NwO??MG?O$#113!209?@$#114!176?A$#115!81?A$#116!6?O!170?AC??O$#118!16?_w]F!8?{^?@}~@??Wo!5?Mw!6?@G$#120!54?@?[!4?W{}$#121!15?MOC@?@!6?_B_?_??A@?c!6?PC_!5?AS_!180?C$#124!53?A!181?Bs$#125!176?_!32?A$#126!148?@?C$#127!177?@$#128!13?C!195?O$#131_$#132!150?A$#133???wvo!167?C$#134^^~FG$#137!138?_$#140!173?o??@$#143!183?GO$#146!183?_$#147!6?@!144?AG!24?O!28?@$#148!13?@!164?G!27?G@$#149!7?C$#150!54?A!13?_?W[[}]}}]gG$#151!66?oo^~fbb@`@@`VF@$#152!10?[!142?C!9?_?_!13?A?G$#153!8?B~`{_!140?B!6?O!6?[!12?@CC!4?@?__!14?_$#154!171?M$#155!81?O$#163!6?_???A?A!147?__!4^~b!12?AB??KWZA@O^_!13?[$#164!155?_!23?K$#169!7?@O!4?_!139?G!25?@!15?}???{f???O$#170!164?_$#173?_!174?G!31?C$#174!5?G!167?A??C$#176!56?_{o__dB@$#180!83?@!65?@!46?~$#184!80?G!128?G$#185!13?O!68?C!68?_?_!51?@??O$#186!12?C!141?WO!14?@!12?@!8?~$#187!170?E!26?_$#195!172?F$#197!79?OA$#200!88?o_???_!25?o_OO!9?@@@Ee!6?_BAJ\?_$#201!83?OnnN^GWoww^|~~Nf!5[!8{}}!4~^GWneown~~~^^^}}}xX_???s{[[\SA}K$#214!150?O$#215!173?G$#217!156?@@@!11?w!26?W$#229!172?G$#237!83?C!65?A_!57?@-#1!16?A!14?C$#2!15?K!161?k!30?FB$#4!17?{b!5~Go|??vM???@_?NW@Co_oF_?Ko!5?}o$#5!8?o!6?O!136?F!24?AWC!14?~!13?GO$#7!18?[!5?`!26?K$#8!76?_?CA!98?C$#9??A!131?C!48?A$#10!77?GG!99?A!4?w$#11?A!126?A!49?_$#12!127?A!7?G??G???_!11?_$#13!14?C!138?@!22?_?@!5?~!22?C$#14!9?o???_G!109?CA!5?A!63?_!10?@$#15!32?CG!22?C$#16!154?C!44?@N$#17!9?CC??K!143?GG!28?ooo?o!7?{oB?WS{$#18!154?Bu!29?F!6?G$#19!157?@A!9?FN!17?@@!8?OA$#21!151?@!19?C!24?F$#23!171?B$#29!76?O$#45!7?_$#46!78?@$#50!75?_?C$#51!151?A_!23?@$#53!32?_!23?@?_!4?qB@$#55???A?_A$#56?CG_!76?A!54?O$#57!123?A!8?G?A!47?o$#59!60?o$#61C$#72!79?_?GGG!42?G!53?_$#73!80?_C?Cuq}v{IG][kmmmww!5{!5oOOOoooww{[__a_O!4ow???_!11?KmNMM$#74!90?A@BA!5?@AABB!5A!9?@!15?@??@@BB@$#81!173?wf[$#95!137?G!41?G???@!9?~!14?O$#96!24?UNA!9?~o_???RNw???N~~r~~$#97!209?K$#98!7?BG!124?C!5?O!12?Go!23?@??A@!25?@$#99!172?@$#101!15?@$#102!15?A!161?O$#105!32?G_$#106!78?O$#107!55?@!22?A!159?_$#108?@!5?C$#109!8?A!5?@!116?C!8?_!12?C!25?A???C!23?A$#111!32?A!203?A_$#112!29?G@!4?^!4?BNK!4?B!8?G$#113!79?G$#114!78?_?C!45?!5@!9?G?O$#116??C?o!72?_$#118!16?|@!9?}^?_J@B{???B[o!4?B}_$#120!60?AewLK$#121!17?A!9?@_?OO??A???CaG!4?[@O!6?@Mo$#123!79?@$#124!31?_?C!23?_!178?@^O$#125!133?A!4?_!4?_!28?W!7?G$#126!151?G!20?_$#127!8?@!114?C??A???E!4?C?O!16?O!25?C$#131??@???@$#132!122?C!10?G!17?C!20?E$#133wwo@BNo!115?A!8?G!19?O$#137!81?A!41?@!8?O@???A!12?A$#140!139?C?G?O!29?@$#143!9?G?_!183?O$#144!173?CW$#146!15?_!61?O!54?C!76?_$#147@!7?C!127?G?O??_!11?G!26?@$#148!7?G!6?A!64?C!49?A!10?O!12?A!54?_$#149???K!148?O$#150!66?KK{oo{{~~[CA$#151!64?o}rrBNNBB??BB@$#152!155?G!8?@B!19?g!13?A!7?_$#153!9?@aNN!143?Ssswwo???KBWO!17?o?KN{!5?_?o!6?B{$#155!176?C!5?@$#157!127?C!51?O$#159!175?B$#161!57?A$#163!10?@!145?bA?FFN~~}o{fgo!16?NMA?BNo!4?_K!7?A$#164!155?@!20?G!8?O$#169!7?O?AWOoRo!180?N!5?{~fj$#170!156?G$#173!6?C!130?C!44?M$#174!4?COG!172?_$#176!57?D^~LXF$#180!125?CC?C!5?G!4?g!31?o$#184!80?@!98?@$#185!129?C!24?G!21?O!30?W$#186!192?F!5?@$#187!197?N$#191???O$#192!33?O!23?O$#193!124?A!7?A???O!4?O!34?A!4?A$#197!32?O!23?AG$#200!81?_bb?@@GBPP??!4PBBA@@!4?KKKkkkKKKEEBAYYWO_!5?ooo???@@?A??ACKBPopP^{$#201!84?@!19?LL@@@!6B@@??!4@!19?BB$#206!4?G$#214!123?GGH!5?@??OA?_C!41?Os$#215!81?OOO!38?G!6?GG!50?G$#217!158?@!11?~G!24?W$#230A!135?C$#231!76?G$#237!79?OW@!7?!4_!31?@??G!4?@o__a???CCG?o!4?_@_$#238!82?C?GK???CC!6?CC!19?_CCC!26?_$#239!173?A?_-#2!16?C!177?}$#4!17?@~F!4~v~??MF!5?NC?G@?{`BENw?BuoE?SFX~K_$#5!16?G!137?G_!38?@$#6!16?O!135?__!55?@K$#7!19?w!4?G!29?W$#8!75?A!75?_!58?Ao$#9!9?C!143?A?O$#10!74?OC!107?@!25?CO$#11!8?CA!174?g$#12!176?oW$#13!15?C!139?C!20?@$#14!4?@!9?o!141?_!20?_!5?C!11?N$#15!59?G!13?G?@$#16!157?_!28?o_!21?O$#17!8?G??ao!146?!4_???_!19?GVev?Z_!5?Bff_ww_|r_o$#18!156?A!40?_!9?@$#19!169?C!18?@!7?E$#21!171?B$#22!6?O$#29!30?_$#50!72?O?A$#51!144?A!8?G!24?@$#53!31?G!28?O??W$#55!4?G??@$#56!4?o?C?_!133?A!29?B$#57!152?@!19?C!9?@$#61!147?_?O$#72!77?G!16?OGG!20?GG?__A!5?_C!6?G???Co!6?@!30?Ox$#73!76?o?w?@^ZoL!4N[[[{K??@HHUUQRRx`@@@EEMNNB@???@!4HfF~~F?@@!4?ABA?G?GG???@$#74!138?@$#81!173?~T$#95!15?@!60?@!116?N$#96!36?JFv???]wxo???@Nx~j_e$#97!210?@$#98!8?@w!143?@C!22?@$#101!16?@_$#102!16?A$#105!60?_$#106!153?O$#107!30?O@!206?@$#108!5?O!187?O$#109!5?g!4?_!5?_!126?@!10?@!22?A!6?O!8?_!15?A$#110!74?C!75?_$#111!17?A!12?C???{!24?O!179?O$#112!28?o!7?ow!5?C!5?G!7?o$#113!140?@!9?O$#114!75?OCA!63?A!10?E!22?_??W???E$#115!72?_$#116!5?C!149?G$#118!17?O!8?}^??B!8?w~!5?@~_!8?AG_$#120!31?OA!27?KvNF$#121!17?K!8?@_@w!4?Bo???E?B!4?E?[!8?@S$#123!73?OG$#124!30?G!27?A!179?}_$#125!74?_??@!70?_???O$#126!144?@$#127!153?C!22?E!7?@$#128!209?G$#131!4?C?G?O$#133~~~e??@C!170?C$#134!7?w$#140!175?M$#142!15?G!192?@$#143!6?_???G??I!181?O$#144!174?i$#146!73?_!80?o$#147!8?A!133?@!11?A$#148!15?A!160?GC!5?AE!10?_!14?_$#149!5?A???@O$#150!33?W!29?_OG~}^NE]@A$#151!33?_!25?A?Go?nv?@$#152!155?@GWo!26?P!11?Fo!8?AE_$#153!10?F[!145?@HVVROoooWwoB!16?FGGGNC!4?@WC!7?GWG$#154!4?A$#155!75?G!107?O$#163!5?@!150?@EEGGK!4NFFNw!22?X!13?CC$#164!156?C!28?M$#165!171?C$#166!171?G$#168!196?_$#169!11?@NtG_!172?O?o_!7?WW^FF^A$#170!183?G!14?G$#173!7?A!143?O$#174???X??A!165?w!5?A$#176!31?_|!26?@B$#180!143?A$#184!149?_$#185!14?FO!60?A!64?@!13?AO!28?_$#186!192?E$#188!171?o$#192!31?A!26?@$#197!31?C?F!34?_ox`M@@$#200!78?C~}_?@!5o!5?@@???HHLKK!5?HH@!12?Ww???B!9?G!5?KNEKGNM$#214!134?C!8?CC!33?__?@w$#215!84?A!9?G!24?G??o_!5?wwOOOGG???c!5?Q?G!31?F?}$#217!170?F!25?G$#218!170?w!25?O$#230!183?_$#231!59?C!13?C$#237!76?Gs@???cE!5?!5Beuooo!5_!5E!5owwwqo!11?EEFFrvt{{RqCc__`oOOF?@G!22?O$#238!75?_??A!4?G!5?___?o??EEE!6?Wwww!5?CEFDFuUUCU!4?W??ggg!7?GOOW???A!30?GE$#240!175?@-#0!18?_$#1!26?w$#2!11?_!5?G!137?FO!21?C!15?@$#4!19?Kbr~FnB??N!7?yW}??~?[???[?B_A_oAB??@EO_$#5!11?O!144?K!22?C!14?ABA?O!14?o$#6!17?O!53?C!66?G!18?_!19?C$#7!19?BKK!23?__!12?o$#8!70?G?@!60?__?O!5?C!4?@@!6?G_!25?O!29?A$#9!11?G!172?A!9?_???G$#10!16?B!126?AA!9?@??O!18?W$#11!5?@C!178?_!7?C$#12!185?O$#13!12?O!57?O?A!59?_?O!7?A???@!38?C!7?_$#14!5?C!5?AA!172?A!12?C!8?C$#15!29?_!4?_!112?A???@???O$#16!15?A!142?O{c!26?fd???@!5?A@?rB@$#17!11?@C!146?B?||{___~A!17?kW?{?R{!7?@G?abb@@B?__$#18!141?A!15?@C!36?G$#20!170?W$#21!195?O$#22!5?_!191?_$#29!136?_!7?C!7?@?C!25?O$#37!171?B$#46!69?G$#47!171?C$#49!171?G$#50!68?O?A@!66?O??G!6?A!4?@!23?O!4?_$#51!175?G$#53!30?CGCr!29?@FB$#55!7?O$#56!7?G?G!128?C?A!34?A$#57!71?O!103?@!5?C$#61!134?G??C!5?@$#72!80?C!5?AAA??C?G__!12?B__@@@??K{{!5_?_oOB?EEC?AAA?@$#73!73?C?R!6?!7C!5?WW?WW@@???@??B?@@?AI!5?GAEEE??BFC$#81!173?BO$#95!69?_!86?A!54?@K$#96!20?O!15?Cc@???~b~^^_???t^N|{~~}G_$#97!139?G!73?G$#98!10?E!183?K?C$#99!171?_$#100!171?O$#101!17?B$#102!17?C$#106!136?G??C!5?@!32?A!4?G$#107!29?W!4?W!25?@G!8?C!168?B$#108!6?o??@!188?_$#109!6?G!10?_!122?C!35?C!6?O@!8?B???G?_!11?A$#110!68?_??A!71?C?A???@$#111!34?@!25?A!177?@Ow$#112!23?wO!11?@B!12?^G!9?O$#114!72?GA!98?M!7?A$#115!135?_?W??G!5?A???@!25?_?G$#116!10?O!165?A!16?G!18?O$#117!18?O$#118!18?K!6?wF??@!9?~~!6?@^o!9?@$#120!30?wqyG!27?@$#121!18?Bo!5?C?~oA!5?~!11?A_K!10?K$#123!69?O!109?G$#124!29?C!4?E!204?KC$#125!72?C!58?_?O!41?C$#126!179?A$#127!6?@??A!175?G!9?C???O!11?C$#128!16?C!140?G!24?G!27?@$#131!7?_$#132!70?_!112?C$#133~^b~???@o_!162?@$#134??[!5?K$#142!16?G!54?G!85?C!39?O!14?_$#143!13?`@!170?@???A!9?G!4?K?GGKK?G$#144!173?{l$#146!12?_!122?O!5?C!38?GG$#147!10?H!173?{!9?O??C$#148!5?AA!149?@!19?@A!15?O???A$#149!11?C$#150!65?KM\??@!67?__?OO!4?CC???AA!26?_$#151!31?C?C!28?N}wopA$#152!158?J?W!25?R?W!13?_$#153!160?BAAB^^^?|$#155!175?_?@$#156!62?_$#163!169?~$#165!196?_$#168!9?C$#169!5?G!6?HM]w_!171?A@~kA!6?AEC[[O[uqor]$#170!14?_D!183?C!11?O$#173!4?@??C@!126?G!8?@$#174?_??}??AAO$#176!31?@@$#179!170?_$#180!195?_$#184!154?A!22?G???O?_$#185!13?O??O!140?A_!21?C!15?H@@?w$#186!5?O$#192!61?C$#193!73?@!101?O!7?@!12?O$#197!30?A!30?AO!5?NF!70?o__www{ww{}}{{o!23?o_?_$#200!75?K?K@BZz!6wW!5?FFBFFMMN^^MNBKK]]M?C!10?FFK$#201!78?A$#206!10?_$#214!71?_??@!36?_!18?_?OK??C??A??@!29?O!5?@@@?F$#215!72?ow{_{o{{_!7?`oowos??{__ooo__oo{oo??O{oo__??FKWGGwW???OOGG?C!4?@!41?B$#218!170?F$#230!183?A$#231!30?@!36?_!69?_?O??G??C???A!4?G_!21?_?O$#237!74?A??B???CB?AA???KK?K!21?!5B!8?gwj@PBB@D@BA?@@!30?_$#238!76?B!6?B!4@?!5B!20?K[O??OP@PP!5?CG$#239!174?A-#1!19?C!5?A??o!11?^$#2!12?BE!4?A!110?A!84?@C$#4!20?Ny@O@?oF!8?Fov??NG}w[}M~w~M^LMM]EF^u|$#5W!11?C?Go??C!48?A!57?G?C!57?o$#6!123?_O!33?W!55?A?_$#7!45?@@!12?_?A$#8!66?G?@!56?OG!5?@!24?G$#9!6?B!178?A!8?M$#10!128?A!29?E!55?C$#11!6?O_!192?O$#12!6?_$#13!14?_?O@!103?_?O!35?_!24?K!15?A$#14!7?G!7?C!159?@!17?M?G$#15!29?b!4?B!28?O!60?_!4?C!26?@_!18?_$#16!7?C!151?Bp_o!23?Aoo][o{!8?BCC??[[c?o$#17?G!159?!6@`w!17?@FC?aA@!9?AHFFaaA@@o$#18!66?O!102?AA!27?@G$#19!169?o$#21!170?_$#22!7?A!191?_$#27!198?_$#29!127?G$#45!5?@$#46!63?G!92?A$#50!65?GA!59?O???C???@!21?C$#51!69?@!144?O$#53!32?E}$#55??O!8?C$#56!5?C!4?@?_!158?_$#57!68?C!59?@$#59!30?__p$#61!121?O?GC?A!47?O$#72!68?G!12?BBB!34?@???@@B$#81!173?Z@$#95!11?@?G!4?G!48?C!63?@!43?O!37?@$#96!21?D!15?F!4?F@Fa?p???p_qpp`xw$#97!157?E_$#98?o!12?C$#99!171?@$#101!19?G$#102!18?@_!110?A$#106!66?_!55?O!4?A$#107!34?C!27?A$#108!6?C!6?O$#109!6?G!5?G`?G??O!156?g!8?@@!8?P!4?@_$#110!66?C!61?C??A!25?O$#111!20?O!8?G$#112!22?}N!12?wGG???o!17?H?@$#114!67?O!51?_$#115!65?O!67?@!42?Y!7?O$#116!14?O???_!181?G$#117!19?O$#118!19?B!4?{|F?M!6?[???F_!8?B!12?O$#120!30?@\?@$#121!20?_??_A?Gw@!6?b???w?o!7?C!12?g$#123!34?_$#124!29?S!4?W!27?C_!176?~$#125!120?_!4?C!45?W!42?_$#127!195?O$#128!68?A!107?@!9?O!6?@!5?C?_$#131_!4?A!207?K$#132!67?G!103?E$#133B?@A!4?BE[$#139!172?A$#140!172?[?E$#142!17?A!106?G!33?@O!40?@O!11?A$#143!11?A???AK!144?A!24?G!14?G!10?@$#144!172?_c$#146!65?_!56?_!34?@!27?G!29?W$#147!16?_!168?C$#148!14?A!111?C???@!44?E!8?A?_!7?__???AC!14?_$#149!7?O$#150!64?M!61?___GGG[]]]ZXRPPpoo!11?@$#151!64?@B$#152!160?G!27?A@!5?A!6?@Aww??W$#153!168?D$#155!129?@!66?_E?O!13?O$#157!196?]?K$#163!169?K$#164!195?@$#165!197?o$#169!15?@B!143?AKM}]}}]!19?GG_@L!10?Go??@@@yMNw_$#170!160?CO!6?A!17?C?@!6?C!13?C??C$#173C!7?_!165?_$#174?FM|~w??[xaw$#176!30?]AG$#179!170?H$#180!196?@$#184!64?_??@!108?C!7?_$#185!14?@??{!141?K!4?_!27?Ao!7?Co!9?A?G$#186??_!166?@$#193!197?@$#197!63?@?C@!58?_?OOooo___`cekmmMNN!11~}_!20?K!5~$#200!84?AA$#214!67?_o}~XBu!4w{~~{{{!10w!5owwsoow{wWGx@@??CCC??AOG!5?@$#215!71?e{H!4FB!5?DD!8F!5NFFJNNFBFfvE}}~~zzz~}\NFEE$#217!170?O$#218!12?O!157?C$#224!197?GO$#230!7?@!190?A$#231!63?EO!63?G??CA!23?W!20?r!5?~$#237!122?G??B@!45?@?G-#1!27?W$#2!15?CPcO`_!92?_!71?Bw!8?g$#3!20?P!7?K!190?O$#4!21?@B?W~F!8?o?~|}??w!5~j!4_o!5~}c?B{$#5!14?B??AGQ!45?@!49?O!5?@!37?_!26?C!11?_!17?@CG$#6!17?G?G!94?O??C!101?_$#7!24?_!34?@@$#8!17?O!46?D!49?_???C!39?{!15?W!43?O$#9??A!4?a$#10!16?C!47?A!55?A!38?@!15?@!20?_$#11?A!64?@$#13!18?A!154?_!13?O!6?U!4?CG$#14?C!4?@!189?C$#15!116?O??C!65?O$#16!160?E@~???@O!20?B???@B!10?@@??FBFNn$#17!6?A!154?W!4?_`@!22?@!12?AA??GCGO?@$#18!116?C!51?K!29?GB!13?o$#20!196?A$#21!169?_!26?@!17?C$#22???O??C$#29!121?A!53?G!8?@$#34!170?A$#45?O!4?G$#48!66?C$#49!170?C$#50!29?@!85?_??G!38?B!17?O@!7?E_$#51!65?_!47?O???A!56?@!40?OC$#53!29?O$#55?_?C??_?C!4?A$#56@??A!4?A!5?G_!49?O!149?G$#57!115?C!55?@?G$#59!29?_VOC$#61!67?@!104?_$#81!217?_$#95!15?AG!142?K$#96!38?A!9?S!4^N!6?Y~[$#97!185?C!31?A$#98??W!12?G!179?C$#100!67?C!146?A$#101!20?C!7?@$#102!18?_?G!174?O$#105!33?_$#106!119?@!53?O$#108!7?@!187?A$#109!15?@_?C!140?A!26?@!10?_OW@!15?A$#110!117?G!67?G$#111!21?o!6?O!5?AG!27?BW!176?B$#112!21?M!14?~!5?F!19?_!177?_$#113!65?G$#114!65?C?w?__?{!5?G!10?_!21?_O!102?C$#115!174?_A$#116??@!14?@!177?@O$#117!27?_$#118!20?A?w^B?_FA!5?_!5?~{$#120!31?BB$#121!22?C_C?W!7?OF???@?B!22?_!176?C$#122!34?@$#123!158?B$#124!28?_!5?K!205?^$#126!88?O!81?O$#127!13?@$#128!14?C!97?_!81?_$#131???G??O?G$#132!170?G!43?@$#133K!65?o?w]]{!11?_???O?O!19?_!61?A$#140!173?A!42?O$#142!187?M!13?@$#143!160?o!26?@??K[]G!6?O$#144!172?Z@$#146!16?A??C!96?G??A@!38?O!26?A$#147?@c!4?[!58?A$#148!118?A!55?C!12?_!6?H!4?_E!16?G$#149!18?@!69?_!107?G$#150!29?K???N!88?Ca??BBBJH?B!15GJ$#152?G!6?_!151?@E!4?]M!20?K!8?O!14?OM$#153!169?F!44?_$#155!198?C!16?@??_$#163!168?q!45?G$#164!214?O$#165!197?A$#169!67?A!92?G_?~}}!22?o~ra_s!7?w}~{{~~owo_$#173???@!4?@!105?G!100?A?O$#174q???~~???!4~{o!155?_$#176!30?gkw$#177!171?G$#180!170?@!26?@$#184!115?G!6?@!52?C$#185!65?A!98?@@!8?A!25?_E@$#186???_!11?O$#191!8?O$#193!87?_!127?_$#197!29?A???O!83?_oww{w[~~{{{su~{!15vs!8~!19?w_oq!4~o$#206!197?GB$#214!68?F@@BB{w{{{s{{w_?ww~NLN!4~{{{wwffbff~~b_?BhWKKC?A?@!97?_$#215!66?G!6?BF!6BF^^FF??A!5?BBBFFWW[WW??[^~[UF!4B@!54?C$#217!169?W$#224!197?C$#231!116?_O??C?A@!33?{!17?_E^NL!4?G$#237!117?@!55?C!42?G$#239!171?oC-#1!26?_$#2!20?C_!174?M$#3!27?O!195?_$#4!22?KN~N!9?N{{~~w?@!14~z~~xqz_{$#5!17?@?GB!86?O!51?^!26?@K!7?B$#6!109?CC!62?A!12?A?_!33?O$#7!23?o!37?K$#8!108?OG!48?@!13?O@!14?O$#9!84?_!110?O$#10!107?_!5?@!44?A!13?GC!14?G!32?G$#11??W_???A$#12!85?_IC$#13???C!107?@$#14???A!15?O!64?O???@!71?z$#15!28?A!144?G!12?G$#16!213?AC$#17!166?F@$#18!65?@!100?_!46?@BA$#20!168?E$#21!215?@$#22!7?O$#29!111?C!62?@!11?O$#46!28?C!85?@$#50!108?_OG!62?OA!10?@_$#51!66?_!18?C!83?A$#53!28?_$#55?@!14?@$#56!4?o?B??C!74?G!10?_!73?C?G$#57!66?G!18?A_G!22?@$#59!29?F$#61!221?_$#81!171?A!45?@A$#95!195?G$#96!57?C??E@C]$#97!21?O!165?O!32?@C$#98!8?o!187?oB$#101!27?G$#102!18?BFW$#105!33?A$#106!109?A$#107!28?@$#108??A!5?G!11?_!176?C$#109??C!4?@C!9?C!66?G?@!22?A!76?@!7?_!24?A$#110!65?C!92?c!27?C$#111!27?_!37?_!173?_$#112!22?o!13?BB!25?@!176?F$#113!220?G$#114!66?E`w{EMO?GGKMG]]WwO!7?M??KKSk??OWG?_OGC!62?_$#115!65?A!92?W!13?_!49?_$#116??_O!4?A!188?G$#117!27?F$#118!22?B???^!7?F!6?~w$#120!30?By$#121!25?o!8?Wo!4?F?E!21?B$#122!34?_$#123!21?G!43?G!121?_$#124!21?F!43?O!174?w$#125!9?G!56?O!16?_??@?A!19?C!59?_???A!43?A??A$#126!19?_$#128!8?@!179?C!8?O?@!19?@$#131!9?O!8?G$#132!86?O!130?O$#133!66?@]FBx@bzoo??U??_?@!4?ooo???_?G??!4_?WMEB@!60?G@$#137!220?O$#140!169?_Q!47?Oc$#142!160?C!33?@??_$#143???@???G!153?ow\}!23?A^~~]_{???KABB?AOO!5?yM?_$#144!170?K@!45?AKG$#146!106?_?G??A@!46?_!27?A!7?C@$#147??@!82?OCA!110?@$#148???G!167?_$#149!7?C!190?A$#150!33?o!78?CC!30?@@$#152!17?A!147?_G!48?O$#153!167?E$#155!9?_!97?G!60?G??O!44?G???CO$#157!169?@$#163!167?O!47?G_$#164!166?O_!47?CO$#168!7?_$#169!161?NBa@N!26?`^!4?o{{{~|nn!5~Dp{W$#170!165?O!49?_$#173?]??K?C??A!7?C!154?@$#174~_??B~w??@!6~}wo!77?_!119?@G_$#176!29?w{D~$#180!106?O!110?_$#184!112?A!59?C$#185!162?C!25?@_!4?A$#187!167?G@$#192!33?@$#193!105?_$#194!168?O!47?C$#197!28?O!4?G!75?_owww}!29~}}!8~|~~!17?o}~~~x!5~w$#200!169?O$#214!71?oKCFFrp```FFMF@?oKNNp~~RRBR~^NFV~F@@?A@!108?@$#231!28?G!4?C!79?A!40?A??~!15?_K@???E!5?E$#237!171?C!45?C$#240!219?O_-#0!255?!25?$#1!25?_$#2!21?@!175?_$#3!26?_$#4!23?o^!11?z~~dBw?B!9~F~~~f!6~B_$#5!21?A!78?_???A!53?G!29?F!8?O$#6!102?G!55?O!30?o!36?_$#7!23?N!15?Ww!12?w!10?_$#8!101?_!55?_@!10?_G@!17?G!33?@C$#9!81?_WA@$#10!170?CA!17?C$#11!9?GG!10?O!59?O$#12!83?C$#13!198?O$#14!160?BC!29?C?wwC??G$#15!27?A!142?_!16?E$#16!164?W!51?C$#17!217?O$#18!66?O$#19!218?O$#22??_!17?@$#29!157?C!14?@$#30!219?_$#45!9?O$#46!27?C$#47!96?A!69?OA$#50!27?G!128?_A!13?G!15?G_$#51!82?_G$#53!33?w$#54!8?C$#55!4?W??@??A?_!7?A$#56!4?F!6?G!8?C!59?O??O!13?@!120?@!4?C$#57!84?C!12?C!71?C!54?O$#59!28?@$#95???o!154?_!66?O$#96!39?AC!16?W!6?[$#97!22?{!135?E!29?G!35?AGO$#98!196?FG$#99!167?C$#100!95?@$#101!26?O$#106!66?F!33?O!68?G@$#107!27?@$#108???K!7?_!147?A!37?C$#109???B!17?G!174?O$#110!102?O???@!50?O!29?@$#111!22?A!11?G!30?P!173?C@$#112!36?C$#114!67?~G~~`f_!4wk}K?@_o}}xxw^|Yy|A?_dQKEA@!116?_$#115!103?GC!52?G!12?OC!16?O$#116!10?_$#117!26?H$#118!25?^!9?_!6?~_$#120!28?A?wx^$#121!24?_!10?^!5?F?[!21?M!173?G$#122!34?F$#123!34?O$#124!22?@!11?_!203?{B$#125!82?A!135?A???@$#126!167?G!51?G$#127!9?@!11?_!60?C@$#128??A!186?A_!4?A?@$#131!4?_$#132!85?@!80?_!52?O$#133!68?v!4?!5FR??@!5?ECF_AcCAwwWILB@@!65?@$#137!221?[$#140!168?KA!49?BTb}w$#142??C!156?G!10?A!18?@O$#143??G!156?o{y{G!26?@H{FB!4?___!7?~?L?K~{$#144!167?_?@$#146!101?O?C?@!53?@$#147!8?@EO!10?C!174?G$#148??@!156?C!9?O!26?_A_$#149!8?A!186?@$#150!27?_!5?F$#152!164?_v!50?A$#153!166?C$#155!66?G$#160!26?E$#163!165?G!51?N_$#164!166?B$#169!161?@BvB!26?qB?C_??@^^^!7~?~q~r?Bw_$#170!164?C!51?@$#173!7?AG_@?SE!67?C!86?_$#174~~???~~{o??FJx!6~w!75?C$#175!28?o$#176!28?K~FE_$#178!220?I$#179!218?G$#180!80?_???A!11?@!7?@!62?@$#184!66?_!34?G???A$#185!190?M!4?W??E!24?AG_$#186??O!7?CO$#193!81?G!17?_??CA$#194!218?C$#197!27?O!75?_ow{}!43~NF~^NN!14?_w!10~^zwe_$#214!71?]WW!5?@BA??G?@?A???@@?C??O!120?C$#217!166?G$#225!97?A$#231!102?_OGCA@!43?ow?_oO@!13?OE!10?_CFXO$#237!167?OQ!55?_\ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_mugi/32x.symbols b/fastfetch/logo_mugi/32x.symbols new file mode 100644 index 0000000..926769d --- /dev/null +++ b/fastfetch/logo_mugi/32x.symbols @@ -0,0 +1,22 @@ +[?25l  ▁▃▄▅▅▅▄▃▄▅▄▄▃▁   + ▃▆▂▃▄▅▅▅▃▄▄▃▁╾▁┈▇▅▃   +▄▇▄▚▆▄╺▇┈▚ ╶▎▆┊┈▄┓▄▁▋▆▄   +▗▘▅▘┌╴▎▁ ┊┈┊▃▅━┈╴▝▎▝▅▖▏▝▖  +▏▘▘╶▘▗┳┓▁▃▌▇╴▖╶▆╷▇▇▋▝┓▝┈┈▖   +▊▘╶╴▇╴▗┈╴▇▎╴╴▝━━╶▏▖┗▋▝▖▖▖▆▝  +┊▁╹▎╷▁▄▄▄▄▎▉▏▆┵▋┍┈╻▄▇╴▚▝▏╴┊▎ +▍▉▏▉▘ ┈▇▆▅╿┧╻▆╺╸╹▖╵▏╸▘▋▏▍▏┊▌ +▆▊▗▁╼▄▇▆▖ ▋▍▝┈▘╻▄╿╷━╺▆▊▎▌▎▍▍ +▗▉▚▘▘▆▇▋▇ ▋┈ ┖╻▏┈▌┨▃▋╼▊▏▚┈▌▏ +┲┉╹▉▂━▂▏▅▁▇▄ ▝╺▆▅╽┕▏▏╴▝▝┊╴▊  +┈╴▏╿╴╻┈▆ ▖▝▗▆▆▋▋▉▏▃╴╱╸╺▋▘  +▗┚ ▗▗▇ ┈┈  ╺▃▂▘▘▃▎┈╴╱┈┊▗   +╶▏ ▌▍ ┊╵▇▇▗▘┊╴╴╶┊▖▉▘  +╹╸╶┊▝ ┈ ▋▋╴▘┊╵▉┈╱╵▘▋▘  +▎▝┐╵╸▁▂ ▁┈▁▂▘┄╴▅╴▚▎▏▁▌  +▊┊┊╺┒▁▂╷╸▆┌▇╴▝▋╽▆╴┏▊╺▉▗▍  +╴▃▅▄▂▇▇▎┊╴┊▅▃▄▊▁▃▊▘╶▋▗   +▖▍▉╴╷▖▗┈╱▆▄▅▁▁╶▘▗▌▏│▊▍    +▝▋▗▌▏┊▖╴┈▃▂▌▁▇╶┕┈▊▌└┊▌    +┉▝▉▌▎▖▋▝╺┊╷╸▇▅▄┊▊╱▊▊▏╴▖    +[?25h \ No newline at end of file diff --git a/fastfetch/logo_mugi/mugi_1.png b/fastfetch/logo_mugi/mugi_1.png new file mode 100644 index 0000000..b079ecf Binary files /dev/null and b/fastfetch/logo_mugi/mugi_1.png differ diff --git a/fastfetch/logo_mugi/mugi_2.png b/fastfetch/logo_mugi/mugi_2.png new file mode 100644 index 0000000..7eeedee Binary files /dev/null and b/fastfetch/logo_mugi/mugi_2.png differ diff --git a/fastfetch/logo_mugi/mugi_3.png b/fastfetch/logo_mugi/mugi_3.png new file mode 100644 index 0000000..e296b3d Binary files /dev/null and b/fastfetch/logo_mugi/mugi_3.png differ diff --git a/fastfetch/logo_rm/1024.png b/fastfetch/logo_rm/1024.png new file mode 100644 index 0000000..195353c Binary files /dev/null and b/fastfetch/logo_rm/1024.png differ diff --git a/fastfetch/logo_rm/2400.png b/fastfetch/logo_rm/2400.png new file mode 100644 index 0000000..3a7e0d7 Binary files /dev/null and b/fastfetch/logo_rm/2400.png differ diff --git a/fastfetch/logo_rm/24x.sixel b/fastfetch/logo_rm/24x.sixel new file mode 100644 index 0000000..e0c03de --- /dev/null +++ b/fastfetch/logo_rm/24x.sixel @@ -0,0 +1,2 @@ +[?25l[?80l[?8452lP0;1;0q"1;1;288;420#0;2;5;5;7#1;2;75;78;81#2;2;7;6;8#3;2;6;6;9#4;2;7;6;9#5;2;7;7;10#6;2;12;7;9#7;2;11;10;12#8;2;13;12;15#9;2;16;16;20#10;2;20;10;13#11;2;30;11;13#12;2;21;20;25#13;2;30;20;24#14;2;22;23;27#15;2;22;23;27#16;2;22;23;27#17;2;23;24;29#18;2;26;31;34#19;2;32;28;34#20;2;32;36;43#21;2;40;30;34#22;2;42;36;39#23;2;36;38;43#24;2;36;43;54#25;2;40;41;48#26;2;50;41;46#27;2;32;49;38#28;2;43;50;59#29;2;45;48;55#30;2;46;52;60#31;2;42;56;55#32;2;46;57;63#33;2;46;56;66#34;2;46;57;67#35;2;47;50;58#36;2;47;50;59#37;2;47;50;59#38;2;47;50;59#39;2;47;55;64#40;2;47;57;65#41;2;48;58;69#42;2;49;50;58#43;2;50;54;61#44;2;49;58;67#45;2;49;58;69#46;2;50;59;65#47;2;50;59;69#48;2;51;60;66#49;2;51;60;70#50;2;53;53;59#51;2;52;60;67#52;2;53;61;67#53;2;53;61;69#54;2;55;56;61#55;2;55;62;67#56;2;69;54;55#57;2;70;61;63#58;2;54;63;65#59;2;56;63;67#60;2;55;63;69#61;2;56;64;69#62;2;59;64;69#63;2;60;68;76#64;2;68;65;67#65;2;66;69;74#66;2;63;75;79#67;2;69;74;79#68;2;72;74;78#69;2;74;78;81#70;2;70;83;78#71;2;76;84;88#72;2;77;84;88#73;2;77;85;89#74;2;89;72;68#75;2;89;79;76#76;2;78;83;86#77;2;87;83;84#78;2;77;85;89#79;2;80;85;88#80;2;82;85;87#81;2;87;85;86#82;2;81;86;87#83;2;82;86;87#84;2;90;86;85#85;2;81;86;87#86;2;82;86;87#87;2;82;86;87#88;2;74;87;88#89;2;83;86;87#90;2;73;89;87#91;2;77;92;84#92;2;83;86;87#93;2;83;87;89#94;2;86;87;89#95;2;87;89;90#96;2;85;91;94#97;2;89;91;92#98;2;87;93;96#99;2;89;94;96#100;2;94;89;92#101;2;94;93;93#102;2;92;94;95#103;2;96;94;94#104;2;94;96;96#105;2;96;96;96#106;2;97;95;94#107;2;97;96;95#108;2;96;97;97#109;2;96;97;97#110;2;96;97;97#111;2;97;97;97#112;2;97;97;97#113;2;97;97;97#114;2;97;97;97#115;2;93;93;93#116;2;25;11;14#117;2;32;12;14#118;2;58;54;58#119;2;66;52;64#120;2;79;56;59#121;2;61;61;67#122;2;29;16;19#123;2;20;21;25#124;2;78;80;83#125;2;84;75;83#126;2;60;65;71#127;2;60;68;75#128;2;49;53;63#129;2;49;52;60#130;2;92;79;75#131;2;78;83;87#132;2;73;61;61#133;2;55;63;67#134;2;42;42;49#135;2;47;41;45#136;2;38;47;35#137;2;41;48;56#138;2;47;54;66#139;2;47;50;59#140;2;35;30;36#141;2;39;30;35#142;2;47;51;59#143;2;47;57;64#144;2;36;40;49#145;2;36;43;50#146;2;24;23;27#147;2;22;23;27#148;2;26;27;32#149;2;27;31;35#150;2;90;83;82#151;2;77;85;89#152;2;70;66;68#153;2;67;69;74#154;2;80;84;86#155;2;84;83;88#156;2;43;47;56#157;2;43;54;64#158;2;49;57;63#159;2;49;58;67#160;2;15;16;20#161;2;16;17;20#162;2;29;18;22#163;2;31;21;25#164;2;47;57;63#165;2;47;57;67#166;2;77;88;84#167;2;76;89;96#168;2;82;90;93#169;2;83;86;87#170;2;46;50;57#171;2;45;52;60#172;2;39;41;48#173;2;40;44;51#174;2;52;54;61#175;2;53;56;63#176;2;92;91;90#177;2;95;89;87#178;2;43;37;41#179;2;36;38;45#180;2;51;60;66#181;2;51;60;70#182;2;52;60;65#183;2;52;60;67#184;2;49;59;68#185;2;50;59;65#186;2;53;62;67#187;2;53;61;69#188;2;62;67;74#189;2;65;65;70#190;2;87;90;92#191;2;85;91;94#192;2;94;94;93#193;2;93;94;95#194;2;10;9;12#195;2;12;10;12#196;2;28;31;32#197;2;31;32;37#198;2;54;58;68#199;2;55;60;65#200;2;56;65;74#201;2;60;63;70#202;2;50;59;68#203;2;50;60;69#204;2;50;60;67#205;2;51;60;66#206;2;22;23;27#207;2;24;25;29#208;2;52;61;69#209;2;53;61;67#210;2;69;73;78#211;2;69;75;79#212;2;69;81;74#213;2;74;83;88#214;2;44;50;57#215;2;46;49;57#216;2;13;11;14#217;2;14;13;16#218;2;77;85;89#219;2;81;85;87#220;2;7;6;8#221;2;7;6;9#222;2;88;90;91#223;2;89;91;92#224;2;95;95;94#225;2;94;96;96#226;2;7;6;8#227;2;6;6;10#228;2;13;6;9#229;2;9;8;11#230;2;62;73;69#231;2;67;74;79#232;2;71;74;78#233;2;72;75;79#234;2;94;86;85#235;2;82;86;87#236;2;84;88;90#237;2;85;88;89#238;2;32;34;41#239;2;33;36;42#240;2;75;92;80#241;2;81;91;96#242;2;83;86;87#243;2;83;87;88#244;2;94;94;95#245;2;96;94;94#246;2;19;10;12#247;2;21;11;15#248;2;91;77;72#249;2;83;80;82#250;2;96;96;95#251;2;97;95;94#252;2;50;53;60#253;2;50;54;61#254;2;72;78;81#0!255?!33?--#10!19?C!9?O!100?O??G??O$#11!19?g$#13!32?_!68?_!25?_$#22!24?G$#54!30?_!98?_$#64!20?G$#65!133?O$#95!135?o$#97!25?O$#108!21?G!4?_$#109!25?_!108?_$#110!21?_OoO??_!104?_$#113!21?O_?_!108?_$#115!20?_$#116!20?A!105?_!9?G$#117!25?G??O$#118!20?CC$#124!29?_!100?_$#135!27?O!104?O$#152!23?G??O$#162!22?C!108?O$#163!19?O!116?_$#178!31?_!96?_!6?G$#223!134?O$#224!22?G!108?_$#228!30?O!4?_!18?_!69?_!4?O$#236!20?O$#244!28?_$#246!21?A?C??G!7?_!67?_!22?_$#247!33?_!100?G-#1!28?C?G?O?_!71?C!18?@!6?G$#9!54?G$#10!71?O!4?G!16?_!23?@!18?A$#11!19?J!116?C$#13!53?C!4?O!40?A$#19!49?C!44?_???C??A?C$#20!101?@$#21!72?O!5?O???__$#22!59?_!50?A$#25!97?G$#26!104?C$#29!48?C$#40!154?__o$#50!42?A!69?A!10?@$#54!70?_??O!47?_$#56!30?O?_!92?O??G$#57!21?_$#62!96?O$#64!20?G!6?C!49?O!53?_$#65!54?O??O$#68!20?@??E!91?A!16?C??G$#73!56?O!39?_o$#74!24?O???G!96?_?O?G$#75!24?G?C!104?G$#76!100?G$#79!45?__$#80!74?O$#81!24?@$#92!76?O$#94!71?_!45?A$#95!23?P!9?@!68?G!25?C???O$#96!102?_$#97!39?A$#102!21?C!22?_!10?_!43?O???O$#104!103?_$#105!21?G!7?C??@!68?O!17?A!7?@!4?_$#108!31?G?GG??_o_OGw??GOG?O?o!21?_?_!29?_gWo???ogGOO?W_G???G??C!5?G$#109!27?B??@!4?o_OA?g_?GC!4?g!22?_!4?_!22?O??GOG???KSS??C?_G!4?A!10?@$#110!22?N??@??A@C???EAE!5?C???G!59?O!5?K??C!5?A?A?EA?B@?@??F@$#111!21?@!4?@?@AA@CO?C???CC??C!69?C??CCC?A!5?C???A?@A$#112!33?AOG!12?O!4?_!57?G???_?_??CC?C???A!6?O$#113!22?o!8?EIC??WMKW?S?_G??OG?o?o?_!19?_?_!27?gO?_Gog_?OoGGO_[OWKGE!4?A@??sG$#115!45?C!7?O!64?A!13?A$#116!20?_!24?A!4?C!35?_!9?G!5?C!4?A!10?@!17?O$#118!20?A!8?G?O?_!88?_?O??G$#120!31?_!91?__?O$#121!35?@!43?_!25?C!7?A!10?@?G???C$#122!19?C!33?G??CG!22?_!4?_!9?O!6?A!5?A!10?@$#124!40?A!5?C!69?A!18?O$#134!36?@!74?A$#135!52?G!69?@$#137!152?_??O$#140!136?@$#141!37?@!83?@$#143!153?_$#145!157?O$#149!151?_$#150!24?C$#151!57?_$#152!24?_A!105?S$#153!51?G$#154!120?_$#162!20?O!17?@$#163!44?A!10?A!13?_!11?_??_!15?@!8?A!10?@$#164!157?_$#178!43?A$#188!56?G$#189!41?A!5?C!53?G!12?A!8?O!11?C$#190!47?_$#193!21?A!26?_!26?O!58?_$#197!54?E$#207!135?_$#210!129?C$#211!99?C$#213!20?C!34?W!42?G$#218!56?_!41?OG__$#222!50?G!56?C!18?@$#223!43?OO!77?O!8?A???A$#224!23?_$#225!21?O!23?O!56?O!5?C$#228!41?@!5?A!7?@!21?G?O!25?A!7?@$#231!55?C!39?_!4?A$#233!34?@$#234!25?{wwo_!96?__oow$#236!98?__$#244!78?_$#246!40?@!5?A!4?C?B@!5?_!7?_!5?G!12?__!8?C!4?@???A!7?@@@!19?_$#247!39?@!35?G!25?C!34?G$#248!24?A!4?O_$#249!23?G??A!98?G$#254!58?_!41?C-#1!36?@!31?@!7?O!54?A!13?AGC$#10!21?A!39?@$#13!132?_$#21!64?A$#23!60?@!77?A$#26!116?GgO$#29!37?G!76?G$#32!134?ocO$#40!144?_!6?`f!4~V$#42!38?_!50?@$#46!151?AO$#50!40?G!91?O?@$#51!99?G!43?G!6?O$#52!83?G$#55!83?O$#56!34?@?A_!78?C?A?@$#59!100?O$#60!61?C$#61!78?C!7?_!4?_!9?O!41?C!4?_OK$#62!72?C!14?G!4?_$#65!79?O!5?G!6?A$#68!24?@!13?A!45?_???G!6?C!35?C$#69!71?G!75?A$#71!53?_!40?@???C$#72!102?O$#73!48?@AsScC[WKH@A!17?GG!8?O!7?@@@???G$#74!27?GB??OOoo!85?SA?@???GO$#75!24?C!105?g$#76!145?CC$#78!51?A!46?@$#79!49?@$#80!65?O!10?A$#81!23?AO$#94!63?_???G!15?C!13?G!15?G!17?OGA$#95!75?O!4?@!18?O?_$#96!46?@!59?G$#97!66?A!6?A!12?@$#101!23?G$#102!47?A!7?AA!44?C$#103!24?_$#104!40?_!7?C$#105!22?@!43?_??@!15?@C!14?@?C$#108!23?@!19?CAC?C!6?@???_?o??W?CC??_oBO?_?_@@??sEA?A??A???CO?_??OA!5?`F?`_oC_r!19?@$#109!39?@B@S??@?O!5?@!7?o??C??C?O??A_?_?_A@a!6?A??AC!4?G__?_A!5?PGW?OCC?P$#110!41?A!6?_!17?G!20?C??G!5?OO!4?A?E!4?AG!5?@$#111!43?_!30?O!29?@!27?@$#112!47?_!45?CG!8?A!5?D?_$#113!37?@@?OobZ|yq!5?@??@???_??w?WG?aeABo`P@@@?_a?I`@B?A?CECGWGoW_??_A?@@?E_eU?FJZ?rA?@!14?A$#115!59?O!17?A???@$#116!63?A??@!24?@$#118!35?@GA?C!75?C?A?@$#120!26?WU!4?@@E}sCC!78?Cc}i``_!4?G$#121!41?G!16?O?G?C??A$#122!22?G!39?A!29?@$#124!75?A!4?G?G!4?@!28?A?@!27?A$#126!66?O!4?C?C!11?_G!10?C!45?A!5?G$#127!74?G??C!67?O???A$#129!37?O$#130!25?O?@??O@_C!90?OOGC?G$#134!23?_!14?G!22?A!71?c!13?@$#135!67?@!47?G??G$#137!136?A???A$#139!55?_$#141!90?@$#142!59?G$#143!136?_!5?[O$#145!139?A$#150!121?G???C!4?SG$#151!47?@??AgWW?C?CA!27?O!15?G$#152!24?A!106?@$#153!22?AO!16?C!27?G!8?O!38?_$#154!63?C!10?A$#156!57?O!76?G$#163!21?@!111?OC@$#164!135?WK!5{a_!13?_$#168!48?G!7?@!46?O$#169!84?C$#171!141?A$#175!93?A!8?_!32?A$#178!39?G$#179!22?C$#180!149?@$#182!89?O!4?A$#185!145?_$#187!146?_??_AG$#188!54?_?O!7?_!13?O!8?_!56?G???OC$#189!88?@?O$#190!49?G@!46?A!6?O$#193!46?G!60?G!7?_$#199!56?_!12?G!26?C?G$#200!147?_$#204!150?`SG$#208!144?O$#210!72?G!6?C!23?_!42?OOI$#211!75?C!8?G???O!6?A!21?O!26?E???C$#213!59?@E!15?G!12?__!9?G$#214!157?G$#218!38?O_!8?AOG?A!4?ACC!25?O!10?A!6?GG$#222!61?G!18?O!4?C!7?_$#223!41?C!6?O_!4?A??_!33?Q!8?D!4?O$#224!23?C$#225!39?Q!6?C!4?@!28?C?O_!5?G!4?C???A!5?_?O!25?C$#228!21?C!43?@$#231!58?G!14?GCGC!11?_$#233!70?C!43?C$#234!25?nb_k~nmMGG!86?CMMNjrrfvB$#236!47?G?C???A!45?D!5?G$#238!137?A$#244!42?G!25?OC!32?C!13?O!14?_$#246!22?O$#247!133?GA$#248!26?C?O!4?A!87?OOO_?C$#249!24?G$#253!93?@!54?@$#254!65?_?O??G!8?G!4?O!60?G?G-#1!34?O??A!10?O!55?A$#10!24?_$#13!131?G$#20!105?A??G$#23!130?O$#26!31?A?W!4?@!81?AA$#28!114?A$#30!42?C!61?@!4?GGG$#32!132?Gqnx?q$#40!145?avcuyI~~~^F@$#42!32?C!10?G$#43!44?G$#46!147?@??@$#54!120?O_$#55!49?C!43?@$#56!31?_!5?@!83?OiA$#59!51?A$#60!96?C$#62!48?G$#65!50?C!47?GO$#68!25?_!8?G!12?__!48?C$#69!62?@!28?@??A$#71!40?@!69?C!18?_$#73!47?C?A@!9?C!51?OwwS__$#74!31?G@!88?@???A$#79!35?C!9?C!12?G!50?C$#80!42?G!12?_!50?G$#93!105?@$#94!33?C!62?A$#96!35?G$#97!33?_!4?A!82?C$#98!96?G$#99!97?O_!12?A$#100!130?@$#102!25?O!8?C?G?_??@???O?A!11?O?@??@!64?O$#104!41?_?A!6?O???A!8?A!43?O$#105!37?_??sOoo??A??__??_!4?C!27?@!8?@!6?@C??@_A?A??@!4?O$#106!25?C_!101?OC$#108!35?__GO{GG!4?@!6?GWCI?AA???_??ZQOBBAa[GSSsAB?HGHO??WQ?ACG??gO_A?Goeak???_!21?A$#109!24?@!10?OOSG!4?@AA!5?OoS_?@!5?{??j_?Ew_TD_O@??@_A_AOFHG???g?S_S??A??@G???o_!12?G$#110!61?G??I???@C!4?DG??O?@?C!8?G!15?@?A$#111!38?C!12?_???O???_!14?A!16?_!9?C!26?_$#112!44?@??@!4?G??A!7?G?C!11?A!4?@???E_?OC?_?_!5?C???O!6?@!7?O$#113!25?G!8?_!7?@??@!8?CGCF@@po?SsOClg?[gWB_ajHk[{UoeguoEkmOQA[GO`@DNQBWW?GO?@@@?@!16?G$#115!51?G!68?g$#116!23?A$#118!118?AA$#120!30?_SW!4@!80?!4@?OgE$#121!24?C!7?aA!11?_!6?A!64?A???G$#122!24?O!105?_C@$#124!49?G!38?@$#126!130?G$#130!30?O!92?PG$#134!131?A$#135!123?C$#137!112?C!41?_$#141!132?A$#143!141?G?@~\GYGCs$#144!109?O$#149!107?G$#150!29?_$#151!115?g$#152!122?C$#153!41?C!11?A!36?@???@!5?_!5?A!24?@$#154!52?C??@$#158!45?G!61?C$#163!23?@$#164!132?oLOE~L~~~v~}$#168!117?C$#170!110?_$#171!131?_!24?A$#173!155?G$#175!40?A$#177!25?BW!101?GA$#178!24?G!91?@!14?O$#182!113?C$#185!46?GG!67?@!33?@$#188!52?@!58?_$#189!35?AA!9?O??O$#190!36?C!5?A!16?C?C!33?C!18?@???C_!10?C$#193!58?_$#197!157?@$#199!34?A!15?GC?@@!40?A!12?O$#204!148?@$#206!106?C$#210!89?@!13?@$#211!50?A!62?A$#213!43?C!4?C!7?_!4?A!48?O???C$#214!39?@!92?C$#218!46?C?A@?@!5?oOG!48?C??O_???[?_$#222!46?_$#223!39?A!4?_???@!7?O???I!26?@!19?A!9?W$#225!44?O!12?G!35?A!24?GCC$#231!41?A!55?G?_!11?C???A$#232!105?C!10?A$#233!47?O$#234!26?F~~^N!93?p|~~F@$#236!44?C!17?A!49?A$#237!109?_$#243!24?A$#246!23?C$#248!31?@!90?@$#254!63?@!28?@!5?O!13?G-#1!46?A!5?C!63?G$#10!25?C$#20!111?C$#21!128?_$#25!122?G$#26!25?@!4?@_G!89?C@$#30!39?_!73?G$#32!129?_{|]^~\v@_$#35!45?A$#40!145?@Q|e||mN@$#43!44?C!67?@$#50!123?A$#52!51?O$#54!32?a$#55!41?O!59?A$#56!30?_E!92?A$#60!103?O!8?G$#62!34?C!5?O!11?G!61?W$#65!103?G!18?A$#68!26?C!74?@$#69!45?C!81?O$#71!34?G!16?_$#73!110?C???@?@@E?GA$#74!28?o@C!92?_?A$#78!119?C$#79!36?A!64?C!14?_$#80!118?_$#85!35?G$#94!50?O!51?A!4?@@!5?C$#96!106?A!10?_!10?A$#97!33?_$#98!53?O!45?@!26?_$#100!27?A$#101!45?@$#102!36?G?QG???_!10?GCA!45?O??B@?c_oo???O$#104!39?E?@@???CAFMCC??oO!43?__!5?C???@$#105!35?psKK@@!8?@@BB@?GOWw__??_!23?_??__o_WowooW[O??CG?C$#106!125?OC$#107!27?C$#108!32?@?`!21?GACHZGTG@sa?PBCTdC?sXaO?KpC?_?OGg_CBKS??ABDA??@@!22?W$#109!27?G!5?@A!21?C?BE?e_??AO?C?A_O@_IC??F`KP??o?OAGWWA??GDC?C???AA$#110!65?@?A!57?_$#111!26?@!19?_!12?OCOG???C_??_!6?O__O!4?C_AOO???G_E?GG!6?C$#112!63?Sg!4?_O??AP@??A?A??`A!5?A??BC???A!28?E$#113!44?__O!10?C???@ABUGH\i[HIIwM?aLLW?AiMWJNDDE@C@?B@$#114!45?O!37?OD!4?@$#115!49?_!62?A$#118!27?_!93?__$#120!29?qYWO!89?OK@$#121!32?C$#122!26?o!101?OC$#124!35?C!11?@???G??@!56?A_???O$#126!43?O!66?A?C$#127!33?C!80?_$#130!28?A!96?@$#134!26?G!6?O!96?A$#139!112?O$#140!121?O$#141!129?G$#143!135?_!5?G@pv}lAXAAP$#148!129?A$#150!28?@!94?O$#151!52?O!63?AA?BA$#153!31?@!9?C?AG!68?A?C??O$#154!43?@$#158!121?C$#162!25?A$#163!130?@$#164!131?A`_?AG}^~~v}MG$#168!100?A$#169!44?A$#171!129?O!23?A$#173!127?_$#175!50?_!51?C$#177!27?@G!95?_G$#179!128?G$#182!38?_???G!71?A?C$#185!118?G$#188!40?_??G!9?C!46?@???_!4?A$#189!43?C@?@!64?@?C???W?__$#190!36?@?@!13?_!50?_$#192!127?@$#193!45?G?g_!52?G!4?_O?O!17?G@$#197!153?C$#199!39?O??_$#201!40?G!74?G???O$#210!33?G!7?G!86?C$#211!54?A!53?A!4?@$#213!41?_!73?_!4?CG$#214!113?_!38?O$#215!120?O$#218!37?B!15?GCA@!50?A!7?@??@?@$#222!34?O!69?O$#223!37?_!72?G$#224!104?G?G$#225!26?A!8?A?O??EA!4?GSGOI!4?___!43?__C@OOG?H$#231!111?G$#232!122?@$#233!42?E!10?A$#234!28?CK!94?OCB$#236!109?C!11?@$#242!33?A$#244!44?O???O!4?_???@!47?_?_W$#248!124?K$#249!27?O$#253!129?@$#254!42?O!12?@!46?G!10?O?A?C?G-#10!27?G$#11!25?@!102?C$#13!128?A$#19!28?G!98?O$#20!35?G$#21!129?A$#22!26?@$#25!128?@$#29!26?A!100?C$#32!126?__?@N^~n~jf~\b_p$#40!145?OB_DB$#42!123?@A$#50!121?_$#52!41?@$#55!36?A!78?O$#56!124?@$#57!32?_$#60!48?C$#61!114?GG$#62!46?_!54?_$#66!114?@$#68!30?@_$#69!35?OG!76?_$#71!28?C!19?G!67?_!5?O$#72!30?G$#73!27?A?CCCKCCAoWGA@!72?C!7?O$#76!99?C!5?C!18?C?@$#79!36?@!13?A!68?@@??C$#80!116?A$#81!125?@$#82!112?C$#85!106?G$#95!64?_$#96!120?I$#98!35?@!68?A!17?C$#99!88?_!10?@??G??O?[KA?E!9?G$#102!40?W[w_oOEB_!6?_!29?o?_?_o?O?O?wxwW??C[{_RBBD@!5?@$#104!34?@!7?C!11?G??BICMGhKGwWG_OG?GGoUWO[[?KMcLAEC?ECAAbB@!12?_!8?A$#105!42?AG!14?@J@EEAFECEKMCEFFNG?M@?KR?BA@@BB?@@@!15?O???_!5?AC?C$#108!50?_!10?@?@!6?A!7?AB!40?C$#109!32?@@!11?C!4?G??_???O???O!4?B@A?@@?O?@F@?_B?@!6?@!16?_??G$#110!107?_$#111!45?A!5?KKW_???_!6?@??@@OWo!8?_!28?Og$#112!43?@!38?_$#114!43?EF@!4?Ooo?O??_Ooo_!8?__?_!6?o!28?ogO$#115!46?G???C!48?__!4?G!4?A$#116!25?AC??_!99?O_$#121!122?@$#122!127?@G_$#124!39?O?A!58?O$#126!100?G$#127!35?C??O!76?A!7?_$#129!33?O$#131!122?A$#134!130?O$#137!38?@!77?G$#141!125?_$#143!133?O?SO?a[NM~~~n{^y[F@$#144!36?C!88?A$#145!37?A!75?@$#146!125?O$#149!33?_!86?_$#151!31?G?G?_??C!85?G$#153!46?O$#154!98?@$#156!126?C??G$#158!116?O!7?O$#162!128?O$#163!126?O$#164!136?G???O!8?_$#168!33?A!17?@!50?O!16?G???G$#171!114?C!35?G$#173!27?D!86?A??_!11?C?_!19?A$#175!31?O$#178!127?A_$#179!34?O!91?G$#182!30?O!6?@!78?C!5?_$#183!115?C$#185!115?_?O$#188!29?G!10?A!58?A!13?Q?@$#189!28?@@!10?C!80?@?A$#190!49?G!62?@!4?C$#193!30?AB!11?O?G??@??A@BCGo!27?_?oO?O?wgWg{!5?AAB!6?C!8?A$#197!29?O!120?O$#199!32?O!6?G!7?G?@!75?C$#201!38?_$#207!127?G$#210!48?A$#211!30?_???G!79?_!8?O$#213!37?_!12?@!63?O???_O!5?G$#218!34?A!12?_?C!51?G_!9?A!5?W??A$#222!42?@!55?A!7?C$#223!29?A??A!30?_O!35?AC?_!7?@!5?@!4?G$#225!54?@?HKC???OO???oO!14?G?CG?G?A??C?ABA??@!17?C$#231!39?@!9?A!50?CO!11?G$#236!28?A!19?O!56?@!6?G!5?@$#239!124?_$#243!45?_?C$#244!39?___??G?@??o??ACAVE!9?_??_!5?!4_???OOOG?GSGGCC?C?CCC??@@!9?O$#246!28?O$#252!126?A$#254!34?_??CAC!7?O!56?@A!11?G?_O-#1!44?A!46?_$#11!122?G$#13!123?A$#19!31?O!90?O$#22!133?_$#23!132?A$#25!124?A$#26!86?_$#30!31?C???O!81?_$#32!124?O]~~~}{w_F~~bU}XFw!7?C$#40!145?agE@$#43!117?O$#52!121?A$#54!121?@$#55!37?@!78?A$#61!116?G?_???A$#62!44?C@!15?_!9?_!43?G!7?@$#65!37?A$#69!62?C$#71!119?@$#73!33?AMF!9?C!56?@G_!12?C[wq_@$#79!44?O!59?O$#80!62?O$#85!46?A$#95!102?_$#96!104?G$#97!38?@$#98!104?C$#99!63?C!20?O??C$#101!71?G$#102!37?C!5?@_?C!7?W]~}}{{K_w!4{}W!8?C??GWGGB@jF@!6?@BBB@C!6?KK???@$#104!38?CAOkG??ogo_oO!10?A!7?B???G!4?A!9?_wo!4?!4_?__!4?_s_Asc[I$#105!38?I{gO!15?@?@A!9?G!20?@@`o!4?K?W???@!5?O?oW_$#108!37?_$#109!37?Wo!13?@!19?C!5?@!11?G???C!17?_?_$#111!61?@!8?@AB!6?B?@ACE!5?CC?SG!10?A!5?@$#112!36?_!53?@!9?O!8?@$#114!60?@!9?ED?F!6?FA@B!6?AAMI!6?K!6?B??BAB$#115!36?O!5?OC$#116!30?A!92?C!7?B$#122!30?O!93?@!5?@$#124!61?O?A!7?O!29?A!13?O$#126!33?@!52?C!15?K!12?CO???@$#127!32?C!82?@$#134!33?_!97?C$#135!30?_$#137!147?_$#140!132?GO$#141!32?_!90?O$#143!136?C@@EwF~n~\VX]g$#144!31?G!117?@$#145!31?AA!115?_$#146!121?G$#149!32?@$#151!33?C@!68?C!13?A$#153!36?G$#154!63?@!22?A!4?O$#156!124?G$#158!118?@AC$#162!31?_!100?C$#163!123?G_$#164!136?Wg?_???O$#168!103?@!5?_$#170!86?G$#171!122?C??`!6?P!16?O$#172!86?O!36?_$#173!129?@???G$#179!30?@$#182!33?O$#183!116?C$#185!34?O$#186!114?@$#188!43?O!57?@?_!10?A$#189!35?_$#190!45?G?@!33?_!10?_!16?O$#193!41?@BA@???CBFE]~f_???A!4?B?AA@?o?wokGQMGWO?cO?C?OG??G??@@AG??A!4?_MG$#199!85?_!30?_$#201!36?C$#207!30?G$#210!102?O$#211!31?@!53?O!16?A!13?@??CGC$#213!33?G_GA!6?_??@!56?O!13?G!4?_$#214!124?C!5?A!19?_$#218!36?@!66?A$#222!114?C$#223!62?A!22?G$#224!47?C!30?_$#225!39?@E?C???O?O?g!18?C!4?A!9?@!4?E??O?AGOO?_!4?A?O?B??G?C$#228!29?L$#231!32?G!12?A$#232!62?G$#233!42?_G$#236!84?_$#239!30?C$#244!40?@A!5?IJK?x_??@??@???@??B@@?_!4?PvlpOcgS?_!4?O!6?UKC[!5?@[@?O?G$#247!32?O$#250!99?O$#254!44?G!70?A?@A??O-#1!71?G!9?e!9?B$#10!29?@$#13!31?O$#18!146?@$#19!31?I?C!90?_$#21!131?O$#26!33?O!53?_$#28!145?A$#29!32?O!54?O!32?A$#32!122?_!4?@BBFN^]}}~}\^E@?o!7?AC$#42!131?_$#49!32?@$#50!29?G!40?C!16?G$#55!92?C!25?G$#56!86?A$#59!83?_$#60!119?A$#62!104?G!13?O$#65!103?A!12?@$#67!63?_$#68!33?_!25?G!10?A!16?A$#69!30?O$#71!80?C???@!36?A$#72!83?G!34?A!4?@$#73!83?C!20?A!14?W?@@EKWO$#74!84?_?G$#76!81?@$#79!30?_!11?A!39?O!10?__!10?C$#80!69?_$#93!51?_!31?A$#94!35?@!51?@$#95!126?C$#96!41?G!67?_G$#97!57?_$#98!83?@!21?@$#99!80?@!13?G!15?C$#102!40?W?C!10?A@@@?@B??!5FBB@!9?G??C!10?@!33?G$#104!40?C!7?@BMM?o?_!16?{m]mAM!4?A!5?AA@???D??@!4?@!4?@$#105!38?@?_??ABBBF]S??_!20?O_OooK!9?K{K???AVFMFBFB!4?B?B?@$#108!49?GO!25?G?O!17?G!9?C?C??_$#109!34?_[vPI_BoW[Ss[g_!39?o?oo???GO?GC?GMO???Ig??XjhFVC_$#110!38?_???_!70?O??GO$#111!34?O?G??Z!4?gG?O?_!47?O?ogco!4?sO??A?EGG$#112!37?ACC???_??_!31?_!17?__OGOO!9?CC?O?O$#114!35?a?kO!59?_!4?_!8?O?___$#115!54?A!7?g!6?O!46?A$#116!120?C$#118!84?G@@$#121!29?O!41?A$#122!33?@$#124!56?_!14?O!9?W!21?C$#126!103?@O$#131!41?C!50?@$#132!84?OAC$#134!33?A!36?G!49?_?O???@???G$#135!70?_!56?C$#137!144?O!7?A$#139!34?@$#140!31?C!88?O!4?_!4?O$#141!121?G!5?A$#142!59?O$#143!137?@a_X}~NF@!4?@??G_$#144!117?A$#145!154?O$#149!149?@$#151!120?@!6?_$#153!34?C!23?_?_!10?C$#154!41?A!29?_!23?_!22?_$#156!121?O$#158!92?G$#162!29?A?_?G!86?G??O?@???G??_$#163!31?@_!89?G???A?C$#164!135?@!4?_$#168!105?A???O$#169!129?O$#171!123?_!20?G$#172!60?G$#173!153?O$#174!92?o!31?O$#175!61?@!55?C!6?@$#178!29?C!4?A!35?O!50?_$#179!60?C!60?C$#185!117?@?@$#188!84?A!34?_$#189!29?_@!97?G$#190!43?@!8?GC!25?_!13?A$#193!34?G!18?H?EEVYC?W??WWGGCE!21?G!18?A!17?O$#199!59?_O!23?C$#200!32?M$#201!60?A!26?C$#210!30?K$#211!80?o!37?@$#213!122?C$#214!129?C???`@!16?@$#218!82?_!10?[!10?@W!4?_!11?A?ACGO_$#222!50?_?O!10?O$#223!51?O!9?C!8?@!8?O!26?O$#225!51?@??wOO!4?_??!4_o!7?D@B@??@!5?@@A!38?_$#228!28?o$#231!42?@!40?O!8?A!30?G$#233!30?A!30?A!42?_!20?A$#236!60?@!19?A?G!11?O!11?_??NO$#237!91?C$#239!153?C$#242!117?G$#244!41?@!8?@?F?CGGGC???OG??OSGG??B@@@???E!23?G??G!23?_$#248!85?{o$#252!71?@$#254!80?G!23?C_!12?CC!6?_-#1!54?O!33?A!4?_??I!41?_$#11!121?C$#13!133?@!5?_$#19!54?_$#21!60?O?O$#22!30?G!24?_!32?_!32?@O$#23!155?A$#25!32?A$#26!58?O!11?@!64?C$#28!147?C$#29!55?O?C???_!59?O!10?G!6?O_$#32!122?F^~}}{wwoo_??@BB@FB???_!6?_$#40!145?G?GOo$#42!59?_$#54!29?@!51?_!6?C???@?O$#56!57?o!5?O!6?A!12?A$#59!93?A$#62!48?OC!31?C!23?@G_$#64!53?_$#65!32?C!14?_!7?G@!39?C$#68!57?A!13?O!26?_!33?@$#71!110?K$#72!128?@$#73!110?@$#74!58?C!5?O!5?o!12?G???G$#76!32?G!17?A!29?C?A!12?A!14?O?_$#77!62?_$#79!82?@!11?B!11?BG_??{!18?A$#80!55?A!15?@O$#81!52?_???G$#85!94?CC!11?CO$#93!79?C$#94!53?O!19?_!6?_!15?_!36?A??_$#95!49?O??G!19?G!6?o!9?O$#97!47?O!24?CO!47?_$#101!88?@$#102!72?A!36?G?@$#104!54?@!10?BBAB!23?C!14?@!23?A$#105!48?@??AB@!10?A?K__!5?A@??@!17?@!11?C!23?C$#106!85?O_$#107!65?O!9?_$#108!39?CO!57?O!14?@$#109!33?GA[HQHgfkOgxEED???K!16?G!5?@OFBC!11?BA!5?DA@CC?RA???@???AG`kJH@G!15?W$#110!34?C??D!4?C!46?A!13?C!11?A???O!12?A$#111!33?cH???A@?B?DAh`AA?O??A!10?GGoWO!5?{Mg{w!10?KoW_!4?AL}gr|gkg!6?D_U?cAC?_!10?@?C$#112!32?_!5?C???@?C!7?C!25?A!10?@C@!8?B!7?A!4?A?@???C$#113!34?o??_OO!6?O!45?O!24?_O$#114!33?Q?BUG_AGOiQ?OGG!28?O!13?GcG!7?OGA?OO!7?SGOOSi_O!13?G?O_$#115!49?_?O???@!53?C!23?G$#117!61?O$#118!59?A!22?_@???A$#121!52?O!6?K!9?w!12?W!10?O!42?G$#122!29?CO?@!88?G$#124!60?@G@!8?G!20?A?G??g!7?C?O!11?A$#126!48?G?@??G!51?A$#130!84?O?B$#132!57?G!12?K!12?C???C$#134!125?@!4?G$#135!29?A!57?@!6?_$#140!134?A$#141!31?_!95?AA???O??A$#143!138?E?CFFF^u{o_?_$#145!146?A$#148!88?O$#149!145?@$#150!60?_!24?@$#153!49?A!6?A!14?_!23?@!41?O$#154!48?_G!21?C!23?_!24?G$#156!120?E$#162!122?_!8?G!5?GO$#163!31?O!27?O!61?A!4?@??C???O_?C$#164!139?GWgGW!4?G$#169!53?CA!5?A!10?A$#171!122?G!14?C???O!12?@$#172!31?@!27?@$#173!58?@!34?C!56?O$#175!81?O!45?@$#176!60?K??G_$#177!58?G!4?_!21?AG$#178!56?_!73?C???@_$#179!93?G!60?A$#188!31?G!49?A!47?A$#189!56?O!12?A??_!16?_!7?O$#190!79?@!29?_?A$#192!85?CO!19?_$#193!33?@!78?G!21?C$#197!58?A$#199!51?_!10?I!18?G!37?@$#201!69?C$#210!54?C!8?@!17?@C!23?S!27?O$#211!80?@$#213!31?C!61?@$#214!123?_!4?C!4?_!4?G$#218!30?B!79?A!18?@$#219!80?G$#222!48?C!14?C!45?@$#223!50?C@!9?C!11?N!33?AGA??O$#224!57?@!6?@$#225!35?_!13?@g!10?B!5?@!4?@!57?@$#231!31?A$#233!55?C!13?@$#234!84?_?C$#236!36?_!42?A$#237!79?G$#238!88?G!53?O!12?C$#242!95?G$#243!54?G!8?A!16?O!14?OO$#244!32?O!71?@!4?O$#248!83?oN??o$#249!56?C?_$#250!64?Cc?CC$#251!85?g$#253!62?C!57?@$#254!30?C!49?A!29?_!20?C-#1!73?@!7?O!18?C!40?C$#13!140?@A$#18!151?O$#19!123?@?O!12?A$#21!88?@$#22!47?O$#23!153?`$#26!82?_!6?G!4?AC$#29!81?A!7?C!49?G?@$#30!34?G$#32!124?@BN^~~}nN}r}Cs!14?O??C$#40!147?@?ABNN]{woo_$#42!31?@!17?C?A???G!16?_!4?G$#50!55?S!4?_!63?G$#54!50?@!8?B!12?B!8?C!8?G!46?@$#56!48?_!4?@!16?_O!10?M!4?@?O@?AA?I??_$#57!47?_???@!4?@!41?O$#61!33?_$#62!47?@!60?A$#64!50?A!4?@!4?O!8?C$#65!34?CA!11?G$#68!60?G!7?_!5?_!21?A??c!9?O$#73!32?_G???O$#74!48?O!7?C!13?N!17?A_?A!4?g?GO?_$#76!109?C?G$#79!36?_?W!72?B$#81!68?O!27?@?A$#84!60?A?B!13?O?O?E!16?AC$#85!109?@??O$#94!80?@!13?G??@!16?_$#95!48?A!27?@$#97!45?O$#98!32?G$#101!108?G$#102!31?O!5?C$#104!39?A$#105!35?_G!31?A!9?C!12?C?O!12?_??_$#106!53?oW???Z!25?kssK_$#107!64?G!9?A??A!25?G?A?_$#109!32?E???AB@cD{AbAD!60?@!7?QAPpd]FBS_$#110!36?C!6?C!71?O??G$#111!32?@!6?X_@OOPI@!17?EF}M!7?F?@B!13?[go!5?BFLv|{][o!5?GKAK??G_A$#113!40?G?@!70?@?`??A?_Gg?_$#114!33?@?O!4?QAkGk!29?@!29?A@!8?D?kAO`OS?W$#115!67?O!31?@!7?A$#116!30?G!109?G?c$#118!50?C!10?_!9?K?[???_!4?P!7?_???DP$#121!55?a???C??_!6?B?B[!5?_!11?C_!9?O!20?@$#122!30?O!105?@!4?O$#124!31?C???C!75?o!11?C!15?BA$#126!113?O$#130!52?O?A??}!25?_!4?G$#132!49?G??A???A!13?O_?_!17?@!5?O$#134!124?A?O!16?O$#135!52?@!8?O!35?G$#137!154?A$#140!61?G!61?A$#141!125?G$#143!146?@?BDC!5?G$#144!158?O$#149!61?C!95?G$#150!56?O???C?C!6?_!11?_!15?C$#152!59?G??O!6?G!6?C!4?G!8?O$#153!46?_AC!18?_!39?@C?G?@G$#154!46?A!61?@!4?C!11?_$#162!124?C?_$#163!30?_!58?@!47?A!6?_$#164!130?@Oo@K?wGwo_$#168!33?C$#169!47?C$#170!140?O_$#171!125?C?_!8?A!10?A$#172!61?@!79?G$#173!46?O!63?_!32?_?@!13?_$#175!110?O$#176!59?_???C!10?O!4?E!11?G@!8?G$#177!52?_G??_???@??w!12?_???w???B??A$#178!81?@!14?C!38?@??C$#179!48?G!40?A$#188!112?A$#189!31?A!14?C??A!23?A??A!14?O???_??@AG?_!39?G$#190!31?_!4?O?A$#192!54?C!8?B!10?G!4?w!12?_@$#193!34?@$#197!61?A$#199!140?C$#201!34?_!11?G!62?G$#210!110?F??_$#213!33?O$#214!34?O!115?G$#218!32?O?A??gc$#219!111?CG$#222!31?G!47?@$#225!33?A!15?@$#233!45?_$#234!88?O!10?G$#237!36?@$#238!142?O!5?C$#239!77?O$#242!109?A??_$#243!48?@$#244!35?G!77?A!10?O!13?@$#246!30?E!112?G$#247!139?C$#248!49?ow{KE@?G@!25?^!4?C!7?O_??o$#249!59?O??G!6?O!6?GC!12?A$#250!64?Pw@@L!5?Cw??G!23?Q$#251!54?_???c!5?_!19?OJJo!5?C$#254!35?@!76?C-#1!77?C!16?G?C!5?C$#10!52?OO$#11!33?G!15?_o_?G!4?G?Oo_$#12!145?A$#13!143?AO$#16!56?___$#17!146?o$#20!144?@$#21!28?_!4?_!14?o!5?_!5?G??O$#22!52?G_!74?A$#23!156?A!7?O$#25!144?G$#26!48?N!8?CC??C!20?@!7?@?G?O$#29!82?A$#32!128?@BBNI~hLpo!24?_$#40!156?@BB@$#46!159?EM[$#50!34?G!25?@!11?A$#54!34?O!31?C$#55!30?O$#56!55?C!5?JKGW???C?@?C!5?GC???G!5?OQO!11?O$#57!51?G?C!13?A??A!8?A??_!13?O$#61!144?C$#62!30?_!83?AGO$#64!82?C!21?O$#65!34?@!10?K!65?@?G@C$#68!52?C!7?A!42?@$#69!115?_$#73!31?SA$#74!49?G!19?G?DG?SO??A_O_?C!9?O???C$#75!65?o!14?C???_???O!7?_???@A$#76!114?C??_$#77!73?_$#79!36?_??_$#81!46?O!58?C??_$#82!113?@$#84!47?[!58?_$#92!46?@$#94!46?MA!59?O$#95!41?_!53?@!10?G!5?G$#98!35?@$#99!40?A$#101!115?A$#102!39?C$#105!110?A_!14?A$#106!51?A??@?B?AB!4?@?o??oO?_!11?LpEqH__!7?cOO_$#107!66?A!41?CO$#108!123?O$#109!39?@??C!69?O???@GgjZc?AOgcGO$#110!118?E??A!4?OO?_$#111!41?DwF}!48?@E!9?@BFMZnkW__??CS???H??i$#113!122?YHDOG$#114!41?ABw@!70?@ABPScOdc?F?__$#115!29?_!86?G$#116!51?O??O??G$#117!33?O!15?O!12?O__$#118!56?C??cC?BCCC?CA!4?CbG?@P?GO?O!7?C!4?AW?@ACG??_$#121!29?O!37?@??C!5?_A!14?A??O!8?CGO_!18?@???_$#122!56?G??G_!83?_?G$#123!55?_$#124!112?AO$#127!32?G$#130!50?C@!5?@!7?G??G!14?@!5?@!7?AAC?O_$#132!70?G??B!4?C!12?G!4?@!5?@?_$#134!72?@!56?C$#135!73?O!19?G$#137!33?A!126?@?C$#140!30?A$#141!30?@$#143!142?O$#150!47?_??G!15?G!4?G!5?_!4?G!9?C??_?_$#151!31?i@$#152!54?C@!12?@C!5?CO?_!4?_!8?P!10?I$#153!45?A!65?A??_$#154!110?@!4?O$#155!128?G$#162!29?G!24?G!4?O!69?GO$#163!52?_!5?O!68?@C??_!10?@C$#164!130?C?T?UqMN!4~k_$#168!35?A$#171!131?O_!9?AO!11?@??C$#172!30?C$#173!143?@!19?G$#174!34?C$#176!55?A!36?_a_$#177!63?@A!4?B!5?ANO??BFO?O???_A!8?G???ACG$#178!127?A!15?G$#179!73?G$#182!32?O!112?C$#183!33?@$#185!162?G$#188!116?_$#189!45?o!47?C!18?C$#190!35?_$#192!90?G_!7?G$#196!55?WOO$#199!30?G?_?a$#204!162?Oo_$#210!45?@!83?O$#213!145?O$#214!130?G!30?A$#218!31?@???K^~~$#222!40?w$#223!39?GCO!85?C$#224!111?C$#225!39?A@G$#228!146?C_$#231!144?A_$#232!114?O$#234!57?A!5?A???G!4?O!4?G?@?G!19?@???O$#236!35?O???O$#239!159?G$#242!112?@EG$#246!28?OC!115?@$#247!33?C$#248!49?FB!20?A??G_???W_??A!6?C!6?@PAKGO_$#249!46?_@!43?B!12?A$#250!65?B@!27?@MG!10?@??O$#251!51?CBBA???@!8?oo?_o???@!8?AMxLEK!9?__$#254!32?C!112?G-#1!35?G!10?@?_$#10!96?C??KG$#11!50?@!40?A@?@!6?OO!43?w$#12!146?@$#13!145?_?A$#15!63?K!34?o$#16!91?CCC$#18!55?B!6?Co!25?_g_???GGO$#19!145?O$#20!119?G$#21!90?@!4?@!6?G??_!38?a??O$#22!99?A!6?A!37?W??_$#26!33?G!15?KG!38?@$#27!54?P?FBB?AFA!27?OWw?_oo_$#29!30?A_?c_!74?A$#31!54?g??CCc@?G!30?_!5?_$#32!133?@BDB@G!10?G$#40!148?wo_$#42!34?A!10?_!86?AC$#50!29?C!4?@!96?@??G$#53!166?O$#54!27?CO!50?A!29?_!11?_$#56!49?O?G!13?@!13?@!6?CG!13?C??O@$#57!83?@A!12?@$#58!88?_!5?W$#60!165?_$#61!145?@!20?_o$#62!30?@!4?O!81?CA$#64!51?@!12?A!19?@!22?CA$#65!26?_!5?G$#68!88?G!11?A!6?B!6?O$#69!31?G!82?_?@$#71!38?O$#74!75?@!6?@$#75!48?E!37?I$#76!39?O$#77!51?_!25?A!25?G!5?C$#79!37?@GM{y$#80!29?A$#81!112?O$#82!42?W$#84!47?F!28?@!34?O$#85!40?AD_$#93!52?@$#94!112?_g!6?G$#95!27?_!25?G!10?_$#97!87?O!28?_$#102!35?@$#104!36?C$#105!42?@???_!12?@!55?A!17?G$#106!50?_!14?GrTgNyqMoMs_sOckskSoT`!13?@?CE?K$#107!52?_o!56?@$#108!116?C!7?C$#109!119?AABD_Xu@EW?ssoOO$#110!119?_??OAA??_A$#111!27?OC!6?A!7?EF[!65?BBFNSOgO???IS!5?wAAC?_$#112!123?G$#113!115?GG???@???_H_H_?G?G??_$#114!29?@!6?A!6?@!73?O_@CK?@??]ODF@G?_$#115!35?C!9?A!6?O?C!32?_!23?_!9?O$#116!92?AB!6?OG!44?C@$#117!49?BE!13?@!22?CEEA!11?_o_$#118!51?O!7?G!17?@!18?@!10?w??G$#121!32?A!13?C!31?A!29?@??C!23?O$#122!26?G!36?@!27?@!5?CEO$#123!89?O!4?C??G$#124!43?O?@!18?O!44?@$#126!32?C$#130!81?@$#132!48?@_!38?@$#134!30?C???[!103?_$#135!26?O!6?Q$#136!59?OC!35?A$#139!145?A$#140!29?GG!75?@$#141!27?A!116?C$#143!143?C!4?C$#144!166?A$#145!151?_$#150!48?O?O!24?A!7?A!22?_$#152!51?E!13?A!32?@?_!5?C??O$#153!46?G_!26?@!35?O$#154!27?GG???_$#158!165?@$#162!90?C???A!41?O_$#163!87?A!12?C_!30?@ACG!8?@??K$#164!135?ACMV!4~z$#171!136?G$#172!120?O!24?C$#173!163?AG$#175!117?@$#176!85?A!19?O$#177!76?C!10?@!11?@!4?A?O?S$#178!28?_!4?@$#180!164?EA$#186!165?C$#187!165?WK$#188!39?_!78?G$#189!28?@!14?G??A!63?A??O?`$#190!36?XC$#192!44?G?O!35?A$#196!54?A!7?@A!25?G!5?A?A$#199!32?@??_!8?O??O!64?G!5?C$#201!31?O!84?A$#204!164?@$#205!163?@$#210!117?A!18?_$#211!32?O$#212!55?Gw?WAGgO?G!23?O$#214!137?O!12?O!16?G$#218!31?@!5?wF@$#222!110?_!9?_$#223!28?A!8?A!4?A$#224!112?C$#230!55?C!8?C!28?G$#231!38?_$#232!44?_$#233!119?S$#234!76?A?@?A!22?@??G?g$#236!31?E!4?_???@?C!9?K$#237!52?AF!39?O$#238!145?G$#239!110?C!37?A$#240!55?o?w_?oO_$#243!43?_!78?_$#244!118?@$#246!98?G$#247!95?C!50?A$#248!80?@A!22?@A$#249!47?GG!60?G?G$#251!65?sKiVoDLpNoGWGkWOGOgKgO!14?BB?K-#1!44?P!63?C_!12?@!66?C???G?O??C??G??O$#11!144?M$#15!98?B$#18!63?@!32?@@C$#19!31?@!106?@$#20!124?O$#21!146?O???_$#22!101?G!4?@!90?A$#23!168?_!50?_$#26!24?_!10?O!68?A!101?G$#27!63?A!24?{!6?@?A$#29!117?_!9?C!11?A?A???G?O!5?_!14?K!18?A$#30!39?A!102?_$#31!94?@??_G$#32!140?@$#40!146?MIKW^^IG$#42!33?@B!161?A!13?G$#46!152?CCwo$#50!25?A!6?A!16?C!150?C!6?GGG$#54!33?C!12?@A@!58?O!34?G?_!46?G$#56!103?C$#57!101?C!5?A$#58!54?@!35?@!5?AS$#59!54?A!44?@$#60!120?C?O?_$#61!126?O!39?F@$#62!39?G!48?A!49?G$#65!38?@!71?O!14?OG$#66!127?_$#68!26?G!5?@!7?_???GC???o!60?_!15?C!13?C!50?AIA!9?O!9?O$#69!38?C$#70!61?O!37?A$#71!119?C?O!4?_$#72!120?_$#75!102?G$#76!117?A!23?_!48?C!5?O???G_!9?O$#77!48?_$#79!40?FF!74?_K$#80!38?G!5?_!70?@!10?A!10?@!53?C!15?O??O$#81!26?C!9?_?_$#82!42?B!73?Q$#84!47?C!53?O!6?A$#85!116?C!82?O$#87!115?A!82?O$#89!197?O!4?_!5?O$#91!55?@@???@!28?o?G??o_$#92!60?O!64?C$#93!41?GC!57?@!15?G!81?G$#94!26?@!9?G!20?O!55?@!28?O$#95!25?O!15?O?G??C!12?O!38?_!11?G???A???@!88?!6_?_$#96!55?A?@$#97!43?O??O@!8?G??@!83?O$#99!56?EABAEC!28?_ooo$#100!25?_$#101!138?A$#102!61?G!53?_$#103!26?A!60?G$#104!57?CKK$#105!37?_!77?O!20?C?S$#106!50?Y?_?O?__!7?NKC_@BkSTU{kB?QE`wBRkx!13?__?OcKU$#107!52?@!34?B!11?w!10?B$#108!135?_$#109!115?G!11?AOOCDG_@OHA$#110!112?_?_!4?@?B!4?@?I?jWQKgDq_?_$#111!53?B!9?G!45?O?v]CS!5?@!8?B?A@O?A??_$#113!62?G!50?wG!7?A??@?@@GO_cBUG?O?C$#115!36?O!62?CG!28?_$#116!145?@$#117!102?FB@@!46?_$#118!26?_A!6?C!72?L!36?O!51?_$#119!34?G$#121!33?A?H!73?@!12?C!5?C!17?_!37?GC??A!5?OA!6?G!12?O$#122!146?@$#124!25?G!11?O?_G!4?g!63?C!14?C!72?C??_?O??O!6?O???_$#126!116?@?O!47?w}$#127!122?G$#134!45?@!61?_!39?@!4?O!32?G!25?G!4?O$#135!27?C$#136!93?E$#139!121?C$#140!25?@$#141!139?@??C??C$#143!143?A???CRF$#144!157?_$#149!154?CG$#150!105?A$#151!123?O$#152!26?O!21?CH$#153!27?@!7?CC!11?A!60?A!13?@???O!59?C?A!4?A!4?C!14?O??_$#154!120?A!77?_$#156!125?G!42?A$#158!118?C$#162!140?A??G?A??_??_$#163!141?C??@O???_$#164!141?@B@$#169!209?O$#170!128?_$#173!118?A!24?_!21?A??O$#175!118?GA$#176!46?gw!6?G!7?O!43?_$#177!74?_!33?@$#178!24?O!8?G!113?_!42?G!14?G!6?G$#182!39?@$#186!122?_$#188!36?A$#189!25?C!19?A???A!58?W!77?C$#192!87?o!24?@$#193!60?G!79?_$#197!125?_!39?G$#199!141?O!76?_$#201!117?@$#205!156?_!8?@$#210!35?A!4?O???E!9?C!68?C?A!13?G!50?A$#211!117?O$#212!61?@E!26?CM?GGAW$#213!36?@!81?_$#214!140?O??C$#218!37?@!81?wW_?_$#219!194?G?C??_!6?O$#222!42?O!86?C!83?_$#223!41?___!71?C!8?@??G$#224!111?G$#225!57?G!65?A!13?K??G$#230!55?G!7?C!25?B?@F@???GO$#231!38?A!84?G$#232!145?_!42?C$#233!37?G?O!84?A!14?O!57?_$#234!72?__$#235!101?@!97?GOO$#236!37?E!4?G!12?C$#237!43?C!14?O!41?E!91?CCCGGG!5?!4_!8?_$#238!124?G!28?A??O$#239!152?@!12?C??@$#240!61?A@!26?GOE??KE{$#242!43?B$#243!38?O!62?A!12?@!80?C$#244!88?@!52?G$#245!64?@$#249!45?OA?W?C!4?OO!43?O!7?_$#250!51?l]G!9?oO__OO!12?A!5?C!21?GC??A$#251!50?`Q?s__??!5_?mORjN}{RJIHBR{~lx[F{kRE!15?ogWoG$#253!39?C!113?O$#254!121?G-#1!41?A???@!60?Og_!32?O!39?A??_!8?A??CC??A_!9?GOO!4?_G$#11!128?_$#12!145?@$#17!105?O$#19!153?O$#21!117?O!32?C!4?_$#22!104?_!12?g!16?G?_!12?A$#23!165?AG!10?A???@_!48?O$#25!109?@!19?A!4?O!42?O!13?@!34?G$#26!37?O$#29!132?G???O!15?@!19?_???O??O!47?O!8?_$#31!88?@$#32!133?o?_$#40!151?AA$#42!106?A!18?A!26?O!20?O!9?@!30?_$#43!116?G!27?@$#46!152?CFN@???A$#50!24?@!106?A!6?_!34?_G???A!11?@!5?A!5?_!21?C$#51!123?_!35?G$#52!122?@O!34?wC$#54!109?A!65?O!8?@!14?G!28?_$#55!116?C!5?A$#60!131?_!29?w$#61!162?oo?G$#62!167?A$#64!24?K!80?G$#65!152?_$#66!141?G$#68!25?c!10?@?_!10?[!56?@!26?C!15?G!48?C?O!8?GG!4?_$#69!116?_!22?C!68?A???C!6?@_$#71!123?A!19?O$#72!118?AOC???K_!16?G?O???_$#73!120?_oO?AW_@E?_!14?OO_$#76!177?G!25?AA$#78!121?G!7?G$#79!114?_K@!21?A??C?@G$#80!42?C!153?G!7?O??C!19?_$#81!44?O?_O$#84!48?@!23?C!15?A$#85!114?O$#86!190?A!19?A$#89!178?C!18?G!12?_$#91!89?@$#92!183?A!33?A$#93!195?O!5?@$#94!25?@!15?C?O?_!60?_O??@$#95!92?A!49?_!37?!4K[O{?_?_!8?_!5?Gxx`@@!4BD@@$#96!145?G?G$#97!38?O!4?G@?D!49?@!124?G_GO$#98!136?@$#99!90?@???@B$#100!149?o__$#101!47?GW!59?@$#102!93?AA!42?A!4?@$#103!65?o$#105!37?@LA!69?O?K!26?D$#106!50?[~\[~}}yvv~~~}G??@???@?GE_?Vr~|}z}^z^M[KKKWGWWG[M|{{}]GD$#107!39?W??__!21?G}{{{o{_ow!23?@$#109!38?A!74?G!17?@?AECCG??_???C$#110!112?s?A!19?@??CWGO_AA$#111!109?_yoIQ@!21?G???@$#112!139?O$#113!97?A!13?A@D!18?@@?AA??@?B$#114!110?C@$#115!40?A?AFmWAEC!47?A!16?_!25?_!6?G$#116!127?W??A$#118!36?A!68?_!91?@$#121!24?q!83?Q!42?O!28?O??_!5?@!25?O?_??@?A$#122!126?C???C!4?O!12?A$#124!25?A!11?C!7?E??_!42?A!16?KG!20?@!51?O!9?A??K?AGA?AA??AA?Gq!9?C?A$#126!116?O!6?G!40?o_B$#127!165?O?@$#134!106?K!20?C!26?O!20?C??O???@!12?A!25?@$#135!117?@$#137!158?@$#140!149?@!51?O$#141!117?C!30?@??GG$#142!146?A$#144!161?C$#146!125?@!21?A$#148!129?@$#151!122?_@o!18?G?__$#152!49?b$#153!25?G!81?A!78?@@!13?C?O_!4?CSC??G?o!17?_$#154!47?_!128?G?G???A!8?A!6?A@???G!11?G??E$#155!40?@@G!92?G!14?O$#156!126?G_!20?C$#158!115?_!27?_!12?_!8?C$#162!126?A!5?_G???_$#163!117?A!10?O??[C!14?@?C@@$#164!134?_$#168!146?C?O$#170!130?G!19?A$#173!107?@!21?_??O!17?G$#175!166?C$#176!47?@A!44?C$#177!50?_!22?C@!11?_o_o_o!6_o$#178!26?@!127?_!68?A$#180!157?}E$#182!142?O!23?_$#185!155?E@!5?G$#186!159?O$#187!159?_{$#188!122?C!5?G$#189!25?O!11?G!69?C?C!43?_!25?A!5?@??@!5?A!7?G!10?G!11?G???_!5?_$#190!114?G!24?A??C$#192!37?A!14?a_???C?G!24?_C!4?O?CO??O$#193!143?C?C$#197!165?@!62?O$#199!126?@!47?O?C!34?_$#204!155?GC@$#205!155?OY$#210!175?G!5?O!26?C??OG?O!17?__$#211!115?O!7?C$#212!90?A???C$#213!116?A!7?@!4?OO!9?C!4?A$#215!151?C$#218!118?|nZF!25?OG$#219!199?O??C$#222!46?O!68?@!21?O!41?C!34?CAMKWqESK$#223!42?@!94?@!6?A!77?Oo_o_$#224!39?_?GO$#225!91?@@@!41?@!4?A$#230!89?A!5?CC@$#231!128?@$#232!140?G!36?C??A!39?O!9?__$#233!198?@!8?A!15?C??O$#234!72?BB$#236!115?A$#237!183?OAmA}[{[{{{w_ooo?`?@DLtC?O!8?O@!5?G$#242!179?G!33?C$#243!188?AA!4?C!25?G_$#244!39?@C!73?C!17?A$#245!53?A!10?O$#247!146?@$#249!46?G!56?_O$#250!39?Cwo!8?B!14?C???@$#251!53?@?@@@G!4?@fB@ABANAW??^~gK?A@C@???@!11?ABB@@FA$#253!153?G$#254!122?G??COA?C!14?_??C-#1!39?A?_!10?O!46?O!54?A!17?O!9?G!27?C@$#11!129?@$#13!131?G!4?_!11?GO!7?G$#19!24?C!109?G!10?O!10?@?_$#21!116?W!14?O!10?CC!4?C?g$#22!102?_!30?@!12?_!11?W?_!23?@$#23!175?C!6?C$#24!112?_O$#26!117?@$#29!25?O!8?_!108?G!4?AG!7?D!11?`!11?C!38?OG!10?G!15?_$#32!135?EA_O!5?O$#40!142?_$#41!113?_$#42!52?_!123?C!43?GC!9?C$#43!113?G$#46!151?_$#50!26?@!143?O!43?_!18?O!5?@$#51!158?@$#52!124?C$#53!161?A$#54!99?_!40?@!4?G!25?A@G???C??C!5?A!18?A!12?A??_$#55!124?G!19?@@!10?A$#56!101?GOGB$#57!103?O$#58!169?CG$#59!215?C!25?A?C$#60!161?CO$#61!129?G!31?@N~$#62!145?A!22?_???A!73?o_$#64!53?_!44?OGC$#65!130?@!16?G!20?]?_!35?O!12?@!14?O?O[^E$#68!25?C!25?G!21?_!28?@?C?A!100?G$#69!113?C!16?_!74?G!4?G!21?_$#71!111?_??G??G!7?G!22?_$#72!118?G???g???_G???@$#73!119?O^}Pw_BKsWO!18?@$#74!100?_oGA$#76!26?C!160?_!15?A!26?C$#77!69?_$#78!123?C?C@$#79!112?GA!17?A!99?o$#80!209?@@$#81!49?@!54?G$#82!108?_$#84!70?_$#85!111?O!118?G$#93!228?@$#94!105?A@A!72?G$#95!107?_?g!74?O??@@BC]K]}MNMMNNEEGG?`BRA?A$#97!109?C!24?_!36?_?OO?o___!25?_???_??W$#99!145?C$#100!149?@BFFM[W_$#101!40?C!5?@???o$#102!112?A!30?@A$#103!46?A?C!13?GO$#105!43?GA!4?O!60?A!32?A$#106!51?@N\~NN]NVYEA?EDc?GG?G?G?[ZlXnn!4~ooo?o!4_$#107!40?@GRfl}s[!19?@@P@@?@!32?GC$#108!110?O$#110!111?C$#111!106?_WF@?A@$#113!105?_O???L@!30?@$#115!39?@?O!5?@?_?_!52?_O!5?G!29?@!30?_!50?w{{}}}W$#117!129?A$#118!24?@!13?@CO!59?O!15?A$#120!102?CC$#121!25?G??O!88?A!14?G??_!6?A!7?C??O?@!23?C!4?G!18?@ACG!6?KO!4?AE!9?@A$#122!128?@??_OA?O!10?A!6?_$#124!25?B!72?_!34?OO!9?C!7?G!22?G!9?O@!15?@?C?A???A?C!9?G$#125!50?A$#126!123?@!24?O!15?~~??@!67?_??_?owwwo$#127!124?A!41?p$#129!128?A!4?C$#134!101?C!49?O???A?OC???_!24?S??_!26?C???O$#135!24?A??C!88?c!14?C!14?O_!6?_???A??O$#140!33?_!154?GO$#141!138?@?A!10?G!5?A?O$#143!139?_??G___!4?O$#146!32?_$#151!118?OG_@C$#152!26?A!70?_???A$#153!26?_G!84?O???@!52?I!4?G!10?@O??G!43?KM^NB$#155!48?B!100?A!5?_$#156!160?O$#157!114?_$#158!114?O$#162!130?K!8?@!4?G??E$#163!129?CA??_C!6?A!7?C??O???C$#164!134?@@L]m[{wOO$#171!137?@?A$#172!233?_$#174!149?_!79?@A$#175!171?O$#176!51?C!20?_$#177!74?_!10?FNN~N!4^~fp[NFB@$#178!30?_!72?@!28?_??G!23?CG!10?@!13?G!18?@$#179!102?A!58?_!10?G$#182!114?E@$#186!159?BDG$#187!125?_!34?A$#188!146?D!19?M~?O!51?A!15?__W}KC$#189!29?_!21?O!102?@?G!31?_!17?C!10?@!14?C$#190!132?CG!12?G$#192!47?A!5?A???@??D@@A!7?_!13?G$#197!247?O$#199!100?G??_OG!72?C!28?o!10?@!13?O$#201!107?@!104?A$#207!31?_$#210!106?C!10?C!52?A??@!9?G!4?C?O!23?G!6?@!9?HBB@$#211!132?A$#213!114?@Q!8?@???C!18?@$#214!134?A?O!4?C$#215!159?G$#218!115?K?off??A???QA!19?O$#219!181?G!47?A$#222!27?O_!20?A!60?_!45?O!20?WWW!4o___!5?o_?!6owwsoO??KK?K?_!8?C!6?C$#223!26?G_!145?__o!33?O?o_!9?BFBB@@??_$#224!41?@$#225!108?GA$#231!124?OO???_$#232!205?@!9?___ow_$#233!153?@?C!31?A???_!16?_?o??OCOOOGC??o$#234!95?WMB$#236!108?OO??C@!116?O$#237!26?O!161?ACJ@B@@@?@@??@!5?C!12?@$#238!115?_!16?@$#239!130?O!58?_!22?@!22?_$#243!176?G$#244!45?@!183?_$#245!51?A???O???G??CL?AG$#249!40?G!8?CL!54?D$#250!40?AEkOO?G_wG!6?__o__wo_woB{o???@$#251!55?_O!7?@GOAEE]U]U^bcQeOO$#252!245?G$#253!152?_!6?_$#254!123?A???@_!28?_!57?GGGC-#1!48?O!4?G?C!41?C!34?C!36?@!24?O!13?_G!12?A$#13!138?_$#19!34?@!80?O@!15?A?O!5?O!14?@??G!23?O$#20!105?O!13?_$#21!101?@!47?C?_!7?A$#22!133?@@!17?O!9?@C$#23!182?_??_!55?G_$#24!100?O!4?_???_!8?W$#25!32?A!82?_!17?A!32?_$#26!41?@?G!54?K?AA$#28!101?O??O!5?_!9?O_$#29!98?A???@!32?AO??O!19?@!6?GAP!10?_???O!31?K!5?C!13?_!4?C?O$#30!114?O$#32!149?G_$#33!112?@$#39!102?O!4?O$#40!145?Z~wWo???A?O$#41!98?_???_?_??_!5?@???G$#42!33?@!63?G!51?A?C!17?OGG!43?O!4?_O!12?C$#46!147?A_???BKw$#47!101?_!12?@?O?_?_$#49!99?__??_!4?_OW{}}M?KO$#50!94?_!38?G!17?O!15?C!13?O!33?_!5?A$#52!108?G!21?C!33?G$#54!44?O!86?@!40?G!6?GG!9?@!24?A!5?@$#55!131?G$#56!99?D$#59!168?_!47?_???O!30?_o$#60!109?C!11?O!4?C!122?_gO?_$#61!125?@???@?O!32?A!78?_oww}~]SG$#62!167?@!40?@C!6?O!25?GWKEF@$#65!49?_!7?G!44?G!66?G!38?Q!8?O?OG!13?G$#67!107?C$#68!52?A!14?O!31?GC!36?G!13?G$#69!104?CC!127?A$#71!131?_!17?@!84?O$#72!118?@@?C?_!6?@$#73!120?FBM^m?_F^[_$#74!93?_G!4?A@$#76!108?@!76?O!21?@$#78!124?@$#79!109?A@!46?@!73?@VG$#80!30?@!23?G!41?_!42?_!47?_!4?G!15?G!13?C$#81!51?@!8?O!5?W!29?C$#82!104?G?EB?@$#85!232?_$#89!209?@$#94!44?G!14?_!45?A$#95!42?@!5?G???G??oo!131?@$#97!48?_!4?A!49?C!64?G!6?AAA?@A???ACCS?KCG??AG?ECF@?@?@$#101!45?O!17?O!142?_!17?AA@$#102!212?O?O!10?C?@$#103!49?C!6?A!9?A!35?A$#104!231?_$#105!43?@?G`oAIMoo!5?C!45?A$#106!59?@!4?G?CCz@{?C??waCDRYrNQNj~VNNVFNFE@$#107!44?FDC?D?OK!4?@??AGGAB@$#111!101?CC?@@$#113!103?A$#115!50?_?@!44?A!70?CEBBA!22?oo__owoowwwWW?O[[M]G!7?GB@@!5?G$#118!94?O!57?_$#121!31?A!22?A!6?__?_!30?K!40?C!36?G!4?G!7?_!4?BA$#122!133?C?_GOCG$#124!27?@!23?A?OCGGOG!39?@?G!36?CO!11?A!5?@!10?G???C!38?@$#126!32?@!94?o!30?A!5?@NA!17?O!53?@@BFFFB@$#127!120?G!9?A!35?@$#128!122?_$#129!106?O$#130!89?_??O$#131!108?C$#133!165?O$#134!137?_A!8?@???@?_!4?@!7?O_!53?G!15?@$#135!148?@$#137!106?_!11?CG!36?_$#138!108?OGCA!7?O$#140!115?A!24?_!22?G!71?O$#141!137?@???_!17?G$#142!153?O$#143!142?`n~c?CC$#144!97?_?O!16?AE$#146!235?G$#151!121?GP??k???_$#152!42?A$#153!28?A!16?_!9?AC!8?__!30?@!74?O!4?C!16?_!21?GGWKC$#154!95?O!38?_!44?C!10?A?@!14?_$#155!50?@???O$#157!116?_$#158!132?_!29?C$#162!135?C$#163!115?K!16?@?I??A!12?GAG???AC?S$#164!138?@BF^]O$#171!140?G$#172!114?_$#173!111?@!42?C!6?C!8?_!82?O$#174!63?_$#175!103?O!60?C?C!4?O!67?A$#176!57?C!6?O!30?A$#177!91?O?G@$#178!26?@A!107?O@!11?A?P?C!8?@AA$#179!98?O!16?@$#180!160?@$#181!117?_$#182!250?AC$#186!160?A$#187!161?A$#188!106?G!19?I!31?C!10?_!47?___$#189!54?@!46?G!36?G!11?C!22?CGGKG!37?@!5?_$#190!131?AG!98?C$#192!47?G!13?O!12?@!12?_!15?@$#193!209?!5_!9?W!4GDK$#199!96?A!95?CG!39?@$#201!174?CC!5?G!32?@$#205!155?_$#209!110?A$#210!30?A!21?C!5?OO_!96?A!10?A???CO!4o_?_!28?A!6?EEFBB$#211!107?G!17?A!55?_$#213!126?P?_?GC$#214!134?CG_??C$#215!53?@$#218!119?A!4?OO!4?O!101?Gs_$#219!105?G$#222!57?__!47?@!71?@ADBBB@BBBEA???B!5@??@?@!6?A$#223!28?@@!19?O!83?O??A!33?C?@BB@@@A??CCCKGWGwowoo_KEMWYGEMMEEFFE???B@@$#224!43?A??A@?@???_!6?A!4?G!162?O?O$#225!225?_?!4_O$#230!173?_$#231!118?AC$#232!31?@!21?C!124?OOO!35?@@$#233!29?A!24?_!48?G!63?O!10?C???G!6?@???S!20?A!7?@$#234!88?_$#236!133?_!97?A$#237!96?G!86?G$#238!97?O!136?A$#239!153?@$#242!95?_O!94?C$#243!208?C!5?C$#244!47?C!87?@!78?_!7?ocsOuUIRN$#245!62?O$#248!90?___O$#249!43?C!21?O?g!28?@$#250!45?AWA!7?@?BBKDFLKEB?@Co?Ca@?C!4?C$#251!65?C@A?MBzX}}B\zyk`KoloS?GOOGG$#253!163?@!85?@??G$#254!108?A!8?@!9?G?A??O-#1!50?D!5?C!143?OG!12?G$#13!136?@$#18!155?O$#19!113?OD!25?A??O_!6?O!84?o$#20!97?A!6?@$#21!93?@!59?C$#22!36?_!30?G!71?AC??_!7?C!66?O$#23!45?G!114?O!81?C$#24!97?@AAA??AAA?@!4?C??o!4?k$#25!175?A!4?C!39?B!35?O$#26!41?GGG$#28!105?@!5?@???GB??@!9?_$#29!144?CG!6?C!19?C!42?C!26?G$#30!69?G!55?C??O$#32!137?@???_!16?C$#33!106?@!14?O?A$#39!106?A$#40!145?BN]vu]!4?_$#41!68?_oowO!4o_!6o_??_!5?__?_!5?@!4?_!7?C???_?@oo__o_$#42!48?G!19?G!70?_!44?C!6?G!25?O$#44!126?G!23?@$#46!147?@GH_???pB??_$#47!66?O_O!8?O!7?__?___?_OO_?_`??@_??OoW!7?A?@_??EMKO$#49!65?__O!4?_!5?!4G???!8O!6?_`_?_o???Ww{{oA???M^[?G??KG$#50!37?O!152?C?O!22?A?G$#54!174?@!4?@??AC!7?O!23?@F?G$#55!58?O?_!69?_!104?@$#56!82?A!9?@$#57!73?C$#59!178?G!63?_?@__kS{~}~~}w$#60!62?_!31?A!7?C!140?s{U[RjB?@$#61!78?C!94?_!69?JAHB$#62!180?O@!5?_$#63!63?__!10?GG!7?G!12?O???CO!6?C$#65!57?G!131?G_???_O?OO!7?!4G?G$#66!85?G!12?O!6?G$#68!37?_!24?@@!78?C!53?O!18?O$#69!59?CW!159?G$#71!89?G!45?_$#72!100?O!27?GA!91?O??_$#73!81?C!43?@@A?@JTCo$#74!79?A!11?@$#75!61?EOA@@$#76!53?G$#79!91?G!130?A???C$#80!52?C!147?G!13?O$#82!59?A!35?@$#85!137?_$#92!198?_$#93!104?C$#94!43?O!4?CG?_!4?@!134?C???@!11?A$#95!41?OO?___!10?A@@!130?A?G!8?_!17?_$#97!43?_!169?O$#98!98?G!9?AA$#99!84?C!4?CC!12?G!30?@$#101!41?_$#102!56?G!28?!4C??C!7?GGG!34?G!62?A?@?@$#103!228?A$#104!135?A!69?OO?O!4?C!10?@???@??A$#105!48?BCG?@ACG!81?O!66?___?__oo__c___!9?B?EEK$#106!66?ABE?A?AA@?@?@@@$#109!47?@!90?_$#111!53?@A$#115!42?_!6?A???C!136?@BFRC?B@@H@?@???@!18?A$#118!66?G!7?CC!7?A$#120!65?C$#121!49?O_?O!8?_!14?CC!6?AAA!48?@!8?O!7?@!38?_!24?O$#122!138?GO???CGO_!5?_$#124!40?O!6?A!8?AC??B!35?@!40?G???A!54?_!8?C!15?@$#126!59?_!75?G!32?@A?A_!4?C?O_!29?G!6?CE$#127!126?C?A!4?@!35?@EKW!16?_!27?A$#128!64?O!49?O$#129!205?G$#130!64?C!11?AA!6?@@$#131!58?C$#132!64?AGC!13?AA$#134!47?K!66?G!23?C!4?A!9?O!33?PC$#135!192?_!23?G??C$#137!96?A!4?A!9?A??_!5?A??@A!31?G??G$#138!112?I??@$#140!45?@!95?CG!23?@!52?G$#141!137?A???GO!8?I?G$#143!142?_?BC$#144!54?_!66?_!33?C$#146!152?O$#149!120?O!33?A??@$#150!65?A?C??C$#151!126?A???CAi?_!100?O$#152!72?C$#153!52?_!90?G!32?A?CK???A!4?@!10?O??G???A!6?G$#154!46?O_???Q???A!84?@$#156!108?@$#157!65?O!4?G!31?A@!12?C???@?@$#158!92?AA!40?C?_!16?_!68?_!19?O$#159!113?C$#162!142?A!93?C$#163!113?_A!22?C?@_@!9?`?@!82?G$#164!138?ACGO?@$#167!93?G???C!9?C$#168!82?C$#169!201?O$#170!147?_$#171!95?A!44?O!16?O$#172!170?G$#173!154?G!18?O!45?O$#174!89?AA!61?A$#175!51?GG_!37?A$#177!62?G!6?C!11?@$#178!44?G?A!89?A?@???@$#179!215?G$#180!159?_$#181!84?O!6?_!7?@!5?_??_???@@!5?A!5?O?O$#182!133?A!37?O!84?_$#185!127?G$#187!135?O$#188!128?@G!40?@!13?G???wOO!26?@@@$#189!47?Oo!14?O!23?AA!5?@!43?O!64?GG??@!4?G$#190!55?O?p!77?C!88?A??C???O]$#191!95?C$#193!51?@A!140?KG?CEE?E?EABB??@@??A!15?C?G$#197!188?A$#199!38?O!11?AC?O!91?_!43?EG??_!25?AC_$#200!72?GGG??G!4?GG!11?OO!6?O??G???@!5?GO!10?_$#201!39?O!9?_$#204!156?@EWO_$#205!156?EG$#210!49?@!4?O!48?C!71?@@BBA??@!12?k!24?_$#211!99?C!25?A???OO$#213!59?G!28?G!9?CO?O!5?AC!7?O!7?@!6?_?CA!100?C$#214!139?G$#215!146?O$#218!58?_!31?G?G!23?_!10?C???GOGO!86?M[[[{wwwoo__~~g$#222!39?_!10?O???@$#223!38?_?_!13?G!81?C!52?@!12?o$#224!203?_$#225!204?O??oCO?CC!5?_!4?@??B??@@@$#231!58?GO!19?C!6?G!13?C!16?_!11?C??@?G!88?_!11?A$#232!194?@$#233!46?@!8?@!4?C!134?A!10?C$#234!62?EK??@!7?AA!6?@@$#236!56?_?A!45?G!118?A!5?G??@$#237!194?A$#238!46?G!66?G!38?G!14?@!74?A$#239!242?@$#241!83?C!8?CCKGKG!4?G??CC$#242!44?O!152?_?_$#243!45?O!154?_$#244!55?CO!137?O?GGGC?E?SC??CAEFBPBB!7?@??@$#246!153?A$#247!236?B$#248!64?G!6?C!6?A!7?!5@$#249!61?X$#250!68?@@?@$#251!69?A@A@@?@?@$#252!180?G???O!70?C$#253!55?_!198?@$#254!80?C!6?G!21?@A!16?@C!7?O!83?O-#1!44?_!99?_!52?@??@$#12!152?_$#13!151?o$#17!112?A$#19!35?A!105?A!52?C!40?_$#20!49?G!64?@!7?AG_$#21!112?G!28?@$#22!142?A!45?A!5?O!41?O$#24!55?G@I?C?G!6?@!4A???C??GGG!4?!11O!22?C@??C!8?AC??O?_$#25!145?A!44?@?@$#26!112?O$#28!49?O!8?O!5?O???A@!7?C!20?O!5?GG???CCA!7?OA!16?_!21?O$#29!149?AE!85?_!20?C$#30!65?O$#33!70?@!31?G!32?O$#36!46?_O$#37!47?G?C$#38!48?C$#39!118?_$#40!145?COo_???KO_???G$#41!49?__!5?AC???OO_??__???@?@@AA?!6FN?G@IJ?HB!7NBIFFBFFFBBB@!7?@C?wbN|D~u_cC[wo__$#42!36?@$#44!153?A$#46!149?@?C?L^~}{o$#47!50?O!7?GG??_?__!6?@???@A!7?NFID?JAK!7?KD??C!13?@_GM!4?i?HEAG$#49!51?WC?G?O?_!9?o!18?C?CC!29?oo???AO??GOO$#50!146?@!42?@!4?A$#51!134?C??O!25?G?_$#52!141?_!96?_??C$#54!34?_!178?C$#55!140?O!61?G!22?@!11?_!5?_??_o?wW?H$#58!180?@$#59!187?@!54?qLpPGLxC@FsZvPno$#60!138?A!102?gLQMMVAEBAG???mO$#61!101?O!37?G!33?{$#62!188?@!12?A!7?A$#63!51?_!5?_!8?KC!34?O!11?A$#65!36?A!16?A!149?@?@$#66!52?OG?O!4?__??CE?G?_!12?O!20?O!4?G!9?A!12?_$#68!196?@!18?C?G$#69!46?C!71?O!17?@!94?G$#71!132?@!73?A!23?C!4?A$#72!61?C!73?A??O!65?C$#73!133?@BCAGGO_!91?HW{$#76!45?G!155?G$#80!37?_!4?O?A!97?G!55?O!7?G!9?C$#82!38?o?_O?A$#86!39?wWg_sGC$#89!36?_GG?C?CG?A$#92!36?C$#94!41?A???@@!152?_!11?___$#95!37?AA@!7?@!93?C!72?_???G$#96!76?G$#97!41?@!160?O!7?_$#98!52?_!19?G??GOOO!6?_!16?_??_???__??_s_os$#99!100?__!13?CC!21?@$#102!204?A$#103!196?C$#104!201?C!8?@$#105!139?@!55?OICEA__?A_OO?g@?@@JJ@BBffZ@A??G!5?_$#107!217?_$#108!203?O!11?A!7?GG_?O$#109!202?_?O!5?O!5?!4O_C?cc?_$#110!141?G$#111!140?C!62?_?__oOWGWWOOO???GCY{AOSG?_$#112!221?_?O??O_$#114!142?O_$#115!140?A!56?G!9?G!7?_!6?@?A??G?_$#116!151?@$#118!111?_$#121!35?G!158?@_?_G!29?GO_$#122!34?G!78?@!30?O_?DI!44?_!42?C$#124!52?@!88?O?O!51?GO?@HA!6?@???A!17?G$#126!62?AD!109?B!27?@!4?C?A?A!14?A!9?G$#127!73?C$#128!54?A!7?G!68?@$#129!47?CA??@$#131!113?C$#133!240?_O???_!4?coAcG$#134!144?GOcA???G!41?@$#137!48?_???A?@??O!5?O??@@!7?C!21?O!21?G?@DOO!5?@!4?G!20?@!7?G$#138!58?C!15?A!8?G$#139!46?O?G$#140!189?A$#141!34?O!77?C!37?_?@_$#142!45?_!184?G!8?_$#143!142?@BEGG$#144!47?_??C!15?OO$#145!165?O!6?A$#148!150?O!39?A$#149!56?G!103?C$#151!135?@?C!94?C$#153!194?_A!4?CO???G@$#154!142?_!83?C$#156!54?C!169?@!10?O$#157!50?GC?C?BC???G!12?AC!7?G!16?O???G??G?C???@!6?A!11?A??G$#158!58?A!78?@!11?_??A!9?A!66?C$#161!191?A$#162!143?G??A??CGA!42?G!41?A$#163!142?C??@???O!86?H$#164!150?@$#167!53?_!15?Gww??w_???oo__?_!9?__??_!4?_O?OOo!8?@$#168!56?_!29?_!22?G!8?C$#169!35?O!180?G$#170!147?G@!62?C!14?A$#171!65?@!82?O$#172!148?C!42?@$#173!55?C!104?_!80?A$#174!46?G???A!151?@!28?O$#175!200?O??G!4?CCC!17?C$#178!35?C!104?@??C@!7?O$#179!48?O!64?A!52?_$#180!160?B???_$#181!52?G!6?_!7?A!7?@?@!13?C!15?G!21?PG$#182!207?C!19?A!29?G$#185!64?@!20?O!73?_$#186!172?@$#187!65?G$#188!138?CC$#189!195?C_!7?@!9?C!8?@$#190!203?C$#191!73?G!25?_!4?_!6?G?OG$#193!200?G!8?_??A??G$#197!172?_?O$#199!49?@!137?A!7?@?O_!5?G!22?C!4?_$#200!59?OO!5?A!16?O!31?@!16?_$#201!45?O!4?@!148?O$#203!84?O$#204!100?O!58?@?FKOO$#208!78?G$#209!60?C!50?C$#210!60?@@??G!47?_!86?C$#211!57?@!5?G!69?A!6?G!64?C?A!24?O$#213!59?A??C!6?SCCC!8?O!5?_!4?__!132?@$#214!163?C$#215!51?A!160?C$#218!58?@@A!54?A!20?C!90?@@BBFAFB@$#222!38?@?@!189?O$#223!42?@!165?@$#225!139?A!57?A!18?_!11?O$#231!62?@?A!24?__!46?A?_!88?A!4?_$#233!47?A@!62?O$#236!205?A$#237!37?@?AA?A@$#238!149?G!7?A???G?_!10?C$#239!162?O!11?G!82?A$#241!53?Oo_!12?G???oo?O___!4?_!12?__!7?O__?OW??G?WJIG$#242!37?O???CG?S$#243!35?_WCCC!4?@?A$#244!202?E!14?C$#246!33?_$#252!49?A???@!186?O$#254!61?A?A!4?C!8?G!10?_??_!44?G!98?C-#1!39?C!106?A?O!81?@$#9!153?@$#10!155?C?GO!27?G$#11!159?_$#12!211?C$#13!149?G!87?O$#18!46?O$#20!44?CCA!78?AG!15?A$#21!111?@!124?C$#22!110?W!40?O$#23!167?@!4?@!84?_$#24!117?w@!6?_??_$#28!46?C!30?OO!38?C!8?O$#29!33?A$#30!211?@$#32!164?O!4?O??E$#33!46?G!33?OO!36?G$#35!40?G$#37!43?GO@$#38!41?OW??_$#40!75?O!8?_!63?@AEMWWwo__?G???G$#41!47?Wgwo_!15?@?@!13?o!32?OAOY??N^]GBFNEFAK__!4@?A$#42!193?_!44?O$#43!38?O_!105?G!63?@$#46!149?@@?C???@BFFM[{__$#47!47?CO@G!13?@@@?@?@!10?__!36?D^^O__!4?HGC?O$#49!47?AFE?O!8?@!13?_!41?_?!5_???__?OopoG!5?A$#50!188?G$#51!166?@ACG$#52!141?@!94?A$#54!199?C??AA??@@@!8?@!13?AG$#55!237?FN^}}~y~w~~pualQ$#58!236?@$#59!240?@??D?B???GO?d^w~vF$#60!210?C!30?@!12?F$#62!194?@$#63!67?A???@???_!39?_!18?O!7?C$#65!37?_!4?_!149?G$#66!53?_!5?@?@?@!6?A!8?!4G!34?@!15?C???A$#68!190?O?_A!10?A$#69!41?_$#71!78?_$#73!52?O!57?A!92?_?o?[KCA$#79!58?@!4?A!165?_$#80!37?A??A!102?@AC!79?A$#82!33?O??C@C@$#85!73?O!129?O!4?A$#86!35?@???A?@@@$#88!132?@??A$#89!33?G?EBCB$#92!149?O$#94!201?C!11?A$#95!34?_!161?O!39?O$#96!112?@$#97!197?@!22?A$#98!52?J?C?Q?ccA???AOOO?W??G???G!10?@?@`@`!7?@@@!6?@@__``@@!22?c__?G?O$#99!52?C???KUYGkK[[WgK_S!4?G!12?_?__?_!13?@!33?WOOooO_!74?_$#101!193?O$#102!51?E!4?@H?QOo__cC_KG!18?_!52?GGG?_?_!60?A$#104!228?_$#105!185?_??OOG!5?E?AqG?KCCC!11?A?A!4?_!7?A_C$#107!200?O!15?C!15?@A$#108!186?_!4?_?G!19?C???C$#109!144?@ACG!39?_!6?G__?_?@@!9?_OGyK_GGG?G{o?wGP?AA??GW_$#111!188?_???O??C?O@H?W@G??A!5?G??AQO_OGo?@?@Q_A@???S$#112!197?aO!11?_O??C???U?CC?KH?@A@C!5?O$#113!212?_o?OG_!6?O?_?O?C!5?_$#114!215?_???C!14?_$#115!187?O!7?G!4?_?O!21?C???C?G$#116!32?C!123?C$#117!160?_$#121!110?cC!71?_!9?C?P!19?@!6?A$#122!33?@!112?@A!4?@??AG!27?O!6?A$#123!45?G$#124!34?@!112?C!43?C!6?G!5?@!5?OG!9?@!9?OC$#126!234?@$#128!76?O$#133!245?C??M@LQG_??G$#134!147?@AC?@???G?C???_!28?C?A!42?C$#137!72?__!44?A!5?@DCO!13?A!28?_$#138!71?_!7?O!47?G$#139!41?G?O?A$#140!32?G!118?_!84?G$#141!152?_?C???G!23?_$#142!40?O??_a$#143!153?C$#144!47?@!91?@!28?A!39?_??A$#145!140?@??A!25?C???A$#148!210?G??@$#149!47?_!116?@A$#151!202?_???O??A$#153!36?_!154?W!45?_$#154!32?_!115?G!63?C$#155!209?_$#156!44?GO@$#157!82?O!35?C!6?O??O_$#158!153?_?@!54?@$#159!143?C$#162!31?_!116?C!4?A!27?_!7?C!45?A??_$#163!150?O???@??O?O!27?G!24?A$#167!53?Ooq_!13?CEF?FF???!4FN^]!7?M}~!4}???^}?]}~M!23?AMCCCc$#168!51?@!33?_!54?C$#169!184?_$#170!152?A???A!77?A$#171!156?O???O!11?_$#173!39?G?CC???_!97?C!25?G$#174!37?O??C!153?A!37?O$#175!40?_$#178!111?A!38?G!7?_!26?O!51?G$#179!232?_$#180!170?O$#181!50?@?_!78?G$#182!142?@!87?O!8?_!17?G$#185!161?A?O$#186!173?@$#188!74?O!74?_!81?_$#189!43?A!142?O???_???O?G!4?A!12?@!5?@!6?CGG$#190!206?C$#191!57?_!10?_!4?C!12?@?@G??A_!6?A_i??A!31?O!9?_$#193!235?G$#199!38?g!70?_!36?OO!48?@G!18?@?@@???A??C!6?@$#200!68?AA_!9?_!35?G!15?A?@???A$#201!32?O!11?@!155?C!4?@!18?A$#204!165?@ACG??_$#205!160?@$#210!36?O!188?C$#211!148?_!60?G$#213!50?E!11?B??A???_!7?_!31?O!5?OC!16?@??A!4?C??G!62?_O$#214!165?_!5?O!85?O$#215!43?C$#218!51?G!9?A!16?G!32?G!92?oGg!23?_$#219!37?G???A!147?_!5?A$#222!200?A!4?A$#223!204?G!15?O!6?G?O$#224!203?@$#225!197?C!33?G$#231!66?A$#232!42?A!155?C!32?C$#233!35?_!109?@!4?_!41?C!28?A!9?@$#236!201?_!17?_$#237!33?_?O$#238!193?@!15?O$#239!161?@$#241!53?NJL!13?CWWOBGGFNF!6?@]]]U]][P@?!4@{]S_@{`@???O]]]MA!18?WwgW$#242!34?I!5?@!105?G!42?G!4?_$#243!34?SGG$#244!194?C!27?@$#246!31?OA!147?_??O$#247!154?A!37?@!19?@!22?@$#252!39?O$#254!33?C!42?_??_!55?_-#1!31?w!8?G??@GG???O!113?_G$#10!29?OA$#11!161?@$#13!172?A!58?_!9?O$#17!158?G!71?G$#19!168?C$#20!52?_!104?G$#21!108?G!53?D!67?OG$#22!109?B!47?C$#24!48?@ACG?!5C?!4A!4?@@!47?S@??_OG?A!4?@???OO_!16?A$#26!48?_$#28!52?C!62?_?A!14?C!20?C$#29!175?A!65?G_$#33!50?@!34?A???_!31?_!14?G$#36!45?@?A$#37!48?C$#40!85?@!69?@$#41!49?@AB@JyywAGKKK???A!17?BRoo?O!24?__??___??O!5?BGOoo`H[swo$#42!107?_!82?A!49?A$#43!50?O!14?@$#45!87?G!29?C!4?C$#46!156?BBBAA??BBAA$#47!52?AO???G??O?CC!18?@CKKC!33?O??H!5?A?G@EAA$#49!57?o___!5?A!19?Go_!23?_O[^@G\^NLB!4?@C?K?A!6?_$#50!170?C!32?O$#54!108?C!51?G$#55!240?@F^!6~tHZ!4?A$#56!37?_O$#57!46?O$#58!255???O$#59!252?OQz\X$#61!162?_$#62!64?@$#63!62?G!4?A!22?_!33?C?@??O_!24?G$#65!188?O???@$#66!83?G_!27?O!12?A!11?CG$#68!161?O!40?_$#69!31?C$#72!199?A!15?G!22?OG$#73!82?C!41?G!66?ooogw[{a{FYBEA!9?oOGC!6?OoO[]FA!7?c$#74!42?!4O$#75!40?OO$#76!39?A!6?C!60?O$#78!60?@??G!72?@!65?G$#79!185?_!13?@!27?A@$#80!33?_??`?C??CC!4?G!160?@$#83!42?A$#86!44?AC??O$#87!32?O$#88!83?O$#89!32?_??_!7?EC$#94!181?@!24?C$#95!33?@?OQGG$#96!217?G$#97!33?EHG!130?G$#98!63?__!8?D@?DH?J!6?@A??OO?OW!5?B?CCOG?G??]C?A!12?K!17?AAA@!6?__???_!55?C??C$#99!62?_!10?AE?AABC!7?@FFFNUN!7?UGR?B\!4?RF!14?G!11?!5B@?@!9?_!36?C!27?_$#100!240?_$#102!77?CC!10?GG?H!8?HRG??A!4?G?@!31?@!37?_!28?O!12?C!11?@$#104!217?@!4?O$#105!162?O!5?O!5?G??KC_?_o@?@GA!4?C@???@!12?_??G!13?@!9?k$#106!38?__??__$#108!173?G??_Og?G?A?C!31?_!20?O$#109!217?O$#110!164?OO!17?A!21?o??C_HF???B??O_?O?F!10?_$#111!163?O_?o?gWGwwos{K_O]uML[P]D@!4?AAB@@!10?{_L?WK@F???gGaBM?B!8?GCPc$#112!181?O!30?A!6?OG$#113!165?_?o?_o!5?O!7?I?A!4?C!11?__?w?YQU?@E??@_?CTK@GCB@!6?oZmZ$#115!34?EC!137?C!15?GL!42?@$#116!177?@$#118!47?_?_$#121!47?C!61?C!51?G$#122!29?_!136?C$#124!37?Q??@GGG???O??_!121?C!16?A$#126!88?G!71?O$#127!108?_$#133!249?IucnlCa__$#134!31?@!129?A!70?O$#135!108?O!70?@$#137!58?A!4?A!60?@!5?ACGG_$#138!52?G!63?A$#139!30?_!15?@$#140!174?A!65?G_$#141!158?!4C!77?@$#142!49?G$#144!50?GO!64?G!6?C!81?CA$#145!207?@$#148!154?C$#151!189?__???O?_?[?WDC?@!7?__!9?__?__??@!7?G$#152!39?O$#153!38?A!9?G!139?A!43?_$#154!39?G!137?A!9?G$#155!165?G$#156!66?@!89?G!10?A!33?_!29?A$#157!51?CO_!4?C!5?A!4?@!46?_!6?A?@!4?@A$#158!154?@!18?@!84?_$#162!30?C!123?A!10?C?C!5?A!55?_!9?A$#163!153?@??C???@??CC!13?@!53?G!7?C$#167!56?@??@!6?C???{{{w?xw???woo_!10?__c_cc_???__???__!13?ooo?o_!8?CG!7?]}}}{{w???OO$#168!112?G!14?C!66?C!19?G_!7?O$#169!207?A$#170!155?A???@??A!65?_$#171!166?@$#172!188?G!49?@$#173!30?O!16?@AC!154?G$#175!51?_!99?@$#177!46?_$#178!169?C!61?O$#179!159?G!69?O$#181!58?OO!57?OA??A_!6?C?@??C@$#182!202?O!27?_!8?C$#185!86?A!78?@$#187!87?C$#188!89?O!113?G!26?C$#189!31?A!130?G!8?C!4?A???@$#190!184?_!11?A!14?_!27?_$#191!66?_??A!4?_???G??C!21?_?O!20?A!13?C!19?_$#193!216?A$#197!30?G$#199!39?@!4?@!144?@?@$#200!54?@?A!4?O??C!5?@!11?A!30?GA!8?O???A!8?A$#201!38?@$#204!172?@$#206!232?@$#207!153?A$#210!45?A!117?G!76?O$#213!55?@!5?@@??C??A???@!41?@!8?_!15?O!10?@A!9?_!25?__!16?A@!22?G?@$#218!108?AG!76?_??OO?GG?C?A!5?@?@!7?O??CAA???_??GK$#219!37?C!8?G$#222!33?G?@K$#223!35?A!162?@!6?G!18?G!8?A$#225!167?G!18?O!17?O!14?A!6?A!10?A$#228!29?G!141?A$#231!61?_?@!7?@!9?@!31?C$#232!187?O$#233!37?@$#236!110?@!80?G!24?O?@@!19?O$#237!32?E?O$#238!152?@$#239!171?@$#241!57?@@???OOWwW{{{AAA?WE?oooFIG!8?___F^Z^ZZ[__?NC_F@O?_!13?K?o!9?BBCw!6{_@@!4?WOO__$#242!32?@O_!5?CB@!148?A$#243!32?G!6?CA$#244!178?A!8?C@!6?A!37?C$#246!176?@!55?A$#247!155?C!75?CC$#251!40?__??__$#252!46?A!142?C!66?C$#253!188?C$#254!128?G!30?O!40?_???C!33?A-#1!31?F!22?G!116?@!27?A$#11!49?C$#13!50?_!176?_!15?g$#20!53?@$#21!49?GO!56?@$#22!46?_!59?G$#23!255?!6?G$#24!112?ogSH?CA!17?@???O_!20?A!13?G$#25!251?_O$#26!49?O$#28!116?K!18?@!27?A!8?A?CG?O$#29!57?_!106?@!61?GC$#30!194?G$#33!65?G!43?_C!9?@!18?C!25?A$#36!30?A$#37!30?C$#38!29?g_!161?O$#41!54?@BB@??A?A!45?oWWSB?`?_`@AA?A?_!8?BFM[xrr!27?A!5?C?O?_$#42!107?A!116?_O??A?@!11?C$#45!170?A$#46!175?C$#47!57?ABA@ACCK!25?@!16?_???IKBGcBOsssvso!8?@!7?_GO_!22?A?AACKKGW?O$#49!60?CD?A??G!18?@@!20?OG!8?G??G!19?ACG!21?!4C?CG!4?__$#50!229?O?A$#52!223?O$#54!105?O$#55!243?@Jz~n~}MMLG$#56!35?oA??_?A?A?_OO__$#57!37?_!5?C???@$#59!250?@OA`{L]^Yu_o$#60!199?@$#61!172?_!5?_$#62!197?C$#63!58?C!28?AA??A!39?@AC?O!4?@!17?CC?C!7?G$#64!45?G$#65!55?O!12?_!122?_$#66!69?O!15?AC??AA!13?_!5?A@!10?@!13?_!23?C!5?GGG???O!4?G$#67!56?C$#68!35?COO?O!5?O!4?C!179?G!11?G$#69!31?G!24?G!8?O$#72!185?O!34?C$#73!70?O!21?C!12?G?G!35?G!27?O!5?CAIUAevTDqbEO[@JEBBA@@!4_o_?o{geC@PooWg?[Gw~VLD?@$#74!40?A???A?G_O$#75!36?_@??G$#76!53?C???O$#79!181?@!26?O?@C!26?A$#80!32?Gi!17?A?O_$#83!32?AC!17?C$#84!43?_$#86!33?O@@!15?O{G$#88!152?_$#89!32?S@A!18?_O$#93!204?G$#94!58?!5_!179?O$#96!91?G!118?G??G@!22?G$#98!64?@@BBBJ!4?SS?C{Kc!12?O!9?WG!23?k??gg_!8?AAATVV!6?BJJG?@@!8?__!8?@!15?_!41?C$#99!74?A!19?G!7?W?O!26?C!11?CCA!48?_!14?@$#100!238?w~~}_$#101!232?@$#102!178?@!13?_!12?C?A!4?C??C!21?A$#105!175?@?@!24?G!26?_!6?O$#106!37?A?B@C?O`?AC$#108!211?G!19?_???C$#110!195?O!5?G?@?@??@!4?C!17?OQ$#111!173?@@?@!20?WOKK?EAE!9?C@B?@!11?oGC[KoB$#112!236?G$#113!196?O?G?AE@C@AB@!6?AA?@!14?gbrJC$#115!201?@!29?C$#116!28?C!20?@$#118!34?_G!14?G$#120!42?A??C$#121!50?B!118?@!23?O$#122!48?A!174?_OGCA@G?@$#124!34?O$#126!173?A!50?GCA$#130!46?C?G$#131!173?_A$#132!36?C?GC_GCGO???C$#133!226?OG?A!14?CC?O?@o@?UBq`_dGW$#134!228?_C$#137!114?A!27?_!18?A$#138!67?O!38?_!6?C?O?A!20?G?G!23?A!6?A$#139!29?OX!191?_$#144!29?A!24?A!56?_!7?@!17?ACG$#146!28?G!201?C$#148!29?@$#149!28?O$#150!37?G$#151!178?Gcgo@G_gLCPN@MC@C!9?OOG?CG_a_@?_Ow?sA??AAB!12?@$#152!36?@?o???o?K$#154!51?`A$#155!57?G!4WOoo___$#156!56?O!141?A$#157!110?_??O?A!20?AC???O$#162!228?O$#163!105?_!124?A!11?B$#167!71?^||_@~_??B~zzVswO!4?A??Fv~f~ff?_@F??FB@!13?NVv?@vP???o!13?nk{][~c??qz??xww$#168!88?OGG!53?O!65?O!9?@$#173!28?_!26?G!50?O!152?@??_$#174!53?A!113?@!32?@!42?A$#175!166?@!59?_!17?_$#176!36?G!4?O$#177!38?CG???@$#178!106?C!136?C$#181!59?@!56?O?GG?GG!17?C!19?A!7?C$#182!189?_!37?P!16?O!15?C$#186!225?_??C$#188!70?_!35?A!84?O$#189!241?@$#190!180?@!15?_!12?O!27?_C$#191!63?@?A!4?I???@??AAq!9?__oGgO!32?KO?C?C!10?@@!10?O???GG!7?_$#192!40?O?G!4?A$#193!193?_!18?G!6?@$#198!55?C$#199!52?@!112?@??@?@!24?G$#200!59?C!5?C?GO!17?A@@@!19?C!13?GO_!8?G!8?O_!17?CD!9?O$#201!66?O??_$#210!31?_$#211!141?A!29?_??_!18?G?C$#213!66?C?G??_!15?GCCCD!15?C!15?A!18?C!8?_!5?C!7?G!10?C!11?_$#214!190?_!5?C$#215!29?C!24?C$#218!88?G!87?AACO?KW?IA?WG?A!5?@?_???O??g!4?AOA?G??C_A??G$#219!55?_$#223!194?O?G???O??G!9?A$#225!199?O$#231!57?C!4?@G!23?C!35?C!73?A$#233!31?O$#234!41?@@??A$#236!175?A!21?_???O!4?C?A!7?C?A!17?_O$#241!67?CCCD?AAGi?X@@W?CCgG?__OO?pFfwG?W?WWfFE?@!16?@?GGrAGiQOW?_!5?@@?GgggORB@B?Wcs@?oo???woooOOO$#242!32?`?KA!15?G$#244!172?@!25?C!18?A!19?@$#246!27?oA!19?@A$#247!243?O$#248!47?G$#249!40?C$#251!37?CB??_???@@$#252!56?_$#253!228?G@$#254!62?G?A!94?A??@!15?O-#1!31?C!19?@!190?G$#10!23?O??A$#13!243?I$#18!177?C$#19!103?_A!116?A$#20!59?CO!4?A!7?AA???O!30?A@$#21!50?E!165?_??O?G$#22!50?G!166?O!25?O$#23!252?@!10?A$#24!105?G?CA??@!31?@?C??O_!27?A_G$#25!102?_$#26!32?C?@!11?@???O$#28!104?OA!36?@!35?G$#29!72?@!152?@?@$#30!184?A??@$#33!112?@!64?G$#35!28?@!49?_!4?O!6?_$#36!28?CA!59?_$#37!30?@!51?O_???_$#38!28?A@!50?oO???__?_!12?_??@$#39!178?@??C$#41!98?CCCEEE?CBA?Ccu?A?AA?A!5?@@@!11?@@B???@A!13?_$#42!218?Og$#43!27?G!187?O$#46!248?C$#47!97?C!8?O@@gWGECECDB?!4@!18?BA!5?_!28?@$#49!100?AG?@?O?Ww???whH!24?A?CCK[Wo_!8?GO_!17?@$#50!223?G!18?O_@$#51!181?_$#53!175?C$#54!32?A$#55!182?CA!60?w^ND@@_$#56!36?@?_!4?_???A{?_O$#57!33?A!11?O$#59!247?A???O[JK^Yjb^~~~w$#60!178?A???O??_$#61!253?O??_$#63!96?C??AG!16?C!27?@!6?@??C$#64!31?_$#65!69?@!21?O!8?O$#66!102?@!17?A!5?AB!9?@??C??O??A!6?AC$#67!99?G$#68!35?@!15?A_$#69!58?@!35?O??O$#71!156?O!57?O$#72!141?G!46?A!7?A!5?A!10?G$#73!179?A@B`HCCW]G]r^zcxu|~rx\f{re}~WUMvxhONJEDA@!11?__G[$#74!32?G!4?_???AG!4?@AN$#75!39?O@??Q?G$#76!27?O???A!139?G$#77!44?A_$#78!118?C???A$#79!234?_$#80!29?_!22?AGCC_W_$#83!29?O??@!19?O???G$#84!36?A!4?CO!4?C$#85!156?C!78?G$#86!27?_??g!21?CchyQ$#87!52?G?A$#89!26?_?_GO!22?RO@C_$#94!59?!4@!31?GG!124?_?O$#96!116?G!56?G!61?@$#98!81?A!11?@@!28?C!4?C??cCCw!5?W?_!4?AC!7?_??GP???o__o_Oo_o__$#99!75?@!13?C??CC!22?Ogo_oww_w???ww?Wog!7?o?_!11?qAE?EM???N^^N^gGRC?G$#100!235?_{!5~F$#102!77?A?AA!5?GCC?CC!23?O?OGWG??W!8?GO!35?FF!59?O$#104!84?CC$#105!81?C!146?@$#106!33?GosWGEGWobKPCO$#108!232?C$#109!223?_!6?A$#110!223?O_???O$#111!224?O?we_IHC@B@$#112!227?O$#113!221?__??wCGMTCBA$#115!80?C$#116!22?_!197?O?G??A@$#118!31?O!19?G$#120!38?O!10?o?_$#121!31?G!194?A$#122!103?O!111?_O??C!23?C$#124!66?@!9?A!18?OO!128?C$#126!186?@!26?_!38?_?__$#127!177?_$#128!147?G$#129!61?A$#130!36?_$#132!37?@?_!4?C$#133!248?A??_?CR?DS[_$#134!221?O$#135!224?A$#137!106?C!39?G!31?S$#138!147?O!28?C$#139!25?O?C!51?o?__?_$#140!105?@$#144!58?C!4?A???A!4?A???C!67?A!30?A???__$#145!68?!4A!5?O!96?@$#146!224?C$#148!25?GC!193?A$#149!77?_!98?A$#150!32?o!4?O???@C!4?O$#151!179?@A??_@GC?C?C_?PEH??K?aW@?X@?fg`GEUE?C?A@!11?_?Oo?E$#152!33?CAA!7?@G?_!4?C$#153!79?C???G$#154!84?G$#155!64?@@!30?GG$#156!62?A!21?O!7?___??___??O?__$#157!106?G?C@A!32?A??C!30?O?O$#158!181?G??OA??@!31?G!24?_$#162!50?@!166?_g???@$#163!104?C!118?C!18?_@$#167!77?@???@@@!4B!8?BB@@!24?ACCC?@F???BBBA!10?@BB`_?@???H??@_o$#168!114?O!32?C!9?_!17?_!56?GC$#170!250?@$#171!175?@G!6?O??_$#172!103?G$#173!27?A!30?AOK!10{|!4{wK?GG!4?OO!8?__!167?O$#175!57?AG_A!157?C!25?A$#177!34?C???@?_???_?AG$#178!220?C$#179!23?_!33?@!6?A?A!154?@$#181!102?G!6?O!5?@??@!4?@!26?_!7?O$#182!222?A!23?OG!4?A!10?C$#185!179?C$#186!221?C?A@$#188!173?@S!13?_!64?_$#189!29?C???@$#190!63?@!10?@!17?GG!135?_!4?A$#191!88?@?@@@?C!21?_???C!5?G?@??@!5?O!4?O!5?G??C??G!7?E!9?@$#192!45?@$#197!24?O!34?G$#199!26?O???A!47?C???G!6?O!154?C!19?_$#200!106?__!5?O_!4?A!22?G??_!14?_!19?O$#201!59?A!10?@!4?A!14?O!10?O$#206!27?@$#207!214?_$#210!25?_!5?@!36?@!4?@!18?O$#211!173?A!9?C!5?@$#213!95?C??I??@!19?A???A???A!8?A!5?_!8?@!7?_!10?A???O!7?_@???_!30?@$#214!180?G$#215!26?G!54?G!5?O???_!8?_$#218!123?A!60?G???O?G?CI!5?E???K!4?@O???@??@!14?O!4?@$#219!30?C$#222!91?G$#223!85?G?!4G!144?O$#225!78?A???C???C!144?G$#231!128?A!25?A??G!17?O!6?G??OA!32?A$#232!28?G!29?O!8?@!31?O$#233!56?@C!35?O!4?O$#234!38?G$#236!171?C?C!62?A$#238!60?_!17?G!25?G!112?G!32?O$#241!76?@?@@@?AA!4?AB!5AB!4?@!18?C?CC?Cwow?CwABBC{{k{{_!5?@@AK[Y]{o@@@E@?]XN$#242!28?O!23?@$#244!83?C!140?G$#246!24?GC@$#248!47?_@$#251!33?oGGCE?FEG???AK$#252!24?_!63?O$#253!180?C!6?_!34?C@!25?A?G$#254!115?g!33?O!5?G???O!12?GOAG_!4?OA!33?G-#0!63?Gwoo?!6o$#1!86?A!5?O!11?O!91?C!54?_??K$#8!67?_$#9!19?C$#10!22?G??O!187?@$#11!27?_$#12!69?G!141?A$#15!70?G$#19!23?G$#20!63?_!12?@!33?GG!13?_!25?@!21?_?_?___!30?A$#21!49?o!50?_G$#22!32?_!68?C!110?A!24?O$#23!27?O!213?_?O??C!17?_$#24!123?OO!25?@?C?Sg???_!12?_?GG$#25!216?@!25?C$#26!37?@???G!7?A??B$#28!156?W!14?O!5?C$#29!20?C!80?A!137?O?C$#30!180?_!9?@$#33!124?_!46?_O!5?A$#35!113?O$#36!84?@??H@C??@@CE@?@!7?C$#37!62?_!12?_??A!15?A@ADAA???A@A?_???O_$#38!76?OM@@!8?W?GMG???C??@A@??A?_C__?_$#39!176?C$#41!149?BA?G_???_O??`o_???_G?_$#42!24?G!215?G$#43!60?A!15?_?C???@!7?A!103?A$#45!169?G!6?O$#47!112?@?@!6?G!26?@??C?O??_?GO_?M]_?_?__???OOO!4?@$#49!113?@?BBECMKSC?GWG!20?@!4?O???CG??XO??[{WWO?GGG$#50!213?A!28?A$#51!186?O$#54!238?G$#55!243?`oow{yy$#56!32?K???CEG??S???_Ng?@@??G$#59!249?C@!6?tDfV^f}N$#60!172?C!5?G!77?_G?Gg_W$#61!255???A$#62!100?C!155?P$#63!117?@G?O?__C!7?_!19?@!11?A?C$#64!53?C$#65!91?O???G!8?C??G!73?O!57?C!10?S!4?O$#66!127?W???_!16?A!9?C@!22?A$#67!174?@$#68!31?A!177?C!43?_O$#69!29?O!31?_!25?E!21?@!4?O??G$#71!199?A$#72!188?G!6?OG_!23?O?O_?g?O??O$#73!122?A!59?@BBBFM?[?CGK@Gp?p?a`A?@?B??@@!6?_?__?o_O?OoM^ENF@$#74!33?_?WAGTP?_??oK_SC?W@C$#75!32?@$#76!22?A?@!59?A$#78!128?O!21?GO!78?@$#79!165?A!10?@!20?G!5?_!24?@??_G$#80!28?G?OG!23?k?oL!19?___C?U?C!7?O!4?G???G??G!145?O$#83!25?@CE?C@O!21?@??CK??O!17?O!13?_?o$#84!41?A?@$#85!175?A!9?O!6?O_?C$#86!23?AEA??@@!24?EBAA?C!20?CAC$#87!54?oOW?_!20?WWgW?G!5?__?_?___?o???W$#89!23?C?CAHAIM!23?H?_@Aw!21?Oa?C?C!8?OO?oG??O?G$#92!252?C$#94!115?GO$#96!143?O!12?A!48?_???_!9?O$#98!120?@@@BB???BB?K??BS[C!4?``??__!8?@!8?@@?@!4?@$#99!128?CC??FB?G!5?^AMFAM?[!6?@?B!8?ABA!4BAA!11?_!34?G$#100!232?_w}^NNFB@$#102!129?G??WCC!7?[?G[O[!34?_G!17?O!25?@$#105!184?O!14?G!11?C$#106!42?DA$#108!182?Oo!16?G?W??G?G???GGOG?OG??G$#109!184?_!21?O???O!8?G$#110!208?G!7?C!5?C?A@$#111!212?O???AAAC?D?A??@$#112!213?C?O??G?@$#113!182?G??_!15?G?WWOG?OWGOCGSKGCCBEAB@@$#114!207?O$#115!218?O$#116!214?@$#118!32?O!67?OOC$#120!35?AH???A?_?KOO?J?E$#121!200?C!6?C!27?_!5?@$#122!215?@!23?GCA$#124!31?C!21?A!25?C!5?A??A!8?G!8?G?@!143?aQ$#126!23?@!37?O!28?@!14?O!86?A???A!12?A!40?a!4?`M$#127!181?@$#128!189?@???A$#129!83?@!5?O???G!4?C!9?G$#130!45?A$#131!112?A$#132!40?@???B!8?o$#133!248?C!9?yO???@$#137!126?_!24?A?G!16?O!5?G?CUQ$#138!154?_!18?G$#139!85?`PO?GC?EE@??A!7?@A?C?o??_$#140!20?A$#142!76?G!23?@!144?G$#144!28?_!48?@!30?O!44?C???O_!22?A$#145!65?C!41?O?G$#148!72?!4G$#149!26?_!49?A$#150!43?C$#151!185?C??A?]GC?W`?O?_@A@BAB?@@!9?_??_???{CM__G$#152!31?@A$#153!60?C!156?@!32?G???`I$#154!26?G!33?G!16?_!5?_OG???_!10?G!150?C?K$#155!110?AECGKOg_O?_!115?O$#156!60?@!42?@!4?AO??O$#157!122?G!30?AG!14?O!7?OO$#158!183?C?G??_!6?A$#160!68?G$#162!21?@!4?O!209?_$#163!49?K!52?B!135?O???@$#167!127?B??`!4?`__`__!8?___?@!4?@!18?@$#168!119?@!6?C?GO?O!60?_!11?_!8?__!9?C$#169!60?_!190?GO$#170!62?O$#171!177?G??C$#172!30?_$#173!22?@!8?_!30?!4B!9FRC!26?__?@??C!4?_$#174!85?O!16?_!7?C$#175!79?A@@!6?C??@!7?C!5?C!9?_!57?C$#177!34?@$#178!237?_$#179!29?_!34?C!173?_$#181!118?A???OG!26?C!4?S???G?G!17?@$#182!174?C!67?_$#185!191?@$#186!187?O!61?@$#188!112?G!71?G???@_!61?@$#189!21?A!79?_!95?CC!9?C$#190!113?C???O__!80?O!5?___?___!19?OC@$#191!129?_?@!7?G!5?@?A!11?A!4?@$#192!45?@$#193!223?C?A$#194!66?G$#198!107?@$#199!21?C!6?O!55?_!4?@O???G!106?!6C$#200!111?@??A?C???A??C??O_!23?G??A??C???E@!14?A$#201!77?O!8?G_!111?C$#202!175?C$#206!74?_$#207!62?C!8?G!80?A$#210!25?G!33?@!29?A!13?C!136?A!11?@@?C$#211!197?A$#213!119?O!8?_?O!13?__!6?_!10?@!4?CCC!7?@?G_!5?@O!4?@!4?A!8?A$#214!243?A$#215!61?C!43?_?A$#217!63?O???G$#218!160?A!27?CA_O?Oc??@?P??_!12?__???O??GG!5?o??A$#219!59?A!20?A$#222!210?C$#223!198?G$#225!133?WW!82?O@$#227!65?G!8?O$#228!19?GG$#229!67?O$#231!110?@??A!7?A!24?@!12?CC!18?G!4?C!7?@!18?@$#232!78?G!9?_!7?G!12?A!144?A$#233!22?C!159?C!31?A!36?A$#234!33?A$#236!134?_!9?O!36?G!9?_!30?G???A$#238!61?BGC!11?C!98?_?_!35?@$#241!125?BBC??MA???ABZ]V^_!6?_WO???@???A$#242!26?@?C!27?@?O!24?G!13?O!154?G$#244!215?A$#246!18?CA?G??O$#248!33?[}dooam{?Ww???Bo?_}w$#251!33?@!7?@A$#252!61?G!24?_$#253!106?O!137?@!19?O$#254!115?C??@??_???C!7?_!15?C!5?A!11?C???C???@A!4?C!4?G_???A!16?A-#0!34?_!17?___!10?BN_?@`xF$#1!26?G!5?O$#3!54?O!18?@$#5!67?O??O$#7!67?G???A$#8!66?OC$#9!53?O!14?_$#12!176?_$#13!219?_!5?O$#15!66?_$#19!98?G!73?O!59?A?@$#20!64?AG!7?C!53?@!32?@!10?A$#21!33?KO!14?b!48?O$#22!49?C!176?O??G$#24!126?@?A!27?AKO!9?D?A???e??OO$#25!26?C$#26!33?A???_!7?@??_G???G$#28!155?@@??@!9?__??C?CAA?@$#29!86?_!13?A!131?C?A?@!22?_$#33!167?A??@??_???@$#35!32?C!30?@?O!30?A!25?G?_$#36!63?A!26?_!21?@!8?_$#37!30?C!34?_!9?@!13?_???_??C???C???A!4?@!4?A?A???O??_$#38!28?BAAE!31?K_!8?OE!17?OG?OGC???CA???@???B@?B@?KK[?gO$#39!176?C??A$#41!131?C!5?EECG!8?O_???@ACQF]Q?@!7?S@D?G@$#42!25?O!71?_!129?O$#43!57?_!139?_$#47!136?A??G!16?G@??G!10?_?@@GH$#49!134?__@???C!7?G!8?_??C[?@??@?AO?C$#53!168?_$#55!226?___o_WWw[}s[}}!6~v~~|m[!5?A$#56!44?A??@OO???C$#59!246?G???@_OEaIGPoTDLE$#60!215?_!36?A??@???AGA@$#61!177?C$#62!62?A!27?G!99?@!63?@$#63!124?@@AC??A??@O???GA!7?EC?O???A!8?A$#65!27?C!30?_!4?_!31?_!7?G???O??G??C??O??A!45?G!25?A!61?@$#66!128?C?G!5?C!4?G!4?B??_?_?@??O!7?AA?G!34?_!25?C$#68!54?C$#69!56?O!57?G!8?G$#71!179?_!27?_??_$#72!180?G?__!12?GGJ??C???A?AS??C???GAEGA?AAG!5?@$#73!128?G???C!15?O!31?CI[W_!11?BFC]EA\DVDYX`cQJWFUBOPQTLKLBCBFFBA$#74!34?GO???__??@?AbaE??O$#76!25?_???G!32?G!11?_!21?_!20?_$#78!155?G!47?O!20?A$#79!126?C!36?_OO!25?@?A!36?A$#80!26?_g?O!27?G???S!13?OQ@C__C??OQA@G??D???@!7?OG?wC??_$#82!57?C???@$#83!28?G!27?C???`G!13?_???GAA??cC!4?D?@A!11?_!6?_$#87!26?OO?_o_!22?@E?@^EYAO!12?GGSRUDHWOGGSC?BAAA@@?@??_O??__?C!4?WWwo_$#88!136?_$#89!28?o!26?@J??HC__!13?cig@WOcGA?GIFC!14?OW!5?_$#93!165?_$#98!132?a?C!7?sssSso_$#99!130?O_!13?_$#100!232?@$#102!120?@??C?C?W!56?C!4?A?C??O$#104!129?O_!54?G?@!4?G$#105!183?@??O$#108!184?BAGCQ??OoO?_$#109!185?@C?COC_$#110!188?_$#112!188?G!4?_$#113!185?CBy?kwG??_$#115!123?A$#116!26?A$#118!52?O$#120!33?@!8?@A!4?G!4?A$#121!98?_!132?A$#122!25?G!194?_$#124!54?AG!27?A!18?_!22?O?_$#126!87?O!30?_!60?O!15?G!5?_$#127!178?_!42?O$#128!126?_$#129!103?C?A??G?C?A!4?O?_!4?O!91?_$#131!166?_$#132!38?_!14?@$#133!249?AOAkw[svkNGA??@$#134!32?A!66?H!123?_$#135!32?@$#137!129?AC!27?_??@!7?L?O???A??G$#138!169?A$#139!29?@@@G!31?W!23?_?Oo_OWG?G!4?DB@@??@!6?A???W??o$#141!222?_$#142!29?C!43?_!22?O!4?A!5?@!6?CC$#144!72?_!88?A!10?GA??O$#145!56?_!40?A$#146!227?G$#148!36?_!13?_???G!17?O!97?GG???_$#149!172?A$#151!180?otA?O_!9?@??O?HX?I?WC?IJLOBWGSL?@GA@??@C$#153!74?O!33?C!142?@$#154!31?O!50?@!11?A??@?O!5?C?G??OCC$#155!118?@@A?@?A$#156!87?_OO??G??C??E!9?OO!7?AACC!105?G!12?@$#157!128?@??GGO!24?G_!7?@!5?G???G@$#158!167?O!28?O$#160!64?@!4?a???A$#161!68?[[E$#162!24?_!199?O???G?C$#163!33?O!65?E@!120?_!9?C?A?@$#165!168?O$#167!130?@B@??[GO?pr!6?G?FJZZY{$#168!129?G!11?C!14?_!31?@???@@$#170!64?C!134?_!22?O$#171!162?A!15?A$#173!27?A!27?O!18?@!19?C!6?@!6?_G!6?@!4?G?O?_!72?_!18?_!11?C$#174!97?O!9?_???A???G$#175!63?O!11?A!18?_!7?G$#181!129?C!30?_!11?_$#182!193?C!6?_!23?_!12?A!22?O$#185!179?G$#186!225?_??O?O__C_?G_$#188!30?G!64?A!5?O!4?A!59?G!13?@!8?@!24?_!10?G$#189!98?@!134?@$#190!121?@C???O?_!54?A!6?A$#191!133?E!9?A!11?_$#193!125?GG?O$#194!51?_???_!16?G$#199!28?C!45?G!8?@@!15?G?O$#200!127?A!4?O?@B?@!11?G!5?C!5?_??@@ACG$#201!109?_!7?@!45?C$#206!175?O$#207!27?@$#209!194?G$#210!32?_!29?C!13?@!8?_!6?C!8?G??C??AA!12?C!42?C!27?A!59?@$#211!195?O!7?_!9?_$#213!129?@?O?_A??G@!23?w??C!14?A!23?___!4?_!12?G$#214!91?G!17?C$#215!73?G!41?@$#217!65?C?BA?G$#218!163?W!18?@CG!9?BEC??@O?A?G?@C?O??C?@??GC!4?C!6?@$#219!57?O?_!26?@!28?O$#222!196?_$#223!121?A??G!106?@$#225!122?A?C$#226!71?C$#227!33?_$#229!35?_!32?@$#231!123?@?A!7?G!11?@!16?C???S!11?C$#232!85?@???G$#233!75?C!6?A!17?_$#235!81?_$#236!164?_!20?O_!6?G$#238!218?_!4?O$#239!177?_$#241!134?G?O_o??rJHJIG@B?CCcc?O$#242!57?A?O!23?c!32?_$#244!129?_$#246!24?OC$#247!173?OO$#248!34?FN!5^~}{|{[[@?^NN$#252!31?G!30?@!38?_!7?A!126?A!26?A$#253!93?C!136?G$#254!164?G??_!11?C!12?C?C??O!14?_!7?O-#0!32?o~B!4@!11?!4@z}o!10?Bo{F$#1!60?@??@!27?A!4?O!11?_$#2!49?@$#5!34?_!6?AAA$#7!39?A!6?A!22?@$#8!38?A?@!5?@A!23?@$#9!38?o?G@!7?C!4A$#10!21?_$#12!42?@?@!129?C?C$#13!202?@$#19!187?_!27?@$#20!57?@A??O!5?_!10?OG?C!90?@$#21!95?OC@!103?A!4?_$#22!183?G$#23!179?@?A$#24!159?AK$#26!96?G$#29!31?O!47?O!28?A!68?G!26?G!13?@$#33!152?CO!5?OO!15?A$#35!72?@!11?A!41?@_A!58?O$#36!62?G!18?_???C??A!18?@!24?C$#37!58?GO!28?@!33?@??@AA???_???_$#38!59?go_???N!5?_!4?O???OG?CCICA?A!7?_!26?AA?CcKOW_O_$#39!161?_$#41!136?@!14?BIGo???Ag!9?oGK{?gO_$#42!32?@!168?C$#43!74?_!11?G!13?@!26?G$#44!161?O$#46!178?C[k?!4_$#47!158?D?_!7?OKso?wO`$#49!153?c!12?ooGAA???@$#50!23?C@$#51!204?A$#52!209?CC!4?C!5?_$#55!189?_!33?G?eey\fzbj|~~~v!7~}]^VJCL??A$#59!245?@@??C??DD$#60!211?G?O$#61!210?G??_$#62!57?_!34?@!4?O!10?C$#63!135?@??A!12?C??G??@G??M?_o?GCB$#64!95?G$#65!83?@!15?G!6?O?G!13?A!87?O$#66!137?@C?O!11?O!9?_OG$#69!64?G!11?G!7?_!4?C???@!12?A??@!21?A?C?G!74?_$#71!166?@!23?_$#72!186?CC?O$#73!181?@?@@BA?G$#76!73?C!23?K?@!19?@$#79!164?AA$#80!24?O??kgGA!30?@?C!11?ICCA!7?_???GKG??E??@_?A?@@`???aG???O???ao?G???G$#82!99?O$#83!25?@???O!32?@!13?A@???@!6?Og!4?G???A??G?Eg!4?ODO?@H?A!6?_G$#86!24?KIKA?EK!31?AA!9?GI??A!10?G?C??AE!7?DG?K???GANE??JLC?E?C$#87!23?o__oPO@P@!42?@!5?@!4?_?o_OO_OoP@!4?o?O_OO!4?o?_o_?o_O?O?o?O$#89!25?SB?D__A!41?OCD@?@!11?_?e!7?G?gOEA???C?_XEEo?HD?eoCO_O$#93!165?@$#94!199?A$#95!204?_$#98!133?@!8?!7@!7?B$#99!134?AC!54?G$#102!131?@@?C?G!54?O$#108!189?@AGP_BehBIOg$#109!188?@?C@???G?S???G$#110!193?@$#111!189?A$#112!195?O?g??O$#113!190?@EM]{@U?sk?oo_$#116!21?O!183?@$#117!200?@$#118!96?AA$#121!63?G!35?A$#122!22?G!154?D@?A?C?G?O!16?@@?!8@$#124!23?G!76?C!5?@!19?O??@!73?O$#126!62?C!22?O!122?_???O$#127!142?_$#128!128?@$#129!99?C!30?A$#133!212?G!35?G?JAAA@B@$#134!22?O$#135!95?_$#137!172?A??A$#138!159?C$#139!57?CC!5?`_w!4?OA??_??___?wGG?A@?@@!32?@@?C?G?K?W_O$#140!200?A!4?_$#141!177?O_!6?O!30?@$#142!58?O?AC?O!8?C!8?O?OO?@C???@$#144!60?KGO!13?_???G?A!76?@$#145!63?_!43?G$#146!43?@$#148!31?_!35?O??_A!102?A?O_$#149!56?B$#151!182?@A??@ACG$#153!22?_!8?G!62?_!11?G!104?O$#154!24?A!6?C!42?O!7?@???O!9?@!24?A???_$#156!71?G!10?C?@!22?A!21?_!122?G$#157!160?A!9?@??D$#158!178?A???G!66?O$#160!56?C!10?G??O!102?A$#161!35?{{{K{s!4{|{{?w!4{$#162!23?A!152?GA!21?@??CG$#163!188?_!12?@??O!9?@$#165!176?@$#167!135?ACCHRfM!7?}{w_@EK??_$#168!134?@$#170!78?G!167?_$#172!66?A!116?C$#173!57?O?A??_!14?O??C!4?@!21?s@!17?_@OA_C?G?O__!47?G!70?A$#174!79?C!43?A?C$#175!59?@!4?A!12?G???A?_!14?O!39?_$#178!179?A?C!23?O!11?@$#179!59?C!11?C!5?_!5?A$#181!160?@!7?_??A$#182!205?AA_??A!46?@$#183!203?ACK[SK??A$#185!178?W_OwOO!18?A!4?AAA$#186!208?OG?CEMyy!4}~^~v~XXDaWC[SA???G$#188!64?C!7?O!66?_!69?O??_$#189!120?@!81?G$#190!132?A!54?@$#191!143?_?_!9?@$#193!192?_$#194!34?K!21?G!11?C$#197!32?A!214?_$#199!58?_!5?O!7?G@!14?C?A!9?A$#200!137?A?CGO!8?@!4?_!5?@???o?GC@$#201!75?O!30?_$#207!175?G$#209!207?G!6?C$#210!61?A!11?A!4?C?A!17?C??@!22?C?G!71?@$#211!184?C$#213!136?A??G?_!8?A?@A?O?AO!4?ACCA!21?O$#214!254?C$#215!57?I@!7?C!60?O?O!4?G?O$#216!68?A$#217!32?C???AA!11?A!18?@$#218!163?@!20?AC?G??O_$#219!79?A!43?C$#220!68?GA$#223!130?@!57?AC$#226!54?C$#227!32?G!6?@!7?@!7?@!14?G$#228!48?@$#229!34?OA!4?A???AA!21?C$#231!163?G?GCA!12?@?A$#232!72?_!14?G!8?_!9?C?O!28?O!73?_$#233!73?_!24?_!110?_$#235!93?C!7?O!18?G$#236!164?@$#238!66?@!104?@!78?O$#241!137?GO??@]]}]}}}@!4?@A{{$#242!28?A!50?@!11?O?G!7?cA!10?G?C?QGG??GG$#244!133?A!66?C$#246!22?C@!24?}!126?C$#252!65?O!32?G!22?@!64?_!16?C$#253!184?O!34?@$#254!162?^C???@!18?G-#0!31?]~~!18?_w~~`!12?B$#1!57?K!45?GG_!24?C!78?@@$#3!56?A!11?@$#5!34?B$#7!34?O$#9!38?_O??_???CM???O?B$#12!69?_!109?A$#13!182?G??_???@???C???_$#17!178?@$#19!184?O!22?@$#20!64?@!5?@??C?@!60?OB?_!41?G$#21!92?_G!98?C$#22!94?B!84?@???G!11?O$#24!162?Co$#25!30?C$#26!92?O$#28!163?G!16?G?O$#29!22?C!52?A!106?C!5?@!4?G$#30!142?O!4?O$#33!161?@$#35!72?_!26?C!32?C$#36!66?O!5?A!25?@!24?_$#37!63?A???_???@??OG!25?C!24?E?@$#38!60?@?BGO@A???Ge?@GsADB@!14?O!4?AC?O!21?_[!7?@@BA$#41!154?@@!4?@?o?o!5?@@B?BBAac_???_$#42!106?C!91?_!8?A$#43!76?O???A!12?_??A$#46!180?@?A@G@$#47!161?O?CG!4?@?A?B??@KWW$#48!193?O?_$#49!155?EKg_?Mm??C{^|o?A?CK[{{O??o$#50!93?O$#52!212?GG?@_$#54!22?A!185?C$#55!213?A!12?B?BAB?!4@?!4@$#60!213?@$#61!211?C$#62!64?_!39?_!19?A$#63!154?AG_?O?_??@!4?G!4?O_$#65!22?@!40?O!14?G!69?_!62?A$#66!159?A$#68!93?A?@!101?O$#69!77?O!17?O!4?@!32?O$#71!139?GCO?O!49?A$#72!138?@??_??G?_$#73!140?g?CG!10?C$#76!80?C!19?_!22?C$#78!159?_$#79!142?@!27?C$#80!23?A@E???E!29?OC!17?O??GC?Aw??HCO!6?G?O!8?o?GC?_?d?@@Oo??A@???W?Oo$#82!60?O!47?G!12?O$#83!23?@!34?WK_G_!16?G?s_G!6?_!5?_??_???@!10?AOGcO?DCH@!5?G$#86!111?_??_???_??_!11?_$#87!23?CA@NED!29?aAGO?_!13?___G?QupAlVORN^F@?_Wsg???@ABA???ATB]JSID??JAGC!4?O??G?O$#89!23?GCGO?A!29?C!21?o?G?G@Qge_!8?O??@A??L???taW`SH?_OMcG@A!4?_CO$#93!23?O$#96!172?O$#98!149?n!5?_!13?O?_$#99!144?@??FMO!8?E!10?Go?_$#101!199?_!5?@$#102!145?@B?@!20?CGO$#105!194?AC!10?A$#108!196?ACDRU_?EAO?WOo$#109!196?@GG??WAOOKg?G$#110!202?_!4?_$#111!201?@$#112!196?CAO???D_G??C$#113!194?@@?@AKhEWHdaS?_?_$#114!195?A$#116!21?@$#121!72?@!21?C!114?GO_$#122!191?A$#124!26?_!65?G!29?O$#126!27?O!54?@!16?G!35?_???OAG?_!50?C!13?@???A$#127!142?_$#129!97?@A???G???O$#134!195?G$#135!93?C!102?_!9?@$#137!162?A$#138!177?@$#139!61?@!4?`E!6?c?KACA@!20?G__!20?O_?@!4?@?AChG$#140!22?O!167?@$#142!29?_!31?ACC!13?G???@!13?C!4?A!5?_!22?@A??G??C!88?_$#144!65?m??O?OW?_!50?C!6?@??GG!4?@!40?O$#148!28?o!109?_!41?C??O$#149!72?G!65?G$#151!139?EO???OO$#153!57?@!4?G!146?A$#154!30?@!52?@!7?_!12?C???@!20?C$#156!29?O!36?G@_???OA!26?GO!5?E!15?OG@!4?@A???O?S!8?G!95?@$#157!162?G!15?AC$#158!185?O!5?C!29?A?A!10?A$#160!30?G!22?C!15?G$#161!35?~~~^n~~^~~~z@?~~NF$#162!181?C!12?G?O!13?GO_$#163!180?A!27?AC$#167!150?G@!6?@O$#168!147?G!10?G!12?G$#169!61?_!67?_$#170!73?G@!51?@!11?C$#172!27?_!116?A$#173!29?G!33?@C?CW??a?CO??@!30?x!17?A!8?C!10?C!46?A!31?O!11?A$#174!96?@!26?G!10?O$#175!99?@O??O??A!22?A?C!11?BC!68?_$#178!22?G!167?A$#179!57?_!7?O!66?AC???_O!45?_$#180!188?ES?Gg$#181!156?OO!8?_A!13?_$#182!221?C??A!8?A!7?@$#183!194?_!20?A$#185!181?@@EF?CG_A!4?O$#186!142?A!69?CS^{^!4~xxp`@?B?@?BA???@$#188!59?@!81?AG!69?@$#189!95?A!36?G$#190!148?O$#191!152?C!4?A!15?_$#194!31?@!37?C$#197!64?A$#199!28?G!50?C!14?GG!10?@!103?C$#200!141?@!14?A??@O?@ABB!5?CG$#201!94?_!27?_???O$#205!185?MZvWg{oO_$#206!68?CO$#207!30?o$#209!214?_!10?A$#210!30?A!29?AC!34?C!4?A!24?_CA$#213!143?C?GO_!5?@?O???C!9?A$#214!222?A!12?A$#215!64?G!5?C!30?_!31?A$#216!34?_$#217!47?O???_G!15?A$#218!144?__!22?A_!22?@$#219!27?G!30?@!46?O??E!18?G???G??_$#222!196?G$#223!145?A$#226!52?O$#227!31?_!24?[$#228!21?C$#229!34?K$#231!139?@!16?@C!33?@$#232!57?Q!39?AC???C!107?A@$#233!76?_!4?A!22?O$#235!117?G$#236!146?C$#237!24?_$#238!22?_!45?G!5?A!107?_!60?@$#239!223?G!13?A$#241!150?v}z}w??@?G$#242!23?_GO?@?@!29?_??O!16?O!4?CC???G!13?C!5?G!6?QA???A!6?_?_?_$#243!24?O_$#244!193?@$#246!21?A!26?N$#247!47?_o$#252!106?G!19?GA$#253!141?C!39?A!4?_!24?GO$#254!138?A!29?D-#0!32?@BAC!14?CCB!4~{$#1!58?A!64?__$#2!48?G$#4!34?C$#5!36?C!12?G??C$#7!32?C??AG??G!9?CG$#8!52?g$#9!48?o??G$#10!21?g$#12!32?G!8?_!15?@!13?C$#13!213?@$#16!36?_o$#17!39?_!28?_$#19!90?O!108?@??C!13?O$#20!27?A!30?_?_!80?C!43?@$#21!89?_G!110?C!13?CG$#22!198?@!18?O$#23!32?_$#24!164?I_$#25!22?A$#28!146?_!16?@?O!19?GC$#29!66?G!23?_!96?A!11?A!5?O!7?A$#30!144?C$#33!159?G??G$#36!68?A!6?@!47?@!16?G$#37!67?@!6?A!17?A!10?@?GA$#38!68?@??@@!32?O\?_$#41!158?Kswwt}?Gw_Wo!7?@BD@?oo?_O_$#42!58?G$#43!75?O!16?C!30?C!16?O$#44!152?O$#46!188?C$#47!159?A?CA!4?W!11?A??MKg$#48!192?CG?qN$#49!157?@R??B???!4FG!6?@???EM???EG$#50!204?G$#54!212?@$#55!121?G!108?_$#58!228?C$#59!108?G$#60!144?A$#61!150?C$#62!30?O!27?C!8?_$#63!157?C_@!9?C!8?C$#64!89?O$#65!108?C!12?A?O$#66!152?G$#68!23?A!84?A$#69!25?C!83?_!26?@??C$#71!144?@$#72!142?C$#73!141?@BK_BD{SgwO!18?_$#76!23?@!52?@!17?@!25?G`$#78!146?A!34?_$#79!176?A$#80!29?g!28?@??G??_!11?K?@`Q??G?b`@DA??O?oQOC@?U?O!9?M??SaHC!6?OAKG??GOG?@CaO$#86!59?CDTKNO!11?oawK?o`tQC]CwG@??gAgfQiQhA?O!6?sLo]~APc?_D!5?Gru|fAKt@iqG?o$#87!59?I?A`!14?D??cA??G??_!4?_?G??H?L?OG!6?KB!8?H!8?@AOP??O???c$#88!180?O$#89!79?AG!15?G!12?@!9?C$#95!24?H@??C!187?_$#97!29?O$#98!155?@A!14?GGGH??G$#99!170?BFFFEMK$#101!214?G$#102!170?C$#105!206?O$#109!204?A???E?A$#110!202?@??EBAHN?RI_$#111!203?ACHKCO_cKsWO_$#112!201?@?@@??X_OH_$#113!210?O$#114!214?_$#118!91?@!109?A$#121!90?C!34?A$#122!186?@?O!15?O_$#123!34?O!5?_!31?G$#124!28?A!35?A!43?@!11?O!4?G!74?@??C$#126!25?G@!38?_!36?A$#127!141?A$#128!145?O$#129!23?G?_!4?C!44?M!17?@!28?BA?@$#134!22?C$#135!92?@!125?_$#137!164?O$#138!164?_!20?O$#139!26?O!42?A@?A?D!29?EC_!34?_$#140!215?G$#141!91?C$#142!27?G_!36?C!37?CP!19?B!14?A$#144!23?_!41?@o!6?M!33?~!56?C!18?BC$#146!186?A$#147!36?O$#148!33?O!35?C!118?_$#149!30?@G!26?O!14?O!68?_!44?G!43?O$#151!143?OO???iS?_$#153!92?G!11?_!33?A$#154!28?G!31?O_!31?C!26?_?_???@!12?G$#156!27?C?@!35?A@???A!31?@?G_!32?@??O$#157!164?@!17?@?A?_O$#158!145?G!54?C!25?@$#160!33?G!5?O!10?A?O!16?GC?O$#161!31?C???PBBVFFN!5~??rpo!17?oww_$#162!187?C!12?A$#163!91?A!122?A??_$#165!151?C$#167!151?AE]}{!21?ooo_$#168!170?O!6?C$#169!30?_!31?Q_G??G!9?OAO?G]?`W?YA!4?OCD?_S_?G_!6?AGO@`?`KAzQA!4?_s???Gc`AMCGO$#170!28?@!174?O$#172!22?W$#173!22?_O!5?AA_!27?_!9?@??C?o!67?O$#174!24?_?_!38?G!9?_!15?O!30?C$#175!25?OCO!39?AG!55?G!12?@$#178!188?G_!12?G!11?C$#179!22?@!8?O!41?@!132?_$#180!190?TF@SrLo{}oo??_$#181!168?_!12?@??P$#182!214?@A!11?A$#183!197?A?KGwo!13?C$#185!189?O!7?@$#186!215?@BN^!7~}{wwO_$#187!149?A$#188!93?A!30?O!15?@!7?@??G$#189!68?C$#191!152?@???C!13?G$#193!207?_$#194!31?A?C$#196!35?_$#197!32?O?_!197?_$#198!123?G$#199!26?A??C!35?O!39?A!15?CG!17?_$#200!150?A??_???A??C!16?A??GO$#201!23?C$#205!187?@BNiwybK$#206!139?@$#207!38?_!34?_!66?A$#210!28?O!62?_!11?G?@!15?OO??C$#211!144?G!15?A$#213!143?_?c???@??_???@G!11?@!9?G$#214!143?@$#215!71?A??G!16?G!11?A!36?C$#217!34?GG?C??WO!6?C??@$#218!146?GB$#219!64?C??C!8?A!13?A!11?C!6?O$#220!38?G$#222!24?E$#223!215?O$#225!213?C$#226!37?G$#227!31?@A!24?A$#229!34?@!16?A$#231!142?GA!16?@!8?A$#232!27?_!36?@$#233!24?O!42?O!33?@$#235!63?O!37?c!15?O!20?G$#238!27?@!113?G$#239!33?_!34?O$#241!150?@@?@@Awo!13?!6o?G$#242!25?A!33?@I!16?GC?@D?AC!4?D!13?_!7?a???G!16?A?_O?C$#244!202?A$#246!21?O!25?{$#247!47?BB!154?G$#252!26?G???G!35?A!41?O!15?C$#253!59?O!6?C!137?_$#254!146?O!28?@-#0!50?EEF!4N$#1!28?A?O??_!22?_!8?C!12?G!8?C$#2!52?G$#4!54?O$#5!36?_!11?C!4?O$#7!38?_!12?@O$#8!36?O!9?C!10?A$#9!44?A???@$#10!21?@!25?C$#12!40?_?A!13?O$#13!192?_!16?O!10?CG$#16!36?G!4?B@???G??O$#17!39?@@_!15?G$#19!89?@!131?O$#20!24?{C!32?CO@C!7?G!4?O!67?@K!64?A$#21!190?C??_$#22!88?A!120?G$#23!33?@@bAECCKGWOoo_?_$#24!165?F_$#26!87?G$#28!149?O!15?G!22?@$#29!25?O!164?A!18?_!9?@G$#33!162?@!25?A$#35!66?C!142?C$#36!23?_!42?G!39?@!34?A$#37!65?_!43?g!31?C_$#38!23?O!42?_!6?G!67?@G_$#39!158?_$#41!159?@Bb}~~_F@!15?NA^FKwo$#42!206?A$#43!65?O!4?OO?_!35?A!102?_$#47!159?AKC!5?E!16?\$#48!194?QMg$#49!161?O!5?W!16?__g$#51!202?A?@$#52!237?_$#55!230?Q??IWw_$#60!143?@$#61!144?G?@!10?G$#63!168?@!13?@_$#65!59?G!5?@!11?O!10?_$#66!159?C_!7?AA!12?A$#68!26?A!38?A!22?@!129?A$#69!62?C$#71!148?A@$#73!144?AJuw??^}{k{GO_$#76!26?C!4?C!28?O_??A!13?O$#78!146?G$#80!26?OWwG_!31?A!5?O???_???@C?A`C?O_?HA?o?@A?k?_B???AA?D!5?@@xCCC`?AO@[_G?_GHD??_LO_C_@I!82?_$#82!76?G$#86!29?o!30?_??C@!4?_!6?UAEG]HM_WxE@??SE_MAPN[HF@@[W?__!4?EEo``]d_ngBKUuQa?IXkAoAKRWqDWO$#87!78?@??q_A?C!4?_O@??C!4?IO??GW!7?AO???H!6?@COO_@D?@A_DG_$#88!155?@???_$#89!71?_!30?_!14?GC!6?G@C??O$#94!208?@!4?_$#95!30?@!67?__$#98!158?K!9?!9o!4?_$#105!214?CW???G$#108!219?_$#109!210?@???_?G?C$#110!212?G!4?C$#111!209?@?AC^W`BOoO_$#112!210?ADA???CIG$#113!212?@?AC$#114!214?@A$#115!216?O$#116!21?A!185?A??_$#118!86?_$#121!22?_!52?C!143?C$#122!21?C!168?GO!14?@?C!10?A??_$#123!38?O!4?@C!7?_$#124!33?O_!24?_?O??_!21?O!53?_$#126!58?O!5?G!4?O!5?O!30?G??@!31?_!8?_!5?C$#127!149?_!41?_$#129!66?O$#134!21?_!66?GA!102?O!14?C$#137!154?@!11?O!23?_$#138!165?O!22?C$#139!22?CG!34?A@!13?O!35?S_!31?S$#140!21?O!25?O$#141!208?G$#142!22?G!44?C!73?G$#144!23?@AG!33?A!7?o!6?f!32?PW!35?O!44?C$#146!189?A$#148!33?C!5?O!8?O!141?O$#149!68?A!4?A$#151!144?@S??`E?@@A?O_$#153!31?_!29?G!43?A!34?A$#154!32?G!30?A!4?_!8?G!28?O!4?O!27?_G!70?GO$#155!209?AC$#156!22?@A@!9?O!24?C!6?A?C!4?C!32?ACA$#157!166?G!20?B?G$#158!194?_!16?O!13?_$#160!34?G!15?@???_!14?C??C$#161!35?G?O!5?A@D@??@O??_!15?BFFB$#162!47?G!141?@!28?@$#163!21?G!65?OC$#167!159?O!9?C!7?N^^N?W$#168!156?A$#169!26?GcC!33?@W!6?_!6?@_t??@LF!5?GgWpOg??A??K@DO!8?HAY?QO?C_R_GCOA?A?WAKP?A?OD$#170!23?C!81?@?_@!34?O$#172!30?G!29?A$#173!25?@???A??a!25?@?G@_???@A!4?G!34?IC!34?A$#174!28?@!59?O!121?O$#175!22?O??_!36?G!12?@!13?C@!50?O$#178!87?_$#179!25?A!5?O!15?_!7?_??_!15?G!33?_!35?_$#180!190?@@LLHpV~~]Co???O$#181!161?G!7?@$#182!148?C!51?G???G???O!12?C$#183!199?`rN\mqmso_$#186!220?@BFN^^!4~l~~sc?O$#187!155?A$#188!64?C!10?_!71?@!9?O$#189!31?@!25?O$#191!157?E!10?!4G!9?@$#194!35?O$#196!33?A?C?H??A?c??G!4?_$#197!38?GAO???G!162?@!15?O!10?AC$#199!29?C?G?G!23?_!9?@!4?O??A?_!132?G$#200!160?O!6?_!15?O??OO$#201!26?@??@!45?G!34?G!29?@$#205!191?EAQC$#206!70?G$#207!34?C???@!4?C!7?_!5?C!10?@??G?@$#209!202?_PC?GG$#210!30?A!29?C!4?G??G!20?G!21?_$#211!145?_$#213!144?C???O!4?@ACG?@G!8?C?@!11?C!4?_$#214!62?O!43?C!40?A!74?G$#215!22?A!7?C!36?G!74?A$#216!48?AG$#217!39?_!5?AA?G??O$#218!152?AO?_$#219!76?_!33?A!12?@@$#220!49?A?G$#223!217?_$#226!49?C!5?O$#227!57?@$#228!20?_$#229!37?_!12?G$#231!147?C!10?O!52?_$#232!32?O!31?O!25?A$#233!32?C!77?C$#235!63?@!41?C$#237!100?__$#238!34?A?D!4?C?_!5?_!183?@$#239!32?@!5?AG?O?G??O$#241!156?@@A!12?F!5No__o]_$#242!26?_A???A!31?_!18?O??A!6?C?@AO?SGS??aa!6?G??G!5?Q!6?__CA??_?G?C?A$#243!27?@!69?_?O$#244!216?_???O$#246!47?B$#249!217?@$#252!58?G??A!48?O$#253!148?G!42?G!13?@!14?A$#254!140?C!8?G!20?E-#0!39?A?CC$#1!21?O!17?G?_??O???W!6?@!7?G!9?C???C!30?G???A!17?A???@G!5?O!55?G$#2!40?A$#3!43?G$#5!38?A@!4?C$#7!43?A$#8!41?@!4?C$#10!20?W!191?G!40?A$#12!45?A$#13!225?O!30?_$#17!46?A$#19!198?G$#20!24?E!12?O!70?A!57?G$#21!85?C!110?A!4?O$#22!47?_!36?O$#23!47?@@@B!190?G$#24!166?V$#28!162?_!28?_$#29!40?G!21?E!22?O!109?@C!17?_!25?C$#30!150?@A!7?A$#33!162?WG@!24?_$#35!54?G$#36!23?C_!50?GC!34?O_!29?@BAO$#37!110?G!38?_$#38!23?A!42?@!43?Ak!25?C???GG$#39!160?CO!4?_$#41!161?CFv}X!18?CKK??^$#42!21?@!178?G_$#43!66?C!18?_!47?C$#44!159?@$#47!161?@???a!18?g_o$#48!196?@$#49!165?C!18?AA@?@$#50!224?G$#51!202?@C$#52!209?KO_$#55!191?G!37?@??@qO?wr[{wo$#59!67?_$#62!23?O!8?@!4?G!12?_!87?G$#63!183?j???_A$#64!84?G$#65!22?@_!41?G!43?_???O!15?C!6?@G$#66!167?A!10?_?O??O???[k$#67!190?C$#68!63?O!22?O$#69!55?_!17?A!116?O$#71!212?@$#73!146?@FDM?G@CJnjnEw_!31?U_!20?G$#76!25?C!9?@!17?A!9?C?_??C!44?G_!13?C!4?@!11?_$#79!195?_$#80!22?G???E?_G??S_?O_?G!12?_???O!5?@?B!8?C!5?EC??I?C!4?_???o@O!6?O???@!7?I@OD?H?G??CN?k?PO??G?Oo?Oo!80?O??C$#82!64?@$#86!26?waPCQ~_W_!7?_?_?O!22?AADB!5?@OY|DGB??OC?U[sCY??_!4?_wC`Ww_!4?@CWLyoquaK{b?XB_I_???o_!4?_?__$#87!22?o!5?K?C?A??_!34?C!7?W@?AOC???_QO`AG!11?PQCA!7?c_?A?G??A???O!9?O!6?_$#89!28?A_!10?O??_!26?G??_!5?__?_!5?_@?_???_o???_o??_!8?A!6?@?_??__??_G_?_!4?_$#92!69?G!8?_!16?C$#95!55?GC_ccC???W???___!25?GOO?H@!115?O!4?_$#97!56?GGWWWo??_!31?A@@HC!116?@?A$#98!168?CKLLHLH@X!4?Z$#99!175?G$#101!97?C$#108!222?Q$#109!195?O??_!16?@?K_@AKG$#110!195?G?_!18?C?OO_?C_$#111!194?C?OO?_!16?B?C?@@?W_$#112!194?G?G!22?_$#113!217?AG??A$#115!97?IE!121?C???O$#116!20?_!203?C$#118!85?A$#121!36?O!28?C!133?O!20?G?@??_$#122!47?C!146?@??C??O?_!10?o$#123!41?G?@$#124!22?C??G!24?G!22?G!13?C$#126!52?A!9?O!10?@!13?A!59?_!43?O_$#127!151?CC$#128!147?G$#129!65?@!9?cG!10?@!24?G_$#134!37?A!160?C$#135!47?O$#137!161?G$#138!190?@$#139!23?@!28?G!56?@CAO!20?A?CC???@AAG??OO$#140!47?A!38?A!170?_$#141!85?G!117?_!19?A$#142!66?A!8?O!34?@!23?C!4?@G@$#144!34?AC??_!15?_!19?M!34?C_!30?CCC?A$#145!74?O$#148!44?@?G?C$#151!148?A@K?ABSO?OW?O!31?G!22?o$#153!43?O!6?C??OA!21?_A!64?O!76?C?O$#154!21?_!14?A!4?O!16?@!9?J!16?@??@!45?G!83?A$#156!24?O!14?_!9?C?O??O??@!9?H!41?A!24?AAA??E!5?CC?O$#158!152?GO!43?A!6?_!21?@A$#160!45?G$#161!42?@$#162!195?A!16?C$#163!47?G!36?_?@!112?G!10?@$#167!177?e^~C?k!4?@$#168!167?G!25?E$#169!26?@T?AH?GCW!34?C@A?O???O?ID??R???GGKG@@JCH!7?EICA?O???@CO???L??TR?GOC?Z?@XGO$#170!53?G!90?@!5?_$#172!109?O$#173!25?_!24?OA!10?@!4?E!6?`!62?AA?C???CG???O?_!58?A?_$#174!23?G!32?A!10?O!64?C$#175!34?CG??O!17?@!5?G??AW!8?AA!31?C!22?CA!6?G!4?O???_!68?_$#179!24?H!11?G!11?__???@!139?@$#180!197?@BEDBG?O$#181!161?A!22?PPA$#182!152?_!38?C!20?A???O!11?C!9?@???_$#183!199?@AKEZN~~~bB$#185!150?O$#186!227?@BM^~}Ln~FKa$#188!49?O!103?__!35?AA!23?G$#189!21?C!20?O!11?@!7?_!68?A!5?@!83?_$#190!194?O$#191!168?G???C???A@???C$#193!196?_$#194!40?@?G$#195!255?C$#197!45?@??A???@!55?@!102?H$#199!21?A???P!7?A!6?_!10?G??CE!20?O!9?G!24?@!18?C!7?@!76?C$#200!167?@!12?_??C$#201!35?AC!16?C!12?_!8?@?@!34?C!30?O$#207!255??O$#209!208?[ok$#210!34?@!28?_!12?@!58?@!54?_???A!21?G$#211!146?A!13?G$#213!150?A@OG!5?C@!6?C!13?_!5?A??G!22?E??_$#214!145?@!65?O!18?_$#215!33?@!52?C!23?O!27?C?A???G!68?G$#217!39?C!4?A!211?G$#218!156?S?_!34?O_$#219!37?C!7?o!31?G!8?_!18?G!34?O$#220!40?C$#222!56?OS??_G!38?A!117?@$#223!96?C?GE!95?C!4?_!13?@$#225!198?O$#226!37?@@??A?C$#228!20?@!204?G!25?@A?A?C$#229!42?A?GC$#231!148?G$#232!21?GA!30?_!53?@!28?G!9?_$#233!25?A!11?_?O!6?_!5?S!12?O!17?_$#235!89?A$#236!193?G$#237!49?G!6?_?AA?C!6?OOO__!23?@??O?M$#238!109?G!36?G!82?O$#239!36?@!9?@??A?@$#241!167?orr!4quucW??J?R$#242!27?G?P_!20?C!12?A!4?@?GW!4?_!14?A?_A??__??G@??_C!6?@AA??C???@O?A!5?p!4?_???_$#243!52?_!4?A?@BA??C!6?O!28?O?F$#244!215?A???G$#246!20?E!190?A!11?@??_!23?@???CG?O$#252!38?C$#253!202?O!10?@A!24?A$#254!151?O!6?@?A_!26?O??@@!21?S-#1!44?CC!7?@!19?C!44?_!92?O!45?A$#10!255?O$#12!216?_$#13!214?O$#16!70?O$#19!20?A!26?A!162?G???A$#20!25?_??_!11?@!13?B_!10?_!136?_$#21!83?A!123?A$#22!205?@!6?G!15?_$#23!255?!17?C$#24!162?@$#25!233?O$#26!82?G@$#28!164?CC!23?A???@?A$#29!26?W!12?@!6?_!15?G!19?O!127?C???C$#30!154?G!35?o!8?G$#35!111?@c!40?G$#36!24?@!38?_!49?Ag!38?o$#37!111?_??U?_!4?o$#38!27?_!85?K?oO$#41!165?@!19?BB$#42!20?_!7?O!42?G!135?C!67?C$#43!63?C!51?C!5?G$#47!163?@B!16?A??BCC$#49!181?{_?{ww$#50!82?_!142?_?G$#52!209?AB?EC!30?C$#55!75?A!79?A!38?A!38?AYCp^^!4~}wO$#59!42?@!202?_!28?C?Go$#60!154?@$#62!56?O!5?@!4?_!97?G$#63!157?O!22?B?Gb???K$#64!48?C!33?C$#65!54?_@!94?@???C$#66!165?_!12?r???C[???oF$#68!84?G!138?A$#69!23?A!40?O!7?_!145?@$#71!191?A?A!7?_!16?_$#72!155?OO!4?_$#73!155?GbEUmVTw!17?_!10?wmOOpgOO!17?EMGo_$#76!53?A!15?C!40?C!5?C???@@$#79!166?A$#80!22?CG!6?CA_?O@O?CO??G??G!4?JG`!4?OoC!4?C!8?@!8?A!9?DA?@A@???@O?@AGGda!6?@G?_??G@ILAcCF_A??BHAh???EoU_IC_CE?A!52?A!19?_$#82!53?_???_!65?O???O!14?G?G$#83!21?O!8?G_?G??_g??G??GW!7?O!5?GG!39?G!6?o!16?G??O?W???G??O!4?o!4?O???g$#86!21?mq!5?CC?\GCKoKPwEcwO_!5?u?eM[!32?@@?BB!4?C?C?@KCKI[\DAW[!6?A?PH??@eDO_I??TxaWke?OJPMXEgRCW[WO{C$#87!29?@B?A@???A!12?C!40?C!6?B!7?AD!23?C?F???C?C???@?@??@?A$#88!179?B$#89!22?H_???BAYO?Pa_IBC?_O?_O!6?oP!5?K?OG!4?C!14?@@@???A?E?CBACNIKASE@Y?Da_?OA!6?@?FEU??C??AL@bwG?D_??|Aog?_@?C?BBa??W$#93!76?_!10?GG??O???__$#94!202?@???C!18?O?O$#95!60?@@??A???C?@@H???UUSck!4?OOOoo___$#96!219?C?_$#97!64?@!6?A!151?G$#98!166?_@@!5?AAAs$#99!166?GMMmuA]]cKK$#101!213?_!12?C$#102!166?S??OG{__Woo!20?@!7?O$#104!199?A???G!15?A$#105!201?C!19?@!34?_$#109!206?G???O!9?AO?@A$#110!201?AA?GGO?o???_!7?C?W??C$#111!200?B?!4C?G!12?@E_?@I$#112!198?@@?@?A!5?__!8?@??C???o$#114!207?O?O?_!9?G?o??G_$#115!208?G!48?G$#116!206?A!21?O!27?A$#118!48?o$#121!24?_!23?G!32?_!127?G!13?C??A$#122!204?@???C??G?O@G$#123!68?O$#124!23?C!25?@!14?GG!10?@!8?A!63?@!39?_!32?A$#126!63?@!56?cC!80?O$#129!24?G!20?@!9?A!18?a!9?A$#134!20?O!27?@!35?@!118?@?A!6?O!43?G$#135!83?C$#137!163?A?A!23?C$#139!24?E!87?A@?G$#140!20?C$#142!63?W!48?@!4?_!160?_$#144!25?@CG!26?C!5?_?o!47?@AW_!40?o!46?O$#145!25?A$#147!69?O$#148!46?A{!23?O$#149!42?A!26?G!174?A$#151!157?@GPgI?W!28?OKgGO_??_!16?OC$#153!29?_!18?A!7?G!10?I??C!4?C!41?O!34?G!61?_$#154!28?G!9?@???C??o!10?A!16?A!7?O!27?@!42?_$#155!255???_$#156!26?AO!18?X!8?C!5?_!12?@!38?O!38?@!92?G$#157!189?@$#158!198?G?O!5?@!69?O$#160!68?_$#161!69?___$#162!20?@!206?C$#163!47?@!161?C!5?S!10?@!28?_C$#167!177?B?{??@$#169!58?C!40?O??_$#170!46?C!185?C!40?C$#171!197?C$#172!41?A!148?G!25?O$#173!55?G!10?G!44?C!41?E$#174!56?_!17?O@!75?@!63?A$#175!24?O!19?@!14?_??A!10?_K!8?G!68?A!37?C$#178!215?_$#179!20?G!4?[!29?O!10?O$#182!164?W!66?@$#183!207?@$#185!196?C!7?_$#186!232?BLdzM__$#188!85?@!70?K!9?@!25?@!23?G_$#189!40?A!19?O!4?_?@G!4?O!9?_$#190!198?A???G$#191!167?Oo?@!6?G$#193!207?_!12?G$#197!70?G!201?A$#198!189?GA$#199!43?@!10?O!8?A??A!16?OC!25?_O!4?G!5?_!99?@?W!32?@$#200!164?_!16?@O!4?B$#201!66?@!43?A???@!5?W!31?C!37?@$#207!45?A$#209!153?@!54?@@?F@AG$#210!23?@??@C!37?O?C!5?G!37?G!8?A!68?O!66?O$#211!155?_!6?A!33?A?C!18?@$#213!154?A??_!9?_!12?W?A!5?G??@???C?G?O!5?_!9?@$#214!243?@$#215!26?_!14?@!12?G$#218!158?@???C!28?C?_C?@A_c?G?O!12?@?OG$#219!110?O!27?C$#222!68?BBA?E???GGGWOG??!4_!169?C$#223!200?C!56?O$#228!19?o!207?AG!29?v$#231!163?C!30?@!5?G!17?A$#232!61?G??_??O!7?w!39?A!6?O$#233!56?C!64?A!30?O$#236!58?@!145?O?_!13?O$#237!57?@?@?A!9?C!5?_aAAC???GG???O??__$#238!43?AA!16?O$#241!169?@?!6@$#242!21?@?O!4?@?_?COBC??AG?C??_!4?G!7?A??CC???@!6?O!14?A@C??G@??PWG?Q?Bo???_??G!7?G???A?o_!4?A?O?O!4?A@!4?__!4?_$#243!56?@?AAA!4?A!11?@@@?A??OCCC?GGGOWOO?!5_$#244!224?C@$#246!255????G$#247!255??@$#252!66?C!141?A!4?@$#253!62?C!139?_!10?G!32?_!28?G$#254!43?C!111?D?G_!4?_?O!12?K?C!7?o-#1!24?C!4?O!20?_!17?O???G??A!4?A!11?O!9?G$#10!19?W!198?O???___A!30?_$#11!249?E$#12!211?C?G!11?@$#13!227?_!16?G???_?O$#19!215?GO!12?!5_?G$#20!25?n!6?G!14?_!7?E!6?^!144?A$#21!48?K!31?O!159?_!4?O$#22!242?O???O$#23!255???A$#25!66?@!168?C$#26!48?@!196?C_$#29!26?_!127?@!54?C!16?C!14?O_!9?G?A!24?C$#35!26?]!4?G!19?_!15?C$#36!30?G!23?_??GOC???GO!9?A!37?@?_G?AA??@$#37!27?CA!26?O?Sg!95?G$#38!27?AH!4?_!24?EqMo?O_!9?G!40?@@@!36?C$#41!162?_?A!17?MK$#42!66?A!165?G$#43!107?CKGGGOO?o_$#47!163?wC!17?po??G$#49!166?o???_!7?C??r?AvzB$#50!215?O???_!6?A!20?O$#52!241?C$#53!170?O$#54!20?@!46?@!155?A!16?O!8?_$#55!236?ABBD!4BbBB!30?E$#58!255?!24?o$#59!255?!22?xm$#60!160?_!59?@$#61!161?O!116?P$#62!46?O!17?C!7?@!22?O!57?A!63?G!21?O$#63!162?GC@??G??C_!6?P!4?@$#65!46?_!17?A!7?C!30?_!52?_!54?G!45?@$#66!164?_?GP!19?@$#67!210?A$#68!79?_!138?_!11?G!21?_??@$#69!30?@!40?O!10?O!18?_!21?@C!28?G!60?O???G$#71!156?C!48?A$#72!157?A!8?C!30?C$#73!156?B|g~KE!8?A!6?G??@!10?xeRDJDADFEDFEACC$#76!54?A!64?@$#78!180?C$#79!165?C???_!33?GG!9?C!13?OOO$#80!23?H!8?@C??QAAG@???Ac???@?K?A!15?_!7?CKS??_!8?O?__?__!10?@!15?@?@o@?OGF?Q`??A?`GCO@O?_xAOGa!71?C!30?g$#82!45?G!42?_!40?A_!5?A???O!5?K!5?O$#83!21?GGA!14?@??ICX!6?H@!27?G!6?_!39?OE???A?@???V?C?a??A!6?@$#86!21?FBC!7?@?BCECCCDC?B?D!4?CA?F@C!21?C!47?ACA?E?FD?A@E@?C?CD@@??BFA@BEC$#87!21?o_OO!5?_!4?GGOW?WoO?w!4?O??G!14?_??__!4?ooO!5?oO?oO__!34?G?GwwGOwo_GOgOo??g?O?OO?G_O?_$#89!22?C_!5?_!4?J?@H?qADge?O???GSA?C!14?_!7?AIa!4?_G_?G??O!4?_!29?Bk@?D?_?CGOK?HHIOAmkf_G?s??H$#92!84?C!12?G!9?@$#93!79?@@???AA!4?C!5?G???@@@A$#94!96?CC!131?G$#95!84?!7@!6BAE?CCC$#96!165?O???O!26?GG$#98!165?G@?aB@FF@nCa$#99!168?KK?GoAOZ\!19?O!18?C!5?G$#102!168?O???G!40?O!8?H$#104!207?OO$#105!209?O!13?CG???G$#108!197?O!7?OO???O$#109!201?_!10?_!12?G$#110!199?o_O!5_?_?@_O`_B?C!8?GB!26?_?@$#111!203?O!6?_!43?G$#112!204?O!7?@!4?A??C!6?G!28?A$#113!202?O!6?_$#114!198?O?O!6?_???P?AB_a?EC?CC@!28?O??E$#115!250?_!4?O$#116!19?_!205?_???A!9?!4G???GGC$#118!80?C$#121!20?A!15?_!184?A!9?G!24?G$#122!221?_!4?_!9?_gg!4?G!4?GO$#123!71?C$#124!20?_???_!6?A!17?_!25?C!23?GgG!118?A!32?_O$#126!104?G!101?A!6?C???@$#127!223?O$#128!190?W$#129!81?g!17?OO?OOO?___aAECCG??GWooc$#134!81?C!130?G!20?G!22?O$#135!81?@$#139!27?H?K??O!20?_?_g_?Gp??_!10?C!6?O!39?AA!31?A$#140!234?G$#141!80?_A!138?_$#142!28?C!17?@!9?O!6?F???G!6?p!30?O!4?@@AAC?ECCKGW|{o!29?O!63?@$#144!29?@?C??_!17?_!4?A!7?_??G!4?[!81?A$#145!206?@$#146!229?C$#148!228?_$#149!247?@$#151!158?E?A@@!29?XcQcA@??@A??C?GC?G$#153!52?O!4?@!9?O!85?C!97?O$#154!24?G!12?_!15?G!21?w!7?A!7?_!6?G_!5?C!47?O$#155!188?o~$#156!27?o!26?O?C??@?F???G!42?OO???@??G!38?w!34?C!18?A$#158!190?`!31?O!56?G$#160!68?B??B!142?G$#161!69?NN$#162!219?O!15?_G!7?OG$#163!48?o!185?_!4?_???O???c$#167!179?E$#168!175?_???@!7?_!9?_GGG$#169!76?@!11?G!16?@$#170!73?@!145?@$#172!65?O!7?_!138?C!21?@$#173!30?A!4?_!19?GA!16?A!37?___BC!39?C!60?G!4?O$#174!32?_!31?G?OA!29?O!7?GGG!10?@!34?@!68?A!4?C!8?C!11?O$#175!46?C!9?@!9?K???O!11?@!13?O!8?_??A!10?A!34?_!82?C!5?c$#178!48?A!31?G!160?_!4?C!6?C$#179!25?O!7?O!19?O!4?@$#181!164?G!16?K??GCS$#182!162?C!41?@!33?C?C?C??_?A$#185!163?@$#186!235?B@??A$#188!82?G!78?G!45?@$#189!20?C???@!8?G!60?O!129?AC??@$#191!166?A?@!8?A$#193!209?@$#197!47?B!172?O$#198!190?A$#199!28?O??O??O!11?G!18?@!6?A!9?C!37?C??AG_!102?C$#200!162?OAO??E??G!6?_i!7?_$#201!28?_!75?_?C??@$#206!210?C$#207!208?A$#210!20?G???A!5?O?C!31?@!7?_!20?O!13?A!12?@!135?C$#211!156?O!5?A!45?C!15?O$#213!158?@?O_???A!7?K!6?i!6?[M??C!11?@!21?O!10?O$#215!26?@??AC!23?G!6?G???C!5?G!34?OO??o!4?AOo_$#216!255???C$#217!68?C$#218!158?O?@!19?O!10?A?GgO_?A!6?G?GG?G!15?OO???!5O$#219!31?_???O!9?@!46?_!5?_$#222!224?@?@$#223!211?A!5?_??G!7?A$#225!198?_!13?A???C??A???G!29?GC$#228!229?@?C!20?CA???G@$#231!165?@!7?_!64?O$#232!54?@!11?_!5?O!10?@!18?_G$#233!20?O!54?@!44?A!4?O$#235!38?_!6?A!96?O!7?C$#236!201?GG!5?@!7?@??G$#237!86?!5A!5C?@@FAAACC$#238!47?[!7?@!6?_!142?@!73?A$#239!255?!21?_$#241!177?D?w$#242!22?O!9?A??@!4?_!8?A?O!24?G??A???[?KW??W?G!14?@!26?GC?_?_A!5?G??C?G_$#243!77?@@!7?!4CG?!4G!7?@BAA$#244!253?O$#246!19?F!210?C!20?G??@$#247!217?O$#249!251?_$#252!46?A!18?A???O!12?A!15?O??O!7?CCOGGO!129?C$#253!155?@$#254!156?G!8?_?_???O?O???O!9?A@!32?@!15?O-#1!34?O!9?_!84?O!121?@$#9!246?@$#10!245?@$#11!231?@??@$#12!201?_$#13!243?@$#19!19?O!59?G!173?g$#20!25?B!13?A!7?B!72?CC?GO!31?O!5?_!7?_??_!25?O$#21!237?!5@$#22!76?O??C$#23!49?A$#24!157?G!5?O!9?O$#25!73?G!195?G$#26!79?A$#28!156?_??A!5?O?__$#29!48?G@!150?_!53?A??O$#33!161?_A_!14?G$#35!25?_!48?_!49?G$#36!23?_??o_!5?@?CQAO??G?OOG!4?CGKO?Oa??ccc??K!9?O!19?CC!6?EA?AA?E???C@?C??C_?a??C?O_!27?K$#37!27?O!12?O?GGG!6?a?_I?OGOAOB?M!10?@!25?CC?CA!7?G!5?OG!7?O_$#38!27?E!6?BAc?COG?O???GG??O?_GPbLDl@IG?@R!31?!4C?A!4?C??CKG?G?O[CG?G?O?_K$#41!157?Ow{cUL@[CA??OC?W??wGwo?OOwW$#42!253?C$#43!23?O!50?A!5?G$#47!160?OG???I???_??_K_??CE??gFE$#49!157?_??A??I?@DO??J!5?CB???F??NB$#50!224?@!15?A!10?O$#51!159?@!35?A$#54!236?!4A?AA$#59!255??!10_??O?G??ogk}{L$#60!255?!19?O???A$#61!255?!17?_??O?B$#62!33?C!12?O!33?O@!23?G!50?@!40?G$#63!163?C!9?@$#64!76?_$#65!23?G!4?C???@??_!4?__!30?F!16?O!13?G!140?A$#66!164?A?g?E!5?G!4?WC!5?@$#68!70?_!7?O!23?@!128?A!13?A$#69!94?A?G!4?@!8?O!15?@$#71!167?@!7?@!23?_$#73!157?@@!12?G!19?FGYxopb?E?KWO?o_$#76!20?@!11?A!76?O$#78!171?C$#79!200?A?C?G$#80!20?CO?@!5?BS!11?@???_!19?CCA?CI!4?B?E!7?_R??_C?AOOO?@???__???_o?_???_!18?COM?PI??_??G`OU??GC_O!98?O$#82!29?C???O!48?O??_??G?CO!37?A!7?G!11?_??A$#83!20?OA!9?KG!7?@???@!23?O?P!6?G!5?_?GE?BC?a???_!9?O???_?__!17?G_@!4?C??CS?d??A@C?SA@$#87!20?_gJ!6?_JqS_!9?@?@!22?L{?D!5?F???gB]LVXC?J@@q@`?@`OO__OO?_O!20?@CGRVeyK_Rao{A@}?`QhgZPA_Wc$#89!21?DCA!5?G_@??_!10?_!21?Z_AI!7?@??Ok@Q??G!4?@o??_O__OO??o?_O!5?_!14?BDCG?@bPG???xI@ASGC?_A`WCJ$#95!229?A!20?O$#97!247?A$#98!172?@?B$#99!201?A???G$#101!251?G$#102!210?_$#105!208?O!12?@!26?A!4?A$#108!201?@!9?G!4?O??O!7?G!24?C$#109!200?@!10?@C??CI?@?`??S???A!4?G!7?_O$#110!204?C?GGF?WOomAhcKA_ME{gcMKCWC[GOCG[_KKGCgwcCCCO_??A$#111!202?A?AAC???A!6?pG???A???A!4?O??C_!9?O!6?@$#112!202?@?@?BC???AA@S!4?GO???G?O??_???O??K??SG???O???O?AC?@$#113!203?@!5?O!8?C@!5?O!23?E$#114!203?A?D?BGNDcHOhQ@AoE?w?AQ__ocW_ccgo?Ooo_OCCWggwkKWK?A$#115!203?C!24?A$#116!189?O!38?@@@$#117!232?@@?@$#118!71?O???KG_$#121!71?_!6?_@!46?A!107?A!8?A!5?@`$#122!19?A!171?_!52?@$#124!39?@!26?O!10?O???C!18?@!14?_!11?CG!56?G!44?A$#126!28?@!61?O!21?O!45?A$#127!190?@!6?C$#128!189?C$#129!35?O?_!70?G?@?@!7?@@!6?O_$#133!254?__$#134!48?C!31?@!107?_?_$#135!189?_!35?@$#137!158?C!17?_???_$#138!168?O!7?O$#139!26?GH!7?HG[GGCO???C?Co?AORFcK?q?W@O?O_!15?C!19?A???CC?C?G?C??G??X?POO__??G!28?O$#140!19?_!53?C!5?O!146?@!28?@$#141!49?C!24?C$#142!24?C!8?AC!4?C!6?C???GC!6?A!15?G!24?A!7?A?AABAEEI!4?_?BFBBC!69?C!5?_!63?O$#144!25?O@!9?@???A!24?_!49?@?AA!6?_!29?_!9?_!23?G$#146!48?A$#148!190?O!56?@$#149!25?K$#151!190?CGVDCH?OE?G??G???_$#153!24?@???G!17?@!25?_!7?_!13?GA!6?G???@!47?A!68?@!8?A$#154!23?C!9?G!32?@!8?B??G!20?@!146?A$#155!184?_oo}N$#156!24?G?C!14?C?C!7?@!69?GC??O!29?BC!108?O$#157!162?O?_$#158!156?A$#162!19?C!207?@!25?O$#163!19?G!28?@w!186?@!5?@$#167!179?A$#168!172?A$#169!222?@$#170!45?A!220?_$#172!50?@!22?O!5?_!112?_$#173!24?O!13?A???C!30?B!40?@?@??E???O??_!29?G!41?G!59?!7O!14?A$#174!41?A!5?O!45?C!15?@!142?G$#175!34?G!8?A!45?_??G!14?G!19?G!126?O!23?O$#178!72?G$#179!24?_?A!19?A!18?^$#181!160?G!8?G!4?O???@!4?@$#182!255?O!20?@$#186!255?!12?O$#188!93?G!94?O??O$#189!28?A!75?G??@!125?A!18?_$#190!186?K@$#197!255?!12?_!4?O$#198!189?A$#199!24?A!17?A?AO!26?O!15?_??G!5?A!8?G?@!4?O!121?A$#200!161?@!5?GGCO_CA?CA??_G??_?C$#201!96?A!20?_!36?`$#210!28?o!52?A!19?G?@!7?O!4?_!37?[!94?_$#213!164?@??A@@?A??C?@??C@!5?A???I!4?CA!4?O?_$#214!255?!16?_$#215!44?C!5?_!12?_!16?A!35?A?@?A!79?O$#218!157?A!38?G?`?C???o?O?_$#219!20?A?O!43?G!9?C!11?O$#223!199?@!7?O$#224!254?@$#228!254?CA$#231!157?C??@!8?A?@!12?O$#232!22?_!19?_!4?_!18?_!23?G?C??G???GG???@@!83?@$#233!38?__???_!31?o!21?GG!31?_$#235!66?A!17?_!51?c?CA$#236!209?_$#238!37?@!24?~!10?_!48?G!155?_$#239!255?!20?A$#241!179?@$#242!20?G!8?O??_!8?@!25?_?@!18?C?A!4?@!31?A!4?W!5?@@???WAC???K?@$#244!251?_$#247!19?@$#252!98?A!15?O???_!129?@$#253!38?@!217?O!12?O!9?@$#254!87?_!78?OC???O???A!4?A!12?_A???OG-#1!38?_!8?B!24?A!79?_!96?@$#9!70?_$#11!204?A$#13!188?@!6?A$#19!49?@O!27?G!108?G!6?A!13?CG$#20!60?_G@!65?AC??O!22?@??O?G@!11?@$#21!78?C!123?_!6?O!5?_$#22!50?A!16?_!124?@!58?G$#23!19?@!186?G!43?G$#24!153?oC??_GC?a??@??w!8?~$#25!19?A!30?_!210?@!7?@$#26!68?G!9?@$#28!164?O?S??o$#29!19?G!29?C!11?A!4?_??_!9?@!115?C?G?O!4?@!39?_!11?A!19?C$#33!154?O!24?@$#35!186?G$#36!48?_O??Q_C[K?P@!4?A!59?A@???@ACC!25?_$#37!25?@_!22?G?D??G_???GC??OCG!59?A???G$#38!25?Q\J!20?H_?AcZaAREMS@?wEwC!56?@!4?C!5?GO??__$#39!162?O???_???C$#41!154?_{w?EB?WA@?cB?@???`?EC?N@$#42!201?_!7?_!43?@$#43!37?A!48?C@@!47?O$#46!189?@$#47!156?CG@?`!4?O??a??N???Y??A??@$#48!194?{gO$#49!157?A!7?G!15?A$#50!70?@!6?O!171?O??C$#51!164?C$#52!255?!22?@$#53!178?O$#54!19?_!167?A$#55!179?C!71?o_C?A??@$#59!252?Wo{|{|!10{Sq^~jfnEA$#60!164?A!47?G!56?C??O???@$#61!170?O!8?O!88?iG_?CWO@$#62!38?O!8?O!93?_!65?O$#64!68?O!8?G$#65!21?G!105?G!25?C!27?O?O!17?@$#66!179?G$#68!69?G!173?G$#69!36?A?C!32?O!8?@!48?O??_!5?O!14?A!48?A$#72!208?A$#73!186?_!9?@@@ACE?K??p_?ABCEEK?GWWWG?O?O_??_$#76!126?G!12?O$#78!163?O!36?@???G$#79!214?A!6?G$#80!29?_?AAg@@C??CoI@???`!20?G??CGO???A???C_aOG!7?OG???@???A@OCCTKBC@D_??`?_G?OGCO?G??O??_?BA!4?G!4?OGwP???QT$#82!32?O!50?@!6?I??CG!16?G!8?G!27?C?G$#83!20?h!8?C?gGCO_!5?@?o@SE!21?B!11?G?S_!6?@?G?@PAA?GB??@P_A_O???O??CIOAE!4?G_??_!5?@?CCC@?GF??@?C@iCG$#87!20?Q@!7?Q{T_AKS?OAHKCcCSjG!20?D_???G!7?oEGGC@???wO@ebA?SCxQG\UciPgQkrIANWtWSCowEoGgoOO??__?@??C?IJ?JUO?aUF??DO@G$#89!20?C!8?@B??@aAw?@ABoAJg!22?A??GE!9?X@CB!4?CcK@OckhwA`s_GI?G?@?Gs??DIA`JC?_Co???__!7?BA@?CO@GFD_?Io?@cA$#92!247?@$#94!241?O???A$#95!235?_!8?O!5?C$#96!227?O$#97!237?O??G$#99!216?A!11?O!4?_$#101!246?C$#102!213?@!20?_$#103!251?@$#105!229?O$#108!217?@!10?G??C$#109!217?AA!14?O?G!10?_$#110!214?@@???@?@CC@I@DAF?XOE?V?FJCFA??AG!4?@$#111!224?C??I??O??G??C??A!8?O$#112!216?@??A??A?ACG?@?G?@!9?C@??@CCCA$#113!218?@?A??A??C!4?AC!8?@!5?W$#114!220?@E@@?@A?CGF?I@^?ZGCH?CRA@@W_GA$#116!78?O!126?A$#117!206?C$#118!77?C?O$#121!21?O@!44?O?A!63?_!105?o!11?A$#122!193?@!9?`?C?C??g??O??_$#123!71?_$#124!24?w!14?O!28?C!4?_!10?_!36?A!12?C!8?_!40?_!58?C?_$#126!39?_!39?G!42?A!7?O?A$#129!22?A?A!98?A!6?@O??G!19?@!33?C!21?O!42?A$#133!253?G@?@$#134!19?C!30?@O!136?O!48?__$#135!69?C!7?B?_!131?O??_$#137!160?A?GA_@G??MA??Co??_GAE$#138!161?CC!14?O!4?@$#139!25?gAs!20?U??G@CP@_x_AA`?h@!10?_!47?@@?A?@??A???O$#140!77?_$#141!51?_!136?A!22?_$#142!25?C!26?G!6?_!14?G!4?A!41?@!4?C!9?_??_$#144!23?A@!35?O?A???W!7?@C_!50?@??G??O!20?A!4?_??_!4?C!5?A!6?@$#145!170?@$#146!197?C?G$#149!167?A!89?A$#151!199?@A?C?OO?@?@?A???K!4?O??o_?__?_$#152!70?A$#153!24?C???o!18?G!37?C!51?O!4?_!95?O??G$#154!69?O??C!12?A??OA!33?C!12?G!108?O$#155!180?oG?aWNF@$#156!22?G!38?O???A!8?S!52?A$#157!154?GA?O??O?@??A???@?_]?G???C$#158!163?C!21?_!5?@!4?A!12?C??_!62?G$#162!187?O_!12?O@!4?G!41?_?C$#163!50?K!136?C!8?C?G?O!7?O???O!4?_!32?O?B$#165!171?O$#168!231?_$#170!194?@!7?O!57?@$#171!164?G!8?G$#172!73?@!61?_!68?_!13?_$#173!22?o!42?@C!6?E!52?@???C???_!24?GC$#174!75?A!9?_!54?_$#175!21?_?G!12?@C!27?O!10?G!8?GAAA!39?G!24?G!46?G!14?O!26?_!5?@?_$#178!49?A!28?A!110?_!13?A!4?G$#179!23?C!37?C!12?aGO!54?G!74?A!36?_$#180!189?W??OG??goo?_$#181!156?BD!10?[!5?@`$#182!198?C!14?_!5?_!39?@$#183!170?G??O!25?_$#188!135?G!44?G?O!24?A$#189!23?O!49?O?@!164?o_???C?A_$#190!212?@??A!16?_$#193!224?G$#197!159?O!117?A$#198!86?G!92?_?_aG?O$#199!37?@!32?O!8?C!7?w!32?@!12?C!70?C!37?G?C?A$#201!38?G!27?@!19?oCC!36?C!56?K?A!51?_$#205!188?GE~}ms?O$#209!173?_$#210!23?_!4?N!43?@!16?@!34?C!6?@!51?C@$#211!216?O$#213!178?_??C!13?@?A?C?G!6?_!4?G!7?_$#214!186?O!67?A$#215!22?C@!36?G?C!12?O!52?CA??G$#218!198?A???G!5?@??@!4?CC???O_??O!4?_$#219!21?A!54?@???A???O!33?@!34?@$#223!219?C???G$#225!243?OG???AG$#228!18?M$#231!163?_!6?_!16?_!17?_!14?_$#232!65?_!6?_!15?G!30?@!64?C$#233!21?C!15?G!9?C!28?C!9?@!96?@$#235!69?@?@!16?_!16?A!37?O!4?A$#236!218?C???G???O$#238!167?@!46?O!47?@$#239!211?G!54?A$#242!29?G??DO?G?_!4?W?A?O!36?A!7?q??OA??CC??_!8?o?a!13?O!8?@??AC??GG??_GOa$#244!220?C$#246!18?o!59?_$#252!19?O!27?_!18?A!18?O!107?A!73?A$#253!73?G$#254!163?G!39?O?H!4?C-#1!23?c!16?@!23?O???A!5?_!108?_!37?G!16?_$#9!18?C$#10!17?OB$#11!217?A$#12!211?C!11?_$#13!218?A!8?C!12?_$#19!52?C!10?O!14?C!112?C!14?@!15?D???C!15?O$#20!56?_?OE!7?A!12?_!80?A!5?A?C!50?O$#21!51?AG_!138?C!32?C$#22!64?G!125?@!13?@!8?@!4?C!26?G$#23!192?G!22?G!29?C$#24!153?B!5?B?@??D??@C$#25!212?C$#26!65?C$#28!165?A???B?A$#29!61?_!99?C!34?_!20?C!4?A!16?_??_!31?@$#35!81?_!60?A$#36!26?GA!19?C!6?@!5?c!16?W!61?@!4?A???C!8?C!12?_$#37!26?_!20?o??@???AI??B?OOK!14?_!63?@!11?C!8?A??_???O$#38!26?Qw!10?_!8?A!4?@FCP!4?GF@?@!10?@?C!64?@B??E??__??GW?G!7?oOoow?O$#41!154?@@!12?@???B$#42!66?A!158?_!47?C$#43!21?@!15?_?C!6?G!17?A!82?Q!10?G!4?O!51?CGG$#46!193?C$#47!160?@!7?A!6?@$#48!193?@CJ@MC$#50!64?C!14?@!164?O?A$#51!202?CQ$#54!54?_!24?A!160?@$#55!180?C??O_!58?_?oww[}ybkDA?A$#59!159?G!58?G!32?OBGW~X]rwaRk_FD$#60!171?G!86?GE\kR^wy~~~}~RJB$#61!166?@!58?@!43?@?KC$#62!18?_??G!6?C!19?C!20?_!5?O!6?_!67?C!5?O!4?_$#64!65?A$#65!19?A!8?@!17?A?A!25?O!5?C!6?C!50?A!21?_$#66!176?_!4?G$#67!179?A??O$#68!238?A$#69!19?C!18?C_!6?@!23?_!10?G!64?@!14?G!20?@$#71!185?@!6?O!18?A$#73!173?GGOOogOGO?GGmzFKCGo?_!35?@@??@$#76!74?G!72?_!12?G!71?C$#78!178?O___??O??_?Oo?_!16?@$#79!182?_$#80!24?C!5?C?GOG?AG!5?A?a!4?_o_!13?g!16?G@??O?O?_?_O?AC??G?g??GB?O!5?@A?@?C?CG?Y??@!4?_A?_E!4?W??O??@!72?G$#82!35?GO!4?A??@!35?A?A_!7?O??A???@???D?@!6?GOA?O!5?AO!12?G!21?O$#83!29?A?G`GC?@???G_?`?H!4?G!31?L??O!5?AGAGOCaA??I?AAO??@O?_???@@AO?S???@I?A!4?G@???C???_!14?_!4?O$#86!35?O!15?G$#87!30?A!57?G!17?O!15?A!8?_A$#89!20?q!8?Go?O@_??F@?OSECoC???WS!14?_O!14?C??c??_ANbCRP??`@GqS??kgAK@MD?C?CC?W[NbA@D?c??{`tcOCcO?W?O[_?GO_O??@@@B!5?_o$#92!20?H!88?G!16?_???O???@$#94!227?_!15?@$#95!228?G!15?C$#96!188?O$#100!236?@$#105!228?_G!4?C!5?A?G?@A$#109!225?OOO??_??g??O?CO$#110!229?O!5?G!9?@$#111!230?G$#112!224?O???O_OOgOosgCWGKIEE$#114!231?gO?G?CW?C?C??A?@$#116!78?@!136?A!12?C$#121!21?C!30?O$#122!195?_!9?@??A???@?I!5?D@!4?A?A!19?@$#124!36?_!28?@C!6?AC_!9?AG!57?G!4?A?C!75?G!10?@$#126!21?O???_??A!38?_!18?B!58?@!31?A!32?A$#127!174?A??CE!34?C$#128!173?O!10?@$#129!46?o!104?G!10?G_!10?_!20?O!28?@$#131!182?A$#133!244?_???_?DKOqd?c`C@$#134!67?@!11?c!126?A!4?@?A$#135!78?G$#137!154?A?@???A???A!6?@?A??@$#138!165?@$#139!25?@DD!10?O!8?H!6?G_?O?O?GAF!12?N!61?@?@!4?A!4?G??OcW?A??C!6?G?_?__$#140!79?W$#141!53?O!137?A!31?CE$#142!25?A??_!25?OC???_!20?G!66?C?C??G!9?C$#143!173?C$#144!22?w!33?G?g?@!7?O!6?C_!67?C???GO?O?_!9?@GG?C$#145!156?A!13?G$#146!189?@!28?O$#147!69?A$#148!78?A!152?A$#149!70?O!6?@!141?O$#151!170?A!8?GO!7?AG$#153!37?O!11?@?C!170?G???g!14?O$#154!19?G!4?B!4?_!35?G!16?O!54?A$#155!183?@!53?@?A$#156!56?AD?H!8?G???_??IO!60?@!5?C?C??O??_???C??@C???C??K??G???_???@!55?A$#157!155?A!9?C$#158!182?G!11?G!8?@$#160!70?GOK$#161!70?FNQ$#162!194?O!21?A??D!9?E!14?G??A$#163!17?_!33?@!10?_!130?G!13?A?C!7?@???C???A!4?A!10?_?O??C$#168!187?G$#169!43?O!87?G$#170!58?C?A!12?O!75?G??O???C?C$#171!173?@@!33?_$#172!22?F!45?_!112?@!34?C!6?@$#173!52?A???Ca!9?C???_?G@??A??O!59?AA!29?O!21?O$#174!28?O!19?O!32?O!62?@!31?A!57?A!13?A$#175!18?O??A???G!12?GG!29?G!66?@??A??C??G!6?C!4?G!17?CC!5?CA!10?_!24?A?O!19?@!5?C$#178!66?@!11?o!144?A!6?C$#179!56?O!89?GG??O?_!13?A!41?OA!62?O$#180!192?@AA?]pzmQY???a$#182!207?@!7?@!5?A$#183!199?Pldzk}[{{G$#185!179?C$#186!216?@???A$#187!172?C$#188!50?A!34?@?A!60?A$#189!223?GGG!13?@??@G$#190!235?@$#195!218?@$#197!18?G!153?O!7?A$#199!19?@!5?O??G!17?C?h!18?OC!4?CA!73?_!13?_!68?C???AA$#200!175?A$#201!39?Q!33?_!13?@!64?A??_!23?@!57?A!9?@$#205!191?@A?@C$#207!69?@!120?A$#210!21?_?@!15?@!46?C!54?C!10?@!27?@A$#211!176?G!11?@!23?A$#213!170?D?G!5?@!4?CA!6?G!16?@!18?@@$#215!53?G??@G!4?Og???G!89?@!4?@I$#218!184?COCO!43?@@?@$#219!40?A!4?O!94?C!18?_$#223!189?_!33?O$#228!213?G??O???_$#231!214?C!11?@$#232!23?A!122?O$#233!23?W!45?O!17?G!74?O!56?G??O$#235!19?oC???w!4?SHvEcRFK???_Hw?I!4?c!14?_O??@!4?@!6?@B?TYko?T_[GcKdFWW?L``Q@Od_G?a~Pn`yke??WhW_|?tV?]IJFPWiU_wK?W?o_?__???A!9?O$#236!188?_$#238!69?C!88?A!22?C!42?_!7?A$#239!72?@$#242!29?@???A?_??A?C?@GC!4?A!33?A!4?_??@???g??s?AS?OC??u_??A?W???__??_?A??G!7?C???__???G!15?O$#244!237?_??O$#245!233?C$#246!17?G!192?C!6?O???_$#247!222?_!4?A$#252!25?C$#253!175?_!32?C!5?@!34?@!21?_$#254!135?@!35?C??SG?G!11?AC!19?@-#1!21?@?N!11?C!18?G!12?C??H?@???C!5?O???_!86?G!4?A!8?G$#13!55?A!146?O$#19!56?AC!20?G!118?A!25?@?@???@$#20!56?@@$#21!239?@$#22!60?A!17?@!118?@???G!22?@!5?@$#23!244?C???G$#29!17?@!37?C!6?@!6?_!9?G!120?C!29?A??@??C???@$#36!47?B!13?G!29?O!62?_!4?W@G?o[P??BAC@O$#37!27?CK!29?oO_!16?@!13?g!59?@?g!4?_C!4?_Ih?CCBO$#38!26?B?O!28?_G?OSA!19?@!69?ESS???OAQaWEB_CkggwaE$#43!27?O!62?OC$#46!226?A$#50!54?A!174?A!21?_$#51!202?A$#52!186?A!22?OCW!27?G$#55!185?@!46?GG?GWOWqorb!5rvvXZ$#58!255?!14?A$#59!159?@!92?OYh}~~|~]~\]BGGA$#60!255????A?`?a`[VFDB$#61!255?!14?@$#62!29?G!33?@!5?GC!9?C!76?O!41?G$#65!18?@!10?C!55?O!70?G!16?A$#68!184?@A$#69!25?A!9?A!150?C$#71!201?_$#72!183?O!15?O$#73!181?BAGo_@AEKG?_BFIKGw?_$#76!21?A!4?_???_!6?G!10?G!13?_C???G$#78!182?C!4?@@??O@??C???_$#79!183?A!13?_$#80!17?G??GK?_!6?P???L?G??_GE???B?G?OGC_!10?_?_x???O?G@@Y!8?A?G__CA!4?A?m?W???GCH?A??G?GP?A??_?_?W?@OG?O??GCE?O???Gh?CPQH@?@q__!21?_?_G$#82!24?C!6?_!7?A@!31?_!32?C!8?C??O!6?C???A!5?@!4?@???C!7?O!5?A!20?C$#83!18?GBA!10?OGB??O!4?@?_O!4?_?A!11?OGA!8?K_!10?O?@@!4?O???AA__???_G??AA??A???_APOE?O??C?G??A??_?}?B?A!5?CO??S!5?@!18?GSA$#85!193?C$#86!20?_!23?C!36?G!24?__??@!12?A???__!6?A!43?G$#87!19?O!32?C!58?O$#89!20?So??_!5?GC`_O?_OO?EGt!4?O??UgHc!9?Gq?A_??_a?OA?O!4?O???ACH?O?@AqC@_OGdWDwFoOA?PCSGAG??A@Pa?PA?OaAX?kUcOOOG?d??SP?_`CaK?G!24?xCA_G_$#92!43?O!52?A!15?O!76?_$#96!184?C?_$#98!189?@$#99!183?@!6?@???_$#102!191?A?O$#108!184?A?W!6?G?_$#109!188?_$#112!187?o!6?O$#114!185?C$#116!78?_!148?@!10?@$#121!16?G$#122!199?C???_!33?@$#124!23?O!5?@!24?O!37?C!88?O$#126!83?_!8?G!87?A$#127!181?C$#129!22?G???C!10?@!30?O!11?_!76?_!14?_!4?@!56?O!11?C??G$#133!234?C!7?O!7?eCNDU@$#134!15?_!63?F!151?@@?@@$#135!231?AAA$#139!27?JB_!27?W?hCA!17?_!70?@?HAG???G?kTfH?CQROP?CH$#140!16?C!61?E!157?@$#142!60?G_C!17?@!4?_!4?G!60?A!7?_!11?G$#144!22?B!32?__!20?C???@C!72?G$#145!190?_$#149!215?_$#151!180?@!16?O$#153!22?_??@O!10?C!10?A!5?C!7?O!4?@?A!88?A$#154!16?OCC!19?G!12?@!19?@!19?A!64?A!16?O?@!12?O$#156!55?G!12?@!7?@A???AA!70?@?A$#158!188?G!10?A!12?G!22?C!31?G$#160!56?C$#162!15?O!180?@???G!25?@?@$#163!54?@!4?A?@!16?O!119?A!35?A!17?_$#168!194?G$#170!58?@!24?Co!155?G$#171!209?@A$#172!155?C!85?G$#173!22?C!32?O!12?E!8?G!5?G!70?AO_!32?O!8?C!38?_AC!5?C!20?O$#174!28?_O!38?_P!7?O!5?AG!67?O!29?_$#175!38?@!7?@!33?O?G!7?C?O!86?A?G!82?_$#178!58?E?@!143?_$#179!154?@$#180!198?@@B?K@!9?O$#182!182?O!4?C!17?_!22?A!9?_?A!6?C!22?@$#183!201?F@M^^~\~GG???_$#186!178?@!33?o_!13?A?!5CGO?G$#188!47?C!147?@$#189!48?@!21?A!78?@??_!23?@$#193!190?ACG$#197!57?A!172?G??O!8?G$#198!37?A$#199!22?O???G_!8?A!25?G!13?A???G!9?_!60?C???@O?C!14?@!79?_!14?C$#201!36?@?A!41?A$#206!56?G$#209!207?a?eo_!26?C$#210!46?A!7?_!8?A!7?G!9?C?@C!65?A!22?C$#211!196?A$#213!179?@??G_!6?O!6?C$#214!228?C$#215!55?@???C!8?G!10?O???O!71?_$#218!182?@CG!4?ACHQ_??O$#219!25?C!9?H???@!27?O???CO!12?G???G!68?@$#223!195?O$#225!192?C$#228!14?_$#232!17?AA!10?A!8?C!9?C!18?A?C!7?_!73?G!28?C$#233!36?C!16?@!17?O!84?CG$#235!16?_o_G!4?Zw!4?E@O[_O??_[_oANHW{_ON@OQA!10?CLC!5?CmoDg!4?__?@DAUUA@??Cj[\@P?DIEOJAT\ip_fccxWpEK?N_dKAH`CDP@Ph_MD@Ysc?myGGQGB}?G!6?C!16?AO?[oSw_$#236!185?O$#238!56?O!144?O$#239!225?A!11?C$#242!18?Oc@!10?IE?A_?_??O?G?ac??_?_??W!10?@O!6?A!13?@?G_??@H?_??c?AO@_!4?CG??@?AdKG?K?G?`gCOA?Ag?AH?_??GQ??@AC_O_?C!7?@!16?CA_$#244!185?G!10?_$#246!15?G@$#247!16?A$#252!92?_!110?O$#253!202?_!8?C!19?G$#254!191?_!8?O-#1!70?A!11?G?G?_!34?_!30?@!19?_!9?@$#2!80?_$#3!79?C$#8!79?A$#11!255??__$#13!205?@!5?O!40?A??_$#19!212?O!39?O$#20!55?A!100?G$#21!214?_!38?@$#26!77?_$#29!16?C!177?GO!58?A$#30!195?G$#36!29?@!26?C?@!32?@!62?@???@E?@?@A?O@B$#37!57?CgE!26?A!60?_??O!6?A??SCa??D???@$#38!53?_??wbUXG!30?E{!58?Oog]??@_g?G[YLaH}{_B~$#42!196?_!14?G???_!38?G$#43!60?O!23?@!6?G$#46!222?_$#50!251?@$#52!183?@!24?@?@@KDNC?G?GO_!26?A$#55!243?!6@BBA$#59!60?_!193?@@!4B@$#60!184?C!76?@$#61!194?C$#62!54?@!36?O!59?G$#65!28?@!23?_!32?O?O!30?_!29?O!23?G!80?C$#69!150?G$#71!209?O$#72!185?GOG!16?CG???_$#73!184?@Ac_G_!4?BCG?O_@@?CACWO_?_$#76!27?A?G!55?G!7?c!20?O!8?_!8?_?_!8?_$#78!185?D@So!6?A?G?@?ACAG$#79!187?A!11?OA!4?O?_$#80!18?AB???O_??g!6?G?E??EG?@?IGMG_G?O!9?O??O!6?O?G?C_A!4?@!7?G??@a??A??C@?AAC??C?C?g??P?OA?E@!5?AgC_@??C??C?_??C??GO@?A!23?OO@?o?_??CO_$#82!20?A?@A??A!7?__!12?@??K!14?S???@?C!29?O!8?C!4?@!11?A!47?@$#83!17?A@?O?O_!4?O??AAO@QO?O?O?EG??@!4?@H!8?_?@?IA!4?AO?cO!6?AM!5?@!4?O?GO_ABa?__???A?A@??ACG?@OGW?KKa?HSG??OQA??O??O?g!5?C!24?_?A???@???G$#86!65?O_!35?@!45?G!32?_$#87!18?O_?I!30?A!10?C!19?O!11?A!14?_!11?A??O!9?O!11?G!25?G$#89!18?_[_?A?Rk?OCo?@_g?G?\B?_P?SO`oAOAoAC!9?N?L_GA_??@??Pa!19?LtGAlgCA@G_Gx@I??AC?AQGCJ???RQ?JO@_\??G?IwHAH?HOQ?SNEBD?A!22?IWoMDE_^$#92!23?@!24?C!56?@!5?_!22?@$#96!196?A$#97!190?@$#99!201?_!4?_$#102!187?@!12?O???O$#104!199?G$#105!188?A!5?O!58?O$#108!191?G???_?@!55?__$#109!189?E?__!4?ACCCG$#110!191?C?_!6?GO_o$#111!190?CO$#112!190?G?OO_?@?A???O??_$#114!188?@@A?G!11?_$#115!191?A$#116!16?G!235?H??O$#118!15?@!62?O$#121!77?O$#122!78?@$#124!16?A!11?A??G!29?G!6?G??_!5?C!11?GC??W!28?_!10?_!13?O!4?A$#126!29?C!31?A!25?A??@!54?_!39?O$#127!208?G$#129!30?G!22?OA!30?A?G!124?_$#133!255?A$#134!209?C$#135!78?G$#139!54?K??G?_F!31?A!55?_?__?R_B?{]?jq@CoWe??]{$#141!207?A!45?A$#142!29?A!27?O!22?@!7?G???@!56?_??GC!5?P???_$#144!54?_`!13?A_!8?@!9?_$#145!191?@$#146!17?_$#147!79?O$#148!80?C!116?_!11?G$#149!55?G!184?@!14?CC$#151!186?G!15?@!4?GO$#152!78?_$#153!17?G!9?@???O!45?G!6?_???_!23?O$#154!52?O!28?@?`!9?A!16?W!20?_!122?O$#156!54?O!14?CO!9?A?_??_!69?G!65?O$#158!205?A!12?C$#162!15?A!62?C!127?A?C!4?_!38?C$#163!210?G!43?C$#168!188?C!8?CG!4?G$#170!69?G!15?@!69?C_$#172!69?@$#173!56?@!24?G!73?OO!35?AC!47?@!4?A$#174!70?G!44?_$#175!30?C!30?@!19?C!4?L??O!56?_??O!22?@!89?@$#179!79?_!8?O!66?_@!39?O!10?C!8?@$#182!208?A?O!31?@$#183!207?@?ACC?A$#186!212?@GOZ}swo_$#188!30?A$#189!68?A?C$#190!198?@??C$#193!199?A$#194!79?G$#197!204?@!15?G!24?A$#199!68?@O!44?_?_!55?A$#201!53?G!28?O?OC!4?_!26?_!54?C$#206!81?O$#209!209?@AAA$#210!30?O!30?C!6?C_!11?A!6?C?A_!27?_!32?C!31?O!67?_$#211!192?@$#213!184?A!12?O!13?_$#214!217?A$#215!56?A!30?C$#218!186?A??O???@??C???_?A$#219!53?A!33?`??O!33?_$#223!189?G!5?@$#225!190?O??G!8?G$#226!80?O$#227!80?G_$#228!14?@$#231!193?A!4?_!4?@$#232!30?@!53?A!26?O?o!30?_!27?O$#233!53?C!32?O!33?_!62?C$#235!16?@DK?LtkKKRlCG?_C\FUDhakXAMgbDO?_AtI_?@!8?oqaD@|O??KGsIH^@!4?C?C???@C!4?L_?c\OOW_KPYfEWs?I@ALGCFOCPAW?@Lo_?Q?UMDGdFAlUMs@L^B???GCD!21?F`cI@iW\?y_$#236!190?_$#238!55?S!100?E$#239!17?O$#242!26?O?_!10?_D_O?_E?TG?D!12?G!8?bB!14?AA!5?OA@!4?KOC?O?_@@?CH!4?G??CD???CC?@AG@?O??_O?`AA!7?B!23?C?C?O?A!72?G$#244!192?C$#246!15?CO!234?_!4?O$#247!78?A$#252!206?@!6?O!46?A$#253!183?AG_!61?A$#254!31?_!174?C-#1!20?_!13?C!34?@!8?G!6?_!7?A_!107?_!53?_$#2!81?uw_$#8!84?_$#9!74?C?I$#10!18?_!58?G!164?O!6?A!9?K$#11!203?O!51?_$#12!18?G!61?O!117?@$#13!215?@??A!24?O$#19!222?G!9?_!4?_$#20!19?_!33?oF!37?O!62?B$#21!221?C??G???O$#22!77?@!151?OO!24?D$#23!219?C$#25!200?A!72?G??_$#26!255???AA$#29!217?@!4?C??G$#30!228?_$#35!91?G$#36!50?OG!4?g?G!64?@??G??G??E?GOO!5?O???O??O?Q?S??O?@_GO@?[?_?WS$#37!35?O!14?_?A?_QO_C!33?C!29?@!5?K?E!6?AGQ?C??B?AE?GAD?A!4?g?OC?G?G?_C?@$#38!37?__!13?{A?_ANQA!58?@@@AAACAEM???MGAEIE[S?O?MD?EKPUDK?K@A?bLAXBieFAu^B`bw@$#42!73?C!180?_???O!14?A$#43!49?_??@!30?A!36?A!11?O!9?@!44?G$#46!225?A$#50!197?@!42?_!10?@$#52!199?@!22?@C$#54!198?A!51?A!6?C$#55!224?C!49?C$#59!128?@!42?_!101?_wo$#62!41?_!8?G!19?O???@!12?_!38?@???O!10?@$#65!18?A!20?O!19?O@!9?_!13?G!31?@!23?@!44?@!55?_$#68!201?O!43?O$#69!59?_!28?G!29?A??C!5?O!7?_!50?G$#71!204?G??_$#72!188?AGSG!19?@???C!6?O$#73!187?BKqJ?GO!6?@??C??O!5?B?A?CCG$#76!36?G???O!9?C!28?G!11?O!34?O$#78!201?@A!10?A$#79!207?O?@$#80!21?@??_E?`_c???O?C?CF!4?IKO??D!14?A[F?OGc!8?AO!4?@CO@??_???WCA???C_???@AKpa?CAAg?aA?SC??W!49?Q_GO???H?OcA__!55?_!11?O$#82!32?C??@???C??A!20?C???@!44?P!60?C$#83!20?A?CC???C@???@!4?@?@C?C??ECCA!12?@A!26?C!4?A?@D???@?A???@??C!66?AC@!5?A$#85!203?A!7?A$#86!78?C!23?C!69?A$#87!21?GGGWwW?OWgw___??GGG?GG??gwGWG!10?w_gg__wGoW!15?W_??WW!4?o_WxWGGgw_GWOGGow_?OwWwog?GW?__??___?_!39?w_G_g_oWowgWsOO$#89!19?DLOpp?@eWGAO?Q?B?E???GR@OB?Ar?AB!10?W@O@WC_@???C@!14?@!5?@GWa?c_O?C\q?_?@G?GWAC!4?G_?_O?__!45?GC@CWI_?EEBGK$#92!49?@$#98!218?O$#99!205?C!4?A!4?G$#102!212?C!8?_$#104!193?C$#105!196?@!10?G!6?G??O!25?_??O$#108!203?@???@!9?_!39?O$#109!194?G?C?c!5?@??E?GC!7?_?_!27?_??ACP$#110!193?@?@_A?___???A??CAw_?w?Oo!27?_?__?__gQ_$#111!194?@!59?G$#112!192?@AEEOcOG!6?D??C?CG?o_!31?OOOCC@C@$#113!208?G!42?O_$#114!195?WIWGOO!4?@A?AO?Wo!6?_!25?_???GW?GIE$#116!17?EO!181?CGG!52?OG$#121!199?C!47?G$#122!77?A!124?O??_!14?C!5?O!31?@$#124!19?G!13?G!9?_!28?O!5?@C!13?@!21?@!18?_!52?_!69?G$#126!35?g!56?_G!25?A!18?@!88?_$#127!218?C$#129!34?G!54?@!49?_!13?_!49?G!10?@$#134!18?C!220?_!4?O$#135!219?A$#139!36?_??_!11?o?@?KDO`@!61?@??AC??AEG?@DPCG?AGEY?Y[H@GHAPGPG@_KqSEc@WO`@?[AGE$#140!225?O!5?_!6?_$#141!255??O@$#142!36?O???_!18?C!10?C!20?AB!31?@!6?@?W!5?CG!4?O!6?A!10?_!109?O$#144!70?@g!14?AO??AC!49?_?_!10?o!74?_$#148!75?@!4?_!120?C!15?A$#151!188?@C?co_!11?G!13?G$#153!51?A!19?@!7?A!5?AG???C!109?G!57?K$#154!18?@!29?_??@!8?C!8?A!14?C!4?A!82?@$#156!55?@!34?@?G_!46?_!5?__??_?_?GO!71?C!47?G$#158!186?A$#160!74?_$#161!74?Y}C$#162!77?C!125?__!18?G???O!30?_$#163!216?@!16?!4_!9?G?C!6?G$#168!213?C!5?O???_$#170!53?C!95?_!4?C!118?C$#172!76?@$#173!53?GG!15?AC?O!11?@C?_!55?__!5?_???G!30?C!37?@$#174!79?@!37?@!53?C$#175!19?O!50?GA!15?C!5?O!31?@???@!57?O$#178!255?A$#179!71?O?G!10?O??G!54?_!12?C$#182!188?_!27?A???A!5?G$#186!218?@@@BABACCGG$#188!38?O!52?@!37?O$#189!138?_$#190!202?@???G??_!12?_$#193!192?A??_!12?O!48?_$#194!80?C$#197!204?O!25?_$#199!37?O!21?G!13?_!12?@?O!36?G!5?O!4?@!34?W$#201!122?C!4?@!9?@?@$#206!82?@$#207!83?C$#210!33?CO!43?o!4?@!9?C!34?O!8?_$#211!205?O!17?O$#213!188?O!12?A!11?@?A!10?_$#215!54?O!93?_$#217!77?_??G$#218!189?@_QC?_!9?C???_?@???C??G??OO??__$#219!44?_!27?G!60?_$#223!191?@??O!13?@$#225!204?A$#226!80?@HCO$#227!80?A?A$#228!241?O!5?C??@$#229!83?G$#231!186?@!15?C$#232!42?_!6?O!74?G!11?_$#233!60?A!11?_!14?A?_!159?C$#235!19?A?EAAC?@?E@FF?B?A@A?ABC?D?@@??C!11?EC@??BEE???B!15?C!5?CB??EBBER@ACDAECB@CcD?CCC?O!52?@BAB@?EE@@?@$#236!193?G!22?G$#239!229?G$#242!20?O_??B??A!4?G!9?O?O!17?O?A!14?_!4?A???A??_!4?C???O!5?_??O?A?@?A??G?_O_??O!5?_!40?C?OS?C@$#244!248?G$#246!76?_O!167?G!10?D$#247!17?@!58?O!122?A$#252!51?C!71?C!6?@!4?@!35?A$#253!206?_!14?G??O$#254!73?A!113?C!32?G-#1!77?C!11?C!4?_!34?C!12?@?G!7?@!101?G?A$#2!81?@~\[o$#10!255????_$#12!85?A!173?_$#13!210?C$#19!205?A?@!4?G$#20!22?_!29?K@!85?@!17?G!30?H$#21!75?_!129?@A??C?_$#22!75?OC!177?A$#23!80?@!125?C!45?_!13?O!4?A$#29!158?o!48?G!62?C$#35!72?C$#36!34?O???K?@o_??G?QU!5?H??A!68?_??G!10?A!18?G?CO_?IO?_AC!17?_???_$#37!36?GCPT!4?O_iC?@I?_?CAIC!66?_!14?A???C!11?_O@??DgJBW??[PCG!19?O$#38!35?W?w_A]NHUcSCgGC?A??q_`!65?_??_O?O!27?@AFEIAcS_TM@A`R!18?OgO$#42!137?A!71?GG!44?@$#43!95?G!32?G!18?G$#50!80?C$#54!255???@$#55!194?O!81?@$#59!255?!10?!4_O_kctQCW_u[$#60!255?!19?G_$#61!255?!13?O_WOYIdZe?G_$#62!48?@!37?C!40?G!25?_!17?@$#64!76?G$#65!21?A!10?O??C!37?@!21?C!34?C!14?G!8?OA!15?G!45?_!33?G$#68!248?_$#69!22?C??_!7?G!53?O!62?O$#71!212?C$#72!192?C???_O$#73!193?F@UC$#76!23?G!6?_!57?A?C!42?G?C!14?_$#79!195?@$#80!25?@?A?E?WCC!27?CGdFA?K^CC??O!5?O!7?Aoo?C?G?@KJ?GD@@?GDKO@P@hC??Aw?AcA?@C??@A?AA_???gCo?s??_??@??@??HC?A!17?E_Ig?_?hoAgI?K_$#82!97?_!50?C!27?O$#85!232?@$#87!27?@B?FDAAAB!22?os`xtYO\~r_xO???W?_o_i!7?GKGp`}_??BCgTWw]~VyQkUg{QXn[{EpdH\GGI@FACE@@BOPWOOKsGwwWoP_qB?bJaIQG!17?G^tQEVRAI[Fo}P\E$#89!21?@?@??EKCWG?H@@!24?GI?A?__???A_!6?GS@!7?C???W!5?ORAAE??_?`BgEA?aOB@?IWQ?DE@E?C@@???`_??g!6?@_O?_aC?SoKC!20?DHGkSD`OD@a$#92!24?A!5?O$#94!251?_?@$#95!250?_$#96!198?G!29?@!7?@$#99!200?_!11?A??G$#102!206?GO!18?@!10?@$#104!217?O$#105!196?@!41?@!13?Q$#108!238?A!8?@$#109!198?DG?G?C_O?_!7?A???aOP@@A?A?OW?C???CC?G_Ec?_?C?A???C@???@$#110!197?AA?OC`g??_!5?@?ACB@C@C?gYPsO{M_OIi_AAOW_B?JpCcH??NJ$#111!200?A?O!16?O!5?A!4?G!4?O??O?P?C??A??O$#112!200?KA?OCG!7?A!4?HG@gS???C???C_?GC!4?K_???AOo??CKB$#113!199?@!15?@GI??I??cC?G!5?C??G?A!6?G?I???@$#114!197?@?E@pMAW_O!6?@@?CCQC_EA?gG_A_EaOOUw_icCOGOIZP_D[??A$#115!253?GC$#116!19?AG_!54?A!176?_O??A$#118!75?G$#121!75?C!4?G!169?O??O$#122!208?IO???O?_!38?@GC$#124!36?A!21?G!11?A??_??O?A!11?A!29?_!11?A!12?A???G!37?@$#125!157?_$#126!71?O!22?@!46?C!11?@!17?C$#127!213?G$#129!21?C?_!12?C!7?@!13?@!12?C!17?A!4?A!29?O!16?A!66?C$#134!212?O$#135!210?O???_$#139!36?_?Ag_?UhIAO?_Y?d?w?\S@!65?_?O?O!17?C!13?ooP?GB_`aGW!19?g?_$#142!22?O!9?_o__O@!12?D!6?G!84?A!13?_??@!4?C???C?_$#144!21?G!28?_O!20?_!22?_!33?o?G???A!22?G!33?G$#145!72?O!20?@$#146!210?_$#148!189?A$#149!75?A$#151!190?@?@?GGOg$#153!58?C!14?A!4?@!47?G!6?A!10?A!10?GC!31?A$#154!73?G!13?@!7?A!28?G!22?O!24?_!14?G!67?C$#156!49?_O!37?@!51?@!13?@@!33?C?G!17?A$#158!191?C???_$#161!75?@?@$#162!21?O$#163!19?@C!183?@?@C???G$#168!197?C!12?@??C??O!12?@!5?@$#170!53?C!31?@?_!42?G$#172!20?A!31?A!77?O!146?G$#173!53?A!17?@G!4?A??A!13?K!38?C??A@!16?_OA!30?_O?C!61?G!10?_!8?@$#174!96?_!35?G???@$#175!20?@?G?_!9?G??A!7?@!26?A?A!19?O!26?_!9?C!6?A!48?OC!4?_$#178!207?A!45?A$#179!138?@!17?GC$#182!211?C_!51?_??O?G$#188!190?A!24?O$#189!36?@!35?@!7?O!76?O!36?_$#193!208?_$#194!86?O$#197!86?G!106?O!74?G!10?AG$#199!23?O!7?_!25?OA!12?G!17?@!33?O!10?E@!6?CA??K?G!59?O!43?C$#201!46?@!94?@!7?O!21?A!77?_?O$#207!74?@$#209!211?O?_$#210!47?@!9?_!13?_!8?_!12?C??O!25?O!48?O$#211!193?G$#213!198?_!11?A$#214!144?C$#215!51?GP!18?A!23?O!31?_!4?C!59?O$#218!191?BA?E?G?O_!9?@?A??G$#219!24?O!9?C!24?@!14?c!11?A!5?@!28?O!21?G!59?@$#221!81?W$#223!199?O!5?C!12?_!8?@$#225!211?@!13?@$#226!81?E?abG_$#227!81?_???C$#228!255????@?G$#231!189?@!18?@_$#232!70?@!63?@!36?_$#233!73?C!51?G!4?_O!8?C!6?CO$#235!61?A!16?G!14?O!23?C!16?_!15?C!21?O$#236!196?A!33?@@?@@$#237!204?A$#238!128?_!85?O?_!36?C$#239!255?!25?O$#242!22?@?@E@?G@?A!27?AS???G!5?G!8?C!6?@???GA!6?C__?_!8?C??_?@!4?A!16?G!7?@!8?C!16?@???_!9?A$#243!22?AEKWwoo_$#244!214?C!32?_?O!5?A$#246!76?@!182?W$#252!93?A$#253!255?!22?O@-#1!80?A!45?O!44?A?@$#2!82?@}r}~g$#8!81?G$#13!24?C!190?C!22?O!15?O???G@$#18!40?_$#19!199?G!18?@!11?O!6?O!5?G$#20!36?_!5?O?G?A!50?_!53?C!36?C??O$#21!74?C!126?_!19?C!5?O!13?O???G!4?A!6?@?A$#22!233?O??O!11?C!4?O$#23!217?O!63?O$#25!73?G$#26!74?I@!170?G$#29!95?@!35?@!54?A!11?_!22?_!13?_$#35!47?@!110?C!32?G$#36!29?OO!6?@@?B@@!7?WC?C!67?C???@!26?__?A??_OE@??ChIPO?C!17?_A$#37!42?GA??GGC??@@A@!67?D!28?_CG!5?A?O@A??Pa?G!4?O!11?O???C$#38!41?AA???@??IEOK?A!43?O!20?CE?A@!26?_?GAJ@???`giOHgE_?nTG??G!12?_GO?bfL$#42!193?_!19?@??C???C!9?_!5?__!4?GO!14?OC$#43!27?A!69?AG!32?A!43?_!39?G$#50!248?A?@!6?G$#51!203?G$#52!244?O??G$#54!197?O!23?A!36?A$#55!205?_!6?A!26?!4_?_$#59!254?A???_ovfv~~~j~}i{{Y\fT]M@@$#60!200?A$#61!201?C!59?GG???S?@TBBdaWI@@A$#62!52?O???A!32?O!29?G$#65!88?A!6?A??C!22?_!5?_!11?O_!31?C!20?C???G??G!40?G$#68!157?A!36?G$#69!29?@!93?O!26?C$#71!214?G$#72!200?C$#73!197?@!17?O?_$#76!71?C!8?C!38?O!51?C??C!30?O$#78!216?_$#79!211?A$#80!55?_?a??@A?SWGGO?CC???_?@_s`O!7?@?`A?@!7?hA?WA_?crAK??DOOI!6?_?C??_OCGo?@!4?O?CAB?{?AC!25?G@S??Az??W@!42?G!11?G$#82!52?_!43?_!13?C!30?_$#87!56?{C|zmhX@DPeKRjgg???WQR@E!9?DYsycGO??@ENUS^b\FPXCxpV@oEECO???__?GGSqGCWO?oOb@FDJZI|C\@L\@B!20?_??@FUG}ux?jXFA$#89!53?_oG?WA???eiaAPBK?R!5?KKIW!9?A?@DQR_???@??H_C?WiAG?AGm?hg`@!8?GGO??_G@??a?ICCp?W_?o!29?B@HC?Ce$#94!248?@!7?O$#95!254?_$#99!201?@!13?_$#102!220?@$#104!210?A$#105!211?CG!32?@$#108!236?A?G$#109!202?@??GQ@cCO_O!13?C@?@E?A???KA!4?@C$#110!203?AACCUAI_G?o_!7?@??B@AF??H??G??@ACCB?AB$#111!204?@???O!24?CAA???A???@$#112!209?_!13?@B!4?A??C@@L!4?BC$#113!204?CA@???GO!20?G!13?A$#114!203?@?@GGHOC?_!8?@?A??AC?CHE@IC?@KD@??E??A$#115!225?C!13?G$#116!22?@$#121!156?@!36?@?A?C!29?G$#122!25?G!174?O!15?G@O???C??G!13?O!4?G??C???@$#123!87?@$#124!54?G!16?A!57?A???@G!41?_!8?C!60?@!10?C$#125!154?_oM@!35?OFo{$#126!26?@!46?A!50?G_!58?_!21?_!11?_$#127!199?@$#129!24?@@A??EEFFM]]W[WOO!13?C!17?G!46?_@???O!11?G!20?C!12?_??C$#133!228?_!14?_?oooww{[]MCA???GGO!13?_??C$#134!219?O!14?_$#135!199?O!16?@?A!4?G??O!27?GCA$#139!31?G!6?_@???@B@??Wc@AA??B!40?@C_!22?B?AB!4?@!21?OOSC??_WKPCmsROCK?aB??o_!12?oJp??A$#140!231?O!14?C!6?_??_$#141!197?_!19?G$#142!28?C??OWP@@FAEMKKc_!4o_O_G?@??@!62?A!14?C!35?O$#144!28?G??__!8?O?GC!51?C!24?O!4?_@!24?A???_!29?CA$#146!255????@$#148!27?O!19?A!171?_$#149!24?A?C$#151!201?G$#152!74?P$#153!51?_!23?A!21?@!22?G!16?O!48?@!37?C$#154!27?@!25?O???@!22?G!8?G!8?A!37?O!34?G!83?OG$#156!37?_!5?O?G!26?A!52?O!4?@!19?O!34?O?C?CO$#158!200?_??_O!49?@@@$#160!81?o!6?G$#162!28?_!173?_!9?@A!14?OO!10?O!8?A!5?GC$#163!73?o!124?O!20?Aa???G!27?_!4?AC$#168!213?G$#170!255?!24?A$#172!39?_!9?@!38?C!8?O!59?G$#173!23?@?A?K?G_!17?A!23?@!23?A!25?G???@!6?A!15?_G??@!4?B!26?_?@!4?o!4?A???O$#174!72?O!26?_!36?CG!18?O!15?_!21?_@A$#175!30?@!22?G!64?C??GO???A?@!9?O!10?O!44?O!43?_!10?C?a$#178!214?A!8?C??G!7?OO!6?O!9?@!4?_$#179!29?_???__!13?@!71?_???CA!63?GG!7?C!12?@$#180!199?_$#182!215?@??G???G??O???_!23?@$#186!216?ACCKWWooo___$#188!202?K!16?@$#189!130?A!4?G!15?A!43?G!49?C$#190!214?O$#194!81?E$#197!26?G!96?G!90?C!66?_$#198!154?O!40?C$#199!28?A!43?_C!46?O!11?@C!21?C!16?O?G!10?G$#201!152?@!19?GA!19?A$#206!25?C$#207!45?C$#209!214?@A?A$#210!55?C!43?O!18?G!6?C!9?A!12?_!23?A!74?@$#211!213?C??O$#213!198?BE@?O?_!5?@$#215!28?O?G!12?C?A?C!24?C!24?G!25?C!8?A??C!15?G!5?O!28?G$#219!80?_!14?C???G_!26?A!10?_!32?O$#222!222?A!21?C$#223!202?AC!45?@$#225!207?_?@!19?G!25?_$#226!82?}@K@?S_$#227!81?@!5?AO$#228!27?_$#232!73?@!44?a@!12?C!6?_!35?O$#233!71?@!8?@!15?O!40?CG!16?G!15?@@!20?G$#235!68?_!6?C_!18?G!21?O!11?C!14?_!4?G$#236!204?G!7?C$#238!35?_!5?_!4?C!42?_$#239!232?O$#242!55?O???COS???c?_?O?O???_!14?CG?Gc!5?O?_??_?C!4?_OI?@!11?C?g_???_!9?AAA?A?@!22?A?G_???CO!64?A$#243!28?@$#246!26?O!171?G$#247!23?A!233?O$#252!96?G$#253!134?A!145?_$#254!196?@!4?A?O-#1!72?O!17?@!8?G!9?G!18?C!82?C!36?_$#2!82?[NP@??@GO_$#5!84?_?A@$#10!241?O$#12!81?@!6?G???_$#13!214?_!6?@!29?O$#15!81?G!5?g$#16!86?OO_$#19!196?G!9?A!27?O!15?A$#20!35?@??@!34?A!23?_???O!11?_!69?C?C??O_!21?G!23?_$#21!71?O!139?O!15?C!7?O$#22!40?A!31?A!157?G!5?O$#23!233?A!39?A$#25!255?!25?C$#29!76?O!131?G!14?@???G!20?A!17?O$#30!209?C$#35!101?G!52?C!30?G!5?G$#36!32?O_??W?G??_OOo?_??@!99?H?A??_k?D_?_C?Q??GIG!5?@A!6?CoO?O@??A@$#37!33?COCA?C??Q???_!63?_?_!37?C@!5?W??HE?O?I@A?@C??AA!10?_!4?M?E$#38!32?_Gk?_{o???__???_!51?@!10?oO!35?Os?M@@??Oe_HQHXJGD?@?EA!5?@!6?_?Go`cM?[$#42!72?G!44?C!84?@!7?O???O!13?C??G!10?G!10?C?@$#43!115?C!34?O!17?__F?!4OpoOA!30?C!22?_$#48!197?GO$#50!72?@!24?@!154?@$#51!203?OG$#52!208?A$#54!192?G!44?_!16?A$#55!238?@AAF@B@?@B$#58!255?!6?_$#59!255?g_OkV~^N^V^NMMCB@B@!4?OM$#61!205?@?A!54?O?G??@@BCA!4?_og?@$#62!116?G!15?_!91?C$#64!70?_$#65!49?_!45?G??_?@?G!68?O!11?@!12?@!52?C$#68!74?_!75?_???A!39?_!22?G!29?G$#69!74?O??G!49?A!43?C$#71!223?C!4?O$#73!218?@AC?KGoW_o___$#76!74?C!44?A!11?_!14?C!24?A$#80!57?@E??O?Eh@_AH@!5?C?@A!13?HOO?C??O?@C?SgW@??A??E?_Og_?C@?CO?OOo???@?_P?R?_B?C_@A?@!23?@!45?_$#82!116?@$#87!52?@@B?BC@NMGNHOCQgus@B??@AHE?Wr!10?@?Lge?CW__?ALJUeiBE@AD?@@?OWwo]fWjRa??`BDG]Jayg}WGoIZ{H!33?@?@$#89!50?o@KEKBcQO??EOOAyLT?AM!4?PE?CFC!10?AE?F@@!5?@??@?CK??@?@A?_???A_ObCGKgGO_AA?CKCC@BoK`CACB!33?@$#92!53?O?C???OO$#94!213?G!6?_!30?G$#95!215?O?C$#102!216?@???GO$#104!217?A$#105!248?G$#108!216?G?C$#109!210?@???A???_!28?O??CCA$#110!209?@?B?@DHQO!24?_?_!9?@$#112!212?A!33?o_O?G$#114!212?DEGA???_!23?_?_???G???A$#115!218?OG$#116!31?G!200?O$#118!71?g$#121!92?O!99?@??G!25?_!16?_$#122!195?_!16?O!13?C??G???O!11?G!5?@$#123!81?E$#124!71?C??G!26?A!12?_A!13?GO!85?C!23?_!10?A$#125!151?oWE@!37?o{^F$#126!108?_!8?@$#129!42?BBFFMKIA!50?A!62?!4_?OO??HGGG?KG{W$#133!228?@A!7?@??@?ECEBA?@@??_ooO[nRg$#134!40?@@!154?O!7?A?C!9?_!26?O$#135!196?A!16?_!11?A!20?C???@?O$#139!33?Q?wC??o!72?O!16?C!17?_GQ?C??O??YUCOACD?AC@?@???@!11?B?A@@@$#140!195?O!29?C!23?_$#141!40?{!211?G$#142!37?AAM?KKKGWPRt!53?O_!6?GG??G!34?_!9?_?__?O[OS?G??CCECEAE?cK!4?A$#144!96?O??CG?_!13?C!29?OC!34?G?A??G$#145!234?_$#146!31?O!178?G$#147!85?_gEO$#148!91?G!116?C$#149!181?_!57?C$#151!220?AC?OG_$#153!91?C!60?C!67?O!18?_$#154!72?_?A???G!14?_???A!12?C!30?@???O!32?@$#156!32?G??A@!75?_!4?A!10?A!18?GA!5?G!26?O?GC?C!84?C$#158!197?C!9?@!68?OG$#160!76?_O_!6?O$#161!77?_$#162!31?@!164?C!8?A?C!16?A!6?O!15?C?A!4?CA$#163!32?A!39?C@!123?@!5?@!5?G!12?@A!4?G!8?O!4?O?G???C?_??G??@$#170!234?C!27?_$#172!78?O!11?A!36?@$#173!37?@!35?{!25?A!18?A!27?_?@!4?O?A!27?A???O??_O!38?O!5?_!32?G$#174!131?O!13?_!6?_??@!16?!4_!16?CA!57?_$#175!112?G!16?A!16?G!23?G!11?A!39?A!31?GC$#178!197?A!45?G??G$#179!32?C@@!4?@!58?@!15?OG???@!62?O?@?G$#180!197?on~{fCA?s$#182!200?A?_!9?_!7?@!5?A!4?@G??G@?A!6?C!10?A!18?_??C?A$#183!200?@GYKS?GG_$#186!211?_!12?@@@BADFEEKG!4?@$#188!229?O??_$#189!49?O!103?G!38?A!16?A!8?GO!24?O!5?O$#190!219?C???_$#194!89?@$#197!235?@GA!41?@$#198!151?G!39?_?@$#199!49?C!25?_!20?gOA??c!7?O???G??A!11?@?C!16?A!22?o$#201!49?G!81?G!21?@!17?_$#205!196?_$#206!81?o!131?O$#207!204?@$#209!201?O?__GooOo_$#210!95?O!4?O??O!11?O!10?@!5?O!38?G!5?@??AA$#211!226?G$#213!219?@?A!9?_$#215!34?A!65?C!12?O!4?@!34?_??@!31?_O$#217!86?C?C_$#218!217?@???G!4?O$#219!50?A!19?O!26?GC!9?O??C!6?C!14?_$#223!241?_???O$#224!253?@$#226!82?boME@??Eg$#227!91?O$#228!30?_!207?OOO$#229!85?G??AOC$#231!206?@$#232!50?@!28?_!24?_!117?_$#233!114?C!5?@$#235!60?@!72?@??@!45?@$#236!218?A???O$#238!31?_$#239!255?!8?_$#242!50?K}qGoGGgG__@__C!4?G!5?G??@?G!12?A??A!6?A??@O?@??A!6?CG?G??c?C!4?C?O!4?CCAO!65?@$#243!53?_?oO?_??_$#244!210?A!4?C$#246!29?@@C$#247!32?@!182?_$#250!249?O??C$#252!130?G!21?A!14?_!8?G?_!33?G$#253!240?C!33?@!4?O-#1!71?O!44?A!102?@!11?O!9?@$#2!83?@!6?@?A$#3!145?A?A$#4!93?G$#5!82?GC!10?O!52?C$#7!82?_!9?!4_!50?G$#8!81?O!9?_?A!52?@G$#9!231?G$#10!31?o!187?A!19?G!6?A$#11!234?O$#12!31?G!46?G!4?OA!61?O!85?G??G$#15!75?A!5?A$#16!85?BBB@!54?_$#17!83?_!4?GG!55?@??O$#19!40?Eo!152?C!30?G!18?C$#20!98?@!8?G!39?@!20?O!11?A!7?_G@$#21!68?OC@!165?O?_$#22!195?@!49?C$#23!149?__O!4?_?!4O_!84?H!25?_!4?@$#25!142?O!119?_$#26!67?_??A!161?O!6?_$#29!42?_!108?A!41?_@!42?O!4?G!6?O!16?O!5?A$#35!100?C!6?O!5?@!61?O$#36!32?CC@??Koa???bA?G?A!57?CC@@!41?C?@!19?OO??G?_?OD_C@OCC$#37!32?B?__@_?G??@?@?E@!60?A!73?A?B??QA$#38!33?AUPqQDO_BW[WB?E@!122?O!7?OgCgCW]kH@$#42!194?G$#43!79?G!34?@!37?CCCG??AA???@@!5?GGCCA@@$#48!194?_wqS_$#50!141?_!81?C!14?O$#51!203?C@$#52!209?_?wp_?MC!22?O$#54!144?A!48?C!35?O!10?C$#55!237?@??Oooowwooo?__!22?@$#59!255?!9?_$#60!255?!10?__o?owW{MMD$#61!255?!13?o??_?O?AB@$#62!80?_!38?O!119?@$#64!68?_A$#65!72?A!6?O!19?GO!10?A!6?G!30?@!77?C!12?@$#68!190?G!30?A!24?@$#69!133?@$#71!227?A???C$#72!231?@!4?C$#73!226?@?B?A?CFFAAA$#76!45?_!21?O!28?@!5?A!6?_$#78!227?@?@@AB!5?A$#80!47?o?WCOKA?_!5?_G__!4?P!10?G!16?GG!13?G??G@??HAgT?AA???AI!5?@H!5?@!80?A$#82!102?G$#85!48?_!4?OC???G!21?@!15?A!5?C!8?O!4?O?@!6?CCGHG@L?GCA??@C$#86!46?_?OcQgogW?_GO_OG!32?@EGC??@A!4?@??GGC?SO??BECCVGACG@F???AKAGG??KIDEC$#87!112?O$#92!52?@@???A??C!4?C?GA!10?_C!16?O_!12?__??_!8?G$#93!137?_$#94!222?@$#95!227?G$#105!244?@@$#111!220?@??A?C$#112!221?@$#115!226?C!16?@$#116!217?@!30?@$#117!235?O$#118!69?G$#119!192?O$#121!68?G!26?G!12?G!61?@!55?G??G$#122!233?O??__$#123!76?WW???C!7?CO!51?_!4?O!23?_$#124!48?GA!20?C@?_!22?O???A??CG@!4?C??A!4?_!123?A$#125!149?AB!39?o}NB$#126!102?O!123?A$#128!157?A!4?@!12?A$#129!72?G!24?@!6?@A?A!4?@?A!36?G??AAA??@@@!10?GGCCEB@@!48?C$#133!249?_$#134!41?G!190?_??_$#139!32?GxGMK@ID?CE?CK@!63?@!37?@!28?__?OiOZ__B?GB$#140!220?A!7?O$#141!40?H!175?@?A!22?G$#142!101?O!50?AA@@H@@???G!9?O?GGGCE$#144!31?@!67?E???A!7?@!4?CG!34?_O!15?O!6?O$#145!72?_A!33?_!80?O$#146!242?C??A$#147!234?G$#148!32?_!44?_O!5?!6O_!52?G?_??ASG!16?_!7?_!54?G$#149!75?@!8?!6_!75?_$#153!49?@!21?_!30?_???A?O!42?@!17?__$#154!74?A!26?C!12?C@!16?@!9?G!87?O$#155!224?C!16?A$#156!72?OC!5?E!18?A?G?@?A?G!8?A!43?G!19?A!9?OA$#158!217?A$#160!78?@??G!7?@!5?O!48?O!4?G!86?G$#161!76?FFE!10?A!55?O$#162!194?A!45?G$#163!192?_W!28?C!8?_$#169!50?hEACa][s?O_OO?H``@?_?I!8?A!14?@C!6?OO!4?OOGEGGO__?AH?AOO?W??SsOQOB@G?A@AH?A$#170!93?@!63?GG$#172!158?___!28?C!54?A!8?_$#173!31?AO!7?O!32?@!29?@!4?CC!8?O!33?P!17?O?_!5?WG?@$#174!75?O!43?_!35?CC???AA??G@@@?G?C?A@$#175!44?_??G!25?G!4?_@!28?_!6?C!36?GGG??CC???AAAGGGHDEAB@!66?_$#179!31?C!44?_!27?CG!4?A!40?_?_ooOo???_!14?_???@!37?@!22?C$#180!195?CLb^\po[a?A_$#182!200?C??@!39?G??G!22?G?C???GC$#183!197?G?aINbW}|Z}z@$#185!217?G$#186!212?M^voqC$#188!229?C$#189!243?A$#194!82?O!62?G$#196!146?_???O!15?_!86?@_!15?C$#197!106?O!40?_!16?_!12?O!83?_$#198!159?C???C?EAACA!19?_C$#199!48?C!23?C!28?G!18?_!39?CCC?C?CCA??@$#201!116?G!106?@?A!7?__$#205!194?O$#206!81?@??!4CE!144?G$#207!75?C!8?!4G!56?_!23?_$#209!206?C@C]~F??G?G!21?@$#210!46?O!26?O!24?C??_!15?O!106?@!14?C$#213!235?@?C$#215!105?C???A!50?GG!11?_!6?C!6?_$#216!81?_$#217!83?G@!5?G!52?OC???G!88?G$#218!225?@???A!5?C???A$#219!101?@!18?O!23?@$#221!82?C!7?CGH!52?CC$#225!222?A$#226!82?BA!6?AFCC!52?A$#227!94?G$#228!30?@!190?C!4?O??_$#229!91?OOO!50?G???C$#231!236?@$#232!99?@!6?_@!9?C$#233!72?@?@_!4?O!13?A!10?O!37?C!47?@$#235!126?A??@!5?C$#236!240?A$#237!138?___$#238!75?G!18?C!53?_!17?OO!6?_!4?C$#239!96?_!65?OoOO!51?O!50?G$#242!51?@??@@B@fNJFf^UY]ED?w???{!22?_Oo_??g__!4?_??__!7?_l`p_ou_?__cOouUOOWOB!99?@$#243!71?C!62?_$#244!228?G$#246!30?E!193?G??O??_!7?G!8?A$#247!243?C$#252!45?O!104?C!12?G!113?A$#253!195?A!19?@!36?_!10?_!10?O$#254!97?A!132?C!7?C-#1!67?_!9?@?G!90?_$#2!154?__??O_?_$#4!160?GO$#5!81?[W!8?OOO!5?_!39?!4_!10?GGG??CC$#7!81?@A!9?GG!47?OOO$#8!91?G???G!43?O!11?O_?CC$#9!93?AAC$#10!234?@!8?A$#11!244?A$#12!29?_!109?GGG?_!6?C!4?A!4?C?O!9?A$#13!189?O?A$#14!85?_!86?W$#15!86?_!79?GC$#16!84?o??___!57?___o!11?KK{WeYm_??_$#17!84?GGG?OOO!53?__!8?A!6?C?AA??@?G$#20!33?@?C???_!31?K!28?O$#21!62?_??CA!125?@$#22!43?A???_!15?OG!177?@$#23!101?_!44?ED!6@$#25!147?A!96?O$#29!38?_??@!38?@!57?C!49?@?S!54?C!22?C$#35!110?C$#36!31?O??@?O??CGWG_!26?O!104?c_O_oEH??a$#37!37?DAH??s!131?G?CIOC_A??D??C$#38!31?_A?OobAK?TC?@!26?_!40?G!62?SGPdEBOSLK?p?G$#42!243?@C$#43!68?O$#46!215?C$#48!193?ZuS}K$#50!243?C??C$#51!202?A?G???_$#52!209?Au{R]@$#54!135?O!35?C!19?@$#55!243?G?HXV{mXJUI?@H!12?A$#59!71?@!181?_C?QCYXPJLBBBE$#60!255?!4?EICAKKC@FB$#61!255?!14?@@$#62!68?G!41?G!10?@$#64!61?_???G$#65!44?@!21?_???C?C!6?O!109?H$#68!46?_!19?C!104?O$#69!133?_$#76!67?A!39?_$#80!45?@HA@ZE?D?_IA?OAS?C!5?_C!4?_GC?G!22?O!9?A??O!7?@A!46?O$#85!45?AA@??G??W?C?iC?_?G!10?a??A$#86!46?CGCC?[Ie]OGSg[GA?EA?GC?A??oGSCgGo$#87!59?@$#92!106?_?_!21?_$#93!79?@!19?@@???@!9?@!8?@$#94!118?G?C!18?@$#95!116?C!4?G!4?C?C?C?CKEKAA@$#109!170?@$#111!170?C$#114!170?A$#115!170?G$#116!240?@A$#118!44?CW??_!15?O$#121!111?C?O!55?@$#122!239?A!5?A$#123!83?_!7?@!5?A!40?G!24?_!8?D$#124!47?O?_!12?O??A?G!4?G???@!22?C!71?_$#125!189?EB$#129!71?_!184?_$#133!244?G??GBPeshTz}CZD?C$#134!169?A?A!17?_$#135!44?G!22?@$#139!30?_GK__B?_@Q?a?W!130?aRG?HGH?QB?AxO$#140!42?@$#141!43?C$#142!40?A!135?A!11?A$#144!32?`GA???O!25?_!5?G!114?GCA!26?_$#146!149?C!89?@$#147!83?O!6?_A!52?O!6?_!11?O?_O_?O$#148!30?G!52?B!4C??G!7?C!42?@CCCO???G??A!7?A??@@!8?_$#149!84?!4BFDD!54?G?GG!13?@!10?O$#152!66?@$#153!107?@$#154!63?GC!5?A!29?G!9?@!4?_$#156!31?CO!36?G!38?@???O_!67?_?_!32?@$#160!92?A?C?@!55?C!4?AA$#161!80?C!10?C???AEC!38?O!5?GGG!6?C!4?A!4?G$#162!31?@!158?G!47?A?A$#163!188?_??C!43?@!5?@$#169!45?c??I?obo??`t?@?BOA!5?C?@??S?qOo!24?__!8?C$#170!33?C$#172!63?_!120?G!51?@$#173!30?O??Q???W??_!25?OO???O@!100?A@!9?OCA!75?O$#174!65?_!6?A$#175!97?@!13?O!27?A!48?C!53?C$#178!42?A???O!199?A$#179!34?C!138?C!9?O!53?@$#180!190?_?W?@j@r~|L_G?A$#182!240?C???@!16?O$#183!199?Aq^dftv~}P!5?O$#186!212?K`MB$#189!108?A!62?G!16?W$#194!80?G!17?OO_!34?_$#196!139?CCC@??C!5?A!4?@@!11?C?@$#197!80?A!8?AA!8?G!34?_!5?AAAB@?G??AA!4?@!5?@!76?@$#199!65?O!43?@A?_?_!25?@!100?C$#201!44?_!24?O!39?C??G$#205!191?occG$#206!83?G?OOO!58?_!18?E??P$#207!83?C???GGG!56?!4O???A!5?A?AA??@@$#209!202?OW?G?@M|HB_!32?O$#210!44?O!53?A!21?@$#214!247?_$#215!34?GGC!34?A!37?A!77?_$#216!82?@!11?G!45?O$#217!92?DD@@GGG!38?OO!11?G??C$#219!79?C!41?A$#221!96?___!57?O$#226!80?__!9?!5_!56?OoOO_GGWo$#227!80?O?_!73?Go_$#228!30?A!202?@$#229!81?AC!11?!4O!38?___!12?GG???CC!4?_$#232!44?A!24?_!52?A$#233!136?G$#235!53?@@??@???!5@??@$#237!98?@AEM]N!4][WO?AEM]Y]U]YS[[]^Y^Y]Y^ZRHBD@A$#238!31?A!4?G!100?G!6?AB??A!5?@!5?@!12?H!8?_!4?@!27?G!50?G$#239!146?@?C!9?@@!79?C!17?_!12?A$#242!47?CO?@!7?A_?K!6?A@???@J@?EFA!24?__???___?H?@_?@@!7?_!4?_?O??C$#243!101?@@O?@@!4?@@???@`!6_`_`?``@_$#246!29?O!207?A!4?A$#247!30?C$#252!242?G$#253!79?_!111?GA!72?G!5?@-#1!50?A!4?O!60?@!54?C$#2!80?eQ!10?HKwzEUAOw_?Oo_!20?__oOw{G?ACEA!16?@BFNE?PbBEo$#3!79?O??G$#4!164?C_$#5!91?CO!37?C!7?C!19?_$#7!155?C!9?C??G$#8!83?C!7?G!36?G!24?@$#9!126?O!39?C$#12!28?C!50?A!12?_!49?@!23?O??_!14?C$#14!88?O_!49?G!4?C!4?B$#15!86?C!53?C??A?D!5?_!13?@?A$#16!84?F^Rvn]g_!46?O?ws{dZy^vn{L^swoo_!8?A?`BD??B$#19!180?_!5?O$#20!28?G!23?O!9?@!7?G!41?O_!4?O!8?G!45?O!4?A?@??C$#21!60?@$#22!49?@??AAA?AAA$#23!255?!11?C$#25!255???C@$#29!48?G!60?A!76?CA$#30!182?G$#35!111?O???C!61?O!4?@$#36!29?KA???Y@?_E!30?w!51?_O!52?AA?@C$#37!34?_Wi??A!77?C???O?O!51?@@???CC$#38!29?O`OKfCEOP!31?C!54?O!49?AOO??G?AA@@@$#42!50?O!11?G!15?O$#43!128?C$#46!187?O!24?C$#48!189?G?C?WOduM$#50!74?_!57?@$#51!202?G!4?_$#52!209?MSG$#55!251?@!7?C$#59!68?_!186?A??A?CCC$#60!253?@!9?C$#62!57?G???G$#64!48?@??@$#65!39?O!9?O?G_?C!57?G!4?A$#68!170?F$#69!47?C??_??C!76?@$#73!182?o__$#76!58?@!9?C!38?O!8?O_$#80!40?g?O???@_!6?_@_?O?W??EOCb?@??_Si@AAOB!27?CCGO???G!4?A!5?CA!45?@$#82!103?@A$#85!41?G???_???A?C?@??@!9?O@A??OG?I!30?@?G!4?A!7?A$#86!42?go_?oBECC??_@?Op_!4?gaIKy!4?APSDTf!32?_?CA?O_??A??ACA$#87!44?W!19?C@!42?O$#92!111?@!6?@??C??@$#118!51?A$#121!55?C???@!11?C!41?O_???_$#122!177?_!8?A$#123!83?AG!5?BO!46?G??A!14?O_!9?C!4?O$#124!39?_???C?@!12?G!5?@!13?C!27?G??HO_!7?C$#126!129?A$#129!44?@?C!67?A??O?G$#133!252?@?@@BA?AA$#134!170?O!10?_!6?@$#135!50?@!8?A!119?_$#139!28?__?gaW@_DMH@???@!26?@!47?G!55?p?GHK?A??A$#141!61?@!123?G$#142!32?O!83?A???O?_???G!138?C$#144!38?_!4?A?C!7?G!4?C??A!8?C!40?G!4?C!56?_?C?CO??H$#145!62?A$#147!83?@?_GG?@S!46?_?o?G?W??_GO?q?HACG!8?@?@?_A??K$#148!129?C!43?@!10?G$#149!105?G!67?E??C$#153!40?C!83?G!46?G$#154!41?A!6?O???@!52?C??c!5?O!16?@$#156!30?GD!7?GA?@!8?_!10?C!46?CG???@!4?O!55?G???@G!5?@!24?O$#158!188?_!21?_$#160!84?O!80?O$#161!134?_?O??C!24?A?_??G$#162!178?_!8?@$#163!185?C?_$#169!40?OsC??O?O__!5?_???O_???GO?C!4?@C?GG!27?@AB??_@A?CG??@??CAC??D?A@$#170!47?G!5?O!5?C?_!54?G!144?A$#172!60?A!64?O$#173!29?A?A@!5?OC@!15?G!13?O!39?C!4?A!4?_??_!6?A!44?_?A?A!73?A$#174!63?@!49?@?@$#175!42?A?C!4?G!7?C???O!7?A?B!36?@$#178!55?A$#179!41?@!12?GG!46?@A!13?G!56?G!38?A$#180!189?o`hGemYHp~w|O??A$#182!199?@!54?A??@!6?C$#183!199?EAnv~|~}ZbO???@$#185!186?G??@$#186!211?AB$#188!61?C!6?O$#189!46?G!15?_!15?G$#194!79?C!56?_!19?G!14?_$#197!107?_!68?_!8?O!76?A$#199!45?A!16?O!45?A!9?C!6?G$#201!54?O?C!12?@!37?@!12?G$#205!187?K]E]Qv@@$#206!86?_!37?_!12?O_???A?_!7?ACG!11?A?C!11?O$#207!27?_!78?O!24?A!38?_??G!5?O$#209!206?@C[`JD$#210!50?G!60?C!9?G$#213!184?O_$#214!250?@$#215!28?O?S!13?A!7?G!17?a!103?C!7?C?A$#216!140?A!13?A!8?@$#217!133?@?_?G!29?O$#218!183?O$#219!45?GA!5?C!54?A!7?G!10?C?A$#221!100?A?ICG!22?O!4?A?C!25?AO!7?O$#226!79?_Xlo!8?BERFCxh|nCOCg?O_!22?g??sWPJHDBB@!17?W{g?CO??GG$#227!79?G??Cw!16?@No!22?_!7?EGO!22?@BCKwgGG$#228!28?@$#229!82?B?_!8?_!39?_!7?@!15?O!10?O???_$#231!183?G$#232!68?G???_???_$#233!60?C!10?G!38?A!11?GG???C!42?G$#235!114?C$#238!29?@!21?O!26?_@!39?_!65?A$#239!75?_!28?C!66?O!14?_$#242!43?G!15?g???O?_!9?O?G!34?@??_???!4@B??B@?@$#246!27?GA$#247!27?O$#249!171?A$#252!112?_!145?C$#254!181?O-#2!79?OVFA??GG?OOO?O!8?F??BRNUOOW!4?O??OWW[?M?@?A@@@!29?@@FGw`AK{wo_$#3!78?G!4?@!4?G!4?O???__!15?O??G!6?@!41?g$#5!81?G??@!5?_???O??@!13?G!10?O?IC$#7!83?G!5?_!6?@!5?O!24?C$#8!88?C!8?O??C!61?O$#9!75?P!13?C!47?C!22?C!17?G$#12!85?@?_!5?G@!35?_!5?A?A!19?@!15?B$#13!181?@!4?_$#14!91?A!39?C!4?o!5?A??@!4?A?G!5?a!11?@?A$#15!74?_!43?C!11?GOAW!6?A?DO?ooG?OO?oOE?O?C!9?@??C?G_?Oo$#16!82?_o__?@BBBCECEIMKCG!27?GOWS?Ke~}Ko`BCVwNvCNV}bd~Dnx{m|G[o_!7?@?AK?[_g?O_$#19!182?_!9?O$#20!69?C!7?O$#22!178?C!13?G$#25!187?@!5?_$#29!183?G$#36!27?Oa_?CQOQA@?_!11?C!17?K$#37!28?C?@?CCD@?g$#38!27?GPX_R_BgKA?KO$#42!117?C!59?@!4?C!12?_$#46!178?@F?C!27?@$#48!194?AYvA$#51!201?w@Q?@$#65!39?C!11?G$#69!39?A!9?G!20?G?A$#72!190?_$#73!184?BCKUcW$#76!49?C?O!8?O?A$#78!186?A??_?_$#80!40?Gc_O@__?@???k?gC_K?@@?_PGI_!4?G!39?@??A?@??@$#82!44?O??OG!4?O???_?G$#85!42?DA?P!10?@??A!6?C$#86!40?CAA??A?D?@??AB@??@F???CCC?B!4?F!40?EECDA?@$#87!41?GWGGCW_o!6?wG??_??O__?G!4?_$#89!45?G?G???_?GO?O?gO??GGOoO$#116!177?C$#121!111?C$#122!175?@!6?AC!5?AC$#123!73?O??I!7?O!5?C!7?A?O!24?OG!4?_???@???_O!30?GO_!5?O$#124!39?@!12?@!7?_!6?C??o?C!4?@!31?@$#126!50?@!62?@!70?C$#129!61?G!6?A!7?_!105?@$#134!184?O_!5?C$#139!27?cGE]gHg?ooOQ_!28?o@$#141!176?B$#142!188?A$#144!51?@!25?G$#145!206?G$#147!82?O???_A???@?@G??AGCGO!24?OO?C?A_@???GOCG???GI???GG?A??B@AO_GO_!6?AE@?U?[?G_?_$#148!69?W!45?G!4?A?@$#149!75?_O$#151!183?@???GW?O$#153!49?O!17?_??C$#154!60?K!51?@$#156!26?o!9?GD!12?G!10?C!7?A???_???C$#158!180?@??_!10?O!13?A$#160!73?K@?C?@!9?_???G!44?@?G!27?@$#161!74?]M!5?_G???A!12?O!24?O???C_A?@!26?A!12?@???C!4?_$#162!179?G!4?GO??@??G??_$#163!193?O$#169!40?B@?DA?FAEA???CE?AA?C???A?@?@!42?@A???A?A$#170!120?@!59?G!9?A$#171!207?C$#172!77?_$#173!26?G!10?A@!11?OA!9?B$#174!51?C!21?@$#175!39?G_!9?A!17?@$#178!181?O$#179!27?@!48?@$#180!191?AA?GDG\~~[??C?A$#182!200?A$#183!197?_??`F}hz{bA$#185!178?A?EGWO_$#188!61?_!123?G!4?G$#189!119?A$#194!91?G???OO!4?__!24?_!8?@?CO!30?GO_$#197!108?@!12?@$#199!61?O!8?A!43?G!68?A!5?C$#201!49?_!27?A$#205!190?@@DND$#206!86?@!5?@A?C!32?G??GO!7?@g?_???_@C$#207!69?_???A!35?A!63?@$#209!204?C?C@@$#210!67?O!4?@$#213!186?@!5?_$#215!27?A!8?C!13?_$#216!85?A!13?A!63?_!5?C$#217!81?O???O!9?@??O??G!8?C!12?O?G??_!9?G?_!20?G!6?A$#218!185?B$#219!60?A!6?A!4?_!45?A$#221!85?C!7?_!8?@?C!54?@!4?C$#226!78?ong?DEK??W???o_?___?@@B?MW?KOHMK?OO???OOG?C?M?CAF@A!31?AEGU@QDQ$#227!78?E!5?A?CC?GG!8?__??fw!8_o__g__c_a_`___!36?@AKO_$#229!86?O!42?A?@!5?A$#231!186?O_$#232!40?O!21?@!51?@$#233!72?O!37?A??G??C$#235!71?O$#238!26?C$#239!112?G$#242!41?O?_c!7?O_?BCOO!5?BC!51?@$#246!25?w@$#247!26?A!148?A!4?O$#252!70?@$#253!177?A???A!7?@$#254!67?G!4?G!118?O-#1!60?@!9?@??@A!149?C!4?O$#2!28?o_!37?__ooOGWG?G??MB!21?!4@BA?AFEAK?G@??___!11?_?__?_Oo?wWOo!20?B??A?@@A$#3!68?O!9?BO!17?@@@!4?A???C???G??O??_!11?@???O!4?G!7?O_!19?CCGo_$#4!126?@!41?G$#5!27?O???_!33?_!5?G??O???G?C!15?@!17?A!6?!4@$#7!80?G!86?G!5?@$#8!67?O!32?A!5?C??G!13?_!12?G!4?C?C!24?O???O$#9!98?A!12?O??_!20?@!35?C$#10!198?C$#11!219?A$#12!27?C!69?A!21?G!19?CA$#13!184?_??@A!37?C$#14!82?g?@!4?_???K?A???g!11?_!10?A??C!17?A!6?_??@!4?A?COgA$#15!82?@GAC__cGIAC?iG!4?W?O_?oW?_O_?_!7?CG?C!13?C@??@???@??E?OY?CeGcK?_A?S_?G!9?@_?G$#16!81?wUt{y\^Z?ssyqSc{[{C_sgOw?_?O_!7?CECAECIUIKAC!8?@?@??B@@?@F@BN`~yXuX`pVXjB[K!9?OaF\UC@$#17!129?C!34?O$#19!184?O!12?A$#20!26?@!42?A!67?A$#21!222?A$#22!221?A$#29!124?_!54?OC@!8?O$#35!29?C!153?_$#36!31?D??gABAOgG!27?A!115?C$#37!30?@??@??C@CS?c$#38!28?A???CACdgG_?FO_!25?@$#42!76?A@!113?_!33?C$#43!193?_$#46!213?_$#50!127?_$#51!202?@A!4?A$#52!210?_$#54!128?G???G??C$#61!192?O$#62!44?_???_!14?_!6?C!4?A$#65!67?B!113?A$#68!182?O!44?_$#71!200?_$#72!193?@???G$#73!189?@?FIQeso?O_$#76!48?A?C!9?A$#78!192?@G??Go_$#80!43?AI@Ao@??@qIPG?CCKK?GIO?G!4?A!63?A$#82!47?@??O?G@?o?_G???_??KA!4?@?A$#85!57?A$#87!43?D@QLI??Ge?CK?JO_`_GBCC@@!5?@$#89!44?CcoC??_OCOaCoHOOOoCOI?C!5?A$#94!126?_??G$#95!181?_!41?C??O$#101!125?_!54?_G$#105!133?C!48?C$#108!225?G!4?_$#110!227?O$#111!228?_$#113!130?G!50?OA!45?O_$#115!127?OO???C$#116!26?A!196?A$#118!222?C$#119!180?G$#121!126?O!9?A!45?@$#122!184?A!6?O_??@???G!21?C$#123!32?_!40?C??O?_??A!9?@!11?C???G??O??_??C!5?O!6?_?Q??G???E?@!5?C!17?AC!7?G?OG$#124!61?A!14?@!57?C$#125!180?OC$#126!48?O$#134!130?C??A!51?O@ACG$#135!196?@$#139!28?@BEIZ[PW?sBBoGO_!24?C$#141!228?G?O$#142!27?@!6?A?O?G???G$#144!28?C??O!36?G!141?C$#145!69?C$#146!196?A$#147!74?_?_o???C?A?@A??U@G!4?A!4?GC??G?_!9?A?AG?G???A?AAA!5?@!4?A??AA???[?C???@AQK?_??@!8?GO`???@B$#148!64?_!62?G_!49?_GA$#149!69?H!94?_!43?@$#151!190?B?CCOG$#153!48?G!16?O?K!63?C??A!89?G!6?_$#154!42?A?O!4?_$#155!182?G$#156!27?A!183?G$#158!199?@???C$#160!30?O!39?G!4?O!17?@!11?C!9?C??G!11?_?O?@G!4?C???C??GO!23?C_$#161!73?_!6?o@!10?@!11?C???G!30?A!5?C???_!25?CO$#162!183?@!5?CG!29?A??G??_!5?_$#163!185?K$#170!49?E!135?A$#171!212?O$#172!197?C$#173!33?_!38?C!92?___!33?@$#174!43?O!5?@!133?AG$#175!49?G$#178!225?O$#179!66?O$#180!188?O!8?@@!6?O_$#182!194?@!9?GG$#183!203?@FF^|gO$#185!185?`Q$#186!211?o$#188!191?G$#189!129?O!52?_[$#194!72?_!22?@!5?A!10?O?Ca?G@@!13?P!8?C!21?@AC??OAA$#196!125?O$#197!77?A!55?G!31?O?O!32?O$#199!50?@!23?@!123?G$#201!42?C!32?@!103?_$#205!186?k{go_$#206!75?_!13?@!5?O?_?OC??G???O!15?OG??C!4?A!13?A?G!10?G?C!4?G!10?a$#207!29?G!138?_$#209!207?ASkW?_$#210!41?@!7?OA!20?C!155?G$#211!199?O$#213!196?C$#214!202?A$#215!30?G$#217!78?O!15?@!4?A!16?A!4?O!47?_!4?I$#218!194?G$#219!61?C$#221!77?G!50?@@!15?G!27?C$#226!27?_?O_!35?_!4?_O??KCCC@!20?@@???A?@BD?@DBH@WOOO??_??@?@!4?_?_OOoO_Gw?_g?o_!17?@?E@@D?A?C$#227!28?G!45?C!4?_!22?AA???C??GG?OO?__!13?`@!4?GG!7?G!20?@AGo$#228!25?@!198?A??C???O$#229!117?@??P!50?G???G$#231!188?@AC!4?A$#232!61?@!8?A$#233!43?G!4?C$#235!55?@C!7?@$#238!200?@$#239!130?O!5?C!29?O!42?A$#242!42?@??G!5?G@_?A??BA??O@?A$#244!226?G$#246!26?oG!173?O!22?O!4?G$#247!202?_$#249!131?G$#252!41?A!142?@$#253!201?_-#1!55?G!62?G$#2!28?@?_}x{s{sWw?o_?_!14?O??g]CA@A?@!54?_O!5?ABvbe~{upu~~uzTnu?KO$#3!30?G!29?O??@!59?O?A!23?A!21?A??C$#4!29?A!92?@!6?A$#5!33?@!21?_???C!21?CO!41?A!5?CG!39?G$#7!130?G$#8!55?O!67?C!4?C!45?A$#9!25?G$#10!24?oA!181?C!19?@$#12!25?_!20?_!24?@!8?G_!37?A!9?G!20?a$#13!179?_!18?O!32?G$#14!67?G!4?_!6?C_!8?O!6?_???C??_!8?A??C!4?O!31?A?_???O??G?A$#15!26?GOc!9?C!4?O!18?@?oO???OGOC?PoO?@!4?EOi?D??OO??ZO]??AoODM?tO@AA_COO?@?E!33?OGcL??t_Cb?gO!6?G$#16!26?oGG!36?gwO[kccIbiLdw}WO?@HLD^i@KEJe|cm@u]|JhgPhInI\pTpkLvWM??_?GG!28?doJOrtIKzORFD!12?B@$#17!121?A!4?@!37?_!5?O$#19!208?G!4?_!16?C$#20!44?O!133?_$#22!195?C???_$#23!116?O???G!4?@!42?H!6?_!67?O$#25!54?O!69?@!116?G$#29!45?O!5?_!113?NGA!4?O!5?@!5?@!25?G$#35!40?C!136?O?OG$#36!36?@?@A@?@C?C$#37!41?A???GG$#38!39?@A?AHJ??O$#42!166?A!45?O?_$#43!198?G$#46!183?C$#48!189?A!4?GG__$#50!119?C!51?_!56?@!5?A??O$#52!211?GIOAI???_!22?G$#54!121?C!55?C$#55!243?GWWwooo$#60!201?_$#65!49?O!9?A!116?_$#68!48?G!4?O!63?_!60?A$#72!199?G???AG???O$#73!196?@@EEBNukcoWO?_$#76!48?C$#78!197?A@?KO?OOG__$#80!47?A?BWA?C@@C???@!171?G$#82!50?C??@??@@$#87!47?@?CAWTICEAA@@$#89!46?@??G@@A?I???A$#92!233?O$#94!120?C!110?C$#95!119?G$#97!117?O$#105!178?C!54?A???_$#108!180?@!50?ACK?w_$#110!232?A$#111!179?A$#113!231?@??[?O$#114!230?@$#115!116?_$#119!178?O???@$#121!61?@!114?O!58?CG$#122!197?G$#123!26?A!42?A!9?A??CO!32?@!5?A!51?@$#124!118?O$#125!180?A$#129!46?CG!132?_O!61?C$#133!250?_$#134!181?C!14?G$#139!37?@A??D?AC?O$#140!182?A!12?A$#141!183?A!24?C$#142!42?C??A??O$#144!39?C$#146!210?O$#147!26?CEO!34?_???c_??IP?C??A?_?@A?aO_Os`gcXA?@?G_??CA?Q??C?GII?a!4?A?_O!5?@!22?@IDOAKA?@?GcOG!7?O???BC$#148!127?O!41?Q!6?GA!29?A$#149!164?G???_G!45?@???G$#151!199?@??G!5?_$#153!45?@!126?_$#155!178?GD$#156!42?G!7?_!116?D!52?O$#158!193?A!46?C!6?G$#160!40?G!27?A!12?A!35?@??A?O!5?@!21?[$#161!25?O!32?_!5?G?C!55?CG!5?O!39?@$#162!180?OG?@!9?@!6?_!4?A???G??_!19?O$#163!182?C!11?A?C!14?O!21?_$#170!166?D!78?_$#172!173?O!32?C!43?O$#173!35?@?A!10?__!6?G!108?OOGE!25?@!21?A!27?C$#175!242?C$#178!229?A???@!4?_$#179!115?_!51?O$#180!188?GC?EoG??O?_$#182!204?A!36?C$#183!193?O?o!11?@BC!4?@???G$#185!181?_owkN?AA!32?_$#186!211?EDF[s{woO_!30?_$#188!48?@!148?C!9?G$#189!179?GCA$#193!177?G$#194!29?C!12?O??_!10?_G?_!20?@??_!34?@!5?K?Ic!21?@!23?G_$#196!119?O!7?GG!35?O!7?G!72?C$#197!47?_!69?G!46?F!8?_!29?@!44?G$#198!177?_$#205!184?Qo~|tx~xMcs$#206!27?_!42?Q??[?AID!10?IA@!6?@@??AO?C??o_C??@?GA??C!37?G?A?C??_!6?_$#207!34?@?A!15?_!7?A!57?_!4?A!4?O!40?_$#209!209?RF@?G$#210!181?@$#213!195?@!14?_$#216!62?_??C!4?@!57?_$#217!26?@?Aw!27?_!5?O!15?@COG!38?_!7?C!40?C!4?S$#221!130?_!18?_$#222!232?@?_$#223!230?A$#225!229?@$#226!29?@O@EAI?G_?o?O_?_!9?_?OOGG_S?IDA@@?@!51?@_?_wc?A?@sG[X?BHMH??HCiOH~rK!21?C@EGG$#227!30?F!4?A?C?G!13?_!5?OKA!18?AG_!36?@@!4?C?A?@!41?@E@O$#228!24?G@!180?A!21?A!5?@???O$#229!27?@!39?A!58?O??_O!39?B$#231!202?@$#232!46?A?A$#233!47?C!9?C$#238!41?G!16?C!64?@!41?_?_OC$#239!166?_!32?O!52?_$#242!51?CG$#246!204?@!30?ACG$#247!25?C$#252!197?O$#253!182?G!9?@!18?_!5?C$#254!196?A???O!4?C-#2!30?x^hO}\jRN!4?@@?@!72?Gc}wMUuXy~{ZVF^|v~~vN~l{van~$#3!38?O!10?@@!8?Q!24?CGO_!30?_$#4!60?A$#5!39?C!8?@???@$#8!29?@!9?G!6?AAA!9?_!26?C!63?O$#9!40?A???A!13?A!90?C$#10!24?X!216?G$#12!25?@!34?OA!22?O!88?A$#13!174?_??C$#14!26?O!13?G!6?GG?GG?A!13?@B?B!5?BW?AA!7?C!16?A?B???A!38?C!6?C?S??C??G!6?G$#15!26?g_!12?oW?G??_??[_?O??Sa!5?O?@??K?`g??@_?gEO?G?_!4?A?O?X?S?_B?`AO_?P?S???g_G??O!35?G?_?O??O??I_?XC@AGAC?_$#16!26?BLN!12?CK?GKKos_C_cGsi\q???[E~[jxokUSziyQzC?n|Tx[O_@AD@M~a|`KTwl]|fZ~imhPczVZ@B@_WK?@!31?oWZlfx[`yjtIjeiEwqC$#17!44?OO!66?C!55?@$#19!177?A$#20!173?O$#21!226?O$#22!202?A!17?C!13?@?G$#23!114?G!112?_$#25!228?G!21?G!5?C?O$#29!200?@!19?G$#35!175?G$#36!177?@$#42!216?@!4?C$#43!215?A!10?_$#46!177?O{QCWA?C!16?_$#48!188?@!5?X^g?O$#50!113?O!56?_$#51!202?G$#54!235?A$#55!247?@?AAAOo_$#59!250?@??CUCgO$#61!217?C$#65!208?G!13?O$#66!210?O$#68!116?@$#71!205?A!7?_??C$#72!221?O$#73!206?B?ENMFUYWkgwwo!5_$#78!207?F@??WGC_?O???O$#80!171?@!68?G$#94!114?C!54?O$#95!114?A!57?@$#97!238?@$#105!112?O!124?G$#108!237?AK$#110!236?A@??_$#111!237?C?C$#113!171?A!64?@?qw$#114!169?_G!69?O$#115!115?@!54?O$#116!206?G?O?_!24?cO$#119!175?FB$#121!168?_???A$#122!175?OG!26?A!15?C!5?O???_$#123!25?E!14?C?A!11?@???@???@!19?A??AC??_!26?O!33?@!21?O$#124!111?__C?A!54?C!70?_$#126!206?C!5?_$#129!203?C!9?@!23?_$#133!248?@@CLNIGwO__$#134!169?GA!5?C!64?O$#135!218?A!8?O$#140!207?G???_$#142!175?_?G!48?C$#146!216?A$#147!25?wCOo!10?_?A?CC??C??O?IcG@?D??_?g?aOEAO???TCLCO`??_??g???GO@??AGbICQ??GC?CO?mGC?CC???_?CA@!30?AaCQGE`?D??D??P?C??A???@$#148!45?_!159?C$#149!42?_?_!180?A!25?O$#151!204?@@!4?@???C$#153!239?A$#154!236?C$#156!174?O$#158!179?@!22?O?A$#160!50?A!7?C!24?C!33?G!31?G!22?_K$#161!39?O???A!7?A!8?G!23?@$#162!178?@!22?@!12?@!7?G!7?__!7?@$#163!173?_!30?C!10?@?A???G??O???_$#170!176?O$#171!203?G$#173!223?P!33?G$#174!174?G$#178!178?A!44?G!12?_???C$#179!202?@$#180!190?X`?_e_V~n~IW$#182!219?A!4?A!4?O!18?A$#183!200?sCC$#185!176?__?kzf|~Y??E!13?A$#186!217?@@@BBFECKGG$#189!171?G$#192!171?C$#194!29?M!8?_!45?I?GO_!30?A@$#196!113?A?C!55?OC$#197!218?C!36?A$#199!112?G$#205!184?`~~x}~e]~^$#206!27?A!18?O!4?S?OA??G???_???C???G?C!9?E!4?@?I??C?AO!9?@??O!5?_???A!33?D!4?AI???OO??o?CG@@$#207!41?_OO!72?A@!48?@@O$#213!212?@?A$#214!249?C$#217!45?A???A???@!4?W?C!21?@??_!30?_?C!30?a!24?B$#218!215?O$#221!148?A$#225!113?G!121?@$#226!30?E_Un@aSk?B??@??@?@???@!7?K@!25?_!30?_?SY@FphHeD?Bcgw_AG??Go?QBG\O?~|$#227!29?o!29?`!23?B?O!31?OW_!29?@$#228!232?__a!7?_$#229!40?@@!19?@$#231!219?G!5?_$#232!237?O$#238!43?_!130?C!55?O$#239!111?O??@!94?O!36?@!12?_$#246!24?e!215?A$#252!224?G???O$#253!253?@$#254!203?@-#1!234?@O$#2!30?t|~uvz@!22?w_!54?w[zng?FnV^~~j~n~nE}|q~nP{~~~|[~|mF$#3!37?O!21?A!34?_!25?_!27?O$#5!36?OA!50?@!26?C@$#7!91?G$#8!29?G!8?E!50?AA!23?G!34?@$#9!38?_!52?O!77?O?A$#10!24?C!192?C!10?_!13?A$#12!25?o!34?A!26?A!61?_?G!16?_$#14!26?G!12?G!4?O_!4?G?C??A!5?C???w!4?@o?_?G?O!5?O!14?_?_@?@???@!46?D_?G?@YO??A$#15!26?aHO!10?oWO??g???WH@KB?RPAB!4?B[GAO@OWGA?@A_??SOCICEBA!8?@KGEAC??H??a?AI?__?A!36?@?@?G?[CGA@H!4?@OW?A$#16!26?TuC!10?F!4_?G[j`eurwvkk{k???B[buCnu@bQHr[\A\n`eipoh{_!4?G@BFMPA`TZYyso}L~oD??W]@@!35?aFI~OHAat[ceTF?B?_?C$#17!109?A!52?_O??_???@$#19!233?_!4?_$#21!239?_$#22!171?G?@$#23!42?@@!64?O?O$#25!41?AA!43?O!132?C$#29!86?G!22?C@!61?C!64?_!7?_$#42!87?O!139?O!7?__$#43!214?@$#46!171?oW]\^X{gY?qa@!13?O$#48!193?AKhKE$#50!241?S$#51!173?__$#54!167?G!55?G!15?O$#55!241?!4_$#58!255???_$#59!254?@?@?_u{W_$#65!233?P!6?G$#68!165?G!69?G$#71!221?C$#72!216?@$#73!218?@B?B?BBAA$#81!110?A$#95!235?@!5?A$#97!167?A$#100!225?G!4K[[MMMEB$#102!238?@??@$#105!110?C@!55?C@$#108!236?O$#110!166?G!72?A$#111!109?O$#112!239?C$#113!237?OKHF$#114!164?_O$#115!168?A$#116!212?@!7?G???O$#121!237?B$#122!169?_!45?A!5?G!8?_!10?G$#123!25?G!35?G!28?@ACG!18?_GA!35?G$#124!169?@!54?G$#125!229?O$#126!217?A??C!11?@$#133!255?BE^^H?_$#134!167?@C$#135!234?_$#141!226?O$#144!42?C$#147!25?F??j!14?O?O_OC!4?G??@???@?_?@@??gCCCKA_Pa?IHOCI??@!9?A_GG_???I@O?K?@???C!36?S?S??S@P?_??AGD!4?GC@$#148!40?C?G??A!39?K???C!75?C$#149!44?@!154?C!46?_$#151!217?@??B?A??!4@$#153!110?G!52?_O_$#155!232?O???C$#158!170?_!28?A@!41?O$#160!29?_!8?O!22?O!33?_!17?OC@!33?G?_$#161!88?A!5?O!54?O$#162!218?C!6?O???_!10?O$#163!170?O?A!40?@$#170!87?go!166?C$#171!198?G$#172!89?O$#173!86?CCG_!171?C$#175!240?_$#178!222?G$#179!41?C!174?A$#180!172?_??_!10?O?Sqqo__bURHF@$#182!255??G???A$#185!174?A?eBVd~LXmnOKh?CG$#188!231?@$#189!108?_??A!54?O!61?O$#190!224?CC!4?A$#194!29?C!28?~??_!24?@??@??G!20?_?A$#196!40?A???C!45?O$#197!44?A!45?_!20?C!54?A??A!73?O$#199!234?O?GC$#204!186?@!4?A$#205!182?COOnaUjHDL^\O?_$#206!42?O???BCAO!7?O!9?GE?_!4?C!4?@?@!13?TO??DCAC!50?aA_?A???G$#207!40?@G?G?D!39?OA!77?G$#213!218?A!10?@$#216!151?O$#217!29?O!8?H!21?C!29?Cc!57?E??_!17?G$#218!222?@!4?AA$#221!119?C$#223!231?A$#226!30?IA?HGCM`!21?CO!26?@!5?_!20?_?aCOOBWOg_??S?O?Ox@AL?OmB???Ab?APG$#227!29?B!6?_K!21?@G!32?O!25?B[_!26?_$#228!242?C$#229!92?o!21?O$#231!230?@$#236!222?CC!5?A$#238!43?C!44?C$#239!41?@?A!42?_??G!22?@!141?A$#244!237?GQ$#246!24?z!189?A!4?G???O$#247!171?C@!58?__!9?@$#249!109?g!56?C$#253!255?!7?O$#254!215?@-#2!31?[xfV??@!21?^[Mo!30?AF]k{woo_!10?O}dzT~jVAo`BU}Xz~}~~v^zX~vqFNfvv~|N$#3!59?_?@!39?O$#5!92?A!10?_$#7!155?_$#8!35?OW!21?E!37?@??C??O!45?G$#9!25?A!12?C!62?G!46?_!14?O$#10!25?o$#12!29?A!32?@!30?O!16?_C!41?@?G!9?CA@$#14!43?CA??Q??O?@C?C!8?A!36?A!47?G!4?@$#15!26?CG!11?G?o@??c??aIAP??`@?C!5?AC__O?_J?A!5?@K?ho?G???o?O!8?@B??G?Q???_!40?a!6?G?A_??C$#16!26?HVtO!9?CtM}Z{IvhXpHiWrQqRb!5?@@\]NVZSNCF@BBBEBMUNpRr_W?wgwo_!4?@??DFCLHH??KH@!37?o\{o??@NED`@OWGC?@$#17!71?OG?C!12?C???C!15?@!56?A@$#21!237?@$#23!77?O!11?A!69?C?G!78?O$#25!73?O!33?A$#29!88?@!67?_!76?@!10?_!18?@$#42!74?_!157?@!5?@$#46!165?_ow{}h!4_oOMj^[!52?A$#50!109?@!48?G???C$#51!173?O$#55!234?A?AEENNF^ZN^lfF{_M_$#58!255?!6?_O$#59!241?G??O!5?O?KMeOAI`r~^N$#60!172?O$#61!172?@?C$#65!171?CA$#68!157?O!4?@$#80!107?G$#94!160?K$#103!107?O$#105!158?O??C$#111!108?A$#113!162?A@$#114!107?_$#116!165?GCA@$#121!107?CG!54?A$#122!164?O$#123!29?C!33?CO!26?A!5?@??C??O!45?@?@$#124!161?A$#126!171?I??B$#127!173?G$#133!243?C??QWwAMoQoWm{t]K$#134!108?O$#135!234?@@$#142!165?O???@$#145!194?A$#147!26?o?Ag!9?qI??_??G?CCC??GGGkO!6?GA?_gC_???A!8?CcCC_!4?G!6?A??GAOcE??OUA!37?E??G_AE?@???_$#148!73?G??CG?_!6?@?CCC!15?O!53?O$#149!71?_!6?O!164?_$#153!164?@!8?A$#156!76?_!10?@!168?@$#158!164?_!30?@!42?G??O!7?@$#160!25?C???@!5?_??W!19?o!4?G_!26?@??_!9?_!7?@!40?O!8?_$#161!25?@!12?B!59?A!53?C!11?G$#163!163?_$#170!73?_?_!90?GCA!66?C$#172!76?O!11?A$#173!72?_?OO!13?@!103?C!56?@!12?G$#175!255?!8?A$#176!108?@$#178!236?@$#179!77?_!114?O$#180!189?g?U??@$#185!170?U@??O?npS_b~bz[G??E$#186!175?F!59?AC$#187!174?G$#188!173?D$#189!157?_?O$#194!36?C!21?@!34?G!18?A!35?C!4?A?O$#196!108?_!51?A!94?@$#197!78?_!30?A!46?O!94?@$#204!171?O$#205!175?G!6?[Cbv~~xV~HNB$#206!26?A_G!10?@?@??@P?C??_Ce?C??G!8?@!5?@!4?C??p??I?GY?G!14?@A!46?A!6?A!6?A$#207!75?C??GO!81?@$#209!245?_$#210!172?G$#211!172?C$#214!191?_$#216!36?_!115?A$#217!38?_!19?G???A!29?C!18?G!36?O!5?C$#221!30?A!4?A!62?C!13?C@!8?Q$#226!30?@bEWg@?A!22?boG_!29?DG@Q??G??_!9?g?YCi?Sg|K?Kh@eC?@??G_Ce?GLwoWGG?AoF!6?O$#227!30?{!4?KB{!24?CO!30?O_?A??G!10?o!9?BKo!23?wB???@CG$#228!24?B$#229!92?@!60?G_$#238!74?G?G!10?A??B!15?_!51?_!73?A$#239!72?O??G!154?@!6?G$#244!159?G$#247!25?G$#249!108?C$#253!231?@!31?C-#2!32?^D!26?E~vE{o!31?@FE~~LKMC??o?_k}|m|~vw`l~ciw`C^zax|nv|z~vx|v^~^FbW$#3!59?@$#4!36?W!110?A$#5!36?C!68?O?_?O!46?C$#8!34?C???C!20?O!35?@$#9!66?G$#10!25?_$#12!26?E??G!4?O!23?@!37?C!51?@!8?@??@$#14!28?A!10?W!10?O??O?C??O!9?a???_!18?_$#15!27?GW!10?ATh?Q@Ag?WjA???pQAIg!9?O?@_?_?O?ogGB`BOj??IG?gB@?g_O!11?@B!38?G@B?O!5?@$#16!27?vc!6?C???DiUzhmlRKfOL^tnEg{t!8?BFLr}WOOo?o?O_{IwjSl{dvnDSy|A[GO!10?A!39?CCC``PGG???@$#19!155?_$#22!162?@$#23!76?CA!28?@!44?C??C!101?A$#25!75?C?@!70?O!108?A$#29!72?B???@!74?O!9?A$#40!158?_$#42!73?@A!185?@$#44!161?C!4?@$#46!157?_OwWw}~~~}~~~x~~^vXwc\U_U!4?OGCA$#50!74?@$#52!250?@$#59!254?@??@@$#68!149?_$#80!152?C$#81!149?O$#94!153?C$#97!107?@$#105!148?_??G$#115!150?O???A$#116!158?C$#118!147?_$#121!150?G??A$#122!157?G$#123!26?X??E!5?@!22?A!6?@!29?A??_!54?_?C??A$#129!249?@$#133!251?@@@?@@??@$#143!156?_$#147!26?_?@@!4?_y???_??CCOOCr??__I?G?@?C!7?CO?K!5?_???O?C?C?ABO??OGCAD?__!11?C!38?AA!4?O$#148!73?G??G?C!28?G!45?G?A$#149!71?B??GG??A$#156!255????A$#158!185?_!4?@$#160!34?G!30?A!31?G!12?@!44?OG??A$#161!29?O!37?_!37?_AO$#162!156?O???A$#164!160?c$#170!73?A?A$#171!157?OG$#172!155?@!92?@$#173!73?CC?A!29?o$#178!159?C$#179!72?C$#185!170?E??_GeFZah^he^SSDC$#194!34?A?@?G!20?G!5?CO!29?A??_!5?@!4?A!46?A$#196!254?A$#197!77?C@!28?C!42?_???@$#199!107?A$#205!182?X_jJIBB@$#206!49?C!5?@!11?G!11?C?OC??O???OA???O!56?A$#207!71?CG!4?G?B!26?C!42?G??A$#210!152?G$#216!147?G$#217!29?_!8?B!20?_!38?O!9?CG!37?O!8?@$#221!30?CA?O???G!22?_!5?_!29?@!12?_!13?@C?g!19?C@$#226!30?w@_I??_o!22?X?GxAG!31?A?X??qrpI??G?OR@APA?GF]Q?ZS?QB?C\EAOGAC?GEAG_??GO!10?A$#227!30?B{?_@??Fo!20?E!4?@!32?CG!11?K!13?BKO_!15?_oKB!10?C$#228!25?C$#229!36?A!109?_C$#238!106?G$#239!255?A$#246!25?Z$#247!154?_!6?@$#252!75?@-#1!70?_!16?O!4?G!54?@$#2!30?LC!5?q!23?AoLMnK!34?A?B@??B?wc|OEmv^L|~EpZI~~v[o@BBNN^?^MFFB??O$#3!100?@?O!27?C!13?O?G$#4!36?A!107?@$#5!29?S!6?C!30?A!33?C??_$#8!29?@?O?A!5?_!27?@!32?A$#9!25?G!75?O!41?G!8?@$#10!25?@$#12!33?W!5?A!60?C$#14!33?_!10?@???@G!21?G!8?GA??@!4?@E???C$#15!26?EC!6?O!6?GGKO!5?_FGGO??a!14?A?O?WAOG?CGM?@???C??@!4?_G!49?A@$#16!26?GJ@!5?mg!4?yat`k}q~mqJw`fltRP^k_!8?B@DH\I^ATDDRWR@CMHMFA_cab?FDDFGG!48?A@$#17!88?_!58?A$#20!32?_$#23!77?_!14?OO!11?C!38?A$#25!89?G?O??O!51?@!7?@$#29!85?O!62?@$#32!146?_?O?G!27?O$#40!147?___Ow{km~|KwGO!4?O$#42!72?_!6?_!15?O???_$#44!162?OOG?CG$#46!153?OO?ArFrn~nnvnzv~~~|^~yzKYJJ?B?@$#50!90?O!5?G$#54!90?G$#68!28?_!65?G$#80!97?O$#94!98?O$#95!85?_$#101!83?_$#114!26?_!57?_$#116!132?_$#121!80?_!20?_$#122!150?C$#123!28?W!10?@!20?O!7?A!76?@??C?A$#124!93?G$#134!73?_!4?_!8?_!43?_!19?C$#141!147?O?G$#143!149?O_$#144!183?A$#147!26?@?C!5?@F!4?@TAAA@L??@S?UOAI_G?Q!8?@KMASAD?@??QC???I?E??_?B?Cb_a??A!47?C???@$#148!27?O!40?_!71?O$#149!68?O!35?S$#153!81?_!4?_!4?G!8?_$#154!82?_!5?O$#158!181?C$#160!25?C!6?OC!5?G!28?C!36?GA!32?O???A???G?C$#161!39?C!19?@G!38?@$#162!24?_!119?_$#163!152?A$#164!159?C$#170!153?A$#171!177?_!6?@$#172!141?G$#173!29?___!72?GA!37?C?A$#178!145?_$#179!67?_$#185!171?A_?DCrDCCF?A$#189!71?_!14?O??O!5?GO??O$#194!29?AO??@??O!24?_!4?_O!33?G!28?G$#196!69?_!76?A$#197!26?O!42?O!5?__!21?_!6?@@$#205!182?@$#206!28?A!6?O!4?C??O!4?OC!6?KC_!11?OO!4?CGI??@C!4?@??@?C!4?A?C??_$#207!83?O!4?G$#216!36?_!67?A$#217!39?O!20?C!42?G!36?GS???C$#221!31?@!6?O!22?G!45?gG!20?A?G!6?O??_$#225!25?_$#226!29?GAI!4?@L_!22?DNqpORK!33?@NC?o[CpEZAnxPG_qA?xMct??GaKw?C?O_~_PGgcBP?GGC$#227!32?N!5?N!21?BO!44?_OE@!17?@BC??O!4?__???A@$#228!24?G!118?_$#229!36?G!31?G!64?_!8?_??O$#238!25?O!58?O!57?C?C$#239!74?_!22?G??O??o!38?G!37?G$#246!24?O!105?oO$#247!25?A!120?O?G??A?@$#250!27?_-#1!35?G!18?O???G!21?@$#2!29?A?A!6?G!23?@@?GWCco!5_!18?GWKc_s[WWgOscSEMBEACF@JMEMGE`|}@|s^~$#3!68?W!24?C!9?C$#4!68?@$#5!72?O!30?@$#7!70?A$#8!28?A??@A!29?o?G@!30?A???A$#9!24?C!7?G???A!4?_!41?O???G!14?A$#10!31?G!98?B???@$#12!24?AC!4?@?O!5?@??O!20?G??C!4?@!6?O!4?O!7?C??A!8?@$#13!86?O!43?_$#14!26?A!6?GA!5?@!17?@?A!18?AG!4?C?@$#15!33?@!7?@OLOAHW?AAH?@???o?P!14?A!4?G?G?G?@!4?B???@?@$#16!25?A!7?ADB!5?EDON[EAJLKEBAd@bAOap_!10?EIGKGGKCCCMCIG?EEB?B?@???@?@$#17!35?C$#19!90?GO!46?A$#22!91?_$#23!36?O$#25!28?@!9?A???__!20?CA$#29!26?@!17?_!7?_$#32!131?NYUw{G$#40!145?guT@I|!5~ecO!5?O??_???G$#44!161?O?GA$#46!156?XZn~~n~vl~~^^^NFB?B@$#50!27?@!8?C!18?O$#54!45?_!7?G!7?G!20?@$#68!34?_!24?C$#81!36?G!14?O$#94!79?@$#95!34?O$#97!35?O!21?G$#105!48?_!6?G!19?@@$#114!33?_!15?_??O???G$#115!74?@???@$#116!23?E!15?OO!42?_!5?G!40?C$#121!32?_!24?C$#122!91?G!38?W!5?AA???@$#123!26?C!12?@A!30?CG!5?OO!6?G$#124!54?G$#134!33?O!15?O!6?C!14?@!11?@$#137!176?@$#141!87?O!45?@!8?@$#143!134?C?_S?c?wwa~VHi}tA$#145!170?O$#147!27?E?@!6?_!4?GAA??OC??@??CA!6?O!11?C??C???QQ??C?F?@C??B??@??@?@$#148!48?O!4?_?C$#149!67?@$#153!51?_!6?C$#154!47?_!25?@$#157!86?___oo$#160!32?C!5?C?C!20?A??A!10?O!15?C??A!6?A$#161!37?G!25?C!12?O$#164!131?ocg??Sg{W{EE[$#171!85?_!46?@?A!38?C$#172!66?@$#173!37?C!46?_???O!79?_$#178!135?A???A$#185!172?CB$#189!46?_???O!8?GK!11?@!8?@$#194!32?@!6?A!33?O!18?C!4?AAA!37?@$#195!135?@$#196!34?G!49?@$#197!25?@!9?_!20?O!4?C!110?G$#206!33?C!8?G??@?@C???C??a?@a!12?A??C??CA!4?A?A!15?@$#207!37?A!28?A!8?AAA$#214!140?A??@$#216!28?C!11?G$#217!36?@!24?@!9?G??O!20?A$#221!31?C!30?C!4?_???O???_!53?W$#222!50?_$#224!53?O$#226!29?CE!6?P?C!22?AqpoCIAFS!22?ocoW[G_ccOgHYjxp{x|zw}spxpvx]A@}AJ_?F$#227!66?_O?GG!5?!7_!9?W!9?CAA@!23?_!6?@?@$#228!25?G!5?O$#229!37?_OG!52?_!46?@$#238!52?G!122?A$#239!63?G$#246!26?!5G_!6?_!101?@$#247!24?@!59?OO??G$#250!77?@-#2!47?OooOWk{CGGCKC???@!5?@@??B@AAMAN]U!11?Bf]yvmUB@B!19?@@EK~zi$#3!50?C!13?A!17?O$#4!66?!8_!31?_?WWC?KC???WW__$#5!107?__ooowwwo__$#6!46?O!45?@!36?O$#8!56?@$#9!32?O???@$#10!31?\?O?CA!6?C?G!46?C$#12!33?G!10?CC!8?@!6?@$#15!34?B@!7?A?A$#16!33?E!12?A!4?@$#17!44?A$#21!130?A$#32!131?fvz~sO__!12?K$#40!144?ATzCAQi@??@!6B@?@@$#46!161?A@$#50!48?@$#68!42?@$#97!45?@$#105!44?@$#111!43?@$#116!41?@$#122!83?~!8?G$#123!48?A!4?@$#134!33?@!96?O$#137!151?_$#141!92?_!37?C$#143!135?G?QA?~]FKxiCz|lT!7?C$#145!154?A!8?A$#147!32?M!14?A!4?@$#153!32?@!14?@$#156!91?A!38?_$#157!84?!7~w$#160!50?A!4?@$#161!34?CA!13?A$#163!92?O!37?@$#164!131?WGC?BnL\~?`wrC!6?A?@???C!4?A??@$#171!91?C$#172!91?@$#173!152?@$#178!130?G$#194!52?A!4?@@@??A$#206!50?@$#214!151?O!7?C$#217!46?C!4?A!8?@?@$#221!64?@!17?n!10?G!12?_??GG!4?G$#226!47?gGGgcO?wuuyqy}!4{}^^^]]^^[}||p|o`h!11?CW`DGPh{}{~~^^FFBFBB!5F^^~~}}xr?CT$#227!46?G?CC???A!7?A?A?@!27?O!35?B$#228!31?_!12?G$#229!47?C!6?A!38?_!35?K$#238!49?@!106?C???C$#239!166?@$#246!31?A_?G??@!4?A???_!45?A!36?_$#249!46?@-#2!48?FTtFBN!27?@!13?yB@!28?@B$#3!82?O$#4!57?_GC?A?@@!8?@@??CKO_!20?o?D?@!13?@BAO__$#5!58?_w{[]ME!8FMM]{wo_!22?_w{}^NFF!6BFN^}{w_$#6!93?@_$#9!128?A$#10!46?@$#19!93?O$#23!151?A$#32!130?}fsoZyC$#40!144?PA_`_o^$#116!83?W!9?C!35?B$#122!83?F$#140!128?_$#141!129?O$#143!137?`GCT?uFm|^]^N_$#145!151?@$#146!127?_$#148!128?C$#156!92?A$#157!84?!8~{$#162!93?G!35?C$#163!129?G$#164!131?WJNcDz]vzi~Hw$#171!130?@$#172!92?@$#178!93?_!35?_$#179!128?O$#194!127?O$#195!66?!7_$#221!47?@O!9?O!23?N!19?W?A!16?C$#226!48?GiIw{o~~~^FBB@@!12?@BBBN^}_!11?FD{}~~~NFA@!16?@N^^~}K$#227!47?A_!45?G$#228!47?_$#229!47?C!13?__oww!7Woo_!18?O!11?_oww!6{wo_!9?@$#238!128?G!22?C$#246!46?AW!45?A$#247!83?_-#2!49?@E@$#3!49?C$#4!54?_KA!25?A!16?wN@!21?@NG$#5!55?o{~FB@!16?@@F^}w!17?o}~^B@!13?@BN~}o$#6!48?@$#9!61?O$#10!49?_!33?@!11?_$#12!60?_??G!6?GG??O$#19!62?_!10?O$#21!128?O$#25!84?_$#28!84?C!9?_$#29!126?O$#32!129?{^Nvw\b`P!12?C$#35!127?G$#40!144?cLhkQA@$#116!94?A!33?C$#119!126?_$#122!128?A$#129!127?A$#134!94?O$#137!84?G!65?G$#140!67?___!56?G_$#141!94?G$#143!136?G?DPWf[WZqURl|A$#146!64?G??GGG$#148!62?O$#149!150?_$#157!84?@!8~}$#160!126?C$#161!72?G$#162!128?G$#163!94?C!33?@$#164!130?_oGFa[UmymfWbf$#171!84?A!44?A$#172!127?O$#173!84?O!44?@$#174!127?C$#178!128?_$#179!127?@!22?O$#195!62?KEEF!6BFEM[W_!29?ow{{}}}{{w_$#196!61?_$#197!63?!4oOOOooo__$#207!65?GG!8?_$#214!93?@$#216!66?!6C?G!51?_$#217!76?_$#221!81?@C!12?A!30?A$#226!49?Ax}~~^B@!25?@!12?@~~~F!25?V@$#227!95?C$#228!48?GO!33?_!11?O$#229!49?G!8?w{]NB@@!8?@@BF]}w_!14?G!7?_{}~NFBB@@@BBF^~}{o$#246!48?E!34?]!10?@-#3!97?O$#4!53?OA!43?oD$#5!54?{~N!24?@F!16?w~~B!19?B^B$#6!50?A$#7!56?O!26?A!39?_C$#12!57?GA!19?A?O$#19!60?{B!15?A[_!15?A!30?_$#20!126?O$#22!84?A$#23!66?O!5wo$#25!84?@$#32!128?{~~umKKPDA!11?G$#40!144?O[FjW$#119!124?_{B$#122!95?@O!30?E$#134!124?OA?_$#140!64?wCB@@???ACO_$#141!84?K!42?O$#143!134?_??CC??MR~nbwSfF$#146!59?@!19?C$#148!57?oC!66?@$#156!126?G$#157!85?!10~o$#161!56?_!20?@$#163!84?o!11?_!30?H$#164!131?HPrRmyxz~~pk$#171!128?A$#173!128?@!20?O$#174!126?C$#179!95?C$#195!78?@A???@!12?C!8?w}~NBB@?@BBN~~w$#196!58?w}B!15?@??W$#197!61?{~~FB!5?@@BN^}{_$#207!80?_!43?G$#214!95?G$#216!57?C!22?G!27?o{{}~}{{o$#221!54?@!44?A$#226!51?F~n!43?NN$#227!50?@G!44?@$#228!49?@O$#229!51?O!5?B@!20?@F}w{!12?A_!4?{~~F@!12?F~~{$#238!65?wKEA@BACW_!74?_$#239!66?_?CECCG_$#246!50?K_!44?G-#3!52?@!45?C$#4!98?B$#5!54?F!44?~~B$#6!52?C_!43?@O$#7!122?C$#10!51?@G!45?_$#12!81?AO$#17!123?@$#18!148?_$#19!60?^!18?Bw!16?G$#20!125?G$#23!66?!8~{_$#25!85?_$#28!85?G!11?_$#32!126?_}~~~Zjv{E[G$#40!145?T?k$#119!122?_{~@$#122!84?A!12?C!27?_B$#123!54?_C$#134!122?O???O$#140!64?~!10?@[_$#141!126?G$#143!133?G?H?edCZK~b~i~RB$#145!148?O$#146!122?G$#148!56?]~_$#156!85?O!39?C$#157!85?F!10~{$#160!54?O$#162!84?@$#163!125?OC$#164!131?cS?BobPYzcr?[!4?C$#171!127?@!20?G$#172!123?A$#174!125?A$#178!96?@$#179!97?O$#195!84?_!19?w~~@!9?@~~}$#196!58?^~_!19?Fw$#197!61?~~~!12?B^~{$#207!55?w`!24?C_$#214!96?A$#216!81?@G!24?}!9~}???_$#217!55?A$#221!53?G$#226!53?F$#227!52?AO$#228!51?AO$#229!54?G@!26?F~!14?G??{~~F!15?@^B$#238!65?h!9?U_$#239!65?U!8?BG$#246!84?W!12?A$#247!84?C-#5!99?@F$#7!84?@$#8!84?G!34?_$#9!54?C_$#10!54?G$#12!54?A!54?_?__$#13!85?G!38?O$#17!55?G!28?_$#18!147?O$#19!61?C!18?@?_!16?O!24?C$#21!125?A$#23!66?F!9~$#25!99?_!25?C$#32!125?o!4~z~ZDl~kA$#36!123?O@$#40!144?O`e$#116!85?_!13?G$#119!120?_{~N$#122!85?O!38?G$#123!55?O$#134!120?OA$#140!64?C_!11?E$#141!85?A!12?A!25?_$#143!136?Q{_Ie~SOn]XB$#144!147?G$#146!83?C!26?_$#148!57?^~_!23?G!36?G$#157!86?!12~w$#161!83?AO!23?_$#162!98?@!26?@$#163!85?C$#164!130?C?cyQ?@@^tX?jn$#171!125?G!21?C$#172!124?A$#173!98?C$#178!85?@$#179!123?_$#194!84?E$#195!103?w~~~!11?~^B$#196!59?^~w!19?~^o$#197!61?B~~z!12?@~~}$#206!54?@$#207!55?F~_!63?@$#216!83?@!23?~!6^!4~??C$#217!113?_$#229!99?AW~~F$#238!65?^o!9?Nw$#239!66?G!9?o$#246!53?BO!44?C_-#10!85?@$#12!85?O!20?@$#17!56?A$#19!82?A???o!13?A!18?@$#22!86?G$#23!68?BN!5~^!36?A?A$#25!123?C$#28!86?@!16?__!15?O$#32!98?`i_!20?o_o}!6~Nz\~Zt!8?O@$#40!144?K$#44!120?GG$#116!100?@!22?A$#119!120?BBB$#123!60?OO$#129!119?A$#134!67?_$#137!102?_??_$#140!66?KO$#143!135?C?@gGkMZhrN$#144!83?_!21?O$#145!62?O!19?_$#146!104?C!10?@$#148!58?BF!24?^_!31?C$#149!102?O!8?G$#156!101?O!20?K$#157!87?!11~]SW$#161!57?C!27?G!16?GG$#163!123?@$#164!131?oCa?_I}VvRpcU$#171!66?_!32?@?_!20?O$#172!65?_!20?C$#173!86?A!13?C???O?_!4?CC???A?A!5?@!20?_A$#179!63?O!20?_!16?G!16?CC$#194!101?A$#195!103?FB@!11?@$#196!60?FFF!18?^\^!20?GKM@??G???@??A$#197!60?GGGN^^!12?~~~_!21?O??OMNNFB@F?C$#198!120?CC$#207!56?@BC!5?_!40?A$#214!115?A!7?G$#217!116?@?@$#229!101?@F$#238!66?RMw_!6?w~!42?_!25?C$#239!67?@CO!5?_F!39?C$#246!101?C$#247!55?@!29?E-#18!69?A!6?G!30?_!14?_$#20!81?_$#23!68?@?AAB@??A???@!63?G$#25!74?A$#28!77?CC???A@!22?@!15?O$#32!80?_??OG!7?OG??_?@ao~wO{}w!14?@N~^N!4^NEloYVBG!5?_$#33!87?O$#40!90?_!43?_?_?_?_$#44!124?_$#49!86?O$#51!131?_$#53!85?_!5?_$#61!129?_$#134!69?@$#137!78?!4A??@@$#140!77?@$#143!136?OFBPFIV[B$#144!79?@$#145!76?C_???@$#149!145?@$#157!77?Ggw[[[KCEMN^~^^NFNN^~}\N?EmA@E$#164!125?O?_???HQNDGKo[mWTgB$#165!85?G!6?_??O$#171!77?OOC???AA!17?@@@!16?A!22?C$#172!77?A$#173!70?@??A!8?@???@$#179!71?@???A??@$#181!94?_$#184!88?_!4?OO$#187!126?_???OO$#200!84?OO__!37?_!4?_!4?_$#202!93?_$#203!95?_$#204!128?_!12?_$#238!76?@!7?_$#239!67?@!6?@@!45?C-#20!105?G$#23!94?@!12?@!27?A$#28!104?C$#32!87?@!12?@@?@@@F!25?@$#40!136?@$#46!137?@$#49!97?AA$#52!141?@$#53!98?C$#61!138?@???@$#137!97?C?C!7?A$#143!97?@$#144!124?@$#145!88?@!41?@??@$#149!96?C!4?C$#156!125?@$#157!102?B$#158!139?@@$#164!101?A$#165!96?@?@$#171!107?C!23?@??@$#173!106?G$#181!99?A!5?C$#184!95?@A??@$#200!104?AA!29?@$#202!100?A$#204!103?A$#238!78?@$#239!100?C!42?@-------#0!255?!33?\ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_rm/24x.symbols b/fastfetch/logo_rm/24x.symbols new file mode 100644 index 0000000..65ec395 --- /dev/null +++ b/fastfetch/logo_rm/24x.symbols @@ -0,0 +1,16 @@ +[?25l ▗▃▂▂▁▁▁▂▂▃▖▁   + ▖▏▆▇▇▇┇╷▗┈▗   +  ▌╶▁▁▂╻▃╴▖╶╾   +  ▆▖▇▇╵▆▆▁╶▃▇▄▂▅▆▅▄▃▂  +  ▗▆▆┵╺┉▄▖▆▗▂▄▁┻╸╶▘▝▏▌  + ╶▎▁▁▗╸▅┳▁▖▆╶▄▃▏▁▁▁▃╴▉   + ▊▝▁▊▝▎╶▉▏▆▚┊▎▅▁▅▚┊━▇   + ▋▍▉▄▖╷┊╼┻╸▁▊▃▃┏▂▆╴▘▝▝▃╸ + ▍▘▁▍▇╵╴┉╴▃▃┛┈▍▇▅▝▃▅─▗▆  + ▖┊▆╴▊▝┈╴▆▁▃▂▅▘▆▄▂▂╴▇▄▘ +  ▎▂▁▃▘▝▇▅▇╴▖▗▆╺╶▝▁╷ ▇   +  ▌▎▉▖╴▁▉╴╴┈▗▅▘▂▅▇▅▄━┻  + ▆▅╹╴▇▊▇▃▊▇▗▅▆  +  ▝▁▝▏▂▃▘▋▍  +  ▇▇▆ ▇▇   +[?25h \ No newline at end of file diff --git a/fastfetch/logo_rm/32x.sixel b/fastfetch/logo_rm/32x.sixel new file mode 100644 index 0000000..d31988a --- /dev/null +++ b/fastfetch/logo_rm/32x.sixel @@ -0,0 +1,2 @@ +[?25l[?80l[?8452lP0;1;0q"1;1;320;438#0;2;5;5;7#1;2;6;6;8#2;2;6;6;9#3;2;6;6;8#4;2;7;7;9#5;2;8;7;10#6;2;10;9;12#7;2;17;8;11#8;2;27;8;10#9;2;14;14;18#10;2;17;18;22#11;2;23;15;20#12;2;31;17;20#13;2;21;22;26#14;2;22;22;26#15;2;21;23;26#16;2;22;23;26#17;2;23;23;28#18;2;24;33;34#19;2;34;26;29#20;2;36;31;36#21;2;32;34;39#22;2;40;35;38#23;2;35;38;43#24;2;35;42;52#25;2;40;41;48#26;2;50;43;48#27;2;34;48;46#28;2;44;48;55#29;2;46;49;57#30;2;46;50;58#31;2;47;49;58#32;2;47;50;58#33;2;47;50;59#34;2;41;54;52#35;2;46;51;59#36;2;43;54;68#37;2;45;56;67#38;2;46;56;62#39;2;46;56;63#40;2;47;56;66#41;2;47;57;70#42;2;49;50;57#43;2;49;54;61#44;2;48;57;66#45;2;48;58;68#46;2;49;58;65#47;2;49;58;69#48;2;50;60;67#49;2;50;60;68#50;2;52;55;61#51;2;51;60;68#52;2;52;60;66#53;2;52;61;69#54;2;55;55;62#55;2;70;54;56#56;2;54;61;67#57;2;63;61;65#58;2;52;63;60#59;2;55;62;67#60;2;55;62;68#61;2;54;64;72#62;2;57;63;68#63;2;58;67;74#64;2;62;66;71#65;2;67;67;70#66;2;63;72;70#67;2;68;76;81#68;2;73;74;78#69;2;74;78;82#70;2;67;83;74#71;2;76;83;87#72;2;76;84;88#73;2;76;85;89#74;2;82;74;80#75;2;86;80;81#76;2;77;84;89#77;2;84;83;85#78;2;78;85;88#79;2;81;85;87#80;2;81;85;87#81;2;86;85;85#82;2;81;85;87#83;2;82;85;87#84;2;90;85;85#85;2;81;85;87#86;2;81;86;87#87;2;82;85;87#88;2;77;87;91#89;2;82;86;87#90;2;74;90;86#91;2;81;91;94#92;2;82;86;87#93;2;83;87;88#94;2;84;87;89#95;2;87;88;89#96;2;85;90;93#97;2;89;90;92#98;2;88;92;95#99;2;89;94;95#100;2;94;89;90#101;2;94;93;93#102;2;93;94;95#103;2;96;94;94#104;2;94;95;96#105;2;95;96;96#106;2;97;94;93#107;2;96;96;95#108;2;95;96;96#109;2;96;96;96#110;2;93;93;93#111;2;84;68;66#112;2;84;74;83#113;2;21;8;12#114;2;26;9;11#115;2;25;34;30#116;2;36;26;29#117;2;36;39;44#118;2;36;41;48#119;2;32;10;11#120;2;15;15;19#121;2;56;56;60#122;2;61;53;68#123;2;60;60;64#124;2;54;61;67#125;2;88;77;75#126;2;78;80;83#127;2;38;32;36#128;2;32;35;43#129;2;25;26;32#130;2;26;30;34#131;2;42;41;47#132;2;46;42;48#133;2;26;22;26#134;2;21;22;26#135;2;33;36;42#136;2;38;35;40#137;2;47;45;40#138;2;41;47;56#139;2;47;55;67#140;2;49;51;59#141;2;90;94;95#142;2;95;87;87#143;2;74;76;80#144;2;73;78;82#145;2;78;86;89#146;2;71;87;95#147;2;78;87;91#148;2;82;86;87#149;2;26;18;22#150;2;31;19;23#151;2;45;55;64#152;2;45;56;67#153;2;81;91;92#154;2;82;85;86#155;2;94;90;88#156;2;92;93;94#157;2;36;29;31#158;2;36;31;35#159;2;45;56;67#160;2;46;56;63#161;2;70;74;78#162;2;72;74;78#163;2;79;87;89#164;2;73;89;89#165;2;46;57;70#166;2;47;57;67#167;2;49;59;65#168;2;49;58;72#169;2;54;54;61#170;2;55;57;63#171;2;48;57;68#172;2;48;58;67#173;2;84;91;95#174;2;89;90;91#175;2;48;58;69#176;2;49;58;65#177;2;68;72;76#178;2;68;74;80#179;2;22;15;20#180;2;22;19;24#181;2;49;59;70#182;2;50;60;65#183;2;87;89;89#184;2;85;90;92#185;2;37;42;52#186;2;40;43;50#187;2;67;65;69#188;2;70;67;71#189;2;16;8;12#190;2;15;10;13#191;2;6;6;8#192;2;49;56;62#193;2;47;57;64#194;2;60;67;75#195;2;62;65;70#196;2;6;6;8#197;2;6;6;10#198;2;42;36;40#199;2;36;38;42#200;2;54;61;67#201;2;57;61;66#202;2;59;63;57#203;2;54;62;67#204;2;66;82;70#205;2;74;82;87#206;2;84;81;86#207;2;76;84;89#208;2;75;92;84#209;2;80;90;95#210;2;41;53;49#211;2;43;54;61#212;2;77;84;87#213;2;80;83;85#214;2;96;96;95#215;2;95;96;96#216;2;43;47;54#217;2;44;48;56#218;2;85;83;87#219;2;77;85;89#220;2;80;85;87#221;2;81;85;86#222;2;89;91;92#223;2;86;92;96#224;2;6;6;8#225;2;7;7;10#226;2;9;8;9#227;2;9;9;11#228;2;10;10;12#229;2;16;17;19#230;2;16;18;21#231;2;93;94;95#232;2;95;94;94#233;2;45;52;60#234;2;46;51;58#235;2;43;53;65#236;2;43;54;65#237;2;49;52;60#238;2;50;54;61#239;2;59;63;69#240;2;58;65;72#241;2;63;70;70#242;2;66;71;76#243;2;97;94;93#244;2;94;95;95#245;2;5;5;6#246;2;6;6;8#247;2;52;52;58#248;2;52;56;62#249;2;83;87;89#250;2;84;87;88#251;2;89;92;94#252;2;89;93;95#253;2;95;96;96#254;2;95;96;96#0!255?!65?--#7!27?O??_!118?O$#8!21?o??G!4?_$#12!22?G$#22!25?O$#26!22?_$#81!26?_$#108!23?_$#109!24?__$#110!23?O$#113!147?_??O_$#114!148?_$#116!28?_$#119!26?O$#121!27?_$#137!22?O$#150!23?G$#158!149?_$#187!24?O$#239!150?_-#7!34?@!4?A!5?CC!4?GG???O??AC?G!20?__!32?GG!6?CC!10?A!14?g$#8!21?}!91?X$#9!151?@$#11!42?C!6?G!4?O???_???O_!45?OGC??OO!5?G!11?C!11?@$#12!59?O$#19!61?G!46?_!14?G$#20!53?O???_$#21!112?_$#26!143?_$#28!117?O$#30!112?G$#42!52?O$#57!26?w???O_!86?O!22?_???OO$#62!111?G$#65!51?O!98?_$#68!22?A!10?A$#72!110?_$#73!111?O$#75!26?C$#77!29?@$#95!37?C!110?@$#96!23?_$#97!140?C!6?_$#102!150?@$#104!23?C!12?C$#107!34?C!88?_!22?A$#108!23?B@@@?CAEIC??c!83?_??O?_???O?_!4?G!4?GOOC?CCAEV$#109!24?}mABBCGCG[WG!6w!4oOoO!5_!62?_?_??_?OOooO__OooowoGoWwOKKGKG?KogK$#110!27?C$#111!27?G!116?_$#113!33?@???AA!4?CC!5?G!4?O???KAC!45?_!5?E!5?GG!6?!6C!5?AAA??@@!6?OE$#119!21?@!10?@!26?_$#121!22?_!7?@?_!23?_!56?_$#123!39?C!87?G$#126!44?G!10?_!58?_!15?G!8?C!4?A!5?O$#127!31?@!103?C$#129!60?G!51?O$#130!60?O$#131!136?C!5?A$#132!40?C!84?G!25?C$#133!48?G!85?C!6?A$#136!35?A!88?G$#142!27?oo__!114?_$#143!119?O$#149!36?A!85?G$#150!112?A$#154!131?G$#156!49?O!71?O!10?G!10?O!6?A$#157!22?G$#158!41?C!74?O!34?A$#162!38?C!90?G!14?O$#169!34?A$#170!143?A$#178!61?O$#179!60?_!90?G$#183!29?G!13?G!103?O$#184!23?G$#187!146?_$#188!28?GO$#189!151?_$#194!62?_$#195!45?G!82?G!9?C!8?@$#198!47?G!98?@$#205!61?_$#206!140?_$#212!111?_$#213!50?O$#215!25?O!6?O?_O!10?_?_!68?_??_?_!4?_?O!6?oG_!9?G$#217!112?C$#222!32?A!113?G$#231!145?A$#240!110?O$#242!22?O!86?_$#244!54?_!60?_$#247!22?C!23?G!79?G!10?C!4?_$#249!22?@O$#250!31?O?_!86?O$#254!42?G!90?G-#7!23?O!50?C!12?@?A!4?A!5?C???A$#8!22?AG$#11!64?@!5?O!7?A??@!23?A$#12!22?@$#17!148?_$#18!166?C$#21!60?@!43?C!65?A???@A$#22!101?G$#26!33?@?A?C?G!39?A!15?C!32?_?O?G?C??A?@@$#38!154?O$#39!150?__?__ooo!10?C!6?G$#42!68?O!5?G$#51!167?O$#52!87?_$#53!166?G$#54!100?G$#55!30?_???ACCGGooo__!85?__ooWGKCCAA?@$#57!138?@!7?A$#60!80?_!27?_!58?_$#61!159?_!5?G$#63!159?O!4?G?_$#64!78?_!4?O$#65!26?@!57?O!48?C$#66!165?O$#67!105?C$#68!26?Q!45?O$#69!93?_!67?O?O$#71!67?O!15?__!19?G$#72!54?OO__O?_?A?K__!40?C???C$#73!55?_O?__??`MOG!39?GKIIDC$#75!145?C$#76!54?G$#77!26?C!65?_$#84!27?_!107?O$#95!37?A?C!37?_$#97!98?G???O!5?O$#98!54?C$#100!26?_$#102!48?A!13?G!15?C!53?C$#104!52?_!20?O!7?A!27?O!24?A$#108!41?ABECAHg?O_?O!8?G!13?_???W!7?G??OOO??O_O??O_!11?OC_??@GE???A_??GH!17?O$#109!24?@N!10?@@BBFDCHR\USwdXPAaBFDFAMKC!9?__?oOoWOCKKEEMMGCWOggGOWGWG_o?O___!5?OPXHX\Fvsvxz~vlN^TFEFFBA@@@!10?@NB$#110!23?@C!55?O!49?G!15?O$#111!27?O?_OW@?C?G_o!94?_O?G?C?a?@??o$#113!24?_!41?A!5?G??C?A??@!9?!4A!4?CC???C!45?O$#114!67?CG!37?@!44?A$#116!69?O$#117!66?CG$#118!173?@$#119!23?C!64?A$#121!23?AG!9?@?A!5?O?_!39?@??A??C$#123!38?C?G!42?@!9?C!52?@$#125!27?M??G??A?G?O!96?_!4?_?_???G$#126!43?O!37?O!12?_!51?_!14?_O_$#127!96?C$#131!85?@!75?G$#132!71?O!10?@$#133!24?O$#135!175?C$#138!152?OO!13?C!7?_$#142!27?@~^Ff}{woo!98?_oww[[]}~~B$#143!25?_!73?G!35?A!24?O???O$#144!85?_!78?_$#145!107?O$#149!97?C$#150!73?G!12?@$#156!48?@!37?A!39?_$#157!65?A!83?_G$#158!149?G$#160!152?_$#161!160?_$#162!45?_!34?A!4?O!20?_$#163!52?G!6?O??CO!45?G_$#167!167?G$#169!94?C$#170!150?A$#174!26?G!31?@!11?_!24?_$#176!158?O!9?O_$#177!146?C?O$#178!64?A$#179!102?G!48?@$#182!150?O!17?_$#183!137?@$#184!50?A??O??G!4?O!47?AH_AAA$#187!91?C!37?O$#188!77?C$#189!150?C$#192!105?O!45?O$#193!158?_!9?G[{{}}}O$#194!63?@!22?_$#195!59?@!9?_!22?C!38?G!31?G$#198!76?C!12?C$#201!79?_!47?_$#205!65?CG!15?_!25?@_$#213!146?G??C!12?_$#215!24?A!17?G?G??ACG??@@??A?C?A!12?_??G?G???GG??CO?G???G???_O?_!15?w?I??C?GOO?I!5?@!13?M$#216!107?@$#217!103?G$#218!86?O?C$#219!51?CCG?G?O???_?__OO!41?C$#222!50?C!10?A!50?_$#231!46?_$#233!171?A$#239!106?A$#240!166?O$#242!61?@!5?_!13?_O!5?_!14?O??O!58?_$#244!47?@???g!6?G!46?_!5?G??_A!12?O!18?_??@$#247!136?A!25?G$#248!68?_!35?O??_$#249!49?A???C!6?O!51?C$#250!35?@!5?G!33?G$#251!51?A??_??G!4?O!48?A?c$#252!110?A$#254!25?O!63?_!27?G-#11!26?_$#21!117?_!29?A$#23!174?O$#25!42?@$#26!35?oO?OOP!89?OQ!4?__$#28!146?G$#29!41?A!87?O$#30!92?@$#38!147?_$#39!148?OGv|]}v~z~~gG$#42!25?@$#43!44?O$#48!168?A$#49!165?G?A$#51!159?@A!5?C?@$#52!46?_!14?C?A!37?C$#55!29?BA!7?CKMKG!87?GK^\SSS?_???@$#56!96?@$#57!26?G$#60!65?@!40?_!10?O!44?C??CA@$#62!72?C!22?C!4?G!24?_$#63!98?A$#64!57?_!37?@!6?G!11?C$#65!67?@!32?A!25?@!6?_$#67!93?B@$#68!43?O??@$#69!58?G?C?A!5?O!6?@!8?@!44?C!32?@$#71!43?C!12?O!10?_!29?A!21?_$#72!47?_!7?G@?CCA??@!21?@?@!8?A?C$#73!54?o?A?B??@@!23?@!25?@!15?_$#74!145?A$#75!27?B!117?C$#77!116?_$#78!71?G$#83!146?C$#84!28?@!110?A!4?G$#94!46?O!68?O$#95!83?A!28?C$#96!51?_!18?O!58?_$#97!26?@$#100!27?C_!115?O$#102!49?_!19?_!33?O!15?@!9?A$#104!37?_!28?A???C!16?CC!39?C?_$#107!26?AG!48?O!5?A??_$#108!46?G?O?G???C!5?__?_?_SCI???oOCG?_SOgC??G??O?[K_?oO??OO!9?OM???WO!5?@?@QG?E$#109!27?O!14?__AEEJNNVM]G!7?OoWw[GICB`r@hWsk[iMUycWs[sGo_bYGGgoo_?p_pr`FNM\ko{wW__?CCKEY^]LFHGE!16?_?A$#110!101?A$#111!30?@A??o?CKIB!93?AGG?SC??@A@$#113!24?@K!121?C@$#114!146?_$#116!148?A$#118!116?O$#121!135?_$#123!42?O$#124!112?A$#125!28?ACC???EEIA!96?BAIAQs@??A?@$#126!26?C!33?O!17?@!5?A!4?@!6?G?@!31?A$#131!44?@$#132!37?O!89?@?GC$#133!25?A!120?O$#136!43?@$#138!126?_!48?A$#142!28?[ww|~~HH@@@!96?@@HHH}}{{F?@$#143!132?_!28?@$#144!79?@!20?C!62?@$#145!68?_!47?@$#150!147?G$#156!39?_!4?C!14?_!7?O!23?@!23?C!29?O$#160!148?guGA`@G?C$#161!145?_$#163!53?@A!59?A$#167!110?@!52?G??GG?B$#169!45?@$#174!89?A!41?_$#176!160?C?G??O??CC$#177!63?C?A!5?C?A!19?C???G!16?G!32?@!14?AA@$#178!45?O!42?@!15?O!22?_$#182!161?C??G??C$#184!48?_!4?OH!50?_!10?A?P?_?_$#185!64?A!53?_$#186!62?C!112?C$#193!159?Uowooo_ooww~~~^N$#194!55?_!14?G!17?A!39?G!31?@!4?@$#195!61?G!36?G!8?_$#198!26?O!101?!4@!15?O$#200!57?O?G$#201!56?_!19?@@!14?A?C??@?G$#205!42?A?G!19?@!4?O!27?C!13?@?A$#207!60?@$#212!116?G!9?O$#213!69?G!5?A$#215!47?C!5?C!15?CA???_??A?_??W_??G_G?OCo!5?_?P??A??@AA??C_??_???WC!4?E$#216!41?@CG!22?@$#217!115?G!32?C@$#218!106?O$#219!53?_?QKN?B?A!32?AA???C!13?@@@!8?_$#222!62?G???_!28?G!7?C!13?A!7?O$#232!92?C!52?G$#233!103?G!23?OO!44?_$#237!60?G$#239!45?_!12?oO!14?A!27?C$#240!82?@???AA!73?A?CCA@$#242!80?@@?@?A!10?C!4?G??G!59?A$#244!27?_!10?_!5?_??O!16?C???@???I???A!40?GA$#247!41?O!92?_$#248!99?A!5?O???@?A?C$#249!52?`??D!59?A?@!5?_$#250!36?_!36?C!34?@?A$#251!43?A?G!4?_??A!67?_!5?G$#252!40?_$#254!41?_!7?O?P!22?@!8?C!20?_!19?O???A-#11!144?O$#12!144?_$#19!27?C!118?@$#21!118?@$#23!144?G$#26!35?_DA!96?CI@o$#30!123?G$#32!124?O$#38!146?C$#39!146?GHPhbvW^Nv~|vM@@???_!4?_$#42!27?A!7?G!83?A$#43!121?A!21?_$#50!55?A$#52!125?@$#55!33?ogDA!98?CI@_$#60!127?_$#64!136?_!7?C$#65!38?A!8?_$#67!111?O$#68!37?@!17?@$#69!53?@$#71!124?A?O?_$#72!66?@!59?NQCX!5?_$#73!41?_!9?@!10?OGCA!58?CA?CZcxgoo_$#75!140?_$#77!123?O$#78!41?O!92?O$#95!49?_!6?A$#96!64?G@$#97!51?G!81?A$#98!62?_!43?@$#100!30?_!112?@$#101!38?C$#102!39?_!15?C!54?A!7?A!12?C$#103!28?@G$#104!43?O?GOOC???__?G_!11?@!51?GG!8?A!12?C$#105!57?O?O!4?@$#107!29?O!83?G!18?C!8?_G$#108!28?C!9?oC??CECAC!9?G?GG???__???oKG?p_?a?[?_?Q???g??gOOO?C!6?C_!4?a?G???COOCG??C$#109!29?_!7?WGGK@B?B?A!10?CBFJDB@OwK}Krr|ENZ\nb~Nvh|v|V~~Tdnk~zv~~n~^zN}~~~[w?o@@BFnbFMK!12?A?@@!8?A@$#110!35?O!75?C$#111!32?_GDA!100?CIO_$#113!26?BW$#114!145?C$#118!47?@$#123!28?O!105?A$#124!125?O$#125!32?O!105?@O$#126!36?G!15?K!7?O!59?C!14?@$#128!121?C??@$#130!119?@$#131!146?A$#134!120?A$#140!50?_$#142!29?B^~NFA!102?CMN^NB$#143!27?@!18?@?O!10?_$#144!62?G$#145!40?_$#149!145?A$#155!29?C!111?OC$#156!40?A!9?C!57?C!8?O!14?@!9?_$#157!145?G$#158!28?_$#160!145?_oumU[Gf_oG$#162!48?_!8?@!65?_$#163!42?O!21?A!64?A??G$#170!50?G???C?@!51?@$#174!62?C$#176!170?C$#177!36?_!11?A??O!61?_$#178!61?O!45?@!15?A$#184!40?P!24?CA!44?_!6?_$#185!52?A$#186!145?@$#188!52?O$#193!157?AGp}}~~~^!4~ZF@$#194!112?_!8?@A$#195!49?O?_?G!68?_!13?O$#200!48?@$#201!112?O!9?G$#205!49?@??@!55?ACG!8?_!4?G!18?O$#212!63?C$#213!125?_!7?C$#215!28?A!7?O!4?C?G!12?O?_?CA!4?o?A?CAGOc?O??OGCAGA???AI?B??G??O?_?O@!4?Co?_A???G???G!22?O$#216!34?O!110?O$#218!28?G!25?A!62?@!16?G$#219!39?@!10?@!10?_!61?C?K?H???O$#221!53?C!7?G$#222!42?_!20?O!79?GA$#231!47?A$#232!55?_$#233!50?A!72?@!47?G$#234!172?A$#239!51?C?A$#240!121?_D$#242!60?_!59?`$#244!37?_!6?_o_???O!12?A!45?@??G!11?_$#247!37?C$#248!49?A?A??@!54?ACG!14?_$#249!67?@!62?C@???O$#250!49?G!69?OO$#251!38?@A??G!64?A?GO!5?O_O!14?G$#254!39?O?I?`WDGKGC???OwOCiS!56?O_!4?OO!9?A-#7!27?_$#8!28?O$#19!29?C!112?O$#21!126?a!8?C!6?C!26?G$#22!144?@$#26!32?OO?BK!99?O$#28!37?C$#29!143?G$#30!43?G$#35!44?C$#38!145?DOA!21?C$#39!145?O@?_k]P|`okzzzTfAA??@$#42!34?O$#43!56?G!67?@$#52!58?A!56?G!11?G$#54!29?A$#55!32?GGNK!99?GDR$#56!55?O$#57!139?_$#60!29?_$#62!30?_!14?G!13?@!69?@?A?C$#63!48?A!78?O$#64!50?@!74?@!4?C$#65!35?O!18?_!78?O?_$#67!43?_!81?A!9?A$#68!31?_!99?C$#69!46?AC!8?O$#71!130?@$#72!40?_!18?A!62?@!10?A$#73!44?_?G!11?C?@!71?@$#76!56?_$#78!113?A?O!14?O$#84!31?C$#85!125?_$#95!39?@!16?C!73?G$#97!124?O$#101!30?C$#102!50?A_Q{W!4?_!53?O???OOGGAC$#104!41?MCA!7?@D?@AB???[KGwU_!27?_!8?o_O_?WGOCWKG?AAAD@!20?G$#105!39?CC!7?OG?O!13?Ao_??_!4?_?_???_o?_!4?G!5?_?o?C__?C?II??I$#107!30?@!58?C???A$#108!34?_???GO@!10?C!13?T?X_COGg`?OCA?aHO?@F_O`a_??_??C?A?_?HBHCC??@@A!28?G?A$#109!30?A!4?__!11?_owG!11?@??FCHZFfVM~Nz\mSUJNeWDnELBVMNLNZF@RJFA?QB@@@??@@!4?@!22?OA@$#111!31?GCE$#113!28?B!112?_G$#114!29?G!113?A$#116!142?_$#117!141?O$#118!125?G!9?@!34?@$#119!29?O$#123!36?A!98?O$#125!33?@!102?GCB$#126!47?@!9?A@!69?CA$#129!143?@$#131!138?_$#135!134?G$#136!30?O$#138!43?O$#142!31?BB!104?G[B$#143!37?G$#145!41?O$#149!28?_$#154!29?@$#155!140?@$#156!38?C?Q???A!4?C??_??G??O!49?_!4?C??G?_ooWwK$#157!143?C$#160!143?O{im|^R`mA]NRC??A$#161!109?_$#162!128?A$#163!57?O!52?_!10?@$#167!37?@!75?@$#170!44?GA$#174!48?G$#177!45?C_!68?CO$#178!39?A!87?_!13?G$#183!126?@$#184!42?G!16?CA!71?O!7?O?@$#185!42?_!80?@$#186!124?A$#187!30?GO$#188!133?G$#192!46?CG!9?C!68?S$#193!157?CCgW||~~}~~^B$#194!36?@!97?@$#195!38?@!92?GG$#198!136?A!6?_$#200!46?O$#201!46?@??A!74?CO?A!8?_$#205!37?AA!18?G!65?A??G!5?A$#207!45?O!85?@??A$#213!127?@O$#215!37?OO!11?C!11?AA@GGAS?GO?O!4?PH_C?W?Y?WOOGPOOO?WKKO?CC??O?AE??C???@!24?C$#217!41?_O$#219!133?`$#221!47?O$#222!43?C!17?@!52?G??_!4?A?G!4?G!11?C$#231!36?O!21?_O?_O!49?__o??GG??C$#233!144?A!23?_$#237!49?@!64?A$#238!132?C$#239!128?_C!4?O$#240!134?C$#242!44?O_??@!6?_!58?C?_!8?C!14?_?A$#243!139?C$#244!41?!5@?_???AGBED?@?G_O_!41?_?__O?O_Q???CCAEE!8?__$#247!137?_$#248!47?AC!79?@?A$#249!39?_!18?G!53?@!11?_???GO?O_?_$#250!32?_!81?@!12?C$#251!38?_!18?_!62?@??o!7?_$#252!115?_!5?_$#254!33?_???_?GG?A!18?ADCg???A_!20?__??_?_?_?WOG?G?SC?CGA!5?@-#8!143?@$#9!144?O$#11!142?KO$#12!140?G???_$#17!36?_!104?C$#22!146?_$#23!38?G!91?O$#25!134?_$#29!134?O$#30!37?G!89?@$#35!129?G$#38!140?O???D$#39!145?AC?CI}~}CJjvlhbNo?C??@A$#42!135?O$#43!32?C!103?O$#52!33?O?G???A!88?A!10?A$#57!35?_$#60!54?@!71?O$#62!112?O!15?C$#64!50?_!60?C!25?@$#67!51?_!61?_!23?G$#69!31?A!10?H?@!72?A!7?AA$#71!126?C$#72!31?@??AE??@??O?@!8?O?A!58?O!13?O???OG?GG$#73!32?AA??EA?@O?AA!87?C!4?g$#76!125?@$#83!125?G$#94!111?G!6?C$#95!110?A$#96!134?@$#97!45?A!71?C$#98!134?CCA$#102!44?GSocgo???__c_???Acg!6?_!17?O???G?OWOO?GoS[[?sw{CAA???@@??O!7?O$#104!43?_!11?O!4?C??h??AC?]CELI[O?{???CSMMGMEA?EC?A@@?A?B?B??@?@!13?G???C!5?@??@$#105!55?G!9?@!6?A?A@C?EBA???@@@???G!6?@???_?O!28?@??A$#108!47?A!9?c?WO!4?C??O!10?C@G!6?@@!28?_??C_!9?AA$#109!47?@BBB!5?[Y}CG??OWWww_!9?wwwo!5?_owo__@!9?_!14?Oo?w[{o!9?A$#113!28?@AC!114?_$#114!32?O!105?_???A$#116!141?G??G$#118!40?A!99?C$#121!36?O$#126!34?O!9?C!6?G?@!75?@!5?_$#127!143?C$#128!39?C$#129!37?O$#130!133?O!4?O!29?@$#131!142?O$#133!33?_!105?G$#136!29?@!112?@$#138!129?C$#141!48?O!46?G!11?O??C!4?@!4?@A$#144!38?O!14?C!63?@!12?C??G$#145!113?G!21?@$#149!31?C$#156!45?GNW?GKC@!18?_!22?___oo?G??GG??g{\wO@AAmUGH?C?@A!7?A$#157!139?O!5?O$#158!30?A$#160!140?_o_?ALZ~zt@?@ZsSGQO$#161!126?_$#163!32?@!19?_?C!56?@!20?C???@E$#170!141?@$#176!128?_$#177!42?_!69?_$#178!41?_!88?_??_$#179!32?G!110?G$#184!33?@?@!17?O?A!57?CO?@!7?@!8?C??C$#185!41?@!98?A!26?C$#186!141?A$#188!35?O$#192!33?GG!91?@COAG!7?G$#193!153?_!4?E[oN~z~~M@$#194!38?C!87?GG$#198!143?A$#200!36?G!100?o$#201!43?G?@!6?C!87?@$#205!30?@??C_!4?GCA!70?C!16?o!9?C$#207!34?C??CaogKC!10?G?@!75?Go!5?C$#213!70?_$#215!64?_???@??@?@???@@???@!4?@!12?_$#216!139?@$#217!143?_!22?O$#219!37?@!76?_$#220!138?A$#221!71?O$#222!43?O!12?@!14?G$#231!44?O_!8?O??@@A@XR?C!7?___?_!6?__!7?GGCC?K?G???CACAA$#232!82?_$#233!40?@!90?_!7?_$#234!127?A$#238!53?A$#240!43?C!8?G!57?@AG!15?@$#242!37?_!87?C?_G$#244!44?_!4?C!6?A??`_ACEBA??C?W?OO?gW!6?OOsoG!4?UCAAM?ECB?bB?B?@@!7?__??_?A??_!5?@$#248!42?O?A!6?O!86?@$#249!36?@!75?A!17?A$#251!34?@!15?O?A?G!59?G?G?ANA@?@A$#252!51?B!57?_?_??CO$#254!48?C!16?_DBI@B??C@EBA??CBI@?A??KE@R@_??@?@!21?O???G-#8!35?O!101?C$#12!36?_!99?GA_!6?@$#20!148?O$#21!34?G$#25!134?C$#38!138?Y!26?@$#39!139?GG??G!4?@Pkv^Kp|U\m{t!4?O_$#42!96?_$#43!37?_!97?@$#50!79?_!16?O$#52!96?C$#55!95?_$#60!128?C$#62!50?@!62?AO!20?A$#63!37?G$#64!68?O!44?C$#67!36?A?_!9?O!45?_!35?G!4?O$#69!38?G!31?@!31?_$#72!36?C?F@!9?G?@!62?@o!16?K?o$#73!37?C?C!90?@K?pA$#94!49?@!20?A!24?C$#95!68?G!10?G!16?@$#96!115?@$#97!121?G$#102!45?A@@@??C??ADENM^}@Q?_HECA@?JGDB@N_O?WoGDHMUCgGGoOO@??oC!4?_?@@EAQB?AO???C?CG$#104!40?O??@AkK???oG?o_o!22?G?C!10?A??A!4?W!4?_C__o?O?_???A_ooP??OWE$#105!41?C!68?C?C$#108!41?GG_G!33?C!9?A!4?C!6?C?CQ!8?G!6?B??A?B??_$#109!40?_OoGO!22?@@!9?BFBF!5?@@F@@BB!6?JFJL]g!5?]!4?@!5?@@_`oW$#113!146?@$#114!33?Z!112?A$#116!137?O$#117!34?O!112?A$#118!35?B!130?G$#126!47?OC!20?A$#127!148?_$#129!36?O$#130!136?A$#131!137?G$#132!34?_$#133!136?O$#136!135?C$#138!36?@!130?_$#141!62?@??E?W??GO!21?G!14?@@$#143!40?GA!27?G!58?O$#144!136?@$#145!48?_?C$#149!135?G?@$#150!33?_!113?C$#156!61?}k}^owAC_scuqk}oW_!11?SKG??B?NB!8?@???@!4?C???CE!4?@$#157!147?G$#158!136?C$#160!139?Vv~~v}{w_EmRG_rMAhaOA$#161!79?O$#163!94?O!21?_$#167!129?C$#169!95?O$#170!68?_$#174!101?G!25?C$#177!69?C$#180!33?C$#182!38?O!88?@!5?A$#183!112?@$#184!93?_!22?O!4?O$#185!34?AC!94?O$#186!34?@!111?C$#188!39?_$#192!129?A__@!32?A$#193!158?@@I~~^^KC$#194!47?_!81?@??AC$#195!127?A$#198!35?_!102?@$#199!35?G!101?_$#201!40?C!55?G!31?G$#205!50?A!63?C!13?A??O_???_$#207!37?B?A@!73?AG!14?EAOG?_$#213!113?G$#215!41?_!35?A!12?A!32?A?O??_$#216!148?G!17?O$#217!39?O!99?_$#219!115?C$#222!67?_?O!46?G$#231!42?@???AGA???AB@Ao_p_@??@!8?@!7?_?qgS`GYOo??_!13?AGKK!8?G???C$#232!86?_!13?_!19?_!5?C$#233!144?@A?@!15?_?_$#234!138?C!8?O$#239!49?A!45?G!18?_$#240!34?C!13?G!64?@!15?W!4?@$#242!37?O?GA!8?C!46?A!17?G!13?@??@??G$#244!44?@@_E?_?OkK[GHO!19?C???GDQaO@_C???C?C???wf!5?A[O??__!5?YFGA?gK??A$#248!36?G!4?@!87?_$#249!49?O?A!38?_!24?A!5?_$#250!101?oO$#251!50?G?@!21?O!19?G$#252!73?G$#254!42?EUcOO!4?_O!13?@!10?@!22?O???@O???_G?O_???@???@O_CGG-#7!32?@$#11!36?_@!97?G???@???G$#12!37?C!96?g?O!5?C???_$#19!32?G?Q??G!95?C!10?OO$#20!141?A$#21!78?G!54?A!27?C!5?A??C$#22!32?O?@_$#23!169?G$#25!34?_$#26!96?G$#29!35?@@$#31!67?G$#35!38?@!27?_!35?K$#38!145?GAW$#39!148?AKa~@ip}yn{ESA$#42!33?@!111?_$#48!35?C$#50!102?O!27?C!7?@$#55!93?_C?O$#56!94?@$#61!36?C$#62!115?C$#63!36?A!96?_$#64!115?G$#65!67?O@!10?A!17?O$#67!89?O!44?A$#68!33?A$#69!47?@!22?_!19?O!12?_!11?@$#71!46?C!46?A!43?@$#72!103?O!12?A!15?S?@ADICO_$#73!132?G??@A?G??_$#76!122?_$#78!92?O!10?Co!12?_$#79!78?@$#92!67?_$#94!45?G!42?_!12?@$#95!65?O??A!71?C$#97!66?C!36?@!10?A$#102!33?O!27?BMEMG??SOGWGGWGME!14?@!29?@_!17?G$#104!33?G!11?_?C!4?@??ABACO_O??_!11?o???G[YUDE\AC??A!6?EJC???BR`?@@!8?A!23?O$#105!54?C!52?C!10?@$#107!44?O!41?_!21?_!4?O$#108!39?s`_IO??oG[??U[OG?O!27?O??_!12?OO???GQQ??C?@IC???KGH??JIPGJ?G_$#109!38?oI]^tnNA?oa|{g_C!33?G!10?GoGG!4?GgYwzw}cw_???uq??Stmvs~oO$#110!33?C$#111!94?G@_$#113!32?A$#114!32?C$#116!37?A$#117!137?O$#118!66?O!95?@???@$#121!37?O!56?A$#123!142?G$#125!94?o}$#126!38?C!7?@!32?G!10?@!6?G!33?_$#128!67?C!62?A$#130!168?C$#131!32?_!100?G!6?@$#132!96?D$#133!34?G!99?C???_$#138!168?@??O$#141!64?@$#143!79?C!10?k$#144!89?GA?_!40?@$#145!92?C@!46?GO$#150!34?C!105?A$#154!37?_!41?O$#156!39?@!19?I@?@@?BB?GlV!5F@@!66?_$#157!36?O!97?O??_$#158!78?O$#160!135?_!5?@@BFFLF{o\?}TM@D?@OG$#161!46?A$#162!139?A$#163!91?_!11?A!13?G!4?G!19?_$#174!45?C!51?C???A$#177!77?_!36?@$#178!89?_???C$#182!102?A$#183!79?_$#184!47?A!10?WC!28?O???A!24?C???[C$#186!78?C!90?A$#192!35?G!95?G$#193!157?OAHB@!5?@ACG_$#194!116?O!15?_!6?_$#195!129?@$#198!78?_!17?A!44?C??G$#200!93?G!22?_$#201!66?G!35?_$#205!89?C!26?G!14?BA!5?O$#207!92?G!10?G!12?D!20?C?GO$#212!117?O$#213!143?O$#215!38?G!14?g__?G!23?_???O!12?_?__!4?C??C!10?C!8?C$#216!67?A!67?O!11?_@$#217!143?C$#218!115?O!14?G$#219!122?O!15?AC$#221!63?_$#222!45?O!11?O??A!28?@?G!12?C!13?_??_!7?A$#231!58?@`CK_GOC!5?_Oo???G??@??@!33?@$#232!91?C!8?A$#233!130?@?@???_!5?A???O??B!9?_!10?O$#234!35?OG$#237!35?A!29?_!67?O$#238!79?@$#239!78?A$#240!115?A$#241!67?@$#242!102?@!28?C???C$#244!54?@@_@a?W_OO!4?_???_?_o!4?EB@?A@A@B??@!5?B@?@C!16?O$#247!38?A!54?O???_$#248!131?O!4?G$#249!57?_!31?A?O!12?G_!15?B$#250!77?O$#251!33?_!12?G?@!68?A!4?A$#252!69?A!18?G$#254!44?_@???AB@ABQ[KC!22?o?cggg?S!10?OC!5?C?@CA?F?@!5?@!23?_-#11!32?CO!100?B_!10?O!4?G$#12!66?_?_!70?@!4?G??@??C$#17!64?C$#19!36?@!104?A!6?_!4?_$#20!154?_$#21!167?_!4?@$#22!135?G!12?@!4?O$#25!66?@!31?O$#26!63?_!14?@!18?G$#28!65?A!83?C$#29!103?G$#38!136?G??A?_??O!26?@$#39!140?C!10?@AIVz|BGHoG!10?C$#42!33?G!30?A?C??G!7?C$#43!133?C$#50!35?_!30?G??C!22?A!54?O$#52!34?@W$#55!64?gC!4?_!7?}!13?G!4?O$#62!118?O$#63!34?O!98?A$#64!55?A???O!10?@!20?O!24?@A$#65!63?G!39?O$#67!133?@$#68!36?C$#69!91?G!26?G$#71!34?C!70?@!16?G!23?G$#72!122?D!19?@A$#76!122?A$#77!54?C!25?_$#78!91?B!12?@!13?A!4?[$#82!88?G!16?G$#85!54?_G!32?A!16?CG!12?O_???_$#92!79?O!8?O!16?Oo_$#93!88?_$#94!70?C!9?O$#95!64?@???G!29?C$#102!121?C$#104!67?C!5?BAEH!47?C!23?O$#105!45?G!12?C!12?O!11?AO?G$#106!65?O$#107!51?O!4?O??C!12?A?o!7?AX@OOS!10?@@CO!6?CG??a?O!12?_???G$#108!36?OC?_AM?G|c?cSRO?hHA??W!24?K_?B@!12?C?c!5?AA??G?`?Do???B???BST?NQQAC!12?@CK?Go$#109!36?_z~^|p~uAR~ZjknnUE@?_EI!13?O??O!6?PCmkeA!10?AYzJ{!4?@Hv~vT]niK_?@C!4?ji^olltwo!12?A?GO?_$#110!55?`$#111!71?_!20?o@???_$#113!32?G$#116!67?_?_$#117!172?G$#118!158?_!12?A$#119!35?@$#121!63?O!13?o!14?C$#125!64?O!28?}F?^$#126!53?O!4?O???p@!15?_!9?G!16?@!25?AG$#127!135?O!4?A??C?O$#129!104?_$#130!163?C$#131!134?O!8?G?G!6?G$#136!66?A!30?A!37?C$#137!65?_$#138!160?@$#142!65?G!28?W@_$#143!59?GC!9?A!33?G!44?_?O$#144!89?C$#149!35?A!116?O$#150!34?_!99?C!7?C!4?_?A$#151!135?@??GS$#154!116?A!35?_$#155!67?O!27?A$#156!68?C!11?C!36?O???A$#157!32?A$#158!148?A$#160!135?AV~ugwWwo__???@@ADDGCAKTO$#161!89?A@$#162!60?GO$#163!143?@AC$#170!53?_G!35?G$#174!63?C!6?O!8?@GW!20?A$#177!89?@!12?@???C!10?G$#178!144?C$#179!134?G$#180!98?_$#183!55?O!13?@G!8?G?_!21?_$#184!33?B!47?E!37?CO??@O$#185!157?_$#186!97?@!5?C!34?@!25?G$#188!62?G!5?O!77?@$#192!35?C$#193!157?OAeMs{wo__$#195!55?C!6?C!35?G!8?G!42?G$#198!32?@!64?C$#200!117?C$#201!58?_!18?@!13?_$#205!34?A!106?@$#207!34?G$#212!33?C!83?@!4?o_$#213!56?A???_G!43?_!13?_$#214!71?K?_G!7?_$#215!43?@!14?@!8?G!5?O!38?G??O!5?O$#216!61?_???@!38?O!35?@!10?C$#217!103?A!37?C!30?A$#220!88?C??C!12?EA!12?CG$#221!61?C!27?O$#222!56?C@???A!17?E!41?@??G$#231!36?G!26?A!12?_!22?_!48?C$#232!68?B??A_???O???A$#233!150?A!10?A???O$#234!136?_!9?_$#237!90?_$#239!62?A!6?O!20?C!17?_!9?_!23?A$#240!92?@!10?@$#241!54?O!14?A!36?AO$#242!56?@!33?A$#243!94?_{$#244!67?@???@@?@@!43?A?g$#247!36?A!29?O!10?I$#248!90?O!41?@$#249!88?@!29?@!4?A$#250!57?_?_O!28?_!17?CO!25?_!12?A$#251!81?@$#254!56?G??BB@!5?A!4?KKCgE???@!6?h!32?G!23?@A-#7!33?_$#11!34?@!103?O!10?@!4?G?_??_$#12!98?A!38?C?_!12?C$#18!162?C$#19!136?@!21?O$#20!155?AC$#21!68?O!90?@$#22!107?O$#25!54?O$#26!58?AA!6?@!14?o!9?y!7?_!4?@AG!43?@$#28!139?O$#38!140?_??@?A!11?A!11?A???O$#39!143?A?@AHKSOO___!6?@?C??@$#42!66?G!39?C$#50!105?@$#54!61?_$#55!55?O??C???K?@!33?C?AC?CGCO??_$#57!61?KA!17?q!57?_$#64!120?C$#65!52?G!27?@!19?_!9?C$#67!123?A$#68!101?_$#69!39?A!83?@A$#71!124?@$#73!37?O$#74!67?G!22?_$#75!67?C?`!31?A?G!5?C?_$#76!41?_$#78!42?O$#81!58?@!30?A!17?BA??G!8?O$#82!121?A??_$#83!121?K$#84!67?A?U@@!10?_!6?{???C!13?CKWO$#85!120?B???O$#92!122?O$#93!53?K!35?@$#94!40?@$#95!35?A!52?A!29?@$#96!36?O$#97!125?@!25?@$#100!65?A$#101!65?C!4?C!5?~!5?W?O$#103!60?_!4?_!6?@!22?@?_$#104!126?O$#105!50?OC!23?@!10?@!15?A!16?O$#106!65?W!28?vA{$#107!49?_!21?G??@o!6?@E@ACN!14?PQO!6?E??WHg{AG!6?C?O?O$#108!35?G?A@?GHAAKbDGHO@B!75?C?A?O??MG?_$#109!35?SN@?_SE@@rSyvuNm!21?GGO!7?A@?@A!15?__!8?EBASFB[__!5?Bzj|nnn~psw!15?@$#110!84?I!70?C$#111!54?_??G??A?O!15?B!19?G?C!5?__O$#113!155?O$#114!34?A$#116!99?A!56?A$#117!68?@!87?O!10?_$#118!171?C$#121!34?_!31?A!10?^?W!10?G@!12?A!6?O$#123!61?A!15?_?CKC!73?G$#125!55?_oow[C?_}???@!10?{!13?~B???Do!11?_$#126!40?A!40?@!24?A??@!12?a??A_$#127!34?G!70?G!32?G$#129!98?@!58?_$#130!68?K!106?_$#131!148?@!5?O$#132!34?O!22?C!27?O!4?E!8?O$#133!60?@$#135!68?A$#136!137?G$#137!63?@!27?C!5?A!4?C$#138!157?@$#142!60?G???A!4?G_!22?W???G$#149!34?C!116?A$#150!136?A$#151!138?@?G_$#154!157?O$#155!64?{!5?Y!13?_???w!4?_??BO$#156!43?_!91?A!18?A$#157!61?@!88?A??G@@?K$#158!153?C$#160!137?@ANV^~{~{|uqgkgOO??@$#161!125?_$#162!39?G!19?@!19?@$#163!38?C$#170!52?c!4?@???O!23?G$#174!54?A!31?O!66?@$#177!35?@!45?A!17?@!8?@!14?G!34?_$#178!38?G!84?C$#183!88?C$#184!41?O!79?@$#185!164?G$#186!151?C$#187!56?C!10?_!18?_!17?C!5?G$#188!57?A!7?@?O!22?O!16?G!28?C$#193!160?@?BBFNM^}{{wo__$#195!51?oA!26?A!20?G!4?_!6?_!8?o???G!26?A$#198!53?_!8?@!5?_!39?_$#199!99?C$#201!109?A!9?AG$#205!37?_$#207!36?_$#211!138?C$#213!51?G?A!30?CC!36?C$#214!71?usvmM!6?Cw??Go!13?WG@_!7?W{caO?_$#215!39?@!5?G!9?@!16?A!27?@@!8?@@@?@!11?G?C???O$#216!38?_!60?G!37?A$#217!155?_!12?@$#218!119?C$#219!42?_$#220!122?@?K$#221!52?O!69?G!31?C$#222!54?C?@!99?G$#231!39?O!15?A$#233!149?A??G!8?A!4?O!5?G$#234!38?O$#239!53?PGG!63?@???_?O$#240!39?C$#241!123?O$#242!125?C$#243!59?_O!33?G{$#244!35?_??A?_$#247!55?CI!9?s!12?_?G???_!4?@!9?O!4?O!29?@$#249!37?G!4?G$#250!52?@?@!33?@!17?@!30?O$#251!43?[$#254!37?C!4?C!67?A!42?A-#7!160?@$#8!37?_!24?_$#11!33?O!124?A$#12!59?_?_??_!92?@CO$#17!158?@??G_$#20!140?@?OO$#21!81?_$#22!53?C!105?_$#23!33?_$#25!36?_!30?C!7?A$#26!53?G_???_!5?OOOq@Go!5?O!4?O!4?BC!4?_!7?C$#28!158?GC$#38!155?G!15?A??G??_$#39!146?AICPpnZwAOUw_$#42!100?AO!39?G$#43!36?O$#46!177?O?_$#55!54?O!13?qo?_!5?_c@OFG_??CG!4?O!6?@G_!4?@G_ACGO_$#57!62?O!6?A!8?O!6?@!21?O??A???_$#62!37?@!122?O$#64!38?_$#65!38?A!11?G!55?C$#67!34?O!125?G$#68!53?_!5?O?C!4?A??@!6?G!6?G?A!16?GG$#69!34?_!90?O$#71!36?C!124?_$#72!35?A!4?GPE$#73!35?_B$#74!57?_??O!16?A!13?O$#75!77?O?_!35?O$#76!35?W???ooMO$#78!40?A_h$#79!125?@$#81!51?gE!54?_$#82!127?_$#83!125?A$#84!52?o!9?@C!13?C!7?C???O@!10?C!6?G!5?G$#92!124?@GW$#93!125?C$#94!45?_$#96!39?C$#100!66?C$#101!56?_!5?G!21?A???A$#103!60?H!55?G$#104!127?A$#105!48?@$#106!57?GMMC!4?NG!4?@G!21?|lX|{_$#107!47?@?P!53?B@!10?A@?Jo|UCo$#108!44?G!82?@?D?GCGGC?[?o$#109!39?@!4?FBy}{m!65?@???GA?O?_???FY~vXvuz~b~Kw_$#110!50?@!53?O?G!8?C!5?@$#111!54?K!13?K!6?O_?BA_!6?__???G!6?A!7?C@??@A$#113!32?_B???O!123?CO$#114!33?K!29?_!77?C$#116!53?A!11?_$#118!160?C!14?O@$#121!52?@!8?@!5?G!4?O!5?G?@GA???W??_!12?C?_?A??@???A?G$#123!61?A!4?@@!5?O!29?O!12?O_$#125!54?B~NB!5?B!8?!4_???[??o?_??O!4?F!6?CO!6?BUKXo_C??_$#126!50?A!23?G!53?O$#128!51?@$#131!91?C!11?_!40?_!15?_$#132!80?C!21?_$#137!53?@$#138!169?@!10?O$#142!56?OC@!5?G!5?N!6?G!7?w??CN}_?o!4?@???O!8?ACGO_$#143!102?A!10?@!12?CC$#145!39?G$#149!140?A$#150!60?_!81?G_!15?G$#154!124?C$#155!62?EGF!6?K!4?F!6?CT??@!5?H!5?G_!8?o_$#156!43?@$#158!160?A$#160!141?@BN^~|tzmMOcF|fg?O$#161!34?A$#163!43?_$#167!180?_$#170!128?_$#174!142?_$#176!175?M[KwO$#177!38?C!11?C!73?O!15?C$#178!34?K$#183!52?G!21?C!30?@!33?A$#184!40?@??W?O$#185!37?G$#186!141?A!17?A!12?C!4?A$#187!34?@!18?O!23?@!8?_!13?@!12?O$#188!38?G!19?O??O!20?@!4?AG!12?I!9?CH!9?A$#192!37?E$#193!157?C!12?@@BFF@A$#194!161?O$#195!50?o!24?@!48?G?@$#198!66?_!24?B!47?@$#199!75?C$#201!38?@!84?@???G$#207!35?C$#213!51?C!74?_$#214!46?C!25?FNB!8?@!18?@CM}o!7?@?E^sF?gg$#215!44?o?@?A!79?G_??a?@$#216!157?A!20?C??_$#217!179?G$#219!40?C$#222!43?C?G$#233!142?C$#234!156?@$#239!125?_A$#242!36?G?O!12?A!75?O$#243!57?O?@AG!9?A!11?AG???@!4?EAQeAAO$#244!39?A!5?C!95?O$#247!63?O!5?C?O??OG!4?I?CO!4?O??G!9?@!12?C!44?@$#248!122?@E$#249!35?@$#250!51?O!62?A!8?GA$#251!43?A-#7!163?P$#8!55?EEBBB!7?BA!32?WWWGGG?_?__$#11!109?_!34?@!18?C$#12!54?@O!10?@??@!29?_!7?G!37?ACGO_!12?_$#15!105?_$#19!65?@!39?O!56?G$#20!36?@$#21!122?O!39?C$#22!30?OC!128?_$#25!161?O$#26!37?_!19?C!12?@?C!9?A!20?C$#27!60?WP???O!42?O$#28!159?@$#39!146?@AA@Qto~}nlVuC$#46!179?@$#49!182?[$#50!38?O$#52!183?w$#53!184?_$#55!55?_!15?@!15?@?@ACG!4?G??@@D?@!5?G???@??G$#57!101?C???C!12?`!26?C$#58!62?__?C$#62!161?C$#64!33?@_!15?@!77?CGO$#65!31?G!6?E!11?AG!54?@$#67!161?A$#68!88?O???E!5?A!9?C!11?O!7?G$#69!34?D!24?C!69?C$#71!161?@$#73!35?@$#74!81?A!17?A!17?@AC$#75!93?OO!4?C!4?A?CC???G!7?O$#76!35?A$#77!85?G!37?O$#78!40?AA~}$#81!51?@_!19?O!21?G$#82!128?A$#83!127?@$#84!52?^w!26?@???O?@!6?@!4?@?A!7?AC??O!4?A$#85!45?To$#92!57?G$#93!57?o$#94!58?gO$#95!47?_$#97!39?C!6?C!75?G!9?O$#101!82?G$#102!32?C!7?G$#103!73?A?AO???O!8?_$#105!39?G$#106!73?O~xm[}mk{!4?__???__?f@F!13?FEKWgo_$#107!47?A?B!71?A?BCoC_!8?O$#108!128?__???_OG_OtOb@pO??O_$#109!31?_G!6?OO!6?D^Wo!9?_!63?JMwWO??FN^lvNnIn[}Mm{w_$#110!31?O!16?_!76?@$#111!53?@!18?A!9?@D?A??C!14?@?AA!8?AC$#113!29?_!31?!4A!42?_!55?i$#114!31?A!28?B!4?A!38?O!4?O!50?A$#115!61?K[[[??[www!29?!5_$#116!37?A!16?G!17?G!23?_?G!61?G$#117!182?@$#118!179?A$#119!37?@!16?EGx!9?A?@EEE!25?ooWW$#121!30?_!51?C?@?GAG???@C!11?@!14?C!25?G$#123!32?_!86?I?O?_$#124!184?O$#125!53?C!29?AG???BM[!16?A?@??@bECGO$#126!50?C!76?C!15?@$#127!36?A!26?@!42?O!53?O$#128!162?@$#130!118?G!45?G$#131!33?O??SG!84?_$#132!36?_O$#133!30?G?@$#135!162?A!17?C$#136!161?_$#137!53?A_!53?GG$#138!178?@$#142!78?@!5?C@E!4?H!5?A!5?A!5?A!5?G@???__$#143!51?A!35?O!43?G$#144!34?G$#145!35?C???@?C?@$#149!68?C$#150!160?D?O$#155!77?@!7?oO??O?O???_G!4?AA!8?@A???O$#156!47?O!82?A$#157!55?@!15?G!38?O?_$#158!64?@!52?CO$#160!147?@DMLIN?@?Q??A$#161!34?O$#162!124?_!4?P_$#163!44?G$#167!180?@??C$#169!148?_$#170!51?O$#174!32?O!17?G$#177!33?C!17?C!76?@!15?A$#182!180?AFA$#184!35?_!5?g??C$#186!38?_$#187!32?A!25?C!13?@!14?K??@??A!5?@!7?@???O!7?_$#188!38?@!44?GA!6?A!8?C!17?C?G$#192!185?_$#193!155?O?gHw$#195!33?A$#198!33?_??GC!16?O!26?@!14?O$#199!108?@$#200!131?_$#201!38?G!87?@???C$#202!65?G!5?o$#204!64?__$#205!34?A$#207!41?@$#210!60?C?@???o_!39?O$#213!61?_$#214!49?_!22?_!46?@B@FCO$#215!46?@G?C!73?G!6?@???A$#216!85?C!59?@!18?O!19?G$#217!146?A$#219!40?@$#220!44?oa$#222!44?A!21?K$#229!106?_$#231!41?O!4?A$#232!39?_!81?C$#233!148?GO!15?_$#234!147?C??_!10?G??_!16?G_$#237!131?O_$#238!129?A$#239!33?G!17?_!75?A??G$#243!73?l?C@a?PA?oo_???_?_?O_?]?DC!14?CO??_$#244!40?_???@$#247!93?G!10?C!10?@A!4?G!25?O$#249!35?W???AC!4?GG$#250!58?Og!66?A-#8!110?@BBB!48?C@$#11!110?A!40?A???O$#12!29?@!26?@!93?@!9?O_$#15!99?B!8?@$#18!98?_$#19!157?_$#20!35?O$#22!153?C$#25!38?@$#26!37?A!16?G!58?O!95?O$#27!60?@!44?G?O$#28!36?@!125?O$#34!99?GG$#35!43?C$#38!159?_!4?@$#39!152?@ABBIXQG$#42!37?OU!13?O?_!99?O!66?_$#50!36?A!15?A$#52!131?_$#53!183?AB$#54!37?_$#55!54?C?A!57?@_?C$#56!129?G$#57!52?@!68?W$#58!60?W!8?@!31?G?@??O???G$#60!184?SBC$#61!184?g{G$#64!40?O!86?C!10?O$#65!121?_!13?C!5?_!70?OO!6?_$#66!71?A!27?O$#68!30?G!8?_!102?_$#69!43?A!87?@$#70!62?DE!4?OI$#71!44?O$#75!55?@?C!60?@??A$#76!42?I$#77!30?@!94?A$#78!41?ND@K$#81!52?_!71?AC$#82!47?H!80?O$#84!53?B!64?O?w@?B$#85!46?JS!81?o$#87!48?O!165?_$#89!112?G$#92!48?K!78?W$#93!47?_!64?O!15?_$#94!35?@!61?A!13?_!20?A$#95!29?G$#97!40?@$#101!123?C$#103!56?OG_!17?C_!6?c!4?B?G!4?O$#104!129?C???C$#105!125?O!10?C!8?G$#106!55?G!15?oVzZ^zTe~~~]gXzzx\Wfefsl]i!20?b_$#107!51?A!6?Cg!37?G!26?o__$#108!133?G???A@AGS?@q?{E`cOw_$#109!29?OA!19?A!8?O!63?O!4?BBFEC?XRRdmLVJ^]LvBx]Yc?O__$#110!30?C!27?A!67?@$#111!116?AO$#113!109?@!51?W$#114!160?_$#115!60?A!9?^!28?CFFF??FNN]}$#116!112?C_?A!44?G$#118!167?A!15?G$#119!113?C}[KG!44?JE$#121!119?|!86?_!8?O$#123!30?O!19?O!74?@!8?C!14?@!60?O$#124!183?@$#126!39?@!13?O???@!40?@!29?G!8?O?O???_!66?_!6?_$#127!160?C$#128!43?O!88?@$#129!161?A$#130!34?C!133?C$#131!34?A!87?@!29?A???O???@!56?O$#132!29?A!7?@G$#133!28?C???A!128?C$#135!50?G$#136!28?G$#137!54?B!48?_!12?O?G$#138!43?_!122?@$#140!134?_$#141!62?o_WOo_$#142!118?A?F$#143!36?G!11?AG?O!19?C!79?C???_!62?_$#148!47?A$#149!152?C$#150!154?G?_!6?G$#153!63?O???O_$#154!51?@!46?G!28?A!11?_!72?__$#155!55?A!59?@??C$#156!127?_$#157!31?G$#158!153?G!7?@$#160!153?@CC$#162!98?O!12?C!97?_!9?_$#163!35?A!5?OO$#170!39?C!9?A?G!74?A$#174!29?_!29?@!11?G!25?c!24?G???O$#176!169?_$#177!39?O!9?c!74?@???C?G!4?_$#178!44?_!85?O$#183!31?@!19?_!13?G!58?CG$#184!40?E$#185!43?G$#186!54?O!76?O?A$#187!53?c???A!38?@@!52?A!56?_???O??O$#188!28?_C!19?O_!70?CC!11?A!5?_$#193!156?DELV??__}~}{wO_$#194!132?_$#195!31?A!4?C???_!14?_!80?G$#198!32?@!80?G!46?A$#201!39?I!8?@!4?G!78?O@$#202!65?DC!4?@!30?GQo$#204!61?@A@!4?No!29?_o?_G??_???O$#208!61?}GGF?GN?C!31?oO??o?_$#210!60?C!4?AB???_!27?C!4?CK???_?C$#212!40?G$#213!52?C!84?G!78?_$#214!51?C!4?GoWE!37?O!24?Og$#215!50?@!71?_!4?@!4?G!17?G$#216!31?C$#217!151?@!34?A$#220!44?B~s!83?_$#221!211?_???_$#222!104?A!28?O??_$#231!52?G!51?@!26?G$#232!55?O!34?O!33?G$#233!155?G??_!4?O$#234!133?_!49?C$#240!186?o$#241!60?_!37?A!109?_$#242!35?CO$#243!55?Cc!15?gCc_?IX???`VACCEacGPWJQ`C!19?`$#244!49?@!14?__!87?O$#247!28?O?_???@G_K_!11?C!68?A??A!93?O$#249!41?__!68?G$#250!48?_!9?@!51?_O_!13?K!8?G!16?G-#8!160?@$#11!130?_!9?_!17?@!5?_$#12!113?@!48?C?O?GO$#17!139?G$#19!163?C?WO$#21!138?C!4?O!16?G!14?G!11?@$#22!29?O@!99?O!30?@$#23!138?A$#25!119?G$#26!27?A?G!8?AC!14?@!57?A!103?C$#27!98?^!9?K@$#28!139?_!101?C$#29!140?OCG!25?C?G$#35!156?C!5?A??C$#38!167?_!9?_$#42!119?O!41?C$#43!131?A$#46!170?O$#49!176?_$#50!140?A$#52!135?A??G$#55!54?M$#57!29?C!24?O!57?@!94?@!6?A?_?_!8?A!8?A$#58!61?A!46?BA$#60!131?C!52?C$#61!184?J$#62!136?@??C!45?_$#64!44?B!95?@!17?C???G!23?O$#65!204?O?@???@O!23?A???C$#66!99?_$#67!136?C$#68!27?__!186?_$#69!41?@!7?C!51?_!27?_?G!8?C!60?_!12?_!9?AC!15?G$#70!99?@$#71!131?_??@!6?G$#72!134?O_?O$#73!137?__??Oo$#76!132?_?I!26?_$#77!43?G!5?G!17?CC$#78!131?O^}c!19?_$#79!155?CA$#81!97?G!22?G$#82!222?A$#83!45?C$#84!98?_!12?C$#85!45?@@!82?F$#86!68?A@!151?EC$#92!225?OOO$#93!203?_!7?_!8?A!7?O!14?O$#94!45?_A!81?O!24?A???G!46?!5_?_!5?@@BB???O?!4GWW[G?o!5?Go$#95!40?C!6?A@!180?C??S[?k?O_!4?_$#97!28?A!17?W[K???Os!74?G!30?C$#100!118?C$#101!55?_@!7?C!32?O$#103!55?IAHF@_c?o_GG??G[_mw[SQO_!5?C?_C@!20?OOI?G?GC$#104!64?@?@!89?G$#105!41?W?O!80?G???@!15?@!6?G?C$#106!56?{E?][W{GWO_GW?_\PFBjHJ]f@B?eOnMxmyr@YjOEA!13?__Wo}djnA$#107!70?A!39?E!13?@!28?G$#108!108?_!14?_?O?G!15?EGBU?iYCfg?O@???_$#109!42?_!80?Oum|V!14?A?EKH~Tdr?E?KWOo_$#110!42?G!8?_!17?C!86?@$#113!144?_!17?O$#114!160?A??O$#116!159?@!5?_???C$#119!168?GG$#121!37?@@A!78?O!90?@??O!6?O!6?A$#123!27?C!92?A!77?_!4?O!4?@$#125!55?@!58?@$#126!28?P!11?G!5?_???M!46?E!11?C!9?_?G?A!29?@!59?`??A??_G`G?c_C?__!12?_$#127!168?O$#128!159?G$#130!161?O?_$#131!130?G!13?O!68?O!32?O$#132!159?A!4?G!32?_???O??A!13?G!5?@$#135!118?_$#136!244?G???_$#141!62?@!4?B@!31?W!4KoO$#142!80?wwW!30?A$#143!29?@!10?@?CC?W!4?p!57?O!9?G!99?C?O?`_!8?_!5?C$#148!217?A??D$#149!145?_$#150!167?G$#153!99?G??A??GGO$#154!70?@!26?@!4?_$#155!63?C!16?CCc!29?C$#156!41?C??O???__??_!75?C!14?@!10?@$#157!161?A$#158!27?@!172?O$#161!246?_$#162!44?C!4?A!157?OOO??@??A???G!5?A!4?aaA$#163!128?_$#167!171?y{W$#170!121?_!121?G???_$#174!41?_!4?C?AO?MMJ!11?E!56?a!119?O?_$#176!136?_!32?_bC?C$#177!43?A!5?@!72?O!7?C!15?_!53?_!5?O???O@!5?C!11?A???A!10?O$#178!137?A???_$#179!139?O$#182!173?_wo$#183!28?G!22?@@!10?A??C!163?C???KOwgWwo!4?_$#184!42?B!109?O_$#186!176?O$#187!27?G!11?@$#188!27?O?A!10?O!13?_!65?@!21?@!62?O!17?@!4?A!5?A$#193!162?@BBBFFbB?@A$#194!136?G!23?O$#195!120?C!20?@?G!55?_!5?@$#198!164?C!48?A???_!20?A$#200!136?O$#201!120?_?K!40?G!81?O$#204!61?@A!37?b?@???B$#205!135?OA?O?G$#207!137?K$#208!99?UCB?ABFCN$#210!103?@$#212!133?@$#213!121?@!20?C!59?_!9?_?@!4?C?W?G??__!5?_???C$#214!55?C!4?A!10?A??_?cc!18?@!12?GH!10?A@@$#215!65?@!55?C?G?@A_A!27?_A$#216!121?O!16?@@!17?C!8?_???C$#217!137?@$#218!160?C$#220!129?WB$#221!220?_??E???C$#222!47?_O??O!12?A!38?_??_!4?@!33?O$#231!69?A!50?O!20?A$#232!28?C!11?A???_!78?C$#233!135?@!33?O$#237!131?@$#238!154?AA$#239!43?@!142?_!53?C$#240!135?C!22?G???_!21?o^N$#241!242?G$#242!41?A!93?G???A???_$#243!55?O?ow_!5?_Oo_o!8?@WA?BXjOPAODK}dSnx{_!11?_?O_C?QOO@$#244!63?@??A!34?OOOo??_!42?G?@!5?O$#247!40?_!78?F!37?@???G!40?O!34?A$#249!45?A?@!111?O$#250!44?G!15?@!97?A!50?_!5?@!6?O?W???C!7?C$#251!151?O???_!4?_$#252!153?O$#254!42?O_-#8!141?AGo$#11!140?@?O??A??A$#12!145?@@!6?O?_$#19!130?@!18?C??G!21?_$#20!156?_$#21!141?@!5?_!31?@!85?O$#22!29?O!137?@!59?_$#26!130?_$#28!142?_??C!17?_!29?G!58?C$#38!147?C!20?@$#39!149?o?__$#42!191?OG!74?_$#43!128?O!31?O!13?O$#46!137?O$#49!175?H@$#50!255?_$#51!177?A@$#52!129?@!7?_!4?A!31?AU}@!6?C$#53!177?Kmc$#55!116?o$#57!27?_E!122?C!54?_!30?G??G$#60!129?C!16?O!32?Wk$#61!180?O{$#62!156?A??G$#64!172?_!11?G_???_!47?A!6?_!21?_$#65!119?@!108?_???@?H?A!4?O$#66!188?_!72?_?_$#67!139?@CO?CA$#68!27?BO!12?@?_!11?_!58?O?C?C!36?O!87?@$#69!127?O_!16?_!71?@@!14?_A???G!5?A__$#71!131?B!10?@$#72!131?W_oWA?@?Q???@??_!14?GC$#73!133?G?c_?Zcw???K!14?EKCWG$#74!54?@G$#75!54?A!62?O$#76!134?bH??CG???A!14?A!5?W$#77!28?_!19?C!4?g!64?_$#78!127?CA??c^D!30?A$#81!49?G??K?CA!61?_?GA$#83!233?G!8?G$#84!80?@@!37?C$#86!216?@$#92!198?@$#93!216?E!5?G$#94!154?@!10?G!31?A!7?JFZnn~|~}t~g{sw{GO???BDJDACO!6?A!4?GC$#95!51?GO!65?W!36?A!9?C!30?A?A??BBFDCGCOO!6?O!4?o_o_??ACykW!5?@!9?@$#96!161?A$#97!49?C!75?_!44?_!75?G{M{$#100!56?_!37?_!71?sGo_$#101!56?C$#102!162?A$#103!44?C!11?@?D??@!4?A??W_APP?`??O???WG__!8?@$#104!44?G?C!105?C!4?G?@?@$#105!42?@!5?_$#106!65?A!4?YhAG_?__`_EafU^^TIQ@H@!17?@AA@??B@$#107!44?QC?g?_!24?KAC@KC!40?_?A??@$#108!122?_@!28?@AG?G??_@$#109!121?w\u|M@!22?@@BA@EK?OO$#110!45?@AC??SobF!66?O$#111!115?_$#113!141?C$#114!147?O$#116!130?K!39?C??O$#117!118?@!25?@$#121!29?_!87?A!84?G!18?A???C!17?_$#123!41?A!75?G!11?_!40?G!20?_!34?G!28?O_$#124!136?AG!39?O$#125!55?C$#126!47?A??@A?O!111?A!38?G!12?A???C??P??G???AKO?CD!15?G$#127!147?A$#129!116?G$#130!165?@$#131!147?G!4?O?_!14?A??O!19?CO!27?@!29?A!9?G$#132!41?C!133?_!17?A$#134!117?C$#136!114?_O!31?@!19?A!33?G$#140!166?A?C$#142!95?_?_!5o___?_o$#143!46?@!68?G!4?@!36?_!13?O!23?A!5?C!17?@A??G?A!12?A!4?O$#144!226?C!13?C$#148!230?@$#149!142?C?_?G???C$#150!146?C!4?G!14?@?A??G$#154!253?O$#155!55?@!39?Ow[GGGKGXWOoWGw__o$#156!48?BB!77?@!22?A!5?C$#157!130?A!17?_!5?O$#158!162?_!28?G$#160!148?GGoO?_$#161!129?O!29?O!32?_!51?CG!9?G$#162!27?C!14?G!76?A!77?@!9?_!12?@!11?A??B?C?G$#163!126?O!36?C$#167!136?@!27?@!6?BBG$#170!169?G?_?_!12?O!5?O?A?CC!44?O!17?G???O$#174!43?O???@???@!65?@!8?G!42?O!30?A!39?BBEKPBVA??C$#176!169?@@!11?C$#177!107?@!11?_?A!78?C??G?O!16?C!8?@?CC_!15?C!4?WwwooOO$#178!128?C!26?@??C!5?_$#182!172?CFL$#183!51?C??g!66?C!77?B@???A!25?O__?_???@@?C$#184!164?C$#186!140?AG!19?_!21?A$#187!27?OH!194?@?O?O$#188!27?G!27?O!57?_!39?G!13?C!65?B$#192!180?A$#193!170?A$#194!136?C$#195!120?C!73?C!4?C!26?_!11?C??G_!11?G$#198!130?O!38?C??G$#199!143?G!91?G$#201!119?O?@!22?O!25?O!24?C@?C!51?A$#202!106?@$#203!177?_OA$#205!129?G!6?GA_!6?G!11?A???O?@$#206!168?G$#207!133?ACOO!4?_???O!10?@!6?O$#212!160?_$#213!54?O!49?@!101?O!12?A!5?_!8?O!14?A$#214!43?D_O??O!24?ER[Z]AZw[$#215!123?GA?A!26?C??O?_$#216!146?A???G$#218!42?C!7?G$#220!126?_G@$#221!202?C!15?A!9?O!14?A!10?_$#222!50?A!112?A??Go!80?o?wwo$#232!42?A??g_?GO_!21?C_$#233!128?G!19?O$#234!129?A!18?C!22?C$#239!120?G!37?G!80?C$#240!182?w{r$#241!105?@!79?O_!53?O!18?G???O__$#242!137?C!49?_!57?O??@!13?_$#243!56?Y~y~~}~~~||~~fDSg!10?`??itl}u}~~]NFBFFFBFEEMMEFE\\M^NCA$#244!126?C$#247!42?O!75?A!30?A!40?_!4?@!8?O!19?I!10?O!13?@???GO$#248!127?_!29?C!35?C$#249!127?A!29?@??A?@??o$#250!148?@!62?A?@I???GC!5?@!16?@$#251!158?@!94?_$#254!43?I@AWO!77?O-#8!163?@$#11!144?A?C?@?GO!18?O$#12!144?@A???A!7?@?A!4?@?A$#19!28?O!100?C!22?_!12?CO?C!6?G_$#20!161?C!13?@$#21!128?O!41?_!74?C$#22!32?G!96?A!16?G!14?G???A!11?AC_$#24!124?_$#25!179?O$#26!29?_???O!76?_G!17?@!77?@$#28!37?_!135?A?O!12?O!57?W$#35!126?C$#38!150?A$#39!151?EN~~|{{kWG$#42!177?O!11?G?@!54?C!9?@!14?A$#43!127?@!20?A!19?_!90?_$#50!190?G!47?_??A??C!24?@!4?G$#52!124?O!13?Ao!37?`AC$#53!178?@$#54!195?A!41?C$#55!112?cACB$#57!108?O!118?@B!8?AG$#60!127?G!51?BH$#61!180?E^$#62!174?@!98?_oo_$#64!185?y???O!8?AA!11?G!25?G!19?C!6?_yw~^MC$#65!116?KA!91?A??O!16?G$#66!187?C!56?G!14?CCE@$#67!144?_??@!17?_$#68!45?G!10?C!90?C!21?C???_$#69!28?A!98?AG!34?G!39?C??G?O!47?A$#71!130?C???C??A??oC?C$#72!130?OW_]HAKC?ENBA!20?C$#73!131?_C@o`A__@?WS$#74!44?A!12?C!19?O???O!34?@$#75!56?@?G!23?O$#76!132?Q???@$#77!109?_$#78!124?G??CB???@!11?O!112?o$#81!55?@$#83!29?A???_$#84!82?_$#85!119?_OG??C@!19?_$#92!231?G$#93!121?S$#94!120?G!25?@!65?@?@?@?@!28?O$#95!29?G!86?A@?O!42?C!5?A!5?_!32?O?_@BEBANABCFBABF?@???O!6?C!10?g$#97!30?GO_!22?O!115?G?G!18?GGwws!28?_?___??g?O[G!17?@$#100!78?O!21?G!66?@@?A?IO$#102!120?C?O!38?A$#103!46?A!4?GIA???@EGCKK[gsfxkf^EzwNOOG!6?OSiOG$#104!52?_!70?C$#106!60?Oo??C?O?A???C@ofNdnjEJFuhbTNoG@?o$#107!47?\bw^_CGc?O!7?O!6?_!9?_!35?g?I$#108!49?@!72?G$#109!115?__O[DB?CB@!25?_!9?@$#110!44?@C!7?@Ac!197?O_$#111!56?A!54?oWKB$#112!166?@$#113!145?G$#116!113?_!15?G!34?_??C$#117!59?_!53?@!51?G!97?_!13?_$#121!27?@!86?O!31?A!13?A!83?@$#123!44?C!12?G!51?GSA!18?@!81?_!16?E!15?A!11?@$#126!54?@A_!52?OG!38?G!44?C!32?A??_!24?@$#127!177?GO!29?A$#129!34?O!93?_!15?C$#130!149?C$#131!27?A!119?_???g!4?@!5?O??@?OG!7?K!29?C?G$#132!38?O!90?O!46?A???O!10?C!11?A!38?@$#133!36?O$#136!37?O!107?@!25?O??C!5?_$#137!113?OG$#138!125?WGO$#142!97?B@BBFBFF^NFNEA@$#143!174?G!13?_!24?_!14?C!4?F!5?ECCAA$#144!125?C!38?O!26?G!46?A$#149!143?@??_G$#150!146?O?_!11?C?GOA??_?G??_?AC$#154!202?C!6?@AC!18?A$#155!79?OO!13?FBNC]CCGKGW_OW?@@$#156!170?CEC!16?__!57?o_y}~n]W$#157!145?C?O??C!15?G$#158!38?_!90?_!18?O!41?C??A!16?O$#160!150?@@???AAA$#161!130?A!108?OOo[[$#162!30?C!28?O!47?__!6?C!113?@???G!5?GGG?@A$#163!161?@A!93?G$#165!126?o_$#167!138?C$#168!125?_$#169!167?A??G?@$#170!202?A!27?G_!4?@$#174!121?A??A!48?C!16?O!5?G{{{owowoo_?_!4?G!7_wowwWwWW??CU?HA!20?_$#176!167?GO_$#177!29?O??O?_!80?O?C!71?@!14?C???@?_!20?O?o??A?C?_?__oo!12?@@@$#178!139?G!26?_!8?_!82?O$#183!46?O!9?G!61?_!29?G!46?C!4?KCG?G?O_!5?S[O[[YW[DK?FEEC??@B@?E!20?C$#184!123?G!23?AC$#186!58?O!90?@!12?@$#187!111?C@$#188!29?@?G!14?_!13?_!53?_G$#192!126?A!51?_$#193!158?O_oo_$#194!138?G!4?o!41?D$#195!28?C!89?@!31?O!37?G!8?A??A!6?G??C!47?A$#198!31?C!126?B!17?P??G!31?O$#199!173?@!71?G!13?O!13?C$#201!36?_!149?_O!8?A!33?O!14?@A$#205!126?@???_!7?O???@!22?O$#206!172?O$#207!131?@G_A[?W!4?_G!20?G$#212!130?GE!4?O!4?_$#213!30?_!90?_!104?@!10?O$#214!45?A??[E?COO!8?o_?G??OG_W???G?A??_$#215!55?G!60?O!5?A$#216!112?A!32?O???_!13?AC!13?G!8?_!6?A!51?_!10?AC$#217!163?_!13?C$#218!28?@!28?O_$#219!128?C!7?_!5?G$#220!120?_??O?A!130?CG_$#222!29?CO_!137?B@@!19?ooo!40?__o_!9?FN^D@$#231!149?O!105?_$#232!45?@DA??_R@CW??_!11?O!51?@@$#233!152?O!6?C!9?O$#234!166?C$#237!175?A!82?G$#239!35?_!154?@!10?A???C???O!52?O!8?O[W$#240!182?~~~!83?_oyk_$#241!186?^B?C!49?_!20?GGM^^DF$#242!123?_!13?@@!5?G!42?GD!4?C!36?C!15?@!12?AA@$#243!57?A@FJ!5BGE@??@?E??_??CHCGHEG?_Fv}~N~w{ow_w!4o_?_$#247!28?G?A!12?@?O!135?_!6?A!22?_!26?O?A!18?G$#248!143?A!48?C$#249!122?_!51?O!80?AO$#250!118?A!40?@!45?G!6?G!22?@$#254!46?G_!5?_-#11!148?CGAC?A!108?_$#12!112?@!36?@!5?G!18?A$#19!31?A!96?@!39?A!7?G$#21!206?_!53?@!20?G$#22!151?G?@!13?O!12?@A$#24!108?_!7?_o!5?@!7?CcGO$#26!46?@??O!55?G$#28!60?@!93?G!27?C!8?C_!46?O!6?A$#37!120?_$#38!156?G!9?G$#39!151?O_?@@FZkPO!11?G$#41!123?_$#42!108?C@C!71?A?OA?O!4?C!8?G!37?_!25?@$#43!136?_$#46!170?EW$#47!132?G$#50!176?A!7?G?_???C???C?C!10?_!38?C$#53!178?@A$#54!167?@$#55!104?O!4?C$#57!47?A!152?G$#59!255?!25?GO$#60!118?O!16?O!4?CO!4?G!35?@!93?ow{{o_$#62!184?C!83?CGww}}~~NFA$#64!58?A!128?__!25?AO!15?@!8?G!25?@$#65!57?@???A!4?O!6?_!72?@?G$#66!241?GC?C$#67!119?G!12?A$#68!31?@!26?C!8?O???OO?G!112?@$#69!117?A??EA@!8?@!8?G!53?AA!5?C??G???_!22?_$#71!118?C!20?a??O@$#72!132?@B?FCkJW??B_Oo!114?O$#73!134?CGPOo?_?G?_$#75!73?G$#76!141?A$#77!47?@!21?O!4?C!77?C$#78!145?@!29?@!81?@|}_$#79!33?@!25?C$#81!64?C!10?O!36?A$#82!118?@$#83!61?_!135?A$#84!106?@$#85!117?CA@!137?A$#92!32?@!73?_!107?@!18?A$#93!60?G!177?C$#94!215?_O$#95!57?A???Wo???_!6?O!39?C???@!29?C!7?_!30?C!15?C!28?A$#97!48?A!4?C!140?!4@?BA?AE?EKMCK]GCW?BNMFBBFBB@B@B??B$#101!63?A??G!41?@$#102!53?O!94?O!83?_?_?__!9?Og[KGGEGE$#103!62?@?AADHJG?LDDBcwIge???@??A?OE?P??@@O?O???@$#104!49?C?G???C!200?_$#105!50?C!5?A_$#106!65?@???E??A??BFsVH~~~}nZlvnx^kZE]IGSGC?I$#107!49?@GOg@DBSSo!7?A??@B!43?A@@$#109!48?@A???_?G!56?CA@$#110!51?_!6?G!158?_!16?G?CQO!8?G?A??A$#111!105?C!4?B@$#114!147?@!6?C$#116!148?A???O???O!11?_$#117!128?O!56?_!59?_!23?_!10?C$#118!122?_!8?G!39?A!8?C$#121!50?_!55?A!62?_!25?C$#123!70?_!79?@!17?C!43?@!26?@$#124!140?A$#125!98?___oooG$#126!60?OCC!7?O!36?OA!43?A!40?A??A!14?@??G!17?@$#127!155?O?_$#128!109?O??G!8?_!7?@A?O$#129!108?G$#130!108?O$#131!147?A?SC!14?A!15?C???C???G!14?O!40?O$#132!36?@!67?_!4?A!67?@!8?@$#133!152?H???_!20?G!6?_!76?C$#135!178?A$#136!127?O!48?@$#137!111?A$#138!110?O??!4O??OGCA!10?_?_$#142!96?__??O??G$#143!34?@!14?G!5?_!4?c??G?W!8?_!41?A???@!47?G!61?_?G!5?A!7?O$#144!119?A!27?O$#149!150?_!22?@???C$#150!127?_E!21?O??_!13?G?G!5?C?Q$#154!213?C$#155!95?_!8?C$#156!55?O@!94?@!35?EBB@!19?_!6?Oo__o__owowww[C?{S]YKG!8?EB@B@D@C@@O$#157!34?A!130?@C?@C$#158!128?G!24?O!107?G$#160!155?A$#161!107?_!7?C!80?GG??O!32?@$#162!54?_!4?G?@!12?O!38?@C!36?A!54?O$#163!121?@$#165!113?__!4?_$#167!144?@!26?C$#168!109?__o_??_!4?OW[]~~~B?Mw_?O_$#169!167?CO$#170!107?@!77?W!19?O!7?B!26?_!4?C$#171!127?C?O?O$#174!75?G!31?A!46?O!31?G!4?A!6?B?@B@@FHBPBB@E!5?@!28?_$#175!112?O$#176!146?O!16?AA_O??@@_$#177!59?A!7?_!48?G!76?GWwoowO?_!14?_!23?!4B@$#178!133?C!7?_???G!113?@$#180!37?@$#182!172?o_!5?@$#183!59?@???o_!88?G$#184!65?_!80?AG!109?C$#185!130?@A!41?O$#186!154?A!33?G!50?G!38?@A$#187!68?__$#188!48?C!13?AC!42?C$#192!145?C?_$#193!157?CRmn~~|{[_???G$#194!134?G!9?A$#195!64?G!88?C!20?@!28?G!11?G!15?O!6?@!6?AG$#198!32?AA!14?G!102?_!14?A??O_!10?@$#199!154?_!44?_!66?A$#200!255?!6?_$#201!35?@!35?_!38?G??G!61?A!10?A?O!10?C!40?O$#205!141?C!4?_!19?@!93?G$#207!134?B?IBCCO@C]K?C$#211!130?C$#213!62?G!5?O!36?_!8?GGC!75?A!22?C!15?G$#214!56?G!7?@C?EC?GA$#215!52?O$#216!109?G?G!15?G!21?A!20?O!11?G???O!52?C!6?@!13?AO!7?O!12?_$#217!118?G!29?@!15?@$#218!50?O??G!5?O!107?A$#220!255????A$#221!212?A$#222!54?G!94?_!40?A@@@!14?Wo?ow_o???G[[G[[MCMCFF??O?B@@@!9?@!9?G$#231!56?_!58?A!119?_??_!9?S?OU?_BGE$#232!51?@D?A??G?_???@!6?C?G!38?C!139?_O$#233!150?G$#234!155?C!11?_?A$#235!118?_!9?__$#237!176?C???A$#238!117?G$#239!72?_!32?O!79?@?G??G!9?_!31?C!11?_!24?EBF@@$#240!141?G!41?NB!75?C!6?BB@C$#241!119?C!69?C?W!7?GCO_!38?owwW@$#242!54?O!84?@@?_??A!46?Wo_!45?CC?CA$#243!73?A???@?O!4?OcOG??_Acx_SFJFZNDMFBB$#244!247?_?__?_WooW_$#247!30?@!162?C???CC???G!36?A!5?G$#248!189?_!24?C!17?A$#249!148?_$#250!58?@?A???O!41?WK!80?C$#254!50?BEAA-#11!154?O??@A?GO!7?_$#12!126?O!25?A??ACGO_??_!5?p?@$#19!126?G!26?C!14?I!73?OO$#21!172?O!14?A??_!48?G$#22!48?G!26?G!78?G$#24!107?!5A???BBA!5?@AG??_!4?~$#25!127?C!134?O!6?C$#26!41?O!60?@!137?G$#28!157?C??C!43?AG!5?C!27?A$#29!162?O_!81?@$#30!72?O!53?A$#31!169?C$#35!151?_$#36!78?O???o!4?oo!5_!23?@!17?__a???_$#38!153?B!17?@$#39!79?G!75?GO_?@A$#41!84?O$#42!42?OO!114?G!50?C!4?_!24?@$#43!120?@$#46!171?o@?@$#47!74?O$#48!176?O$#50!99?A!104?G!35?F$#51!105?A!7?C$#52!192?O$#53!80?G!6?C!28?_?A!5?G!6?C$#54!160?O$#55!71?A?C!8?C!6?AA$#56!255?!14?O!14?O$#57!44?O!6?@!107?G$#59!255?!17?g?_WCH@osOx[$#60!255?!14?_s{Si^fzu}NJnE__$#61!75?O!5?G!5?GG??G!11?AQ!25?O!7?CG??_$#62!142?@!47?O!79?JBBT$#63!82?G!6?GG?G!12?O!9?O!13?G!17?@?GG!37?BE$#64!53?__??OO!5?G!89?_!35?IG!16?__?_!22?G!6?@@@$#65!238?O$#67!65?G!29?G!11?OO?C!6?G!21?A???AG_$#68!69?@!80?@!6?A!67?G!10?G$#69!66?C!29?G!12?C!38?C??O!72?O!19?O$#71!66?G!30?G!22?C!21?G$#72!122?A!16?@@DC?@AY{Oo!99?_??__oO???MsW$#73!90?C!49?A??@EC$#74!70?O$#75!68?E$#76!146?_$#77!45?OO!9?G$#78!245?W]]{[ggOW?___?pB_$#83!56?@$#84!68?X???@@!4?C$#85!248?A$#88!119?E$#94!59?G???AA$#95!42?_!7?_!6?AC!4?!4@!150?A!5?G??O!8?O!6?_$#96!101?G!10?O???C$#97!48?_!8?_!158?G!12?@$#98!111?O$#99!94?CC?!4C!9?GG$#102!46?_!11?A!159?K?KMCCEAEBB???BOA@A@B!9?@!8?O$#103!74?A??@@$#104!52?@!8?CO!89?O!78?___?cc?__?_!7?@??@BC@MB$#105!61?G!88?AC!85?_!17?C?G$#106!76?BAA!4@?@?@$#107!53?@!4?@$#108!153?_$#109!54?EGO??AE$#110!47?_!6?@!159?I!4?G???A!10?@$#111!72?CGC!5?C!6?AA!10?@@@$#113!151?@!18?A$#114!155?_???C$#116!168?C?C$#117!126?C!42?G!16?@???@!17?@!53?G!6?B$#118!128?O!5?_!41?C$#121!71?O!13?C!5?A?AA$#123!41?_!53?AA$#125!70?ALI!6?C!4?AAA!5?!7@$#126!48?O???_??Q!4?O!4?C!39?@@!46?O!58?C???CC!6?G!12?G$#128!119?@$#129!169?O$#130!51?G!157?A$#131!155?P??@!11?O!29?C$#132!156?A??O_!78?CO$#133!126?_!58?@!76?A$#135!173?G!14?C$#136!52?K!51?@!47?C!88?O??C$#137!47?G!26?G$#138!73?O!32?A?@???AAA!13?G@!7?@A!4?_$#139!127?G!12?G$#140!77?G$#142!69?]K!6?C!4?AA!6?@@$#143!49?OO???G?_!158?_!13?C!7?O$#144!63?G!25?C!25?C!27?O!103?_$#145!98?G$#147!129?_$#149!153?G!108?@$#150!103?@!23?@!26?@$#152!128?A$#155!74?@!6?A!6?@@$#156!45?_!11?@?C!91?G!60?AFDN?@BBB@J!4@?O!5?O!11?@!6?C?G$#157!127?A!42?G$#158!40?_!8?GGA!210?C$#159!114?@$#160!154?C$#161!63?C!153?G_$#162!51?O?C!13?@_!159?C!14?_$#163!121?@@!128?C!6?`$#165!76?_o_o?o?o_Oo??!4O!12?_!7?@!5?o!14?@L?S__o$#167!173?A$#168!72?!4_O???o!4?_!7?O!10o_?___!4`___OooGww{{pB@O??Nz~?EQ]GWO?O$#170!58?GO!26?C!13?A!68?A!21?C!8?G!4?O!4?C?O!26?O?G?C$#171!128?@$#173!92?C!9?GCCKCK!5?GG???C$#174!43?__!4?_!102?G$#175!134?G$#176!164?@GWV!4?a$#177!61?@A!134?@@???@A!12?A??O!6?G$#178!83?G!10?G!16?C!18?_!12?G!117?@$#181!123?A$#182!173?DM[go!68?_$#183!51?_!9?A!148?@!19?A!7?G$#184!61?O!38?G!15?G!33?C!98?A??C$#186!159?A!14?O!21?C!65?_!21?G$#187!81?C$#188!67?E??@!87?C$#192!141?G!7?CO$#193!160?@FN^}vfg!10?_$#194!65?_!4?__!14?G!6?G!12?O!11?G!21?C!7?@!41?C!19?_$#195!52?A!44?A!71?@!46?`???O?O!4?G?I?GG$#198!46?G!196?GA$#199!202?AC$#200!65?O$#201!52?OOO`AC?_!41?A!93?A???@!11?G!5?_$#205!108?CO???O!15?O!8?@!10?A_!94?C!15?A$#207!141?A???P@A_$#209!91?C!11?GG?G?G!8?C$#210!201?@$#211!129?A$#212!66?O!78?GC?G!101?SOG!7?GC$#213!47?O!108?@!56?G!11?O!10?O$#214!53?A$#215!59?@!171?O$#216!53?G!6?_!138?_!12?GO!14?G$#217!57?G!81?C??O!9?@???_!4?G!9?G!36?O$#220!64?C?A$#221!62?C!148?A$#222!60?G!150?@@!14?O$#223!93?C!8?C!6?G!10?AA$#231!60?@?G!153?O??C_!4?C!4?C@?B?A@!10?@??@$#232!223?_??___o!4?C???C?_!11?A??A@$#233!78?G!45?C_!8?O!13?A!5?ACGO_!16?_$#234!175?A!13?G!79?G!13?A$#235!118?@!6?S?_CC!6?@$#237!170?_$#238!244?G$#239!56?C!9?__?_!28?A!8?@!95?@!5?@!11?O!8?H??G!8?G?_$#240!102?A!11?C!28?C_!42?@???o_!48?EEA?A$#241!189?@!4?@???GWo!8?WWO!5?O!5?O$#242!61?_??O??W!16?GG??C!23?C?O!6?C!20?A?O!50?@BEEE!4?C!7?_!22?G$#243!73?A?FC??AA??@?@?@$#244!55?C!159?O!5?__?__?C??oESC???E!13?B??@$#247!76?G!6?CC!7?A!58?A!9?_!48?A??_!30?@$#248!58?_!186?_$#249!62?`?_A!33?G!10?O!41?_!101?G?O?]$#250!214?O???O_$#251!63?o!85?@!100?A$#252!96?C!4?C!10?G??G$#254!234?_!19?A??C-#7!255?!8?@$#11!164?ISgO!47?_$#12!125?C!30?@???@??@$#19!38?O!119?C!10?@$#20!162?A$#21!126?@!54?C!19?A!61?O$#22!161?_!7?_$#24!55?OG???GCG?C?G?O!6?a??A?CCC??G???OOO!4?!11_!8?O!4?G??C!8?_F?AG_!8?AC??O_$#25!165?G$#26!124?OG$#28!56?C!112?A!44?@$#29!164?@A!90?O$#30!53?G!30?G$#32!51?_oOK$#33!52?GC$#35!229?G$#36!59?G?A???G?O!8?@@@???AC???@HLHHHJ!9?BVVFUFE!4?E??EMEE!13?@?P@H??H!4?C_?o_$#37!112?O$#38!160?A$#39!72?@!85?@EGC$#42!162?@$#43!62?@$#46!171?@BM[$#49!179?CSW_$#50!220?O!16?G!14?C$#52!122?G!111?C!26?_$#53!83?G???O$#56!72?O!202?O!4?C!4?A$#59!255?!12?_?r}atOi??gOCRqeBU[$#60!70?O!23?_!96?@!37?A???C!34?wK@\InTn~VnzgLX{h_$#61!57?G!4?_!8?G?OC?_!51?@!22?O!40?w$#62!69?D!83?A!54?A!21?A!18?@$#63!60?O!11?A?W!18?_!18?_!18?A$#64!200?@!9?@!10?@!13?C!19?_$#65!218?_!4?_??@!12?G!12?G$#67!66?@?GAAC!10?G!9?_!21?_!32?A???@!80?C$#68!227?@$#69!67?A!82?G!4?G!67?O$#71!154?O!106?G$#72!66?A!81?@?AM[O_!76?C!20?@A@?KH@JTA$#73!65?A!9?O!15?_!35?C!19?@AC@!107?Q?G$#76!65?@?C!81?@!104?A@?AG$#77!217?G???O!5?A$#78!63?@!5?G!158?CCC!20?@?@?EAC?CAC$#80!44?O$#82!43?_$#83!41?O???GWGCSC$#86!44?_O_OG?G$#87!41?_G??_?_!108?O$#88!89?_$#91!130?OO$#92!40?_G_OG??C?g?C!176?@$#93!43?G!4?A?A$#94!49?@!170?_$#95!41?CCAA???@?@@!105?_O!57?A!33?C!5?_$#97!157?G$#98!80?G???OO_!41?G?_$#102!156?C!65?O???C$#104!217?oO?AC!8?@???@??@???A@?@C$#105!231?OO@?A?ABQS?CQ?GA?CO?GO$#107!220?C!10?@@???AC??@C?C$#108!226?_?_!6?_?_!4?_$#109!154?@EGO_!70?oO??OoO_OOC???_{O{]wKwo$#110!229?@$#113!37?_!130?@!93?OA$#114!168?A$#116!124?_!37?C$#117!161?@!12?A!111?O$#118!63?A!116?A!81?@_$#121!211?@$#123!216?C$#124!153?C!39?G!74?C$#126!50?O??@!169?A!17?G!11?O$#127!160?O??G!45?C$#128!54?_!5?@@O!11?_??A!48?A!8?@CO$#129!63?O!94?G!103?CG$#130!76?A!47?C??@!39?_$#131!38?_!117?A!7?O???S!44?@$#132!39?G@!167?C???@$#133!159?O!50?C???A$#135!166?O!95?A$#136!39?C!170?A!4?AO$#138!60?A???_C???O?_??A!4?C!6?G?O???O!14?__!5?O?O!27?@???G$#139!73?A$#140!55?C$#143!41?@!17?A!195?O$#144!66?C!4?O!81?_!98?A!5?_$#146!77?woo??_!32?_??__o$#147!130?@$#148!48?_$#149!160?_??C!4?_!94?C$#150!125?A!31?A???A!100?_$#151!110?_$#152!132?G$#153!81?G!43?_!5?_$#154!42?O!5?OA$#156!220?G!27?A$#157!159?G$#158!157?C!55?A??G$#159!58?C!65?A$#160!158?A$#161!53?A$#162!39?OC!10?G!175?O!4?A$#163!64?@$#165!55?_!6?Ck!4?__!7?CC@?A@ACCDEEAEEECWR?B@RBRF[GGWHWXUE?EHMAH@@@?F?@??A???@AO?[_EU?Nu|?C?GWo$#167!175?o_!6?_$#168!56?ooW!5?GOO_!6?@DC???B@?@BBA!7?FK^[]K[KW!7?HHNH?@L!4?F?B!8?@_}_???~o?A~y{o$#170!55?AB?A!156?@!8?O?O!4?GGG??G!17?G$#173!59?__!20?_?O_??_!28?_!5?_o??_ocCE$#174!42?@??@A$#175!111?O!6?O!13?C$#176!70?@!98?C^}{o_G$#177!52?C!4?@!66?G!92?C!4?K!5?A!11?G$#178!66?_!4?A!41?_!9?G??C!134?O$#179!255?!7?G$#182!177?BFIG_O!68?A???G$#183!41?AA@@A?A!4?@!171?_???O!4?A$#184!225?G$#185!54?OG?C!15?_!75?G??_!97?A??C$#186!53?_!5?@?G!102?C!12?_!13?A!94?_$#187!216?_$#192!71?@!80?@?G!38?c$#193!160?CWwo_@B?GW_!5?@$#194!73?K!78?A!74?G$#195!55?@!4?C!64?O!90?@??@@?@!26?A???GO$#198!167?A$#199!125?@!85?AA$#200!111?_!36?C$#201!219?_?g??B!9?G!12?@???C$#203!193?O$#205!58?_O?_!13?G!52?A!17?@!8?_!70?G!23?@!6?O$#207!131?C!17?AC??G!102?@??o_$#209!76?W?GG_?O_!4?_?_!26?_???oO???O?OR$#211!109?_!7?O$#212!255?!6?@$#213!236?C!5?O!11?_$#215!225?_!4?!4_?@??c`_!4?`?_!4?_$#216!57?A!105?A?_CK!25?A!15?A!38?@!19?A!16?@$#217!59?C!7?G!77?@!111?_$#218!58?@!100?_$#219!255????C$#220!68?C$#221!241?O$#222!46?@@!178?A$#223!80?OO???_!40?GG?gGG$#231!225?A$#232!218?MG?AA?C!9?A$#233!72?_!22?_!25?G!10?O!22?O_@?@!7?@!5?@??O$#234!179?@!42?_!44?O$#235!61?OA?O_!4?_??@!5?A!7?G!5?O!19?O!5?G!13?G??AG_!6?A$#237!51?O!173?O$#238!230?G$#239!50?_???@!12?@A!148?@@!4?D?@!5?A???G??G$#240!192?F!15?@@$#241!217?A$#242!64?A???@?K?K!46?O!34?C!99?C$#244!154?A!64?E!4?G!17?G$#247!40?A!114?@$#248!54?A!173?G$#249!86?O!140?C$#250!39?_W??!4C!4?AA!166?O!26?@$#251!153?@$#254!223?G?C?_!8?P???A`AHAA???_???_-#9!171?C$#11!169?A!36?_!56?_$#12!172?C?_$#17!234?OG$#19!123?G!43?_!68?C$#20!168?A!92?G$#21!52?A!139?G!42?A?A!48?_$#22!123?C!38?@AC!7?O!89?@$#23!178?@$#24!130?_K!6?AG_!12?@!5?G$#25!255?!31?O$#26!123?O$#28!42?_??OG!126?C!38?G??A!48?_!21?C$#29!43?_!5?_!112?_!123?A$#30!47?O!184?A?A$#32!44?__o_o?FB$#33!49?C$#35!170?G!6?_$#36!55?_!21?A!12?_!40?_!4?]~{o??]!5?@@BBBA$#38!181?O!5?_$#39!168?_$#41!132?@$#42!214?C?C!40?G!4?A$#43!172?A$#47!53?A$#49!183?@A?GO_$#50!217?@??P!18?A!6?CC!5?O!4?_$#52!185?C!5?G!70?C??@$#53!64?@??A!86?@!37?C$#56!255?!8?KO?y?C_`?wgKA??C$#59!255?!8?AAMCeXI?qA@B_k?AKYrhhIO$#60!192?@!71?Lo?GAP]DCC_\PyxaDKUUtn$#61!56?A!9?A!63?C!26?G??O$#62!86?_$#63!70?A??C??@!75?C$#65!38?@!205?A$#67!63?@?A??EC??C!25?!4@!28?A!15?@CA?CC!4?G!102?@$#69!159?O$#72!155?@!74?O??G!26?@$#73!129?G!98?_O_O$#76!67?C??C$#77!221?@!22?C$#78!161?_$#79!38?A$#82!40?G?G?A@??@$#83!234?_$#85!123?@$#86!42?C@??B$#87!37?_?KE?@GCA?@$#88!80?E!25?A!9?O!11?_$#91!79?O!14?@??_!55?_$#92!38?oO@^AA?CCAA!164?G$#93!38?G@O$#95!165?_!45?O!6?O!8?A!8?G$#96!64?A!6?C$#97!159?AC!76?C$#98!58?@???@??WSOOo!11?O_!18?AA!8?@?B??@!5?A??A@B?@$#99!57?W!4?Aqs__G_??OOOG_!5?_!73?OOO??_$#102!164?_!80?_$#104!212?O!9?O??_!7?@!12?A!4?O$#107!222?COA?G!13?G?@!7?@$#108!210?_!4?_?OG?_CBaP??G@???@??__???@`o?@@OG?@?@Aa?AG?C___$#109!159?@ACGO!50?_OO??K?A_?_RP?G@@@!4?Oo{lsOKwwWhaqqaedKMKO??W$#110!255???_$#113!35?oC!136?WO_!29?_!4?G?C!23?A!24?C$#114!37?@!132?C!37?O$#117!255?!6?@$#118!44?O??G!83?A!59?C$#121!124?A$#123!123?A!133?C$#124!131?@$#126!48?C!112?AC!50?_??@!7?G!20?A???C??G?_?_$#127!124?@!40?G!41?_$#128!49?G?k?@!84?@CO!14?A??C!75?G$#129!166?_!66?_$#130!50?_!106?C$#131!169?C!4?G$#133!36?GA!127?O??@!40?O!52?O$#134!50?O$#136!215?@$#138!130?OO!9?_!12?A?C$#140!222?G???C!4?A$#141!65?C??GG?G???OO!79?_$#143!36?_!184?O!6?C!27?@?O$#144!49?@!184?C$#145!230?G$#146!59?_!17?@HLG?N^???B^^]]]}{!9?|!6{!4?{_?{{{w!25?AK[!4G$#147!84?_!11?@$#148!37?OCA???C@$#149!164?G!48?CA$#150!167?@???I!4?_!34?G$#156!162?O!66?K!18?G!8?@??G$#157!166?O???@!4?O!86?G$#162!214?OC!33?G!4?O$#165!51?OOooR_!14?BA@BEE!52?_??{?{E`??@A^`}Y[SO!6?C$#167!87?_!86?@JN^}so_??@?O!46?O$#168!52?gKNC@!8?@@??@@?@AC@?CA!53?A~Bx!4?D??@dbgh_A???C?C$#170!37?C!5?O!169?O???_?P???G!5?A!8?A!9?C??G???_$#173!56?G?EOJ!15?G?O?OL??DOB!8?MAW?{?oGA!6?@?ss??Cs???AC?w?oK!24?o$#174!158?@!76?@@@$#176!165?C???wO?`BECO???G!4?AC$#177!41?_!176?@??G??C???A!23?O??@?O$#178!57?@!27?_!37?_!136?A$#179!161?@AC!6?A!90?A$#180!169?@!65?C$#181!158?G$#182!179?G??@ACG?GO_$#183!219?a$#184!158?O!67?_!4?C$#185!48?GO!210?C$#188!245?C$#189!172?G$#192!156?A?A!107?@$#193!163?@BBM][?_p$#194!55?G!12?@!9?CA!12?_!36?O!16?A?O$#195!122?O!85?_!5?G$#198!122?_!140?O$#200!255?!12?O_C?G$#201!45?G???A!165?G?A_!8?C$#203!192?A!70?@???@!4?@QO?AD?P_$#205!56?O_!9?@?A!27?@!4?@@!20?C!24?_!5?G@$#207!231?gWC$#209!56?C?_Nc~!15?W__@AO_YN[[??!4@Ao{C{?{Ks{AB@BBBAwGG~BGGBBBCG??{Ko[C!20?oo?OG$#212!229?_??C$#213!42?O?G??C!112?@??G!53?C!44?_$#215!218?C?C!16?G?O?G!5?O@?O???@!5?O$#216!36?O!13?G!109?GO!11?_!19?@!92?H$#217!52?@!106?C!22?_!50?A$#218!164?O!70?O!20?C$#219!227?_$#221!37?G!125?_$#222!161?G!47?_!13?C!10?@???@!22?O$#223!57?A??O?{GG!5?!4_?G?_??_!14?@?!4A!10?EB???AB???@@??@A?BA@!23?_$#231!220?G!36?AA$#232!243?C!15?C$#233!157?@!8?@$#234!255????@A$#235!52?C!35?__?_!38?G!8?AG$#237!225?C!15?A$#239!216?A$#242!157?A!74?_$#244!216?G!8?G?O$#247!210?O!19?A!9?A?A!13?A$#248!212?_!5?A!24?A!6?G$#249!228?O$#250!39?__!175?_$#252!57?CW!4?C??G_??W?GGo?_!77?O_?___$#254!211?_!5?G??A_?@??A@??C!10?C?@???@??C??@?O??G-#7!33?G!156?G!11?@$#8!178?A$#10!176?_$#11!33?_C!135?C!13?OO!5?G!4?C???A??@!60?@??_$#12!169?A???O!9?O!82?G$#17!175?_!81?G$#19!121?G@!58?O!19?A??@$#20!255????_$#21!52?A!133?G??A?@!40?@!33?O$#22!175?OOO!89?O$#23!228?O$#24!59?OOO?O?G??GG!4?C!4?A???@@!44?OF!5?_WCA??@ACGO_!21?G$#25!169?C$#26!122?A$#29!54?O_!114?A!8?GA$#30!48?@?AA!116?C$#32!34?O!12?@?B?CKW$#33!50?D$#36!55?FN??KgG_!80?C!5?!4_$#37!63?G$#38!174?@??C$#41!65?O!10?C!66?@$#42!121?O!56?_!23?A??@!52?@$#43!180?G!11?C!92?C$#44!70?C$#47!144?A$#49!189?@AA$#50!212?C??@!69?_$#52!226?_!40?G$#53!129?A???AO$#56!255?!11?BCBuLa[QgF?OA$#59!255?!12?BCHOG`_?GR@DcAOhYr@$#60!255??@!13?aTAKVocmGZhlUdKA$#61!71?O!9?A!11?@A!31?O!15?O!9?O$#63!59?A!9?_!4?G??C!13?G!61?_$#64!52?O!110?@$#65!42?C!147?O$#67!58?@??C!5?CC???O??G!4?@?AA!41?_!12?O?C!10?C!16?G???_!56?CA@$#69!43?G!77?_!90?@$#72!216?___O?_OG?GA?BA!9?__O!11?WGCC!8?O$#73!79?C!10?C!127?O?gOkoEcG?C@!22?O_oA$#78!221?C?A?@!15?G?C$#79!47?C$#82!46?O??_$#83!45?_?O$#86!50?O_$#87!49?G$#88!64?CC!7?O!10?A!57?_!9?GO$#91!76?G!79?_$#92!35?w@!8?KAGGO??_$#93!37?@!6?O$#95!36?WAB??_!190?A$#96!85?A!153?O$#97!37?wc_!145?_!22?O??O??@!14?O$#98!67?A!6?@?@G!4?O!4?C!7?A??GG??GG!8?AQO???S!4?OO!16?O!13?A???@@$#99!65?@?@?@@ABA!7?CC???OOO!7?CCUCuWEsc!9?C??C_!4?gII!29?KGKG??CC$#102!197?G!6?A!45?O$#104!208?@!5?C!6?A!19?C??C!6?G$#105!198?O!43?A$#107!202?C??A??A!10?A?@!18?@$#108!188?_??___?o?_??_GWK?WoyC???A@??GA??@!11?s?sj?OJC???_?ICDBI??D@!5?q??@A$#109!187?_?__??Oo??OGGOO_okcKCG?@?OWGKE?E@A?@!6?_ogG}BS~NOJEB`Posjy{PMFA!6?L~E}{$#113!33?OA!136?G!4?@!18?C???A!56?_$#114!255???O$#116!175?@??C?S!84?A$#117!168?A!23?A!71?A$#118!67?G!105?_!10?A!24?_$#119!177?B?C$#120!255????C$#126!41?G!149?O!14?@???G$#127!120?_!53?O???O$#128!51?@@CGO!6?O???G!6?C!55?_!44?_!54?GCA$#129!170?G$#130!56?_!114?O!86?A$#131!176?A_@!9?O!9?C$#132!255?!11?C$#133!197?C!60?O$#135!34?G$#138!53?A???_O!5?G!7?C??C??A?A?@!47?G!8?@!48?@$#139!147?O$#140!45?@!163?O$#141!64?@???@A!15?W!13?A!12?_C!10?_!35?A$#143!39?AAC??C!5?G??_!21?A!46?C!60?_!19?A$#145!165?A!50?O!34?O$#146!59?@BBE!15?ooo_?__!19?!7@!4?@@??@@@!32?o!9?!4woo_$#147!91?O!28?G!17?_$#148!36?A!9?K$#149!186?O!5?G!72?C$#150!168?@!13?O$#151!96?O_$#154!40?C???_O?_O$#156!38?G!153?O!17?_C!5?@!22?G$#157!179?Q!13?G!63?_$#158!35?@!131?@!19?O!5?C$#159!59?_!78?A$#161!255?!11?_$#162!208?_?A$#163!213?_!27?_C!9?GC?@$#165!53?@???MM?C_G?__o?O?OGG!19?MkG!42?F!4?Eg!4?MEO$#167!179?@@BNMC$#168!54?B??@!5?_???o_O???G!12?!4@BFOOoo_!29?_w}D_~~|n^N_@CAEGOxbfNPXKW$#170!42?@???@!133?_!29?C$#171!130?O!14?CG$#173!63?A?AA!4?_?_?O???G?O_WW?_?C?w!4?@@?@@?@?@A?kCkC_G@??O?OA_C?w@?O!13?_G!12?CJOOo?o?_g??C$#174!37?C?C_!168?C!20?GC$#175!141?@$#176!170?@@DNEMKGG??K??G!6?C$#177!41?AG??A?A!119?A!45?A$#178!78?C!19?_!129?G$#179!255????G$#181!145?O$#182!190?@$#183!40?W?_!123?@$#184!162?@!49?_??O!4?C?A?@!17?O?B!19?o$#186!183?@?C!41?_$#188!182?_!28?A$#189!172?O$#192!185?G$#193!77?A!93?AA?G$#194!69?C!19?A!6?G!30?C@!21?A!15?A!60?O!29?C$#195!121?A!59?_!13?G!17?C!49?@$#198!121?C!50?G$#199!255?!30?G$#200!81?@!183?G??O$#201!34?_A!5?@?C!76?O!78?C!11?@$#203!255?!13?G!4?@??G?o?SA$#205!66?C???_!21?_!33?G!12?G!27?C!88?G!7?C$#207!214?__?O?gO??CwQSN!12?O?G!8?__?CWA!8?_$#209!62?@CA!7?_?o_opH@K??CC_??A{?_??@!5?@?@??}QyQy]r?@@A}@@]A???!4@!11?O!10?@BFJ?_??o?oOOwE?C!4?_$#211!136?O!33?O$#212!221?G!4?@???@$#213!35?C???@??O!5?C!147?G???C$#215!198?_o!18?@!12?O??G???C!5?G?O??C@??A!7?x$#216!171?C!22?G!16?G??A!41?O$#217!71?C!138?O$#218!215?A$#219!250?_$#221!41?O!4?_?_?_O!132?_!27?G$#222!38?OW$#223!63?@!11?@!10?C_g!8?H!6?W!6?CO?AK?a!22?o!13?C!4@?GG?A$#231!211?_??O!13?_$#233!164?@!4?@$#235!54?CGOO_!5?O!5?G!14?@!6?@ACG!33?G!5?_??G?@!7?_$#237!48?A$#238!43?@B!9?_$#239!40?@?A!6?C!159?G!6?@$#240!76?A!18?C!159?_$#241!165?@!91?@$#242!97?O!43?G!115?A$#244!219?C!25?@$#247!179?_!9?O$#248!43?A!7?G!213?@??_$#249!74?A!52?A!90?G!19?_!4?A!10?A!9?G$#250!36?c!6?oG!188?@$#251!217?G!25?G!5?_$#252!66?@?A?A@?@!7?GG??CII!8?AA?oGeoA!8?Kgg_?GG!4?ECCE!14?_!14?EAEMCBAC$#254!186?_!9?o???Gc??O?A@?B!7?C!5?@!13?_!16?@-#7!31?O@$#8!54?[$#11!251?_OG?_!12?A$#12!255??G!12?G$#17!32?G$#19!118?_!150?O$#21!255?!32?A$#23!253?C$#24!58?AC!66?_OC_OOGCA@!13?ACGWO_!27?G?G?!4G!4?_$#26!40?O!229?O$#29!33?C$#30!195?_!21?_$#32!33?w$#36!60?CCK!85?MKHBFJC!25?O$#37!134?@$#41!147?@$#42!252?_!5?@$#50!120?A!133?_$#52!255?CA$#53!125?@!55?C$#54!255???G$#55!41?E?_@?O?OP_$#56!254?O!15?GB??QAA!6?G$#57!39?_G?@@???@@?@@$#59!255?!14?@@cSIK?gCTO^KvAwHY??_$#60!255?!15?EW`s?|TzgI_rGtFuc{o$#61!68?`!4?_!20?C???CC?G!20?O?C!54?I???_$#63!68?C!27?OGG!57?G$#64!59?O$#65!182?C$#67!70?G?O?_!18?A?O_?!4O!22?A!11?G!6?@!10?@!20?O@??___!36?O!35?@$#68!52?CA!214?G$#69!99?@A$#71!221?C??@!27?C$#72!63?_!132?OO??W?O?OS?_GC??CC?_?CHF???@!9?WO?A?@@!4?o__KCgDLA!12?B$#73!99?_!98?Og?GG_gGcOoosagOoGVOE?CAA!8?O_??G??A???_??WOOISW$#75!42?A?_$#76!177?_$#80!59?_$#84!41?G$#86!36?G_!15?@??CG$#87!57?_$#88!79?W!11?OO??_!6?_!34?O!32?O!9?C$#89!36?B?a$#91!77?_!4?C!95?A$#92!35?^s]SMA!16?Oo$#94!37?@!154?G!13?A!12?_!45?G$#95!38?@@!139?@!5?C!80?@$#96!69?C?G!52?@!116?O$#97!196?G!68?O$#98!71?C?G?G?G!9?o_!53?_??_!14?WWOW!8?CC???E$#99!101?!4@!7?@!10?@$#100!255?!10?_Ko_$#101!53?_!212?_G$#102!221?O!5?_???G!14?A$#103!43?C??_$#104!239?CO@??C$#105!187?@$#106!41?o[IEe??EEAKO$#107!184?@@!7?@?A???A!7?@$#108!181?@A@??A!4?A??A??B?C?A?A@!18?_o_O?I?BA??A@?O??K?HAA??@!9?_G??dE$#109!180?@?@?AA@?ABADEE?@ECC@A@B@?@@!14?_oWG[M^TNCDDB@?__OW?MED@B@!11?O}VIxU$#111!40?_???O?G_$#113!31?_E!224?A$#114!55?G$#116!55?o!63?C!135?A?@$#117!255?!34?O$#118!33?A!25?G!69?@!55?G!38?A$#119!53?C$#121!52?A!66?A$#123!48?_$#125!45?G?GG?O_$#126!40?C!8?_??@!11?_!202?A$#127!55?C!212?@$#128!32?O!24?@??O!87?@!34?G$#129!33?@!220?A$#131!255?O!12?C$#132!118?O!137?C!10?@$#137!47?O$#138!60?G!66?GIA?G!18?AC?_!24?O?GG!10?O!26?O!5?@$#140!218?_$#141!114?@!121?@$#142!42?_!6?G??_$#143!222?G??A!32?A$#144!65?_!92?_!57?_$#145!207?A!26?c??@?A!4?G??A!16?o$#146!78?Ffff?@NK???N^NN[W!10?E!6}{???]{??W]M!14?M^^^??][!19?bfbbrbb!4?@$#147!100?__G!53?C!17?_$#150!53?G!200?C$#151!100?C!76?O$#154!35?_??G!17?O$#155!43?O!7?Q$#156!194?G!29?C!10?_??_!18?O!8?OCO$#157!54?_!65?@!149?_$#159!127?_$#161!118?G$#163!198?G!4?C!6?@!27?C?@!23?G$#165!59?BBZB[?G!28?BF!26?_o?]]??GMCO?SEO!7?@AF?Oooo_CYG!25?O!7?_?_?_$#168!58?@???OB^V^^Wwoo_!20?@?GNFA!22?_??w_@FpS@bbxgwb!8?@?M!7?so_!24?OO!5oOoO_$#169!255?!14?_$#170!220?O!5?@$#173!70?BBABOrC?W???bG??N?M_!12?E?]`@@@?@??}ay??C_?@@!18?bO??GO!9?AH?F?dabO!6?MppO?A?C$#174!181?A??C???C$#176!222?C$#178!66?_!30?O!59?O!36?O!13?A!14?A$#179!255?@O$#180!255???C$#183!40?@@!144?C$#184!197?G!4?C!25?_?O!4?AO!6?G!4?@!15?B$#186!58?C!193?G!33?@$#187!45?O@!6?OA$#188!45?@$#192!255?!33?G$#194!67?_!31?GG!22?G!13?@!6?A?G!29?O$#195!56?A!121?@!77?_$#198!119?G!136?@!12?C$#200!255?!17?G@`$#201!34?_!20?@!4?_$#203!253?_?G!16?A!5?Ad$#205!68?A!28?__??CO!17?c!15?C_!17?A!19?__?G!17?_!12?A!43?A$#206!62?_$#207!178?_!16?O??_O_o_WC_WC?GA[RjNVGJ?GB@@!7?__O_GSKE??__?o??K_oBAA@@$#209!69?@??@OB?bB_?WW?Eor?N@O!5_!6?A?}?W???@?@A?[C`A!5?E!14?___[N__!10?@@EF?FAD?KW[[K[Kp??@MK??C$#211!130?_$#212!197?_!9?GC$#213!54?@AG$#215!183?A!4?@???@?D?@?B!21?_!5?_!5?A!25?_@gO?`$#216!32?_!24?A???_!159?G$#217!56?@!193?_O$#219!210?G@!17?_!12?O$#220!119?@!145?C$#221!39?O!16?_$#222!183?C???C!13?C!64?A$#223!69?AC?KCKCWS!4?Wo??_?O!11?@???_!12?@A!26?O__!10?Ww_?GC!8?IIM??G$#231!200?C$#233!190?G??O$#235!98?@A!32?CA!15?@!29?O$#237!223?C$#238!253?O$#239!34?^!142?@??A!10?G!16?@$#241!119?O$#242!57?CG!86?C?O_!33?_!26?@!10?G$#243!44?G?EE??K?G$#244!229?O!10?A$#248!254?G!14?A$#249!232?G!4?G?_!5?C!18?C$#250!189?C$#251!195?G!9?A!27?C$#252!86?O!26?@?@??@$#254!187?A??D??G?C!4?@???A!25?G!7?G!19?C!4?G-#7!28?_OA$#10!30?G!166?_$#11!244?_!4?A@!19?_$#12!55?@!60?O!131?C??G$#17!246?G!5?G?A$#19!247?G!22?G$#20!116?G$#21!80?OO!114?_!50?C???O!28?A$#23!31?C!44?OO$#24!119?__?OCCDAA!29?CGG!34?O?@$#26!38?G@!4?C!6?GO??Wc!214?G$#28!36?O!241?G$#29!255?!37?O$#30!32?D!173?O!8?@$#32!30?_OQ^!30?_$#33!31?_G!36?O!10?G$#35!202?_!13?@$#36!110?!4_???Os??kco!29?@GY$#41!197?G$#42!249?O?@!19?U$#43!255?!22?O!13?C$#48!116?C$#50!34?G$#52!191?C!6?G!48?o???C$#53!196?C$#55!39?SGG@C??@C?AC@KAD$#56!255?!16?@oMvGG$#57!36?_!4?C???G!5?A$#59!255?!17?B@?@CGA@`zt~q[AxOAC$#60!204?O!39?O!27?C??EAE@A?CA?Lb|Enlyw_$#61!133?O???@!16?O!6?G!32?C$#62!212?C!76?O$#63!75?@!35?O??G!24?C!30?O!18?@!8?o?_$#64!63?Q!12?C?G$#67!106?_???O??G!5?@!11?_???O??OOOG!8?AC???_!12?C??O!15?@@?C!23?@$#68!50?@!5?@!8?O$#69!61?A!8?@!128?_!9?C$#71!191?O!6?A!48?A$#72!76?@!122?OG?DDEGc?SOoQo_O??_OogoS?Kq?OYo@{C?WGAILhKOQX@?A!14?O$#73!132?_!66?KTS?GG?@`?a?h@WgwoGgGOK_GaG{M?F}?WGcq{cAQQbG?KA??@!11?_$#74!39?GO???@$#75!38?_?C@G??SQ$#76!203?A!12?G!8?CA!16?A???@$#78!220?C!41?O$#80!35?G?@!19?O?@$#82!35?@!23?A$#83!58?O??_$#84!47?G$#86!36?GA!22?O$#87!34?_!23?Gw_W$#88!81?C???A!8?@?@B!12?A?GC!24?@??C??C!20?Q!5?A!4?@!5?C?@$#91!100?@!87?A$#92!35?CFC@!18?FB?E?_$#93!217?@$#94!69?G!145?A!46?_$#95!65?GCKKCGGG!181?C!14?A$#96!101?@!134?@$#97!217?C!46?A$#98!77?@!5?A!4?OO!10?_?_??@!8?AA!26?@???CC!24?@@@!16?G!67?_$#99!174?O??__???Gogwo_WGG_$#100!255?!8?o[UvBv{$#101!51?O$#102!93?_!95?O!24?C!6?A!13?@!27?@$#104!90?_!133?@$#105!255?!4?O$#106!39?___OwoaKpACW_$#108!217?A?BA@?@!10?@!19?O?A?GA@A$#109!89?_!126?A?B?@?@!29?_og{|~tHMDB$#111!38?O??AA???_A!5?SA$#113!29?GC!218?_!20?@$#114!250?O$#117!72?O!5?O!176?@!23?C$#118!30?O!33?O?_!4?O!12?_!43?@!31?O!35?O!51?A$#119!55?A$#121!56?A$#123!37?G!79?@$#124!246?_?OG??A@$#125!52?@Hw$#126!75?K!11?_$#127!246?O?_$#128!73?OOO???O??O!39?GG!31?@A!4?_$#129!31?A!33?_!129?O$#130!63?C!57?O$#132!245?_$#133!117?C!152?S$#135!255?!25?G$#136!116?_$#137!38?C!12?CA_?c$#138!124?IA!33?O!34?G??A!10?G??C?A$#139!75?A!86?_$#140!61?@??G$#141!87?O!85?O!15?_$#142!48?_$#143!76?GG???G!187?@$#144!192?C!10?O$#145!231?A??A??@$#146!79?BB@C?@LG???NIZ!4YO!8?CSUSCCE!25?_aea?AyO???YWWOO!11?LL]IEEK???MM??FFF$#147!80?C!17?@!62?C!28?A$#148!57?G_?G?O$#150!254?@$#154!35?A!22?CC$#155!43?@A!4?O??_$#156!88?_!126?C!48?_gG{$#157!117?A!134?CA$#159!73?@!55?@$#161!33?_!32?O$#162!38?A$#163!160?A!65?@$#165!109?_??OO?O?_GOFBBBo?osoSCOO?C?C?KGG!9?@BBEEC@X???O!29?@@?A?A$#167!210?C$#168!74?@!33?_!5?oG???MG???@wGGMizNNNJNJMA!13?CG??{_reK!29?@??B@EG$#169!250?_$#170!34?A!27?@!5?O$#171!160?_!34?_$#173!78?@!4?DI?AJFMO!6?C[K[M^FMS!10?@!20?_???@iC?Cwg`!11?@@@PA?_?_??@I?K_?IG?_??BCCCE$#174!255?!8?G$#177!73?A$#178!77?A!56?O!57?O!4?@!12?G!34?G$#179!31?@!213?O!24?A$#180!29?_!223?C$#181!195?G$#184!82?G!90?_!16?_!27?C???A!9?A@!28?C?@$#185!193?G!49?_$#186!62?A!4?!17_?_!29?_?G$#187!37?o?A!5?@??P`A$#188!40?A?CA!4?G$#192!203?_!72?_???O$#194!76?A!30?_!33?OO!6?@!12?O!6?G?__!19?A?_!12?O$#195!62?C!4?O$#198!56?W$#200!255?!17?GOGO!6?G$#201!34?@!39?A??C!5?O??_$#203!250?CA@!20?_?_P@C$#205!78?AC!35?C!20?OO!5?O!8?G!6?@???_!6?G!14?@@!4?A!14?G!35?_???C$#206!63?@C!7?A?G$#207!198?@BAJY?@fAEb@B?G@???O!4?Gc???`dG?@_s?C?OoC`KDCAD@!14?_G$#209!81?AB?C?D?G@?TCDCDCGARAO?OO_ZJHJHJ@?C!18?!4_??@@??h@iAQYcc!4_!7?KK\_Q`Pp`?CMA@oCFwGwBCAAA??A$#211!158?C$#212!223?OO$#213!57?_??@?G_$#215!251?_!6?AC$#216!63?G!6?O!8?G!169?@$#217!31?G!173?O$#218!64?BFJBBAEECKC!9?O$#219!232?@$#220!69?@$#221!35?O!25?C$#222!213?C!11?@!26?O??A!5?G???@??G$#223!87?C!8?__?_?_?g`I!7?B?@A!25?C??@@@C!12?AAA!11?O?@??O?_!5?CC$#233!201?_!7?G$#234!255?!35?@$#235!72?@!45?A?O!5?D@!26?@??A!37?@?S$#237!32?_$#238!249?CA$#240!71?@!121?_!13?G$#242!34?O!43?C!113?G!5?C!5?_!7?A$#243!40?@O_?G???CG_$#244!91?__?_$#247!35?_!82?@!131?G!20?_$#248!34?C!179?A!33?G$#249!192?_S!25?C???A!9?A!29?E$#250!253?G$#251!85?O!130?C!43?O$#252!83?G??O!8?_??_!15?@!49?_!7?O?_??OO???OGO?GW_?O-#7!26?A$#8!237?O$#10!169?_$#11!23?O!4?@!218?@!21?G$#12!113?_G!124?G!5?A!22?_$#17!242?@$#19!114?C$#20!239?O!28?O$#21!68?O!129?C!95?O$#22!242?E!26?O$#24!117?@@!43?@???GO??_!28?C$#26!35?{!7?C!10?_?@$#28!93?A??C!17?_!4?O$#29!27?C!59?C??A!11?C!12?G???_$#30!86?_?GICG?CG??O!4?O_!4?_???G???OO$#32!65?A?_!19?oSCG?KGCCW???g_?WWwwgWoGW???o__$#33!26?G??A@!35?G!19?OGA??C???G?GGG?GgC_??O?Go_o!5?_$#35!213?O$#37!198?G$#41!196?@??O$#43!255?!22?G$#50!104?C$#52!201?A_!29?_!10?A?@!23?_!8?C$#53!117?CG!40?A!13?@!27?G$#55!40?O_G?W_??GpAw?@]?AK$#56!255?!15?OLB@@!6?@$#57!255?!14?A$#59!255?!22?O?EB?!5BMaO$#60!255?!26?A???C{p\n~~~w$#61!110?@!9?G???O?A_!6?_!30?_!9?AG??_$#62!255?!23?OGC?CCCw!7?C$#63!128?@!28?@??C!16?C?G!16?C_??A!18?_$#64!23?_???G??A!33?@!25?O!8?O!178?_???G?O$#67!112?A!16?@??O!25?A??G!6?G!5?@?A!6?_!8?A!4?OO!5?A!15?_!9?_$#68!57?@$#69!66?_!62?G!63?O??_!6?_!11?O$#71!136?_!72?O!12?_!5?_$#72!202?DPGR`?`e_DgEBEHGA?DWQ?@hD?ROEOJB@HFFA@!12?_?_O??KCC$#73!203?G`gQPS@D_C?C@QRXEYFGF{AWt?CXNO[AC!4?@!12?_OgWW_JA@$#75!43?A?O?@$#76!178?C$#79!32?C$#80!28?_?g???C!24?I`??@$#84!44?C?@C?I?C$#86!33?@P!23?B??W@_$#87!25?__OO_Ogwm_!23?CTOdY]Ko!23?!7_$#88!171?O???G$#91!151?@$#92!34?G!29?O$#94!104?A?@$#95!100?AA?A@BA$#96!130?H!43?_!9?_!10?AG$#97!255?!5?OC@$#98!134?H?WG`???CW??GgW!8?A?GO???@!7?KKW_!7?OO?SEGKIOC$#99!129?EA??BCMCAC!4?C??FBF!9?__??__!8?A!5?A!4?B@_```__?``_$#100!255?!7?UyfHrYF$#101!50?G!210?O!4?C$#102!100?@!29?C$#103!36?A!7?A$#104!93?@??@!151?A!7?A$#105!251?O$#106!36?KUHD?@???Mio@??B@$#108!248?C?C??G$#109!239?___oooww{w}ZNFFFB@@$#111!38?_o_GEG???A!5?E@?KO$#113!21?_???C!210?O?O??I$#114!24?G!213?G!4?C!26?@$#116!55?w$#117!66?@!21?@!204?@_$#118!66?C!19?I!11?CC!14?A$#123!57?A!187?C$#124!238?C$#125!36?@_??GCoo_!5?_?ww??o_$#126!24?_?O!5?@!31?AG!25?@!6?A!8?@!12?O?O!126?@!18?G$#127!114?O$#128!25?G!39?@?C!17?G?A!77?C!32?@?@_!31?_?O$#129!26?C!221?@$#130!66?AG_!15?_OC@!80?O!30?@!37?G$#131!244?A!22?_$#132!246?@$#133!244?C$#134!234?_$#136!113?O?C!119?_!6?G!26?C$#137!35?B!5?O!13?B??o$#138!116?E!46?AA??G_!28?A?g_?A??C!6?O$#139!164?C$#140!95?O!15?C!104?_$#141!131?CC!10?B!41?@???@?_$#142!36?_?OG!12?C$#143!29?C!160?@!91?_$#144!108?@!64?A!17?@!11?C??G!72?_$#145!255??C$#146!176?O???G$#147!156?@!25?O$#148!27?_?G?C?O!26?E?_$#149!115?A!130?A$#150!115?@!124?K??@!26?A$#151!163?@$#152!198?_?G$#153!133?O$#154!29?OCOA!27?GA??_$#155!40?C!7?O?P?A$#156!92?@!8?@!136?_!21?_ggCWuGD$#157!55?C$#158!22?_$#162!237?_!43?O$#163!159?C!4?_!28?C!57?_?O!6?G$#165!113?@!4?E??@HHG!40?Wo_!8?C??OO!17?A$#167!196?A!4?O??C$#168!111?@@A@??A?FFMEEF^XXooo___!24?@@BFMKW!4?O?_??AC?GW?___$#170!31?@!238?G$#173!137?_??F?G?eE???NAcFCF@w!9?B?F?B!4?@!4?B?G$#174!103?@!137?O$#177!97?A??O!142?G!36?O?O_$#178!123?O!11?_!36?@!4?O!15?A@?O$#180!27?A!211?C$#181!200?O$#182!218?_!55?A@$#184!195?_!58?G???@$#185!92?A!7?C!19?_!79?C$#186!24?O!42?RN!15~^F@!4?A!5?C!19?G!122?A$#187!48?C$#188!50?C!7?G$#192!203?A??C!8?_!56?G??_$#194!109?@!18?G??O!34?C!5?_!8?O!12?O!15?O???O!21?G$#195!65?C!22?_?@!5?A??_!180?G$#198!255?!15?C$#200!201?C!5?G!64?CA??__G$#201!92?O??A!5?O!19?_!118?O$#203!255?!16?A$#205!127?A!37?A!4?O??_C!22?G!13?G?_!7?_!7?_!9?A$#206!111?A!10?_!146?@$#207!202?O?O??a??AAB@GGCCCX??DwASaIKJ??C?KA??@!17?_cQO@$#209!139?~w~o?Xw!4?|Ywzw}!6?O??@?F?NKN!4?`??FCNC$#211!197?C?A$#212!125?_!76?G!5?A!4?G$#213!59?_!36?___!181?__$#215!252?G$#216!28?A@!55?_!15?C!10?C!5?O!122?C!28?_$#217!113?K??G!91?G!70?@$#218!99?A??A!4?!4A!10?O?__$#220!255?!4?_$#221!28?G??A??A!27?C$#222!102?@!160?@$#223!134?OO?OO!4?_?@oO?o!7?WWOGO!10?OO?O?_!4?AKK[GG??CK!4G$#231!97?@!148?C$#233!116?@!78?@!15?O$#234!209?G!7?_!53?O!4?O$#235!197?@$#237!89?@!20?C$#238!94?O!10?CCC!136?@$#239!25?O!40?O!22?O?O!155?A!33?C$#240!195?C!14?G???_!68?GG$#241!255?!24?O?G?O_$#242!119?G!6?c!36?O!30?CO!5?@!5?C!23?_??O!6?@$#243!36?OHEABA!4@SGaC$#244!94?@@??@@$#247!236?_$#248!28?C!64?OA???O!9?CC!163?C!19?A$#249!127?C!50?_!12?A??A!62?A???A$#251!252?O$#252!128?E??JJKA@BDI???B!4?C_!7?EcC?__!15?B@???@?AAAOUQO?O!57?_!4?C$#254!244?G-#1!75?G$#2!72?A!8?_$#4!76?O$#6!74?O$#7!20?@AA???C$#10!76?A$#11!30?O!230?O?G$#12!111?O!155?@$#13!69?@$#17!78?A???O$#19!110?_$#21!30?_!39?G_!194?O!27?@$#22!113?@$#23!71?@!197?@$#24!138?G??O!28?BCIq?G??o!9?_?_G?A!4?oP$#25!22?@!249?A$#26!46?C!5?Q??G$#28!115?G$#29!34?G_!34?O!43?O!14?_$#30!32?OoO!65?@!12?_?o?OG?@!5?OO$#32!31?_!37?W_!12?oKB@!8?KGCAD?@@B@!7?_???o_PX?G!4o?_$#33!32?_?_O!32?A!15?OC!10?CAC!4A??!4@!5?_!5?WOGKGG_?_$#36!140?G!30?W??_?_!16?___$#41!189?G$#42!112?@!148?_?O$#43!193?@!75?G$#44!194?@$#47!172?C$#50!94?O!25?A$#51!191?@$#52!255?!19?@$#53!132?@?C??B!45?CC!9?C$#54!255????_$#55!36?E???B@A??@IO_`gBlA^o???m$#56!255?!10?!4_owgk{}oG!9?_$#57!112?G$#59!255?!18?A?@Pn!5?___DVo_C??G$#60!208?G!69?_???_?OGYgN^zn~E$#61!129?@!7?G??C!7?O!34?O`$#62!200?O!78?_???OGF!5?O?@$#63!131?A?C?G?O??_C!7?_!12?_!7?O!4?@!5?__$#64!84?_!10?O??G!7?A!12?A!6?C!155?O?A$#67!134?G!4?@!5?G?G!4?O?_!7?O!4?A?G!29?A_@$#68!111?C!11?@!4?G!103?@$#69!28?A!39?O!22?_???AO??G!30?A?C!27?G!26?@@@!14?A!5?G$#71!243?O_!8?C$#72!208?BB?C?AA?C?Ico_G??OO_?o?O??O?__o?_?_??W_OaQ?_Co?{KF$#73!200?AO_???@??CABF?@BAicGGGo_O?_OO?O_oo?oOO??OOW?O_[KSgvOb@[?B$#78!161?G!53?C`$#79!61?O!28?_!5?_!5?_!11?C$#80!32?@!30?B!23?C@!15?GO_!4?A??A$#82!86?_!17?_$#83!31?A!29?A???A!28?@!22?A$#86!27?@!6?D!30?OC!19?G??Q?EH!6?o?GOoOG?G?A$#87!28?@BB??F!26?QLFW~hOc_!16?_OwIlV@EDa`?oo?_oGGCCSS[KE??C?CA$#88!146?_!7?G$#89!62?__?C?O!20?c??O!8?O!9?G$#92!32?A?A!25?C?OC??AG!25?A!21?A!164?@$#94!125?@A?AA???_!68?@_!8?O$#95!126?@ACCCKW!124?_?O$#96!238?G$#97!136?_!120?OC@!5?@$#98!151?E!11?GG!81?A$#99!143?@A?A???A!6?F@@?EFFB$#100!255?!4?EJBC$#102!135?_!12?@!82?!4G$#104!149?C!53?O??G!35?C$#108!203?AC??O!13?A!5?A???A!9?A???@?@$#109!202?EKowo__!14?AEEECEEECEEBFFBFFFDBBB?@$#111!36?@_?E??@E?AO_?]Fc!6?@O$#113!23?AA??CC$#114!29?_G$#116!36?_!18?@!206?O$#117!26?A!95?A!74?G?G$#118!72?@!36?_??OO??G!4?C!54?G!17?AA??G$#120!75?A$#121!35?@$#124!204?@$#125!37?^~x{}{x~{`M^??W?|??~~}$#126!85?O?A!15?C!4?A!21?O!82?_!68?B$#127!111?_A$#128!32?G!87?C!16?C?GO?_!28?@??C??O!11?_??G??GG??_$#129!29?C!49?A???C$#130!31?G!37?A@!9?AAA?@!38?A!55?_!13?GG$#131!255?!7?G???@$#132!255?!9?G$#134!77?A!5?A$#135!255?!8?_$#137!36?G!13?O???_C!55?G$#138!136?C!4?_!27?@??O!13?OOCC?_!4?Qp@CK$#139!136?A!35?@!19?A$#140!93?O!27?_!7?O$#141!143?A???E!10?C?A$#143!35?C!31?A!24?Og!19?G!4?A!161?OGC$#144!128?@!57?@???@!20?_$#145!202?O!10?C?G!25?G$#146!145?oO!6?OOoo!9?!4o_$#147!140?@?A??C$#148!31?@!29?_G???`!23?GG!13?_G$#149!255?!4?_!4?C$#150!255?!5?_!5?A$#152!187?A$#153!159?C$#154!26?@!33?@!5?G!212?FC$#156!230?G!17?@!9?WGCCBA@$#157!55?A!56?C!152?C$#158!29?G!235?A$#159!194?O$#161!107?A!7?@!163?O???A$#162!255?!28?@$#163!207?G!4?G?Co???A!4?G!22?A!10?A$#165!139?O??O!9?__!15?AG?_??oEg?WwW???O??!4O$#168!130?@@ABBD@?AEA!9?__!15?@BCC_?HZA?EMFFF^JYmmGIAAESS?CC$#169!255?!5?O$#170!87?@!8?A!13?@???G???C!12?_!91?@@@???@$#173!141?@??G??_??GGDFDAE??o?_???@$#175!187?C$#176!197?A$#177!86?C!7?C??@!4?C!10?A@??C!101?@!11?@!46?E??OGC$#178!136?O?O??A??_!32?@!7?@$#179!25?A$#182!255?!16?C$#184!134?O!25?C!52?O???@!4?C???G!17?C$#185!125?C??O?_$#186!33?G!39?!9@`@A!34?C$#187!35?A$#188!59?@!50?O!109?@!42?C$#190!21?@$#192!209?GO!56?O$#194!136?G?@_?G!4?G??OOO!14?@!9?@!6?_!14?A$#195!116?@!104?@!8?@$#197!73?A!8?G$#198!36?O$#199!255?!10?G$#200!255?!13?O??OO??E_!8?O$#201!27?A!39?@!17?G!15?C???A!116?@$#203!255?!20?GEO$#205!142?KO!4?_!19?C!36?@???O$#206!125?A!6?_!128?G??A$#207!207?B??D??@???SOOC???_???_?_???_!4?_?_?GG??_GC?CWIaB??@$#209!143?GOB!6?IGALGoo?o??OowMKG$#211!198?C$#212!221?O!29?J??@$#213!25?@!6?C!27?_!55?C!101?@!60?GGF$#215!204?G!17?A!11?C??C!7?A$#216!30?C!37?@!14?G!33?G???B@???GG$#217!31?O!37?C!52?C?C!168?O$#218!124?@??D?GGO?G?O?_$#219!144?C!56?_!9?G!4?W!4?C?W?_!13?O???_?C!4?G!5?O$#221!60?G!27?O!7?@???G!8?O$#222!208?O!18?GG!4?@???G!25?@$#223!142?@?@?C???D@!4?@GGG??G??E$#226!74?C$#227!74?_O???_$#228!70?CO??I!4_$#233!195?@@???@!4?A?C$#234!108?_!153?_?_?C$#235!135?A??C!4?_!27?A?C?CO!10?_??K?_??O_C$#237!86?A!7?G???@?C???A!4?@!8?_!5?A!67?@$#238!23?@!45?_!47?@$#239!24?@!67?_!18?@!166?O??_$#240!206?A!4?O_!67?_???C$#241!31?C!36?G!209?G!4?G@$#242!107?_!30?_!8?O!13?O?_!14?@!22?G!4?C?C!69?@$#243!47?@$#244!148?EA!59?_!13?C$#245!70?AM{{?CK[[[{[C$#247!35?G$#248!68?C!28?G!21?__!80?C?@!22?@@@!38?A@$#249!143?C!4?G!52?A!8?_??Gw!10?G!13?GG!8?@!6?_G$#250!255?!25?A$#251!133?O_!67?G??C!14?A!8?G!6?G!6?C$#252!146?@@?H!8?AA@@??C!70?G-#0!74?A$#2!39?O???_!9?_???O$#4!74?@_???@$#6!59?G!15?O$#7!27?C!9?G!16?_$#8!197?_!24?_$#9!45?_!5?_!4?O???C!12?C?K??A$#10!40?O!5?_???_!30?@!108?C$#11!198?_!26?_???!6_??_!11?G!5?A?@$#12!54?O!55?@!127?_!6?O$#14!47?__$#17!36?_!24?G!129?C$#19!110?A!128?_$#21!62?O!9?A!119?@!54?G$#22!36?@!71?OG$#24!143?@!30?@?G_!9?A???G???A?G$#25!197?O?_$#26!59?A$#28!95?_!24?G!10?@!8?O$#29!30?@!49?_C!15?O!4?C??A???@?@!24?O???_!115?@$#30!35?@!27?O!18?A!14?_?G_?OG??K?A!13?@???@??A!5?O$#32!31?@@?@!30?_!4?B}O!8?W@!13?_?ooWg?CKC?EC??A@@B@???_C!6?@B@BEIGSgG?_$#33!33?BAA!34?C?g!28?OGO?GA?@???Q!6?O!9?CCGCSG?_oO_$#36!146?C!4?_??A!21?CG!16?C??CC$#37!188?C?G$#41!173?@!16?A??A$#42!243?_!13?A$#43!105?@!109?A!73?G$#47!187?O$#50!113?A!178?@$#52!195?@!27?O!31?C$#53!181?@$#55!37?@?G??O!10?O???G?@$#56!249?_???Gogwgm]fp|z~nz~~n@^tlpidBAC@??C!6?C$#59!255?!19?IO?ClZ{~vz~z\WA@AA$#60!199?C!82?G??CAFLE@@$#61!142?@!6?G!5?D!7?@!15?a!5?@?C_$#63!147?G!4?A!13?C!12?O!6?E$#64!34?C!26?C!73?A!77?@$#65!111?C$#67!141?@?A???A??@!17?O!12?A??A?_!32?G!6?O!9?O!7?G!7?A$#68!107?_$#69!111?O!7?C??G!25?O!31?i!46?O!7?O$#71!218?CC!10?O!15?C?A$#72!200?SOsQowO!8?@??A?GGG?C?AK@AKCGGKA?GB??GND?D?A@?@??@$#73!157?C!41?OJMJcK?__!11?BFA@E?KGBID?I@FB@FCGJEA?AE?@@?B?A??@$#76!174?_!6?CC!34?@@??@??@!6?@$#78!181?o??_$#79!33?G!56?@!4?@!7?@!9?_!5?A$#82!32?C?_!28?AA@?CI!14?OG???c@C???CA!6?@!7?OG???Wo_G!9?_$#83!35?G!32?O!20?O!25?_$#85!183?G$#86!29?Sk?_O!32?@!15?_GoAI?@?OcC!4?@!7?_!17?CkGo?O$#87!28?ogOCW_GO!25?BD@?E]WDw!13?_EhTUYGiAYI@KEEBBB@!4?_O??G???O?EME@??ogQ?CgGO__$#88!146?@???G!15?A@?@$#89!31?G!30?A?C??A!17?C???A???@A?@!28?A$#92!31?_!33?G!19?O?_!4?@O!15?_!6?GO!5?O?o?O?_$#95!138?C$#96!144?C$#97!137?A!80?O$#98!146?OP?@!10?Gw?O!9?O$#102!138?AACCC!4?_!63?@!4?G$#104!137?@!6?W!60?A$#105!206?C???G$#108!209?OA???_$#109!205?@BF^nt}}wWwoo__$#111!38?C!4?OO???@@?OO??BG$#113!26?oGA!164?GG!32?__!6?__!7?O!7?C$#114!226?_$#116!37?A!16?M!53?_!141?G$#117!94?_!14?A!110?O!20?O!46?O$#118!73?O!6?O!15?O!9?@!13?o!75?G$#120!196?O$#123!60?A$#124!217?C!27?!4_Oo_OoGOCC??W!4?O$#125!38?BF!5N^^^]]^NNN?KFFF$#126!30?A??C!36?_!23?O!17?C?G!8?A???C$#127!58?G$#128!81?A!93?CO!11?AC?`C?O???G$#129!62?_!17?G$#130!63?_!9?G!116?_??@!48?O!8?C??A$#131!247?O!6?C$#132!36?A!205?_!8?G$#133!192?G??O$#134!195?G$#135!27?O$#138!144?@A!28?AA!10?@?OQ@??C@?_A$#140!104?O$#143!60?@!4?O!16?O!9?_!8?A!4?O!11?_$#144!63?G!32?G?C!81?O??D!30?A$#145!181?G$#146!150?AECc__`!9?@CLKLLC$#147!157?A!5?A!9?G$#148!31?O??O!29?@!21?_??c???C!20?_!10?C$#149!29?@!191?_$#150!37?CG!70?C!113?__!28?C!4?@$#152!187?G$#154!67?@!19?H???O!23?C!10?G$#156!139?C???O$#157!240?_!5?O!9?A$#158!28?C!26?O$#161!69?A!69?G?O?_!73?G$#162!220?_$#163!182?g!22?C$#165!153?B@AC!8?CGo_!5?C?BT?@!7?@?@!6?C$#168!144?A@???OO@@???A!7?A?O!5?@AGp?A~K!8?HGOQQ__c$#170!64?O!37?A!18?O!6?C$#173!145?G??aE!7?OAeAC@??O$#177!27?_???A!38?O!32?_@!7?GO!7?_!4?A??G?O?_???C$#178!165?G!16?@A??O!11?P?_!15?A!38?@$#179!243?O!4?G$#180!49?_$#182!216?C!22?O!4?_$#184!135?@!4?G?O?_!67?@$#185!98?G!22?C!10?@?A??G?O?_!54?A$#186!36?O!27?_!38?AA??@!13?G!13?CC!84?O$#188!109?O$#192!180?@!17?A!54?A!32?_$#194!140?@?A??C??C?_?_?C!10?A?G!6?O!12?_!9?@?A$#196!37?O!23?_!17?O$#197!52?_!8?O!12?_$#198!41?O!12?@!4?C!181?_$#200!255?!11?C??O}_IQC?QGO_$#201!29?A!40?G!28?C!12?_?C!8?@?@$#203!251?O_!4?OO_?MAC!11?DGo??A$#205!141?A!4?G!4?O!12?C?_??_??A!7?C???Go!13?@!28?OO???OO!13?C$#207!201?`?H!13?A???CAHIBD??G@OU??KGBC?HD?G@AAC??A@@$#209!143?C!5?_CG!5W_C?C?CC?@?AAQqqw$#211!189?_!4?A$#212!222?C!5?C?A!8?C$#213!67?_?C!13?C@!6?@!12?_!13?P?@$#215!207?G!5?C$#216!73?_!27?C!19?A!11?A!4?G???_!116?@$#217!71?@C!24?G!24?A!117?O!5?G$#218!134?@?A$#219!204?A!11?@$#220!139?@!44?O$#221!35?_!27?CG???_!22?G??G!15?_!19?O?_$#222!207?O!5?A$#223!148?@!8?HxXpBygw_$#225!77?_$#227!44?_!33?C$#228!72?@!4?O?_C$#229!75?B~N@$#231!136?@$#233!186?G$#234!100?C!117?GO!30?C$#235!146?ACG!26?G_!15?_O$#237!82?C!30?G!13?A!94?O$#238!35?CC!44?_?@!9?_!27?@!8?G?O$#239!32?A!33?_??@!12?G!22?O!7?C!5?GA?C!10?@!50?C$#240!182?A??C!10?@!17?@!9?O!13?O!6?G$#241!36?G$#242!28?G!33?G!20?A!31?A?@!6?@!39?@!8?C!10?@I!13?G!25?O!11?O!11?C$#244!142?GG?O!68?C$#245!37?_o!4_!12?___oow!12?B[???wMB$#247!108?G?C!137?O$#248!95?O!6?_!4?G???_!4?@!17?_!117?G$#249!182?Oo!22?G!8?C$#251!138?@??G???_!58?@???_$#252!140?A!5?_!26?_-#0!45?@@?@@!10?C!14?C??A$#1!76?C$#2!36?A!38?G$#4!44?@!5?@$#6!36?@?Q!13?@!22?OA$#7!24?C!28?O@$#8!23?_!171?C$#9!40?@@!11?Ao!4@!17?@$#10!62?@!12?_??G!113?@??A$#11!200?@?A?C?G!17?AC$#12!209?_!19?_$#17!24?O!49?A!118?@$#19!105?_?A!89?@!7?G!20?G$#21!66?AC!18?O!65?_!43?O!76?_$#23!63?_!14?_$#24!178?C!12?@!4?@$#25!35?C!165?@?A$#26!106?S$#28!63?A!5?_!9?C!7?O?A!29?@!24?P!61?O$#29!67?ACGO???O!67?PG$#30!63?@???O_??O!8?@!8?G_?CICC!46?C_??K$#32!64?MOg???G?al!5?wA?__O?_CooWKYCHBBA@!11?A!26?@??BfACMS_WO?o$#33!65?KP_?C??DQ_!10?G?_???o??A?C@?@!8?O!29?@B??_A?GO_go?_$#36!168?@EKo_???E{!14?A$#41!192?G$#42!204?G!23?_$#43!155?_!42?@?A!23?@!5?@@$#46!199?GC$#50!118?_$#51!157?O$#52!225?@BEEM]ME!4AEnypcHZl]O$#56!255?@?SH?!4@VC`@@H@_@?@$#57!108?@$#59!231?O!30?O_??WKO??EKC??EK?FFAB@$#60!232?G?C?Go$#61!153?@!15?GA!4?@???G???_oGCA$#63!182?_OG?A@$#64!25?G!45?G!12?G!12?C!12?@!7?C!30?C?G!82?G$#65!109?O$#66!232?O$#67!153?a!14?C??C?_?A!4?^KCC!20?A$#68!80?_$#69!85?C!24?_!70?A??A@!20?C!26?_$#71!183?A!23?A$#72!206?@?B?O$#73!203?@@??C??GO_$#78!182?@?@!25?C$#79!97?_!4?G$#80!26?G?O?A??A!52?A!10?G??O??G!9?G??W!7?q_???O???O$#82!26?OCCGOC??G!49?C@!9?O??_??g??PC!6?A?BG?C!4?CA?@??CBAGG?A_O?C?G$#83!33?g!67?S???A!21?G?C?_$#85!112?O$#86!27?_?O@!38?@!29?O???@G!6?_??_??O!5?H!8?@C@??_$#87!26?_Jh?G?@@@!35?@!10?OH@??@@@!10?CG?@_?@@??@OO?R?@AB???co?CI@`J?LP_@s?A[G$#88!175?C$#89!25?_!89?_$#91!160?@?G$#92!26?CO?c_ZiSE!35?A!11?ECAA!8?_?_OWgCAeEA!6?Cc?[Udg???YJs?OMUog?EEi?QK?OO$#94!146?@$#95!221?@$#97!148?A$#98!150?A!10?_$#102!148?@A!61?C$#108!214?W?@?CI??_$#109!210?@BBNF}y~zTvu[{o__$#113!23?OGB!27?_A$#116!196?C!6?C!23?G$#117!79?A$#118!63?C!24?K??A!27?K!20?_OG!133?O$#120!74?@$#121!105?O?C$#124!233?C?CDHODMZucQ`n~z^z\^FZ_LB?@G!4?@$#126!68?@??C!21?_??G!9?a???G?@!7?_$#128!64?@@???O_???C!9?__?G?CA?@!59?O!24?@$#129!78?O@!114?C$#130!63?W!4?G!126?G?_!12?_$#131!208?_$#133!208?O$#134!35?G!157?A??A$#135!255?!24?G!5?@$#136!24?_C!196?@!4?O$#137!107?@$#138!177?AI!15?@$#140!72?O!7?C!28?G$#143!34?O!47?O!4?A?@!19?A!10?O!16?A?C!92?_?_$#144!35?@!71?O$#145!209?A?G$#146!151?AACLZVG!8?~}wo@BM$#147!154?O???O$#148!32?O!50?A@!17?OOC!7?G_!10?@Co???o???G?_?_$#150!106?G!89?GO_!8?O!15?@!4?O$#154!28?A@C_!49?G!14?O???_!10?G?C!10?G$#156!147?@!61?@A$#157!197?A?@?A$#161!81?A!53?@$#162!69?A!164?O$#163!212?O_$#165!155?C!14?OG!4?@!9?O?goE{?{GO_$#167!198?MUwK_wO$#168!152?@?A?G!11?A@??O???G?o!6?oG{VNxAs?o`$#170!34?_!36?@!16?A!47?@$#173!157?_ID?E?X_g!7?Y@G$#177!26?A!43?C!23?O!4?A?@!9?A!6?@!20?_!84?C!8?O?_$#178!181?O??CA!16?@$#181!178?@$#182!201?oW?_o__!19?@G!6?@!39?O??G$#185!119?O!23?@?A!4?G$#186!65?A?G!6?G!10?O!7?@!25?a@!23?__ACCG!131?C?A$#189!194?A$#190!53?LK$#192!154?_!24?O!17?GO_!28?@P$#194!167?@??_!8?F__WG?C_$#195!81?_!26?G!11?C!19?O!12?O$#197!35?O!26?A!15?C$#198!197?C!28?C$#199!26?@$#200!158?_!50?O!54?G_A_aO?@AZWD?B$#201!35?A!29?_!14?G!5?C!5?_??G!14?C!7?O!19?A?C$#203!248?C_Ca_wc]qgu}u}m]_YCQKe}WO?EIH?F??@??@$#205!151?@!4?_!19?_!4?@A!25?G$#207!205?@A@?C$#209!150?@?CG???FDY]XVE^V!6?@C}o$#213!64?_!18?G!14?C!6?G?G!13?@$#215!212?C??@C??_GG??GO$#216!66?C?O??_!19?@!51?O!7?O!53?C!19?A$#217!86?G???C!181?_$#219!205?A??CG$#221!25?O???A??C!48?C!13?_!4?A???_???E!23?O??K???G!85?G$#222!226?O$#223!149?@!10?_?__!9?@$#226!39?@$#227!38?_!4?@!7?@$#228!38?K???@$#229!39?!14}??!4}~$#234!202?C!4?G$#235!179?_$#237!68?A!24?O!14?_??@!118?_?@$#238!98?A?@!132?@$#239!81?@!8?@!27?G$#240!231?_?G?Go$#241!141?G$#242!71?A!8?O!28?_!8?A?G!24?@?A!28?O!9?@!24?_!23?O$#244!212?GO!8?A!4?_$#245!35?_{~@!8?@!12?x~{!12?Bw~@$#246!60?A$#247!223?A$#248!64?O??@!4?G!10?O!23?_?C!10?A!113?@$#249!159?_!23?@$#251!150?C?G$#252!151?C$#254!214?_-#2!77?@$#6!38?E!18?_$#9!38?_!19?GC$#10!31?_!45?C!76?_$#11!24?C!175?AC???_!5?@?A??G??_!10?@!4?_$#12!24?O!179?O!9?C??O!13?A$#13!33?G$#17!34?A$#19!199?@!12?A$#21!76?_O???CA@!68?@c!108?A$#22!210?@$#23!73?C!4?O??_!56?C@!10?G???O!94?O$#24!180?Eg!19?O$#25!118?C!93?@!55?@$#26!233?C$#28!30?_!32?A!7?C??O!5?OG?A!34?G!20?A!13?O!51?O$#29!32?G!37?@?@I?_!6?D!27?C?__!4?_!19?G!8?D???_$#30!32?_!40?OCG??IC_???C??A?@!21?E??_???@!19?_G!9?A$#32!68?AAM???a!4?bA?o{QFA@B!15?_??@?@B???O!22?_OsN@?@@A??G?CDK$#33!67?@@D?W?@@???C??@G?GGDC!17?G!6?KW!28?@!5?@@BI$#36!182?_!14?BAC???_$#41!196?A$#42!63?O!152?O$#43!86?G!72?B!44?G!53?A$#46!203?C!10?G$#50!63?G$#52!157?@!77?GWGv~zwcO}?OG???!6A$#53!173?TC???CG!5?C!7?O?OC$#54!217?G$#56!255???@??@???@$#57!104?@$#59!255?!10?@$#60!234?CCA@$#61!178?_???BB??A???C$#63!176?_A???A!9?G$#64!88?C!21?G???G!28?A$#67!155?_CO?_!11?AG_???C$#68!105?_!9?O!115?C$#69!157?AH!4?GO!48?@!19?@$#71!161?G$#72!155?G?_??G$#73!155?Qo!5?_$#79!33?A!66?O!9?O!25?G!8?O$#80!27?D??CC!32?GA?G!18?_!6?cR??B?`HE!6?O!14?@CC??_!5?@?A!11?_$#82!65?COC!23?aP!8?H!14?AA???@???I@??@???OOO@@!6?O$#83!31?@!60?_??C!6?G!26?A@$#85!160?@$#86!29?C!34?@?GO??_!19?O!5?@!5?AA??_!8?@!6?C??OA?G???G$#87!27?ANO??A!31?C_?__!18?_?G?OC??`??x???D!4?Gco???@A?@!4?QGQh@sCDCG?@??G!7?o??O$#88!170?@?O$#89!64?O!32?O!23?G!7?G!14?G$#91!167?C$#92!26?IG?@J?D@!31?Ge?WO!18?WOkCGJKA_KC[_o?@???_GG_!4?M?@???cBkQ_GoOoshUMMF?A???osGcg_o$#93!27?Oo!35?A$#94!26?_$#96!190?GO$#98!165?G!24?__$#99!163?CEU!9?A!12?C$#105!215?@!7?C$#108!219?G?_A??AO???_?_$#109!216?BBDB]]hr~|l~n}SwO_$#113!53?~$#116!104?A!113?_$#117!34?@!37?C!6?O$#118!33?o!37?A_?GQ??_G!57?G!8?@??G!6?@!90?A!13?A$#119!24?G$#120!57?O!18?G$#121!232?A$#123!104?G!124?@$#124!236?CuG?CFZn@~hpp`@@?!4@!9?@$#126!25?C!64?A!26?O!20?@!7?G??_!11?A!54?C!16?O_$#127!103?G!98?C!12?G$#128!72?W!74?AC??O_G!7?C!19?O!19?G_O$#129!72?A???Og!82?A!37?@?C?G$#130!71?@???@!4?G!134?C!53?@$#131!234?GO$#132!201?A!4?_!6?C!22?_$#133!24?_$#134!31?O!31?_!135?A$#137!105?@$#138!162?G!39?O?_$#140!90?@!15?A??A!31?A!4?C??O$#141!162?A!25?O$#143!108?A!8?_!24?A!89?H$#144!116?G!70?G$#146!176?@O$#147!174?@$#148!25?@D??A?A!37?_!18?__??A???A??AA!6?O!6?@!7?o!4?BA?AO_@_$#149!233?GO$#150!24?A!178?G!28?C$#152!179?@$#154!29?G!61?G?O?GK_A!28?G???E!4?C!5?G$#157!24?@!78?O$#158!218?O$#161!30?O!85?O!45?C$#162!25?G!61?G!21?C!124?@$#165!172?@!4?@@?oCO!6?@?@?@@B@___$#167!157?C!43?@?B??@??@$#168!171?@EIwo??Yu??K{~z{_@ABENM}kw[[Wo_$#170!25?_!58?_O???A!22?A!34?G??_$#171!180?@$#173!166?rACfA__???K!10?A$#176!246?C$#177!67?AC!22?@!10?O??A!10?_!20?C!7?C!87?A$#178!174?A$#182!202?B?FN]~~}}{{woo_!40?A$#185!81?O$#186!32?O!30?@!16?C???@!34?w!25?@???C!110?A$#187!103?C$#188!230?A$#192!156?A!7?_!35?@!16?_!32?A$#194!175?G!5?@!4?@O!4?O$#195!31?G?C!32?@???O!149?_$#197!34?{!41?C$#198!102?_?C$#200!154?G$#201!105?C!5?O?C!26?O$#203!252?@!5?@@?@@@$#205!154?C!21?OG!9?@A$#207!154?BC???[?OO_$#209!166?KxzW{[!5?_$#213!29?_!34?_!21?O!20?C???_?A??CG??B!20?G$#215!217?CAC@@SG??A?O?G$#216!73?_!4?@??A!29?GO!5?AD!17?OA!7?A???O?Q!93?A?A?_$#217!75?C!42?OA!28?A!4?A!105?A$#218!219?O$#219!156?G?C?o_$#221!25?A!39?P!19?_?O?C!4?_OO???C!5?O!5?@?C??C??{!12?_?_!7?C$#223!164?G!10?@A!11?_???_$#227!38?@$#228!38?W!38?A$#229!39?!14~?~~~NFB$#231!218?G$#233!157?Go!4?O$#234!249?A!17?@$#235!180?G!19?G$#237!63?C!42?C!104?A$#238!80?@!27?@!6?_!20?_$#239!25?O!45?_!35?A???@$#240!158?A?C!74?A@$#241!69?G!71?C$#242!106?H!29?O???_!7?O!4?@?@!37?_!40?A@$#245!35?~~~!20?ow~~~!13?B$#247!103?_!127?@$#248!104?OO!38?A!69?A$#249!175?C!11?C?C!24?@A$#250!26?O_$#252!161?@@B@`!22?GwO-#0!36?AC?K???O$#1!38?A$#2!35?@!27?@$#4!41?GO!13?C$#6!34?@!22?B!6?_$#7!53?W$#9!34?A???@?C!11?g??C??_!17?_??G$#10!39?o???_!20?G$#11!208?G_!17?_!8?@A?G$#12!207?A!15?C!16?O_$#15!42?_$#16!38?_$#17!41?_!165?C$#19!24?@!77?@!121?G$#20!24?C$#21!36?_!27?C$#22!209?O!11?A$#23!30?C???G!42?@???A_$#24!182?IO!19?A?GA$#25!81?C!75?_!70?_$#26!100?GA$#28!25?K!46?@!9?C!139?C???_$#29!29?O!44?_!26?O!13?CO!37?A$#30!77?A?A??A!33?G_B!37?O$#31!76?G$#32!25?__!45?A?B@E?B?F?@m!18?C!11?@BCWk!19?@@!16?_$#33!30?O!44?A???@???P!19?A!12?ACO?_!15?@BA$#36!177?w??ww_!20?_$#42!25?A!193?@!18?AC$#43!155?C!84?G$#50!25?@$#52!219?ESWwoo_!12?@BAH|~IIiN???C??G$#53!175?B???@!4?A!16?G!5?O$#57!237?C$#60!160?G$#61!166?A!29?A$#63!197?C$#64!27?_G@!72?O!14?A!16?O!4?C$#65!137?_!88?G$#67!158?O!29?C!9?G$#68!134?__$#69!65?O!5?@!32?A!34?G!18?@$#71!162?@$#72!158?K??COW?O$#73!156?@A?o_ACcG_Oo$#78!164?A$#79!105?_A_$#80!66?O_?OI!21?_??g_?C!5?GG@@O???A!9?g?@_GG?A!11?Ng??@?GGA?A$#82!65?@?@@!17?C???CCA??AC???@!7?@@!13?A??A!4?C!8?A???AC??C$#83!87?G?A!4?@!30?@!13?O!6?O$#86!65?G??QAO!16?_CG??C??C??W!8?KA?P?GGO!8?G??_??_??GA!5?_!4?O!4?_???G$#87!67?A?c`_!13?d@?_OIiWOa?A?_!4?OcC??CG?H!9?ACC??CpMHu?O!7?s?OA??@aA?A?_Oo$#88!199?O$#89!66?A!20?A!46?A!10?O$#91!174?O!14?O$#92!65?CD[GHC[!13?YiPRdPP@N[PH{BNA???OQsQ_UEqss_!6?SRP]?PEoSHx_X@!6?oB|gGmOpL{[[_G$#94!31?C$#95!26?@@$#96!196?C$#98!190?@@$#99!173?A!15?CAKEIKKG$#108!225?A@??C?@C?aA$#109!223?@B@ENJZz}rx\{swo$#113!53?f!152?@!19?O$#114!238?C$#117!119?A!120?_$#118!31?@A!40?Z???C???OO!36?|!63?_$#120!38?OA!6?O!30?G??O$#121!99?_$#124!240?DEA?ttTo~~~awo?O_$#126!74?C!25?C!14?_!4?@_!12?C!5?@!11?A$#128!30?@!48?CG@!75?G!24?C!20?@C$#129!34?CO?_!40?C??_!73?AC$#130!30?A!126?O!50?O$#131!102?A!104?@C!12?@$#132!224?C!12?@$#133!24?o$#134!40?_!35?O!77?@$#135!35?_$#136!101?G$#138!160?C!6?C!14?@!21?A@$#139!205?O$#140!33?E!68?G@!32?ACC$#141!189?G$#143!26?G?C??O!69?@!18?A!114?@$#144!112?@?G!79?@$#146!167?AEK{{{!24?!4_$#147!188?@$#148!65?AG?c!17?O???_??_!9?_?@???_g!10?H?__!7?FC!6?G?C?Da?@?O?_?C$#149!225?G$#150!100?OC!118?@?A$#151!169?_$#154!75?G!11?CG!7?OA!8?G?G!16?A??@??A!15?C$#157!24?G$#158!24?A!75?_$#161!31?A!42?O_!8?_!32?@!37?_$#162!136?_!17?C$#163!195?A$#165!176?{?owD???O?o__!8?@BB@?_G_??_$#167!162?_$#168!174?@KBCGEAE?Fl~N^O!6?@@ACKMV]SPaK$#170!29?E!85?O!19?A??OA$#173!169?@@B!17?_oO?O_??G$#174!26?AG!4?o!189?@??C$#177!84?[!35?C!14?@??_!12?@!71?A!12?A$#178!167?G!10?A$#180!36?O$#181!204?GC$#182!208?BF^!8~wic!31?C$#183!27?E$#184!173?@$#185!32?@!122?@$#186!33?@o!38?C??@!4?GG!33?_!36?@!7?O$#190!52?O$#192!159?A!49?G_!12?G!28?A$#194!161?_!4?C?OO!5?O?A@!9?G!11?O_$#195!64?@!7?O!11?@$#197!35?AC$#198!225?O$#201!28?O??_!40?G!31?@!32?O$#203!251?WCGo_$#205!159?C!4?@!9?C_?@!10?A$#207!157?@??O??BOGG?_$#209!167?@@AA?B{g!16?___?__OO$#211!168?G$#213!27?O???GG!41?GO!23?O??_G$#215!228?S?C?GE??G$#216!30?G!34?_!7?_!39?@AG!111?O!11?O$#217!25?O!7?G!122?I?_@$#219!158?AG@@I?cC_$#221!33?_!37?A!25?@!13?C!13?[!7?_!16?@$#223!166?@!25?P@OOO$#225!38?G$#226!35?C!8?O!9?G???G$#227!54?O$#228!36?GG???OG??O!9?O?GO!5?O$#229!35?G?O?@RFFNnnn!5~F?fbro!19?owo_$#232!229?_$#234!29?_!36?_!184?@$#235!181?@OG!18?@???oG_$#237!64?A!36?_!33?CC?G!13?@$#238!29?G??C!81?C?@!20?G$#239!26?O???_??O!41?C!27?C!16?G!14?OO!16?A?G$#240!157?C???G???A$#241!84?A!28?A$#242!72?_!61?G!20?O!4?A!4?@!8?A???C$#245!36?@BC?G!14?GGCF!4~}$#247!238?G$#248!28?_!43?C!47?O!14?GG!104?O$#250!26?C?B$#252!189?BKAGCA$#254!239?_-#0!54?GC?O??___$#1!56?O$#4!58?_$#5!57?A$#6!54?O$#7!23?A!29?C$#9!50?KCB??_A!19?F?O?G$#10!38?_!7?@?A!5?_!8?_!13?O???A$#11!52?O!157?A!17?@??G!12?GO$#12!212?_!19?_$#15!41?@!5?A$#16!37?G!5?AB?A?G$#17!40?@?`@?E!4?O!13?A!146?_$#19!99?A!111?G!30?@$#20!241?@$#21!24?C!12?D@GI?OC_G??O?__!107?O!69?@?C$#22!97?O!112?@$#23!24?G??O!6?_@!13?_!24?K!7?O$#24!183?AW!25?G$#25!67?@$#28!64?G!10?@!7?_!16?@!18?O!109?C!15?_$#29!26?_C@!5?O?G!30?C!5?@@A!7?O!33?@C?A!36?@!55?_$#30!65?CA!51?@?@G!34?@$#32!25?q!39?A!7?C???_??_o?A!37?o_!34?u_$#33!25?L!39?@!7?A!9?L!34?A??C!35?GW$#36!177?F??FNNGA!18?F???A^{_$#41!179?G$#42!245?G$#43!72?_$#50!32?A!83?@$#52!165?O!8?O!44?@QZ~^~~}}[wo!12?@BFFOK$#53!170?@$#57!98?A$#61!173?G!14?C!13?@O$#63!176?A!9?O$#64!29?A??G?@!36?W???G!10?_$#67!162?A!9?A!16?G!12?A!4?_$#68!84?@!150?_$#69!72?A!11?C!31?AG!45?@!10?_$#71!160?G!4?G?@$#72!160?@!8?g?o$#73!160?A~WOA@FahEc?WO!15?A$#76!173?C$#79!102?C!5?C???C!15?G@!12?A$#80!30?O!38?GAA!13?GG@SK?C?C???C@!10?A??A?o_O!7?O?_A??G??AA??C!4?__?OC_?G!4?G$#83!89?A!5?A!15?_!22?O!11?@!5?@$#86!32?_!52?O?A@_K@@??_C@???C@_C?GOGPAO@O?G!6?@?C_???S@AX??GO_??O@??@KA?aC?paD@$#87!31?O!39?@!13?f?CiO`QGP?OH!4?gQCHqAg`C?@oC@E__!5?G??GGOI?@e_gqAOS_??@RABoEHQbC?oa$#88!189?P!10?O?O$#89!29?O!121?G?G$#91!188?O?G?C$#92!30?K!38?DX?G!13?AG?@QgCI\LAA??OOGJQLDFAg{MGJMPKO!4?AUITVSF?Q[?[CCCGgMN[[K_?GPS@[A[ASK$#93!35?G$#94!34?A$#95!34?C$#96!175?O$#97!230?@!10?A$#98!175?G!12?__$#104!240?_$#108!239?P?O$#109!231?@BFN^~~~M]kwO_$#113!23?{!29?@!157?O!18?C$#114!229?A!16?_$#116!98?C$#117!26?@!15?GGOO?__!17?_O!6?O!7?B!36?_$#118!26?G?Q!6?A!46?g!36?Bo!63?_$#120!63?O@!14?O$#124!246?GLR!4~maYggq!4_$#126!30?@??_??O!47?G!38?_!10?@???@!16?@!76?C$#127!243?A$#128!26?E?K!35?C?@?G!12?GC!76?G!23?@$#129!24?B!13?G?O?A!4?G!161?@!20?A!11?A$#130!27?_!8?CO?@?Q?_C?G??O!14?OGCA!12?O!77?B!99?@AC$#131!98?O!131?G$#132!211?C$#133!53?_$#134!39?O!36?G!4?D$#135!36?A?C???C?G_?O$#138!159?C??@?G!18?CC!24?A$#140!27?A_!46?C!80?A!71?A!4?_$#143!29?C??@!38?_???O!8?A!71?_!76?GO!8?G$#144!67?_!69?@!28?_$#146!172?@!24?~~~i?k$#148!86?@!5?A?A!8?O??O?O?@??_!9?@@??@!8?g??P!4?W_!9?O$#149!243?C$#150!97?_G@$#154!29?__GO!36?A_!15?C_!4?o__!5?_?_?_?_!17?_A?___c_!8?__??C!4?_!5?_$#157!52?_!178?O$#158!232?O$#161!67?G_!7?_$#162!72?@!23?_$#165!178?FDwoo?@CB?B!14?Gn~m[_$#167!172?C$#168!176?@Gwq???o?zK@!16?O?P$#170!24?_!4?@!92?O!110?O_$#173!173?@CEG!10?O???IG?V_M!4?i$#177!34?G??_!34?O!45?_??@$#178!177?O$#180!41?_???@C!4?O!158?C$#182!211?BN^!5~}lc?_??@?_??_!16?_$#183!33?@$#185!160?_!10?A$#186!27?G!4?CG!40?_!42?AGCG!38?_!72?G$#188!97?G$#189!52?GG$#190!52?CQ$#192!163?C!48?O$#194!159?A!4?O!38?_$#195!69?O!5?_!168?O$#197!63?G$#198!244?C$#199!36?@AAECK?O??o$#200!175?_$#201!31?A?C?_!37?o!47?A$#203!247?A!5?P\dVVK[WO$#205!159?@???G!5?@A@!4?C_!9?CGC$#206!231?A$#207!160?C?__`A?GS?OK__$#209!173?AB@O!10?G??VTR^G^P???DT$#213!31?C???O_!34?C!12?O?OO!11?_!22?C!12?@@A$#215!243?_$#216!24?O?O!4?@?O!40?A?O?_!20?C!19?GC!37?C!87?O$#217!68?C!10?_!38?O!44?A?_$#219!162?C??CWSAOG$#220!174?G$#221!29?G?_?A!34?@?C?C!11?_!11?O???GA!23?G!7?@!4?A??A!5?G!7?A$#223!176?_!10?_??!5_?_$#225!55?O$#227!57?_@$#228!39?_!11?G??C?_$#229!38?O?_!7?DD@B??BB@@!19?NNNF$#230!47?D?IA$#232!240?@$#234!68?A$#235!207?@??O$#237!27?@!38?G??_???G!24?_!128?@$#238!68?O!30?GA$#239!65?o!90?G$#241!35?C!30?O!32?O?@$#242!64?_!35?C!21?G!33?O???O???C!21?_A$#244!239?_$#245!55?GKK]!4^F$#246!59?_$#248!117?C!38?C$#250!30?A!211?C-#0!41?ACK?GGOO$#1!44?CO???O$#4!42?A$#6!40?A!20?@$#7!22?W!224?@!33?K?g$#8!255?!23?CC$#9!39?@??@???_C??_!7?@!225?_$#10!42?G$#11!52?O!182?G!11?A$#12!95?GA$#15!56?@??A$#16!44?@!4?C$#17!47?A???_!6?A!175?A$#19!246?@$#20!95?O$#21!23?G!21?_@@?A?C??G?A!103?@$#22!220?O$#23!48?@??A!6?C???@!99?O$#24!184?}!26?@$#25!120?G!146?O$#26!95?C$#28!60?_!22?q!37?C!27?G$#29!83?G!12?G!26?G!24?G!6?O!4?_$#30!26?E!46?AA!47?ICO!33?G_!8?G!43?O!24?C$#31!121?A_!27?O$#32!25?Bx!46?KK!8?Co!36?@To_!22?G???OOSSCcCfJK$#33!72?@@O!22?A!59?`?C$#35!236?A$#36!180?qee!27?p$#37!185?G$#42!216?A!15?@!16?_$#43!162?G!91?_$#48!177?C$#50!59?C!13?O?O!76?C$#52!218?@DGF^~|!7~}w_!28?@$#53!185?_$#59!255?!10?O_$#60!164?_$#62!166?A?O!6?@$#63!207?A$#64!25?O!46?G!12?_!12?@!24?@!25?C!6?A$#65!58?O!181?_$#67!167?G!18?F!16?X!4?_o?O!26?O$#68!84?C$#69!37?BA!38?@??@!5?C!8?A?G!27?O!21?C!15?O?@??C?_!6?OG!35?C$#71!170?@?G!40?G!22?C$#72!162?AA?I?O@COB?A!40?_!22?O$#73!163?CHCg@?I?{_?H?_!36?_G!23?_$#79!29?G??_!60?@!34?_!9?O$#80!28?_?GoA??S!40?@?W?C!6?y??g?@G?@??G??g?P!11?G_AE_!7?ACC!4?G??CCGCA!5?A!6?@$#83!31?A!39?A!17?A!9?@!6?@!17?@??_A!10?C!6?c$#86!28?G?@!39?C!9?G!6?C?`T?S!8?OO?C!10?O?_!8?A???_Cd?C?OoA_A??_!8?@$#87!24?c???OrC@S_{_WO_!28?A??AC!4?AG?CQ!7?[C?b_S???oOaO?gk`M?@!7?fFGWO!5?MH[PJ]pGkpB`HHQ@xJIFA@@_B?B?@$#88!186?G!12?_$#89!33?O??_!43?_!23?O!13?_!13?O!7?o???__$#92!31?K?CAG!30?AD???G!4?Cq?_!8?@GA?G!5?CCNAAA??cA!6?X?WC?G!6?O@?O?GA?A?GA!5?@!6?B$#93!70?@!7?_!32?@@_A$#94!61?_???G!5?O!37?@@?_$#95!62?O?G???o??_!36?A??A]!125?C$#97!110?cO!128?@$#98!188?OpB`?@a_E!4?F$#102!215?W$#104!247?G$#108!239?@!6?O$#109!216?o__!18?@BE]{ofF]ko_$#113!22?_@!209?@CO_!11?CO_!29?C???O_$#114!213?@??C??O$#117!23?O???_!11?O!9?@@@AASCC!62?@!131?CG$#118!38?G!17?G!63?@!36?!4OC!22?@!49?O!15?A$#119!221?_$#121!53?_!40?O$#123!247?C$#124!212?C!37?@BCN^zv~^~^~~}sGO_$#126!24?A!33?GGC?A@?A!4?O!14?@!12?A!20?C_!29?_!68?_!22?C??_$#128!27?O!7?@!4?_!23?A!55?AO!40?_$#129!27?@!17?@!4?C!4?@!4?A!159?_$#130!27?M!15?O!4?A!5?@??A!7?@!54?C_$#131!97?@!116?@C?C$#132!222?_$#133!23?C!28?GO$#135!50?A!4?I!180?O$#136!53?@!42?C$#138!166?@C!8?A??_$#140!85?C!63?O$#141!215?_$#143!28?C!39?@?_?_!8?C!62?G!6?_!84?@$#144!68?A!142?_$#146!177?B!19?WWWO?O!5?W$#148!86?_!15?@??_!23?_@??@!11?@?_$#149!217?G$#150!94?_!120?A??G!14?A$#154!24?G!4?Cq?HJ???_!38?WCEY?_??B?O@aO?[AAF???_W_DC?IPA?@!4?@c??P@!6?@c?G??A?Q?kE?_@GCcC?CA?B_??A??@$#156!107?WwW!107?O!21?G$#158!52?_G!194?G$#161!34?@?@!5?O!81?C!29?A$#162!25?_!40?@!176?G$#165!179?QLXXe?E!18?OOoo?BM$#167!212?g$#168!178?@L???X?@!18?nnNK?C$#170!36?C??GO!16?G??OW!13?e!20?O!50?O???C$#171!185?O$#173!186?_k_KK?COW?O???AOI$#174!62?_oo___!39?c??AG$#177!28?A!27?_!4?C!16?@@!6?A!9?_!46?O!8?_!63?G!27?o$#178!211?G!24?G$#179!23?A$#180!46?A!4?G!162?A$#182!215?@@BEAFW??A!39?A$#183!65?OOO!41?A?c$#185!36?A!32?A!84?GG!7?_!13?G$#186!37?C!31?[!12?x!38?G!30?GG??G!4?_!50?@$#189!255?!27?GO$#192!161?A!73?@!29?C$#194!178?A!28?@@G?C!22?@??_?_$#195!35?A??D!5?_!15?GA!23?A!34?O!24?G!7?_?A$#196!48?_$#198!96?@$#199!52?DCA??C$#200!255?!10?_$#201!25?G!13?AC!18?O!4?@!16?A???O!38?G!21?O???C???_$#203!252?B??CG?_?_???G$#205!161?@C??_!12?C!24?e!4?A!26?A?G$#207!162?@HEOS?a@E?VlE}G!36?SO$#209!188?K??GGG?WGffFl?d!5?C$#213!39?CGO_!21?C!6?@!9?G!12?G!58?A!83?A!8?A?O$#215!242?@?G$#216!23?_!39?C!5?@!4?@!7?E@!66?GG!4?O???AW!56?O!30?@???O$#217!58?__!35?_!61?G!75?C?C!30?G$#218!241?A$#219!164?O??_??G??Oo?O_$#221!24?O!18?_!12?OO!10?C?G!10?O!4?G!6?_!30?A!10?O!6?O!13?@$#222!108?CcW$#223!186?ORBAoUreCF`!4?g$#225!44?O??_?_$#226!40?@!4?C?G??O!9?@$#227!43?A!4?G$#228!41?D??A?C??G?O!7?@$#229!45?A!4?G$#230!43?@!4?C!8?@$#231!241?@G??@$#232!242?A$#233!169?_!8?O$#234!219?G!18?G$#235!211?A$#237!25?C!36?G!6?_!4?_!10?G!37?A!22?G!8?_$#238!62?CA!17?@$#239!28?@!26?O!16?C!13?@!10?C!27?_!18?OO$#240!167?A?O!43?A$#241!41?G$#242!24?@!47?O!75?C!27?D?_!33?A$#245!44?G?O$#246!255?!25?G$#247!75?@$#248!37?GO_?_!15?_!14?A_?G!8?G!34?A!28?O!8?A!81?O$#250!54?__!7?G?CKGG!7?_!29?W!6?]!129?O$#252!194?@-#7!253?_!30?]?@O$#11!22?_!199?@?A!5?O??_!5?_$#17!255?!30?@$#19!94?@$#21!41?@!10?o!185?C!66?O?_$#22!53?a!180?_$#23!44?C!15?O!63?_!86?_$#24!180?C???F!25?O$#25!50?O!188?O!32?_!13?G$#26!92?G$#28!29?_!21?O!30?@!40?CO!39?@$#29!27?A!17?C??GG!7?@!19?_!4?G@!140?@$#30!125?W_!35?@!55?O__$#31!27?_A!137?A$#32!26?@S!66?C!28?BNeWo_!5?_!26?@?@?A??C$#33!27?G!23?C!30?O?@!40?@C$#35!171?_!69?A$#36!180?@BB$#42!47?O!175?A!6?G!7?_!46?G$#43!95?@!38?O!93?C$#50!231?_!54?O$#52!171?C!53?@@BBFFNNN^[{o$#53!181?O!19?_$#54!255?!30?O$#56!255?!48?O$#57!52?@!168?@!64?_$#59!255?!8?A?O_?KG!35?__$#60!255?!47?O$#61!180?G!20?C_$#62!212?C$#63!167?@!5?o!26?A!37?A$#64!26?O!21?@!10?@!13?[!21?A!26?G!5?O!5?G!23?@!7?C!17?O!26?G$#67!198?q?pA!6?f~!7?G???_$#68!92?C$#69!23?O!47?_!7?_!81?A!7?@$#71!168?@!11?O!59?A_$#72!172?a??G?BC!33?_???A!23?K$#73!171?@@MWCcKg!6?A!27?GA_C_G!19?@D??_$#77!72?@$#78!222?_$#79!32?@!6?@??O!56?A!29?A!13?O?@!4?`???BA$#80!34?AO?@???_?G!4?_A!4?O?COO!5?_!23?@?A!5?AAG???G!6?KC!4?cA?_J_?_!7?A?A!8?C?cCAGG?a??_H_c_!7?_??G$#82!33?_!5?A$#83!31?A!33?_!40?@O??A?G!4?O!22?O???A!4?G?G!7?O$#86!24?HA!5?@?GG?O_?G?C?O_??_!7?OG!30?@!4?A!4?G?CP??A??_!4?_??p?Oa??AO!6?BP?A@??O?IC_?@A@??o?O!6?@AKOGI_C!4?o$#87!25?W???@AcgPSgcShoCGG?O@?AA_A@??G?ogC_!6?_!19?@CA!6?GGCF?EDa?tUSEO?_WC|IYH@FO@g!5?ACKHHoN?Gx`ZXaIhGWK@enTKQ^CGOSqeeoC?oW?_$#89!29?AGG!4?GG!52?@@@!6?@!35?@!4?C!6?@$#91!192?C$#92!30?C?A!10?_?_a!7?__!7?G??O__!12?@!4?AA?G?C???OSO???A???GA___??_!23?E!7?_?A!4?c$#93!33?C!24?A???C?G??OO!10?@!5?CC?C?K!5?_?__?_!5?@?A??@$#94!62?ACCC?G!8?@?AAC!4?G??OO!131?O$#95!63?A??CC!4?O??g?A???[??_OOO?__!19?@!113?C!22?O?_$#96!217?A$#97!245?A???@$#98!201?@$#99!185?oGgO_wO_??_$#102!216?@$#108!223?OGG!18?GO$#109!217?@ABEMKKOooo__!12?@FVkgBEYw_$#110!250?C$#113!22?^!203?C?G!7?@!15?G!31?`?A$#114!237?AG!12?A$#116!92?O!132?A?C?G$#117!42?A$#118!29?O!18?O?G???AA!4?A_!107?C!13?_!28?A$#121!52?A$#123!250?AG$#124!255??ADTTv|f|zJ\]PC?_$#126!25?@!28?@C???G?@G!32?C!30?@!6?OC!21?@$#127!237?C$#128!28?{!31?K!61?AG$#129!52?G$#130!45?GG!4?G$#131!92?_G!133?G$#132!225?C???O??O$#133!255?!31?C$#136!52?C$#137!53?O$#138!179?@AG!28?K???C$#140!42?@!18?G!8?_!11?_A$#141!186?O?g!4?O$#143!45?A???@!9?C!15?A!9?@!37?_!5?_???_?_!29?C!45?C!35?C$#144!46?@!11?@!68?C!44?C?_!43?_O$#146!197?M@]??C]$#147!203?_$#148!24?_C!10?A?U?O!4?O!11?A!6?O!24?C!9?O?O!16?G!13?G!4?O!12?O!4?G!6?OG?G??_$#149!53?C!178?_!17?@CO$#150!93?C!129?@!7?O$#154!24?E!5?@OSA`F@A?CgO_?@!5?_!4?G?Cg!4?o?O!14?@!8?B?A??_??@OGgGT|A_GGIOWEQAC@cCOCW!6?@??ssC?BA?C_EHoSA@oCO??A@?QS?G?G?CWgCC_G?O!57?G!14?@$#156!220?G!23?_!6?O$#157!93?A!144?O$#158!237?@$#161!41?A!19?A!22?G!72?@$#162!23?G!144?G!77?C$#163!215?@???G$#165!182?GB!20?[[C]??@$#167!212?@??G$#168!181?CCK!17?W??bbz`$#170!26?C??G!14?I??@!22?G??@!9?G!10?G!74?O!75?@?G$#173!186?CD?A??HGJ@C$#174!64?@@BBB??EC???KWWOO!149?_$#177!26?_?@!14?@???C!11?A!10?@!4?@!18?O!26?A!163?_$#178!172?O!68?C$#182!172?G!60?O!21?@!15?O$#183!62?@@AA??C??HI??OQCCKg!4?!4_!19?@@$#184!184?_!38?_$#185!47?G!8?@!66?O!41?@!4?O$#186!27?@!21?O!28?_!43?D!45?A?G!85?C!13?C!14?A!15?O$#187!91?_?@$#192!182?_!52?A!4?@!28?A$#194!170?A!27?K?K?O!5?W!4?C$#195!49?C!6?A!4?C_!6?AC!55?A!42?_!78?O$#198!53?G$#199!255?!49?_$#200!255?!12?_a_W$#201!23?A!16?@!5?C???C_???@!13?D???_!9?o!75?@!86?A$#203!255??@AIiGAW?CcA@?O_$#205!171?G!30?G@!7?@O?G?O!23?_$#206!211?A$#207!174?A_P_Oc__!31?POO?C!21?AOWO$#209!186?BAFDFFAFCMIp?`??B$#213!23?_!5?CO!11?C!7?@A!24?_!7?O!37?O$#215!218?@!27?O_@C$#216!43?E!16?`O!32?A!26?@!45?A!90?_!45?O$#217!69?_!4?_!7?E!83?@???_!13?G!31?G$#218!228?O$#219!173?@DRIOBW!33?_`A_???O!22?_$#220!243?O$#221!24?O_!14?A!18?O!11?O???C!5?_???A!5?O!4?@!7?G@??C!8?G?_CC!6?G!6?C!17?_!11?OO$#222!222?A!20?G??@$#223!185?C!5?G!4?@$#226!255?!32?_$#231!248?G$#233!170?@!46?O$#235!182?OO!26?a$#237!26?A!27?C!14?O!4?@!9?A!8?O!66?@???A!4?G!56?A$#238!30?_!39?O???W!8?C!83?C!67?_$#239!26?G!46?A!10?C!78?A!84?_$#240!170?CA!41?A$#241!23?C$#242!46?O?C!13?O!7?A!91?A!6?A?O!7?A!5?@!26?G??C!23?G??K$#244!222?O?_$#247!23?@!29?@!198?_!32?C$#248!69?G!4?E!18?_!33?G!83?O!25?G!19?G$#249!88?G?O!127?C$#250!65?GG?G???_!4?@@?AA!4?GG???G???_?_!13?@$#252!185?G_O?W?_O_oOo$#254!219?C@!21?A-#1!255?!32?@$#7!21?G!234?_!25?GA??_$#8!255?!21?_o$#9!79?O!170?G$#10!75?OA??_!153?_$#12!239?A$#13!231?O$#15!78?A$#17!75?_???A$#19!53?C!182?@$#21!28?{!23?z!8?K!7?_!102?O!38?@!63?O!32?@$#23!66?C?A!4?O$#25!22?O!38?_!17?@?_!168?C!34?_$#26!91?@$#28!64?O??C!5?A!7?O!45?G!111?C$#29!29?@A!51?E!169?_$#30!27?@?W!32?C_??G!59?A???C!40?O!51?A$#31!68?@!13?G!163?OO$#32!27?A?e{wo_!28?G?_oow??m!11?o!40?CM?PF^MW???F{o!33?Fg$#33!27?C!34?A!7?P!11?@!39?GGOW???o_w_?G$#35!244?G$#42!74?A!179?_$#43!133?_!93?G!45?A!32?@$#52!181?W!78?C$#53!205?C$#57!90?C$#59!255?!8?G??AD`?DgAKO!32?A$#60!255?!52?@I_$#61!198?g$#62!255?!53?sW$#63!183?S!5?_!8?C!4?G!21?A$#64!34?O!36?KG!10?_!8?G@!27?G!123?O$#65!233?@$#67!172?A!9?@A??_!16?A!4?FM!10?@$#68!133?@$#69!75?@!13?O!43?O!40?A!10?O!23?@$#71!173?@?P!36?O?@!4?_!6?OO$#72!172?@?_?@??p?A!11?_!18?C_Sg??G??W??_??_!15?B??G$#73!173?M?_OYcEH@!31?S?@WfUMi_?cOOa???_!10?@$#76!186?A??O$#77!90?A!158?C!32?_$#79!40?O??O!20?C!53?@?C??@!13?@?@?C?A!14?A??@$#80!23?@G?O!9?@?A?A?S??O???A!5?AOG@!59?C??C!9?AC!4?A?_Q@h??OX?WKC?Goo!7?OH?G?_$#82!45?C???P$#83!43?A!15?O!4?A!87?C???C__$#86!24?AO!8?K@???C@???_B?GA_!5?C??C!6?A!46?@???B???@!19?C!4?gC???o?@??A???KG?GA?@aXO$#87!23?uC?_!7?BK?N?GgFgcC?W@LCf???C_`dIC_???@@!18?oo?o_!21?@@?BAA?@??IB!9?@!5?CA]?qO[f@AB?qApoDCsXOLoVebSRSSCcO$#88!200?O$#89!24?_F!13?O!4?@_?Q!9?O?@!6?@!48?@!20?@???@??@O!9?@?_@O!5?_A??IG$#92!32?@???A?G?CG?GO!11?G??G!12?@!11?GG??O!4?_!11?@??AAAE?CC?CGAK!18?C???C??C?C!20?@$#93!47?_!38?G!7?__!6?@?@??A!4?C??G??G$#94!84?A?C!6?K?OP@O?Q___CCCcgGgOoo?__$#95!80?@!4?AAACC!4?HNIMM]K[[[wwwWOoO_??_!129?O!4?G??@$#96!184?DG$#98!185?C@S[?wg?OoGo!41?_$#99!188?BAA?@FFEC$#102!235?O???_!8?@!4?G$#104!232?@!14?G$#108!229?A?@!15?@!5?O!30?O$#109!227?!4@CEMMCW[WW!4o_`beK??F]!30?_gM$#113!21?o!213?@??A!15?C_!27?C@$#114!250?O??@$#116!53?A$#117!64?G!4?A!191?_!22?A!22?C$#118!32?GO_!28?O?G???C???_!52?KO!43?@G!56?G!5?_$#120!76?_??K$#121!89?_$#124!255?!5?BN~pM\|IEFO?O$#126!26?A!39?A@!4?A!8?@!11?A!39?C!104?C!11?A!33?C$#128!28?B?@A!29?R_!6?W???G!51?A!45?A!52?A$#129!22?A!52?C@@$#130!52?C!25?@!147?C?G?O!9?A$#131!90?_!160?O$#132!91?A!145?@!16?O!28?G$#133!237?A!44?O$#134!75?G$#135!251?_$#136!255?!31?G$#140!51?A!39?_!30?OO??_!8?A$#141!191?@$#143!26?@!27?_!5?G??K!68?GA!35?A$#144!173?O?C!33?o!12?A!19?C$#145!200?C!28?C$#146!197?_!10?_$#147!184?A!15?g$#148!25?_!7?A!4?@B??@???_!9?A!52?@!22?@!9?A!6?@?GAAA?AK!4?C?C?@$#149!22?@!231?G!26?_$#150!53?w!185?@!35?_$#154!23?GPGC!6?D?QOoc_?oA@IGFCoGO???HXCAo_???@!22?o!19?@@@???A?@C?E?B??@!15?X?_G?_GA_Wf?@E?GGH???B_W?_G_GA?_$#156!226?@!19?C$#157!53?@!36?O$#158!22?C!211?@$#161!71?@??_!5?C!11?O!26?O!121?G$#162!72?C?G$#163!227?A???G!12?@$#165!202?__$#167!172?C!7?_?A$#168!182?oG!14?O??~^O~z~~$#170!27?G!23?O!10?@!57?O$#172!182?C$#173!192?_!4?F$#177!31?@!28?C!4?C!5?A!9?A!49?C!38?_!78?O???C$#178!175?A!5?_!4?C!11?@$#180!77?A!156?_!5?C$#182!238?@!35?G$#183!84?!4@BB@???E?C!151?_!36?O$#184!225?@!8?O!10?A$#185!31?C!35?A!5?C!137?E!13?C$#186!124?@???_!43?_!49?@!9?o$#188!249?_$#190!255?!31?O$#192!227?C!13?C!67?C$#194!185?_G!11?A!4?C!6?@!12?@!21?G$#195!60?A!19?_??O!202?@$#198!90?G!162?A!20?_$#199!22?G!236?AG!49?O$#200!229?O!34?@_?oOOiTKO$#201!33?G?_!15?_!19?_O!7?G??A!8?E!30?A!10?_!113?O!4?_!32?A$#203!255?!4?@?O?EoA??Gg?A@$#205!176?K???OC!18?B??@!4?W?A!13?C?G?S$#207!174?[G_dOGE!31?JIIUfW_PSE{WHg??__!11?ABCEC$#209!197?W?~$#213!32?A!21?O!8?A!10?O!17?_!37?@!5?A!32?C!81?G$#215!230?AA???GC!11?A$#216!22?_!9?C!29?O!5?{@!4?@A!49?D!45?C!11?@!59?G!5?@$#217!127?_$#218!210?{!24?A$#219!176?A?J!34?@_???@$#220!237?_$#221!26?G!9?k?O!11?G???A!4?AO!19?A!36?_!4?A!9?AG???G_?G!6?_??G!6?A$#222!228?A!54?O?@$#223!184?W??G_G?OWG?o$#229!76?[ww$#230!77?CC$#234!221?@!88?_$#237!51?D!21?@!17?O!29?o!4_!6?O!78?g$#238!72?_!8?G!37?__!8?@!6?G_!104?G$#239!27?O!43?O??C!6?C?L!34?_???C!7?A!4?@!34?O!78?A$#240!174?@!55?G!5?_$#241!27?_$#242!136?CO!31?@???_!8?G_??O!25?_!18?_?O$#246!255?!32?A$#247!91?C!144?A!13?_!22?_!12?C$#248!51?G!8?@!19?O!10?G@!41?O!35?G!40?O!28?@!31?_$#249!85?C!13?@??A$#250!84?C??KGG???OO?_o`_`B?BAAA?CCCGGGWOWOO$#251!230?C?G!7?G$#252!184?_B?b?DDEE?G@J$#254!250?@-#7!255?!24?@!4?OC$#8!250?!8G??G!12?A??@$#9!77?@@!158?@$#10!76?@!195?O$#11!248?G!8?O?H??@@!9?@!10?G$#12!54?_!203?G???G?@??@?@@?A???C$#17!53?O!219?O$#19!53?B!201?O!15?A???G?C$#20!254?O$#21!28?f!11?G???__!23?~!179?C!35?@!20?O$#22!89?@$#23!51?_?_!4?C?A@!15?A???C!50?_$#24!176?_$#25!47?__!189?A!11?C!56?C$#26!255?!16?G$#28!30?G!18?_!18?@!50?A!9?@??O!106?@!6?G$#29!27?_!12?O!48?O!27?A??A!7?G!5?_!37?A!89?C!12?O$#30!29?Eo!4?A?_!18?_?g??_??GWgq??aK!40?_???A!7?G!5?AO!40?O$#31!61?A!10?A$#32!29?!6@?CWoo___!12?_?oOw{[~~vfVL}?\o@!9?~!6?_C!17?!4_?__a!4_c_?__??o!5?O?__`__!31?@k$#33!36?G!37?A!15?A!31?_??__??_??@@BRR][O!31?A$#35!173?G!37?G$#36!177?_??oO$#42!22?@!67?@!177?A$#43!138?A!113?C!8?C$#50!255?!14?G??C$#52!173?A!79?C!6?C!7?G!5?C!35?O$#53!189?E!11?G???G$#56!255?!11?A$#57!54?A$#59!255?!18?C!32?_G??@$#60!178?C!55?@!19?C!52?oOJI$#61!180?@??OCO???@C?_???O!9?_A$#62!211?O!47?C!48?nsC$#63!188?_?G!7?H$#64!22?G!4?G!11?C!11?Q!5?C??@!46?A??CO!125?A$#67!176?O?W@??o?A!9?_??@??_!6?G!4?@???O?_!27?A$#68!88?C!20?O!140?O$#69!78?C!4?_!7?C!91?@??@?G???G??_$#71!174?A???A!7?A?C???CA!32?@!14?@$#72!174?gA!11?O!24?wG?A?XG?O!6?@??@@$#73!174?PLJ?@!34?s]_L??o!5?@???@??@$#76!175?OC!23?G!11?C??K?C?G?@!25?A$#77!255?!14?_!11?@$#79!33?G?_!21?@!27?_??A!6?G!5?_!5?G!34?A!25?_$#80!25?@!118?A?@!7?A@!6?B!4?A$#82!24?gg!9?O!10?C??C!24?_C??O_!4?S?GA???O?G?o??W_!4?O!36?C_??KqO???_G???_??G??OG???_C$#83!44?G!5?B!99?G!6?G?A!5?D$#86!23?bA!8?O_!5?@?A??DH?QHW!4?AD!21?G!5?_ACD!4?AC??O???K?O?GO?O!33?GH??_?Gc_??_C__??CO?OcU?O?@?WG$#87!23?KOOY!5?{_G???@AAECIEOANLOC!4?@AA!16?GwoW_S!4?JXPw@??g[_iCA{eSoOgW??O?GGG!30?QO\sA?`XCD[UxH?]cw`TnG_yIsCWcs$#88!199?_D!7?@$#89!58?@@!32?@?@!49?@!11?@?@$#92!34?O!12?O!26?O!19?O@`?@@A??A!9?GG!28?_!10?OO!4?g!5?G$#93!77?_!23?B!9?G$#94!109?@@@!138?A!8?A$#95!112?@@!94?O!40?O???@!5?_$#96!184?@???@???@??K$#97!255?!29?A$#98!183?C??G!4?[??@@!34?AA!11?@$#99!187?D!8?A$#101!255?!27?A$#102!219?C$#104!224?A!14?C!41?G$#105!227?_!12?_$#108!219?A?G?K??C?GC?w!4?OC!7?_?_!5?_?__$#109!218?A?EEKO[{w[sw{C!4{kw{wWwwooOoPo``_`?_!18?!6_soQHD$#110!255????_!13?_$#113!21?~!219?A??CCC??G!8?OOPP!8O!4?@@??A!4?_$#114!255?!12?C???@@?G$#116!89?A!183?GA$#117!81?G!49?_!111?A$#118!29?_!5?@!5?O!4?_???_?S??O?G!23?o!44?GG?OO!143?O$#119!255?!6?G!6?C$#120!236?@$#123!88?G!166?@!28?C$#126!26?_A!7?G??A???G!37?B!23?A???O!6?@!124?C!23?!4_!9?G!4?CA$#127!88?_!174?G!6?C$#128!28?WO!8?C???O!9?B!28?B!91?_$#129!53?C!194?C$#130!53?G!184?@$#131!89?G!163?O!15?A!5?C???A$#132!255?!10?G!5?C???A!6?_$#133!242?A!15?@!21?@$#135!235?@!28?C$#136!242?C!14?@!25?O$#137!54?G!33?O$#138!177?O$#140!71?A!35?_!6?A!5?GGWWOSO?_?HDIM[KK!74?C$#143!22?_!21?O!35?C!21?C!13?G!53?@_!109?C$#144!27?C!168?G!14?_!49?A$#145!186?O!33?@O$#147!187?G!12?A!7?C$#148!24?DAC!6?C!5?@???C!5?A!5?C!23?G!14?C?GA?G?GA!37?C??A??GCAGA??ACA?AA!5?C_@??@$#149!54?O!188?C!12?O$#150!255?!10?@D?@C$#153!191?_??G$#154!23?O?C@!7?C!6?!4@I!39?Ca!5?_R?AC@?A!5?GG!5?G!26?@B@C?GPCA?RoB@??G?P?CA??@@?AWA$#156!227?A!6?A!9?@$#157!89?C!175?C$#158!247?G!22?A$#161!27?@!8?_!38?A!4?w!129?O$#162!51?G!53?A!148?@!22?OC$#163!183?A!6?A!26?AC@???_!24?A$#165!179?oG_@__!17?Bj$#168!178?_?CNE?WN???w!6?_{o??v{S~v^@$#170!22?A!8?W!42?@!16?@!14?_!6?C!57?C!38?_!30?C!25?I!8?O??G$#173!199?S$#174!255?!16?_$#177!22?O!32?G!18?C!8?M!6?_!12?Cc!4C!62?O!108?G$#178!180?A!5?_?O?O?O!23?_$#179!247?C!37?A$#180!239?A$#183!255?!23?O!4?G$#184!195?O!11?_G!11?G!15?A!5?@!8?!8A$#185!36?A!42?@!48?O$#186!29?GC!6?E?G!12?_!19?o??@??A!43?CC?G!7?_!39?O!89?C$#187!245?G$#188!54?@!229?@$#189!240?A!29?O$#190!255?!16?O$#192!173?C!5?A!96?A$#194!177?G?G??G??_!11?AA!8?C!55?A$#195!32?A!40?o!31?_!5?C!59?G!104?G?G$#198!255?!9?G!7?G$#200!255?!10?A$#201!22?C!8?_?A?CO!36?G!35?A!4?!5O?O$#205!175?_???C???G???_??_??|O!5?O!6?OA@??A!20?@$#206!209?AC$#207!174?C??F!35?B@@A?O?_?@@@???@$#209!199?J$#212!255?!5?A$#213!37?@??C!17?A!17?C!24?C!13?G!23?A!104?G!18?_!4?_$#215!243?G!4?@??@$#216!30?A!12?_!8?G???G??C!12?GF!47?C??C???@ACG!124?@!53?_$#217!36?@?G!4?O!12?O??A!12?C!45?A!11?_!41?@!78?C$#218!208?_{J!50?_$#219!214?_O!5?__$#221!46?O!29?G!26?_!36?G_!13?C!12?@AA!91?_$#222!222?O!57?A$#223!196?@$#231!226?A!30?_!22?C$#233!217?_$#237!31?A!58?G!24?!5C?A?@?@FFEK?AC!78?A!32?A$#238!34?A!6?G!71?AC???!4@BABA!13?G_!70?@$#239!51?@!38?O!17?A???SO!4?GO!131?O$#240!173?@!66?@!4?A!9?!4C!5?A$#241!91?A$#242!51?C!25?C?A???P!22?A??CO!5?@G!20?@CO!57?C!63?A$#244!225?A!9?A!9?@$#247!54?C!197?O!13?G???G$#248!27?O???C!39?@!4?A!33?AAA!4?@?G?O$#249!114?@!71?C?A???A!25?@!30?A$#250!100?@?!7@!151?_!9?_$#251!224?_???AA??AA$#252!187?A??@B??EAC$#254!222?AA!22?@!34?_O-#7!255?!27?@$#8!226?_$#11!21?C!190?G?O!10?O!54?_G$#12!54?@_$#19!54?A!26?@@!5?@!126?_$#20!54?C$#21!69?C!64?@!37?O!40?G!79?O!6?C!8?G$#23!27?C!41?_!11?Co!54?A!143?A$#24!180?OC!4?G?_O??G!7?_$#25!226?O!61?CC$#26!78?O!6?C_!195?C$#28!54?O!81?@!162?A$#29!138?G!33?G!106?C$#30!28?GWA!9?G???A?@???@A!4?_Cg@W??GG@AI??S!35?@?@?@!6?@@???A@A!5?A???C?CO?B_GC__!27?CA!44?@$#31!255?!25?A$#32!25?oK_oe|!7?@FFNFFDFEFFFA@BF_@^zV}f~~vv}lt^?b~o!9?C!5?O@!14?@@?@?@?!6@??@@B@A@BBFEFDNNMY[whroFCWWO_!26?B$#33!53?G!12?O!15?A!45?@!81?@$#35!217?_$#36!176?LC??@wA!12?G?M]!4?K$#37!187?C$#41!183?C!7?_$#42!214?_!7?G$#43!96?_!207?A@$#48!184?C$#52!219?@!70?O!7?_$#56!255?!27?GC$#57!80?C$#59!255?!27?OWGOWGO!6?G$#60!255?!29?OG?OGWGGG?G??C???_go!5?B$#61!185?G!5?@!8?A?_$#62!212?C!80?G!4?C_aOOG{}~~N$#63!187?A?C!4?@!4?G!5?A$#64!31?w!51?A!15?C???A!12?A!7?C!4?G!14?G!58?_!5?C$#65!78?_$#67!185?C!7?@!5?E!4?G?@!16?C?G$#68!128?G!75?_!72?O?_G$#69!22?@!61?_!4?O!16?A?AA!61?E!44?O???C$#72!213?CA?GOCo!4?E?A?KWGOoO$#73!212?@ADKA??KPP_b@EGG??__?__?_$#78!221?G$#79!91?CO??C!51?A!12?A$#80!37?_!6?_!32?@!6?O!6?G?G!7?@!7?C!4?c?C??_!5?G!23?CG@???G??C??_G@$#82!23?x!8?APQBCG!6?OO!4?O!23?ORC!9?B???__C?s?A?AA_Os??W?G??cO???SO!4?O!5?O???_!10?@???GHG@??@GK?@?AH!4?@QcCgS$#83!51?O!43?G!8?C??_!17?_!22?_?@?G!10?O$#86!22?_!10?G?G!14?_!43?@?G!6?_!14?_!13?_!13?O!4?G_?_$#87!22?OAK!7?LEdoaSg!4?o??ooOOGgo!21?nczIFP!6?C???[@hbAODD@@P_GOGC{SWwOK{_O?_kWK{goww?g_ooo??_!9?B?LCSVyUeUvRe}Zhu{\vmulJzVj^$#88!190?A$#92!34?G!58?O!14?C!9?C!6?O$#93!105?_$#94!207?A$#97!207?@!22?C!42?_$#102!233?G!5?_!36?_$#105!245?A$#107!255?!7?O???O!7?A!5?@$#108!230?AC??A??A?AC?@K?G?LGWA?AC@??_!4?G?A_?@AI@!5?A$#109!227?@@B@BFFLLN\^Tz~}r~t~qvf|n|z}~~^~~~^f~|^n}|d}~~^\NLfrP$#113!21?B!255?!5?A$#114!210?C!16?_$#116!87?_!121?_$#117!73?_!7?A!58?O!156?_???A$#118!27?Q!53?o!51?@???C???O!31?@!9?O!8?o!27?A$#121!77?_!9?C$#122!208?_$#123!79?G$#126!22?A?O!12?A!42?_!4?A!4?@!16?A!97?C$#127!87?O!125?O$#128!26?_GA!106?@??CG??_!29?_GA!4?oG??G??_??G!10?O!9?A!10?C$#129!21?_!59?G$#130!28?@!40?Z!66?A!49?O$#131!54?G!33?C!120?G?G!13?_$#133!21?O!202?O!56?C$#135!228?_$#136!55?C!224?O$#137!87?G$#138!174?C@??_???O_?_???_!5?_G??_G$#140!41?_!46?_!31?A!20?A$#143!80?O!16?G!12?AA!10?C!48?@$#144!95?_$#147!190?@$#148!23?CB!7?__!5?_!8?__!27?C!7?@!4?AAACGB?A???G?G_???_?G_?C?_?O!26?FAB???_O???P?cO?@!5?O$#149!209?O$#150!55?O$#154!25?@!6?O??CW?O!6?_!29?G???_!11?O!11?CO!8?!4G??O??G???O!34?A??G$#156!226?@!52?A$#157!55?G!27?@AG$#158!88?A$#160!182?_$#161!38?C!4?G!56?A!4?A!6?A$#162!49?G!30?G!4?_!48?_!6?@$#163!227?A?C!4?O??_$#165!176?qzGLe?K@QOE?E@_E??GE?p_?CO]A$#168!173?_w{??VA?A@A`?@o@AOWB?u@B?@O?n@PF@$#170!25?G!72?G!31?G!15?_!24?O!102?_!34?C$#175!187?GG$#177!25?C!14?_!7?G!31?@!8?G!6?O??O??@?A!8?AA!8?C!18?A!62?O!71?G$#178!174?@!25?@!13?G!12?O$#179!21?G!194?_!6?G$#180!211?C$#182!210?_o__!89?C$#184!206?A!25?G??O??_$#185!141?_$#186!26?O!45?BO!61?A!37?C!41?O!6?C?G!61?CC??CCSCC$#187!84?C?O$#188!78?G!5?@??A$#192!210?O?O!70?_c!11?C$#194!181?@??G!5?G!38?_$#195!31?C!12?G!28?B$#198!80?A!129?G!70?O$#199!255?!30?_!11?G???G!6?_$#200!255?!53?O$#201!45?G!5?C!21?C!44?A!6?C!9?_!139?_$#205!185?B?@??C!8?@!11?A!5?@_!5?_$#206!207?kKA$#207!213?@?@CC!4?A???C$#211!196?O$#212!208?O$#213!22?C!16?O??_!9?G!33?G@!11?_!21?C!5?G???O!15?_!22?_$#215!235?A???G!11?O!9?_!7?O$#216!27?@C!26?A!16?C!15?G!51?G!141?_!12?C$#217!29?@!38?_?G?G!9?G_!55?C!31?_!109?_$#218!204?OG{OB@!70?C$#219!211?@A??A@IY?g_P!4?CO?OG???_$#221!22?G??A!10?@!5?O!34?O?A!4?G!4?_!8?C?GC!11?O$#231!255?!24?G$#234!255?!30?C!5?O$#235!173?O?A!12?O???C{?O_$#236!196?C$#237!38?A??O!31?G!24?O!177?O$#238!26?A!13?O!12?o!35?A!7?O?G!26?C$#239!31?B!7?G??G???G!36?K!5?C!10?C!16?A!27?O$#240!219?A$#242!24?_?@!20?G!67?A!16?O!10?C!27?G!21?A!11?_!15?A?O$#244!236?O$#247!79?C!5?O!195?@$#248!37?@!12?C?C!30?O!13?__??AA@!15?A!13?O!144?G!17?G??CO$#249!225?@$#250!255?!20?O??C$#251!228?A-#7!20?M$#8!87?W$#9!77?_$#11!228?_???I?O???G!39?C$#12!56?G!29?O!132?A?C!7?A!4?C?_G!5?_$#17!77?O!129?C$#19!55?@O_!29?F!123?_!19?E$#20!201?_$#21!21?A!45?G!112?O$#22!227?_!13?_$#23!67?O@!4?A!73?G!95?O$#24!170?wA!5?O?OC@??O@@?@???_E?A?GA$#25!21?G???O!56?O$#26!86?A!177?O$#28!21?_!122?@!30?O!48?O!62?@$#29!63?O!17?A!69?O!83?G$#30!24?G???_g!25?O?G?K`???C?@AG?@GA!10?S!55?@?@!16?_!17?G???_!4?G$#31!255?!16?O$#32!24?s???^V~!21?_]^G?F~r]~~Ny~M@o}}vD!9?AGo!55?@?AAC@BACCGGOOOoo_?_!15?_$#33!64?@$#35!223?C$#36!171?wB_???_!8?o!9?BE@$#37!186?G!9?C$#39!198?C@$#41!187?O$#42!238?O$#43!188?_!4?O!32?_!4?@!59?@$#46!212?_$#50!73?G!194?_?A$#52!181?A???_!11?_!20?O??woo__!11?O?__!52?@!11?GA$#56!255?!26?@@$#57!73?_!14?_$#59!255?!23?oge}}~~wEcK!5?@$#60!255?!30?EwYq}}m{iuanfWQd]??O@$#62!229?C!61?OASG\OWflY`~~nE@$#63!201?@!49?_$#64!23?O!7?F!11?O!8?G!19?OO!5?GO???@???A!8?O!39?@!11?A!8?O!43?G$#67!182?@!15?g!9?O_!16?G!4?_!9?G!10?_$#68!44?O!30?O!83?O!111?G$#69!148?@!54?A!20?C!7?@$#71!229?O$#72!208?_!13?@@ACACC!4?@@@B@???EEA?CC!4?G??_??_$#73!181?G!24?__!13?@?A???GGGOO__!4?@BE?GGK?GGGWW?O?O?O??_$#79!106?CC!9?G!45?O$#82!22?A!9?@CDGL?CSaG!4?C?O__B!29?_!7?C`LMC!6?@?GAKA?@!5?a?_AOo@OO?`GAAG??WG@???A_cO?G!10?A??A??G?G?CG?@E??C$#83!104?A!6?A!6?G??@?C?OC!14?_!13?C!11?CG$#85!100?C!52?A$#86!26?O!6?g_???Ag!4?CA???GU!26?C???O!7?GO?_!5?OA???@?_G??G?c_?OGDC?G!5?`?_?B@?A!4?S!5?O?O?_!8?@B@K?@@A@A$#87!22?X@??G!5?CPYsq~HAPOo@H|bvlVG[@!22?BG?FE!9?qMq@B@!4?\qvt{`X`iJv|P^KhVw`BuneuArKwP^{cv{nnvwIWgOOG_o_o?_@@B@?B@AKEABMYDCwXyfB$#89!22?C???_!5?A!5?_!7?O!33?A!12?O!10?OCQ?C?A??O!9?O!6?A??O!4?A!22?O!5?@$#92!22?_!57?C!27?_!5?A???C!8?A!14?_G!5?_!10?C???Q?_?O!97?C$#93!142?O$#95!255?!8?_!10?_$#96!255?!4?O$#97!255?!12?G!5?G$#98!255?!5?O$#100!255?!7?_$#102!255?G$#104!251?C!9?G$#105!243?@???A!8?G!16?O$#107!255?!8?A!4?A$#108!253?CB??C??G!6?@!4?C$#109!244?!4@!4BFBCFFJNNFFFDFFBA@@@c_e]NFB$#110!255?!15?_$#112!255?!9?_$#113!20?O!205?O!14?O!4?_$#114!20?_!66?_!141?@!15?_$#116!210?O!14?O!4?A$#117!81?@?A!101?C!47?A!71?O$#118!25?K@!40?C!14?G?G!60?A!4?O!26?C?_$#119!228?@$#120!79?O$#121!76?C!9?C?W!175?G$#124!181?O$#126!43?C!30?@?@!4?G!12?A!41?@??A!4?G??O!15?_!39?OC$#127!233?K!43?O$#128!25?A!40?_?A!4?@!9?@CO!57?@A?C?G!26?G_AA???_??A!20?G!63?O$#129!74?_!5?_!129?_!19?@!44?_???@$#130!21?@!154?CG$#131!56?_O$#132!218?A?C?G!9?C!45?G$#133!74?O!133?HO!19?_C!16?_!28?O$#135!78?G!148?O!5?O!5?G!8?_$#136!55?AA$#137!75?GA!9?@$#138!174?O??@D@??O@g?A?E?o?PH_L?O??@$#140!24?A!28?`!41?A!45?A!6?A!5?_!5?_!9?C!96?_$#143!23?C!18?G!9?C?_!39?_!60?G!13?O!30?C!68?A!7?C$#144!206?O!20?A$#145!240?@!16?O$#148!32?G??@!4?G!6?G??@!38?@???g!4?g_GG!11?@!7?G!5?C_!6?G!4?k!12?CC?C!7?GC$#149!86?_!140?@!7?C!41?G$#150!56?C!151?A!8?@!5?G!16?O???_!34?A$#154!32?_A?A??O@C_?A??G?A!30?@G!11?O!9?A!4?OO??G!10?HG??@!7?O!18?@!5?@!4?_$#156!246?A$#157!86?G!121?CG!26?G!39?_$#158!235?_$#161!27?_!14?@!45?C!81?@!29?_??@$#162!255?!14?C$#163!244?A!7?G$#165!172?{CMA@?OC@??G???_???`!5?@$#167!185?O!64?_$#168!173?Z@@??gA???oB??N??BW??N$#169!255?!8?O?W_!11?A$#170!42?C!9?O!42?O?A!45?C??G!10?O!43?OC?@!61?O!5?@@$#171!183?C!7?A$#174!255?!17?A$#175!190?CC??O$#177!23?G???W!13?A!30?_?A?_!21?A!43?C!8?C!10?_!38?G!60?O!6?_$#178!207?G!24?O$#179!224?G$#180!218?@?A?C!19?O$#182!182?C!6?C!9?G!9?EN^^~~~}}k{w!15?O$#183!255?!14?G!4?@O$#184!241?@???A???C???G!7?o$#185!63?_!107?@??_!21?_$#186!21?O???_!42?C!4?C!9?_?g!59?C!79?G!10?C$#187!75?C$#188!77?A!187?_G$#189!242?_$#192!180?G!8?A??C!26?@?A!18?G???O!47?@$#194!182?A!22?_!28?_$#195!23?_!7?G!12?_!36?C!58?A!12?G!16?A!101?G$#198!77?@!157?O?_?O!40?@$#199!21?C!206?A$#200!255?!24?OG$#201!24?@!6?_!10?A!12?_!16?G?C!13?@!6?@AH!53?_!9?_!40?AK???A!18?@!40?OO$#203!255?!22?_??O!4?@$#205!181?C!7?_!30?@?A!7?G!4?A??C!7?O!6?_$#206!200?GA???H!66?O$#207!207?O!47?_$#211!196?O$#213!26?C!24?_A!32?A!12?C!51?a!9?O!8?G!93?G!6?G$#216!25?@!29?C@!9?O??@!4?G!67?@!4?C!5?_!22?O!4?_!27?@!6?@!14?G!17?_!38?@@$#217!67?_!14?D?A!64?W??_!116?O$#218!200?OC?_WEB@$#219!198?O!25?@BC!10?AAC???C?G?SO??O?O?O_?_?_$#221!23?A!8?O!8?C?_A!31?O???@!4?@!28?C??A!6?C!11?C??C?C!10?C???G$#222!254?G!7?G$#229!78?o_$#231!255?!13?G$#232!255?!15?C!7?@$#233!182?G!5?W@??I$#234!230?_!59?@$#235!171?C???CA??GA??AC?C???G!4?oG???A$#237!238?_$#238!95?C!42?@!8?@??C!54?O!80?@!20?@$#239!26?A@???O!11?G!41?C!8?W_{?@!100?_!4?a!62?C???A$#240!189?G!9?C!28?O!5?A??C$#241!75?_?G$#242!27?E!66?C??_!47?G??O!5?G!14?_!19?O???_!5?A??`???C!38?O$#247!255?!24?C$#248!41?@!40?_!12?G@C!54?G!46?O??O!31?G!33?C$#249!248?C!9?O$#250!255?!16?@!4?G$#251!242?@!7?C-#7!18?_C!216?C??G???OO$#8!241?@$#9!77?@??G$#11!19?O!67?A!128?O!17?A??C@!4?AA???_??@??@A!12?O?G??A$#12!57?@!155?A!36?@??A!18?C$#14!251?_$#17!246?O$#19!59?O!8?_!18?P!142?@!11?A$#21!65?C!22?G!103?O!7?@!31?D!5?C!8?O!10?@$#22!60?_!186?A$#23!65?G!97?C!76?A$#24!173?@!8?B???A$#25!213?C!18?_!26?@$#26!57?A?_$#28!25?A!48?@_!12?O!66?@!19?@!127?C$#29!65?@?_!20?AG!68?A??A!9?A!24?A!63?@$#30!31?_!10?O!15?@??OA???C?O!15?@!76?@B???O?G??C???A!5?G?G??G??Go$#32!24?]???F~nW!11?K!8?~]!5?FNn@?F_w^NNF@!12?A^w???O_!66?@@@??I?Ucc_KMWKKFCC???ffwow{swwo?__$#33!24?@!5?O!11?_!10?_!27?O!4?C!76?@A!13?__!22?A$#35!195?__$#42!78?O!136?C!35?C!21?C$#43!188?@!11?A?C!11?A$#44!191?A$#50!76?G!89?A$#52!194?A???A!5?O!14?OH|~m!4~}}}c?@!38?G$#56!255?!14?__?o_{QK@_$#59!255?!16?o?O?_PiZ]~vnn~zr`cP@EOB??_!5?G$#60!255?!26?GOO?CK]YguxBs~]\hPOSO@$#62!20?_!174?C!44?C!47?@EG?kG?`AUmnjNEB$#64!74?C!4?_!11?O!82?G!5?G!20?@!43?G$#65!72?C!190?_@$#67!190?A!6?@$#68!58?O!38?A!97?A!7?O$#69!32?O!11?G!28?AO!8?G!72?A!6?O!12?G!22?@!10?@!32?C$#71!189?A!22?C$#72!191?CCCG!4?C_??CCS@?_C?C?G?_$#73!189?@???G?GOWw?SO???@uxA@KGG_O!20?@$#77!255??_!5?_$#78!209?_$#79!26?_!10?C?C!5?G??C!52?O?_!19?G!10?A?G!19?O$#82!21?_!4?G!6?A?R??I?A???O``S_?G!4?C?G!34?G@_!6?L?CCS@??@??_???G?PC?_??_?CK?_???AO?C_?WA???@?oS??E?O???K??CG!6?@!5?_$#83!33?G??G_!10?@!9?_!23?_!13?_!5?_??G!10?@C!33?@?C$#86!21?O@!9?A?X?cG?H??A!4?_?cO!40?GO?Xo??I?OAO?AA?GM?A??@A??Og??OO!4?PCO?GI?K??C??@?J@?`B_?D?s_AC??Oc??GO_!12?O?G$#87!22?k_??RW!4?CtCcQ@oqCF@?_U??WOf!4?iKO!14?o{!8?A!7?BFFmAGO?TtB_LQX`yr@y_~N]|Kqh?r|Gfv^~jazFlvpL`vqB~B[bc}CMKI}qpINwi}_cWw?o_!5?B!5?__?G$#89!22?O!17?G!78?G!15?G!5?G$#92!22?A???C!5?@??G@?@!7?WB?@!4?@?O!32?@???O???O!5?@_!5?G?O??`?A???BG???O??G???_??@G???O??I??@?GG!26?O?G$#93!98?_!55?O$#95!250?O$#97!255?!6?_$#98!203?_$#101!255?!4?A$#104!251?O!13?O$#107!255?!9?A$#108!252?G!6?G!12?@$#109!247?!5GOWWW[[[S[]]][MMNFFBB$#113!19?GB!210?@?A!5?@G!8?_??@@!12?_$#114!214?CG!26?@!11?A$#116!252?A!14?_?O$#117!63?A!20?G$#118!62?OD?A!9?K!7?A!5?_!69?AA!6?G??@!12?C!6?GG!51?G$#120!77?AG?B$#121!71?G$#124!194?O?C$#126!27?A!13?G!12?C!22?O!4?C!7?C!6?C!77?G??S!14?_?@!62?A!14?@$#127!69?OWC!15?C!144?A!18?A!19?G???@$#128!62?_?o?@!8?A!4?OC?@??@??O!72?C??GG?OO_!8?@??C?E@??C!4?O??@!45?G$#129!20?C!58?O!121?A!55?@$#130!77?C!98?@!7?@!26?@$#131!59?G!214?A$#132!216?G!12?@!11?A!5?@CCC!16?O$#133!241?G!14?@!17?@$#135!212?A!22?A!16?_$#136!69?_!201?C$#138!171?@!5?@@!8?A?C@?@?@!44?A$#140!28?G!12?_!46?_!83?O$#143!21?C?G???@!15?@!10?O??C!18?A!4?@@!9?_!86?OO!63?C!10?_!9?@O$#144!197?C$#145!202?O$#148!34?A??A!8?E?AI!5?OA!37?C!5?C?AG??CCoCS!4?AC?E?AC!8?Q?CO???O?c_?O?oO!14?_!13?OO_$#149!255?@$#150!58?C!28?_!124?@!27?@!4?A?_$#154!27?_!6?_???C!32?_!25?_?A_!9?@!4?O!25?C!18?O$#156!255?C??___$#157!87?G!130?_!27?A??@$#158!237?@!18?A$#161!23?E!8?_!7?_!33?G!6?_!7?A!75?@$#162!44?C!9?G!17?@!80?@!50?_$#163!208?CGO$#165!187?@???@$#168!183?B$#169!246?C$#170!31?@!11?Q!7?_!8?O!13?A!8?C_!5?G!63?@!13?C!8?C???O!70?C_!9?@$#174!255???_!10?G$#177!43?_A!6?@!24?@!18?@?@!62?C!6?A!5?O!20?_!54?O$#178!190?C!6?_$#179!245?O$#180!217?_!47?_$#182!205?_!8?@BFN^nuA?P!4?@$#184!208?G$#185!81?G!106?A$#186!25?x!36?GG??A!8?P!8?O???C?_!65?@!7?G!6?_!5?AA!6?A!5?O!72?_!36?_$#188!253?C_$#190!250?_$#192!213?@!17?G!7?C?C$#194!216?_!21?A$#195!51?A!24?C!168?C$#198!58?I!13?A@!143?O!30?BAA$#199!19?_$#200!198?@!16?O!20?A!38?KA?C_$#201!20?O!7?_!22?C!28?_!15?B!60?A!6?@!4?@$#203!244?@@!27?G??_S?@$#205!194?CO?A!13?A!22?@??A$#206!202?@$#207!198?Cw?G???A?A!4?_O$#211!192?A$#213!21?G?O???C!4?G!21?a@?_!13?O!11?O!11?AG!157?C$#216!20?G!4?C!36?CoG!11?o!7?C_!75?C??C??O!4?AA??A??A!7?C!43?O!15?C$#217!65?O!20?A!70?@!11?_O$#219!196?G???G__?IGGCPAAOO?_$#221!37?O??P!6?G!8?_!15?G?_???_!4?_!11?C?G?GG!12?_!34?@!8?G!6?_?@!79?G$#222!209?O!56?@$#229!78?FNC$#232!255?!5?A$#233!199?A$#234!214?G!29?G!59?@$#235!172?@!13?@$#237!31?C!10?G!8?O!29?A!7?C!79?A!73?@!4?O!13?@$#238!24?_!28?@??@!13?_A!159?A!25?A???@$#239!41?O!35?g!4?G!5?@!76?_!37?@!38?C!29?A$#240!193?A!10?@!31?@$#241!21?A!60?O$#242!23?@!18?C?@!51?C!65?G!14?_?C!12?G@!7?CGA$#244!210?_$#247!255?!13?_GO$#248!21?@!6?O??A!19?G!112?O!7?_!30?G!42?@$#249!211?_$#250!255?!15?C-#7!16?O!246?@$#10!62?G$#11!62?A!161?O!30?@$#12!87?O!131?@???G$#13!62?C$#17!62?O$#19!61?A$#20!66?A$#21!17?O!238?G??O!10?GGC??G$#22!252?@$#25!85?A!174?A!6?A!8?G!20?G$#28!18?C!42?_?G!108?@!121?_$#29!67?A!20?A!82?A!30?O!95?C$#30!29?A?A!29?O?O?L?C!20?C!4?__!7?O!73?G???P???_S@?O??I!31?O$#31!30?C!34?O_G!20?@!4?G!7?C!68?GG!5?CC?CG$#32!25?C???@J\o!19?@!8?K?_w_[o]B!16?B?w??@A!8?w_!65?BNvSo??oszz~iv~~^j}~n~~t$#33!29?C??G!35?_!31?G!66?@???_$#35!209?G$#42!220?@???G??_!22?@$#43!208?C!51?O!14?C$#52!206?@!14?@ABFN^^!5~}{oo_!14?A!4?AAA!16?C!4?_$#56!253?AAC??CKKWWWOkwPp`qR?QRO??@$#59!255?!14?Q@_R`_@OryUV^v}!4~V~~]zNJNFD$#60!220?C!34?A!9?O!6?_???AC?H??G@!4?G!4?_!5?@$#62!255?!33?_??`COS?GAB$#63!199?@$#64!20?@!4?_??@!22?@!23?G$#65!78?A$#67!212?_!4?@???G$#69!33?O!6?C!36?G@!113?_!8?A$#71!210?G!11?O$#72!203?Y?O!5?GG?A?CAS?WO?_$#73!200?@?FCG_?@ADECO`@AB?GS__$#76!204?C!12?G?G$#78!215?C$#79!33?@???A!96?_!19?G!19?A$#80!18?_?G??A!10?O?C@??O???`!4?O???OU??A?A!10?O!9?G??C_!11?O_D?@???I!5?A??_G!4?S@?G_??E???Q_??B!4?@_?G!6?@?A@???@CG?K?A?O@C!30?A?CO$#82!48?_!68?C!20?C!15?@$#83!19?WOev@??IT!5?CisaORO_o?OApIL?_eGg?H?^[_S!10?_TGoA!6?CPo[!9?@HKM_a???ICO]_iALaqCoVcJ?AIGOK?^?FF?cBVAKWSOwU?FRRQAbqfWSSMIuhWpQv@_l[?MOO_!5?L@!17?aExGSC$#85!26?C$#86!21?O!4?@Go!14?GSAO?ICGc??_I!16?A@!4?O?CGC@?_!8?CAB?O!6?J@S??O@!4?@_L`_O_?T_`GO?@??@?A?E?GK??K??GG?CA@?S?U???GO!4?oAG!7?A!21?GOWG$#87!18?O??@GS??_aG!4?AD?Xc_???O_??Da@HOO?_?P??A!12?a@G{!5?ARAGA!5?G_??A??OA???AD_C?GPG_KK@CGIOaGO`D?G?O??o?[_{O_hh??@O??CTSC??G?_???cGc?_J?`E?gc!26?xCq?G??_$#89!57?@$#92!19?_?G?_??O!8?B?G!6?G??O?A!5?_???G!10?GG!7?B@?GA!14?G@?@??@??@?T???YA_!6?A???G!5?G!5?@?A???H??@??@??@!4?@??O??H!28?\$#96!204?A$#97!213?A$#99!214?C$#104!215?G$#108!206?CO!7?O$#109!205?AGGo_??ACG?O_$#113!16?_K@!237?!7@$#114!220?A$#116!253?@!26?_$#117!63?@!21?@!85?@?O!77?A!17?G???C$#118!76?G!9?W!4?A!118?O$#124!235?G!20?A!4?CC?gA!29?O$#126!19?A!4?O!4?_!9?@???@!8?C!47?A??O!105?O$#128!62?@!27?@!82?_!37?_$#129!225?_$#130!62?_!155?@???G$#131!64?C?@?@!182?@$#132!221?A$#133!63?A$#136!61?@$#140!25?G!43?C!30?C!68?O$#143!18?G!59?G!5?@!18?_!70?O!33?G$#144!39?C!50?C!82?@!37?O$#145!203?@$#148!20?_!14?G???_??_???_?O???O???_?T_!12?CA!4?__?__!7?o!4?C?@!6?O__!11?O?CC?P_??ogC!5?C!4?OgC__???Ga?gO_??AA!4?O?_!30?AC__?_$#150!65?A?@!19?n!138?_!27?@!9?@$#154!45?C??C?@!4?C?_G!13?o!23?_??O??@!4?AC_?O@?@?O!4?A??A!4?JG!4?@A?A_??_??g??O?_!9?AC?A!34?A_$#157!60?@???A!157?C$#158!63?C$#161!20?A!7?A!10?A??C!17?c!9?A!4?_!9?G!15?A!65?A!7?C!16?O$#162!24?G!16?C!37?O!127?C$#163!216?G$#167!201?C!21?C$#170!29?G__C!7?@!12?A!23?_!11?H!84?_G!92?A$#177!33?_!35?O!22?_AG!110?@A$#179!221?C$#180!18?A$#182!222?@!15?_!27?A$#184!211?ADGO??O$#185!92?G!79?C$#186!25?@!38?@!11?S!14?CC!79?A!60?@$#192!207?A!29?O!19?G!6?C??G!9?G$#195!19?@!4?A!28?C!6?A!28?A!102?C$#198!225?O!39?@$#200!255?!12?_!7?a`?C?G$#201!24?@!16?AA!32?A??C!16?_!4?_!72?C!18?A!4?@$#203!255??CCG$#205!218?A$#207!201?@??o???@A???O?@?C!4?_$#213!19?C!4?_???C!12?GGA!7?A?G!6?W!8?_!7?C!13?O???O???G!68?O!27?@???C$#215!216?_$#216!25?A!60?_!6?O!78?GG!45?A!14?A!14?@!13?_!4?G!5?C$#217!76?a!9?C!148?C$#218!210?_$#219!206?_!7?_!4?_$#221!20?C??G!9?G!4?KGG??C?G!13?@!10?C??C@!4?Co!4?O!7?@!5?C!23?A!77?O$#222!206?O$#234!198?@!37?G!17?C!8?C!35?A@$#237!42?@!33?@@!11?_??O?O!81?A!15?@!7?A$#238!30?O!10?@!10?A@!21?@!9?C!6?@!7?O?G$#239!17?_!14?A!7?A!28?G@!4?C!13?C?G!77?_!31?G_$#241!24?C!4?O!47?O!95?A!25?A$#242!32?@!42?O?A?G!22?C!63?@?G!7?@!15?G!9?G_!20?_$#244!205?C?_$#247!255?!24?_$#248!25?O!63?OA??C!74?C!97?@$#249!205?G!4?@!4?_$#251!218?_$#254!204?@!6?@-#2!89?O$#7!16?A!70?A$#8!255?!30?_$#9!88?_?_$#11!17?C!209?@??C?G!50?O$#12!16?@!212?A!4?O?_!43?A$#17!88?A$#19!255?!26?A$#21!173?A!92?@$#23!217?O!13?G!13?O$#25!213?A$#26!86?G$#28!60?_!169?A$#29!94?@!77?_!30?@$#30!60?G?G???C@!22?G!5?C!5?A!66?_R@A?OG_???HCA?aP?EG?S!13?C!11?G$#31!63?G?CA!28?A!71?_!9?o?_!9?_!26?O$#32!32?@C!25?_S?ov~zxM!8?@!12?A!4?_@!5?F|!63?_?oOk}L?nv^N~^uZ||\Mnxv^b@$#33!76?A!12?@!82?O!8?_?A?_O???G$#35!205?O!23?C$#42!97?O!181?@$#43!255?!31?C$#52!229?@@BBFnN^^n~]{O_o!23?@!15?C$#56!167?O!102?@@@!4?@$#59!255?!14?@???@?BBA@A??@BB@!4B@@$#60!255?!30?A$#62!101?O$#64!32?C!26?G!31?O!6?G!27?_$#65!255?!26?G$#67!205?G!24?G$#68!123?O$#69!59?C!146?_$#71!233?_$#72!204?@?TGW?_???@B?G??_??ACAK?WWo?_$#73!205?FIqc_!6?A??O?@??B?AC???o$#76!229?_$#79!29?I??O!6?_!13?@!26?cO!16?A!5?A!10?_!7?G!7?@!17?C!7?A$#80!20?C?OAQ_!4?_O???G_??@_??G?GC?O??H??@G?i@!9?OA???CA???@?OG??cA!5?BAG???@?@G???_G???D_??O?HCG?A???AH??C?@C??Xb@@O@C?G?O??_C?GG@E_?YO???e??@G@?@!26?CA?__?M?W?_$#82!20?@!22?@$#83!18?AA??`_`?_a@???_?A??_?A??_?D_aAac@c__?__O!10?_?`__`G!4?`@??_@_!19?___D??@`!5?_?@__??@???_??@??C??_?_`_d`c??`_@_P@_@_O__O?@?@!27?___P`?@``O?o$#86!19?CG@CG?OGO?@!5?EBATO???O?A?gH@O???_???O!10?cG?OG_w???G?_I?W!7?p?G???@!5?@?G?goA?A_??_EB!5?A??J?GG___?_a??G?O!4?OA??_U?GC?E_GP?ACO??A?@!23?GP?GA@?W??`$#87!20?AUIPGGCKWC[_???O[[IKZJWEQTHSCYKQIUQU]CKB!9?WEXFQT!4?E?CS]AW!5?CKC!5?MO???SVRFAG[UCNyUX?CX]EMCCU]O^UR][E[OOKUB^A^I]XKWQQ?GGUXCGCTIHTOAA?KMC!23?AMGCSYMEOFEG$#89!20?O_!4?O??O!49?O!27?O!4?W!4?OG??G!13?GG?G_!10?O?_??_?G!5?G!30?O???O??G$#92!20?_??CCAA?E??C!9?SC???O???A?C???@?A!11?OC!8?AA???C!20?C?OA@_??@?A!4?O!10?A??A???O!5?AA???A!6?@A??_A?O!29?A_$#95!255?!27?O$#102!219?C$#104!210?G!7?A@??C$#108!209?@AOOG!5?A?C?OO!56?_$#109!209?ADMgoo???@?E?Wg?__!55?_$#113!17?Go!68?@!192?@???_$#114!255?!25?W$#116!86?_!193?C$#117!77?C!11?C!122?@!58?A$#118!62?A!14?I!163?A$#120!89?G$#121!86?C$#123!87?O$#124!238?O?_?gO?_!27?A$#126!34?C!40?@??C!8?_???G?A?O?A??c!27?_!40?A$#127!255?!28?_$#128!61?C@!27?O!7?_!74?`$#129!61?W!156?_!9?A!4?O$#130!19?_!41?_!111?[!66?@!47?C$#132!17?A!217?O?_!44?A$#133!235?_$#136!18?G$#140!32?AG!60?A?A??_!91?A$#143!18?C!11?A!37?C!24?O?_?_!70?GC$#144!93?_$#145!218?C$#148!18?@@?G!4?@@__?G??@@?@_??_@_g!5?_?@GC@?@!13?AG!5?A?G?_@?@!18?G!12?@?C?@@@??@!10?`!9?_K@C!5?@??C?G??CC@!25?C???GC$#150!255?!27?C$#154!42?A!4?@!4?O?G!14?@!5?C!5?@!36?O_!5?G!10?CA???C!5?@!14?GC?I??A!23?O!8?_$#156!212?A$#157!231?C!49?@$#158!87?G!192?_$#161!58?_!17?O!13?A!8?O???@!23?_!35?_??O??@$#163!207?@!8?@A!7?G$#170!19?O!58?O!14?@?GWC!106?G$#177!17?@!16?G!43?G!17?`???A??E!20?_$#178!204?A!14?_$#182!243?G!41?C$#183!211?@$#184!208?A!12?O!4?O?_$#185!61?A$#186!214?C!63?C!8?C$#187!86?A$#190!87?C$#192!232?C$#194!214?A$#195!30?@!29?@!6?_!18?@!13?@!24?_!65?O$#196!88?G$#197!88?S$#198!86?O!141?@!4?G$#199!255?!22?C$#200!215?C!58?B???A$#201!34?o!33?@!21?C!100?G!11?A$#205!218?O!6?@??C$#207!207?C?O!6?CCGGO_?@?C?G$#213!31?AG!35?G!7?_!45?O?O!37?_!29?@!10?CO$#215!208?@???C??_!5?G??_$#216!61?@C!14?O_!18?GO!116?G!10?@!40?@$#217!77?@!10?@!183?A$#219!209?G!12?B!4?O$#221!19?G!5?D!7?_?_!4?C!34?A!6?@!7?@!7?C!8?G???G??C??_??_??_!6?_!15?@!7?A!10?O!28?@!86?O$#222!211?_!9?A$#234!242?C???_!32?C!10?A?@$#237!77?_!13?_!9?G!63?_$#238!59?O!35?C$#239!33?@!42?G!87?_$#240!232?O$#241!68?A!34?o$#242!31?@?O!60?S!6?_?G!87?_!21?@!13?A$#244!213?C!13?_$#246!89?_$#247!217?_!63?CG$#248!33?A!26?A!6?O!8?C!92?G!21?C!13?_!77?C$#249!210?O!9?@?_C$#251!209?C!10?G???G$#254!214?GO_@!7?O-#2!91?CO$#7!18?@!250?_!14?M$#8!225?_!58?`@$#9!82?G??C!5?AG$#10!84?A!8?_!125?@$#11!20?_!202?W_!17?C?G??O??_!20?_!5?C$#12!238?@?A!10?_$#17!19?@!62?C???_$#19!248?O!36?O$#21!60?C!41?_!148?C!4?_$#23!225?O$#25!20?G$#26!86?G!167?_!32?W$#28!79?G!93?A$#29!59?G!36?C!6?_$#30!56?_?_???C@?E@!11?O!18?O???C!30?A??C?GEC??GGM__GCAC?W_C?C??kOE?d!5?o???S@_@o?@?gA?@O??Q?B!17?_$#31!61?C???@!70?A??G???COA!9?C!4?_??O!7?G???GG?@!4?AA??G?M$#32!39?_!17?w]F?wz}nwA!35?H!28?A?AEACEG?[[SO?[]uy{y{c[www{}QMw~I~v~~~N~V?g}VuN}}~Vl|{n~vlpC$#33!64?O?C!35?C!26?@!9?A!25?G!16?O!7?G$#42!81?O!19?O$#43!103?O!144?_!55?C$#50!81?_???A$#52!240?@@A@@@?@??C$#56!251?O?O$#57!220?C$#59!255?!49?g$#60!240?C!63?O_$#62!255?!50?O$#64!20?C!16?G!39?@!25?A!29?@?G!24?@$#65!98?_!122?G!53?O??C!4?I$#68!77?C!195?_$#69!21?O!44?_A!33?@??_!32?O!7?@!45?A!31?_!20?O$#71!239?C$#72!208?D^fKcO_!6?@!4?G!6?@A?ACK?G?O?_$#73!208?G?WqWg!9?ACK?O__?@@?@EC??G?W?O$#77!255?!22?G$#79!24?G!5?A!6?_?A!9?O!21?G?I!13?O!9?A$#80!24?@?gO!5?GQC?A?@?OQW???K@?KA?OC?C!10?W@??__?BGA!5?@!4?C!7?_!8?LCAAHg!5?SS?W_o?G?_??G?c!4?_?_!5?@!49?@CC_F?_?O?@_G$#82!69?C!5?A!59?O$#83!21?MA\QUDKZZ\]Ff_iNDFG\?CCIo}awl`t}N`F!11?_qp|VX`Wdt???@A!5?B!6?O??@KW!4?Or\@c@HLzC?jG\fFBVCKTJU_c?ggwWO_?__??@?@!7?@??@@!35?WqgpUgZJDNHo[Ruo$#85!124?G$#86!21?@C?C@O?c_??_OGO!4?AKHA?C?OE!5?W!13?C?A?A?cO?_??A@???@!7?AK!4?_o!7?QE?QCjz!4?OCGPaA???O?O??_!6?@!50?_CA?@???Y_QA@_$#87!43?@!108?@!39?G$#89!45?G!7?_!26?C!6?_$#92!22?g??G?A?C?@!7?C?A??@B@@?A?G!5?@!18?G???G!6?G!18?_???A_??C?B_???__@???C!8?O!19?@!36?@???c?_?_CA$#93!104?A$#97!236?G$#102!231?A!6?O$#104!224?@$#108!215?G?_!8?AC??SG?O_GO??__!38?OKo@$#109!213?@FD~^{{go_??@@BFMIS{gWo_o_!36?__owkqL}???_$#113!19?S!65?o!135?CG!47?_??O?G??A@!5?E?A$#114!19?G!204?O!60?G$#116!86?@!200?C$#117!79?O!15?A!76?a!132?G$#118!60?P!17?C!94?@!69?G$#119!255?!29?O?@$#120!82?o$#121!255?!28?P$#123!219?A!65?_$#124!243?AAEF?ACG$#126!77?G?@_???@!46?C??G???@!11?@!7?@!46?@!74?@$#127!243?C!39?_???_$#128!59?_I@!16?B_!11?@C???G_?@CG!70?[!34?G$#129!83?A!138?C!51?O$#130!88?@!152?C!4?O?@$#131!246?G!6?_!18?_$#132!239?@!9?O!36?A$#133!239?A$#137!86?C$#140!128?@!10?O???A$#143!42?__!44?O!48?@!8?@!59?C$#144!57?A!68?@!99?O$#145!240?O??_$#148!20?@??_?_A_!4?O?C!6?@??S!5?Q?@?A!13?GI???O!24?A!8?w?O_!9?G!4?OGA?W?O!21?@???@!36?AGO!5?G??G$#150!245?G$#153!230?_$#154!22?P?_??@??__!4?O!18?G@!15?CC!36?S??O??_!5?AO?C_?G?C!62?OG???S$#156!241?_$#157!86?A!165?_$#158!86?O!162?_!26?G$#161!92?@!43?@???_!6?@@@!9?@!31?@$#162!56?G!165?O!63?C$#163!212?A!10?@???G!9?G$#169!218?@$#170!38?_!91?A!12?_!10?A!6?@$#177!39?O!27?@!9?A?A!8?G!4?G?G??@?G!34?@!147?C$#178!223?C!23?_$#179!19?A$#180!20?O!205?_!10?@$#182!224?G!22?G$#184!213?C!12?C!5?A?C!4?O??_$#186!59?O!28?A!6?CO???A?O!69?@!48?A!32?O$#190!85?G!134?A$#192!206?@!29?@?A!6?O$#194!208?O$#195!55?_!25?G!21?C!34?O!140?A$#196!89?C@$#197!89?W$#198!241?A$#200!207?C!12?@$#201!57?C@!7?G!12?C!8?C???A!10?G!27?@!9?A!11?A?AA$#203!242?@!4?EKG?GO$#205!207?A!14?A!12?@?A$#207!207?@A!13?@!22?__$#213!20?A!13?@@??G!16?O!21?O???C!6?_!8?C???_!26?A!10?_!4?@!46?C!14?G_$#215!213?A?A??A?O!55?O!4?A!4?O$#216!60?_A!16?G!14?O@!76?_$#217!249?A!56?_$#219!209?_?@??O!9?A???O!4?A$#221!23?A!8?G???_!7?_!11?A!10?C!12?O??@!9?D_O@?OC!5?G?C!9?A?G!5?_?O!11?@!61?C??C$#228!89?_$#229!83?{{$#233!252?G$#237!99?A!44?_!6?A!92?C$#238!21?_!16?O?_!15?O!21?_!16?@!6?A!54?A!32?O!15?A$#239!101?A!25?@!4?@!9?_!84?_$#241!41?_!24?O!36?@!28?C!8?_$#242!37?O!44?A!11?A?aG!31?A!4?@!107?G$#244!212?@??O!12?G@???C$#246!89?B}w_$#247!255?_$#248!100?@!29?@??C??G???A?A!9?A!37?_!16?O!42?O$#249!215?_!14?@$#250!255?!31?G$#251!214?G!10?A???O$#254!231?_!42?_-#1!90?O$#2!95?_$#7!255?@???!6@!19?_??A?_$#9!95?O$#10!89?@$#11!230?S_G??_!46?C!4?@$#12!21?CO!206?G???O$#17!82?A???B$#19!22?G!61?O!143?A$#21!21?@!36?O!150?_$#23!58?_!27?C$#25!22?CO!71?G!49?_!63?A!18?@$#28!148?O!81?G?O!50?C!17?G$#29!79?G!76?G!123?_$#30!39?_O?C?G???GGCG!4?GCA?HQ!93?C!12?@???A@??G?O??O?@?C??o!22?O$#31!57?@???C??A!114?C??A???C$#32!40?`azNu}]kSsWswo[~vI@ouh~~L!14?O!25?O!37?_??O!8?@@@?G??O!7?@??AFNVNnZ~n|m^Jz~N~!20?_?_$#33!38?_??P?o??_O_?_??G_??O!25?G!58?_?_!24?@!7?o?_???O_o!25?_$#42!255?!27?A???A$#50!255?!24?_$#52!233?_$#59!255?!48?I@?@??C$#60!235?O!15?@!47?_??OOQrAo??O$#62!230?A!29?AAA!37?_ogckK{??w_$#64!37?_!7?@???A!14?_!37?@?@!42?G?@!11?G_!27?_!72?A$#67!232?C$#68!255?!15?@$#69!38?OA!106?@!17?O!64?@!20?@!34?C$#71!215?_!38?A$#72!211?CEEKG[_!12?@?AC!15?@$#73!210?BA?@RE_G?_!28?@$#78!247?@$#79!30?C!34?_!4?O!29?@O!5?C!13?C???_!31?_!33?G?G_!6?_$#80!25?O!5?G??GAOW?G!10?@!15?AAD??GSD?C@!5?_!15?O???G!4?G?@A??A?D@!8?C@???@?@?G?C??A!24?CGG???C!20?@!5?G???D$#82!68?G!6?_!25?C!10?_??A???_!12?G!72?A$#83!23?A??@B?BA?NHAG?F?C!7?@@??@@!13?HL?EF?BA[JCV!10?J!6?@G???ABA??BE@MKCINDC?KVD??HFELICCLJCLAIEFHLE?AKFI@ACAE!12?CCCGC??KCGG!19?EGBIEEAE@MIFAJDA`$#86!30?@A?E?@@?G!10?@!16?S??O?A??BO?_!9?gc!8?__???O_??@AO!4?GgOA??@D__?A@Q`?OAA_@?_o?@OC?GC?C?C_?O?_O_O_?__???G??Cw???_!20?BsDWO@HMOO?@_gCOO$#87!96?C!32?C!9?@$#89!26?_??G??_!35?_???_!13?O?O!8?O!21?O?OOO!79?OO$#92!24?@JACXc_s?oCsC?E!13?A@!11?O_?O___!4?_?_!7?_@!7?AA??___c!4?O`?@s?_Q??_qEO??`_?_QA___Oc`?AoO?PR?@E!4?___?_O_!4?C!6?C?__OO!18?Os?O??_oo_?o_??oEG$#93!23?@CC[o??O$#94!255?!27?@$#95!255?!29?G?@$#96!233?A$#97!239?_$#102!218?C!9?O!6?C??O!5?@???A!5?C!6?C!18?G$#104!255?!7?C!16?O$#108!218?@?\G??A??O!5?@???A@GCEOc?OA!6?S!8?GC???KK???_@CBhS??CB$#109!217?@?FAv}~{{W__!5?@BFLMVzxnZ}m!4{k{[?!7woow{{wqq}}m^}z{Uj~NB???CA$#110!255?!16?@$#113!85?B!170?@@@!6?@@!18?OC$#114!20?@!206?@!55?B!4?_$#117!85?G!11?@!63?@!13?O!52?G!52?O!21?@???A_$#118!59?C!19?A_!17?A!4?@G!41?_O?G!10?@!4?@@!7?G!37?O!39?@$#119!226?@$#120!82?@C$#124!255?!52?G$#126!24?G!15?C!5?@!4?A!13?G!15?OO_!12?O!6?G!34?_!20?C??G?AA$#128!58?GB!19?@!71?C???A!6?@@@!6?A?___!37?_$#129!89?A!62?C!57?G!42?@!30?O$#130!94?A!58?C!82?_$#131!234?_$#133!21?A?_!201?@A!7?O!32?@!15?_?G$#135!89?C!141?C$#136!255?!13?@$#140!80?G!17?@!58?GG!5?_$#143!22?@!31?@!23?G?@G???O!14?G!5?O!39?G???A!10?_AA??A!5?_!35?_$#144!152?G!59?G!42?A$#145!231?@$#148!28?A!7?A!31?A!40?AW!6?G??G??G??G?O?OO???G!33?G!26?@???@!5?GG$#150!84?G!142?AC!55?@$#154!24?A??GCOG@O?`?G!30?o?HG@?w??OG!7?_?O!9?G???G?O??G_?o_@OO@Go?GG_?G?OO?G_?G?COOO?AGKG???G!6?OO!12?OO?oOO?G!18?_???_gS!4?GKC$#156!232?@!22?C!10?A!15?O??@$#157!84?_!146?G$#158!227?C!53?G$#161!50?A!54?C!37?O???@?O?A!5?O!50?A!55?A$#162!81?C!79?A$#163!218?GO!14?C??O!13?A$#170!22?A?O!14?O?C!11?C!51?G!35?_!10?@!10?_!26?@$#174!226?C$#177!40?G!24?C!12?C??A!13?C!43?_!7?_@???AI!6?A!10?C!37?G!74?A$#178!255??A$#179!254?@$#180!229?A$#183!255?!28?O$#184!216?@!19?G!8?@!4?A$#185!57?_!96?C!16?@$#186!58?C!23?C!6?G!13?A?_!44?G!5?A??@!7?@!4?@?O!34?C?G!99?_$#190!84?CC$#194!209?@!27?_!20?A$#195!78?A??@!22?_!35?_!10?G!7?A!5?_!42?@$#196!90?_$#197!93?@C$#198!229?C??_$#199!255?!27?G!26?A$#201!48?A!29?@?C!8?_!7?AC!4?C!47?@!5?C!5?O!4?A!21?M!39?_$#205!234?G$#207!211?@???PAOo!12?A!4?O?_!14?A$#213!38?@!14?A!24?O!8?E!9?CG@!42?O??@!10?O!9?_!6?O!50?@!56?C$#215!218?A???@???_!7?A!12?A??O?_g!7?G!9?O$#216!79?CO!23?S!49?A??A!15?C!35?OC!20?O!48?O!17?_$#217!59?G!98?@?OO!8?A?C???_!33?O???_!14?O$#218!255?!27?_$#219!212?@G???C!17?G!16?A$#221!34?O?_!34?SG?_?I!4?_?O!12?@??OS!14?_!4?AA!23?GA??A!10?_!34?@!9?O@?C!56?A$#222!249?A$#229!83?BB$#231!255?!26?_$#234!233?G!68?C!4?C??G$#237!23?G_!15?AG??@!20?@!79?O!4?C???@???A$#238!39?@!12?C?A!44?K!56?C$#239!25?_!39?A!28?@!11?_!37?O!5?@???G???O!14?G!16?O$#240!255?!4?A$#241!86?G!12?A$#242!23?C!56?A?G!66?C!8?C!8?A!45?O!43?A$#244!229?_!53?G$#246!90?N~~}w$#247!89?O!179?@$#248!47?A!16?O!14?_!16?_!7?A!43?G!4?@?G???OG!8?A!130?O$#249!220?_!25?@$#250!28?_!196?A$#251!217?A!9?G!28?!5C$#254!219?G!46?C-#2!90?@!6?O$#6!90?O$#7!255?!28?@$#10!51?O!45?G$#11!237?@???C?G??O?_!24?_?O!6?@!4?OA$#12!27?_!206?A!43?G!7?C$#13!28?O$#17!236?G$#21!50?o?G!84?_???C??@!88?A!8?C$#22!236?@!46?_O???G$#23!80?@!24?@!34?G!66?G$#25!255?!56?A$#26!82?O?@$#28!51?_!29?_!61?@!4?G!59?C@?_!4?AG!61?G$#29!136?_???C!93?C!51?_!9?@$#30!41?AAA??A!7?o_K?O@?C!18?O!52?O??A?DA???C??G?O!22?O?B??G_Ag???Q???K_???_!14?_?GA?BGC$#32!38?@ABD@GRYtzNMNBbrBX_kIk\HD!44?G_!23?o?G{KEI?B@!9?_!17?OgKS???OX[RVW~d^a^PAJ!18?_ETP[vG$#33!25?A!11?BEDKG{tKdGCO@?CC???OQdQAAI@!16?_!25?@CO!24?GSAOW?D?A@!26?_O_IC??_E`Cgf?G_\_a\s??O!17?GM_?A$#42!105?A!129?A!14?_!30?C$#43!221?_$#52!219?G???O!12?ACCGWOoo!63?@@?G$#54!217?O$#56!255?!25?O$#57!83?P$#59!255?!21?__ooGwoW!5?c!4?A?O$#60!255?!27?G?G???_WkWwwkE?nWOE?R_QDW_?AA$#62!255?!35?OcCCOwmOfnx~k^lyf]}\D$#64!26?@!6?C!47?C!54?@!7?A!71?_!26?C!31?CA$#65!170?A!48?_!59?@$#68!173?O?A!39?C$#69!64?@!83?_!18?O!23?G?O!26?CG?G$#71!222?_$#72!218?A$#73!218?@E?O?_$#79!64?G???_!6?G!36?G!4?G?C???O!72?C???G$#82!201?@$#83!62?_?o_gT??yUaAoeqKQ???A?GO?GS!9?EWUG_GwO??A?g?CA?COC?WW\@J_ieOC@p@A@!8?_?o?a@A@??J@dqHgRhStwWg_GCE@@!22?GXcA\OEDsYFAOD$#86!63?oEFCiCC@_D_FPGo@???@???lUA!11?`AI@C!4?E?SRGIiCp_A_?s_LSGD`YAA??@!4?_??G??_??D?D@CMAL_?KEHA@_S]cG!23?A@CcZP?gO???gciG$#89!124?O$#92!30?@AD@!31?G@?@@C?G@??D@!7?n!11?@?_?@@!5?@?Fb?@?@H?B??A?C?@@g?CC?@A!15?C?C!5?C??a??A!27?@!4?_??`??d??C?@$#93!27?@@@E@AA$#95!255?!21?C$#97!255?!23?A$#104!231?A!17?O$#105!228?@O$#108!224?C!8?W!14?@?C?Dg?PGG???_G???_?C?IO$#109!223?BBN^^}n}sw_o_!6?@BBFFNMNZ^YV~mvv~|~^v}~^^~r]SJNBB@@???@$#112!173?_[!40?w[?o$#113!235?C???A!41?A!6?@$#114!23?@CGO!211?O!48?A$#116!82?_C!149?@!46?C$#118!24?@!4?O?_!20?O??A!24?A!25?C!35?A!27?CA@??OA!30?OAO!4?@$#120!220?_$#122!174?_$#123!255?!21?G?C$#124!222?G??_!18?__$#126!35?@!27?G!15?O???_!5?O!17?@C!26?@!16?O_!13?B!22?O!82?O$#127!238?A?C!6?_!26?_$#128!29?__!23?C!52?_!30?O!29?OG!38?O?_!4?@$#129!26?G!69?@$#130!25?C??_!20?_???G!89?A$#131!239?O!40?A!6?G$#132!244?O??O!29?O$#133!232?@!11?G!4?_!22?_!4?G!7?O$#134!255?!32?C$#135!98?_!139?@?A$#140!26?CCGGOOO_cKMKgwoo??_!88?_!11?G!4?_!23?@!39?O!26?_$#143!79?G!25?C!35?G?G!46?G!57?O??_$#144!89?G!19?O$#148!65?O!6?O!11?O??__!13?O!7?OG_O!4?O_@?A!5?G_!12?O!6?A?G!4?AP!38?G!6?OG@$#149!239?_!44?_$#150!237?G??_!4?O!30?O!10?_C$#154!34?@!31?Q?Yy?H?[G??Ak???C?_?Q@@!9?@DGsCuAg???H???ctOaAK?E_G?A?OAQ?GC!8?_o?_???A???A?OW?SA?O?GECA?Q?@A!23?BA??_FGoI??P?A!78?_$#156!244?C$#157!255?!30?G$#158!255?!31?G$#161!79?C!9?C!100?CO$#162!62?O!18?AG!64?C$#163!233?C!6?@$#170!30?G!5?@!44?G!52?_!12?O!44?G!21?_$#174!255?!14?_!9?A$#177!29?C!4?A!62?A!36?A!11?O!18?@??G??@!18?A_C!13?O!63?_???C$#178!216?@$#179!24?A!254?C$#180!27?O$#182!234?@@$#184!221?@ACGO!10?_!5?A$#185!56?@@$#186!56?A!23?C!16?C!8?GO!31?G!7?G!19?_!8?@!32?_!27?O$#188!84?A!90?D!39?A?_!63?@$#192!217?C!20?G$#194!221?C$#195!60?_!28?@!59?g$#197!90?E!5?A$#198!83?I!152?C!5?G$#199!255?!37?A$#201!27?A!80?G_!23?C!11?@!26?_G!19?_!13?C!37?G!31?A$#203!255?!25?_$#205!220?A?S!9?A???O$#207!217?@C@HA!15?_$#213!28?A!32?_!17?_?@??C!4?_!8?G!5?@?_!24?GC!12?O!4?G!13?@!25?_C!15?A!78?O$#215!222?@!4?_???G!27?A???@?_??G@@C??G$#216!27?G!4?_!15?_O?G??GC!86?C?CC!4?O!24?_C!29?_?@!9?GO!51?_??O!8?CCC!23?_?@$#217!53?C!26?G!25?A!42?O!18?_!39?G!73?C$#221!88?G!10?A!19?@!20?O??O?A@_??A!7?_!4?@!28?A!4?A??A$#222!246?G!28?I?@$#227!90?G$#228!90?_$#231!252?_!24?C$#233!220?O$#234!255?!38?A$#237!25?@A!6?WWqooO!42?O!57?O!35?G!102?@$#238!28?C???G$#239!79?@!18?O!7?OA!23?o!12?G!6?O!14?@!7?A$#240!224?_!13?_$#242!31?G!31?C!15?A!9?A!48?_!30?C!20?@!26?A!6?O!6?@???G???@?A$#244!230?@!10?@!31?G$#246!91?!5~{_$#247!246?_!28?_!12?O$#248!61?O?A!68?G!4?@!8?C!5?_!84?A?C?G$#249!226?_!7?GO$#250!29?A?C!241?C$#254!232?C!39?O-#1!96?G?AO$#6!99?G$#7!28?@???G!224?A!28?@$#9!90?@!5?O$#10!90?C!5?_$#11!29?@!4?G_!45?G!136?_!11?_!20?@@!26?G???OG$#12!35?W!45?C!139?@!4?G?O!14?A!5?O!5?A!8?A!20?C$#13!90?_$#17!39?C!189?O$#19!81?A!136?OG!4?C!40?A$#21!33?C!47?O!18?O!112?A$#22!82?@!139?A!19?@!33?O$#23!36?O!44?@!28?_!25?@!68?C!6?@$#25!240?@!18?O!46?C$#26!219?A!59?C!4?O??@$#28!107?@G??_!29?C!83?G!27?_$#29!131?G???A!27?_!8?_!37?@$#30!31?@???@?O??_!14?AA!51?@E?O!29?G!24?COdB???OWXX!4?@?Q???_C???G!10?O???gQW?A?@$#32!32?A?A??___?o__O?D???@B@KFD?@!52?G!21?C!32?OgEIKB@??Ccej}~fwul|h{IZ@?_tNCOO?O!7?[VDeoCwC$#33!33?A?ABA?AW??PJ@__AIUcArw?@?@!50?@C!54?_OgO!4?__A?S@?WEH?AUBT_A?OAOwG_o?o___!5?g@MwC$#35!52?C!173?C!18?G$#42!220?C!28?@!18?A???@_$#43!80?@!148?C???_!22?C!54?_$#50!129?O!181?C$#52!221?g[wWoo_G?O!12?@@@A?CG!19?A!42?A$#54!214?A???G$#56!250?A!14?G!7?A!7?@!4?C!17?G!4?_$#59!255?!9?G???SGCoaO@?GFDB!4?_ogK??Q@A?_A_Q?C@$#60!255?!31?Oq~|lw|^ZlJ@yHOGBMC@?@??_W$#62!255?!34?A?E?_COSkDqmV[@BEB???O$#64!55?O!51?A!83?@??@$#65!255?!10?@$#68!172?@!42?A!39?@!8?@$#69!110?@C!16?O???Q!7?G???O_!58?C!20?A???G!9?@$#73!224?@!16?CGWO$#74!171?C!42?GO$#76!239?A!4?_$#77!255?!29?@$#79!63?A!9?A!11?G!19?@@!7?@!9?@!18?C!12?O!5?A!41?@$#82!66?@!39?O!44?G$#83!57?OOAbBD?Q?SOOZSK}_cHG``K???`kAj]SO!11?GHSaiGo???@EXS?GAlGGE_PUq@PID@?_?GKKwG_?`@ABQD|u_{?[wg??EeSG_tHA!25?G!5?@EACKHC$#86!58?CGWCQ?KEIgE?h??G?CsIKP???O??O!13?FECH[?AG???A@E_?eh?QRo@MGG_E?A???o?o_COO@??@K?_A?IAC??O?@@?HCQ?C@!32?@C@?AH$#92!56?W_!5?`@???@!9?O!4?C@@??@!12?@!4?C!9?O!8?@!12?_!13?_??_!4?O!35?A$#93!67?A!58?G!130?@$#95!230?C!27?@@??@$#102!239?c$#104!255?!29?A$#105!233?G$#107!230?@?@!48?G$#108!233?@@?@K???O!40?G$#109!229?@AFME]^}qwWO?_!35?__oO?C$#112!170?oWE@!41?`{^F$#113!30?A??G!186?@??A!27?_!4?A?!4A!7?@!5?_?O!4?_$#114!31?C!209?@!20?AA!16?C$#116!252?_!25?G$#117!31?A!11?G!95?A!138?O??C$#118!38?G!4?C?A?@!60?A!25?A!29?O?A!36?_?_@!17?A$#120!90?A$#121!80?G$#122!172?G!40?_??A??@$#123!82?A$#124!245?A@FBeKMKO?GWOo_?CC???O!4?E?@$#126!82?C!16?@!13?_!29?G!19?O!26?_!7?G!41?_!15?@!6?@!21?@$#127!45?O!204?@!20?@!10?@???A$#128!41?C!6?@!60?G!21?OGC!70?O?_!4?@???C$#129!32?C!4?C!6?CC!176?@!19?A!7?_!31?A$#130!34?CCC?C?C!5?A!52?C!8?C$#131!219?O!9?_!37?@$#132!227?O!16?A?C?G!34?_$#133!36?G!194?_!36?@$#134!90?O!6?o$#135!255?!55?G$#136!45?G$#140!37?@B@ABOA??O[{sgWw!75?_!41?C!22?_?_??_!14?G$#143!58?A!73?@!6?@!137?_$#144!82?G$#145!240?C$#148!56?_??_?G?O?G??_??_?O?_A??A!9?_!15?C??_!6?[??A??GM_!16?O!4?CW??S?o!4?__O???G??@!24?C!7?@AB?AD$#149!244?C???O!34?@$#150!80?_!138?C!25?C?G!22?@!10?A$#154!57?GgSCogK_p_DGcAR@DZQ@SA!4?IQs?`iG!11?Oaa@O!8?Ib@SOdc@O?_CUGD?EA??O?O?CG_AA??HA?H@???CCX?OHabC?A!26?O!4?@!5?C?AA$#157!220?A!33?A!11?A!7?_$#158!255?!21?_!8?A$#161!55?_!44?G!38?C!15?C!45?O$#162!154?@!10?A$#169!171?_!42?sG$#170!99?A!9?O!33?_!20?G?@!24?C???C!6?O!10?O!40?@!20?O$#174!241?_$#177!59?@!22?o!29?O!14?_!5?G!19?A??C!12?_!27?G!5?G!27?G!50?O$#178!225?@$#179!225?C!20?G$#180!90?G!136?G$#182!219?_wU_?_???_!14?C!13?G$#183!255?!5?@@$#184!237?@!4?O$#185!110?O!18?_!13?O$#186!30?@!8?G??K?_??A!33?_!48?_!9?C?G!22?C?@!4?OCB!29?GG!54?C!5?_$#188!217?_!65?G$#192!227?A!73?_$#194!223?@!4?E!12?A$#195!170?G??A!107?_$#197!100?_$#198!45?_!34?O!169?O??B!13?A$#200!255?!10?C?w?cy?OKGAA???@$#201!56?C!23?C!30?G!18?G???D!5?A!30?A!33?A$#203!252?OK{s__!5?KCOKCgO?GK?ULD?A$#205!226?AD!16?G?O?_$#207!238?@?A?C??o__$#213!57?C!21?_!9?B!17?C?_!19?G?`?@???A???Oc!7?@!39?@!4?AC!8?@$#215!228?@!9?C?G$#216!32?@@???G!11?@!80?O!4?@?@!6?_!20?G!7?G!30?_O!6?A!51?O!47?D$#217!34?@?_?OO?G!96?@!25?_!41?A!55?G!40?O???A@$#221!86?C??C!12?O???_?O???G!21?_?A!14?AA???IG???H??C!25?A!8?G$#222!255?!27?C$#227!97?G$#228!98?`$#231!235?_$#233!226?@???G?_$#234!255?!5?_$#237!40?@?B???G!65?_!40?@!15?O!19?K!4?A!21?@!6?C!23?O$#238!57?A!84?O!9?@!36?o?G!4?G!35?O$#239!101?_!8?A!27?A!52?A!22?@!19?_!45?G$#240!231?O$#241!151?@$#242!131?C!23?A!44?O$#244!229?A$#246!91?!5~FF[_$#247!252?A!13?@!17?CG$#248!55?G!24?A!52?A!20?A!96?O!25?G??A$#249!241?G$#250!233?O!45?O???A$#251!238?A!4?_-#1!92?_!68?___$#2!101?A!62?_$#4!94?A$#6!103?O$#7!255?!12?AA???_!4?G$#9!84?G!9?C@???G??C$#10!94?G!176?_??O$#11!216?O!18?A?C!16?@?A!16?@??G?C??@$#12!217?C!14?@!25?A!13?@$#16!94?___?_$#17!90?~!145?A!23?C$#19!234?A!44?A$#20!216?G!45?C$#21!110?_!53?O!37?A!36?C!49?G!4?C$#22!241?O!29?@$#23!113?C!8?_!40?@!35?_!34?@$#25!103?G!56?_$#26!255?!7?A$#28!45?I!35?I!86?_!41?G?A!20?A!4?G$#29!45?C!35?C?O!42?A!18?@!16?A!5?O!33?@!4?A???C$#30!36?@Q?ECHW???O_??O?__!58?@?C!7?A!41?CAA??O?A??C@!6?@!18?_?Q@C!4?A?@$#31!255?!15?_$#32!35?w{cnxzUDz??jY{mco[O!59?A?G?_??oWK?EA?@!35?CGH@???GKNDBKFCCFE@?B@B@@@!13?okiQooggoB$#33!36?AHO??_aC??CCBPJNBEM!61?O??_?CON??G!37?BCC@??OOOY?AGJJ?@EECA?AA???@!5?_oO?BG?ShMKSP@$#35!53?G!120?G$#42!218?A!37?@!13?@$#43!183?G!4?C!6?OAG!81?G!6?G!12?@!9?G$#50!146?A$#52!218?_?DZ|zv!6~}}{{wgwoo_!16?C???@!7?@!10?GI??G!11?A!9?C?@$#56!255?!28?G$#59!255?!25?CCEEEFFAB???C?A!10?G??O?A$#60!255?!6?G!21?@@??DCFFBBB@A@!6?_o??C?C@$#62!255?!12?O!23?C???@?@@!6?owwMB$#64!80?_?@!32?C!12?A!18?G!42?C!61?_!15?O$#65!242?G!25?C???A$#67!255?!5?G$#68!78?_!44?_!43?C??@!41?O??O!30?C!18?G???_O$#69!55?@!58?_!133?O$#71!251?O$#72!250?CC?G?_???OO__??_$#73!246?!4@B?OSG?W_w??O??_$#77!244?C$#78!253?_$#79!76?C!35?O???C!16?G??O!8?G$#83!57?D??A?G?@??a!4?@A?B?B??C??F@@???S!14?A???@!6?@AABF!10?BD??b??AQ?A?BA!4?@A@Y?@A?DH??@$#86!66?@@??AA?C?CA?A!7?@@C!14?ACO_???CS?_???C!11?ACAJ@?h_`?ss???O?G@C?c@C]@jOC?@?A$#87!55?__?__?___WG???OGOW?G?_G!27?GO_???G_!5?G!5?__??GWwwo_OCCWK?GW[{__Oo?gW?W?SOGok[G$#89!60?_??O_!10?O!13?G!16?G!10?G!24?_?G???_O??_!5?O_$#92!56?FW\@SQRFEcK?WGC?eP@!4?_!23?@H!4?@!25?O??@@!18?@$#93!59?C?KC??O_?c_???___!13?@$#97!242?A!31?G$#104!243?G@$#108!243?C$#109!238?@BAAC?GGOO__!18?GG!4KEEBB@$#110!255?!18?A$#112!166?oWMB!42?_{~NB$#113!34?E!205?G???_!24?A$#114!242?O!14?A!15?_?O$#116!79?A!179?A!20?A$#117!44?_!40?A!42?_!126?A!12?@$#118!35?A!71?AK!15?G!75?_!8?E?_!25?A$#120!84?OC?w!5?_!4?@O!61?O$#121!79?@$#122!169?C!43?A??C$#123!244?O$#124!236?O!4?_!15?@@!23?G$#126!103?C!4?_C???O!13?G!18?@?O!11?OC!76?A!7?G???_!24?@$#127!44?O!32?_!177?@!9?C$#128!109?O?@A?O_!7?O?GCA@!33?C??_!35?C?@???@A?CG$#129!35?@!51?C!16?_!136?G!19?C$#130!200?OG!57?C??@!48?@$#131!255?!8?A??C!4?A??@$#132!80?@!134?_?@!13?@!29?A!15?C?C??@$#133!34?o!208?O$#134!86?A!7?O]^~[??@!60?G$#135!84?C$#136!44?@_$#137!79?C$#140!47?@!5?@@!51?A!62?__???OO???G!4?C???A???@@@?_??GC$#143!79?GA!27?A?@!9?C!127?G!23?O!5?A$#144!127?C!34?@$#145!248?C$#148!57?_?G!9?A?G!5?C!37?A!4?A!11?CACAGC_??c???O_!6?_???A?AE$#149!217?A!27?_!7?@$#154!55?GWAAQH@?G?@Q[BDPd?GQGP?@O!8?Ba!15?C???A!6?@@C?@!7?CC???SG?B??I@B??C???ADAcB?_Ca?A??@$#156!245?O!33?@$#157!44?K!33?G!137?_?@!20?G!23?CC$#158!44?A$#161!80?O!7?G!17?C!4?A!78?@$#162!82?_!45?O!107?@???C$#163!245?@$#169!212?G!62?G$#170!54?O!53?O???C!5?_!5?@!56?___?__ooAO!54?C???O!57?A$#174!255?!13?_$#177!104?O??@!9?O!72?A$#179!34?G!198?@!36?A$#180!98?A$#182!217?o[~ycACG!15?O?_!42?G$#183!255?!21?C$#184!246?A$#185!169?G?@!30?C!55?C$#186!45?O!35?_?_!23?C!6?G!12?O!83?OC!39?@!35?G$#187!78?C$#188!77?O!88?G!74?@!27?O$#190!238?C$#192!235?C$#195!82?QG!22?@!4?_??A!52?_$#196!102?G$#198!78?O!138?G!18?C!23?A$#199!255?!23?G!18?A!12?C$#201!82?K!5?O!24?@!5?O!4?O@@!17?@A!19?O??@!15?_!4?[G!52?A???G!16?G$#203!255?!4?@@$#205!253?A??C!7?O$#206!255?!16?O$#207!247?AAEGIM?s[_W?g_?Oo$#213!55?A!24?G???A!17?@??B?O??G!8?G!5?O_!16?@???AG$#215!237?@??@C$#216!45?@!35?P!27?G???G?O!5?_???C!35?G?G!6?E!35?@?@!4?@!21?@!37?O!6?@!22?O$#217!35?C!80?_!46?A!36?GO!85?G$#218!247?_$#221!55?S!18?C?G!28?_!4?A?G?@???O??@!22?AC!8?G!114?C$#222!243?@!23?_$#227!93?O!69?O$#228!99?C$#229!84?_w{!12?_$#231!245?A$#233!255?!7?G$#234!255?!38?C$#237!109?_!16?O!44?!4_?!4OGGG?GKCC???AAaqb\VNFB$#238!102?A!17?G!46?A!7?__???OO!4?GG???CcSKK$#239!107?G!38?C!95?@!8?_$#240!254?A!11?O$#241!129?_$#242!54?_!32?A!28?G!4?A!25?C!96?A!5?O@!13?O$#244!255?!12?G$#246!91?~^N@!4?B~{o_!58?O$#247!246?_!20?C$#248!88?_!21?O!11?@!4?_?@!47?!4_?!5O?G`_wWG!69?G!38?_$#249!249?G!16?_$#250!65?A!4?_!195?G$#251!247?C-#1!104?A$#2!104?@$#4!91?@@!8?AAA!57?@@$#5!101?!5C!58?@$#7!34?C!211?@??A??C??G??OO??_?A!4?_$#8!255?!5?C$#9!35?G!56?C!7?AGoOOQO!52?CC???A!95?A!7?@$#10!84?A?A!5?G!14?O!54?C!27?G$#11!34?@!180?@!34?A!11?G!4?O$#12!213?O!57?_$#14!159?G$#15!101?O!74?_$#16!92?O!7?C!71?_!12?___$#17!92?_A!5BA?_!58?G???C!16?___oOOO!68?A$#19!45?CG_$#21!99?__!5?C!11?CA!38?__ooO?Gg___???OO!4?OO??GKC??C!5?O??C??@!40?_$#23!120?@!8?@!34?o??GC?O!6?C??G!27?_$#25!163?_!13?G!103?G!24?A$#26!74?_$#28!35?_!12?_!31?_!29?@!88?A!15?C!47?C$#29!79?_???@!27?A!9?_!11?G!63?A$#30!35?@`???AGD???_AC@??@!64?@?@!70?C??_!4?@?@g?_UAWI$#32!36?ENZm_VypioBKREAB!140?CCEoaxooOS|\gxfCFb$#33!38?CP\_?MS??@G?@!61?A!5?@C!12?C!39?A!9?A!8?CGA_BP?GKmBAA@C?P$#42!213?GA?@!41?G!13?@$#43!255?@!47?G$#50!189?@$#52!217?ADy^|t|}~~^!8~n~}|MB!32?A$#54!210?G$#56!255?!10?CCC?GCECCsW??OO!13?G??C$#59!255?!15?A?GA!7?Oo??_OO!4?OO__O!7?C$#60!255?!22?g?Go_?ooO__!4o__OWgGK{[SKCA@$#62!255?!9?@!29?G??soAAJBB@A@$#64!120?C!89?O$#65!49?O!37?G!29?C!71?G!70?G$#67!255????@??@$#68!49?_!31?G!106?O$#69!86?O!47?G$#74!210?_?O$#79!52?C!9?_!82?A$#80!56?C!13?G$#82!51?g???O!6?G?_!6?G!4?O!47?C?CA!25?@$#83!53?W??_C!7?_??G!6?A!7?O!23?@!7?A!17?A!20?`$#86!52?O?GA???q@???A@U??O!44?A!6?A!6?A!4?@?A@??@@?A???AAA@@!4?@@$#87!50?oO_c?HIrtDs}TtXQ_}qcOAw??__?O??_??__!21?EBA???@@!6?CA@BA@?CC??@?F@E@?EAB@@ID??DE?BB???G@@$#89!70?D???C!31?@??C!12?C??@!12?@!7?@$#92!59?G!5?GG@?GADEDA??KN???W???_?_!19?CG!5?KG!5?GWGK?WG?G?O??GGII??C[CCGCGG?GCC??ECA$#93!73?A@@???@??e!4?_!20?GOSW!4O??O_!4?Ooo?O?o_!5?OOOW??IO?G??G?G?KK$#94!110?__!4?__!22?!7_o_?o?O$#95!139?_!9?_?__o!102?C$#104!189?O$#109!189?_!61?@$#112!211?{NF@$#113!34?q!212?@!8?G???O??g_AO??@_$#116!75?GA!137?GA!56?_$#117!157?G!7?OOOWO!6K[?GG!12?_!58?A!39?G???C$#118!36?G!43?W!49?A!38?K!21?G!6?A!10?C@$#119!255?!6?C$#120!90?A!12?___!53?A!5?A$#121!75?C!112?_$#124!236?O?@A@!26?GK??G?O?_S$#126!50?G???@!22?A!36?K!6?G!11?C$#127!46?O!27?O!138?_!53?A$#128!35?Q?_!49?C!23?@!4?@A!70?C!20?GA$#129!36?O!47?CG!7?!7C!57?OC??G???C!4?__!7?__?OO?GGG??O???GG!61?G???O???O?@$#130!86?G??_???!6wWW!7?_!47?__OO??GG??DE?_!4?O??__?OO??GCC!5?O!4?C!10?O!73?G!7?G$#131!47?O!142?_$#132!46?C!165?_!45?C??G!6?AO$#133!255?!11?_$#134!85?C?A??@!8?@!91?O$#135!162?_O!11?O?O???KC!59?@!21?O!37?O??C$#137!77?@$#140!81?A??G!27?C!78?AA?@$#143!53?A!20?G!4?C???C!27?CGA?@!19?O_!21?A!98?C$#144!106?A??@!20?C!128?@@$#148!54?C?O???A@AA!4?@?_o@!4?_!5?_!39?A??A!7?_!12?@??A???A$#149!214?C!44?C$#150!45?A!218?G?A???@$#154!52?G???@GI?G??GCC@??B???G???O!11?@!20?G!5?CG!5?C??GC?G!7?CCGCG??@??C??C??A?OA$#156!253?A$#157!45?@!216?C!5?O$#158!248?@$#161!89?C!18?O!7?A$#162!88?C!21?A!22?O$#169!211?@$#170!80?@!7?@!31?_?_!46?A!4?@@@!9?@@!67?A!9?@???A$#174!252?@$#177!51?C!33?O!26?@!22?_$#178!255???@!4?@$#179!253?C!11?_$#180!35?C!49?AC!6?@!64?G!4?C!9?_!17?_!75?_$#182!214?_w}|yD_AIA@??_$#185!119?G!73?G$#186!37?O!43?@!36?A!48?@!8?AAA!10?C!6?G!10?_??C!43?@$#187!76?@$#188!75?O!135?A!40?A!6?G$#189!255????A???AA$#190!163?A!95?A!8?_$#192!240?O!39?G$#194!255??@!6?@$#195!113?G!4?G!130?@!5?C$#198!255?!10?G!5?@?_$#199!166?G!4?O!6?CCC!73?C!20?A!31?@$#200!255?!14?CG?OGG?GO__$#201!52?A!26?O!9?G!29?O!10?@?G!44?!9@$#203!255?!16?OA??C_?G$#213!76?G?_???@?O!4?A!19?_!12?O_!7?GA!24?C!30?G$#216!38?_!5?@G!34?C!8?O!30?O!10?C!23?_O!17?AA???AA!13?OC??C!9?G!32?C!20?OO??@!33?@$#217!173?A!7?A!27?O!67?C$#221!54?qc!12?C!4?O!5?A?O?G!38?@!4?@???@???C$#222!250?@???A$#225!91?A!8?@!62?@$#227!90?_CA!67?B$#228!90?[w!10?!5G!54?AA??@!91?A???A$#229!106?__!53?C!13?_$#230!84?!4@!78?A!7?_$#234!214?O!77?G!5?A?_$#237!50?C??@!26?A!40?@!46?B@!13?A!5?AA@@@$#238!113?C!6?G!49?@B!12?A???A?@!62?@$#239!81?C?A!4?A!39?@!30?@$#241!120?A$#242!79?G!49?A$#246!101?@@@$#247!73?_??C!189?G$#248!49?G!55?@?G!13?O!9?A??O!35?A?@@!11?AAA@!75?C!5?O$#250!87?OW!23?!4_OO_!5?_??__o?O__??O__??O?O?OO?OO?OG?OG-#1!102?G?!7O!38?!4_!18?CC???Aa$#2!89?CC!20?__!35?_!24?CG?O$#4!101?o?GGG!46?!6O!11?CC???AA!5?_$#5!90?@@!9?GC!5?GG!40?O!7?G!12?AA???@$#7!33?@$#9!102?@@?AAA??CG!37?O!6?CcC!9?G??@!5?@??G$#10!92?C!59?C!16?@!22?o$#12!208?_OG$#14!158?AA!7?@$#15!92?@??G!67?O$#16!93?{wowwooO!56?A_oooO_!5o_!10?EM^!5~w??~$#17!32?_!60?AEECCKKK!53?AAA???GI!4GLG!10?!4@!6?C$#21!41?C!27?_!92?!4A!41?_!59?A!26?C??A$#22!56?_!9?_!204?@$#23!70?O!219?G$#25!109?@!44?@!120?O??_!6?O$#26!52?G?O!212?@$#28!33?O??C?A!8?`!30?_G!46?O_!75?O!62?@!22?G$#29!37?@???A!35?C!47?G!76?G$#30!34?_??wS??_A_G@?OG!25?G???O!116?E??`?K?@?A?_O@$#31!110?A!14?O$#32!33?_[Gb?_K`@P?DMYMs!26?C??C!114?}npfuAYQAEbph[ME$#33!35?F??GoWW_FA?D??_!28?G!43?@!70?@OGWH[D@L_C?O$#42!213?@$#43!255?!41?A$#52!216?OCAGcv{n!10~}~~^D@!34?@?O??_!4?O???G$#56!255?!15?A!4?@!4?A!5?_!11?@$#57!54?_!10?_$#59!255?!22?@A??LgWA?KG!4?C$#60!255?!19?ACAOPXTaVflnBFFFEDBBBA@@$#62!255?!35?@A???@$#64!119?_$#65!49?C?C!138?A$#68!209?C$#69!50?A!25?A$#77!190?G$#79!61?A!8?@$#82!51?A???D???C?`?C???H!6?_??@???@??gEO$#83!52?_@??L?A!6?G!14?O_??A@_!28?__?_!12?_!5?_!4?_$#86!52?A!4?DOO@???HAI!5?_?A!5?GOha?_C?@!34?G!14?_??_!5?O$#87!50?P`DAKIAOLh_OPpSTP?DFA@???_p!4?CA@PG@A!34?_?O!7?_!6?_???_$#92!51?O!4?OG!4?_G!16?_???C!28?GG??g???OSO_!4?O!4?_o`O?O!4?OOO$#93!60?C!49?@?CCOGO??CGCG!5?GGOOW??G?HG?_WOWG?GG??C$#94!111?B@?ADBBFBF!4?@BEFED@CA@FACFCB@LEADECAC?A$#95!129?@AAB?E??A?BCAA@DA@BDBB@@!36?G$#97!190?_$#109!189?B$#112!210?B$#113!32?WA$#114!212?@$#116!53?O!16?GCA$#117!36?G!5?G??__!21?_!94?@@!42?@O$#118!35?_?E?A???G!29?G!5?C!119?_?O??CCA$#120!88?_@!14?@???AA!45?C!4?C!6?C?O_?@$#121!57?_!132?@$#123!69?G$#124!234?@???A!32?A!4?CC?AG$#126!50?G??G?O!8?_!8?A!46?O!7?O!15?_!8?@!35?O$#127!212?A!60?@$#128!33?G!10?O!43?O!111?_??G$#129!34?@!58?@@@!5A!46?_!15?CCC!26?A$#130!38?@?A!38?A!16?!5@!49?G??A?!6@DC??@!22?A???@!9?O$#131!188?@!80?@$#132!210?C!57?@$#134!92?A!7?_@!60?_!16?A!12?K$#135!162?@$#136!211?A$#140!120?_??EC!83?G$#143!58?_!8?O!4?CC!14?A!60?G!39?_C$#144!50?_$#148!53?C@!4?AA?A?A?CAA!6?B!6?C!4?C!29?O!5?_$#150!48?@!162?C$#154!54?A??A??WKKA???CG!4?_?O!5?IO[?OIX!27?O??O!6?A!4?_??_$#157!49?AC!4?_!11?_?O???@!198?@$#158!255?!10?@$#161!80?A!48?_$#162!49?@!21?A?O$#167!212?C$#170!71?G!7?_!31?C!14?G$#177!49?G!26?G!42?O?_!23?__!5?A$#180!33?C!58?_!67?A!5?A?@!13?_$#182!210?_ow}~~nz|vZGBO!44?A!4?G$#183!190?O$#185!78?A!126?A$#186!34?A?O??@!5?O!25?OG???C??@!44?G!76?_??G?@!32?A$#187!52?O!19?@$#188!70?C!140?@$#190!104?A$#192!211?G$#195!72?O!15?C!24?O_$#197!89?A?w!19?O!61?ACW_$#198!51?G!16?O!201?@$#199!255?!17?G!15?_$#200!255?!14?A?CC?KIHG???O$#201!49?O!24?CG!47?@AC$#203!255?!17?AE???AKC_$#213!74?@!5?C$#216!35?O!4?C?CO!4?A!77?_$#221!53?_!17?_??O!12?_!36?@_CG$#225!90?AE!14?GG!43?O!16?C$#227!103?CCC!4?G!44?GGG!12?A!4?@$#228!101?CAA??!4C??O_!37?!4G???OK!7?AAA???@@???AC$#229!101?A???@@@!45?CC!15?@$#230!92?W!15?@!72?O$#232!189?C$#234!209?_O!26?_G!31?C!16?_!5?C$#237!77?_!10?G!39?_$#238!44?_!34?O!42?A!86?@$#239!70?_!6?O??@!31?G!96?A$#242!77?G@$#246!89?ww!11?oo!7_!42?!4_!12?GWwwwocK[{wo$#247!148?O??C!57?G$#248!77?A!43?@!5?O$#250!112?ABDAKCGG?I!5?@??GK?\W?[?OGWC???G??G-#1!92?_O!18?CA!26?O!8?I!27?A@??O!5?G$#2!88?C??AO!20?OO??G!20?_!4?C???@@!29?CA???C$#4!101?@G!45?O$#5!152?C!30?A??C$#6!87?_!27?A!34?O!32?G$#7!30?C$#9!94?_!6?C!35?_!6?A!4?O?G_!19?AC!10?Qg?CO??_$#10!84?_??O!6?O!7?O!81?GA?OC?_?D$#11!31?A!163?_!5?_???AG?_$#12!196?_???O$#14!170?A!35?@$#16!93?@N~~~}~~o_!50?w{{}!12~v|}{o_!8?@@Pbbb??L$#17!197?O??G$#19!199?O$#21!78?C!8?G!50?O!6?@!43?O!9?G!96?A$#22!197?_$#23!62?C!80?A$#25!69?@!221?@$#28!49?@!13?C!13?_!40?G!7?O!5?G!6?G!58?G!8?G$#29!32?AS!17?A!70?C!14?O!57?O@!8?G$#30!31?_OAGoFA@?Ca?@!87?C??G?G!7?@!50?@GG?CC???@$#31!78?O$#32!31?Oc`oKw\}]JT?A!32?_R!52?A?CGOWOGG!54?HWGCCAAABB@$#33!32?G??A?_?`oGN!33?OK!51?@!63?Q@???C?@$#43!255?!27?@$#50!49?A!26?G!40?C?O_!10?A$#52!219?Oen!11~^MB@!50?A??@$#56!202?_$#59!255?!30?@??A?A??A$#60!203?C???_!76?@?@@@B?AA$#64!43?_!13?C???G$#65!56?O!7?C!4?O!9?A$#68!127?O!62?C$#69!48?A!27?@??C!46?G??GO!6?C???A$#72!202?W?O_$#73!204?GO$#77!190?A$#79!45?O!8?@!9?G??C!6?G!9?@!33?AG$#82!44?O!4?O_?O!7?_???_??G!4?@C?G???OA?@??GG$#83!44?_Ms???G_@O__???_O??_O!5?ACA?cA???_H@??I?A!30?B@?G?O_!4?GO!5?@?A?BA?@$#85!57?A$#86!44?G??QOGO?g?A???A???OW?_C???C@???D!5?GGA??C!29?@??D!12?@?@???@$#87!46?GGG??W?bOR!5?_!4?g???`WObR!4?GCECL?@!34?CO_??AEC?__??BA?A@??@@$#92!46?A?C_!6?A!4?O!8?GAGW!7?O!4?@!31?C?O???@@?G!7?A@$#93!128?_$#113!29?_G@!166?O$#114!205?C?O$#116!59?@@??@$#117!42?_!7?A!79?C??_$#118!57?_??CC!6?_!53?A!5?AC!63?_C?O@???CC$#120!104?_!66?@$#121!57?@$#124!234?@$#126!51?@?G??C!5?G!4?a!14?O!45?C!6?CC$#128!32?@!15?@!7?G??G!5?A?@!10?A!44?CGO!5?G??_?_!56?C?A??@$#129!31?C!25?G!74?O!7?G!51?G?_!9?A$#130!30?_!27?G!23?_!109?o???A!38?G$#131!209?_$#132!208?O$#134!93?A!4?@!4?_!38?C!6?_??W??A!13?G???GO_!10?O??_?AA$#135!255?!30?A!9?CC$#137!65?@$#140!58?C!62?A???G$#143!56?@??A!9?_!10?O!6?@!44?a!56?B$#144!75?_$#148!47?c_!13?_??G!4?O?c!12?S!35?_!6?O$#150!207?@$#154!45?_???C!15?OO!4?_!10?A?CA!52?A$#157!61?@@?@!141?A$#161!52?A$#162!58?O!22?_$#170!66?A!11?_!4?O!40?C$#174!190?@$#177!44?C@!9?C!24?_???O?_!40?_!6?C???C!4?@$#179!30?O$#180!101?G!46?_?_$#182!199?_!7?CM^!9~nXO!13?C!58?A$#185!43?C@!23?O!57?_$#186!31?G??A!7?O!10?C???O!6?A!13?H!42?@!5?@?A???O!7?C!61?AC@!28?O$#192!206?OA@$#194!201?G$#195!87?A!27?@!6?@$#197!88?B??@K_!18?BK_?C?O!22?G!6?ACG_!25?@AK[cC???G$#198!58?@$#199!255?!26?@$#200!255?!28?@$#201!43?O!10?C!13?AG!9?@!36?A???@??A?_!7?C!8?A$#207!203?w_?_$#213!46?@???C!14?C?O!7?O!9?_!34?ACGO_C@A???`!57?C$#216!34?D@!7?GA!7?C??G???C!6?@?HA!58?@?G!59?G???A??A?@!36?A!49?A!8?A$#217!33?G!26?G!26?C!107?C$#221!58?_O!26?O!32?A?G?@A$#225!103?O!15?_!35?@$#227!92?AG!7?A???_!40?@!29?_$#228!114?@!24?O!7?_???O??A!19?GO!6?@!7?OO$#229!83?_!8?@C$#230!153?C??@$#234!200?_O!4?C!26?_$#237!69?C!61?O!8?C!57?_$#238!47?@!20?C!54?G!11?_$#239!51?C??G!6?AAA!12?C!53?@!8?C$#242!60?A!15?A$#246!88?w~~{!10?FN^^!6~w`M{wo_!20?__oww{}}]K@FFBB@!17?@BFN^{wpbJyocC??G$#247!189?G$#248!50?@!5?_!67?O-#1!98?G!5?_!9?APG!5?C???O!7?A!4?A!4?@!36?@??C?_$#2!93?AAC???G?G???O???__!10?A!7?G!6?@?BC!43?AOO$#4!87?A!12?_!9?@A?GO!22?G!4?A!35?A!11?O_$#5!90?G!5?O!43?C!13?G!22?@!11?G$#6!102?G!10?_!39?E$#7!28?C$#8!194?@$#9!84?H?_???O!4?OA?_!4?G!5?@!23?A???O???C?A!8?A?C_!24?O_!11?@?A!4?O$#10!81?K!12?O??_!6?G??@??AS!11?C!15?O!4?_!8?@O!22?A!13?O`?A?C?G??_$#11!202?@A!9?GO$#12!196?A!5?_!9?C$#16!91?Ooo_`@@@BBB!4F!4MKG!29?GW[[]]!4~}wobF^!11~x!7~}swo_!7?@BFNM}{{woO__$#17!29?A!47?K???A__$#19!198?C??O$#21!77?A!7?C!41?G!83?C$#22!195?@$#23!85?AA$#25!77?@!47?G$#28!29?G!10?C!15?A@!156?G$#29!29?o!38?C$#30!30?a_AAO!4?W??QO!32?_$#31!56?O$#32!30?[Vc`mklhXBpW_?_!31?^$#33!31?GX[@RQUecA_Kg!12?@$#42!121?@!81?_$#43!85?O!127?C$#46!198?A$#52!218?_?Agvz~~~^vfB@$#64!43?@!11?C!12?O!6?A!9?_$#65!78?@$#67!205?C$#69!67?@!12?O!52?@!73?O_$#72!204?@?DCOCG_O$#73!206?AHCoo?__$#79!63?c!6?O???C$#82!47?U?OW?C!6?Q?C??A?_!4?C@G!4?GA!42?@!6?@$#83!45?Ag?EA?OaAC???_CC?OGCo@??OEQI?O!4?Gc!42?@?C?A??@$#86!45?C@G?G??OSW!4?@!10?_??aG!4?s!44?A?E?A???@$#87!45?XU`W@AjGgA??O^_oxcP@EM??e@GCSB???_!45?@B?@@AA@$#92!44?@???__C!9?@?G?OG!4?G?_!5?O!48?C$#113!28?w@$#114!199?G$#116!205?O_!4?A!4?_$#117!68?@$#118!29?C!51?@$#120!82?@?U?O???_?G!17?O!32?_$#126!54?_@!24?G!42?A$#127!204?G!5?@$#129!77?o???O!4?C!43?C???@!71?O_$#130!230?_$#131!202?A$#133!205?G!4?A$#134!86?G!4?_!4?_?A??C???G@!5?O!27?WOC???_!5?C!15?E!8?G!9?@A???O!4?G_O$#135!122?A$#140!43?C$#143!67?A!12?@$#144!78?A!49?C!77?G???C$#148!44?A???@C@C@@@!5?AABA_@O!4?`?@!5?@$#149!204?C$#154!57?_?G!9?G??O?_$#161!67?G_!62?A$#162!57?C!9?C$#167!196?!4@?C?W?_$#170!57?A!10?G!16?@$#176!212?A!4?_$#177!44?G_!9?A!11?o!7?@$#178!209?A$#179!209?@$#180!91?G!20?G!31?A_@!6?G?G!20?@!12?CG!24?_$#182!199?AFIK?o!6?@@BFN^^^~|VGC???_G$#185!56?K!11?A$#186!30?@!10?A!42?_G!46?A!79?G!17?C$#190!197?C$#192!202?O!10?O$#194!203?@!4?@!5?_$#196!103?_O???_!23?C$#197!93?@??CCC?G!5?OO???__?`mo___`!21_!10?@!29?BCG_$#198!200?G??C!11?O$#201!43?A!11?G!19?G!50?G$#205!211?G$#207!205?B?AIG?O$#213!44?C!24?@!8?C?A$#216!41?@@!43?@!110?A???@$#217!40?GC!13?_!175?A$#221!50?_!6?G??G???G!61?@$#225!87?@!7?A!16?C$#227!93?G@!13?O!15?G!6?C!4?O!51?C$#228!99?c!9?O!18?G!6?@??G???_??@!9?O!30?@A$#229!82?]^!16?C!7?@!42?@!27?G$#230!97?A!15?O!24?OG!16?_!21?C$#234!232?@$#237!55?O!19?_!123?C$#238!81?_$#239!56?_!18?C$#241!124?C$#242!204?A$#246!87?{~~FFFCKGGWOOOooO?___???@BFK?F^^^][WWOO?OOOWWW[[]MFC@BB@@!34?@FN]{xbN]{wo_$#247!129?C$#248!44?O!30?O-#1!81?_!46?G!4?@!52?G$#2!30?_!43?_!9?CC??_!18?@@@!4?A!29?@!6?O!6?G!28?A???_$#4!106?@!19?C!4?@@!57?A$#5!187?O!4?@$#6!126?_!20?@!6?G!38?A$#7!29?S!193?O!20?C???A!5?G?O$#8!243?A$#9!31?G!53?O?_?O!13?@@!4?A!5?C!9?_?C!5?O!12?_?@!37?O_!6?C$#10!83?_??A!20?A!37?AAAO?@G??AC!4?C??G!28?g??G$#11!204?A!8?_!8?O!30?G?O$#12!203?@?O!11?@!27?CAG$#13!111?O$#14!91?__!4?T??D?_!27?C!5?G?G!24?C?@!8?A!6?D!11?O$#15!84?___???w^^!4~I~~y}]}}}!5{k!6wooo___!5?C?EMMK[S[S[KKCCc!7?!4@A!5BFBN]!8~|!6~y[GG!6?GO_`fN~^FB$#16!198?_G$#17!30?C??O!104?_???G!10?E!28?_O$#19!249?OC$#21!35?_!109?CO!36?_??_!29?@???I!10?@$#22!206?G!5?_$#23!223?@!8?A$#25!78?G!125?_$#26!246?C!5?G$#28!31?C!185?A!16?G$#29!30?A!5?_!39?@!74?A$#30!31?BD?C??O_B??@PC!9?O!21?I$#31!33?C???G?O??O???O$#32!30?@?AAJR\DUCulegYEko$#33!33?H?KAaHgHQGE`w??_!5?G!20?EC$#42!218?@!30?C$#43!221?O!13?O$#46!228?_$#48!226?A$#52!221?@??@BDN^~~}{wo_$#64!46?A!37?@$#67!212?G??@???G$#68!142?_!58?C_$#69!47?C?_!21?_!137?@A$#72!211?B@CIsSG??o$#73!212?CHDIgcGo$#79!52?_!4?@AA?O!12?@!4?C$#82!65?G$#83!47?@?CGKV@??OOD@cG?_yVW??WZO\GG!7?A$#86!49?OAOG???k?WCG@JM??CgCa???FA!5?B$#89!57?G$#92!59?_?AOO??_?_?_F!9?A$#95!202?O$#97!253?O$#105!141?_???G???C!100?G$#107!201?O$#108!252?O$#109!143?O??G?C!52?_K!48?O?__$#110!140?_$#112!203?C$#113!28?@_G!187?A?CG??_!22?AO??C!5?_$#114!244?A!5?_$#116!205?_?@ACG$#117!224?A$#118!29?@!154?__$#120!73?_!12?O!21?A!13?O!26?@??G???!4C!4?O!26?O$#121!139?_?O???OC!101?G!5?O$#122!199?_GA?o[$#123!151?C$#126!53?O?O!12?@!9?C??@!65?G!99?C???G$#127!211?O$#128!32?G!44?G$#129!75?O?@!4?C!57?O!68?AC!12?_$#130!77?E!70?AG??A!31?OO!22?@$#131!143?_$#132!204?@?C$#133!211?GO$#134!79?G!6?@???C!6?_!8?A!5?C!8?O!8?A???AAA_!9?O??G@??CA!5?C!20?AC!9?@A?o$#135!199?OC@$#136!205?G$#140!75?@$#143!53?_!90?G!105?O$#144!211?C$#148!47?A??_@!5?_??O?_?@!14?@$#149!205?C$#150!245?A$#154!48?DJTa?E?_?E_WAcC@C_BOWDCGA?C???@A$#161!67?A$#162!56?@!146?A!44?C$#167!206?@A??O$#170!47?G!6?CC!26?@$#176!236?_$#177!54?@!25?C???A$#179!29?A$#180!89?_A!10?@!11?C!4?G!5?_???C??G??O??!8A_!10?@!62?C$#182!205?@a{{w__!7?@@$#183!142?O$#186!225?C!7?C$#188!150?A!49?O??G$#192!227?O$#194!214?_$#195!54?A!30?A!116?@$#196!78?O!7?CG?C!20?@!4?A???C???G!6?@!12?@!4?_!36?@?G@[o$#197!32?O!44?O??G!6?O!24?AA???CC??GG?OOO___!15?@@_??O!4?GGG?GGG?O_!21?BCG_$#198!205?A!13?A$#199!152?C$#201!54?_!19?O$#205!216?A$#206!200?_G$#207!210?@?AAO??Oo??_$#213!67?C!15?A!63?C??C$#216!34?O!20?@!16?_!8?C!61?G$#217!55?A!166?@$#221!46?@?I!4?G??A???@!7?A!4?O!4?A!6?@$#222!255?_$#225!111?A!76?O$#227!30?O!58?G!39?A??O??_!54?G??G$#228!34?_!41?O!5?_CO!20?@!4?A!5?C???G??O!5?G!19?O???G!8?G!19?@ACG??_A?C???O$#229!102?@!27?G!5?_!57?O$#230!90?@!23?C!4?G!45?_!24?C$#231!202?A!46?G??_$#234!206?O!19?G$#237!75?G$#238!45?@$#240!218?C$#241!55?G$#242!48?O!18?@!145?O!8?_$#246!31?o__!41?!4_ooWWWGGGF^B!21?!5@!4B!4FNNJZRPoo__`!8@!6?___!11o_!19?@BEC@E@@BECG$#247!148?GA!101?_!4?_$#248!83?@$#250!144?O-#1!145?_!44?O$#2!34?@??A?C?G!20?_???O!65?@!4?_?C!50?@@G$#4!74?C!14?A!53?C?G$#5!32?C!46?@!60?oG??GO!43?E$#6!71?@!5?A!117?O$#7!226?@!24?@???GO_?@$#9!28?G???G!32?G!5?O???C!4?@!9?C!37?@??A!10?AGP!21?A!21?@$#10!28?o!9?A?C!35?C!10?@CO??_!37?A!6?O!28?@o!26?CG$#11!200?_OG?@!9?@!4?O_!4?@!6?O!20?A!8?GO$#12!203?C!12?C$#13!61?_!9?_$#14!73?_!4?GC_?C!8?A!4?_`!4?G???C!5?@O!6?G?_A??C!54?O$#15!29?w{w!40?oOoww{sw]}z!4~}w_@D^~~~^]!4~v~~~z~|~~~}n!6~v~^|~~z}}]KK?__OO!5?@!24?B!13~n!12?BFF@$#16!187?@?_!6?GA$#17!130?O???O!6?O!40?o!5?C??O$#19!231?G$#21!48?_!86?G!5?@O!44?aG$#22!204?A!13?O$#23!41?C!145?O!10?@$#25!66?C!116?_??O!15?C!72?O$#28!184?OG!30?A!54?G$#29!42?C!141?GC$#30!38?@??@??A?C?@?O$#32!39?@B?BB?NGZCUkwo_$#33!41?A?CD?BCYG$#42!184?E!7?_???O!8?@$#43!255?!22?_$#52!215?@!14?@BfN^^~~}{Woo!31?O$#56!255?!12?G??O_?_?_$#59!255?!13?GW?OOO_$#64!52?GO$#65!131?O!6?@?@!119?C$#68!197?G$#69!218?C???_$#71!216?@A!6?A!6?_$#72!220?K?@cc??W_O$#73!218?ADB]WO?_[??_$#77!133?G$#79!51?B!4?O$#83!55?CMgOHIF?EE???@$#86!52?@?OA@C`UDWB@?@@$#92!54?CW!8?@??@$#95!201?@$#105!132?O!67?A!55?C$#108!254?@??CCO??_$#109!197?OGC@!54?BBAGKwo$#110!255????O$#112!200?C$#113!27?oE!198?A?CG!23?C!5?AC??_$#114!215?A$#116!217?G$#117!39?A!30?@!115?_!4?_!5?C!23?_!7?G!36?G$#118!187?K!51?A???O$#120!29?A!6?@!5?G!4?_!41?@!46?GC$#121!255?C$#122!197?_aoWCB@$#123!133?O$#124!240?_??_$#126!54?A!10?C!68?G$#128!37?@!5?G$#129!45?O!88?C!6?_!40?N!5?_!6?_!7?A!27?O$#130!129?_!5?C??A???_!45?O!37?A!11?@$#131!132?G!68?_!11?@$#132!132?_!100?O?_!20?G$#133!218?G$#134!29?C!44?G!4?A?@!8?A!17?A!23?C??_!4?A!26?C!21?O???@$#135!68?A!148?C!54?G$#140!201?G$#143!67?A!193?GO$#144!228?G$#148!57?A$#150!234?_$#154!52?E?G@_PM?O?K??AA$#158!252?@!5?@$#161!69?@$#162!53?C$#167!202?_??G$#169!196?_$#170!60?_$#174!199?A$#176!204?C!26?C$#177!53?@@!199?A!8?_$#179!228?C$#180!63?O!27?G!35?@!8?C!4?A?p!23?G!65?_$#182!203?owu!7~}{woo_?O!8?@A?G!8?G!28?G$#186!46?O!90?A!45?X?_@$#188!199?@?A$#192!216?G!27?_$#194!230?O$#195!51?C$#196!34?A@!7?O!20?O???C!21?G!44?A!10?O!43?KA$#197!33?}!12?_!19?_W!20?@CO_!38?@@?AA???WG?C?A?@!19?@_!23?AKAcG$#198!255???O_$#200!255?!21?_$#201!50?A$#203!255?!17?_$#205!223?@$#206!198?S$#207!217?@@A?@EIW[__O?_$#213!50?@??G!5?_!70?_!126?@$#216!49?_!133?E`PM!15?O!11?A!4?_$#217!44?G!140?A!84?_$#218!199?G!53?@$#221!55?_!7?G$#225!69?A!62?A!33?W!22?@??@$#227!29?@!42?G!56?@!10?C!25?C$#228!30?A!13?O!22?C??_!17?AG_O!44?_G!4?G?_!44?G??OA$#229!32?O!40?G!4?A!54?C??A!51?A?_$#230!31?C_!104?@?A$#231!131?_!125?GA_$#232!139?@$#233!240?C$#234!203?G!11?C!8?@!43?O$#239!54?_!7?O$#242!53?A!165?G!5?A$#246!30?@BB@{}}{{wwoo___!17?__oG_w{]MFFBBB@@!54?!4@?coG?C?EEn!18~}!26?CWo$#247!64?G!194?A$#248!49?@!177?C-#1!145?@$#2!33?@!9?O!8?A!4?A??@!33?o$#4!44?C!4?C!13?@!4?A$#5!56?C??A!9?@!74?@$#6!166?A$#7!27?C!230?@A?O!4?AG$#9!32?w!22?A!4?A!4?@!25?AGA!36?_!11?@@$#10!45?C!4?@?GGA!12?O!22?@!42?A!32?_!26?A$#11!196?O!26?A??G?O?_!11?G?O$#12!197?GA@$#13!90?_!32?G$#14!49?__!7?G!13?_@???@!8?@OA!4?@!10?C??o!7?G!11?@_!41?O??O!5?o$#15!28?w~~~!13?!4wWO!5owwow!4{M???w{}~^}~~~}!8~}n|~]w_?BNN^!6~z~~N!7~v!7~v^FB_OwKEB@!33?}~~n~~n!5~N~~u!5{K??_$#16!125?G!56?@!5?AA??C$#17!183?A???A@@???O!47?G$#19!221?@??C!23?_$#21!128?@!54?@??@!5?A!34?G!50?_!5?G$#22!196?_?C!44?G$#23!185?@!68?_$#25!58?@!125?@!7?@?C!29?A!48?A!7?A!4?_$#28!196?G??A!37?@!14?O$#29!53?@!143?B$#30!238?C$#32!54?@$#33!193?_G$#35!234?@$#43!223?C!21?_!30?G$#46!199?G$#50!55?@$#52!218?@CQw{Gwo!12?@@@BCFB@GC!27?C$#54!195?@$#57!189?G$#59!255?!19?A@DKQ}}{wwo$#60!255?!30?_$#64!57?@$#65!188?_??@!74?G$#69!225?A!6?_??A?C!25?_$#71!241?O$#72!226?@AC??TAgSO_?OOO?__$#73!226?ADBBL?\Ei?Ow_??_$#77!127?C$#95!128?A@!61?C$#97!129?A$#101!189?O$#104!255?!5?@$#105!127?G$#109!126?O!62?_G!70?BF^{w_$#110!128?C!61?O$#113!27?B!201?_!17?_!12?C!4?@??_$#114!255?!7?_$#117!249?C!35?O$#118!52?@$#120!32?E!11?O?C!11?C@!5?A!100?C!25?_$#121!125?O!64?_G$#122!194?o[F$#124!240?A?B?CMEG[WOO__$#129!126?C!57?A?A!4?O??A??C!48?_$#130!51?@!75?A!57?A?@OC$#131!128?G!93?A!23?O!12?@$#132!197?O??@!24?G!15?C!7?_!12?O$#133!195?_!26?@$#134!28?E!15?_!5?G!4?G???C???A???_??@!21?O???O_!32?OG??@!31?W@!14?G!9?G$#135!130?A!112?O??@$#143!255?!12?_$#144!230?O!13?_$#149!225?C!35?G!4?C$#150!236?@?A?C!4?O$#158!255?!12?O$#162!126?G$#167!197?_os]khn_@??_$#170!255?!9?@$#174!255?!7?G??C$#177!56?@!204?C$#179!235?@?A?C$#180!28?@!22?G??G!7?A?o!4?A!21?C??C!37?C$#182!200?_RUO^}~~^!9~}zkE?o??O!20?O$#186!229?O!47?O$#188!126?_!63?A!4?A$#189!27?W$#190!27?_$#192!198?G!21?@!19?G!9?G$#196!33?A!14?@!17?A!98?C$#197!43?_!12?A!8?w@!24?@E[?_!35?_?C!31?g@!26?G$#198!227?O$#199!124?_!4?C?@!58?@!74?A$#200!226?C!46?@??A@$#203!251?_!22?@A?AL$#205!233?@!5?G$#207!224?@@???KAI?O?kK?G__$#215!255?!9?A$#216!198?@!40?A$#217!231?_!4?A$#222!130?@$#225!49?@!115?O$#227!48?C!43?@!39?G?A$#228!44?G??C!5?A???C!6?@C?G!26?GO_!34?O???@!5?@!51?D@$#229!68?C$#230!32?@!28?A!31?_!98?O$#231!190?C$#232!191?A$#233!247?A$#234!255?!24?@$#238!244?G$#240!223?@!18?O$#242!228?G$#246!33?{!9~N!4BAAEE!4C??A??@@???{F@!63?ow{}!5~!5}!19~B$#247!127?O!132?A$#248!250?_!21?@!9?C$#254!125?_!140?O-#1!128?O$#2!65?O!66?H!32?^$#4!42?O!22?_O!62?C$#5!66?@$#6!99?G$#7!237?G!20?AAA!8?S$#8!255?!7?@$#9!32?P!10?@!22?C_!29?GG??O!25?O!62?O$#10!43?A!20?A??O!28?G!29?_??@!36?^_!22?GA$#11!193?A!38?@?A!15?@!5?AA$#12!190?_!60?@$#14!28?ooo_!11?oo!6?!10oaoo!4?poopoo_Ospooopoow_oooq!4oO!8?Ooowoq!12o???ooO!40?OO_ooop!6osooO???_o$#15!28?!4N!11?KF@!6?!9NLNN???FMNNM!4NJMNNNMNNF!4NL!4NKG???@BF!4NFNL!13NB??KMF@!38?!6NM!6NJ!4NF@??KA$#16!44?GA@???_F!42?_!4?O$#17!45?_??@`TG!71?@!62?A???@$#19!192?C$#21!45?O?AQG!45?O???_!24?G!58?_!39?C?@!11?C$#22!191?O$#23!46?CCC!48?O!126?A$#25!47?G$#28!96?_!143?G$#33!193?@$#35!193?C!49?O$#42!246?_!21?O$#43!248?@!35?_$#46!192?OG?OET]$#52!218?JGOLBB@!56?A$#56!255?!27?C$#57!122?G$#59!255?!26?@BMN^^MS__$#60!251?A!6?C!24?@O__og$#62!255???C!31?O$#64!255?!4?C$#65!255?!13?A$#67!247?@!7?C$#68!247?_!12?C$#71!254?C$#72!236?@??AC@B??TWEI??G$#73!235?@?A??BAKENGD?CGCCCG$#77!124?@!62?A$#78!248?O$#85!255?G$#94!251?O!16?C$#95!125?@!122?_$#97!253?O$#100!249?_??_?O___?gOoW$#104!123?G$#105!188?@$#108!185?_!79?G$#109!124?A!61?GCA!75?`v~^$#110!122?OC!61?O$#113!231?@???CC?G?OO??_!10?A!5?A!6?_G$#114!191?G!41?A!9?_$#117!47?O!47?_??_!88?P!75?@!26?O$#120!32?_!31?W!63?C!60?_$#121!123?A$#123!121?_$#124!255?!25?@$#126!255?!9?O$#127!195?@!56?@$#129!46?A@_?I!71?C???@!61?G???@!49?O??_!7?A$#130!45?C__?U!48?O!22?O?_!125?@!6?@$#131!125?A!68?A$#132!253?@$#134!31?O!29?O!5?G!6?O_!9?O!12?@ACGO!25?A!37?_?_O!19?OC@$#135!45?G??G!238?@$#136!255?!13?@$#143!255?!12?_$#144!234?@!15?A$#149!194?@!44?G$#156!250?__?__OOOoO_G$#158!255?!7?A$#162!188?C$#167!192?go{mxi`NVKFJTC?O$#174!252?O!4?G!5?G$#177!124?C$#178!236?A!4?G??O$#179!254?A$#180!64?@!29?A!5?_??_!23?G!64?A$#182!199?ogrwsiz~n!10~svnAC!32?@$#183!184?_??G?@$#186!46?W!49?O!138?A!16?A!30?O$#187!186?C$#189!27?_$#190!27?^!163?C$#192!255?!34?G$#193!191?_$#194!255??C$#195!123?O!138?__G$#196!41?G$#197!41?oM!22?N!29?ADAC!31?@@Ew!31?_$#199!184?O$#205!239?C$#206!255?!8?C$#207!237?@B@?C?H?AAG?EG?GC$#213!255?!9?A???G$#216!97?_!87?G???A!73?A$#217!221?O!11?@$#218!255?!6?C$#219!247?O!6?G$#222!255????G?G?C$#226!255?!14?A$#227!42?_!23?G!61?G$#228!32?M!33?A!27?@??@ACW__!24?_?A$#229!64?C$#230!64?_!30?C$#232!122?_!63?O$#239!255?!8?OC$#240!238?C$#246!33?!8~F@!23?_!28?@AC!30?_w}}oF!31~$#247!186?_!67?@$#249!249?OO!5?G-#1!103?A!22?C$#2!33?C!31?_!37?_!30?@$#4!41?a!23?\??G!36?C!27?@G!29?O!5?_$#6!33?_!68?V!4?G!57?A???C$#7!27?@$#9!101?@!4?C!18?C!39?W??@$#10!28?w???E!31?~!4?G_!30?G_?@A??G??_!13?A!41?@!20?@$#11!248?@!5?C???C?!5C?A@$#14!29?~z^_!10?~~}!5~|~~~^{!7~!5?FZx~v}!7~N^^Zz!8~w_!8?@B@FNN^~z~~z~~F?_{^F@!40?}{o@FN\^~~~^NFB`_OGCB@$#15!45?@!77?_$#16!82?_!99?OGCA$#17!83?___!9?CO_??_o!18?@$#19!255??C$#20!249?@$#21!95?@G???Q!20?O!57?G!76?G!18?C$#23!220?@$#25!255?!30?A$#26!255?!12?A$#29!97?CE!156?A!35?@$#33!255?!4?A$#42!97?B!82?_!69?@!7?A!6?A$#43!255?!4?O$#46!188?WC??@?@?@E?G?A$#49!191?C$#52!218?A!41?G!9?A??C$#54!255??A$#56!255????G?O?OoOWg{qa[{wgogW??___??O$#59!255?!22?__?O?o_?G`|~vu{g$#60!192?CCw!77?C!4?W?O?O?O_p]A???AO$#61!191?G$#62!255?!34?GH$#64!193?O$#65!182?G?A$#68!255?!5?@$#77!181?CA$#81!180?G??@$#95!255?!9?A$#100!253?@?@@?@@$#104!178?_!84?A$#109!120?OA!58?OGCA@!78?@@@$#113!27?}!160?A!57?@@??AAA!6?C$#114!189?@$#116!255?!10?C$#117!98?O@!22?A!55?O!92?A$#118!96?C$#120!32?@!35?A!40?O!14?O?@!38?_??C?G$#123!121?G!59?O???@$#124!194?C!64?G!4?__!12?G$#129!95?A??__@!18?G!61?A$#130!180?C?@!86?@!15?C$#132!120?A!68?A!73?G!4?@$#134!28?F?C_O!18?A???_B!11?@?CE?G@!7?O??CC!20?E??O??C??C!49?@A!4?a_!9?_OGCA$#135!97?O?OK!116?G$#136!254?A$#143!255?!7?@$#149!253?A$#150!255???C$#156!254?@??@$#157!185?_OG!67?C$#161!191?_$#162!120?C$#167!188?_w!5AByPp@OK?yK$#170!255???A$#174!121?@!57?O$#176!186?_o??C@?@???G$#177!255?!5?A!5?@$#180!32?G!91?G!43?GA?O$#182!190?G!4?{C_Munp~Dr!10~NNF@@!37?G$#186!99?I$#188!119?_??@!60?C!67?@$#190!184?_OGC$#192!255?!29?G$#196!33?B!5?O@O!23?A?A!35?C??G??_!26?_$#197!33?W!5?_]@!25?@?_!34?A???O!16?G!8?Ew!28?_@???GO$#198!188?C$#200!255?!11?O?K[_??O?O_$#203!255?!6?O_!11?G???O$#206!252?@$#216!96?AGHC!19?O!98?CA!41?_!12?C!5?!4G$#217!96?@$#218!121?C$#225!102?G!24?@$#227!40?_!62?@!20?_!43?A$#228!42?~!25?CO!40?_!15?A!38?C???O?_$#229!101?E$#230!169?_$#231!120?G!58?_!81?A$#233!215?O$#234!190?@!88?G!12?C$#237!255?!6?@$#240!190?O??_$#241!190?_??G$#242!191?Ow$#246!34?!5~N?K!24?~{o!34?W{woo_!16?ow}!5~}oF^!27~N$#247!177?_$#248!255?!6?GG?G?C$#250!120?_$#254!255?!7?A-#2!34?G!72?O!6?C$#4!41?F!62?@!12?O!6?@!38?O!9?_$#5!40?_!129?@C$#6!33?_!8?G!22?C!41?_!5?A!59?O$#7!27?@$#9!28?A!4?M!4?_?B!24?_!4?@CO!30?@??O!8?C!6?_A!40?O!14?G$#10!29?o!34?@!49?A??G!4?G@!41?@!8?G??O??CA$#12!177?_??G$#13!173?C$#14!29?Fv~}!6?o???!4~^!9~v!5~^o!6?@F^z!4~@!8?@p~~~n!9~[wo!8?@BBB@?O~F!42?{~~~^G??@@GWKCEB@$#16!80?@!8?M$#17!79?A!6?@@y!29?_?G!51?G!5?A$#21!80?A?@?@?a!31?O_C!52?G??C!89?A!23?G$#23!86?O!125?G$#25!85?C$#28!81?c!38?A!48?_!118?O$#29!82?C$#42!81?W??G$#43!255?!12?A!13?O$#46!185?GgOM?_GK??M?A$#52!255?!16?C!10?O$#56!255?!10?@@@ABABD?B?IG!5?O@O$#57!177?A$#59!255?!18?@!4?CEA@MBSJ@JNJFB@$#60!191?A!81?A?D?AIGKM@KI?]S?C$#62!193?@$#81!178?@$#95!175?A$#104!176?A$#109!119?E!57?@$#110!119?G$#113!28?w!149?O??CA$#117!85?aG!192?O$#118!81?A??A$#120!28?@!10?C!65?G!6?@!9?O!47?A?@$#124!192?A$#126!171?_$#129!81?@!5?_C!83?_??@$#130!79?{!5?@?]!30?A!51?O!92?@!9?G!18?A$#131!118?C!55?A!7?C$#134!29?GG?@!14?_!9?G!5?_M!8?_C!18?O!9?a??_!6?@??CC!52?C!7?G$#135!83?@??C$#143!171?O$#156!174?C$#157!179?O!4?@$#167!186?AH@dWso{qomX|D}?CqA?A$#176!179?__ow{}vTeoYC???K?O_!15?A$#177!175?C!15?@$#180!39?G!31?AG!31?C!15?_!44?A!7?A?O!6?@$#182!190?A??A@@@CAy@~zL|~|~~~^NF@$#183!119?@$#186!80?c?AA_O!125?O!62?G$#187!120?@$#188!176?@$#189!28?C!154?@$#190!176?_$#192!180?O$#196!34?C???C??w!29?O!33?A??_???A!10?O!11?@CO?_!23?A$#197!34?o???W@??_!22?B!4?AG_!32?CG!4?@!11?G!12?BKo!23?oKB!6?@A?O$#198!183?A$#199!179?@!111?C$#200!255?!13?@?@?ACCAD???@!4?C$#203!255?!22?D@@$#213!119?O$#216!80?W??_CG!32?G!59?_!35?@!55?C!9?O$#217!82?_CO!96?G!28?_$#222!170?_$#225!164?C$#227!40?O?O!73?G!6?C$#228!33?P!5?AK?F!22?W!38?A!59?G!10?_$#229!164?_!6?G$#234!255?!9?@$#240!190?@$#241!192?@$#246!34?B~~~B!27?!4~{_!33?@FN^~~}{{wwo_!5?_}!10~}wbN^!22~N`!7?AC?_$#247!82?WW!88?O$#248!255?!20?G-#1!33?A!6?C$#2!37?A!29?_!41?A?O!28?AO!17?G$#4!34?C!5?b!79?_[!21?_!18?H$#5!33?@$#6!73?A!36?G!7?_$#9!28?_???_!4?O!5?o!31?_!33?C?_!56?_$#10!32?G!5?A!4?C!21?A!8?CO!34?O!10?@!42?@??_?O???A$#11!173?C$#12!169?_$#14!29?w~~B!5?w@!4?!6~}}~~n!5~z!4~o!8?@F~~^}!5{k{k}v~~V~~~z!4~n~^~~~]{o_!53?_`pOGKEAB$#15!60?C!58?A!48?O$#16!79?@A!5?AA@!76?A?G$#17!81?AA?AA?@!30?O!52?@$#21!80?@!79?_??GC$#22!171?O$#23!84?@$#25!82?@$#28!174?C$#42!166?I$#46!181?g?oo??CSOGGED?O?``C$#65!170?@$#68!167?C$#101!164?G$#109!166?C??@$#110!167?A$#113!28?N!141?O???A@$#117!81?@?@!34?G!43?o$#120!37?_@!34?@!87?O!10?C$#129!83?A??@!76?_$#130!85?@!31?G?@!45?O?@C$#131!176?@$#134!29?F??C!5?C}???@!6?@@??O!10?G!8?AG??_!6?O?O?G??g???C!4?O?_???_?G!6?_!47?A!6?C$#135!118?@!86?O$#143!165?C$#150!172?G$#156!168?A$#162!168?@$#167!186?c?gCDaXy~f~MKgARgKO$#176!172?__w{}|~~~V~NN~ZzBjqT_$#177!164?O$#180!43?A!21?C!41?@!62?G$#182!195?G?OQR|kVRNNFB@$#186!117?oA!87?G$#190!28?O!142?G$#192!203?_$#193!171?_OO???A$#195!163?O$#196!35?A_@??W@!24?@O!4?@C!36?C!10?_C!17?G$#197!34?B{?C!4?~!23?M!41?@!13?A!16?BCGo!15?_OKB!12?@$#216!118?C!42?_!7?A_!4?A!31?CA$#217!209?@$#222!165?G$#225!74?O!41?OA??@!42?C$#227!122?@$#228!37?G!28?O!7?G!44?C?A!37?_$#229!32?O!10?G!73?C!55?@$#230!65?@_!41?A$#233!173?G$#246!33?{w@^!4?}!25?N!4~}w_!34?@BN!4~N@?w]?w!16~{pfN^!14~^FRKEB-#1!32?C!99?_!23?G$#2!42?@!25?G!44?C_??o??@!25?C!6?W$#4!33?_!6?@?A!33?O!38?@G???A!23?@A!16?@$#5!32?A!7?A!34?_!75?_$#6!32?_!10?Q!69?GC$#7!27?@!117?C!4?_!7?O!4?C$#9!40?o!31?_???C!78?GA$#10!27?_A!8?@!6?o!33?_!32?@C$#12!145?G???_!6?_$#14!29?BBB!6?BQ!4?BBJ!4BF!4BAJ!4BFBBBa!10?BABH!6B@!8BbBBB!9@BBA!52?@$#16!42?_!46?G!20?O!4?A$#17!29?_?_G!46?g!12?_??C!11?A!53?@$#19!27?G!136?C$#21!35?O!7?_!30?_?G!14?_!8?A!9?CO?OO$#22!157?_??O!7?@$#23!75?G!80?C$#25!34?O!38?_!83?A$#28!97?C$#29!158?_$#38!161?O!38?A$#42!95?O!6?A!5?G$#46!181?CG_?I?[tsUs[{s[GFCB$#57!30?G!47?O!4?OO???_$#65!29?G!52?o!11?O???C!4?C$#68!97?G???C???C$#77!28?O??O!48?O!7?O$#107!30?O$#109!90?OO$#110!89?O!17?C$#113!26?_E!127?_!5?G???A?@$#114!146?G$#116!166?A$#117!74?O!41?@$#120!28?@!38?C!8?A!78?C!7?AA?@$#121!89?_!13?A!5?C$#123!81?_$#126!84?_$#129!30?_??G??G!62?G!16?C!40?C?A$#130!34?G!55?G!5?O!10?G!6?G??@!40?@!39?G$#131!80?_!9?_G!9?A!10?G!35?_$#132!78?G$#134!28?cCCC!4?O}{l!4?K{s!4{w!4{|s!4{w{{{\o!9?CDCE!6KMK!4Ccc_?ooo!7woQO?c_!52?@$#135!35?G!39?O!20?C!102?C$#143!28?G!54?_?__O!20?C??G$#150!147?O!11?O$#157!145?o!16?G$#158!27?O$#160!146?__$#162!81?O$#167!187?@??GB?BABBG@?@$#170!77?G$#174!79?O$#176!170?@A?B@BBJrrNjVRzTzaIJ@Gb?H?C$#180!67?G!8?@!31?___??_$#182!198?A??@$#183!99?C!6?C???G$#186!32?OO!81?CA!41?A@@$#187!85?O!7?G$#188!86?O_!14?C?C!4?G$#189!148?O!5?_$#193!159?___ooww{{}~}|~{}{{sKKoO_KC_C???_!5?O$#196!35?@!32?C!50?A!34?CQ!5?C$#197!36?F!6?K!23?@O!43?@???_?WK!23?@E!4?O??O???O??G$#199!106?A!8?G$#213!93?OG$#215!96?G$#216!98?G!6?A!96?@$#217!163?G?C$#225!75?D!68?w??G!5?_!8?C$#227!40?C!33?G!40?O!38?G??OC?I$#228!32?@!7?G??@!23?A_!4?O!38?A!4?A!34?_!4?@$#229!77?O!85?@$#230!36?_$#231!29?O$#232!92?O$#233!167?A!27?_$#234!146?O$#244!95?G$#246!33?Ffe!5?~[!25?B~~~^NFA__!35?BB_OKfp{!11~^!10~}?@BFNN^^NFR@@GGCCAA$#247!31?G!60?G!11?A!7?O$#250!100?C-#1!70?G???@$#2!35?@!6?GC!28?_o???CC!4?O!19?A!10?A?@$#4!79?G$#5!32?A!111?@$#6!69?O!11?G!20?G$#7!25?A??CC???C!7?_OG!48?_!9?_!41?_$#9!31?@!11?@@!19?__??@G?C!7?C??G!11?G!6?A$#10!28?A!7?@!8?C!16?_!4?_?CA!21?G???C???A??@$#11!35?O$#12!44?G!51?G!4?C$#14!46?I??C???G!12?@!16?@???G$#16!57?C??O$#17!38?_A!7?OO!5?G$#19!100?C!50?@$#20!153?@$#21!58?CO$#22!35?_$#25!94?O!6?O$#38!146?@G?CO!4?G!36?A$#39!146?OAcagY}qUspb[??G$#42!51?O!16?C$#46!168?_!10?C??boOABFJB!4@$#57!40?A!11?O!10?A$#65!67?A$#77!38?O!25?CA$#81!57?G$#95!60?G$#104!56?O$#107!47?_$#109!37?O!10?!4_???O??GG??C$#110!40?C$#113!26?B???CCC?CK!9?O!49?G??CC$#117!50?O!19?C!120?C$#118!185?_!8?@$#120!63?_??_!16?G!9?G???C!15?@$#121!37?_!20?OC$#126!39?C!13?O???O??C$#127!101?G!43?A$#129!56?_!6?G!4?A$#130!38?C??@!7?O!11?A!11?@$#131!55?G!6?G!82?O!8?@$#132!55?_$#134!27?@@@B!5?KFB`OC???BDNNJNNN!4F!4bPPPXXWXw???A!6?@BFFEFFNF!4N!4F!4B@@@$#136!39?O!6?_$#138!93?_!93?O?G$#143!64?A$#150!152?@$#157!93?O???G!47?@$#160!146?mtZXEc?Kg$#162!65?C$#176!170?CGC?@ePIiH{vKHM\KGCCEA$#177!36?O$#180!29?A!6?A???_?A???O!14?_!17?AC!4?G$#182!169?_$#186!42?@!28?A@!25?G$#187!54?_?G!4?G!4?CC$#189!44?C!47?O!9?O!41?W$#190!45?G$#193!155?AM[b~~v!6~^^zvz~}XmtTqBGOE`?O$#196!34?A!34?A!4?G?G!36?A!4?__O?ooWoOOOo_$#197!35?A!8?A!29?OGC!7?!8O!10?A???@@!7?@$#198!145?K$#211!94?_!4oww$#213!53?_!12?A$#216!37?G??GA!20?A!38?_!43?_$#217!150?@$#222!36?_?G$#225!41?O!38?G!21?C!5?!4@$#227!144?E$#228!31?A!37?_!8?@!25?@@!6?@?@$#229!71?@$#230!27?A!12?@!43?G$#231!39?G$#232!52?_?O$#233!155?@$#246!32?@B@!6?GCA!25?@pw[Mevrzy!4o!9_!11?{!9}{{}}~^^n~NNfNnnnN^!13~$#254!61?C?C-#1!69?!5_ooo?oo___!33?oowW[MMMEEMKKM[wo__$#2!53?C!16?B!32?A!39?K$#4!77?_!41?__oOoWWoOOo_$#5!103?G$#6!54?A!13?@$#7!35?O?O??@!51?~!10?_!40?@$#8!35?_$#9!35?M!14?C??A!4?@!10?@$#10!48?A!8?@$#12!144?G$#14!54?@$#17!36?@!15?@$#18!183?@$#19!144?_$#21!51?@!124?C???A$#23!47?@$#38!145?A@?B???C!15?@??@?A$#39!146?ODWEZ~ZZ|A|]?g$#42!49?@$#113!46?@ACCG_!50?@!41?A$#114!102?A!41?C$#117!168?_$#118!168?O!6?C$#130!170?@$#132!50?@$#134!36?MF@!10?AAA?@?@$#135!172?A$#136!102?O$#138!93?~!74?G$#150!102?C!41?O$#157!102?G$#160!145?{mycxc?_cAt$#176!174?AA@AB@?@$#180!35?@??A@!16?@$#189!36?OGCA!11?O!51?O$#193!155?GA`~V!8~!4?!4@A@??@$#196!52?_?C??A!7?__oOWW[\SKMG[KK[[Ggw___!15?@!7?_o_suNJFDB!5@?BB@BDJ\[wgoO!4?A$#197!51?CC??AA!12?A?@!31?C!39?O$#211!94?!8~$#216!102?_$#217!145?@$#225!61?@!5?@!54?_?__?__$#227!51?G$#228!59?@@!82?_$#229!52?A$#233!168?A!10?A??@$#234!168?C$#246!52?Www{{{!4}~~~^^MmCCAAJB@F!5BVVF^^^!4~!12?!7~^N^JH?C?A!6?@!4?ACABFVNn!4~@$#247!48?@-#1!63?_o[KEA!4@!7?@@@BAEMWw__!21?w{MFB@!14?@BFN{o!4?A$#4!65?_OGKAEAA!6@BAAECKGo_!26?oWKEB@@@!7?@BFCKwo$#5!53?_!13?_??G?C?G!4?CC???O_!31?O??AAA!4@?AACGO_!7?_$#7!51?A_!39?F$#12!103?A!39?_$#20!144?@$#21!168?@$#25!93?w!9?O!38?O$#38!144?O@@??OO$#39!145?GIDUAJU~tljtJBQ$#113!51?@W!50?@_!38?G$#114!143?O$#120!142?C@$#127!103?G$#129!142?G$#130!168?A$#138!93?F$#149!143?C$#150!103?C$#160!144?_usyhlch?GQ$#180!143?A$#186!144?C$#189!52?C!39?w!11?O$#193!153?A?SIs{l!8~$#196!53?G!6?_okVL@B@@!15?@@?FBW[{!12?@_??_o}fFB!22?@AVsQ$#197!52?@O!50?E$#198!144?A$#211!94?!9~$#216!142?_$#225!66?_O?K?C?!6A??C?G?O!29?_OGCA??@!4?@@???IO$#226!68?oooww{S!4[!4wo_!31?__w!4{!5}{{wo_$#227!52?A!21?!5_!25?G$#233!103?_$#234!144?G$#246!53?F!6~^NRGAA!20?@?CFBB!13?^~~^N@W??@!21?ALgJl^@-#1!54?A???c~~~F@!25?@BM!15?S{~~~F!24?B^~B$#2!106?O$#4!62?w]F@!21?@BM{o!20?w~F@!18?@F~{_$#5!63?_?A@!20?ACO!24?GA!18?AG$#6!70?GCAAA@@?AAACCGO!20?C!14?_owWGWWo__$#7!54?O!50?G$#9!68?_!71?G$#11!142?g$#12!104?@$#19!104?A!38?@$#20!93?O$#21!142?A!24?O$#25!93?@!48?@$#33!141?c$#38!144?Hpa_?O$#39!153?AC_~knvF!5?A$#113!53?E_!87?O$#114!105?O$#117!93?A$#118!167?G$#122!141?W$#129!69?_??OO!66?O$#132!140?_$#133!71?O??!4O!64?C$#135!141?A$#136!93?G!10?C$#150!105?_$#157!93?_!49?A$#158!70?!12_$#160!143?_uM\^~n~~~|z^?R!9?A$#179!70?O!8?O$#180!78?O???_!58?@$#186!104?G!38?G$#189!53?@!38?B$#190!73?GGGKKGGGO?_$#193!158?OGw!5~|@$#197!54?C_!49?@_$#198!143?C$#199!93?C$#211!94?!10~o$#217!167?C$#225!105?A$#226!64?w{]FB@@!11?@@BFN[w_!24?o{~^FB@@!6?@@BN^~{o$#227!54?G!11?_w[MEB@@@??!4@BAEKwo_!4?{!24?_w{]M!5FN]]{o_$#228!69?O?GKCCEAACCCGWO_!38?_o__$#229!80?O$#233!143?O$#246!54?@^~~Z!32?@!14?NjB!31?C-#1!56?Cp]~N!46?Av~N$#4!60?o~B!28?B!18?o~F@!23?FF$#5!62?[!49?GA!22?@g$#6!85?@A!30?_wF@!8?@Fw_!6?@$#7!54?@$#9!84?@$#11!141?G$#12!93?G!12?G!34?_$#17!64?OCA!21?O!50?A$#19!93?B$#20!142?A$#21!72?CG??AAACG?_!58?A$#25!105?A!33?C$#38!142?O{i$#39!155?v^JEmO!5?@$#113!55?K_!49?C$#114!93?o!47?O$#116!106?O$#117!138?_$#118!166?O$#122!139?w^$#129!64?_w!17?@???G$#130!66?{]F!17?Go_!77?_$#131!142?C$#133!86?C!54?C$#136!72?_o!5{woo$#150!93?C!48?@$#157!105?@$#158!67?_w~~~ZFBB@@@BFN^}}{o$#160!142?_BT!10~G_cp!7?C$#180!67?@!17?A!52?O$#186!141?@$#189!55?A!50?A_$#190!88?G_!31?w{}}}{{o_$#193!157?OGPn!5~A$#196!107?C$#197!56?G!35?B!14?G$#199!106?_$#211!94?!11~w$#216!140?_?G$#217!166?G$#225!55?@!36?{!14?O$#226!62?_^B@!22?BN~{!20?o{~^@!16?B~~}OG$#227!56?O!7?CA@!19?@BCO!16?@!8?_}^F!12?F^{$#228!87?C!31?w}FB@@@BBN]w$#229!63?_G$#233!105?C$#246!56?BM`!48?@G-#1!58?D~Q!47?@^$#4!60?lF!30?@!17?~^$#5!58?O!52?_@$#6!93?O!22?_n!14?^$#7!56?AS!35?A$#9!62?A!27?C$#11!140?C$#12!108?_!31?O$#16!61?_$#17!63?@$#19!107?C$#21!71?s!11?AO$#23!165?O$#25!94?G$#38!141?_QIg`__?_$#39!141?O!7?A???O?LUz\rDO@G?C$#113!56?@G!35?@!13?@O$#114!107?A!32?G$#116!140?_@$#117!107?G$#122!137?w~N$#127!94?_$#128!140?@$#129!62?w}~j!23?AO!49?A$#130!65?S~g!19?@^{_!74?_$#134!62?C$#135!139?_$#136!72?!6~^!4~{g!9?O!41?_C$#138!94?A!11?@!58?G$#151!142?_$#158!67?V~~~J!11?@F~~}_$#160!141?GLtV]^^~\~~~n~qHC_$#180!89?@G!45?OA$#186!94?C$#189!58?_!34?K!14?G$#190!91?_!27?s!10~{$#193!156?_?AKyn}v~B$#197!57?@G!49?A$#198!141?A$#199!78?_$#211!94?@!11~}_$#216!139?O?C$#217!107?O$#225!109?_$#226!62?@!27?@N}!19?}~~!20?~N$#227!57?A!32?AO?_!14?C!6?~^!16?~~??@$#228!61?G!55?O~J!10?B~_$#229!61?O$#246!58?A-#4!110?FC$#5!93?G!17?B$#6!110?O!5?~!16?~G$#7!94?_$#9!60?_$#10!60?O!31?G$#11!138?_A$#12!94?C$#13!60?G$#14!60?C$#17!61?~{!29?O$#19!94?@!44?G$#21!71?@!13?s$#22!139?O$#25!138?G$#38!140?KQLNNNBC?@KC@G@$#39!143?_O_??O_PO_oOpx~rrto??@$#113!58?BW!34?O!14?C_$#114!94?G!44?C$#116!108?@$#117!135?C!28?G$#122!135?w~~B$#127!109?O$#129!62?B~~~!25?M_!45?O$#130!66?~~!21?J~o!72?O$#131!108?A!25?_$#133!134?O!4?@$#136!71?A!6~vj^!4~G$#140!138?C$#150!94?A!14?G$#158!68?~~~{!13?B~~~s$#160!140?olqO_O{zn]aj]FmME?G$#180!91?@!43?A$#189!59?C!49?A$#190!92?C!25?I!12~G$#193!158?CKIN~~A$#197!59?B$#198!140?@$#199!78?GS_$#211!95?^!12~w$#216!95?_!13?_!29?_$#217!140?A$#225!93?C!16?G_$#226!92?BO!17?W~~@$#227!93?B!15?@!4?}~!18?F@$#228!60?@!32?_!23?~t!12?v~$#230!60?A$#233!108?C!55?C-#5!111?@G$#6!112?O???N!15?F$#7!111?C_$#9!61?C!32?C!33?G$#10!61?A!31?@G!35?O$#11!95?_!42?@$#12!137?O$#14!94?_$#16!61?@$#17!62?^{!29?A$#19!95?G!42?A$#21!72?@K_!48?_!5?O?O$#22!137?_$#25!95?@!34?_?O!4?A$#38!141?C???C!16?_$#39!139?_A??@G?KD]Jcj~~d~f~qjKAQ@$#113!60?BG!75?G$#114!110?@G$#117!163?C$#120!62?_$#122!133?W~~N$#129!63?B~~~o!24?~{!25?G!6?G$#130!67?N~_!20?n~!25?__$#132!133?C??O$#133!116?_O!15?A???C$#135!136?_$#136!73?B^!11~$#139!133?_$#140!137?@$#150!95?O$#151!139?G$#157!95?C!14?AO$#158!69?^~~}o!12?!4~O!27?OowwwWWWo$#160!138?oV|z~}vzry`sZS??Y?W$#179!121?!4C$#180!94?O!32?G$#186!110?C!13?_???O$#189!94?B$#190!119?FF!4B!4FNB?G$#193!158?LSr|L$#198!138?C$#199!95?A!29?_?O$#211!96?!14~w$#216!111?_!15?_$#217!129?_?__!5?G$#226!112?F~$#227!111?A??~~$#228!116?ONF!11?KN?@$#229!118?G$#233!163?A$#234!128?_-#10!115?@$#17!94?@$#21!67?AA?A?G!4?_!7?OQGG?G!23?C?A?CAA$#25!81?_!42?@$#38!134?GC???G???@C!4?C$#39!134?A!6?_!4?KkjXLv~~z~~~v~EE$#51!134?@$#113!95?E$#114!95?@$#117!69?A!5?WO??O???_!4?O!24?C!11?@$#118!70?C!20?G??G!22?CG!17?@!24?O$#128!113?A$#129!66?@@!25?FE$#130!68?@@!21?FF!22?A@BB!14?C_$#135!69?C!51?A$#136!74?DFNNNn~!4^N$#138!87?!5_OO?OQ!17?G?CG!16?O$#139!133?@?@$#151!135?I???D$#157!112?@$#158!70?@FFBA!11?LFFNF!28?!4@$#160!134?Cow}~q~^~}z~rRSaqG??C$#179!95?G$#180!65?@$#185!91?OGGO!23?O!14?A!28?@$#186!78?O???_???_O??O!5?C!18?C!7?@!12?A$#193!158?G?x@$#199!73?C!4?_!5?__???O$#211!92?!4_`!15~{!5o!18?C$#216!77?O!18?G!15?A$#226!114?@$#228!113?@A$#233!74?G!38?G?GG?_!18?@!23?G$#234!73?G-#18!119?O$#21!89?O!64?_$#38!135?@G!6?A$#39!89?G!20?O!27?G!5?@?SC@I?nJJL^NNNF@$#40!107?_$#45!96?C$#48!93?C!11?GO!9?_!33?G??O$#49!104?GO_??_!41?O$#53!95?COG!41?G!5?C$#60!153?_??O$#61!94?GGG!41?OO!4?GO???O_!6?O$#63!94?C??O!52?O$#117!94?O$#118!85?C!7?G?O?_!21?_!27?_$#129!80?@???@$#130!79?@?@!53?CO!23?C$#135!146?_$#138!85?@PO!47?A?O!22?A$#151!94?A???W???G??C?O?O??I???AI$#160!106?C!5?_??_!20?FNFFFNNDEBBZMDF?SCA$#167!154?O???O$#172!101?G?GC?G?_?__$#182!146?G$#185!88?O??G!7?O$#186!142?O$#192!140?O??O$#193!103?C!13?_!22?G??G!4?O!10?G$#203!144?O$#211!85?AMNNFNFFB@BBFFNNVVRRBBN^NN^T~~^\T~$#216!155?_?_$#217!100?O!58?O$#233!141?O!10?_!5?_$#240!145?G-#18!107?A!9?C$#21!110?A$#38!109?A!8?@$#48!111?@$#53!107?@@!7?A$#61!109?@@!4?@?@$#63!116?@$#117!108?A$#118!118?C$#138!119?B$#160!114?@$#193!112?@!4?A$#211!113?@!4?A---#0!255?!65?\ +[?25h \ No newline at end of file diff --git a/fastfetch/logo_rm/32x.symbols b/fastfetch/logo_rm/32x.symbols new file mode 100644 index 0000000..4926f93 --- /dev/null +++ b/fastfetch/logo_rm/32x.symbols @@ -0,0 +1,23 @@ +[?25l  ▂▁     ▁   +  ▖▗▇▇▆▅▆▆▅▇▇┓▗▅▅▌  +   ▖╸╴┈╴▂╷┈┒▋▗▘▌▗   +  ▍┈╷─▊▁╌╷└╷┗╺▗╸▂  +   ▂┈╹▄▏▆╺━╴╸▂▝▂▝▆╻  ▂▁▁   +  ▊ ▖╵▂▁╴╴▁▁▃▏╲▅▄▂▅▄━▇╹╺┊▆━▃   +  ▗▆▖╾▂▄━▃▃▄▏▅▂▂▝▖▆▁╸╼┑▆━╹▅▋  +   ▘▆╿▖▂▂▁▁▃▘▂▝╾▖▆▇▇▃▆━┊▃┙▝▁▝▖  +  ▌▗▂▃▖▖▘▃▆▇▄╴▂┑▇▖▇▇▂▃▗▃▃▄▝▇▂▘  +  ▍▝▃▁▍▋▍╴╸▊▏▝▆▚╌▊▊▅▖▆▄▝╴▄▇   +  ▎▖▆▍▃▗▍╹▁▁▝▃▆▆┈▏▘╴▍▇▅┖┊▚▇▖╻   + ▏▏▅▎▉╲╻╺╵▆▆▅╾╷▂▇▇▇▘▅▆▁▃▇▇▃▆▆▚  + ▊┊▘▇▉▗└▂▏▍┓╴╷▂▂▃╹╵▎▚╶▅▆▃▆▅▄▗▅   +  ▝▖▇▗▘▉╴▝╴┊▁━╵▇▗▏┈▂▂▍▄▁╾▉▃▅▝▆▂  +  ▍▂▁▂▊╹▎▝▂▇▁▂▄▇▅▉▆▁▘▌▗▆▅▄▂━━▅  +  ▉▃▁╵▁▃┙▆┈▄▆▇╼╴▖▇▃▊╴╾╾▃ ▗▁▁  +  ▊▎╺▇▌ ▁▗▃┊╸┈ ▋▁╱▘▌▗▅▅▃━▁▂▇   +  ▊┊╴▁▂┈▇┌─┈┊ ▗▂▃▅┊▂▄  ▇▇   +  ▝▇▖▇▁┊▎▍▗▃▖▘▌▉▆▇  +  ▝▘▎▇▍▝╴▆▗▏▋▋  +  ▆▅▃▂▂▁▆▝▂▂▘  +   +[?25h \ No newline at end of file diff --git a/fastfetch/logo_rm/512.png b/fastfetch/logo_rm/512.png new file mode 100644 index 0000000..28285b1 Binary files /dev/null and b/fastfetch/logo_rm/512.png differ diff --git a/fish/.gitignore b/fish/.gitignore new file mode 100644 index 0000000..3b90514 --- /dev/null +++ b/fish/.gitignore @@ -0,0 +1,2 @@ +fish_variables +fish_plugins \ No newline at end of file diff --git a/fish/conf.d.disabled/.gitignore b/fish/conf.d.disabled/.gitignore new file mode 100644 index 0000000..be9e93b --- /dev/null +++ b/fish/conf.d.disabled/.gitignore @@ -0,0 +1,4 @@ +* +!.gitignore +!path.fish +!ssh-agent.fish \ No newline at end of file diff --git a/fish/conf.d.disabled/path.fish b/fish/conf.d.disabled/path.fish new file mode 100644 index 0000000..55df502 --- /dev/null +++ b/fish/conf.d.disabled/path.fish @@ -0,0 +1,11 @@ +fish_add_path $HOME/.local/bin +fish_add_path $HOME/bin + +# cargo +if test -f $HOME/.cargo/env.fish + source $HOME/.cargo/env.fish +end + +if test -d $HOME/.scripts + fish_add_path $HOME/.scripts +end diff --git a/fish/conf.d.disabled/ssh-agent.fish b/fish/conf.d.disabled/ssh-agent.fish new file mode 100644 index 0000000..9ec2375 --- /dev/null +++ b/fish/conf.d.disabled/ssh-agent.fish @@ -0,0 +1,8 @@ +if test -z "$SSH_AUTH_SOCK" + eval (command ssh-agent -c) >/dev/null 2>&1 + for key in $HOME/.ssh/keys/* + if test -f $key + command ssh-add $key >/dev/null 2>&1 + end + end +end \ No newline at end of file diff --git a/fish/config.fish b/fish/config.fish new file mode 100755 index 0000000..512a37c --- /dev/null +++ b/fish/config.fish @@ -0,0 +1,31 @@ +if not status is-interactive + return +end + +# no greeting +set fish_greeting + +# ls alias +alias ls="ls --hyperlink=auto --color=auto" + +# nvim +if type -q nvim + set -x EDITOR nvim + set -x VISUAL nvim +end + +if test -d $HOME/.config/fish/prev.d + for file in $HOME/.config/fish/prev.d/*.fish + if test -f $file + source $file + end + end +end + +if test -d $HOME/.config/fish/post.d + for file in $HOME/.config/fish/post.d/*.fish + if test -f $file + source $file + end + end +end \ No newline at end of file diff --git a/fish/functions/__bass.py b/fish/functions/__bass.py new file mode 100755 index 0000000..3f02bd4 --- /dev/null +++ b/fish/functions/__bass.py @@ -0,0 +1,140 @@ +""" +To be used with a companion fish function like this: + + function refish + set -l _x (python /tmp/bass.py source ~/.nvm/nvim.sh ';' nvm use iojs); source $_x; and rm -f $_x + end + +""" + +from __future__ import print_function + +import json +import os +import signal +import subprocess +import sys +import traceback + + +BASH = 'bash' + +FISH_READONLY = [ + 'PWD', 'SHLVL', 'history', 'pipestatus', 'status', 'version', + 'FISH_VERSION', 'fish_pid', 'hostname', '_', 'fish_private_mode' +] + +IGNORED = [ + 'PS1', 'XPC_SERVICE_NAME' +] + +def ignored(name): + if name == 'PWD': # this is read only, but has special handling + return False + # ignore other read only variables + if name in FISH_READONLY: + return True + if name in IGNORED or name.startswith("BASH_FUNC"): + return True + if name.startswith('%'): + return True + return False + +def escape(string): + # use json.dumps to reliably escape quotes and backslashes + return json.dumps(string).replace(r'$', r'\$') + +def escape_identifier(word): + return escape(word.replace('?', '\\?')) + +def comment(string): + return '\n'.join(['# ' + line for line in string.split('\n')]) + +def gen_script(): + # Use the following instead of /usr/bin/env to read environment so we can + # deal with multi-line environment variables (and other odd cases). + env_reader = "%s -c 'import os,json; print(json.dumps({k:v for k,v in os.environ.items()}))'" % (sys.executable) + args = [BASH, '-c', env_reader] + output = subprocess.check_output(args, universal_newlines=True) + old_env = output.strip() + + pipe_r, pipe_w = os.pipe() + if sys.version_info >= (3, 4): + os.set_inheritable(pipe_w, True) + command = 'eval $1 && ({}; alias) >&{}'.format( + env_reader, + pipe_w + ) + args = [BASH, '-c', command, 'bass', ' '.join(sys.argv[1:])] + p = subprocess.Popen(args, universal_newlines=True, close_fds=False) + os.close(pipe_w) + with os.fdopen(pipe_r) as f: + new_env = f.readline() + alias_str = f.read() + if p.wait() != 0: + raise subprocess.CalledProcessError( + returncode=p.returncode, + cmd=' '.join(sys.argv[1:]), + output=new_env + alias_str + ) + new_env = new_env.strip() + + old_env = json.loads(old_env) + new_env = json.loads(new_env) + + script_lines = [] + + for k, v in new_env.items(): + if ignored(k): + continue + v1 = old_env.get(k) + if not v1: + script_lines.append(comment('adding %s=%s' % (k, v))) + elif v1 != v: + script_lines.append(comment('updating %s=%s -> %s' % (k, v1, v))) + # process special variables + if k == 'PWD': + script_lines.append('cd %s' % escape(v)) + continue + else: + continue + if k == 'PATH': + value = ' '.join([escape(directory) + for directory in v.split(':')]) + else: + value = escape(v) + script_lines.append('set -g -x %s %s' % (k, value)) + + for var in set(old_env.keys()) - set(new_env.keys()): + script_lines.append(comment('removing %s' % var)) + script_lines.append('set -e %s' % var) + + script = '\n'.join(script_lines) + + alias_lines = [] + for line in alias_str.splitlines(): + _, rest = line.split(None, 1) + k, v = rest.split("=", 1) + alias_lines.append("alias " + escape_identifier(k) + "=" + v) + alias = '\n'.join(alias_lines) + + return script + '\n' + alias + +script_file = os.fdopen(3, 'w') + +if not sys.argv[1:]: + print('__bass_usage', file=script_file, end='') + sys.exit(0) + +try: + script = gen_script() +except subprocess.CalledProcessError as e: + sys.exit(e.returncode) +except Exception: + print('Bass internal error!', file=sys.stderr) + raise # traceback will output to stderr +except KeyboardInterrupt: + signal.signal(signal.SIGINT, signal.SIG_DFL) + os.kill(os.getpid(), signal.SIGINT) +else: + script_file.write(script) diff --git a/fish/functions/bass.fish b/fish/functions/bass.fish new file mode 100755 index 0000000..2b3af16 --- /dev/null +++ b/fish/functions/bass.fish @@ -0,0 +1,29 @@ +function bass + set -l bash_args $argv + set -l bass_debug + if test "$bash_args[1]_" = '-d_' + set bass_debug true + set -e bash_args[1] + end + + set -l script_file (mktemp) + if command -v python3 >/dev/null 2>&1 + command python3 -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file + else + command python -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file + end + set -l bass_status $status + if test $bass_status -ne 0 + return $bass_status + end + + if test -n "$bass_debug" + cat $script_file + end + source $script_file + command rm $script_file +end + +function __bass_usage + echo "Usage: bass [-d] " +end diff --git a/fish/post.d/fetch.fish b/fish/post.d/fetch.fish new file mode 100644 index 0000000..3f357ea --- /dev/null +++ b/fish/post.d/fetch.fish @@ -0,0 +1,34 @@ +if not set -q fetch_logo_type + set -g fetch_logo_type "auto" +end + +if test "$fetch_logo_type" = "symbols" + set -g fetch_args "--logo-type raw --logo-width 32 --logo \"$HOME/.config/fastfetch/logo_mugi/32x.symbols\"" + set -g fetch_args_brief "--logo-type raw --logo-width 24 --logo \"$HOME/.config/fastfetch/logo_mugi/24x.symbols\"" +else if test "$fetch_logo_type" = "logo" + set -g fetch_args "--logo-type builtin" + set -g fetch_args_brief "--logo-type small" +else if test "$fetch_logo_type" = "sixel" + set -g fetch_args "--logo-type raw --logo-width 32 --logo \"$HOME/.config/fastfetch/logo_mugi/32x.sixel\"" + set -g fetch_args_brief "--logo-type raw --logo-width 24 --logo \"$HOME/.config/fastfetch/logo_mugi/24x.sixel\"" +else # "kitty" or "auto" and others + set -g fetch_args "--logo-type $fetch_logo_type --logo-height 21 --logo \"$HOME/.config/fastfetch/logo_mugi/mugi_3.png\"" + set -g fetch_args_brief "--logo-type $fetch_logo_type --logo-height 13 --logo \"$HOME/.config/fastfetch/logo_mugi/mugi_1.png\"" +end + +if type -q fastfetch + alias ff="fastfetch -c $HOME/.config/fastfetch/config.jsonc $fetch_args" + + if test -f "$HOME/.config/fastfetch/brief.jsonc" + alias ff-brief="fastfetch -c $HOME/.config/fastfetch/brief.jsonc $fetch_args_brief" + else + alias ff-brief=ff + end +end + +# add 'set -g no_fetch' somewhere other than post.d to disable fetching +if not set -q no_fetch + if type -q ff-brief + ff-brief + end +end diff --git a/fish/prev.d/.gitignore b/fish/prev.d/.gitignore new file mode 100644 index 0000000..0ae4370 --- /dev/null +++ b/fish/prev.d/.gitignore @@ -0,0 +1,6 @@ +* +!.gitignore +!zoxide.fish +!prompt.fish +!ssh-agent.fish +!theme.fish \ No newline at end of file diff --git a/fish/prev.d/prompt.fish b/fish/prev.d/prompt.fish new file mode 100644 index 0000000..b0da92f --- /dev/null +++ b/fish/prev.d/prompt.fish @@ -0,0 +1,12 @@ +function fish_prompt -d "Write out the prompt" + # This shows up as USER@HOST /home/user/ >, with the directory colored + # $USER and $hostname are set by fish, so you can just use them + # instead of using `whoami` and `hostname` + printf '%s@%s %s%s%s > ' $USER $hostname \ + (set_color $fish_color_cwd) (prompt_pwd) (set_color normal) +end + +# oh-my-posh +if test -f $HOME/.config/posh_theme.omp.json; and type -q oh-my-posh + oh-my-posh init fish --config $HOME/.config/posh_theme.omp.json | source +end \ No newline at end of file diff --git a/fish/prev.d/theme.fish b/fish/prev.d/theme.fish new file mode 100644 index 0000000..eab922f --- /dev/null +++ b/fish/prev.d/theme.fish @@ -0,0 +1,6 @@ +set -l theme 'Catpuccin Mocha' + +if not set -q fish_current_theme; or not string match -q "$theme" "$fish_current_theme" + set -U fish_current_theme "$theme" + fish_config theme save "$theme" +end \ No newline at end of file diff --git a/fish/prev.d/zoxide.fish b/fish/prev.d/zoxide.fish new file mode 100644 index 0000000..cd85ed8 --- /dev/null +++ b/fish/prev.d/zoxide.fish @@ -0,0 +1,4 @@ +if type -q zoxide + zoxide init fish | source + alias cd=z +end \ No newline at end of file diff --git a/fish/themes/Catppuccin Frappe.theme b/fish/themes/Catppuccin Frappe.theme new file mode 100644 index 0000000..b4c1994 --- /dev/null +++ b/fish/themes/Catppuccin Frappe.theme @@ -0,0 +1,30 @@ +# name: 'Catppuccin Frappé' +# url: 'https://github.com/catppuccin/fish' +# preferred_background: 303446 + +fish_color_normal c6d0f5 +fish_color_command 8caaee +fish_color_param eebebe +fish_color_keyword e78284 +fish_color_quote a6d189 +fish_color_redirection f4b8e4 +fish_color_end ef9f76 +fish_color_comment 838ba7 +fish_color_error e78284 +fish_color_gray 737994 +fish_color_selection --background=414559 +fish_color_search_match --background=414559 +fish_color_option a6d189 +fish_color_operator f4b8e4 +fish_color_escape ea999c +fish_color_autosuggestion 737994 +fish_color_cancel e78284 +fish_color_cwd e5c890 +fish_color_user 81c8be +fish_color_host 8caaee +fish_color_host_remote a6d189 +fish_color_status e78284 +fish_pager_color_progress 737994 +fish_pager_color_prefix f4b8e4 +fish_pager_color_completion c6d0f5 +fish_pager_color_description 737994 \ No newline at end of file diff --git a/fish/themes/Catppuccin Latte.theme b/fish/themes/Catppuccin Latte.theme new file mode 100644 index 0000000..002dace --- /dev/null +++ b/fish/themes/Catppuccin Latte.theme @@ -0,0 +1,30 @@ +# name: 'Catppuccin Latte' +# url: 'https://github.com/catppuccin/fish' +# preferred_background: eff1f5 + +fish_color_normal 4c4f69 +fish_color_command 1e66f5 +fish_color_param dd7878 +fish_color_keyword d20f39 +fish_color_quote 40a02b +fish_color_redirection ea76cb +fish_color_end fe640b +fish_color_comment 8c8fa1 +fish_color_error d20f39 +fish_color_gray 9ca0b0 +fish_color_selection --background=ccd0da +fish_color_search_match --background=ccd0da +fish_color_option 40a02b +fish_color_operator ea76cb +fish_color_escape e64553 +fish_color_autosuggestion 9ca0b0 +fish_color_cancel d20f39 +fish_color_cwd df8e1d +fish_color_user 179299 +fish_color_host 1e66f5 +fish_color_host_remote 40a02b +fish_color_status d20f39 +fish_pager_color_progress 9ca0b0 +fish_pager_color_prefix ea76cb +fish_pager_color_completion 4c4f69 +fish_pager_color_description 9ca0b0 \ No newline at end of file diff --git a/fish/themes/Catppuccin Macchiato.theme b/fish/themes/Catppuccin Macchiato.theme new file mode 100644 index 0000000..c8be912 --- /dev/null +++ b/fish/themes/Catppuccin Macchiato.theme @@ -0,0 +1,30 @@ +# name: 'Catppuccin Macchiato' +# url: 'https://github.com/catppuccin/fish' +# preferred_background: 24273a + +fish_color_normal cad3f5 +fish_color_command 8aadf4 +fish_color_param f0c6c6 +fish_color_keyword ed8796 +fish_color_quote a6da95 +fish_color_redirection f5bde6 +fish_color_end f5a97f +fish_color_comment 8087a2 +fish_color_error ed8796 +fish_color_gray 6e738d +fish_color_selection --background=363a4f +fish_color_search_match --background=363a4f +fish_color_option a6da95 +fish_color_operator f5bde6 +fish_color_escape ee99a0 +fish_color_autosuggestion 6e738d +fish_color_cancel ed8796 +fish_color_cwd eed49f +fish_color_user 8bd5ca +fish_color_host 8aadf4 +fish_color_host_remote a6da95 +fish_color_status ed8796 +fish_pager_color_progress 6e738d +fish_pager_color_prefix f5bde6 +fish_pager_color_completion cad3f5 +fish_pager_color_description 6e738d \ No newline at end of file diff --git a/fish/themes/Catppuccin Mocha.theme b/fish/themes/Catppuccin Mocha.theme new file mode 100644 index 0000000..892a000 --- /dev/null +++ b/fish/themes/Catppuccin Mocha.theme @@ -0,0 +1,30 @@ +# name: 'Catppuccin Mocha' +# url: 'https://github.com/catppuccin/fish' +# preferred_background: 1e1e2e + +fish_color_normal cdd6f4 +fish_color_command 89b4fa +fish_color_param f2cdcd +fish_color_keyword f38ba8 +fish_color_quote a6e3a1 +fish_color_redirection f5c2e7 +fish_color_end fab387 +fish_color_comment 7f849c +fish_color_error f38ba8 +fish_color_gray 6c7086 +fish_color_selection --background=313244 +fish_color_search_match --background=313244 +fish_color_option a6e3a1 +fish_color_operator f5c2e7 +fish_color_escape eba0ac +fish_color_autosuggestion 6c7086 +fish_color_cancel f38ba8 +fish_color_cwd f9e2af +fish_color_user 94e2d5 +fish_color_host 89b4fa +fish_color_host_remote a6e3a1 +fish_color_status f38ba8 +fish_pager_color_progress 6c7086 +fish_pager_color_prefix f5c2e7 +fish_pager_color_completion cdd6f4 +fish_pager_color_description 6c7086 \ No newline at end of file diff --git a/fuzzel/fuzzel.ini b/fuzzel/fuzzel.ini new file mode 100755 index 0000000..3fc8ea3 --- /dev/null +++ b/fuzzel/fuzzel.ini @@ -0,0 +1,24 @@ +terminal=kitty -e +prompt=">> " +layer=overlay + +[colors] +background=1e1e2edd +text=cdd6f4ff +prompt=bac2deff +placeholder=7f849cff +input=cdd6f4ff +match=89b4faff +selection=585b70ff +selection-text=cdd6f4ff +selection-match=89b4faff +counter=7f849cff +border=89b4faff + + +[border] +radius=17 +width=2 + +[dmenu] +exit-immediately-if-empty=yes diff --git a/ghostty/config b/ghostty/config new file mode 100644 index 0000000..c8393b3 --- /dev/null +++ b/ghostty/config @@ -0,0 +1,19 @@ +theme = catppuccin-mocha + +background-opacity = 0.75 +background-blur = true + +window-padding-x = 10 +window-padding-y = 10 + +keybind = ctrl+shift+r=reload_config + +command = exec fish + +confirm-close-surface = false + +font-family = MeloLGM Nerd Font +font-size = 12 + +# just for fun +# custom-shader = ~/.config/ghostty/shaders/glitchy.glsl diff --git a/ghostty/shaders/animated-gradient-shader.glsl b/ghostty/shaders/animated-gradient-shader.glsl new file mode 100644 index 0000000..01b541c --- /dev/null +++ b/ghostty/shaders/animated-gradient-shader.glsl @@ -0,0 +1,40 @@ +// credits: https://github.com/unkn0wncode +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + // Create seamless gradient animation + float speed = 0.2; + float gradientFactor = (uv.x + uv.y) / 2.0; + + // Use smoothstep and multiple sin waves for smoother transition + float t = sin(iTime * speed) * 0.5 + 0.5; + gradientFactor = smoothstep(0.0, 1.0, gradientFactor); + + // Create smooth circular animation + float angle = iTime * speed; + vec3 color1 = vec3(0.1, 0.1, 0.5); + vec3 color2 = vec3(0.5, 0.1, 0.1); + vec3 color3 = vec3(0.1, 0.5, 0.1); + + // Smooth interpolation between colors using multiple mix operations + vec3 gradientStartColor = mix( + mix(color1, color2, smoothstep(0.0, 1.0, sin(angle) * 0.5 + 0.5)), + color3, + smoothstep(0.0, 1.0, sin(angle + 2.0) * 0.5 + 0.5) + ); + + vec3 gradientEndColor = mix( + mix(color2, color3, smoothstep(0.0, 1.0, sin(angle + 1.0) * 0.5 + 0.5)), + color1, + smoothstep(0.0, 1.0, sin(angle + 3.0) * 0.5 + 0.5) + ); + + vec3 gradientColor = mix(gradientStartColor, gradientEndColor, gradientFactor); + + vec4 terminalColor = texture(iChannel0, uv); + float mask = 1.0 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, gradientColor, mask); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/bettercrt.glsl b/ghostty/shaders/bettercrt.glsl new file mode 100644 index 0000000..8f58b89 --- /dev/null +++ b/ghostty/shaders/bettercrt.glsl @@ -0,0 +1,33 @@ +// Original shader collected from: https://www.shadertoy.com/view/WsVSzV +// Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) +// Slight modifications were made to give a green-ish effect. + +// This shader was modified by April Hall (arithefirst) +// Sourced from https://github.com/m-ahdal/ghostty-shaders/blob/main/retro-terminal.glsl +// Changes made: +// - Removed tint +// - Made the boundaries match ghostty's background color + +float warp = 0.25; // simulate curvature of CRT monitor +float scan = 0.50; // simulate darkness between scanlines + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // squared distance from center + vec2 uv = fragCoord / iResolution.xy; + vec2 dc = abs(0.5 - uv); + dc *= dc; + + // warp the fragment coordinates + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; + + // determine if we are drawing in a scanline + float apply = abs(sin(fragCoord.y) * 0.25 * scan); + + // sample the texture + vec3 color = texture(iChannel0, uv).rgb; + + // mix the sampled color with the scanline intensity + fragColor = vec4(mix(color, vec3(0.0), apply), 1.0); +} diff --git a/ghostty/shaders/bloom.glsl b/ghostty/shaders/bloom.glsl new file mode 100644 index 0000000..ad22448 --- /dev/null +++ b/ghostty/shaders/bloom.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.2; + } + } + + fragColor = color; +} \ No newline at end of file diff --git a/ghostty/shaders/cineShader-Lava.glsl b/ghostty/shaders/cineShader-Lava.glsl new file mode 100644 index 0000000..224a2ce --- /dev/null +++ b/ghostty/shaders/cineShader-Lava.glsl @@ -0,0 +1,79 @@ +// INFO: This shader is a port of https://www.shadertoy.com/view/3sySRK + +// INFO: Change these variables to create some variation in the animation +#define BLACK_BLEND_THRESHOLD .4 // This is controls the dim of the screen +#define COLOR_SPEED 0.1 // This controls the speed at which the colors change +#define MOVEMENT_SPEED 0.1 // This controls the speed at which the balls move + +float opSmoothUnion( float d1, float d2, float k ) +{ + float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 ); + return mix( d2, d1, h ) - k*h*(1.0-h); +} + +float sdSphere( vec3 p, float s ) +{ + return length(p)-s; +} + +float map(vec3 p) +{ + float d = 2.0; + for (int i = 0; i < 16; i++) { + float fi = float(i); + float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0; + d = opSmoothUnion( + sdSphere(p + sin(time*MOVEMENT_SPEED + fi * vec3(52.5126, 64.62744, 632.25)) * vec3(2.0, 2.0, 0.8), mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))), + d, + 0.4 + ); + } + return d; +} + +vec3 calcNormal( in vec3 p ) +{ + const float h = 1e-5; // or some other value + const vec2 k = vec2(1,-1); + return normalize( k.xyy*map( p + k.xyy*h ) + + k.yyx*map( p + k.yyx*h ) + + k.yxy*map( p + k.yxy*h ) + + k.xxx*map( p + k.xxx*h ) ); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord/iResolution.xy; + + vec3 rayOri = vec3((uv - 0.5) * vec2(iResolution.x/iResolution.y, 1.0) * 6.0, 3.0); + vec3 rayDir = vec3(0.0, 0.0, -1.0); + + float depth = 0.0; + vec3 p; + + for(int i = 0; i < 64; i++) { + p = rayOri + rayDir * depth; + float dist = map(p); + depth += dist; + if (dist < 1e-6) { + break; + } + } + + depth = min(6.0, depth); + vec3 n = calcNormal(p); + float b = max(0.0, dot(n, vec3(0.577))); + vec3 col = (0.5 + 0.5 * cos((b + iTime*COLOR_SPEED * 3.0) + uv.xyx * 2.0 + vec3(0,2,4))) * (0.85 + b * 0.35); + col *= exp( -depth * 0.15 ); + + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); + +} + diff --git a/ghostty/shaders/crt.glsl b/ghostty/shaders/crt.glsl new file mode 100644 index 0000000..31d1bec --- /dev/null +++ b/ghostty/shaders/crt.glsl @@ -0,0 +1,310 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +//============================================================== +// +// [CRTS] PUBLIC DOMAIN CRT-STYLED SCALAR by Timothy Lottes +// +// [+] Adapted with alterations for use in Ghostty by Qwerasd. +// For more information on changes, see comment below license. +// +//============================================================== +// +// LICENSE = UNLICENSE (aka PUBLIC DOMAIN) +// +//-------------------------------------------------------------- +// This is free and unencumbered software released into the +// public domain. +//-------------------------------------------------------------- +// Anyone is free to copy, modify, publish, use, compile, sell, +// or distribute this software, either in source code form or as +// a compiled binary, for any purpose, commercial or +// non-commercial, and by any means. +//-------------------------------------------------------------- +// In jurisdictions that recognize copyright laws, the author or +// authors of this software dedicate any and all copyright +// interest in the software to the public domain. We make this +// dedication for the benefit of the public at large and to the +// detriment of our heirs and successors. We intend this +// dedication to be an overt act of relinquishment in perpetuity +// of all present and future rights to this software under +// copyright law. +//-------------------------------------------------------------- +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +//-------------------------------------------------------------- +// For more information, please refer to +// +//============================================================== + +// This shader is a modified version of the excellent +// FixingPixelArtFast by Timothy Lottes on Shadertoy. +// +// The original shader can be found at: +// https://www.shadertoy.com/view/MtSfRK +// +// Modifications have been made to reduce the verbosity, +// and many of the comments have been removed / reworded. +// Additionally, the license has been moved to the top of +// the file, and can be read above. I (Qwerasd) choose to +// release the modified version under the same license. + +// The appearance of this shader can be altered +// by adjusting the parameters defined below. + +// "Scanlines" per real screen pixel. +// e.g. SCALE 0.5 means each scanline is 2 pixels. +// Recommended values: +// o High DPI displays: 0.33333333 +// - Low DPI displays: 0.66666666 +#define SCALE 0.33333333 + +// "Tube" warp +#define CRTS_WARP 1 + +// Darkness of vignette in corners after warping +// 0.0 = completely black +// 1.0 = no vignetting +#define MIN_VIN 0.5 + +// Try different masks +// #define CRTS_MASK_GRILLE 1 +// #define CRTS_MASK_GRILLE_LITE 1 +// #define CRTS_MASK_NONE 1 +#define CRTS_MASK_SHADOW 1 + +// Scanline thinness +// 0.50 = fused scanlines +// 0.70 = recommended default +// 1.00 = thinner scanlines (too thin) +#define INPUT_THIN 0.75 + +// Horizonal scan blur +// -3.0 = pixely +// -2.5 = default +// -2.0 = smooth +// -1.0 = too blurry +#define INPUT_BLUR -2.75 + +// Shadow mask effect, ranges from, +// 0.25 = large amount of mask (not recommended, too dark) +// 0.50 = recommended default +// 1.00 = no shadow mask +#define INPUT_MASK 0.65 + +float FromSrgb1(float c) { + return (c <= 0.04045) ? c * (1.0 / 12.92) : + pow(c * (1.0 / 1.055) + (0.055 / 1.055), 2.4); +} +vec3 FromSrgb(vec3 c) { + return vec3( + FromSrgb1(c.r), FromSrgb1(c.g), FromSrgb1(c.b)); +} + +vec3 CrtsFetch(vec2 uv) { + return FromSrgb(texture(iChannel0, uv.xy).rgb); +} + +#define CrtsRcpF1(x) (1.0/(x)) +#define CrtsSatF1(x) clamp((x),0.0,1.0) + +float CrtsMax3F1(float a, float b, float c) { + return max(a, max(b, c)); +} + +vec2 CrtsTone( + float thin, + float mask) { + #ifdef CRTS_MASK_NONE + mask = 1.0; + #endif + + #ifdef CRTS_MASK_GRILLE_LITE + // Normal R mask is {1.0,mask,mask} + // LITE R mask is {mask,1.0,1.0} + mask = 0.5 + mask * 0.5; + #endif + + vec2 ret; + float midOut = 0.18 / ((1.5 - thin) * (0.5 * mask + 0.5)); + float pMidIn = 0.18; + ret.x = ((-pMidIn) + midOut) / ((1.0 - pMidIn) * midOut); + ret.y = ((-pMidIn) * midOut + pMidIn) / (midOut * (-pMidIn) + midOut); + + return ret; +} + +vec3 CrtsMask(vec2 pos, float dark) { + #ifdef CRTS_MASK_GRILLE + vec3 m = vec3(dark, dark, dark); + float x = fract(pos.x * (1.0 / 3.0)); + if (x < (1.0 / 3.0)) m.r = 1.0; + else if (x < (2.0 / 3.0)) m.g = 1.0; + else m.b = 1.0; + return m; + #endif + + #ifdef CRTS_MASK_GRILLE_LITE + vec3 m = vec3(1.0, 1.0, 1.0); + float x = fract(pos.x * (1.0 / 3.0)); + if (x < (1.0 / 3.0)) m.r = dark; + else if (x < (2.0 / 3.0)) m.g = dark; + else m.b = dark; + return m; + #endif + + #ifdef CRTS_MASK_NONE + return vec3(1.0, 1.0, 1.0); + #endif + + #ifdef CRTS_MASK_SHADOW + pos.x += pos.y * 3.0; + vec3 m = vec3(dark, dark, dark); + float x = fract(pos.x * (1.0 / 6.0)); + if (x < (1.0 / 3.0)) m.r = 1.0; + else if (x < (2.0 / 3.0)) m.g = 1.0; + else m.b = 1.0; + return m; + #endif +} + +vec3 CrtsFilter( + vec2 ipos, + vec2 inputSizeDivOutputSize, + vec2 halfInputSize, + vec2 rcpInputSize, + vec2 rcpOutputSize, + vec2 twoDivOutputSize, + float inputHeight, + vec2 warp, + float thin, + float blur, + float mask, + vec2 tone +) { + // Optional apply warp + vec2 pos; + #ifdef CRTS_WARP + // Convert to {-1 to 1} range + pos = ipos * twoDivOutputSize - vec2(1.0, 1.0); + + // Distort pushes image outside {-1 to 1} range + pos *= vec2( + 1.0 + (pos.y * pos.y) * warp.x, + 1.0 + (pos.x * pos.x) * warp.y); + + // TODO: Vignette needs optimization + float vin = 1.0 - ( + (1.0 - CrtsSatF1(pos.x * pos.x)) * (1.0 - CrtsSatF1(pos.y * pos.y))); + vin = CrtsSatF1((-vin) * inputHeight + inputHeight); + + // Leave in {0 to inputSize} + pos = pos * halfInputSize + halfInputSize; + #else + pos = ipos * inputSizeDivOutputSize; + #endif + + // Snap to center of first scanline + float y0 = floor(pos.y - 0.5) + 0.5; + // Snap to center of one of four pixels + float x0 = floor(pos.x - 1.5) + 0.5; + + // Inital UV position + vec2 p = vec2(x0 * rcpInputSize.x, y0 * rcpInputSize.y); + // Fetch 4 nearest texels from 2 nearest scanlines + vec3 colA0 = CrtsFetch(p); + p.x += rcpInputSize.x; + vec3 colA1 = CrtsFetch(p); + p.x += rcpInputSize.x; + vec3 colA2 = CrtsFetch(p); + p.x += rcpInputSize.x; + vec3 colA3 = CrtsFetch(p); + p.y += rcpInputSize.y; + vec3 colB3 = CrtsFetch(p); + p.x -= rcpInputSize.x; + vec3 colB2 = CrtsFetch(p); + p.x -= rcpInputSize.x; + vec3 colB1 = CrtsFetch(p); + p.x -= rcpInputSize.x; + vec3 colB0 = CrtsFetch(p); + + // Vertical filter + // Scanline intensity is using sine wave + // Easy filter window and integral used later in exposure + float off = pos.y - y0; + float pi2 = 6.28318530717958; + float hlf = 0.5; + float scanA = cos(min(0.5, off * thin) * pi2) * hlf + hlf; + float scanB = cos(min(0.5, (-off) * thin + thin) * pi2) * hlf + hlf; + + // Horizontal kernel is simple gaussian filter + float off0 = pos.x - x0; + float off1 = off0 - 1.0; + float off2 = off0 - 2.0; + float off3 = off0 - 3.0; + float pix0 = exp2(blur * off0 * off0); + float pix1 = exp2(blur * off1 * off1); + float pix2 = exp2(blur * off2 * off2); + float pix3 = exp2(blur * off3 * off3); + float pixT = CrtsRcpF1(pix0 + pix1 + pix2 + pix3); + + #ifdef CRTS_WARP + // Get rid of wrong pixels on edge + pixT *= max(MIN_VIN, vin); + #endif + + scanA *= pixT; + scanB *= pixT; + + // Apply horizontal and vertical filters + vec3 color = + (colA0 * pix0 + colA1 * pix1 + colA2 * pix2 + colA3 * pix3) * scanA + + (colB0 * pix0 + colB1 * pix1 + colB2 * pix2 + colB3 * pix3) * scanB; + + // Apply phosphor mask + color *= CrtsMask(ipos, mask); + + // Tonal control, start by protecting from /0 + float peak = max(1.0 / (256.0 * 65536.0), + CrtsMax3F1(color.r, color.g, color.b)); + // Compute the ratios of {R,G,B} + vec3 ratio = color * CrtsRcpF1(peak); + // Apply tonal curve to peak value + peak = peak * CrtsRcpF1(peak * tone.x + tone.y); + // Reconstruct color + return ratio * peak; +} + +float ToSrgb1(float c) { + return (c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 0.41666) - 0.055); +} +vec3 ToSrgb(vec3 c) { + return vec3( + ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b)); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + float aspect = iResolution.x / iResolution.y; + fragColor.rgb = CrtsFilter( + fragCoord.xy, + vec2(1.0), + iResolution.xy * SCALE * 0.5, + 1.0 / (iResolution.xy * SCALE), + 1.0 / iResolution.xy, + 2.0 / iResolution.xy, + iResolution.y, + vec2(1.0 / (50.0 * aspect), 1.0 / 50.0), + INPUT_THIN, + INPUT_BLUR, + INPUT_MASK, + CrtsTone(INPUT_THIN, INPUT_MASK) + ); + + // Linear to SRGB for output. + fragColor.rgb = ToSrgb(fragColor.rgb); +} \ No newline at end of file diff --git a/ghostty/shaders/cubes.glsl b/ghostty/shaders/cubes.glsl new file mode 100644 index 0000000..2a09505 --- /dev/null +++ b/ghostty/shaders/cubes.glsl @@ -0,0 +1,114 @@ +// credits: https://github.com/rymdlego + +const float speed = 0.2; +const float cube_size = 1.0; +const float cube_brightness = 1.0; +const float cube_rotation_speed = 2.8; +const float camera_rotation_speed = 0.1; + + + +mat3 rotationMatrix(vec3 m,float a) { + m = normalize(m); + float c = cos(a),s=sin(a); + return mat3(c+(1.-c)*m.x*m.x, + (1.-c)*m.x*m.y-s*m.z, + (1.-c)*m.x*m.z+s*m.y, + (1.-c)*m.x*m.y+s*m.z, + c+(1.-c)*m.y*m.y, + (1.-c)*m.y*m.z-s*m.x, + (1.-c)*m.x*m.z-s*m.y, + (1.-c)*m.y*m.z+s*m.x, + c+(1.-c)*m.z*m.z); +} + +float sphere(vec3 pos, float radius) +{ + return length(pos) - radius; +} + +float box(vec3 pos, vec3 size) +{ + float t = iTime; + pos = pos * 0.9 * rotationMatrix(vec3(sin(t/4.0*speed)*10.,cos(t/4.0*speed)*12.,2.7), t*2.4/4.0*speed*cube_rotation_speed); + return length(max(abs(pos) - size, 0.0)); +} + + +float distfunc(vec3 pos) +{ + float t = iTime; + + float size = 0.45 + 0.25*abs(16.0*sin(t*speed/4.0)); + // float size = 2.3 + 1.8*tan((t-5.4)*6.549); + size = cube_size * 0.16 * clamp(size, 2.0, 4.0); + + //pos = pos * rotationMatrix(vec3(0.,-3.,0.7), 3.3 * mod(t/30.0, 4.0)); + vec3 q = mod(pos, 5.0) - 2.5; + float obj1 = box(q, vec3(size)); + return obj1; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + float t = iTime; + vec2 screenPos = -1.0 + 2.0 * fragCoord.xy / iResolution.xy; + screenPos.x *= iResolution.x / iResolution.y; + vec3 cameraOrigin = vec3(t*1.0*speed, 0.0, 0.0); + // vec3 cameraOrigin = vec3(t*1.8*speed, 3.0+t*0.02*speed, 0.0); + vec3 cameraTarget = vec3(t*100., 0.0, 0.0); + cameraTarget = vec3(t*20.0,0.0,0.0) * rotationMatrix(vec3(0.0,0.0,1.0), t*speed*camera_rotation_speed); + + vec3 upDirection = vec3(0.5, 1.0, 0.6); + + vec3 cameraDir = normalize(cameraTarget - cameraOrigin); + vec3 cameraRight = normalize(cross(upDirection, cameraOrigin)); + vec3 cameraUp = cross(cameraDir, cameraRight); + + vec3 rayDir = normalize(cameraRight * screenPos.x + cameraUp * screenPos.y + cameraDir); + + const int MAX_ITER = 64; + const float MAX_DIST = 48.0; + const float EPSILON = 0.001; + + float totalDist = 0.0; + vec3 pos = cameraOrigin; + float dist = EPSILON; + + for (int i = 0; i < MAX_ITER; i++) + { + if (dist < EPSILON || totalDist > MAX_DIST) + break; + dist = distfunc(pos); + totalDist += dist; + pos += dist*rayDir; + } + + vec4 cubes; + + if (dist < EPSILON) + { + // Lighting Code + vec2 eps = vec2(0.0, EPSILON); + vec3 normal = normalize(vec3( + distfunc(pos + eps.yxx) - distfunc(pos - eps.yxx), + distfunc(pos + eps.xyx) - distfunc(pos - eps.xyx), + distfunc(pos + eps.xxy) - distfunc(pos - eps.xxy))); + float diffuse = max(0., dot(-rayDir, normal)); + float specular = pow(diffuse, 32.0); + vec3 color = vec3(diffuse + specular); + vec3 cubeColor = vec3(abs(screenPos),0.5+0.5*sin(t*2.0))*0.8; + cubeColor = mix(cubeColor.rgb, vec3(0.0,0.0,0.0), 1.0); + color += cubeColor; + cubes = vec4(color, 1.0) * vec4(1.0 - (totalDist/MAX_DIST)); + cubes = vec4(cubes.rgb*0.02*cube_brightness, 0.1); + } + else { + cubes = vec4(0.0); + } + + vec2 uv = fragCoord/iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + vec3 blendedColor = terminalColor.rgb + cubes.rgb; + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/dither.glsl b/ghostty/shaders/dither.glsl new file mode 100644 index 0000000..7bfe740 --- /dev/null +++ b/ghostty/shaders/dither.glsl @@ -0,0 +1,30 @@ +// Simple "dithering" effect +// (c) moni-dz (https://github.com/moni-dz) +// CC BY-NC-SA 4.0 (https://creativecommons.org/licenses/by-nc-sa/4.0/) + +// Packed bayer pattern using bit manipulation +const float bayerPattern[4] = float[4]( + 0x0514, // Encoding 0,8,2,10 + 0xC4E6, // Encoding 12,4,14,6 + 0x3B19, // Encoding 3,11,1,9 + 0xF7D5 // Encoding 15,7,13,5 +); + +float getBayerFromPacked(int x, int y) { + int idx = (x & 3) + ((y & 3) << 2); + return float((int(bayerPattern[y & 3]) >> ((x & 3) << 2)) & 0xF) * (1.0 / 16.0); +} + +#define LEVELS 2.0 // Available color steps per channel +#define INV_LEVELS (1.0 / LEVELS) + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord * (1.0 / iResolution.xy); + vec3 color = texture(iChannel0, uv).rgb; + + float threshold = getBayerFromPacked(int(fragCoord.x), int(fragCoord.y)); + vec3 dithered = floor(color * LEVELS + threshold) * INV_LEVELS; + + fragColor = vec4(dithered, 1.0); +} diff --git a/ghostty/shaders/drunkard.glsl b/ghostty/shaders/drunkard.glsl new file mode 100644 index 0000000..e900d4a --- /dev/null +++ b/ghostty/shaders/drunkard.glsl @@ -0,0 +1,68 @@ +// Drunken stupor effect using fractal Brownian motion and Perlin noise +// (c) moni-dz (https://github.com/moni-dz) +// CC BY-NC-SA 4.0 (https://creativecommons.org/licenses/by-nc-sa/4.0/) + +vec2 hash2(vec2 p) { + uvec2 q = uvec2(floatBitsToUint(p.x), floatBitsToUint(p.y)); + q = (q * uvec2(1597334673U, 3812015801U)) ^ (q.yx * uvec2(2798796415U, 1979697793U)); + return vec2(q) * (1.0/float(0xffffffffU)) * 2.0 - 1.0; +} + +float perlin2d(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + vec2 u = f*f*(3.0-2.0*f); + + return mix(mix(dot(hash2(i + vec2(0.0,0.0)), f - vec2(0.0,0.0)), + dot(hash2(i + vec2(1.0,0.0)), f - vec2(1.0,0.0)), u.x), + mix(dot(hash2(i + vec2(0.0,1.0)), f - vec2(0.0,1.0)), + dot(hash2(i + vec2(1.0,1.0)), f - vec2(1.0,1.0)), u.x), u.y); +} + +#define OCTAVES 10 // How many passes of fractal Brownian motion to perform +#define GAIN 0.5 // How much should each pixel move +#define LACUNARITY 2.0 // How fast should each ripple be per pass + +float fbm(vec2 p) { + float sum = 0.0; + float amp = 0.5; + float freq = 1.0; + + for(int i = 0; i < OCTAVES; i++) { + sum += amp * perlin2d(p * freq); + freq *= LACUNARITY; + amp *= GAIN; + } + + return sum; +} + + +#define NOISE_SCALE 1.0 // How distorted the image you want to be +#define NOISE_INTENSITY 0.05 // How strong the noise effect is +#define ABERRATION true // Chromatic aberration +#define ABERRATION_DELTA 0.1 // How strong the chromatic aberration effect is +#define ANIMATE true +#define SPEED 0.4 // Animation speed + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord/iResolution.xy; + float time = ANIMATE ? iTime * SPEED : 0.0; + + vec2 noisePos = uv * NOISE_SCALE + vec2(time); + float noise = fbm(noisePos) * NOISE_INTENSITY; + + vec3 col; + + if (ABERRATION) { + col.r = texture(iChannel0, uv + vec2(noise * (1.0 + ABERRATION_DELTA))).r; + col.g = texture(iChannel0, uv + vec2(noise)).g; + col.b = texture(iChannel0, uv + vec2(noise * (1.0 - ABERRATION_DELTA))).b; + } else { + vec2 distortedUV = uv + vec2(noise); + col = texture(iChannel0, distortedUV).rgb; + } + + fragColor = vec4(col, 1.0); +} diff --git a/ghostty/shaders/fireworks-rockets.glsl b/ghostty/shaders/fireworks-rockets.glsl new file mode 100644 index 0000000..e2f0b5a --- /dev/null +++ b/ghostty/shaders/fireworks-rockets.glsl @@ -0,0 +1,109 @@ +// This Ghostty shader is a lightly modified port of https://www.shadertoy.com/view/4dBGRw + +#define BLACK_BLEND_THRESHOLD .4 + +//Creates a diagonal red-and-white striped pattern. +vec3 barberpole(vec2 pos, vec2 rocketpos) { + float d = (pos.x - rocketpos.x) + (pos.y - rocketpos.y); + vec3 col = vec3(1.0); + + d = mod(d * 20., 2.0); + if (d > 1.0) { + col = vec3(1.0, 0.0, 0.0); + } + + return col; +} + +vec3 rocket(vec2 pos, vec2 rocketpos) { + vec3 col = vec3(0.0); + float f = 0.; + float absx = abs(rocketpos.x - pos.x); + float absy = abs(rocketpos.y - pos.y); + + // Wooden stick + if (absx < 0.01 && absy < 0.22) { + col = vec3(1.0, 0.5, 0.5); + } + + // Barberpole + if (absx < 0.05 && absy < 0.15) { + col = barberpole(pos, rocketpos); + } + + // Rocket Point + float pointw = (rocketpos.y - pos.y - 0.25) * -0.7; + if ((rocketpos.y - pos.y) > 0.1) { + f = smoothstep(pointw - 0.001, pointw + 0.001, absx); + + col = mix(vec3(1.0, 0.0, 0.0), col, f); + } + + // Shadow + f = -.5 + smoothstep(-0.05, 0.05, (rocketpos.x - pos.x)); + col *= 0.7 + f; + + return col; +} + +float rand(float val, float seed) { + return cos(val * sin(val * seed) * seed); +} + +float distance2(in vec2 a, in vec2 b) { + return dot(a - b, a - b); +} + +mat2 rr = mat2(cos(1.0), -sin(1.0), sin(1.0), cos(1.0)); + +vec3 drawParticles(vec2 pos, vec3 particolor, float time, vec2 cpos, float gravity, float seed, float timelength) { + vec3 col = vec3(0.0); + vec2 pp = vec2(1.0, 0.0); + for (float i = 1.0; i <= 128.0; i++) { + float d = rand(i, seed); + float fade = (i / 128.0) * time; + vec2 particpos = cpos + time * pp * d; + pp = rr * pp; + col = mix(particolor / fade, col, smoothstep(0.0, 0.0001, distance2(particpos, pos))); + } + col *= smoothstep(0.0, 1.0, (timelength - time) / timelength); + + return col; +} +vec3 drawFireworks(float time, vec2 uv, vec3 particolor, float seed) { + float timeoffset = 2.0; + vec3 col = vec3(0.0); + if (time <= 0.) { + return col; + } + if (mod(time, 6.0) > timeoffset) { + col = drawParticles(uv, particolor, mod(time, 6.0) - timeoffset, vec2(rand(ceil(time / 6.0), seed), -0.5), 0.5, ceil(time / 6.0), seed); + } else { + col = rocket(uv * 3., vec2(3. * rand(ceil(time / 6.0), seed), 3. * (-0.5 + (timeoffset - mod(time, 6.0))))); + } + return col; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = 1.0 - 2.0 * fragCoord.xy / iResolution.xy; + uv.x *= iResolution.x / iResolution.y; + vec3 col = vec3(0.1, 0.1, 0.2); + + // Flip the y-axis so that the rocket is drawn from the bottom of the screen + uv.y = -uv.y; + + col += 0.1 * uv.y; + + col += drawFireworks(iTime, uv, vec3(1.0, 0.1, 0.1), 1.); + col += drawFireworks(iTime - 2.0, uv, vec3(0.0, 1.0, 0.5), 2.); + col += drawFireworks(iTime - 4.0, uv, vec3(1.0, 1.0, 0.1), 3.); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/fireworks.glsl b/ghostty/shaders/fireworks.glsl new file mode 100644 index 0000000..42bc98d --- /dev/null +++ b/ghostty/shaders/fireworks.glsl @@ -0,0 +1,116 @@ +// This Ghostty shader is a port of https://www.shadertoy.com/view/lscGRl + +// "Fireworks" by Martijn Steinrucken aka BigWings - 2015 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +// Email:countfrolic@gmail.com Twitter:@The_ArtOfCode + +#define BLACK_BLEND_THRESHOLD .4 +#define PI 3.141592653589793238 +#define TWOPI 6.283185307179586 +#define S(x,y,z) smoothstep(x,y,z) +#define B(x,y,z,w) S(x-z, x+z, w)*S(y+z, y-z, w) +#define saturate(x) clamp(x,0.,1.) + +#define NUM_EXPLOSIONS 3. +#define NUM_PARTICLES 42. + +// Noise functions by Dave Hoskins +#define MOD3 vec3(.1031,.11369,.13787) +vec3 hash31(float p) { + vec3 p3 = fract(vec3(p) * MOD3); + p3 += dot(p3, p3.yzx + 19.19); + return fract(vec3((p3.x + p3.y) * p3.z, (p3.x + p3.z) * p3.y, (p3.y + p3.z) * p3.x)); +} +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * MOD3); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); +} + +float circ(vec2 uv, vec2 pos, float size) { + uv -= pos; + + size *= size; + return S(size * 1.1, size, dot(uv, uv)); +} + +float light(vec2 uv, vec2 pos, float size) { + uv -= pos; + + size *= size; + return size / dot(uv, uv); +} + +vec3 explosion(vec2 uv, vec2 p, float seed, float t) { + vec3 col = vec3(0.); + + vec3 en = hash31(seed); + vec3 baseCol = en; + for (float i = 0.; i < NUM_PARTICLES; i++) { + vec3 n = hash31(i) - .5; + + vec2 startP = p - vec2(0., t * t * .1); + vec2 endP = startP + normalize(n.xy) * n.z - vec2(0., t * .2); + + float pt = 1. - pow(t - 1., 2.); + vec2 pos = mix(p, endP, pt); + float size = mix(.01, .005, S(0., .1, pt)); + size *= S(1., .1, pt); + + float sparkle = (sin((pt + n.z) * 21.) * .5 + .5); + sparkle = pow(sparkle, pow(en.x, 3.) * 50.) * mix(0.01, .01, en.y * n.y); + + //size += sparkle*B(.6, 1., .1, t); + size += sparkle * B(en.x, en.y, en.z, t); + + col += baseCol * light(uv, pos, size); + } + + return col; +} + +vec3 Rainbow(vec3 c) { + float t = iTime; + + float avg = (c.r + c.g + c.b) / 3.; + c = avg + (c - avg) * sin(vec3(0., .333, .666) + t); + + c += sin(vec3(.4, .3, .3) * t + vec3(1.1244, 3.43215, 6.435)) * vec3(.4, .1, .5); + + return c; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + uv.x -= .5; + uv.x *= iResolution.x / iResolution.y; + + // Flip the y-axis so that the gravity is downwards + uv.y = -uv.y + 1.; + + float n = hash12(uv + 10.); + float t = iTime * .5; + + vec3 c = vec3(0.); + + for (float i = 0.; i < NUM_EXPLOSIONS; i++) { + float et = t + i * 1234.45235; + float id = floor(et); + et -= id; + + vec2 p = hash31(id).xy; + p.x -= .5; + p.x *= 1.6; + c += explosion(uv, p, id, et); + } + c = Rainbow(c); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, c.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/galaxy.glsl b/ghostty/shaders/galaxy.glsl new file mode 100644 index 0000000..8a7eda9 --- /dev/null +++ b/ghostty/shaders/galaxy.glsl @@ -0,0 +1,139 @@ +float triangle(float x, float period) { + return 2.0 * abs(3.0* ((x / period) - floor((x / period) + 0.5))) - 1.0; +} + +float field(in vec3 position) { + float strength = 7.0 + 0.03 * log(1.0e-6 + fract(sin(iTime) * 373.11)); + float accumulated = 0.0; + float previousMagnitude = 0.0; + float totalWeight = 0.0; + + for (int i = 0; i < 6; ++i) { + float magnitude = dot(position, position); + position = abs(position) / magnitude + vec3(-0.5, -0.8 + 0.1 * sin(-iTime * 0.1 + 2.0), -1.1 + 0.3 * cos(iTime * 0.3)); + float weight = exp(-float(i) / 7.0); + accumulated += weight * exp(-strength * pow(abs(magnitude - previousMagnitude), 2.3)); + totalWeight += weight; + previousMagnitude = magnitude; + } + + return max(0.0, 5.0 * accumulated / totalWeight - 0.7); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + const float baseSpeed = 0.02; + const int maxIterations = 16; + const float formulaParameter = 0.79; + const float volumeSteps = 7.0; + const float stepSize = 0.24; + const float zoomFactor = 0.1; + const float tilingFactor = 0.85; + const float baseBrightness = 0.0008; + const float darkMatter = 0.2; + const float distanceFading = 0.56; + const float colorSaturation = 0.9; + const float transverseMotion = 0.2; + const float cloudOpacity = 0.48; + const float zoomSpeed = 0.0002; + + vec2 normalizedCoordinates = 2.0 * fragCoord.xy / vec2(512) - 1.0; + vec2 scaledCoordinates = normalizedCoordinates * vec2(512) / 512.0; + + float timeElapsed = iTime; + float speedAdjustment = -baseSpeed; + float formulaAdjustment = formulaParameter; + + speedAdjustment = zoomSpeed * cos(iTime * 0.02 + 3.1415926 / 4.0); + + vec2 uvCoordinates = scaledCoordinates; + + float rotationXZ = 0.9; + float rotationYZ = -0.6; + float rotationXY = 0.9 + iTime * 0.08; + + mat2 rotationMatrixXZ = mat2(vec2(cos(rotationXZ), sin(rotationXZ)), vec2(-sin(rotationXZ), cos(rotationXZ))); + mat2 rotationMatrixYZ = mat2(vec2(cos(rotationYZ), sin(rotationYZ)), vec2(-sin(rotationYZ), cos(rotationYZ))); + mat2 rotationMatrixXY = mat2(vec2(cos(rotationXY), sin(rotationXY)), vec2(-sin(rotationXY), cos(rotationXY))); + + vec2 canvasCenter = vec2(0.5, 0.5); + vec3 rayDirection = vec3(uvCoordinates * zoomFactor, 1.0); + vec3 cameraPosition = vec3(0.0, 0.0, 0.0); + cameraPosition.x -= 2.0 * (canvasCenter.x - 0.5); + cameraPosition.y -= 2.0 * (canvasCenter.y - 0.5); + + vec3 forwardVector = vec3(0.0, 0.0, 1.0); + cameraPosition.x += transverseMotion * cos(0.01 * iTime) + 0.001 * iTime; + cameraPosition.y += transverseMotion * sin(0.01 * iTime) + 0.001 * iTime; + cameraPosition.z += 0.003 * iTime; + + rayDirection.xz *= rotationMatrixXZ; + forwardVector.xz *= rotationMatrixXZ; + rayDirection.yz *= rotationMatrixYZ; + forwardVector.yz *= rotationMatrixYZ; + + cameraPosition.xy *= -1.0 * rotationMatrixXY; + cameraPosition.xz *= rotationMatrixXZ; + cameraPosition.yz *= rotationMatrixYZ; + + float zoomOffset = (timeElapsed - 3311.0) * speedAdjustment; + cameraPosition += forwardVector * zoomOffset; + float sampleOffset = mod(zoomOffset, stepSize); + float normalizedSampleOffset = sampleOffset / stepSize; + + float stepDistance = 0.24; + float secondaryStepDistance = stepDistance + stepSize / 2.0; + vec3 accumulatedColor = vec3(0.0); + float fieldContribution = 0.0; + vec3 backgroundColor = vec3(0.0); + + for (float stepIndex = 0.0; stepIndex < volumeSteps; ++stepIndex) { + vec3 primaryPosition = cameraPosition + (stepDistance + sampleOffset) * rayDirection; + vec3 secondaryPosition = cameraPosition + (secondaryStepDistance + sampleOffset) * rayDirection; + + primaryPosition = abs(vec3(tilingFactor) - mod(primaryPosition, vec3(tilingFactor * 2.0))); + secondaryPosition = abs(vec3(tilingFactor) - mod(secondaryPosition, vec3(tilingFactor * 2.0))); + + fieldContribution = field(secondaryPosition); + + float particleAccumulator = 0.0, particleDistance = 0.0; + for (int i = 0; i < maxIterations; ++i) { + primaryPosition = abs(primaryPosition) / dot(primaryPosition, primaryPosition) - formulaAdjustment; + float distanceChange = abs(length(primaryPosition) - particleDistance); + particleAccumulator += i > 2 ? min(12.0, distanceChange) : distanceChange; + particleDistance = length(primaryPosition); + } + particleAccumulator *= particleAccumulator * particleAccumulator; + + float fadeFactor = pow(distanceFading, max(0.0, float(stepIndex) - normalizedSampleOffset)); + accumulatedColor += vec3(stepDistance, stepDistance * stepDistance, stepDistance * stepDistance * stepDistance * stepDistance) + * particleAccumulator * baseBrightness * fadeFactor; + backgroundColor += mix(0.4, 1.0, cloudOpacity) * vec3(1.8 * fieldContribution * fieldContribution * fieldContribution, + 1.4 * fieldContribution * fieldContribution, fieldContribution) * fadeFactor; + stepDistance += stepSize; + secondaryStepDistance += stepSize; + } + + accumulatedColor = mix(vec3(length(accumulatedColor)), accumulatedColor, colorSaturation); + + vec4 foregroundColor = vec4(accumulatedColor * 0.01, 1.0); + backgroundColor *= cloudOpacity; + backgroundColor.b *= 1.8; + backgroundColor.r *= 0.05; + + backgroundColor.b = 0.5 * mix(backgroundColor.g, backgroundColor.b, 0.8); + backgroundColor.g = 0.0; + backgroundColor.bg = mix(backgroundColor.gb, backgroundColor.bg, 0.5 * (cos(iTime * 0.01) + 1.0)); + + vec2 terminalUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, terminalUV); + + float brightnessThreshold = 0.1; + float terminalBrightness = dot(terminalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); + + if (terminalBrightness < brightnessThreshold) { + fragColor = mix(terminalColor, vec4(foregroundColor.rgb + backgroundColor, 1.0), 0.24); + } else { + fragColor = terminalColor; + } +} + diff --git a/ghostty/shaders/gears-and-belts.glsl b/ghostty/shaders/gears-and-belts.glsl new file mode 100644 index 0000000..9976b34 --- /dev/null +++ b/ghostty/shaders/gears-and-belts.glsl @@ -0,0 +1,377 @@ +// sligltly modified version of https://www.shadertoy.com/view/DsVSDV +// The only changes are done in the mainImage function +// Ive added comments on what to modify +// works really well with most colorschemes + +#define Rot(a) mat2(cos(a),-sin(a),sin(a),cos(a)) +#define antialiasing(n) n/min(iResolution.y,iResolution.x) +#define S(d,b) smoothstep(antialiasing(3.0),b,d) +#define B(p,s) max(abs(p).x-s.x,abs(p).y-s.y) +#define deg45 .707 +#define R45(p) (( p + vec2(p.y,-p.x) ) *deg45) +#define Tri(p,s) max(R45(p).x,max(R45(p).y,B(p,s))) +#define DF(a,b) length(a) * cos( mod( atan(a.y,a.x)+6.28/(b*8.0), 6.28/((b*8.0)*0.5))+(b-1.)*6.28/(b*8.0) + vec2(0,11) ) + +float random (vec2 p) { + return fract(sin(dot(p.xy, vec2(12.9898,78.233)))* 43758.5453123); +} + +float innerGear(vec2 p, float dir){ + p*=Rot(radians(-iTime*45.+45.)*dir); + vec2 prevP = p; + + //p*=Rot(radians(iTime*45.+20.)); + p = DF(p,7.); + p-=vec2(0.24); + p*=Rot(deg45); + float d = B(p,vec2(0.01,0.06)); + p = prevP; + float d2 = abs(length(p)-0.42)-0.02; + d = min(d,d2); + d2 = abs(length(p)-0.578)-0.02; + d = min(d,d2); + d2 = abs(length(p)-0.499)-0.005; + d = min(d,d2); + + p = DF(p,7.); + p-=vec2(0.43); + p*=Rot(deg45); + d2 = B(p,vec2(0.01,0.04)); + d = min(d,d2); + + return d; +} + +vec3 pattern1(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + float size = 0.499; + float thick = 0.15; + + p+=vec2(size); + float d = abs(length(p)-size)-thick; + d = max(d,innerGear(p,dir)); + col = mix(col,vec3(1.),S(d,0.0)); + + p = prevP; + p-=vec2(size); + d = abs(length(p)-size)-thick; + d = max(d,innerGear(p,dir)); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 pattern2(vec2 p, vec3 col, float dir){ + + vec2 prevP = p; + float size = 0.33; + float thick = 0.15; + float thift = 0.0; + float speed = 0.3; + + p-=vec2(size,0.); + float d = B(p,vec2(size,thick)); + + p.x+=thift; + p.x-=iTime*speed*dir; + p.x=mod(p.x,0.08)-0.04; + d = max(d,B(p,vec2(0.011,thick))); + p = prevP; + d = max(-(abs(p.y)-0.1),d); + //d = min(B(p,vec2(1.,0.1)),d); + p.y=abs(p.y)-0.079; + d = min(B(p,vec2(1.,0.02)),d); + + p = prevP; + p-=vec2(0.0,size); + float d2 = B(p,vec2(thick,size)); + + p.y+=thift; + p.y+=iTime*speed*dir; + p.y=mod(p.y,0.08)-0.04; + d2 = max(d2,B(p,vec2(thick,0.011))); + + p = prevP; + d2 = max(-(abs(p.x)-0.1),d2); + d2 = min(B(p,vec2(0.005,1.)),d2); + p.x=abs(p.x)-0.079; + d2 = min(B(p,vec2(0.02,1.)),d2); + + d = min(d,d2); + + p = prevP; + p+=vec2(0.0,size); + d2 = B(p,vec2(thick,size)); + + p.y+=thift; + p.y-=iTime*speed*dir; + p.y=mod(p.y,0.08)-0.04; + d2 = max(d2,B(p,vec2(thick,0.011))); + + p = prevP; + d2 = max(-(abs(p.x)-0.1),d2); + d2 = min(B(p,vec2(0.005,1.)),d2); + p.x=abs(p.x)-0.079; + d2 = min(B(p,vec2(0.02,1.)),d2); + + d = min(d,d2); + + p = prevP; + p+=vec2(size,0.0); + d2 = B(p,vec2(size,thick)); + + p.x+=thift; + p.x+=iTime*speed*dir; + p.x=mod(p.x,0.08)-0.04; + d2 = max(d2,B(p,vec2(0.011,thick))); + d = min(d,d2); + p = prevP; + d = max(-(abs(p.y)-0.1),d); + d = min(B(p,vec2(1.,0.005)),d); + p.y=abs(p.y)-0.079; + d = min(B(p,vec2(1.,0.02)),d); + + p = prevP; + d2 = abs(B(p,vec2(size*0.3)))-0.05; + d = min(d,d2); + + col = mix(col,vec3(1.),S(d,0.0)); + + d = B(p,vec2(0.08)); + col = mix(col,vec3(0.),S(d,0.0)); + + p*=Rot(radians(60.*iTime*dir)); + d = B(p,vec2(0.03)); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 drawBelt(vec2 p, vec3 col, float size){ + vec2 prevP = p; + + p*=size; + vec2 id = floor(p); + vec2 gr = fract(p)-0.5; + float dir = mod(id.x+id.y,2.)*2.-1.; + float n = random(id); + + if(n<0.5){ + if(n<0.25){ + gr.x*=-1.; + } + col = pattern1(gr,col,dir); + } else { + if(n>0.75){ + gr.x*=-1.; + } + col = pattern2(gr,col,dir); + } + + return col; +} + +vec3 gear(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + + p*=Rot(radians(iTime*45.+13.)*-dir); + p = DF(p,7.); + p-=vec2(0.23); + p*=Rot(deg45); + float d = B(p,vec2(0.01,0.04)); + p = prevP; + float d2 = abs(length(p)-0.29)-0.02; + d = min(d,d2); + col = mix(col,vec3(1.),S(d,0.0)); + + p*=Rot(radians(iTime*30.-30.)*dir); + p = DF(p,6.); + p-=vec2(0.14); + p*=Rot(radians(45.)); + d = B(p,vec2(0.01,0.03)); + p = prevP; + d2 =abs( length(p)-0.1)-0.02; + p*=Rot(radians(iTime*25.+30.)*-dir); + d2 = max(-(abs(p.x)-0.05),d2); + d = min(d,d2); + col = mix(col,vec3(1.),S(d,0.0)); + + return col; +} + +vec3 item0(vec2 p, vec3 col, float dir){ + vec2 prevP = p; + p.x*=dir; + p*=Rot(radians(iTime*30.+30.)); + float d = abs(length(p)-0.2)-0.05; + col = mix(col,vec3(0.3),S(d,0.0)); + + d = abs(length(p)-0.2)-0.05; + d = max(-p.x,d); + float a = clamp(atan(p.x,p.y)*0.5,0.3,1.); + + col = mix(col,vec3(a),S(d,0.0)); + + return col; +} + + +vec3 item1(vec2 p, vec3 col, float dir){ + p.x*=dir; + vec2 prevP = p; + p*=Rot(radians(iTime*30.+30.)); + float d = abs(length(p)-0.25)-0.04; + d = abs(max((abs(p.y)-0.15),d))-0.005; + float d2 = abs(length(p)-0.25)-0.01; + d2 = max((abs(p.y)-0.12),d2); + d = min(d,d2); + + d2 = abs(length(p)-0.27)-0.01; + d2 = max(-(abs(p.y)-0.22),d2); + d = min(d,d2); + d2 = B(p,vec2(0.01,0.32)); + d2 = max(-(abs(p.y)-0.22),d2); + d = min(d,d2); + + p = prevP; + p*=Rot(radians(iTime*-20.+30.)); + p = DF(p,2.); + p-=vec2(0.105); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.03,0.01)); + d = min(d,d2); + + p = prevP; + d2 = abs(length(p)-0.09)-0.005; + d2 = max(-(abs(p.x)-0.03),d2); + d2 = max(-(abs(p.y)-0.03),d2); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +vec3 item2(vec2 p, vec3 col, float dir){ + p.x*=dir; + p*=Rot(radians(iTime*50.-10.)); + vec2 prevP = p; + float d = abs(length(p)-0.15)-0.005; + float d2 = abs(length(p)-0.2)-0.01; + d2 = max((abs(p.y)-0.15),d2); + d = min(d,d2); + + p = DF(p,1.); + p-=vec2(0.13); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.008,0.1)); + d = min(d,d2); + + p = prevP; + p = DF(p,4.); + p-=vec2(0.18); + p*=Rot(radians(45.)); + d2 = B(p,vec2(0.005,0.02)); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +float needle(vec2 p){ + p.y-=0.05; + p*=1.5; + vec2 prevP = p; + p.y-=0.3; + p.x*=6.; + float d = Tri(p,vec2(0.3)); + p = prevP; + p.y+=0.1; + p.x*=2.; + p.y*=-1.; + float d2 = Tri(p,vec2(0.1)); + d = min(d,d2); + return d; +} + +vec3 item3(vec2 p, vec3 col, float dir){ + + p*=Rot(radians(sin(iTime*dir)*120.)); + vec2 prevP = p; + + p.y= abs(p.y)-0.05; + float d = needle(p); + p = prevP; + float d2 = abs(length(p)-0.1)-0.003; + d2 = max(-(abs(p.x)-0.05),d2); + d = min(d,d2); + d2 = abs(length(p)-0.2)-0.005; + d2 = max(-(abs(p.x)-0.08),d2); + d = min(d,d2); + + p = DF(p,4.); + p-=vec2(0.18); + d2 = length(p)-0.01; + p = prevP; + d2 = max(-(abs(p.x)-0.03),d2); + d = min(d,d2); + + col = mix(col,vec3(0.6),S(d,0.0)); + + return col; +} + +vec3 drawGearsAndItems(vec2 p, vec3 col, float size){ + vec2 prevP = p; + p*=size; + p+=vec2(0.5); + + vec2 id = floor(p); + vec2 gr = fract(p)-0.5; + + float n = random(id); + float dir = mod(id.x+id.y,2.)*2.-1.; + if(n<0.3){ + col = gear(gr,col,dir); + } else if(n>=0.3 && n<0.5){ + col = item0(gr,col,dir); + } else if(n>=0.5 && n<0.7){ + col = item1(gr,col,dir); + } else if(n>=0.7 && n<0.8) { + col = item2(gr,col,dir); + } else if(n>=0.8){ + col = item3(gr,col,dir); + } + + return col; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 p = (fragCoord-0.5*iResolution.xy)/iResolution.y; + // set speed of downwards motion + p.y+=iTime*0.02; + + float size = 4.; + vec3 col = vec3(0.); + + // Modify the colors to be darker by multiplying with a small factor + vec3 darkFactor = vec3(.5); // This makes everything 50% as bright + + // Get the original colors but make them darker + col = drawBelt(p, col, size) * darkFactor; + col = drawGearsAndItems(p, col, size) * darkFactor; + + // Additional option: you can add a color tint to make it less stark white + vec3 tint = vec3(0.1, 0.12, 0.15); // Slight blue-ish dark tint + col = col * tint; + + vec2 uv = fragCoord/iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + + // Blend with reduced opacity for the shader elements + vec3 blendedColor = terminalColor.rgb + col.rgb * 0.7; // Reduced blend factor + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/glitchy.glsl b/ghostty/shaders/glitchy.glsl new file mode 100644 index 0000000..603e3ec --- /dev/null +++ b/ghostty/shaders/glitchy.glsl @@ -0,0 +1,117 @@ +// modified version of https://www.shadertoy.com/view/wld3WN +// amount of seconds for which the glitch loop occurs +#define DURATION 10. +// percentage of the duration for which the glitch is triggered +#define AMT .1 + +#define SS(a, b, x) (smoothstep(a, b, x) * smoothstep(b, a, x)) + +#define UI0 1597334673U +#define UI1 3812015801U +#define UI2 uvec2(UI0, UI1) +#define UI3 uvec3(UI0, UI1, 2798796415U) +#define UIF (1. / float(0xffffffffU)) + +// Hash by David_Hoskins +vec3 hash33(vec3 p) +{ + uvec3 q = uvec3(ivec3(p)) * UI3; + q = (q.x ^ q.y ^ q.z)*UI3; + return -1. + 2. * vec3(q) * UIF; +} + +// Gradient noise by iq +float gnoise(vec3 x) +{ + // grid + vec3 p = floor(x); + vec3 w = fract(x); + + // quintic interpolant + vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.); + + // gradients + vec3 ga = hash33(p + vec3(0., 0., 0.)); + vec3 gb = hash33(p + vec3(1., 0., 0.)); + vec3 gc = hash33(p + vec3(0., 1., 0.)); + vec3 gd = hash33(p + vec3(1., 1., 0.)); + vec3 ge = hash33(p + vec3(0., 0., 1.)); + vec3 gf = hash33(p + vec3(1., 0., 1.)); + vec3 gg = hash33(p + vec3(0., 1., 1.)); + vec3 gh = hash33(p + vec3(1., 1., 1.)); + + // projections + float va = dot(ga, w - vec3(0., 0., 0.)); + float vb = dot(gb, w - vec3(1., 0., 0.)); + float vc = dot(gc, w - vec3(0., 1., 0.)); + float vd = dot(gd, w - vec3(1., 1., 0.)); + float ve = dot(ge, w - vec3(0., 0., 1.)); + float vf = dot(gf, w - vec3(1., 0., 1.)); + float vg = dot(gg, w - vec3(0., 1., 1.)); + float vh = dot(gh, w - vec3(1., 1., 1.)); + + // interpolation + float gNoise = va + u.x * (vb - va) + + u.y * (vc - va) + + u.z * (ve - va) + + u.x * u.y * (va - vb - vc + vd) + + u.y * u.z * (va - vc - ve + vg) + + u.z * u.x * (va - vb - ve + vf) + + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh); + + return 2. * gNoise; +} + +// gradient noise in range [0, 1] +float gnoise01(vec3 x) +{ + return .5 + .5 * gnoise(x); +} + +// warp uvs for the crt effect +vec2 crt(vec2 uv) +{ + float tht = atan(uv.y, uv.x); + float r = length(uv); + // curve without distorting the center + r /= (1. - .1 * r * r); + uv.x = r * cos(tht); + uv.y = r * sin(tht); + return .5 * (uv + 1.); +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord / iResolution.xy; + float t = iTime; + + // smoothed interval for which the glitch gets triggered + float glitchAmount = SS(DURATION * .001, DURATION * AMT, mod(t, DURATION)); + float displayNoise = 0.; + vec3 col = vec3(0.); + vec2 eps = vec2(5. / iResolution.x, 0.); + vec2 st = vec2(0.); + + // analog distortion + float y = uv.y * iResolution.y; + float distortion = gnoise(vec3(0., y * .01, t * 500.)) * (glitchAmount * 4. + .1); + distortion *= gnoise(vec3(0., y * .02, t * 250.)) * (glitchAmount * 2. + .025); + + ++displayNoise; + distortion += smoothstep(.999, 1., sin((uv.y + t * 1.6) * 2.)) * .02; + distortion -= smoothstep(.999, 1., sin((uv.y + t) * 2.)) * .02; + st = uv + vec2(distortion, 0.); + // chromatic aberration + col.r += textureLod(iChannel0, st + eps + distortion, 0.).r; + col.g += textureLod(iChannel0, st, 0.).g; + col.b += textureLod(iChannel0, st - eps - distortion, 0.).b; + + // white noise + scanlines + displayNoise = 0.2 * clamp(displayNoise, 0., 1.); + col += (.15 + .65 * glitchAmount) * (hash33(vec3(fragCoord, mod(float(iFrame), + 1000.))).r) * displayNoise; + col -= (.25 + .75 * glitchAmount) * (sin(4. * t + uv.y * iResolution.y * 1.75)) + * displayNoise; + fragColor = vec4(col, 1.0); +} diff --git a/ghostty/shaders/glow-rgbsplit-twitchy.glsl b/ghostty/shaders/glow-rgbsplit-twitchy.glsl new file mode 100644 index 0000000..9411e4e --- /dev/null +++ b/ghostty/shaders/glow-rgbsplit-twitchy.glsl @@ -0,0 +1,144 @@ +// First it does a "chromatic aberration" by splitting the rgb signals by a product of sin functions +// over time, then it does a glow effect in a perceptual color space +// Based on kalgynirae's Ghostty passable glow shader and NickWest's Chromatic Aberration shader demo +// Passable glow: https://github.com/kalgynirae/dotfiles/blob/main/ghostty/glow.glsl +// "Chromatic Aberration": https://www.shadertoy.com/view/Mds3zn + +// sRGB linear -> nonlinear transform from https://bottosson.github.io/posts/colorwrong/ +float f(float x) { + if (x >= 0.0031308) { + return 1.055 * pow(x, 1.0 / 2.4) - 0.055; + } else { + return 12.92 * x; + } +} + +float f_inv(float x) { + if (x >= 0.04045) { + return pow((x + 0.055) / 1.055, 2.4); + } else { + return x / 12.92; + } +} + +// Oklab <-> linear sRGB conversions from https://bottosson.github.io/posts/oklab/ +vec4 toOklab(vec4 rgb) { + vec3 c = vec3(f_inv(rgb.r), f_inv(rgb.g), f_inv(rgb.b)); + float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b; + float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b; + float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b; + float l_ = pow(l, 1.0 / 3.0); + float m_ = pow(m, 1.0 / 3.0); + float s_ = pow(s, 1.0 / 3.0); + return vec4( + 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, + 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, + 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, + rgb.a + ); +} + +vec4 toRgb(vec4 oklab) { + vec3 c = oklab.rgb; + float l_ = c.r + 0.3963377774 * c.g + 0.2158037573 * c.b; + float m_ = c.r - 0.1055613458 * c.g - 0.0638541728 * c.b; + float s_ = c.r - 0.0894841775 * c.g - 1.2914855480 * c.b; + float l = l_ * l_ * l_; + float m = m_ * m_ * m_; + float s = s_ * s_ * s_; + vec3 linear_srgb = vec3( + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s + ); + return vec4( + clamp(f(linear_srgb.r), 0.0, 1.0), + clamp(f(linear_srgb.g), 0.0, 1.0), + clamp(f(linear_srgb.b), 0.0, 1.0), + oklab.a + ); +} + +// Bloom samples from https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) +}; + +float offsetFunction(float iTime) { + float amount = 1.0; + const float periods[4] = {6.0, 16.0, 19.0, 27.0}; + for (int i = 0; i < 4; i++) { + amount *= 1.0 + 0.5 * sin(iTime*periods[i]); + } + //return amount; + return amount * periods[3]; +} + +const float DIM_CUTOFF = 0.35; +const float BRIGHT_CUTOFF = 0.65; +const float ABBERATION_FACTOR = 0.05; + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + float amount = offsetFunction(iTime); + + vec3 col; + col.r = texture( iChannel0, vec2(uv.x-ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).r; + col.g = texture( iChannel0, uv ).g; + col.b = texture( iChannel0, vec2(uv.x+ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).b; + + vec4 splittedColor = vec4(col, 1.0); + vec4 source = toOklab(splittedColor); + vec4 dest = source; + + if (source.x > DIM_CUTOFF) { + dest.x *= 1.2; + // dest.x = 1.2; + } else { + vec2 step = vec2(1.414) / iResolution.xy; + vec3 glow = vec3(0.0); + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + float weight = s.z; + vec4 c = toOklab(texture(iChannel0, uv + s.xy * step)); + if (c.x > DIM_CUTOFF) { + glow.yz += c.yz * weight * 0.3; + if (c.x <= BRIGHT_CUTOFF) { + glow.x += c.x * weight * 0.05; + } else { + glow.x += c.x * weight * 0.10; + } + } + } + // float lightness_diff = clamp(glow.x - dest.x, 0.0, 1.0); + // dest.x = lightness_diff; + // dest.yz = dest.yz * (1.0 - lightness_diff) + glow.yz * lightness_diff; + dest.xyz += glow.xyz; + } + + fragColor = toRgb(dest); +} diff --git a/ghostty/shaders/gradient-background.glsl b/ghostty/shaders/gradient-background.glsl new file mode 100644 index 0000000..beae0cf --- /dev/null +++ b/ghostty/shaders/gradient-background.glsl @@ -0,0 +1,25 @@ +// credits: https://github.com/unkn0wncode +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalize pixel coordinates (range from 0 to 1) + vec2 uv = fragCoord.xy / iResolution.xy; + + // Create a gradient from bottom right to top left as a function (x + y)/2 + float gradientFactor = (uv.x + uv.y) / 2.0; + + // Define gradient colors (adjust to your preference) + vec3 gradientStartColor = vec3(0.1, 0.1, 0.5); // Start color (e.g., dark blue) + vec3 gradientEndColor = vec3(0.5, 0.1, 0.1); // End color (e.g., dark red) + + vec3 gradientColor = mix(gradientStartColor, gradientEndColor, gradientFactor); + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb, gradientColor, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} \ No newline at end of file diff --git a/ghostty/shaders/in-game-crt.glsl b/ghostty/shaders/in-game-crt.glsl new file mode 100644 index 0000000..34cfc62 --- /dev/null +++ b/ghostty/shaders/in-game-crt.glsl @@ -0,0 +1,304 @@ +// In-game CRT shader +// Author: sarphiv +// License: CC BY-NC-SA 4.0 +// Description: +// Shader for ghostty that is focussed on being usable while looking like a stylized CRT terminal in a modern video game. +// I know a tiny bit about shaders, and nothing about GLSL, +// so this is a Frakenstein's monster combination of other shaders together with a lot of surgery. +// On the bright side, i've cleaned up the body parts and surgery a lot. + +// Based on: +// 1. https://gist.github.com/mitchellh/39d62186910dcc27cad097fed16eb882 (forces the choice of license) +// 2. https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// 3. https://gist.github.com/seanwcom/0fbe6b270aaa5f28823e053d3dbb14ca + + +// Settings: +// How straight the terminal is in each axis +// (x, y) \in R^2 : x, y > 0 +#define CURVE 13.0, 11.0 + +// How far apart the different colors are from each other +// x \in R +#define COLOR_FRINGING_SPREAD 1.0 + +// How much the ghost images are spread out +// x \in R : x >= 0 +#define GHOSTING_SPREAD 0.75 +// How visible ghost images are +// x \in R : x >= 0 +#define GHOSTING_STRENGTH 1.0 + +// How much of the non-linearly darkened colors are mixed in +// [0, 1] +#define DARKEN_MIX 0.4 + +// How far in the vignette spreads +// x \in R : x >= 0 +#define VIGNETTE_SPREAD 0.3 +// How bright the vignette is +// x \in R : x >= 0 +#define VIGNETTE_BRIGHTNESS 6.4 + +// Tint all colors +// [0, 1]^3 +#define TINT 0.93, 1.00, 0.96 + +// How visible the scan line effect is +// NOTE: Technically these are not scan lines, but rather the lack of them +// [0, 1] +#define SCAN_LINES_STRENGTH 0.15 +// How bright the spaces between the lines are +// [0, 1] +#define SCAN_LINES_VARIANCE 0.35 +// Pixels per scan line effect +// x \in R : x > 0 +#define SCAN_LINES_PERIOD 4.0 + +// How visible the aperture grille is +// x \in R : x >= 0 +#define APERTURE_GRILLE_STRENGTH 0.2 +// Pixels per aperture grille +// x \in R : x > 0 +#define APERTURE_GRILLE_PERIOD 2.0 + +// How much the screen flickers +// x \in R : x >= 0 +#define FLICKER_STRENGTH 0.05 +// How fast the screen flickers +// x \in R : x > 0 +#define FLICKER_FREQUENCY 15.0 + +// How much noise is added to filled areas +// [0, 1] +#define NOISE_CONTENT_STRENGTH 0.15 +// How much noise is added everywhere +// [0, 1] +#define NOISE_UNIFORM_STRENGTH 0.03 + +// How big the bloom is +// x \in R : x >= 0 +#define BLOOM_SPREAD 8.0 +// How visible the bloom is +// [0, 1] +#define BLOOM_STRENGTH 0.04 + +// How fast colors fade in and out +// [0, 1] +#define FADE_FACTOR 0.55 + + + +// Disabled values for when the settings are not defined +#ifndef COLOR_FRINGING_SPREAD +#define COLOR_FRINGING_SPREAD 0.0 +#endif + +#if !defined(GHOSTING_SPREAD) || !defined(GHOSTING_STRENGTH) +#undef GHOSTING_SPREAD +#undef GHOSTING_STRENGTH +#define GHOSTING_SPREAD 0.0 +#define GHOSTING_STRENGTH 0.0 +#endif + +#ifndef DARKEN_MIX +#define DARKEN_MIX 0.0 +#endif + +#if !defined(VIGNETTE_SPREAD) || !defined(VIGNETTE_BRIGHTNESS) +#undef VIGNETTE_SPREAD +#undef VIGNETTE_BRIGHTNESS +#define VIGNETTE_SPREAD 0.0 +#define VIGNETTE_BRIGHTNESS 1.0 +#endif + +#ifndef TINT +#define TINT 1.00, 1.00, 1.00 +#endif + +#if !defined(SCAN_LINES_STRENGTH) || !defined(SCAN_LINES_VARIANCE) || !defined(SCAN_LINES_PERIOD) +#undef SCAN_LINES_STRENGTH +#undef SCAN_LINES_VARIANCE +#undef SCAN_LINES_PERIOD +#define SCAN_LINES_STRENGTH 0.0 +#define SCAN_LINES_VARIANCE 1.0 +#define SCAN_LINES_PERIOD 1.0 +#endif + +#if !defined(APERTURE_GRILLE_STRENGTH) || !defined(APERTURE_GRILLE_PERIOD) +#undef APERTURE_GRILLE_STRENGTH +#undef APERTURE_GRILLE_PERIOD +#define APERTURE_GRILLE_STRENGTH 0.0 +#define APERTURE_GRILLE_PERIOD 1.0 +#endif + +#if !defined(FLICKER_STRENGTH) || !defined(FLICKER_FREQUENCY) +#undef FLICKER_STRENGTH +#undef FLICKER_FREQUENCY +#define FLICKER_STRENGTH 0.0 +#define FLICKER_FREQUENCY 1.0 +#endif + +#if !defined(NOISE_CONTENT_STRENGTH) || !defined(NOISE_UNIFORM_STRENGTH) +#undef NOISE_CONTENT_STRENGTH +#undef NOISE_UNIFORM_STRENGTH +#define NOISE_CONTENT_STRENGTH 0.0 +#define NOISE_UNIFORM_STRENGTH 0.0 +#endif + +#if !defined(BLOOM_SPREAD) || !defined(BLOOM_STRENGTH) +#undef BLOOM_SPREAD +#undef BLOOM_STRENGTH +#define BLOOM_SPREAD 0.0 +#define BLOOM_STRENGTH 0.0 +#endif + +#ifndef FADE_FACTOR +#define FADE_FACTOR 1.00 +#endif + + + +// Constants +#define PI 3.1415926535897932384626433832795 + +#ifdef BLOOM_SPREAD +// Golden spiral samples used for bloom. +// [x, y, weight] weight is inverse of distance. +const vec3[24] bloom_samples = { + vec3( 0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3( 1.554155680728463, -1.2588090085709776, 0.5), + vec3( 1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3( 0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3( 2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3( 0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3( 2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3( 2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3( 1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3( 4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3( 0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3( 3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3( 3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) +}; +#endif + + + + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + // Get texture coordinates + vec2 uv = fragCoord.xy / iResolution.xy; + +#ifdef CURVE + // Curve texture coordinates to mimic non-flat CRT monior + uv = (uv - 0.5) * 2.0; + uv.xy *= 1.0 + pow((abs(vec2(uv.y, uv.x)) / vec2(CURVE)), vec2(2.0)); + uv = (uv / 2.0) + 0.5; +#endif + + + // Retrieve colors from appropriate locations + fragColor.r = texture(iChannel0, vec2(uv.x + 0.0003 * COLOR_FRINGING_SPREAD, uv.y + 0.0003 * COLOR_FRINGING_SPREAD)).x; + fragColor.g = texture(iChannel0, vec2(uv.x + 0.0000 * COLOR_FRINGING_SPREAD, uv.y - 0.0006 * COLOR_FRINGING_SPREAD)).y; + fragColor.b = texture(iChannel0, vec2(uv.x - 0.0006 * COLOR_FRINGING_SPREAD, uv.y + 0.0000 * COLOR_FRINGING_SPREAD)).z; + fragColor.a = texture(iChannel0, uv).a; + + + // Add faint ghost images + fragColor.r += 0.04 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(+0.025, -0.027) + uv.xy).x; + fragColor.g += 0.02 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(-0.022, -0.020) + uv.xy).y; + fragColor.b += 0.04 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(-0.020, -0.018) + uv.xy).z; + + + // Quadratically darken everything + fragColor.rgb = mix(fragColor.rgb, fragColor.rgb*fragColor.rgb, DARKEN_MIX); + + + // Vignette effect + fragColor.rgb *= VIGNETTE_BRIGHTNESS * pow(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y), VIGNETTE_SPREAD); + + + // Tint all colors + fragColor.rgb *= vec3(TINT); + + + // NOTE: At this point, RGB values may be above 1 + + + // Add scan lines effect + fragColor.rgb *= mix( + 1.0, + SCAN_LINES_VARIANCE/2.0*(1.0 + sin(2*PI* uv.y * iResolution.y/SCAN_LINES_PERIOD)), + SCAN_LINES_STRENGTH + ); + + + // Add aperture grille + int aperture_grille_step = int(8 * mod(fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD); + float aperture_grille_mask; + + if (aperture_grille_step < 3) + aperture_grille_mask = 0.0; + else if (aperture_grille_step < 4) + aperture_grille_mask = mod(8*fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD; + else if (aperture_grille_step < 7) + aperture_grille_mask = 1.0; + else if (aperture_grille_step < 8) + aperture_grille_mask = mod(-8*fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD; + + fragColor.rgb *= 1.0 - APERTURE_GRILLE_STRENGTH*aperture_grille_mask; + + + // Add flicker + fragColor *= 1.0 - FLICKER_STRENGTH/2.0*(1.0 + sin(2*PI*FLICKER_FREQUENCY*iTime)); + + + // Add noise + // NOTE: Hard-coded noise distributions + float noiseContent = smoothstep(0.4, 0.6, fract(sin(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y) * iTime * 4096.0) * 65536.0)); + float noiseUniform = smoothstep(0.4, 0.6, fract(sin(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y) * iTime * 8192.0) * 65536.0)); + fragColor.rgb *= clamp(noiseContent + 1.0 - NOISE_CONTENT_STRENGTH, 0.0, 1.0); + fragColor.rgb = clamp(fragColor.rgb + noiseUniform * NOISE_UNIFORM_STRENGTH, 0.0, 1.0); + + + // NOTE: At this point, RGB values are again within [0, 1] + + + // Remove output outside of screen bounds + if (uv.x < 0.0 || uv.x > 1.0) + fragColor.rgb *= 0.0; + if (uv.y < 0.0 || uv.y > 1.0) + fragColor.rgb *= 0.0; + + +#ifdef BLOOM_SPREAD + // Add bloom + vec2 step = BLOOM_SPREAD * vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 bloom_sample = bloom_samples[i]; + vec4 neighbor = texture(iChannel0, uv + bloom_sample.xy * step); + float luminance = 0.299 * neighbor.r + 0.587 * neighbor.g + 0.114 * neighbor.b; + + fragColor += luminance * bloom_sample.z * neighbor * BLOOM_STRENGTH; + } + + fragColor = clamp(fragColor, 0.0, 1.0); +#endif + + + // Add fade effect to smoothen out color transitions + // NOTE: May need to be iTime/iTimeDelta dependent + fragColor = vec4(FADE_FACTOR*fragColor.rgb, FADE_FACTOR); +} diff --git a/ghostty/shaders/inside-the-matrix.glsl b/ghostty/shaders/inside-the-matrix.glsl new file mode 100644 index 0000000..6992069 --- /dev/null +++ b/ghostty/shaders/inside-the-matrix.glsl @@ -0,0 +1,413 @@ +/* + Feel free to do anything you want with this code. + This shader uses "runes" code by FabriceNeyret2 (https://www.shadertoy.com/view/4ltyDM) + which is based on "runes" by otaviogood (https://shadertoy.com/view/MsXSRn). + These random runes look good as matrix symbols and have acceptable performance. + + @pkazmier modified this shader to work in Ghostty. +*/ + +const int ITERATIONS = 40; //use less value if you need more performance +const float SPEED = .5; + +const float STRIP_CHARS_MIN = 7.; +const float STRIP_CHARS_MAX = 40.; +const float STRIP_CHAR_HEIGHT = 0.15; +const float STRIP_CHAR_WIDTH = 0.10; +const float ZCELL_SIZE = 1. * (STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX); //the multiplier can't be less than 1. +const float XYCELL_SIZE = 12. * STRIP_CHAR_WIDTH; //the multiplier can't be less than 1. + +const int BLOCK_SIZE = 10; //in cells +const int BLOCK_GAP = 2; //in cells + +const float WALK_SPEED = 0.5 * XYCELL_SIZE; +const float BLOCKS_BEFORE_TURN = 3.; + + +const float PI = 3.14159265359; + + +// ---- random ---- + +float hash(float v) { + return fract(sin(v)*43758.5453123); +} + +float hash(vec2 v) { + return hash(dot(v, vec2(5.3983, 5.4427))); +} + +vec2 hash2(vec2 v) +{ + v = vec2(v * mat2(127.1, 311.7, 269.5, 183.3)); + return fract(sin(v)*43758.5453123); +} + +vec4 hash4(vec2 v) +{ + vec4 p = vec4(v * mat4x2( 127.1, 311.7, + 269.5, 183.3, + 113.5, 271.9, + 246.1, 124.6 )); + return fract(sin(p)*43758.5453123); +} + +vec4 hash4(vec3 v) +{ + vec4 p = vec4(v * mat4x3( 127.1, 311.7, 74.7, + 269.5, 183.3, 246.1, + 113.5, 271.9, 124.6, + 271.9, 269.5, 311.7 ) ); + return fract(sin(p)*43758.5453123); +} + + +// ---- symbols ---- +// Slightly modified version of "runes" by FabriceNeyret2 - https://www.shadertoy.com/view/4ltyDM +// Which is based on "runes" by otaviogood - https://shadertoy.com/view/MsXSRn + +float rune_line(vec2 p, vec2 a, vec2 b) { // from https://www.shadertoy.com/view/4dcfW8 + p -= a, b -= a; + float h = clamp(dot(p, b) / dot(b, b), 0., 1.); // proj coord on line + return length(p - b * h); // dist to segment +} + +float rune(vec2 U, vec2 seed, float highlight) +{ + float d = 1e5; + for (int i = 0; i < 4; i++) // number of strokes + { + vec4 pos = hash4(seed); + seed += 1.; + + // each rune touches the edge of its box on all 4 sides + if (i == 0) pos.y = .0; + if (i == 1) pos.x = .999; + if (i == 2) pos.x = .0; + if (i == 3) pos.y = .999; + // snap the random line endpoints to a grid 2x3 + vec4 snaps = vec4(2, 3, 2, 3); + pos = ( floor(pos * snaps) + .5) / snaps; + + if (pos.xy != pos.zw) //filter out single points (when start and end are the same) + d = min(d, rune_line(U, pos.xy, pos.zw + .001) ); // closest line + } + return smoothstep(0.1, 0., d) + highlight*smoothstep(0.4, 0., d); +} + +float random_char(vec2 outer, vec2 inner, float highlight) { + vec2 seed = vec2(dot(outer, vec2(269.5, 183.3)), dot(outer, vec2(113.5, 271.9))); + return rune(inner, seed, highlight); +} + + +// ---- digital rain ---- + +// xy - horizontal, z - vertical +vec3 rain(vec3 ro3, vec3 rd3, float time) { + vec4 result = vec4(0.); + + // normalized 2d projection + vec2 ro2 = vec2(ro3); + vec2 rd2 = normalize(vec2(rd3)); + + // we use formulas `ro3 + rd3 * t3` and `ro2 + rd2 * t2`, `t3_to_t2` is a multiplier to convert t3 to t2 + bool prefer_dx = abs(rd2.x) > abs(rd2.y); + float t3_to_t2 = prefer_dx ? rd3.x / rd2.x : rd3.y / rd2.y; + + // at first, horizontal space (xy) is divided into cells (which are columns in 3D) + // then each xy-cell is divided into vertical cells (along z) - each of these cells contains one raindrop + + ivec3 cell_side = ivec3(step(0., rd3)); //for positive rd.x use cell side with higher x (1) as the next side, for negative - with lower x (0), the same for y and z + ivec3 cell_shift = ivec3(sign(rd3)); //shift to move to the next cell + + // move through xy-cells in the ray direction + float t2 = 0.; // the ray formula is: ro2 + rd2 * t2, where t2 is positive as the ray has a direction. + ivec2 next_cell = ivec2(floor(ro2/XYCELL_SIZE)); //first cell index where ray origin is located + for (int i=0; i= t2s && tmin <= t2) { + float u = s.x * rd2.y - s.y * rd2.x; //horizontal coord in the matrix strip + if (abs(u) < target_rad) { + u = (u/target_rad + 1.) / 2.; + float z = ro3.z + rd3.z * tmin/t3_to_t2; + float v = (z - target_z) / target_length; //vertical coord in the matrix strip + if (v >= 0.0 && v < 1.0) { + float c = floor(v * chars_count); //symbol index relative to the start of the strip, with addition of char_z_shift it becomes an index relative to the whole cell + float q = fract(v * chars_count); + vec2 char_hash = hash2(vec2(c+char_z_shift, cell_hash2.x)); + if (char_hash.x >= 0.1 || c == 0.) { //10% of missed symbols + float time_factor = floor(c == 0. ? time*5.0 : //first symbol is changed fast + time*(1.0*cell_hash2.z + //strips are changed sometime with different speed + cell_hash2.w*cell_hash2.w*4.*pow(char_hash.y, 4.))); //some symbols in some strips are changed relatively often + float a = random_char(vec2(char_hash.x, time_factor), vec2(u,q), max(1., 3. - c/2.)*0.2); //alpha + a *= clamp((chars_count - 0.5 - c) / 2., 0., 1.); //tail fade + if (a > 0.) { + float attenuation = 1. + pow(0.06*tmin/t3_to_t2, 2.); + vec3 col = (c == 0. ? vec3(0.67, 1.0, 0.82) : vec3(0.25, 0.80, 0.40)) / attenuation; + float a1 = result.a; + result.a = a1 + (1. - a1) * a; + result.xyz = (result.xyz * a1 + col * (1. - a1) * a) / result.a; + if (result.a > 0.98) return result.xyz; + } + } + } + } + } + // not found in this cell - go to next vertical cell + zcell += cell_shift.z; + } + // go to next horizontal cell + } + + return result.xyz * result.a; +} + + +// ---- main, camera ---- + +vec2 rotate(vec2 v, float a) { + float s = sin(a); + float c = cos(a); + mat2 m = mat2(c, -s, s, c); + return m * v; +} + +vec3 rotateX(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(1.,0.,0.,0.,c,-s,0.,s,c) * v; +} + +vec3 rotateY(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(c,0.,-s,0.,1.,0.,s,0.,c) * v; +} + +vec3 rotateZ(vec3 v, float a) { + float s = sin(a); + float c = cos(a); + return mat3(c,-s,0.,s,c,0.,0.,0.,1.) * v; +} + +float smoothstep1(float x) { + return smoothstep(0., 1., x); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + if (STRIP_CHAR_WIDTH > XYCELL_SIZE || STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX > ZCELL_SIZE) { + // error + fragColor = vec4(1., 0., 0., 1.); + return; + } + + vec2 uv = fragCoord.xy / iResolution.xy; + + float time = iTime * SPEED; + + const float turn_rad = 0.25 / BLOCKS_BEFORE_TURN; //0 .. 0.5 + const float turn_abs_time = (PI/2.*turn_rad) * 1.5; //multiplier different than 1 means a slow down on turns + const float turn_time = turn_abs_time / (1. - 2.*turn_rad + turn_abs_time); //0..1, but should be <= 0.5 + + float level1_size = float(BLOCK_SIZE) * BLOCKS_BEFORE_TURN * XYCELL_SIZE; + float level2_size = 4. * level1_size; + float gap_size = float(BLOCK_GAP) * XYCELL_SIZE; + + vec3 ro = vec3(gap_size/2., gap_size/2., 0.); + vec3 rd = vec3(uv.x, 2.0, uv.y); + + float tq = fract(time / (level2_size*4.) * WALK_SPEED); //the whole cycle time counter + float t8 = fract(tq*4.); //time counter while walking on one of the four big sides + float t1 = fract(t8*8.); //time counter while walking on one of the eight sides of the big side + + vec2 prev; + vec2 dir; + if (tq < 0.25) { + prev = vec2(0.,0.); + dir = vec2(0.,1.); + } else if (tq < 0.5) { + prev = vec2(0.,1.); + dir = vec2(1.,0.); + } else if (tq < 0.75) { + prev = vec2(1.,1.); + dir = vec2(0.,-1.); + } else { + prev = vec2(1.,0.); + dir = vec2(-1.,0.); + } + float angle = floor(tq * 4.); //0..4 wich means 0..2*PI + + prev *= 4.; + + const float first_turn_look_angle = 0.4; + const float second_turn_drift_angle = 0.5; + const float fifth_turn_drift_angle = 0.25; + + vec2 turn; + float turn_sign = 0.; + vec2 dirL = rotate(dir, -PI/2.); + vec2 dirR = -dirL; + float up_down = 0.; + float rotate_on_turns = 1.; + float roll_on_turns = 1.; + float add_angel = 0.; + if (t8 < 0.125) { + turn = dirL; + //dir = dir; + turn_sign = -1.; + angle -= first_turn_look_angle * (max(0., t1 - (1. - turn_time*2.)) / turn_time - max(0., t1 - (1. - turn_time)) / turn_time * 2.5); + roll_on_turns = 0.; + } else if (t8 < 0.250) { + prev += dir; + turn = dir; + dir = dirL; + angle -= 1.; + turn_sign = 1.; + add_angel += first_turn_look_angle*0.5 + (-first_turn_look_angle*0.5+1.0+second_turn_drift_angle)*t1; + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else if (t8 < 0.375) { + prev += dir + dirL; + turn = dirR; + //dir = dir; + turn_sign = 1.; + add_angel += second_turn_drift_angle*sqrt(1.-t1); + //roll_on_turns = 0.; + } else if (t8 < 0.5) { + prev += dir + dir + dirL; + turn = dirR; + dir = dirR; + angle += 1.; + turn_sign = 0.; + up_down = sin(t1*PI) * 0.37; + } else if (t8 < 0.625) { + prev += dir + dir; + turn = dir; + dir = dirR; + angle += 1.; + turn_sign = -1.; + up_down = sin(-min(1., t1/(1.-turn_time))*PI) * 0.37; + } else if (t8 < 0.750) { + prev += dir + dir + dirR; + turn = dirL; + //dir = dir; + turn_sign = -1.; + add_angel -= (fifth_turn_drift_angle + 1.) * smoothstep1(t1); + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else if (t8 < 0.875) { + prev += dir + dir + dir + dirR; + turn = dir; + dir = dirL; + angle -= 1.; + turn_sign = 1.; + add_angel -= fifth_turn_drift_angle - smoothstep1(t1) * (fifth_turn_drift_angle * 2. + 1.); + rotate_on_turns = 0.; + roll_on_turns = 0.; + } else { + prev += dir + dir + dir; + turn = dirR; + //dir = dir; + turn_sign = 1.; + angle += fifth_turn_drift_angle * (1.5*min(1., (1.-t1)/turn_time) - 0.5*smoothstep1(1. - min(1.,t1/(1.-turn_time)))); + } + + if (iMouse.x > 10. || iMouse.y > 10.) { + vec2 mouse = iMouse.xy / iResolution.xy * 2. - 1.; + up_down = -0.7 * mouse.y; + angle += mouse.x; + rotate_on_turns = 1.; + roll_on_turns = 0.; + } else { + angle += add_angel; + } + + rd = rotateX(rd, up_down); + + vec2 p; + if (turn_sign == 0.) { + // move forward + p = prev + dir * (turn_rad + 1. * t1); + } + else if (t1 > (1. - turn_time)) { + // turn + float tr = (t1 - (1. - turn_time)) / turn_time; + vec2 c = prev + dir * (1. - turn_rad) + turn * turn_rad; + p = c + turn_rad * rotate(dir, (tr - 1.) * turn_sign * PI/2.); + angle += tr * turn_sign * rotate_on_turns; + rd = rotateY(rd, sin(tr*turn_sign*PI) * 0.2 * roll_on_turns); //roll + } else { + // move forward + t1 /= (1. - turn_time); + p = prev + dir * (turn_rad + (1. - turn_rad*2.) * t1); + } + + rd = rotateZ(rd, angle * PI/2.); + + ro.xy += level1_size * p; + + ro += rd * 0.2; + rd = normalize(rd); + + // vec3 col = rain(ro, rd, time); + vec3 col = rain(ro, rd, time) * 0.25; + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Combine the matrix effect with the terminal color + // vec3 blendedColor = terminalColor.rgb + col; + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1.2 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); + vec3 blendedColor = mix(terminalColor.rgb * 1.2, col, mask); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/just-snow.glsl b/ghostty/shaders/just-snow.glsl new file mode 100644 index 0000000..c72b7fd --- /dev/null +++ b/ghostty/shaders/just-snow.glsl @@ -0,0 +1,52 @@ +// Copyright (c) 2013 Andrew Baldwin (twitter: baldand, www: http://thndl.com) +// License = Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) + +// "Just snow" +// Simple (but not cheap) snow made from multiple parallax layers with randomly positioned +// flakes and directions. Also includes a DoF effect. Pan around with mouse. + +#define LIGHT_SNOW // Comment this out for a blizzard + +#ifdef LIGHT_SNOW + #define LAYERS 50 + #define DEPTH .5 + #define WIDTH .3 + #define SPEED .6 +#else // BLIZZARD + #define LAYERS 200 + #define DEPTH .1 + #define WIDTH .8 + #define SPEED 1.5 +#endif + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + const mat3 p = mat3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934); + vec2 uv = fragCoord.xy / iResolution.xy; + + vec3 acc = vec3(0.0); + float dof = 5.0 * sin(iTime * 0.1); + for (int i = 0; i < LAYERS; i++) { + float fi = float(i); + vec2 q =-uv*(1.0 + fi * DEPTH); + q += vec2(q.y * (WIDTH * mod(fi * 7.238917, 1.0) - WIDTH * 0.5), -SPEED * iTime / (1.0 + fi * DEPTH * 0.03)); + vec3 n = vec3(floor(q), 31.189 + fi); + vec3 m = floor(n) * 0.00001 + fract(n); + vec3 mp = (31415.9 + m) / fract(p * m); + vec3 r = fract(mp); + vec2 s = abs(mod(q, 1.0) - 0.5 + 0.9 * r.xy - 0.45); + s += 0.01 * abs(2.0 * fract(10.0 * q.yx) - 1.0); + float d = 0.6 * max(s.x - s.y, s.x + s.y) + max(s.x, s.y) - 0.01; + float edge = 0.005 + 0.05 * min(0.5 * abs(fi - 5.0 - dof), 1.0); + acc += vec3(smoothstep(edge, -edge, d) * (r.x / (1.0 + 0.02 * fi * DEPTH))); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + // Combine the snow effect with the terminal color + vec3 blendedColor = terminalColor.rgb + acc; + + // Use the terminal's original alpha + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/matrix-hallway.glsl b/ghostty/shaders/matrix-hallway.glsl new file mode 100644 index 0000000..2bbee86 --- /dev/null +++ b/ghostty/shaders/matrix-hallway.glsl @@ -0,0 +1,40 @@ +// based on the following Shader Toy entry +// +// [SH17A] Matrix rain. Created by Reinder Nijhoff 2017 +// Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// @reindernijhoff +// +// https://www.shadertoy.com/view/ldjBW1 +// + +#define SPEED_MULTIPLIER 1. +#define GREEN_ALPHA .33 + +#define BLACK_BLEND_THRESHOLD .4 + +#define R fract(1e2 * sin(p.x * 8. + p.y)) + +void mainImage(out vec4 fragColor, vec2 fragCoord) { + vec3 v = vec3(fragCoord, 1) / iResolution - .5; + // vec3 s = .5 / abs(v); + // scale? + vec3 s = .9 / abs(v); + s.z = min(s.y, s.x); + vec3 i = ceil( 8e2 * s.z * ( s.y < s.x ? v.xzz : v.zyz ) ) * .1; + vec3 j = fract(i); + i -= j; + vec3 p = vec3(9, int(iTime * SPEED_MULTIPLIER * (9. + 8. * sin(i).x)), 0) + i; + vec3 col = fragColor.rgb; + col.g = R / s.z; + p *= j; + col *= (R >.5 && j.x < .6 && j.y < .8) ? GREEN_ALPHA : 0.; + + // Sample the terminal screen texture including alpha channel + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.2, col, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/mnoise.glsl b/ghostty/shaders/mnoise.glsl new file mode 100644 index 0000000..a414a46 --- /dev/null +++ b/ghostty/shaders/mnoise.glsl @@ -0,0 +1,119 @@ +vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +vec4 permute(vec4 x) { return mod289(((x * 34.0) + 10.0) * x); } +vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } +float snoise(vec3 v) { + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod289(i); + vec4 p = permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + + vec4(0.0, i1.y, i2.y, 1.0)) + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + // Normalise gradients + vec4 norm = + taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = + max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + m = m * m; + return 105.0 * + dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); +} + +float noise2D(vec2 uv) { + uvec2 pos = uvec2(floor(uv * 1000.)); + return float((pos.x * 68657387u ^ pos.y * 361524851u + pos.x) % 890129u) * + (1.0 / 890128.0); +} + +float roundRectSDF(vec2 center, vec2 size, float radius) { + return length(max(abs(center) - size + radius, 0.)) - radius; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy, sd = vec2(2.), sdh = vec2(1.); + vec4 ghosttyCol = texture(iChannel0, uv); + float ratio = iResolution.y / iResolution.x, + fw = max(fwidth(uv.x), fwidth(uv.y)); + + vec2 puv = floor(uv * vec2(60., 60. * ratio)) / 60.; + puv += + (smoothstep(0., 0.7, noise2D(puv)) - 0.5) * 0.05 - vec2(0., iTime * 0.08); + + uv = fract(vec2(uv.x, uv.y * ratio) * 10.); + float d = roundRectSDF((sd + 0.01) * (uv - .5), sdh, 0.075), + d2 = roundRectSDF((sd + 0.065) * (fract(uv * 6.) - .5), sdh, 0.2), + noiseTime = iTime * 0.03, noise = snoise(vec3(puv, noiseTime)); + + noise += snoise(vec3(puv * 1.1, noiseTime + 0.5)) + .1; + noise += snoise(vec3(puv * 2., noiseTime + 0.8)); + noise = pow(noise, 2.); + + vec3 col1 = vec3(0.), col2 = vec3(0.), col3 = vec3(0.07898), + col4 = vec3(0.089184), + fcol = mix(mix(mix(col1, col3, smoothstep(0.0, 0.3, noise)), col2, + smoothstep(0.0, 0.5, noise)), + col4, smoothstep(0.0, 1.0, noise)); + + fragColor = vec4( + ghosttyCol.rgb + + mix(col4, fcol, smoothstep(fw, -fw, d) * smoothstep(fw, -fw, d2)), + ghosttyCol.a); +} diff --git a/ghostty/shaders/negative.glsl b/ghostty/shaders/negative.glsl new file mode 100644 index 0000000..48101f6 --- /dev/null +++ b/ghostty/shaders/negative.glsl @@ -0,0 +1,8 @@ + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord/iResolution.xy; + vec4 color = texture(iChannel0, uv); + fragColor = vec4(1.0 - color.x, 1.0 - color.y, 1.0 - color.z, color.w); +} + diff --git a/ghostty/shaders/retro-terminal.glsl b/ghostty/shaders/retro-terminal.glsl new file mode 100644 index 0000000..c5f315a --- /dev/null +++ b/ghostty/shaders/retro-terminal.glsl @@ -0,0 +1,34 @@ +// Original shader collected from: https://www.shadertoy.com/view/WsVSzV +// Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) +// Slight modifications were made to give a green-ish effect. + +float warp = 0.25; // simulate curvature of CRT monitor +float scan = 0.50; // simulate darkness between scanlines + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // squared distance from center + vec2 uv = fragCoord / iResolution.xy; + vec2 dc = abs(0.5 - uv); + dc *= dc; + + // warp the fragment coordinates + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; + + // sample inside boundaries, otherwise set to black + if (uv.y > 1.0 || uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0) + fragColor = vec4(0.0, 0.0, 0.0, 1.0); + else + { + // determine if we are drawing in a scanline + float apply = abs(sin(fragCoord.y) * 0.5 * scan); + + // sample the texture and apply a teal tint + vec3 color = texture(iChannel0, uv).rgb; + vec3 tealTint = vec3(0.0, 0.8, 0.6); // teal color (slightly more green than blue) + + // mix the sampled color with the teal tint based on scanline intensity + fragColor = vec4(mix(color * tealTint, vec3(0.0), apply), 1.0); + } +} diff --git a/ghostty/shaders/sin-interference.glsl b/ghostty/shaders/sin-interference.glsl new file mode 100644 index 0000000..a1b9a40 --- /dev/null +++ b/ghostty/shaders/sin-interference.glsl @@ -0,0 +1,28 @@ +// Based on https://www.shadertoy.com/view/ms3cWn +float map(float value, float min1, float max1, float min2, float max2) { + return min2 + (value - min1) * (max2 - min2) / (max1 - min1); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord / iResolution.xy; + float d = length(uv - 0.5) * 2.0; + float t = d * d * 25.0 - iTime * 2.0; + vec3 col = 0.5 + 0.5 * cos(t / 20.0 + uv.xyx + vec3(0.0,2.0,4.0)); + + vec2 center = iResolution.xy * 0.5; + float distCentre = distance(fragCoord.xy, center); + float dCSin = sin(distCentre * 0.05); + + vec2 anim = vec2(map(sin(iTime),-1.0,1.0,0.0,iResolution.x),map(sin(iTime*1.25),-1.0,1.0,0.0,iResolution.y)); + float distMouse = distance(fragCoord.xy, anim); + float dMSin = sin(distMouse * 0.05); + + float greycol = (((dMSin * dCSin) + 1.0) * 0.5); + greycol = greycol * map(d, 0.0, 1.4142135623730951, 0.5, 0.0); + + vec4 terminalColor = texture(iChannel0, uv); + vec3 blendedColor = mix(terminalColor.rgb, vec3(greycol * col.x, greycol * col.y, greycol * col.z), 0.25); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/smoke-and-ghost.glsl b/ghostty/shaders/smoke-and-ghost.glsl new file mode 100644 index 0000000..a11f8dc --- /dev/null +++ b/ghostty/shaders/smoke-and-ghost.glsl @@ -0,0 +1,193 @@ +// Settings for detection +#define TARGET_COLOR vec3(0.0, 0.0, 0.0) // RGB target pixels to transform +#define REPLACE_COLOR vec3(0.0, 0.0, 0.0) // Color to replace target pixels +#define COLOR_TOLERANCE 0.001 // Color matching tolerance + +// Smoke effect settings +#define SMOKE_COLOR vec3(1., 1., 1.0) // Base color of smoke +#define SMOKE_RADIUS 0.011 // How far the smoke spreads +#define SMOKE_SPEED 0.5 // Speed of smoke movement +#define SMOKE_SCALE 25.0 // Scale of smoke detail +#define SMOKE_INTENSITY 0.2 // Intensity of the smoke effect +#define SMOKE_RISE_HEIGHT 0.14 // How high the smoke rises +#define ALPHA_MAX 0.5 // Maximum opacity for smoke +#define VERTICAL_BIAS 1.0 + +// Ghost face settings +#define FACE_COUNT 1 // Number of ghost faces +#define FACE_SCALE vec2(0.03, 0.05) // Size of faces, can be wider/elongated +#define FACE_DURATION 1.2 // How long faces last, can be wider/elongated +#define FACE_TRANSITION 1.5 // Face fade in/out duration +#define FACE_COLOR vec3(0.0, 0.0, 0.0) +#define GHOST_BG_COLOR vec3(1.0, 1.0, 1.0) +#define GHOST_BG_SCALE vec2(0.03, 0.06) + +float random(vec2 st) { + return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); +} + +float random1(float n) { + return fract(sin(n) * 43758.5453123); +} + +vec2 random2(float n) { + return vec2( + random1(n), + random1(n + 1234.5678) + ); +} + +float noise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + float a = random(i); + float b = random(i + vec2(1.0, 0.0)); + float c = random(i + vec2(0.0, 1.0)); + float d = random(i + vec2(1.0, 1.0)); + + vec2 u = f * f * (3.0 - 2.0 * f); + return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; +} + +// Modified elongated ellipse for more cartoon-like shapes +float cartoonEllipse(vec2 uv, vec2 center, vec2 scale) { + vec2 d = (uv - center) / scale; + float len = length(d); + // Add cartoon-like falloff + return smoothstep(1.0, 0.8, len); +} + +// Function to create ghost background shape +float ghostBackground(vec2 uv, vec2 center) { + vec2 d = (uv - center) / GHOST_BG_SCALE; + float baseShape = length(d * vec2(1.0, 0.8)); // Slightly oval + + // Add wavy bottom + float wave = sin(d.x * 6.28 + iTime) * 0.2; + float bottomWave = smoothstep(0.0, -0.5, d.y + wave); + + return smoothstep(1.0, 0.8, baseShape) + bottomWave; +} + +float ghostFace(vec2 uv, vec2 center, float time, float seed) { + vec2 faceUV = (uv - center) / FACE_SCALE; + + float eyeSize = 0.25 + random1(seed) * 0.05; + float eyeSpacing = 0.35; + vec2 leftEyePos = vec2(-eyeSpacing, 0.2); + vec2 rightEyePos = vec2(eyeSpacing, 0.2); + + float leftEye = cartoonEllipse(faceUV, leftEyePos, vec2(eyeSize)); + float rightEye = cartoonEllipse(faceUV, rightEyePos, vec2(eyeSize)); + + // Add simple eye highlights + float leftHighlight = cartoonEllipse(faceUV, leftEyePos + vec2(0.1, 0.1), vec2(eyeSize * 0.3)); + float rightHighlight = cartoonEllipse(faceUV, rightEyePos + vec2(0.1, 0.1), vec2(eyeSize * 0.3)); + + vec2 mouthUV = faceUV - vec2(0.0, -0.9); + float mouthWidth = 0.5 + random1(seed + 3.0) * 0.1; + float mouthHeight = 0.8 + random1(seed + 7.0) * 0.1; + + float mouth = cartoonEllipse(mouthUV, vec2(0.0), vec2(mouthWidth, mouthHeight)); + + // Combine features + float face = max(max(leftEye, rightEye), mouth); + face = max(face, max(leftHighlight, rightHighlight)); + + // Add border falloff + face *= smoothstep(1.2, 0.8, length(faceUV)); + + return face; +} + +float calculateSmoke(vec2 uv, vec2 sourcePos) { + float verticalDisp = (uv.y - sourcePos.y) * VERTICAL_BIAS; + vec2 smokeUV = uv * SMOKE_SCALE; + smokeUV.y -= iTime * SMOKE_SPEED * (1.0 + verticalDisp); + smokeUV.x += sin(iTime * 0.5 + uv.y * 4.0) * 0.1; + + float n = noise(smokeUV) * 0.5 + 0.5; + n += noise(smokeUV * 2.0 + iTime * 0.1) * 0.25; + + float verticalFalloff = 1.0 - smoothstep(0.0, SMOKE_RISE_HEIGHT, verticalDisp); + return n * verticalFalloff; +} + +float isTargetPixel(vec2 uv) { + vec4 color = texture(iChannel0, uv); + return float(all(lessThan(abs(color.rgb - TARGET_COLOR), vec3(COLOR_TOLERANCE)))); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord/iResolution.xy; + vec4 originalColor = texture(iChannel0, uv); + + // Calculate smoke effect + float smokeAccum = 0.0; + float targetInfluence = 0.0; + + float stepSize = SMOKE_RADIUS / 4.0; + for (float x = -SMOKE_RADIUS; x <= SMOKE_RADIUS; x += stepSize) { + for (float y = -SMOKE_RADIUS; y <= 0.0; y += stepSize) { + vec2 offset = vec2(x, y); + vec2 sampleUV = uv + offset; + + if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && + sampleUV.y >= 0.0 && sampleUV.y <= 1.0) { + float isTarget = isTargetPixel(sampleUV); + if (isTarget > 0.0) { + float dist = length(offset); + float falloff = 1.0 - smoothstep(0.0, SMOKE_RADIUS, dist); + float smoke = calculateSmoke(uv, sampleUV); + smokeAccum += smoke * falloff; + targetInfluence += falloff; + } + } + } + } + + smokeAccum /= max(targetInfluence, 1.0); + targetInfluence = smoothstep(0.0, 1.0, targetInfluence); + float smokePresence = smokeAccum * targetInfluence; + + // Calculate ghost faces with backgrounds + float faceAccum = 0.0; + float bgAccum = 0.0; + float timeBlock = floor(iTime / FACE_DURATION); + + if (smokePresence > 0.2) { + for (int i = 0; i < FACE_COUNT; i++) { + vec2 facePos = random2(timeBlock + float(i) * 1234.5); + facePos = facePos * 0.8 + 0.1; + + float faceTime = mod(iTime, FACE_DURATION); + float fadeFactor = smoothstep(0.0, FACE_TRANSITION, faceTime) * + (1.0 - smoothstep(FACE_DURATION - FACE_TRANSITION, FACE_DURATION, faceTime)); + + // Add ghost background + float ghostBg = ghostBackground(uv, facePos) * fadeFactor; + bgAccum = max(bgAccum, ghostBg); + + // Add face features + float face = ghostFace(uv, facePos, iTime, timeBlock + float(i) * 100.0) * fadeFactor; + faceAccum = max(faceAccum, face); + } + + bgAccum *= smoothstep(0.2, 0.4, smokePresence); + faceAccum *= smoothstep(0.2, 0.4, smokePresence); + } + + // Combine all elements + bool isTarget = all(lessThan(abs(originalColor.rgb - TARGET_COLOR), vec3(COLOR_TOLERANCE))); + vec3 baseColor = isTarget ? REPLACE_COLOR : originalColor.rgb; + + // Layer the effects: base -> smoke -> ghost background -> face features + vec3 smokeEffect = mix(baseColor, SMOKE_COLOR, smokeAccum * SMOKE_INTENSITY * targetInfluence * (1.0 - faceAccum)); + vec3 withBackground = mix(smokeEffect, GHOST_BG_COLOR, bgAccum * 0.7); + vec3 finalColor = mix(withBackground, FACE_COLOR, faceAccum); + + float alpha = mix(originalColor.a, ALPHA_MAX, max(smokePresence, max(bgAccum, faceAccum) * smokePresence)); + + fragColor = vec4(finalColor, alpha); +} diff --git a/ghostty/shaders/sparks-from-fire.glsl b/ghostty/shaders/sparks-from-fire.glsl new file mode 100644 index 0000000..4adb791 --- /dev/null +++ b/ghostty/shaders/sparks-from-fire.glsl @@ -0,0 +1,242 @@ +// adapted by Alex Sherwin for Ghstty from https://www.shadertoy.com/view/wl2Gzc + +//Shader License: CC BY 3.0 +//Author: Jan Mróz (jaszunio15) + +#define SMOKE_INTENSITY_MULTIPLIER 0.9 +#define PARTICLES_ALPHA_MOD 0.9 +#define SMOKE_ALPHA_MOD 0.5 +#define LAYERS_COUNT 8 + +#define BLACK_BLEND_THRESHOLD .4 + +#define VEC3_1 (vec3(1.0)) + +#define PI 3.1415927 +#define TWO_PI 6.283185 + +#define ANIMATION_SPEED 1.0 +#define MOVEMENT_SPEED .33 +#define MOVEMENT_DIRECTION vec2(0.7, 1.0) + +#define PARTICLE_SIZE 0.0025 + +#define PARTICLE_SCALE (vec2(0.5, 1.6)) +#define PARTICLE_SCALE_VAR (vec2(0.25, 0.2)) + +#define PARTICLE_BLOOM_SCALE (vec2(0.5, 0.8)) +#define PARTICLE_BLOOM_SCALE_VAR (vec2(0.3, 0.1)) + +#define SPARK_COLOR vec3(1.0, 0.4, 0.05) * 1.5 +#define BLOOM_COLOR vec3(1.0, 0.4, 0.05) * 0.8 +#define SMOKE_COLOR vec3(1.0, 0.43, 0.1) * 0.8 + +#define SIZE_MOD 1.05 + + +float hash1_2(in vec2 x) +{ + return fract(sin(dot(x, vec2(52.127, 61.2871))) * 521.582); +} + +vec2 hash2_2(in vec2 x) +{ + return fract(sin(x * mat2x2(20.52, 24.1994, 70.291, 80.171)) * 492.194); +} + +//Simple interpolated noise +vec2 noise2_2(vec2 uv) +{ + //vec2 f = fract(uv); + vec2 f = smoothstep(0.0, 1.0, fract(uv)); + + vec2 uv00 = floor(uv); + vec2 uv01 = uv00 + vec2(0,1); + vec2 uv10 = uv00 + vec2(1,0); + vec2 uv11 = uv00 + 1.0; + vec2 v00 = hash2_2(uv00); + vec2 v01 = hash2_2(uv01); + vec2 v10 = hash2_2(uv10); + vec2 v11 = hash2_2(uv11); + + vec2 v0 = mix(v00, v01, f.y); + vec2 v1 = mix(v10, v11, f.y); + vec2 v = mix(v0, v1, f.x); + + return v; +} + +//Simple interpolated noise +float noise1_2(in vec2 uv) +{ + // vec2 f = fract(uv); + vec2 f = smoothstep(0.0, 1.0, fract(uv)); + + vec2 uv00 = floor(uv); + vec2 uv01 = uv00 + vec2(0,1); + vec2 uv10 = uv00 + vec2(1,0); + vec2 uv11 = uv00 + 1.0; + + float v00 = hash1_2(uv00); + float v01 = hash1_2(uv01); + float v10 = hash1_2(uv10); + float v11 = hash1_2(uv11); + + float v0 = mix(v00, v01, f.y); + float v1 = mix(v10, v11, f.y); + float v = mix(v0, v1, f.x); + + return v; +} + + +float layeredNoise1_2(in vec2 uv, in float sizeMod, in float alphaMod, in int layers, in float animation) +{ + float noise = 0.0; + float alpha = 1.0; + float size = 1.0; + vec2 offset; + for (int i = 0; i < layers; i++) + { + offset += hash2_2(vec2(alpha, size)) * 10.0; + + //Adding noise with movement + noise += noise1_2(uv * size + iTime * animation * 8.0 * MOVEMENT_DIRECTION * MOVEMENT_SPEED + offset) * alpha; + alpha *= alphaMod; + size *= sizeMod; + } + + noise *= (1.0 - alphaMod)/(1.0 - pow(alphaMod, float(layers))); + return noise; +} + +//Rotates point around 0,0 +vec2 rotate(in vec2 point, in float deg) +{ + float s = sin(deg); + float c = cos(deg); + return mat2x2(s, c, -c, s) * point; +} + +//Cell center from point on the grid +vec2 voronoiPointFromRoot(in vec2 root, in float deg) +{ + vec2 point = hash2_2(root) - 0.5; + float s = sin(deg); + float c = cos(deg); + point = mat2x2(s, c, -c, s) * point * 0.66; + point += root + 0.5; + return point; +} + +//Voronoi cell point rotation degrees +float degFromRootUV(in vec2 uv) +{ + return iTime * ANIMATION_SPEED * (hash1_2(uv) - 0.5) * 2.0; +} + +vec2 randomAround2_2(in vec2 point, in vec2 range, in vec2 uv) +{ + return point + (hash2_2(uv) - 0.5) * range; +} + + +vec3 fireParticles(in vec2 uv, in vec2 originalUV) +{ + vec3 particles = vec3(0.0); + vec2 rootUV = floor(uv); + float deg = degFromRootUV(rootUV); + vec2 pointUV = voronoiPointFromRoot(rootUV, deg); + float dist = 2.0; + float distBloom = 0.0; + + //UV manipulation for the faster particle movement + vec2 tempUV = uv + (noise2_2(uv * 2.0) - 0.5) * 0.1; + tempUV += -(noise2_2(uv * 3.0 + iTime) - 0.5) * 0.07; + + //Sparks sdf + dist = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_SCALE, PARTICLE_SCALE_VAR, rootUV)); + + //Bloom sdf + distBloom = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_BLOOM_SCALE, PARTICLE_BLOOM_SCALE_VAR, rootUV)); + + //Add sparks + particles += (1.0 - smoothstep(PARTICLE_SIZE * 0.6, PARTICLE_SIZE * 3.0, dist)) * SPARK_COLOR; + + //Add bloom + particles += pow((1.0 - smoothstep(0.0, PARTICLE_SIZE * 6.0, distBloom)) * 1.0, 3.0) * BLOOM_COLOR; + + //Upper disappear curve randomization + float border = (hash1_2(rootUV) - 0.5) * 2.0; + float disappear = 1.0 - smoothstep(border, border + 0.5, originalUV.y); + + //Lower appear curve randomization + border = (hash1_2(rootUV + 0.214) - 1.8) * 0.7; + float appear = smoothstep(border, border + 0.4, originalUV.y); + + return particles * disappear * appear; +} + + +//Layering particles to imitate 3D view +vec3 layeredParticles(in vec2 uv, in float sizeMod, in float alphaMod, in int layers, in float smoke) +{ + vec3 particles = vec3(0); + float size = 1.0; + // float alpha = 1.0; + float alpha = 1.0; + vec2 offset = vec2(0.0); + vec2 noiseOffset; + vec2 bokehUV; + + for (int i = 0; i < layers; i++) + { + //Particle noise movement + noiseOffset = (noise2_2(uv * size * 2.0 + 0.5) - 0.5) * 0.15; + + //UV with applied movement + bokehUV = (uv * size + iTime * MOVEMENT_DIRECTION * MOVEMENT_SPEED) + offset + noiseOffset; + + //Adding particles if there is more smoke, remove smaller particles + particles += fireParticles(bokehUV, uv) * alpha * (1.0 - smoothstep(0.0, 1.0, smoke) * (float(i) / float(layers))); + + //Moving uv origin to avoid generating the same particles + offset += hash2_2(vec2(alpha, alpha)) * 10.0; + + alpha *= alphaMod; + size *= sizeMod; + } + + return particles; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = (2.0 * fragCoord - iResolution.xy) / iResolution.x; + + // float vignette = 1.1 - smoothstep(0.4, 1.4, length(uv + vec2(0.0, 0.3))); + float vignette = 1.3 - smoothstep(0.4, 1.4, length(uv + vec2(0.0, 0.3))); + + uv *= 2.5; + + float smokeIntensity = layeredNoise1_2(uv * 10.0 + iTime * 4.0 * MOVEMENT_DIRECTION * MOVEMENT_SPEED, 1.7, 0.7, 6, 0.2); + smokeIntensity *= pow(smoothstep(-1.0, 1.6, uv.y), 2.0); + vec3 smoke = smokeIntensity * SMOKE_COLOR * vignette * SMOKE_INTENSITY_MULTIPLIER * SMOKE_ALPHA_MOD; + + //Cutting holes in smoke + smoke *= pow(layeredNoise1_2(uv * 4.0 + iTime * 0.5 * MOVEMENT_DIRECTION * MOVEMENT_SPEED, 1.8, 0.5, 3, 0.2), 2.0) * 1.5; + + vec3 particles = layeredParticles(uv, SIZE_MOD, PARTICLES_ALPHA_MOD, LAYERS_COUNT, smokeIntensity); + + vec3 col = particles + smoke + SMOKE_COLOR * 0.02; + col *= vignette; + + col = smoothstep(-0.08, 1.0, col); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb, col, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/spotlight.glsl b/ghostty/shaders/spotlight.glsl new file mode 100644 index 0000000..19f457a --- /dev/null +++ b/ghostty/shaders/spotlight.glsl @@ -0,0 +1,42 @@ +// Created by Paul Robello + + +// Smooth oscillating function that varies over time +float smoothOscillation(float t, float frequency, float phase) { + return sin(t * frequency + phase); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + // Resolution and UV coordinates + vec2 uv = fragCoord.xy / iResolution.xy; + + // Used to fix distortion when calculating distance to circle center + vec2 ratio = vec2(iResolution.x / iResolution.y, 1.0); + + // Get the texture from iChannel0 + vec4 texColor = texture(iChannel0, uv); + + // Spotlight center moving based on a smooth random pattern + float time = iTime * 1.0; // Control speed of motion + vec2 spotlightCenter = vec2( + 0.5 + 0.4 * smoothOscillation(time, 1.0, 0.0), // Smooth X motion + 0.5 + 0.4 * smoothOscillation(time, 1.3, 3.14159) // Smooth Y motion with different frequency and phase + ); + + // Distance from the spotlight center + float distanceToCenter = distance(uv * ratio, spotlightCenter); + + // Spotlight intensity based on distance + float spotlightRadius = 0.25; // Spotlight radius + float softness = 20.0; // Spotlight edge softness. Higher values have sharper edge + float spotlightIntensity = smoothstep(spotlightRadius, spotlightRadius - (1.0 / softness), distanceToCenter); + + // Ambient light level + float ambientLight = 0.5; // Controls the minimum brightness across the texture + + // Combine the spotlight effect with the texture + vec3 spotlightEffect = texColor.rgb * mix(vec3(ambientLight), vec3(1.0), spotlightIntensity); + + // Final color output + fragColor = vec4(spotlightEffect, texColor.a); +} \ No newline at end of file diff --git a/ghostty/shaders/starfield-colors.glsl b/ghostty/shaders/starfield-colors.glsl new file mode 100644 index 0000000..d4e0d14 --- /dev/null +++ b/ghostty/shaders/starfield-colors.glsl @@ -0,0 +1,158 @@ +// transparent background +const bool transparent = false; + +// terminal contents luminance threshold to be considered background (0.0 to 1.0) +const float threshold = 0.15; + +// divisions of grid +const float repeats = 30.; + +// number of layers +const float layers = 21.; + +// star colours +const vec3 blue = vec3(51., 64., 195.) / 255.; +const vec3 cyan = vec3(117., 250., 254.) / 255.; +const vec3 white = vec3(255., 255., 255.) / 255.; +const vec3 yellow = vec3(251., 245., 44.) / 255.; +const vec3 red = vec3(247, 2., 20.) / 255.; + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +// spectrum function +vec3 spectrum(vec2 pos) { + pos.x *= 4.; + vec3 outCol = vec3(0); + if (pos.x > 0.) { + outCol = mix(blue, cyan, fract(pos.x)); + } + if (pos.x > 1.) { + outCol = mix(cyan, white, fract(pos.x)); + } + if (pos.x > 2.) { + outCol = mix(white, yellow, fract(pos.x)); + } + if (pos.x > 3.) { + outCol = mix(yellow, red, fract(pos.x)); + } + + return 1. - (pos.y * (1. - outCol)); +} + +float N21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +vec2 N22(vec2 p) { + float n = N21(p); + return vec2(n, N21(p + n)); +} + +mat2 scale(vec2 _scale) { + return mat2(_scale.x, 0.0, + 0.0, _scale.y); +} + +// 2D Noise based on Morgan McGuire +float noise(in vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + float a = N21(i); + float b = N21(i + vec2(1.0, 0.0)); + float c = N21(i + vec2(0.0, 1.0)); + float d = N21(i + vec2(1.0, 1.0)); + + // Smooth Interpolation + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve + + // Mix 4 corners percentages + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +float perlin2(vec2 uv, int octaves, float pscale) { + float col = 1.; + float initScale = 4.; + for (int l; l < octaves; l++) { + float val = noise(uv * initScale); + if (col <= 0.01) { + col = 0.; + break; + } + val -= 0.01; + val *= 0.5; + col *= val; + initScale *= pscale; + } + return col; +} + +vec3 stars(vec2 uv, float offset) { + float timeScale = -(iTime + offset) / layers; + float trans = fract(timeScale); + float newRnd = floor(timeScale); + vec3 col = vec3(0.); + + // Translate uv then scale for center + uv -= vec2(0.5); + uv = scale(vec2(trans)) * uv; + uv += vec2(0.5); + + // Create square aspect ratio + uv.x *= iResolution.x / iResolution.y; + + // Create boxes + uv *= repeats; + + // Get position + vec2 ipos = floor(uv); + + // Return uv as 0 to 1 + uv = fract(uv); + + // Calculate random xy and size + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; + float rndSize = N21(ipos) * 100. + 200.; + + vec2 j = (rndXY - uv) * rndSize; + float sparkle = 1. / dot(j, j); + + // Set stars to be pure white + col += spectrum(fract(rndXY * newRnd * ipos)) * vec3(sparkle); + + col *= smoothstep(1., 0.8, trans); + return col; // Return pure white stars only +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord / iResolution.xy; + + vec3 col = vec3(0.); + + for (float i = 0.; i < layers; i++) { + col += stars(uv, i); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + if (transparent) { + col += terminalColor.rgb; + } + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(threshold, luminance(terminalColor.rgb)); + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/starfield.glsl b/ghostty/shaders/starfield.glsl new file mode 100644 index 0000000..f82b5d3 --- /dev/null +++ b/ghostty/shaders/starfield.glsl @@ -0,0 +1,135 @@ +// transparent background +const bool transparent = false; + +// terminal contents luminance threshold to be considered background (0.0 to 1.0) +const float threshold = 0.15; + +// divisions of grid +const float repeats = 30.; + +// number of layers +const float layers = 21.; + +// star colors +const vec3 white = vec3(1.0); // Set star color to pure white + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +float N21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +vec2 N22(vec2 p) { + float n = N21(p); + return vec2(n, N21(p + n)); +} + +mat2 scale(vec2 _scale) { + return mat2(_scale.x, 0.0, + 0.0, _scale.y); +} + +// 2D Noise based on Morgan McGuire +float noise(in vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + float a = N21(i); + float b = N21(i + vec2(1.0, 0.0)); + float c = N21(i + vec2(0.0, 1.0)); + float d = N21(i + vec2(1.0, 1.0)); + + // Smooth Interpolation + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve + + // Mix 4 corners percentages + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +float perlin2(vec2 uv, int octaves, float pscale) { + float col = 1.; + float initScale = 4.; + for (int l; l < octaves; l++) { + float val = noise(uv * initScale); + if (col <= 0.01) { + col = 0.; + break; + } + val -= 0.01; + val *= 0.5; + col *= val; + initScale *= pscale; + } + return col; +} + +vec3 stars(vec2 uv, float offset) { + float timeScale = -(iTime + offset) / layers; + float trans = fract(timeScale); + float newRnd = floor(timeScale); + vec3 col = vec3(0.); + + // Translate uv then scale for center + uv -= vec2(0.5); + uv = scale(vec2(trans)) * uv; + uv += vec2(0.5); + + // Create square aspect ratio + uv.x *= iResolution.x / iResolution.y; + + // Create boxes + uv *= repeats; + + // Get position + vec2 ipos = floor(uv); + + // Return uv as 0 to 1 + uv = fract(uv); + + // Calculate random xy and size + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; + float rndSize = N21(ipos) * 100. + 200.; + + vec2 j = (rndXY - uv) * rndSize; + float sparkle = 1. / dot(j, j); + + // Set stars to be pure white + col += white * sparkle; + + col *= smoothstep(1., 0.8, trans); + return col; // Return pure white stars only +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord / iResolution.xy; + + vec3 col = vec3(0.); + + for (float i = 0.; i < layers; i++) { + col += stars(uv, i); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + if (transparent) { + col += terminalColor.rgb; + } + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(threshold, luminance(terminalColor.rgb)); + + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/tft.glsl b/ghostty/shaders/tft.glsl new file mode 100644 index 0000000..3d77443 --- /dev/null +++ b/ghostty/shaders/tft.glsl @@ -0,0 +1,23 @@ +/** Size of TFT "pixels" */ +float resolution = 4.0; + +/** Strength of effect */ +float strength = 0.5; + +void _scanline(inout vec3 color, vec2 uv) +{ + float scanline = step(1.2, mod(uv.y * iResolution.y, resolution)); + float grille = step(1.2, mod(uv.x * iResolution.x, resolution)); + color *= max(1.0 - strength, scanline * grille); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + vec3 color = texture(iChannel0, uv).rgb; + + _scanline(color, uv); + + fragColor.xyz = color; + fragColor.w = 1.0; +} diff --git a/ghostty/shaders/underwater.glsl b/ghostty/shaders/underwater.glsl new file mode 100644 index 0000000..8c2fb22 --- /dev/null +++ b/ghostty/shaders/underwater.glsl @@ -0,0 +1,74 @@ +// adapted by Alex Sherwin for Ghostty from https://www.shadertoy.com/view/lljGDt + +#define BLACK_BLEND_THRESHOLD .4 + +float hash21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +float rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord, float seedA, float seedB, float speed) +{ + vec2 sourceToCoord = coord - raySource; + float cosAngle = dot(normalize(sourceToCoord), rayRefDirection); + + // Add subtle dithering based on screen coordinates + float dither = hash21(coord) * 0.015 - 0.0075; + + float ray = clamp( + (0.45 + 0.15 * sin(cosAngle * seedA + iTime * speed)) + + (0.3 + 0.2 * cos(-cosAngle * seedB + iTime * speed)) + dither, + 0.0, 1.0); + + // Smoothstep the distance falloff + float distFade = smoothstep(0.0, iResolution.x, iResolution.x - length(sourceToCoord)); + return ray * mix(0.5, 1.0, distFade); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + uv.y = 1.0 - uv.y; + vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y); + + // Set the parameters of the sun rays + vec2 rayPos1 = vec2(iResolution.x * 0.7, iResolution.y * 1.1); + vec2 rayRefDir1 = normalize(vec2(1.0, 0.116)); + float raySeedA1 = 36.2214; + float raySeedB1 = 21.11349; + float raySpeed1 = 1.1; + + vec2 rayPos2 = vec2(iResolution.x * 0.8, iResolution.y * 1.2); + vec2 rayRefDir2 = normalize(vec2(1.0, -0.241)); + const float raySeedA2 = 22.39910; + const float raySeedB2 = 18.0234; + const float raySpeed2 = 0.9; + + // Calculate the colour of the sun rays on the current fragment + vec4 rays1 = + vec4(1.0, 1.0, 1.0, 0.0) * + rayStrength(rayPos1, rayRefDir1, coord, raySeedA1, raySeedB1, raySpeed1); + + vec4 rays2 = + vec4(1.0, 1.0, 1.0, 0.0) * + rayStrength(rayPos2, rayRefDir2, coord, raySeedA2, raySeedB2, raySpeed2); + + vec4 col = rays1 * 0.5 + rays2 * 0.4; + + // Attenuate brightness towards the bottom, simulating light-loss due to depth. + // Give the whole thing a blue-green tinge as well. + float brightness = 1.0 - (coord.y / iResolution.y); + col.r *= 0.05 + (brightness * 0.8); + col.g *= 0.15 + (brightness * 0.6); + col.b *= 0.3 + (brightness * 0.5); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/ghostty/shaders/water.glsl b/ghostty/shaders/water.glsl new file mode 100644 index 0000000..c240b58 --- /dev/null +++ b/ghostty/shaders/water.glsl @@ -0,0 +1,35 @@ + +#define TAU 6.28318530718 +#define MAX_ITER 6 + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec3 water_color = vec3(1.0, 1.0, 1.0) * 0.5; + float time = iTime * 0.5+23.0; + vec2 uv = fragCoord.xy / iResolution.xy; + + vec2 p = mod(uv*TAU, TAU)-250.0; + vec2 i = vec2(p); + float c = 1.0; + float inten = 0.005; + + for (int n = 0; n < MAX_ITER; n++) + { + float t = time * (1.0 - (3.5 / float(n+1))); + i = p + vec2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x)); + c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten))); + } + c /= float(MAX_ITER); + c = 1.17-pow(c, 1.4); + vec3 color = vec3(pow(abs(c), 15.0)); + color = clamp((color + water_color)*1.2, 0.0, 1.0); + + // perterb uv based on value of c from caustic calc above + vec2 tc = vec2(cos(c)-0.75,sin(c)-0.75)*0.04; + uv = clamp(uv + tc,0.0,1.0); + + fragColor = texture(iChannel0, uv); + // give transparent pixels a color + if ( fragColor.a == 0.0 ) fragColor=vec4(1.0,1.0,1.0,1.0); + fragColor *= vec4(color, 1.0); +} \ No newline at end of file diff --git a/grub/Elegant-Based/MapleMono-CN-Regular.pf2 b/grub/Elegant-Based/MapleMono-CN-Regular.pf2 new file mode 100644 index 0000000..0181f02 Binary files /dev/null and b/grub/Elegant-Based/MapleMono-CN-Regular.pf2 differ diff --git a/grub/Elegant-Based/background.png b/grub/Elegant-Based/background.png new file mode 100755 index 0000000..cc2ce7d Binary files /dev/null and b/grub/Elegant-Based/background.png differ diff --git a/grub/Elegant-Based/dejavu_sans_12.pf2 b/grub/Elegant-Based/dejavu_sans_12.pf2 new file mode 100755 index 0000000..19e0499 Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_12.pf2 differ diff --git a/grub/Elegant-Based/dejavu_sans_14.pf2 b/grub/Elegant-Based/dejavu_sans_14.pf2 new file mode 100755 index 0000000..dcc727e Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_14.pf2 differ diff --git a/grub/Elegant-Based/dejavu_sans_16.pf2 b/grub/Elegant-Based/dejavu_sans_16.pf2 new file mode 100755 index 0000000..37f3ef4 Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_16.pf2 differ diff --git a/grub/Elegant-Based/dejavu_sans_24.pf2 b/grub/Elegant-Based/dejavu_sans_24.pf2 new file mode 100755 index 0000000..8c3e434 Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_24.pf2 differ diff --git a/grub/Elegant-Based/dejavu_sans_32.pf2 b/grub/Elegant-Based/dejavu_sans_32.pf2 new file mode 100755 index 0000000..bbbbe28 Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_32.pf2 differ diff --git a/grub/Elegant-Based/dejavu_sans_48.pf2 b/grub/Elegant-Based/dejavu_sans_48.pf2 new file mode 100755 index 0000000..776c982 Binary files /dev/null and b/grub/Elegant-Based/dejavu_sans_48.pf2 differ diff --git a/grub/Elegant-Based/icons/4MLinux.png b/grub/Elegant-Based/icons/4MLinux.png new file mode 100755 index 0000000..72b60c6 Binary files /dev/null and b/grub/Elegant-Based/icons/4MLinux.png differ diff --git a/grub/Elegant-Based/icons/AlpineLinux.png b/grub/Elegant-Based/icons/AlpineLinux.png new file mode 100755 index 0000000..4c27dc6 Binary files /dev/null and b/grub/Elegant-Based/icons/AlpineLinux.png differ diff --git a/grub/Elegant-Based/icons/Manjaro.i686.png b/grub/Elegant-Based/icons/Manjaro.i686.png new file mode 100755 index 0000000..8cdc0c5 Binary files /dev/null and b/grub/Elegant-Based/icons/Manjaro.i686.png differ diff --git a/grub/Elegant-Based/icons/Manjaro.x86_64.png b/grub/Elegant-Based/icons/Manjaro.x86_64.png new file mode 100755 index 0000000..8cdc0c5 Binary files /dev/null and b/grub/Elegant-Based/icons/Manjaro.x86_64.png differ diff --git a/grub/Elegant-Based/icons/SystemRescueCD.png b/grub/Elegant-Based/icons/SystemRescueCD.png new file mode 100755 index 0000000..c56a441 Binary files /dev/null and b/grub/Elegant-Based/icons/SystemRescueCD.png differ diff --git a/grub/Elegant-Based/icons/android.png b/grub/Elegant-Based/icons/android.png new file mode 100755 index 0000000..5a92580 Binary files /dev/null and b/grub/Elegant-Based/icons/android.png differ diff --git a/grub/Elegant-Based/icons/anonymous.png b/grub/Elegant-Based/icons/anonymous.png new file mode 100755 index 0000000..31b883c Binary files /dev/null and b/grub/Elegant-Based/icons/anonymous.png differ diff --git a/grub/Elegant-Based/icons/antergos.png b/grub/Elegant-Based/icons/antergos.png new file mode 100755 index 0000000..9cfbc2e Binary files /dev/null and b/grub/Elegant-Based/icons/antergos.png differ diff --git a/grub/Elegant-Based/icons/arch.png b/grub/Elegant-Based/icons/arch.png new file mode 100755 index 0000000..078b383 Binary files /dev/null and b/grub/Elegant-Based/icons/arch.png differ diff --git a/grub/Elegant-Based/icons/archcraft.png b/grub/Elegant-Based/icons/archcraft.png new file mode 100755 index 0000000..6115f47 Binary files /dev/null and b/grub/Elegant-Based/icons/archcraft.png differ diff --git a/grub/Elegant-Based/icons/archlinux.png b/grub/Elegant-Based/icons/archlinux.png new file mode 100755 index 0000000..078b383 Binary files /dev/null and b/grub/Elegant-Based/icons/archlinux.png differ diff --git a/grub/Elegant-Based/icons/arcolinux.png b/grub/Elegant-Based/icons/arcolinux.png new file mode 100755 index 0000000..c4029f9 Binary files /dev/null and b/grub/Elegant-Based/icons/arcolinux.png differ diff --git a/grub/Elegant-Based/icons/artix.png b/grub/Elegant-Based/icons/artix.png new file mode 100755 index 0000000..7f12ea1 Binary files /dev/null and b/grub/Elegant-Based/icons/artix.png differ diff --git a/grub/Elegant-Based/icons/brunch-settings.png b/grub/Elegant-Based/icons/brunch-settings.png new file mode 100755 index 0000000..595fb09 Binary files /dev/null and b/grub/Elegant-Based/icons/brunch-settings.png differ diff --git a/grub/Elegant-Based/icons/brunch.png b/grub/Elegant-Based/icons/brunch.png new file mode 100755 index 0000000..79757c5 Binary files /dev/null and b/grub/Elegant-Based/icons/brunch.png differ diff --git a/grub/Elegant-Based/icons/cachyos.png b/grub/Elegant-Based/icons/cachyos.png new file mode 100644 index 0000000..e565a15 Binary files /dev/null and b/grub/Elegant-Based/icons/cachyos.png differ diff --git a/grub/Elegant-Based/icons/cancel.png b/grub/Elegant-Based/icons/cancel.png new file mode 100755 index 0000000..7059c5d Binary files /dev/null and b/grub/Elegant-Based/icons/cancel.png differ diff --git a/grub/Elegant-Based/icons/chakra.png b/grub/Elegant-Based/icons/chakra.png new file mode 100755 index 0000000..b5450d3 Binary files /dev/null and b/grub/Elegant-Based/icons/chakra.png differ diff --git a/grub/Elegant-Based/icons/chimera.png b/grub/Elegant-Based/icons/chimera.png new file mode 100755 index 0000000..f33db61 Binary files /dev/null and b/grub/Elegant-Based/icons/chimera.png differ diff --git a/grub/Elegant-Based/icons/debian.png b/grub/Elegant-Based/icons/debian.png new file mode 100755 index 0000000..6ee1670 Binary files /dev/null and b/grub/Elegant-Based/icons/debian.png differ diff --git a/grub/Elegant-Based/icons/deepin.png b/grub/Elegant-Based/icons/deepin.png new file mode 100755 index 0000000..b7307fb Binary files /dev/null and b/grub/Elegant-Based/icons/deepin.png differ diff --git a/grub/Elegant-Based/icons/devuan.png b/grub/Elegant-Based/icons/devuan.png new file mode 100755 index 0000000..1fd8eaf Binary files /dev/null and b/grub/Elegant-Based/icons/devuan.png differ diff --git a/grub/Elegant-Based/icons/driver.png b/grub/Elegant-Based/icons/driver.png new file mode 100755 index 0000000..58bb462 Binary files /dev/null and b/grub/Elegant-Based/icons/driver.png differ diff --git a/grub/Elegant-Based/icons/edit.png b/grub/Elegant-Based/icons/edit.png new file mode 100755 index 0000000..8a64dbe Binary files /dev/null and b/grub/Elegant-Based/icons/edit.png differ diff --git a/grub/Elegant-Based/icons/efi.png b/grub/Elegant-Based/icons/efi.png new file mode 100755 index 0000000..e2b0294 Binary files /dev/null and b/grub/Elegant-Based/icons/efi.png differ diff --git a/grub/Elegant-Based/icons/elementary.png b/grub/Elegant-Based/icons/elementary.png new file mode 100755 index 0000000..e363800 Binary files /dev/null and b/grub/Elegant-Based/icons/elementary.png differ diff --git a/grub/Elegant-Based/icons/endeavouros.png b/grub/Elegant-Based/icons/endeavouros.png new file mode 100755 index 0000000..85b2211 Binary files /dev/null and b/grub/Elegant-Based/icons/endeavouros.png differ diff --git a/grub/Elegant-Based/icons/fedora.png b/grub/Elegant-Based/icons/fedora.png new file mode 100755 index 0000000..6e4792b Binary files /dev/null and b/grub/Elegant-Based/icons/fedora.png differ diff --git a/grub/Elegant-Based/icons/find.efi.png b/grub/Elegant-Based/icons/find.efi.png new file mode 100755 index 0000000..2515b85 Binary files /dev/null and b/grub/Elegant-Based/icons/find.efi.png differ diff --git a/grub/Elegant-Based/icons/find.none.png b/grub/Elegant-Based/icons/find.none.png new file mode 100755 index 0000000..a44e700 Binary files /dev/null and b/grub/Elegant-Based/icons/find.none.png differ diff --git a/grub/Elegant-Based/icons/freebsd.png b/grub/Elegant-Based/icons/freebsd.png new file mode 100755 index 0000000..b8f4f51 Binary files /dev/null and b/grub/Elegant-Based/icons/freebsd.png differ diff --git a/grub/Elegant-Based/icons/gentoo.png b/grub/Elegant-Based/icons/gentoo.png new file mode 100755 index 0000000..b611d16 Binary files /dev/null and b/grub/Elegant-Based/icons/gentoo.png differ diff --git a/grub/Elegant-Based/icons/gnu-linux.png b/grub/Elegant-Based/icons/gnu-linux.png new file mode 100755 index 0000000..3fd8fb3 Binary files /dev/null and b/grub/Elegant-Based/icons/gnu-linux.png differ diff --git a/grub/Elegant-Based/icons/gpart.png b/grub/Elegant-Based/icons/gpart.png new file mode 100755 index 0000000..770bbdd Binary files /dev/null and b/grub/Elegant-Based/icons/gpart.png differ diff --git a/grub/Elegant-Based/icons/haiku.png b/grub/Elegant-Based/icons/haiku.png new file mode 100755 index 0000000..683b135 Binary files /dev/null and b/grub/Elegant-Based/icons/haiku.png differ diff --git a/grub/Elegant-Based/icons/help.png b/grub/Elegant-Based/icons/help.png new file mode 100755 index 0000000..3bb6ad1 Binary files /dev/null and b/grub/Elegant-Based/icons/help.png differ diff --git a/grub/Elegant-Based/icons/kali.png b/grub/Elegant-Based/icons/kali.png new file mode 100755 index 0000000..8f36dce Binary files /dev/null and b/grub/Elegant-Based/icons/kali.png differ diff --git a/grub/Elegant-Based/icons/kaos.png b/grub/Elegant-Based/icons/kaos.png new file mode 100755 index 0000000..7d26788 Binary files /dev/null and b/grub/Elegant-Based/icons/kaos.png differ diff --git a/grub/Elegant-Based/icons/kbd.png b/grub/Elegant-Based/icons/kbd.png new file mode 100755 index 0000000..540ef51 Binary files /dev/null and b/grub/Elegant-Based/icons/kbd.png differ diff --git a/grub/Elegant-Based/icons/kernel.png b/grub/Elegant-Based/icons/kernel.png new file mode 100755 index 0000000..88ae952 Binary files /dev/null and b/grub/Elegant-Based/icons/kernel.png differ diff --git a/grub/Elegant-Based/icons/korora.png b/grub/Elegant-Based/icons/korora.png new file mode 100755 index 0000000..cd06b6b Binary files /dev/null and b/grub/Elegant-Based/icons/korora.png differ diff --git a/grub/Elegant-Based/icons/kubuntu.png b/grub/Elegant-Based/icons/kubuntu.png new file mode 100755 index 0000000..6f5e0b1 Binary files /dev/null and b/grub/Elegant-Based/icons/kubuntu.png differ diff --git a/grub/Elegant-Based/icons/lang.png b/grub/Elegant-Based/icons/lang.png new file mode 100755 index 0000000..5c21955 Binary files /dev/null and b/grub/Elegant-Based/icons/lang.png differ diff --git a/grub/Elegant-Based/icons/lfs.png b/grub/Elegant-Based/icons/lfs.png new file mode 100755 index 0000000..3fd8fb3 Binary files /dev/null and b/grub/Elegant-Based/icons/lfs.png differ diff --git a/grub/Elegant-Based/icons/linux.png b/grub/Elegant-Based/icons/linux.png new file mode 100755 index 0000000..3fd8fb3 Binary files /dev/null and b/grub/Elegant-Based/icons/linux.png differ diff --git a/grub/Elegant-Based/icons/linuxmint.png b/grub/Elegant-Based/icons/linuxmint.png new file mode 100755 index 0000000..1a6c1ea Binary files /dev/null and b/grub/Elegant-Based/icons/linuxmint.png differ diff --git a/grub/Elegant-Based/icons/lubuntu.png b/grub/Elegant-Based/icons/lubuntu.png new file mode 100755 index 0000000..ed6543a Binary files /dev/null and b/grub/Elegant-Based/icons/lubuntu.png differ diff --git a/grub/Elegant-Based/icons/macosx.png b/grub/Elegant-Based/icons/macosx.png new file mode 100755 index 0000000..83adb8a Binary files /dev/null and b/grub/Elegant-Based/icons/macosx.png differ diff --git a/grub/Elegant-Based/icons/mageia.png b/grub/Elegant-Based/icons/mageia.png new file mode 100755 index 0000000..a17eaab Binary files /dev/null and b/grub/Elegant-Based/icons/mageia.png differ diff --git a/grub/Elegant-Based/icons/manjaro.png b/grub/Elegant-Based/icons/manjaro.png new file mode 100755 index 0000000..8cdc0c5 Binary files /dev/null and b/grub/Elegant-Based/icons/manjaro.png differ diff --git a/grub/Elegant-Based/icons/manjarolinux.png b/grub/Elegant-Based/icons/manjarolinux.png new file mode 100755 index 0000000..8cdc0c5 Binary files /dev/null and b/grub/Elegant-Based/icons/manjarolinux.png differ diff --git a/grub/Elegant-Based/icons/memtest.png b/grub/Elegant-Based/icons/memtest.png new file mode 100755 index 0000000..58bb462 Binary files /dev/null and b/grub/Elegant-Based/icons/memtest.png differ diff --git a/grub/Elegant-Based/icons/mx-linux.png b/grub/Elegant-Based/icons/mx-linux.png new file mode 100755 index 0000000..f0cccf0 Binary files /dev/null and b/grub/Elegant-Based/icons/mx-linux.png differ diff --git a/grub/Elegant-Based/icons/neon.png b/grub/Elegant-Based/icons/neon.png new file mode 100755 index 0000000..225eeae Binary files /dev/null and b/grub/Elegant-Based/icons/neon.png differ diff --git a/grub/Elegant-Based/icons/nixos.png b/grub/Elegant-Based/icons/nixos.png new file mode 100755 index 0000000..ebcd1fe Binary files /dev/null and b/grub/Elegant-Based/icons/nixos.png differ diff --git a/grub/Elegant-Based/icons/opensuse.png b/grub/Elegant-Based/icons/opensuse.png new file mode 100755 index 0000000..453aa5e Binary files /dev/null and b/grub/Elegant-Based/icons/opensuse.png differ diff --git a/grub/Elegant-Based/icons/parrot.png b/grub/Elegant-Based/icons/parrot.png new file mode 100755 index 0000000..a0b383d Binary files /dev/null and b/grub/Elegant-Based/icons/parrot.png differ diff --git a/grub/Elegant-Based/icons/pop-os.png b/grub/Elegant-Based/icons/pop-os.png new file mode 100755 index 0000000..aa05f39 Binary files /dev/null and b/grub/Elegant-Based/icons/pop-os.png differ diff --git a/grub/Elegant-Based/icons/pop.png b/grub/Elegant-Based/icons/pop.png new file mode 100755 index 0000000..aa05f39 Binary files /dev/null and b/grub/Elegant-Based/icons/pop.png differ diff --git a/grub/Elegant-Based/icons/recovery.png b/grub/Elegant-Based/icons/recovery.png new file mode 100755 index 0000000..d70ed51 Binary files /dev/null and b/grub/Elegant-Based/icons/recovery.png differ diff --git a/grub/Elegant-Based/icons/regolith.png b/grub/Elegant-Based/icons/regolith.png new file mode 100755 index 0000000..788d51b Binary files /dev/null and b/grub/Elegant-Based/icons/regolith.png differ diff --git a/grub/Elegant-Based/icons/restart.png b/grub/Elegant-Based/icons/restart.png new file mode 100755 index 0000000..ee964f3 Binary files /dev/null and b/grub/Elegant-Based/icons/restart.png differ diff --git a/grub/Elegant-Based/icons/shutdown.png b/grub/Elegant-Based/icons/shutdown.png new file mode 100755 index 0000000..37a7f6b Binary files /dev/null and b/grub/Elegant-Based/icons/shutdown.png differ diff --git a/grub/Elegant-Based/icons/siduction.png b/grub/Elegant-Based/icons/siduction.png new file mode 100755 index 0000000..9d1ad15 Binary files /dev/null and b/grub/Elegant-Based/icons/siduction.png differ diff --git a/grub/Elegant-Based/icons/solus.png b/grub/Elegant-Based/icons/solus.png new file mode 100755 index 0000000..830f938 Binary files /dev/null and b/grub/Elegant-Based/icons/solus.png differ diff --git a/grub/Elegant-Based/icons/steamos.png b/grub/Elegant-Based/icons/steamos.png new file mode 100755 index 0000000..d0d286f Binary files /dev/null and b/grub/Elegant-Based/icons/steamos.png differ diff --git a/grub/Elegant-Based/icons/submenu.png b/grub/Elegant-Based/icons/submenu.png new file mode 100755 index 0000000..b70f325 Binary files /dev/null and b/grub/Elegant-Based/icons/submenu.png differ diff --git a/grub/Elegant-Based/icons/type.png b/grub/Elegant-Based/icons/type.png new file mode 100755 index 0000000..5224d85 Binary files /dev/null and b/grub/Elegant-Based/icons/type.png differ diff --git a/grub/Elegant-Based/icons/tz.png b/grub/Elegant-Based/icons/tz.png new file mode 100755 index 0000000..47bf9be Binary files /dev/null and b/grub/Elegant-Based/icons/tz.png differ diff --git a/grub/Elegant-Based/icons/ubuntu.png b/grub/Elegant-Based/icons/ubuntu.png new file mode 100755 index 0000000..a32b716 Binary files /dev/null and b/grub/Elegant-Based/icons/ubuntu.png differ diff --git a/grub/Elegant-Based/icons/ubuntuDDE.png b/grub/Elegant-Based/icons/ubuntuDDE.png new file mode 100755 index 0000000..bd68bfc Binary files /dev/null and b/grub/Elegant-Based/icons/ubuntuDDE.png differ diff --git a/grub/Elegant-Based/icons/unknown.png b/grub/Elegant-Based/icons/unknown.png new file mode 100755 index 0000000..3fd8fb3 Binary files /dev/null and b/grub/Elegant-Based/icons/unknown.png differ diff --git a/grub/Elegant-Based/icons/unset.png b/grub/Elegant-Based/icons/unset.png new file mode 100755 index 0000000..f587a0d Binary files /dev/null and b/grub/Elegant-Based/icons/unset.png differ diff --git a/grub/Elegant-Based/icons/void.png b/grub/Elegant-Based/icons/void.png new file mode 100755 index 0000000..6ae1f61 Binary files /dev/null and b/grub/Elegant-Based/icons/void.png differ diff --git a/grub/Elegant-Based/icons/windows.png b/grub/Elegant-Based/icons/windows.png new file mode 100755 index 0000000..a6b4d03 Binary files /dev/null and b/grub/Elegant-Based/icons/windows.png differ diff --git a/grub/Elegant-Based/icons/xubuntu.png b/grub/Elegant-Based/icons/xubuntu.png new file mode 100755 index 0000000..3d4777d Binary files /dev/null and b/grub/Elegant-Based/icons/xubuntu.png differ diff --git a/grub/Elegant-Based/icons/zorin.png b/grub/Elegant-Based/icons/zorin.png new file mode 100755 index 0000000..5908edf Binary files /dev/null and b/grub/Elegant-Based/icons/zorin.png differ diff --git a/grub/Elegant-Based/select_c.png b/grub/Elegant-Based/select_c.png new file mode 100755 index 0000000..64c7916 Binary files /dev/null and b/grub/Elegant-Based/select_c.png differ diff --git a/grub/Elegant-Based/select_e.png b/grub/Elegant-Based/select_e.png new file mode 100755 index 0000000..8d6f304 Binary files /dev/null and b/grub/Elegant-Based/select_e.png differ diff --git a/grub/Elegant-Based/select_w.png b/grub/Elegant-Based/select_w.png new file mode 100755 index 0000000..4e5a9ad Binary files /dev/null and b/grub/Elegant-Based/select_w.png differ diff --git a/grub/Elegant-Based/terminus-12.pf2 b/grub/Elegant-Based/terminus-12.pf2 new file mode 100755 index 0000000..6092035 Binary files /dev/null and b/grub/Elegant-Based/terminus-12.pf2 differ diff --git a/grub/Elegant-Based/terminus-14.pf2 b/grub/Elegant-Based/terminus-14.pf2 new file mode 100755 index 0000000..8ab8bd1 Binary files /dev/null and b/grub/Elegant-Based/terminus-14.pf2 differ diff --git a/grub/Elegant-Based/terminus-16.pf2 b/grub/Elegant-Based/terminus-16.pf2 new file mode 100755 index 0000000..6e6b25d Binary files /dev/null and b/grub/Elegant-Based/terminus-16.pf2 differ diff --git a/grub/Elegant-Based/terminus-18.pf2 b/grub/Elegant-Based/terminus-18.pf2 new file mode 100755 index 0000000..129cef1 Binary files /dev/null and b/grub/Elegant-Based/terminus-18.pf2 differ diff --git a/grub/Elegant-Based/theme.txt b/grub/Elegant-Based/theme.txt new file mode 100755 index 0000000..95c112e --- /dev/null +++ b/grub/Elegant-Based/theme.txt @@ -0,0 +1,44 @@ +# GRUB2 gfxmenu Linux theme +# Designed for any resolution + +# Global Property +title-text: "" +desktop-image: "background.png" +desktop-color: "#242424" +terminal-font: "Terminus Regular 18" +terminal-box: "terminal_box_*.png" +terminal-left: "0" +terminal-top: "0" +terminal-width: "100%" +terminal-height: "100%" +terminal-border: "0" + +# Show the boot menu ++ boot_menu { + left = 52% + top = 18% + width = 28% + height = 54% + item_font = "Maple Mono CN Regular 24" + item_color = "#efefef" + selected_item_color = "#ffffff" + icon_width = 48 + icon_height = 48 + item_icon_space = 8 + item_height = 72 + item_padding = 4 + item_spacing = 8 + selected_item_pixmap_style = "select_*.png" +} + +# Show a countdown message using the label component ++ label { + top = 76% + left = 55% + width = 23% + align = "center" + id = "__timeout__" + text = "Booting in %d seconds" + color = "#ffffff" + font = "Maple Mono CN Regular 24" +} diff --git a/grub/background.psd b/grub/background.psd new file mode 100755 index 0000000..e0a8710 Binary files /dev/null and b/grub/background.psd differ diff --git a/gsimplecal/config b/gsimplecal/config new file mode 100644 index 0000000..c18b57b --- /dev/null +++ b/gsimplecal/config @@ -0,0 +1,2 @@ +close_on_unfocus = 1 +mainwindow_resizable = 1 \ No newline at end of file diff --git a/hypr/fix.sh.noeffect b/hypr/fix.sh.noeffect new file mode 100755 index 0000000..58dd6fc --- /dev/null +++ b/hypr/fix.sh.noeffect @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +sleep 4 +killall -e xdg-desktop-portal-hyprland +killall xdg-desktop-portal +/usr/lib/xdg-desktop-portal-hyprland & +sleep 4 +/usr/lib/xdg-desktop-portal & diff --git a/hypr/hypridle.conf b/hypr/hypridle.conf new file mode 100755 index 0000000..0d2c740 --- /dev/null +++ b/hypr/hypridle.conf @@ -0,0 +1,23 @@ +$lock_cmd = pidof hyprlock || hyprlock +$suspend_cmd = pidof steam || systemctl suspend || loginctl suspend # fuck nvidia + +general { + lock_cmd = $lock_cmd + before_sleep_cmd = loginctl lock-session +} + +listener { + timeout = 180 # 3mins + on-timeout = loginctl lock-session +} + +listener { + timeout = 300 # 5mins + on-timeout = hyprctl dispatch dpms off + on-resume = hyprctl dispatch dpms on +} + +listener { + timeout = 540 # 9mins + on-timeout = $suspend_cmd +} diff --git a/hypr/hyprland.conf b/hypr/hyprland.conf new file mode 100755 index 0000000..481952a --- /dev/null +++ b/hypr/hyprland.conf @@ -0,0 +1,10 @@ +# This file sources other files in `hyprland` and `custom` folders +# You wanna add your stuff in file in `custom` + +# Defaults +source=~/.config/hypr/hyprland/env.conf +source=~/.config/hypr/hyprland/execs.conf +source=~/.config/hypr/hyprland/general.conf +source=~/.config/hypr/hyprland/rules.conf +source=~/.config/hypr/hyprland/colors.conf +source=~/.config/hypr/hyprland/keybinds.conf \ No newline at end of file diff --git a/hypr/hyprland/colors.conf b/hypr/hyprland/colors.conf new file mode 100755 index 0000000..a405272 --- /dev/null +++ b/hypr/hyprland/colors.conf @@ -0,0 +1,34 @@ +# exec = export SLURP_ARGS='-d -c BFE9F8BB -b 214C5844 -s 00000000' + +general { + col.active_border = rgba(89b4faFF) + col.inactive_border = rgba(89b4fa80) +} + +misc { + background_color = rgba(181825FF) +} + +plugin { + hyprbars { + # Honestly idk if it works like css, but well, why not + bar_text_font = Rubik, Geist, AR One Sans, Reddit Sans, Inter, Roboto, Ubuntu, Noto Sans, sans-serif + bar_height = 30 + bar_padding = 10 + bar_button_padding = 5 + bar_precedence_over_border = true + bar_part_of_window = true + + bar_color = rgba(091516FF) + col.text = rgba(D7E5E6FF) + + + # example buttons (R -> L) + # hyprbars-button = color, size, on-click + hyprbars-button = rgb(D7E5E6), 13, 󰖭, hyprctl dispatch killactive + hyprbars-button = rgb(D7E5E6), 13, 󰖯, hyprctl dispatch fullscreen 1 + hyprbars-button = rgb(D7E5E6), 13, 󰖰, hyprctl dispatch movetoworkspacesilent special + } +} + +windowrulev2 = bordercolor rgba(00DCE3AA) rgba(00DCE377),pinned:1 \ No newline at end of file diff --git a/hypr/hyprland/env.conf b/hypr/hyprland/env.conf new file mode 100755 index 0000000..b32f997 --- /dev/null +++ b/hypr/hyprland/env.conf @@ -0,0 +1,26 @@ +# ######### Input method ########## +# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland +env = QT_IM_MODULE, fcitx +env = XMODIFIERS, @im=fcitx +# env = GTK_IM_MODULE, fcitx +env = SDL_IM_MODULE, fcitx +env = GLFW_IM_MODULE, ibus +env = INPUT_METHOD, fcitx + +# ############ Themes ############# +env = QT_QPA_PLATFORM, wayland +env = QT_QPA_PLATFORMTHEME, qt5ct +env = QT_STYLE_OVERRIDE,kvantum +# env = WLR_NO_HARDWARE_CURSORS, 1 + +# ######## Screen tearing ######### +# env = WLR_DRM_NO_ATOMIC, 1 + +# ############ nvidia ############# +env = LIBVA_DRIVER_NAME,nvidia +env = NVD_BACKEND,direct + +# ############ others ############# +env = XCURSOR_SIZE,24 +env = HYPRCURSOR_SIZE,24 +env = ELECTRON_OZONE_PLATFORM_HINT,auto diff --git a/hypr/hyprland/execs.conf b/hypr/hyprland/execs.conf new file mode 100755 index 0000000..e459962 --- /dev/null +++ b/hypr/hyprland/execs.conf @@ -0,0 +1,35 @@ +# Bar, wallpaper +exec-once = waybar +exec-once = hyprpaper + +# Input method +exec-once = fcitx5 + +# Core components (authentication, lock screen, notification daemon) +exec-once = gnome-keyring-daemon --start --components=secrets +# exec-once = hyprpolkitagent +exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 +exec-once = hypridle +exec-once = dbus-update-activation-environment --all +exec-once = sleep 1 && dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP # Some fix idk +exec-once = hyprpm reload +exec-once = mako +exec-once = nm-applet +exec-once = blueman-applet + +# Audio +exec-once = easyeffects --gapplication-service + +# Clipboard: history +# exec-once = wl-paste --watch cliphist store & +exec-once = wl-paste --type text --watch cliphist store +exec-once = wl-paste --type image --watch cliphist store + +# Cursor +exec-once = hyprctl setcursor Bibata-Modern-Ice 24 + +# Plugins +exec-once = hyprctl plugin load "/usr/lib/libhyprexpo.so" + +# dock +# exec-once = nwg-dock-hyprland -d -i 32 -c "fuzzel" -ico "$HOME/.config/nwg-dock-hyprland/archlinux.png" diff --git a/hypr/hyprland/general.conf b/hypr/hyprland/general.conf new file mode 100755 index 0000000..cb8d713 --- /dev/null +++ b/hypr/hyprland/general.conf @@ -0,0 +1,178 @@ +# MONITOR CONFIG +monitor=,preferred,auto,1 +monitor=eDP-1,2560x1600@240,auto,1.25 # dGPU only +monitor=eDP-2,2560x1600@240,auto,1.25 # iGPU & dGPU hybrid +# monitor=,addreserved, 0, 0, 0, 0 # Custom reserved area + +# HDMI port: mirror display. To see device name, use `hyprctl monitors` +# monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 + + +input { + # Keyboard: Add a layout and uncomment kb_options for Win+Space switching shortcut + kb_layout = de + # kb_options = grp:win_space_toggle + numlock_by_default = true + repeat_delay = 250 + repeat_rate = 35 + + touchpad { + natural_scroll = yes + disable_while_typing = true + clickfinger_behavior = true + scroll_factor = 0.5 + } + special_fallthrough = true + follow_mouse = 1 + + sensitivity = -0.25 +} + +binds { + # focus_window_on_workspace_c# For Auto-run stuff see execs.confhange = true + scroll_event_delay = 0 +} + +gestures { + workspace_swipe = true + workspace_swipe_distance = 700 + workspace_swipe_fingers = 4 + workspace_swipe_cancel_ratio = 0.2 + workspace_swipe_min_speed_to_force = 5 + workspace_swipe_direction_lock = true + workspace_swipe_direction_lock_threshold = 10 + workspace_swipe_create_new = true +} + +general { + # Gaps and border + gaps_in = 2 + gaps_out = 0, 3, 3, 3 + gaps_workspaces = 50 + border_size = 2 + + resize_on_border = true + no_focus_fallback = true + layout = dwindle + + #focus_to_other_workspaces = true # ahhhh i still haven't properly implemented this + allow_tearing = true # This just allows the `immediate` window rule to work +} + +dwindle { + preserve_split = true + # no_gaps_when_only = 1 + smart_split = false + smart_resizing = false +} + +decoration { + rounding = 20 + + blur { + enabled = true + xray = true + special = false + new_optimizations = true + size = 14 + passes = 4 + brightness = 1 + noise = 0.01 + contrast = 1 + popups = true + popups_ignorealpha = 0.6 + } + + # Shadow + shadow { + enabled = true + ignore_window = true + range = 20 + offset = 0 2 + render_power = 4 + color = rgba(0000002A) + } + + # Shader + # screen_shader = ~/.config/hypr/shaders/nothing.frag + # screen_shader = ~/.config/hypr/shaders/vibrance.frag + + # Dim + dim_inactive = false + dim_strength = 0.1 + dim_special = 0 + + active_opacity = 1 + inactive_opacity = 0.9 +} + +animations { + enabled = true + # Animation curves + + bezier = linear, 0, 0, 1, 1 + bezier = md3_standard, 0.2, 0, 0, 1 + bezier = md3_decel, 0.05, 0.7, 0.1, 1 + bezier = md3_accel, 0.3, 0, 0.8, 0.15 + bezier = overshot, 0.05, 0.9, 0.1, 1.1 + bezier = crazyshot, 0.1, 1.5, 0.76, 0.92 + bezier = hyprnostretch, 0.05, 0.9, 0.1, 1.0 + bezier = menu_decel, 0.1, 1, 0, 1 + bezier = menu_accel, 0.38, 0.04, 1, 0.07 + bezier = easeInOutCirc, 0.85, 0, 0.15, 1 + bezier = easeOutCirc, 0, 0.55, 0.45, 1 + bezier = easeOutExpo, 0.16, 1, 0.3, 1 + bezier = softAcDecel, 0.26, 0.26, 0.15, 1 + bezier = md2, 0.4, 0, 0.2, 1 # use with .2s duration + # Animation configs + animation = windows, 1, 3, md3_decel, popin 60% + animation = windowsIn, 1, 3, md3_decel, popin 60% + animation = windowsOut, 1, 3, md3_accel, popin 60% + animation = border, 1, 10, default + animation = fade, 1, 3, md3_decel + # animation = layers, 1, 2, md3_decel, slide + animation = layersIn, 1, 3, menu_decel, slide + animation = layersOut, 1, 1.6, menu_accel + animation = fadeLayersIn, 1, 2, menu_decel + animation = fadeLayersOut, 1, 2, menu_accel + animation = workspaces, 1, 7, menu_decel, slide + # animation = workspaces, 1, 2.5, softAcDecel, slide + # animation = workspaces, 1, 7, menu_decel, slidefade 15% + # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15% + animation = specialWorkspace, 1, 3, md3_decel, slidevert +} + +misc { + vfr = 1 + animate_manual_resizes = false + animate_mouse_windowdragging = false + enable_swallow = false + swallow_regex = (foot|kitty|allacritty|Alacritty) + + disable_hyprland_logo = true + force_default_wallpaper = 0 + new_window_takes_over_fullscreen = 2 + allow_session_lock_restore = true + + initial_workspace_tracking = false + + middle_click_paste = false +} + +# Overview +plugin { + hyprexpo { + columns = 3 + gap_size = 5 + bg_col = rgb(000000) + workspace_method = first 1 # [center/first] [workspace] e.g. first 1 or center m+1 + + enable_gesture = true # laptop touchpad, 4 fingers + gesture_distance = 300 # how far is the "max" + gesture_positive = false + } +} + +xwayland { + force_zero_scaling = true +} \ No newline at end of file diff --git a/hypr/hyprland/keybinds.conf b/hypr/hyprland/keybinds.conf new file mode 100755 index 0000000..107010b --- /dev/null +++ b/hypr/hyprland/keybinds.conf @@ -0,0 +1,165 @@ +# Lines ending with `# [hidden]` won't be shown on cheatsheet +# Lines starting with #! are section headings + +#! +##! Apps +bind = Super, C, exec, code --password-store=gnome-libsecret # Launch VSCode (editor) +bind = Super, E, exec, nautilus --new-window # Launch Dolphin (file manager) +bind = Super, W, exec, firefox --new-window # Launch Firefox +bind = Super, X, exec, gnome-text-editor --new-window # Launch GNOME Text Editor +bind = Super, B, exec, ghostty -e btop # Launch btop (system monitor) +bind = Ctrl+Super, V, exec, pavucontrol # Launch pavucontrol (volume mixer) +bind = Ctrl+Super+Shift, V, exec, easyeffects # Launch EasyEffects (equalizer & other audio effects) + +#! +##! Essentials +bind = Super, T, exec, kitty # Launch kitty (terminal) +bind = Super+Shift, T, exec, ghostty # Launch ghostty (terminal) +bind = Super, Return, exec, kitty # [hidden] +bind = Super+Shift, Return, exec, ghostty # [hidden] +bind = Super, Super_L, exec, pkill fuzzel || fuzzel # Launch fuzzel (app launcher) +bind = Alt, Space, exec, pkill fuzzel || fuzzel # [hidden] Launch fuzzel (app launcher) +# bind = , mouse:276, exec, pkill fuzzel || fuzzel # [hidden] Launch fuzzel (app launcher) +bind = Super, Space, exec, pkill fuzzel || fuzzel -d -l 0 | xargs -r -I{} bash -c '{}' # Launch fuzzel (command launcher) + +##! Actions +# Screenshot, Record, OCR, Color picker, Clipboard history +bind = Super, V, exec, pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy # Clipboard history >> clipboard +bind = Super, Period, exec, pkill fuzzel || ~/.scripts/fuzzel-emoji # Pick emoji >> clipboard +bind = Ctrl+Shift+Alt, Delete, exec, pkill wlogout || wlogout -p layer-shell # [hidden] +bind = Super+Shift, S, exec, hyprshot -m region # Screen snip +bind = , Print, exec, hyprshot -m region # Screen snip +# Color picker +bind = Super+Shift, C, exec, hyprpicker -a # Pick color (Hex) >> clipboard +# Fullscreen screenshot +# bindl=,Print,exec,grim - | wl-copy # Screenshot >> clipboard +# bindl= Ctrl,Print, exec, mkdir -p ~/Pictures/Screenshots && ~/.config/ags/scripts/grimblast.sh copysave screen ~/Pictures/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png # Screenshot >> clipboard & file +# Recording stuff +# bind = Super+Alt, R, exec, ~/.config/ags/scripts/record-script.sh # Record region (no sound) +# bind = Ctrl+Alt, R, exec, ~/.config/ags/scripts/record-script.sh --fullscreen # [hidden] Record screen (no sound) +bind = Super+Alt, R, exec, ~/.scripts/record-script.sh --fullscreen-sound # Record screen (with sound) +# wallpaper +bind = Super+Shift, W, exec, fish ~/.scripts/change_wallpaper.fish # Change wallpaper + +##! Session +# bind = Ctrl+Super, L, exec, ags run-js 'lock.lock()' # [hidden] +bind = Super, L, exec, loginctl lock-session # Lock +bindl = Super+Shift, L, exec, sleep 0.1 && systemctl suspend || loginctl suspend # Suspend system +bind = Ctrl+Shift+Alt+Super, Delete, exec, systemctl poweroff || loginctl poweroff # [hidden] Power off + +#! +##! Media +bindl= Super+Shift, N, exec, playerctl next # Next track +bindl= ,XF86AudioNext, exec, playerctl next # [hidden] +bindl= ,XF86AudioPrev, exec, playerctl previous # [hidden] +bind = Super+Shift+Alt, mouse:275, exec, playerctl previous # [hidden] +bind = Super+Shift+Alt, mouse:276, exec, playerctl next # [hidden] +bindl= Super+Shift, B, exec, playerctl previous # Previous track +bindl= Super+Shift, P, exec, playerctl play-pause # Play/pause media +bindl= ,XF86AudioPlay, exec, playerctl play-pause # [hidden] +bindl= ,XF86AudioPause, exec, playerctl play-pause # [hidden] + +#! +##! Sound & Brightness +bindl = Alt ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_SOURCE@ toggle # [hidden] +bindl = Super ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_SOURCE@ toggle # [hidden] +bindl = ,XF86AudioMute, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 0% # [hidden] +bindl = Super+Shift,M, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 0% # [hidden] +bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ # [hidden] +bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- # [hidden] +bindle=, XF86MonBrightnessUp, exec, brightnessctl -d intel_backlight set 5%+ # [hidden] +bindle=, XF86MonBrightnessDown, exec, brightnessctl -d intel_backlight set 5%- # [hidden] + +#! +##! Window management +# Focusing +#/# bind = Super, ←/↑/→/↓,, # Move focus in direction +bind = Super, Left, movefocus, l # [hidden] +bind = Super, Right, movefocus, r # [hidden] +bind = Super, Up, movefocus, u # [hidden] +bind = Super, Down, movefocus, d # [hidden] +bindm = Super, mouse:272, movewindow +bindm = Super, mouse:273, resizewindow +bind = Super, Q, killactive, +bind = Super, mouse:274, killactive # [hidden] Kill active window +bind = Super+Shift+Alt, Q, exec, hyprctl kill # Pick and kill a window + +##! Window arrangement +#/# bind = Super+Shift, ←/↑/→/↓,, # Window: move in direction +bind = Super+Shift, Left, movewindow, l # [hidden] +bind = Super+Shift, Right, movewindow, r # [hidden] +bind = Super+Shift, Up, movewindow, u # [hidden] +bind = Super+Shift, Down, movewindow, d # [hidden] +# Window split ratio< +#/# binde = Super, +/-,, # Window: split ratio +/- 0.1 +binde = Super, udiaeresis, splitratio, -0.1 # [hidden] +binde = Super, plus, splitratio, +0.1 # [hidden] +# Positioning mode +bind = Super+Alt, Space, togglefloating, +bind = Super, mouse:276, togglefloating # [hidden] +bind = Super+Alt, F, fullscreenstate, 0 3 # Toggle fake fullscreen +bind = Super, F, fullscreen, 0 +bind = Super, D, fullscreen, 1 + +#! +##! Workspace navigation +# Switching +#/# bind = Super, Hash,, # Focus workspace # (1, 2, 3, 4, ...) +bind = Super, 1, exec, ~/.scripts/hyprland_workspace_action.sh workspace 1 # [hidden] +bind = Super, 2, exec, ~/.scripts/hyprland_workspace_action.sh workspace 2 # [hidden] +bind = Super, 3, exec, ~/.scripts/hyprland_workspace_action.sh workspace 3 # [hidden] +bind = Super, 4, exec, ~/.scripts/hyprland_workspace_action.sh workspace 4 # [hidden] +bind = Super, 5, exec, ~/.scripts/hyprland_workspace_action.sh workspace 5 # [hidden] +bind = Super, 6, exec, ~/.scripts/hyprland_workspace_action.sh workspace 6 # [hidden] +bind = Super, 7, exec, ~/.scripts/hyprland_workspace_action.sh workspace 7 # [hidden] +bind = Super, 8, exec, ~/.scripts/hyprland_workspace_action.sh workspace 8 # [hidden] +bind = Super, 9, exec, ~/.scripts/hyprland_workspace_action.sh workspace 9 # [hidden] +bind = Super, 0, exec, ~/.scripts/hyprland_workspace_action.sh workspace 10 # [hidden] +#/# bind = Ctrl+Super, ←/→,, # Workspace: focus left/right +bind = Ctrl+Super, Right, workspace, +1 # [hidden] +bind = Ctrl+Super, Left, workspace, -1 # [hidden] +#/# bind = Super, Scroll ↑/↓,, # Workspace: focus left/right +bind = Super, mouse_up, workspace, +1 # [hidden] +bind = Super, mouse_down, workspace, -1 # [hidden] +bind = Ctrl+Super, mouse_up, workspace, +1 # [hidden] +bind = Ctrl+Super, mouse_down, workspace, -1 # [hidden] +#/# bind = Super, Page_↑/↓,, # Workspace: focus left/right +bind = Super, Page_Down, workspace, +1 # [hidden] +bind = Super, Page_Up, workspace, -1 # [hidden] +bind = Ctrl+Super, Page_Down, workspace, +1 # [hidden] +bind = Ctrl+Super, Page_Up, workspace, -1 # [hidden] +## Special +bind = Super, S, togglespecialworkspace, s +bind = Super, mouse:275, togglespecialworkspace, s # [hidden] + +##! Workspace management +# Move window to workspace Super + Alt + [0-9] +#/# bind = Super+Alt, Hash,, # Window: move to workspace # (1, 2, 3, 4, ...) +bind = Super+Alt, 1, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 1 # [hidden] +bind = Super+Alt, 2, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 2 # [hidden] +bind = Super+Alt, 3, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 3 # [hidden] +bind = Super+Alt, 4, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 4 # [hidden] +bind = Super+Alt, 5, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 5 # [hidden] +bind = Super+Alt, 6, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 6 # [hidden] +bind = Super+Alt, 7, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 7 # [hidden] +bind = Super+Alt, 8, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 8 # [hidden] +bind = Super+Alt, 9, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 9 # [hidden] +bind = Super+Alt, 0, exec, ~/.scripts/hyprland_workspace_action.sh movetoworkspacesilent 10 # [hidden] +bind = Ctrl+Super+Shift, Right, movetoworkspace, +1 # [hidden] +bind = Ctrl+Super+Shift, Left, movetoworkspace, -1 # [hidden] +bind = Ctrl+Super, Up, workspace, -5 # [hidden] +bind = Ctrl+Super, Down, workspace, +5 # [hidden] +#/# bind = Super+Shift, Scroll ↑/↓,, # Window: move to workspace left/right +bind = Super+Shift, mouse_down, movetoworkspace, -1 # [hidden] +bind = Super+Shift, mouse_up, movetoworkspace, +1 # [hidden] +bind = Super+Alt, mouse_down, movetoworkspace, -1 # [hidden] +bind = Super+Alt, mouse_up, movetoworkspace, +1 # [hidden] +#/# bind = Super+Shift, Page_↑/↓,, # Window: move to workspace left/right +bind = Super+Alt, Page_Down, movetoworkspace, +1 # [hidden] +bind = Super+Alt, Page_Up, movetoworkspace, -1 # [hidden] +bind = Super+Shift, Page_Down, movetoworkspace, +1 # [hidden] +bind = Super+Shift, Page_Up, movetoworkspace, -1 # [hidden] +bind = Super+Alt, S, movetoworkspace, special:s +bind = Super, P, pin +bind = Alt, Tab, cyclenext +bind = Super, Tab, hyprexpo:expo, toggle # can be: toggle, select, off/disable or on/enable diff --git a/hypr/hyprland/rules.conf b/hypr/hyprland/rules.conf new file mode 100755 index 0000000..9edc0c5 --- /dev/null +++ b/hypr/hyprland/rules.conf @@ -0,0 +1,81 @@ +# ######## Window rules ######## + +# Uncomment to apply global transparency to all windows: +# windowrulev2 = opacity 0.89 override 0.89 override, class:.* + +# Disable blur for XWayland windows (or context menus with shadow would look weird) +windowrulev2 = noblur, xwayland:1 + +# kitty +windowrulev2 = float, class:^(com.mitchellh.ghostty)$ +windowrulev2 = size 60%, class:^(com.mitchellh.ghostty)$ + +# Floating +windowrulev2 = float, class:^(blueberry\.py)$ +windowrulev2 = float, class:^(blueman-manager)$ +windowrulev2 = size 45%, class:^(blueman-manager)$ +windowrulev2 = float, class:^(pavucontrol)$ +windowrulev2 = size 45%, class:^(pavucontrol)$ +windowrulev2 = center, class:^(pavucontrol)$ +windowrulev2 = float, class:^(org.pulseaudio.pavucontrol)$ +windowrulev2 = size 45%, class:^(org.pulseaudio.pavucontrol)$ +windowrulev2 = center, class:^(org.pulseaudio.pavucontrol)$ +windowrulev2 = float, class:^(Waydroid)$ +windowrulev2 = float, class:^(org.kde.kcalc)$ +windowrulev2 = float, class:^(org.kde.kalk)$ +windowrulev2 = float, class:^(org.gnome.NautilusPreviewer)$ # Sushi in Nautilus + +# Picture-in-Picture +windowrulev2 = float, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ +windowrulev2 = keepaspectratio, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ +windowrulev2 = move 73% 72%, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ +windowrulev2 = size 25%, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ +windowrulev2 = float, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ +windowrulev2 = pin, title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ + +# Dialog windows – float+center these windows. +windowrulev2 = center, title:^(Open File)(.*)$ +windowrulev2 = center, title:^(Select a File)(.*)$ +windowrulev2 = center, title:^(Choose wallpaper)(.*)$ +windowrulev2 = center, title:^(Open Folder)(.*)$ +windowrulev2 = center, title:^(Save As)(.*)$ +windowrulev2 = center, title:^(Library)(.*)$ +windowrulev2 = center, title:^(File Upload)(.*)$ +windowrulev2 = float, title:^(Open File)(.*)$ +windowrulev2 = float, title:^(Select a File)(.*)$ +windowrulev2 = float, title:^(Choose wallpaper)(.*)$ +windowrulev2 = float, title:^(Open Folder)(.*)$ +windowrulev2 = float, title:^(Save As)(.*)$ +windowrulev2 = float, title:^(Library)(.*)$ +windowrulev2 = float, title:^(File Upload)(.*)$ + + +# --- Tearing --- +windowrulev2 = immediate, title:.*\.exe +windowrulev2 = immediate, class:^(steam_app) + +# No shadow for tiled windows (matches windows that are not floating). +windowrulev2 = noshadow, floating:0 + +# ######## Workspace rules ######## +workspace = special:special, gapsout:30 + +# ######## Layer rules ######## +layerrule = xray 1, .* +# layerrule = noanim, .* +layerrule = noanim, walker +layerrule = noanim, selection +layerrule = noanim, overview +layerrule = noanim, anyrun +layerrule = noanim, indicator.* +layerrule = noanim, osk +layerrule = noanim, hyprpicker + +layerrule = noanim, noanim +layerrule = blur, gtk-layer-shell +layerrule = ignorezero, gtk-layer-shell +layerrule = blur, launcher +layerrule = ignorealpha 0.5, launcher +layerrule = blur, notifications +layerrule = ignorealpha 0.69, notifications +layerrule = blur, logout_dialog # wlogout \ No newline at end of file diff --git a/hypr/hyprlock.conf b/hypr/hyprlock.conf new file mode 100755 index 0000000..d71dbd0 --- /dev/null +++ b/hypr/hyprlock.conf @@ -0,0 +1,104 @@ +# $text_color = rgba(D7E5E6FF) +# $entry_background_color = rgba(09151611) +# $entry_border_color = rgba(82949555) +# $entry_color = rgba(B8CACBFF) +$text_color = rgba(FFFFFFFF) +$entry_background_color = rgba(33333360) +$entry_border_color = rgba(3B3B3B100) +$entry_color = rgba(FFFFFFFF) +$font_family = Rubik Light +$font_family_clock = Rubik Light +$font_material_symbols = Material Symbols Rounded + +background { + # color = rgba(041011FF) + # color = rgba(000000FF) + # path = {{ SWWW_WALL }} + path = ~/.config/backgrounds/116327446_p3.jpg + # blur_size = 5 + # blur_passes = 4 +} +input-field { + monitor = + size = 250, 50 + outline_thickness = 2 + dots_size = 0.1 + dots_spacing = 0.3 + outer_color = $entry_border_color + inner_color = $entry_background_color + font_color = $entry_color + # fade_on_empty = true + + position = 0, 20 + halign = center + valign = center +} + +label { # Clock + monitor = + text = $TIME + shadow_passes = 1 + shadow_size = 15 + shadow_boost = 0.5 + color = $text_color + font_size = 65 + font_family = $font_family_clock + + position = 0, 300 + halign = center + valign = center +} +label { # Greeting + monitor = + text = Hi, $USER + shadow_passes = 1 + shadow_size = 15 + shadow_boost = 0.5 + color = $text_color + font_size = 20 + font_family = $font_family + + position = 0, 240 + halign = center + valign = center +} +label { # lock icon + monitor = + text = lock + shadow_passes = 1 + shadow_boost = 0.5 + color = $text_color + font_size = 21 + font_family = $font_material_symbols + + position = 0, 65 + halign = center + valign = bottom +} +label { # "locked" text + monitor = + text = locked + shadow_passes = 1 + shadow_boost = 0.5 + color = $text_color + font_size = 14 + font_family = $font_family + + position = 0, 45 + halign = center + valign = bottom +} + +label { # Status + monitor = + text = cmd[update:5000] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/status.sh + shadow_passes = 1 + shadow_boost = 0.5 + color = $text_color + font_size = 14 + font_family = $font_family + + position = 30, -30 + halign = left + valign = top +} diff --git a/hypr/hyprlock/status.sh b/hypr/hyprlock/status.sh new file mode 100755 index 0000000..dd80633 --- /dev/null +++ b/hypr/hyprlock/status.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +############ Variables ############ +enable_battery=false +battery_charging=false + +####### Check availability ######## +for battery in /sys/class/power_supply/*BAT*; do + if [[ -f "$battery/uevent" ]]; then + enable_battery=true + if [[ $(cat /sys/class/power_supply/*/status | head -1) == "Charging" ]]; then + battery_charging=true + fi + break + fi +done + +############# Output ############# +if [[ $enable_battery == true ]]; then + if [[ $battery_charging == true ]]; then + echo -n "(+) " + fi + echo -n "$(cat /sys/class/power_supply/*/capacity | head -1)"% + if [[ $battery_charging == false ]]; then + echo -n " remaining" + fi +fi + +echo '' \ No newline at end of file diff --git a/hypr/hyprpaper.conf b/hypr/hyprpaper.conf new file mode 100644 index 0000000..5d6cb19 --- /dev/null +++ b/hypr/hyprpaper.conf @@ -0,0 +1,2 @@ +preload = /home/kolkas/.config/backgrounds/arona_desks.jpg +wallpaper = , /home/kolkas/.config/backgrounds/arona_desks.jpg diff --git a/hypr/shaders/chromatic_abberation.frag b/hypr/shaders/chromatic_abberation.frag new file mode 100755 index 0000000..5389241 --- /dev/null +++ b/hypr/shaders/chromatic_abberation.frag @@ -0,0 +1,24 @@ +// vim: set ft=glsl: + +precision highp float; +varying highp vec2 v_texcoord; +uniform highp sampler2D tex; + +#define STRENGTH 0.0027 + +void main() { + vec2 center = vec2(0.5, 0.5); + vec2 offset = (v_texcoord - center) * STRENGTH; + + float rSquared = dot(offset, offset); + float distortion = 1.0 + 1.0 * rSquared; + vec2 distortedOffset = offset * distortion; + + vec2 redOffset = vec2(distortedOffset.x, distortedOffset.y); + vec2 blueOffset = vec2(distortedOffset.x, distortedOffset.y); + + vec4 redColor = texture2D(tex, v_texcoord + redOffset); + vec4 blueColor = texture2D(tex, v_texcoord + blueOffset); + + gl_FragColor = vec4(redColor.r, texture2D(tex, v_texcoord).g, blueColor.b, 1.0); +} diff --git a/hypr/shaders/crt.frag b/hypr/shaders/crt.frag new file mode 100755 index 0000000..a37ff9f --- /dev/null +++ b/hypr/shaders/crt.frag @@ -0,0 +1,511 @@ +#version 100 +precision highp float; +varying highp vec2 v_texcoord; +varying highp vec3 v_pos; +uniform highp sampler2D tex; +uniform lowp float time; + +#define BORDER_COLOR vec4(vec3(0.0, 0.0, 0.0), 1.0) // black border +#define BORDER_RADIUS 1.0 // larger vignette radius +#define BORDER_SIZE 0.01 // small border size +#define CHROMATIC_ABERRATION_STRENGTH 0.00 +#define DENOISE_INTENSITY 0.0001 // +#define DISTORTION_AMOUNT 0.00 // moderate distortion amount +#define HDR_BLOOM 0.75 // bloom intensity +#define HDR_BRIGHTNESS 0.011 // brightness +#define HDR_CONTRAST 0.011 // contrast +#define HDR_SATURATION 1.0// saturation +#define LENS_DISTORTION_AMOUNT 0.0 +#define NOISE_THRESHOLD 0.0001 +#define PHOSPHOR_BLUR_AMOUNT 0.77 // Amount of blur for phosphor glow +#define PHOSPHOR_GLOW_AMOUNT 0.77 // Amount of phosphor glow +#define SAMPLING_RADIUS 0.0001 +#define SCANLINE_FREQUENCY 540.0 +#define SCANLINE_THICKNESS 0.0507 +#define SCANLINE_TIME time * 471.24 +#define SHARPNESS 0.25 +#define SUPERSAMPLING_SAMPLES 16.0 +#define VIGNETTE_RADIUS 0.0 // larger vignette radius +#define PI 3.14159265359 +#define TWOPI 6.28318530718 + +vec2 applyBarrelDistortion(vec2 coord, float amt) { + vec2 p = coord.xy / vec2(1.0); + vec2 v = p * 2.0 - vec2(1.0); + float r = dot(v, v); + float k = 1.0 + pow(r, 2.0) * pow(amt, 2.0); + vec2 result = v * k; + return vec2(0.5, 0.5) + 0.5 * result.xy; +} + +vec4 applyColorCorrection(vec4 color) { + color.rgb *= vec3(1.0, 0.79, 0.89); + return vec4(color.rgb, 1.0); +} + +vec4 applyBorder(vec2 tc, vec4 color, float borderSize, vec4 borderColor) { + float dist_x = min(tc.x, 1.0 - tc.x); + float dist_y = min(tc.y, 1.0 - tc.y); + float dist = min(dist_x, dist_y) * -1.0; + float border = smoothstep(borderSize, 0.0, dist); + border += smoothstep(borderSize, 0.0, dist); + return mix(color, borderColor, border); +} + +vec4 applyFakeHDR(vec4 color, float brightness, float contrast, float saturation, float bloom) { + color.rgb = (color.rgb - vec3(0.5)) * exp2(brightness) + vec3(0.5); + vec3 crtfactor = vec3(1.05, 0.92, 1.0); + color.rgb = pow(color.rgb, crtfactor); + // // NTSC + // vec3 lumCoeff = vec3(0.2125, 0.7154, 0.0721); + + // // BT.709 + // vec3 lumCoeff = vec3(0.299, 0.587, 0.114); + + // BT.2020 + vec3 lumCoeff = vec3(0.2627, 0.6780, 0.0593); + + // // Warm NTSC + // vec3 lumCoeff = vec3(0.2125, 0.7010, 0.0865); + + float luminance = dot(color.rgb, lumCoeff); + luminance = pow(luminance, 2.2); + color.rgb = mix(vec3(luminance), color.rgb, saturation); + color.rgb = mix(color.rgb, vec3(1.0), pow(max(0.0, luminance - 1.0 + bloom), 4.0)); + return color; +} + +vec4 applyVignette(vec4 color) { + vec2 center = vec2(0.5, 0.5); // center of screen + float radius = VIGNETTE_RADIUS; // radius of vignette effect + float softness = 1.0; // softness of vignette effect + float intensity = 0.7; // intensity of vignette effect + vec2 offset = v_texcoord - center; // offset from center of screen + float distance = length(offset); // distance from center of screen + float alpha = smoothstep(radius, radius - radius * softness, distance) * intensity; // calculate alpha value for vignette effect + return mix(vec4(0.0, 0.0, 0.0, alpha), color, alpha); // mix black with color using calculated alpha value +} + +vec4 applyPhosphorGlow(vec2 tc, vec4 color, sampler2D tex) { + // Calculate average color value of the texture + vec4 texelColor = color; + float averageColor = (texelColor.r + texelColor.g + texelColor.b) / 3.0; + + // Determine brightness-dependent color factor + float factor = mix( + mix(0.09, + mix(0.005, 0.0075, (averageColor - 0.1) / 0.1), + step(0.01, averageColor)), 0.0005, + step(0.02, averageColor)); + // Apply phosphor glow effect + vec4 sum = vec4(0.0); + vec4 pixels[9]; + pixels[0] = texture2D(tex, tc - vec2(0.001, 0.001)); + pixels[1] = texture2D(tex, tc - vec2(0.001, 0.0)); + pixels[2] = texture2D(tex, tc - vec2(0.001, -0.001)); + pixels[3] = texture2D(tex, tc - vec2(0.0, 0.001)); + pixels[4] = texture2D(tex, tc); + pixels[5] = texture2D(tex, tc + vec2(0.001, 0.001)); + pixels[6] = texture2D(tex, tc + vec2(0.001, 0.0)); + pixels[7] = texture2D(tex, tc + vec2(0.001, -0.001)); + pixels[8] = texture2D(tex, tc + vec2(0.0, 0.001)); + +// Perform operations on input pixels in parallel + sum = pixels[0] + + pixels[1] + + pixels[2] + + pixels[3] + + pixels[4] + + pixels[5] + + pixels[6] + + pixels[7] + + pixels[8]; + sum /= 9.0; + sum += texture2D(tex, tc - vec2(0.01, 0.01)) * 0.001; + sum += texture2D(tex, tc - vec2(0.0, 0.01)) * 0.001; + sum += texture2D(tex, tc - vec2(-0.01, 0.01)) * 0.001; + sum += texture2D(tex, tc - vec2(0.01, 0.0)) * 0.001; + sum += color * PHOSPHOR_BLUR_AMOUNT; + sum += texture2D(tex, tc - vec2(-0.01, 0.0)) * 0.001; + sum += texture2D(tex, tc - vec2(0.01, -0.01)) * 0.001; + sum += texture2D(tex, tc - vec2(0.0, -0.01)) * 0.001; + sum += texture2D(tex, tc - vec2(-0.01, -0.01)) * 0.001; + sum *= PHOSPHOR_GLOW_AMOUNT; + + // Initialize sum_sum_factor to zero + vec4 sum_sum_factor = vec4(0.0); + // Compute sum_j for i = -1 + vec4 sum_j = vec4(0.0); + sum_j += texture2D(tex, tc + vec2(-1, -1) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, -1) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, -1) * 0.01); + sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01); + sum_sum_factor += sum_j * vec4(0.011); + + // Compute sum_j for i = 0 + sum_j = vec4(0.0); + sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01); + sum_sum_factor += sum_j * vec4(0.011); + + // Compute sum_j for i = 1 + sum_j = vec4(0.0); + sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01); + sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01); + sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01); + sum_sum_factor += sum_j * vec4(0.011); + color += mix(sum_sum_factor * sum_sum_factor * vec4(factor), sum, 0.5); + return color; +} + +vec4 applyAdaptiveSharpen(vec2 tc, vec4 color, sampler2D tex) { + vec4 color_tl = texture2D(tex, tc + vec2(-1.0, -1.0) * 0.5 / 2160.0); + vec4 color_tr = texture2D(tex, tc + vec2(1.0, -1.0) * 0.5 / 2160.0); + vec4 color_bl = texture2D(tex, tc + vec2(-1.0, 1.0) * 0.5 / 2160.0); + vec4 color_br = texture2D(tex, tc + vec2(1.0, 1.0) * 0.5 / 2160.0); + float sharpness = SHARPNESS; + vec3 color_no_alpha = color.rgb; + vec3 color_tl_no_alpha = color_tl.rgb; + vec3 color_tr_no_alpha = color_tr.rgb; + vec3 color_bl_no_alpha = color_bl.rgb; + vec3 color_br_no_alpha = color_br.rgb; + float delta = (dot(color_no_alpha, vec3(0.333333)) + dot(color_tl_no_alpha, vec3(0.333333)) + dot(color_tr_no_alpha, vec3(0.333333)) + dot(color_bl_no_alpha, vec3(0.333333)) + dot(color_br_no_alpha, vec3(0.333333))) * 0.2 - dot(color_no_alpha, vec3(0.333333)); + vec3 sharp_color_no_alpha = color_no_alpha + min(vec3(0.0), vec3(delta * sharpness)); + vec4 sharp_color = vec4(sharp_color_no_alpha, color.a); + return sharp_color; +} + +vec4 applyScanlines(vec2 tc, vec4 color) { + float scanline = (cos(tc.y * SCANLINE_FREQUENCY + SCANLINE_TIME) * + sin(tc.y * SCANLINE_FREQUENCY + SCANLINE_TIME)) * SCANLINE_THICKNESS; + float alpha = clamp(1.0 - abs(scanline), 0.0, 1.0); + return vec4(color.rgb * alpha, color.a); +} + +vec4 applyChromaticAberration(vec2 uv, vec4 color) { + vec2 center = vec2(0.5, 0.5); // center of the screen + vec2 offset = (uv - center) * CHROMATIC_ABERRATION_STRENGTH; // calculate the offset from the center + + // apply lens distortion + float rSquared = dot(offset, offset); + float distortion = 1.0 + LENS_DISTORTION_AMOUNT * rSquared; + vec2 distortedOffset = offset * distortion; + + // apply chromatic aberration + vec2 redOffset = vec2(distortedOffset.x * 1.00, distortedOffset.y * 1.00); + vec2 blueOffset = vec2(distortedOffset.x * 1.00, distortedOffset.y * 1.00); + + vec4 redColor = texture2D(tex, uv + redOffset); + vec4 blueColor = texture2D(tex, uv + blueOffset); + + vec4 result = vec4(redColor.r, color.g, blueColor.b, color.a); + + return result; +} + +vec4 reduceGlare(vec4 color) { + // Calculate the intensity of the color by taking the average of the RGB components + float intensity = (color.r + color.g + color.b) / 3.0; + // Set the maximum intensity that can be considered for glare + float maxIntensity = 0.98; + // Use smoothstep to create a smooth transition from no glare to full glare + // based on the intensity of the color and the maximum intensity + float glareIntensity = smoothstep(maxIntensity - 0.02, maxIntensity, intensity); + // Set the amount of glare to apply to the color + float glareAmount = 0.02; + // Mix the original color with the reduced color that has glare applied to it + vec3 reducedColor = mix(color.rgb, vec3(glareIntensity), glareAmount); + // Return the reduced color with the original alpha value + return vec4(reducedColor, color.a); +} + +// Apply a fake HDR effect to the input color. +// Parameters: +// - inputColor: the color to apply the effect to. +// - brightness: the brightness of the image. Should be a value between 0 and 1. +// - contrast: the contrast of the image. Should be a value between 0 and 1. +// - saturation: the saturation of the image. Should be a value between 0 and 2. +// - bloom: the intensity of the bloom effect. Should be a value between 0 and 1. +vec4 applyFakeHDREffect(vec4 inputColor, float brightness, float contrast, float saturation, float bloom) { + const float minBrightness = 0.0; + const float maxBrightness = 1.0; + const float minContrast = 0.0; + const float maxContrast = 1.0; + const float minSaturation = 0.0; + const float maxSaturation = 2.0; + const float minBloom = 0.0; + const float maxBloom = 1.0; + + // Check input parameters for validity + if (brightness < minBrightness || brightness > maxBrightness) { + return vec4(0.0, 0.0, 0.0, 1.0); // Return black with alpha of 1.0 to indicate error + } + if (contrast < minContrast || contrast > maxContrast) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + if (saturation < minSaturation || saturation > maxSaturation) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + if (bloom < minBloom || bloom > maxBloom) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + + // Apply brightness and contrast + vec3 color = inputColor.rgb; + color = (color - vec3(0.5)) * exp2(brightness * 10.0) + vec3(0.5); + color = mix(vec3(0.5), color, pow(contrast * 4.0 + 1.0, 2.0)); + + // // NTSC + // vec3 lumCoeff = vec3(0.2125, 0.7154, 0.0721); + + // // BT.709 + // vec3 lumCoeff = vec3(0.299, 0.587, 0.114); + + // // BT.2020 + // vec3 lumCoeff = vec3(0.2627, 0.6780, 0.0593); + + // Warm NTSC + vec3 lumCoeff = vec3(0.2125, 0.7010, 0.0865); + + // Apply saturation + float luminance = dot(color, lumCoeff); + vec3 grey = vec3(luminance); + color = mix(grey, color, saturation); + + // Apply bloom effect + float threshold = 1.0 - bloom; + vec3 bloomColor = max(color - threshold, vec3(0.0)); + bloomColor = pow(bloomColor, vec3(2.0)); + bloomColor = mix(vec3(0.0), bloomColor, pow(min(luminance, threshold), 4.0)); + color += bloomColor; + + return vec4(color, inputColor.a); +} + +vec4 bilateralFilter(sampler2D tex, vec2 uv, vec4 color, float sampleRadius, float noiseThreshold, float intensity) { + vec4 filteredColor = vec4(0.0); + float totalWeight = 0.0; + + // Top-left pixel + vec4 sample = texture2D(tex, uv + vec2(-1.0, -1.0)); + float dist = length(vec2(-1.0, -1.0)); + float colorDist = length(sample - color); + float weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Top pixel + sample = texture2D(tex, uv + vec2(0.0, -1.0)); + dist = length(vec2(0.0, -1.0)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Top-right pixel + sample = texture2D(tex, uv + vec2(1.0, -1.0)); + dist = length(vec2(1.0, -1.0)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Left pixel + sample = texture2D(tex, uv + vec2(-1.0, 0.0)); + dist = length(vec2(-1.0, 0.0)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Center pixel + sample = texture2D(tex, uv); + dist = 0.0; + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Right pixel + sample = texture2D(tex, uv + vec2(1.0, 0.0)); + dist = length(vec2(1.0, 0.0)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + // Bottom-left pixel + sample = texture2D(tex, uv + vec2(-1.0, 1.0)); + dist = length(vec2(-1.0, 1.0)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + +// Bottom pixel + sample = texture2D(tex, uv + vec2(0.0, sampleRadius)); + dist = length(vec2(0.0, sampleRadius)); + colorDist = length(sample - color); + weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius)); + filteredColor += sample * weight; + totalWeight += weight; + + filteredColor /= totalWeight; + return mix(color, filteredColor, step(noiseThreshold, length(filteredColor - color))); +} + +vec4 supersample(sampler2D tex, vec2 uv, float sampleRadius, float noiseThreshold, float intensity) { + float radiusSq = sampleRadius * sampleRadius; + vec2 poissonDisk; + vec4 color = vec4(0.0); + + float r1_0 = sqrt(0.0 / 16.0); + float r2_0 = fract(1.0 / 3.0); + float theta_0 = TWOPI * r2_0; + poissonDisk = vec2(r1_0 * cos(theta_0), r1_0 * sin(theta_0)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_1 = sqrt(1.0 / 16.0); + float r2_1 = fract(2.0 / 3.0); + float theta_1 = TWOPI * r2_1; + poissonDisk = vec2(r1_1 * cos(theta_1), r1_1 * sin(theta_1)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_2 = sqrt(2.0 / 16.0); + float r2_2 = fract(3.0 / 3.0); + float theta_2 = TWOPI * r2_2; + poissonDisk = vec2(r1_2 * cos(theta_2), r1_2 * sin(theta_2)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_3 = sqrt(3.0 / 16.0); + float r2_3 = fract(4.0 / 3.0); + float theta_3 = TWOPI * r2_3; + poissonDisk = vec2(r1_3 * cos(theta_3), r1_3 * sin(theta_3)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_4 = sqrt(4.0 / 16.0); + float r2_4 = fract(5.0 / 3.0); + float theta_4 = TWOPI * r2_4; + poissonDisk = vec2(r1_4 * cos(theta_4), r1_4 * sin(theta_4)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_5 = sqrt(5.0 / 16.0); + float r2_5 = fract(6.0 / 3.0); + float theta_5 = TWOPI * r2_5; + poissonDisk = vec2(r1_5 * cos(theta_5), r1_5 * sin(theta_5)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_6 = sqrt(6.0 / 16.0); + float r2_6 = fract(7.0 / 3.0); + float theta_6 = TWOPI * r2_6; + poissonDisk = vec2(r1_6 * cos(theta_6), r1_6 * sin(theta_6)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_7 = sqrt(7.0 / 16.0); + float r2_7 = fract(8.0 / 3.0); + float theta_7 = TWOPI * r2_7; + poissonDisk = vec2(r1_7 * cos(theta_7), r1_7 * sin(theta_7)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_8 = sqrt(8.0 / 16.0); + float r2_8 = fract(9.0 / 3.0); + float theta_8 = TWOPI * r2_8; + poissonDisk = vec2(r1_8 * cos(theta_8), r1_8 * sin(theta_8)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_9 = sqrt(9.0 / 16.0); + float r2_9 = fract(10.0 / 3.0); + float theta_9 = TWOPI * r2_9; + poissonDisk = vec2(r1_9 * cos(theta_9), r1_9 * sin(theta_9)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_10 = sqrt(10.0 / 16.0); + float r2_10 = fract(11.0 / 3.0); + float theta_10 = TWOPI * r2_10; + poissonDisk = vec2(r1_10 * cos(theta_10), r1_10 * sin(theta_10)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_11 = sqrt(11.0 / 16.0); + float r2_11 = fract(12.0 / 3.0); + float theta_11 = TWOPI * r2_11; + poissonDisk = vec2(r1_11 * cos(theta_11), r1_11 * sin(theta_11)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_12 = sqrt(12.0 / 16.0); + float r2_12 = fract(13.0 / 3.0); + float theta_12 = TWOPI * r2_12; + poissonDisk = vec2(r1_12 * cos(theta_12), r1_12 * sin(theta_12)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_13 = sqrt(13.0 / 16.0); + float r2_13 = fract(14.0 / 3.0); + float theta_13 = TWOPI * r2_13; + poissonDisk = vec2(r1_13 * cos(theta_13), r1_13 * sin(theta_13)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_14 = sqrt(14.0 / 16.0); + float r2_14 = fract(15.0 / 3.0); + float theta_14 = TWOPI * r2_14; + poissonDisk = vec2(r1_14 * cos(theta_14), r1_14 * sin(theta_14)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + float r1_15 = sqrt(15.0 / 16.0); + float r2_15 = fract(16.0 / 3.0); + float theta_15 = TWOPI * r2_15; + poissonDisk = vec2(r1_15 * cos(theta_15), r1_15 * sin(theta_15)); + color += texture2D(tex, uv + poissonDisk * sampleRadius); + + return bilateralFilter(tex, uv, color, sampleRadius, noiseThreshold, intensity); +} +void main() { + vec2 tc_no_dist = v_texcoord; + + vec2 tc = applyBarrelDistortion(tc_no_dist, DISTORTION_AMOUNT); + + // [-1, 1] + vec2 tc_no_dist_symmetric = tc_no_dist * 2.0 - 1.0; + + // [0,1] + vec2 tc_no_dist_normalized = (tc_no_dist_symmetric + 1.0) / 2.0; + + // vec4 color = texture2D(tex, tc); + vec4 color = supersample(tex, tc, SAMPLING_RADIUS, NOISE_THRESHOLD, DENOISE_INTENSITY); + + color = applyAdaptiveSharpen(tc, color, tex); + + color = applyPhosphorGlow(tc, color, tex); + + color = reduceGlare(color); + + color = mix(applyFakeHDREffect(color, HDR_BRIGHTNESS, HDR_CONTRAST, HDR_SATURATION, HDR_BLOOM), color, 0.5); + + color = applyColorCorrection(color); + + color /= SUPERSAMPLING_SAMPLES; + + color = mix(applyChromaticAberration(tc, color), color, 0.25); + + color = mix(color, applyVignette(color), 0.37); + + color = applyBorder(tc_no_dist_normalized, color, 1.0 - BORDER_SIZE * BORDER_RADIUS, BORDER_COLOR); + + color = mix(applyBorder(tc, color, BORDER_SIZE, BORDER_COLOR), color, 0.05); + + color = applyScanlines(tc, color); + + gl_FragColor = color; + gl_FragColor.a = 1.0; +} + diff --git a/hypr/shaders/drugs.frag b/hypr/shaders/drugs.frag new file mode 100755 index 0000000..1190ed0 --- /dev/null +++ b/hypr/shaders/drugs.frag @@ -0,0 +1,42 @@ + +precision highp float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float time; + +void warpco(inout vec2 tc) { + tc -= 0.5; + tc *= length(tc) * 2.0; + tc += 0.5; +} + +float rand1d(float seed) { + return sin(seed*1454.0); +} + +float rand2d(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453); +} + +vec3 rgb(in vec2 tc, float freq, float amp, inout vec4 centre) { + vec2 off = vec2(1.0/800.0, 0.0) * sin(tc.t * freq + time) * amp; + vec2 off2 = vec2(1.0/800.0, 0.0) * sin(tc.t * freq - time * 1.5) * amp; + centre = texture2D(tex, tc); + return vec3(texture2D(tex, tc-off).r, centre.g, texture2D(tex, tc+off2).b); +} + +void main() { + // vec2 px = 1.0 / textureSize(tex, 0).st; + vec2 tc = v_texcoord; + warpco(tc); + tc = mix(v_texcoord, tc, sin(time * 2.0)*0.07); + tc.x += rand2d(floor(tc * 20.0 + floor(time * 2.5))) * 0.01; + tc.x += rand1d(floor(tc.x * 40.0)) * 0.005 * rand1d(time * 0.001); + tc.y += sin(tc.x + time) * 0.02; + vec4 centre; + vec3 bent = rgb(tc, 100.0, 5.0, centre); + vec3 col = mix(centre.rgb, bent, sin(time)); + gl_FragColor = vec4(col, centre.a); + // gl_FragColor = vec4(texture2D(tex, v_texcoord)); +} \ No newline at end of file diff --git a/hypr/shaders/extradark.frag b/hypr/shaders/extradark.frag new file mode 100755 index 0000000..089ee81 --- /dev/null +++ b/hypr/shaders/extradark.frag @@ -0,0 +1,21 @@ +// vim: set ft=glsl: +// blue light filter shader +// values from https://reshade.me/forum/shader-discussion/3673-blue-light-filter-similar-to-f-lux + +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; + +void main() { + + vec4 pixColor = texture2D(tex, v_texcoord); + + // red + pixColor[0] *= 0.7; + // green + pixColor[1] *= 0.6; + // blue + pixColor[2] *= 0.5; + + gl_FragColor = pixColor; +} diff --git a/hypr/shaders/invert.frag b/hypr/shaders/invert.frag new file mode 100755 index 0000000..864f718 --- /dev/null +++ b/hypr/shaders/invert.frag @@ -0,0 +1,13 @@ +// vim: set ft=glsl: +// blue light filter shader +// values from https://reshade.me/forum/shader-discussion/3673-blue-light-filter-similar-to-f-lux + +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; + +void main() { + vec4 pixColor = texture2D(tex, v_texcoord); + pixColor.rgb = 1.0 - pixColor.rgb; + gl_FragColor = pixColor; +} \ No newline at end of file diff --git a/hypr/shaders/solarized.frag b/hypr/shaders/solarized.frag new file mode 100755 index 0000000..1c37f2c --- /dev/null +++ b/hypr/shaders/solarized.frag @@ -0,0 +1,41 @@ +// -*- mode:c -*- +precision lowp float; +varying vec2 v_texcoord; +uniform sampler2D tex; + +float distanceSquared(vec3 pixColor, vec3 solarizedColor) { + vec3 distanceVector = pixColor - solarizedColor; + return dot(distanceVector, distanceVector); +} + +void main() { + vec3 solarized[16]; + solarized[0] = vec3(0.,0.169,0.212); + solarized[1] = vec3(0.027,0.212,0.259); + solarized[2] = vec3(0.345,0.431,0.459); + solarized[3] = vec3(0.396,0.482,0.514); + solarized[4] = vec3(0.514,0.58,0.588); + solarized[5] = vec3(0.576,0.631,0.631); + solarized[6] = vec3(0.933,0.91,0.835); + solarized[7] = vec3(0.992,0.965,0.89); + solarized[8] = vec3(0.71,0.537,0.); + solarized[9] = vec3(0.796,0.294,0.086); + solarized[10] = vec3(0.863,0.196,0.184); + solarized[11] = vec3(0.827,0.212,0.51); + solarized[12] = vec3(0.424,0.443,0.769); + solarized[13] = vec3(0.149,0.545,0.824); + solarized[14] = vec3(0.165,0.631,0.596); + solarized[15] = vec3(0.522,0.6,0.); + + vec3 pixColor = vec3(texture2D(tex, v_texcoord)); + int closest = 0; + float closestDistanceSquared = distanceSquared(pixColor, solarized[0]); + for (int i = 1; i < 15; i++) { + float newDistanceSquared = distanceSquared(pixColor, solarized[i]); + if (newDistanceSquared < closestDistanceSquared) { + closest = i; + closestDistanceSquared = newDistanceSquared; + } + } + gl_FragColor = vec4(solarized[closest], 1.); +} diff --git a/kitty/Catppuccin-Macchiato.conf b/kitty/Catppuccin-Macchiato.conf new file mode 100644 index 0000000..a45b09f --- /dev/null +++ b/kitty/Catppuccin-Macchiato.conf @@ -0,0 +1,80 @@ +# vim:ft=kitty + +## name: Catppuccin-Macchiato +## author: Pocco81 (https://github.com/Pocco81) +## license: MIT +## upstream: https://github.com/catppuccin/kitty/blob/main/macchiato.conf +## blurb: Soothing pastel theme for the high-spirited! + + + +# The basic colors +foreground #CAD3F5 +background #24273A +selection_foreground #24273A +selection_background #F4DBD6 + +# Cursor colors +cursor #F4DBD6 +cursor_text_color #24273A + +# URL underline color when hovering with mouse +url_color #F4DBD6 + +# Kitty window border colors +active_border_color #B7BDF8 +inactive_border_color #6E738D +bell_border_color #EED49F + +# OS Window titlebar colors +wayland_titlebar_color system +macos_titlebar_color system + +# Tab bar colors +active_tab_foreground #181926 +active_tab_background #C6A0F6 +inactive_tab_foreground #CAD3F5 +inactive_tab_background #1E2030 +tab_bar_background #181926 + +# Colors for marks (marked text in the terminal) +mark1_foreground #24273A +mark1_background #B7BDF8 +mark2_foreground #24273A +mark2_background #C6A0F6 +mark3_foreground #24273A +mark3_background #7DC4E4 + +# The 16 terminal colors + +# black +color0 #494D64 +color8 #5B6078 + +# red +color1 #ED8796 +color9 #ED8796 + +# green +color2 #A6DA95 +color10 #A6DA95 + +# yellow +color3 #EED49F +color11 #EED49F + +# blue +color4 #8AADF4 +color12 #8AADF4 + +# magenta +color5 #F5BDE6 +color13 #F5BDE6 + +# cyan +color6 #8BD5CA +color14 #8BD5CA + +# white +color7 #B8C0E0 +color15 #A5ADCB diff --git a/kitty/Catppuccin-Mocha.conf b/kitty/Catppuccin-Mocha.conf new file mode 100644 index 0000000..2533db7 --- /dev/null +++ b/kitty/Catppuccin-Mocha.conf @@ -0,0 +1,80 @@ +# vim:ft=kitty + +## name: Catppuccin-Mocha +## author: Pocco81 (https://github.com/Pocco81) +## license: MIT +## upstream: https://github.com/catppuccin/kitty/blob/main/mocha.conf +## blurb: Soothing pastel theme for the high-spirited! + + + +# The basic colors +foreground #CDD6F4 +background #1E1E2E +selection_foreground #1E1E2E +selection_background #F5E0DC + +# Cursor colors +cursor #F5E0DC +cursor_text_color #1E1E2E + +# URL underline color when hovering with mouse +url_color #F5E0DC + +# Kitty window border colors +active_border_color #B4BEFE +inactive_border_color #6C7086 +bell_border_color #F9E2AF + +# OS Window titlebar colors +wayland_titlebar_color system +macos_titlebar_color system + +# Tab bar colors +active_tab_foreground #11111B +active_tab_background #CBA6F7 +inactive_tab_foreground #CDD6F4 +inactive_tab_background #181825 +tab_bar_background #11111B + +# Colors for marks (marked text in the terminal) +mark1_foreground #1E1E2E +mark1_background #B4BEFE +mark2_foreground #1E1E2E +mark2_background #CBA6F7 +mark3_foreground #1E1E2E +mark3_background #74C7EC + +# The 16 terminal colors + +# black +color0 #45475A +color8 #585B70 + +# red +color1 #F38BA8 +color9 #F38BA8 + +# green +color2 #A6E3A1 +color10 #A6E3A1 + +# yellow +color3 #F9E2AF +color11 #F9E2AF + +# blue +color4 #89B4FA +color12 #89B4FA + +# magenta +color5 #F5C2E7 +color13 #F5C2E7 + +# cyan +color6 #94E2D5 +color14 #94E2D5 + +# white +color7 #BAC2DE +color15 #A6ADC8 diff --git a/kitty/OneDark-Pro.conf b/kitty/OneDark-Pro.conf new file mode 100644 index 0000000..bb3cee1 --- /dev/null +++ b/kitty/OneDark-Pro.conf @@ -0,0 +1,62 @@ +# vim:ft=kitty + +## name: OneDark-Pro +## author: VictorPL (https://github.com/VictorPLopes) +## license: MIT +## upstream: https://github.com/VictorPLopes/OneDark-Pro-Kitty-Terminal/blob/main/kitty-themes/OneDark-Pro.conf +## blurb: Kitty theme inspired by Binaryify's One Dark Pro theme for Visual Studio Code. + +# Colors + +# The basic colors +foreground #ABB2BF +background #282C34 +selection_foreground #282C34 +selection_background #ABB2BF + +# Cursor colors +cursor #ABB2BF +cursor_text_color #282C34 + +# URL underline color when hovering with mouse +url_color #ABB2BF + +# Tab bar colors +active_tab_foreground #3F4451 +active_tab_background #D7DAE0 +inactive_tab_foreground #ABB2BF +inactive_tab_background #282C34 + +# The 16 terminal colors + +# black +color0 #3F4451 +color8 #4F5666 + +# red +color1 #E06C75 +color9 #BE5046 + +# green +color2 #98C379 +color10 #A5E075 + +# yellow +color3 #D19A66 +color11 #E5C07B + +# blue +color4 #61AFEF +color12 #4DC4FF + +# purple +color5 #C678DD +color13 #DE73FF + +# cyan +color6 #56B6C2 +color14 #4CD1E0 + +# white +color7 #D7DAE0 +color15 #E6E6E6 \ No newline at end of file diff --git a/kitty/OneTimeDark.conf b/kitty/OneTimeDark.conf new file mode 100644 index 0000000..dc0760b --- /dev/null +++ b/kitty/OneTimeDark.conf @@ -0,0 +1,62 @@ +# vim:ft=kitty + +## name: OneDark-Pro +## author: VictorPL (https://github.com/VictorPLopes) +## license: MIT +## upstream: https://github.com/VictorPLopes/OneDark-Pro-Kitty-Terminal/blob/main/kitty-themes/OneDark-Pro.conf +## blurb: Kitty theme inspired by Binaryify's One Dark Pro theme for Visual Studio Code. + +# Colors + +# The basic colors +foreground #ABB2BF +background #282C34 +selection_foreground #282C34 +selection_background #ABB2BF + +# Cursor colors +cursor #ABB2BF +cursor_text_color #282C34 + +# URL underline color when hovering with mouse +url_color #ABB2BF + +# Tab bar colors +active_tab_foreground #3F4451 +active_tab_background #D7DAE0 +inactive_tab_foreground #ABB2BF +inactive_tab_background #282C34 + +# The 16 terminal colors + +# black +color0 #3F4451 +color8 #4F5666 + +# red +color1 #E06C75 +color9 #BE5046 + +# green +color2 #98C379 +color10 #A5E075 + +# yellow +color3 #D19A66 +color11 #E5C07B + +# blue +color4 #61AFEF +color12 #4DC4FF + +# purple +color5 #C678DD +color13 #DE73FF + +# cyan +color6 #56B6C2 +color14 #4CD1E0 + +# white +color7 #D7DAE0 +color15 #E6E6E6 diff --git a/kitty/TokyoNight.conf b/kitty/TokyoNight.conf new file mode 100644 index 0000000..e309eee --- /dev/null +++ b/kitty/TokyoNight.conf @@ -0,0 +1,77 @@ +# Tokyo Night color scheme for kitty terminal emulator +# https://github.com/davidmathers/tokyo-night-kitty-theme +# +# Based on Tokyo Night color theme for Visual Studio Code +# https://github.com/enkia/tokyo-night-vscode-theme + +foreground #a9b1d6 +background #1a1b26 + +# Black +color0 #414868 +color8 #414868 + +# Red +color1 #f7768e +color9 #f7768e + +# Green +color2 #73daca +color10 #73daca + +# Yellow +color3 #e0af68 +color11 #e0af68 + +# Blue +color4 #7aa2f7 +color12 #7aa2f7 + +# Magenta +color5 #bb9af7 +color13 #bb9af7 + +# Cyan +color6 #7dcfff +color14 #7dcfff + +# White +color7 #c0caf5 +color15 #c0caf5 + +# Cursor +cursor #c0caf5 +cursor_text_color #1a1b26 + +# Selection highlight +selection_foreground none +selection_background #28344a + +# The color for highlighting URLs on mouse-over +url_color #9ece6a + +# Window borders +active_border_color #3d59a1 +inactive_border_color #101014 +bell_border_color #e0af68 + +# Tab bar +tab_bar_style fade +tab_fade 1 +active_tab_foreground #3d59a1 +active_tab_background #16161e +active_tab_font_style bold +inactive_tab_foreground #787c99 +inactive_tab_background #16161e +inactive_tab_font_style bold +tab_bar_background #101014 + +# Title bar +macos_titlebar_color #16161e + +# Storm +# background #24283b +# cursor_text_color #24283b +# active_tab_background #1f2335 +# inactive_tab_background #1f2335 +# macos_titlebar_color #1f2335 diff --git a/kitty/kitty.app.png b/kitty/kitty.app.png new file mode 100644 index 0000000..cbecb93 Binary files /dev/null and b/kitty/kitty.app.png differ diff --git a/kitty/kitty.conf b/kitty/kitty.conf new file mode 100755 index 0000000..8520e7f --- /dev/null +++ b/kitty/kitty.conf @@ -0,0 +1,48 @@ +allow_remote_control yes +listen_on unix:/tmp/kitty +shell_integration enabled + +# kitty-scrollback.nvim Kitten alias +action_alias kitty_scrollback_nvim kitten $HOME/.local/share/nvim/lazy/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py +# Browse scrollback buffer in nvim +map kitty_mod+h kitty_scrollback_nvim +# Browse output of the last shell command in nvim +map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output +# Show clicked command output in nvim +mouse_map ctrl+shift+right press ungrabbed combine : mouse_select_command_output : kitty_scrollback_nvim --config ksb_builtin_last_visited_cmd_output + +# disable the stupid notification +confirm_os_window_close 0 + +# set shell to fish +shell fish + +# hide_window_decorations yes +window_padding_width 10 + +background_opacity 0.75 +background_blur 16 + +font_family Meslo LGM Nerd Font +font_size 12 + +tab_bat_style powerline +tab_powerline_style round +tab_title_template {title}{' :{}:'.format(num_windows) if num_windows > 1 else ''} + +map ctrl+up previous_window +map ctrl+down next_window + +cursor_trail 1 +cursor_shape beam + +include Catppuccin-Mocha.conf + +map ctrl+plus change_font_size all +1 +map ctrl+kp_add change_font_size all +1 + +map ctrl+minus change_font_size all -1 +map ctrl+kp_subtract change_font_size all -1 + +map ctrl+0 change_font_size all 0 +map ctrl+kp_0 change_font_size all 0 diff --git a/mako/config b/mako/config new file mode 100644 index 0000000..2c92741 --- /dev/null +++ b/mako/config @@ -0,0 +1,16 @@ +max-visible=10 +layer=top +font=Noto Sans 12 +border-radius=12 +max-icon-size=48 +default-timeout=5000 +anchor=top-right +margin=20 + +background-color=#1e1e2e +text-color=#cdd6f4 +border-color=#89b4fa +progress-color=over #313244 + +[urgency=high] +border-color=#fab387 \ No newline at end of file diff --git a/mpv/.gitignore b/mpv/.gitignore new file mode 100644 index 0000000..f4e1cd8 --- /dev/null +++ b/mpv/.gitignore @@ -0,0 +1 @@ +lastopen.json diff --git a/mpv/bookmarker.json b/mpv/bookmarker.json new file mode 100644 index 0000000..9b684a8 --- /dev/null +++ b/mpv/bookmarker.json @@ -0,0 +1 @@ +[{"version":2,"name":"27-第二十七:寻仙台开启!-1080P 高清-AVC.mp4 @ 00:00:08.233","pos":8.233000,"path":"/home/wrq/down/沙雕动漫/第一百二十二集:疯狂钢管舞!/27-第二十七:寻仙台开启!-1080P 高清-AVC.mp4"}] \ No newline at end of file diff --git a/mpv/input.conf b/mpv/input.conf new file mode 100644 index 0000000..bec5fdd --- /dev/null +++ b/mpv/input.conf @@ -0,0 +1,195 @@ +# vim: syntax=config + +# 左键单击暂停/双击全屏 +# MOUSE_BTN0 cycle pause +MBTN_LEFT_DBL cycle fullscreen +MBTN_LEFT cycle pause + +# 滚轮控制音量 +AXIS_UP add volume +2 +AXIS_DOWN add volume -2 + +# 快进和后退 +RIGHT osd-msg-bar seek +2 relative+keyframes +LEFT osd-msg-bar seek -2 relative+keyframes +l osd-msg-bar seek +2 relative+keyframes +h osd-msg-bar seek -2 relative+keyframes +SHIFT+RIGHT osd-msg-bar seek +10 relative+keyframes +SHIFT+LEFT osd-msg-bar seek -10 relative+keyframes +L osd-msg-bar seek +10 relative+keyframes +H osd-msg-bar seek -10 relative+keyframes + +# 音量 +UP add volume +2 +DOWN add volume -2 +k add volume +2 +j add volume -2 +SHIFT+UP add volume +10 +SHIFT+DOWN add volume -10 +K add volume +10 +J add volume -10 + +# 亮度 +. add brightness +1 +, add brightness -1 + +# 播放下一个/上一个 + +ALT+h playlist-prev ; show-text "${playlist-pos-1}/${playlist-count}" +PGUP playlist-prev ; show-text "${playlist-pos-1}/${playlist-count}" + +ALT+l playlist-next ; show-text "${playlist-pos-1}/${playlist-count}" +PGDWN playlist-next ; show-text "${playlist-pos-1}/${playlist-count}" + +# 显示播放信息 +CTRL+i script-binding stats/display-stats-toggle + +# 音轨 +a script_message audio-menu # 打开音轨菜单 +A cycle audio # 下一个音轨 + +# 第一字幕列表选择 +s script_message subtitle-menu# 打开字幕菜单 +# # 第一字幕的下一个字幕 +S cycle sub +# # 第二字幕的下一个字幕 +# ALT+d cycle secondary-sid +# # 是否显示字幕 # cycle through subtitles +CTRL+s cycle sub-visibility + + +# 播放速度 +ALT+b add speed +0.05 +B add speed -0.05 +CTRL+b set speed 1.0 + +# 音轨延迟 +ALT+n add audio-delay +0.10 +N add audio-delay -0.10 +CTRL+n set sub-delay 0 + +# 字幕延迟 +ALT+m add sub-delay +0.10 +M add sub-delay -0.10 +CTRL+m set sub-delay 0 + +# 字幕大小和位置 +t add sub-scale -0.05 # decrease subtitle font size +r add sub-scale +0.05 # increase subtitle font size +T add sub-pos -1 # move subtitles up +R add sub-pos +1 # move subtitles down +CTRL+t set sub-scale 1.2 +CTRL+r set sub-pos 100 + +# f 全屏,这个是默认的 +SPACE cycle pause #暂停 +IDEOGRAPHIC_SPACE cycle pause +m cycle mute #静音 +CTRL+p show-progress + + +# 媒体按键 +MENU show-progress +PLAY cycle pause +PAUSE cycle pause +PLAYPAUSE cycle pause +FORWARD osd-msg-bar seek +5 relative keyframes +REWIND osd-msg-bar seek -5 relative keyframes +VOLUME_UP add volume +2 ; show-text "Volume: ${volume}" +VOLUME_DOWN add volume -2 ; show-text "Volume: ${volume}" +MUTE cycle mute +CLOSE_WIN quit + +# 播放列表 +# SHIFT+RETURN 打开列表 +# UP/DOWN移动选择 +# RETURN 打开 +# ESC退出 +SHIFT+ENTER script-binding playlistmanager/showplaylist +ALT+k script-binding playlistmanager/moveup +ALT+j script-binding playlistmanager/movedown +ENTER script-binding playlistmanager/playfile +ESC script-binding playlistmanager/hideplaylist + +# 书签 +# o 打开书签 +# O 保存当前为书签 +# ESC :关闭书签菜单 +# UP/DOWN/j/k/J/K :浏览当前页面上的书签(按住可快速滚动) +# LEFT/RIGHT :浏览书签页面(按住可快速滚动) +# ENTER :加载当前选择的书签 +# d/DEL :删除当前选择的书 +o script_message bookmarker-menu +O script_message bookmarker-quick-save +d script_message bookmarker-menu + +# 打开上次播放的 +CTRL+l script_message lastopen + + +# 文件管理器 +# ctrl + o 打开文件管理器 +# alt + o 输入要打开的目录 +# up/down 移动选择 +# left/right 进入/离开目录 +# Return 播放 + +#忽略 +c ignore +e ignore +g ignore +i ignore +p ignore +q ignore +u ignore +v ignore +w ignore +x ignore +y ignore +z ignore +A ignore +C ignore +D ignore +E ignore +F ignore +G ignore +I ignore +P ignore +Q ignore +U ignore +V ignore +W ignore +X ignore +Y ignore +Z ignore +< ignore +> ignore +? ignore +/ ignore +[ ignore +] ignore +{ ignore +} ignore +\ ignore +| ignore +0 ignore +1 ignore +2 ignore +3 ignore +4 ignore +5 ignore +6 ignore +7 ignore +8 ignore +9 ignore +BS ignore +KP0 ignore +KP1 ignore +KP2 ignore +KP3 ignore +KP4 ignore +KP5 ignore +KP6 ignore +KP7 ignore +KP8 ignore +KP9 ignore diff --git a/mpv/mpv.conf b/mpv/mpv.conf new file mode 100644 index 0000000..81a2247 --- /dev/null +++ b/mpv/mpv.conf @@ -0,0 +1,123 @@ +# vim: syntax=config + + +########### +# General # +########### +auto-window-resize=no +save-position-on-quit +input-ipc-server=/tmp/mpvsocket # listen for IPC on this socket +load-stats-overlay=no +load-auto-profiles=no + +brightness=-8 +monitorpixelaspect=1 +no-border # no window title bar +msg-module # prepend module name to log messages +msg-color # color log messages on terminal +term-osd-bar # display a progress bar on the terminal +use-filedir-conf # look for additional config files in the directory of the opened file +input-media-keys=no # enable/disable OSX media keys +cursor-autohide=1000 # autohide the curser after 1s +prefetch-playlist=yes +force-seekable=yes + +screenshot-format=png +screenshot-png-compression=8 +screenshot-template='~/down/%F (%P) %n' +watch-later-directory='~/.mpv/watch_later' +write-filename-in-watch-later-config +watch-later-options-remove=fullscreen + +hls-bitrate=max # use max quality for HLS streams + + + +[default] + + +######### +# Cache # +######### + +cache=auto + + +############# +# OSD / OSC # +############# +osc=no +osd-level=1 # enable osd and display --osd-status-msg on interaction +osd-duration=2500 # hide the osd after x ms +osd-status-msg='${time-pos} / ${duration}${?percent-pos: (${percent-pos}%)}${?frame-drop-count:${!frame-drop-count==0: Dropped: ${frame-drop-count}}}\n${?chapter:Chapter: ${chapter}}' + +osd-font='Source Han Sans CN' +osd-font-size=32 +osd-color='#CCFFFFFF' # ARGB format +osd-border-color='#DD322640' # ARGB format +osd-bar-align-y=0 # progress bar y alignment (-1 top, 0 centered, 1 bottom) +osd-border-size=2 # size for osd text and progress bar +osd-bar-h=2 # height of osd bar as a fractional percentage of your screen height +osd-bar-w=60 # width of " " " + + +############# +# Subtitles # +############# +sub-ass + +demuxer-mkv-subtitle-preroll=yes # try to show embedded subs when seeking even when no index information is present +demuxer-mkv-subtitle-preroll-secs=2 + +sub-auto=fuzzy # external subs don't have to match the file name exactly to autoload +sub-file-paths-append=ass # search for external subs in these relative subdirectories +sub-file-paths-append=srt +sub-file-paths-append=sub +sub-file-paths-append=subs +sub-file-paths-append=subtitles + +embeddedfonts=yes # use embedded fonts for SSA/ASS subs +sub-fix-timing=no # do not try to fix gaps (which might make it worse in some cases) +sub-ass-force-style=Kerning=yes # allows you to override style parameters of ASS scripts +sub-use-margins +sub-ass-force-margins + +# the following options only apply to subtitles without own styling (i.e. not ASS but e.g. SRT) +sub-font="Source Han Sans CN" +sub-font-size=45 +sub-color="#FFFFFFFF" +sub-border-color="#FF262626" +sub-border-size=3.2 +sub-shadow-offset=1 +sub-shadow-color="#33000000" +sub-scale=1.2 + + +############# +# Languages # +############# + +alang=eng,chi # automatically select these subtitles (decreasing priority) +slang=zh,zh-cn,zh-sim # automatically select these audio tracks (decreasing priority) + + +######### +# Audio # +######### + +audio-file-auto=fuzzy # external audio doesn't has to match the file name exactly to autoload +audio-pitch-correction=yes # automatically insert scaletempo when playing with higher speed +volume-max=200 # maximum volume in %, everything above 100 results in amplification +volume=80 # default volume, 100 = unchanged + + +################ +# Video Output # +################ +profile=fast +vo=gpu-next +video-rotate=no +hwdec=auto +gpu-api=opengl +# Defaults for all profiles + diff --git a/mpv/sample-file/input.conf-sample b/mpv/sample-file/input.conf-sample new file mode 100644 index 0000000..000f7ae --- /dev/null +++ b/mpv/sample-file/input.conf-sample @@ -0,0 +1,184 @@ +# mpv keybindings +# +# Location of user-defined bindings: ~/.config/mpv/input.conf +# +# Lines starting with # are comments. Use SHARP to assign the # key. +# Copy this file and uncomment and edit the bindings you want to change. +# +# List of commands and further details: DOCS/man/input.rst +# List of special keys: --input-keylist +# Keybindings testing mode: mpv --input-test --force-window --idle +# +# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore'). +# +# Strings need to be quoted and escaped: +# KEY show-text "This is a single backslash: \\ and a quote: \" !" +# +# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with +# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal). +# +# The default keybindings are hardcoded into the mpv binary. +# You can disable them completely with: --no-input-default-bindings + +# Developer note: +# On compilation, this file is baked into the mpv binary, and all lines are +# uncommented (unless '#' is followed by a space) - thus this file defines the +# default key bindings. + +# If this is enabled, treat all the following bindings as default. +#default-bindings start + +#MBTN_LEFT ignore # don't do anything +#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen +#MBTN_RIGHT cycle pause # toggle pause/playback mode +#MBTN_BACK playlist-prev # skip to the previous file +#MBTN_FORWARD playlist-next # skip to the next file + +# Mouse wheels, touchpad or other input devices that have axes +# if the input devices supports precise scrolling it will also scale the +# numeric value accordingly +#WHEEL_UP add volume 2 +#WHEEL_DOWN add volume -2 +#WHEEL_LEFT seek -10 # seek 10 seconds backward +#WHEEL_RIGHT seek 10 # seek 10 seconds forward + +## Seek units are in seconds, but note that these are limited by keyframes +#RIGHT seek 5 # seek 5 seconds forward +#LEFT seek -5 # seek 5 seconds backward +#UP seek 60 # seek 1 minute forward +#DOWN seek -60 # seek 1 minute backward +# Do smaller, always exact (non-keyframe-limited), seeks with shift. +# Don't show them on the OSD (no-osd). +#Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward +#Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward +#Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward +#Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward +#Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle +#Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle +#Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed +#Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed +#Alt+left add video-pan-x 0.1 # move the video right +#Alt+right add video-pan-x -0.1 # move the video left +#Alt+up add video-pan-y 0.1 # move the video down +#Alt+down add video-pan-y -0.1 # move the video up +#Alt++ add video-zoom 0.1 # zoom in +#ZOOMIN add video-zoom 0.1 # zoom in +#Alt+- add video-zoom -0.1 # zoom out +#ZOOMOUT add video-zoom -0.1 # zoom out +#Ctrl+WHEEL_UP add video-zoom 0.1 # zoom in +#Ctrl+WHEEL_DOWN add video-zoom -0.1 # zoom out +#Alt+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 # reset zoom and pan settings +#PGUP add chapter 1 # seek to the next chapter +#PGDWN add chapter -1 # seek to the previous chapter +#Shift+PGUP seek 600 # seek 10 minutes forward +#Shift+PGDWN seek -600 # seek 10 minutes backward +#[ multiply speed 1/1.1 # decrease the playback speed +#] multiply speed 1.1 # increase the playback speed +#{ multiply speed 0.5 # halve the playback speed +#} multiply speed 2.0 # double the playback speed +#BS set speed 1.0 # reset the speed to normal +#Shift+BS revert-seek # undo the previous (or marked) seek +#Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek +#q quit +#Q quit-watch-later # exit and remember the playback position +#q {encode} quit 4 +#ESC set fullscreen no # leave fullscreen +#ESC {encode} quit 4 +#p cycle pause # toggle pause/playback mode +#. frame-step # advance one frame and pause +#, frame-back-step # go back by one frame and pause +#SPACE cycle pause # toggle pause/playback mode +#> playlist-next # skip to the next file +#ENTER playlist-next # skip to the next file +#< playlist-prev # skip to the previous file +#O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always +#o show-progress # show playback progress +#P show-progress # show playback progress +#i script-binding stats/display-stats # display information and statistics +#I script-binding stats/display-stats-toggle # toggle displaying information and statistics +#` script-binding console/enable # open the console +#z add sub-delay -0.1 # shift subtitles 100 ms earlier +#Z add sub-delay +0.1 # delay subtitles by 100 ms +#x add sub-delay +0.1 # delay subtitles by 100 ms +#ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio +#ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier +#Shift+g add sub-scale +0.1 # increase the subtitle font size +#Shift+f add sub-scale -0.1 # decrease the subtitle font size +#9 add volume -2 +#/ add volume -2 +#0 add volume 2 +#* add volume 2 +#m cycle mute # toggle mute +#1 add contrast -1 +#2 add contrast 1 +#3 add brightness -1 +#4 add brightness 1 +#5 add gamma -1 +#6 add gamma 1 +#7 add saturation -1 +#8 add saturation 1 +#Alt+0 set current-window-scale 0.5 # halve the window size +#Alt+1 set current-window-scale 1.0 # reset the window size +#Alt+2 set current-window-scale 2.0 # double the window size +#b cycle deband # toggle the debanding filter +#d cycle deinterlace # cycle the deinterlacing filter +#r add sub-pos -1 # move subtitles up +#R add sub-pos +1 # move subtitles down +#t add sub-pos +1 # move subtitles down +#v cycle sub-visibility # hide or show the subtitles +#Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles +#V cycle sub-ass-vsfilter-aspect-compat # toggle stretching SSA/ASS subtitles with anamorphic videos to match the historical renderer +#u cycle-values sub-ass-override "force" "yes" # toggle overriding SSA/ASS subtitle styles with the normal styles +#j cycle sub # switch subtitle track +#J cycle sub down # switch subtitle track backwards +#SHARP cycle audio # switch audio track +#_ cycle video # switch video track +#T cycle ontop # toggle placing the video on top of other windows +#f cycle fullscreen # toggle fullscreen +#s screenshot # take a screenshot of the video in its original resolution with subtitles +#S screenshot video # take a screenshot of the video in its original resolution without subtitles +#Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles +#Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots +#w add panscan -0.1 # decrease panscan +#W add panscan +0.1 # shrink black bars by cropping the video +#e add panscan +0.1 # shrink black bars by cropping the video +#A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect) +#POWER quit +#PLAY cycle pause # toggle pause/playback mode +#PAUSE cycle pause # toggle pause/playback mode +#PLAYPAUSE cycle pause # toggle pause/playback mode +#PLAYONLY set pause no # unpause +#PAUSEONLY set pause yes # pause +#STOP quit +#FORWARD seek 60 # seek 1 minute forward +#REWIND seek -60 # seek 1 minute backward +#NEXT playlist-next # skip to the next file +#PREV playlist-prev # skip to the previous file +#VOLUME_UP add volume 2 +#VOLUME_DOWN add volume -2 +#MUTE cycle mute # toggle mute +#CLOSE_WIN quit +#CLOSE_WIN {encode} quit 4 +#ctrl+w quit +#E cycle edition # switch edition +#l ab-loop # set/clear A-B loop points +#L cycle-values loop-file "inf" "no" # toggle infinite looping +#ctrl+c quit 4 +#DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always +#ctrl+h cycle-values hwdec "auto-safe" "no" # toggle hardware decoding +#F8 show-text ${playlist} # show the playlist +#F9 show-text ${track-list} # show the list of video, audio and sub tracks + +# +# Legacy bindings (may or may not be removed in the future) +# +#! add chapter -1 # seek to the previous chapter +#@ add chapter 1 # seek to the next chapter + +# +# Not assigned by default +# (not an exhaustive list of unbound commands) +# + +# ? cycle sub-forced-events-only # display only DVD/PGS forced subtitle events +# ? stop # stop playback (quit or enter idle mode) diff --git a/mpv/sample-file/mpv.conf-sample b/mpv/sample-file/mpv.conf-sample new file mode 100644 index 0000000..d873c06 --- /dev/null +++ b/mpv/sample-file/mpv.conf-sample @@ -0,0 +1,143 @@ +# +# Example mpv configuration file +# +# Warning: +# +# The commented example options usually do _not_ set the default values. Call +# mpv with --list-options to see the default values for most options. There is +# no builtin or example mpv.conf with all the defaults. +# +# +# Configuration files are read system-wide from /usr/local/etc/mpv.conf +# and per-user from ~/.config/mpv/mpv.conf, where per-user settings override +# system-wide settings, all of which are overridden by the command line. +# +# Configuration file settings and the command line options use the same +# underlying mechanisms. Most options can be put into the configuration file +# by dropping the preceding '--'. See the man page for a complete list of +# options. +# +# Lines starting with '#' are comments and are ignored. +# +# See the CONFIGURATION FILES section in the man page +# for a detailed description of the syntax. +# +# Profiles should be placed at the bottom of the configuration file to ensure +# that settings wanted as defaults are not restricted to specific profiles. + +################## +# video settings # +################## + +# Start in fullscreen mode by default. +#fs=yes + +# force starting with centered window +#geometry=50%:50% + +# don't allow a new window to have a size larger than 90% of the screen size +#autofit-larger=90%x90% + +# Do not close the window on exit. +#keep-open=yes + +# Do not wait with showing the video window until it has loaded. (This will +# resize the window once video is loaded. Also always shows a window with +# audio.) +#force-window=immediate + +# Disable the On Screen Controller (OSC). +#osc=no + +# Keep the player window on top of all other windows. +#ontop=yes + +# Specify fast video rendering preset (for --vo= only) +# Recommended for mobile devices or older hardware with limited processing power +#profile=fast + +# Specify high quality video rendering preset (for --vo= only) +# Offers superior image fidelity and visual quality for an enhanced viewing +# experience on capable hardware +#profile=high-quality + +# Force video to lock on the display's refresh rate, and change video and audio +# speed to some degree to ensure synchronous playback - can cause problems +# with some drivers and desktop environments. +#video-sync=display-resample + +# Enable hardware decoding if available. Often, this does not work with all +# video outputs, but should work well with default settings on most systems. +# If performance or energy usage is an issue, forcing the vdpau or vaapi VOs +# may or may not help. +#hwdec=auto + +################## +# audio settings # +################## + +# Specify default audio device. You can list devices with: --audio-device=help +# The option takes the device string (the stuff between the '...'). +#audio-device=alsa/default + +# Do not filter audio to keep pitch when changing playback speed. +#audio-pitch-correction=no + +# Output 5.1 audio natively, and upmix/downmix audio with a different format. +#audio-channels=5.1 +# Disable any automatic remix, _if_ the audio output accepts the audio format. +# of the currently played file. See caveats mentioned in the manpage. +# (The default is "auto-safe", see manpage.) +#audio-channels=auto + +################## +# other settings # +################## + +# Pretend to be a web browser. Might fix playback with some streaming sites, +# but also will break with shoutcast streams. +#user-agent="Mozilla/5.0" + +# cache settings +# +# Use a large seekable RAM cache even for local input. +#cache=yes +# +# Use extra large RAM cache (needs cache=yes to make it useful). +#demuxer-max-bytes=500M +#demuxer-max-back-bytes=100M +# +# Disable the behavior that the player will pause if the cache goes below a +# certain fill size. +#cache-pause=no +# +# Store cache payload on the hard disk instead of in RAM. (This may negatively +# impact performance unless used for slow input such as network.) +#cache-dir=~/.cache/ +#cache-on-disk=yes + +# Display English subtitles if available. +#slang=en + +# Play Finnish audio if available, fall back to English otherwise. +#alang=fi,en + +# Change subtitle encoding. For Arabic subtitles use 'cp1256'. +# If the file seems to be valid UTF-8, prefer UTF-8. +# (You can add '+' in front of the codepage to force it.) +#sub-codepage=cp1256 + +# You can also include other configuration files. +#include=/path/to/the/file/you/want/to/include + +############ +# Profiles # +############ + +# The options declared as part of profiles override global default settings, +# but only take effect when the profile is active. + +# The following profile can be enabled on the command line with: --profile=eye-cancer + +#[eye-cancer] +#sharpen=5 diff --git a/mpv/script-opts/console.conf b/mpv/script-opts/console.conf new file mode 100644 index 0000000..a814186 --- /dev/null +++ b/mpv/script-opts/console.conf @@ -0,0 +1 @@ +font_size=44 diff --git a/mpv/script-opts/file_browser.conf b/mpv/script-opts/file_browser.conf new file mode 100644 index 0000000..3bf8058 --- /dev/null +++ b/mpv/script-opts/file_browser.conf @@ -0,0 +1,175 @@ +####################################################### +# This is the default config file for mpv-file-browser +# https://github.com/CogentRedTester/mpv-file-browser +####################################################### + +# root directories, separated by commas +# on linux you will probably want to add `/`, +# on windows this should be used to add different drive letters +# Examples: +# linux: root=~/,/ +# windows: root=~/,C:/ +root=~/ + +# characters to separate root directories, each character works individually +# this is in case one is using directories with strange names +root_separators=,; + +# number of entries to show on the screen at once +num_entries=20 + +# wrap the cursor around the top and bottom of the list +wrap=no + +# only show files compatible with mpv in the browser +filter_files=yes + +# experimental feature that recurses directories concurrently when appending items to the playlist +# this feature has the potential for massive performance improvements when using addons with asynchronous IO +concurrent_recursion=no + +# maximum number of recursions that can run concurrently +# if this number is too high it risks overflowing the mpv event queue, which will cause some directories to be dropped entirely +max_concurrency=16 + +# enable custom keybinds +# the keybind json file must go in ~~/script-opts +custom_keybinds=no + +# file-browser only shows files that are compatible with mpv by default +# adding a file extension to this list will add it to the extension whitelist +# extensions are separated with the root separators, do not use any spaces +extension_whitelist= + +# add file extensions to this list to disable default filetypes +# note that this will also override audio/subtitle_extension options below +extension_blacklist= + +# files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist +# items on this list are automatically added to the extension whitelist +audio_extensions=mka,dts,dtshd,dts-hd,truehd,true-hd + +# files with these extensions will be added as additional subtitle tracks for the current file instead of appended to the playlist +# items on this list are automatically added to the extension whitelist +subtitle_extensions=etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs + +# filter directories or files starting with a period like .config +# for linux systems +filter_dot_dirs=no +filter_dot_files=no + +# substitude forward slashes for backslashes when appending a local file to the playlist +# may be useful on windows systems +substitute_backslash=no + +# interpret backslashes `\` in paths as forward slashes `/` +# this is useful on Windows, which natively uses backslashes. +# As backslashes are valid filename characters in Unix systems this could +# cause mangled paths, though such filenames are rare. +# Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform` +# property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`. +normalise_backslash=auto + +# this option reverses the behaviour of the alt+ENTER keybind +# when disabled the keybind is required to enable autoload for the file +# when enabled the keybind disables autoload for the file +autoload=no + +# if autoload is triggered by selecting the currently playing file, then +# the current file will have it's watch-later config saved before being closed and re-opened +# essentially the current file will not be restarted +autoload_save_current=yes + +# when opening the browser in idle mode prefer the current working directory over the root +# note that the working directory is set as the 'current' directory regardless, so `home` will +# move the browser there even if this option is set to false +default_to_working_directory=no + +# when moving up a directory do not stop on empty protocol schemes like `ftp://` +# e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://` +skip_protocol_schemes=yes + +# map optical device paths to their respective file paths, +# e.g. mapping bd:// to the value of the bluray-device property +map_bd_device=yes +map_dvd_device=yes +map_cdda_device=yes + +# enables addons +addons=no +addon_directory=~~/script-modules/file-browser-addons + +# directory to load external modules - currently just user-input-module +module_directory=~~/script-modules + +# turn the OSC idle screen off and on when opening and closing the browser +# this should only be enabled if file-browser is the only thing controlling the idle-screen, +# if multiple sources attempt to control the idle-screen at the same time it can cause unexpected behaviour. +toggle_idlescreen=no + +# Set the current open status of the browser in the `file_browser/open` field of the `user-data` property. +# This property is only available in mpv v0.36+. +set_user_data=yes + +# Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property. +# This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically disable this option. +set_shared_script_properties=no + +#################################### +######### style settings ########### +#################################### + +# force file-browser to use a specific text alignment (default: top-left) +# uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 +# set to 0 to use the default mpv osd-align options +alignment=7 + +# The format string used for the header. Uses custom-keybind substitution codes to +# dynamically change the contents of the header. See: docs/custom-keybinds.md#codes +# e.g. to add file numbers, set this to: {\fnMonospace}[%i/%x]{\fn} %q\N---------------------------------------------------- +format_string_header=%q\N---------------------------------------------------- + +# The format strings used for the wrappers. Supports custom-keybind substitution codes, and +# supports two additional codes: `%<` and `%>` to show the number of items before and after the visible list, respectively. +# Setting these options to empty strings will disable the wrappers. +format_string_topwrapper=%< item(s) above\N +format_string_bottomwrapper=\N%> item(s) remaining + +# allows custom icons be set for the folder and cursor +# the `\h` character is a hard space to add padding +folder_icon={\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h +cursor_icon={\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h + +# set the opacity of fonts in hexadecimal from 00 (opaque) to FF (transparent) +font_opacity_selection_marker=99 + +# print the header in bold font +font_bold_header=yes + +# scale the size of the browser; 2 would double the size, 0.5 would halve it, etc. +# the header and wrapper scaling is relative to the base scaling +scaling_factor_base=1 +scaling_factor_header=1.4 +scaling_factor_wrappers=0.64 + +# set custom font names, blank is the default +# setting custom fonts for the folder/cursor can fix broken or missing icons +font_name_header= +font_name_body= +font_name_wrappers= +font_name_folder= +font_name_cursor= + +# set custom font colours +# colours are in hexadecimal format in Blue Green Red order +# note that this is the opposite order to most RGB colour codes +font_colour_header=00ccff +font_colour_body=ffffff +font_colour_wrappers=00ccff +font_colour_cursor=00ccff + +# these are colours applied to list items in different states +font_colour_selected=fce788 +font_colour_multiselect=fcad88 +font_colour_playing=33ff66 +font_colour_playing_multiselected=22b547 diff --git a/mpv/script-opts/mpv_thumbnail_script.conf b/mpv/script-opts/mpv_thumbnail_script.conf new file mode 100644 index 0000000..74d5af9 --- /dev/null +++ b/mpv/script-opts/mpv_thumbnail_script.conf @@ -0,0 +1,49 @@ +# Automatically generate the thumbnails on video load, without a keypress +autogenerate=no + +# 1 hour, Only automatically thumbnail videos shorter than this (seconds) +autogenerate_max_duration=3600 + +# SHA1-sum filenames over this length +# It's nice to know what files the thumbnails are (hence directory names) +# but long URLs may approach filesystem limits. +hash_filename_length=128 + +# Use mpv to generate thumbnail even if ffmpeg is found in PATH +# ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)! +# mpv is a bit slower, but has better support overall (eg. subtitles in the previews) +prefer_mpv=yes + +# Disable the built-in keybind ("T") to add your own +disable_keybinds=no + +# The thumbnail count target +# (This will result in a thumbnail every ~10 seconds for a 25 minute video) +thumbnail_count=150 + +# The above target count will be adjusted by the minimum and +# maximum time difference between thumbnails. +# The thumbnail_count will be used to calculate a target separation, +# and min/max_delta will be used to constrict it. + +# In other words, thumbnails will be: +# at least min_delta seconds apart (limiting the amount) +# at most max_delta seconds apart (raising the amount if needed) +min_delta=5 +# 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours! +max_delta=90 + + +# Overrides for remote urls (you generally want less thumbnails!) +# Thumbnailing network paths will be done with mpv + +# Allow thumbnailing network paths (naive check for "://") +thumbnail_network=no +# Override thumbnail count, min/max delta +remote_thumbnail_count=60 +remote_min_delta=15 +remote_max_delta=120 + +# Try to grab the raw stream and disable ytdl for the mpv subcalls +# Much faster than passing the url to ytdl again, but may cause problems with some sites +remote_direct_stream=yes diff --git a/mpv/script-opts/osc.conf b/mpv/script-opts/osc.conf new file mode 100644 index 0000000..03a4135 --- /dev/null +++ b/mpv/script-opts/osc.conf @@ -0,0 +1,22 @@ +# Timestamp +# Display total time instead of remaining time +timetotal=yes +# Display timecodes with milliseconds +timems=no + +# Whether to display the chapters/playlist at the OSD when left-clicking the next/previous OSC buttons, respectively. +playlist_osd=yes +chapters_osd=yes + +# Duration of fade out in ms, 0 = no fade +fadeduration=200 + +# Minimum amount of pixels the mouse has to move between ticks to make the OSC show up. Default pre-0.21.0 was 3. +minmousemove=0 + +# auto=hide/show on mouse move +# Also supports never and always +visibility=auto + +# Use a Unicode minus sign instead of an ASCII hyphen when displaying the remaining playback time. +unicodeminus=no diff --git a/mpv/script-opts/playlistmanager.conf b/mpv/script-opts/playlistmanager.conf new file mode 100644 index 0000000..56c5f7e --- /dev/null +++ b/mpv/script-opts/playlistmanager.conf @@ -0,0 +1,169 @@ +#### ------- Mpv-Playlistmanager configuration ------- #### + +#navigation keybindings force override only while playlist is visible +#if "no" then you can display the playlist by any of the navigation keys +dynamic_binds=yes + +# To bind multiple keys separate them by a space + +# main key to show playlist +key_showplaylist=SHIFT+ENTER + +# display playlist while key is held down +key_peek_at_playlist= + +# dynamic keys +key_moveup=UP +key_movedown=DOWN +key_movepageup=PGUP +key_movepagedown=PGDWN +key_movebegin=HOME +key_moveend=END +key_selectfile=RIGHT LEFT +key_unselectfile= +key_playfile=ENTER +key_removefile=BS +key_closeplaylist=ESC SHIFT+ENTER + +# extra functionality keys +key_sortplaylist= +key_shuffleplaylist= +key_reverseplaylist= +key_loadfiles= +key_saveplaylist= + +#json format for replacing, check .lua for explanation +#example json=[{"ext":{"all":true},"rules":[{"_":" "}]},{"ext":{"mp4":true,"mkv":true},"rules":[{"^(.+)%..+$":"%1"},{"%s*[%[%(].-[%]%)]%s*":""},{"(%w)%.(%w)":"%1 %2"}]},{"protocol":{"http":true,"https":true},"rules":[{"^%a+://w*%.?":""}]}] +#empty for no replace +filename_replace=[{"protocol":{"all":true},"rules":[{"%%(%x%x)":"hex_to_char"}]}] + +#filetypes to search from directory +loadfiles_filetypes=["jpg","jpeg","png","tif","tiff","gif","webp","svg","bmp","mp3","wav","ogm","flac","m4a","wma","ogg","opus","mkv","avi","mp4","ogv","webm","rmvb","flv","wmv","mpeg","mpg","m4v","3gp"] + +#loadfiles at startup if 1 or more items in playlist +loadfiles_on_start=no +#loadfiles from working directory on idle startup +loadfiles_on_idle_start=no +#always put loaded files after currently playing file +loadfiles_always_append=no + +#sort playlist when any files are added to playlist after initial load +sortplaylist_on_file_add=no + +#default sorting method, must be one of: "name-asc", "name-desc", "date-asc", "date-desc", "size-asc", "size-desc". +default_sort=name-asc + +#linux | windows | auto +system=auto + +#Use ~ for home directory. Leave as empty to use mpv/playlists +playlist_savepath= + +#constant filename to save playlist as. Note that it will override existing playlist. Leave empty for generated name. +playlist_save_filename= + +#save playlist automatically after current file was unloaded +save_playlist_on_file_end=no + +#show file title every time a new file is loaded +show_title_on_file_load=no +#show playlist every time a new file is loaded +show_playlist_on_file_load=no +#close playlist when selecting file to play +close_playlist_on_playfile=no + +#sync cursor when file is loaded from outside reasons(file-ending, playlist-next shortcut etc.) +sync_cursor_on_load=yes + +#allow the playlist cursor to loop from end to start and vice versa +loop_cursor=yes + +#allow playlistmanager to write watch later config when navigating between files +allow_write_watch_later_config=yes + +#reset cursor navigation when closing or opening playlist +reset_cursor_on_close=yes +reset_cursor_on_open=yes + +#prefer to display titles for following files: "all", "url", "none". Sorting still uses filename +prefer_titles=url + +#youtube-dl executable for title resolving if enabled, probably "youtube-dl" or "yt-dlp", can be absolute path +youtube_dl_executable=yt-dlp + +#call youtube-dl to resolve the titles of urls in the playlist +#if yes, prefer_titles must be set to "url" or "all" for this to work +resolve_url_titles=no + +#call ffprobe to resolve the titles of local files in the playlist (if they exist in the metadata) +#if yes, prefer_titles must be set to "all" for this to work +resolve_local_titles=no + +#timeout in seconds for url title resolving +resolve_title_timeout=15 + +#how many url titles can be resolved at a time. Higher number might lead to stutters. +concurrent_title_resolve_limit=10 + +#osd timeout on inactivity in seconds, use 0 for no timeout +playlist_display_timeout=0 + +#when peeking at playlist, show playlist at the very least for display timeout +peek_respect_display_timeout=no + +#the maximum amount of lines playlist will render. -1 will automatically calculate lines. +showamount=-1 + +#playlist ass style overrides +#example {\q2\an7\fnUbuntu\fs10\b0\bord1} equals: line-wrap=no, align=top left, font=Ubuntu, size=10, bold=no, border=1 +#read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags +#undeclared tags will use default osd settings +#these styles will be used for the whole playlist +#\q2 style is recommended since filename wrapping may lead to unexpected rendering +#\an7 style is recommended to align to top left, otherwise osd-align-x/y is respected +style_ass_tags={\q2\an7} +#paddings for left right and top bottom +text_padding_x=30 +text_padding_y=60 + +#screen dim when menu is open 0.0 - 1.0 (0 is no dim, 1 is black) +curtain_opacity=0.7 + +#set title of window with stripped name +set_title_stripped=no +title_prefix= +title_suffix= - mpv + +#slice long filenames, and how many chars to show +slice_longfilenames=no +slice_longfilenames_amount=70 + +#Playing header. One newline will be added after the string. +#%mediatitle or %filename = title or name of playing file +#%pos = position of playing file +#%cursor = position of navigation +#%plen = playlist lenght +#%N = newline +playlist_header=[%cursor/%plen] + +#Playlist file templates +#%pos = position of file with leading zeros +#%name = title or name of file +#%N = newline +#you can also use the ass tags mentioned above. For example: +# selected_file={\c&HFF00FF&}➔ %name | to add a color for selected file. However, if you +# use ass tags you need to reset them for every line (see https://github.com/jonniek/mpv-playlistmanager/issues/20) +normal_file={\c&HEEECE8&}○ %name +hovered_file={\c&H33FFFF&}● %name +selected_file={\c&HFF00FF&}➔ %name +playing_file={\c&H91ff4c&}▷ %name +playing_hovered_file={\c&H00FF00&}▶ %name +playing_selected_file={\c&Hff9ad3&}➤ %name + +#what to show when playlist is truncated +playlist_sliced_prefix=... +playlist_sliced_suffix=... + +#output visual feedback to OSD when saving, shuffling, reversing playlists +display_osd_feedback=yes + diff --git a/mpv/script-opts/tethys.conf b/mpv/script-opts/tethys.conf new file mode 100644 index 0000000..19a2cbd --- /dev/null +++ b/mpv/script-opts/tethys.conf @@ -0,0 +1,54 @@ +### Config +showPictureInPictureButton=yes +showSpeedButton=yes +# Show name and shortcut of buttons on hover +showShortcutTooltip=yes +# Show chapter above timestamp in seekbar tooltip +showChapterTooltip=yes +# skipback/skipfrwd amount in seconds +skipBy=5 +# RightClick skipback/skipfrwd amount in seconds +skipByMore=30 +# "exact" (mordenx default) or "relative+keyframes" (mpv default) +skipMode=exact +# PictureInPicture 33% screen width, 10px from bottom right +pipGeometry=33%+-10+-10 +# PictureInPicture will show video on all virtual desktops +pipAllWorkspaces=yes + +### Sizes +# 16:9 video thumbnail = 256x144 +thumbnailSize=256 +seekbarHeight=20 +controlsHeight=64 +buttonTooltipSize=20 +windowBarHeight=44 +windowButtonSize=44 +windowTitleSize=24 +cacheTextSize=20 +timecodeSize=27 +seekbarTimestampSize=30 +seekbarTimestampOutline=1 +chapterTickSize=6 +windowTitleOutline=1 + +### Colors (uses GGBBRR for some reason) +### Alpha ranges 0 (opaque) .. 255 (transparent) +textColor=FFFFFF +buttonColor=CCCCCC +buttonHoveredColor=FFFFFF +buttonHoveredRectColor=000000 +# Easily debug button geometry by setting buttonHoveredRectAlpha to 80 +buttonHoveredRectAlpha=255 +tooltipColor=CCCCCC +windowBarColor=000000 +# windowBarAlpha (80 is mpv default) (255 morden default) +windowBarAlpha=255 +windowButtonColor=CCCCCC +closeButtonHoveredColor=1111DD +seekbarHandleColor=FFFFFF +seekbarFgColor=483DD7 +seekbarBgColor=929292 +seekbarCacheColor=000000 +seekbarCacheAlpha=128 +chapterTickColor=CCCCCC diff --git a/mpv/scripts/audio_manager.lua b/mpv/scripts/audio_manager.lua new file mode 100644 index 0000000..bb44dd2 --- /dev/null +++ b/mpv/scripts/audio_manager.lua @@ -0,0 +1,186 @@ +local utils = require 'mp.utils' + +-- 参数设置 +local audioTracksPerPage = 10 +local closeAfterLoad = true +local rate = 1.5 + +-- 全局变量和实用函数 +local styleOn = mp.get_property("osd-ass-cc/0") +local audioTracks = {} +local currentSlot = 1 +local currentPage = 1 +local maxPage = 1 +local active = false + +-- 控制列表 +local audioTrackControls = { + ESC = function() abort("") end, + e = function() abort("") end, + DOWN = function() jumpSlot(1) end, + UP = function() jumpSlot(-1) end, + j = function() jumpSlot(1) end, + k = function() jumpSlot(-1) end, + RIGHT = function() jumpPage(1) end, + LEFT = function() jumpPage(-1) end, + ENTER = function() loadAudioTrack(currentSlot) end, + KP_ENTER = function() loadAudioTrack(currentSlot) end +} + +local audioTrackFlags = { + DOWN = {repeatable = true}, + UP = {repeatable = true}, + RIGHT = {repeatable = true}, + LEFT = {repeatable = true} +} + +-- 激活自定义控件 +function activateControls(name, controls, flags) + for key, func in pairs(controls) do + mp.add_forced_key_binding(key, name..key, func, flags[key]) + end +end + +-- 取消激活自定义控件 +function deactivateControls(name, controls) + for key, _ in pairs(controls) do + mp.remove_key_binding(name..key) + end +end + +-- 加载音轨列表 +function listAudioTracks() + audioTracks = {} + local tracks = mp.get_property_native("track-list") + for _, track in ipairs(tracks) do + if track.type == "audio" then + table.insert(audioTracks, track) + end + end + calcPages() +end + +-- 计算当前页和总页数 +function calcPages() + currentPage = math.floor((currentSlot - 1) / audioTracksPerPage) + 1 + if currentPage == 0 then currentPage = 1 end + maxPage = math.floor((#audioTracks - 1) / audioTracksPerPage) + 1 + if maxPage == 0 then maxPage = 1 end +end + +-- 获取指定页的音轨数量 +function getAmountAudioTracksOnPage(page) + local n = audioTracksPerPage + if page == maxPage then n = #audioTracks % audioTracksPerPage end + if n == 0 then n = audioTracksPerPage end + if #audioTracks == 0 then n = 0 end + return n +end + +-- 获取指定页的第一个音轨索引 +function getFirstSlotOnPage(page) + return (page - 1) * audioTracksPerPage + 1 +end + +-- 获取指定页的最后一个音轨索引 +function getLastSlotOnPage(page) + local endSlot = getFirstSlotOnPage(page) + getAmountAudioTracksOnPage(page) - 1 + if endSlot > #audioTracks then endSlot = #audioTracks end + return endSlot +end + +-- 跳到指定数量的音轨前或后 +function jumpSlot(i) + currentSlot = currentSlot + i + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + if currentSlot < startSlot then currentSlot = endSlot end + if currentSlot > endSlot then currentSlot = startSlot end + + displayAudioTracks() +end + +-- 跳到指定数量的页前或后 +function jumpPage(i) + local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1 + currentPage = currentPage + i + if currentPage < 1 then currentPage = maxPage + currentPage end + if currentPage > maxPage then currentPage = currentPage - maxPage end + + local audioTracksOnPage = getAmountAudioTracksOnPage(currentPage) + if oldPos > audioTracksOnPage then oldPos = audioTracksOnPage end + currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1 + + displayAudioTracks() +end + +-- 显示当前页的音轨 +function displayAudioTracks() + -- 确定当前页的第一个和最后一个音轨索引 + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + -- 准备显示的文本并显示 + local display = styleOn .. "{\\b1}Audio Tracks page " .. currentPage .. "/" .. maxPage .. ":{\\b0}" + for i = startSlot, endSlot do + local track = audioTracks[i] + if (track.title or track.lang or track.src) == nil then + goto nextSlot + end + local selection = "" + if i == currentSlot then + selection = "{\\b1}{\\c&H00FFFF&}>" + end + display = display .. "\n" .. selection .. i .. ": " .. (track.title or track.lang or track.src) .. "{\\r}" + ::nextSlot:: + end + mp.osd_message(display, rate) +end + +-- 加载指定的音轨 +function loadAudioTrack(slot) + if slot >= 1 and slot <= #audioTracks then + local track = audioTracks[slot] + if (track.title or track.lang or track.src) == nil then + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the audio track at slot " .. slot) + return + end + mp.set_property_native("aid", track.id) + mp.osd_message(string.format("Loaded audio track: %s", track.title or track.lang or track.src), 2) + if closeAfterLoad then + abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully loaded audio track:{\\r}\n"..(track.title or track.lang or track.src)) + end + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the audio track at slot " .. slot) + end +end + +-- 定时器 +local timer = mp.add_periodic_timer(rate * 0.95, displayAudioTracks) +timer:kill() + +-- 终止程序 +function abort(message) + mode = "none" + deactivateControls("audio", audioTrackControls) + timer:kill() + mp.osd_message(message) + active = false +end + +-- 处理音轨菜单的状态 +function handler() + if active then + abort("") + else + activateControls("audio", audioTrackControls, audioTrackFlags) + listAudioTracks() + displayAudioTracks() + timer:resume() + active = true + end +end + +-- 注册脚本消息 +mp.register_script_message("audio-menu", handler) \ No newline at end of file diff --git a/mpv/scripts/autoload.lua b/mpv/scripts/autoload.lua new file mode 100644 index 0000000..dedfc64 --- /dev/null +++ b/mpv/scripts/autoload.lua @@ -0,0 +1,415 @@ +-- This script automatically loads playlist entries before and after the +-- currently played file. It does so by scanning the directory a file is +-- located in when starting playback. It sorts the directory entries +-- alphabetically, and adds entries before and after the current file to +-- the internal playlist. (It stops if it would add an already existing +-- playlist entry at the same position - this makes it "stable".) +-- Add at most 5000 * 2 files when starting a file (before + after). + +--[[ +To configure this script use file autoload.conf in directory script-opts (the "script-opts" +directory must be in the mpv configuration directory, typically ~/.config/mpv/). + +Option `ignore_patterns` is a comma-separated list of patterns (see lua.org/pil/20.2.html). +Additionally to the standard lua patterns, you can also escape commas with `%`, +for example, the option `bak%,x%,,another` will be resolved as patterns `bak,x,` and `another`. +But it does not mean you need to escape all lua patterns twice, +so the option `bak%%,%.mp4,` will be resolved as two patterns `bak%%` and `%.mp4`. + +Example configuration would be: + +disabled=no +images=no +videos=yes +audio=yes +additional_image_exts=list,of,ext +additional_video_exts=list,of,ext +additional_audio_exts=list,of,ext +ignore_hidden=yes +same_type=yes +directory_mode=recursive +ignore_patterns=^~,^bak-,%.bak$ + +--]] + +local MAX_ENTRIES = 5000 +local MAX_DIR_STACK = 20 + +local msg = require 'mp.msg' +local options = require 'mp.options' +local utils = require 'mp.utils' + +local o = { + disabled = false, + images = true, + videos = true, + audio = true, + additional_image_exts = "", + additional_video_exts = "", + additional_audio_exts = "", + ignore_hidden = true, + same_type = false, + directory_mode = "auto", + ignore_patterns = "" +} + +local function Set(t) + local set = {} + for _, v in pairs(t) do set[v] = true end + return set +end + +local EXTENSIONS_VIDEO_DEFAULT = Set { + '3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov', + 'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m' +} + +local EXTENSIONS_AUDIO_DEFAULT = Set { + 'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg', + 'ogm', 'opus', 'wav', 'wma' +} + +local EXTENSIONS_IMAGES_DEFAULT = Set { + 'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png', + 'svg', 'tga', 'tif', 'tiff', 'webp' +} + +local EXTENSIONS, EXTENSIONS_VIDEO, EXTENSIONS_AUDIO, EXTENSIONS_IMAGES + +local function SetUnion(a, b) + for k in pairs(b) do a[k] = true end + return a +end + +-- Returns first and last positions in string or past-to-end indices +local function FindOrPastTheEnd(string, pattern, start_at) + local pos1, pos2 = string:find(pattern, start_at) + return pos1 or #string + 1, + pos2 or #string + 1 +end + +local function Split(list) + local set = {} + + local item_pos = 1 + local item = "" + + while item_pos <= #list do + local pos1, pos2 = FindOrPastTheEnd(list, "%%*,", item_pos) + + local pattern_length = pos2 - pos1 + local is_comma_escaped = pattern_length % 2 + + local pos_before_escape = pos1 - 1 + local item_escape_count = pattern_length - is_comma_escaped + + item = item .. string.sub(list, item_pos, pos_before_escape + item_escape_count) + + if is_comma_escaped == 1 then + item = item .. "," + else + set[item] = true + item = "" + end + + item_pos = pos2 + 1 + end + + set[item] = true + + -- exclude empty items + set[""] = nil + + return set +end + +local function split_option_exts(video, audio, image) + if video then o.additional_video_exts = Split(o.additional_video_exts) end + if audio then o.additional_audio_exts = Split(o.additional_audio_exts) end + if image then o.additional_image_exts = Split(o.additional_image_exts) end +end + +local function split_patterns() + o.ignore_patterns = Split(o.ignore_patterns) +end + +local function create_extensions() + EXTENSIONS = {} + EXTENSIONS_VIDEO = {} + EXTENSIONS_AUDIO = {} + EXTENSIONS_IMAGES = {} + if o.videos then + SetUnion(SetUnion(EXTENSIONS_VIDEO, EXTENSIONS_VIDEO_DEFAULT), o.additional_video_exts) + SetUnion(EXTENSIONS, EXTENSIONS_VIDEO) + end + if o.audio then + SetUnion(SetUnion(EXTENSIONS_AUDIO, EXTENSIONS_AUDIO_DEFAULT), o.additional_audio_exts) + SetUnion(EXTENSIONS, EXTENSIONS_AUDIO) + end + if o.images then + SetUnion(SetUnion(EXTENSIONS_IMAGES, EXTENSIONS_IMAGES_DEFAULT), o.additional_image_exts) + SetUnion(EXTENSIONS, EXTENSIONS_IMAGES) + end +end + +local function validate_directory_mode() + if o.directory_mode ~= "recursive" and o.directory_mode ~= "lazy" + and o.directory_mode ~= "ignore" then + o.directory_mode = nil + end +end + +options.read_options(o, nil, function(list) + split_option_exts(list.additional_video_exts, list.additional_audio_exts, + list.additional_image_exts) + if list.videos or list.additional_video_exts or + list.audio or list.additional_audio_exts or + list.images or list.additional_image_exts then + create_extensions() + end + if list.directory_mode then + validate_directory_mode() + end + if list.ignore_patterns then + split_patterns() + end +end) + +split_option_exts(true, true, true) +split_patterns() +create_extensions() +validate_directory_mode() + +local function add_files(files) + local oldcount = mp.get_property_number("playlist-count", 1) + for i = 1, #files do + mp.commandv("loadfile", files[i][1], "append") + mp.commandv("playlist-move", oldcount + i - 1, files[i][2]) + end +end + +local function get_extension(path) + return path:match("%.([^%.]+)$") or "nomatch" +end + +local function is_ignored(file) + for pattern in pairs(o.ignore_patterns) do + if file:match(pattern) then + return true + end + end + return false +end + +-- alphanum sorting for humans in Lua +-- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua + +local function alphanumsort(filenames) + local function padnum(n, d) + return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d)) + or ("%03d%s"):format(#n, n) + end + + local tuples = {} + for i, f in ipairs(filenames) do + tuples[i] = {f:lower():gsub("0*(%d+)%.?(%d*)", padnum), f} + end + table.sort(tuples, function(a, b) + return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1] + end) + for i, tuple in ipairs(tuples) do filenames[i] = tuple[2] end + return filenames +end + +local autoloaded +local added_entries = {} +local autoloaded_dir + +local function scan_dir(path, current_file, dir_mode, separator, dir_depth, total_files, extensions) + if dir_depth == MAX_DIR_STACK then + return + end + msg.trace("scanning: " .. path) + local files = utils.readdir(path, "files") or {} + local dirs = dir_mode ~= "ignore" and utils.readdir(path, "dirs") or {} + local prefix = path == "." and "" or path + + local function filter(t, iter) + for i = #t, 1, -1 do + if not iter(t[i]) then + table.remove(t, i) + end + end + end + + filter(files, function(v) + -- Always accept current file + local current = prefix .. v == current_file + if current then + return true + end + if o.ignore_hidden and v:match("^%.") then + return false + end + if is_ignored(v) then + return false + end + + local ext = get_extension(v) + return ext and extensions[ext:lower()] + end) + filter(dirs, function(d) + return not (o.ignore_hidden and d:match("^%.")) + end) + alphanumsort(files) + alphanumsort(dirs) + + for i, file in ipairs(files) do + files[i] = prefix .. file + end + + local function append(t1, t2) + local t1_size = #t1 + for i = 1, #t2 do + t1[t1_size + i] = t2[i] + end + end + + append(total_files, files) + if dir_mode == "recursive" then + for _, dir in ipairs(dirs) do + scan_dir(prefix .. dir .. separator, current_file, dir_mode, + separator, dir_depth + 1, total_files, extensions) + end + else + for i, dir in ipairs(dirs) do + dirs[i] = prefix .. dir + end + append(total_files, dirs) + end +end + +local function find_and_add_entries() + local aborted = mp.get_property_native("playback-abort") + if aborted then + msg.debug("stopping: playback aborted") + return + end + + local path = mp.get_property("path", "") + local dir, filename = utils.split_path(path) + msg.trace(("dir: %s, filename: %s"):format(dir, filename)) + if o.disabled then + msg.debug("stopping: autoload disabled") + return + elseif #dir == 0 then + msg.debug("stopping: not a local path") + return + end + + local pl_count = mp.get_property_number("playlist-count", 1) + local this_ext = get_extension(filename) + -- check if this is a manually made playlist + if pl_count > 1 and autoloaded == nil then + msg.debug("stopping: manually made playlist") + return + elseif pl_count == 1 then + autoloaded = true + autoloaded_dir = dir + added_entries = {} + end + + local extensions + if o.same_type then + if EXTENSIONS_VIDEO[this_ext:lower()] then + extensions = EXTENSIONS_VIDEO + elseif EXTENSIONS_AUDIO[this_ext:lower()] then + extensions = EXTENSIONS_AUDIO + elseif EXTENSIONS_IMAGES[this_ext:lower()] then + extensions = EXTENSIONS_IMAGES + end + else + extensions = EXTENSIONS + end + if not extensions then + msg.debug("stopping: no matched extentions list") + return + end + + local pl = mp.get_property_native("playlist", {}) + local pl_current = mp.get_property_number("playlist-pos-1", 1) + msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current, + utils.to_string(pl))) + + local files = {} + scan_dir(autoloaded_dir, path, + o.directory_mode or mp.get_property("directory-mode", "lazy"), + mp.get_property_native("platform") == "windows" and "\\" or "/", + 0, files, extensions) + + if next(files) == nil then + msg.debug("no other files or directories in directory") + return + end + + -- Find the current pl entry (dir+"/"+filename) in the sorted dir list + local current + for i = 1, #files do + if files[i] == path then + current = i + break + end + end + if not current then + msg.debug("current file not found in directory") + return + end + msg.trace("current file position in files: "..current) + + -- treat already existing playlist entries, independent of how they got added + -- as if they got added by autoload + for _, entry in ipairs(pl) do + added_entries[entry.filename] = true + end + + local append = {[-1] = {}, [1] = {}} + for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1 + for i = 1, MAX_ENTRIES do + local pos = current + i * direction + local file = files[pos] + if file == nil or file[1] == "." then + break + end + + -- skip files that are/were already in the playlist + if not added_entries[file] then + if direction == -1 then + msg.verbose("Prepending " .. file) + table.insert(append[-1], 1, {file, pl_current + i * direction + 1}) + else + msg.verbose("Adding " .. file) + if pl_count > 1 then + table.insert(append[1], {file, pl_current + i * direction - 1}) + else + mp.commandv("loadfile", file, "append") + end + end + added_entries[file] = true + end + end + if pl_count == 1 and direction == -1 and #append[-1] > 0 then + local load = append[-1] + for i = 1, #load do + mp.commandv("loadfile", load[i][1], "append") + end + mp.commandv("playlist-move", 0, current) + end + end + + if pl_count > 1 then + add_files(append[1]) + add_files(append[-1]) + end +end + +mp.register_event("start-file", find_and_add_entries) diff --git a/mpv/scripts/bookmarker-menu.lua b/mpv/scripts/bookmarker-menu.lua new file mode 100644 index 0000000..e0e061b --- /dev/null +++ b/mpv/scripts/bookmarker-menu.lua @@ -0,0 +1,711 @@ +-- // Bookmarker Menu v1.3.1 for mpv \\ -- +-- See README.md for instructions + +-- Maximum number of characters for bookmark name +local maxChar = 100 +-- Number of bookmarks to be displayed per page +local bookmarksPerPage = 10 +-- Whether to close the Bookmarker menu after loading a bookmark +local closeAfterLoad = true +-- Whether to close the Bookmarker menu after replacing a bookmark +local closeAfterReplace = true +-- Whether to ask for confirmation to replace a bookmark (Uses the Typer for confirmation) +local confirmReplace = false +-- Whether to ask for confirmation to delete a bookmark (Uses the Typer for confirmation) +local confirmDelete = false +-- The rate (in seconds) at which the bookmarker needs to refresh its interface; lower is more frequent +local rate = 1.5 +-- The filename for the bookmarks file +local bookmarkerName = "bookmarker.json" + +-- All the "global" variables and utilities; don't touch these +local utils = require 'mp.utils' +local styleOn = mp.get_property("osd-ass-cc/0") +local styleOff = mp.get_property("osd-ass-cc/1") +local bookmarks = {} +local currentSlot = 0 +local currentPage = 1 +local maxPage = 1 +local active = false +local mode = "none" +local bookmarkStore = {} +local oldSlot = 0 + +-- // Controls \\ -- + +-- List of custom controls and their function +local bookmarkerControls = { + ESC = function() abort("") end, + e = function() abort("") end, + DOWN = function() jumpSlot(1) end, + UP = function() jumpSlot(-1) end, + j = function() jumpSlot(1) end, + k = function() jumpSlot(-1) end, + RIGHT = function() jumpPage(1) end, + LEFT = function() jumpPage(-1) end, + O = function() addBookmark() end, + -- O = function() mode="save" typerStart() end, + p = function() mode="replace" typerStart() end, + r = function() mode="rename" typerStart() end, + f = function() mode="filepath" typerStart() end, + m = function() mode="move" moverStart() end, + d = function() mode="delete" typerStart() end, + DEL = function() mode="delete" typerStart() end, + ENTER = function() jumpToBookmark(currentSlot) end, + KP_ENTER = function() jumpToBookmark(currentSlot) end +} + +local bookmarkerFlags = { + DOWN = {repeatable = true}, + UP = {repeatable = true}, + RIGHT = {repeatable = true}, + LEFT = {repeatable = true} +} + +-- Activate the custom controls +function activateControls(name, controls, flags) + for key, func in pairs(controls) do + mp.add_forced_key_binding(key, name..key, func, flags[key]) + end +end + +-- Deactivate the custom controls +function deactivateControls(name, controls) + for key, _ in pairs(controls) do + mp.remove_key_binding(name..key) + end +end + +-- // Typer \\ -- + +-- Controls for the Typer +local typerControls = { + ESC = function() typerExit() end, + ENTER = function() typerCommit() end, + KP_ENTER = function() typerCommit() end, + RIGHT = function() typerCursor(1) end, + LEFT = function() typerCursor(-1) end, + BS = function() typer("backspace") end, + DEL = function() typer("delete") end, + SPACE = function() typer(" ") end, + SHARP = function() typer("#") end, + KP0 = function() typer("0") end, + KP1 = function() typer("1") end, + KP2 = function() typer("2") end, + KP3 = function() typer("3") end, + KP4 = function() typer("4") end, + KP5 = function() typer("5") end, + KP6 = function() typer("6") end, + KP7 = function() typer("7") end, + KP8 = function() typer("8") end, + KP9 = function() typer("9") end, + KP_DEC = function() typer(".") end +} + +-- All standard keys for the Typer +local typerKeys = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","!","@","$","%","^","&","*","(",")","-","_","=","+","[","]","{","}","\\","|",";",":","'","\"",",",".","<",">","/","?","`","~"} +-- For some reason, semicolon is not possible, but it's listed there just in case anyway + +local typerText = "" +local typerPos = 0 +local typerActive = false + +-- Function to activate the Typer +-- use typerStart() for custom controls around activating the Typer +function activateTyper() + for key, func in pairs(typerControls) do + mp.add_forced_key_binding(key, "typer"..key, func, {repeatable=true}) + end + for i, key in ipairs(typerKeys) do + mp.add_forced_key_binding(key, "typer"..key, function() typer(key) end, {repeatable=true}) + end + typerText = "" + typerActive = true +end + +-- Function to deactivate the Typer +-- use typerExit() for custom controls around deactivating the Typer +function deactivateTyper() + for key, _ in pairs(typerControls) do + mp.remove_key_binding("typer"..key) + end + for i, key in ipairs(typerKeys) do + mp.remove_key_binding("typer"..key) + end + typerActive = false + return typerText +end + +-- Function to move the cursor of the typer; can wrap around +function typerCursor(direction) + typerPos = typerPos + direction + if typerPos < 0 then typerPos = typerText:len() end + if typerPos > typerText:len() then typerPos = 0 end + typer("") +end + +-- Function for handling the text as it is being typed +function typer(s) + -- Don't touch this part + if s == "backspace" then + if typerPos > 0 then + typerText = typerText:sub(1, typerPos - 1) .. typerText:sub(typerPos + 1) + typerPos = typerPos - 1 + end + elseif s == "delete" then + if typerPos < typerText:len() then + typerText = typerText:sub(1, typerPos) .. typerText:sub(typerPos + 2) + end + else + if mode == "filepath" or typerText:len() < maxChar then + typerText = typerText:sub(1, typerPos) .. s .. typerText:sub(typerPos + 1) + typerPos = typerPos + s:len() + end + end + + -- Enter custom script and display message here + local preMessage = "Enter a bookmark name:" + if mode == "save" then + preMessage = styleOn.."{\\b1}Save a new bookmark with custom name:{\\b0}"..styleOff + elseif mode == "replace" then + preMessage = styleOn.."{\\b1}Type \"y\" to replace the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff + elseif mode == "delete" then + preMessage = styleOn.."{\\b1}Type \"y\" to delete the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff + elseif mode == "rename" then + preMessage = styleOn.."{\\b1}Rename an existing bookmark:{\\b0}"..styleOff + elseif mode == "filepath" then + preMessage = styleOn.."{\\b1}Change the bookmark's filepath:{\\b0}"..styleOff + end + + local postMessage = "" + local split = typerPos + math.floor(typerPos / maxChar) + local messageLines = math.floor((typerText:len() - 1) / maxChar) + 1 + for i = 1, messageLines do + postMessage = postMessage .. typerText:sub((i-1) * maxChar + 1, i * maxChar) .. "\n" + end + postMessage = postMessage:sub(1,postMessage:len()-1) + + mp.osd_message(preMessage.."\n"..postMessage:sub(1,split)..styleOn.."{\\c&H00FFFF&}{\\b1}|{\\r}"..styleOff..postMessage:sub(split+1), 9999) +end + +-- // Mover \\ -- + +-- Controls for the Mover +local moverControls = { + ESC = function() moverExit() end, + DOWN = function() jumpSlot(1) end, + UP = function() jumpSlot(-1) end, + RIGHT = function() jumpPage(1) end, + LEFT = function() jumpPage(-1) end, + s = function() addBookmark() end, + m = function() moverCommit() end, + ENTER = function() moverCommit() end, + KP_ENTER = function() moverCommit() end +} + +local moverFlags = { + DOWN = {repeatable = true}, + UP = {repeatable = true}, + RIGHT = {repeatable = true}, + LEFT = {repeatable = true} +} + +-- Function to activate the Mover +function moverStart() + if bookmarkExists(currentSlot) then + deactivateControls("bookmarker", bookmarkerControls) + activateControls("mover", moverControls, moverFlags) + displayBookmarks() + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot) + end +end + +-- Function to commit the action of the Mover +function moverCommit() + saveBookmarks() + moverExit() +end + +-- Function to deactivate the Mover +-- If isError is set, then it'll abort +function moverExit(isError) + deactivateControls("mover", moverControls) + mode = "none" + if not isError then + loadBookmarks() + displayBookmarks() + activateControls("bookmarker", bookmarkerControls, bookmarkerFlags) + end +end + +-- // General utilities \\ -- + +-- Check if the operating system is Mac OS +function isMacOS() + local homedir = os.getenv("HOME") + return (homedir ~= nil and string.sub(homedir,1,6) == "/Users") +end + +-- Check if the operating system is Windows +function isWindows() + local windir = os.getenv("windir") + return (windir~=nil) +end + +-- Check whether a certain file exists +function fileExists(path) + local f = io.open(path,"r") + if f~=nil then + io.close(f) + return true + else + return false + end +end + +-- Get the filepath of a file from the mpv config folder +function getFilepath(filename) + if isWindows() then + return os.getenv("APPDATA"):gsub("\\", "/") .. "/mpv/" .. filename + else + return os.getenv("HOME") .. "/.config/mpv/" .. filename + end +end + +-- Load a table from a JSON file +-- Returns nil if the file can't be found +function loadTable(path) + local contents = "" + local myTable = {} + local file = io.open( path, "r" ) + if file then + local contents = file:read( "*a" ) + myTable = utils.parse_json(contents); + io.close(file) + return myTable + end + return nil +end + +-- Save a table as a JSON file file +-- Returns true if successful +function saveTable(t, path) + local contents = utils.format_json(t) + local file = io.open(path .. ".tmp", "wb") + file:write(contents) + io.close(file) + os.remove(path) + os.rename(path .. ".tmp", path) + return true +end + +-- Convert a pos (seconds) to a hh:mm:ss.mmm format +function parseTime(pos) + local hours = math.floor(pos/3600) + local minutes = math.floor((pos % 3600)/60) + local seconds = math.floor((pos % 60)) + local milliseconds = math.floor(pos % 1 * 1000) + return string.format("%02d:%02d:%02d.%03d",hours,minutes,seconds,milliseconds) +end + +-- // Bookmark functions \\ -- + +-- Checks whether the specified bookmark exists +function bookmarkExists(slot) + return (slot >= 1 and slot <= #bookmarks) +end + +-- Calculates the current page and the total number of pages +function calcPages() + currentPage = math.floor((currentSlot - 1) / bookmarksPerPage) + 1 + if currentPage == 0 then currentPage = 1 end + maxPage = math.floor((#bookmarks - 1) / bookmarksPerPage) + 1 + if maxPage == 0 then maxPage = 1 end +end + +-- Get the amount of bookmarks on the specified page +function getAmountBookmarksOnPage(page) + local n = bookmarksPerPage + if page == maxPage then n = #bookmarks % bookmarksPerPage end + if n == 0 then n = bookmarksPerPage end + if #bookmarks == 0 then n = 0 end + return n +end + +-- Get the index of the first slot on the specified page +function getFirstSlotOnPage(page) + return (page - 1) * bookmarksPerPage + 1 +end + +-- Get the index of the last slot on the specified page +function getLastSlotOnPage(page) + local endSlot = getFirstSlotOnPage(page) + getAmountBookmarksOnPage(page) - 1 + if endSlot > #bookmarks then endSlot = #bookmarks end + return endSlot +end + +-- Jumps a certain amount of slots forward or backwards in the bookmarks list +-- Keeps in mind if the current mode is to move bookmarks +function jumpSlot(i) + if mode == "move" then + oldSlot = currentSlot + bookmarkStore = bookmarks[oldSlot] + end + + currentSlot = currentSlot + i + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + if currentSlot < startSlot then currentSlot = endSlot end + if currentSlot > endSlot then currentSlot = startSlot end + + if mode == "move" then + table.remove(bookmarks, oldSlot) + table.insert(bookmarks, currentSlot, bookmarkStore) + end + + displayBookmarks() +end + +-- Jumps a certain amount of pages forward or backwards in the bookmarks list +-- Keeps in mind if the current mode is to move bookmarks +function jumpPage(i) + if mode == "move" then + oldSlot = currentSlot + bookmarkStore = bookmarks[oldSlot] + end + + local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1 + currentPage = currentPage + i + if currentPage < 1 then currentPage = maxPage + currentPage end + if currentPage > maxPage then currentPage = currentPage - maxPage end + + local bookmarksOnPage = getAmountBookmarksOnPage(currentPage) + if oldPos > bookmarksOnPage then oldPos = bookmarksOnPage end + currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1 + + if mode == "move" then + table.remove(bookmarks, oldSlot) + table.insert(bookmarks, currentSlot, bookmarkStore) + end + + displayBookmarks() +end + +-- Parses a bookmark name for storing, also trimming it +-- Replaces %t with the timestamp of the bookmark +-- Replaces %p with the time position of the bookmark +function parseName(name) + local pos = 0 + if mode == "rename" then pos = bookmarks[currentSlot]["pos"] else pos = mp.get_property_number("time-pos") end + name, _ = name:gsub("%%t", parseTime(pos)) + name, _ = name:gsub("%%p", pos) + name = trimName(name) + return name +end + +-- Parses a bookmark name for displaying, also trimming it +-- Replaces all { with an escaped { so it won't be interpreted as a tag +function displayName(name) + name, _ = name:gsub("{", "\\{") + name = trimName(name) + return name +end + +-- Trims a name to the max number of characters +function trimName(name) + if name:len() > maxChar then name = name:sub(1,maxChar) end + return name +end + +-- Parses a Windows path with backslashes to one with normal slashes +function parsePath(path) + if type(path) == "string" then path, _ = path:gsub("\\", "/") end + return path +end + +-- Loads all the bookmarks in the global table and sets the current page and total number of pages +-- Also checks for older versions of bookmarks and "updates" them +-- Also checks for bookmarks made by "mpv-bookmarker" and converts them +-- Also removes anything it doesn't recognize as a bookmark +function loadBookmarks() + bookmarks = loadTable(getFilepath(bookmarkerName)) + if bookmarks == nil then bookmarks = {} end + + local doSave = false + local doEject = false + local doReplace = false + local ejects = {} + local newmarks = {} + + for key, bookmark in pairs(bookmarks) do + if type(key) == "number" then + if bookmark.version == nil or bookmark.version == 1 then + if bookmark.name ~= nil and bookmark.path ~= nil and bookmark.pos ~= nil then + bookmark.path = parsePath(bookmark.path) + bookmark.version = 2 + doSave = true + else + table.insert(ejects, key) + doEject = true + end + end + else + if bookmark.filename ~= nil and bookmark.pos ~= nil and bookmark.filepath ~= nil then + local newmark = { + name = trimName(""..bookmark.filename.." @ "..parseTime(bookmark.pos)), + pos = bookmark.pos, + path = parsePath(bookmark.filepath), + version = 2 + } + table.insert(newmarks, newmark) + end + doReplace = true + doSave = true + end + end + + if doEject then + for i = #ejects, 1, -1 do table.remove(bookmarks, ejects[i]) end + doSave = true + end + + if doReplace then bookmarks = newmarks end + if doSave then saveBookmarks() end + + if #bookmarks > 0 and currentSlot == 0 then currentSlot = 1 end + calcPages() +end + +-- Save the globally loaded bookmarks to the JSON file +function saveBookmarks() + saveTable(bookmarks, getFilepath(bookmarkerName)) +end + +-- Make a bookmark of the current media file, position and name +-- Name can be specified or left blank to automake a name +-- Returns the bookmark if successful or nil if it can't make a bookmark +function makeBookmark(bname) + if mp.get_property("path") ~= nil then + if bname == nil then bname = mp.get_property("media-title").." @ %t" end + local bookmark = { + name = parseName(bname), + pos = mp.get_property_number("time-pos"), + path = parsePath(mp.get_property("path")), + version = 2 + } + return bookmark + else + return nil + end +end + +-- Add the current position as a bookmark to the global table and then saves it +-- Returns the slot of the newly added bookmark +-- Returns -1 if there's an error +function addBookmark(name) + local bookmark = makeBookmark(name) + if bookmark == nil then + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for") + return -1 + end + table.insert(bookmarks, bookmark) + + if #bookmarks == 1 then currentSlot = 1 end + + calcPages() + saveBookmarks() + displayBookmarks() + return #bookmarks +end + +-- Edit a property of a bookmark at the specified slot +-- Returns -1 if there's an error +function editBookmark(slot, property, value) + if bookmarkExists(slot) then + if property == "name" then value = parseName(value) end + bookmarks[slot][property] = value + saveBookmarks() + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot) + return -1 + end +end + +-- Replaces the bookmark at the specified slot with a provided bookmark +-- Keeps the name and its position in the list +-- If the slot is not specified, picks the currently selected bookmark to replace +-- If a bookmark is not provided, generates a new bookmark +function replaceBookmark(slot) + if slot == nil then slot = currentSlot end + if bookmarkExists(slot) then + local bookmark = makeBookmark(bookmarks[slot]["name"]) + if bookmark == nil then + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for") + return -1 + end + bookmarks[slot] = bookmark + saveBookmarks() + if closeAfterReplace then + abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully replaced bookmark:{\\r}\n"..displayName(bookmark["name"])) + return -1 + end + return 1 + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot) + return -1 + end +end + +-- Quickly saves a bookmark without bringing up the menu +function quickSave() + if not active then + loadBookmarks() + local slot = addBookmark() + if slot > 0 then mp.osd_message("Saved new bookmark at slot " .. slot) end + end +end + +-- Quickly loads the last bookmark without bringing up the menu +function quickLoad() + if not active then + loadBookmarks() + local slot = #bookmarks + if slot > 0 then mp.osd_message("Loaded bookmark at slot " .. slot) end + jumpToBookmark(slot) + end +end + +-- Deletes the bookmark in the specified slot from the global table and then saves it +function deleteBookmark(slot) + table.remove(bookmarks, slot) + if currentSlot > #bookmarks then currentSlot = #bookmarks end + + calcPages() + saveBookmarks() + displayBookmarks() +end + +-- Jump to the specified bookmark +-- This means loading it, reading it, and jumping to the file + position in the bookmark +function jumpToBookmark(slot) + if bookmarkExists(slot) then + local bookmark = bookmarks[slot] + if string.sub(bookmark["path"], 1, 4) == "http" or fileExists(bookmark["path"]) then + if parsePath(mp.get_property("path")) == bookmark["path"] then + mp.set_property_number("time-pos", bookmark["pos"]) + else + mp.commandv("loadfile", parsePath(bookmark["path"]), "replace", -1, "start="..bookmark["pos"]) end + if closeAfterLoad then abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully found file for bookmark:{\\r}\n"..displayName(bookmark["name"])) end + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find file for bookmark:\n" .. displayName(bookmark["name"])) + end + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot " .. slot) + end +end + +-- Displays the current page of bookmarks +function displayBookmarks() + -- Determine which slot is the first and last on the current page + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + -- Prepare the text to display and display it + local display = styleOn .. "{\\b1}Bookmarks page " .. currentPage .. "/" .. maxPage .. ":{\\b0}" + for i = startSlot, endSlot do + local btext = displayName(bookmarks[i]["name"]) + local selection = "" + if i == currentSlot then + selection = "{\\b1}{\\c&H00FFFF&}>" + if mode == "move" then btext = "----------------" end + btext = btext + end + display = display .. "\n" .. selection .. i .. ": " .. btext .. "{\\r}" + end + mp.osd_message(display, rate) +end + +local timer = mp.add_periodic_timer(rate * 0.95, displayBookmarks) +timer:kill() + +-- Commits the message entered with the Typer with custom scripts preceding it +-- Should typically end with typerExit() +function typerCommit() + local status = 0 + if mode == "save" then + status = addBookmark(typerText) + elseif mode == "replace" and typerText == "y" then + status = replaceBookmark(currentSlot, makeBookmark(bookmarks[currentSlot]["name"])) + elseif mode == "delete" and typerText == "y" then + deleteBookmark(currentSlot) + elseif mode == "rename" then + editBookmark(currentSlot, "name", typerText) + elseif mode == "filepath" then + editBookmark(currentSlot, "path", typerText) + end + if status >= 0 then typerExit() end +end + +-- Exits the Typer without committing with custom scripts preceding it +function typerExit() + deactivateTyper() + displayBookmarks() + timer:resume() + mode = "none" + activateControls("bookmarker", bookmarkerControls, bookmarkerFlags) +end + +-- Starts the Typer with custom scripts preceding it +function typerStart() + if (mode == "save" or mode=="replace") and mp.get_property("path") == nil then + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for") + return -1 + end + if (mode == "replace" or mode == "rename" or mode == "filepath" or mode == "delete") and not bookmarkExists(currentSlot) then + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot) + return -1 + end + if (mode == "replace" and not confirmReplace) or (mode == "delete" and not confirmDelete) then + typerText = "y" + typerCommit() + return + end + + deactivateControls("bookmarker", bookmarkerControls) + timer:kill() + activateTyper() + if mode == "rename" then typerText = bookmarks[currentSlot]["name"] end + if mode == "filepath" then typerText = bookmarks[currentSlot]["path"] end + typerPos = typerText:len() + typer("") +end + +-- Aborts the program with an optional error message +function abort(message) + mode = "none" + moverExit(true) + deactivateTyper() + deactivateControls("bookmarker", bookmarkerControls) + timer:kill() + mp.osd_message(message) + active = false +end + +-- Handles the state of the bookmarker +function handler() + if active then + abort("") + else + activateControls("bookmarker", bookmarkerControls, bookmarkerFlags) + loadBookmarks() + displayBookmarks() + timer:resume() + active = true + end +end + +mp.register_script_message("bookmarker-menu", handler) +mp.register_script_message("bookmarker-quick-save", quickSave) +mp.register_script_message("bookmarker-quick-load", quickLoad) diff --git a/mpv/scripts/file-browser/LICENSE b/mpv/scripts/file-browser/LICENSE new file mode 100644 index 0000000..bcb110c --- /dev/null +++ b/mpv/scripts/file-browser/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Oscar Manglaras + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mpv/scripts/file-browser/README.md b/mpv/scripts/file-browser/README.md new file mode 100644 index 0000000..09bb57f --- /dev/null +++ b/mpv/scripts/file-browser/README.md @@ -0,0 +1,227 @@ +# mpv-file-browser + +![cover](screenshots/bunny.png) + +This script allows users to browse and open files and folders entirely from within mpv. The script uses nothing outside the mpv API, so should work identically on all platforms. The browser can move up and down directories, start playing files and folders, or add them to the queue. + +By default only file types compatible with mpv will be shown, but this can be changed in the config file. + +This script requires at least **mpv v0.33**. + +Originally, file-browser worked with versions of mpv going back to +v0.31, you can find those older versions of file-browser in the +[mpv-v0.31 branch](https://github.com/CogentRedTester/mpv-file-browser/tree/mpv-v0.31). +That branch will no longer be receiving any feature updates, +but I will try to fix any bugs that are reported on the issue +tracker. + +## Installation + +### Basic + +Clone this git repository into the mpv `~~/scripts` directory and +change the name of the folder from `mpv-file-browser` to `file-browser`. +You can then pull to receive updates. +Alternatively, you can download the zip and extract the contents to `~~/scripts/file-browser`. +`~~/` is the mpv config directory which is typically `~/.config/mpv/` on linux and `%APPDATA%/mpv/` on windows. + +Create a `file_browser.conf` file in the `~~/script-opts/` directory and customise the [`root` option](#root-directory) for your +system. The [`docs/file_browser.conf`](docs/file_browser.conf) file contains the full list of options and their defaults. + +
+Expected directory tree: + +``` +~~/ +├── script-opts +│   └── file-browser.conf +└── scripts +    └── file-browser +       ├── addons/ +       ├── docs/ +       ├── modules/ +       ├── screenshots/ +       ├── LICENSE +       ├── main.lua +       └── README.md +``` +
+ +### Advanced + +To setup [custom keybinds](docs/custom-keybinds.md) enable the `custom_keybinds` option in `file_browser.conf` and +create a `~~/script-opts/file-browser-keybinds.json` file. Do **not** copy the `file-browser-keybinds.json` file +stored in this repository, that file is a collection of random examples, many of which are for completely different +operating systems. Use them and the [docs](docs/custom-keybinds.md) to create your own collection of keybinds. + +To setup [addons](addons/README.md) enable the `addons` option in `file_browser.conf` and place the addon files +in the `~~/script-modules/file-browser-addons/` directory. + +If you are not going to enable custom keybinds or addons then there is no reason to +create `file-browser-keybinds.json` or `script-modules/file-browser-addons/`. + +
+Expected directory tree: + +``` +~~/ +├── script-modules +│   └── file-browser-addons +│   ├── addon1.lua +│   ├── addon2.lua +│   └── etc.lua +├── script-opts +│   ├── file_browser.conf +│   └── file-browser-keybinds.json +└── scripts +    └── file-browser +       ├── addons/ +       ├── docs/ +       ├── modules/ +       ├── screenshots/ +       ├── LICENSE +       ├── main.lua +       └── README.md +``` +
+ +## Keybinds + +The following keybinds are set by default + +| Key | Name | Description | +|-------------|----------------------------------|-------------------------------------------------------------------------------| +| MENU | browse-files | toggles the browser | +| Ctrl+o | open-browser | opens the browser | +| Alt+o | browse-directory/get-user-input | opens a dialogue box to type in a directory - requires [mpv-user-input](#mpv-user-input) when mpv < v0.38 | + +The following dynamic keybinds are only set while the browser is open: + +| Key | Name | Description | +|-------------|---------------|-------------------------------------------------------------------------------| +| ESC | close | closes the browser or clears the selection | +| ENTER | play | plays the currently selected file or folder | +| Shift+ENTER | play_append | appends the current file or folder to the playlist | +| Alt+ENTER | play_autoload | loads playlist entries before and after the selected file (like autoload.lua) | +| RIGHT | down_dir | enter the currently selected directory | +| LEFT | up_dir | move to the parent directory | +| DOWN | scroll_down | move selector down the list | +| UP | scroll_up | move selector up the list | +| PGDWN | page_down | move selector down the list by a page (the num_entries option) | +| PGUP | page_up | move selector up the list by a page (the num_entries option) | +| Shift+PGDWN | list_bottom | move selector to the bottom of the list | +| Shift+PGUP | list_top | move selector to the top of the list | +| HOME | goto_current | move to the directory of the currently playing file | +| Shift+HOME | goto_root | move to the root directory | +| Ctrl+r | reload | reload directory and reset cache | +| s | select_mode | toggles multiselect mode | +| S | select_item | toggles selection for the current item | +| Ctrl+a | select_all | select all items in the current directory | + +When attempting to play or append a subtitle file the script will instead load the subtitle track into the existing video. + +The behaviour of the autoload keybind can be reversed with the `autoload` script-opt. +By default the playlist will only be autoloaded if `Alt+ENTER` is used on a single file, however when the option is switched autoload will always be used on single files *unless* `Alt+ENTER` is used. Using autoload on a directory, or while appending an item, will not work. + +## Root Directory + +To accomodate for both windows and linux this script has its own virtual root directory where drives and file folders can be manually added. The root directory can only contain folders. + +The root directory is set using the `root` option, which is a comma separated list of directories. Entries are sent through mpv's `expand-path` command. By default the only root value is the user's home folder: + +`root=~/` + +It is highly recommended that this be customised for the computer being used; [file_browser.conf](file_browser.conf) contains commented out suggestions for generic linux and windows systems. For example, my windows root looks like: + +`root=~/,C:/,D:/,E:/,Z:/` + +## Multi-Select + +By default file-browser only opens/appends the single item that the cursor has selected. +However, using the `s` keybinds specified above, it is possible to select multiple items to open all at once. Selected items are shown in a different colour to the cursor. +When in multiselect mode the cursor changes colour and scrolling up and down the list will drag the current selection. If the original item was unselected, then dragging will select items, if the original item was selected, then dragging will unselect items. + +When multiple items are selected using the open or append commands all selected files will be added to the playlist in the order they appear on the screen. +The currently selected (with the cursor) file will be ignored, instead the first multi-selected item in the folder will follow replace/append behaviour as normal, and following selected items will be appended to the playlist afterwards in the order that they appear on the screen. + +## Custom Keybinds + +File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item. +This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard. + +To see how to enable and use custom keybinds, see [custom-keybinds.md](docs/custom-keybinds.md). + +## Add-ons + +Add-ons are ways to add extra features to file-browser, for example adding support for network file servers like ftp, or implementing virtual directories in the root like recently opened files. +They can be enabled by setting `addon` script-opt to yes, and placing the addon file into the `~~/script-modules/file-browser-addons/` directory. + +For a list of existing addons see the [wiki](https://github.com/CogentRedTester/mpv-file-browser/wiki/Addon-List). +For instructions on writing your own addons see [addons.md](docs/addons.md). + +## Script Messages + +File-browser supports a small number of script messages that allow the user or other scripts to talk with the browser. + +### `browse-directory` + +`script-message browse-directory [directory]` + +Opens the given directory in the browser. If the browser is currently closed it will be opened. + +### `get-directory-contents` + +`script-message get-directory-contents [directory] [response-string]` + +Reads the given directory, and sends the resulting tables to the specified script-message in the format: + +`script-message [response-string] [list] [opts]` + +The [list](docs/addons.md#the-list-array) +and [opts](docs/addons.md#the-opts-table) +tables are formatted as json strings through the `mp.utils.format_json` function. +See [addons.md](docs/addons.md) for how the tables are structured, and what each field means. +The API_VERSION field of the `opts` table refers to what version of the addon API file browser is using. +The `response-string` refers to an arbitrary script-message that the tables should be sent to. + +This script-message allows other scripts to utilise file-browser's directory parsing capabilities, as well as those of the file-browser addons. + +## Configuration + +See [file_browser.conf](docs/file_browser.conf) for the full list of options and their default values. +The file is placed in the `~~/script-opts/` folder. + +## Conditional Auto-Profiles + +file-browser provides a property that can be used with [conditional auto-profiles](https://mpv.io/manual/master/#conditional-auto-profiles) +to detect when the browser is open. +On mpv v0.36+ you should use the `user-data` property with the `file_browser/open` boolean. + +Here is an example of an auto-profile that hides the OSC logo when using file-browser in an idle window: + +```properties +[hide-logo] +profile-cond= idle_active and user_data.file_browser.open +profile-restore=copy +osc=no +``` + +On older versions of mpv you can use the `file_browser-open` field of the `shared-script-properties` property: + +```properties +[hide-logo] +profile-cond= idle_active and shared_script_properties["file_browser-open"] == "yes" +profile-restore=copy +osc=no +``` + +See [#55](https://github.com/CogentRedTester/mpv-file-browser/issues/55) for more details on this. + +## [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) + +mpv-user-input is a script that provides an API to request text input from the user over the OSD. +It was built using `console.lua` as a base, so supports almost all the same text input commands. +If `user-input.lua` is loaded by mpv, and `user-input-module` is in the `~~/script-modules/` directory, +then using `Alt+o` will open an input box that can be used to directly enter directories for file-browser to open. + +Mpv v0.38 added the `mp.input` module, which means `mpv-user-input` is no-longer necessary from that version onwards. diff --git a/mpv/scripts/file-browser/addons/README.md b/mpv/scripts/file-browser/addons/README.md new file mode 100644 index 0000000..4a0c378 --- /dev/null +++ b/mpv/scripts/file-browser/addons/README.md @@ -0,0 +1,12 @@ +# addons + +Add-ons are ways to add extra features to file-browser, for example adding support for network file servers like ftp, or implementing virtual directories in the root like recently opened files. +They can be enabled by setting `addon` script-opt to yes, and placing the addon file into the `~~/script-modules/file-browser-addons/` directory. + +Browsing filesystems provided by add-ons should feel identical to the normal handling of the script, +but they may require extra commandline tools be installed. + +Since addons are loaded programatically from the addon directory it is possible for anyone to write their own addon. +Instructions on how to do this are available [here](../docs/addons.md). + +For a list of available addons see the [wiki](https://github.com/CogentRedTester/mpv-file-browser/wiki/Addon-List). diff --git a/mpv/scripts/file-browser/addons/apache-browser.lua b/mpv/scripts/file-browser/addons/apache-browser.lua new file mode 100644 index 0000000..138148d --- /dev/null +++ b/mpv/scripts/file-browser/addons/apache-browser.lua @@ -0,0 +1,89 @@ +--[[ + An addon for mpv-file-browser which adds support for apache http directory indexes +]]-- + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' +local fb = require "file-browser" + +--decodes a URL address +--this piece of code was taken from: https://stackoverflow.com/questions/20405985/lua-decodeuri-luvit/20406960#20406960 +local decodeURI +do + local char, gsub, tonumber = string.char, string.gsub, tonumber + local function _(hex) return char(tonumber(hex, 16)) end + + function decodeURI(s) + s = gsub(s, '%%(%x%x)', _) + return s + end +end + +local apache = { + priority = 80, + api_version = "1.1.0" +} + +function apache:can_parse(name) + return name:find("^https?://") +end + +--send curl errors through the browser empty_text +function apache:send_error(str) + return {}, {empty_text = "curl error: "..str} +end + +local function execute(args) + msg.trace(utils.to_string(args)) + local _, cmd = fb.get_parse_state():yield( + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback()) + ) + return cmd +end + +function apache:parse(directory) + msg.verbose(directory) + + local test = execute({"curl", "-k", "-l", "-I", directory}) + local response = test.stdout:match("(%d%d%d [^\n\r]+)") + if test.stdout:match("Content%-Type: ([^\r\n/]+)") ~= "text" then return nil end + if response ~= "200 OK" then return self:send_error(response) end + + local html = execute({"curl", "-k", "-l", directory}) + if html.status ~= 0 then return self:send_error(tostring(html.status)) + elseif not html.stdout:find("%[PARENTDIR%]") then return nil end + + html = html.stdout + local list = {} + for str in string.gmatch(html, "[^\r\n]+") do + local valid = true + if str:sub(1,4) ~= "" then valid = false end + + local link = str:match('href="(.-)"') + local alt = str:match('alt="%[(.-)%]"') + + if valid and not alt or not link then valid = false end + if valid and alt == "PARENTDIR" or alt == "ICO" then valid = false end + if valid and link:find("[:?<>|]") then valid = false end + + local is_dir = (alt == "DIR") + if valid and is_dir and not self.valid_dir(link) then valid = false end + if valid and not is_dir and not self.valid_file(link) then valid = false end + + if valid then + msg.trace(alt..": "..link) + table.insert(list, { name = link, type = (is_dir and "dir" or "file"), label = decodeURI(link) }) + end + end + + return list, {filtered = true, directory_label = decodeURI(directory)} +end + +return apache diff --git a/mpv/scripts/file-browser/addons/favourites.lua b/mpv/scripts/file-browser/addons/favourites.lua new file mode 100644 index 0000000..ef181b1 --- /dev/null +++ b/mpv/scripts/file-browser/addons/favourites.lua @@ -0,0 +1,191 @@ +--[[ + An addon for mpv-file-browser which adds a Favourites path that can be loaded from the ROOT +]]-- + +local mp = require "mp" +local msg = require "mp.msg" +local utils = require "mp.utils" +local save_path = mp.command_native({"expand-path", "~~/script-opts/file_browser_favourites.txt"}) +do + local file = io.open(save_path, "a+") + if not file then + msg.error("cannot access file", ("%q"):format(save_path), "make sure that the directory exists") + return {} + end + file:close() +end + +local favourites = nil +local favs = { + api_version = "1.4.0", + priority = 30, + cursor = 1 +} + +local use_virtual_directory = true +local full_paths = {} + +local function create_favourite_object(str) + local item = { + type = str:sub(-1) == "/" and "dir" or "file", + path = str, + redirect = not use_virtual_directory, + name = str:match("([^/]+/?)$") + } + full_paths[str:match("([^/]+)/?$")] = str + return item +end + +function favs:setup() + self:register_root_item('Favourites/') +end + +local function update_favourites() + favourites = {} + + local file = io.open(save_path, "r") + if not file then return end + + for str in file:lines() do + table.insert(favourites, create_favourite_object(str)) + end + file:close() +end + +function favs:can_parse(directory) + return directory:find("Favourites/") == 1 +end + +function favs:parse(directory) + if not favourites then update_favourites() end + if directory == "Favourites/" then + local opts = { + filtered = true, + sorted = true + } + if self.cursor ~= 1 then opts.selected_index = self.cursor ; self.cursor = 1 end + return favourites, opts + end + + if use_virtual_directory then + -- converts the relative favourite path into a full path + local name = directory:match("Favourites/([^/]+)/?") + + local _, finish = directory:find("Favourites/([^/]+/?)") + local full_path = (full_paths[name] or "")..directory:sub(finish+1) + local list, opts = self:defer(full_path or "") + + if not list then return nil end + opts.id = self:get_id() + if opts.directory_label then + opts.directory_label = opts.directory_label:gsub(full_paths[name], "Favourites/"..name..'/') + if opts.directory_label:find("Favourites/") ~= 1 then opts.directory_label = nil end + end + + for _, item in ipairs(list) do + if not item.path then item.redirect = false end + item.path = item.path or full_path..item.name + end + + return list, opts + end + + local path = full_paths[ directory:match("([^/]+/?)$") or "" ] + + local list, opts = self:defer(path) + if not list then return nil end + opts.directory = opts.directory or path + return list, opts +end + +local function get_favourite(path) + for index, value in ipairs(favourites) do + if value.path == path then return index, value end + end +end + +--update the browser with new contents of the file +local function update_browser() + if favs.get_directory():find("[fF]avourites/") then + if favs.get_directory():find("[fF]avourites/$") then + local cursor = favs.get_selected_index() + favs.rescan() + favs.set_selected_index(cursor) + favs.redraw() + else + favs.clear_cache() + end + end +end + +--write the contents of favourites to the file +local function write_to_file() + local file = io.open(save_path, "w+") + if not file then return msg.error(file, "could not open favourites file") end + for _, item in ipairs(favourites) do + file:write(string.format("%s\n", item.path)) + end + file:close() +end + +local function add_favourite(path) + if get_favourite(path) then return end + update_favourites() + table.insert(favourites, create_favourite_object(path)) + write_to_file() +end + +local function remove_favourite(path) + update_favourites() + local index = get_favourite(path) + if not index then return end + table.remove(favourites, index) + write_to_file() +end + +local function move_favourite(path, direction) + update_favourites() + local index, item = get_favourite(path) + if not index or not favourites[index + direction] then return end + + favourites[index] = favourites[index + direction] + favourites[index + direction] = item + write_to_file() +end + +local function toggle_favourite(cmd, state, co) + local path = favs.get_full_path(state.list[state.selected], state.directory) + + if state.directory:find("[fF]avourites/$") then remove_favourite(path) + else add_favourite(path) end + update_browser() +end + +local function move_key(cmd, state, co) + if not state.directory:find("[fF]avourites/") then return false end + local path = favs.get_full_path(state.list[state.selected], state.directory) + + local cursor = favs.get_selected_index() + if cmd.name == favs:get_id().."/move_up" then + move_favourite(path, -1) + favs.set_selected_index(cursor-1) + else + move_favourite(path, 1) + favs.set_selected_index(cursor+1) + end + update_browser() +end + +update_favourites() +mp.register_script_message("favourites/add_favourite", add_favourite) +mp.register_script_message("favourites/remove_favourite", remove_favourite) +mp.register_script_message("favourites/move_up", function(path) move_favourite(path, -1) end) +mp.register_script_message("favourites/move_down", function(path) move_favourite(path, 1) end) + +favs.keybinds = { + { "F", "toggle_favourite", toggle_favourite, {}, }, + { "Ctrl+UP", "move_up", move_key, {repeatable = true} }, + { "Ctrl+DOWN", "move_down", move_key, {repeatable = true} }, +} + +return favs diff --git a/mpv/scripts/file-browser/addons/find.lua b/mpv/scripts/file-browser/addons/find.lua new file mode 100644 index 0000000..c91847f --- /dev/null +++ b/mpv/scripts/file-browser/addons/find.lua @@ -0,0 +1,104 @@ +--[[ + An addon for mpv-file-browser for searching the current directory + Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons + + Requires mpv-user-input: https://github.com/CogentRedTester/mpv-user-input + + Keybinds: + Ctrl+f open search box + Ctrl+F open advanced search box (supports Lua patterns) + n cycle to next valid item +]]-- + +local msg = require "mp.msg" +local fb = require "file-browser" +local input_loaded, input = pcall(require, "mp.input") +local user_input_loaded, user_input = pcall(require, "user-input-module") + +local find = { + api_version = "1.3.0" +} +local latest_coroutine = nil +local global_fb_state = getmetatable(fb.get_state()).__original + +local function compare(name, query) + if name:find(query) then return true end + if name:lower():find(query) then return true end + if name:upper():find(query) then return true end + + return false +end + +local function main(key, state, co) + if not state.list then return false end + + local text + if key.name == "find/find" then text = "Find: enter search string" + else text = "Find: enter advanced search string" end + + if input_loaded then + input.get({ + prompt = text .. "\n>", + id = "file-browser/find", + submit = fb.coroutine.callback(), + }) + elseif user_input_loaded then + user_input.get_user_input( fb.coroutine.callback(), { text = text, id = "find", replace = true } ) + end + + local query, error = coroutine.yield() + if input_loaded then input.terminate() end + if not query then return msg.debug(error) end + + -- allow the directory to be changed before this point + local list = fb.get_list() + local parse_id = global_fb_state.co + + if key.name == "find/find" then + query = fb.pattern_escape(query) + end + + local results = {} + + for index, item in ipairs(list) do + if compare(item.label or item.name, query) then + table.insert(results, index) + end + end + + if (#results < 1) then + msg.warn("No matching items for '"..query.."'") + return + end + + --keep cycling through the search results if any are found + --putting this into a separate coroutine removes any passthrough ambiguity + --the final return statement should return to `step_find` not any other function + fb.coroutine.run(function() + latest_coroutine = coroutine.running() + while (true) do + for _, index in ipairs(results) do + fb.set_selected_index(index) + coroutine.yield(true) + + if parse_id ~= global_fb_state.co then + latest_coroutine = nil + return false + end + end + end + end) +end + +local function step_find() + if not latest_coroutine then return false end + return fb.coroutine.resume_err(latest_coroutine) +end + +find.keybinds = { + {"Ctrl+f", "find", main, {}}, + {"Ctrl+F", "find_advanced", main, {}}, + {"n", "next", step_find, {}}, +} + +return find diff --git a/mpv/scripts/file-browser/addons/ftp-browser.lua b/mpv/scripts/file-browser/addons/ftp-browser.lua new file mode 100644 index 0000000..f25a001 --- /dev/null +++ b/mpv/scripts/file-browser/addons/ftp-browser.lua @@ -0,0 +1,86 @@ +--[[ + An addon for mpv-file-browser which adds support for ftp servers +]]-- + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' +local fb = require 'file-browser' + +local ftp = { + priority = 100, + api_version = "1.1.0" +} + +function ftp:can_parse(directory) + return directory:sub(1, 6) == "ftp://" +end + +--in my experience curl has been somewhat unreliable when it comes to ftp requests +--this fuction retries the request a few times just in case +local function execute(args) + msg.debug(utils.to_string(args)) + local _, cmd = fb.get_parse_state():yield( + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback()) + ) + return cmd +end + +-- encodes special characters using the URL percent encoding format +function urlEncode(url) + local domain, path = string.match(url, '(ftp://[^/]-/)(.*)') + if not path then return url end + + -- these are the unreserved URI characters according to RFC 3986 + -- https://www.rfc-editor.org/rfc/rfc3986#section-2.3 + path = string.gsub(path, '[^%w.~_%-]', function(c) + return ('%%%x'):format(string.byte(c)) + end) + return domain..path +end + +function ftp:parse(directory) + msg.verbose(directory) + + local ftp = execute({"curl", "-k", "-g", "--retry", "4", urlEncode(directory)}) + + local entries = execute({"curl", "-k", "-g", "-l", "--retry", "4", urlEncode(directory)}) + + if entries.status == 28 then + msg.error(entries.stderr) + elseif entries.status ~= 0 or ftp.status ~= 0 then + msg.error(entries.stderr) + return + end + + local response = {} + for str in string.gmatch(ftp.stdout, "[^\r\n]+") do + table.insert(response, str) + end + + local list = {} + local i = 1 + for str in string.gmatch(entries.stdout, "[^\r\n]+") do + if str and response[i] then + msg.trace(str .. ' | ' .. response[i]) + + if response[i]:sub(1,1) == "d" then + table.insert(list, { name = str..'/', type = "dir" }) + else + table.insert(list, { name = str, type = "file" }) + end + + i = i+1 + end + end + + return list +end + +return ftp diff --git a/mpv/scripts/file-browser/addons/home-label.lua b/mpv/scripts/file-browser/addons/home-label.lua new file mode 100644 index 0000000..521f84b --- /dev/null +++ b/mpv/scripts/file-browser/addons/home-label.lua @@ -0,0 +1,27 @@ +--[[ + An addon for mpv-file-browser which displays ~/ for the home directory instead of the full path +]]-- + +local mp = require "mp" +local fb = require "file-browser" + +local home = fb.fix_path(mp.command_native({"expand-path", "~/"}), true) + +local home_label = { + priority = 100, + api_version = "1.0.0" +} + +function home_label:can_parse(directory) + return directory:sub(1, home:len()) == home +end + +function home_label:parse(directory) + local list, opts = self:defer(directory) + if (not opts.directory or opts.directory == directory) and not opts.directory_label then + opts.directory_label = "~/"..(directory:sub(home:len()+1) or "") + end + return list, opts +end + +return home_label \ No newline at end of file diff --git a/mpv/scripts/file-browser/addons/last-open-directory.lua b/mpv/scripts/file-browser/addons/last-open-directory.lua new file mode 100644 index 0000000..62cf474 --- /dev/null +++ b/mpv/scripts/file-browser/addons/last-open-directory.lua @@ -0,0 +1,56 @@ +--[[ + An addon for mpv-file-browser which stores the last opened directory and + sets it as the opened directory the next time mpv is opened. + + Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons +]]-- + +local mp = require 'mp' +local msg = require 'mp.msg' + +local fb = require 'file-browser' + +local state_file = mp.command_native({'expand-path', '~~state/last_opened_directory'}) +msg.verbose('using', state_file) + +local function write_directory(directory) + local file = io.open(state_file, 'w+') + + if not file then return msg.error('could not open', state_file, 'for writing') end + + directory = directory or fb.get_directory() + msg.verbose('writing', directory, 'to', state_file) + file:write(directory) + file:close() +end + + +local addon = { + api_version = '1.7.0', + priority = 0, +} + +function addon:setup() + local file = io.open(state_file, "r") + if not file then + return msg.error('failed to open', state_file, 'for reading') + end + + local dir = file:read("*a") + msg.verbose('setting default directory to', dir) + fb.browse_directory(dir, false) + file:close() +end + +function addon:can_parse(dir, parse_state) + if parse_state.source == 'browser' then write_directory(dir) end + return false +end + +function addon:parse() + return nil +end + +mp.register_event('shutdown', function() write_directory() end) + +return addon diff --git a/mpv/scripts/file-browser/addons/ls.lua b/mpv/scripts/file-browser/addons/ls.lua new file mode 100644 index 0000000..29f20d5 --- /dev/null +++ b/mpv/scripts/file-browser/addons/ls.lua @@ -0,0 +1,57 @@ +--[[ + An addon for mpv-file-browser which uses the Linux ls command to parse native directories + This behaves near identically to the native parser, but IO is done asynchronously. + + Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons +]]-- + +local mp = require "mp" +local msg = require "mp.msg" +local fb = require "file-browser" + +local ls = { + priority = 109, + api_version = "1.1.0", + name = "ls", + keybind_name = "file" +} + +local function command(args, parse_state) + local _, cmd = parse_state:yield( + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback()) + ) + + return cmd.status == 0 and cmd.stdout or nil +end + +function ls:can_parse(directory) + return directory ~= '' and not fb.get_protocol(directory) +end + +function ls:parse(directory, parse_state) + local list = {} + local files = command({"ls", "-1", "-p", "-A", "-N", "--zero", directory}, parse_state) + + if not files then return nil end + + for str in files:gmatch("%Z+") do + local is_dir = str:sub(-1) == "/" + msg.trace(str) + + if is_dir and fb.valid_dir(str) then + table.insert(list, {name = str, type = "dir"}) + elseif fb.valid_file(str) then + table.insert(list, {name = str, type = "file"}) + end + end + + return list, {filtered = true} +end + +return ls diff --git a/mpv/scripts/file-browser/addons/m3u-browser.lua b/mpv/scripts/file-browser/addons/m3u-browser.lua new file mode 100644 index 0000000..5b3f45f --- /dev/null +++ b/mpv/scripts/file-browser/addons/m3u-browser.lua @@ -0,0 +1,54 @@ +--[[ + An addon for mpv-file-browser which adds support for m3u playlists + + If the first entry of a playlist isn't working it is because some playlists are created with random invisible unicode in the first line + Vim makes it easy to detect these + + This addon requires that my API mpv-read-file be available in ~~/script-modules/ + https://github.com/CogentRedTester/mpv-read-file +]]-- + +local rf = require "read-file" + +local m3u = { + priority = 100, + api_version = "1.0.0", + name = "m3u" +} + +local full_paths = {} + +function m3u:setup() + self.register_parseable_extension("m3u") + self.register_parseable_extension("m3u8") +end + +function m3u:can_parse(directory) + return directory:find("m3u8?/?$") +end + +function m3u:parse(directory) + directory = directory:gsub("/$", "") + local list = {} + + local path = full_paths[ directory ] or directory + local playlist = rf.get_file_handler( path ) + + --if we can't read the path then stop here + if not playlist then return {}, {sorted = true, filtered = true, empty_text = "Could not read filepath"} end + + local parent = self.fix_path(path:match("^(.+/[^/]+)/"), true) + + local lines = playlist:read("*a") + + for item in lines:gmatch("[^%c]+") do + item = self.fix_path(item) + local fullpath = self.join_path(parent, item) + + local name = ( self.get_protocol(item) and item or fullpath:match("([^/]+)/?$") ) + table.insert(list, {name = name, path = fullpath, type = "file"}) + end + return list, {filtered = true, sorted = true} +end + +return m3u diff --git a/mpv/scripts/file-browser/addons/powershell.lua b/mpv/scripts/file-browser/addons/powershell.lua new file mode 100644 index 0000000..77b579a --- /dev/null +++ b/mpv/scripts/file-browser/addons/powershell.lua @@ -0,0 +1,81 @@ +--[[ + An addon for mpv-file-browser which uses powershell commands to parse native directories + + This is slower than the default parser for local drives, but faster for network drives + The drive_letters array below is used to list the drives to use this parser for +]]-- + +--list the drive letters to use here (case sensitive) +local drive_letters = { + "Y", "Z" +} + +local mp = require "mp" +local msg = require "mp.msg" +local fb = require "file-browser" + +local wn = { + priority = 109, + api_version = "1.1.0", + name = "powershell", + keybind_name = "file" +} + +local drives = {} +for _, letter in ipairs(drive_letters) do + drives[letter] = true +end + +local function command(args, parse_state) + local _, cmd = parse_state:yield( + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback()) + ) + + return cmd.status == 0 and cmd.stdout or nil, cmd.stderr +end + +function wn:can_parse(directory) + return directory ~= '' and not self.get_protocol(directory) and drives[ directory:sub(1,1) ] +end + +function wn:parse(directory, parse_state) + local list = {} + local files, err = command({"powershell", "-noprofile", "-command", [[ + $dirs = Get-ChildItem -LiteralPath ]]..string.format("%q", directory)..[[ -Directory + $files = Get-ChildItem -LiteralPath ]]..string.format("%q", directory)..[[ -File + + foreach ($n in $dirs.Name) { + $n += "/" + $u8clip = [System.Text.Encoding]::UTF8.GetBytes($n) + [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length) + Write-Host "" + } + + foreach ($n in $files.Name) { + $u8clip = [System.Text.Encoding]::UTF8.GetBytes($n) + [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length) + Write-Host "" + } + ]]}, parse_state) + + if not files then msg.debug(err) ; return nil end + + for str in files:gmatch("[^\n\r]+") do + local is_dir = str:sub(-1) == "/" + if is_dir and self.valid_dir(str) then + table.insert(list, {name = str, type = "dir"}) + elseif self.valid_file(str) then + table.insert(list, {name = str, type = "file"}) + end + end + + return self.sort(list), {filtered = true, sorted = true} +end + +return wn diff --git a/mpv/scripts/file-browser/addons/root.lua b/mpv/scripts/file-browser/addons/root.lua new file mode 100644 index 0000000..a045819 --- /dev/null +++ b/mpv/scripts/file-browser/addons/root.lua @@ -0,0 +1,54 @@ +--[[ + An addon that loads root items from a `~~/script-opts/file-browser-root.json` file. + The contents of this file will override the root script-opt. + + The json file takes the form of a list array as defined by the addon API: + https://github.com/CogentRedTester/mpv-file-browser/blob/master/addons/addons.md#the-list-array + + The main purpose of this addon is to allow for users to customise the appearance of their root items + using the label or ass fields: + + [ + { "name": "Favourites/" }, + { "label": "~/", "name": "C:/Users/User/" }, + { "label": "1TB HDD", "name": "D:/" }, + { "ass": "{\\c&H007700&}Green Text", "name": "E:/" }, + { "label": "FTP Server", name: "ftp://user:password@server.com/" } + ] + + Make sure local directories always end with `/`. + `path` and `name` behave the same in the root but either name or label should have a value. + ASS styling codes: https://aegi.vmoe.info/docs/3.0/ASS_Tags/ +]] + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' +local fb = require 'file-browser' + +-- loads the root json file +local config_path = mp.command_native({'expand-path', '~~/script-opts/file-browser-root.json'}) + +local file = io.open(config_path, 'r') +if not file then + msg.error('failed to read file', config_path) + return +end + +local root_config = utils.parse_json(file:read("*a")) +if not root_config then + msg.error('failed to parse contents of', config_path, '- Check the syntax is correct.') + return +end + +local function setup() + for i, item in ipairs(root_config) do + fb.register_root_item(item, item.priority) + end +end + +return { + api_version = '1.4.0', + setup = setup, + priority = -1000, +} diff --git a/mpv/scripts/file-browser/addons/url-decode.lua b/mpv/scripts/file-browser/addons/url-decode.lua new file mode 100644 index 0000000..1d57c3b --- /dev/null +++ b/mpv/scripts/file-browser/addons/url-decode.lua @@ -0,0 +1,35 @@ +--[[ + An addon for file-browser which decodes URLs so that they are more readable +]] + +local urldecode = { + priority = 5, + api_version = "1.0.0" +} + +--decodes a URL address +--this piece of code was taken from: https://stackoverflow.com/questions/20405985/lua-decodeuri-luvit/20406960#20406960 +local decodeURI +do + local char, gsub, tonumber = string.char, string.gsub, tonumber + local function _(hex) return char(tonumber(hex, 16)) end + + function decodeURI(s) + s = gsub(s, '%%(%x%x)', _) + return s + end +end + +function urldecode:can_parse(directory) + return self.get_protocol(directory) +end + +function urldecode:parse(directory) + local list, opts = self:defer(directory) + if opts.directory and not self.get_protocol(opts.directory) then return list, opts end + + opts.directory_label = decodeURI(opts.directory_label or (opts.directory or directory)) + return list, opts +end + +return urldecode diff --git a/mpv/scripts/file-browser/addons/windir.lua b/mpv/scripts/file-browser/addons/windir.lua new file mode 100644 index 0000000..dd52cea --- /dev/null +++ b/mpv/scripts/file-browser/addons/windir.lua @@ -0,0 +1,97 @@ +--[[ + An addon for mpv-file-browser which uses the Windows dir command to parse native directories + This behaves near identically to the native parser, but IO is done asynchronously. + + Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons +]]-- + +local mp = require "mp" +local msg = require "mp.msg" +local fb = require "file-browser" + +--this is a LuaJit module this addon will not load if not using LuaJit +local ffi = require 'ffi' +ffi.cdef([[ + int __stdcall WideCharToMultiByte(unsigned int CodePage, unsigned int dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, const char *lpDefaultChar, bool *lpUsedDefaultChar); +]]) + +--converts a UTF16 string to a UTF8 string +--this function was adapted from https://github.com/mpv-player/mpv/issues/10139#issuecomment-1117954648 +local function utf8(WideCharStr) + WideCharStr = ffi.cast("wchar_t*", WideCharStr) + if not WideCharStr then return nil end + + local utf8_size = ffi.C.WideCharToMultiByte(65001, 0, WideCharStr, -1, nil, 0, nil, nil) --CP_UTF8 + if utf8_size > 0 then + local utf8_path = ffi.new("char[?]", utf8_size) + local utf8_size = ffi.C.WideCharToMultiByte(65001, 0, WideCharStr, -1, utf8_path, utf8_size, nil, nil) + if utf8_size > 0 then + --removes the trailing `\0` character which can break things + return ffi.string(utf8_path, utf8_size):sub(1, -2) + end + end +end + +local dir = { + priority = 109, + api_version = "1.1.0", + name = "cmd-dir", + keybind_name = "file" +} + +local function command(args, parse_state) + local _, cmd = parse_state:yield( + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args, + }, fb.coroutine.callback() ) + ) + cmd.stdout = utf8(cmd.stdout) + cmd.stderr = utf8(cmd.stderr) + + --dir returns this exact error message if the directory is empty + if cmd.status == 1 and cmd.stderr == "File Not Found\r\n" then cmd.status = 0 end + + return cmd.status == 0 and cmd.stdout or nil, cmd.stderr +end + +function dir:can_parse(directory) + if directory == "" then return end + return not fb.get_protocol(directory) +end + +function dir:parse(directory, parse_state) + local list = {} + local files, dirs, err + + -- the dir command expects backslashes for our paths + directory = directory:gsub("/", "\\") + + dirs, err = command({ "cmd", "/U", "/c", "dir", "/b", "/ad", directory }, parse_state) + if not dirs then return msg.error(err) end + + files, err = command({ "cmd", "/U", "/c", "dir", "/b", "/a-d", directory }, parse_state) + if not files then return msg.error(err) end + + for name in dirs:gmatch("[^\n\r]+") do + name = name.."/" + if fb.valid_dir(name) then + table.insert(list, { name = name, type = "dir" }) + msg.trace(name) + end + end + + for name in files:gmatch("[^\n\r]+") do + if fb.valid_file(name) then + table.insert(list, { name = name, type = "file" }) + msg.trace(name) + end + end + + return list, { filtered = true } +end + +return dir diff --git a/mpv/scripts/file-browser/addons/winroot.lua b/mpv/scripts/file-browser/addons/winroot.lua new file mode 100644 index 0000000..f3b592a --- /dev/null +++ b/mpv/scripts/file-browser/addons/winroot.lua @@ -0,0 +1,52 @@ +--[[ + Automatically populates the root with windows drives on startup. + Ctrl+r will add new drives mounted since startup. + + Drives will only be added if they are not already present in the root. + + Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons +]] + +local mp = require 'mp' +local msg = require 'mp.msg' +local fb = require 'file-browser' + +-- returns a list of windows drives +local function get_drives() + local result = mp.command_native({ + name = 'subprocess', + playback_only = false, + capture_stdout = true, + args = {'fsutil', 'fsinfo', 'drives'} + }) + if result.status ~= 0 then return msg.error('could not read windows root') end + + local root = {} + for drive in result.stdout:gmatch("(%a:)\\") do + table.insert(root, drive..'/') + end + return root +end + +-- adds windows drives to the root if they are not already present +local function import_drives() + local drives = get_drives() + + for _, drive in ipairs(drives) do + fb.register_root_item(drive) + end +end + +local keybind = { + key = 'Ctrl+r', + name = 'import_root_drives', + command = import_drives, + parser = 'root', + passthrough = true +} + +return { + api_version = '1.4.0', + setup = import_drives, + keybinds = { keybind } +} diff --git a/mpv/scripts/file-browser/docs/addons.md b/mpv/scripts/file-browser/docs/addons.md new file mode 100644 index 0000000..a86fedc --- /dev/null +++ b/mpv/scripts/file-browser/docs/addons.md @@ -0,0 +1,958 @@ +# How to Write an Addon - API v1.7.0 + +Addons provide ways for file-browser to parse non-native directory structures. This document describes how one can create their own custom addon. + +If you have an independent script but want to use file-browser's parsing capabilities, perhaps to make use of existing addons, then look [here](https://github.com/CogentRedTester/mpv-file-browser#get-directory-contents). + +## Terminology + +For the purpose of this document addons refer to the scripts being loaded while parsers are the objects the scripts return. +An addon can return multiple parsers, but when they only returns one the terms are almost synonymous. +Additionally, `method` refers to functions called using the `object:funct()` syntax, and hence have access to the self object, whereas `function` is the standard `object.funct()` syntax. + +## API Version + +The API version, shown in the title of this document, allows file-browser to ensure that addons are using the correct +version of the API. It follows [semantic versioning](https://semver.org/) conventions of `MAJOR.MINOR.PATCH`. +A parser sets its version string with the `version` field, as seen [below](#overview). + +Any change that breaks backwards compatability will cause the major version number to increase. +A parser MUST have the same major version number as the API, otherwise an error message will be printed and the parser will +not be loaded. + +A minor version number denotes a change to the API that is backwards compatible. This includes additional API functions, +or extra fields in tables that were previously unused. It may also include additional arguments to existing functions that +add additional behaviour without changing the old behaviour. +If the parser's minor version number is greater than the API_VERSION, then a warning is printed to the console. + +Patch numbers denote bug fixes, and are ignored when loading an addon. +For this reason addon authors are allowed to leave the patch number out of their version tag and just use `MAJOR.MINOR`. + +## Overview + +File-browser automatically loads any lua files from the `~~/script-modules/file-browser-addons` directory as modules. +Each addon must return either a single parser table, or an array of parser tables. Each parser object must contain the following three members: + +| key | type | arguments | returns | description | +|-----------|--------|---------------------------|------------------------|--------------------------------------------------------------------------------------------------------------| +| priority | number | - | - | a number to determine what order parsers are tested - see [here](#priority-suggestions) for suggested values | +| api_version| string | - | - | the API version the parser is using - see [API Version](#api-version) | +| can_parse | method | string, parse_state_table | boolean | returns whether or not the given path is compatible with the parser | +| parse | method | string, parse_state_table | list_table, opts_table | returns an array of item_tables, and a table of options to control how file_browser handles the list | + +Additionally, each parser can optionally contain: + +| key | type | arguments | returns | description | +|--------------|--------|-----------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | - | - | the name of the parser used for debug messages and to create a unique id - by default uses the filename with `.lua` or `-browser.lua` removed | +| keybind_name | string | - | - | the name to use when setting custom keybind filters - uses the value of name by default but can be set manually so that the same keys work with multiple addons | +| setup | method | - | - | if it exists this method is automatically run after all parsers are imported and API functions are made available | +| keybinds | table | - | - | an array of keybind objects for the browser to set when loading - see [#keybinds] | + +All parsers are given a unique string ID based on their name. If there are collisions then numbers are appended to the end of the name until a free name is found. +These IDs are primarily used for debug messages, though they may gain additional functionality in the future. + +Here is an extremely simple example of an addon creating a parser table and returning it to file-browser. + +```lua +local parser = { + api_version = '1.0.0', + priority = 100, + name = "example" -- this parser will have the id 'example' or 'example_#' if there are duplicates +} + +function parser:can_parse(directory) + return directory == "Example/" +end + +function parser:parse(directory, state) + local list, opts + ------------------------------ + --- populate the list here --- + ------------------------------ + return list, opts +end + +return parser + +``` + +## Parsing + +When a directory is loaded file-browser will iterate through the list of parsers from lowest to highest priority. +The first parser for which `can_parse` returns true will be selected as the parser for that directory. + +The `parse` method will then be called on the selected parser, which is expected to return either a table of list items, or nil. +If an empty table is returned then file-browser will treat the directory as empty, otherwise if the list_table is nil then file-browser will attempt to run `parse` on the next parser for which `can_parse` returns true. +This continues until a parser returns a list_table, or until there are no more parsers. + +The entire parse operation is run inside of a coroutine, this allows parsers to pause execution to handle asynchronous operations. +Please read [coroutines](#coroutines) for all the details. + +### Parse State Table + +The `parse` and `can_parse` functions are passed a state table as its second argument, this contains the following fields. + +| key | type | description | +|----------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| source | string | the source of the parse request | +| directory | string | the directory of the parse request - for debugging purposes | +| already_deferred | boolean | whether or not [defer](#advanced-functions) was called during this parse, if so then file-browser will not try to query any more parsers after receiving the result - set automatically, but can be manually disabled | +| yield | method | a wrapper around `coroutine.yield()` - see [coroutines](#coroutines) | +| is_coroutine_current | method | returns if the browser is waiting on the current coroutine to populate the list | + +`already_deferred` is an optimisation. If a script uses defer and still returns nil, then that means that none of the remaining parsers will be able to parse the path. +Therefore, it is more efficient to just immediately jump to the root. +It is up to the addon author to manually disable this if their use of `defer` conflicts with this assumption. + +Source can have the following values: + +| source | description | +|----------------|---------------------------------------------------------------------------------------------------------| +| browser | triggered by the main browser window | +| loadlist | the browser is scanning the directory to append to the playlist | +| script-message | triggered by the `get-directory-contents` script-message | +| addon | caused by an addon calling the `parse_directory` API function - note that addons can set a custom state | + +Note that all calls to any `parse` function during a specific parse request will be given the same parse_state table. +This theoretically allows parsers to communicate with parsers of a lower priority (or modify how they see source information), +but no guarantees are made that specific keys will remain unused by the API. + +#### Coroutines + +Any calls to `parse()` (or `can_parse()`, but you should never be yielding inside there) are done in a [Lua coroutine](https://www.lua.org/manual/5.1/manual.html#2.11). +This means that you can arbitrarily pause the parse operation if you need to wait for some asynchronous operation to complete, +such as waiting for user input, or for a network request to complete. + +Making these operations asynchronous has performance +advantages as well, for example recursively opening a network directory tree could cause the browser to freeze +for a long period of time. If the network query were asynchronous then the browser would only freeze during actual operations, +during network operations it would be free for the user interract with. The browser has even been designed so that +a loadfile/loadlist operation saves it's own copy of the current directory, so even if the user hops around like crazy the original +open operation will still occur in the correct order (though there's nothing stopping them starting a new operation which will cause +random ordering.) + +However, there is one downside to this behaviour. If the parse operation is requested by the browser, then it is +possible for the user to change directories while the coroutine is yielded. If you were to resume the coroutine +in that situation, then any operations you do are wasted, and unexpected bahaviour could happen. +file-browser will automatically detect when it receives a list from an aborted coroutine, so there is no risk +of the current list being replaced, but any other logic in your script will continue until `parse` returns. + +To fix this there are two methods available in the state table, the `yield()` method is a wrapper around `coroutine.yield()` that +detects when the browser has abandoned the parse, and automatically kills the coroutine by throwing an error. +The `is_coroutine_current()` method simply compares if the current coroutine (as returned by `coroutine.running()`) matches the +coroutine that the browser is waiting for. Remember this is only a problem when the browser is the source of the request, +if the request came from a script-message, or from a loadlist command there are no issues. + +### The List Array + +The list array must be made up of item_tables, which contain details about each item in the directory. +Each item has the following members: + +| key | type | required | description | +|-------------|-----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | yes | name of the item, and the string to append after the directory when opening a file/folder | +| type | string | yes | determines whether the item is a file ("file") or directory ("dir") | +| label | string | no | an alternative string to print to the screen instead of name | +| ass | string | no | a string to print to the screen without escaping ass styling - overrides label and name | +| path | string | no | opening the item uses this full path instead of appending directory and name | +| redirect | bool | no | whether `path` should redirect the browser when opening a directory - default yes (nil counts as true) | +| mpv_options | string or table | no | a list of options to be sent to mpv when loading the file - can be in the form `opt1=value1,opt2=value2,...` or a table of string keys and values | + +File-browser expects that `type` and `name` will be set for each item, so leaving these out will probably crash the script. +File-browser also assumes that all directories end in a `/` when appending name, and that there will be no backslashes. +The API function [`fix_path`](#utility-functions) can be used to ensure that paths conform to file-browser rules. + +Here is an example of a static list table being returned by the `parse` method. +This would allow one to specify a custom list of items. + +```lua +function parser:parse(directory, state) + local list = { + { name = "first/", type = "dir" }, + { name = "second/", type = "dir" }, + { name = "third/", type = "dir" }, + { name = "file%01", type = "file", label = "file1" }, + { name = "file2", type = "file", path = "https://youtube.com/video" }, + } + + return list +end +``` + +### The Opts Table + +The options table allows scripts to better control how they are handled by file-browser. +None of these values are required, and the opts table can even left as nil when returning. + +| key | type | description | +|-----------------|---------|------------------------------------------------------------------------------------------------------------------------------| +| filtered | boolean | if true file-browser will not run the standard filter() function on the list | +| sorted | boolean | if true file-browser will not sort the list | +| directory | string | changes the browser directory to this - used for redirecting to other locations | +| directory_label | string | display this label in the header instead of the actual directory - useful to display encoded paths | +| empty_text | string | display this text when the list is empty - can be used for error messages | +| selected_index | number | the index of the item on the list to select by default - a.k.a. the cursor position | +| id | number | id of the parser that successfully returns a list - set automatically, but can be set manually to take ownership (see defer) | + +The previous static example, but modified so that file browser does not try to filter or re-order the list: + +```lua +function parser:parse(directory, state) + local list = { + { name = "first/", type = "dir" }, + { name = "second/", type = "dir" }, + { name = "third/", type = "dir" }, + { name = "file%01", type = "file", label = "file1" }, + { name = "file2", type = "file", path = "https://youtube.com/video" }, + } + + return list, { sorted = true, filtered = true } +end +``` + +`id` is used to declare ownership of a page. The name of the parser that has ownership is used for custom-keybinds parser filtering. +When using `defer` id will be the id of whichever parser first returned a list. +This is the only situation when a parser may want to set id manually. + +## Priority Suggestions + +Below is a table of suggested priority ranges: + +| Range | Suggested Use | Example parsers | +|---------|------------------------------------------------------------------------------------------------|------------------------------------------------| +| 0-20 | parsers that purely modify the results of other parsers | [m3u-fixer](m3u-browser.lua) | +| 21-40 | virtual filesystems which need to link to the results of other parsers | [favourites](favourites.lua) | +| 41-50 | to support specific sites or systems which can be inferred from the path | | +| 51-80 | limitted support for specific protocols which requires complex parsing to verify compatability | [apache](apache-browser.lua) | +| 81-90 | parsers that only need to modify the results of full parsers | [home-label](home-label.lua) | +| 91-100 | use for parsers which fully support a non-native protocol with absolutely no overlap | [ftp](ftp-browser.lua), [m3u](m3u-browser.lua) | +| 101-109 | replacements for the native file parser or fallbacks for the full parsers | [powershell](powershell.lua) | +| 110 | priority of the native file parser - don't use | | +| 111+ | fallbacks for native parser - potentially alternatives to the default root | | + +## Keybinds + +Addons have the ability to set custom keybinds using the `keybinds` field in the `parser` table. `keybinds` must be an array of tables, each of which may be in two forms. + +Firstly, the keybind_table may be in the form +`{ "key", "name", [function], [flags] }` +where the table is an array whose four values corresond to the four arguments for the [mp.add_key_binding](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) API function. + +```lua +local function main(keybind, state, co) + -- deletes files +end + +parser.keybinds = { + { "Alt+DEL", "delete_files", main, {} }, +} +``` + +Secondly, the keybind_table may use the same formatting as file-browser's [custom-keybinds](../custom-keybinds.md). +Using the array form is equivalent to setting `key`, `name`, `command`, and `flags` of the custom-keybind form, and leaving everything else on the defaults. + +```lua +parser.keybinds = { + { + key = "Alt+DEL", + name = "delete_files", + command = {"run", "rm", "%F"}, + filter = "files" + } +} +``` + +These keybinds are evaluated only once shortly after the addon is loaded, they cannot be modified dynamically during runtime. +Keybinds are applied after the default keybinds, but before the custom keybinds. This means that addons can overwrite the +default keybinds, but that users can ovewrite addon keybinds. Among addons, those with higher priority numbers have their keybinds loaded before those +with lower priority numbers. +Remember that a lower priority value is better, they will overwrite already loaded keybinds. +Keybind passthrough works the same way, though there is some custom behaviour when it comes to [raw functions](#keybind-functions). + +### Keybind Names + +In either form the naming of the function is different from custom keybinds. Instead of using the form `file_browser/dynamic/custom/[name]` +they use the form `file_browser/dynamic/[parser_ID]/[name]`, where `[parser_id]` is a unique string ID for the parser, which can be retrieved using the +`parser:get_id()` method. + +### Native Functions vs Command Tables + +There are two ways of specifying the behaviour of a keybind. +It can be in command table form, as done when using custom-keybind syntax, and it can be done in +native function form, as done when using the `mp.add_key_binding` syntax. +However, these two ways of specifying commands are independant of how the overall keybind is defined. +What this means is that the command field of the custom-keybinds syntax can be an array, and the +3rd value in the array syntax can be a table of mpv commands. + +```lua +local function main(keybind, state, co) + -- deletes files +end + +-- this is a valid keybind table +parser.keybinds = { + { "Alt+DEL", "delete_files", {"run", "rm", "%F"}, {} }, + + { + key = "Alt+DEL", + name = "delete_files", + command = main + } +} +``` + +There are some limitations however, not all custom-keybind options are supported when using native functions. +The supported options are: `key`, `name`, `condition`, `flags`, `parser`, `passthrough`. The other options can be replicated manually (see below). + +### Keybind Functions + +This section details the use of keybind functions. + +#### Function Call + +If one uses the raw function then the functions are called directly in the form: + +`fn(keybind, state, coroutine)` + +Where `keybind` is the keybind_table of the key being run, `state` is a table of state values at the time of the key press, and `coroutine` is the coroutine object +that the keybind is being executed inside. + +The `keybind` table uses the same fields as defined +in [custom-keybinds.md](../custom-keybinds.md). Any random extra fields placed in the original +`file-browser-keybinds.json` will likely show up as well (this is not guaranteed). +Note that even if the array form is used, the `keybind` table will still use the custom-keybind format. + +The entire process of running a keybind is handled with a coroutine, so the addon can safely pause and resume the coroutine at will. The `state` table is provided to +allow addons to keep a record of important state values that may be changed during a paused coroutine. + +#### State Table + +The state table contains copies of the following values at the time of the key press. + +| key | description | +|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| directory | the current directory | +| directory_label | the current directory_label - can (and often will) be `nil` | +| list | the current list_table | +| selected | index of the currently selected list item | +| selection | table of currently selected items (for multi-select) - in the form { index = true, ... } - always available even if the `multiselect` flag is not set | +| parser | a copy of the parser object that provided the current directory | + +The following example shows the implementation of the `delete_files` keybind using the state values: + +```lua +local fb = require "file-browser" -- see #api-functions and #utility-functions + +local function main(keybind, state, co) + for index, item in state.list do + if state.selection[index] and item.type == "file" then + os.remove( fb.get_full_path(item, state.directory) ) + end + end +end + +parser.keybinds = { + { "Alt+DEL", "delete_files", main, {} }, +} +``` + +#### Passthrough + +If the `passthrough` field of the keybind_table is set to `true` or `false` then file-browser will +handle everything. However, if the passthrough field is not set (meaning the bahviour should be automatic) +then it is up to the addon to ensure that they are +correctly notifying when the operation failed and a passthrough should occur. +In order to tell the keybind handler to run the next priority command, the keybind function simply needs to return the value `false`, +any other value (including `nil`) will be treated as a successful operation. + +The below example only allows removing files from the `/tmp/` directory and allows other +keybinds to run in different directories: + +```lua +local fb = require "file-browser" -- see #api-functions and #utility-functions + +local function main(keybind, state, co) + if state.directory ~= "/tmp/" then return false end + + for index, item in state.list do + if state.selection[index] and item.type == "file" then + os.remove( fb.get_full_path(item, state.directory) ) + end + end +end + +parser.keybinds = { + { "Alt+DEL", "delete_files", main, {} }, +} +``` + +## The API + +The API is available through a module, which can be loaded with `require "file-browser"`. +The API provides a variety of different values and functions for an addon to use +in order to make them more powerful. +Function definitions are written using Typescript-style type annotations. + +```lua +local fb = require "file-browser" + +local parser = { + priority = 100, +} + +function parser:setup() + fb.register_root_item("Example/") +end + +return parser +``` + +### Parser API + +In addition to the standard API there is also an extra parser API that provides +several parser specific methods, listed below using `parser:method` instead of `fb.function`. +This API is added to the parser object after it is loaded by file-browser, +so if a script wants to call them immediately on load they must do so in the `setup` method. +All the standard API functions are also available in the parser API. + +```lua +local parser = { + priority = 100, +} + +function parser:setup() + -- same operations + self.insert_root_item({ name = "Example/", type = "dir" }) + parser.insert_root_item({ name = "Example/", type = "dir" }) +end + +-- will not work since the API hasn't been added to the parser yet +parser.insert_root_item({ name = "Example/", type = "dir" }) + +return parser +``` + +### General Functions + +#### `fb.API_VERSION: string` + +The current API version in use by file-browser. + +#### `fb.add_default_extension(ext: string): void` + +Adds the given extension to the default extension filter whitelist. Can only be run inside the `setup()` method. + +#### `fb.browse_directory(directory: string, open_browser: bool = true): coroutine` + +Clears the cache and opens the given directory in the browser. +If the `open_browser` argument is truthy or `nil` then the browser will be opened +if it is currently closed. If `open_browser` is `false` then the directory will +be opened in the background. +Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle, +allowing one to store this value and use it to identify the triggered parse operation. + +This is the equivalent of calling the `browse-directory` script-message. + +#### `fb.insert_root_item(item: item_table, pos?: number): void` + +Add an item_table to the root list at the specified position. If `pos` is nil then append to the end of the root. +`item` must be a valid item_table of `type='dir'`. + +#### `fb.register_directory_mapping(directory: string | nil, mapping: string, pattern?: bool): void` + +Creates a directory mapping for the given directory. A directory mapping is a +one-way mapping from an external directory string, to an internal directory +within file-browser's directory tree. It allows external paths that may not +exist within file-browser's tree to be mapped to a location that is. +Internally, this is used by file-browser to map the `bd://`, `dvd://`, and `cdda://` +protocol paths to their respective device locations in the filesystem. + +Note that as this is still an experimental feature, the exact situations when mappings +are resolved is subject to change. Currently, mapping occurs only when +receiving a directory from an external source, such as the mpv `path` property, +or the `browse-directory` script message. + +`directory` is a string that represents a location within file-browser's file-system. +`mapping` is a string that will be replaced by the `directory` string if found in a path: + +```lua +fb.register_directory_mapping('/dev/dvd', 'dvd://') +fb.resolve_directory_mapping('dvd://1') -- /dev/dvd/1 +``` + +There can only be one `directory` string associated with each unique `mapping` string, +but multiple mappings can point to the same directory. +If `directory` is set to `nil` then the existing mapping for `mapping` will be removed. +If `pattern` is set to true, then `mapping` will be treated as a Lua +pattern. Any part of an input path that matches the pattern will be substituted for +the `directory` string. + +```lua +fb.register_directory_mapping('/dev/dvd', '^dvd://.*', true) +fb.resolve_directory_mapping('dvd://1') -- /dev/dvd +``` + +When `pattern` is falsy, `mapping` is equivalent to `'^'..fb.pattern_escape(mapping)`. +Captures in the pattern may be given extra behaviour in the future. + +#### `fb.register_parseable_extension(ext: string): void` + +Register a file extension that the browser will attempt to open, like a directory - for addons which can parse files such +as playlist files. + +#### `fb.register_root_item(item: string | item_table, priority?: number): boolean` + +Registers an item to be added to the root and an optional priority value that determines the position relative to other items (default is 100). +A lower priority number is better, meaning they will be placed earlier in the list. +Only adds the item if it is not already in the root and returns a boolean that specifies whether or not the item was added. +Must be called during or after the `parser:setup()` method is run. + +If `item` is a string then a new item_table is created with the values: `{ type = 'dir', name = item }`. +If `item` is an item_table then it must be a valid directory item. +Use [`fb.fix_path(name, true)`](#fbfix_pathpath-string-is_directory-boolean-string) to ensure the name field is correct. + +This function should be used over the older `fb.insert_root_item`. + +#### `fb.remove_parseable_extension(ext: string): void` + +Remove a file extension that the browser will attempt to open like a directory. + +#### `fb.parse_directory(directory: string, parse?: parse_state_table): (list_table, opts_table) | nil` + +Starts a new scan for the given directory and returns a list_table and opts_table on success and `nil` on failure. +Must be called from inside a [coroutine](#coroutines). + +This function allows addons to request the contents of directories from the loaded parsers. There are no protections +against infinite recursion, so be careful about calling this from within another parse. + +Do not use the same `parse` table for multiple parses, state values for the two operations may intefere with each other +and cause undefined behaviour. If the `parse.source` field is not set then it will be set to `"addon"`. + +Note that this function is for creating new parse operations, if you wish to create virtual directories or modify +the results of other parsers then use [`defer`](#parserdeferdirectory-string-list_table-opts_table--nil). + +Also note that every parse operation is expected to have its own unique coroutine. This acts as a unique +ID that can be used internally or by other addons. This means that if multiple `parse_directory` operations +are run within a single coroutine then file-browser will automatically create a new coroutine for the scan, +which hands execution back to the original coroutine upon completion. + +#### `parser:register_root_item(item: string | item_table, priority?: number): boolean` + +A wrapper around [`fb.register_root_item`](#fbregister_root_itemitem-string--item_table-priority-number-boolean) +which uses the parser's priority value if `priority` is undefined. + +#### `fb.remove_all_mappings(directory: string): string[]` + +Removes all [directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void) +that resolve to the given `directory`. Returns a list of the `mapping` strings +that were removed. + +### Advanced Functions + +#### `fb.clear_cache(): void` + +Clears the directory cache. Use this if you are modifying the contents of directories other +than the current one to ensure that their contents will be rescanned when next opened. + +#### `fb.coroutine.assert(err?: string): coroutine` + +Throws an error if it is not called from within a coroutine. Returns the currently running coroutine on success. +The string argument can be used to throw a custom error string. + +#### `fb.coroutine.callback(time_limit?: number): function` + +Creates and returns a callback function that resumes the current coroutine. +This function is designed to help streamline asynchronous operations. The best way to explain is with an example: + +```lua +local function execute(args) + mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback()) + + local _, cmd = coroutine.yield() + + return cmd.status == 0 and cmd.stdout or nil +end +``` + +This function uses the mpv [subprocess](https://mpv.io/manual/master/#command-interface-subprocess) +command to execute some system operation. To prevent the whole script (file-browser and all addons) from freezing +it uses the [command_native_async](https://mpv.io/manual/master/#lua-scripting-mp-command-native-async(table-[,fn])) command +to execute the operation asynchronously and takes a callback function as its second argument. + +`coroutine.callback())` will automatically create a callback function to resume whatever coroutine ran the `execute` function. +Any arguments passed into the callback function (by the async function, not by you) will be passed on to the resume; +in this case `command_native_async` passes three values into the callback, of which only the second is of interest to me. + +If `time_limit` is set to a number, then a boolean is passed as the first resume argument to the coroutine. +If the callback is not run within `time_limit` seconds then the coroutine will be resumed, and the first +argument will be `false`. If the callback is run within the time limit then the first argument will be `true`. + +```lua +local function execute(args) + local t = mp.command_native_async({ + name = "subprocess", + playback_only = false, + capture_stdout = true, + capture_stderr = true, + args = args + }, fb.coroutine.callback(10)) + + local success, _, cmd = coroutine.yield() + if not success then + mp.abort_async_command(t) + msg.error("command timed out") + return nil + end + + return cmd.status == 0 and cmd.stdout or nil +end +``` + +The expectation is that the programmer will yield execution before that callback returns. In this example I +yield immediately after running the async command. + +If you are doing this during a parse operation you could also substitute `coroutine.yield()` with `parse_state:yield()` to abort the parse if the user changed +browser directories during the asynchronous operation. + +If you have no idea what I've been talking about read the [Lua manual on coroutines](https://www.lua.org/manual/5.1/manual.html#2.11). + +#### `fb.coroutine.resume_catch(co: coroutine, ...): (boolean, ...)` + +Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments. +If the coroutine throws an error then an error message and stacktrace is printed to the console. +All the return values of `coroutine.resume` are caught and returned. + +#### `fb.coroutine.resume_err(co: coroutine, ...): boolean` + +Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments. +If the coroutine throws an error then an error message and stacktrace is printed to the console. +Returns the success boolean returned by `coroutine.resume`, but drops all other return values. + +#### `fb.coroutine.run(fn: function, ...): void` + +Runs the given function in a new coroutine, passing through any additional arguments. + +#### `fb.coroutine.queue(fn: function, ...): coroutine` + +Runs the given function in a coroutine when the script next goes idle, passing through +any additional arguments. The (not yet started) coroutine is returned by the function. + +#### `fb.rescan(): coroutine` + +Rescans the current directory. Equivalent to Ctrl+r without the cache refresh for higher level directories. +Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle, +allowing one to store this value and use it to identify the triggered parse operation. + +#### `fb.redraw(): void` + +Forces a redraw of the browser UI. + +#### `parser:defer(directory: string): (list_table, opts_table) | nil` + +Forwards the given directory to the next valid parser. For use from within a parse operation. + +The `defer` function is very powerful, and can be used by scripts to create virtual directories, or to modify the results of other parsers. +However, due to how much freedom Lua gives coders, it is impossible for file-browser to ensure that parsers are using defer correctly, which can cause unexpected results. +The following are a list of recommendations that will increase the compatability with other parsers: + +* Always return the opts table that is returned by defer, this can contain important values for file-browser, as described [above](#the-opts-table). + * If required modify values in the existing opts table, don't create a new one. +* Respect the `sorted` and `filtered` values in the opts table. This may mean calling `sort` or `filter` manually. +* Think about how to handle the `directory_label` field, especially how it might interract with any virtual paths the parser may be maintaining. +* Think about what to do if the `directory` field is set. +* Think if you want your parser to take full ownership of the results of `defer`, if so consider setting `opts.id = self:get_id()`. + * Currently this only affects custom keybind filtering, though it may be changed in the future. + +The [home-label](https://github.com/CogentRedTester/mpv-file-browser/blob/master/addons/home-label.lua) +addon provides a good simple example of the safe use of defer. It lets the normal file +parser load the home directory, then modifies the directory label. + +```lua +local mp = require "mp" +local fb = require "file-browser" + +local home = fb.fix_path(mp.command_native({"expand-path", "~/"}), true) + +local home_label = { + api_version = '1.0.0', + priority = 100 +} + +function home_label:can_parse(directory) + return directory:sub(1, home:len()) == home +end + +function home_label:parse(directory, ...) + local list, opts = self:defer(directory, ...) + + if (not opts.directory or opts.directory == directory) and not opts.directory_label then + opts.directory_label = "~/"..(directory:sub(home:len()+1) or "") + end + + return list, opts +end + +return home_label +``` + +### Utility Functions + +#### `fb.ass_escape(str: string, substitute_newline?: true | string): string` + +Returns the `str` string with escaped ass styling codes. +The optional 2nd argument allows replacing newlines with the given string, or `'\\n'` if set to `true`. + +#### `fb.copy_table(t: table, depth?: number): table` + +Returns a copy of table `t`. +The copy is done recursively to the given `depth`, and any cyclical table references are maintained. +Both keys and values are copied. If `depth` is undefined then it defaults to `math.huge` (infinity). +Additionally, the original table is stored in the `__original` field of the copy's metatable. +The copy behaviour of the metatable itself is subject to change, but currently it is not copied. + +#### `fb.evaluate_string(str: string, chunkname?: string, env?: table, defaults?: bool = true): unknown` + +Loads `str` as a chunk of Lua statement(s) and runs them, returning the result. +Errors are propagated to the caller. `chunkname` is used +for debug output and error messages. + +Each chunk has a separate global environment table that inherits +from the main global table. This means new globals can be created safely, +but the default globals can still be accessed. As such, this method +cannot and should not be used for security or sandboxing. + +A custom environment table can be provided with the `env` argument. +Inheritance from the global table is disabled if `defaults` is `false`. + +Examples: + +```lua +fb.evaluate_string('return 5 + 5') -- 10 +fb.evaluate_string('x = 20 ; return x * x') -- 400 + +local code = [[ +local arr = {1, 2, 3, 4} +table.insert(arr, x) +return unpack(arr) +]] +fb.evaluate_string(code, 'test3', {x = 5}) -- 1, 2, 3, 4, 5 +fb.evaluate_string(code, 'test4', nil, false) -- Lua error: [string "test4"]:2: attempt to index global 'table' (a nil value) + +``` + +In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively. +Additionally, in mpv v0.38+ the `mp.input` module is available as `input`. +This addon API is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) +is installed then user-input will be available in `user_input`. +These modules are all unavailable if `defaults` is `false`. + +#### `fb.filter(list: list_table): list_table` + +Iterates through the given list and removes items that don't pass the user set filters +(dot files/directories and valid file extensions). +Returns the list but does not create a copy; the `list` table is filtered in-place. + +#### `fb.fix_path(path: string, is_directory?: boolean): string` + +Takes a path and returns a file-browser compatible path string. +The optional second argument is a boolean that tells the function to format the path to be a +directory. + +#### `fb.get_extension(filename: string, def?: any): string | def` + +Returns the file extension for the string `filename`, or `nil` if there is no extension. +If `def` is defined then that is returned instead of `nil`. + +The full stop is not included in the extension, so `test.mkv` will return `mkv`. + +#### `fb.get_full_path(item: item_table, directory?: string): string` + +Takes an item table and returns the item's full path assuming it is in the given directory. +Takes into account `item.name`/`item.path` fields, etc. +If directory is nil then it uses the currently open directory. + +#### `fb.get_protocol(url: string, def?: any): string | def` + +Returns the protocol scheme for the string `url`, or `nil` if there is no scheme. +If `def` is defined then that is returned instead of `nil`. + +The `://` is not included, so `https://example.com/test.mkv` will return `https`. + +#### `fb.iterate_opt(opts: string): iterator` + +Takes an options string consisting of a list of items separated by the `root_separators` defined in `file_browser.conf` and +returns an iterator function that can be used to iterate over each item in the list. + +```lua +local opt = "a,b,zz z" -- root_separators=, +for item in fb.iterate_opt(opt) do + print(item) -- prints: 'a', 'b', 'zz z' +end +``` + +#### `fb.join_path(p1: string, p2: string): string` + +A wrapper around [`mp.utils.join_path`](https://mpv.io/manual/master/#lua-scripting-utils-join-path(p1,-p2)) +which treats paths with network protocols as absolute paths. + +#### `fb.pattern_escape(str: string): string` + +Returns `str` with Lua special pattern characters escaped. + +#### `fb_utils.resolve_directory_mapping(path: string): string` + +Takes a `path` string and resolves any +[directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void), +replacing any substrings that match a mapping with the associated directory. + +Only the first valid mapping is applied, but this behaviour will likely change in +the future. Changes to this behaviour will not consitute a major version bump so should not +be relied upon. + +#### `fb.sort(list: list_table): list_table` + +Iterates through the given list and sorts the items using file-browser's sorting algorithm. +Returns the list but does not create a copy; the `list` table is sorted in-place. + +#### `fb.valid_file(name: string): boolean` + +Tests if the string `name` passes the user set filters for valid files (extensions/dot files/etc). + +#### `fb.valid_dir(name: string): boolean` + +Tests if the string `name` passes the user set filters for valid directories (dot folders/etc). + +### Getters + +These functions allow addons to safely get information from file-browser. +All tables returned by these functions are copies sent through the [`fb.copy_table`](#fbcopy_tablet-table-depth-number-table) +function to ensure addons can't accidentally break things. + +#### `fb.get_audio_extensions(): table` + +Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened +as additional audio tracks. +All of these are included in `fb.get_extensions`. + +#### `fb.get_current_file(): table` + +A table containing the path of the current open file in the form: +`{directory = "/home/me/", name = "bunny.mkv", path = "/home/me/bunny.mkv"}`. + +#### `fb.get_current_parser(): string` + +The unique id of the parser that successfully parsed the current directory. + +#### `fb.get_current_parser_keyname(): string` + +The `keybind_name` of the parser that successfully parsed the current directory. +Used for custom-keybind filtering. + +#### `fb.get_directory(): string` + +The current directory open in the browser. + +#### `fb.get_dvd_device(): string` + +The current dvd-device as reported by mpv's `dvd-device` property. +Formatted to work with file-browser. + +#### `fb.get_extensions(): table` + +Returns the set of valid extensions after applying the user's whitelist/blacklist options. +The table is in the form `{ mkv = true, mp3 = true, ... }`. +Sub extensions, audio extensions, and parseable extensions are all included in this set. + +#### `fb.get_list(): list_table` + +The list_table currently open in the browser. + +#### `fb.get_open_status(): boolean` + +Returns true if the browser is currently open and false if not. + +#### `fb.get_opt(name: string): string | number | boolean` + +Returns the script-opt with the given name. + +#### `fb.get_parsers(): table` + +Returns a table of all the loaded parsers/addons. +The formatting of this table in undefined, but it should +always contain an array of the parsers in order of priority. + +#### `fb.get_parse_state(co?: coroutine): parse_state_table` + +Returns the [parse_state table](#parse-state-table) for the given coroutine. +If no coroutine is given then it uses the running coroutine. +Every parse operation is guaranteed to have a unique coroutine. + +#### `fb.get_parseable_extensions(): table` + +Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are +treated as parseable by the browser. +All of these are included in `fb.get_extensions`. + +#### `fb.get_root(): list_table` + +Returns the root table. + +#### `fb.get_script_opts(): table` + +The table of script opts set by the user. This currently does not get +changed during runtime, but that is not guaranteed for future minor version increments. + +#### `fb.get_selected_index(): number` + +The current index of the cursor. +Note that it is possible for the cursor to be outside the bounds of the list; +for example when the list is empty this usually returns 1. + +#### `fb.get_selected_item(): item_table | nil` + +Returns the item_table of the currently selected item. +If no item is selected (for example an empty list) then returns nil. + +#### `fb.get_state(): table` + +Returns the current state values of the browser. +These are not documented and are subject to change at any time, +adding a proper getter for anything is a valid request. + +#### `fb.get_sub_extensions(): table` + +Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened +as additional subtitle tracks. +All of these are included in `fb.get_extensions`. + +#### `parser:get_id(): string` + +The unique id of the parser. Used for log messages and various internal functions. + +#### `parser:get_index(): number` + +The index of the parser in order of preference (based on the priority value). +`defer` uses this internally. + +### Setters + +#### `fb.set_selected_index(pos: number): number | false` + +Sets the cursor position and returns the new index. +If the input is not a number return false, if the input is out of bounds move it in bounds. + +## Examples + +For standard addons that add support for non-native filesystems, but otherwise don't do anything fancy, see [ftp-browser](ftp-browser.lua) and [apache-browser](apache-browser.lua). + +For more simple addons that make a few small modifications to how other parsers are displayed, see [home-label](home-label.lua). + +For more complex addons that maintain their own virtual directory structure, see +[favourites](favourites.lua). diff --git a/mpv/scripts/file-browser/docs/custom-keybinds.md b/mpv/scripts/file-browser/docs/custom-keybinds.md new file mode 100644 index 0000000..611bd7e --- /dev/null +++ b/mpv/scripts/file-browser/docs/custom-keybinds.md @@ -0,0 +1,330 @@ +# Custom Keybinds + +File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item. +This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard. + +The feature is disabled by default, but is enabled with the `custom_keybinds` script-opt. +Keybinds are declared in the `~~/script-opts/file-browser-keybinds.json` file, the config takes the form of an array of json objects, with the following keys: + +| option | required | default | description | +|---------------|----------|------------|--------------------------------------------------------------------------------------------| +| key | yes | - | the key to bind the command to - same syntax as input.conf | +| command | yes | - | json array of commands and arguments | +| name | no | numeric id | name of the script-binding - see [modifying default keybinds](#modifying-default-keybinds) | +| condition | no | - | a Lua [expression](#expressions) - the keybind will only run if this evaluates to true | +| flags | no | - | flags to send to the mpv add_keybind function - see [here](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) | +| filter | no | - | run the command on just a file (`file`) or folder (`dir`) | +| parser | no | - | run the command only in directories provided by the specified parser. | +| multiselect | no | `false` | command is run on all selected items | +| multi-type | no | `repeat` | which multiselect mode to use - `repeat` or `concat` | +| delay | no | `0` | time to wait between sending repeated multi commands | +| concat-string | no | `' '` (space) | string to insert between items when concatenating multi commands | +| passthrough | no | - | force or ban passthrough behaviour - see [passthrough](#passthrough-keybinds) | +| api_version | no | - | tie the keybind to a particular [addon API version](./addons.md#api-version), printing warnings and throwing errors if the keybind is used with wrong versions | + +Example: + +```json +{ + "key": "KP1", + "command": ["print-text", "example"], +} +``` + +The command can also be an array of arrays, in order to send multiple commands at once: + +```json +{ + "key": "KP2", + "command": [ + ["print-text", "example2"], + ["show-text", "example2"] + ] +} +``` + +Filter should not be included unless one wants to limit what types of list entries the command should be run on. +To only run the command for directories use `dir`, to only run the command for files use `file`. + +The parser filter is for filtering keybinds to only work inside directories loaded by specific parsers. +There are two parsers in the base script, the default parser for native filesystems is called `file`, while the root parser is called `root`. +Other parsers can be supplied by addons, and use the addon's filename with `-browser.lua` or just `.lua` stripped unless otherwise stated. +For example `ftp-browser.lua` would have a parser called `ftp`. +You can set the filter to match multiple parsers by separating the names with spaces. + +```json +{ + "key": "KP2", + "command": [ ["print-text", "example3"] ], + "parser": "ftp file" +} +``` + +The `flags` field is mostly only useful for addons, but can also be useful if one wants a key to be repeatable. +In this case the the keybind would look like the following: + +```json +{ + "key": "p", + "command": ["print-text", "spam-text"], + "flags": { "repeatable": true } +} +``` + +## Codes + +The script will scan every string in the command for the special substitution strings, they are: + +| code | description | +|--------|---------------------------------------------------------------------| +| `%%` | escape code for `%` | +| `%f` | filepath of the selected item | +| `%n` | filename of the selected item | +| `%p` | currently open directory | +| `%q` | currently open directory but preferring the directory label | +| `%d` | name of the current directory (characters between the last two '/') | +| `%r` | name of the parser for the currently open directory | +| `%x` | number of items in the currently open directory | +| `%i` | the 1-based index of the selected item in the list | +| `%j` | the 1-based index of the item in a multiselection - returns 1 for single selections | + +Additionally, using the uppercase forms of those codes will send the substituted string through the `string.format("%q", str)` function. +This adds double quotes around the string and automatically escapes any characters which would break the string encapsulation. +This is not necessary for most mpv commands, but can be very useful when sending commands to the OS with the `run` command, +or when passing values into [expressions](#conditional-command-condition-command). + +Example of a command to add an audio track: + +```json +{ + "key": "Ctrl+a", + "command": ["audio-add", "%f"], + "filter": "file" +} +``` + +Any commands that contain codes representing specific items (`%f`, `%n`, `%i` etc) will +not be run if no item is selected (for example in an empty directory). +In these cases [passthrough](#passthrough-keybinds) rules will apply. + +## Multiselect Commands + +When multiple items are selected the command can be run for all items in the order they appear on the screen. +This can be controlled by the `multiselect` flag, which takes a boolean value. +When not set the flag defaults to `false`. + +There are two different multiselect modes, controlled by the `multi-type` option. There are two options: + +### `repeat` + +The default mode that sends the commands once for each item that is selected. +If time is needed between running commands of multiple selected items (for example, due to file handlers) then the `delay` option can be used to set a duration (in seconds) between commands. + +### `concat` + +Run a single command, but replace item specific codes with a concatenated string made from each selected item. +For example `["print-text", "%n" ]` would print the name of each item selected separated by `' '` (space). +The string inserted between each item is determined by the `concat-string` option, but `' '` is the default. + +## Passthrough Keybinds + +When loading keybinds from the json file file-browser will move down the list and overwrite any existing bindings with the same key. +This means the lower an item on the list, the higher preference it has. +However, file-browser implements a layered passthrough system for its keybinds; if a keybind is blocked from running by user filters, then the next highest preference command will be sent, continuing until a command is sent or there are no more keybinds. +The default dynamic keybinds are considered the lowest priority. + +The `filter`, `parser`, and `condition` options can all trigger passthrough, as well as some [codes](#codes). +If a multi-select command is run on multiple items then passthrough will occur if any of the selected items fail the filters. + +Passthrough can be forcibly disabled or enabled using the passthrough option. +When set to `true` passthrough will always be activate regardless of the state of the filters. + +## Modifying Default Keybinds + +Since the custom keybinds are applied after the default dynamic keybinds they can be used to overwrite the default bindings. +Setting new keys for the existing binds can be done with the `script-binding [binding-name]` command, where `binding-name` is the full name of the keybinding. +For this script the names of the dynamic keybinds are in the format `file_browser/dynamic/[name]` where `name` is a unique identifier documented in the [keybinds](README.md#keybinds) table. + +For example to change the scroll buttons from the arrows to the scroll wheel: + +```json +[ + { + "key": "WHEEL_UP", + "command": ["script-binding", "file_browser/dynamic/scroll_up"] + }, + { + "key": "WHEEL_DOWN", + "command": ["script-binding", "file_browser/dynamic/scroll_down"] + }, + { + "key": "UP", + "command": ["osd-auto", "add", "volume", "2"] + }, + { + "key": "DOWN", + "command": ["osd-auto", "add", "volume", "-2"] + } +] +``` + +Custom keybinds can be called using the same method, but users must set the `name` value inside the `file-browser-keybinds.json` file. +To avoid conflicts custom keybinds use the format: `file_browser/dynamic/custom/[name]`. + +## Expressions + +Expressions are used to evaluate Lua code into a string that can be used for commands. +These behave similarly to those used for [`profile-cond`](https://mpv.io/manual/master/#conditional-auto-profiles) +values. In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively. +Additionally, in mpv v0.38+ the `mp.input` module is available as `input`. + +The file-browser [addon API](addons/addons.md#the-api) is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) +is installed then user-input API will be available in `user_input`. + +This example only runs the keybind if the browser is in the Windows C drive or if +the selected item is a matroska file: + +```json +[ + { + "key": "KP1", + "command": ["print-text", "in my C:/ drive!"], + "condition": "(%P):find('C:/') == 1" + }, + { + "key": "KP2", + "command": ["print-text", "Matroska File!"], + "condition": "fb.get_extension(%N) == 'mkv'" + } +] +``` + +If the `condition` expression contains any item specific codes (`%F`, `%I`, etc) then it will be +evaluated on each individual item, otherwise it will evaluated once for the whole keybind. +If a code is invalid (for example using `%i` in empty directories) then the expression returns false. + +There are some utility script messages that extend the power of expressions. +[`conditional-command`](#conditional-command-condition-command) allows one to specify conditions that +can apply to individual items or commands. The tradeoff is that you lose the automated passthrough behaviour. +There is also [`evaluate-expressions`](#evaluate-expressions-command) which allows one to evaluate expressions inside commands. + +## Utility Script Messages + +There are a small number of custom script messages defined by file-browser to support custom keybinds. + +### `=> ` + +A basic script message that makes it easier to chain multiple utility script messages together. +Any `=>` string will be substituted for `script-message`. + +```json +{ + "key": "KP1", + "command": ["script-message", "=>", "delay-command", "%j * 2", "=>", "evaluate-expressions", "print-text", "!{%j * 2}"], + "multiselect": true +} +``` + +### `conditional-command [condition] ` + +Runs the following command only if the condition [expression](#expressions) is `true`. + +This example command will only run if the player is currently paused: + +```json +{ + "key": "KP1", + "command": ["script-message", "conditional-command", "mp.get_property_bool('pause')", "print-text", "is paused"], +} +``` + +Custom keybind codes are evaluated before the expressions. + +This example only runs if the currently selected item in the browser has a `.mkv` extension: + +```json +{ + "key": "KP1", + "command": ["script-message", "conditional-command", "fb.get_extension(%N) == 'mkv'", "print-text", "a matroska file"], +} +``` + +### `delay-command [delay] ` + +Delays the following command by `[delay]` seconds. +Delay is an [expression](#expressions). + +The following example will send the `print-text` command after 5 seconds: + +```json +{ + "key": "KP1", + "command": ["script-message", "delay-command", "5", "print-text", "example"], +} +``` + +### `evaluate-expressions ` + +Evaluates embedded Lua expressions in the following command. +Expressions have the same behaviour as the [`conditional-command`](#conditional-command-condition-command) script-message. +Expressions must be surrounded by `!{}` characters. +Additional `!` characters can be placed at the start of the expression to +escape the evaluation. + +For example the following keybind will print 3 to the console: + +```json +{ + "key": "KP1", + "command": ["script-message", "evaluate-expressions", "print-text", "!{1 + 2}"], +} +``` + +This example replaces all `/` characters in the path with `\` +(note that the `\` needs to be escaped twice, once for the json file, and once for the string in the lua expression): + +```json +{ + "key": "KP1", + "command": ["script-message", "evaluate-expressions", "print-text", "!{ string.gsub(%F, '/', '\\\\') }"], +} +``` + +### `run-statement ` + +Runs the following string a as a Lua statement. This is similar to an [expression](#expressions), +but instead of the code evaluating to a value it must run a series of statements. Basically it allows +for function bodies to be embedded into custom keybinds. All the same modules are available. +If multiple strings are sent to the script-message then they will be concatenated together with newlines. + +The following keybind will use [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) to +rename items in file-browser: + +```json +{ + "key": "KP1", + "command": ["script-message", "run-statement", + "assert(user_input, 'install mpv-user-input!')", + + "local line, err = user_input.get_user_input_co({", + "id = 'rename-file',", + "source = 'custom-keybind',", + "request_text = 'rename file:',", + "queueable = true,", + "default_input = %N,", + "cursor_pos = #(%N) - #fb.get_extension(%N, '')", + "})", + + "if not line then return end", + "os.rename(%F, utils.join_path(%P, line))", + + "fb.rescan()" + ], + "parser": "file", + "multiselect": true +} +``` + +## Examples + +See [here](file-browser-keybinds.json). diff --git a/mpv/scripts/file-browser/docs/file-browser-keybinds.json b/mpv/scripts/file-browser/docs/file-browser-keybinds.json new file mode 100644 index 0000000..4713137 --- /dev/null +++ b/mpv/scripts/file-browser/docs/file-browser-keybinds.json @@ -0,0 +1,118 @@ +[ + { + "key": "KP1", + "command": ["print-text", "file: %f"], + "multiselect": true + }, + { + "key": "KP2", + "command": ["print-text", "name: %n"], + "multiselect": true + }, + { + "key": "KP3", + "command": ["print-text", "open directory: %p"] + }, + { + "key": "KP4", + "command": ["print-text", "directory name: %d"] + }, + { + "key": "KP5", + "command": ["print-text", "escape the code: %%f"], + "multiselect": true + }, + { + "key": "KP6", + "command": ["print-text", "full filepath via concatenation: %p%n"], + "multiselect": true + }, + { + "key": "KP7", + "command": ["print-text", "quote/escape filepath: %F"], + "multiselect": true + }, + + + { + "comment": "deletes the currently selected file", + "key": "Alt+DEL", + "command": ["run", "rm", "%F"], + "filter": "file", + "multiselect": true, + "multi-type": "concat" + }, + { + "comment": "opens the currently selected items in a new mpv window", + "key": "Ctrl+ENTER", + "command": ["run", "mpv", "%F"], + "multiselect": true, + "multi-type": "concat" + }, + { + "key": "Ctrl+c", + "command": [ + ["run", "powershell", "-command", "Set-Clipboard", "%F"], + ["print-text", "copied filepath to clipboard"] + ], + "multiselect": true, + "delay": 0.3 + }, + { + "comment": "Opens the current directory in windows explorer", + "key": "Ctrl+o", + "command": ["run", "powershell", "-command", "explorer.exe", "(( %P ).TrimEnd('/') -replace '/', '\\' )"], + "multiselect": false + }, + { + "comment": "Opens the selected directory in windows explorer", + "key": "Ctrl+O", + "command": ["run", "powershell", "-command", "explorer.exe", "(( %F ).TrimEnd('/') -replace '/', '\\' )"], + "filter": "dir", + "multiselect": true + }, + { + "comment": "Opens the current directory in windows explorer and highlights the currently selected file", + "key": "Ctrl+O", + "command": ["run", "powershell", "-command", "explorer.exe", "'/select,'", "( %F -replace '/', '\\' )"], + "filter": "file", + "multiselect": true + }, + { + "key": "INS", + "command": ["run", "powershell", "-command", "Set-Content", "-LiteralPath", "( %P + '/.ordered-chapters.m3u' )", "-Value", "( %N )"], + "multiselect": true, + "multi-type": "concat", + "concat-string": "+ '\n' +" + }, + + + { + "key": "WHEEL_UP", + "command": ["script-binding", "file_browser/dynamic/scroll_up"] + }, + { + "key": "WHEEL_DOWN", + "command": ["script-binding", "file_browser/dynamic/scroll_down"] + }, + { + "key": "MBTN_LEFT", + "command": ["script-binding", "file_browser/dynamic/down_dir"] + }, + { + "key": "MBTN_RIGHT", + "command": ["script-binding", "file_browser/dynamic/up_dir"] + }, + { + "key": "MBTN_MID", + "command": ["script-binding", "file_browser/dynamic/play"] + }, + { + "key": "UP", + "command": ["osd-auto", "add", "volume", "2"] + }, + { + "key": "DOWN", + "command": ["osd-auto", "add", "volume", "-2"] + } +] \ No newline at end of file diff --git a/mpv/scripts/file-browser/docs/file_browser.conf b/mpv/scripts/file-browser/docs/file_browser.conf new file mode 100644 index 0000000..3bf8058 --- /dev/null +++ b/mpv/scripts/file-browser/docs/file_browser.conf @@ -0,0 +1,175 @@ +####################################################### +# This is the default config file for mpv-file-browser +# https://github.com/CogentRedTester/mpv-file-browser +####################################################### + +# root directories, separated by commas +# on linux you will probably want to add `/`, +# on windows this should be used to add different drive letters +# Examples: +# linux: root=~/,/ +# windows: root=~/,C:/ +root=~/ + +# characters to separate root directories, each character works individually +# this is in case one is using directories with strange names +root_separators=,; + +# number of entries to show on the screen at once +num_entries=20 + +# wrap the cursor around the top and bottom of the list +wrap=no + +# only show files compatible with mpv in the browser +filter_files=yes + +# experimental feature that recurses directories concurrently when appending items to the playlist +# this feature has the potential for massive performance improvements when using addons with asynchronous IO +concurrent_recursion=no + +# maximum number of recursions that can run concurrently +# if this number is too high it risks overflowing the mpv event queue, which will cause some directories to be dropped entirely +max_concurrency=16 + +# enable custom keybinds +# the keybind json file must go in ~~/script-opts +custom_keybinds=no + +# file-browser only shows files that are compatible with mpv by default +# adding a file extension to this list will add it to the extension whitelist +# extensions are separated with the root separators, do not use any spaces +extension_whitelist= + +# add file extensions to this list to disable default filetypes +# note that this will also override audio/subtitle_extension options below +extension_blacklist= + +# files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist +# items on this list are automatically added to the extension whitelist +audio_extensions=mka,dts,dtshd,dts-hd,truehd,true-hd + +# files with these extensions will be added as additional subtitle tracks for the current file instead of appended to the playlist +# items on this list are automatically added to the extension whitelist +subtitle_extensions=etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs + +# filter directories or files starting with a period like .config +# for linux systems +filter_dot_dirs=no +filter_dot_files=no + +# substitude forward slashes for backslashes when appending a local file to the playlist +# may be useful on windows systems +substitute_backslash=no + +# interpret backslashes `\` in paths as forward slashes `/` +# this is useful on Windows, which natively uses backslashes. +# As backslashes are valid filename characters in Unix systems this could +# cause mangled paths, though such filenames are rare. +# Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform` +# property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`. +normalise_backslash=auto + +# this option reverses the behaviour of the alt+ENTER keybind +# when disabled the keybind is required to enable autoload for the file +# when enabled the keybind disables autoload for the file +autoload=no + +# if autoload is triggered by selecting the currently playing file, then +# the current file will have it's watch-later config saved before being closed and re-opened +# essentially the current file will not be restarted +autoload_save_current=yes + +# when opening the browser in idle mode prefer the current working directory over the root +# note that the working directory is set as the 'current' directory regardless, so `home` will +# move the browser there even if this option is set to false +default_to_working_directory=no + +# when moving up a directory do not stop on empty protocol schemes like `ftp://` +# e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://` +skip_protocol_schemes=yes + +# map optical device paths to their respective file paths, +# e.g. mapping bd:// to the value of the bluray-device property +map_bd_device=yes +map_dvd_device=yes +map_cdda_device=yes + +# enables addons +addons=no +addon_directory=~~/script-modules/file-browser-addons + +# directory to load external modules - currently just user-input-module +module_directory=~~/script-modules + +# turn the OSC idle screen off and on when opening and closing the browser +# this should only be enabled if file-browser is the only thing controlling the idle-screen, +# if multiple sources attempt to control the idle-screen at the same time it can cause unexpected behaviour. +toggle_idlescreen=no + +# Set the current open status of the browser in the `file_browser/open` field of the `user-data` property. +# This property is only available in mpv v0.36+. +set_user_data=yes + +# Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property. +# This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically disable this option. +set_shared_script_properties=no + +#################################### +######### style settings ########### +#################################### + +# force file-browser to use a specific text alignment (default: top-left) +# uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 +# set to 0 to use the default mpv osd-align options +alignment=7 + +# The format string used for the header. Uses custom-keybind substitution codes to +# dynamically change the contents of the header. See: docs/custom-keybinds.md#codes +# e.g. to add file numbers, set this to: {\fnMonospace}[%i/%x]{\fn} %q\N---------------------------------------------------- +format_string_header=%q\N---------------------------------------------------- + +# The format strings used for the wrappers. Supports custom-keybind substitution codes, and +# supports two additional codes: `%<` and `%>` to show the number of items before and after the visible list, respectively. +# Setting these options to empty strings will disable the wrappers. +format_string_topwrapper=%< item(s) above\N +format_string_bottomwrapper=\N%> item(s) remaining + +# allows custom icons be set for the folder and cursor +# the `\h` character is a hard space to add padding +folder_icon={\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h +cursor_icon={\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h + +# set the opacity of fonts in hexadecimal from 00 (opaque) to FF (transparent) +font_opacity_selection_marker=99 + +# print the header in bold font +font_bold_header=yes + +# scale the size of the browser; 2 would double the size, 0.5 would halve it, etc. +# the header and wrapper scaling is relative to the base scaling +scaling_factor_base=1 +scaling_factor_header=1.4 +scaling_factor_wrappers=0.64 + +# set custom font names, blank is the default +# setting custom fonts for the folder/cursor can fix broken or missing icons +font_name_header= +font_name_body= +font_name_wrappers= +font_name_folder= +font_name_cursor= + +# set custom font colours +# colours are in hexadecimal format in Blue Green Red order +# note that this is the opposite order to most RGB colour codes +font_colour_header=00ccff +font_colour_body=ffffff +font_colour_wrappers=00ccff +font_colour_cursor=00ccff + +# these are colours applied to list items in different states +font_colour_selected=fce788 +font_colour_multiselect=fcad88 +font_colour_playing=33ff66 +font_colour_playing_multiselected=22b547 diff --git a/mpv/scripts/file-browser/main.lua b/mpv/scripts/file-browser/main.lua new file mode 100644 index 0000000..4eec577 --- /dev/null +++ b/mpv/scripts/file-browser/main.lua @@ -0,0 +1,73 @@ +--[[ + mpv-file-browser + + This script allows users to browse and open files and folders entirely from within mpv. + The script uses nothing outside the mpv API, so should work identically on all platforms. + The browser can move up and down directories, start playing files and folders, or add them to the queue. + + For full documentation see: https://github.com/CogentRedTester/mpv-file-browser +]]-- + +local mp = require 'mp' + +local o = require 'modules.options' + +-- setting the package paths +package.path = mp.command_native({"expand-path", o.module_directory}).."/?.lua;"..package.path + +local addons = require 'modules.addons' +local keybinds = require 'modules.keybinds' +local setup = require 'modules.setup' +local controls = require 'modules.controls' +local observers = require 'modules.observers' +local script_messages = require 'modules.script-messages' + +local input_loaded, input = pcall(require, "mp.input") +local user_input_loaded, user_input = pcall(require, "user-input-module") + + +-- root and addon setup +setup.root() +addons.load_internal_parsers() +if o.addons then addons.load_external_addons() end + +--these need to be below the addon setup in case any parsers add custom entries +setup.extensions_list() +keybinds.setup_keybinds() + +-- property observers +mp.observe_property('path', 'string', observers.current_directory) +if o.map_dvd_device then mp.observe_property('dvd-device', 'string', observers.dvd_device) end +if o.map_bd_device then mp.observe_property('bluray-device', 'string', observers.bd_device) end +if o.map_cdda_device then mp.observe_property('cdda-device', 'string', observers.cd_device) end + +-- scripts messages +mp.register_script_message('=>', script_messages.chain) +mp.register_script_message('delay-command', script_messages.delay_command) +mp.register_script_message('conditional-command', script_messages.conditional_command) +mp.register_script_message('evaluate-expressions', script_messages.evaluate_expressions) +mp.register_script_message('run-statement', script_messages.run_statement) + +mp.register_script_message('browse-directory', controls.browse_directory) +mp.register_script_message("get-directory-contents", script_messages.get_directory_contents) + +--declares the keybind to open the browser +mp.add_key_binding('MENU','browse-files', controls.toggle) +mp.add_key_binding('Ctrl+o','open-browser', controls.open) + +if input_loaded then + mp.add_key_binding("Alt+o", "browse-directory/get-user-input", function() + input.get({ + prompt = "open directory:", + id = "file-browser/browse-directory", + submit = function(text) + controls.browse_directory(text) + input.terminate() + end + }) + end) +elseif user_input_loaded then + mp.add_key_binding("Alt+o", "browse-directory/get-user-input", function() + user_input.get_user_input(controls.browse_directory, {request_text = "open directory:"}) + end) +end diff --git a/mpv/scripts/file-browser/modules/addons.lua b/mpv/scripts/file-browser/modules/addons.lua new file mode 100644 index 0000000..d03a78f --- /dev/null +++ b/mpv/scripts/file-browser/modules/addons.lua @@ -0,0 +1,174 @@ +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb = require 'modules.apis.fb' +local fb_utils = require 'modules.utils' +local parser_API = require 'modules.apis.parser' + +local API_MAJOR, API_MINOR, API_PATCH = g.API_VERSION:match("(%d+)%.(%d+)%.(%d+)") +API_MAJOR, API_MINOR, API_PATCH = tonumber(API_MAJOR), tonumber(API_MINOR), tonumber(API_PATCH) + +--checks if the given parser has a valid version number +local function check_api_version(parser, id) + if parser.version then + msg.warn(('%s: use of the `version` field is deprecated - use `api_version` instead'):format(id)) + parser.api_version = parser.version + end + + local version = parser.api_version + if type(version) ~= 'string' then return msg.error(("%s: field `api_version` must be a string, got %s"):format(id, tostring(version))) end + + local major, minor = version:match("(%d+)%.(%d+)") + major, minor = tonumber(major), tonumber(minor) + + if not major or not minor then + return msg.error(("%s: invalid version number, expected v%d.%d.x, got v%s"):format(id, API_MAJOR, API_MINOR, version)) + elseif major ~= API_MAJOR then + return msg.error(("%s has wrong major version number, expected v%d.x.x, got, v%s"):format(id, API_MAJOR, version)) + elseif minor > API_MINOR then + msg.warn(("%s has newer minor version number than API, expected v%d.%d.x, got v%s"):format(id, API_MAJOR, API_MINOR, version)) + end + return true +end + +--create a unique id for the given parser +local function set_parser_id(parser) + local name = parser.name + if g.parsers[name] then + local n = 2 + name = parser.name.."_"..n + while g.parsers[name] do + n = n + 1 + name = parser.name.."_"..n + end + end + + g.parsers[name] = parser + g.parsers[parser] = { id = name } +end + +--runs an addon in a separate environment +local function run_addon(path) + local name_sqbr = string.format("[%s]", path:match("/([^/]*)%.lua$")) + local addon_environment = fb_utils.redirect_table(_G) + addon_environment._G = addon_environment + + --gives each addon custom debug messages + addon_environment.package = fb_utils.redirect_table(addon_environment.package) + addon_environment.package.loaded = fb_utils.redirect_table(addon_environment.package.loaded) + local msg_module = { + log = function(level, ...) msg.log(level, name_sqbr, ...) end, + fatal = function(...) return msg.fatal(name_sqbr, ...) end, + error = function(...) return msg.error(name_sqbr, ...) end, + warn = function(...) return msg.warn(name_sqbr, ...) end, + info = function(...) return msg.info(name_sqbr, ...) end, + verbose = function(...) return msg.verbose(name_sqbr, ...) end, + debug = function(...) return msg.debug(name_sqbr, ...) end, + trace = function(...) return msg.trace(name_sqbr, ...) end, + } + addon_environment.print = msg_module.info + + addon_environment.require = function(module) + if module == "mp.msg" then return msg_module end + return require(module) + end + + local chunk, err + if setfenv then + --since I stupidly named a function loadfile I need to specify the global one + --I've been using the name too long to want to change it now + chunk, err = _G.loadfile(path) + if not chunk then return msg.error(err) end + setfenv(chunk, addon_environment) + else + chunk, err = _G.loadfile(path, "bt", addon_environment) + if not chunk then return msg.error(err) end + end + + local success, result = xpcall(chunk, fb_utils.traceback) + return success and result or nil +end + +--setup an internal or external parser +local function setup_parser(parser, file) + parser = setmetatable(parser, { __index = parser_API }) + parser.name = parser.name or file:gsub("%-browser%.lua$", ""):gsub("%.lua$", "") + + set_parser_id(parser) + if not check_api_version(parser, file) then return msg.error("aborting load of parser", parser:get_id(), "from", file) end + + msg.verbose("imported parser", parser:get_id(), "from", file) + + --sets missing functions + if not parser.can_parse then + if parser.parse then parser.can_parse = function() return true end + else parser.can_parse = function() return false end end + end + + if parser.priority == nil then parser.priority = 0 end + if type(parser.priority) ~= "number" then return msg.error("parser", parser:get_id(), "needs a numeric priority") end + + table.insert(g.parsers, parser) +end + +--load an external addon +local function setup_addon(file, path) + if file:sub(-4) ~= ".lua" then return msg.verbose(path, "is not a lua file - aborting addon setup") end + + local addon_parsers = run_addon(path) + if addon_parsers and not next(addon_parsers) then return msg.verbose('addon', path, 'returned empry table - special case, ignoring') end + if not addon_parsers or type(addon_parsers) ~= "table" then return msg.error("addon", path, "did not return a table") end + + --if the table contains a priority key then we assume it isn't an array of parsers + if not addon_parsers[1] then addon_parsers = {addon_parsers} end + + for _, parser in ipairs(addon_parsers) do + setup_parser(parser, file) + end +end + +--loading external addons +local function load_addons(directory) + directory = fb_utils.fix_path(directory, true) + + local files = utils.readdir(directory) + if not files then error("could not read addon directory") end + + for _, file in ipairs(files) do + setup_addon(file, directory..file) + end + table.sort(g.parsers, function(a, b) return a.priority < b.priority end) + + --we want to store the indexes of the parsers + for i = #g.parsers, 1, -1 do g.parsers[ g.parsers[i] ].index = i end + + --we want to run the setup functions for each addon + for index, parser in ipairs(g.parsers) do + if parser.setup then + local success = xpcall(function() parser:setup() end, fb_utils.traceback) + if not success then + msg.error("parser", parser:get_id(), "threw an error in the setup method - removing from list of parsers") + table.remove(g.parsers, index) + end + end + end +end + +local function load_internal_parsers() + local internal_addon_dir = mp.get_script_directory()..'/modules/parsers/' + load_addons(internal_addon_dir) +end + +local function load_external_addons() + local addon_dir = mp.command_native({"expand-path", o.addon_directory..'/'}) + load_addons(addon_dir) +end + +return { + check_api_version = check_api_version, + load_internal_parsers = load_internal_parsers, + load_external_addons = load_external_addons +} diff --git a/mpv/scripts/file-browser/modules/apis/fb.lua b/mpv/scripts/file-browser/modules/apis/fb.lua new file mode 100644 index 0000000..f7739e5 --- /dev/null +++ b/mpv/scripts/file-browser/modules/apis/fb.lua @@ -0,0 +1,136 @@ +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local ass = require 'modules.ass' +local directory_movement = require 'modules.navigation.directory-movement' +local scanning = require 'modules.navigation.scanning' +local cache = require 'modules.cache' +local controls = require 'modules.controls' + +local fb = setmetatable({}, { __index = setmetatable({}, { __index = fb_utils }) }) +package.loaded["file-browser"] = setmetatable({}, { __index = fb }) + +--these functions we'll provide as-is +fb.redraw = ass.update_ass +fb.rescan = scanning.rescan +fb.browse_directory = controls.browse_directory + +function fb.clear_cache() + cache:clear() +end + +--a wrapper around scan_directory for addon API +function fb.parse_directory(directory, parse_state) + if not parse_state then parse_state = { source = "addon" } + elseif not parse_state.source then parse_state.source = "addon" end + return scanning.scan_directory(directory, parse_state) +end + +--register file extensions which can be opened by the browser +function fb.register_parseable_extension(ext) + g.parseable_extensions[string.lower(ext)] = true +end +function fb.remove_parseable_extension(ext) + g.parseable_extensions[string.lower(ext)] = nil +end + +--add a compatible extension to show through the filter, only applies if run during the setup() method +function fb.add_default_extension(ext) + table.insert(g.compatible_file_extensions, ext) +end + +--add item to root at position pos +function fb.insert_root_item(item, pos) + msg.debug("adding item to root", item.label or item.name, pos) + item.ass = item.ass or fb.ass_escape(item.label or item.name) + item.type = "dir" + table.insert(g.root, pos or (#g.root + 1), item) +end + +-- add a new mapping to the given directory +function fb.register_directory_mapping(directory, mapping, pattern) + if not pattern then mapping = '^'..fb_utils.pattern_escape(mapping) end + g.directory_mappings[mapping] = directory + msg.verbose('registering directory alias', mapping, directory) + + directory_movement.set_current_file(g.current_file.original_path) + return mapping +end + +-- remove all directory mappings that map to the given directory +function fb.remove_all_mappings(directory) + local removed = {} + for mapping, target in pairs(g.directory_mappings) do + if target == directory then + g.directory_mappings[mapping] = nil + table.insert(removed, mapping) + end + end + return removed +end + +--a newer API for adding items to the root +--only adds the item if the same item does not already exist in the root +--the priority variable is a number that specifies the insertion location +--a lower priority is placed higher in the list and the default is 100 +function fb.register_root_item(item, priority) + msg.verbose('registering root item:', utils.to_string(item)) + if type(item) == 'string' then + item = {name = item} + end + + -- if the item is already in the list then do nothing + if fb.list.some(g.root, function(r) + return fb.get_full_path(r, '') == fb.get_full_path(item, '') + end) then return false end + + item._priority = priority + for i, v in ipairs(g.root) do + if (v._priority or 100) > (priority or 100) then + fb.insert_root_item(item, i) + return true + end + end + fb.insert_root_item(item) + return true +end + +--providing getter and setter functions so that addons can't modify things directly +function fb.get_script_opts() return fb.copy_table(o) end +function fb.get_opt(key) return o[key] end +function fb.get_extensions() return fb.copy_table(g.extensions) end +function fb.get_sub_extensions() return fb.copy_table(g.sub_extensions) end +function fb.get_audio_extensions() return fb.copy_table(g.audio_extensions) end +function fb.get_parseable_extensions() return fb.copy_table(g.parseable_extensions) end +function fb.get_state() return fb.copy_table(g.state) end +function fb.get_dvd_device() return g.dvd_device end +function fb.get_parsers() return fb.copy_table(g.parsers) end +function fb.get_root() return fb.copy_table(g.root) end +function fb.get_directory() return g.state.directory end +function fb.get_list() return fb.copy_table(g.state.list) end +function fb.get_current_file() return fb.copy_table(g.current_file) end +function fb.get_current_parser() return g.state.parser:get_id() end +function fb.get_current_parser_keyname() return g.state.parser.keybind_name or g.state.parser.name end +function fb.get_selected_index() return g.state.selected end +function fb.get_selected_item() return fb.copy_table(g.state.list[g.state.selected]) end +function fb.get_open_status() return not g.state.hidden end +function fb.get_parse_state(co) return g.parse_states[co or coroutine.running() or ""] end + +function fb.set_empty_text(str) + g.state.empty_text = str + fb.redraw() +end + +function fb.set_selected_index(index) + if type(index) ~= "number" then return false end + if index < 1 then index = 1 end + if index > #g.state.list then index = #g.state.list end + g.state.selected = index + fb.redraw() + return index +end + +return fb diff --git a/mpv/scripts/file-browser/modules/apis/parse-state.lua b/mpv/scripts/file-browser/modules/apis/parse-state.lua new file mode 100644 index 0000000..8ddf542 --- /dev/null +++ b/mpv/scripts/file-browser/modules/apis/parse-state.lua @@ -0,0 +1,32 @@ + +local msg = require 'mp.msg' + +local g = require 'modules.globals' + +local parse_state_API = {} + +--a wrapper around coroutine.yield that aborts the coroutine if +--the parse request was cancelled by the user +--the coroutine is +function parse_state_API:yield(...) + local co = coroutine.running() + local is_browser = co == g.state.co + if self.source == "browser" and not is_browser then + msg.error("current coroutine does not match browser's expected coroutine - did you unsafely yield before this?") + error("current coroutine does not match browser's expected coroutine - aborting the parse") + end + + local result = table.pack(coroutine.yield(...)) + if is_browser and co ~= g.state.co then + msg.verbose("browser no longer waiting for list - aborting parse for", self.directory) + error(g.ABORT_ERROR) + end + return unpack(result, 1, result.n) +end + +--checks if the current coroutine is the one handling the browser's request +function parse_state_API:is_coroutine_current() + return coroutine.running() == g.state.co +end + +return parse_state_API diff --git a/mpv/scripts/file-browser/modules/apis/parser.lua b/mpv/scripts/file-browser/modules/apis/parser.lua new file mode 100644 index 0000000..cdfe71f --- /dev/null +++ b/mpv/scripts/file-browser/modules/apis/parser.lua @@ -0,0 +1,25 @@ +local msg = require 'mp.msg' + +local g = require 'modules.globals' +local scanning = require 'modules.navigation.scanning' +local fb = require 'modules.apis.fb' + +local parser_api = setmetatable({}, { __index = fb }) + +function parser_api:get_index() return g.parsers[self].index end +function parser_api:get_id() return g.parsers[self].id end + +--a wrapper that passes the parsers priority value if none other is specified +function parser_api:register_root_item(item, priority) + return fb.register_root_item(item, priority or g.parsers[self:get_id()].priority) +end + +--runs choose_and_parse starting from the next parser +function parser_api:defer(directory) + msg.trace("deferring to other parsers...") + local list, opts = scanning.choose_and_parse(directory, self:get_index() + 1) + fb.get_parse_state().already_deferred = true + return list, opts +end + +return parser_api diff --git a/mpv/scripts/file-browser/modules/ass.lua b/mpv/scripts/file-browser/modules/ass.lua new file mode 100644 index 0000000..0fc5791 --- /dev/null +++ b/mpv/scripts/file-browser/modules/ass.lua @@ -0,0 +1,175 @@ +-------------------------------------------------------------------------------------------------------- +-----------------------------------------List Formatting------------------------------------------------ +-------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------- + +local utils = require 'mp.utils' + +local g = require 'modules.globals' +local o = require 'modules.options' +local fb_utils = require 'modules.utils' + +local state = g.state +local style = g.style +local ass = g.ass + +local function draw() + ass:update() +end + +local function remove() + ass:remove() +end + +local string_buffer = {} + +--appends the entered text to the overlay +local function append(...) + for i = 1, select("#", ...) do + table.insert(string_buffer, select(i, ...) or '' ) + end +end + +--appends a newline character to the osd +local function newline() + table.insert(string_buffer, '\\N') +end + +local function flush_buffer() + ass.data = table.concat(string_buffer, '') + string_buffer = {} +end + +--detects whether or not to highlight the given entry as being played +local function highlight_entry(v) + if g.current_file.path == nil then return false end + local full_path = fb_utils.get_full_path(v) + local alt_path = v.name and g.state.directory..v.name or nil + + if fb_utils.parseable_item(v) then + return string.find(g.current_file.directory, full_path, 1, true) + or (alt_path and string.find(g.current_file.directory, alt_path, 1, true)) + else + return g.current_file.path == full_path + or (alt_path and g.current_file.path == alt_path) + end +end + +local ass_cache = setmetatable({}, {__mode = 'k'}) + +-- escape ass values and replace newlines +local function ass_escape(str) + if ass_cache[str] then return ass_cache[str] end + local escaped = fb_utils.ass_escape(str, true) + ass_cache[str] = escaped + return escaped +end + +--refreshes the ass text using the contents of the list +local function update_ass() + if state.hidden then state.flag_update = true ; return end + + append(style.global) + + local dir_name = state.directory_label or state.directory + if dir_name == "" then dir_name = "ROOT" end + append(style.header) + append(fb_utils.substitute_codes(o.format_string_header, nil, nil, nil, ass_escape)) + newline() + + if #state.list < 1 then + append(state.empty_text) + flush_buffer() + draw() + return + end + + local start = 1 + local finish = start+o.num_entries-1 + + --handling cursor positioning + local mid = math.ceil(o.num_entries/2)+1 + if state.selected+mid > finish then + local offset = state.selected - finish + mid + + --if we've overshot the end of the list then undo some of the offset + if finish + offset > #state.list then + offset = offset - ((finish+offset) - #state.list) + end + + start = start + offset + finish = finish + offset + end + + --making sure that we don't overstep the boundaries + if start < 1 then start = 1 end + local overflow = finish < #state.list + --this is necessary when the number of items in the dir is less than the max + if not overflow then finish = #state.list end + + -- these are the number values to place into the wrappers + local wrapper_overrides = {['<'] = tostring(start-1), ['>'] = tostring(#state.list-finish)} + + --adding a header to show there are items above in the list + if o.format_string_topwrapper ~= '' and start > 1 then + append(style.footer_header, fb_utils.substitute_codes(o.format_string_topwrapper, wrapper_overrides, nil, nil, ass_escape)) + newline() + end + + for i=start, finish do + local v = state.list[i] + local playing_file = highlight_entry(v) + append(style.body) + + --handles custom styles for different entries + if i == state.selected or i == state.multiselect_start then + if not (i == state.selected) then append(style.selection_marker) end + + if not state.multiselect_start then append(style.cursor) + else + if state.selection[state.multiselect_start] then append(style.cursor_select) + else append(style.cursor_deselect) end + end + append(o.cursor_icon, "\\h", style.body) + else + append(g.style.indent, o.cursor_icon, "\\h", style.body) + end + + --sets the selection colour scheme + local multiselected = state.selection[i] + + --sets the colour for the item + local function set_colour() + if multiselected then append(style.multiselect) + elseif i == state.selected then append(style.selected) end + + if playing_file then append( multiselected and style.playing_selected or style.playing) end + end + set_colour() + + --sets the folder icon + if v.type == 'dir' then + append(style.folder, o.folder_icon, "\\h", style.body) + set_colour() + end + + --adds the actual name of the item + append(v.ass or ass_escape(v.label or v.name)) + newline() + end + + if o.format_string_bottomwrapper ~= '' and overflow then + append(style.footer_header) + append(fb_utils.substitute_codes(o.format_string_bottomwrapper, wrapper_overrides, nil, nil, ass_escape)) + end + + flush_buffer() + draw() +end + +return { + update_ass = update_ass, + highlight_entry = highlight_entry, + draw = draw, + remove = remove, +} diff --git a/mpv/scripts/file-browser/modules/cache.lua b/mpv/scripts/file-browser/modules/cache.lua new file mode 100644 index 0000000..5e393dd --- /dev/null +++ b/mpv/scripts/file-browser/modules/cache.lua @@ -0,0 +1,139 @@ +-------------------------------------------------------------------------------------------------------- +--------------------------------------Cache Implementation---------------------------------------------- +-------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------- + +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' + +local function get_keys(t) + local keys = {} + for key in pairs(t) do + table.insert(keys, key) + end + return keys +end + +local cache = { + cache = setmetatable({}, {__mode = 'kv'}), + traversal_stack = {}, + history = {}, + cached_values = { + "directory", "directory_label", "list", "selected", "selection", "parser", "empty_text", "co" + }, + dangling_refs = {}, +} + +function cache:print_debug_info() + local cache_keys = get_keys(self.cache) + msg.verbose('Printing cache debug info') + msg.verbose('cache size:', #cache_keys) + msg.debug(utils.to_string(cache_keys)) + msg.trace(utils.to_string(self.cache[cache_keys[#cache_keys]])) + + msg.verbose('traversal_stack size:', #self.traversal_stack) + msg.debug(utils.to_string(fb_utils.list.map(self.traversal_stack, function(ref) return ref.directory end))) + + msg.verbose('history size:', #self.history) + msg.debug(utils.to_string(fb_utils.list.map(self.history, function(ref) return ref.directory end))) +end + +function cache:replace_dangling_refs(directory, ref) + for _, v in ipairs(self.traversal_stack) do + if v.directory == directory then + v.ref = ref + self.dangling_refs[directory] = nil + end + end + for _, v in ipairs(self.history) do + if v.directory == directory then + v.ref = ref + self.dangling_refs[directory] = nil + end + end +end + +function cache:add_current_state() + local directory = g.state.directory + if directory == nil then return end + + local t = self.cache[directory] or {} + for _, value in ipairs(self.cached_values) do + t[value] = g.state[value] + end + + self.cache[directory] = t + if self.dangling_refs[directory] then + self:replace_dangling_refs(directory, t) + end +end + +-- Creates a reference to the cache of a particular directory to prevent it +-- from being garbage collected. +function cache:get_cache_ref(directory) + return { + directory = directory, + ref = self.cache[directory], + } +end + +function cache:append_history() + self:add_current_state() + local history_size = #self.history + + -- We don't want to have the same directory in the history over and over again. + if history_size > 0 and self.history[history_size].directory == g.state.directory then return end + + table.insert(self.history, self:get_cache_ref(g.state.directory)) + if (history_size + 1) > 100 then table.remove(self.history, 1) end +end + +function cache:in_cache(directory) + return self.cache[directory] ~= nil +end + +function cache:apply(directory) + directory = directory or g.state.directory + local t = self.cache[directory] + if not t then return false end + + msg.verbose('applying cache for', directory) + + for _, value in ipairs(self.cached_values) do + msg.debug('setting', value, 'to', t[value]) + g.state[value] = t[value] + end + + return true +end + +function cache:push() + local stack_size = #self.traversal_stack + if stack_size > 0 and self.traversal_stack[stack_size].directory == g.state.directory then return end + table.insert(self.traversal_stack, self:get_cache_ref(g.state.directory)) +end + +function cache:pop() + table.remove(self.traversal_stack) +end + +function cache:clear_traversal_stack() + self.traversal_stack = {} +end + +function cache:clear() + self.cache = setmetatable({}, {__mode = 'kv'}) + for _, v in ipairs(self.traversal_stack) do + v.ref = nil + self.dangling_refs[v.directory] = true + end + for _, v in ipairs(self.history) do + v.ref = nil + self.dangling_refs[v.directory] = true + end +end + +return cache diff --git a/mpv/scripts/file-browser/modules/controls.lua b/mpv/scripts/file-browser/modules/controls.lua new file mode 100644 index 0000000..fcfe790 --- /dev/null +++ b/mpv/scripts/file-browser/modules/controls.lua @@ -0,0 +1,90 @@ + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local movement = require 'modules.navigation.directory-movement' +local ass = require 'modules.ass' +local cursor = require 'modules.navigation.cursor' + +local controls = {} + +--opens the browser +function controls.open() + if not g.state.hidden then return end + + for _,v in ipairs(g.state.keybinds) do + mp.add_forced_key_binding(v[1], 'dynamic/'..v[2], v[3], v[4]) + end + + if o.set_shared_script_properties then utils.shared_script_property_set('file_browser-open', 'yes') end + if o.set_user_data then mp.set_property_bool('user-data/file_browser/open', true) end + + if o.toggle_idlescreen then mp.commandv('script-message', 'osc-idlescreen', 'no', 'no_osd') end + g.state.hidden = false + if g.state.directory == nil then + local path = mp.get_property('path') + if path or o.default_to_working_directory then movement.goto_current_dir() else movement.goto_root() end + return + end + + if not g.state.flag_update then ass.draw() + else g.state.flag_update = false ; ass.update_ass() end +end + +--closes the list and sets the hidden flag +function controls.close() + if g.state.hidden then return end + + for _,v in ipairs(g.state.keybinds) do + mp.remove_key_binding('dynamic/'..v[2]) + end + + if o.set_shared_script_properties then utils.shared_script_property_set("file_browser-open", "no") end + if o.set_user_data then mp.set_property_bool('user-data/file_browser/open', false) end + + if o.toggle_idlescreen then mp.commandv('script-message', 'osc-idlescreen', 'yes', 'no_osd') end + g.state.hidden = true + ass.remove() +end + +--toggles the list +function controls.toggle() + if g.state.hidden then controls.open() + else controls.close() end +end + +--run when the escape key is used +function controls.escape() + --if multiple items are selection cancel the + --selection instead of closing the browser + if next(g.state.selection) or g.state.multiselect_start then + g.state.selection = {} + cursor.disable_select_mode() + ass.update_ass() + return + end + controls.close() +end + +--opens a specific directory +function controls.browse_directory(directory, open_browser) + if not directory then return end + if open_browser == nil then open_browser = true end + + directory = mp.command_native({"expand-path", directory}) or '' + -- directory = join_path( mp.get_property("working-directory", ""), directory ) + + if directory ~= "" then directory = fb_utils.fix_path(directory, true) end + msg.verbose('recieved directory from script message: '..directory) + + directory = fb_utils.resolve_directory_mapping(directory) + local co = movement.goto_directory(directory) + if open_browser then controls.open() end + return co +end + +return controls diff --git a/mpv/scripts/file-browser/modules/globals.lua b/mpv/scripts/file-browser/modules/globals.lua new file mode 100644 index 0000000..75db142 --- /dev/null +++ b/mpv/scripts/file-browser/modules/globals.lua @@ -0,0 +1,115 @@ +-------------------------------------------------------------------------------------------------------- +------------------------------------------Variable Setup------------------------------------------------ +-------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------- + +local mp = require 'mp' + +local globals = {} +local o = require 'modules.options' + +--sets the version for the file-browser API +globals.API_VERSION = "1.7.0" + +--gets the current platform (only works in mpv v0.36+) +globals.PLATFORM = mp.get_property_native('platform') + +--the osd_overlay API was not added until v0.31. The expand-path command was not added until 0.30 +assert(mp.create_osd_overlay, "Script requires minimum mpv version 0.33") + +globals.ass = mp.create_osd_overlay("ass-events") +globals.ass.res_y = 720 / o.scaling_factor_base + +local BASE_FONT_SIZE = 25 + +globals.style = { + global = o.alignment == 0 and "" or ([[{\an%d}]]):format(o.alignment), + + -- full line styles + header = ([[{\r\q2\b%s\fs%d\fn%s\c&H%s&}]]):format((o.font_bold_header and "1" or "0"), o.scaling_factor_header*BASE_FONT_SIZE, o.font_name_header, o.font_colour_header), + body = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(BASE_FONT_SIZE, o.font_name_body, o.font_colour_body), + footer_header = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(o.scaling_factor_wrappers*BASE_FONT_SIZE, o.font_name_wrappers, o.font_colour_wrappers), + + --small section styles (for colours) + multiselect = ([[{\c&H%s&}]]):format(o.font_colour_multiselect), + selected = ([[{\c&H%s&}]]):format(o.font_colour_selected), + playing = ([[{\c&H%s&}]]):format(o.font_colour_playing), + playing_selected = ([[{\c&H%s&}]]):format(o.font_colour_playing_multiselected), + + --icon styles + indent = ([[{\alpha&H%s}]]):format('ff'), + cursor = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_cursor), + cursor_select = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_multiselect), + cursor_deselect = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_selected), + folder = ([[{\fn%s}]]):format(o.font_name_folder), + selection_marker = ([[{\alpha&H%s}]]):format(o.font_opacity_selection_marker), +} + +globals.state = { + list = {}, + selected = 1, + hidden = true, + flag_update = false, + keybinds = nil, + + parser = nil, + directory = nil, + directory_label = nil, + prev_directory = "", + co = nil, + + multiselect_start = nil, + initial_selection = nil, + selection = {} +} + +--the parser table actually contains 3 entries for each parser +--a numeric entry which represents the priority of the parsers and has the parser object as the value +--a string entry representing the id of each parser and with the parser object as the value +--and a table entry with the parser itself as the key and a table value in the form { id = %s, index = %d } +globals.parsers = {} + +--this table contains the parse_state tables for every parse operation indexed with the coroutine used for the parse +--this table has weakly referenced keys, meaning that once the coroutine for a parse is no-longer used by anything that +--field in the table will be removed by the garbage collector +globals.parse_states = setmetatable({}, { __mode = "k"}) + +globals.extensions = {} +globals.sub_extensions = {} +globals.audio_extensions = {} +globals.parseable_extensions = {} + +--This table contains mappings to convert external directories to cannonical +--locations within the file-browser file tree. The keys of the table are Lua +--patterns used to evaluate external directory paths. The value is the path +--that should replace the part of the path than matched the pattern. +--These mappings should only applied at the edges where external paths are +--ingested by file-browser. +globals.directory_mappings = {} + +globals.current_file = { + directory = nil, + name = nil, + path = nil, + original_path = nil, +} + +globals.root = {} + +--default list of compatible file extensions +--adding an item to this list is a valid request on github +globals.compatible_file_extensions = { + "264","265","3g2","3ga","3ga2","3gp","3gp2","3gpp","3iv","a52","aac","adt","adts","ahn","aif","aifc","aiff","amr","ape","asf","au","avc","avi","awb","ay", + "bmp","cue","divx","dts","dtshd","dts-hd","dv","dvr","dvr-ms","eac3","evo","evob","f4a","flac","flc","fli","flic","flv","gbs","gif","gxf","gym", + "h264","h265","hdmov","hdv","hes","hevc","jpeg","jpg","kss","lpcm","m1a","m1v","m2a","m2t","m2ts","m2v","m3u","m3u8","m4a","m4v","mk3d","mka","mkv", + "mlp","mod","mov","mp1","mp2","mp2v","mp3","mp4","mp4v","mp4v","mpa","mpe","mpeg","mpeg2","mpeg4","mpg","mpg4","mpv","mpv2","mts","mtv","mxf","nsf", + "nsfe","nsv","nut","oga","ogg","ogm","ogv","ogx","opus","pcm","pls","png","qt","ra","ram","rm","rmvb","sap","snd","spc","spx","svg","thd","thd+ac3", + "tif","tiff","tod","trp","truehd","true-hd","ts","tsa","tsv","tta","tts","vfw","vgm","vgz","vob","vro","wav","weba","webm","webp","wm","wma","wmv","wtv", + "wv","x264","x265","xvid","y4m","yuv" +} + +globals.ABORT_ERROR = { + msg = "browser is no longer waiting for list - aborting parse" +} + +return globals diff --git a/mpv/scripts/file-browser/modules/keybinds.lua b/mpv/scripts/file-browser/modules/keybinds.lua new file mode 100644 index 0000000..4530408 --- /dev/null +++ b/mpv/scripts/file-browser/modules/keybinds.lua @@ -0,0 +1,308 @@ +------------------------------------------------------------------------------------------ +----------------------------------Keybind Implementation---------------------------------- +------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------ + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local addons = require 'modules.addons' +local playlist = require 'modules.playlist' +local controls = require 'modules.controls' +local movement = require 'modules.navigation.directory-movement' +local scanning = require 'modules.navigation.scanning' +local cursor = require 'modules.navigation.cursor' +local cache = require 'modules.cache' + +g.state.keybinds = { + {'ENTER', 'play', function() playlist.add_files('replace', false) end}, + {'Shift+ENTER', 'play_append', function() playlist.add_files('append-play', false) end}, + {'Alt+ENTER', 'play_autoload',function() playlist.add_files('replace', true) end}, + {'ESC', 'close', controls.escape}, + {'RIGHT', 'down_dir', movement.down_dir}, + {'LEFT', 'up_dir', movement.up_dir}, + {'DOWN', 'scroll_down', function() cursor.scroll(1, o.wrap) end, {repeatable = true}}, + {'UP', 'scroll_up', function() cursor.scroll(-1, o.wrap) end, {repeatable = true}}, + {'PGDWN', 'page_down', function() cursor.scroll(o.num_entries) end, {repeatable = true}}, + {'PGUP', 'page_up', function() cursor.scroll(-o.num_entries) end, {repeatable = true}}, + {'Shift+PGDWN', 'list_bottom', function() cursor.scroll(math.huge) end}, + {'Shift+PGUP', 'list_top', function() cursor.scroll(-math.huge) end}, + {'HOME', 'goto_current', movement.goto_current_dir}, + {'Shift+HOME', 'goto_root', movement.goto_root}, + {'Ctrl+r', 'reload', function() cache:clear(); scanning.rescan() end}, + {'s', 'select_mode', cursor.toggle_select_mode}, + {'S', 'select_item', cursor.toggle_selection}, + {'Ctrl+a', 'select_all', cursor.select_all} +} + +--a map of key-keybinds - only saves the latest keybind if multiple have the same key code +local top_level_keys = {} + +--format the item string for either single or multiple items +local function create_item_string(base_code_fn, items, state, cmd, quoted) + if not items[1] then return end + local func = quoted and function(...) return ("%q"):format(base_code_fn(...)) end or base_code_fn + + local out = {} + for _, item in ipairs(items) do + table.insert(out, func(item, state)) + end + + return table.concat(out, cmd['concat-string'] or ' ') +end + +local KEYBIND_CODE_PATTERN = fb_utils.get_code_pattern(fb_utils.code_fns) +local item_specific_codes = 'fnij' + +--substitutes the key codes for the +local function substitute_codes(str, cmd, items, state) + local overrides = {} + + for code in item_specific_codes:gmatch('.') do + overrides[code] = function(_,s) return create_item_string(fb_utils.code_fns[code], items, s, cmd) end + overrides[code:upper()] = function(_,s) return create_item_string(fb_utils.code_fns[code], items, s, cmd, true) end + end + + return fb_utils.substitute_codes(str, overrides, items[1], state) +end + +--iterates through the command table and substitutes special +--character codes for the correct strings used for custom functions +local function format_command_table(cmd, items, state) + local copy = {} + for i = 1, #cmd.command do + copy[i] = {} + + for j = 1, #cmd.command[i] do + copy[i][j] = substitute_codes(cmd.command[i][j], cmd, items, state) + end + end + return copy +end + +--runs all of the commands in the command table +--key.command must be an array of command tables compatible with mp.command_native +--items must be an array of multiple items (when multi-type ~= concat the array will be 1 long) +local function run_custom_command(cmd, items, state) + local custom_cmds = cmd.codes and format_command_table(cmd, items, state) or cmd.command + + for _, custom_cmd in ipairs(custom_cmds) do + msg.debug("running command:", utils.to_string(custom_cmd)) + mp.command_native(custom_cmd) + end +end + +--returns true if the given code set has item specific codes (%f, %i, etc) +local function has_item_codes(codes) + for code in pairs(codes) do + if item_specific_codes:find(code:lower(), 1, true) then return true end + end + return false +end + +--runs one of the custom commands +local function run_custom_keybind(cmd, state, co) + --evaluates a condition and passes through the correct values + local function evaluate_condition(condition, items) + local cond = substitute_codes(condition, cmd, items, state) + return fb_utils.evaluate_string('return '..cond) == true + end + + -- evaluates the string condition to decide if the keybind should be run + local do_item_condition + if cmd.condition then + if has_item_codes(cmd.condition_codes) then + do_item_condition = true + elseif not evaluate_condition(cmd.condition, {}) then + return false + end + end + + if cmd.parser then + local parser_str = ' '..cmd.parser..' ' + if not parser_str:find( '%W'..(state.parser.keybind_name or state.parser.name)..'%W' ) then return false end + end + + --these are for the default keybinds, or from addons which use direct functions + if type(cmd.command) == 'function' then return cmd.command(cmd, cmd.addon and fb_utils.copy_table(state) or state, co) end + + --the function terminates here if we are running the command on a single item + if not (cmd.multiselect and next(state.selection)) then + if cmd.filter then + if not state.list[state.selected] then return false end + if state.list[state.selected].type ~= cmd.filter then return false end + end + + if cmd.codes then + --if the directory is empty, and this command needs to work on an item, then abort and fallback to the next command + if not state.list[state.selected] and has_item_codes(cmd.codes) then return false end + end + + if do_item_condition and not evaluate_condition(cmd.condition, { state.list[state.selected] }) then + return false + end + run_custom_command(cmd, { state.list[state.selected] }, state) + return true + end + + --runs the command on all multi-selected items + local selection = fb_utils.sort_keys(state.selection, function(item) + if do_item_condition and not evaluate_condition(cmd.condition, { item }) then return false end + return not cmd.filter or item.type == cmd.filter + end) + if not next(selection) then return false end + + if cmd["multi-type"] == "concat" then + run_custom_command(cmd, selection, state) + + elseif cmd["multi-type"] == "repeat" or cmd["multi-type"] == nil then + for i,_ in ipairs(selection) do + run_custom_command(cmd, {selection[i]}, state) + + if cmd.delay then + mp.add_timeout(cmd.delay, function() fb_utils.coroutine.resume_err(co) end) + coroutine.yield() + end + end + end + + --we passthrough by default if the command is not run on every selected item + if cmd.passthrough ~= nil then return end + + local num_selection = 0 + for _ in pairs(state.selection) do num_selection = num_selection+1 end + return #selection == num_selection +end + +--recursively runs the keybind functions, passing down through the chain +--of keybinds with the same key value +local function run_keybind_recursive(keybind, state, co) + msg.trace("Attempting custom command:", utils.to_string(keybind)) + + if keybind.passthrough ~= nil then + run_custom_keybind(keybind, state, co) + if keybind.passthrough == true and keybind.prev_key then + run_keybind_recursive(keybind.prev_key, state, co) + end + else + if run_custom_keybind(keybind, state, co) == false and keybind.prev_key then + run_keybind_recursive(keybind.prev_key, state, co) + end + end +end + +--a wrapper to run a custom keybind as a lua coroutine +local function run_keybind_coroutine(key) + msg.debug("Received custom keybind "..key.key) + local co = coroutine.create(run_keybind_recursive) + + local state_copy = { + directory = g.state.directory, + directory_label = g.state.directory_label, + list = g.state.list, --the list should remain unchanged once it has been saved to the global state, new directories get new tables + selected = g.state.selected, + selection = fb_utils.copy_table(g.state.selection), + parser = g.state.parser, + } + local success, err = coroutine.resume(co, key, state_copy, co) + if not success then + msg.error("error running keybind:", utils.to_string(key)) + fb_utils.traceback(err, co) + end +end + +--scans the given command table to identify if they contain any custom keybind codes +local function scan_for_codes(command_table, codes) + if type(command_table) ~= "table" then return codes end + for _, value in pairs(command_table) do + local type = type(value) + if type == "table" then + scan_for_codes(value, codes) + elseif type == "string" then + for code in value:gmatch(KEYBIND_CODE_PATTERN) do + codes[code] = true + end + end + end + return codes +end + +--inserting the custom keybind into the keybind array for declaration when file-browser is opened +--custom keybinds with matching names will overwrite eachother +local function insert_custom_keybind(keybind) + -- api checking for the keybinds is optional, so set to a valid version if it does not exist + keybind.api_version = keybind.api_version or '1.0.0' + if not addons.check_api_version(keybind, 'keybind '..keybind.name) then return end + + --we'll always save the keybinds as either an array of command arrays or a function + if type(keybind.command) == "table" and type(keybind.command[1]) ~= "table" then + keybind.command = {keybind.command} + end + + keybind.codes = scan_for_codes(keybind.command, {}) + if not next(keybind.codes) then keybind.codes = nil end + keybind.prev_key = top_level_keys[keybind.key] + + if keybind.condition then + keybind.condition_codes = {} + for code in string.gmatch(keybind.condition, KEYBIND_CODE_PATTERN) do keybind.condition_codes[code] = true end + end + + table.insert(g.state.keybinds, {keybind.key, keybind.name, function() run_keybind_coroutine(keybind) end, keybind.flags or {}}) + top_level_keys[keybind.key] = keybind +end + +--loading the custom keybinds +--can either load keybinds from the config file, from addons, or from both +local function setup_keybinds() + if not o.custom_keybinds and not o.addons then return end + + --this is to make the default keybinds compatible with passthrough from custom keybinds + for _, keybind in ipairs(g.state.keybinds) do + top_level_keys[keybind[1]] = { key = keybind[1], name = keybind[2], command = keybind[3], flags = keybind[4] } + end + + --this loads keybinds from addons + if o.addons then + for i = #g.parsers, 1, -1 do + local parser = g.parsers[i] + if parser.keybinds then + for i, keybind in ipairs(parser.keybinds) do + --if addons use the native array command format, then we need to convert them over to the custom command format + if not keybind.key then keybind = { key = keybind[1], name = keybind[2], command = keybind[3], flags = keybind[4] } + else keybind = fb_utils.copy_table(keybind) end + + keybind.name = g.parsers[parser].id.."/"..(keybind.name or tostring(i)) + keybind.addon = true + insert_custom_keybind(keybind) + end + end + end + end + + --loads custom keybinds from file-browser-keybinds.json + if o.custom_keybinds then + local path = mp.command_native({"expand-path", "~~/script-opts"}).."/file-browser-keybinds.json" + local custom_keybinds, err = io.open( path ) + if not custom_keybinds then return error(err) end + + local json = custom_keybinds:read("*a") + custom_keybinds:close() + + json = utils.parse_json(json) + if not json then return error("invalid json syntax for "..path) end + + for i, keybind in ipairs(json) do + keybind.name = "custom/"..(keybind.name or tostring(i)) + insert_custom_keybind(keybind) + end + end +end + +return { + setup_keybinds = setup_keybinds, +} diff --git a/mpv/scripts/file-browser/modules/navigation/cursor.lua b/mpv/scripts/file-browser/modules/navigation/cursor.lua new file mode 100644 index 0000000..c2a430f --- /dev/null +++ b/mpv/scripts/file-browser/modules/navigation/cursor.lua @@ -0,0 +1,121 @@ +-------------------------------------------------------------------------------------------------------- +--------------------------------Scroll/Select Implementation-------------------------------------------- +-------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------- + +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local ass = require 'modules.ass' + +local cursor = {} + +--disables multiselect +function cursor.disable_select_mode() + g.state.multiselect_start = nil + g.state.initial_selection = nil +end + +--enables multiselect +function cursor.enable_select_mode() + g.state.multiselect_start = g.state.selected + g.state.initial_selection = fb_utils.copy_table(g.state.selection) +end + +--calculates what drag behaviour is required for that specific movement +local function drag_select(original_pos, new_pos) + if original_pos == new_pos then return end + + local setting = g.state.selection[g.state.multiselect_start] + for i = original_pos, new_pos, (new_pos > original_pos and 1 or -1) do + --if we're moving the cursor away from the starting point then set the selection + --otherwise restore the original selection + if i > g.state.multiselect_start then + if new_pos > original_pos then + g.state.selection[i] = setting + elseif i ~= new_pos then + g.state.selection[i] = g.state.initial_selection[i] + end + elseif i < g.state.multiselect_start then + if new_pos < original_pos then + g.state.selection[i] = setting + elseif i ~= new_pos then + g.state.selection[i] = g.state.initial_selection[i] + end + end + end +end + +--moves the selector up and down the list by the entered amount +function cursor.scroll(n, wrap) + local num_items = #g.state.list + if num_items == 0 then return end + + local original_pos = g.state.selected + + if original_pos + n > num_items then + g.state.selected = wrap and 1 or num_items + elseif original_pos + n < 1 then + g.state.selected = wrap and num_items or 1 + else + g.state.selected = original_pos + n + end + + if g.state.multiselect_start then drag_select(original_pos, g.state.selected) end + ass.update_ass() +end + +--selects the first item in the list which is highlighted as playing +function cursor.select_playing_item() + for i,item in ipairs(g.state.list) do + if ass.highlight_entry(item) then + g.state.selected = i + return + end + end +end + +--scans the list for which item to select by default +--chooses the folder that the script just moved out of +--or, otherwise, the item highlighted as currently playing +function cursor.select_prev_directory() + if g.state.prev_directory:find(g.state.directory, 1, true) == 1 then + local i = 1 + while (g.state.list[i] and fb_utils.parseable_item(g.state.list[i])) do + if g.state.prev_directory:find(fb_utils.get_full_path(g.state.list[i]), 1, true) then + g.state.selected = i + return + end + i = i+1 + end + end + + cursor.select_playing_item() +end + +--toggles the selection +function cursor.toggle_selection() + if not g.state.list[g.state.selected] then return end + g.state.selection[g.state.selected] = not g.state.selection[g.state.selected] or nil + ass.update_ass() +end + +--select all items in the list +function cursor.select_all() + for i,_ in ipairs(g.state.list) do + g.state.selection[i] = true + end + ass.update_ass() +end + +--toggles select mode +function cursor.toggle_select_mode() + if g.state.multiselect_start == nil then + cursor.enable_select_mode() + cursor.toggle_selection() + else + cursor.disable_select_mode() + ass.update_ass() + end +end + +return cursor diff --git a/mpv/scripts/file-browser/modules/navigation/directory-movement.lua b/mpv/scripts/file-browser/modules/navigation/directory-movement.lua new file mode 100644 index 0000000..90834fc --- /dev/null +++ b/mpv/scripts/file-browser/modules/navigation/directory-movement.lua @@ -0,0 +1,86 @@ + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local ass = require 'modules.ass' +local cache = require 'modules.cache' +local scanning = require 'modules.navigation.scanning' +local fb_utils = require 'modules.utils' + +local directory_movement = {} + +function directory_movement.set_current_file(filepath) + --if we're in idle mode then we want to open the working directory + if filepath == nil then + g.current_file.directory = fb_utils.fix_path( mp.get_property("working-directory", ""), true) + g.current_file.name = nil + g.current_file.path = nil + return + end + + local absolute_path = fb_utils.absolute_path(filepath) + local resolved_path = fb_utils.resolve_directory_mapping(absolute_path) + + g.current_file.directory, g.current_file.name = utils.split_path(resolved_path) + g.current_file.original_path = absolute_path + g.current_file.path = resolved_path + + if not g.state.hidden then ass.update_ass() + else g.state.flag_update = true end +end + +--the base function for moving to a directory +function directory_movement.goto_directory(directory, moving_adjacent) + -- update cache to the lastest state values before changing the current directory + cache:add_current_state() + + local current = g.state.list[g.state.selected] + g.state.directory = directory + + if g.state.directory_label then + if moving_adjacent == 1 then + g.state.directory_label = g.state.directory_label..(current.label or current.name) + elseif moving_adjacent == -1 then + g.state.directory_label = string.match(g.state.directory_label, "^(.-/+)[^/]+/*$") + end + end + + return scanning.rescan(moving_adjacent or false) +end + +--loads the root list +function directory_movement.goto_root() + msg.verbose('jumping to root') + return directory_movement.goto_directory("") +end + +--switches to the directory of the currently playing file +function directory_movement.goto_current_dir() + msg.verbose('jumping to current directory') + return directory_movement.goto_directory(g.current_file.directory) +end + +--moves up a directory +function directory_movement.up_dir() + local parent_dir = g.state.directory:match("^(.-/+)[^/]+/*$") or "" + + if o.skip_protocol_schemes and parent_dir:find("^(%a[%w+-.]*)://$") then + return directory_movement.goto_root() + end + + return directory_movement.goto_directory(parent_dir, -1) +end + +--moves down a directory +function directory_movement.down_dir() + local current = g.state.list[g.state.selected] + if not current or not fb_utils.parseable_item(current) then return end + + local directory, redirected = fb_utils.get_new_directory(current, g.state.directory) + return directory_movement.goto_directory(directory, not redirected and 1) +end + +return directory_movement diff --git a/mpv/scripts/file-browser/modules/navigation/scanning.lua b/mpv/scripts/file-browser/modules/navigation/scanning.lua new file mode 100644 index 0000000..dc22567 --- /dev/null +++ b/mpv/scripts/file-browser/modules/navigation/scanning.lua @@ -0,0 +1,182 @@ +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local cache = require 'modules.cache' +local cursor = require 'modules.navigation.cursor' +local ass = require 'modules.ass' + +local parse_state_API = require 'modules.apis.parse-state' + +local function clear_non_adjacent_state() + g.state.directory_label = nil + cache:clear_traversal_stack() +end + +--parses the given directory or defers to the next parser if nil is returned +local function choose_and_parse(directory, index) + msg.debug(("finding parser for %q"):format(directory)) + local parser, list, opts + local parse_state = g.parse_states[coroutine.running() or ""] + while list == nil and not parse_state.already_deferred and index <= #g.parsers do + parser = g.parsers[index] + if parser:can_parse(directory, parse_state) then + msg.debug("attempting parser:", parser:get_id()) + list, opts = parser:parse(directory, parse_state) + end + index = index + 1 + end + if not list then return nil, {} end + + msg.debug("list returned from:", parser:get_id()) + opts = opts or {} + if list then opts.id = opts.id or parser:get_id() end + return list, opts +end + +--sets up the parse_state table and runs the parse operation +local function run_parse(directory, parse_state) + msg.verbose(("scanning files in %q"):format(directory)) + parse_state.directory = directory + + local co = coroutine.running() + g.parse_states[co] = setmetatable(parse_state, { __index = parse_state_API }) + + local list, opts = choose_and_parse(directory, 1) + + if list == nil then return msg.debug("no successful parsers found") end + opts.parser = g.parsers[opts.id] + + if not opts.filtered then fb_utils.filter(list) end + if not opts.sorted then fb_utils.sort(list) end + return list, opts +end + +--returns the contents of the given directory using the given parse state +--if a coroutine has already been used for a parse then create a new coroutine so that +--the every parse operation has a unique thread ID +local function parse_directory(directory, parse_state) + local co = fb_utils.coroutine.assert("scan_directory must be executed from within a coroutine - aborting scan "..utils.to_string(parse_state)) + if not g.parse_states[co] then return run_parse(directory, parse_state) end + + --if this coroutine is already is use by another parse operation then we create a new + --one and hand execution over to that + local new_co = coroutine.create(function() + fb_utils.coroutine.resume_err(co, run_parse(directory, parse_state)) + end) + + --queue the new coroutine on the mpv event queue + mp.add_timeout(0, function() + local success, err = coroutine.resume(new_co) + if not success then + fb_utils.traceback(err, new_co) + fb_utils.coroutine.resume_err(co) + end + end) + return g.parse_states[co]:yield() +end + +--sends update requests to the different parsers +local function update_list(moving_adjacent) + msg.verbose('opening directory: ' .. g.state.directory) + + g.state.selected = 1 + g.state.selection = {} + + --loads the current directry from the cache to save loading time + if cache:in_cache(g.state.directory) then + msg.verbose('found directory in cache') + cache:apply(g.state.directory) + g.state.prev_directory = g.state.directory + return + end + local directory = g.state.directory + local list, opts = parse_directory(g.state.directory, { source = "browser" }) + + --if the running coroutine isn't the one stored in the state variable, then the user + --changed directories while the coroutine was paused, and this operation should be aborted + if coroutine.running() ~= g.state.co then + msg.verbose(g.ABORT_ERROR.msg) + msg.debug("expected:", g.state.directory, "received:", directory) + return + end + + --apply fallbacks if the scan failed + if not list and cache:in_cache(g.state.prev_directory) then + --switches settings back to the previously opened directory + --to the user it will be like the directory never changed + msg.warn("could not read directory", g.state.directory) + cache:apply(g.state.prev_directory) + return + elseif not list then + --opens the root instead + msg.warn("could not read directory", g.state.directory, "redirecting to root") + list, opts = parse_directory("", { source = "browser" }) + + -- sets the directory redirect flag + opts.directory = '' + end + + g.state.list = list + g.state.parser = opts.parser + + --setting custom options from parsers + g.state.directory_label = opts.directory_label + g.state.empty_text = opts.empty_text or g.state.empty_text + + --we assume that directory is only changed when redirecting to a different location + --therefore we need to change the `moving_adjacent` flag and clear some state values + if opts.directory then + g.state.directory = opts.directory + moving_adjacent = false + clear_non_adjacent_state() + end + + if opts.selected_index then + g.state.selected = opts.selected_index or g.state.selected + if g.state.selected > #g.state.list then g.state.selected = #g.state.list + elseif g.state.selected < 1 then g.state.selected = 1 end + end + + if moving_adjacent then cursor.select_prev_directory() + else cursor.select_playing_item() end + g.state.prev_directory = g.state.directory +end + +--rescans the folder and updates the list +--returns the coroutine for the new parse operation +local function rescan(moving_adjacent) + if moving_adjacent == nil then moving_adjacent = 0 end + + --we can only make assumptions about the directory label when moving from adjacent directories + if not moving_adjacent then clear_non_adjacent_state() end + + g.state.empty_text = "~" + g.state.list = {} + cursor.disable_select_mode() + ass.update_ass() + + --the directory is always handled within a coroutine to allow addons to + --pause execution for asynchronous operations + g.state.co = fb_utils.coroutine.queue(function() + update_list(moving_adjacent) + if g.state.empty_text == "~" then g.state.empty_text = "empty directory" end + + cache:append_history() + if type(moving_adjacent) == 'number' and moving_adjacent < 0 then cache:pop() + else cache:push() end + if not cache.traversal_stack[1] then cache:push() end + + ass.update_ass() + end) + + return g.state.co +end + +return { + rescan = rescan, + scan_directory = parse_directory, + choose_and_parse = choose_and_parse, +} diff --git a/mpv/scripts/file-browser/modules/observers.lua b/mpv/scripts/file-browser/modules/observers.lua new file mode 100644 index 0000000..b7ba61b --- /dev/null +++ b/mpv/scripts/file-browser/modules/observers.lua @@ -0,0 +1,28 @@ + +local directory_movement = require 'modules.navigation.directory-movement' +local fb = require 'modules.apis.fb' +local fb_utils = require 'modules.utils' + +local observers ={} + +--saves the directory and name of the currently playing file +function observers.current_directory(_, filepath) + directory_movement.set_current_file(filepath) +end + +function observers.dvd_device(_, device) + if not device or device == "" then device = '/dev/dvd' end + fb.register_directory_mapping(fb_utils.absolute_path(device), '^dvd://.*', true) +end + +function observers.bd_device(_, device) + if not device or device == '' then device = '/dev/bd' end + fb.register_directory_mapping(fb_utils.absolute_path(device), '^bd://.*', true) +end + +function observers.cd_device(_, device) + if not device or device == '' then device = '/dev/cdrom' end + fb.register_directory_mapping(fb_utils.absolute_path(device), '^cdda://.*', true) +end + +return observers diff --git a/mpv/scripts/file-browser/modules/options.lua b/mpv/scripts/file-browser/modules/options.lua new file mode 100644 index 0000000..3e266fe --- /dev/null +++ b/mpv/scripts/file-browser/modules/options.lua @@ -0,0 +1,147 @@ +local utils = require 'mp.utils' +local opt = require 'mp.options' + +local o = { + --root directories + root = "~/", + + --characters to use as separators + root_separators = ",;", + + --number of entries to show on the screen at once + num_entries = 20, + + --wrap the cursor around the top and bottom of the list + wrap = false, + + --only show files compatible with mpv + filter_files = true, + + --experimental feature that recurses directories concurrently when + --appending items to the playlist + concurrent_recursion = false, + + --maximum number of recursions that can run concurrently + max_concurrency = 16, + + --enable custom keybinds + custom_keybinds = false, + + --blacklist compatible files, it's recommended to use this rather than to edit the + --compatible list directly. A semicolon separated list of extensions without spaces + extension_blacklist = "", + + --add extra file extensions + extension_whitelist = "", + + --files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist + audio_extensions = "mka,dts,dtshd,dts-hd,truehd,true-hd", + + --files with these extensions will be added as additional subtitle tracks instead of appended to the playlist + subtitle_extensions = "etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs", + + --filter dot directories like .config + --most useful on linux systems + filter_dot_dirs = false, + filter_dot_files = false, + + --substitude forward slashes for backslashes when appending a local file to the playlist + --potentially useful on windows systems + substitute_backslash = false, + + --interpret backslashes `\` in paths as forward slashes `/` + --this is useful on Windows, which natively uses backslashes. + --As backslashes are valid filename characters in Unix systems this could + --cause mangled paths, though such filenames are rare. + --Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform` + --property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`. + normalise_backslash = 'auto', + + --this option reverses the behaviour of the alt+ENTER keybind + --when disabled the keybind is required to enable autoload for the file + --when enabled the keybind disables autoload for the file + autoload = false, + + --if autoload is triggered by selecting the currently playing file, then + --the current file will have it's watch-later config saved before being closed + --essentially the current file will not be restarted + autoload_save_current = true, + + --when opening the browser in idle mode prefer the current working directory over the root + --note that the working directory is set as the 'current' directory regardless, so `home` will + --move the browser there even if this option is set to false + default_to_working_directory = false, + + --when moving up a directory do not stop on empty protocol schemes like `ftp://` + --e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://` + skip_protocol_schemes = true, + + --map optical device paths to their respective file paths, + --e.g. mapping bd:// to the value of the bluray-device property + map_bd_device = true, + map_dvd_device = true, + map_cdda_device = true, + + --allows custom icons be set for the folder and cursor + --the `\h` character is a hard space to add padding between the symbol and the text + folder_icon = [[{\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h]], + cursor_icon = [[{\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h]], + + --enable addons + addons = false, + addon_directory = "~~/script-modules/file-browser-addons", + + --directory to load external modules - currently just user-input-module + module_directory = "~~/script-modules", + + --turn the OSC idle screen off and on when opening and closing the browser + toggle_idlescreen = false, + + --Set the current open status of the browser in the `file_browser/open` field of the `user-data` property. + --This property is only available in mpv v0.36+. + set_user_data = true, + + --Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property. + --This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically ignore this option. + set_shared_script_properties = false, + + --force file-browser to use a specific text alignment (default: top-left) + --uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3 + --set to 0 to use the default mpv osd-align options + alignment = 7, + + --style settings + format_string_header = '%q\\N----------------------------------------------------', + format_string_topwrapper = '%< item(s) above\\N', + format_string_bottomwrapper = '\\N%> item(s) remaining', + + font_bold_header = true, + font_opacity_selection_marker = "99", + + scaling_factor_base = 1, + scaling_factor_header = 1.4, + scaling_factor_wrappers = 0.64, + + font_name_header = "", + font_name_body = "", + font_name_wrappers = "", + font_name_folder = "", + font_name_cursor = "", + + font_colour_header = "00ccff", + font_colour_body = "ffffff", + font_colour_wrappers = "00ccff", + font_colour_cursor = "00ccff", + + font_colour_multiselect = "fcad88", + font_colour_selected = "fce788", + font_colour_playing = "33ff66", + font_colour_playing_multiselected = "22b547" + +} + +opt.read_options(o, 'file_browser') + +o.set_shared_script_properties = o.set_shared_script_properties and utils.shared_script_property_set + +return o diff --git a/mpv/scripts/file-browser/modules/parsers/file.lua b/mpv/scripts/file-browser/modules/parsers/file.lua new file mode 100644 index 0000000..70ef46b --- /dev/null +++ b/mpv/scripts/file-browser/modules/parsers/file.lua @@ -0,0 +1,44 @@ +-- This file is an internal file-browser addon. +-- It should not be imported like a normal module. + +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +--parser object for native filesystems +local file_parser = { + name = "file", + priority = 110, + api_version = '1.0.0', +} + +--try to parse any directory except for the root +function file_parser:can_parse(directory) + return directory ~= '' +end + +--scans the given directory using the mp.utils.readdir function +function file_parser:parse(directory) + local new_list = {} + local list1 = utils.readdir(directory, 'dirs') + if list1 == nil then return nil end + + --sorts folders and formats them into the list of directories + for i=1, #list1 do + local item = list1[i] + + msg.trace(item..'/') + table.insert(new_list, {name = item..'/', type = 'dir'}) + end + + --appends files to the list of directory items + local list2 = utils.readdir(directory, 'files') + for i=1, #list2 do + local item = list2[i] + + msg.trace(item) + table.insert(new_list, {name = item, type = 'file'}) + end + return new_list +end + +return file_parser diff --git a/mpv/scripts/file-browser/modules/parsers/root.lua b/mpv/scripts/file-browser/modules/parsers/root.lua new file mode 100644 index 0000000..a2e92bb --- /dev/null +++ b/mpv/scripts/file-browser/modules/parsers/root.lua @@ -0,0 +1,25 @@ + +local g = require 'modules.globals' + +--parser object for the root +--not inserted to the parser list as it has special behaviour +--it does get added to parsers under its ID to prevent confusing duplicates +local root_parser = { + name = "root", + priority = math.huge, + api_version = '1.0.0', +} + +function root_parser:can_parse(directory) + return directory == '' +end + +--we return the root directory exactly as setup +function root_parser:parse() + return g.root, { + sorted = true, + filtered = true, + } +end + +return root_parser diff --git a/mpv/scripts/file-browser/modules/playlist.lua b/mpv/scripts/file-browser/modules/playlist.lua new file mode 100644 index 0000000..bf4124e --- /dev/null +++ b/mpv/scripts/file-browser/modules/playlist.lua @@ -0,0 +1,292 @@ +------------------------------------------------------------------------------------------ +---------------------------------File/Playlist Opening------------------------------------ +------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------ + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local ass = require 'modules.ass' +local cursor = require 'modules.navigation.cursor' +local controls = require 'modules.controls' +local scanning = require 'modules.navigation.scanning' +local movement = require 'modules.navigation.directory-movement' + +local state = g.state + +-- In mpv v0.38 a new index argument was added to the loadfile command. +-- For some crazy reason this new argument is placed before the existing options +-- argument, breaking any scripts that used it. This function finds the correct index +-- for the options argument using the `command-list` property. +local function get_loadfile_options_arg_index() + local command_list = mp.get_property_native('command-list', {}) + for _, command in ipairs(command_list) do + if command.name == 'loadfile' then + for i, arg in ipairs(command.args or {}) do + if arg.name == 'options' then + return i + end + end + end + end + + return 3 +end + +local LEGACY_LOADFILE_SYNTAX = get_loadfile_options_arg_index() == 3 + +-- A wrapper around loadfile to handle the syntax changes introduced in mpv v0.38. +local function legacy_loadfile_wrapper(file, flag, options) + if LEGACY_LOADFILE_SYNTAX then + return mp.command_native({"loadfile", file, flag, options}) + else + return mp.command_native({"loadfile", file, flag, -1, options}) + end +end + +--adds a file to the playlist and changes the flag to `append-play` in preparation +--for future items +local function loadfile(file, opts, mpv_opts) + if o.substitute_backslash and not fb_utils.get_protocol(file) then + file = file:gsub("/", "\\") + end + + if opts.flag == "replace" then msg.verbose("Playling file", file) + else msg.verbose("Appending", file, "to the playlist") end + + if mpv_opts then + msg.debug('Settings opts on', file, ':', utils.to_string(mpv_opts)) + end + + if not legacy_loadfile_wrapper(file, opts.flag, mpv_opts) then msg.warn(file) end + opts.flag = "append-play" + opts.items_appended = opts.items_appended + 1 +end + +--this function recursively loads directories concurrently in separate coroutines +--results are saved in a tree of tables that allows asynchronous access +local function concurrent_loadlist_parse(directory, load_opts, prev_dirs, item_t) + --prevents infinite recursion from the item.path or opts.directory fields + if prev_dirs[directory] then return end + prev_dirs[directory] = true + + local list, list_opts = scanning.scan_directory(directory, { source = "loadlist" }) + if list == g.root then return end + + --if we can't parse the directory then append it and hope mpv fares better + if list == nil then + msg.warn("Could not parse", directory, "appending to playlist anyway") + item_t.type = "file" + return + end + + directory = list_opts.directory or directory + if directory == "" then return end + + --we must declare these before we start loading sublists otherwise the append thread will + --need to wait until the whole list is loaded (when synchronous IO is used) + item_t._sublist = list or {} + list._directory = directory + + --launches new parse operations for directories, each in a different coroutine + for _, item in ipairs(list) do + if fb_utils.parseable_item(item) then + fb_utils.coroutine.run(concurrent_loadlist_wrapper, fb_utils.get_new_directory(item, directory), load_opts, prev_dirs, item) + end + end + return true +end + +--a wrapper function that ensures the concurrent_loadlist_parse is run correctly +function concurrent_loadlist_wrapper(directory, opts, prev_dirs, item) + --ensures that only a set number of concurrent parses are operating at any one time. + --the mpv event queue is seemingly limited to 1000 items, but only async mpv actions like + --command_native_async should use that, events like mp.add_timeout (which coroutine.sleep() uses) should + --be handled enturely on the Lua side with a table, which has a significantly larger maximum size. + while (opts.concurrency > o.max_concurrency) do + fb_utils.coroutine.sleep(0.1) + end + opts.concurrency = opts.concurrency + 1 + + local success = concurrent_loadlist_parse(directory, opts, prev_dirs, item) + opts.concurrency = opts.concurrency - 1 + if not success then item._sublist = {} end + if coroutine.status(opts.co) == "suspended" then fb_utils.coroutine.resume_err(opts.co) end +end + +--recursively appends items to the playlist, acts as a consumer to the previous functions producer; +--if the next directory has not been parsed this function will yield until the parse has completed +local function concurrent_loadlist_append(list, load_opts) + local directory = list._directory + + for _, item in ipairs(list) do + if not g.sub_extensions[ fb_utils.get_extension(item.name, "") ] + and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ] + then + while (not item._sublist and fb_utils.parseable_item(item)) do + coroutine.yield() + end + + if fb_utils.parseable_item(item) then + concurrent_loadlist_append(item._sublist, load_opts) + else + loadfile(fb_utils.get_full_path(item, directory), load_opts, item.mpv_options) + end + end + end +end + +--recursive function to load directories using the script custom parsers +--returns true if any items were appended to the playlist +local function custom_loadlist_recursive(directory, load_opts, prev_dirs) + --prevents infinite recursion from the item.path or opts.directory fields + if prev_dirs[directory] then return end + prev_dirs[directory] = true + + local list, opts = scanning.scan_directory(directory, { source = "loadlist" }) + if list == g.root then return end + + --if we can't parse the directory then append it and hope mpv fares better + if list == nil then + msg.warn("Could not parse", directory, "appending to playlist anyway") + loadfile(directory, load_opts.flag) + return true + end + + directory = opts.directory or directory + if directory == "" then return end + + for _, item in ipairs(list) do + if not g.sub_extensions[ fb_utils.get_extension(item.name, "") ] + and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ] + then + if fb_utils.parseable_item(item) then + custom_loadlist_recursive( fb_utils.get_new_directory(item, directory) , load_opts, prev_dirs) + else + local path = fb_utils.get_full_path(item, directory) + loadfile(path, load_opts, item.mpv_options) + end + end + end +end + + +--a wrapper for the custom_loadlist_recursive function +local function loadlist(item, opts) + local dir = fb_utils.get_full_path(item, opts.directory) + local num_items = opts.items_appended + + if o.concurrent_recursion then + item = fb_utils.copy_table(item) + opts.co = fb_utils.coroutine.assert() + opts.concurrency = 0 + + --we need the current coroutine to suspend before we run the first parse operation, so + --we schedule the coroutine to run on the mpv event queue + mp.add_timeout(0, function() + fb_utils.coroutine.run(concurrent_loadlist_wrapper, dir, opts, {}, item) + end) + concurrent_loadlist_append({item, _directory = opts.directory}, opts) + else + custom_loadlist_recursive(dir, opts, {}) + end + + if opts.items_appended == num_items then msg.warn(dir, "contained no valid files") end +end + +--load playlist entries before and after the currently playing file +local function autoload_dir(path, opts) + if o.autoload_save_current and path == g.current_file.path then + mp.commandv("write-watch-later-config") end + + --loads the currently selected file, clearing the playlist in the process + loadfile(path, opts) + + local pos = 1 + local file_count = 0 + for _,item in ipairs(state.list) do + if item.type == "file" + and not g.sub_extensions[ fb_utils.get_extension(item.name, "") ] + and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ] + then + local p = fb_utils.get_full_path(item) + + if p == path then pos = file_count + else loadfile( p, opts, item.mpv_options) end + + file_count = file_count + 1 + end + end + mp.commandv("playlist-move", 0, pos+1) +end + +--runs the loadfile or loadlist command +local function open_item(item, opts) + if fb_utils.parseable_item(item) then + return loadlist(item, opts) + end + + local path = fb_utils.get_full_path(item, opts.directory) + if g.sub_extensions[ fb_utils.get_extension(item.name, "") ] then + mp.commandv("sub-add", path, opts.flag == "replace" and "select" or "auto") + elseif g.audio_extensions[ fb_utils.get_extension(item.name, "") ] then + mp.commandv("audio-add", path, opts.flag == "replace" and "select" or "auto") + else + if opts.autoload then autoload_dir(path, opts) + else loadfile(path, opts, item.mpv_options) end + end +end + +--handles the open options as a coroutine +--once loadfile has been run we can no-longer guarantee synchronous execution - the state values may change +--therefore, we must ensure that any state values that could be used after a loadfile call are saved beforehand +local function open_file_coroutine(opts) + if not state.list[state.selected] then return end + if opts.flag == 'replace' then controls.close() end + + --we want to set the idle option to yes to ensure that if the first item + --fails to load then the player has a chance to attempt to load further items (for async append operations) + local idle = mp.get_property("idle", "once") + mp.set_property("idle", "yes") + + --handles multi-selection behaviour + if next(state.selection) then + local selection = fb_utils.sort_keys(state.selection) + --reset the selection after + state.selection = {} + + cursor.disable_select_mode() + ass.update_ass() + + --the currently selected file will be loaded according to the flag + --the flag variable will be switched to append once a file is loaded + for i=1, #selection do + open_item(selection[i], opts) + end + + else + local item = state.list[state.selected] + if opts.flag == "replace" then movement.down_dir() end + open_item(item, opts) + end + + if mp.get_property("idle") == "yes" then mp.set_property("idle", idle) end +end + +--opens the selelected file(s) +local function open_file(flag, autoload) + fb_utils.coroutine.run(open_file_coroutine, { + flag = flag, + autoload = (autoload ~= o.autoload and flag == "replace"), + directory = state.directory, + items_appended = 0 + }) +end + +return { + add_files = open_file, +} diff --git a/mpv/scripts/file-browser/modules/script-messages.lua b/mpv/scripts/file-browser/modules/script-messages.lua new file mode 100644 index 0000000..28c47af --- /dev/null +++ b/mpv/scripts/file-browser/modules/script-messages.lua @@ -0,0 +1,93 @@ +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' +local scanning = require 'modules.navigation.scanning' + +local script_messages = {} + +--allows other scripts to request directory contents from file-browser +function script_messages.get_directory_contents(directory, response_str) + fb_utils.coroutine.run(function() + if not directory then msg.error("did not receive a directory string"); return end + if not response_str then msg.error("did not receive a response string"); return end + + directory = mp.command_native({"expand-path", directory}, "") + if directory ~= "" then directory = fb_utils.fix_path(directory, true) end + msg.verbose(("recieved %q from 'get-directory-contents' script message - returning result to %q"):format(directory, response_str)) + + directory = fb_utils.resolve_directory_mapping(directory) + + local list, opts = scanning.scan_directory(directory, { source = "script-message" } ) + if opts then opts.API_VERSION = g.API_VERSION end + + local err + list, err = fb_utils.format_json_safe(list) + if not list then msg.error(err) end + + opts, err = fb_utils.format_json_safe(opts) + if not opts then msg.error(err) end + + mp.commandv("script-message", response_str, list or "", opts or "") + end) +end + +--a helper script message for custom keybinds +--substitutes any '=>' arguments for 'script-message' +--makes chaining script-messages much easier +function script_messages.chain(...) + local command = table.pack('script-message', ...) + for i, v in ipairs(command) do + if v == '=>' then command[i] = 'script-message' end + end + mp.commandv(table.unpack(command)) +end + +--a helper script message for custom keybinds +--sends a command after the specified delay +function script_messages.delay_command(delay, ...) + local command = table.pack(...) + local success, err = pcall(mp.add_timeout, fb_utils.evaluate_string('return '..delay), function() mp.commandv(table.unpack(command)) end) + if not success then return msg.error(err) end +end + +--a helper script message for custom keybinds +--sends a command only if the given expression returns true +function script_messages.conditional_command(condition, ...) + local command = table.pack(...) + fb_utils.coroutine.run(function() + if fb_utils.evaluate_string('return '..condition) == true then mp.commandv(table.unpack(command)) end + end) +end + +--a helper script message for custom keybinds +--extracts lua expressions from the command and evaluates them +--expressions must be surrounded by !{}. Another ! before the { will escape the evaluation +function script_messages.evaluate_expressions(...) + local args = table.pack(...) + fb_utils.coroutine.run(function() + for i, arg in ipairs(args) do + args[i] = arg:gsub('(!+)(%b{})', function(lead, expression) + if #lead % 2 == 0 then return string.rep('!', #lead/2)..expression end + + local eval = fb_utils.evaluate_string('return '..expression:sub(2, -2)) + return type(eval) == "table" and utils.to_string(eval) or tostring(eval) + end) + end + + mp.commandv(table.unpack(args)) + end) +end + +--a helper function for custom-keybinds +--concatenates the command arguments with newlines and runs the +--string as a statement of code +function script_messages.run_statement(...) + local statement = table.concat(table.pack(...), '\n') + fb_utils.coroutine.run(fb_utils.evaluate_string, statement) +end + +return script_messages diff --git a/mpv/scripts/file-browser/modules/setup.lua b/mpv/scripts/file-browser/modules/setup.lua new file mode 100644 index 0000000..6889baf --- /dev/null +++ b/mpv/scripts/file-browser/modules/setup.lua @@ -0,0 +1,52 @@ +local mp = require 'mp' + +local o = require 'modules.options' +local g = require 'modules.globals' +local fb_utils = require 'modules.utils' + +--sets up the compatible extensions list +local function setup_extensions_list() + --setting up subtitle extensions + for ext in fb_utils.iterate_opt(o.subtitle_extensions:lower()) do + g.sub_extensions[ext] = true + g.extensions[ext] = true + end + + --setting up audio extensions + for ext in fb_utils.iterate_opt(o.audio_extensions:lower()) do + g.audio_extensions[ext] = true + g.extensions[ext] = true + end + + --adding file extensions to the set + for _, ext in ipairs(g.compatible_file_extensions) do + g.extensions[ext] = true + end + + --adding extra extensions on the whitelist + for str in fb_utils.iterate_opt(o.extension_whitelist:lower()) do + g.extensions[str] = true + end + + --removing extensions that are in the blacklist + for str in fb_utils.iterate_opt(o.extension_blacklist:lower()) do + g.extensions[str] = nil + end +end + +--splits the string into a table on the separators +local function setup_root() + for str in fb_utils.iterate_opt(o.root) do + local path = mp.command_native({'expand-path', str}) + path = fb_utils.fix_path(path, true) + + local temp = {name = path, type = 'dir', label = str, ass = fb_utils.ass_escape(str, true)} + + g.root[#g.root+1] = temp + end +end + +return { + extensions_list = setup_extensions_list, + root = setup_root, +} diff --git a/mpv/scripts/file-browser/modules/utils.lua b/mpv/scripts/file-browser/modules/utils.lua new file mode 100644 index 0000000..743566c --- /dev/null +++ b/mpv/scripts/file-browser/modules/utils.lua @@ -0,0 +1,490 @@ +-------------------------------------------------------------------------------------------------------- +-----------------------------------------Utility Functions---------------------------------------------- +---------------------------------------Part of the addon API-------------------------------------------- +-------------------------------------------------------------------------------------------------------- + +local mp = require 'mp' +local msg = require 'mp.msg' +local utils = require 'mp.utils' + +local o = require 'modules.options' +local g = require 'modules.globals' + +local input_loaded, input = pcall(require, 'mp.input') +local user_input_loaded, user_input = pcall(require, 'user-input-module') + +--creates a table for the API functions +--adds one metatable redirect to prevent addon authors from accidentally breaking file-browser +local fb_utils = { API_VERSION = g.API_VERSION } + +fb_utils.list = {} +fb_utils.coroutine = {} + +--implements table.pack if on lua 5.1 +if not table.pack then + table.unpack = unpack +---@diagnostic disable-next-line: duplicate-set-field + function table.pack(...) + local t = {n = select("#", ...), ...} + return t + end +end + +-- returns the index of the given item in the table +-- return -1 if item does not exist +function fb_utils.list.indexOf(t, item, from_index) + for i = from_index or 1, #t, 1 do + if t[i] == item then return i end + end + return -1 +end + +--returns whether or not the given table contains an entry that +--causes the given function to evaluate to true +function fb_utils.list.some(t, fn) + for i, v in ipairs(t) do + if fn(v, i, t) then return true end + end + return false +end + +-- Creates a new table populated with the results of +-- calling a provided function on every element in t. +function fb_utils.list.map(t, fn) + local new_t = {} + for i, v in ipairs(t) do + new_t[i] = fn(v, i, t) + end + return new_t +end + +--prints an error message and a stack trace +--accepts an error object and optionally a coroutine +--can be passed directly to xpcall +function fb_utils.traceback(errmsg, co) + if co then + msg.warn(debug.traceback(co)) + else + msg.warn(debug.traceback("", 2)) + end + msg.error(errmsg) +end + +--returns a table that stores the given table t as the __index in its metatable +--creates a prototypally inherited table +function fb_utils.redirect_table(t) + return setmetatable({}, { __index = t }) +end + +function fb_utils.set_prototype(t, proto) + return setmetatable(t, { __index = proto }) +end + +--prints an error if a coroutine returns an error +--unlike the next function this one still returns the results of coroutine.resume() +function fb_utils.coroutine.resume_catch(...) + local returns = table.pack(coroutine.resume(...)) + if not returns[1] and returns[2] ~= g.ABORT_ERROR then + fb_utils.traceback(returns[2], select(1, ...)) + end + return table.unpack(returns, 1, returns.n) +end + +--resumes a coroutine and prints an error if it was not sucessful +function fb_utils.coroutine.resume_err(...) + local success, err = coroutine.resume(...) + if not success and err ~= g.ABORT_ERROR then + fb_utils.traceback(err, select(1, ...)) + end + return success +end + +--in lua 5.1 there is only one return value which will be nil if run from the main thread +--in lua 5.2 main will be true if running from the main thread +function fb_utils.coroutine.assert(err) + local co, main = coroutine.running() + assert(not main and co, err or "error - function must be executed from within a coroutine") + return co +end + +-- Creates a callback function to resume the current coroutine with the given time limit. +-- If the time limit expires the coroutine will be resumed. The first return value will be true +-- if the callback was resumed within the time limit and false otherwise. +-- If time_limit is falsy then there will be no time limit and there will be no additional return value. +function fb_utils.coroutine.callback(time_limit) + local co = fb_utils.coroutine.assert("cannot create a coroutine callback for the main thread") + local timer = time_limit and mp.add_timeout(time_limit, function () + msg.debug("time limit on callback expired") + fb_utils.coroutine.resume_err(co, false) + end) + return function(...) + if timer then + if not timer:is_enabled() then return + else timer:kill() end + return fb_utils.coroutine.resume_err(co, true, ...) + end + return fb_utils.coroutine.resume_err(co, ...) + end +end + +--puts the current coroutine to sleep for the given number of seconds +function fb_utils.coroutine.sleep(n) + mp.add_timeout(n, fb_utils.coroutine.callback()) + coroutine.yield() +end + + +--Runs the given function in a coroutine, passing through any additional arguments. +--Does not run the coroutine immediately, instead it ques the coroutine to run when the thread is next idle. +--Returns the coroutine object so that the caller can act on it before it is run. +function fb_utils.coroutine.queue(fn, ...) + local co = coroutine.create(fn) + local args = table.pack(...) + mp.add_timeout(0, function() fb_utils.coroutine.resume_err(co, table.unpack(args, 1, args.n)) end) + return co +end + +--runs the given function in a coroutine, passing through any additional arguments +--this is for triggering an event in a coroutine +function fb_utils.coroutine.run(fn, ...) + local co = coroutine.create(fn) + fb_utils.coroutine.resume_err(co, ...) +end + +--get the full path for the current file +function fb_utils.get_full_path(item, dir) + if item.path then return item.path end + return (dir or g.state.directory)..item.name +end + +--gets the path for a new subdirectory, redirects if the path field is set +--returns the new directory path and a boolean specifying if a redirect happened +function fb_utils.get_new_directory(item, directory) + if item.path and item.redirect ~= false then return item.path, true end + if directory == "" then return item.name end + if string.sub(directory, -1) == "/" then return directory..item.name end + return directory.."/"..item.name +end + +--returns the file extension of the given file +function fb_utils.get_extension(filename, def) + return string.lower(filename):match("%.([^%./]+)$") or def +end + +--returns the protocol scheme of the given url, or nil if there is none +function fb_utils.get_protocol(filename, def) + return string.lower(filename):match("^(%a[%w+-.]*)://") or def +end + +--formats strings for ass handling +--this function is based on a similar function from https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L110 +function fb_utils.ass_escape(str, replace_newline) + if replace_newline == true then replace_newline = "\\\239\187\191n" end + + --escape the invalid single characters + str = string.gsub(str, '[\\{}\n]', { + -- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if + -- it isn't followed by a recognised character, so add a zero-width + -- non-breaking space + ['\\'] = '\\\239\187\191', + ['{'] = '\\{', + ['}'] = '\\}', + -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of + -- consecutive newlines + ['\n'] = '\239\187\191\\N', + }) + + -- Turn leading spaces into hard spaces to prevent ASS from stripping them + str = str:gsub('\\N ', '\\N\\h') + str = str:gsub('^ ', '\\h') + + if replace_newline then + str = str:gsub("\\N", replace_newline) + end + return str +end + +--escape lua pattern characters +function fb_utils.pattern_escape(str) + return string.gsub(str, "([%^%$%(%)%%%.%[%]%*%+%-])", "%%%1") +end + +--standardises filepaths across systems +function fb_utils.fix_path(str, is_directory) + if str == '' then return str end + if o.normalise_backslash == 'yes' or (o.normalise_backslash == 'auto' and g.PLATFORM == 'windows') then + str = string.gsub(str, [[\]],[[/]]) + end + str = str:gsub([[/%./]], [[/]]) + if is_directory and str:sub(-1) ~= '/' then str = str..'/' end + return str +end + +--wrapper for utils.join_path to handle protocols +function fb_utils.join_path(working, relative) + return fb_utils.get_protocol(relative) and relative or utils.join_path(working, relative) +end + +--converts the given path into an absolute path and normalises it using fb_utils.fix_path +function fb_utils.absolute_path(path) + local absolute_path = fb_utils.join_path(mp.get_property('working-directory', ''), path) + return fb_utils.fix_path(absolute_path) +end + +--sorts the table lexicographically ignoring case and accounting for leading/non-leading zeroes +--the number format functionality was proposed by github user twophyro, and was presumably taken +--from here: http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua +function fb_utils.sort(t) + local function padnum(n, d) + return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d)) + or ("%03d%s"):format(#n, n) + end + + --appends the letter d or f to the start of the comparison to sort directories and folders as well + local tuples = {} + for i, f in ipairs(t) do + tuples[i] = {f.type:sub(1, 1) .. (f.label or f.name):lower():gsub("0*(%d+)%.?(%d*)", padnum), f} + end + table.sort(tuples, function(a, b) + return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1] + end) + for i, tuple in ipairs(tuples) do t[i] = tuple[2] end + return t +end + +function fb_utils.valid_dir(dir) + if o.filter_dot_dirs and string.sub(dir, 1, 1) == "." then return false end + return true +end + +function fb_utils.valid_file(file) + if o.filter_dot_files and (string.sub(file, 1, 1) == ".") then return false end + if o.filter_files and not g.extensions[ fb_utils.get_extension(file, "") ] then return false end + return true +end + +--returns whether or not the item can be parsed +function fb_utils.parseable_item(item) + return item.type == "dir" or g.parseable_extensions[fb_utils.get_extension(item.name, "")] +end + +-- Takes a directory string and resolves any directory mappings, +-- returning the resolved directory. +function fb_utils.resolve_directory_mapping(path) + if not path then return path end + + for mapping, target in pairs(g.directory_mappings) do + local start, finish = string.find(path, mapping) + if start then + msg.debug('mapping', mapping, 'found for', path, 'changing to', target) + + -- if the mapping is an exact match then return the target as is + if finish == #path then return target end + + -- else make sure the path is correctly formatted + target = fb_utils.fix_path(target, true) + return string.gsub(path, mapping, target) + end + end + + return path +end + +--removes items and folders from the list +--this is for addons which can't filter things during their normal processing +function fb_utils.filter(t) + local max = #t + local top = 1 + for i = 1, max do + local temp = t[i] + t[i] = nil + + if ( temp.type == "dir" and fb_utils.valid_dir(temp.label or temp.name) ) or + ( temp.type == "file" and fb_utils.valid_file(temp.label or temp.name) ) + then + t[top] = temp + top = top+1 + end + end + return t +end + +--returns a string iterator that uses the root separators +function fb_utils.iterate_opt(str) + return string.gmatch(str, "([^"..fb_utils.pattern_escape(o.root_separators).."]+)") +end + +--sorts a table into an array of selected items in the correct order +--if a predicate function is passed, then the item will only be added to +--the table if the function returns true +function fb_utils.sort_keys(t, include_item) + local keys = {} + for k in pairs(t) do + local item = g.state.list[k] + if not include_item or include_item(item) then + item.index = k + keys[#keys+1] = item + end + end + + table.sort(keys, function(a,b) return a.index < b.index end) + return keys +end + +--Uses a loop to get the length of an array. The `#` operator is undefined if there +--are gaps in the array, this ensures there are none as expected by the mpv node function. +local function get_length(t) + local i = 1 + while t[i] do i = i+1 end + return i - 1 +end + +--recursively removes elements of the table which would cause +--utils.format_json to throw an error +local function json_safe_recursive(t) + if type(t) ~= "table" then return t end + + local array_length = get_length(t) + local isarray = array_length > 0 + + for key, value in pairs(t) do + local ktype = type(key) + local vtype = type(value) + + if vtype ~= "userdata" and vtype ~= "function" and vtype ~= "thread" + and (( isarray and ktype == "number" and key <= array_length) + or (not isarray and ktype == "string")) + then + t[key] = json_safe_recursive(t[key]) + elseif key then + t[key] = nil + if isarray then array_length = get_length(t) end + end + end + return t +end + +--formats a table into a json string but ensures there are no invalid datatypes inside the table first +function fb_utils.format_json_safe(t) + --operate on a copy of the table to prevent any data loss in the original table + t = json_safe_recursive(fb_utils.copy_table(t)) + local success, result, err = pcall(utils.format_json, t) + if success then return result, err + else return nil, result end +end + +--evaluates and runs the given string in both Lua 5.1 and 5.2 +--the name argument is used for error reporting +--provides the mpv modules and the fb module to the string +function fb_utils.evaluate_string(str, chunkname, custom_env, env_defaults) + local env + if env_defaults ~= false then + env = fb_utils.redirect_table(_G) + env.mp = fb_utils.redirect_table(mp) + env.msg = fb_utils.redirect_table(msg) + env.utils = fb_utils.redirect_table(utils) + env.fb = fb_utils.redirect_table(fb_utils) + env.input = input_loaded and fb_utils.redirect_table(input) + env.user_input = user_input_loaded and fb_utils.redirect_table(user_input) + env = fb_utils.set_prototype(custom_env or {}, env) + else + env = custom_env or {} + end + + local chunk, err + if setfenv then + chunk, err = loadstring(str, chunkname) + if chunk then setfenv(chunk, env) end + else + chunk, err = load(str, chunkname, 't', env) + end + if not chunk then + msg.warn('failed to load string:', str) + msg.error(err) + chunk = function() return nil end + end + + return chunk() +end + +--copies a table without leaving any references to the original +--uses a structured clone algorithm to maintain cyclic references +local function copy_table_recursive(t, references, depth) + if type(t) ~= "table" or depth == 0 then return t end + if references[t] then return references[t] end + + local copy = setmetatable({}, { __original = t }) + references[t] = copy + + for key, value in pairs(t) do + key = copy_table_recursive(key, references, depth - 1) + copy[key] = copy_table_recursive(value, references, depth - 1) + end + return copy +end + +--a wrapper around copy_table to provide the reference table +function fb_utils.copy_table(t, depth) + --this is to handle cyclic table references + return copy_table_recursive(t, {}, depth or math.huge) +end + +--functions to replace custom-keybind codes +fb_utils.code_fns = { + ["%"] = "%", + + f = function(item, s) return item and fb_utils.get_full_path(item, s.directory) or "" end, + n = function(item, s) return item and (item.label or item.name) or "" end, + i = function(item, s) + local i = fb_utils.list.indexOf(s.list, item) + return i ~= -1 and ('%0'..math.ceil(math.log10(#s.list))..'d'):format(i) or 0 + end, + j = function (item, s) + return fb_utils.list.indexOf(s.list, item) ~= -1 and math.abs(fb_utils.list.indexOf( fb_utils.sort_keys(s.selection) , item)) or 0 + end, + x = function(_, s) return #s.list or 0 end, + p = function(_, s) return s.directory or "" end, + q = function(_, s) return s.directory == '' and 'ROOT' or s.directory_label or s.directory or "" end, + d = function(_, s) return (s.directory_label or s.directory):match("([^/]+)/?$") or "" end, + r = function(_, s) return s.parser.keybind_name or s.parser.name or "" end, +} + +-- programatically creates a pattern that matches any key code +-- this will result in some duplicates but that shouldn't really matter +function fb_utils.get_code_pattern(codes) + local CUSTOM_KEYBIND_CODES = "" + for key in pairs(codes) do CUSTOM_KEYBIND_CODES = CUSTOM_KEYBIND_CODES..key:lower()..key:upper() end + for key in pairs((getmetatable(codes) or {}).__index or {}) do CUSTOM_KEYBIND_CODES = CUSTOM_KEYBIND_CODES..key:lower()..key:upper() end + return('%%%%([%s])'):format(fb_utils.pattern_escape(CUSTOM_KEYBIND_CODES)) +end + +-- substitutes codes in the given string for other substrings +-- overrides is a map of characters->strings|functions that determines the replacement string is +-- item and state are values passed to functions in the map +-- modifier_fn is given the replacement substrings before they are placed in the main string (the return value is the new replacement string) +function fb_utils.substitute_codes(str, overrides, item, state, modifier_fn) + local replacers = overrides and setmetatable(fb_utils.copy_table(overrides), {__index = fb_utils.code_fns}) or fb_utils.code_fns + item = item or g.state.list[g.state.selected] + state = state or g.state + + return (string.gsub(str, fb_utils.get_code_pattern(replacers), function(code) + local result + + if type(replacers[code]) == "string" then + result = replacers[code] + --encapsulates the string if using an uppercase code + elseif not replacers[code] then + local lower_fn = replacers[code:lower()] + if not lower_fn then return end + result = string.format("%q", lower_fn(item, state)) + else + result = replacers[code](item, state) + end + + if modifier_fn then return modifier_fn(result) end + return result + end)) +end + + +return fb_utils diff --git a/mpv/scripts/file-browser/screenshots/bunny.png b/mpv/scripts/file-browser/screenshots/bunny.png new file mode 100644 index 0000000..589e5bb Binary files /dev/null and b/mpv/scripts/file-browser/screenshots/bunny.png differ diff --git a/mpv/scripts/file-browser/screenshots/front.png b/mpv/scripts/file-browser/screenshots/front.png new file mode 100644 index 0000000..35a0826 Binary files /dev/null and b/mpv/scripts/file-browser/screenshots/front.png differ diff --git a/mpv/scripts/lastopen.lua b/mpv/scripts/lastopen.lua new file mode 100644 index 0000000..5025649 --- /dev/null +++ b/mpv/scripts/lastopen.lua @@ -0,0 +1,97 @@ +local utils = require 'mp.utils' +local lastopenFileName = "lastopen.json" + +local styleOn = mp.get_property("osd-ass-cc/0") +local styleOff = mp.get_property("osd-ass-cc/1") + + +-- Check if the operating system is Windows +function isWindows() + local windir = os.getenv("windir") + return (windir~=nil) +end + + +-- Get the filepath of a file from the mpv config folder +local function getFilepath(filename) + if isWindows() then + return os.getenv("APPDATA"):gsub("\\", "/") .. "/mpv/" .. filename + else + return os.getenv("HOME") .. "/.config/mpv/" .. filename + end +end + + +local options = { + path = getFilepath(lastopenFileName) +} + +-- Save a table as a JSON file file +-- Returns true if successful +function saveTable(t, path) + local contents = utils.format_json(t) + local file = io.open(path .. ".tmp", "wb") + file:write(contents) + io.close(file) + os.remove(path) + os.rename(path .. ".tmp", path) + return true +end + +function file_exists(path) + local file = io.open(path, "r") -- Try to open the file in read mode + if file then + file:close() -- Close the file if it was successfully opened + return true + else + return false + end +end + +local function save_data() + local data = { + path = mp.get_property('path'), + time_pos = mp.get_property_number('time-pos') + } + saveTable(data, options.path) +end + +function loadData(path) + local contents = "" + local myTable = {} + local file = io.open( path, "r" ) + if file then + local contents = file:read( "*a" ) + myTable = utils.parse_json(contents); + io.close(file) + return myTable + end + return nil +end + +-- Parses a Windows path with backslashes to one with normal slashes +function parsePath(path) + if type(path) == "string" then path, _ = path:gsub("\\", "/") end + return path +end + +local function load_data() + local data = loadData(getFilepath(lastopenFileName)) + if data then + if data.path and file_exists(data.path) then + mp.commandv("loadfile", parsePath(data.path), "replace", -1) + local message = styleOn.."{\\b1}Last Open load:\n"..data.path.."{\\b0}"..styleOff + mp.osd_message(message) + elseif not file_exists(data.path) then + mp.osd_message('File not found: '..data.path) + else + mp.osd_message('Failed to parse lastopen.json') + end + else + mp.osd_message('No lastopen.json found') + end +end + +mp.register_event('start-file', save_data) + +mp.register_script_message("lastopen", load_data) diff --git a/mpv/scripts/mpv_thumbnail_script_server.lua b/mpv/scripts/mpv_thumbnail_script_server.lua new file mode 100644 index 0000000..0085ea0 --- /dev/null +++ b/mpv/scripts/mpv_thumbnail_script_server.lua @@ -0,0 +1,736 @@ +--[[ + Copyright (C) 2017 AMM + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]]-- +--[[ + mpv_thumbnail_script.lua 0.4.3 - commit 682becf (branch master) + https://github.com/TheAMM/mpv_thumbnail_script + Built on 2020-01-17 00:00:00 +]]-- +local assdraw = require 'mp.assdraw' +local msg = require 'mp.msg' +local opt = require 'mp.options' +local utils = require 'mp.utils' + +-- Determine platform -- +ON_WINDOWS = (package.config:sub(1,1) ~= '/') + +-- Some helper functions needed to parse the options -- +function isempty(v) return (v == false) or (v == nil) or (v == "") or (v == 0) or (type(v) == "table" and next(v) == nil) end + +function divmod (a, b) + return math.floor(a / b), a % b +end + +-- Better modulo +function bmod( i, N ) + return (i % N + N) % N +end + +function join_paths(...) + local sep = ON_WINDOWS and "\\" or "/" + local result = ""; + for i, p in pairs({...}) do + if p ~= "" then + if is_absolute_path(p) then + result = p + else + result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p + end + end + end + return result:gsub("[\\"..sep.."]*$", "") +end + +-- /some/path/file.ext -> /some/path, file.ext +function split_path( path ) + local sep = ON_WINDOWS and "\\" or "/" + local first_index, last_index = path:find('^.*' .. sep) + + if last_index == nil then + return "", path + else + local dir = path:sub(0, last_index-1) + local file = path:sub(last_index+1, -1) + + return dir, file + end +end + +function is_absolute_path( path ) + local tmp, is_win = path:gsub("^[A-Z]:\\", "") + local tmp, is_unix = path:gsub("^/", "") + return (is_win > 0) or (is_unix > 0) +end + +function Set(source) + local set = {} + for _, l in ipairs(source) do set[l] = true end + return set +end + +--------------------------- +-- More helper functions -- +--------------------------- + +-- Removes all keys from a table, without destroying the reference to it +function clear_table(target) + for key, value in pairs(target) do + target[key] = nil + end +end +function shallow_copy(target) + local copy = {} + for k, v in pairs(target) do + copy[k] = v + end + return copy +end + +-- Rounds to given decimals. eg. round_dec(3.145, 0) => 3 +function round_dec(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end + +function file_exists(name) + local f = io.open(name, "rb") + if f ~= nil then + local ok, err, code = f:read(1) + io.close(f) + return code == nil + else + return false + end +end + +function path_exists(name) + local f = io.open(name, "rb") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +function create_directories(path) + local cmd + if ON_WINDOWS then + cmd = { args = {"cmd", "/c", "mkdir", path} } + else + cmd = { args = {"mkdir", "-p", path} } + end + utils.subprocess(cmd) +end + +-- Find an executable in PATH or CWD with the given name +function find_executable(name) + local delim = ON_WINDOWS and ";" or ":" + + local pwd = os.getenv("PWD") or utils.getcwd() + local path = os.getenv("PATH") + + local env_path = pwd .. delim .. path -- Check CWD first + + local result, filename + for path_dir in env_path:gmatch("[^"..delim.."]+") do + filename = join_paths(path_dir, name) + if file_exists(filename) then + result = filename + break + end + end + + return result +end + +local ExecutableFinder = { path_cache = {} } +-- Searches for an executable and caches the result if any +function ExecutableFinder:get_executable_path( name, raw_name ) + name = ON_WINDOWS and not raw_name and (name .. ".exe") or name + + if self.path_cache[name] == nil then + self.path_cache[name] = find_executable(name) or false + end + return self.path_cache[name] +end + +-- Format seconds to HH.MM.SS.sss +function format_time(seconds, sep, decimals) + decimals = decimals == nil and 3 or decimals + sep = sep and sep or "." + local s = seconds + local h, s = divmod(s, 60*60) + local m, s = divmod(s, 60) + + local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals) + + return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s) +end + +-- Format seconds to 1h 2m 3.4s +function format_time_hms(seconds, sep, decimals, force_full) + decimals = decimals == nil and 1 or decimals + sep = sep ~= nil and sep or " " + + local s = seconds + local h, s = divmod(s, 60*60) + local m, s = divmod(s, 60) + + if force_full or h > 0 then + return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s) + elseif m > 0 then + return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s) + else + return string.format("%." .. tostring(decimals) .. "fs", s) + end +end + +-- Writes text on OSD and console +function log_info(txt, timeout) + timeout = timeout or 1.5 + msg.info(txt) + mp.osd_message(txt, timeout) +end + +-- Join table items, ala ({"a", "b", "c"}, "=", "-", ", ") => "=a-, =b-, =c-" +function join_table(source, before, after, sep) + before = before or "" + after = after or "" + sep = sep or ", " + local result = "" + for i, v in pairs(source) do + if not isempty(v) then + local part = before .. v .. after + if i == 1 then + result = part + else + result = result .. sep .. part + end + end + end + return result +end + +function wrap(s, char) + char = char or "'" + return char .. s .. char +end +-- Wraps given string into 'string' and escapes any 's in it +function escape_and_wrap(s, char, replacement) + char = char or "'" + replacement = replacement or "\\" .. char + return wrap(string.gsub(s, char, replacement), char) +end +-- Escapes single quotes in a string and wraps the input in single quotes +function escape_single_bash(s) + return escape_and_wrap(s, "'", "'\\''") +end + +-- Returns (a .. b) if b is not empty or nil +function joined_or_nil(a, b) + return not isempty(b) and (a .. b) or nil +end + +-- Put items from one table into another +function extend_table(target, source) + for i, v in pairs(source) do + table.insert(target, v) + end +end + +-- Creates a handle and filename for a temporary random file (in current directory) +function create_temporary_file(base, mode, suffix) + local handle, filename + suffix = suffix or "" + while true do + filename = base .. tostring(math.random(1, 5000)) .. suffix + handle = io.open(filename, "r") + if not handle then + handle = io.open(filename, mode) + break + end + io.close(handle) + end + return handle, filename +end + + +function get_processor_count() + local proc_count + + if ON_WINDOWS then + proc_count = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + local cpuinfo_handle = io.open("/proc/cpuinfo") + if cpuinfo_handle ~= nil then + local cpuinfo_contents = cpuinfo_handle:read("*a") + local _, replace_count = cpuinfo_contents:gsub('processor', '') + proc_count = replace_count + end + end + + if proc_count and proc_count > 0 then + return proc_count + else + return nil + end +end + +function substitute_values(string, values) + local substitutor = function(match) + if match == "%" then + return "%" + else + -- nil is discarded by gsub + return values[match] + end + end + + local substituted = string:gsub('%%(.)', substitutor) + return substituted +end + +-- ASS HELPERS -- +function round_rect_top( ass, x0, y0, x1, y1, r ) + local c = 0.551915024494 * r -- circle approximation + ass:move_to(x0 + r, y0) + ass:line_to(x1 - r, y0) -- top line + if r > 0 then + ass:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) -- top right corner + end + ass:line_to(x1, y1) -- right line + ass:line_to(x0, y1) -- bottom line + ass:line_to(x0, y0 + r) -- left line + if r > 0 then + ass:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) -- top left corner + end +end + +function round_rect(ass, x0, y0, x1, y1, rtl, rtr, rbr, rbl) + local c = 0.551915024494 + ass:move_to(x0 + rtl, y0) + ass:line_to(x1 - rtr, y0) -- top line + if rtr > 0 then + ass:bezier_curve(x1 - rtr + rtr*c, y0, x1, y0 + rtr - rtr*c, x1, y0 + rtr) -- top right corner + end + ass:line_to(x1, y1 - rbr) -- right line + if rbr > 0 then + ass:bezier_curve(x1, y1 - rbr + rbr*c, x1 - rbr + rbr*c, y1, x1 - rbr, y1) -- bottom right corner + end + ass:line_to(x0 + rbl, y1) -- bottom line + if rbl > 0 then + ass:bezier_curve(x0 + rbl - rbl*c, y1, x0, y1 - rbl + rbl*c, x0, y1 - rbl) -- bottom left corner + end + ass:line_to(x0, y0 + rtl) -- left line + if rtl > 0 then + ass:bezier_curve(x0, y0 + rtl - rtl*c, x0 + rtl - rtl*c, y0, x0 + rtl, y0) -- top left corner + end +end +local SCRIPT_NAME = "mpv_thumbnail_script" + +local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/" + +local thumbnailer_options = { + -- The thumbnail directory + cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"), + + ------------------------ + -- Generation options -- + ------------------------ + + -- Automatically generate the thumbnails on video load, without a keypress + autogenerate = true, + + -- Only automatically thumbnail videos shorter than this (seconds) + autogenerate_max_duration = 3600, -- 1 hour + + -- SHA1-sum filenames over this length + -- It's nice to know what files the thumbnails are (hence directory names) + -- but long URLs may approach filesystem limits. + hash_filename_length = 128, + + -- Use mpv to generate thumbnail even if ffmpeg is found in PATH + -- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)! + -- mpv is a bit slower, but has better support overall (eg. subtitles in the previews) + prefer_mpv = true, + + -- Explicitly disable subtitles on the mpv sub-calls + mpv_no_sub = false, + -- Add a "--no-config" to the mpv sub-call arguments + mpv_no_config = false, + -- Add a "--profile=" to the mpv sub-call arguments + -- Use "" to disable + mpv_profile = "", + -- Output debug logs to .log, ala //000000.bgra.log + -- The logs are removed after successful encodes, unless you set mpv_keep_logs below + mpv_logs = true, + -- Keep all mpv logs, even the succesfull ones + mpv_keep_logs = false, + + -- Disable the built-in keybind ("T") to add your own + disable_keybinds = false, + + --------------------- + -- Display options -- + --------------------- + + -- Move the thumbnail up or down + -- For example: + -- topbar/bottombar: 24 + -- rest: 0 + vertical_offset = 24, + + -- Adjust background padding + -- Examples: + -- topbar: 0, 10, 10, 10 + -- bottombar: 10, 0, 10, 10 + -- slimbox/box: 10, 10, 10, 10 + pad_top = 10, + pad_bot = 0, + pad_left = 10, + pad_right = 10, + + -- If true, pad values are screen-pixels. If false, video-pixels. + pad_in_screenspace = true, + -- Calculate pad into the offset + offset_by_pad = true, + + -- Background color in BBGGRR + background_color = "000000", + -- Alpha: 0 - fully opaque, 255 - transparent + background_alpha = 80, + + -- Keep thumbnail on the screen near left or right side + constrain_to_screen = true, + + -- Do not display the thumbnailing progress + hide_progress = false, + + ----------------------- + -- Thumbnail options -- + ----------------------- + + -- The maximum dimensions of the thumbnails (pixels) + thumbnail_width = 200, + thumbnail_height = 200, + + -- The thumbnail count target + -- (This will result in a thumbnail every ~10 seconds for a 25 minute video) + thumbnail_count = 150, + + -- The above target count will be adjusted by the minimum and + -- maximum time difference between thumbnails. + -- The thumbnail_count will be used to calculate a target separation, + -- and min/max_delta will be used to constrict it. + + -- In other words, thumbnails will be: + -- at least min_delta seconds apart (limiting the amount) + -- at most max_delta seconds apart (raising the amount if needed) + min_delta = 5, + -- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours! + max_delta = 90, + + + -- Overrides for remote urls (you generally want less thumbnails!) + -- Thumbnailing network paths will be done with mpv + + -- Allow thumbnailing network paths (naive check for "://") + thumbnail_network = false, + -- Override thumbnail count, min/max delta + remote_thumbnail_count = 60, + remote_min_delta = 15, + remote_max_delta = 120, + + -- Try to grab the raw stream and disable ytdl for the mpv subcalls + -- Much faster than passing the url to ytdl again, but may cause problems with some sites + remote_direct_stream = true, +} + +read_options(thumbnailer_options, SCRIPT_NAME) +function skip_nil(tbl) + local n = {} + for k, v in pairs(tbl) do + table.insert(n, v) + end + return n +end + +function create_thumbnail_mpv(file_path, timestamp, size, output_path, options) + options = options or {} + + local ytdl_disabled = not options.enable_ytdl and (mp.get_property_native("ytdl") == false + or thumbnailer_options.remote_direct_stream) + + local header_fields_arg = nil + local header_fields = mp.get_property_native("http-header-fields") + if #header_fields > 0 then + -- We can't escape the headers, mpv won't parse "--http-header-fields='Name: value'" properly + header_fields_arg = "--http-header-fields=" .. table.concat(header_fields, ",") + end + + local profile_arg = nil + if thumbnailer_options.mpv_profile ~= "" then + profile_arg = "--profile=" .. thumbnailer_options.mpv_profile + end + + local log_arg = "--log-file=" .. output_path .. ".log" + + local mpv_command = skip_nil({ + "mpv", + -- Hide console output + "--msg-level=all=no", + + -- Disable ytdl + (ytdl_disabled and "--no-ytdl" or nil), + -- Pass HTTP headers from current instance + header_fields_arg, + -- Pass User-Agent and Referer - should do no harm even with ytdl active + "--user-agent=" .. mp.get_property_native("user-agent"), + "--referrer=" .. mp.get_property_native("referrer"), + -- Disable hardware decoding + "--hwdec=no", + + -- Insert --no-config, --profile=... and --log-file if enabled + (thumbnailer_options.mpv_no_config and "--no-config" or nil), + profile_arg, + (thumbnailer_options.mpv_logs and log_arg or nil), + + file_path, + + "--start=" .. tostring(timestamp), + "--frames=1", + "--hr-seek=yes", + "--no-audio", + -- Optionally disable subtitles + (thumbnailer_options.mpv_no_sub and "--no-sub" or nil), + + ("--vf=scale=%d:%d"):format(size.w, size.h), + "--vf-add=format=bgra", + "--of=rawvideo", + "--ovc=rawvideo", + "--o=" .. output_path + }) + return utils.subprocess({args=mpv_command}) +end + + +function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path) + local ffmpeg_command = { + "ffmpeg", + "-loglevel", "quiet", + "-noaccurate_seek", + "-ss", format_time(timestamp, ":"), + "-i", file_path, + + "-frames:v", "1", + "-an", + + "-vf", ("scale=%d:%d"):format(size.w, size.h), + "-c:v", "rawvideo", + "-pix_fmt", "bgra", + "-f", "rawvideo", + + "-y", output_path + } + return utils.subprocess({args=ffmpeg_command}) +end + + +function check_output(ret, output_path, is_mpv) + local log_path = output_path .. ".log" + local success = true + + if ret.killed_by_us then + return nil + else + if ret.error or ret.status ~= 0 then + msg.error("Thumbnailing command failed!") + msg.error("mpv process error:", ret.error) + msg.error("Process stdout:", ret.stdout) + if is_mpv then + msg.error("Debug log:", log_path) + end + + success = false + end + + if not file_exists(output_path) then + msg.error("Output file missing!", output_path) + success = false + end + end + + if is_mpv and not thumbnailer_options.mpv_keep_logs then + -- Remove successful debug logs + if success and file_exists(log_path) then + os.remove(log_path) + end + end + + return success +end + + +function do_worker_job(state_json_string, frames_json_string) + msg.debug("Handling given job") + local thumb_state, err = utils.parse_json(state_json_string) + if err then + msg.error("Failed to parse state JSON") + return + end + + local thumbnail_indexes, err = utils.parse_json(frames_json_string) + if err then + msg.error("Failed to parse thumbnail frame indexes") + return + end + + local thumbnail_func = create_thumbnail_mpv + if not thumbnailer_options.prefer_mpv then + if ExecutableFinder:get_executable_path("ffmpeg") then + thumbnail_func = create_thumbnail_ffmpeg + else + msg.warn("Could not find ffmpeg in PATH! Falling back on mpv.") + end + end + + local file_duration = mp.get_property_native("duration") + local file_path = thumb_state.worker_input_path + + if thumb_state.is_remote then + if (thumbnail_func == create_thumbnail_ffmpeg) then + msg.warn("Thumbnailing remote path, falling back on mpv.") + end + thumbnail_func = create_thumbnail_mpv + end + + local generate_thumbnail_for_index = function(thumbnail_index) + -- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state + local thumb_idx = thumbnail_index - 1 + msg.debug("Starting work on thumbnail", thumb_idx) + + local thumbnail_path = thumb_state.thumbnail_template:format(thumb_idx) + -- Grab the "middle" of the thumbnail duration instead of the very start, and leave some margin in the end + local timestamp = math.min(file_duration - 0.25, (thumb_idx + 0.5) * thumb_state.thumbnail_delta) + + mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index)) + + -- The expected size (raw BGRA image) + local thumbnail_raw_size = (thumb_state.thumbnail_size.w * thumb_state.thumbnail_size.h * 4) + + local need_thumbnail_generation = false + + -- Check if the thumbnail already exists and is the correct size + local thumbnail_file = io.open(thumbnail_path, "rb") + if thumbnail_file == nil then + need_thumbnail_generation = true + else + local existing_thumbnail_filesize = thumbnail_file:seek("end") + if existing_thumbnail_filesize ~= thumbnail_raw_size then + -- Size doesn't match, so (re)generate + msg.warn("Thumbnail", thumb_idx, "did not match expected size, regenerating") + need_thumbnail_generation = true + end + thumbnail_file:close() + end + + if need_thumbnail_generation then + local ret = thumbnail_func(file_path, timestamp, thumb_state.thumbnail_size, thumbnail_path, thumb_state.worker_extra) + local success = check_output(ret, thumbnail_path, thumbnail_func == create_thumbnail_mpv) + + if success == nil then + -- Killed by us, changing files, ignore + msg.debug("Changing files, subprocess killed") + return true + elseif not success then + -- Real failure + mp.osd_message("Thumbnailing failed, check console for details", 3.5) + return true + end + else + msg.debug("Thumbnail", thumb_idx, "already done!") + end + + -- Verify thumbnail size + -- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end) + thumbnail_file = io.open(thumbnail_path, "rb") + + -- Bail if we can't read the file (it should really exist by now, we checked this in check_output!) + if thumbnail_file == nil then + msg.error("Thumbnail suddenly disappeared!") + return true + end + + -- Check the size of the generated file + local thumbnail_file_size = thumbnail_file:seek("end") + thumbnail_file:close() + + -- Check if the file is big enough + local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size) + if missing_bytes > 0 then + msg.warn(("Thumbnail missing %d bytes (expected %d, had %d), padding %s"):format( + missing_bytes, thumbnail_raw_size, thumbnail_file_size, thumbnail_path + )) + -- Pad the file if it's missing content (eg. ffmpeg seek to file end) + thumbnail_file = io.open(thumbnail_path, "ab") + thumbnail_file:write(string.rep(string.char(0), missing_bytes)) + thumbnail_file:close() + end + + msg.debug("Finished work on thumbnail", thumb_idx) + mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path) + end + + msg.debug(("Generating %d thumbnails @ %dx%d for %q"):format( + #thumbnail_indexes, + thumb_state.thumbnail_size.w, + thumb_state.thumbnail_size.h, + file_path)) + + for i, thumbnail_index in ipairs(thumbnail_indexes) do + local bail = generate_thumbnail_for_index(thumbnail_index) + if bail then return end + end + +end + +-- Set up listeners and keybinds + +-- Job listener +mp.register_script_message("mpv_thumbnail_script-job", do_worker_job) + + +-- Register this worker with the master script +local register_timer = nil +local register_timeout = mp.get_time() + 1.5 + +local register_function = function() + if mp.get_time() > register_timeout and register_timer then + msg.error("Thumbnail worker registering timed out") + register_timer:stop() + else + msg.debug("Announcing self to master...") + mp.commandv("script-message", "mpv_thumbnail_script-worker", mp.get_script_name()) + end +end + +register_timer = mp.add_periodic_timer(0.1, register_function) + +mp.register_script_message("mpv_thumbnail_script-slaved", function() + msg.debug("Successfully registered with master") + register_timer:stop() +end) diff --git a/mpv/scripts/osc_tethys.lua b/mpv/scripts/osc_tethys.lua new file mode 100644 index 0000000..82e6bc8 --- /dev/null +++ b/mpv/scripts/osc_tethys.lua @@ -0,0 +1,5545 @@ +local assdraw = require 'mp.assdraw' +local msg = require 'mp.msg' +local opt = require 'mp.options' +local utils = require 'mp.utils' + +-- Windows: C:\Users\USER\AppData\Roaming\mpv\script-opts\tethys.conf +-- Linux: ~/config/mpv/script-opts/tethys.conf +local tethys = { + -- Config + showPictureInPictureButton = true, + showSpeedButton = true, + showShortcutTooltip = true, -- Show name and shortcut of buttons on hover + showChapterTooltip = true, -- Show chapter above timestamp in seekbar tooltip + skipBy = 5, -- skipback/skipfrwd amount in seconds + skipByMore = 30, -- RightClick skipback/skipfrwd amount in seconds + skipMode = "exact", -- "exact" (mordenx default) or "relative+keyframes" (mpv default) + pipGeometry = "33%+-10+-10", -- PictureInPicture 33% screen width, 10px from bottom right + pipAllWorkspaces = true, -- PictureInPicture will show video on all virtual desktops + + -- Sizes + thumbnailSize = 256, -- 16:9 = 256x144 + seekbarHeight = 20, + controlsHeight = 64, + smallButtonSize = 42, -- controlsHeight * 2/3 + trackButtonSize = 36, -- controlsHeight / 2 + buttonTooltipSize = 20, + windowBarHeight = 44, + windowButtonSize = 44, + windowTitleSize = 24, + cacheTextSize = 20, + timecodeSize = 27, + seekbarTimestampSize = 30, + seekbarTimestampOutline = 1, + chapterTickSize = 6, + windowTitleOutline = 1, + + -- Misc + osdSymbolFont = "mpv-osd-symbols", -- Seems to be hardcoded and unchangeable + + -- Colors (uses GGBBRR for some reason) + -- Alpha ranges 0 (opaque) .. 255 (transparent) + textColor = "FFFFFF", + buttonColor = "CCCCCC", + buttonHoveredColor = "FFFFFF", + buttonHoveredRectColor = "000000", + buttonHoveredRectAlpha = 255, -- Easily debug button geometry by setting to 80 + tooltipColor = "CCCCCC", + windowBarColor = "000000", + windowBarAlpha = 255, -- (80 is mpv default) (255 morden default) + windowButtonColor = "CCCCCC", + closeButtonHoveredColor = "1111DD", -- #DD1111 + seekbarHandleColor = "FFFFFF", + seekbarFgColor = "483DD7", -- #d73d48 + seekbarBgColor = "929292", + seekbarCacheColor = "000000", + seekbarCacheAlpha = 128, + chapterTickColor = "CCCCCC", +} +read_options(tethys, "tethys") + +local function parseColor(color) + if string.find(color, "#") then + local colorU = string.upper(color) + local r = string.sub(colorU, 2, 3) + local g = string.sub(colorU, 4, 5) + local b = string.sub(colorU, 6, 7) + return b..g..r + else + return color + end +end +local function parseConfig(configTable) + for k,v in pairs(configTable) do + if string.find(k, "Color") then + configTable[k] = parseColor(v) + end + end +end + +parseConfig(tethys) + +tethys.bottomBarHeight = tethys.seekbarHeight + tethys.controlsHeight +tethys.buttonW = tethys.controlsHeight +tethys.buttonH = tethys.controlsHeight +tethys.smallButtonSize = math.min(tethys.controlsHeight, tethys.smallButtonSize) +tethys.trackButtonSize = math.min(tethys.controlsHeight, tethys.trackButtonSize) +tethys.windowButtonSize = math.min(tethys.windowBarHeight, tethys.windowButtonSize) +tethys.windowControlsRect = { + w = tethys.windowButtonSize * 3, + h = tethys.windowBarHeight, +} + +tethys.trackTextScale = 105 + +-- [1] Foreground, [2] Karaoki Foreground, [3] Border, [4] Shadow +-- https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index22h3 +tethys.windowBarAlphaTable = {[1] = tethys.windowBarAlpha, [2] = 255, [3] = 255, [4] = 255} +tethys.seekbarCacheAlphaTable = {[1] = tethys.seekbarCacheAlpha, [2] = 255, [3] = 255, [4] = 255} +tethys.tooltipAlphaTable = {[1] = 0, [2] = 255, [3] = 88, [4] = 255} -- Opache Text, 65% opacity outlines + +tethys.showButtonHoveredRect = tethys.buttonHoveredRectAlpha < 255 -- Note: 255=transparent + +tethys.isPictureInPicture = false +tethys.pipWasFullscreen = false +tethys.pipWasMaximized = false +tethys.pipWasOnTop = false +tethys.pipHadBorders = false + +tethys.userdataAvail = (function() + local list = mp.get_property_native("property-list") + for k,v in ipairs(list) do + if (v == "user-data") then + return true + end + end + return false +end)() + + +-- https://github.com/libass/libass/wiki/ASSv5-Override-Tags#color-and-alpha---c-o +function genColorStyle(color) + return "{\\c&H"..color.."&}" -- Not sure why &H...& is used in santa_hat_lines + -- return "{\\c("..color..")}" -- Works + -- return "{\\c(#"..color..")}" -- Only works for paths, and breaks other stuff. +end + +---- mpv's stats.lua has some ASS formatting +-- https://aegi.vmoe.info/docs/3.0/ASS_Tags/ +-- https://github.com/libass/libass/wiki/ASSv5-Override-Tags +-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L62 +-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L176 +-- "{\\r}{\\an7}{\\fs%d}{\\fn%s}{\\bord%f}{\\3c&H%s&}{\\1c&H%s&}{\\alpha&H%s&}{\\xshad%f}{\\yshad%f}{\\4c&H%s&}" +-- {\\bord%f} = border size +-- {\\3c&H%s&} = border color +-- {\\1c&H%s&} = font color +-- {\\alpha&H%s&} = alpha +-- {\\xshad%f}{\\yshad%f} = shadow x,y offset +-- {\\4c&H%s&} = shadow color +-- {\\b(400)} = font weight, 400=normal, 700=bold +---- \\q2 in windowTitle is unknown +---- Not sure why \1c is rect fill color. Here's docs for \3c: +-- https://github.com/libass/libass/wiki/Libass'-ASS-Extensions#borderstyle4 +-- "{\\1c&H"..color.."}" +local tethysStyle = { + button = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.buttonH, tethys.osdSymbolFont), + buttonHovered = genColorStyle(tethys.buttonHoveredColor), + buttonHoveredRect = ("{\\rDefault\\blur0\\bord0\\1c&H%s\\1a&H%X&}"):format(tethys.buttonHoveredRectColor, tethys.buttonHoveredRectAlpha), + smallButton = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.smallButtonSize, tethys.osdSymbolFont), + trackButton = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)\\fn(%s)}"):format(tethys.buttonColor, tethys.trackButtonSize, tethys.osdSymbolFont), + trackText = ("{\\fscx%s\\fscy%s\\fn(%s)}"):format(tethys.trackTextScale, tethys.trackTextScale, mp.get_property("options/osd-font")), + windowBar = ("{\\1c&H%s}"):format(tethys.windowBarColor), + windowButton = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)\\fn(%s)}"):format(tethys.windowTitleOutline, tethys.windowButtonColor, tethys.windowButtonSize, tethys.osdSymbolFont), + closeButtonHovered = genColorStyle(tethys.closeButtonHoveredColor), + windowTitle = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.windowTitleOutline, tethys.textColor, tethys.windowTitleSize), + buttonTooltip = ("{\\blur0\\bord(1)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.tooltipColor, tethys.buttonTooltipSize), + buttonKeybindFormat = ("{\\bord(3)\\b(700)} %s {\\bord(1)\\b(400)}"), -- Spaces around the key to accound for thick outlines + timecode = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.textColor, tethys.timecodeSize), + cacheText = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.textColor, tethys.cacheTextSize, tethys.osdSymbolFont), + seekbar = ("{\\blur0\\bord0\\1c&H%s\\3c&HFFFFFF\\fs(%d)}"):format(tethys.seekbarFgColor, tethys.seekbarHeight), + seekbarTimestamp = ("{\\blur0\\bord(%d)\\1c&H%s\\3c&H000000\\fs(%d)}"):format(tethys.seekbarTimestampOutline, tethys.textColor, tethys.seekbarTimestampSize), + text = genColorStyle(tethys.textColor), + seekbarHandle = genColorStyle(tethys.seekbarHandleColor), + seekbarFg = genColorStyle(tethys.seekbarFgColor), + seekbarBg = genColorStyle(tethys.seekbarBgColor), + seekbarCache = genColorStyle(tethys.seekbarCacheColor), + chapterTick = genColorStyle(tethys.chapterTickColor), +} + +---- Icons +-- 44x44 +local tethysIcon_play = "{\\p1}m 0 0 m 44 44 m 37.236218 17.599999 b 41.584084 20.610064 41.584084 21.923269 37.236218 24.933333 b 22.516553 35.123867 9.369549 44 6.436216 44 b 3.502883 44 3.502883 39.6 3.502883 21.266665 b 3.502883 4.4 3.502883 0 6.436216 0 b 9.369549 0 22.516553 7.409462 37.236218 17.599999{\\p0}" +local tethysIcon_pause = "{\\p1}m 0 0 m 44 44 m 17.5 40.2064 b 17.5 45.263808 4.5 45.263808 4.5 40.2107 l 4.5 3.793057 b 4.5 -1.264352 17.5 -1.264352 17.5 3.793057 m 39.5 40.2064 b 39.5 45.263808 26.5 45.263808 26.5 40.2107 l 26.5 3.793057 b 26.5 -1.264352 39.5 -1.264352 39.5 3.793057{\\p0}" +local mpvOsdIcon_close = "{\\p1}m 0 0 m 44 44 m 34 34 l 30.571428 34 l 22 25.535715 l 13.535714 34 l 10 34 l 10 30.571428 l 18.464286 22 l 10 13.535714 l 10 10 l 13.535714 10 l 22 18.464286 l 30.571428 10 l 34 10 l 34 13.535714 l 25.535715 22 l 34 30.464285{\\p0}" +local mpvOsdIcon_maximize = "{\\p1}m 0 0 m 44 44 m 34 33 l 10 33 l 10 11 l 34 11 m 32 31 l 32 15 l 12 15 l 12 31{\\p0}" +local mpvOsdIcon_minimize = "{\\p1}m 0 0 m 44 44 m 34 25 l 10 25 l 10 19 l 34 19{\\p0}" +local mpvOsdIcon_restore = "{\\p1}m 0 0 m 44 44 m 34 25 l 27.999999 25 l 27.999999 33 l 10 33 l 10 18.999999 l 16 18.999999 l 16 11 l 34 11 m 32 23.000001 l 32 15 l 18 15 l 18 18.999999 l 27.999999 18.999999 l 27.999999 23.000001 m 26 31 l 26 23.000001 l 12 23.000001 l 12 31{\\p0}" +-- 32x28 +local mpvOsdIcon_fs_enter = "{\\p1}m 0 0 m 32 28 m 0 23.454546 l 0 4.545454 b 0 3.454545 1.090909 2.363636 2.181818 2.363636 l 29.818182 2.363636 b 30.90909 2.363636 32 3.454545 32 4.545454 l 32 23.454546 b 32 24.545456 30.90909 25.636364 29.818182 25.636364 l 2.181818 25.636364 b 1.090909 25.636364 0 24.545456 0 23.454546 m 2.181818 23.454546 l 29.818182 23.454546 l 29.818182 4.545454 l 2.181818 4.545454 m 21.090909 6.727272 l 27.636363 6.727272 l 27.636363 13.272728 m 22.036363 11.09091 l 22.036363 16.872726 l 9.963636 16.872726 l 9.963636 11.09091 m 10.909091 21.272728 l 4.363636 21.272728 l 4.363636 14.727272{\\p0}" +local mpvOsdIcon_fs_exit = "{\\p1}m 0 0 m 32 28 m 0 23.454546 l 0 4.545454 b 0 3.454545 1.090909 2.363636 2.181818 2.363636 l 29.818182 2.363636 b 30.909091 2.363636 32 3.454545 32 4.545454 l 32 23.454546 b 32 24.545454 30.909091 25.636364 29.818182 25.636364 l 2.181818 25.636364 b 1.090909 25.636364 0 24.545454 0 23.454546 m 2.181818 23.454546 l 29.818182 23.454546 l 29.818182 4.545454 l 2.181818 4.545454 m 8.254546 14.000001 l 4.363636 18 l 4.363636 10 m 27.636364 18 l 23.745455 14.000001 l 27.636364 10 m 21.636364 10.181818 l 21.636364 17.781818 l 10.363636 17.781818 l 10.363636 10.181818{\\p0}" +-- 28x28 +local tethysIcon_ch_prev = "{\\p1}m 0 0 m 28 28 m 15.555834 12.5 b 14.073607 13.526159 14.073607 13.973842 15.555834 15.000001 b 20.573903 18.474048 25.055836 21.5 26.055836 21.5 b 27.055835 21.5 27.055835 20.000001 27.055835 13.75 b 27.055835 8.000001 27.055835 6.5 26.055836 6.5 b 25.055836 6.5 20.573903 9.025952 15.555834 12.5 m 2.055835 12.5 b 0.573608 13.526159 0.573608 13.973842 2.055835 15.000001 b 7.073904 18.474048 11.555837 21.5 12.555836 21.5 b 13.555836 21.5 13.555836 20.000001 13.555836 13.75 b 13.555836 8.000001 13.555836 6.5 12.555836 6.5 b 11.555837 6.5 7.073904 9.025952 2.055835 12.5{\\p0}" +local tethysIcon_ch_next = "{\\p1}m 0 0 m 28 28 m 12.444166 12.5 b 13.926393 13.526159 13.926393 13.973842 12.444166 15.000001 b 7.426097 18.474048 2.944164 21.5 1.944165 21.5 b 0.944165 21.5 0.944165 20.000001 0.944165 13.75 b 0.944165 8.000001 0.944165 6.5 1.944165 6.5 b 2.944164 6.5 7.426097 9.025952 12.444166 12.5 m 25.944165 12.5 b 27.426392 13.526159 27.426392 13.973842 25.944165 15.000001 b 20.926096 18.474048 16.444163 21.5 15.444164 21.5 b 14.444164 21.5 14.444164 20.000001 14.444164 13.75 b 14.444164 8.000001 14.444164 6.5 15.444164 6.5 b 16.444163 6.5 20.926096 9.025952 25.944165 12.5{\\p0}" +local tethysIcon_pip_enter = "{\\p1}m 0 0 m 28 28 m 14 16 l 22 16 l 22 21 l 14 21 m 2 5 b 2 5 2 22 2 23 b 2 24 3 25 4 25 b 5 25 24 25 24 25 b 25 25 26 24 26 23 l 26 5 b 26 4 25 3 24 3 l 4 3 b 3 3 2 4 2 5 m 4 5 l 24 5 l 24 23 l 4 23{\\p0}" +local tethysIcon_pip_exit = "{\\p1}m 0 0 m 28 28 m 14 3 l 14 5 l 24 5 l 24 23 l 4 23 l 4 16 l 2 16 l 2 23 b 2 24 3 25 4 25 l 24 25 b 25 25 26 24 26 23 l 26 5 b 26 4 25 3 24 3 m 2 3 l 2 12 l 4 12 l 4 7 l 18 20 l 20 18 l 6 5 l 11 5 l 11 3{\\p0}" +local tethysIcon_pl_prev = "{\\p1}m 0 0 m 28 28 m 10.133332 11.8 b 7.959399 13.305034 7.959399 13.961635 10.133332 15.466668 b 17.493166 20.561937 24.066668 25 25.533334 25 b 27 25 27 22.800002 27 13.633333 b 27 5.200001 27 3 25.533334 3 b 24.066668 3 17.493166 6.70473 10.133332 11.8 m 1 23.103196 b 1 25.631901 7.574631 25.631901 7.574631 23.105396 l 7.574631 4.896528 b 7.574631 2.367824 1 2.367824 1 4.896528{\\p0}" +local tethysIcon_pl_next = "{\\p1}m 0 0 m 28 28 m 17.866668 11.8 b 20.040601 13.305034 20.040601 13.961635 17.866668 15.466668 b 10.506834 20.561937 3.933332 25 2.466666 25 b 1 25 1 22.800002 1 13.633333 b 1 5.200001 1 3 2.466666 3 b 3.933332 3 10.506834 6.70473 17.866668 11.8 m 27 23.103196 b 27 25.631901 20.425369 25.631901 20.425369 23.105396 l 20.425369 4.896528 b 20.425369 2.367824 27 2.367824 27 4.896528{\\p0}" +local tethysIcon_skipback = "{\\p1}m 0 0 m 28 28 m 2.511898 -0 l 2.511898 9.57764 l 12.089539 9.57764 l 12.089539 6.385093 l 8.163287 6.385093 b 11.540598 3.999689 16.093522 3.879191 19.632345 6.243757 b 23.661324 8.935835 25.219633 14.07368 23.365296 18.550442 b 21.510961 23.027205 16.775533 25.558703 12.023026 24.613371 b 7.27052 23.668038 3.864989 19.515531 3.864989 14.669918 l 0.672442 14.669918 b 0.672442 21.018992 5.172403 26.50492 11.399482 27.743563 b 17.626561 28.982206 23.884976 25.638369 26.314661 19.772589 b 28.744346 13.906809 26.684352 7.114815 21.40529 3.587458 b 18.765759 1.82378 15.680838 1.117147 12.694376 1.411288 b 10.187051 1.658238 7.750413 2.61433 5.704444 4.242179 l 5.704444 -0{\\p0}" +local tethysIcon_skipfrwd = "{\\p1}m 0 0 m 28 28 m 25.488102 -0 l 25.488102 9.57764 l 15.910461 9.57764 l 15.910461 6.385093 l 19.836712 6.385093 b 16.459402 3.999689 11.906478 3.879191 8.367655 6.243757 b 4.338676 8.935835 2.780367 14.07368 4.634704 18.550442 b 6.489039 23.027205 11.224467 25.558703 15.976974 24.613371 b 20.729479 23.668038 24.135011 19.515531 24.135011 14.669918 l 27.327558 14.669918 b 27.327558 21.018992 22.827597 26.50492 16.600518 27.743563 b 10.373439 28.982206 4.115024 25.638369 1.685339 19.772589 b -0.744346 13.906809 1.315648 7.114815 6.59471 3.587458 b 9.234241 1.82378 12.319162 1.117147 15.305624 1.411288 b 17.812949 1.658238 20.249586 2.61433 22.295555 4.242179 l 22.295555 -0{\\p0}" +local tethysIcon_speed = "{\\p1}m 0 0 m 28 28 m 14 2.053711 b 10.414212 2.053711 6.827634 3.417483 4.099609 6.145508 b -1.35644 11.601557 -1.35644 20.490239 4.099609 25.946289 l 6.017578 24.02832 b 1.597151 19.607893 1.597151 12.483903 6.017578 8.063476 b 10.438006 3.64305 17.561994 3.64305 21.982422 8.063476 b 26.402849 12.483903 26.402849 19.607893 21.982422 24.02832 l 23.900391 25.946289 b 29.35644 20.490239 29.35644 11.601557 23.900391 6.145508 b 21.172366 3.417483 17.585788 2.053711 14 2.053711 m 17.886719 10.034179 l 14.351562 13.571289 b 14.235118 13.554564 14.117639 13.54608 14 13.545898 b 13.336959 13.545898 12.701074 13.80929 12.232233 14.278131 b 11.763392 14.746972 11.5 15.382857 11.5 16.045898 b 11.5 17.42661 12.619288 18.545898 14 18.545898 b 14.663041 18.545898 15.298926 18.282506 15.767767 17.813665 b 16.236608 17.344824 16.5 16.708939 16.5 16.045898 b 16.499911 15.927607 16.491426 15.809472 16.47461 15.692382 l 20.009767 12.155273{\\p0}" +local tethysIcon_vol_033 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}" +local tethysIcon_vol_066 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}" +local tethysIcon_vol_100 = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 23.532835 3.779296 l 21.294544 6.017587 b 22.97216 7.695202 24.35259 10.812999 24.344937 13.990067 b 24.337337 17.167135 22.938039 20.301821 21.257445 21.982413 l 23.499858 24.220704 b 26.040275 21.680287 27.501508 17.812486 27.510697 13.99831 b 27.519997 10.184133 26.076229 6.322689 23.532835 3.779296 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}" +local tethysIcon_vol_101 = "{\\p1}m 0 0 m 28 28 m 26.774083 5.201582 l 25.69218 18.248063 b 25.66035 18.693555 25.533063 18.916303 25.31033 18.916303 b 25.08759 18.916303 24.960302 18.693563 24.928482 18.248063 l 23.878399 5.201582 l 23.878399 5.074292 b 23.878399 4.660623 24.005689 4.342418 24.292068 4.119669 b 24.578454 3.865105 24.928482 3.737822 25.31033 3.737822 b 25.724 3.737822 26.042205 3.865111 26.328594 4.119669 b 26.614979 4.342409 26.774083 4.660623 26.774083 5.074292 m 26.774083 22.734783 b 26.774083 23.180275 26.614991 23.530301 26.360414 23.816689 b 26.074028 24.134895 25.724 24.262178 25.31033 24.262178 b 24.928482 24.262178 24.578454 24.134888 24.292068 23.816689 b 24.005682 23.530301 23.878399 23.180275 23.878399 22.734783 b 23.878399 22.321115 24.005689 21.971087 24.292068 21.684702 b 24.578454 21.366494 24.928482 21.239213 25.31033 21.239213 b 25.724 21.239213 26.074028 21.366487 26.360414 21.684702 b 26.614979 21.971087 26.774083 22.321115 26.774083 22.734783 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 20.116395 7.368459 l 17.915201 9.643849 b 18.793615 10.494225 19.496549 12.085227 19.477484 14.012366 b 19.458484 15.939505 18.683596 17.529199 17.842625 18.356568 l 20.064426 20.611347 b 21.82241 18.8818 22.618007 16.592612 22.643244 14.04122 b 22.668484 11.489827 21.937955 9.131882 20.116395 7.368459 m 16.562393 10.929048 l 14.418911 13.150849 l 14.418911 14.870154 l 16.488207 17.07095 b 17.436586 16.089838 17.82417 15.024196 17.820228 13.983409 b 17.816228 12.942625 17.530838 11.909297 16.562404 10.929049{\\p0}" +local tethysIcon_vol_mute = "{\\p1}m 0 0 m 28 28 m 4.710272 20.331519 l 1.360222 18.656494 b 0.489258 18.221011 0.489258 18.221011 0.489258 17.165758 l 0.489258 14 l 0.489258 10.83424 b 0.489258 9.778988 0.48926 9.778988 1.337532 9.354852 l 4.710272 7.668481 m 5.765524 7.674466 l 9.986538 3.453454 b 10.706239 2.706516 12.097044 1.342947 12.097044 3.453454 l 12.097044 24.558517 b 12.097044 26.669023 10.738402 25.263082 9.986538 24.558517 l 5.765524 20.337504 m 26.699268 7.480125 b 26.905593 7.480125 27.111919 7.52139 27.276978 7.68645 b 27.607099 8.01657 27.607099 8.51175 27.276978 8.841871 l 22.077583 14.041265 l 27.276978 19.240659 b 27.565833 19.529515 27.565833 19.98343 27.276978 20.31355 b 26.988123 20.602406 26.492943 20.602406 26.204087 20.31355 l 21.004692 15.114157 l 15.805297 20.31355 b 15.516442 20.602406 14.979997 20.602406 14.691142 20.31355 b 14.361021 19.98343 14.361021 19.48825 14.691142 19.158129 l 19.849271 13.958735 l 14.649877 8.759341 b 14.361021 8.470485 14.361021 8.01657 14.649877 7.68645 b 14.979997 7.397594 15.433912 7.397594 15.764033 7.68645 l 20.963428 12.885844 l 26.162823 7.68645 b 26.286617 7.52139 26.492943 7.480125 26.699268 7.480125{\\p0}" + +function scaleIcon(iconStr, iconScale) + -- Match space before number to ignore {\p1} and {\p0} + return iconStr:gsub(" ([%d%.]+)", function(numStr) + local num = tonumber(numStr) + num = num * iconScale + return " " .. tostring(num) + end) +end +local iconScale = tethys.controlsHeight / 64 +if iconScale ~= 1 then + tethysIcon_play = scaleIcon(tethysIcon_play, iconScale) + tethysIcon_pause = scaleIcon(tethysIcon_pause, iconScale) +end +iconScale = tethys.windowButtonSize / 44 +if iconScale ~= 1 then + mpvOsdIcon_close = scaleIcon(mpvOsdIcon_close, iconScale) + mpvOsdIcon_maximize = scaleIcon(mpvOsdIcon_maximize, iconScale) + mpvOsdIcon_minimize = scaleIcon(mpvOsdIcon_minimize, iconScale) + mpvOsdIcon_restore = scaleIcon(mpvOsdIcon_restore, iconScale) +end +iconScale = tethys.smallButtonSize / 42 +if iconScale ~= 1 then + mpvOsdIcon_fs_enter = scaleIcon(mpvOsdIcon_fs_enter, iconScale) + mpvOsdIcon_fs_exit = scaleIcon(mpvOsdIcon_fs_exit, iconScale) + tethysIcon_ch_prev = scaleIcon(tethysIcon_ch_prev, iconScale) + tethysIcon_ch_next = scaleIcon(tethysIcon_ch_next, iconScale) + tethysIcon_pip_enter = scaleIcon(tethysIcon_pip_enter, iconScale) + tethysIcon_pip_exit = scaleIcon(tethysIcon_pip_exit, iconScale) + tethysIcon_pl_prev = scaleIcon(tethysIcon_pl_prev, iconScale) + tethysIcon_pl_next = scaleIcon(tethysIcon_pl_next, iconScale) + tethysIcon_skipback = scaleIcon(tethysIcon_skipback, iconScale) + tethysIcon_skipfrwd = scaleIcon(tethysIcon_skipfrwd, iconScale) + tethysIcon_speed = scaleIcon(tethysIcon_speed, iconScale) + tethysIcon_vol_033 = scaleIcon(tethysIcon_vol_033, iconScale) + tethysIcon_vol_066 = scaleIcon(tethysIcon_vol_066, iconScale) + tethysIcon_vol_100 = scaleIcon(tethysIcon_vol_100, iconScale) + tethysIcon_vol_101 = scaleIcon(tethysIcon_vol_101, iconScale) + tethysIcon_vol_mute = scaleIcon(tethysIcon_vol_mute, iconScale) +end + + + + + + + + + + + + + + + + + + + +-- +-- Parameters +-- +-- default user option values +-- do not touch, change them in osc.conf +local user_opts = { + showwindowed = true, -- show OSC when windowed? + showfullscreen = true, -- show OSC when fullscreen? + idlescreen = true, -- show mpv logo on idle + scalewindowed = 1, -- scaling of the controller when windowed + scalefullscreen = 1, -- scaling of the controller when fullscreen + scaleforcedwindow = 2, -- scaling when rendered on a forced window + vidscale = true, -- scale the controller with the video? + valign = 0.8, -- vertical alignment, -1 (top) to 1 (bottom) + halign = 0, -- horizontal alignment, -1 (left) to 1 (right) + barmargin = 0, -- vertical margin of top/bottombar + boxalpha = 80, -- alpha of the background box, + -- 0 (opaque) to 255 (fully transparent) + hidetimeout = 500, -- duration in ms until the OSC hides if no + -- mouse movement. enforced non-negative for the + -- user, but internally negative is "always-on". + fadeduration = 200, -- duration of fade out in ms, 0 = no fade + deadzonesize = 0.5, -- size of deadzone + minmousemove = 0, -- minimum amount of pixels the mouse has to + -- move between ticks to make the OSC show up + iamaprogrammer = false, -- use native mpv values and disable OSC + -- internal track list management (and some + -- functions that depend on it) + -- layout = "bottombar", + layout = "tethys", + seekbarstyle = "bar", -- bar, diamond or knob + seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle + seekrangestyle = "inverted",-- bar, line, slider, inverted or none + seekrangeseparate = true, -- whether the seekranges overlay on the bar-style seekbar + seekrangealpha = 200, -- transparency of seekranges + seekbarkeyframes = true, -- use keyframes when dragging the seekbar + title = "${media-title}", -- string compatible with property-expansion + -- to be shown as OSC title + tooltipborder = 1, -- border of tooltip in bottom/topbar + timetotal = false, -- display total time instead of remaining time? + timems = false, -- display timecodes with milliseconds? + tcspace = 100, -- timecode spacing (compensate font size estimation) + visibility = "auto", -- only used at init to set visibility_mode(...) + -- visibility = "always", -- only used at init to set visibility_mode(...) + boxmaxchars = 80, -- title crop threshold for box layout + boxvideo = false, -- apply osc_param.video_margins to video + windowcontrols = "auto", -- whether to show window controls + windowcontrols_alignment = "right", -- which side to show window controls on + greenandgrumpy = false, -- disable santa hat + livemarkers = true, -- update seekbar chapter markers on duration change + chapters_osd = true, -- whether to show chapters OSD on next/prev + playlist_osd = true, -- whether to show playlist OSD on next/prev + chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable + unicodeminus = false, -- whether to use the Unicode minus sign character +} + +-- read options from config and command-line +opt.read_options(user_opts, "osc", function(list) update_options(list) end) + +local osc_param = { -- calculated by osc_init() + playresy = 0, -- canvas size Y + playresx = 0, -- canvas size X + display_aspect = 1, + unscaled_y = 0, + areas = {}, + video_margins = { + l = 0, r = 0, t = 0, b = 0, -- left/right/top/bottom + }, +} + +local osc_styles = { + bigButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}", + smallButtonsL = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}", + smallButtonsLlabel = "{\\fscx105\\fscy105\\fn" .. mp.get_property("options/osd-font") .. "}", + smallButtonsR = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}", + topButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}", + + elementDown = "{\\1c&H999999}", + timecodes = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs20}", + vidtitle = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\q2}", + box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", + + topButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}", + smallButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}", + timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}", + timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}", + vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}", + + wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}", + wcTitle = "{\\1c&HFFFFFF\\fs24\\q2}", + wcBar = "{\\1c&H000000}", +} + + + + + + + + + + + + + + + + + + +---- Tooltip Utils +-- See MPV's stats.lua for a full example (Shortcut: I + 4) +-- https://github.com/mpv-player/mpv/blob/master/player/lua/stats.lua#L433 +local bindings = mp.get_property_native("input-bindings", {}) +local active = {} -- map: key-name -> bind-info +for _, bind in pairs(bindings) do + if bind.priority >= 0 and ( + not active[bind.key] or + (active[bind.key].is_weak and not bind.is_weak) or + (bind.is_weak == active[bind.key].is_weak and + bind.priority > active[bind.key].priority) + ) and not bind.cmd:find("script-binding stats/__forced_", 1, true) + then + active[bind.key] = bind + end +end +local ordered = {} +for _, bind in pairs(active) do + table.insert(ordered, bind) + _,_, bind.mods = bind.key:find("(.*)%+.") + _, bind.mods_count = bind.key:gsub("%+.", "") +end +table.sort(ordered, function(a, b) + if a.subject ~= b.subject then + return a.subject < b.subject + elseif a.mods_count ~= b.mods_count then + return a.mods_count < b.mods_count + elseif a.mods ~= b.mods then + return a.mods < b.mods + elseif a.key:len() ~= b.key:len() then + return a.key:len() < b.key:len() + elseif a.key:lower() ~= b.key:lower() then + return a.key:lower() < b.key:lower() + else + return a.key > b.key -- only case differs, lowercase first + end +end) +-- for _, bind in pairs(ordered) do +-- jsonstr, err = utils.format_json(bind) +-- print(jsonstr) +-- end + +function isIgnored(bind, ignoredKeys) + for _, ignoredKey in pairs(ignoredKeys) do + if bind.key == ignoredKey then + return true + end + end + return false +end +function grepBindByCmd(pattern, ignoredKeys) + ignoredKeys = ignoredKeys or {} + local cmdBinds = {} + for _, bind in pairs(ordered) do + local ignored = isIgnored(bind, ignoredKeys) + if not ignored and bind.cmd:find(pattern) then + -- print(bind.key, bind.cmd) + cmdBinds[#cmdBinds+1] = bind + end + end + return cmdBinds +end + +function grepSeekBinds(ignoredKeys) + ignoredKeys = ignoredKeys or {} + local backBinds = {} + local frwdBinds = {} + for _, bind in pairs(ordered) do + if isIgnored(bind, ignoredKeys) then + -- skip + elseif bind.cmd:find("^seek(%s+)(%-[%d%.]+)") then + backBinds[#backBinds+1] = bind + elseif bind.cmd:find("^no%-osd(%s+)seek(%s+)(%-[%d%.]+)") then + backBinds[#backBinds+1] = bind + elseif bind.cmd:find("^seek(%s+)(%+?[%d%.]+)") then + frwdBinds[#frwdBinds+1] = bind + elseif bind.cmd:find("^no%-osd(%s+)seek(%s+)(%+?[%d%.]+)") then + frwdBinds[#frwdBinds+1] = bind + end + end + return backBinds, frwdBinds +end +function grepSpeedBinds(ignoredKeys) + ignoredKeys = ignoredKeys or {} + local downBinds = {} + local upBinds = {} + for _, bind in pairs(ordered) do + if isIgnored(bind, ignoredKeys) then + -- skip + elseif bind.cmd:find("^add(%s+)speed(%s+)(%+?[%d%.]+)$") then + upBinds[#upBinds+1] = bind + elseif bind.cmd:find("^add(%s+)speed(%s+)(%-[%d%.]+)$") then + downBinds[#downBinds+1] = bind + elseif bind.cmd:find("^multiply(%s+)speed(%s+)([%d%.]+)/([%d%.]+)$") then + local num, den = bind.cmd:match("^multiply%s+speed%s+([%d%.]+)/([%d%.]+)$") + num = tonumber(num) -- numerator + den = tonumber(den) -- denominator + if num < den then + downBinds[#downBinds+1] = bind + else + upBinds[#upBinds+1] = bind + end + elseif bind.cmd:find("^multiply(%s+)speed(%s+)([%d%.]+)$") then + local x = bind.cmd:match("^multiply%s+speed%s+([%d%.]+)$") + x = tonumber(x) + if x < 1 then + downBinds[#downBinds+1] = bind + else + upBinds[#upBinds+1] = bind + end + end + end + return downBinds, upBinds +end + +function humanBindKey(key) + if key == 'PGUP' then return 'PgUp' + elseif key == 'PGDWN' then return 'PgDn' + elseif key == 'UP' then return '⇧' + elseif key == 'DOWN' then return '⇩' + elseif key == 'LEFT' then return '⇦' + elseif key == 'RIGHT' then return '⇨' + elseif key == 'Shift+UP' then return 'Shift ⇧' + elseif key == 'Shift+DOWN' then return 'Shift ⇩' + elseif key == 'Shift+LEFT' then return 'Shift ⇦' + elseif key == 'Shift+RIGHT' then return 'Shift ⇨' + elseif key == 'WHEEL_UP' then return 'Scroll Up' + elseif key == 'WHEEL_DOWN' then return 'Scroll Down' + elseif key == 'SHARP' then return '#' + elseif key == 'BS' then return 'Backspace' + elseif key == '{' then return '\\{' + elseif key == '}' then return '\\}' + else return key + end +end +function formatBindKey(key) + return tethysStyle.buttonKeybindFormat:format(humanBindKey(key)) +end +function formatBinds(binds) + local str = "" + for i, bind in pairs(binds) do + if i ~= 1 then -- lua arrays start at 1 + str = str .. " or " + end + str = str .. formatBindKey(bind.key) + end + return str +end +function formatSeekBind(bind) + local seekBy + if bind.cmd:match("^no%-osd%s+seek") then + seekBy = bind.cmd:match("^no%-osd%s+seek%s+([%+%-]?[%d%.]+)") + else + seekBy = bind.cmd:match("^seek%s+([%+%-]?[%d%.]+)") + end + seekBy = tonumber(seekBy) -- Note: +0.1 is parsed okay + local label + if seekBy < 0 then + return ("Back %ss %s"):format(-seekBy, formatBindKey(bind.key)) + else + return ("Forward %ss %s"):format(seekBy, formatBindKey(bind.key)) + end +end +function formatSeekBinds(binds) + local list = {} + for i, bind in pairs(binds) do + table.insert(list, formatSeekBind(bind)) + end + return list +end + +---- Filter bindings by commands using regex +---- Keys passed into grepBindByCmd() are ignored. +-- %s+ = One or more spaces +-- %- = A literal dash '-' +-- %-? = May or may not contain a dash +-- %d+ = One or more digits from 0 to 9 +-- (%-?%d+) = Positive or negative integer +local pauseBinds = grepBindByCmd("^cycle(%s+)pause", {"p", "PLAYPAUSE", "MBTN_RIGHT", "PLAY", "PAUSE"}) +local seekBackBinds, seekFrwdBinds = grepSeekBinds({"REWIND", "Shift+PGDWN", "FORWARD", "Shift+PGUP"}) +local muteBinds = grepBindByCmd("^cycle(%s+)mute", {"MUTE"}) +local volDnBinds = grepBindByCmd("^add(%s+)volume(%s+)(%-%d+)", {"VOLUME_DOWN", "WHEEL_LEFT"}) +local volUpBinds = grepBindByCmd("^add(%s+)volume(%s+)(%d+)", {"VOLUME_UP", "WHEEL_RIGHT"}) +local plPrevBinds = grepBindByCmd("^playlist%-prev", {"PREV", "MBTN_BACK"}) +local plNextBinds = grepBindByCmd("^playlist%-next", {"NEXT", "MBTN_FORWARD"}) +local chPrevBinds = grepBindByCmd("^add chapter (%-%d+)", {}) +local chNextBinds = grepBindByCmd("^add chapter (%d+)", {}) +local audioBinds = grepBindByCmd("^cycle(%s+)audio", {}) +local subBinds = grepBindByCmd("^cycle(%s+)sub$", {}) +local speedResetBinds = grepBindByCmd("^set(%s+)speed(%s+)1", {}) +local speedDnBinds, speedUpBinds = grepSpeedBinds() +local fullscreenBinds = grepBindByCmd("^cycle(%s+)fullscreen", {"MBTN_LEFT_DBL"}) +---- Generate tooltips +local pauseTooltip = ("Play %s"):format(formatBinds(pauseBinds)) +local seekBackTooltip = formatSeekBinds(seekBackBinds) +local seekFrwdTooltip = formatSeekBinds(seekFrwdBinds) +local muteTooltip = formatBinds(muteBinds) +local volDnTooltip = formatBinds(volDnBinds) +local volUpTooltip = formatBinds(volUpBinds) +local volTooltip = ("Mute %s\\NVolume Up %s\\NVolume Down %s"):format(muteTooltip, volUpTooltip, volDnTooltip) +local plPrevTooltip = ("Previous %s"):format(formatBinds(plPrevBinds)) +local plNextTooltip = ("Next %s"):format(formatBinds(plNextBinds)) +local chPrevTooltip = ("Prev Chapter %s"):format(formatBinds(chPrevBinds)) +local chNextTooltip = ("Next Chapter %s"):format(formatBinds(chNextBinds)) +local audioTooltip = ("Audio Track %s"):format(formatBinds(audioBinds)) +local subTooltip = ("Subtitle Track %s"):format(formatBinds(subBinds)) +local speedResetTooltip = formatBinds(speedResetBinds) +local speedDnTooltip = formatBinds(speedDnBinds) +local speedUpTooltip = formatBinds(speedUpBinds) +local speedTooltip = ("Reset %s\\NFaster %s\\NSlower %s"):format(speedResetTooltip, speedUpTooltip, speedDnTooltip) +local pipTooltip = "Picture In Picture" +local fullscreenTooltip = ("Fullscreen %s"):format(formatBinds(fullscreenBinds)) +-- print("pauseTooltip", pauseTooltip) +-- print("seekBackTooltip", utils.format_json(seekBackTooltip)) +-- print("seekFrwdTooltip", utils.format_json(seekFrwdTooltip)) +-- print("muteTooltip", muteTooltip) +-- print("volDnTooltip", volDnTooltip) +-- print("volUpTooltip", volUpTooltip) +-- print("volTooltip", utils.format_json(volTooltip)) +-- print("plPrevTooltip", plPrevTooltip) +-- print("plNextTooltip", plNextTooltip) +-- print("chPrevTooltip", chPrevTooltip) +-- print("chNextTooltip", chNextTooltip) +-- print("audioTooltip", audioTooltip) +-- print("subTooltip", subTooltip) +-- print("speedResetTooltip", speedResetTooltip) +-- print("speedDnTooltip", speedDnTooltip) +-- print("speedUpTooltip", speedUpTooltip) +-- print("speedTooltip", utils.format_json(speedTooltip)) +-- print("pipTooltip", pipTooltip) +-- print("fullscreenTooltip", fullscreenTooltip) + + + + + + + + + + + + + + + + + + + +---- Playlist / Chapter Utils +function getDeltaListItem(listKey, curKey, delta, clamp) + local pos = mp.get_property_number(curKey, 0) + 1 + local count, limlist = limited_list(listKey, pos) + if count == 0 then + return nil + end + + local curIndex = -1 + for i, v in ipairs(limlist) do + if v.current then + curIndex = i + break + end + end + + local deltaIndex = curIndex + delta + if curIndex == -1 then + return nil + elseif deltaIndex < 1 then + if clamp then + deltaIndex = 1 + else + return nil + end + elseif deltaIndex > count then + if clamp then + deltaIndex = count + else + return nil + end + end + + local deltaItem = limlist[deltaIndex] + return deltaIndex, deltaItem +end + +function getDeltaChapter(delta) + local deltaIndex, deltaChapter = getDeltaListItem('chapter-list', 'chapter', delta, true) + if deltaChapter == nil then -- Video Done + return nil + end + deltaChapter = { + index = deltaIndex, + time = deltaChapter.time, + title = deltaChapter.title, + label = nil, + } + local label = deltaChapter.title + if label == nil then + label = string.format('Chapter %02d', deltaChapter.index) + end + -- local time = mp.format_time(deltaChapter.time) + -- deltaChapter.label = string.format('[%s] %s', time, label) + deltaChapter.label = label + return deltaChapter +end + +function getDeltaPlaylistItem(delta) + local deltaIndex, deltaItem = getDeltaListItem('playlist', 'playlist-pos', delta, false) + if deltaItem == nil then + return nil + end + deltaItem = { + index = deltaIndex, + filename = deltaItem.filename, + title = deltaItem.title, + label = nil, + } + local label = deltaItem.title + if label == nil then + local _, filename = utils.split_path(deltaItem.filename) + label = filename + end + deltaItem.label = label + return deltaItem +end + + + + + + + + + + + + + + + + + + + +---- Thumbnailer (https://github.com/TheAMM/mpv_thumbnail_script) +-- mpv_thumbnail_script/lib/helpers.lua +-- (partial file) Only copied the needed functions +function clear_table(target) + for key, value in pairs(target) do + target[key] = nil + end +end +ON_WINDOWS = (package.config:sub(1,1) ~= '/') +function is_absolute_path( path ) + local tmp, is_win = path:gsub("^[A-Z]:\\", "") + local tmp, is_unix = path:gsub("^/", "") + return (is_win > 0) or (is_unix > 0) +end +function join_paths(...) + local sep = ON_WINDOWS and "\\" or "/" + local result = ""; + for i, p in pairs({...}) do + if p ~= "" then + if is_absolute_path(p) then + result = p + else + result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p + end + end + end + return result:gsub("[\\"..sep.."]*$", "") +end +function create_directories(path) + local cmd + if ON_WINDOWS then + cmd = { args = {"cmd", "/c", "mkdir", path} } + else + cmd = { args = {"mkdir", "-p", path} } + end + utils.subprocess(cmd) +end +function file_exists(name) + local f = io.open(name, "rb") + if f ~= nil then + local ok, err, code = f:read(1) + io.close(f) + return code == nil + else + return false + end +end +-- Find an executable in PATH or CWD with the given name +function find_executable(name) + local delim = ON_WINDOWS and ";" or ":" + local pwd = os.getenv("PWD") or utils.getcwd() + local path = os.getenv("PATH") + local env_path = pwd .. delim .. path -- Check CWD first + local result, filename + for path_dir in env_path:gmatch("[^"..delim.."]+") do + filename = join_paths(path_dir, name) + if file_exists(filename) then + result = filename + break + end + end + return result +end +-- Searches for an executable and caches the result if any +local ExecutableFinder = { path_cache = {} } +function ExecutableFinder:get_executable_path(name, raw_name) + name = ON_WINDOWS and not raw_name and (name .. ".exe") or name + if self.path_cache[name] == nil then + self.path_cache[name] = find_executable(name) or false + end + return self.path_cache[name] +end + + + +-- mpv_thumbnail_script/lib/sha1.lua +-- $Revision: 1.5 $ +-- $Date: 2014-09-10 16:54:25 $ + +-- This module was originally taken from http://cube3d.de/uploads/Main/sha1.txt. + +------------------------------------------------------------------------------- +-- SHA-1 secure hash computation, and HMAC-SHA1 signature computation, +-- in pure Lua (tested on Lua 5.1) +-- License: MIT +-- +-- Usage: +-- local hashAsHex = sha1.hex(message) -- returns a hex string +-- local hashAsData = sha1.bin(message) -- returns raw bytes +-- +-- local hmacAsHex = sha1.hmacHex(key, message) -- hex string +-- local hmacAsData = sha1.hmacBin(key, message) -- raw bytes +-- +-- +-- Pass sha1.hex() a string, and it returns a hash as a 40-character hex string. +-- For example, the call +-- +-- local hash = sha1.hex("iNTERFACEWARE") +-- +-- puts the 40-character string +-- +-- "e76705ffb88a291a0d2f9710a5471936791b4819" +-- +-- into the variable 'hash' +-- +-- Pass sha1.hmacHex() a key and a message, and it returns the signature as a +-- 40-byte hex string. +-- +-- +-- The two "bin" versions do the same, but return the 20-byte string of raw +-- data that the 40-byte hex strings represent. +-- +------------------------------------------------------------------------------- +-- +-- Description +-- Due to the lack of bitwise operations in 5.1, this version uses numbers to +-- represents the 32bit words that we combine with binary operations. The basic +-- operations of byte based "xor", "or", "and" are all cached in a combination +-- table (several 64k large tables are built on startup, which +-- consumes some memory and time). The caching can be switched off through +-- setting the local cfg_caching variable to false. +-- For all binary operations, the 32 bit numbers are split into 8 bit values +-- that are combined and then merged again. +-- +-- Algorithm: http://www.itl.nist.gov/fipspubs/fip180-1.htm +-- +------------------------------------------------------------------------------- + +local sha1 = (function() +local sha1 = {} + +-- set this to false if you don't want to build several 64k sized tables when +-- loading this file (takes a while but grants a boost of factor 13) +local cfg_caching = false +-- local storing of global functions (minor speedup) +local floor,modf = math.floor,math.modf +local char,format,rep = string.char,string.format,string.rep + +-- merge 4 bytes to an 32 bit word +local function bytes_to_w32 (a,b,c,d) return a*0x1000000+b*0x10000+c*0x100+d end +-- split a 32 bit word into four 8 bit numbers +local function w32_to_bytes (i) + return floor(i/0x1000000)%0x100,floor(i/0x10000)%0x100,floor(i/0x100)%0x100,i%0x100 +end + +-- shift the bits of a 32 bit word. Don't use negative values for "bits" +local function w32_rot (bits,a) + local b2 = 2^(32-bits) + local a,b = modf(a/b2) + return a+b*b2*(2^(bits)) +end + +-- caching function for functions that accept 2 arguments, both of values between +-- 0 and 255. The function to be cached is passed, all values are calculated +-- during loading and a function is returned that returns the cached values (only) +local function cache2arg (fn) + if not cfg_caching then return fn end + local lut = {} + for i=0,0xffff do + local a,b = floor(i/0x100),i%0x100 + lut[i] = fn(a,b) + end + return function (a,b) + return lut[a*0x100+b] + end +end + +-- splits an 8-bit number into 8 bits, returning all 8 bits as booleans +local function byte_to_bits (b) + local b = function (n) + local b = floor(b/n) + return b%2==1 + end + return b(1),b(2),b(4),b(8),b(16),b(32),b(64),b(128) +end + +-- builds an 8bit number from 8 booleans +local function bits_to_byte (a,b,c,d,e,f,g,h) + local function n(b,x) return b and x or 0 end + return n(a,1)+n(b,2)+n(c,4)+n(d,8)+n(e,16)+n(f,32)+n(g,64)+n(h,128) +end + +-- debug function for visualizing bits in a string +local function bits_to_string (a,b,c,d,e,f,g,h) + local function x(b) return b and "1" or "0" end + return ("%s%s%s%s %s%s%s%s"):format(x(a),x(b),x(c),x(d),x(e),x(f),x(g),x(h)) +end + +-- debug function for converting a 8-bit number as bit string +local function byte_to_bit_string (b) + return bits_to_string(byte_to_bits(b)) +end + +-- debug function for converting a 32 bit number as bit string +local function w32_to_bit_string(a) + if type(a) == "string" then return a end + local aa,ab,ac,ad = w32_to_bytes(a) + local s = byte_to_bit_string + return ("%s %s %s %s"):format(s(aa):reverse(),s(ab):reverse(),s(ac):reverse(),s(ad):reverse()):reverse() +end + +-- bitwise "and" function for 2 8bit number +local band = cache2arg (function(a,b) + local A,B,C,D,E,F,G,H = byte_to_bits(b) + local a,b,c,d,e,f,g,h = byte_to_bits(a) + return bits_to_byte( + A and a, B and b, C and c, D and d, + E and e, F and f, G and g, H and h) + end) + +-- bitwise "or" function for 2 8bit numbers +local bor = cache2arg(function(a,b) + local A,B,C,D,E,F,G,H = byte_to_bits(b) + local a,b,c,d,e,f,g,h = byte_to_bits(a) + return bits_to_byte( + A or a, B or b, C or c, D or d, + E or e, F or f, G or g, H or h) + end) + +-- bitwise "xor" function for 2 8bit numbers +local bxor = cache2arg(function(a,b) + local A,B,C,D,E,F,G,H = byte_to_bits(b) + local a,b,c,d,e,f,g,h = byte_to_bits(a) + return bits_to_byte( + A ~= a, B ~= b, C ~= c, D ~= d, + E ~= e, F ~= f, G ~= g, H ~= h) + end) + +-- bitwise complement for one 8bit number +local function bnot (x) + return 255-(x % 256) +end + +-- creates a function to combine to 32bit numbers using an 8bit combination function +local function w32_comb(fn) + return function (a,b) + local aa,ab,ac,ad = w32_to_bytes(a) + local ba,bb,bc,bd = w32_to_bytes(b) + return bytes_to_w32(fn(aa,ba),fn(ab,bb),fn(ac,bc),fn(ad,bd)) + end +end + +-- create functions for and, xor and or, all for 2 32bit numbers +local w32_and = w32_comb(band) +local w32_xor = w32_comb(bxor) +local w32_or = w32_comb(bor) + +-- xor function that may receive a variable number of arguments +local function w32_xor_n (a,...) + local aa,ab,ac,ad = w32_to_bytes(a) + for i=1,select('#',...) do + local ba,bb,bc,bd = w32_to_bytes(select(i,...)) + aa,ab,ac,ad = bxor(aa,ba),bxor(ab,bb),bxor(ac,bc),bxor(ad,bd) + end + return bytes_to_w32(aa,ab,ac,ad) +end + +-- combining 3 32bit numbers through binary "or" operation +local function w32_or3 (a,b,c) + local aa,ab,ac,ad = w32_to_bytes(a) + local ba,bb,bc,bd = w32_to_bytes(b) + local ca,cb,cc,cd = w32_to_bytes(c) + return bytes_to_w32( + bor(aa,bor(ba,ca)), bor(ab,bor(bb,cb)), bor(ac,bor(bc,cc)), bor(ad,bor(bd,cd)) + ) +end + +-- binary complement for 32bit numbers +local function w32_not (a) + return 4294967295-(a % 4294967296) +end + +-- adding 2 32bit numbers, cutting off the remainder on 33th bit +local function w32_add (a,b) return (a+b) % 4294967296 end + +-- adding n 32bit numbers, cutting off the remainder (again) +local function w32_add_n (a,...) + for i=1,select('#',...) do + a = (a+select(i,...)) % 4294967296 + end + return a +end +-- converting the number to a hexadecimal string +local function w32_to_hexstring (w) return format("%08x",w) end + +-- calculating the SHA1 for some text +function sha1.hex(msg) + local H0,H1,H2,H3,H4 = 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0 + local msg_len_in_bits = #msg * 8 + + local first_append = char(0x80) -- append a '1' bit plus seven '0' bits + + local non_zero_message_bytes = #msg +1 +8 -- the +1 is the appended bit 1, the +8 are for the final appended length + local current_mod = non_zero_message_bytes % 64 + local second_append = current_mod>0 and rep(char(0), 64 - current_mod) or "" + + -- now to append the length as a 64-bit number. + local B1, R1 = modf(msg_len_in_bits / 0x01000000) + local B2, R2 = modf( 0x01000000 * R1 / 0x00010000) + local B3, R3 = modf( 0x00010000 * R2 / 0x00000100) + local B4 = 0x00000100 * R3 + + local L64 = char( 0) .. char( 0) .. char( 0) .. char( 0) -- high 32 bits + .. char(B1) .. char(B2) .. char(B3) .. char(B4) -- low 32 bits + + msg = msg .. first_append .. second_append .. L64 + + assert(#msg % 64 == 0) + + local chunks = #msg / 64 + + local W = { } + local start, A, B, C, D, E, f, K, TEMP + local chunk = 0 + + while chunk < chunks do + -- + -- break chunk up into W[0] through W[15] + -- + start,chunk = chunk * 64 + 1,chunk + 1 + + for t = 0, 15 do + W[t] = bytes_to_w32(msg:byte(start, start + 3)) + start = start + 4 + end + + -- + -- build W[16] through W[79] + -- + for t = 16, 79 do + -- For t = 16 to 79 let Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16). + W[t] = w32_rot(1, w32_xor_n(W[t-3], W[t-8], W[t-14], W[t-16])) + end + + A,B,C,D,E = H0,H1,H2,H3,H4 + + for t = 0, 79 do + if t <= 19 then + -- (B AND C) OR ((NOT B) AND D) + f = w32_or(w32_and(B, C), w32_and(w32_not(B), D)) + K = 0x5A827999 + elseif t <= 39 then + -- B XOR C XOR D + f = w32_xor_n(B, C, D) + K = 0x6ED9EBA1 + elseif t <= 59 then + -- (B AND C) OR (B AND D) OR (C AND D + f = w32_or3(w32_and(B, C), w32_and(B, D), w32_and(C, D)) + K = 0x8F1BBCDC + else + -- B XOR C XOR D + f = w32_xor_n(B, C, D) + K = 0xCA62C1D6 + end + + -- TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt; + A,B,C,D,E = w32_add_n(w32_rot(5, A), f, E, W[t], K), + A, w32_rot(30, B), C, D + end + -- Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E. + H0,H1,H2,H3,H4 = w32_add(H0, A),w32_add(H1, B),w32_add(H2, C),w32_add(H3, D),w32_add(H4, E) + end + local f = w32_to_hexstring + return f(H0) .. f(H1) .. f(H2) .. f(H3) .. f(H4) +end + +local function hex_to_binary(hex) + return hex:gsub('..', function(hexval) + return string.char(tonumber(hexval, 16)) + end) +end + +function sha1.bin(msg) + return hex_to_binary(sha1.hex(msg)) +end + +local xor_with_0x5c = {} +local xor_with_0x36 = {} +-- building the lookuptables ahead of time (instead of littering the source code +-- with precalculated values) +for i=0,0xff do + xor_with_0x5c[char(i)] = char(bxor(i,0x5c)) + xor_with_0x36[char(i)] = char(bxor(i,0x36)) +end + +local blocksize = 64 -- 512 bits + +function sha1.hmacHex(key, text) + assert(type(key) == 'string', "key passed to hmacHex should be a string") + assert(type(text) == 'string', "text passed to hmacHex should be a string") + + if #key > blocksize then + key = sha1.bin(key) + end + + local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. string.rep(string.char(0x36), blocksize - #key) + local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. string.rep(string.char(0x5c), blocksize - #key) + + return sha1.hex(key_xord_with_0x5c .. sha1.bin(key_xord_with_0x36 .. text)) +end + +function sha1.hmacBin(key, text) + return hex_to_binary(sha1.hmacHex(key, text)) +end + +return sha1 +end)() + + + +-- mpv_thumbnail_script/src/options.lua +local SCRIPT_NAME = "mpv_thumbnail_script" + +local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/" + +local thumbnailer_options = { + -- The thumbnail directory + cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"), + + ------------------------ + -- Generation options -- + ------------------------ + + -- Automatically generate the thumbnails on video load, without a keypress + autogenerate = true, + + -- Only automatically thumbnail videos shorter than this (seconds) + autogenerate_max_duration = 3600, -- 1 hour + + -- SHA1-sum filenames over this length + -- It's nice to know what files the thumbnails are (hence directory names) + -- but long URLs may approach filesystem limits. + hash_filename_length = 128, + + -- Use mpv to generate thumbnail even if ffmpeg is found in PATH + -- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)! + -- mpv is a bit slower, but has better support overall (eg. subtitles in the previews) + prefer_mpv = true, + + -- Explicitly disable subtitles on the mpv sub-calls + mpv_no_sub = false, + -- Add a "--no-config" to the mpv sub-call arguments + mpv_no_config = false, + -- Add a "--profile=" to the mpv sub-call arguments + -- Use "" to disable + mpv_profile = "", + -- Output debug logs to .log, ala //000000.bgra.log + -- The logs are removed after successful encodes, unless you set mpv_keep_logs below + mpv_logs = true, + -- Keep all mpv logs, even the succesfull ones + mpv_keep_logs = false, + + -- Disable the built-in keybind ("T") to add your own + disable_keybinds = false, + + --------------------- + -- Display options -- + --------------------- + + -- Move the thumbnail up or down + -- For example: + -- topbar/bottombar: 24 + -- rest: 0 + vertical_offset = 24, + + -- Adjust background padding + -- Examples: + -- topbar: 0, 10, 10, 10 + -- bottombar: 10, 0, 10, 10 + -- slimbox/box: 10, 10, 10, 10 + pad_top = 10, + pad_bot = 0, + pad_left = 10, + pad_right = 10, + + -- If true, pad values are screen-pixels. If false, video-pixels. + pad_in_screenspace = true, + -- Calculate pad into the offset + offset_by_pad = true, + + -- Background color in BBGGRR + background_color = "000000", + -- Alpha: 0 - fully opaque, 255 - transparent + background_alpha = 80, + + -- Keep thumbnail on the screen near left or right side + constrain_to_screen = true, + + -- Do not display the thumbnailing progress + hide_progress = false, + + ----------------------- + -- Thumbnail options -- + ----------------------- + + -- The maximum dimensions of the thumbnails (pixels) + thumbnail_width = 200, + thumbnail_height = 200, + + -- The thumbnail count target + -- (This will result in a thumbnail every ~10 seconds for a 25 minute video) + thumbnail_count = 150, + + -- The above target count will be adjusted by the minimum and + -- maximum time difference between thumbnails. + -- The thumbnail_count will be used to calculate a target separation, + -- and min/max_delta will be used to constrict it. + + -- In other words, thumbnails will be: + -- at least min_delta seconds apart (limiting the amount) + -- at most max_delta seconds apart (raising the amount if needed) + min_delta = 5, + -- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours! + max_delta = 90, + + + -- Overrides for remote urls (you generally want less thumbnails!) + -- Thumbnailing network paths will be done with mpv + + -- Allow thumbnailing network paths (naive check for "://") + thumbnail_network = false, + -- Override thumbnail count, min/max delta + remote_thumbnail_count = 60, + remote_min_delta = 15, + remote_max_delta = 120, + + -- Try to grab the raw stream and disable ytdl for the mpv subcalls + -- Much faster than passing the url to ytdl again, but may cause problems with some sites + remote_direct_stream = true, +} + +read_options(thumbnailer_options, SCRIPT_NAME) + + + +-- mpv_thumbnail_script/src/thumbnailer_shared.lua +local Thumbnailer = { + cache_directory = thumbnailer_options.cache_directory, + + state = { + ready = false, + available = false, + enabled = false, + + thumbnail_template = nil, + + thumbnail_delta = nil, + thumbnail_count = 0, + + thumbnail_size = nil, + + finished_thumbnails = 0, + + -- List of thumbnail states (from 1 to thumbnail_count) + -- ready: 1 + -- in progress: 0 + -- not ready: -1 + thumbnails = {}, + + worker_input_path = nil, + -- Extra options for the workers + worker_extra = {}, + }, + -- Set in register_client + worker_register_timeout = nil, + -- A timer used to wait for more workers in case we have none + worker_wait_timer = nil, + workers = {} +} + +function Thumbnailer:clear_state() + clear_table(self.state) + self.state.ready = false + self.state.available = false + self.state.finished_thumbnails = 0 + self.state.thumbnails = {} + self.state.worker_extra = {} +end + + +function Thumbnailer:on_file_loaded() + self:clear_state() +end + +function Thumbnailer:on_thumb_ready(index) + self.state.thumbnails[index] = 1 + + -- Full recount instead of a naive increment (let's be safe!) + self.state.finished_thumbnails = 0 + for i, v in pairs(self.state.thumbnails) do + if v > 0 then + self.state.finished_thumbnails = self.state.finished_thumbnails + 1 + end + end +end + +function Thumbnailer:on_thumb_progress(index) + if self.state.thumbnails[index] == nil then + msg.warn("self.state.thumbnails[index] == nil", index, "count", #self.state.thumbnails) + return + end + self.state.thumbnails[index] = math.max(self.state.thumbnails[index], 0) +end + +function Thumbnailer:on_start_file() + -- Clear state when a new file is being loaded + self:clear_state() +end + +function Thumbnailer:on_video_change(params) + -- Gather a new state when we get proper video-dec-params and our state is empty + if params ~= nil then + if not self.state.ready then + self:update_state() + end + end +end + + +function Thumbnailer:update_state() + msg.debug("Gathering video/thumbnail state") + + self.state.thumbnail_delta = self:get_delta() + self.state.thumbnail_count = self:get_thumbnail_count(self.state.thumbnail_delta) + + -- Prefill individual thumbnail states + for i = 1, self.state.thumbnail_count do + self.state.thumbnails[i] = -1 + end + + self.state.thumbnail_template, self.state.thumbnail_directory = self:get_thumbnail_template() + self.state.thumbnail_size = self:get_thumbnail_size() + + self.state.ready = true + + local file_path = mp.get_property_native("path") + self.state.is_remote = file_path:find("://") ~= nil + + self.state.available = false + + -- Make sure the file has video (and not just albumart) + local track_list = mp.get_property_native("track-list") + local has_video = false + for i, track in pairs(track_list) do + if track.type == "video" and not track.external and not track.albumart then + has_video = true + break + end + end + + if has_video and self.state.thumbnail_delta ~= nil and self.state.thumbnail_size ~= nil and self.state.thumbnail_count > 0 then + self.state.available = true + end + + msg.debug("Thumbnailer.state:", utils.to_string(self.state)) + +end + + +function Thumbnailer:get_thumbnail_template() + local file_path = mp.get_property_native("path") + local is_remote = file_path:find("://") ~= nil + + local filename = mp.get_property_native("filename/no-ext") + local filesize = mp.get_property_native("file-size", 0) + + if is_remote then + filesize = 0 + end + + filename = filename:gsub('[^a-zA-Z0-9_.%-\' ]', '') + -- Hash overly long filenames (most likely URLs) + if #filename > thumbnailer_options.hash_filename_length then + filename = sha1.hex(filename) + end + + local file_key = ("%s-%d"):format(filename, filesize) + + local thumbnail_directory = join_paths(self.cache_directory, file_key) + local file_template = join_paths(thumbnail_directory, "%06d.bgra") + return file_template, thumbnail_directory +end + + +function Thumbnailer:get_thumbnail_size() + local video_dec_params = mp.get_property_native("video-dec-params") + if video_dec_params == nil then + return nil + end + local video_width = video_dec_params.dw + local video_height = video_dec_params.dh + if not (video_width and video_height) then + return nil + end + + local w, h + if video_width > video_height then + w = thumbnailer_options.thumbnail_width + h = math.floor(video_height * (w / video_width)) + else + h = thumbnailer_options.thumbnail_height + w = math.floor(video_width * (h / video_height)) + end + return { w=w, h=h } +end + + +function Thumbnailer:get_delta() + local file_path = mp.get_property_native("path") + local file_duration = mp.get_property_native("duration") + local is_seekable = mp.get_property_native("seekable") + + -- Naive url check + local is_remote = file_path:find("://") ~= nil + + local remote_and_disallowed = is_remote + if is_remote and thumbnailer_options.thumbnail_network then + remote_and_disallowed = false + end + + if remote_and_disallowed or not is_seekable or not file_duration then + -- Not a local path (or remote thumbnails allowed), not seekable or lacks duration + return nil + end + + local thumbnail_count = thumbnailer_options.thumbnail_count + local min_delta = thumbnailer_options.min_delta + local max_delta = thumbnailer_options.max_delta + + if is_remote then + thumbnail_count = thumbnailer_options.remote_thumbnail_count + min_delta = thumbnailer_options.remote_min_delta + max_delta = thumbnailer_options.remote_max_delta + end + + local target_delta = (file_duration / thumbnail_count) + local delta = math.max(min_delta, math.min(max_delta, target_delta)) + + return delta +end + + +function Thumbnailer:get_thumbnail_count(delta) + if delta == nil then + return 0 + end + local file_duration = mp.get_property_native("duration") + + return math.ceil(file_duration / delta) +end + +function Thumbnailer:get_closest(thumbnail_index) + -- Given a 1-based index, find the closest available thumbnail and return it's 1-based index + + -- Check the direct thumbnail index first + if self.state.thumbnails[thumbnail_index] > 0 then + return thumbnail_index + end + + local min_distance = self.state.thumbnail_count + 1 + local closest = nil + + -- Naive, inefficient, lazy. But functional. + for index, value in pairs(self.state.thumbnails) do + local distance = math.abs(index - thumbnail_index) + if distance < min_distance and value > 0 then + min_distance = distance + closest = index + end + end + return closest +end + +function Thumbnailer:get_thumbnail_index(time_position) + -- Returns a 1-based thumbnail index for the given timestamp (between 1 and thumbnail_count, inclusive) + if self.state.thumbnail_delta and (self.state.thumbnail_count and self.state.thumbnail_count > 0) then + return math.min(math.floor(time_position / self.state.thumbnail_delta) + 1, self.state.thumbnail_count) + else + return nil + end +end + +function Thumbnailer:get_thumbnail_path(time_position) + -- Given a timestamp, return: + -- the closest available thumbnail path (if any) + -- the 1-based thumbnail index calculated from the timestamp + -- the 1-based thumbnail index of the closest available (and used) thumbnail + -- OR nil if thumbnails are not available. + + local thumbnail_index = self:get_thumbnail_index(time_position) + if not thumbnail_index then return nil end + + local closest = self:get_closest(thumbnail_index) + + if closest ~= nil then + return self.state.thumbnail_template:format(closest-1), thumbnail_index, closest + else + return nil, thumbnail_index, nil + end +end + +function Thumbnailer:register_client() + self.worker_register_timeout = mp.get_time() + 2 + + mp.register_script_message("mpv_thumbnail_script-ready", function(index, path) + self:on_thumb_ready(tonumber(index), path) + end) + mp.register_script_message("mpv_thumbnail_script-progress", function(index, path) + self:on_thumb_progress(tonumber(index), path) + end) + + mp.register_script_message("mpv_thumbnail_script-worker", function(worker_name) + if not self.workers[worker_name] then + msg.debug("Registered worker", worker_name) + self.workers[worker_name] = true + mp.commandv("script-message-to", worker_name, "mpv_thumbnail_script-slaved") + end + end) + + -- Notify workers to generate thumbnails when video loads/changes + -- This will be executed after the on_video_change (because it's registered after it) + mp.observe_property("video-dec-params", "native", function() + local duration = mp.get_property_native("duration") + local max_duration = thumbnailer_options.autogenerate_max_duration + + if duration ~= nil and self.state.available and thumbnailer_options.autogenerate then + -- Notify if autogenerate is on and video is not too long + if duration < max_duration or max_duration == 0 then + self:start_worker_jobs() + end + end + end) + + local thumb_script_key = not thumbnailer_options.disable_keybinds and "T" or nil + mp.add_key_binding(thumb_script_key, "generate-thumbnails", function() + if self.state.available then + mp.osd_message("Started thumbnailer jobs") + self:start_worker_jobs() + else + mp.osd_message("Thumbnailing unavailable") + end + end) +end + +function Thumbnailer:_create_thumbnail_job_order() + -- Returns a list of 1-based thumbnail indices in a job order + local used_frames = {} + local work_frames = {} + + -- Pick frames in increasing frequency. + -- This way we can do a quick few passes over the video and then fill in the gaps. + for x = 6, 0, -1 do + local nth = (2^x) + + for thi = 1, self.state.thumbnail_count, nth do + if not used_frames[thi] then + table.insert(work_frames, thi) + used_frames[thi] = true + end + end + end + return work_frames +end + +function Thumbnailer:prepare_source_path() + local file_path = mp.get_property_native("path") + + if self.state.is_remote and thumbnailer_options.remote_direct_stream then + -- Use the direct stream (possibly) provided by ytdl + -- This skips ytdl on the sub-calls, making the thumbnailing faster + -- Works well on YouTube, rest not really tested + file_path = mp.get_property_native("stream-path") + file_path = file_path:gsub(",ytdl_description.+", "") + + -- edl:// urls can get LONG. In which case, save the path (URL) + -- to a temporary file and use that instead. + local playlist_filename = join_paths(self.state.thumbnail_directory, "playlist.txt") + + if #file_path > 8000 then + -- Path is too long for a playlist - just pass the original URL to + -- workers and allow ytdl + self.state.worker_extra.enable_ytdl = true + file_path = mp.get_property_native("path") + msg.warn("Falling back to original URL and ytdl due to LONG source path. This will be slow.") + + elseif #file_path > 1024 then + local playlist_file = io.open(playlist_filename, "wb") + if not playlist_file then + msg.error(("Tried to write a playlist to %s but couldn't!"):format(playlist_file)) + return false + end + + playlist_file:write(file_path .. "\n") + playlist_file:close() + + file_path = "--playlist=" .. playlist_filename + msg.warn("Using playlist workaround due to long source path") + end + end + + self.state.worker_input_path = file_path + return true +end + +function Thumbnailer:start_worker_jobs() + -- Create directory for the thumbnails, if needed + local l, err = utils.readdir(self.state.thumbnail_directory) + if err then + msg.debug("Creating thumbnail directory", self.state.thumbnail_directory) + create_directories(self.state.thumbnail_directory) + end + + -- Try to prepare the source path for workers, and bail if unable to do so + if not self:prepare_source_path() then + return + end + + local worker_list = {} + for worker_name in pairs(self.workers) do table.insert(worker_list, worker_name) end + + local worker_count = #worker_list + + -- In case we have a worker timer created already, clear it + -- (For example, if the video-dec-params change in quick succession or the user pressed T, etc) + if self.worker_wait_timer then + self.worker_wait_timer:stop() + end + + if worker_count == 0 then + local now = mp.get_time() + if mp.get_time() > self.worker_register_timeout then + -- Workers have had their time to register but we have none! + local err = "No thumbnail workers found. Make sure you are not missing a script!" + msg.error(err) + mp.osd_message(err, 3) + + else + -- We may be too early. Delay the work start a bit to try again. + msg.warn("No workers found. Waiting a bit more for them.") + -- Wait at least half a second + local wait_time = math.max(self.worker_register_timeout - now, 0.5) + self.worker_wait_timer = mp.add_timeout(wait_time, function() self:start_worker_jobs() end) + end + + else + -- We have at least one worker. This may not be all of them, but they have had + -- their time to register; we've done our best waiting for them. + self.state.enabled = true + + msg.debug( ("Splitting %d thumbnails amongst %d worker(s)"):format(self.state.thumbnail_count, worker_count) ) + + local frame_job_order = self:_create_thumbnail_job_order() + local worker_jobs = {} + for i = 1, worker_count do worker_jobs[worker_list[i]] = {} end + + -- Split frames amongst the workers + for i, thumbnail_index in ipairs(frame_job_order) do + local worker_id = worker_list[ ((i-1) % worker_count) + 1 ] + table.insert(worker_jobs[worker_id], thumbnail_index) + end + + local state_json_string = utils.format_json(self.state) + msg.debug("Giving workers state:", state_json_string) + + for worker_name, worker_frames in pairs(worker_jobs) do + if #worker_frames > 0 then + local frames_json_string = utils.format_json(worker_frames) + msg.debug("Assigning job to", worker_name, frames_json_string) + mp.commandv("script-message-to", worker_name, "mpv_thumbnail_script-job", state_json_string, frames_json_string) + end + end + end +end + +mp.register_event("start-file", function() Thumbnailer:on_start_file() end) +mp.observe_property("video-dec-params", "native", function(name, params) Thumbnailer:on_video_change(params) end) + + +-- osc_tethys ExecutableFinder checks +ExecutableFinder.hasChecked = false +ExecutableFinder.hasFfmpeg = false +ExecutableFinder.hasMpv = false +ExecutableFinder.hasMpvNet = false +function ExecutableFinder:check() + if ExecutableFinder.hasChecked then + return + end + ExecutableFinder.hasFfmpeg = ExecutableFinder:get_executable_path("ffmpeg") + ExecutableFinder.hasMpv = ExecutableFinder:get_executable_path("mpv") + ExecutableFinder.hasMpvNet = ExecutableFinder:get_executable_path("mpvnet") + ExecutableFinder.hasChecked = true + -- msg.warn("hasFfmpeg", ExecutableFinder.hasFfmpeg) + -- msg.warn("hasMpv", ExecutableFinder.hasMpv) + -- msg.warn("hasMpvNet", ExecutableFinder.hasMpvNet) +end + + +-- osc_tethys mpv_thumbnail_script overrides +thumbnailer_options.thumbnail_width = tethys.thumbnailSize +thumbnailer_options.thumbnail_height = tethys.thumbnailSize +thumbnailer_options.mpv_no_config = true +thumbnailer_options.mpv_no_sub = true +thumbnailer_options.hide_progress = true -- Not implemented + +Thumbnailer:register_client() + + +-- Thumbnail State +function ThumbState() + return { + overlayId = 1, + visible = false, + wasVisible = false, + thumbPath = nil, + globalWidth = nil, + globalHeight = nil, + } +end +local seekbarThumb = ThumbState() +seekbarThumb.overlayId = 1 + + + + + + + + + + + + + + + + + + + +-- Render Funcs +function calcTrackButtonWidth(trackArr) + -- "ICON -/0" or "ICON 1/1" or "ICON 1/10" + local trackButtonSize = tethys.trackButtonSize + local trackIconWidth = trackButtonSize * (32/23.273) + local trackDigitWidth = trackButtonSize * (tethys.trackTextScale / 100) * 0.4 + local spaceDigitRatio = 0.4 + local slashDigitRatio = 0.7 + -- print("trackButtonSize", trackButtonSize) + -- print("trackIconWidth", trackIconWidth) + -- print("trackDigitWidth", trackDigitWidth) + local numTrackDigits = 1 + if trackArr ~= nil and #trackArr > 0 then + numTrackDigits = math.floor(math.log(#trackArr, 10)) + 1 + end + local trackButtonWidth = math.ceil(trackIconWidth + trackDigitWidth * (spaceDigitRatio + numTrackDigits + slashDigitRatio + numTrackDigits)) + -- print("numTrackDigits", numTrackDigits) + -- print("trackButtonWidth", trackButtonWidth) + return trackButtonWidth +end + +-- Thumbnail Funcs +function canShowThumb(videoPath) + local isRemote = videoPath:find("://") ~= nil + ExecutableFinder:check() + if not (ExecutableFinder.hasMpv or ExecutableFinder.hasMpvNet or ExecutableFinder.hasFfmpeg) then + return false + end + if isRemote then + return false + end + return true +end + +function showThumbnail(thumbState, globalX, globalY) + -- https://mpv.io/manual/master/#command-interface-overlay-add + -- msg.warn("showThumbnail", thumbState.overlayId) + mp.command_native({ + "overlay-add", thumbState.overlayId, + globalX, globalY, + thumbState.thumbPath, + 0, -- byte offset + "bgra", -- image format + thumbState.globalWidth, thumbState.globalHeight, + thumbState.globalWidth * 4, -- "stride" + }) + thumbState.visible = true +end +function hideThumbnail(thumbState) + -- https://mpv.io/manual/master/#command-interface-overlay-remove + -- msg.warn("hideThumbnail", thumbState.overlayId) + mp.command_native({ + "overlay-remove", thumbState.overlayId, + }) +end +function thumbPreRender(thumbState) + thumbState.wasVisible = thumbState.visible + thumbState.visible = false +end +function thumbPostRender(thumbState) + if not thumbState.visible and thumbState.wasVisible then + hideThumbnail(thumbState) + end +end +function preRenderThumbnails() + thumbPreRender(seekbarThumb) +end +function postRenderThumbnails() + thumbPostRender(seekbarThumb) +end + +-- From: Slider.tooltipF(pos) +function formatTimestamp(percent) + local duration = mp.get_property_number("duration", nil) + if not ((duration == nil) or (percent == nil)) then + local sec = duration * (percent / 100) + return mp.format_time(sec) + else + return "" + end +end + +-- Seekbar Tooltip +function renderThumbnailTooltip(pos, sliderPos, ass) + local tooltipBgColor = "FFFFFF" + local tooltipBgAlpha = 80 + local thumbOutline = 3 + + local videoPath = mp.get_property_native("path", nil) + local videoDuration = mp.get_property_number("duration", nil) + -- msg.warn("sliderPos", sliderPos, "videoDuration", videoDuration, "videoPath", videoPath) + if (videoPath == nil) or (videoDuration == nil) or (sliderPos == nil) then + return + end + local thumbTime = videoDuration * (sliderPos / 100) + local thumbTimestamp = mp.format_time(thumbTime) -- ffmpeg requires "HH:MM:SS.zzz" for seeking + local timestampLabel = thumbTimestamp + -- msg.warn("thumbTime", thumbTime, "timestampLabel", timestampLabel) + + ---- Geometry + local scaleX, scaleY = get_virt_scale_factor() + local videoDecParams = mp.get_property_native("video-dec-params") + if videoDecParams == nil then + return + end + local videoWidth = videoDecParams.dw + local videoHeight = videoDecParams.dh + if not (videoWidth and videoHeight) then + return + end + + local thumb_size = Thumbnailer.state.thumbnail_size + if thumb_size == nil then + return + end + local thumbGlobalWidth = thumb_size.w + local thumbGlobalHeight = thumb_size.h + local thumbWidth = math.floor(thumbGlobalWidth * scaleX) + local thumbHeight = math.floor(thumbGlobalHeight * scaleY) + + local chapter = get_chapter(thumbTime) + local hasChapter = not (chapter == nil) and chapter.title and chapter.title ~= "" + local showChapter = hasChapter and tethys.showChapterTooltip + local chapterLabel = "" + local chapterHeight = 0 + if showChapter then + chapterHeight = tethys.seekbarTimestampSize + chapterLabel = chapter.title + end + + local timestampWidth = thumbWidth + local timestampHeight = tethys.seekbarTimestampSize + + local bgHeight = thumbOutline + thumbHeight + thumbOutline + + local tooltipWidth = thumbOutline + thumbWidth + thumbOutline + local tooltipHeight = bgHeight + chapterHeight + timestampHeight + + + -- Note: pos x,y is an=2 (bottom-center) + local windowWidth = osc_param.playresx + local tooltipX = math.floor(pos.x - tooltipWidth/2) + local tooltipY = math.floor(pos.y - tooltipHeight) + local textAn = 5 -- x,y is center + local isLongChapter + if tooltipX < 0 then + tooltipX = 0 + textAn = 4 -- x,y is left-center + elseif windowWidth - tooltipWidth < tooltipX then + tooltipX = windowWidth - tooltipWidth + textAn = 6 -- x,y is right-center + end + + local thumbX = tooltipX + thumbOutline + local thumbY = tooltipY + thumbOutline + local thumbGlobalX = math.floor(thumbX / scaleX) + local thumbGlobalY = math.floor(thumbY / scaleY) + -- msg.warn("thumbX", thumbX, "thumbY", thumbY, "thumbGlobalX", thumbGlobalX, "thumbGlobalY", thumbGlobalY) + + + local longChapterTitle = chapterLabel:len() >= 30 + local chapterAn = longChapterTitle and textAn or 5 -- x,y is center + local chapterX + if chapterAn == 4 then -- Left-Center + chapterX = thumbX + elseif chapterAn == 6 then -- Right-Center + chapterX = thumbX + thumbWidth + else -- Center + chapterX = thumbX + math.floor(thumbWidth/2) + end + local chapterY = thumbY + thumbHeight + math.floor(chapterHeight/2) + + local timestampAn = 5 -- x,y is center + local timestampX = thumbX + math.floor(thumbWidth/2) + local timestampY = thumbY + thumbHeight + chapterHeight + math.floor(timestampHeight/2) + + ---- Chapter + if showChapter then + ass:new_event() + ass:pos(chapterX, chapterY) + ass:an(chapterAn) + ass:append(tethysStyle.seekbarTimestamp) + ass:append(chapterLabel) + end + + ---- Timestamp + ass:new_event() + ass:pos(timestampX, timestampY) + ass:an(timestampAn) + ass:append(tethysStyle.seekbarTimestamp) + ass:append(timestampLabel) + + -- If thumbnails are not available, bail + if not (Thumbnailer.state.enabled and Thumbnailer.state.available) then + return + end + + local thumbPath, thumbIndex, closestIndex = Thumbnailer:get_thumbnail_path(thumbTime) + -- msg.warn("renderThumbnailTooltip", thumbIndex, closestIndex, thumbPath) + + if thumbPath then + ---- Thumb BG/Outline + ass:new_event() + ass:pos(tooltipX, tooltipY) + ass:an(7) + ass:append(("{\\bord0\\1c&H%s&\\1a&H%X&}"):format(tooltipBgColor, tooltipBgAlpha)) + ass:draw_start() + ass:rect_cw(0, 0, tooltipWidth, bgHeight) + ass:draw_stop() + + ---- Thumb BG + if not (tooltipBgAlpha == 0) then + -- Overlay Image must be drawn on top of a solid color or else it'll look + -- like it was filtered. + ass:new_event() + ass:pos(thumbX, thumbY) + ass:an(7) + ass:append(("{\\bord0\\1c&H%s&\\1a&H%X&}"):format(tooltipBgColor, 0)) + ass:draw_start() + ass:rect_cw(0, 0, thumbWidth, thumbHeight) + ass:draw_stop() + end + + ---- Render Thumbnail + seekbarThumb.thumbPath = thumbPath + seekbarThumb.globalWidth = thumbGlobalWidth + seekbarThumb.globalHeight = thumbGlobalHeight + showThumbnail(seekbarThumb, thumbGlobalX, thumbGlobalY) + end +end + +-- Playlist Tooltip +function renderPlaylistTooltip(pos, playlistDelta, ass) + local deltaItem = getDeltaPlaylistItem(playlistDelta) + if deltaItem == nil then + return nil + end + + local videoPath = deltaItem.filename + local thumbTimestamp = mp.format_time(0.5) + local thumbGlobalWidth = 100 + local thumbGlobalHeight = 100 +end + + + + + + + + + + + + + + + + + + + +-- internal states, do not touch +local state = { + showtime, -- time of last invocation (last mouse move) + osc_visible = false, + anistart, -- time when the animation started + anitype, -- current type of animation + animation, -- current animation alpha + mouse_down_counter = 0, -- used for softrepeat + active_element = nil, -- nil = none, 0 = background, 1+ = see elements[] + active_event_source = nil, -- the "button" that issued the current event + rightTC_trem = not user_opts.timetotal, -- if the right timecode should display total or remaining time + tc_ms = user_opts.timems, -- Should the timecodes display their time with milliseconds + mp_screen_sizeX, mp_screen_sizeY, -- last screen-resolution, to detect resolution changes to issue reINITs + initREQ = false, -- is a re-init request pending? + marginsREQ = false, -- is a margins update pending? + last_mouseX, last_mouseY, -- last mouse position, to detect significant mouse movement + mouse_in_window = false, + message_text, + message_hide_timer, + fullscreen = false, + tick_timer = nil, + tick_last_time = 0, -- when the last tick() was run + hide_timer = nil, + cache_state = nil, + idle = false, + enabled = true, + input_enabled = true, + showhide_enabled = false, + dmx_cache = 0, + using_video_margins = false, + border = true, + maximized = false, + osd = mp.create_osd_overlay("ass-events"), + chapter_list = {}, -- sorted by time +} + +local window_control_box_width = 80 +local tick_delay = 0.03 + +local is_december = os.date("*t").month == 12 + +-- +-- Helperfunctions +-- + +function kill_animation() + state.anistart = nil + state.animation = nil + state.anitype = nil +end + +function set_osd(res_x, res_y, text) + if state.osd.res_x == res_x and + state.osd.res_y == res_y and + state.osd.data == text then + return + end + state.osd.res_x = res_x + state.osd.res_y = res_y + state.osd.data = text + state.osd.z = 1000 + state.osd:update() +end + +local margins_opts = { + {"l", "video-margin-ratio-left"}, + {"r", "video-margin-ratio-right"}, + {"t", "video-margin-ratio-top"}, + {"b", "video-margin-ratio-bottom"}, +} + +-- scale factor for translating between real and virtual ASS coordinates +function get_virt_scale_factor() + local w, h = mp.get_osd_size() + if w <= 0 or h <= 0 then + return 0, 0 + end + return osc_param.playresx / w, osc_param.playresy / h +end + +-- return mouse position in virtual ASS coordinates (playresx/y) +function get_virt_mouse_pos() + if state.mouse_in_window then + local sx, sy = get_virt_scale_factor() + local x, y = mp.get_mouse_pos() + return x * sx, y * sy + else + return -1, -1 + end +end + +function set_virt_mouse_area(x0, y0, x1, y1, name) + local sx, sy = get_virt_scale_factor() + mp.set_mouse_area(x0 / sx, y0 / sy, x1 / sx, y1 / sy, name) +end + +function scale_value(x0, x1, y0, y1, val) + local m = (y1 - y0) / (x1 - x0) + local b = y0 - (m * x0) + return (m * val) + b +end + +-- returns hitbox spanning coordinates (top left, bottom right corner) +-- according to alignment +function get_hitbox_coords(x, y, an, w, h) + + local alignments = { + [1] = function () return x, y-h, x+w, y end, + [2] = function () return x-(w/2), y-h, x+(w/2), y end, + [3] = function () return x-w, y-h, x, y end, + + [4] = function () return x, y-(h/2), x+w, y+(h/2) end, + [5] = function () return x-(w/2), y-(h/2), x+(w/2), y+(h/2) end, + [6] = function () return x-w, y-(h/2), x, y+(h/2) end, + + [7] = function () return x, y, x+w, y+h end, + [8] = function () return x-(w/2), y, x+(w/2), y+h end, + [9] = function () return x-w, y, x, y+h end, + } + + return alignments[an]() +end + +function get_hitbox_coords_geo(geometry) + return get_hitbox_coords(geometry.x, geometry.y, geometry.an, + geometry.w, geometry.h) +end + +function get_element_hitbox(element) + return element.hitbox.x1, element.hitbox.y1, + element.hitbox.x2, element.hitbox.y2 +end + +function mouse_hit(element) + return mouse_hit_coords(get_element_hitbox(element)) +end + +function mouse_hit_coords(bX1, bY1, bX2, bY2) + local mX, mY = get_virt_mouse_pos() + return (mX >= bX1 and mX <= bX2 and mY >= bY1 and mY <= bY2) +end + +function limit_range(min, max, val) + if val > max then + val = max + elseif val < min then + val = min + end + return val +end + +-- translate value into element coordinates +function get_slider_ele_pos_for(element, val) + + local ele_pos = scale_value( + element.slider.min.value, element.slider.max.value, + element.slider.min.ele_pos, element.slider.max.ele_pos, + val) + + return limit_range( + element.slider.min.ele_pos, element.slider.max.ele_pos, + ele_pos) +end + +-- translates global (mouse) coordinates to value +function get_slider_value_at(element, glob_pos) + + local val = scale_value( + element.slider.min.glob_pos, element.slider.max.glob_pos, + element.slider.min.value, element.slider.max.value, + glob_pos) + + return limit_range( + element.slider.min.value, element.slider.max.value, + val) +end + +-- get value at current mouse position +function get_slider_value(element) + return get_slider_value_at(element, get_virt_mouse_pos()) +end + +function countone(val) + if not (user_opts.iamaprogrammer) then + val = val + 1 + end + return val +end + +-- align: -1 .. +1 +-- frame: size of the containing area +-- obj: size of the object that should be positioned inside the area +-- margin: min. distance from object to frame (as long as -1 <= align <= +1) +function get_align(align, frame, obj, margin) + return (frame / 2) + (((frame / 2) - margin - (obj / 2)) * align) +end + +-- multiplies two alpha values, formular can probably be improved +function mult_alpha(alphaA, alphaB) + return 255 - (((1-(alphaA/255)) * (1-(alphaB/255))) * 255) +end + +function add_area(name, x1, y1, x2, y2) + -- create area if needed + if (osc_param.areas[name] == nil) then + osc_param.areas[name] = {} + end + table.insert(osc_param.areas[name], {x1=x1, y1=y1, x2=x2, y2=y2}) +end + +function ass_append_alpha(ass, alpha, modifier) + local ar = {} + + for ai, av in pairs(alpha) do + av = mult_alpha(av, modifier) + if state.animation then + av = mult_alpha(av, state.animation) + end + ar[ai] = av + end + + ass:append(string.format("{\\1a&H%X&\\2a&H%X&\\3a&H%X&\\4a&H%X&}", + ar[1], ar[2], ar[3], ar[4])) +end + +function ass_draw_rr_h_cw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_cw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_cw(x0, y0, x1, y1, r1, r2) + end +end + +function ass_draw_rr_h_ccw(ass, x0, y0, x1, y1, r1, hexagon, r2) + if hexagon then + ass:hexagon_ccw(x0, y0, x1, y1, r1, r2) + else + ass:round_rect_ccw(x0, y0, x1, y1, r1, r2) + end +end + + +-- +-- Picture In Picture +-- + +function togglePictureInPicture() + local isPiP = tethys.isPictureInPicture + if isPiP then -- Disable + mp.commandv('set', 'on-all-workspaces', 'no') + if not tethys.pipWasOnTop then + mp.commandv('set', 'ontop', 'no') + end + if tethys.pipHadBorders then + mp.commandv('set', 'border', 'yes') + end + local videoDecParams = mp.get_property_native("video-dec-params") + if videoDecParams ~= nil then + local videoWidth = videoDecParams.dw + local videoHeight = videoDecParams.dh + if videoWidth and videoHeight then + mp.commandv('set', 'geometry', ''..videoWidth..'x'..videoHeight) + end + end + if tethys.pipWasMaximized then + mp.commandv('set', 'window-maximized', 'yes') + end + if tethys.pipWasFullscreen then + mp.commandv('set', 'fullscreen', 'yes') + end + else -- Enable + tethys.pipWasFullscreen = state.fullscreen + tethys.pipWasMaximized = state.maximized + tethys.pipWasOnTop = mp.get_property('ontop') == "yes" + tethys.pipHadBorders = state.border + mp.commandv('set', 'fullscreen', 'no') + mp.commandv('set', 'window-maximized', 'no') + mp.commandv('set', 'border', 'no') + mp.commandv('set', 'geometry', tethys.pipGeometry) + mp.commandv('set', 'ontop', 'yes') + if tethys.pipAllWorkspaces then + mp.commandv('set', 'on-all-workspaces', 'yes') + end + end + tethys.isPictureInPicture = not isPiP + if tethys.userdataAvail then + mp.set_property_native("user-data/pictureinpicture", tostring(tethys.isPictureInPicture)) + else + utils.shared_script_property_set("pictureinpicture", tostring(tethys.isPictureInPicture)) + end +end + + +-- +-- Tracklist Management +-- + +local nicetypes = {video = "Video", audio = "Audio", sub = "Subtitle"} + +-- updates the OSC internal playlists, should be run each time the track-layout changes +function update_tracklist() + local tracktable = mp.get_property_native("track-list", {}) + + -- by osc_id + tracks_osc = {} + tracks_osc.video, tracks_osc.audio, tracks_osc.sub = {}, {}, {} + -- by mpv_id + tracks_mpv = {} + tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {} + for n = 1, #tracktable do + if not (tracktable[n].type == "unknown") then + local type = tracktable[n].type + local mpv_id = tonumber(tracktable[n].id) + + -- by osc_id + table.insert(tracks_osc[type], tracktable[n]) + + -- by mpv_id + tracks_mpv[type][mpv_id] = tracktable[n] + tracks_mpv[type][mpv_id].osc_id = #tracks_osc[type] + end + end +end + +-- return a nice list of tracks of the given type (video, audio, sub) +function get_tracklist(type) + local msg = "Available " .. nicetypes[type] .. " Tracks: " + if not tracks_osc or #tracks_osc[type] == 0 then + msg = msg .. "none" + else + for n = 1, #tracks_osc[type] do + local track = tracks_osc[type][n] + local lang, title, selected = "unknown", "", "○" + if not(track.lang == nil) then lang = track.lang end + if not(track.title == nil) then title = track.title end + if (track.id == tonumber(mp.get_property(type))) then + selected = "●" + end + msg = msg.."\n"..selected.." "..n..": ["..lang.."] "..title + end + end + return msg +end + +-- relatively change the track of given by tracks + --(+1 -> next, -1 -> previous) +function set_track(type, next) + local current_track_mpv, current_track_osc + if (mp.get_property(type) == "no") then + current_track_osc = 0 + else + current_track_mpv = tonumber(mp.get_property(type)) + current_track_osc = tracks_mpv[type][current_track_mpv].osc_id + end + local new_track_osc = (current_track_osc + next) % (#tracks_osc[type] + 1) + local new_track_mpv + if new_track_osc == 0 then + new_track_mpv = "no" + else + new_track_mpv = tracks_osc[type][new_track_osc].id + end + + mp.commandv("set", type, new_track_mpv) + + if (new_track_osc == 0) then + show_message(nicetypes[type] .. " Track: none") + else + show_message(nicetypes[type] .. " Track: " + .. new_track_osc .. "/" .. #tracks_osc[type] + .. " [".. (tracks_osc[type][new_track_osc].lang or "unknown") .."] " + .. (tracks_osc[type][new_track_osc].title or "")) + end +end + +-- get the currently selected track of , OSC-style counted +function get_track(type) + local track = mp.get_property(type) + if track ~= "no" and track ~= nil then + local tr = tracks_mpv[type][tonumber(track)] + if tr then + return tr.osc_id + end + end + return 0 +end + +-- WindowControl helpers +function window_controls_enabled() + val = user_opts.windowcontrols + if val == "auto" then + return not state.border + else + return val ~= "no" + end +end + +function window_controls_alignment() + return user_opts.windowcontrols_alignment +end + +-- +-- Element Management +-- + +local elements = {} + +function new_ass_node(elem_ass) + elem_ass:append("{}") -- hack to troll new_event into inserting a \n + elem_ass:new_event() +end +function reset_ass(elem_ass, element) + new_ass_node(elem_ass) + local elem_geo = element.layout.geometry + elem_ass:pos(elem_geo.x, elem_geo.y) + elem_ass:an(elem_geo.an) + elem_ass:append(element.layout.style) +end + +function prepare_elements() + + -- remove elements without layout or invisble + local elements2 = {} + for n, element in pairs(elements) do + if not (element.layout == nil) and (element.visible) then + table.insert(elements2, element) + end + end + elements = elements2 + + function elem_compare (a, b) + return a.layout.layer < b.layout.layer + end + + table.sort(elements, elem_compare) + + + for _,element in pairs(elements) do + + local elem_geo = element.layout.geometry + + -- Calculate the hitbox + local bX1, bY1, bX2, bY2 = get_hitbox_coords_geo(elem_geo) + element.hitbox = {x1 = bX1, y1 = bY1, x2 = bX2, y2 = bY2} + + local style_ass = assdraw.ass_new() + + -- prepare static elements + reset_ass(style_ass, element) + -- style_ass:append("{}") -- hack to troll new_event into inserting a \n + -- style_ass:new_event() + -- style_ass:pos(elem_geo.x, elem_geo.y) + -- style_ass:an(elem_geo.an) + -- style_ass:append(element.layout.style) + + element.style_ass = style_ass + + local static_ass = assdraw.ass_new() + + + if (element.type == "box") then + --draw box + static_ass:draw_start() + ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, + element.layout.box.radius, element.layout.box.hexagon) + static_ass:draw_stop() + + elseif (element.type == "slider") then + --draw static slider parts + + local r1 = 0 + local r2 = 0 + local slider_lo = element.layout.slider + -- offset between element outline and drag-area + local foV = slider_lo.border + slider_lo.gap + + -- calculate positions of min and max points + if (slider_lo.stype ~= "bar") then + r1 = elem_geo.h / 2 + element.slider.min.ele_pos = elem_geo.h / 2 + element.slider.max.ele_pos = elem_geo.w - (elem_geo.h / 2) + if (slider_lo.stype == "diamond") then + r2 = (elem_geo.h - 2 * slider_lo.border) / 2 + elseif (slider_lo.stype == "knob") then + r2 = r1 + end + else + element.slider.min.ele_pos = + slider_lo.border + slider_lo.gap + element.slider.max.ele_pos = + elem_geo.w - (slider_lo.border + slider_lo.gap) + end + + element.slider.min.glob_pos = + element.hitbox.x1 + element.slider.min.ele_pos + element.slider.max.glob_pos = + element.hitbox.x1 + element.slider.max.ele_pos + + -- -- -- + + ---- This is drawn over + -- the box + -- static_ass:draw_start() + -- ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h, r1, slider_lo.stype == "diamond") + -- the "hole" + -- ass_draw_rr_h_ccw(static_ass, slider_lo.border, slider_lo.border, + -- elem_geo.w - slider_lo.border, elem_geo.h - slider_lo.border, + -- r2, slider_lo.stype == "diamond") + -- static_ass:draw_stop() + + + + -- Chapter Markers / Ticks / Nibbles + -- We store this ass as a property so we can draw them overtop the seekbar + local nibbles_ass = assdraw.ass_new() + nibbles_ass:append(tethysStyle.chapterTick) + nibbles_ass:draw_start() + if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then + local markers = element.slider.markerF() + for _,marker in pairs(markers) do + if (marker > element.slider.min.value) and + (marker < element.slider.max.value) then + + local s = get_slider_ele_pos_for(element, marker) + local a = tethys.chapterTickSize * 0.8 + local sliderMid = elem_geo.h / 2 + local tickY = sliderMid - tethys.chapterTickSize + nibbles_ass:move_to(s - (a/2), tickY) + nibbles_ass:line_to(s + (a/2), tickY) + nibbles_ass:line_to(s, sliderMid) + end + end + end + nibbles_ass:draw_stop() + slider_lo.nibbles_ass = nibbles_ass + end + + element.static_ass = static_ass + + + -- if the element is supposed to be disabled, + -- style it accordingly and kill the eventresponders + if not (element.enabled) then + element.layout.alpha[1] = 136 + element.eventresponder = nil + end + end +end + + +-- +-- Element Rendering +-- + +-- returns nil or a chapter element from the native property chapter-list +function get_chapter(possec) + local cl = state.chapter_list -- sorted, get latest before possec, if any + + for n=#cl,1,-1 do + if possec >= cl[n].time then + return cl[n] + end + end +end + +function render_elements(master_ass) + + -- when the slider is dragged or hovered and we have a target chapter name + -- then we use it instead of the normal title. we calculate it before the + -- render iterations because the title may be rendered before the slider. + state.forced_title = nil + local se, ae = state.slider_element, elements[state.active_element] + if user_opts.chapter_fmt ~= "no" and se and (ae == se or (not ae and mouse_hit(se))) then + local dur = mp.get_property_number("duration", 0) + if dur > 0 then + local possec = get_slider_value(se) * dur / 100 -- of mouse pos + local ch = get_chapter(possec) + if ch and ch.title and ch.title ~= "" then + state.forced_title = string.format(user_opts.chapter_fmt, ch.title) + end + end + end + + for n=1, #elements do + local element = elements[n] + + local style_ass = assdraw.ass_new() + style_ass:merge(element.style_ass) + ass_append_alpha(style_ass, element.layout.alpha, 0) + + if element.eventresponder and (state.active_element == n) then + + -- run render event functions + if not (element.eventresponder.render == nil) then + element.eventresponder.render(element) + end + + if mouse_hit(element) then + -- mouse down styling + if (element.styledown) then + style_ass:append(osc_styles.elementDown) + end + + if (element.softrepeat) and (state.mouse_down_counter >= 15 + and state.mouse_down_counter % 5 == 0) then + + element.eventresponder[state.active_event_source.."_down"](element) + end + state.mouse_down_counter = state.mouse_down_counter + 1 + end + + end + + local elem_ass = assdraw.ass_new() + + elem_ass:merge(style_ass) + + if not (element.type == "button") then + elem_ass:merge(element.static_ass) + end + + if (element.type == "slider") then + + local slider_lo = element.layout.slider + local elem_geo = element.layout.geometry + local s_min = element.slider.min.value + local s_max = element.slider.max.value + + -- draw pos marker + local foH, xp + local pos = element.slider.posF() + local foV = slider_lo.border + slider_lo.gap + local innerH = elem_geo.h - (2 * foV) + local seekRanges = element.slider.seekRangesF() + local seekRangeLineHeight = innerH / 5 + + if slider_lo.stype ~= "bar" then + foH = elem_geo.h / 2 + else + foH = slider_lo.border + slider_lo.gap + end + + -- Reset everything as static_ass ended with draw_stop() + reset_ass(elem_ass, element) + + if pos then + xp = get_slider_ele_pos_for(element, pos) + + -- Thick Slider BG Before Handle + local sliderFgRatio = 6 -- 1/6th Height + elem_ass:append(tethysStyle.seekbarFg) + elem_ass:draw_start() + -- Note: round_rect_cw(x0, y0, x1, y1, r1, r2) + elem_ass:round_rect_cw( + foH - innerH / sliderFgRatio, + foH - innerH / sliderFgRatio, + xp, + foH + innerH / sliderFgRatio, + innerH / sliderFgRatio, + 0 + ) + elem_ass:draw_stop() + reset_ass(elem_ass, element) + + -- Thin Slider BG After Handle + -- local sliderBgRatio = 15 -- 1/15th Height + local sliderBgRatio = 6 + elem_ass:append(tethysStyle.seekbarBg) + elem_ass:draw_start() + -- Note: round_rect_cw(x0, y0, x1, y1, r1, r2) + elem_ass:round_rect_cw( + xp, + foH - innerH / sliderBgRatio, + elem_geo.w - foH + innerH / sliderBgRatio, + foH + innerH / sliderBgRatio, + 0, + innerH / sliderBgRatio + ) + elem_ass:draw_stop() + reset_ass(elem_ass, element) + + -- Cache / Seek Ranges + elem_ass:append(tethysStyle.seekbarCache) + ass_append_alpha(elem_ass, tethys.seekbarCacheAlphaTable, 0) + elem_ass:draw_start() + -- local cacheBgRatio = 21 -- 1/21th Height + local seekbarY1 = foH - innerH / sliderFgRatio + local seekbarY2 = foH + innerH / sliderFgRatio + local cachebarY1 = seekbarY1 + 1 + local cachebarY2 = seekbarY2 - 1 + for _,range in pairs(seekRanges or {}) do + local pstart = get_slider_ele_pos_for(element, range["start"]) + local pend = get_slider_ele_pos_for(element, range["end"]) + -- Note: round_rect_ccw(x0, y0, x1, y1, r1, r2) + -- elem_ass:round_rect_ccw( + -- pstart, + -- foH - innerH / cacheBgRatio, + -- pend, + -- foH + innerH / cacheBgRatio, + -- innerH / cacheBgRatio, + -- nil + -- ) + elem_ass:round_rect_ccw( + pstart, + cachebarY1, + pend, + cachebarY2, + 0, + nil + ) + end + elem_ass:draw_stop() + reset_ass(elem_ass, element) + + -- Chapter Ticks + elem_ass:merge(slider_lo.nibbles_ass) + reset_ass(elem_ass, element) + + -- Circle Knob/Handle + elem_ass:append(tethysStyle.seekbarHandle) + elem_ass:draw_start() + local r = (user_opts.seekbarhandlesize * innerH) / 2 + -- Note: round_rect_cw(x0, y0, x1, y1, r1, r2) + elem_ass:round_rect_cw( + xp - r, + foH - r, + xp + r, + foH + r, + r, + nil + ) + elem_ass:draw_stop() + reset_ass(elem_ass, element) + end + + -- add tooltip + if not (element.slider.tooltipF == nil) then + + if mouse_hit(element) then + local sliderPos = get_slider_value(element) + local tooltipLabel = element.slider.tooltipF(sliderPos) + + local an = slider_lo.tooltip_an + + local ty + + if (an == 2) then + ty = element.hitbox.y1 - slider_lo.border + else + ty = element.hitbox.y1 + elem_geo.h/2 + end + + local tx = get_virt_mouse_pos() + if (slider_lo.adjust_tooltip) then + if (an == 2) then + if (sliderPos < (s_min + 3)) then + an = an - 1 + elseif (sliderPos > (s_max - 3)) then + an = an + 1 + end + elseif (sliderPos > (s_max-s_min)/2) then + an = an + 1 + tx = tx - 5 + else + an = an - 1 + tx = tx + 10 + end + end + + -- Tooltip + Thumbnail + -- https://github.com/TheAMM/mpv_thumbnail_script + local thumbPos = { + x=get_virt_mouse_pos(), + y=ty, + an=2, -- x,y is bottom-center + } + renderThumbnailTooltip(thumbPos, sliderPos, elem_ass) + + end + end + + elseif (element.type == "button") then + local button_lo = element.layout.button + + local buttontext + if type(element.content) == "function" then + buttontext = element.content() -- function objects + elseif not (element.content == nil) then + buttontext = element.content -- text objects + end + + local maxchars = element.layout.button.maxchars + if not (maxchars == nil) and (#buttontext > maxchars) then + local max_ratio = 1.25 -- up to 25% more chars while shrinking + local limit = math.max(0, math.floor(maxchars * max_ratio) - 3) + if (#buttontext > limit) then + while (#buttontext > limit) do + buttontext = buttontext:gsub(".[\128-\191]*$", "") + end + buttontext = buttontext .. "..." + end + local _, nchars2 = buttontext:gsub(".[\128-\191]*", "") + local stretch = (maxchars/#buttontext)*100 + buttontext = string.format("{\\fscx%f}", + (maxchars/#buttontext)*100) .. buttontext + end + + local isButton = element.eventresponder and ( + not (element.eventresponder["mbtn_left_down"] == nil) + or not (element.eventresponder["mbtn_left_up"] == nil) + ) + local buttonHovered = mouse_hit(element) + if isButton and buttonHovered and element.enabled then + buttontext = button_lo.hover_style .. buttontext + + -- Hover BG Rect + if tethys.showButtonHoveredRect then + local elem_geo = element.layout.geometry + local bgrect_ass = assdraw.ass_new() + bgrect_ass:merge(style_ass) + bgrect_ass:append(tethysStyle.buttonHoveredRect) + bgrect_ass:draw_start() + bgrect_ass:round_rect_cw( + 0, 0, elem_geo.w, elem_geo.h, + 0, 0 + ) + bgrect_ass:draw_stop() + master_ass:merge(bgrect_ass) + end + + -- Hover Glow/Shadow + local shadow_ass = assdraw.ass_new() + shadow_ass:merge(style_ass) + shadow_ass:append("{\\blur5}" .. buttontext .. "{\\blur0}") + master_ass:merge(shadow_ass) + end + + elem_ass:append(buttontext) + + -- Tooltip + if buttonHovered and (not (button_lo.tooltip == nil)) then + local tx = button_lo.tooltip_geo.x + local ty = button_lo.tooltip_geo.y + local labelList = {} + if type(button_lo.tooltip) == "function" then + labelList = button_lo.tooltip() + else + labelList = button_lo.tooltip + end + if type(labelList) == "string" then + labelList = { labelList } + end + if not (type(labelList) == "table") then + labelList = {} + end + local rowY = ty + for i, label in ipairs(labelList) do + rowY = ty - ((i-1) * tethys.buttonTooltipSize) + new_ass_node(elem_ass) + elem_ass:pos(tx, rowY) + elem_ass:an(button_lo.tooltip_an) + elem_ass:append(button_lo.tooltip_style) + ass_append_alpha(elem_ass, tethys.tooltipAlphaTable, 0) + elem_ass.scale = 1 + elem_ass:append(label) + elem_ass.scale = 4 + end + rowY = rowY - tethys.buttonTooltipSize + + if not (button_lo.playlist == nil) then + local thumbPos = { + x = tx, + y = rowY, + an = button_lo.tooltip_an, + } + renderPlaylistTooltip(thumbPos, button_lo.playlist, elem_ass) + end + end + end + + master_ass:merge(elem_ass) + end +end + +-- +-- Message display +-- + +-- pos is 1 based +function limited_list(prop, pos) + local proplist = mp.get_property_native(prop, {}) + local count = #proplist + if count == 0 then + return count, proplist + end + + local fs = tonumber(mp.get_property('options/osd-font-size')) + local max = math.ceil(osc_param.unscaled_y*0.75 / fs) + if max % 2 == 0 then + max = max - 1 + end + local delta = math.ceil(max / 2) - 1 + local begi = math.max(math.min(pos - delta, count - max + 1), 1) + local endi = math.min(begi + max - 1, count) + + local reslist = {} + for i=begi, endi do + local item = proplist[i] + item.current = (i == pos) and true or nil + table.insert(reslist, item) + end + return count, reslist +end + +function get_playlist() + local pos = mp.get_property_number('playlist-pos', 0) + 1 + local count, limlist = limited_list('playlist', pos) + if count == 0 then + return 'Empty playlist.' + end + + local message = string.format('Playlist [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local title = v.title + local _, filename = utils.split_path(v.filename) + if title == nil then + title = filename + end + message = string.format('%s %s %s\n', message, + (v.current and '●' or '○'), title) + end + return message +end + +function get_chapterlist() + local pos = mp.get_property_number('chapter', 0) + 1 + local count, limlist = limited_list('chapter-list', pos) + if count == 0 then + return 'No chapters.' + end + + local message = string.format('Chapters [%d/%d]:\n', pos, count) + for i, v in ipairs(limlist) do + local time = mp.format_time(v.time) + local title = v.title + if title == nil then + title = string.format('Chapter %02d', i) + end + message = string.format('%s[%s] %s %s\n', message, time, + (v.current and '●' or '○'), title) + end + return message +end + +function show_message(text, duration) + + -- print("text: "..text.." duration: " .. duration) + if duration == nil then + duration = tonumber(mp.get_property("options/osd-duration")) / 1000 + elseif not type(duration) == "number" then + print("duration: " .. duration) + end + + -- cut the text short, otherwise the following functions + -- may slow down massively on huge input + text = string.sub(text, 0, 4000) + + -- replace actual linebreaks with ASS linebreaks + text = string.gsub(text, "\n", "\\N") + + state.message_text = text + + if not state.message_hide_timer then + state.message_hide_timer = mp.add_timeout(0, request_tick) + end + state.message_hide_timer:kill() + state.message_hide_timer.timeout = duration + state.message_hide_timer:resume() + request_tick() +end + +function render_message(ass) + if state.message_hide_timer and state.message_hide_timer:is_enabled() and + state.message_text + then + local _, lines = string.gsub(state.message_text, "\\N", "") + + local fontsize = tonumber(mp.get_property("options/osd-font-size")) + local outline = tonumber(mp.get_property("options/osd-border-size")) + local maxlines = math.ceil(osc_param.unscaled_y*0.75 / fontsize) + local counterscale = osc_param.playresy / osc_param.unscaled_y + + fontsize = fontsize * counterscale / math.max(0.65 + math.min(lines/maxlines, 1), 1) + outline = outline * counterscale / math.max(0.75 + math.min(lines/maxlines, 1)/2, 1) + + local style = "{\\bord" .. outline .. "\\fs" .. fontsize .. "}" + + + ass:new_event() + ass:append(style .. state.message_text) + else + state.message_text = nil + end +end + +-- +-- Initialisation and Layout +-- + +function new_element(name, type) + elements[name] = {} + elements[name].type = type + + -- add default stuff + elements[name].eventresponder = {} + elements[name].visible = true + elements[name].enabled = true + elements[name].softrepeat = false + elements[name].styledown = (type == "button") + elements[name].state = {} + + if (type == "slider") then + elements[name].slider = {min = {value = 0}, max = {value = 100}} + end + + + return elements[name] +end + +function add_layout(name) + if not (elements[name] == nil) then + -- new layout + elements[name].layout = {} + + -- set layout defaults + elements[name].layout.layer = 50 + elements[name].layout.alpha = {[1] = 0, [2] = 255, [3] = 255, [4] = 255} + + if (elements[name].type == "button") then + elements[name].layout.button = { + maxchars = nil, + hover_style = tethysStyle.buttonHovered, + playlist = nil, + } + elseif (elements[name].type == "slider") then + -- slider defaults + elements[name].layout.slider = { + border = 1, + gap = 1, + nibbles_top = true, + nibbles_bottom = true, + stype = "slider", + adjust_tooltip = true, + tooltip_style = "", + tooltip_an = 2, + alpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255}, + } + elseif (elements[name].type == "box") then + elements[name].layout.box = {radius = 0, hexagon = false} + end + + return elements[name].layout + else + msg.error("Can't add_layout to element \""..name.."\", doesn't exist.") + end +end + +-- Window Controls +function window_controls(topbar) + local windowBarHeight = 30 + local windowButtonSize = tethys.windowButtonSize + local windowBarSpacing = 5 + local wc_geo = { + x = 0, + y = tethys.windowBarHeight + user_opts.barmargin, + an = 1, -- x,y is bottom left + w = osc_param.playresx, + h = tethys.windowBarHeight, + } + + local alignment = window_controls_alignment() + local controlbox_w = windowBarSpacing + tethys.windowControlsRect.w + local titlebox_w = wc_geo.w - controlbox_w + + -- Default alignment is "right" + local controlbox_left = wc_geo.w - controlbox_w + local titlebox_left = wc_geo.x + local titlebox_right = wc_geo.w - controlbox_w + + if alignment == "left" then + controlbox_left = wc_geo.x + titlebox_left = wc_geo.x + controlbox_w + titlebox_right = wc_geo.w + end + + add_area("window-controls", + get_hitbox_coords(controlbox_left, wc_geo.y, wc_geo.an, + controlbox_w, wc_geo.h)) + + local lo + + -- Background Bar + new_element("wcbar", "box") + lo = add_layout("wcbar") + lo.geometry = wc_geo + lo.layer = 10 + lo.style = tethysStyle.windowBar + lo.alpha = tethys.windowBarAlphaTable + + local winControlsX = controlbox_left + windowBarSpacing + tethys.windowButtonSize/2 + local winControlsY = wc_geo.y - (wc_geo.h / 2) + local winControlsAlignment = 5 -- x,y is center + local first_geo = { + x = winControlsX + tethys.windowButtonSize*0, + y = winControlsY, + an = winControlsAlignment, + w = tethys.windowButtonSize, + h = tethys.windowButtonSize, + } + local second_geo = { + x = winControlsX + tethys.windowButtonSize*1, + y = winControlsY, + an = winControlsAlignment, + w = tethys.windowButtonSize, + h = tethys.windowButtonSize, + } + local third_geo = { + x = winControlsX + tethys.windowButtonSize*2, + y = winControlsY, + an = winControlsAlignment, + w = tethys.windowButtonSize, + h = tethys.windowButtonSize, + } + + -- Window control buttons use symbols in the custom mpv osd font + -- because the official unicode codepoints are sufficiently + -- exotic that a system might lack an installed font with them, + -- and libass will complain that they are not present in the + -- default font, even if another font with them is available. + + -- Close: 🗙 + ne = new_element("close", "button") + ne.content = mpvOsdIcon_close + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("quit") end + lo = add_layout("close") + lo.geometry = alignment == "left" and first_geo or third_geo + lo.style = tethysStyle.windowButton + lo.button.hover_style = tethysStyle.closeButtonHovered + lo.alpha[3] = 0 -- show outline (aka border) + + -- Minimize: 🗕 + ne = new_element("minimize", "button") + ne.content = mpvOsdIcon_minimize + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "window-minimized") end + lo = add_layout("minimize") + lo.geometry = alignment == "left" and second_geo or first_geo + lo.style = tethysStyle.windowButton + lo.alpha[3] = 0 -- show outline (aka border) + + -- Maximize: 🗖 /🗗 + ne = new_element("maximize", "button") + if state.maximized or state.fullscreen then + ne.content = mpvOsdIcon_restore + else + ne.content = mpvOsdIcon_maximize + end + ne.eventresponder["mbtn_left_up"] = + function () + if state.fullscreen then + mp.commandv("cycle", "fullscreen") + else + mp.commandv("cycle", "window-maximized") + end + end + lo = add_layout("maximize") + lo.geometry = alignment == "left" and third_geo or second_geo + lo.style = tethysStyle.windowButton + lo.alpha[3] = 0 -- show outline (aka border) + + -- deadzone below window controls + local sh_area_y0, sh_area_y1 + sh_area_y0 = user_opts.barmargin + sh_area_y1 = (wc_geo.y + (wc_geo.h / 2)) + + get_align(1 - (2 * user_opts.deadzonesize), + osc_param.playresy - (wc_geo.y + (wc_geo.h / 2)), 0, 0) + add_area("showhide_wc", wc_geo.x, sh_area_y0, wc_geo.w, sh_area_y1) + + if topbar then + -- The title is already there as part of the top bar + return + else + -- Apply boxvideo margins to the control bar + osc_param.video_margins.t = wc_geo.h / osc_param.playresy + end + + -- Window Title + ne = new_element("wctitle", "button") + ne.content = function () + local title = mp.command_native({"expand-text", user_opts.title}) + -- escape ASS, and strip newlines and trailing slashes + title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") + return not (title == "") and title or "mpv" + end + local vertPad = (wc_geo.h - tethys.windowTitleSize)/2 + local leftPad = vertPad + local rightPad = vertPad * 2 + lo = add_layout("wctitle") + lo.geometry = { + x = titlebox_left + leftPad, + y = wc_geo.y - wc_geo.h/2, + an = 4, -- x,y is left-center + w = titlebox_w, + h = wc_geo.h, + } + -- Note: \q(2) = No Wrap + lo.style = string.format("%s{\\clip(%f,%f,%f,%f)\\q(2)}", + tethysStyle.windowTitle, + lo.geometry.x - tethys.windowTitleOutline, + wc_geo.y - wc_geo.h - tethys.windowTitleOutline, + titlebox_right - rightPad + tethys.windowTitleOutline, + wc_geo.y + tethys.windowTitleOutline + ) + lo.alpha[3] = 0 -- show text outline (aka border) + + add_area("window-controls-title", + titlebox_left, 0, titlebox_right, wc_geo.h) +end + +-- +-- Layouts +-- + +local layouts = {} + +-- Classic box layout +layouts["box"] = function () + + local osc_geo = { + w = 550, -- width + h = 138, -- height + r = 10, -- corner-radius + p = 15, -- padding + } + + -- make sure the OSC actually fits into the video + if (osc_param.playresx < (osc_geo.w + (2 * osc_geo.p))) then + osc_param.playresy = (osc_geo.w+(2*osc_geo.p))/osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + -- position of the controller according to video aspect and valignment + local posX = math.floor(get_align(user_opts.halign, osc_param.playresx, + osc_geo.w, 0)) + local posY = math.floor(get_align(user_opts.valign, osc_param.playresy, + osc_geo.h, 0)) + + -- position offset for contents aligned at the borders of the box + local pos_offsetX = (osc_geo.w - (2*osc_geo.p)) / 2 + local pos_offsetY = (osc_geo.h - (2*osc_geo.p)) / 2 + + osc_param.areas = {} -- delete areas + + -- area for active mouse input + add_area("input", get_hitbox_coords(posX, posY, 5, osc_geo.w, osc_geo.h)) + + -- area for show/hide + local sh_area_y0, sh_area_y1 + if user_opts.valign > 0 then + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + posY - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy + else + -- deadzone below OSC + sh_area_y0 = 0 + sh_area_y1 = (posY + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (posY + (osc_geo.h / 2)), 0, 0) + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + -- fetch values + local osc_w, osc_h, osc_r, osc_p = + osc_geo.w, osc_geo.h, osc_geo.r, osc_geo.p + + local lo + + -- + -- Background box + -- + + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = {x = posX, y = posY, an = 5, w = osc_w, h = osc_h} + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + lo.alpha[3] = user_opts.boxalpha + lo.box.radius = osc_r + + -- + -- Title row + -- + + local titlerowY = posY - pos_offsetY - 10 + + lo = add_layout("title") + lo.geometry = {x = posX, y = titlerowY, an = 8, w = 496, h = 12} + lo.style = osc_styles.vidtitle + lo.button.maxchars = user_opts.boxmaxchars + + lo = add_layout("pl_prev") + lo.geometry = + {x = (posX - pos_offsetX), y = titlerowY, an = 7, w = 12, h = 12} + lo.style = osc_styles.topButtons + + lo = add_layout("pl_next") + lo.geometry = + {x = (posX + pos_offsetX), y = titlerowY, an = 9, w = 12, h = 12} + lo.style = osc_styles.topButtons + + -- + -- Big buttons + -- + + local bigbtnrowY = posY - pos_offsetY + 35 + local bigbtndist = 60 + + lo = add_layout("playpause") + lo.geometry = + {x = posX, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("skipback") + lo.geometry = + {x = posX - bigbtndist, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("skipfrwd") + lo.geometry = + {x = posX + bigbtndist, y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("ch_prev") + lo.geometry = + {x = posX - (bigbtndist * 2), y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("ch_next") + lo.geometry = + {x = posX + (bigbtndist * 2), y = bigbtnrowY, an = 5, w = 40, h = 40} + lo.style = osc_styles.bigButtons + + lo = add_layout("cy_audio") + lo.geometry = + {x = posX - pos_offsetX, y = bigbtnrowY, an = 1, w = 70, h = 18} + lo.style = osc_styles.smallButtonsL + + lo = add_layout("cy_sub") + lo.geometry = + {x = posX - pos_offsetX, y = bigbtnrowY, an = 7, w = 70, h = 18} + lo.style = osc_styles.smallButtonsL + + lo = add_layout("tog_fs") + lo.geometry = + {x = posX+pos_offsetX - 25, y = bigbtnrowY, an = 4, w = 25, h = 25} + lo.style = osc_styles.smallButtonsR + + lo = add_layout("volume") + lo.geometry = + {x = posX+pos_offsetX - (25 * 2) - osc_geo.p, + y = bigbtnrowY, an = 4, w = 25, h = 25} + lo.style = osc_styles.smallButtonsR + + -- + -- Seekbar + -- + + lo = add_layout("seekbar") + lo.geometry = + {x = posX, y = posY+pos_offsetY-22, an = 2, w = pos_offsetX*2, h = 15} + lo.style = osc_styles.timecodes + lo.slider.tooltip_style = osc_styles.vidtitle + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + + -- + -- Timecodes + Cache + -- + + local bottomrowY = posY + pos_offsetY - 5 + + lo = add_layout("tc_left") + lo.geometry = + {x = posX - pos_offsetX, y = bottomrowY, an = 4, w = 110, h = 18} + lo.style = osc_styles.timecodes + + lo = add_layout("tc_right") + lo.geometry = + {x = posX + pos_offsetX, y = bottomrowY, an = 6, w = 110, h = 18} + lo.style = osc_styles.timecodes + + lo = add_layout("cache") + lo.geometry = + {x = posX, y = bottomrowY, an = 5, w = 110, h = 18} + lo.style = osc_styles.timecodes + +end + +-- slim box layout +layouts["slimbox"] = function () + + local osc_geo = { + w = 660, -- width + h = 70, -- height + r = 10, -- corner-radius + } + + -- make sure the OSC actually fits into the video + if (osc_param.playresx < (osc_geo.w)) then + osc_param.playresy = (osc_geo.w)/osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + -- position of the controller according to video aspect and valignment + local posX = math.floor(get_align(user_opts.halign, osc_param.playresx, + osc_geo.w, 0)) + local posY = math.floor(get_align(user_opts.valign, osc_param.playresy, + osc_geo.h, 0)) + + osc_param.areas = {} -- delete areas + + -- area for active mouse input + add_area("input", get_hitbox_coords(posX, posY, 5, osc_geo.w, osc_geo.h)) + + -- area for show/hide + local sh_area_y0, sh_area_y1 + if user_opts.valign > 0 then + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + posY - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy + else + -- deadzone below OSC + sh_area_y0 = 0 + sh_area_y1 = (posY + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (posY + (osc_geo.h / 2)), 0, 0) + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + local lo + + local tc_w, ele_h, inner_w = 100, 20, osc_geo.w - 100 + + -- styles + local styles = { + box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}", + timecodes = "{\\1c&HFFFFFF\\3c&H000000\\fs20\\bord2\\blur1}", + tooltip = "{\\1c&HFFFFFF\\3c&H000000\\fs12\\bord1\\blur0.5}", + } + + + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = {x = posX, y = posY - 1, an = 2, w = inner_w, h = ele_h} + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + lo.alpha[3] = 0 + if not (user_opts["seekbarstyle"] == "bar") then + lo.box.radius = osc_geo.r + lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" + end + + + lo = add_layout("seekbar") + lo.geometry = + {x = posX, y = posY - 1, an = 2, w = inner_w, h = ele_h} + lo.style = osc_styles.timecodes + lo.slider.border = 0 + lo.slider.gap = 1.5 + lo.slider.tooltip_style = styles.tooltip + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + lo.slider.adjust_tooltip = false + + -- + -- Timecodes + -- + + lo = add_layout("tc_left") + lo.geometry = + {x = posX - (inner_w/2) + osc_geo.r, y = posY + 1, + an = 7, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + lo = add_layout("tc_right") + lo.geometry = + {x = posX + (inner_w/2) - osc_geo.r, y = posY + 1, + an = 9, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + -- Cache + + lo = add_layout("cache") + lo.geometry = + {x = posX, y = posY + 1, + an = 8, w = tc_w, h = ele_h} + lo.style = styles.timecodes + lo.alpha[3] = user_opts.boxalpha + + +end + +function bar_layout(direction) + local osc_geo = { + x = -2, + y, + an = (direction < 0) and 7 or 1, + w, + h = 56, + } + + local padX = 9 + local padY = 3 + local buttonW = 27 + local tcW = (state.tc_ms) and 170 or 110 + if user_opts.tcspace >= 50 and user_opts.tcspace <= 200 then + -- adjust our hardcoded font size estimation + tcW = tcW * user_opts.tcspace / 100 + end + + local tsW = 90 + local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2 + + -- Special topbar handling when window controls are present + local padwc_l + local padwc_r + if direction < 0 or not window_controls_enabled() then + padwc_l = 0 + padwc_r = 0 + elseif window_controls_alignment() == "left" then + padwc_l = window_control_box_width + padwc_r = 0 + else + padwc_l = 0 + padwc_r = window_control_box_width + end + + if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then + osc_param.playresy = minW / osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + osc_geo.y = direction * (54 + user_opts.barmargin) + osc_geo.w = osc_param.playresx + 4 + if direction < 0 then + osc_geo.y = osc_geo.y + osc_param.playresy + end + + local line1 = osc_geo.y - direction * (9 + padY) + local line2 = osc_geo.y - direction * (36 + padY) + + osc_param.areas = {} + + add_area("input", get_hitbox_coords(osc_geo.x, osc_geo.y, osc_geo.an, + osc_geo.w, osc_geo.h)) + + local sh_area_y0, sh_area_y1 + if direction > 0 then + -- deadzone below OSC + sh_area_y0 = user_opts.barmargin + sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0) + else + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + osc_geo.y - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy - user_opts.barmargin + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + local lo, geo + + -- Background bar + new_element("bgbox", "box") + lo = add_layout("bgbox") + + lo.geometry = osc_geo + lo.layer = 10 + lo.style = osc_styles.box + lo.alpha[1] = user_opts.boxalpha + + + -- Playlist prev/next + geo = { x = osc_geo.x + padX, y = line1, + an = 4, w = 18, h = 18 - padY } + lo = add_layout("pl_prev") + lo.geometry = geo + lo.style = osc_styles.topButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("pl_next") + lo.geometry = geo + lo.style = osc_styles.topButtonsBar + + local t_l = geo.x + geo.w + padX + + -- Cache + geo = { x = osc_geo.x + osc_geo.w - padX, y = geo.y, + an = 6, w = 150, h = geo.h } + lo = add_layout("cache") + lo.geometry = geo + lo.style = osc_styles.vidtitleBar + + local t_r = geo.x - geo.w - padX*2 + + -- Title + geo = { x = t_l, y = geo.y, an = 4, + w = t_r - t_l, h = geo.h } + lo = add_layout("title") + lo.geometry = geo + lo.style = string.format("%s{\\clip(%f,%f,%f,%f)}", + osc_styles.vidtitleBar, + geo.x, geo.y-geo.h, geo.w, geo.y+geo.h) + + + -- Playback control buttons + geo = { x = osc_geo.x + padX + padwc_l, y = line2, an = 4, + w = buttonW, h = 36 - padY*2} + lo = add_layout("playpause") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("ch_prev") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("ch_next") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- Left timecode + geo = { x = geo.x + geo.w + padX + tcW, y = geo.y, an = 6, + w = tcW, h = geo.h } + lo = add_layout("tc_left") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + + local sb_l = geo.x + padX + + -- Fullscreen button + geo = { x = osc_geo.x + osc_geo.w - buttonW - padX - padwc_r, y = geo.y, an = 4, + w = buttonW, h = geo.h } + lo = add_layout("tog_fs") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- Volume + geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("volume") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + -- Track selection buttons + geo = { x = geo.x - tsW - padX, y = geo.y, an = geo.an, w = tsW, h = geo.h } + lo = add_layout("cy_sub") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } + lo = add_layout("cy_audio") + lo.geometry = geo + lo.style = osc_styles.smallButtonsBar + + + -- Right timecode + geo = { x = geo.x - padX - tcW - 10, y = geo.y, an = geo.an, + w = tcW, h = geo.h } + lo = add_layout("tc_right") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + + local sb_r = geo.x - padX + + + -- Seekbar + geo = { x = sb_l, y = geo.y, an = geo.an, + w = math.max(0, sb_r - sb_l), h = geo.h } + new_element("bgbar1", "box") + lo = add_layout("bgbar1") + + lo.geometry = geo + lo.layer = 15 + lo.style = osc_styles.timecodesBar + lo.alpha[1] = + math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8) + if not (user_opts["seekbarstyle"] == "bar") then + lo.box.radius = geo.h / 2 + lo.box.hexagon = user_opts["seekbarstyle"] == "diamond" + end + + lo = add_layout("seekbar") + lo.geometry = geo + lo.style = osc_styles.timecodesBar + lo.slider.border = 0 + lo.slider.gap = 2 + lo.slider.tooltip_style = osc_styles.timePosBar + lo.slider.tooltip_an = 5 + lo.slider.stype = user_opts["seekbarstyle"] + lo.slider.rtype = user_opts["seekrangestyle"] + + if direction < 0 then + osc_param.video_margins.b = osc_geo.h / osc_param.playresy + else + osc_param.video_margins.t = osc_geo.h / osc_param.playresy + end +end + +layouts["bottombar"] = function() + bar_layout(-1) +end + +layouts["topbar"] = function() + bar_layout(1) +end + +layouts["tethys"] = function() + local direction = -1 + local osc_geo = { + x = -2, + y, + an = (direction < 0) and 7 or 1, + w, + h = tethys.bottomBarHeight, + } + + -- Alias + local buttonW = tethys.buttonW + local buttonH = tethys.buttonH + local smallButtonSize = tethys.smallButtonSize + + -- Props + local padX = 9 + local padY = 3 + local tcW = (state.tc_ms) and 170 or 110 + local tsW = 90 + local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2 + + -- Special topbar handling when window controls are present + if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then + osc_param.playresy = minW / osc_param.display_aspect + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + end + + -- osc_geo.y = direction * (54 + user_opts.barmargin) + osc_geo.y = direction * (osc_geo.h) + osc_geo.w = osc_param.playresx + 4 + if direction < 0 then + osc_geo.y = osc_geo.y + osc_param.playresy + end + + -- local line1 = osc_geo.y - direction * (9 + padY) + -- local line2 = osc_geo.y - direction * (36 + padY) + local line1Y = osc_geo.y - direction * tethys.seekbarHeight + local line2Y = osc_geo.y - direction * tethys.controlsHeight + local leftPad = padX + local rightPad = padX + local leftX = osc_geo.x + leftPad + local rightX = osc_geo.w - rightPad + local leftSectionWidth = leftPad + local rightSectionWidth = rightPad + + osc_param.areas = {} + + add_area("input", get_hitbox_coords(osc_geo.x, osc_geo.y, osc_geo.an, + osc_geo.w, osc_geo.h)) + + local sh_area_y0, sh_area_y1 + if direction > 0 then + -- deadzone below OSC + sh_area_y0 = user_opts.barmargin + sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) + + get_align(1 - (2*user_opts.deadzonesize), + osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0) + else + -- deadzone above OSC + sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize), + osc_geo.y - (osc_geo.h / 2), 0, 0) + sh_area_y1 = osc_param.playresy - user_opts.barmargin + end + add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1) + + local lo, geo + + -- Background bar + new_element("bgbox", "box") + lo = add_layout("bgbox") + + local boxBlur = 20 -- 0 .. 20 + geo = { + x = osc_geo.x - boxBlur, + y = osc_geo.y - boxBlur, + an = osc_geo.an, + w = osc_geo.w + boxBlur*2, + h = osc_geo.h + boxBlur*2, + } + lo.geometry = geo + lo.layer = 10 + lo.style = ("{\\rDefault\\blur(%d)\\bord0\\1c&H000000\\3c&HFFFFFF}"):format(boxBlur) + lo.alpha[1] = 80 --- 0 (opaque) to 255 (fully transparent) + + function setButtonTooltip(button_lo, text) + button_lo.button.tooltip = text + button_lo.button.tooltip_style = tethysStyle.buttonTooltip + local hw = button_lo.geometry.w/2 + local ty = osc_geo.y + padY * direction + local an + local tx + local edgeThreshold = 60 + if button_lo.geometry.x - edgeThreshold < osc_geo.x + padX then + an = 1 -- x,y is bottom-left + tx = math.max(osc_geo.x + padX, button_lo.geometry.x - hw) + elseif osc_geo.x + osc_geo.w - padX < button_lo.geometry.x + edgeThreshold then + an = 3 -- x,y is bottom-right + tx = math.min(button_lo.geometry.x + hw, osc_geo.x + osc_geo.w - padX) + else + an = 2 -- x,y is bottom-center + tx = button_lo.geometry.x + end + button_lo.button.tooltip_an = an + button_lo.button.tooltip_geo = { x = tx , y = ty } + end + + ---- Left Section (Added Left-to-Right) + -- Playback control buttons + geo = { + x = leftX + leftSectionWidth + buttonW/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = buttonW, + h = buttonH, + } + lo = add_layout("playpause") + lo.geometry = geo + lo.style = tethysStyle.button + if tethys.showShortcutTooltip then + setButtonTooltip(lo, pauseTooltip) + end + leftSectionWidth = leftSectionWidth + geo.w + + -- Skip Backwards + geo = { + x = leftX + leftSectionWidth + smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("skipback") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, seekBackTooltip) + end + leftSectionWidth = leftSectionWidth + geo.w + + -- Skip Forwards + geo = { + x = leftX + leftSectionWidth + smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("skipfrwd") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, seekFrwdTooltip) + end + leftSectionWidth = leftSectionWidth + geo.w + + -- Chapter Prev + geo = { + x = leftX + leftSectionWidth + smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("ch_prev") + lo.geometry = geo + lo.style = tethysStyle.smallButton + setButtonTooltip(lo, function() + local shortcutLabel = chPrevTooltip + local prevChapter = getDeltaChapter(-1) + if tethys.showShortcutTooltip then + if prevChapter == nil then + return { shortcutLabel } + else + return { tethysStyle.text..prevChapter.label, shortcutLabel } + end + else + if prevChapter == nil then + return {} + else + return { tethysStyle.text..prevChapter.label } + end + end + end) + if elements["ch_prev"].visible then + leftSectionWidth = leftSectionWidth + geo.w + end + + -- Chapter Next + geo = { + x = leftX + leftSectionWidth + smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("ch_next") + lo.geometry = geo + lo.style = tethysStyle.smallButton + setButtonTooltip(lo, function() + local shortcutLabel = chNextTooltip + local nextChapter = getDeltaChapter(1) + if tethys.showShortcutTooltip then + if nextChapter == nil then + return { shortcutLabel } + else + return { tethysStyle.text..nextChapter.label, shortcutLabel } + end + else + if nextChapter == nil then + return {} + else + return { tethysStyle.text..nextChapter.label } + end + end + end) + if elements["ch_next"].visible then + leftSectionWidth = leftSectionWidth + geo.w + end + + -- Pad between Skip/Chapter and Volume + leftSectionWidth = leftSectionWidth + padX + + -- Volume + geo = { + x = leftX + leftSectionWidth + smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("volume") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, volTooltip) + end + if elements["volume"].visible then + leftSectionWidth = leftSectionWidth + geo.w + end + + ---- Right Section (Added Right-to-Left) + -- Fullscreen button + geo = { + x = rightX - rightSectionWidth - smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("tog_fs") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, fullscreenTooltip) + end + if elements["tog_fs"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- PictureInPicture button + geo = { + x = rightX - rightSectionWidth - smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("tog_pip") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, pipTooltip) + end + if elements["tog_pip"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Speed + geo = { + x = rightX - rightSectionWidth - smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("speed") + lo.geometry = geo + lo.style = tethysStyle.smallButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, speedTooltip) + end + if elements["speed"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Subtitle track + local trackButtonSize = tethys.trackButtonSize + local trackButtonWidth = calcTrackButtonWidth(tracks_osc.sub) + geo = { + x = rightX - rightSectionWidth - trackButtonWidth/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = trackButtonWidth, + h = buttonH, + } + lo = add_layout("cy_sub") + lo.geometry = geo + lo.style = tethysStyle.trackButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, subTooltip) + end + if elements["cy_sub"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Audio track + trackButtonWidth = calcTrackButtonWidth(tracks_osc.audio) + geo = { + x = rightX - rightSectionWidth - trackButtonWidth/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = trackButtonWidth, + h = buttonH, + } + lo = add_layout("cy_audio") + lo.geometry = geo + lo.style = tethysStyle.trackButton + if tethys.showShortcutTooltip then + setButtonTooltip(lo, audioTooltip) + end + if elements["cy_audio"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Pad between Fullscreen/Tracks and Playlist + rightSectionWidth = rightSectionWidth + padX + + -- Playlist next + geo = { + x = rightX - rightSectionWidth - smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("pl_next") + lo.geometry = geo + lo.style = tethysStyle.smallButton + lo.button.playlist = 1 + setButtonTooltip(lo, function() + local shortcutLabel = plNextTooltip + local nextItem = getDeltaPlaylistItem(1) + if tethys.showShortcutTooltip then + if nextItem == nil then + return { shortcutLabel } + else + return { tethysStyle.text..nextItem.label, shortcutLabel } + end + else + if nextItem == nil then + return {} + else + return { tethysStyle.text..nextItem.label } + end + end + end) + if elements["pl_next"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Playlist prev + geo = { + x = rightX - rightSectionWidth - smallButtonSize/2, + y = line1Y + buttonH/2, + an = 5, -- x,y is center + w = smallButtonSize, + h = buttonH, + } + lo = add_layout("pl_prev") + lo.geometry = geo + lo.style = tethysStyle.smallButton + lo.button.playlist = -1 + setButtonTooltip(lo, function() + local shortcutLabel = plPrevTooltip + local nextItem = getDeltaPlaylistItem(-1) + if tethys.showShortcutTooltip then + if nextItem == nil then + return { shortcutLabel } + else + return { tethysStyle.text..nextItem.label, shortcutLabel } + end + else + if nextItem == nil then + return {} + else + return { tethysStyle.text..nextItem.label } + end + end + end) + if elements["pl_prev"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + -- Pad between Playlist and Cache + if elements["cache"].visible then + rightSectionWidth = rightSectionWidth + padX + end + + -- Cache + geo = { + x = rightX - rightSectionWidth, + y = line1Y + buttonH/2, + an = 6, -- x,y is right-center + w = 110, + h = buttonH, + } + lo = add_layout("cache") + lo.geometry = geo + lo.style = tethysStyle.cacheText + if elements["cache"].visible then + rightSectionWidth = rightSectionWidth + geo.w + end + + ---- Center Section + -- Pad Center + leftSectionWidth = leftSectionWidth + padX + rightSectionWidth = rightSectionWidth + padX + + -- Timecodes + geo = { + x = leftX + leftSectionWidth, + y = line1Y + buttonH/2, + an = 4, -- x,y is top-left + w = osc_geo.w - leftSectionWidth - rightSectionWidth, + h = buttonH, + } + lo = add_layout("tc_both") + lo.geometry = geo + lo.style = tethysStyle.timecode + + + -- Seekbar + -- geo = { x = sb_l, y = geo.y, an = geo.an, + -- w = math.max(0, sb_r - sb_l), h = geo.h } + geo = { + x = osc_geo.x, + y = osc_geo.y, + an = 7, + w = osc_geo.w, + h = tethys.seekbarHeight, + } + + lo = add_layout("seekbar") + lo.geometry = geo + lo.style = tethysStyle.seekbar + lo.slider.border = 0 + lo.slider.gap = 2 + lo.slider.tooltip_style = tethysStyle.seekbarTimestamp + lo.slider.tooltip_an = 2 + lo.slider.stype = "knob" -- user_opts["seekbarstyle"] -- bar diamond knob + lo.slider.rtype = "slider" -- user_opts["seekrangestyle"] -- bar line slider inverted none + + if direction < 0 then + osc_param.video_margins.b = osc_geo.h / osc_param.playresy + else + osc_param.video_margins.t = osc_geo.h / osc_param.playresy + end +end + +-- Validate string type user options +function validate_user_opts() + if layouts[user_opts.layout] == nil then + msg.warn("Invalid setting \""..user_opts.layout.."\" for layout") + user_opts.layout = "bottombar" + end + + if user_opts.seekbarstyle ~= "bar" and + user_opts.seekbarstyle ~= "diamond" and + user_opts.seekbarstyle ~= "knob" then + msg.warn("Invalid setting \"" .. user_opts.seekbarstyle + .. "\" for seekbarstyle") + user_opts.seekbarstyle = "bar" + end + + if user_opts.seekrangestyle ~= "bar" and + user_opts.seekrangestyle ~= "line" and + user_opts.seekrangestyle ~= "slider" and + user_opts.seekrangestyle ~= "inverted" and + user_opts.seekrangestyle ~= "none" then + msg.warn("Invalid setting \"" .. user_opts.seekrangestyle + .. "\" for seekrangestyle") + user_opts.seekrangestyle = "inverted" + end + + if user_opts.seekrangestyle == "slider" and + user_opts.seekbarstyle == "bar" then + msg.warn("Using \"slider\" seekrangestyle together with \"bar\" seekbarstyle is not supported") + user_opts.seekrangestyle = "inverted" + end + + if user_opts.windowcontrols ~= "auto" and + user_opts.windowcontrols ~= "yes" and + user_opts.windowcontrols ~= "no" then + msg.warn("windowcontrols cannot be \"" .. + user_opts.windowcontrols .. "\". Ignoring.") + user_opts.windowcontrols = "auto" + end + if user_opts.windowcontrols_alignment ~= "right" and + user_opts.windowcontrols_alignment ~= "left" then + msg.warn("windowcontrols_alignment cannot be \"" .. + user_opts.windowcontrols_alignment .. "\". Ignoring.") + user_opts.windowcontrols_alignment = "right" + end +end + +function update_options(list) + validate_user_opts() + request_tick() + visibility_mode(user_opts.visibility, true) + update_duration_watch() + request_init() +end + +local UNICODE_MINUS = string.char(0xe2, 0x88, 0x92) -- UTF-8 for U+2212 MINUS SIGN + +-- OSC INIT +function osc_init() + msg.debug("osc_init") + + -- set canvas resolution according to display aspect and scaling setting + local baseResY = 720 + local display_w, display_h, display_aspect = mp.get_osd_size() + local scale = 1 + + if (mp.get_property("video") == "no") then -- dummy/forced window + scale = user_opts.scaleforcedwindow + elseif state.fullscreen then + scale = user_opts.scalefullscreen + else + scale = user_opts.scalewindowed + end + + if user_opts.vidscale then + osc_param.unscaled_y = baseResY + else + osc_param.unscaled_y = display_h + end + osc_param.playresy = osc_param.unscaled_y / scale + if (display_aspect > 0) then + osc_param.display_aspect = display_aspect + end + osc_param.playresx = osc_param.playresy * osc_param.display_aspect + + -- stop seeking with the slider to prevent skipping files + state.active_element = nil + + osc_param.video_margins = {l = 0, r = 0, t = 0, b = 0} + + elements = {} + + -- some often needed stuff + local pl_count = mp.get_property_number("playlist-count", 0) + local have_pl = (pl_count > 1) + local pl_pos = mp.get_property_number("playlist-pos", 0) + 1 + local have_ch = (mp.get_property_number("chapters", 0) > 0) + local loop = mp.get_property("loop-playlist", "no") + + local ne + + -- title + ne = new_element("title", "button") + + ne.content = function () + local title = state.forced_title or + mp.command_native({"expand-text", user_opts.title}) + -- escape ASS, and strip newlines and trailing slashes + title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") + return not (title == "") and title or "mpv" + end + + ne.eventresponder["mbtn_left_up"] = function () + local title = mp.get_property_osd("media-title") + if (have_pl) then + title = string.format("[%d/%d] %s", countone(pl_pos - 1), + pl_count, title) + end + show_message(title) + end + + ne.eventresponder["mbtn_right_up"] = + function () show_message(mp.get_property_osd("filename")) end + + -- playlist buttons + + -- prev + ne = new_element("pl_prev", "button") + + ne.content = tethysIcon_pl_prev + ne.enabled = (pl_pos > 1) or (loop ~= "no") + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("playlist-prev", "weak") + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_playlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_playlist(), 3) end + + --next + ne = new_element("pl_next", "button") + + ne.content = tethysIcon_pl_next + ne.enabled = (have_pl and (pl_pos < pl_count)) or (loop ~= "no") + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("playlist-next", "weak") + if user_opts.playlist_osd then + show_message(get_playlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_playlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_playlist(), 3) end + + + -- big buttons + + --playpause + ne = new_element("playpause", "button") + + ne.content = function () + if mp.get_property("pause") == "yes" then + return tethysIcon_play + else + return tethysIcon_pause + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "pause") end + + --skipback + ne = new_element("skipback", "button") + + ne.softrepeat = true + ne.content = tethysIcon_skipback + ne.eventresponder["mbtn_left_down"] = + function () mp.commandv("seek", -tethys.skipBy, tethys.skipMode) end + ne.eventresponder["shift+mbtn_left_down"] = + function () mp.commandv("frame-back-step") end + ne.eventresponder["mbtn_right_down"] = + function () mp.commandv("seek", -tethys.skipByMore, tethys.skipMode) end + + --skipfrwd + ne = new_element("skipfrwd", "button") + + ne.softrepeat = true + ne.content = tethysIcon_skipfrwd + ne.eventresponder["mbtn_left_down"] = + function () mp.commandv("seek", tethys.skipBy, tethys.skipMode) end + ne.eventresponder["shift+mbtn_left_down"] = + function () mp.commandv("frame-step") end + ne.eventresponder["mbtn_right_down"] = + function () mp.commandv("seek", tethys.skipByMore, tethys.skipMode) end + + --ch_prev + ne = new_element("ch_prev", "button") + + ne.visible = have_ch + ne.enabled = have_ch + ne.content = tethysIcon_ch_prev + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("add", "chapter", -1) + if user_opts.chapters_osd then + show_message(get_chapterlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_chapterlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_chapterlist(), 3) end + + --ch_next + ne = new_element("ch_next", "button") + + ne.visible = have_ch + ne.enabled = have_ch + ne.content = tethysIcon_ch_next + ne.eventresponder["mbtn_left_up"] = + function () + mp.commandv("add", "chapter", 1) + if user_opts.chapters_osd then + show_message(get_chapterlist(), 3) + end + end + ne.eventresponder["shift+mbtn_left_up"] = + function () show_message(get_chapterlist(), 3) end + ne.eventresponder["mbtn_right_up"] = + function () show_message(get_chapterlist(), 3) end + + -- + update_tracklist() + + --cy_audio + ne = new_element("cy_audio", "button") + + ne.visible = (#tracks_osc.audio > 1) + ne.enabled = (#tracks_osc.audio > 0) + ne.content = function () + local aid = "–" + if not (get_track("audio") == 0) then + aid = get_track("audio") + end + return ("\238\132\134" .. tethysStyle.trackText + .. " " .. aid .. "/" .. #tracks_osc.audio) + end + ne.eventresponder["mbtn_left_up"] = + function () set_track("audio", 1) end + ne.eventresponder["mbtn_right_up"] = + function () set_track("audio", -1) end + ne.eventresponder["shift+mbtn_left_down"] = + function () show_message(get_tracklist("audio"), 2) end + + --cy_sub + ne = new_element("cy_sub", "button") + + ne.enabled = (#tracks_osc.sub > 0) + ne.content = function () + local sid = "–" + if not (get_track("sub") == 0) then + sid = get_track("sub") + end + return ("\238\132\135" .. tethysStyle.trackText + .. " " .. sid .. "/" .. #tracks_osc.sub) + end + ne.eventresponder["mbtn_left_up"] = + function () set_track("sub", 1) end + ne.eventresponder["mbtn_right_up"] = + function () set_track("sub", -1) end + ne.eventresponder["shift+mbtn_left_down"] = + function () show_message(get_tracklist("sub"), 2) end + + --tog_pip + ne = new_element("tog_pip", "button") + ne.visible = tethys.showPictureInPictureButton + ne.content = function () + if (tethys.isPictureInPicture) then + return tethysIcon_pip_exit + else + return tethysIcon_pip_enter + end + end + ne.eventresponder["mbtn_left_up"] = function () + togglePictureInPicture() + end + + --tog_fs + ne = new_element("tog_fs", "button") + ne.content = function () + if (state.fullscreen) then + return mpvOsdIcon_fs_exit + else + return mpvOsdIcon_fs_enter + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "fullscreen") end + + --seekbar + ne = new_element("seekbar", "slider") + + ne.enabled = not (mp.get_property("percent-pos") == nil) + state.slider_element = ne.enabled and ne or nil -- used for forced_title + ne.slider.markerF = function () + local duration = mp.get_property_number("duration", nil) + if not (duration == nil) then + local chapters = mp.get_property_native("chapter-list", {}) + local markers = {} + for n = 1, #chapters do + markers[n] = (chapters[n].time / duration * 100) + end + return markers + else + return {} + end + end + ne.slider.posF = + function () return mp.get_property_number("percent-pos", nil) end + ne.slider.tooltipF = function (pos) + local duration = mp.get_property_number("duration", nil) + if not ((duration == nil) or (pos == nil)) then + possec = duration * (pos / 100) + return mp.format_time(possec) + else + return "" + end + end + ne.slider.seekRangesF = function() + if user_opts.seekrangestyle == "none" then + return nil + end + local cache_state = state.cache_state + if not cache_state then + return nil + end + local duration = mp.get_property_number("duration", nil) + if (duration == nil) or duration <= 0 then + return nil + end + local ranges = cache_state["seekable-ranges"] + if #ranges == 0 then + return nil + end + local nranges = {} + for _, range in pairs(ranges) do + nranges[#nranges + 1] = { + ["start"] = 100 * range["start"] / duration, + ["end"] = 100 * range["end"] / duration, + } + end + return nranges + end + ne.eventresponder["mouse_move"] = --keyframe seeking when mouse is dragged + function (element) + if not element.state.mbtnleft then + return -- allow drag for mbtnleft only + end + -- mouse move events may pile up during seeking and may still get + -- sent when the user is done seeking, so we need to throw away + -- identical seeks + local seekto = get_slider_value(element) + if (element.state.lastseek == nil) or + (not (element.state.lastseek == seekto)) then + local flags = "absolute-percent" + if not user_opts.seekbarkeyframes then + flags = flags .. "+exact" + end + mp.commandv("seek", seekto, flags) + element.state.lastseek = seekto + end + + end + ne.eventresponder["mbtn_left_down"] = --exact seeks on single clicks + function (element) + element.state.mbtnleft = true + mp.commandv("seek", get_slider_value(element), "absolute-percent", "exact") + end + ne.eventresponder['mbtn_left_up'] = + function (element) + element.state.mbtnleft = false + end + ne.eventresponder['mbtn_right_down'] = --seeks to chapter start + function (element) + -- Source: https://github.com/maoiscat/mpv-osc-morden/blob/main/morden.lua#L1395-L1413 + local duration = mp.get_property_number("duration", nil) + if not (duration == nil) then + local chapters = mp.get_property_native("chapter-list", {}) + if #chapters > 0 then + local pos = get_slider_value(element) + local ch = #chapters + for n = 1, ch do + if chapters[n].time / duration * 100 >= pos then + ch = n - 1 + break + end + end + mp.commandv("set", "chapter", ch - 1) + --if chapters[ch].title then show_message(chapters[ch].time) end + end + end + end + ne.eventresponder["reset"] = + function (element) element.state.lastseek = nil end + + -- tc_both (current pos) + ne = new_element("tc_both", "button") + + ne.content = function () + if (state.rightTC_trem) then + local minus = user_opts.unicodeminus and UNICODE_MINUS or "-" + if (state.tc_ms) then + return (mp.get_property_osd("playback-time/full").." / "..minus..mp.get_property_osd("playtime-remaining/full")) + else + return (mp.get_property_osd("playback-time").." / "..minus..mp.get_property_osd("playtime-remaining")) + end + else + if (state.tc_ms) then + return (mp.get_property_osd("playback-time/full").." / "..mp.get_property_osd("duration/full")) + else + return (mp.get_property_osd("playback-time").." / "..mp.get_property_osd("duration")) + end + end + end + ne.eventresponder["mbtn_left_up"] = function () + state.rightTC_trem = not state.rightTC_trem + end + + -- tc_left (current pos) + ne = new_element("tc_left", "button") + + ne.content = function () + if (state.tc_ms) then + return (mp.get_property_osd("playback-time/full")) + else + return (mp.get_property_osd("playback-time")) + end + end + ne.eventresponder["mbtn_left_up"] = function () + state.tc_ms = not state.tc_ms + request_init() + end + + -- tc_right (total/remaining time) + ne = new_element("tc_right", "button") + + ne.visible = (mp.get_property_number("duration", 0) > 0) + ne.content = function () + if (state.rightTC_trem) then + local minus = user_opts.unicodeminus and UNICODE_MINUS or "-" + if state.tc_ms then + return (minus..mp.get_property_osd("playtime-remaining/full")) + else + return (minus..mp.get_property_osd("playtime-remaining")) + end + else + if state.tc_ms then + return (mp.get_property_osd("duration/full")) + else + return (mp.get_property_osd("duration")) + end + end + end + ne.eventresponder["mbtn_left_up"] = + function () state.rightTC_trem = not state.rightTC_trem end + + -- cache + ne = new_element("cache", "button") + + ne.content = function () + local cache_state = state.cache_state + if not (cache_state and cache_state["seekable-ranges"] and + #cache_state["seekable-ranges"] > 0) then + -- probably not a network stream + return "" + end + local dmx_cache = cache_state and cache_state["cache-duration"] + local thresh = math.min(state.dmx_cache * 0.05, 5) -- 5% or 5s + if dmx_cache and math.abs(dmx_cache - state.dmx_cache) >= thresh then + state.dmx_cache = dmx_cache + else + dmx_cache = state.dmx_cache + end + local min = math.floor(dmx_cache / 60) + local sec = math.floor(dmx_cache % 60) -- don't round e.g. 59.9 to 60 + return "Cache: " .. (min > 0 and + string.format("%sm%02.0fs", min, sec) or + string.format("%3.0fs", sec)) + end + + -- volume + ne = new_element("volume", "button") + + ne.content = function() + local volume = mp.get_property_number("volume", 0) + local mute = mp.get_property_native("mute") + local volicon = { + tethysIcon_vol_033, + tethysIcon_vol_066, + tethysIcon_vol_100, + tethysIcon_vol_101, + } + if volume == 0 or mute then + return tethysIcon_vol_mute + else + return volicon[math.min(4,math.ceil(volume / (100/3)))] + end + end + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "mute") end + + ne.eventresponder["wheel_up_press"] = + function () mp.commandv("osd-auto", "add", "volume", 5) end + ne.eventresponder["wheel_down_press"] = + function () mp.commandv("osd-auto", "add", "volume", -5) end + + -- speed + ne = new_element("speed", "button") + ne.visible = tethys.showSpeedButton + ne.content = function() + return tethysIcon_speed + end + ne.eventresponder["mbtn_left_up"] = function () + local speed = mp.get_property_number("speed", 1) + local normalDiff = math.abs(speed - 1) + if normalDiff >= 0.1 then + mp.commandv("osd-auto", "set", "speed", 1) + else + mp.commandv("osd-auto", "set", "speed", 2) + end + end + ne.eventresponder["wheel_up_press"] = + function () mp.commandv("osd-auto", "add", "speed", 0.25) end + ne.eventresponder["wheel_down_press"] = + function () mp.commandv("osd-auto", "add", "speed", -0.25) end + + -- load layout + layouts[user_opts.layout]() + + -- load window controls + if window_controls_enabled() then + window_controls(user_opts.layout == "topbar") + end + + --do something with the elements + prepare_elements() + + update_margins() +end + +function reset_margins() + if state.using_video_margins then + for _, opt in ipairs(margins_opts) do + mp.set_property_number(opt[2], 0.0) + end + state.using_video_margins = false + end +end + +function update_margins() + local margins = osc_param.video_margins + + -- Don't use margins if it's visible only temporarily. + if (not state.osc_visible) or + (state.fullscreen and not user_opts.showfullscreen) or + (not state.fullscreen and not user_opts.showwindowed) + then + margins = {l = 0, r = 0, t = 0, b = 0} + end + + if user_opts.boxvideo then + -- check whether any margin option has a non-default value + local margins_used = false + + if not state.using_video_margins then + for _, opt in ipairs(margins_opts) do + if mp.get_property_number(opt[2], 0.0) ~= 0.0 then + margins_used = true + end + end + end + + if not margins_used then + for _, opt in ipairs(margins_opts) do + local v = margins[opt[1]] + if (v ~= 0) or state.using_video_margins then + mp.set_property_number(opt[2], v) + state.using_video_margins = true + end + end + end + else + reset_margins() + end + + if tethys.userdataAvail then + mp.set_property_native("user-data/osc/margins", { + l = margins.l, r = margins.r, t = margins.t, b = margins.b, + }) + else + utils.shared_script_property_set("osc-margins", + string.format("%f,%f,%f,%f", margins.l, margins.r, margins.t, margins.b)) + end +end + +function shutdown() + reset_margins() + if tethys.userdataAvail then + mp.set_property_native("user-data/osc/margins", nil) + else + utils.shared_script_property_set("osc-margins", nil) + end +end + +-- +-- Other important stuff +-- + + +function updateSubMarginY(oscVisible) + local defMarginY = 22 -- https://mpv.io/manual/master/#options-sub-margin-y + local subMarginY = oscVisible and (defMarginY+tethys.bottomBarHeight) or defMarginY + mp.set_property_number("sub-margin-y", subMarginY) +end + +function show_osc() + -- show when disabled can happen (e.g. mouse_move) due to async/delayed unbinding + if not state.enabled then return end + + msg.trace("show_osc") + --remember last time of invocation (mouse move) + state.showtime = mp.get_time() + + osc_visible(true) + + if (user_opts.fadeduration > 0) then + state.anitype = nil + end +end + +function hide_osc() + msg.trace("hide_osc") + if not state.enabled then + -- typically hide happens at render() from tick(), but now tick() is + -- no-op and won't render again to remove the osc, so do that manually. + state.osc_visible = false + render_wipe() + elseif (user_opts.fadeduration > 0) then + if not(state.osc_visible == false) then + state.anitype = "out" + request_tick() + end + else + osc_visible(false) + end +end + +function osc_visible(visible) + if state.osc_visible ~= visible then + state.osc_visible = visible + update_margins() + updateSubMarginY(visible) + end + request_tick() +end + +function pause_state(name, enabled) + state.paused = enabled + request_tick() +end + +function cache_state(name, st) + state.cache_state = st + request_tick() +end + +-- Request that tick() is called (which typically re-renders the OSC). +-- The tick is then either executed immediately, or rate-limited if it was +-- called a small time ago. +function request_tick() + if state.tick_timer == nil then + state.tick_timer = mp.add_timeout(0, tick) + end + + if not state.tick_timer:is_enabled() then + local now = mp.get_time() + local timeout = tick_delay - (now - state.tick_last_time) + if timeout < 0 then + timeout = 0 + end + state.tick_timer.timeout = timeout + state.tick_timer:resume() + end +end + +function mouse_leave() + if get_hidetimeout() >= 0 then + hide_osc() + end + -- reset mouse position + state.last_mouseX, state.last_mouseY = nil, nil + state.mouse_in_window = false +end + +function request_init() + state.initREQ = true + request_tick() +end + +-- Like request_init(), but also request an immediate update +function request_init_resize() + request_init() + -- ensure immediate update + state.tick_timer:kill() + state.tick_timer.timeout = 0 + state.tick_timer:resume() +end + +function render_wipe() + msg.trace("render_wipe()") + state.osd.data = "" -- allows set_osd to immediately update on enable + state.osd:remove() +end + +function render() + msg.trace("rendering") + local current_screen_sizeX, current_screen_sizeY, aspect = mp.get_osd_size() + local mouseX, mouseY = get_virt_mouse_pos() + local now = mp.get_time() + + -- check if display changed, if so request reinit + if not (state.mp_screen_sizeX == current_screen_sizeX + and state.mp_screen_sizeY == current_screen_sizeY) then + + request_init_resize() + + state.mp_screen_sizeX = current_screen_sizeX + state.mp_screen_sizeY = current_screen_sizeY + end + + -- init management + if state.active_element then + -- mouse is held down on some element - keep ticking and igore initReq + -- till it's released, or else the mouse-up (click) will misbehave or + -- get ignored. that's because osc_init() recreates the osc elements, + -- but mouse handling depends on the elements staying unmodified + -- between mouse-down and mouse-up (using the index active_element). + request_tick() + elseif state.initREQ then + osc_init() + state.initREQ = false + + -- store initial mouse position + if (state.last_mouseX == nil or state.last_mouseY == nil) + and not (mouseX == nil or mouseY == nil) then + + state.last_mouseX, state.last_mouseY = mouseX, mouseY + end + end + + + -- fade animation + if not(state.anitype == nil) then + + if (state.anistart == nil) then + state.anistart = now + end + + if (now < state.anistart + (user_opts.fadeduration/1000)) then + + if (state.anitype == "in") then --fade in + osc_visible(true) + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 255, 0, now) + elseif (state.anitype == "out") then --fade out + state.animation = scale_value(state.anistart, + (state.anistart + (user_opts.fadeduration/1000)), + 0, 255, now) + end + + else + if (state.anitype == "out") then + osc_visible(false) + end + kill_animation() + end + else + kill_animation() + end + + --mouse show/hide area + for k,cords in pairs(osc_param.areas["showhide"]) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "showhide") + end + if osc_param.areas["showhide_wc"] then + for k,cords in pairs(osc_param.areas["showhide_wc"]) do + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "showhide_wc") + end + else + set_virt_mouse_area(0, 0, 0, 0, "showhide_wc") + end + do_enable_keybindings() + + --mouse input area + local mouse_over_osc = false + + for _,cords in ipairs(osc_param.areas["input"]) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "input") + end + if state.osc_visible ~= state.input_enabled then + if state.osc_visible then + mp.enable_key_bindings("input") + else + mp.disable_key_bindings("input") + end + state.input_enabled = state.osc_visible + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + + if osc_param.areas["window-controls"] then + for _,cords in ipairs(osc_param.areas["window-controls"]) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "window-controls") + mp.enable_key_bindings("window-controls") + else + mp.disable_key_bindings("window-controls") + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + if osc_param.areas["window-controls-title"] then + for _,cords in ipairs(osc_param.areas["window-controls-title"]) do + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + + -- autohide + if not (state.showtime == nil) and (get_hidetimeout() >= 0) then + local timeout = state.showtime + (get_hidetimeout()/1000) - now + if timeout <= 0 then + if (state.active_element == nil) and not (mouse_over_osc) then + hide_osc() + end + else + -- the timer is only used to recheck the state and to possibly run + -- the code above again + if not state.hide_timer then + state.hide_timer = mp.add_timeout(0, tick) + end + state.hide_timer.timeout = timeout + -- re-arm + state.hide_timer:kill() + state.hide_timer:resume() + end + end + + + -- actual rendering + local ass = assdraw.ass_new() + + -- Messages + render_message(ass) + + -- PreRender + preRenderThumbnails() + + -- actual OSC + if state.osc_visible then + render_elements(ass) + end + + -- PostRender + postRenderThumbnails() + + -- submit + set_osd(osc_param.playresy * osc_param.display_aspect, + osc_param.playresy, ass.text) +end + +-- +-- Eventhandling +-- + +local function element_has_action(element, action) + return element and element.eventresponder and + element.eventresponder[action] +end + +function process_event(source, what) + local action = string.format("%s%s", source, + what and ("_" .. what) or "") + + if what == "down" or what == "press" then + + for n = 1, #elements do + + if mouse_hit(elements[n]) and + elements[n].eventresponder and + (elements[n].eventresponder[source .. "_up"] or + elements[n].eventresponder[action]) then + + if what == "down" then + state.active_element = n + state.active_event_source = source + end + -- fire the down or press event if the element has one + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + + end + end + + elseif what == "up" then + + if elements[state.active_element] then + local n = state.active_element + + if n == 0 then + --click on background (does not work) + elseif element_has_action(elements[n], action) and + mouse_hit(elements[n]) then + + elements[n].eventresponder[action](elements[n]) + end + + --reset active element + if element_has_action(elements[n], "reset") then + elements[n].eventresponder["reset"](elements[n]) + end + + end + state.active_element = nil + state.mouse_down_counter = 0 + + elseif source == "mouse_move" then + + state.mouse_in_window = true + + local mouseX, mouseY = get_virt_mouse_pos() + if (user_opts.minmousemove == 0) or + (not ((state.last_mouseX == nil) or (state.last_mouseY == nil)) and + ((math.abs(mouseX - state.last_mouseX) >= user_opts.minmousemove) + or (math.abs(mouseY - state.last_mouseY) >= user_opts.minmousemove) + ) + ) then + show_osc() + end + state.last_mouseX, state.last_mouseY = mouseX, mouseY + + local n = state.active_element + if element_has_action(elements[n], action) then + elements[n].eventresponder[action](elements[n]) + end + end + + -- ensure rendering after any (mouse) event - icons could change etc + request_tick() +end + + +local logo_lines = { + -- White border + "{\\c&HE5E5E5&\\p6}m 895 10 b 401 10 0 410 0 905 0 1399 401 1800 895 1800 1390 1800 1790 1399 1790 905 1790 410 1390 10 895 10 {\\p0}", + -- Purple fill + "{\\c&H682167&\\p6}m 925 42 b 463 42 87 418 87 880 87 1343 463 1718 925 1718 1388 1718 1763 1343 1763 880 1763 418 1388 42 925 42{\\p0}", + -- Darker fill + "{\\c&H430142&\\p6}m 1605 828 b 1605 1175 1324 1456 977 1456 631 1456 349 1175 349 828 349 482 631 200 977 200 1324 200 1605 482 1605 828{\\p0}", + -- White fill + "{\\c&HDDDBDD&\\p6}m 1296 910 b 1296 1131 1117 1310 897 1310 676 1310 497 1131 497 910 497 689 676 511 897 511 1117 511 1296 689 1296 910{\\p0}", + -- Triangle + "{\\c&H691F69&\\p6}m 762 1113 l 762 708 b 881 776 1000 843 1119 911 1000 978 881 1046 762 1113{\\p0}", +} + +local santa_hat_lines = { + -- Pompoms + "{\\c&HC0C0C0&\\p6}m 500 -323 b 491 -322 481 -318 475 -311 465 -312 456 -319 446 -318 434 -314 427 -304 417 -297 410 -290 404 -282 395 -278 390 -274 387 -267 381 -265 377 -261 379 -254 384 -253 397 -244 409 -232 425 -228 437 -228 446 -218 457 -217 462 -216 466 -213 468 -209 471 -205 477 -203 482 -206 491 -211 499 -217 508 -222 532 -235 556 -249 576 -267 584 -272 584 -284 578 -290 569 -305 550 -312 533 -309 523 -310 515 -316 507 -321 505 -323 503 -323 500 -323{\\p0}", + "{\\c&HE0E0E0&\\p6}m 315 -260 b 286 -258 259 -240 246 -215 235 -210 222 -215 211 -211 204 -188 177 -176 172 -151 170 -139 163 -128 154 -121 143 -103 141 -81 143 -60 139 -46 125 -34 129 -17 132 -1 134 16 142 30 145 56 161 80 181 96 196 114 210 133 231 144 266 153 303 138 328 115 373 79 401 28 423 -24 446 -73 465 -123 483 -174 487 -199 467 -225 442 -227 421 -232 402 -242 384 -254 364 -259 342 -250 322 -260 320 -260 317 -261 315 -260{\\p0}", + -- Main cap + "{\\c&H0000F0&\\p6}m 1151 -523 b 1016 -516 891 -458 769 -406 693 -369 624 -319 561 -262 526 -252 465 -235 479 -187 502 -147 551 -135 588 -111 1115 165 1379 232 1909 761 1926 800 1952 834 1987 858 2020 883 2053 912 2065 952 2088 1000 2146 962 2139 919 2162 836 2156 747 2143 662 2131 615 2116 567 2122 517 2120 410 2090 306 2089 199 2092 147 2071 99 2034 64 1987 5 1928 -41 1869 -86 1777 -157 1712 -256 1629 -337 1578 -389 1521 -436 1461 -476 1407 -509 1343 -507 1284 -515 1240 -519 1195 -521 1151 -523{\\p0}", + -- Cap shadow + "{\\c&H0000AA&\\p6}m 1657 248 b 1658 254 1659 261 1660 267 1669 276 1680 284 1689 293 1695 302 1700 311 1707 320 1716 325 1726 330 1735 335 1744 347 1752 360 1761 371 1753 352 1754 331 1753 311 1751 237 1751 163 1751 90 1752 64 1752 37 1767 14 1778 -3 1785 -24 1786 -45 1786 -60 1786 -77 1774 -87 1760 -96 1750 -78 1751 -65 1748 -37 1750 -8 1750 20 1734 78 1715 134 1699 192 1694 211 1689 231 1676 246 1671 251 1661 255 1657 248 m 1909 541 b 1914 542 1922 549 1917 539 1919 520 1921 502 1919 483 1918 458 1917 433 1915 407 1930 373 1942 338 1947 301 1952 270 1954 238 1951 207 1946 214 1947 229 1945 239 1939 278 1936 318 1924 356 1923 362 1913 382 1912 364 1906 301 1904 237 1891 175 1887 150 1892 126 1892 101 1892 68 1893 35 1888 2 1884 -9 1871 -20 1859 -14 1851 -6 1854 9 1854 20 1855 58 1864 95 1873 132 1883 179 1894 225 1899 273 1908 362 1910 451 1909 541{\\p0}", + -- Brim and tip pompom + "{\\c&HF8F8F8&\\p6}m 626 -191 b 565 -155 486 -196 428 -151 387 -115 327 -101 304 -47 273 2 267 59 249 113 219 157 217 213 215 265 217 309 260 302 285 283 373 264 465 264 555 257 608 252 655 292 709 287 759 294 816 276 863 298 903 340 972 324 1012 367 1061 394 1125 382 1167 424 1213 462 1268 482 1322 506 1385 546 1427 610 1479 662 1510 690 1534 725 1566 752 1611 796 1664 830 1703 880 1740 918 1747 986 1805 1005 1863 991 1897 932 1916 880 1914 823 1945 777 1961 725 1979 673 1957 622 1938 575 1912 534 1862 515 1836 473 1790 417 1755 351 1697 305 1658 266 1633 216 1593 176 1574 138 1539 116 1497 110 1448 101 1402 77 1371 37 1346 -16 1295 15 1254 6 1211 -27 1170 -62 1121 -86 1072 -104 1027 -128 976 -133 914 -130 851 -137 794 -162 740 -181 679 -168 626 -191 m 2051 917 b 1971 932 1929 1017 1919 1091 1912 1149 1923 1214 1970 1254 2000 1279 2027 1314 2066 1325 2139 1338 2212 1295 2254 1238 2281 1203 2287 1158 2282 1116 2292 1061 2273 1006 2229 970 2206 941 2167 938 2138 918{\\p0}", +} + +-- called by mpv on every frame +function tick() + if state.marginsREQ == true then + update_margins() + state.marginsREQ = false + end + + if (not state.enabled) then return end + + if (state.idle) then + + -- render idle message + msg.trace("idle message") + local icon_x, icon_y = 320 - 26, 140 + local line_prefix = ("{\\rDefault\\an7\\1a&H00&\\bord0\\shad0\\pos(%f,%f)}"):format(icon_x, icon_y) + + local ass = assdraw.ass_new() + -- mpv logo + if user_opts.idlescreen then + for i, line in ipairs(logo_lines) do + ass:new_event() + ass:append(line_prefix .. line) + end + end + + -- Santa hat + if is_december and user_opts.idlescreen and not user_opts.greenandgrumpy then + for i, line in ipairs(santa_hat_lines) do + ass:new_event() + ass:append(line_prefix .. line) + end + end + + if user_opts.idlescreen then + ass:new_event() + ass:pos(320, icon_y+65) + ass:an(8) + ass:append("Drop files or URLs to play here.") + end + set_osd(640, 360, ass.text) + + if state.showhide_enabled then + mp.disable_key_bindings("showhide") + mp.disable_key_bindings("showhide_wc") + state.showhide_enabled = false + end + + + elseif (state.fullscreen and user_opts.showfullscreen) + or (not state.fullscreen and user_opts.showwindowed) then + + -- render the OSC + render() + else + -- Flush OSD + render_wipe() + end + + state.tick_last_time = mp.get_time() + + if state.anitype ~= nil then + -- state.anistart can be nil - animation should now start, or it can + -- be a timestamp when it started. state.idle has no animation. + if not state.idle and + (not state.anistart or + mp.get_time() < 1 + state.anistart + user_opts.fadeduration/1000) + then + -- animating or starting, or still within 1s past the deadline + request_tick() + else + kill_animation() + end + end +end + +function do_enable_keybindings() + if state.enabled then + if not state.showhide_enabled then + mp.enable_key_bindings("showhide", "allow-vo-dragging+allow-hide-cursor") + mp.enable_key_bindings("showhide_wc", "allow-vo-dragging+allow-hide-cursor") + end + state.showhide_enabled = true + end +end + +function enable_osc(enable) + state.enabled = enable + if enable then + do_enable_keybindings() + else + hide_osc() -- acts immediately when state.enabled == false + if state.showhide_enabled then + mp.disable_key_bindings("showhide") + mp.disable_key_bindings("showhide_wc") + end + state.showhide_enabled = false + end +end + +-- duration is observed for the sole purpose of updating chapter markers +-- positions. live streams with chapters are very rare, and the update is also +-- expensive (with request_init), so it's only observed when we have chapters +-- and the user didn't disable the livemarkers option (update_duration_watch). +function on_duration() request_init() end + +local duration_watched = false +function update_duration_watch() + local want_watch = user_opts.livemarkers and + (mp.get_property_number("chapters", 0) or 0) > 0 and + true or false -- ensure it's a boolean + + if (want_watch ~= duration_watched) then + if want_watch then + mp.observe_property("duration", nil, on_duration) + else + mp.unobserve_property(on_duration) + end + duration_watched = want_watch + end +end + +validate_user_opts() +update_duration_watch() + +mp.register_event("shutdown", shutdown) +mp.register_event("start-file", request_init) +mp.observe_property("track-list", nil, request_init) +mp.observe_property("playlist", nil, request_init) +mp.observe_property("chapter-list", "native", function(_, list) + list = list or {} -- safety, shouldn't return nil + table.sort(list, function(a, b) return a.time < b.time end) + state.chapter_list = list + update_duration_watch() + request_init() +end) + +mp.register_script_message("osc-message", show_message) +mp.register_script_message("osc-chapterlist", function(dur) + show_message(get_chapterlist(), dur) +end) +mp.register_script_message("osc-playlist", function(dur) + show_message(get_playlist(), dur) +end) +mp.register_script_message("osc-tracklist", function(dur) + local msg = {} + for k,v in pairs(nicetypes) do + table.insert(msg, get_tracklist(k)) + end + show_message(table.concat(msg, '\n\n'), dur) +end) + +mp.observe_property("fullscreen", "bool", + function(name, val) + state.fullscreen = val + state.marginsREQ = true + request_init_resize() + end +) +mp.observe_property("border", "bool", + function(name, val) + state.border = val + request_init_resize() + end +) +mp.observe_property("window-maximized", "bool", + function(name, val) + state.maximized = val + request_init_resize() + end +) +mp.observe_property("idle-active", "bool", + function(name, val) + state.idle = val + request_tick() + end +) +mp.observe_property("pause", "bool", pause_state) +mp.observe_property("demuxer-cache-state", "native", cache_state) +mp.observe_property("vo-configured", "bool", function(name, val) + request_tick() +end) +mp.observe_property("playback-time", "number", function(name, val) + request_tick() +end) +mp.observe_property("osd-dimensions", "native", function(name, val) + -- (we could use the value instead of re-querying it all the time, but then + -- we might have to worry about property update ordering) + request_init_resize() +end) + +-- mouse show/hide bindings +mp.set_key_bindings({ + {"mouse_move", function(e) process_event("mouse_move", nil) end}, + {"mouse_leave", mouse_leave}, +}, "showhide", "force") +mp.set_key_bindings({ + {"mouse_move", function(e) process_event("mouse_move", nil) end}, + {"mouse_leave", mouse_leave}, +}, "showhide_wc", "force") +do_enable_keybindings() + +--mouse input bindings +mp.set_key_bindings({ + {"mbtn_left", function(e) process_event("mbtn_left", "up") end, + function(e) process_event("mbtn_left", "down") end}, + {"shift+mbtn_left", function(e) process_event("shift+mbtn_left", "up") end, + function(e) process_event("shift+mbtn_left", "down") end}, + {"mbtn_right", function(e) process_event("mbtn_right", "up") end, + function(e) process_event("mbtn_right", "down") end}, + -- alias to shift_mbtn_left for single-handed mouse use + {"mbtn_mid", function(e) process_event("shift+mbtn_left", "up") end, + function(e) process_event("shift+mbtn_left", "down") end}, + {"wheel_up", function(e) process_event("wheel_up", "press") end}, + {"wheel_down", function(e) process_event("wheel_down", "press") end}, + {"mbtn_left_dbl", "ignore"}, + {"shift+mbtn_left_dbl", "ignore"}, + {"mbtn_right_dbl", "ignore"}, +}, "input", "force") +mp.enable_key_bindings("input") + +mp.set_key_bindings({ + {"mbtn_left", function(e) process_event("mbtn_left", "up") end, + function(e) process_event("mbtn_left", "down") end}, +}, "window-controls", "force") +mp.enable_key_bindings("window-controls") + +function get_hidetimeout() + if user_opts.visibility == "always" then + return -1 -- disable autohide + end + return user_opts.hidetimeout +end + +function always_on(val) + if state.enabled then + if val then + show_osc() + else + hide_osc() + end + end +end + +-- mode can be auto/always/never/cycle +-- the modes only affect internal variables and not stored on its own. +function visibility_mode(mode, no_osd) + if mode == "cycle" then + if not state.enabled then + mode = "auto" + elseif user_opts.visibility ~= "always" then + mode = "always" + else + mode = "never" + end + end + + if mode == "auto" then + always_on(false) + enable_osc(true) + elseif mode == "always" then + enable_osc(true) + always_on(true) + elseif mode == "never" then + enable_osc(false) + else + msg.warn("Ignoring unknown visibility mode '" .. mode .. "'") + return + end + + user_opts.visibility = mode + if tethys.userdataAvail then + mp.set_property_native("user-data/osc/visibility", mode) + else + utils.shared_script_property_set("osc-visibility", mode) + end + + if not no_osd and tonumber(mp.get_property("osd-level")) >= 1 then + mp.osd_message("OSC visibility: " .. mode) + end + + -- Reset the input state on a mode change. The input state will be + -- recalculated on the next render cycle, except in 'never' mode where it + -- will just stay disabled. + mp.disable_key_bindings("input") + mp.disable_key_bindings("window-controls") + state.input_enabled = false + + update_margins() + request_tick() +end + +function idlescreen_visibility(mode, no_osd) + if mode == "cycle" then + if user_opts.idlescreen then + mode = "no" + else + mode = "yes" + end + end + + if mode == "yes" then + user_opts.idlescreen = true + else + user_opts.idlescreen = false + end + + if tethys.userdataAvail then + mp.set_property_native("user-data/osc/idlescreen", mode) + else + utils.shared_script_property_set("osc-idlescreen", mode) + end + + if not no_osd and tonumber(mp.get_property("osd-level")) >= 1 then + mp.osd_message("OSC logo visibility: " .. tostring(mode)) + end + + request_tick() +end + +visibility_mode(user_opts.visibility, true) +mp.register_script_message("osc-visibility", visibility_mode) +mp.add_key_binding(nil, "visibility", function() visibility_mode("cycle") end) + +mp.register_script_message("osc-idlescreen", idlescreen_visibility) + +set_virt_mouse_area(0, 0, 0, 0, "input") +set_virt_mouse_area(0, 0, 0, 0, "window-controls") diff --git a/mpv/scripts/playlistmanager.lua b/mpv/scripts/playlistmanager.lua new file mode 100644 index 0000000..88f7753 --- /dev/null +++ b/mpv/scripts/playlistmanager.lua @@ -0,0 +1,1699 @@ +local settings = { + --navigation keybindings force override only while playlist is visible + --if "no" then you can display the playlist by any of the navigation keys + dynamic_binds = true, + + -- to bind multiple keys separate them by a space + + -- main key to show playlist + key_showplaylist = "SHIFT+ENTER", + + -- display playlist while key is held down + key_peek_at_playlist = "", + + -- dynamic keys + key_moveup = "UP", + key_movedown = "DOWN", + key_movepageup = "PGUP", + key_movepagedown = "PGDWN", + key_movebegin = "HOME", + key_moveend = "END", + key_selectfile = "RIGHT LEFT", + key_unselectfile = "", + key_playfile = "ENTER", + key_removefile = "BS", + key_closeplaylist = "ESC SHIFT+ENTER", + + -- extra functionality keys + key_sortplaylist = "", + key_shuffleplaylist = "", + key_reverseplaylist = "", + key_loadfiles = "", + key_saveplaylist = "", + + --replaces matches on filenames based on extension, put as empty string to not replace anything + --replace rules are executed in provided order + --replace rule key is the pattern and value is the replace value + --uses :gsub('pattern', 'replace'), read more http://lua-users.org/wiki/StringLibraryTutorial + --'all' will match any extension or protocol if it has one + --uses json and parses it into a lua table to be able to support .conf file + + filename_replace = [[ + [ + { + "protocol": { "all": true }, + "rules": [ + { "%%(%x%x)": "hex_to_char" } + ] + } + ] + ]], + +--[=====[ START OF SAMPLE REPLACE - Remove this line to use it + --Sample replace: replaces underscore to space on all files + --for mp4 and webm; remove extension, remove brackets and surrounding whitespace, change dot between alphanumeric to space + filename_replace = [[ + [ + { + "ext": { "all": true}, + "rules": [ + { "_" : " " } + ] + },{ + "ext": { "mp4": true, "mkv": true }, + "rules": [ + { "^(.+)%..+$": "%1" }, + { "%s*[%[%(].-[%]%)]%s*": "" }, + { "(%w)%.(%w)": "%1 %2" } + ] + },{ + "protocol": { "http": true, "https": true }, + "rules": [ + { "^%a+://w*%.?": "" } + ] + } + ] + ]], +--END OF SAMPLE REPLACE ]=====] + + --json array of filetypes to search from directory + loadfiles_filetypes = [[ + [ + "jpg", "jpeg", "png", "tif", "tiff", "gif", "webp", "svg", "bmp", + "mp3", "wav", "ogm", "flac", "m4a", "wma", "ogg", "opus", + "mkv", "avi", "mp4", "ogv", "webm", "rmvb", "flv", "wmv", "mpeg", "mpg", "m4v", "3gp" + ] + ]], + + --loadfiles at startup if 1 or more items in playlist + loadfiles_on_start = false, + -- loadfiles from working directory on idle startup + loadfiles_on_idle_start = false, + --always put loaded files after currently playing file + loadfiles_always_append = false, + + --sort playlist when files are added to playlist + sortplaylist_on_file_add = false, + + --default sorting method, must be one of: "name-asc", "name-desc", "date-asc", "date-desc", "size-asc", "size-desc". + default_sort = "name-asc", + + --"linux | windows | auto" + system = "auto", + + --Use ~ for home directory. Leave as empty to use mpv/playlists + playlist_savepath = "", + + -- constant filename to save playlist as. Note that it will override existing playlist. Leave empty for generated name. + playlist_save_filename = "", + + --save playlist automatically after current file was unloaded + save_playlist_on_file_end = false, + + + --show file title every time a new file is loaded + show_title_on_file_load = false, + --show playlist every time a new file is loaded + show_playlist_on_file_load = false, + --close playlist when selecting file to play + close_playlist_on_playfile = false, + + --sync cursor when file is loaded from outside reasons(file-ending, playlist-next shortcut etc.) + --has the sideeffect of moving cursor if file happens to change when navigating + --good side is cursor always following current file when going back and forth files with playlist-next/prev + sync_cursor_on_load = true, + + --allow the playlist cursor to loop from end to start and vice versa + loop_cursor = true, + + + -- allow playlistmanager to write watch later config when navigating between files + allow_write_watch_later_config = true, + + -- reset cursor navigation when closing or opening playlist + reset_cursor_on_close = true, + reset_cursor_on_open = true, + + --prefer to display titles for following files: "all", "url", "none". Sorting still uses filename. + prefer_titles = "url", + + --youtube-dl executable for title resolving if enabled, probably "youtube-dl" or "yt-dlp", can be absolute path + youtube_dl_executable = "yt-dlp", + + --call youtube-dl to resolve the titles of urls in the playlist + resolve_url_titles = false, + + --call ffprobe to resolve the titles of local files in the playlist (if they exist in the metadata) + resolve_local_titles = false, + + -- timeout in seconds for url title resolving + resolve_title_timeout = 15, + + -- how many url titles can be resolved at a time. Higher number might lead to stutters. + concurrent_title_resolve_limit = 10, + + --osd timeout on inactivity in seconds, use 0 for no timeout + playlist_display_timeout = 0, + + -- when peeking at playlist, show playlist at the very least for display timeout + peek_respect_display_timeout = false, + + -- the maximum amount of lines playlist will render. -1 will automatically calculate lines. + showamount = -1, + + --playlist ass style overrides inside curly brackets, \keyvalue is one field, extra \ for escape in lua + --example {\\q2\\an7\\fnUbuntu\\fs10\\b0\\bord1} equals: line-wrap=no, align=top left, font=Ubuntu, size=10, bold=no, border=1 + --read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags + --undeclared tags will use default osd settings + --these styles will be used for the whole playlist + --\\q2 style is recommended since filename wrapping may lead to unexpected rendering + --\\an7 style is recommended to align to top left otherwise, osd-align-x/y is respected + style_ass_tags = "{\\q2\\an7}", + --paddings for left right and top bottom + text_padding_x = 30, + text_padding_y = 60, + + --screen dim when menu is open 0.0 - 1.0 (0 is no dim, 1 is black) + curtain_opacity=0.0, + + --set title of window with stripped name + set_title_stripped = false, + title_prefix = "", + title_suffix = " - mpv", + + --slice long filenames, and how many chars to show + slice_longfilenames = false, + slice_longfilenames_amount = 70, + + --Playlist header template + --%mediatitle or %filename = title or name of playing file + --%pos = position of playing file + --%cursor = position of navigation + --%plen = playlist length + --%N = newline + playlist_header = "[%cursor/%plen]", + + --Playlist file templates + --%pos = position of file with leading zeros + --%name = title or name of file + --%N = newline + --you can also use the ass tags mentioned above. For example: + -- selected_file="{\\c&HFF00FF&}➔ %name" | to add a color for selected file. However, if you + -- use ass tags you need to reset them for every line (see https://github.com/jonniek/mpv-playlistmanager/issues/20) + normal_file = "○ %name", + hovered_file = "● %name", + selected_file = "➔ %name", + playing_file = "▷ %name", + playing_hovered_file = "▶ %name", + playing_selected_file = "➤ %name", + + + -- what to show when playlist is truncated + playlist_sliced_prefix = "...", + playlist_sliced_suffix = "...", + + --output visual feedback to OSD for tasks + display_osd_feedback = true, +} +local opts = require("mp.options") +opts.read_options(settings, "playlistmanager", function(list) update_opts(list) end) + +local utils = require("mp.utils") +local msg = require("mp.msg") +local assdraw = require("mp.assdraw") + +local alignment_table = { + [1] = { ["x"] = "left", ["y"] = "bottom" }, + [2] = { ["x"] = "center", ["y"] = "bottom" }, + [3] = { ["x"] = "right", ["y"] = "bottom" }, + [4] = { ["x"] = "left", ["y"] = "center" }, + [5] = { ["x"] = "center", ["y"] = "center" }, + [6] = { ["x"] = "right", ["y"] = "center" }, + [7] = { ["x"] = "left", ["y"] = "top" }, + [8] = { ["x"] = "center", ["y"] = "top" }, + [9] = { ["x"] = "right", ["y"] = "top" }, +} + +--check os +if settings.system=="auto" then + local o = {} + if mp.get_property_native('options/vo-mmcss-profile', o) ~= o then + settings.system = "windows" + else + settings.system = "linux" + end +end + +-- auto calculate showamount +if settings.showamount == -1 then + -- same as draw_playlist() height + local h = 720 + + local playlist_h = h + -- both top and bottom with same padding + playlist_h = playlist_h - settings.text_padding_y * 2 + + -- osd-font-size is based on 720p height + -- see https://mpv.io/manual/stable/#options-osd-font-size + -- details in https://mpv.io/manual/stable/#options-sub-font-size + -- draw_playlist() is based on 720p, need some conversion + local fs = mp.get_property_native('osd-font-size') * h / 720 + -- get the ass font size + if settings.style_ass_tags ~= nil then + local ass_fs_tag = settings.style_ass_tags:match('\\fs%d+') + if ass_fs_tag ~= nil then + fs = tonumber(ass_fs_tag:match('%d+')) + end + end + + settings.showamount = math.floor(playlist_h / fs) + + -- exclude the header line + if settings.playlist_header ~= "" then + settings.showamount = settings.showamount - 1 + -- probably some newlines (%N or \N) in the header + for _ in settings.playlist_header:gmatch('%%N') do + settings.showamount = settings.showamount - 1 + end + for _ in settings.playlist_header:gmatch('\\N') do + settings.showamount = settings.showamount - 1 + end + end + + msg.info('auto showamount: ' .. settings.showamount) +end + +--global variables +local playlist_overlay = mp.create_osd_overlay("ass-events") +local playlist_visible = false +local strippedname = nil +local path = nil +local directory = nil +local filename = nil +local pos = 0 +local plen = 0 +local cursor = 0 +--table for saved media titles for later if we prefer them +local title_table = {} +-- table for urls and local file paths that we have requested to be resolved to titles +local requested_titles = {} + +local filetype_lookup = {} + +function refresh_UI() + if not playlist_visible then return end + refresh_globals() + if plen == 0 then return end + draw_playlist() +end + +function update_opts(changelog) + msg.verbose('updating options') + + --parse filename json + if changelog.filename_replace then + if(settings.filename_replace~="") then + settings.filename_replace = utils.parse_json(settings.filename_replace) + else + settings.filename_replace = false + end + end + + --parse loadfiles json + if changelog.loadfiles_filetypes then + settings.loadfiles_filetypes = utils.parse_json(settings.loadfiles_filetypes) + + filetype_lookup = {} + --create loadfiles set + for _, ext in ipairs(settings.loadfiles_filetypes) do + filetype_lookup[ext] = true + end + end + + if changelog.resolve_url_titles then + resolve_titles() + end + + if changelog.resolve_local_titles then + resolve_titles() + end + + if changelog.playlist_display_timeout then + keybindstimer = mp.add_periodic_timer(settings.playlist_display_timeout, remove_keybinds) + keybindstimer:kill() + end + + refresh_UI() +end + +update_opts({filename_replace = true, loadfiles_filetypes = true}) + +----- winapi start ----- +-- in windows system, we can use the sorting function provided by the win32 API +-- see https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw +local winapisort = nil +if settings.system == "windows" then + -- ffiok is false usually means the mpv builds without luajit + local ffiok, ffi = pcall(require, "ffi") + if ffiok then + ffi.cdef[[ + int MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); + int StrCmpLogicalW(const wchar_t * psz1, const wchar_t * psz2); + ]] + + local shlwapi = ffi.load("shlwapi.dll") + + function MultiByteToWideChar(MultiByteStr) + local UTF8_CODEPAGE = 65001 + if MultiByteStr then + local utf16_len = ffi.C.MultiByteToWideChar(UTF8_CODEPAGE, 0, MultiByteStr, -1, nil, 0) + if utf16_len > 0 then + local utf16_str = ffi.new("wchar_t[?]", utf16_len) + if ffi.C.MultiByteToWideChar(UTF8_CODEPAGE, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then + return utf16_str + end + end + end + return "" + end + + winapisort = function (a, b) + return shlwapi.StrCmpLogicalW(MultiByteToWideChar(a), MultiByteToWideChar(b)) < 0 + end + + end +end +----- winapi end ----- + +local sort_modes = { + { + id="name-asc", + title="name ascending", + sort_fn=function (a, b, playlist) + if winapisort ~= nil then + return winapisort(playlist[a].string, playlist[b].string) + end + return alphanumsort(playlist[a].string, playlist[b].string) + end, + }, + { + id="name-desc", + title="name descending", + sort_fn=function (a, b, playlist) + if winapisort ~= nil then + return winapisort(playlist[b].string, playlist[a].string) + end + return alphanumsort(playlist[b].string, playlist[a].string) + end, + }, + { + id="date-asc", + title="date ascending", + sort_fn=function (a, b) + return (get_file_info(a).mtime or 0) < (get_file_info(b).mtime or 0) + end, + }, + { + id="date-desc", + title="date descending", + sort_fn=function (a, b) + return (get_file_info(a).mtime or 0) > (get_file_info(b).mtime or 0) + end, + }, + { + id="size-asc", + title="size ascending", + sort_fn=function (a, b) + return (get_file_info(a).size or 0) < (get_file_info(b).size or 0) + end, + }, + { + id="size-desc", + title="size descending", + sort_fn=function (a, b) + return (get_file_info(a).size or 0) > (get_file_info(b).size or 0) + end, + }, +} + +local sort_mode = 1 +for mode, sort_data in pairs(sort_modes) do + if sort_data.id == settings.default_sort then + sort_mode = mode + end +end + +function is_protocol(path) + return type(path) == 'string' and path:match('^%a[%a%d-_]+://') ~= nil +end + +function on_file_loaded() + refresh_globals() + if settings.sync_cursor_on_load then cursor=pos end + refresh_UI() -- refresh only after moving cursor + + filename = mp.get_property("filename") + path = mp.get_property('path') + local media_title = mp.get_property("media-title") + if is_protocol(path) and not title_table[path] and path ~= media_title then + title_table[path] = media_title + end + + strippedname = stripfilename(mp.get_property('media-title')) + if settings.show_title_on_file_load then + mp.commandv('show-text', strippedname) + end + if settings.show_playlist_on_file_load then + showplaylist() + end + if settings.set_title_stripped then + mp.set_property("title", settings.title_prefix..strippedname..settings.title_suffix) + end +end + +function on_start_file() + refresh_globals() + filename = mp.get_property("filename") + path = mp.get_property('path') + --if not a url then join path with working directory + if not is_protocol(path) then + path = utils.join_path(mp.get_property('working-directory'), path) + directory = utils.split_path(path) + else + directory = nil + end + + if settings.loadfiles_on_start and plen == 1 then + local ext = filename:match("%.([^%.]+)$") + -- a directory or playlist has been loaded, let's not do anything as mpv will expand it into files + if ext and filetype_lookup[ext:lower()] then + msg.info("Loading files from playing files directory") + playlist() + end + end +end + +function on_end_file() + if settings.save_playlist_on_file_end then save_playlist() end + strippedname = nil + path = nil + directory = nil + filename = nil +end + +function refresh_globals() + pos = mp.get_property_number('playlist-pos', 0) + plen = mp.get_property_number('playlist-count', 0) +end + +function escapepath(dir, escapechar) + return string.gsub(dir, escapechar, '\\'..escapechar) +end + +function replace_table_has_value(value, valid_values) + if value == nil or valid_values == nil then + return false + end + return valid_values['all'] or valid_values[value] +end + +local filename_replace_functions = { + --decode special characters in url + hex_to_char = function(x) return string.char(tonumber(x, 16)) end +} + +-- from http://lua-users.org/wiki/LuaUnicode +local UTF8_PATTERN = '[%z\1-\127\194-\244][\128-\191]*' + +-- return a substring based on utf8 characters +-- like string.sub, but negative index is not supported +local function utf8_sub(s, i, j) + if i > j then + return s + end + + local t = {} + local idx = 1 + for char in s:gmatch(UTF8_PATTERN) do + if i <= idx and idx <= j then + local width = #char > 2 and 2 or 1 + idx = idx + width + t[#t + 1] = char + end + end + return table.concat(t) +end + +--strip a filename based on its extension or protocol according to rules in settings +function stripfilename(pathfile, media_title) + if pathfile == nil then return '' end + local ext = pathfile:match("%.([^%.]+)$") + local protocol = pathfile:match("^(%a%a+)://") + if not ext then ext = "" end + local tmp = pathfile + if settings.filename_replace and not media_title then + for k,v in ipairs(settings.filename_replace) do + if replace_table_has_value(ext, v['ext']) or replace_table_has_value(protocol, v['protocol']) then + for ruleindex, indexrules in ipairs(v['rules']) do + for rule, override in pairs(indexrules) do + override = filename_replace_functions[override] or override + tmp = tmp:gsub(rule, override) + end + end + end + end + end + local tmp_clip = utf8_sub(tmp, 1, settings.slice_longfilenames_amount) + if settings.slice_longfilenames and tmp ~= tmp_clip then + tmp = tmp_clip .. "..." + end + return tmp +end + +--gets the file info of an item +function get_file_info(item) + local path = mp.get_property('playlist/' .. item - 1 .. '/filename') + if is_protocol(path) then return {} end + local file_info = utils.file_info(path) + if not file_info then + msg.warn('failed to read file info for', path) + return {} + end + + return file_info +end + +--gets a nicename of playlist entry at 0-based position i +function get_name_from_index(i, notitle) + refresh_globals() + if plen <= i then msg.error("no index in playlist", i, "length", plen); return nil end + local _, name = nil + local title = mp.get_property('playlist/'..i..'/title') + local name = mp.get_property('playlist/'..i..'/filename') + + local should_use_title = settings.prefer_titles == 'all' or is_protocol(name) and settings.prefer_titles == 'url' + + --check if file has a media title stored + if not title and should_use_title and title_table[name] then + title = title_table[name] + end + + --if we have media title use a more conservative strip + if title and not notitle and should_use_title then + -- Escape a string for verbatim display on the OSD + -- Ref: https://github.com/mpv-player/mpv/blob/94677723624fb84756e65c8f1377956667244bc9/player/lua/stats.lua#L145 + return stripfilename(title, true):gsub("\\", '\\\239\187\191'):gsub("{", "\\{"):gsub("^ ", "\\h") + end + + --remove paths if they exist, keeping protocols for stripping + if string.sub(name, 1, 1) == '/' or name:match("^%a:[/\\]") then + _, name = utils.split_path(name) + end + return stripfilename(name):gsub("\\", '\\\239\187\191'):gsub("{", "\\{"):gsub("^ ", "\\h") +end + +function parse_header(string) + local esc_title = stripfilename(mp.get_property("media-title"), true):gsub("%%", "%%%%") + local esc_file = stripfilename(mp.get_property("filename")):gsub("%%", "%%%%") + return string:gsub("%%N", "\\N") + -- add a blank character at the end of each '\N' to ensure that the height of the empty line is the same as the non empty line + :gsub("\\N", "\\N ") + :gsub("%%pos", mp.get_property_number("playlist-pos",0)+1) + :gsub("%%plen", mp.get_property("playlist-count")) + :gsub("%%cursor", cursor+1) + :gsub("%%mediatitle", esc_title) + :gsub("%%filename", esc_file) + -- undo name escape + :gsub("%%%%", "%%") +end + +function parse_filename(string, name, index) + local base = tostring(plen):len() + local esc_name = stripfilename(name):gsub("%%", "%%%%") + return string:gsub("%%N", "\\N") + :gsub("%%pos", string.format("%0"..base.."d", index+1)) + :gsub("%%name", esc_name) + -- undo name escape + :gsub("%%%%", "%%") +end + +function parse_filename_by_index(index) + local template = settings.normal_file + + local is_idle = mp.get_property_native('idle-active') + local position = is_idle and -1 or pos + + if index == position then + if index == cursor then + if selection then + template = settings.playing_selected_file + else + template = settings.playing_hovered_file + end + else + template = settings.playing_file + end + elseif index == cursor then + if selection then + template = settings.selected_file + else + template = settings.hovered_file + end + end + + return parse_filename(template, get_name_from_index(index), index) +end + +function is_terminal_mode() + local width, height, aspect_ratio = mp.get_osd_size() + return width == 0 and height == 0 and aspect_ratio == 0 +end + +function draw_playlist() + refresh_globals() + local ass = assdraw.ass_new() + local terminaloutput = "" + + local _, _, a = mp.get_osd_size() + local h = 720 + local w = math.ceil(h * a) + + if settings.curtain_opacity ~= nil and settings.curtain_opacity ~= 0 and settings.curtain_opacity <= 1.0 then + -- curtain dim from https://github.com/christoph-heinrich/mpv-quality-menu/blob/501794bfbef468ee6a61e54fc8821fe5cd72c4ed/quality-menu.lua#L699-L707 + local alpha = 255 - math.ceil(255 * settings.curtain_opacity) + ass.text = string.format('{\\pos(0,0)\\rDefault\\an7\\1c&H000000&\\alpha&H%X&}', alpha) + ass:draw_start() + ass:rect_cw(0, 0, w, h) + ass:draw_stop() + ass:new_event() + end + + ass:append(settings.style_ass_tags) + + -- add \clip style + -- make both left and right follow text_padding_x + -- both top and bottom follow text_padding_y + local border_size = mp.get_property_number('osd-border-size') + if settings.style_ass_tags ~= nil then + local bord = tonumber(settings.style_ass_tags:match('\\bord(%d+%.?%d*)')) + if bord ~= nil then border_size = bord end + end + ass:append(string.format('{\\clip(%f,%f,%f,%f)}', + settings.text_padding_x - border_size, settings.text_padding_y - border_size, + w - 1 - settings.text_padding_x + border_size, h - 1 - settings.text_padding_y + border_size)) + + -- align from mpv.conf + local align_x = mp.get_property("osd-align-x") + local align_y = mp.get_property("osd-align-y") + -- align from style_ass_tags + if settings.style_ass_tags ~= nil then + local an = tonumber(settings.style_ass_tags:match('\\an(%d)')) + if an ~= nil and alignment_table[an] ~= nil then + align_x = alignment_table[an]["x"] + align_y = alignment_table[an]["y"] + end + end + -- range of x [0, w-1] + local pos_x + if align_x == 'left' then + pos_x = settings.text_padding_x + elseif align_x == 'right' then + pos_x = w - 1 - settings.text_padding_x + else + pos_x = math.floor((w - 1) / 2) + end + -- range of y [0, h-1] + local pos_y + if align_y == 'top' then + pos_y = settings.text_padding_y + elseif align_y == 'bottom' then + pos_y = h - 1 - settings.text_padding_y + else + pos_y = math.floor((h - 1) / 2) + end + ass:pos(pos_x, pos_y) + + if settings.playlist_header ~= "" then + local header = parse_header(settings.playlist_header) + ass:append(header.."\\N") + terminaloutput = terminaloutput..header.."\n" + end + + -- (visible index, playlist index) pairs of playlist entries that should be rendered + local visible_indices = {} + + local one_based_cursor = cursor + 1 + table.insert(visible_indices, one_based_cursor) + + local offset = 1; + local visible_indices_length = 1; + while visible_indices_length < settings.showamount and visible_indices_length < plen do + -- add entry for offset steps below the cursor + local below = one_based_cursor + offset + if below <= plen then + table.insert(visible_indices, below) + visible_indices_length = visible_indices_length + 1; + end + + -- add entry for offset steps above the cursor + -- also need to double check that there is still space, this happens if we have even numbered limit + local above = one_based_cursor - offset + if above >= 1 and visible_indices_length < settings.showamount and visible_indices_length < plen then + table.insert(visible_indices, 1, above) + visible_indices_length = visible_indices_length + 1; + end + + offset = offset + 1 + end + + -- both indices are 1 based + for display_index, playlist_index in pairs(visible_indices) do + if display_index == 1 and playlist_index ~= 1 then + ass:append(settings.playlist_sliced_prefix.."\\N") + terminaloutput = terminaloutput..settings.playlist_sliced_prefix.."\n" + elseif display_index == settings.showamount and playlist_index ~= plen then + ass:append(settings.playlist_sliced_suffix) + terminaloutput = terminaloutput..settings.playlist_sliced_suffix.."\n" + else + -- parse_filename_by_index expects 0 based index + local fname = parse_filename_by_index(playlist_index - 1) + ass:append(fname.."\\N") + terminaloutput = terminaloutput..fname.."\n" + end + end + + if is_terminal_mode() then + local timeout_setting = settings.playlist_display_timeout + local timeout = timeout_setting == 0 and 2147483 or timeout_setting + -- TODO: probably have to strip ass tags from terminal output + -- would maybe be possible to use terminal color output instead + mp.osd_message(terminaloutput, timeout) + else + playlist_overlay.data = ass.text + playlist_overlay:update() + end +end + +local peek_display_timer = nil +local peek_button_pressed = false + +function peek_timeout() + peek_display_timer:kill() + if not peek_button_pressed and not playlist_visible then + remove_keybinds() + end +end + +function handle_complex_playlist_toggle(table) + local event = table["event"] + if event == "press" then + msg.error("Complex key event not supported. Falling back to normal playlist display.") + showplaylist() + elseif event == "down" then + showplaylist(1000000) + if settings.peek_respect_display_timeout then + peek_button_pressed = true + peek_display_timer = mp.add_periodic_timer(settings.playlist_display_timeout, peek_timeout) + end + elseif event == "up" then + -- set playlist state to not visible, doesn't actually hide playlist yet + -- this will allow us to check if other functionality has rendered playlist before removing binds + playlist_visible = false + + function remove_keybinds_after_timeout() + -- if playlist is still not visible then lets actually hide it + -- this lets other keys that interupt the peek to render playlist without peek up event closing it + if not playlist_visible then + remove_keybinds() + end + end + + if settings.peek_respect_display_timeout then + peek_button_pressed = false + if not peek_display_timer:is_enabled() then + mp.add_timeout(0.01, remove_keybinds_after_timeout) + end + else + -- use small delay to let dynamic binds run before keys are potentially unbound + mp.add_timeout(0.01, remove_keybinds_after_timeout) + end + end +end + +function toggle_playlist(show_function) + local show = show_function or showplaylist + if playlist_visible then + remove_keybinds() + else + -- toggle always shows without timeout + show(0) + end +end + +function showplaylist(duration) + refresh_globals() + if plen == 0 then return end + if not playlist_visible and settings.reset_cursor_on_open then + resetcursor() + end + + playlist_visible = true + add_keybinds() + + draw_playlist() + keybindstimer:kill() + + local dur = tonumber(duration) or settings.playlist_display_timeout + if dur > 0 then + keybindstimer = mp.add_periodic_timer(dur, remove_keybinds) + end +end + +function showplaylist_non_interactive(duration) + refresh_globals() + if plen == 0 then return end + if not playlist_visible and settings.reset_cursor_on_open then + resetcursor() + end + playlist_visible = true + draw_playlist() + keybindstimer:kill() + + local dur = tonumber(duration) or settings.playlist_display_timeout + if dur > 0 then + keybindstimer = mp.add_periodic_timer(dur, remove_keybinds) + end +end + +selection=nil +function selectfile() + refresh_globals() + if plen == 0 then return end + if not selection then + selection=cursor + else + selection=nil + end + showplaylist() +end + +function unselectfile() + selection=nil + showplaylist() +end + +function resetcursor() + selection = nil + cursor = mp.get_property_number('playlist-pos', 1) +end + +function removefile() + refresh_globals() + if plen == 0 then return end + selection = nil + if cursor==pos then mp.command("script-message unseenplaylist mark true \"playlistmanager avoid conflict when removing file\"") end + mp.commandv("playlist-remove", cursor) + if cursor==plen-1 then cursor = cursor - 1 end + if plen == 1 then + remove_keybinds() + else + showplaylist() + end +end + +function moveup() + refresh_globals() + if plen == 0 then return end + if cursor~=0 then + if selection then mp.commandv("playlist-move", cursor,cursor-1) end + cursor = cursor-1 + elseif settings.loop_cursor then + if selection then mp.commandv("playlist-move", cursor,plen) end + cursor = plen-1 + end + showplaylist() +end + +function movedown() + refresh_globals() + if plen == 0 then return end + if cursor ~= plen-1 then + if selection then mp.commandv("playlist-move", cursor,cursor+2) end + cursor = cursor + 1 + elseif settings.loop_cursor then + if selection then mp.commandv("playlist-move", cursor,0) end + cursor = 0 + end + showplaylist() +end + + +function movepageup() + refresh_globals() + if plen == 0 or cursor == 0 then return end + local offset = settings.showamount % 2 == 0 and 1 or 0 + local last_file_that_doesnt_scroll = math.ceil(settings.showamount / 2) + local reverse_cursor = plen - cursor + local files_to_jump = math.max(last_file_that_doesnt_scroll + offset - reverse_cursor, 0) + settings.showamount - 2 + local prev_cursor = cursor + cursor = cursor - files_to_jump + if cursor < last_file_that_doesnt_scroll then + cursor = 0 + end + if selection then + mp.commandv("playlist-move", prev_cursor, cursor) + end + showplaylist() +end + +function movepagedown() + refresh_globals() + if plen == 0 or cursor == plen - 1 then return end + local last_file_that_doesnt_scroll = math.ceil(settings.showamount / 2) - 1 + local files_to_jump = math.max(last_file_that_doesnt_scroll - cursor, 0) + settings.showamount - 2 + local prev_cursor = cursor + cursor = cursor + files_to_jump + + local cursor_on_last_page = plen - (settings.showamount - 3) + if cursor > cursor_on_last_page then + cursor = plen - 1 + end + if selection then + mp.commandv("playlist-move", prev_cursor, cursor + 1) + end + showplaylist() +end + + +function movebegin() + refresh_globals() + if plen == 0 or cursor == 0 then return end + local prev_cursor = cursor + cursor = 0 + if selection then mp.commandv("playlist-move", prev_cursor, cursor) end + showplaylist() +end + +function moveend() + refresh_globals() + if plen == 0 or cursor == plen-1 then return end + local prev_cursor = cursor + cursor = plen-1 + if selection then mp.commandv("playlist-move", prev_cursor, cursor+1) end + showplaylist() +end + +function write_watch_later(force_write) + if settings.allow_write_watch_later_config then + if mp.get_property_bool("save-position-on-quit") or force_write then + mp.command("write-watch-later-config") + end + end +end + +function playlist_next() + write_watch_later(true) + mp.commandv("playlist-next", "weak") + if settings.close_playlist_on_playfile then + remove_keybinds() + end + refresh_UI() +end + +function playlist_prev() + write_watch_later(true) + mp.commandv("playlist-prev", "weak") + if settings.close_playlist_on_playfile then + remove_keybinds() + end + refresh_UI() +end + +function playlist_random() + write_watch_later() + refresh_globals() + if plen < 2 then return end + math.randomseed(os.time()) + local random = pos + while random == pos do + random = math.random(0, plen-1) + end + mp.set_property("playlist-pos", random) + if settings.close_playlist_on_playfile then + remove_keybinds() + end +end + +function playfile() + refresh_globals() + if plen == 0 then return end + selection = nil + local is_idle = mp.get_property_native('idle-active') + if cursor ~= pos or is_idle then + write_watch_later() + mp.set_property("playlist-pos", cursor) + else + if cursor~=plen-1 then + cursor = cursor + 1 + end + write_watch_later() + mp.commandv("playlist-next", "weak") + end + if settings.close_playlist_on_playfile then + remove_keybinds() + elseif playlist_visible then + showplaylist() + end +end + +function file_filter(filenames) + local files = {} + for i = 1, #filenames do + local file = filenames[i] + local ext = file:match('%.([^%.]+)$') + if ext and filetype_lookup[ext:lower()] then + table.insert(files, file) + end + end + return files +end + +function get_playlist_filenames_set() + local filenames = {} + for n=0,plen-1,1 do + local filename = mp.get_property('playlist/'..n..'/filename') + local _, file = utils.split_path(filename) + filenames[file] = true + end + return filenames +end + +--Creates a playlist of all files in directory, will keep the order and position +--For exaple, Folder has 12 files, you open the 5th file and run this, the remaining 7 are added behind the 5th file and prior 4 files before it +function playlist(force_dir) + refresh_globals() + if not directory and plen > 0 then return end + local hasfile = true + if plen == 0 then + hasfile = false + dir = mp.get_property('working-directory') + else + dir = directory + end + + if dir == "." then dir = "" end + if force_dir then dir = force_dir end + + local files = file_filter(utils.readdir(dir, "files")) + if winapisort ~= nil then + table.sort(files, winapisort) + else + table.sort(files, alphanumsort) + end + + + if files == nil then + msg.verbose("no files in directory") + return + end + + local filenames = get_playlist_filenames_set() + local c, c2 = 0,0 + if files then + local cur = false + local filename = mp.get_property("filename") + for _, file in ipairs(files) do + if file == nil or file[1] == "." then + break + end + local appendstr = "append" + if not hasfile then + cur = true + appendstr = "append-play" + hasfile = true + end + if filename == file then + cur = true + elseif filenames[file] then + -- skip files already in playlist + elseif cur == true or settings.loadfiles_always_append then + mp.commandv("loadfile", utils.join_path(dir, file), appendstr) + msg.info("Appended to playlist: " .. file) + c2 = c2 + 1 + else + mp.commandv("loadfile", utils.join_path(dir, file), appendstr) + msg.info("Prepended to playlist: " .. file) + mp.commandv("playlist-move", mp.get_property_number("playlist-count", 1)-1, c) + c = c + 1 + end + end + if c2 > 0 or c>0 then + msg.info("Added "..c + c2.." files to playlist") + else + msg.info("No additional files found") + end + cursor = mp.get_property_number('playlist-pos', 1) + else + msg.error("Could not scan for files: "..(error or "")) + end + refresh_globals() + if playlist_visible then + showplaylist() + end + if settings.display_osd_feedback then + if c2 > 0 or c>0 then + mp.osd_message("Added "..c + c2.." files to playlist") + else + mp.osd_message("No additional files found") + end + end + return c + c2 +end + +function parse_home(path) + if not path:find("^~") then + return path + end + local home_dir = os.getenv("HOME") or os.getenv("USERPROFILE") + if not home_dir then + local drive = os.getenv("HOMEDRIVE") + local path = os.getenv("HOMEPATH") + if drive and path then + home_dir = utils.join_path(drive, path) + else + msg.error("Couldn't find home dir.") + return nil + end + end + local result = path:gsub("^~", home_dir) + return result +end + +local interactive_save = false +function activate_playlist_save() + if interactive_save then + remove_keybinds() + mp.command("script-message playlistmanager-save-interactive \"start interactive filenaming process\"") + else + save_playlist() + end +end + +--saves the current playlist into a m3u file +function save_playlist(filename) + local length = mp.get_property_number('playlist-count', 0) + if length == 0 then return end + + --get playlist save path + local savepath + if settings.playlist_savepath == nil or settings.playlist_savepath == "" then + savepath = mp.command_native({"expand-path", "~~home/"}).."/playlists" + else + savepath = parse_home(settings.playlist_savepath) + if savepath == nil then return end + end + + --create savepath if it doesn't exist + if utils.readdir(savepath) == nil then + local windows_args = {'powershell', '-NoProfile', '-Command', 'mkdir', savepath} + local unix_args = { 'mkdir', savepath } + local args = settings.system == 'windows' and windows_args or unix_args + local res = utils.subprocess({ args = args, cancellable = false }) + if res.status ~= 0 then + msg.error("Failed to create playlist save directory "..savepath..". Error: "..(res.error or "unknown")) + return + end + end + + local name = filename + if name == nil then + if settings.playlist_save_filename == nil or settings.playlist_save_filename == "" then + local date = os.date("*t") + local datestring = ("%02d-%02d-%02d_%02d-%02d-%02d"):format(date.year, date.month, date.day, date.hour, date.min, date.sec) + + name = datestring.."_playlist-size_"..length..".m3u" + else + name = settings.playlist_save_filename + end + end + + local savepath = utils.join_path(savepath, name) + local file, err = io.open(savepath, "w") + if not file then + msg.error("Error in creating playlist file, check permissions. Error: "..(err or "unknown")) + else + file:write("#EXTM3U\n") + local i=0 + while i < length do + local pwd = mp.get_property("working-directory") + local filename = mp.get_property('playlist/'..i..'/filename') + local fullpath = filename + if not is_protocol(filename) then + fullpath = utils.join_path(pwd, filename) + end + local title = mp.get_property('playlist/'..i..'/title') or title_table[filename] + if title then + file:write("#EXTINF:,"..title.."\n") + end + file:write(fullpath, "\n") + i=i+1 + end + local saved_msg = "Playlist written to: "..savepath + if settings.display_osd_feedback then mp.osd_message(saved_msg) end + msg.info(saved_msg) + file:close() + end +end + +function alphanumsort(a, b) + local function padnum(d) + local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + return tostring(a):lower():gsub("%.?%d+",padnum)..("%3d"):format(#b) + < tostring(b):lower():gsub("%.?%d+",padnum)..("%3d"):format(#a) +end + +-- fast sort algo from https://github.com/zsugabubus/dotfiles/blob/master/.config/mpv/scripts/playlist-filtersort.lua +function sortplaylist(startover) + local playlist = mp.get_property_native('playlist') + if #playlist < 2 then return end + + local order = {} + for i=1, #playlist do + order[i] = i + playlist[i].string = get_name_from_index(i - 1, true) + end + + table.sort(order, function(a, b) + return sort_modes[sort_mode].sort_fn(a, b, playlist) + end) + + for i=1, #playlist do + playlist[order[i]].new_pos = i + end + + for i=1, #playlist do + while true do + local j = playlist[i].new_pos + if i == j then + break + end + mp.commandv('playlist-move', (i) - 1, (j + 1) - 1) + mp.commandv('playlist-move', (j - 1) - 1, (i) - 1) + playlist[j], playlist[i] = playlist[i], playlist[j] + end + end + + for i = 1, #playlist do + local filename = mp.get_property('playlist/' .. i - 1 .. '/filename') + local ext = filename:match("%.([^%.]+)$") + if not ext or not filetype_lookup[ext:lower()] then + --move the directory to the end of the playlist + mp.commandv('playlist-move', i - 1, #playlist) + end + end + + cursor = mp.get_property_number('playlist-pos', 0) + if startover then + mp.set_property('playlist-pos', 0) + end + if playlist_visible then + showplaylist() + end + if settings.display_osd_feedback then + mp.osd_message("Playlist sorted with "..sort_modes[sort_mode].title) + end +end + +function reverseplaylist() + local length = mp.get_property_number('playlist-count', 0) + if length < 2 then return end + for outer=1, length-1, 1 do + mp.commandv('playlist-move', outer, 0) + end + if playlist_visible then + showplaylist() + end + if settings.display_osd_feedback then + mp.osd_message("Playlist reversed") + end +end + +function shuffleplaylist() + refresh_globals() + if plen < 2 then return end + mp.command("playlist-shuffle") + math.randomseed(os.time()) + mp.commandv("playlist-move", pos, math.random(0, plen-1)) + + local playlist = mp.get_property_native('playlist') + for i = 1, #playlist do + local filename = mp.get_property('playlist/' .. i - 1 .. '/filename') + local ext = filename:match("%.([^%.]+)$") + if not ext or not filetype_lookup[ext:lower()] then + --move the directory to the end of the playlist + mp.commandv('playlist-move', i - 1, #playlist) + end + end + + mp.set_property('playlist-pos', 0) + refresh_globals() + if playlist_visible then + showplaylist() + end + if settings.display_osd_feedback then + mp.osd_message("Playlist shuffled") + end +end + +function bind_keys(keys, name, func, opts) + if keys == nil or keys == "" then + mp.add_key_binding(keys, name, func, opts) + return + end + local i = 1 + for key in keys:gmatch("[^%s]+") do + local prefix = i == 1 and '' or i + mp.add_key_binding(key, name..prefix, func, opts) + i = i + 1 + end +end + +function bind_keys_forced(keys, name, func, opts) + if keys == nil or keys == "" then + mp.add_forced_key_binding(keys, name, func, opts) + return + end + local i = 1 + for key in keys:gmatch("[^%s]+") do + local prefix = i == 1 and '' or i + mp.add_forced_key_binding(key, name..prefix, func, opts) + i = i + 1 + end +end + +function unbind_keys(keys, name) + if keys == nil or keys == "" then + mp.remove_key_binding(name) + return + end + local i = 1 + for key in keys:gmatch("[^%s]+") do + local prefix = i == 1 and '' or i + mp.remove_key_binding(name..prefix) + i = i + 1 + end +end + +function add_keybinds() + bind_keys_forced(settings.key_moveup, 'moveup', moveup, "repeatable") + bind_keys_forced(settings.key_movedown, 'movedown', movedown, "repeatable") + bind_keys_forced(settings.key_movepageup, 'movepageup', movepageup, "repeatable") + bind_keys_forced(settings.key_movepagedown, 'movepagedown', movepagedown, "repeatable") + bind_keys_forced(settings.key_movebegin, 'movebegin', movebegin, "repeatable") + bind_keys_forced(settings.key_moveend, 'moveend', moveend, "repeatable") + bind_keys_forced(settings.key_selectfile, 'selectfile', selectfile) + bind_keys_forced(settings.key_unselectfile, 'unselectfile', unselectfile) + bind_keys_forced(settings.key_playfile, 'playfile', playfile) + bind_keys_forced(settings.key_removefile, 'removefile', removefile, "repeatable") + bind_keys_forced(settings.key_closeplaylist, 'closeplaylist', remove_keybinds) +end + +function remove_keybinds() + keybindstimer:kill() + keybindstimer = mp.add_periodic_timer(settings.playlist_display_timeout, remove_keybinds) + keybindstimer:kill() + playlist_overlay.data = "" + playlist_overlay:remove() + if is_terminal_mode() then + mp.osd_message("") + end + playlist_visible = false + if settings.reset_cursor_on_close then + resetcursor() + end + if settings.dynamic_binds then + unbind_keys(settings.key_moveup, 'moveup') + unbind_keys(settings.key_movedown, 'movedown') + unbind_keys(settings.key_movepageup, 'movepageup') + unbind_keys(settings.key_movepagedown, 'movepagedown') + unbind_keys(settings.key_movebegin, 'movebegin') + unbind_keys(settings.key_moveend, 'moveend') + unbind_keys(settings.key_selectfile, 'selectfile') + unbind_keys(settings.key_unselectfile, 'unselectfile') + unbind_keys(settings.key_playfile, 'playfile') + unbind_keys(settings.key_removefile, 'removefile') + unbind_keys(settings.key_closeplaylist, 'closeplaylist') + end +end + +keybindstimer = mp.add_periodic_timer(settings.playlist_display_timeout, remove_keybinds) +keybindstimer:kill() + +if not settings.dynamic_binds then + add_keybinds() +end + +if settings.loadfiles_on_idle_start and mp.get_property_number('playlist-count', 0) == 0 then + playlist() +end + +mp.observe_property('playlist-count', "number", function(_, plcount) + --if we promised to listen and sort on playlist size increase do it + if settings.sortplaylist_on_file_add and (plcount > plen) then + msg.info("Added files will be automatically sorted") + refresh_globals() + sortplaylist() + end + refresh_UI() + resolve_titles() +end) +mp.observe_property('osd-dimensions', 'native', refresh_UI) + + +url_request_queue = {} +function url_request_queue.push(item) table.insert(url_request_queue, item) end +function url_request_queue.pop() return table.remove(url_request_queue, 1) end +local url_titles_to_fetch = url_request_queue +local ongoing_url_requests = {} + +function url_fetching_throttler() + if #url_titles_to_fetch == 0 then + url_title_fetch_timer:kill() + end + + local ongoing_url_requests_count = 0 + for _, ongoing in pairs(ongoing_url_requests) do + if ongoing then + ongoing_url_requests_count = ongoing_url_requests_count + 1 + end + end + + -- start resolving some url titles if there is available slots + local amount_to_fetch = math.max(0, settings.concurrent_title_resolve_limit - ongoing_url_requests_count) + for index=1,amount_to_fetch,1 do + local file = url_titles_to_fetch.pop() + if file then + ongoing_url_requests[file] = true + resolve_ytdl_title(file) + end + end +end + +url_title_fetch_timer = mp.add_periodic_timer(0.1, url_fetching_throttler) +url_title_fetch_timer:kill() + +local_request_queue = {} +function local_request_queue.push(item) table.insert(local_request_queue, item) end +function local_request_queue.pop() return table.remove(local_request_queue, 1) end +local local_titles_to_fetch = local_request_queue +local ongoing_local_request = false + +-- this will only allow 1 concurrent local title resolve process +function local_fetching_throttler() + if not ongoing_local_request then + local file = local_titles_to_fetch.pop() + if file then + ongoing_local_request = true + resolve_ffprobe_title(file) + end + end +end + +function resolve_titles() + if settings.prefer_titles == 'none' then return end + if not settings.resolve_url_titles and not settings.resolve_local_titles then return end + + local length = mp.get_property_number('playlist-count', 0) + if length < 2 then return end + -- loop all items in playlist because we can't predict how it has changed + local added_urls = false + local added_local = false + for i=0,length - 1,1 do + local filename = mp.get_property('playlist/'..i..'/filename') + local title = mp.get_property('playlist/'..i..'/title') + if i ~= pos + and filename + and not title + and not title_table[filename] + and not requested_titles[filename] + then + requested_titles[filename] = true + if filename:match('^https?://') and settings.resolve_url_titles then + url_titles_to_fetch.push(filename) + added_urls = true + elseif settings.prefer_titles == "all" and settings.resolve_local_titles then + local_titles_to_fetch.push(filename) + added_local = true + end + end + end + if added_urls then + url_title_fetch_timer:resume() + end + if added_local then + local_fetching_throttler() + end +end + +function resolve_ytdl_title(filename) + local args = { + settings.youtube_dl_executable, + '--no-playlist', + '--flat-playlist', + '-sJ', + '--no-config', + filename, + } + local req = mp.command_native_async( + { + name = "subprocess", + args = args, + playback_only = false, + capture_stdout = true + }, + function (success, res) + ongoing_url_requests[filename] = false + if res.killed_by_us then + msg.verbose('Request to resolve url title ' .. filename .. ' timed out') + return + end + if res.status == 0 then + local json, err = utils.parse_json(res.stdout) + if not err then + local is_playlist = json['_type'] and json['_type'] == 'playlist' + local title = (is_playlist and '[playlist]: ' or '') .. json['title'] + msg.verbose(filename .. " resolved to '" .. title .. "'") + title_table[filename] = title + mp.set_property_native('user-data/playlistmanager/titles', title_table) + refresh_UI() + else + msg.error("Failed parsing json, reason: "..(err or "unknown")) + end + else + msg.error("Failed to resolve url title "..filename.." Error: "..(res.error or "unknown")) + end + end + ) + + mp.add_timeout( + settings.resolve_title_timeout, + function() + mp.abort_async_command(req) + ongoing_url_requests[filename] = false + end + ) +end + +function resolve_ffprobe_title(filename) + local args = { "ffprobe", "-show_format", "-show_entries", "format=tags", "-loglevel", "quiet", filename } + local req = mp.command_native_async( + { + name = "subprocess", + args = args, + playback_only = false, + capture_stdout = true + }, + function (success, res) + ongoing_local_request = false + local_fetching_throttler() + if res.killed_by_us then + msg.verbose('Request to resolve local title ' .. filename .. ' timed out') + return + end + if res.status == 0 then + local title = string.match(res.stdout, "title=([^\n\r]+)") + if title then + msg.verbose(filename .. " resolved to '" .. title .. "'") + title_table[filename] = title + mp.set_property_native('user-data/playlistmanager/titles', title_table) + refresh_UI() + end + else + msg.error("Failed to resolve local title "..filename.." Error: "..(res.error or "unknown")) + end + end + ) +end + +--script message handler +function handlemessage(msg, value, value2) + if msg == "show" and value == "playlist" then + if value2 ~= "toggle" then + showplaylist(value2) + return + else + toggle_playlist(showplaylist) + return + end + end + if msg == "show" and value == "playlist-nokeys" then + if value2 ~= "toggle" then + showplaylist_non_interactive(value2) + return + else + toggle_playlist(showplaylist_non_interactive) + return + end + end + if msg == "show" and value == "filename" and strippedname and value2 then + mp.commandv('show-text', strippedname, tonumber(value2)*1000 ) ; return + end + if msg == "show" and value == "filename" and strippedname then + mp.commandv('show-text', strippedname ) ; return + end + if msg == "sort" then sortplaylist(value) ; return end + if msg == "shuffle" then shuffleplaylist() ; return end + if msg == "reverse" then reverseplaylist() ; return end + if msg == "loadfiles" then playlist(value) ; return end + if msg == "save" then save_playlist(value) ; return end + if msg == "playlist-next" then playlist_next() ; return end + if msg == "playlist-prev" then playlist_prev() ; return end + if msg == "playlist-next-random" then playlist_random() ; return end + if msg == "enable-interactive-save" then interactive_save = true end + if msg == "close" then remove_keybinds() end +end + +mp.register_script_message("playlistmanager", handlemessage) + +bind_keys(settings.key_sortplaylist, "sortplaylist", function() + sortplaylist() + sort_mode = sort_mode + 1 + if sort_mode > #sort_modes then sort_mode = 1 end +end) +bind_keys(settings.key_shuffleplaylist, "shuffleplaylist", shuffleplaylist) +bind_keys(settings.key_reverseplaylist, "reverseplaylist", reverseplaylist) +bind_keys(settings.key_loadfiles, "loadfiles", playlist) +bind_keys(settings.key_saveplaylist, "saveplaylist", activate_playlist_save) +bind_keys(settings.key_showplaylist, "showplaylist", showplaylist) +bind_keys( + settings.key_peek_at_playlist, + "peek_at_playlist", + handle_complex_playlist_toggle, + { complex=true } +) + +mp.register_event("start-file", on_start_file) +mp.register_event("file-loaded", on_file_loaded) +mp.register_event("end-file", on_end_file) diff --git a/mpv/scripts/stats.lua b/mpv/scripts/stats.lua new file mode 100644 index 0000000..890dca0 --- /dev/null +++ b/mpv/scripts/stats.lua @@ -0,0 +1,1183 @@ +-- Display some stats. +-- +-- Please consult the readme for information about usage and configuration: +-- https://github.com/Argon-/mpv-stats +-- +-- Please note: not every property is always available and therefore not always +-- visible. + +local mp = require 'mp' +local options = require 'mp.options' +local utils = require 'mp.utils' + +-- Options +local o = { + -- Default key bindings + key_oneshot = "i", + key_toggle = "I", + key_page_1 = "1", + key_page_2 = "2", + key_page_3 = "3", + key_page_4 = "4", + key_page_0 = "0", + -- For pages which support scrolling + key_scroll_up = "UP", + key_scroll_down = "DOWN", + scroll_lines = 1, + + duration = 4, + redraw_delay = 1, -- acts as duration in the toggling case + ass_formatting = true, + persistent_overlay = false, -- whether the stats can be overwritten by other output + print_perfdata_passes = false, -- when true, print the full information about all passes + filter_params_max_length = 100, -- a filter list longer than this many characters will be shown one filter per line instead + debug = false, + + -- Graph options and style + plot_perfdata = true, + plot_vsync_ratio = true, + plot_vsync_jitter = true, + skip_frames = 5, + global_max = true, + flush_graph_data = true, -- clear data buffers when toggling + plot_bg_border_color = "0000FF", + plot_bg_color = "262626", + plot_color = "FFFFFF", + + -- Text style + font = "sans", + font_mono = "monospace", -- monospaced digits are sufficient + font_size = 10, + font_color = "FFFFFF", + border_size = 0.8, + border_color = "262626", + shadow_x_offset = 0.0, + shadow_y_offset = 0.0, + shadow_color = "000000", + alpha = "11", + + -- Custom header for ASS tags to style the text output. + -- Specifying this will ignore the text style values above and just + -- use this string instead. + custom_header = "", + + -- Text formatting + -- With ASS + ass_nl = "\\N", + ass_indent = "\\h\\h\\h\\h\\h", + ass_prefix_sep = "\\h\\h", + ass_b1 = "{\\b1}", + ass_b0 = "{\\b0}", + ass_it1 = "{\\i1}", + ass_it0 = "{\\i0}", + -- Without ASS + no_ass_nl = "\n", + no_ass_indent = "\t", + no_ass_prefix_sep = " ", + no_ass_b1 = "\027[1m", + no_ass_b0 = "\027[0m", + no_ass_it1 = "\027[3m", + no_ass_it0 = "\027[0m", + + bindlist = "no", -- print page 4 to the terminal on startup and quit mpv +} +options.read_options(o) + +local format = string.format +local max = math.max +local min = math.min + +-- Function used to record performance data +local recorder = nil +-- Timer used for redrawing (toggling) and clearing the screen (oneshot) +local display_timer = nil +-- Timer used to update cache stats. +local cache_recorder_timer = nil +-- Current page and : mappings +local curr_page = o.key_page_1 +local pages = {} +local scroll_bound = false +-- Save these sequences locally as we'll need them a lot +local ass_start = mp.get_property_osd("osd-ass-cc/0") +local ass_stop = mp.get_property_osd("osd-ass-cc/1") +-- Ring buffers for the values used to construct a graph. +-- .pos denotes the current position, .len the buffer length +-- .max is the max value in the corresponding buffer +local vsratio_buf, vsjitter_buf +local function init_buffers() + vsratio_buf = {0, pos = 1, len = 50, max = 0} + vsjitter_buf = {0, pos = 1, len = 50, max = 0} +end +local cache_ahead_buf, cache_speed_buf +local perf_buffers = {} +-- Save all properties known to this version of mpv +local property_list = {} +for p in string.gmatch(mp.get_property("property-list"), "([^,]+)") do property_list[p] = true end +-- Mapping of properties to their deprecated names +local property_aliases = { + ["decoder-frame-drop-count"] = "drop-frame-count", + ["frame-drop-count"] = "vo-drop-frame-count", + ["container-fps"] = "fps", +} + +local function graph_add_value(graph, value) + graph.pos = (graph.pos % graph.len) + 1 + graph[graph.pos] = value + graph.max = max(graph.max, value) +end + +-- Return deprecated name for the given property +local function compat(p) + while not property_list[p] and property_aliases[p] do + p = property_aliases[p] + end + return p +end + +-- "\\" in UTF-8 (U+2060 is WORD-JOINER) +local ESC_BACKSLASH = "\\" .. string.char(0xE2, 0x81, 0xA0) + +local function no_ASS(t) + if not o.use_ass then + return t + elseif not o.persistent_overlay then + -- mp.osd_message supports ass-escape using osd-ass-cc/{0|1} + return ass_stop .. t .. ass_start + else + -- mp.set_osd_ass doesn't support ass-escape. roll our own. + -- similar to mpv's sub/osd_libass.c:mangle_ass(...), excluding + -- space after newlines because no_ASS is not used with multi-line. + -- space at the begining is replaced with "\\h" because it matters + -- at the begining of a line, and we can't know where our output + -- ends up. no issue if it ends up at the middle of a line. + return tostring(t) + :gsub("\\", ESC_BACKSLASH) + :gsub("{", "\\{") + :gsub("^ ", "\\h") + end +end + + +local function b(t) + return o.b1 .. t .. o.b0 +end + + +local function it(t) + return o.it1 .. t .. o.it0 +end + + +local function text_style() + if not o.use_ass then + return "" + end + if o.custom_header and o.custom_header ~= "" then + return o.custom_header + else + return format("{\\r}{\\an7}{\\fs%d}{\\fn%s}{\\bord%f}{\\3c&H%s&}" .. + "{\\1c&H%s&}{\\alpha&H%s&}{\\xshad%f}{\\yshad%f}{\\4c&H%s&}", + o.font_size, o.font, o.border_size, + o.border_color, o.font_color, o.alpha, o.shadow_x_offset, + o.shadow_y_offset, o.shadow_color) + end +end + + +local function has_vo_window() + return mp.get_property("vo-configured") == "yes" +end + + +-- Generate a graph from the given values. +-- Returns an ASS formatted vector drawing as string. +-- +-- values: Array/table of numbers representing the data. Used like a ring buffer +-- it will get iterated backwards `len` times starting at position `i`. +-- i : Index of the latest data value in `values`. +-- len : The length/amount of numbers in `values`. +-- v_max : The maximum number in `values`. It is used to scale all data +-- values to a range of 0 to `v_max`. +-- v_avg : The average number in `values`. It is used to try and center graphs +-- if possible. May be left as nil +-- scale : A value that will be multiplied with all data values. +-- x_tics: Horizontal width multiplier for the steps +local function generate_graph(values, i, len, v_max, v_avg, scale, x_tics) + -- Check if at least one value exists + if not values[i] then + return "" + end + + local x_max = (len - 1) * x_tics + local y_offset = o.border_size + local y_max = o.font_size * 0.66 + local x = 0 + + -- try and center the graph if possible, but avoid going above `scale` + if v_avg then + scale = min(scale, v_max / (2 * v_avg)) + end + + local s = {format("m 0 0 n %f %f l ", x, y_max - (y_max * values[i] / v_max * scale))} + i = ((i - 2) % len) + 1 + + for p = 1, len - 1 do + if values[i] then + x = x - x_tics + s[#s+1] = format("%f %f ", x, y_max - (y_max * values[i] / v_max * scale)) + end + i = ((i - 2) % len) + 1 + end + + s[#s+1] = format("%f %f %f %f", x, y_max, 0, y_max) + + local bg_box = format("{\\bord0.5}{\\3c&H%s&}{\\1c&H%s&}m 0 %f l %f %f %f 0 0 0", + o.plot_bg_border_color, o.plot_bg_color, y_max, x_max, y_max, x_max) + return format("%s{\\r}{\\pbo%f}{\\shad0}{\\alpha&H00}{\\p1}%s{\\p0}{\\bord0}{\\1c&H%s}{\\p1}%s{\\p0}%s", + o.prefix_sep, y_offset, bg_box, o.plot_color, table.concat(s), text_style()) +end + + +local function append(s, str, attr) + if not str then + return false + end + attr.prefix_sep = attr.prefix_sep or o.prefix_sep + attr.indent = attr.indent or o.indent + attr.nl = attr.nl or o.nl + attr.suffix = attr.suffix or "" + attr.prefix = attr.prefix or "" + attr.no_prefix_markup = attr.no_prefix_markup or false + attr.prefix = attr.no_prefix_markup and attr.prefix or b(attr.prefix) + s[#s+1] = format("%s%s%s%s%s%s", attr.nl, attr.indent, + attr.prefix, attr.prefix_sep, no_ASS(str), attr.suffix) + return true +end + + +-- Format and append a property. +-- A property whose value is either `nil` or empty (hereafter called "invalid") +-- is skipped and not appended. +-- Returns `false` in case nothing was appended, otherwise `true`. +-- +-- s : Table containing strings. +-- prop : The property to query and format (based on its OSD representation). +-- attr : Optional table to overwrite certain (formatting) attributes for +-- this property. +-- exclude: Optional table containing keys which are considered invalid values +-- for this property. Specifying this will replace empty string as +-- default invalid value (nil is always invalid). +local function append_property(s, prop, attr, excluded) + excluded = excluded or {[""] = true} + local ret = mp.get_property_osd(prop) + if not ret or excluded[ret] then + if o.debug then + print("No value for property: " .. prop) + end + return false + end + return append(s, ret, attr) +end + + +local function append_perfdata(s, dedicated_page) + local vo_p = mp.get_property_native("vo-passes") + if not vo_p then + return + end + + local ds = mp.get_property_bool("display-sync-active", false) + local target_fps = ds and mp.get_property_number("display-fps", 0) + or mp.get_property_number(compat("container-fps"), 0) + if target_fps > 0 then target_fps = 1 / target_fps * 1e9 end + + -- Sums of all last/avg/peak values + local last_s, avg_s, peak_s = {}, {}, {} + for frame, data in pairs(vo_p) do + last_s[frame], avg_s[frame], peak_s[frame] = 0, 0, 0 + for _, pass in ipairs(data) do + last_s[frame] = last_s[frame] + pass["last"] + avg_s[frame] = avg_s[frame] + pass["avg"] + peak_s[frame] = peak_s[frame] + pass["peak"] + end + end + + -- Pretty print measured time + local function pp(i) + -- rescale to microseconds for a saner display + return format("%05d", i / 1000) + end + + -- Format n/m with a font weight based on the ratio + local function p(n, m) + local i = 0 + if m > 0 then + i = tonumber(n) / m + end + -- Calculate font weight. 100 is minimum, 400 is normal, 700 bold, 900 is max + local w = (700 * math.sqrt(i)) + 200 + return format("{\\b%d}%02d%%{\\b0}", w, i * 100) + end + + -- ensure that the fixed title is one element and every scrollable line is + -- also one single element. + s[#s+1] = format("%s%s%s%s{\\fs%s}%s{\\fs%s}", + dedicated_page and "" or o.nl, dedicated_page and "" or o.indent, + b("Frame Timings:"), o.prefix_sep, o.font_size * 0.66, + "(last/average/peak μs)", o.font_size) + + for frame, data in pairs(vo_p) do + local f = "%s%s%s{\\fn%s}%s / %s / %s %s%s{\\fn%s}%s%s%s" + + if dedicated_page then + s[#s+1] = format("%s%s%s:", o.nl, o.indent, + b(frame:gsub("^%l", string.upper))) + + for _, pass in ipairs(data) do + s[#s+1] = format(f, o.nl, o.indent, o.indent, + o.font_mono, pp(pass["last"]), + pp(pass["avg"]), pp(pass["peak"]), + o.prefix_sep .. o.prefix_sep, p(pass["last"], last_s[frame]), + o.font, o.prefix_sep, o.prefix_sep, pass["desc"]) + + if o.plot_perfdata and o.use_ass then + -- use the same line that was already started for this iteration + s[#s] = s[#s] .. + generate_graph(pass["samples"], pass["count"], + pass["count"], pass["peak"], + pass["avg"], 0.9, 0.25) + end + end + + -- Print sum of timing values as "Total" + s[#s+1] = format(f, o.nl, o.indent, o.indent, + o.font_mono, pp(last_s[frame]), + pp(avg_s[frame]), pp(peak_s[frame]), "", "", o.font, + o.prefix_sep, o.prefix_sep, b("Total")) + else + -- for the simplified view, we just print the sum of each pass + s[#s+1] = format(f, o.nl, o.indent, o.indent, o.font_mono, + pp(last_s[frame]), pp(avg_s[frame]), pp(peak_s[frame]), + "", "", o.font, o.prefix_sep, o.prefix_sep, + frame:gsub("^%l", string.upper)) + end + end +end + +local function ellipsis(s, maxlen) + if not maxlen or s:len() <= maxlen then return s end + return s:sub(1, maxlen - 3) .. "..." +end + +-- command prefix tokens to strip - includes generic property commands +local cmd_prefixes = { + osd_auto=1, no_osd=1, osd_bar=1, osd_msg=1, osd_msg_bar=1, raw=1, sync=1, + async=1, expand_properties=1, repeatable=1, set=1, add=1, multiply=1, + toggle=1, cycle=1, cycle_values=1, ["!reverse"]=1, change_list=1, +} +-- commands/writable-properties prefix sub-words (followed by -) to strip +local name_prefixes = { + define=1, delete=1, enable=1, disable=1, dump=1, write=1, drop=1, revert=1, + ab=1, hr=1, secondary=1, +} +-- extract a command "subject" from a command string, by removing all +-- generic prefix tokens and then returning the first interesting sub-word +-- of the next token. For target-script name we also check another token. +-- The tokenizer works fine for things we care about - valid mpv commands, +-- properties and script names, possibly quoted, white-space[s]-separated. +-- It's decent in practice, and worst case is "incorrect" subject. +local function cmd_subject(cmd) + cmd = cmd:gsub(";.*", ""):gsub("%-", "_") -- only first cmd, s/-/_/ + local TOKEN = '^%s*"?([%w_!]*)' -- captures+ends before a (maybe) final " + local tok, sname, subw + + repeat tok, cmd = cmd:match(TOKEN .. '"?(.*)') + until not cmd_prefixes[tok] + -- tok is the 1st non-generic command/property name token, cmd is the rest + + sname = tok == "script_message_to" and cmd:match(TOKEN) + or tok == "script_binding" and cmd:match(TOKEN .. "/") + if sname and sname ~= "" then + return "script: " .. sname + end + + -- return the first sub-word of tok which is not a useless prefix + repeat subw, tok = tok:match("([^_]*)_?(.*)") + until tok == "" or not name_prefixes[subw] + return subw:len() > 1 and subw or "[unknown]" +end + +local function get_kbinfo_lines(width) + -- active keys: only highest priotity of each key, and not our (stats) keys + local bindings = mp.get_property_native("input-bindings", {}) + local active = {} -- map: key-name -> bind-info + for _, bind in pairs(bindings) do + if bind.priority >= 0 and ( + not active[bind.key] or + (active[bind.key].is_weak and not bind.is_weak) or + (bind.is_weak == active[bind.key].is_weak and + bind.priority > active[bind.key].priority) + ) and not bind.cmd:find("script-binding stats/__forced_", 1, true) + then + active[bind.key] = bind + end + end + + -- make an array, find max key len, add sort keys (.subject/.mods[_count]) + local ordered = {} + local kspaces = "" -- as many spaces as the longest key name + for _, bind in pairs(active) do + bind.subject = cmd_subject(bind.cmd) + if bind.subject ~= "ignore" then + ordered[#ordered+1] = bind + _,_, bind.mods = bind.key:find("(.*)%+.") + _, bind.mods_count = bind.key:gsub("%+.", "") + if bind.key:len() > kspaces:len() then + kspaces = string.rep(" ", bind.key:len()) + end + end + end + + local function align_right(key) + return kspaces:sub(key:len()) .. key + end + + -- sort by: subject, mod(ifier)s count, mods, key-len, lowercase-key, key + table.sort(ordered, function(a, b) + if a.subject ~= b.subject then + return a.subject < b.subject + elseif a.mods_count ~= b.mods_count then + return a.mods_count < b.mods_count + elseif a.mods ~= b.mods then + return a.mods < b.mods + elseif a.key:len() ~= b.key:len() then + return a.key:len() < b.key:len() + elseif a.key:lower() ~= b.key:lower() then + return a.key:lower() < b.key:lower() + else + return a.key > b.key -- only case differs, lowercase first + end + end) + + -- key/subject pre/post formatting for terminal/ass. + -- key/subject alignment uses spaces (with mono font if ass) + -- word-wrapping is disabled for ass, or cut at 79 for the terminal + local term = not o.use_ass + local kpre = term and "" or format("{\\q2\\fn%s}", o.font_mono) + local kpost = term and " " or format(" {\\fn%s}", o.font) + local spre = term and kspaces .. " " + or format("{\\q2\\fn%s}%s {\\fn%s}{\\fs%d\\u1}", + o.font_mono, kspaces, o.font, 1.3*o.font_size) + local spost = term and "" or format("{\\u0\\fs%d}", o.font_size) + local _, itabs = o.indent:gsub("\t", "") + local cutoff = term and (width or 79) - o.indent:len() - itabs * 7 - spre:len() + + -- create the display lines + local info_lines = {} + local subject = nil + for _, bind in ipairs(ordered) do + if bind.subject ~= subject then -- new subject (title) + subject = bind.subject + append(info_lines, "", {}) + append(info_lines, "", { prefix = spre .. subject .. spost }) + end + if bind.comment then + bind.cmd = bind.cmd .. " # " .. bind.comment + end + append(info_lines, ellipsis(bind.cmd, cutoff), + { prefix = kpre .. no_ASS(align_right(bind.key)) .. kpost }) + end + return info_lines +end + +local function append_general_perfdata(s, offset) + local perf_info = mp.get_property_native("perf-info") or {} + local count = 0 + for _, data in ipairs(perf_info) do + count = count + 1 + end + offset = max(1, min((offset or 1), count)) + + local i = 0 + for _, data in ipairs(perf_info) do + i = i + 1 + if i >= offset then + append(s, data.text or data.value, {prefix="["..tostring(i).."] "..data.name..":"}) + + if o.plot_perfdata and o.use_ass and data.value then + buf = perf_buffers[data.name] + if not buf then + buf = {0, pos = 1, len = 50, max = 0} + perf_buffers[data.name] = buf + end + graph_add_value(buf, data.value) + s[#s+1] = generate_graph(buf, buf.pos, buf.len, buf.max, nil, 0.8, 1) + end + end + end + return offset +end + +local function append_display_sync(s) + if not mp.get_property_bool("display-sync-active", false) then + return + end + + local vspeed = append_property(s, "video-speed-correction", {prefix="DS:"}) + if vspeed then + append_property(s, "audio-speed-correction", + {prefix="/", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true}) + else + append_property(s, "audio-speed-correction", + {prefix="DS:" .. o.prefix_sep .. " - / ", prefix_sep=""}) + end + + append_property(s, "mistimed-frame-count", {prefix="Mistimed:", nl=""}) + append_property(s, "vo-delayed-frame-count", {prefix="Delayed:", nl=""}) + + -- As we need to plot some graphs we print jitter and ratio on their own lines + if not display_timer.oneshot and (o.plot_vsync_ratio or o.plot_vsync_jitter) and o.use_ass then + local ratio_graph = "" + local jitter_graph = "" + if o.plot_vsync_ratio then + ratio_graph = generate_graph(vsratio_buf, vsratio_buf.pos, vsratio_buf.len, vsratio_buf.max, nil, 0.8, 1) + end + if o.plot_vsync_jitter then + jitter_graph = generate_graph(vsjitter_buf, vsjitter_buf.pos, vsjitter_buf.len, vsjitter_buf.max, nil, 0.8, 1) + end + append_property(s, "vsync-ratio", {prefix="VSync Ratio:", suffix=o.prefix_sep .. ratio_graph}) + append_property(s, "vsync-jitter", {prefix="VSync Jitter:", suffix=o.prefix_sep .. jitter_graph}) + else + -- Since no graph is needed we can print ratio/jitter on the same line and save some space + local vratio = append_property(s, "vsync-ratio", {prefix="VSync Ratio:"}) + append_property(s, "vsync-jitter", {prefix="VSync Jitter:", nl="" or o.nl}) + end +end + + +local function append_filters(s, prop, prefix) + local length = 0 + local filters = {} + + for _,f in ipairs(mp.get_property_native(prop, {})) do + local n = f.name + if f.enabled ~= nil and not f.enabled then + n = n .. " (disabled)" + end + + if f.label ~= nil then + n = "@" .. f.label .. ": " .. n + end + + local p = {} + for key,value in pairs(f.params) do + p[#p+1] = key .. "=" .. value + end + if #p > 0 then + p = " [" .. table.concat(p, " ") .. "]" + else + p = "" + end + + length = length + n:len() + p:len() + filters[#filters+1] = no_ASS(n) .. it(no_ASS(p)) + end + + if #filters > 0 then + local ret + if length < o.filter_params_max_length then + ret = table.concat(filters, ", ") + else + local sep = o.nl .. o.indent .. o.indent + ret = sep .. table.concat(filters, sep) + end + s[#s+1] = o.nl .. o.indent .. b(prefix) .. o.prefix_sep .. ret + end +end + + +local function add_header(s) + s[#s+1] = text_style() +end + + +local function add_file(s) + append(s, "", {prefix="File:", nl="", indent=""}) + append_property(s, "filename", {prefix_sep="", nl="", indent=""}) + if not (mp.get_property_osd("filename") == mp.get_property_osd("media-title")) then + append_property(s, "media-title", {prefix="Title:"}) + end + + local editions = mp.get_property_number("editions") + local edition = mp.get_property_number("current-edition") + local ed_cond = (edition and editions > 1) + if ed_cond then + append_property(s, "edition-list/" .. tostring(edition) .. "/title", + {prefix="Edition:"}) + append_property(s, "edition-list/count", + {prefix="(" .. tostring(edition + 1) .. "/", suffix=")", nl="", + indent=" ", prefix_sep=" ", no_prefix_markup=true}) + end + + local ch_index = mp.get_property_number("chapter") + if ch_index and ch_index >= 0 then + append_property(s, "chapter-list/" .. tostring(ch_index) .. "/title", {prefix="Chapter:", + nl=ed_cond and "" or o.nl}) + append_property(s, "chapter-list/count", + {prefix="(" .. tostring(ch_index + 1) .. "/", suffix=")", nl="", + indent=" ", prefix_sep=" ", no_prefix_markup=true}) + end + + local fs = append_property(s, "file-size", {prefix="Size:"}) + append_property(s, "file-format", {prefix="Format/Protocol:", nl=fs and "" or o.nl}) + + local demuxer_cache = mp.get_property_native("demuxer-cache-state", {}) + if demuxer_cache["fw-bytes"] then + demuxer_cache = demuxer_cache["fw-bytes"] -- returns bytes + else + demuxer_cache = 0 + end + local demuxer_secs = mp.get_property_number("demuxer-cache-duration", 0) + if demuxer_cache + demuxer_secs > 0 then + append(s, utils.format_bytes_humanized(demuxer_cache), {prefix="Total Cache:"}) + append(s, format("%.1f", demuxer_secs), {prefix="(", suffix=" sec)", nl="", + no_prefix_markup=true, prefix_sep="", indent=o.prefix_sep}) + end +end + + +local function add_video(s) + local r = mp.get_property_native("video-params") + -- in case of e.g. lavi-complex there can be no input video, only output + if not r then + r = mp.get_property_native("video-out-params") + end + if not r then + return + end + + local osd_dims = mp.get_property_native("osd-dimensions") + local scaled_width = osd_dims["w"] - osd_dims["ml"] - osd_dims["mr"] + local scaled_height = osd_dims["h"] - osd_dims["mt"] - osd_dims["mb"] + + append(s, "", {prefix=o.nl .. o.nl .. "Video:", nl="", indent=""}) + if append_property(s, "video-codec", {prefix_sep="", nl="", indent=""}) then + append_property(s, "hwdec-current", {prefix="(hwdec:", nl="", indent=" ", + no_prefix_markup=true, suffix=")"}, {no=true, [""]=true}) + end + append_property(s, "avsync", {prefix="A-V:"}) + if append_property(s, compat("decoder-frame-drop-count"), + {prefix="Dropped Frames:", suffix=" (decoder)"}) then + append_property(s, compat("frame-drop-count"), {suffix=" (output)", nl="", indent=""}) + end + if append_property(s, "display-fps", {prefix="Display FPS:", suffix=" (specified)"}) then + append_property(s, "estimated-display-fps", + {suffix=" (estimated)", nl="", indent=""}) + else + append_property(s, "estimated-display-fps", + {prefix="Display FPS:", suffix=" (estimated)"}) + end + if append_property(s, compat("container-fps"), {prefix="FPS:", suffix=" (specified)"}) then + append_property(s, "estimated-vf-fps", + {suffix=" (estimated)", nl="", indent=""}) + else + append_property(s, "estimated-vf-fps", + {prefix="FPS:", suffix=" (estimated)"}) + end + + append_display_sync(s) + append_perfdata(s, o.print_perfdata_passes) + + if append(s, r["w"], {prefix="Native Resolution:"}) then + append(s, r["h"], {prefix="x", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true}) + end + if append(s, scaled_width, {prefix="Scaled Resolution:"}) then + append(s, scaled_height, {prefix="x", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true}) + end + append_property(s, "current-window-scale", {prefix="Window Scale:"}) + if r["aspect"] ~= nil then + append(s, format("%.2f", r["aspect"]), {prefix="Aspect Ratio:"}) + end + append(s, r["pixelformat"], {prefix="Pixel Format:"}) + if r["hw-pixelformat"] ~= nil then + append(s, r["hw-pixelformat"], {prefix_sep="[", nl="", indent=" ", + suffix="]"}) + end + + -- Group these together to save vertical space + local prim = append(s, r["primaries"], {prefix="Primaries:"}) + local cmat = append(s, r["colormatrix"], {prefix="Colormatrix:", nl=prim and "" or o.nl}) + append(s, r["colorlevels"], {prefix="Levels:", nl=cmat and "" or o.nl}) + + -- Append HDR metadata conditionally (only when present and interesting) + local hdrpeak = r["sig-peak"] or 0 + local hdrinfo = "" + if hdrpeak > 1 then + hdrinfo = " (HDR peak: " .. format("%.2f", hdrpeak) .. ")" + end + + append(s, r["gamma"], {prefix="Gamma:", suffix=hdrinfo}) + append_property(s, "packet-video-bitrate", {prefix="Bitrate:", suffix=" kbps"}) + append_filters(s, "vf", "Filters:") +end + + +local function add_audio(s) + local r = mp.get_property_native("audio-params") + -- in case of e.g. lavi-complex there can be no input audio, only output + if not r then + r = mp.get_property_native("audio-out-params") + end + if not r then + return + end + + append(s, "", {prefix=o.nl .. o.nl .. "Audio:", nl="", indent=""}) + append_property(s, "audio-codec", {prefix_sep="", nl="", indent=""}) + local cc = append(s, r["channel-count"], {prefix="Channels:"}) + append(s, r["format"], {prefix="Format:", nl=cc and "" or o.nl}) + append(s, r["samplerate"], {prefix="Sample Rate:", suffix=" Hz"}) + append_property(s, "packet-audio-bitrate", {prefix="Bitrate:", suffix=" kbps"}) + append_filters(s, "af", "Filters:") +end + + +-- Determine whether ASS formatting shall/can be used and set formatting sequences +local function eval_ass_formatting() + o.use_ass = o.ass_formatting and has_vo_window() + if o.use_ass then + o.nl = o.ass_nl + o.indent = o.ass_indent + o.prefix_sep = o.ass_prefix_sep + o.b1 = o.ass_b1 + o.b0 = o.ass_b0 + o.it1 = o.ass_it1 + o.it0 = o.ass_it0 + else + o.nl = o.no_ass_nl + o.indent = o.no_ass_indent + o.prefix_sep = o.no_ass_prefix_sep + o.b1 = o.no_ass_b1 + o.b0 = o.no_ass_b0 + o.it1 = o.no_ass_it1 + o.it0 = o.no_ass_it0 + end +end + + +-- Returns an ASS string with "normal" stats +local function default_stats() + local stats = {} + eval_ass_formatting() + add_header(stats) + add_file(stats) + add_video(stats) + add_audio(stats) + return table.concat(stats) +end + +local function scroll_vo_stats(stats, fixed_items, offset) + local ret = {} + local count = #stats - fixed_items + offset = max(1, min((offset or 1), count)) + + for i, line in pairs(stats) do + if i <= fixed_items or i >= fixed_items + offset then + ret[#ret+1] = stats[i] + end + end + return ret, offset +end + +-- Returns an ASS string with extended VO stats +local function vo_stats() + local stats = {} + eval_ass_formatting() + add_header(stats) + + -- first line (title) added next is considered fixed + local fixed_items = #stats + 1 + append_perfdata(stats, true) + + local page = pages[o.key_page_2] + stats, page.offset = scroll_vo_stats(stats, fixed_items, page.offset) + return table.concat(stats) +end + +local kbinfo_lines = nil +local function keybinding_info(after_scroll) + local header = {} + local page = pages[o.key_page_4] + eval_ass_formatting() + add_header(header) + append(header, "", {prefix=o.nl .. page.desc .. ":", nl="", indent=""}) + + if not kbinfo_lines or not after_scroll then + kbinfo_lines = get_kbinfo_lines() + end + -- up to 20 lines for the terminal - so that mpv can also print + -- the status line without scrolling, and up to 40 lines for libass + -- because it can put a big performance toll on libass to process + -- many lines which end up outside (below) the screen. + local term = not o.use_ass + local nlines = #kbinfo_lines + page.offset = max(1, min((page.offset or 1), term and nlines - 20 or nlines)) + local maxline = min(nlines, page.offset + (term and 20 or 40)) + return table.concat(header) .. + table.concat(kbinfo_lines, "", page.offset, maxline) +end + +local function perf_stats() + local stats = {} + eval_ass_formatting() + add_header(stats) + local page = pages[o.key_page_0] + append(stats, "", {prefix=o.nl .. o.nl .. page.desc .. ":", nl="", indent=""}) + page.offset = append_general_perfdata(stats, page.offset) + return table.concat(stats) +end + +local function opt_time(t) + if type(t) == type(1.1) then + return mp.format_time(t) + end + return "?" +end + +-- Returns an ASS string with stats about the demuxer cache etc. +local function cache_stats() + local stats = {} + + eval_ass_formatting() + add_header(stats) + append(stats, "", {prefix=o.nl .. o.nl .. "Cache info:", nl="", indent=""}) + + local info = mp.get_property_native("demuxer-cache-state") + if info == nil then + append(stats, "Unavailable.", {}) + return table.concat(stats) + end + + local a = info["reader-pts"] + local b = info["cache-end"] + + append(stats, opt_time(a) .. " - " .. opt_time(b), {prefix = "Packet queue:"}) + + local r = nil + if (a ~= nil) and (b ~= nil) then + r = b - a + end + + local r_graph = nil + if not display_timer.oneshot and o.use_ass then + r_graph = generate_graph(cache_ahead_buf, cache_ahead_buf.pos, + cache_ahead_buf.len, cache_ahead_buf.max, + nil, 0.8, 1) + r_graph = o.prefix_sep .. r_graph + end + append(stats, opt_time(r), {prefix = "Read-ahead:", suffix = r_graph}) + + -- These states are not necessarily exclusive. They're about potentially + -- separate mechanisms, whose states may be decoupled. + local state = "reading" + local seek_ts = info["debug-seeking"] + if seek_ts ~= nil then + state = "seeking (to " .. mp.format_time(seek_ts) .. ")" + elseif info["eof"] == true then + state = "eof" + elseif info["underrun"] then + state = "underrun" + elseif info["idle"] == true then + state = "inactive" + end + append(stats, state, {prefix = "State:"}) + + local speed = info["raw-input-rate"] or 0 + local speed_graph = nil + if not display_timer.oneshot and o.use_ass then + speed_graph = generate_graph(cache_speed_buf, cache_speed_buf.pos, + cache_speed_buf.len, cache_speed_buf.max, + nil, 0.8, 1) + speed_graph = o.prefix_sep .. speed_graph + end + append(stats, utils.format_bytes_humanized(speed) .. "/s", {prefix="Speed:", + suffix=speed_graph}) + + append(stats, utils.format_bytes_humanized(info["total-bytes"]), + {prefix = "Total RAM:"}) + append(stats, utils.format_bytes_humanized(info["fw-bytes"]), + {prefix = "Forward RAM:"}) + + local fc = info["file-cache-bytes"] + if fc ~= nil then + fc = utils.format_bytes_humanized(fc) + else + fc = "(disabled)" + end + append(stats, fc, {prefix = "Disk cache:"}) + + append(stats, info["debug-low-level-seeks"], {prefix = "Media seeks:"}) + append(stats, info["debug-byte-level-seeks"], {prefix = "Stream seeks:"}) + + append(stats, "", {prefix=o.nl .. o.nl .. "Ranges:", nl="", indent=""}) + + append(stats, info["bof-cached"] and "yes" or "no", + {prefix = "Start cached:"}) + append(stats, info["eof-cached"] and "yes" or "no", + {prefix = "End cached:"}) + + local ranges = info["seekable-ranges"] or {} + for n, r in ipairs(ranges) do + append(stats, mp.format_time(r["start"]) .. " - " .. + mp.format_time(r["end"]), + {prefix = format("Range %s:", n)}) + end + + return table.concat(stats) +end + +-- Record 1 sample of cache statistics. +-- (Unlike record_data(), this does not return a function, but runs directly.) +local function record_cache_stats() + local info = mp.get_property_native("demuxer-cache-state") + if info == nil then + return + end + + local a = info["reader-pts"] + local b = info["cache-end"] + if (a ~= nil) and (b ~= nil) then + graph_add_value(cache_ahead_buf, b - a) + end + + graph_add_value(cache_speed_buf, info["raw-input-rate"] or 0) +end + +cache_recorder_timer = mp.add_periodic_timer(0.25, record_cache_stats) +cache_recorder_timer:kill() + +-- Current page and : mapping +curr_page = o.key_page_1 +pages = { + [o.key_page_1] = { f = default_stats, desc = "Default" }, + [o.key_page_2] = { f = vo_stats, desc = "Extended Frame Timings", scroll = true }, + [o.key_page_3] = { f = cache_stats, desc = "Cache Statistics" }, + [o.key_page_4] = { f = keybinding_info, desc = "Active key bindings", scroll = true }, + [o.key_page_0] = { f = perf_stats, desc = "Internal performance info", scroll = true }, +} + + +-- Returns a function to record vsratio/jitter with the specified `skip` value +local function record_data(skip) + init_buffers() + skip = max(skip, 0) + local i = skip + return function() + if i < skip then + i = i + 1 + return + else + i = 0 + end + + if o.plot_vsync_jitter then + local r = mp.get_property_number("vsync-jitter", nil) + if r then + vsjitter_buf.pos = (vsjitter_buf.pos % vsjitter_buf.len) + 1 + vsjitter_buf[vsjitter_buf.pos] = r + vsjitter_buf.max = max(vsjitter_buf.max, r) + end + end + + if o.plot_vsync_ratio then + local r = mp.get_property_number("vsync-ratio", nil) + if r then + vsratio_buf.pos = (vsratio_buf.pos % vsratio_buf.len) + 1 + vsratio_buf[vsratio_buf.pos] = r + vsratio_buf.max = max(vsratio_buf.max, r) + end + end + end +end + +-- Call the function for `page` and print it to OSD +local function print_page(page, after_scroll) + -- the page functions assume we start in ass-enabled mode. + -- that's true for mp.set_osd_ass, but not for mp.osd_message. + local ass_content = pages[page].f(after_scroll) + if o.persistent_overlay then + mp.set_osd_ass(0, 0, ass_content) + else + mp.osd_message((o.use_ass and ass_start or "") .. ass_content, + display_timer.oneshot and o.duration or o.redraw_delay + 1) + end +end + + +local function clear_screen() + if o.persistent_overlay then mp.set_osd_ass(0, 0, "") else mp.osd_message("", 0) end +end + +local function scroll_delta(d) + if display_timer.oneshot then display_timer:kill() ; display_timer:resume() end + pages[curr_page].offset = (pages[curr_page].offset or 1) + d + print_page(curr_page, true) +end +local function scroll_up() scroll_delta(-o.scroll_lines) end +local function scroll_down() scroll_delta(o.scroll_lines) end + +local function reset_scroll_offsets() + for _, page in pairs(pages) do + page.offset = nil + end +end +local function bind_scroll() + if not scroll_bound then + mp.add_forced_key_binding(o.key_scroll_up, "__forced_"..o.key_scroll_up, scroll_up, {repeatable=true}) + mp.add_forced_key_binding(o.key_scroll_down, "__forced_"..o.key_scroll_down, scroll_down, {repeatable=true}) + scroll_bound = true + end +end +local function unbind_scroll() + if scroll_bound then + mp.remove_key_binding("__forced_"..o.key_scroll_up) + mp.remove_key_binding("__forced_"..o.key_scroll_down) + scroll_bound = false + end +end +local function update_scroll_bindings(k) + if (pages[k].scroll) then + bind_scroll() + else + unbind_scroll() + end +end + +-- Add keybindings for every page +local function add_page_bindings() + local function a(k) + return function() + reset_scroll_offsets() + update_scroll_bindings(k) + curr_page = k + print_page(k) + if display_timer.oneshot then display_timer:kill() ; display_timer:resume() end + end + end + for k, _ in pairs(pages) do + mp.add_forced_key_binding(k, "__forced_"..k, a(k), {repeatable=true}) + end + update_scroll_bindings(curr_page) +end + + +-- Remove keybindings for every page +local function remove_page_bindings() + for k, _ in pairs(pages) do + mp.remove_key_binding("__forced_"..k) + end + unbind_scroll() +end + + +local function process_key_binding(oneshot) + reset_scroll_offsets() + -- Stats are already being displayed + if display_timer:is_enabled() then + -- Previous and current keys were oneshot -> restart timer + if display_timer.oneshot and oneshot then + display_timer:kill() + print_page(curr_page) + display_timer:resume() + -- Previous and current keys were toggling -> end toggling + elseif not display_timer.oneshot and not oneshot then + display_timer:kill() + cache_recorder_timer:stop() + clear_screen() + remove_page_bindings() + if recorder then + mp.unobserve_property(recorder) + recorder = nil + end + end + -- No stats are being displayed yet + else + if not oneshot and (o.plot_vsync_jitter or o.plot_vsync_ratio) then + recorder = record_data(o.skip_frames) + -- Rely on the fact that "vsync-ratio" is updated at the same time. + -- Using "none" to get a sample any time, even if it does not change. + -- Will stop working if "vsync-jitter" property change notification + -- changes, but it's fine for an internal script. + mp.observe_property("vsync-jitter", "none", recorder) + end + if not oneshot then + cache_ahead_buf = {0, pos = 1, len = 50, max = 0} + cache_speed_buf = {0, pos = 1, len = 50, max = 0} + cache_recorder_timer:resume() + end + display_timer:kill() + display_timer.oneshot = oneshot + display_timer.timeout = oneshot and o.duration or o.redraw_delay + add_page_bindings() + print_page(curr_page) + display_timer:resume() + end +end + + +-- Create the timer used for redrawing (toggling) or clearing the screen (oneshot) +-- The duration here is not important and always set in process_key_binding() +display_timer = mp.add_periodic_timer(o.duration, + function() + if display_timer.oneshot then + display_timer:kill() ; clear_screen() ; remove_page_bindings() + else + print_page(curr_page) + end + end) +display_timer:kill() + +-- Single invocation key binding +mp.add_key_binding(o.key_oneshot, "display-stats", function() process_key_binding(true) end, + {repeatable=true}) + +-- Toggling key binding +mp.add_key_binding(o.key_toggle, "display-stats-toggle", function() process_key_binding(false) end, + {repeatable=false}) + +-- Single invocation bindings without key, can be used in input.conf to create +-- bindings for a specific page: "e script-binding stats/display-page-2" +for k, _ in pairs(pages) do + mp.add_key_binding(nil, "display-page-" .. k, + function() + curr_page = k + process_key_binding(true) + end, {repeatable=true}) +end + +-- Reprint stats immediately when VO was reconfigured, only when toggled +mp.register_event("video-reconfig", + function() + if display_timer:is_enabled() then + print_page(curr_page) + end + end) + +-- --script-opts=stats-bindlist=[-]{yes|} +if o.bindlist ~= "no" then + mp.command("no-osd set really-quiet yes") + if o.bindlist:sub(1, 1) == "-" then + o.bindlist = o.bindlist:sub(2) + o.no_ass_b0 = "" + o.no_ass_b1 = "" + end + local width = max(40, math.floor(tonumber(o.bindlist) or 79)) + mp.add_timeout(0, function() -- wait for all other scripts to finish init + o.ass_formatting = false + o.no_ass_indent = " " + eval_ass_formatting() + io.write(pages[o.key_page_4].desc .. ":" .. + table.concat(get_kbinfo_lines(width)) .. "\n") + mp.command("quit") + end) +end diff --git a/mpv/scripts/subtitle_manager.lua b/mpv/scripts/subtitle_manager.lua new file mode 100644 index 0000000..1216c16 --- /dev/null +++ b/mpv/scripts/subtitle_manager.lua @@ -0,0 +1,190 @@ +local utils = require 'mp.utils' + +-- 参数设置 +local subtitlesPerPage = 10 +local closeAfterLoad = true +local rate = 1.5 + +-- 全局变量和实用函数 +local styleOn = mp.get_property("osd-ass-cc/0") +local subtitles = {} +local currentSlot = 1 +local currentPage = 1 +local maxPage = 1 +local active = false + +-- 控制列表 +local subtitleControls = { + ESC = function() abort("") end, + e = function() abort("") end, + DOWN = function() jumpSlot(1) end, + UP = function() jumpSlot(-1) end, + j = function() jumpSlot(1) end, + k = function() jumpSlot(-1) end, + RIGHT = function() jumpPage(1) end, + LEFT = function() jumpPage(-1) end, + ENTER = function() loadSubtitle(currentSlot) end, + KP_ENTER = function() loadSubtitle(currentSlot) end +} + +local subtitleFlags = { + DOWN = {repeatable = true}, + UP = {repeatable = true}, + RIGHT = {repeatable = true}, + LEFT = {repeatable = true} +} + +-- 激活自定义控件 +function activateControls(name, controls, flags) + for key, func in pairs(controls) do + mp.add_forced_key_binding(key, name..key, func, flags[key]) + end +end + +-- 取消激活自定义控件 +function deactivateControls(name, controls) + for key, _ in pairs(controls) do + mp.remove_key_binding(name..key) + end +end + +-- 实用函数 +function fileExists(path) + local f = io.open(path, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +-- 加载字幕列表 +function listSubtitles() + subtitles = {} + local tracks = mp.get_property_native("track-list") + for _, track in ipairs(tracks) do + if track.type == "sub" then + table.insert(subtitles, track) + end + end + calcPages() +end + +-- 计算当前页和总页数 +function calcPages() + currentPage = math.floor((currentSlot - 1) / subtitlesPerPage) + 1 + if currentPage == 0 then currentPage = 1 end + maxPage = math.floor((#subtitles - 1) / subtitlesPerPage) + 1 + if maxPage == 0 then maxPage = 1 end +end + +-- 获取指定页的字幕数量 +function getAmountSubtitlesOnPage(page) + local n = subtitlesPerPage + if page == maxPage then n = #subtitles % subtitlesPerPage end + if n == 0 then n = subtitlesPerPage end + if #subtitles == 0 then n = 0 end + return n +end + +-- 获取指定页的第一个字幕索引 +function getFirstSlotOnPage(page) + return (page - 1) * subtitlesPerPage + 1 +end + +-- 获取指定页的最后一个字幕索引 +function getLastSlotOnPage(page) + local endSlot = getFirstSlotOnPage(page) + getAmountSubtitlesOnPage(page) - 1 + if endSlot > #subtitles then endSlot = #subtitles end + return endSlot +end + +-- 跳到指定数量的字幕前或后 +function jumpSlot(i) + currentSlot = currentSlot + i + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + if currentSlot < startSlot then currentSlot = endSlot end + if currentSlot > endSlot then currentSlot = startSlot end + + displaySubtitles() +end + +-- 跳到指定数量的页前或后 +function jumpPage(i) + local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1 + currentPage = currentPage + i + if currentPage < 1 then currentPage = maxPage + currentPage end + if currentPage > maxPage then currentPage = currentPage - maxPage end + + local subtitlesOnPage = getAmountSubtitlesOnPage(currentPage) + if oldPos > subtitlesOnPage then oldPos = subtitlesOnPage end + currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1 + + displaySubtitles() +end + +-- 显示当前页的字幕 +function displaySubtitles() + -- 确定当前页的第一个和最后一个字幕索引 + local startSlot = getFirstSlotOnPage(currentPage) + local endSlot = getLastSlotOnPage(currentPage) + + -- 准备显示的文本并显示 + local display = styleOn .. "{\\b1}Subtitles page " .. currentPage .. "/" .. maxPage .. ":{\\b0}" + for i = startSlot, endSlot do + local sub = subtitles[i] + local selection = "" + if i == currentSlot then + selection = "{\\b1}{\\c&H00FFFF&}>" + end + display = display .. "\n" .. selection .. i .. ": " .. (sub.title or sub.lang or sub.src) .. "{\\r}" + end + mp.osd_message(display, rate) +end + +-- 加载指定的字幕 +function loadSubtitle(slot) + if slot >= 1 and slot <= #subtitles then + local sub = subtitles[slot] + mp.set_property_native("sid", sub.id) + mp.osd_message(string.format("Loaded subtitle: %s", sub.title or sub.lang or sub.src), 2) + if closeAfterLoad then + abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully loaded subtitle:{\\r}\n"..(sub.title or sub.lang or sub.src)) + end + else + abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the subtitle at slot " .. slot) + end +end + +-- 定时器 +local timer = mp.add_periodic_timer(rate * 0.95, displaySubtitles) +timer:kill() + + +-- 终止程序 +function abort(message) + mode = "none" + deactivateControls("subtitle", subtitleControls) + timer:kill() + mp.osd_message(message) + active = false +end + +-- 处理字幕菜单的状态 +function handler() + if active then + abort("") + else + activateControls("subtitle", subtitleControls, subtitleFlags) + listSubtitles() + displaySubtitles() + timer:resume() + active = true + end +end + +-- 注册脚本消息 +mp.register_script_message("subtitle-menu", handler) \ No newline at end of file diff --git a/nvim/.gitignore b/nvim/.gitignore new file mode 100755 index 0000000..ed1d552 --- /dev/null +++ b/nvim/.gitignore @@ -0,0 +1,9 @@ +tt.* +.tests +doc/tags +debug +.repro +foo.* +*.log +data +lazy-lock.json diff --git a/nvim/.neoconf.json b/nvim/.neoconf.json new file mode 100755 index 0000000..7c48087 --- /dev/null +++ b/nvim/.neoconf.json @@ -0,0 +1,15 @@ +{ + "neodev": { + "library": { + "enabled": true, + "plugins": true + } + }, + "neoconf": { + "plugins": { + "lua_ls": { + "enabled": true + } + } + } +} diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100755 index 0000000..2514f9e --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,2 @@ +-- bootstrap lazy.nvim, LazyVim and your plugins +require("config.lazy") diff --git a/nvim/lazyvim.json b/nvim/lazyvim.json new file mode 100755 index 0000000..b69d261 --- /dev/null +++ b/nvim/lazyvim.json @@ -0,0 +1,20 @@ +{ + "extras": [ + "lazyvim.plugins.extras.ai.copilot", + "lazyvim.plugins.extras.ai.copilot-chat", + "lazyvim.plugins.extras.lang.clangd", + "lazyvim.plugins.extras.lang.cmake", + "lazyvim.plugins.extras.lang.git", + "lazyvim.plugins.extras.lang.go", + "lazyvim.plugins.extras.lang.json", + "lazyvim.plugins.extras.lang.markdown", + "lazyvim.plugins.extras.lang.python", + "lazyvim.plugins.extras.lang.typescript", + "lazyvim.plugins.extras.util.mini-hipatterns" + ], + "install_version": 7, + "news": { + "NEWS.md": "10960" + }, + "version": 8 +} \ No newline at end of file diff --git a/nvim/lua/config/autocmds.lua b/nvim/lua/config/autocmds.lua new file mode 100755 index 0000000..0a38af5 --- /dev/null +++ b/nvim/lua/config/autocmds.lua @@ -0,0 +1,10 @@ +-- Autocmds are automatically loaded on the VeryLazy event +-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua +-- +-- Add any additional autocmds here +-- with `vim.api.nvim_create_autocmd` +-- +-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults) +-- e.g. vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell") + +vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell") diff --git a/nvim/lua/config/keymaps.lua b/nvim/lua/config/keymaps.lua new file mode 100755 index 0000000..b4ce3cd --- /dev/null +++ b/nvim/lua/config/keymaps.lua @@ -0,0 +1,16 @@ +-- Keymaps are automatically loaded on the VeryLazy event +-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua +-- Add any additional keymaps here + +local km = vim.keymap + +local map = vim.keymap.set + +-- split windows horizontally and vertically +map("n", "sv", "v") +map("n", "sh", "s") + +-- no highlight +map("n", "nh", ":nohl") + +map("i", "jk", "") diff --git a/nvim/lua/config/lazy.lua b/nvim/lua/config/lazy.lua new file mode 100755 index 0000000..d73bfa1 --- /dev/null +++ b/nvim/lua/config/lazy.lua @@ -0,0 +1,53 @@ +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +require("lazy").setup({ + spec = { + -- add LazyVim and import its plugins + { "LazyVim/LazyVim", import = "lazyvim.plugins" }, + -- import/override with your plugins + { import = "plugins" }, + }, + defaults = { + -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup. + -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default. + lazy = false, + -- It's recommended to leave version=false for now, since a lot the plugin that support versioning, + -- have outdated releases, which may break your Neovim install. + version = false, -- always use the latest git commit + -- version = "*", -- try installing the latest stable version for plugins that support semver + }, + install = { colorscheme = { "tokyonight", "habamax" } }, + checker = { + enabled = true, -- check for plugin updates periodically + notify = false, -- notify on update + }, -- automatically check for plugin updates + performance = { + rtp = { + -- disable some rtp plugins + disabled_plugins = { + "gzip", + -- "matchit", + -- "matchparen", + -- "netrwPlugin", + "tarPlugin", + "tohtml", + "tutor", + "zipPlugin", + }, + }, + }, +}) diff --git a/nvim/lua/config/options.lua b/nvim/lua/config/options.lua new file mode 100755 index 0000000..e1cfedd --- /dev/null +++ b/nvim/lua/config/options.lua @@ -0,0 +1,11 @@ +-- Options are automatically loaded before lazy.nvim startup +-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua +-- Add any additional options before + +-- vim.opt.relativenumber = false + +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.expandtab = true +vim.opt.autoindent = true + diff --git a/nvim/lua/plugins/colorscheme.lua b/nvim/lua/plugins/colorscheme.lua new file mode 100755 index 0000000..8014a5d --- /dev/null +++ b/nvim/lua/plugins/colorscheme.lua @@ -0,0 +1,51 @@ +return { + { + "catppuccin/nvim", + opts = { + flavor = "mocah", + transparent_background = true, + styles = { + functions = { "bold" }, + keywords = { "bold" }, + }, + }, + }, + -- { + -- "olimorris/onedarkpro.nvim", + -- priority = 1000, -- Ensure it loads first + -- config = function() + -- require("onedarkpro").setup({ + -- options = { + -- transparency = true, + -- }, + -- styles = { + -- comments = "italic", + -- keywords = "bold", + -- }, + -- }) + -- require("onedarkpro").load() + -- end, + -- }, + { + "LazyVim/LazyVim", + opts = { + colorscheme = "catppuccin", + }, + }, +} + +-- return { +-- { +-- "folke/tokyonight.nvim", +-- lazy = true, +-- opts = { +-- style = "moon", +-- }, +-- }, +-- { +-- "LazyVim/LazyVim", +-- opts = { +-- colorscheme = "tokyonight", +-- }, +-- }, +-- } diff --git a/nvim/lua/plugins/example.lua b/nvim/lua/plugins/example.lua new file mode 100755 index 0000000..17f53d6 --- /dev/null +++ b/nvim/lua/plugins/example.lua @@ -0,0 +1,197 @@ +-- since this is just an example spec, don't actually load anything here and return an empty spec +-- stylua: ignore +if true then return {} end + +-- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim +-- +-- In your plugin files, you can: +-- * add extra plugins +-- * disable/enabled LazyVim plugins +-- * override the configuration of LazyVim plugins +return { + -- add gruvbox + { "ellisonleao/gruvbox.nvim" }, + + -- Configure LazyVim to load gruvbox + { + "LazyVim/LazyVim", + opts = { + colorscheme = "gruvbox", + }, + }, + + -- change trouble config + { + "folke/trouble.nvim", + -- opts will be merged with the parent spec + opts = { use_diagnostic_signs = true }, + }, + + -- disable trouble + { "folke/trouble.nvim", enabled = false }, + + -- override nvim-cmp and add cmp-emoji + { + "hrsh7th/nvim-cmp", + dependencies = { "hrsh7th/cmp-emoji" }, + ---@param opts cmp.ConfigSchema + opts = function(_, opts) + table.insert(opts.sources, { name = "emoji" }) + end, + }, + + -- change some telescope options and a keymap to browse plugin files + { + "nvim-telescope/telescope.nvim", + keys = { + -- add a keymap to browse plugin files + -- stylua: ignore + { + "fp", + function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end, + desc = "Find Plugin File", + }, + }, + -- change some options + opts = { + defaults = { + layout_strategy = "horizontal", + layout_config = { prompt_position = "top" }, + sorting_strategy = "ascending", + winblend = 0, + }, + }, + }, + + -- add pyright to lspconfig + { + "neovim/nvim-lspconfig", + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- pyright will be automatically installed with mason and loaded with lspconfig + pyright = {}, + }, + }, + }, + + -- add tsserver and setup with typescript.nvim instead of lspconfig + { + "neovim/nvim-lspconfig", + dependencies = { + "jose-elias-alvarez/typescript.nvim", + init = function() + require("lazyvim.util").lsp.on_attach(function(_, buffer) + -- stylua: ignore + vim.keymap.set( "n", "co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" }) + vim.keymap.set("n", "cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer }) + end) + end, + }, + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- tsserver will be automatically installed with mason and loaded with lspconfig + tsserver = {}, + }, + -- you can do any additional lsp server setup here + -- return true if you don't want this server to be setup with lspconfig + ---@type table + setup = { + -- example to setup with typescript.nvim + tsserver = function(_, opts) + require("typescript").setup({ server = opts }) + return true + end, + -- Specify * to use this function as a fallback for any server + -- ["*"] = function(server, opts) end, + }, + }, + }, + + -- for typescript, LazyVim also includes extra specs to properly setup lspconfig, + -- treesitter, mason and typescript.nvim. So instead of the above, you can use: + { import = "lazyvim.plugins.extras.lang.typescript" }, + + -- add more treesitter parsers + { + "nvim-treesitter/nvim-treesitter", + opts = { + ensure_installed = { + "bash", + "html", + "javascript", + "json", + "lua", + "markdown", + "markdown_inline", + "python", + "query", + "regex", + "tsx", + "typescript", + "vim", + "yaml", + }, + }, + }, + + -- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above + -- would overwrite `ensure_installed` with the new value. + -- If you'd rather extend the default config, use the code below instead: + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + -- add tsx and treesitter + vim.list_extend(opts.ensure_installed, { + "tsx", + "typescript", + }) + end, + }, + + -- the opts function can also be used to change the default opts: + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function(_, opts) + table.insert(opts.sections.lualine_x, { + function() + return "😄" + end, + }) + end, + }, + + -- or you can return new options to override all the defaults + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function() + return { + --[[add your custom lualine config here]] + } + end, + }, + + -- use mini.starter instead of alpha + { import = "lazyvim.plugins.extras.ui.mini-starter" }, + + -- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc + { import = "lazyvim.plugins.extras.lang.json" }, + + -- add any tools you want to have installed below + { + "williamboman/mason.nvim", + opts = { + ensure_installed = { + "stylua", + "shellcheck", + "shfmt", + "flake8", + }, + }, + }, +} diff --git a/nvim/lua/plugins/kitty.lua b/nvim/lua/plugins/kitty.lua new file mode 100644 index 0000000..4143ed1 --- /dev/null +++ b/nvim/lua/plugins/kitty.lua @@ -0,0 +1,14 @@ +return { + { + 'mikesmithgh/kitty-scrollback.nvim', + enabled = true, + lazy = true, + cmd = { 'KittyScrollbackGenerateKittens', 'KittyScrollbackCheckHealth' }, + event = { 'User KittyScrollbackLaunch' }, + config = function() + vim.keymap.set({ 'n' }, '', '(KsbCloseOrQuitAll)', {}) -- quit kitty-scrollback.nvim with Esc key + -- vim.keymap.set({ 'n' }, 'q', '(KsbCloseOrQuitAll)', {}) -- uncomment if you would like to also quit with the q key + require('kitty-scrollback').setup() + end, + }, +} diff --git a/nvim/lua/plugins/snacks.lua b/nvim/lua/plugins/snacks.lua new file mode 100755 index 0000000..af535ab --- /dev/null +++ b/nvim/lua/plugins/snacks.lua @@ -0,0 +1,16 @@ +return { + "snacks.nvim", + opts = { + dashboard = { + preset = { + header = [[ +███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ +████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ +██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║ +██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ +██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ +╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝]], + }, + }, + }, +} diff --git a/nvim/lua/plugins/tree.lua b/nvim/lua/plugins/tree.lua new file mode 100644 index 0000000..a229be0 --- /dev/null +++ b/nvim/lua/plugins/tree.lua @@ -0,0 +1,18 @@ +return { + "nvim-neo-tree/neo-tree.nvim", + opts = { + filesystem = { + filtered_items = { + hide_dotfiles = false, -- show dotfiles + hide_gitignored = false, -- show gitignored files + }, + follow_current_file = { + enabled = true, -- focus on the current file in the tree + }, + use_libuv_file_watcher = true, -- use libuv for file watching + }, + window = { + width = 25, + }, + }, +} diff --git a/nvim/stylua.toml b/nvim/stylua.toml new file mode 100755 index 0000000..5d6c50d --- /dev/null +++ b/nvim/stylua.toml @@ -0,0 +1,3 @@ +indent_type = "Spaces" +indent_width = 2 +column_width = 120 \ No newline at end of file diff --git a/nwg-dock-hyprland/archlinux.png b/nwg-dock-hyprland/archlinux.png new file mode 100644 index 0000000..315eaf5 Binary files /dev/null and b/nwg-dock-hyprland/archlinux.png differ diff --git a/nwg-dock-hyprland/mocha.css b/nwg-dock-hyprland/mocha.css new file mode 100644 index 0000000..0eb6a82 --- /dev/null +++ b/nwg-dock-hyprland/mocha.css @@ -0,0 +1,26 @@ +@define-color rosewater #f5e0dc; +@define-color flamingo #f2cdcd; +@define-color pink #f5c2e7; +@define-color mauve #cba6f7; +@define-color red #f38ba8; +@define-color maroon #eba0ac; +@define-color peach #fab387; +@define-color yellow #f9e2af; +@define-color green #a6e3a1; +@define-color teal #94e2d5; +@define-color sky #89dceb; +@define-color sapphire #74c7ec; +@define-color blue #89b4fa; +@define-color lavender #b4befe; +@define-color text #cdd6f4; +@define-color subtext1 #bac2de; +@define-color subtext0 #a6adc8; +@define-color overlay2 #9399b2; +@define-color overlay1 #7f849c; +@define-color overlay0 #6c7086; +@define-color surface2 #585b70; +@define-color surface1 #45475a; +@define-color surface0 #313244; +@define-color base #1e1e2e; +@define-color mantle #181825; +@define-color crust #11111b; diff --git a/nwg-dock-hyprland/style.css b/nwg-dock-hyprland/style.css new file mode 100644 index 0000000..18fe10b --- /dev/null +++ b/nwg-dock-hyprland/style.css @@ -0,0 +1,42 @@ +@import 'mocha.css'; + +window { + background: alpha(@base, 0.6); + border-radius: 20px; + border-style: none; +} + +#box { + /* Define attributes of the box surrounding icons here */ + padding: 10px; +} + +#active { + /* This is to underline the button representing the currently active window */ + border-color: @blue; +} + +button, +image { + background: none; + border-style: none; + box-shadow: none; + color: @overlay0; +} + +button { + padding: 4px; + margin-left: 4px; + margin-right: 4px; + color: @overlay2; + font-size: 12px; +} + +button:hover { + background: @surface0; + border-radius: 14px; +} + +button:focus { + box-shadow: none; +} diff --git a/posh_theme.omp.json b/posh_theme.omp.json new file mode 100755 index 0000000..0236364 --- /dev/null +++ b/posh_theme.omp.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json", + "blocks": [ + { + "alignment": "left", + "segments": [ + { + "foreground": "#74c7ec", + "properties": { + "windows": "\ue62a" + }, + "style": "plain", + "template": "{{.Icon}}", + "type": "os" + }, + { + "foreground": "#74c7ec", + "style": "plain", + "template": " {{.UserName}}", + "type": "session" + }, + { + "foreground": "#74c7ec", + "style": "plain", + "template": "@{{.HostName}}", + "type": "session" + }, + { + "foreground": "#94e2d5", + "properties": { + "folder_separator_icon": "/", + "style": "letter" + }, + "style": "powerline", + "template": " \uf07b {{ .Path }} ", + "type": "path" + }, + { + "foreground": "#a6e3a1", + "powerline_symbol": "\ue0b1", + "properties": { + "branch_icon": " ", + "fetch_stash_count": true, + "fetch_status": true, + "fetch_upstream_icon": true, + "fetch_worktree_count": true + }, + "style": "powerline", + "template": " {{ url .UpstreamIcon .UpstreamURL }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \ueb4b {{ .StashCount }}{{ end }} ", + "type": "git" + }, + { + "foreground": "#f9e2af", + "powerline_symbol": "\ue0b1", + "template": " \ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} ", + "style": "powerline", + "type": "python" + } + ], + "type": "prompt" + }, + { + "alignment": "left", + "newline": true, + "segments": [ + { + "foreground": "#fab387", + "style": "plain", + "template": "\ue3bf ", + "type": "root" + }, + { + "foreground": "#74c7ec", + "foreground_templates": [ + "{{ if gt .Code 0 }}#f38ba8{{ end }}" + ], + "properties": { + "always_enabled": true + }, + "style": "plain", + "template": "{{ if gt .Code 0 }}{{ .Code }} {{ end }}# ", + "type": "status" + } + ], + "type": "prompt" + } + ], + "transient_prompt": { + "background": "transparent", + "foreground_templates": [ + "{{ if gt .Code 0 }}#f38ba8{{ end }}" + ], + "foreground": "#74c7ec", + "template": "# " + }, + "version": 3 +} \ No newline at end of file diff --git a/waybar/config.jsonc b/waybar/config.jsonc new file mode 100644 index 0000000..dd40256 --- /dev/null +++ b/waybar/config.jsonc @@ -0,0 +1,391 @@ +{ + // ------------------------------------------------------------------------- + // Global configuration + // ------------------------------------------------------------------------- + "layer": "top", + "position": "top", + "height": 10, + "margin-left": 0, + "margin-bottom": 0, + "margin-right": 0, + "spacing": 2, // Gaps between modules (px) + "modules-left": [ + "custom/rofi", + "hyprland/workspaces", + "hyprland/window", + //"hyprland/submap", + //"idle_inhibitor", + //"mpd" + "custom/mediaplayer" + ], + "modules-center": [ + "clock#date", + "custom/caffeine" + //"custom/gammastep" + ], + "modules-right": [ + "network#speed", + "memory", + "cpu", + "battery", + //"pulseaudio", + "backlight", + "wireplumber", + // "bluetooth", + // "network", + "tray", + "custom/power" + ], + // ------------------------------------------------------------------------- + // Modules + // ------------------------------------------------------------------------- + "custom/sp1": { + "format": " | ", + "tooltip": false + }, + "custom/sp2": { + "format": " |", + "tooltip": false + }, + "custom/screenshot_t": { + "format": " ", + "on-click": "~/.config/hypr/scripts/screenshot_full", + "on-click-right": "~/.config/hypr/scripts/screenshot_area" + }, + "clock#1": { + "format": " {:%a}", + "tooltip": false, + "on-click": "gsimplecal" + }, + "clock#2": { + "format": " {:%d-%h-%Y}", + "tooltip": false, + "on-click": "gsimplecal" + }, + "clock#3": { + "format": " {:%H:%M:%S %p}", + "tooltip": false, + "on-click": "gsimplecal" + }, + "temperature": { + // "thermal-zone": 1, + "interval": 4, + //"hwmon-path": "/sys/class/hwmon/hwmon3/temp1_input", + "critical-threshold": 80, + // "format-critical": " {temperatureC}°C", + "format-critical": " {temperatureC}°C", + "format": "{icon} {temperatureC}°C", + "format-icons": ["", "", ""], + "max-length": 7, + "min-length": 7, + "on-click": "xsensors" + }, + "memory": { + "interval": 30, + // "format": " {used:0.2f} / {total:0.0f} GB", + "format": " {percentage}%", + "on-click": "ghostty -e btop", + "min-length": 7, + "max-length": 7 + }, + "battery": { + "interval": 2, + "states": { + "good": 95, + "warning": 30, + "critical": 15 + }, + "format": "{icon} {capacity}%", + "format-charging": " {capacity}%", + "format-plugged": " {capacity}%", + "format-icons": ["", "", "", "", ""], + "max-length": 7, + "min-length": 7 + }, + "network": { + "format-wifi": " {essid} ({signalStrength}%)", + "format-ethernet": "{ifname}: {ipaddr}/{cidr} ", + "format-linked": "{ifname} (No IP)", + "format": "", + "format-disconnected": "󰌙", + "format-alt": "{ifname}: {ipaddr}/{cidr}", + "on-click": "wl-copy $(ip address show up scope global | grep inet | head -n1 | cut -d/ -f 1 | tr -d [:space:] | cut -c5-)", + "on-click-right": "wl-copy $(ip address show up scope global | grep inet6 | head -n1 | cut -d/ -f 1 | tr -d [:space:] | cut -c6-)", + "tooltip-format": " {bandwidthUpBits}  {bandwidthDownBits}\n{ifname}\n{ipaddr}/{cidr}\n", + "tooltip-format-wifi": " {essid} {frequency}MHz\nStrength: {signaldBm}dBm ({signalStrength}%)\nIP: {ipaddr}/{cidr}\n {bandwidthUpBits}  {bandwidthDownBits}", + "interval": 10, + "max-length": 12 + }, + "custom/storage": { + "format": " {}", + "format-alt": "{percentage}% ", + "format-alt-click": "click-right", + "return-type": "json", + "interval": 60, + "exec": "~/.config/waybar/modules/storage.sh" + }, + "backlight": { + "device": "intel_backlight", + "format": "{icon} {percent}%", + "format-alt": "{percent}% {icon}", + "format-alt-click": "click-right", + //"format-icons": ["", ""], + "format-icons": ["", ""], + "on-scroll-down": "brightnessctl -d intel_backlight set 5%-", + "on-scroll-up": "brightnessctl -d intel_backlight set +5%", + "max-length": 7, + "min-length": 7 + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + }, + "tooltip": "true" + }, + "custom/weather": { + "format": "{}", + "format-alt": "{alt}: {}", + "format-alt-click": "click-right", + "interval": 3600, + "exec": "curl -s 'https://wttr.in/?format=1'", + //"return-type": "json", + //"exec": "~/.config/waybar/modules/weather.sh", + "exec-if": "ping wttr.in -c1" + }, + "custom/pacman": { + "format": "􏆲 {}", + "interval": 3600, // every hour + "exec": "checkupdates | wc -l", // # of updates + "exec-if": "exit 0", // always run; consider advanced run conditions + "on-click": "ghostty -e 'paru'; pkill -SIGRTMIN+8 waybar", // update system + "signal": 8, + "max-length": 7, + "min-length": 3 + }, + "custom/spotify": { + "exec": "~/.config/waybar/mediaplayer.py --player spotify", + "format": "{} ", + "return-type": "json", + "on-click": "playerctl play-pause", + "on-scroll-up": "playerctl next", + "on-scroll-down": "playerctl previous" + }, + "custom/mediaplayer": { + "format": "{text}", + "return-type": "json", + "max-length": 40, + "format-icons": { + "spotify": "", + "default": "" + }, + "escape": true, + "exec": "$HOME/.config/waybar/modules/mediaplayer.py 2> /dev/null", + "on-click": "playerctl play-pause", + "on-scroll-up": "playerctl next", + "on-scroll-down": "playerctl previous" + }, + "custom/media": { + "format": "{0} {1}", + "return-type": "json", + "max-length": 40, + "format-icons": { + "spotify": "", + "default": "🎜" + }, + "escape": true + //"exec": "~/.config/waybar/mediaplayer.py" // Script in resources folder + // "exec": "~/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name + }, + "custom/power": { + "format": "󰐥", + "tooltip": false, + "on-click": "wlogout", + "min-length": 2, + "max-length": 2 + }, + "custom/rofi": { + "format": "", + "tooltip": false, + "on-click-right": "fuzzel -l 0 -p '>> ' | xargs -r sh -c", + "on-click": "fuzzel", + "on-click-middle": "pkill -9 fuzzel", + "min-length": 2, + "max-length": 2 + }, + "custom/caffeine": { + "format": "{icon}", + "return-type": "json", + "interval": "once", + "exec": "$HOME/.config/waybar/modules/caffeine.sh", + "on-click": "$HOME/.config/waybar/modules/caffeine.sh toggle && sleep 1", + "exec-on-event": true, + "min-length": 2, + "max-length": 2, + "tooltip": false, + "format-icons": { + "active": "", + "inactive": "󰒲" + } + }, + "clock": { + "format": " {:%H:%M  %e %b}", + "tooltip-format": "{:%Y %B}\n{calendar}", + "today-format": "{}" + }, + "clock#date": { + "format": "󰥔 {:%H:%M |  %e %b}", + "tooltip-format": "{:%Y %B}\n{calendar}", + "today-format": "{}" + }, + "custom/gammastep": { + "interval": 5, + "return-type": "json", + "exec": { + "pre": "if unit_status=\"$(systemctl --user is-active gammastep)\"; then\nstatus=\"$unit_status ($(journalctl --user -u gammastep.service -g 'Period: ' | tail -1 | cut -d ':' -f6 | xargs))\"\nelse\nstatus=\"$unit_status\"\nfi", + "alt": "${status:-inactive}", + "tooltip": "Gammastep is $status" + }, + "format": "{icon}", + "format-icons": { + "activating": "󰁪 ", + "deactivating": "󰁪 ", + "inactive": "? ", + "active (Night)": " ", + "active (Nighttime)": " ", + "active (Transition (Night)": " ", + "active (Transition (Nighttime)": " ", + "active (Day)": " ", + "active (Daytime)": " ", + "active (Transition (Day)": " ", + "active (Transition (Daytime)": " " + }, + "on-click": "systemctl --user is-active gammastep && systemctl --user stop gammastep || systemctl --user start gammastep" + }, + "cpu": { + "interval": 1, + //"format": " {}%", // Icon: microchip + "format": " {usage}%", + "max-length": 7, + "min-length": 7, + "on-click": "ghostty -e btop" + }, + "mpd": { + "max-length": 25, + "format": " {title}", + "format-paused": " {title}", + "format-stopped": "", + "format-disconnected": "", + "on-click": "mpc --quiet toggle", + "on-click-right": "mpc update; mpc ls | mpc add", + "on-click-middle": "ghostty -e ncmpcpp", + "on-scroll-up": "mpc --quiet prev", + "on-scroll-down": "mpc --quiet next", + "smooth-scrolling-threshold": 5, + "tooltip-format": "{title} - {artist} ({elapsedTime:%M:%S}/{totalTime:%H:%M:%S})" + }, + "custom/title": { + "format": "{}", + "interval": 0, + "return-type": "json", + //"max-length": 35, + "tooltip": false + }, + "custom/title#name": { + "format": "{}", + "interval": 0, + "return-type": "json", + "max-length": 35, + "exec": "$HOME/.scripts/title" + }, + /*"custom/keyboard": { + "format": " {}", + "interval": 1, + "exec": "$HOME/.config/waybar/get_kbdlayout.sh" + },*/ + "hyprland/workspaces": { + "all-outputs": true, + "format": "{name}", + "show-special": true, + "on-scroll-up": "hyprctl dispatch workspace e+1 1>/dev/null", + "on-scroll-down": "hyprctl dispatch workspace e-1 1>/dev/null", + "sort-by-number": true, + "active-only": false + }, + "hyprland/window": { + "max-length": 100, + "separate-outputs": true, + "hide-empty-text": true + }, + "pulseaudio": { + "scroll-step": 3, // %, can be a float + "format": "{icon} {volume}% {format_source}", + "format-bluetooth": "{volume}% {icon} {format_source}", + "format-bluetooth-muted": " {icon} {format_source}", + "format-muted": " {format_source}", + //"format-source": "{volume}% ", + //"format-source-muted": "", + "format-source": "", + "format-source-muted": "", + "format-icons": { + "headphone": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", ""] + }, + "on-click": "pavucontrol", + "on-click-right": "amixer sset Master toggle" + }, + "bluetooth": { + "format-on": "󰂯", + "format-off": "󰂲", + "format-disabled": "", // an empty format will hide the module + "format-connected": "󰂱 {num_connections}", + "tooltip-format-connected": "{device_enumerate}", + "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}", + "on-click": "blueberry", + "max-length": 3, + "min-length": 3 + }, + "wireplumber": { + "on-click": "pavucontrol", + //on-click: "${wpctl} set-mute @DEFAULT_AUDIO_SINK@ toggle"; + "on-scroll-down": "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 0.04-", + "on-scroll-up": "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 0.04+", + "format": "{icon} {volume}%", + "format-muted": "", + "format-source": "", + "format-source-muted": "", + //"format-muted": "", + //"format-icons": [ "" ] + "format-icons": { + "headphone": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", "", "", "", ""] + }, + "max-length": 7, + "min-length": 7 + }, + "tray": { + "icon-size": 15, + "spacing": 5 + }, + "network#speed": { + "interval": 1, + "format": "{ifname}", + "format-wifi": " {bandwidthDownBytes}  {bandwidthUpBytes} ", + "format-ethernet": " {bandwidthDownBytes}  {bandwidthUpBytes} ", + "format-disconnected": "󰌙", + "tooltip-format": "{ipaddr}", + "format-linked": "󰈁 {ifname} (No IP)", + "tooltip-format-wifi": "{essid} {signalStrength}%", + "tooltip-format-ethernet": "{ifname} 󰌘", + "tooltip-format-disconnected": "󰌙 Disconnected", + "max-length": 18, + "min-length": 18 + } +} diff --git a/waybar/mediaplayer.py b/waybar/mediaplayer.py new file mode 100755 index 0000000..7404f48 --- /dev/null +++ b/waybar/mediaplayer.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +import argparse +import logging +import sys +import signal +import gi +import json +gi.require_version('Playerctl', '2.0') +from gi.repository import Playerctl, GLib + +logger = logging.getLogger(__name__) + + +def write_output(text, player): + logger.info('Writing output') + + output = {'text': text, + 'class': 'custom-' + player.props.player_name, + 'alt': player.props.player_name} + + sys.stdout.write(json.dumps(output) + '\n') + sys.stdout.flush() + + +def on_play(player, status, manager): + logger.info('Received new playback status') + on_metadata(player, player.props.metadata, manager) + + +def on_metadata(player, metadata, manager): + logger.info('Received new metadata') + track_info = '' + + if player.props.player_name == 'spotify' and \ + 'mpris:trackid' in metadata.keys() and \ + ':ad:' in player.props.metadata['mpris:trackid']: + track_info = 'AD PLAYING' + elif player.get_artist() != '' and player.get_title() != '': + track_info = '{artist} - {title}'.format(artist=player.get_artist(), + title=player.get_title()) + else: + track_info = player.get_title() + + if player.props.status != 'Playing' and track_info: + track_info = ' ' + track_info + write_output(track_info, player) + + +def on_player_appeared(manager, player, selected_player=None): + if player is not None and (selected_player is None or player.name == selected_player): + init_player(manager, player) + else: + logger.debug("New player appeared, but it's not the selected player, skipping") + + +def on_player_vanished(manager, player): + logger.info('Player has vanished') + sys.stdout.write('\n') + sys.stdout.flush() + + +def init_player(manager, name): + logger.debug('Initialize player: {player}'.format(player=name.name)) + player = Playerctl.Player.new_from_name(name) + player.connect('playback-status', on_play, manager) + player.connect('metadata', on_metadata, manager) + manager.manage_player(player) + on_metadata(player, player.props.metadata, manager) + + +def signal_handler(sig, frame): + logger.debug('Received signal to stop, exiting') + sys.stdout.write('\n') + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurance of -v + parser.add_argument('-v', '--verbose', action='count', default=0) + + # Define for which player we're listening + parser.add_argument('--player') + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, + format='%(name)s %(levelname)s %(message)s') + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + # Log the sent command line arguments + logger.debug('Arguments received {}'.format(vars(arguments))) + + manager = Playerctl.PlayerManager() + loop = GLib.MainLoop() + + manager.connect('name-appeared', lambda *args: on_player_appeared(*args, arguments.player)) + manager.connect('player-vanished', on_player_vanished) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + for player in manager.props.player_names: + if arguments.player is not None and arguments.player != player.name: + logger.debug('{player} is not the filtered player, skipping it' + .format(player=player.name) + ) + continue + + init_player(manager, player) + + loop.run() + + +if __name__ == '__main__': + main() diff --git a/waybar/mocha.css b/waybar/mocha.css new file mode 100644 index 0000000..0eb6a82 --- /dev/null +++ b/waybar/mocha.css @@ -0,0 +1,26 @@ +@define-color rosewater #f5e0dc; +@define-color flamingo #f2cdcd; +@define-color pink #f5c2e7; +@define-color mauve #cba6f7; +@define-color red #f38ba8; +@define-color maroon #eba0ac; +@define-color peach #fab387; +@define-color yellow #f9e2af; +@define-color green #a6e3a1; +@define-color teal #94e2d5; +@define-color sky #89dceb; +@define-color sapphire #74c7ec; +@define-color blue #89b4fa; +@define-color lavender #b4befe; +@define-color text #cdd6f4; +@define-color subtext1 #bac2de; +@define-color subtext0 #a6adc8; +@define-color overlay2 #9399b2; +@define-color overlay1 #7f849c; +@define-color overlay0 #6c7086; +@define-color surface2 #585b70; +@define-color surface1 #45475a; +@define-color surface0 #313244; +@define-color base #1e1e2e; +@define-color mantle #181825; +@define-color crust #11111b; diff --git a/waybar/modules/caffeine.sh b/waybar/modules/caffeine.sh new file mode 100755 index 0000000..9f249f7 --- /dev/null +++ b/waybar/modules/caffeine.sh @@ -0,0 +1,28 @@ +#!/bin/env bash + +function output() { + jq -n --unbuffered --compact-output \ + --arg alt "$1" \ + --arg class "$2" \ + '{alt: $alt, class: [$class]}' +} + +if [ -n "$1" ]; then + pid=$(pgrep -x "hypridle") + if [ -n "$pid" ]; then + killall hypridle > /dev/null 2>&1 + else + hyprctl dispatch exec hypridle > /dev/null 2>&1 + fi + exit 0 +fi + +sleep 0.3 # Allow hypridle to start +pid=$(pgrep -x "hypridle") +if [ -n "$pid" ]; then + output "inactive" "inactive" + notify-send "Caffeine disabled" "Caffeine mode is now inactive." +else + output "active" "active" + notify-send "Caffeine enabled" "Caffeine mode is now active." +fi \ No newline at end of file diff --git a/waybar/modules/mail.py b/waybar/modules/mail.py new file mode 100755 index 0000000..abc36ec --- /dev/null +++ b/waybar/modules/mail.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +import os +import imaplib + +import mailsecrets + +def getmails(username, password, server): + imap = imaplib.IMAP4_SSL(server, 993) + imap.login(username, password) + imap.select('INBOX') + ustatus, uresponse = imap.uid('search', None, 'UNSEEN') + if ustatus == 'OK': + unread_msg_nums = uresponse[0].split() + else: + unread_msg_nums = [] + + fstatus, fresponse = imap.uid('search', None, 'FLAGGED') + if fstatus == 'OK': + flagged_msg_nums = fresponse[0].split() + else: + flagged_msg_nums = [] + + return [len(unread_msg_nums), len(flagged_msg_nums)] + +ping = os.system("ping " + mailsecrets.server + " -c1 > /dev/null 2>&1") +if ping == 0: + mails = getmails(mailsecrets.username, mailsecrets.password, mailsecrets.server) + text = '' + alt = '' + + if mails[0] > 0: + text = alt = str(mails[0]) + if mails[1] > 0: + alt = str(mails[1]) + "  " + alt + else: + exit(1) + + print('{"text":"' + text + '", "alt": "' + alt + '"}') + +else: + exit(1) diff --git a/waybar/modules/mediaplayer.py b/waybar/modules/mediaplayer.py new file mode 100755 index 0000000..b9842bc --- /dev/null +++ b/waybar/modules/mediaplayer.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +from typing import List +import os +import json +import signal +import sys +import logging +import argparse +from gi.repository.Playerctl import Player +from gi.repository import Playerctl, GLib +import gi +gi.require_version("Playerctl", "2.0") + +logger = logging.getLogger(__name__) + + +def signal_handler(sig, frame): + logger.info("Received signal to stop, exiting") + sys.stdout.write("\n") + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +class PlayerManager: + def __init__(self, selected_player=None, excluded_player=[]): + self.manager = Playerctl.PlayerManager() + self.loop = GLib.MainLoop() + self.manager.connect( + "name-appeared", lambda *args: self.on_player_appeared(*args)) + self.manager.connect( + "player-vanished", lambda *args: self.on_player_vanished(*args)) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + self.selected_player = selected_player + self.excluded_player = excluded_player.split(',') if excluded_player else [] + + self.init_players() + + def init_players(self): + for player in self.manager.props.player_names: + if player.name in self.excluded_player: + continue + if self.selected_player is not None and self.selected_player != player.name: + logger.debug(f"{player.name} is not the filtered player, skipping it") + continue + self.init_player(player) + + def run(self): + logger.info("Starting main loop") + self.loop.run() + + def init_player(self, player): + logger.info(f"Initialize new player: {player.name}") + player = Playerctl.Player.new_from_name(player) + player.connect("playback-status", + self.on_playback_status_changed, None) + player.connect("metadata", self.on_metadata_changed, None) + self.manager.manage_player(player) + self.on_metadata_changed(player, player.props.metadata) + + def get_players(self) -> List[Player]: + return self.manager.props.players + + def write_output(self, text, player): + logger.debug(f"Writing output: {text}") + + output = {"text": text, + "class": "custom-" + player.props.player_name, + "alt": player.props.player_name} + + sys.stdout.write(json.dumps(output) + "\n") + sys.stdout.flush() + + def clear_output(self): + sys.stdout.write("\n") + sys.stdout.flush() + + def on_playback_status_changed(self, player, status, _=None): + logger.debug(f"Playback status changed for player {player.props.player_name}: {status}") + self.on_metadata_changed(player, player.props.metadata) + + def get_first_playing_player(self): + players = self.get_players() + logger.debug(f"Getting first playing player from {len(players)} players") + if len(players) > 0: + # if any are playing, show the first one that is playing + # reverse order, so that the most recently added ones are preferred + for player in players[::-1]: + if player.props.status == "Playing": + return player + # if none are playing, show the first one + return players[0] + else: + logger.debug("No players found") + return None + + def show_most_important_player(self): + logger.debug("Showing most important player") + # show the currently playing player + # or else show the first paused player + # or else show nothing + current_player = self.get_first_playing_player() + if current_player is not None: + self.on_metadata_changed(current_player, current_player.props.metadata) + else: + self.clear_output() + + def on_metadata_changed(self, player, metadata, _=None): + logger.debug(f"Metadata changed for player {player.props.player_name}") + player_name = player.props.player_name + artist = player.get_artist() + title = player.get_title() + title = title.replace("&", "&") + + track_info = "" + if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]: + track_info = "Advertisement" + elif artist is not None and title is not None: + track_info = f"{artist} - {title}" + else: + track_info = title + + if track_info: + if player.props.status == "Playing": + track_info = " " + track_info + else: + track_info = " " + track_info + # only print output if no other player is playing + current_playing = self.get_first_playing_player() + if current_playing is None or current_playing.props.player_name == player.props.player_name: + self.write_output(track_info, player) + else: + logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping") + + def on_player_appeared(self, _, player): + logger.info(f"Player has appeared: {player.name}") + if player.name in self.excluded_player: + logger.debug( + "New player appeared, but it's in exclude player list, skipping") + return + if player is not None and (self.selected_player is None or player.name == self.selected_player): + self.init_player(player) + else: + logger.debug( + "New player appeared, but it's not the selected player, skipping") + + def on_player_vanished(self, _, player): + logger.info(f"Player {player.props.player_name} has vanished") + self.show_most_important_player() + + +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurrence of -v + parser.add_argument("-v", "--verbose", action="count", default=0) + + parser.add_argument("-x", "--exclude", "- Comma-separated list of excluded player") + + # Define for which player we"re listening + parser.add_argument("--player") + + parser.add_argument("--enable-logging", action="store_true") + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + if arguments.enable_logging: + logfile = os.path.join(os.path.dirname( + os.path.realpath(__file__)), "media-player.log") + logging.basicConfig(filename=logfile, level=logging.DEBUG, + format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s") + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + logger.info("Creating player manager") + if arguments.player: + logger.info(f"Filtering for player: {arguments.player}") + if arguments.exclude: + logger.info(f"Exclude player {arguments.exclude}") + + player = PlayerManager(arguments.player, arguments.exclude) + player.run() + + +if __name__ == "__main__": + main() diff --git a/waybar/modules/spotify.sh b/waybar/modules/spotify.sh new file mode 100755 index 0000000..c00622b --- /dev/null +++ b/waybar/modules/spotify.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +class=$(playerctl metadata --player=spotify --format '{{lc(status)}}') +icon="" + +if [[ $class == "playing" ]]; then + info=$(playerctl metadata --player=spotify --format '{{artist}} - {{title}}') + if [[ ${#info} > 40 ]]; then + info=$(echo $info | cut -c1-40)"..." + fi + text=$info" "$icon +elif [[ $class == "paused" ]]; then + text=$icon +elif [[ $class == "stopped" ]]; then + text="" +fi + +echo -e "{\"text\":\""$text"\", \"class\":\""$class"\"}" diff --git a/waybar/modules/storage.sh b/waybar/modules/storage.sh new file mode 100755 index 0000000..ae2a5ce --- /dev/null +++ b/waybar/modules/storage.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +mount="/" +warning=20 +critical=10 + +df -h -P -l "$mount" | awk -v warning=$warning -v critical=$critical ' +/\/.*/ { + text=$4 + tooltip="Filesystem: "$1"\rSize: "$2"\rUsed: "$3"\rAvail: "$4"\rUse%: "$5"\rMounted on: "$6 + use=$5 + exit 0 +} +END { + class="" + gsub(/%$/,"",use) + if ((100 - use) < critical) { + class="critical" + } else if ((100 - use) < warning) { + class="warning" + } + print "{\"text\":\""text"\", \"percentage\":"use",\"tooltip\":\""tooltip"\", \"class\":\""class"\"}" +} +' diff --git a/waybar/modules/weather.sh b/waybar/modules/weather.sh new file mode 100755 index 0000000..06157ef --- /dev/null +++ b/waybar/modules/weather.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +cachedir=~/.cache/rbn +cachefile=${0##*/}-$1 + +if [ ! -d $cachedir ]; then + mkdir -p $cachedir +fi + +if [ ! -f $cachedir/$cachefile ]; then + touch $cachedir/$cachefile +fi + +# Save current IFS +SAVEIFS=$IFS +# Change IFS to new line. +IFS=$'\n' + +cacheage=$(($(date +%s) - $(stat -c '%Y' "$cachedir/$cachefile"))) +if [ $cacheage -gt 1740 ] || [ ! -s $cachedir/$cachefile ]; then + data=($(curl -s https://en.wttr.in/$1\?0qnT 2>&1)) + echo ${data[0]} | cut -f1 -d, > $cachedir/$cachefile + echo ${data[1]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile + echo ${data[2]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile +fi + +weather=($(cat $cachedir/$cachefile)) + +# Restore IFSClear +IFS=$SAVEIFS + +temperature=$(echo ${weather[2]} | sed -E 's/([[:digit:]])+\.\./\1 to /g') + +#echo ${weather[1]##*,} + +# https://fontawesome.com/icons?s=solid&c=weather +case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in +"clear" | "sunny") + condition="" + ;; +"partly cloudy") + condition="杖" + ;; +"cloudy") + condition="" + ;; +"overcast") + condition="" + ;; +"mist" | "fog" | "freezing fog") + condition="" + ;; +"patchy rain possible" | "patchy light drizzle" | "light drizzle" | "patchy light rain" | "light rain" | "light rain shower" | "rain") + condition="" + ;; +"moderate rain at times" | "moderate rain" | "heavy rain at times" | "heavy rain" | "moderate or heavy rain shower" | "torrential rain shower" | "rain shower") + condition="" + ;; +"patchy snow possible" | "patchy sleet possible" | "patchy freezing drizzle possible" | "freezing drizzle" | "heavy freezing drizzle" | "light freezing rain" | "moderate or heavy freezing rain" | "light sleet" | "ice pellets" | "light sleet showers" | "moderate or heavy sleet showers") + condition="ﭽ" + ;; +"blowing snow" | "moderate or heavy sleet" | "patchy light snow" | "light snow" | "light snow showers") + condition="流" + ;; +"blizzard" | "patchy moderate snow" | "moderate snow" | "patchy heavy snow" | "heavy snow" | "moderate or heavy snow with thunder" | "moderate or heavy snow showers") + condition="ﰕ" + ;; +"thundery outbreaks possible" | "patchy light rain with thunder" | "moderate or heavy rain with thunder" | "patchy light snow with thunder") + condition="" + ;; +*) + condition="" + echo -e "{\"text\":\""$condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" + ;; +esac + +#echo $temp $condition + +echo -e "{\"text\":\""$temperature $condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" diff --git a/waybar/style.css b/waybar/style.css new file mode 100644 index 0000000..513ee99 --- /dev/null +++ b/waybar/style.css @@ -0,0 +1,372 @@ +@import 'mocha.css'; + +* { + font-family: 'Fira Sans Semibold', 'Font Awesome 6 Free', FontAwesome, Roboto, Helvetica, Arial, sans-serif; + font-size: 12px; /* Slightly smaller font size */ + font-weight: 900; + margin: 0; + padding: 0; + transition-property: background-color; + transition-duration: 0.5s; +} + +/* Reset all styles */ +* { + border: none; + border-radius: 3px; + min-height: 0; + margin: 2px 1px 2px 1px; +} + +/* The whole bar */ +#waybar { + background-color: transparent; + color: #ffffff; + transition-property: background-color; + transition-duration: 0.5s; + border-radius: 0px; + margin: 0px 0px; +} + +window#waybar.hidden { + opacity: 0.2; +} + +tooltip { + background: @base; + border: 3px solid @overlay0; +} + +#workspaces button { + padding: 3px 5px; /* Adjusted padding to reduce height */ + margin: 3px 5px; /* Reduced margin slightly */ + border-radius: 6px; + color: @foreground; + background-color: alpha(@base, 0); + transition: all 0.3s ease-in-out; + font-size: 13px; /* Slightly smaller font size */ +} + +#workspaces button:hover { + background: @surface0; +} + +#workspaces button.active { + color: @foreground; + background: @blue; +} + +#workspaces button.urgent { + background-color: @red; +} + +#workspaces { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 3px 6px; /* Adjusted padding to reduce height */ + border: 3px solid @blue; +} + +#window { + background-color: alpha(@base, 0.6); + font-size: 15px; /* Slightly smaller font size */ + font-weight: 800; + color: @foreground; + border-radius: 14px; + padding: 3px 6px; /* Reduced padding */ + margin: 2px; + opacity: 1; +} + +#clock, +#battery, +#cpu, +#memory, +#disk, +#temperature, +#backlight, +#network, +#pulseaudio, +#wireplumber, +#custom-media, +#mode, +#idle_inhibitor, +#mpd, +#bluetooth, +#custom-hyprPicker, +#custom-power-menu, +#custom-spotify, +#custom-weather, +#custom-weather.severe, +#custom-weather.sunnyDay, +#custom-weather.clearNight, +#custom-weather.cloudyFoggyDay, +#custom-weather.cloudyFoggyNight, +#custom-weather.rainyDay, +#custom-weather.rainyNight, +#custom-weather.showyIcyDay, +#custom-weather.snowyIcyNight, +#custom-weather.default { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; /* Adjusted padding */ +} + +#custom-screenshot_t { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; +} + +#custom-spotify { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 3px 12px; +} + +#custom-mediaplayer { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 3px 12px; +} + +#tray { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; /* Adjusted padding */ + border: 3px solid @blue; +} + +#cpu { + color: @maroon; + background-color: alpha(@base, 0.6); + padding: 6px; +} + +#memory { + color: @yellow; + background-color: alpha(@base, 0.6); + padding: 6px; +} + +#custom-power { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; + border: 4px solid @maroon; +} + +#custom-power:hover { + background-color: alpha(@maroon, 0.3); +} + +#custom-rofi { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; + border: 4px solid @teal; +} + +#custom-rofi:hover { + background-color: alpha(@teal, 0.3); +} + +#custom-caffeine { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; + border: 4px solid @yellow; +} + +#custom-caffeine:hover { + background-color: alpha(@yellow, 0.3); +} + +#custom-caffeine.active { + border: 4px solid @peach; +} + +#custom-storage { + background-color: alpha(@base, 0.6); + border-radius: 14px; + padding: 6px; +} + +#custom-launcher { + background-color: #1b242b; + color: #6a92d7; + border-radius: 7.5px; + padding: 3px 6px; /* Adjusted padding */ +} + +#custom-weather.severe { + color: #eb937d; +} + +#custom-weather.sunnyDay { + color: #c2ca76; +} + +#custom-weather.clearNight { + color: #cad3f5; +} + +#custom-weather.cloudyFoggyDay, +#custom-weather.cloudyFoggyNight { + color: #c2ddda; +} + +#custom-weather.rainyDay, +#custom-weather.rainyNight { + color: #5aaca5; +} + +#custom-weather.showyIcyDay, +#custom-weather.snowyIcyNight { + color: #d6e7e5; +} + +#custom-weather.default { + color: #dbd9d8; +} + +/* If workspaces is the leftmost module, omit left margin */ +.modules-left > widget:first-child > #workspaces { + margin-left: 0; +} + +/* If workspaces is the rightmost module, omit right margin */ +.modules-right > widget:last-child > #workspaces { + margin-right: 0; +} + +#pulseaudio { + color: #7d9bba; +} + +#wireplumber { + color: @teal; +} + +#backlight { + color: #8fbcbb; +} + +#clock { + color: #c8d2e0; + border: 3px solid @blue; +} + +#battery { + color: #c0caf5; +} + +#battery.charging, +#battery.full, +#battery.plugged { + color: @green; +} + +@keyframes blink { + to { + background-color: rgba(30, 34, 42, 0.5); + color: #abb2bf; + } +} + +#battery.critical:not(.charging) { + color: @red; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; +} + +label:focus { + background-color: #000000; +} + +#disk { + background-color: #964b00; +} + +#bluetooth { + color: @sapphire; +} + +#bluetooth.disconnected { + color: @red; +} + +#network { + color: @lavender; +} + +#network.disconnected { + color: @red; +} + +#custom-media { + background-color: #66cc99; + color: #2a5c45; + min-width: 100px; +} + +#custom-media.custom-spotify { + background-color: #66cc99; +} + +#custom-media.custom-vlc { + background-color: #ffa000; +} + +#temperature { + background-color: #f0932b; +} + +#temperature.critical { + background-color: #eb4d4b; +} + +#tray > .passive { + -gtk-icon-effect: dim; +} + +#tray > .needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; +} + +#idle_inhibitor { + background-color: #2d3436; +} + +#idle_inhibitor.activated { + background-color: #ecf0f1; + color: #2d3436; +} + +#language { + background: #00b093; + color: #740864; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state { + background: #97e1ad; + color: #000000; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state > label { + padding: 0 0px; +} + +#keyboard-state > label.locked { + background: rgba(0, 0, 0, 0.2); +} diff --git a/waybar/waybar.sh b/waybar/waybar.sh new file mode 100755 index 0000000..d03b9eb --- /dev/null +++ b/waybar/waybar.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# Terminate already running bar instances +killall -q waybar + +# Wait until the processes have been shut down +while pgrep -x waybar >/dev/null; do sleep 1; done + +# Launch main +waybar & diff --git a/wlogout/icons/hibernate.svg b/wlogout/icons/hibernate.svg new file mode 100644 index 0000000..4d5010f --- /dev/null +++ b/wlogout/icons/hibernate.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/icons/lock.svg b/wlogout/icons/lock.svg new file mode 100644 index 0000000..a7832ba --- /dev/null +++ b/wlogout/icons/lock.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/icons/logout.svg b/wlogout/icons/logout.svg new file mode 100644 index 0000000..4fac745 --- /dev/null +++ b/wlogout/icons/logout.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/icons/reboot.svg b/wlogout/icons/reboot.svg new file mode 100644 index 0000000..d8e6844 --- /dev/null +++ b/wlogout/icons/reboot.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/icons/shutdown.svg b/wlogout/icons/shutdown.svg new file mode 100644 index 0000000..abb804d --- /dev/null +++ b/wlogout/icons/shutdown.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/icons/suspend.svg b/wlogout/icons/suspend.svg new file mode 100644 index 0000000..5ee54b1 --- /dev/null +++ b/wlogout/icons/suspend.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + diff --git a/wlogout/layout b/wlogout/layout new file mode 100644 index 0000000..d67313c --- /dev/null +++ b/wlogout/layout @@ -0,0 +1,36 @@ +{ + "label" : "lock", + "action" : "swaylock", + "text" : "Lock", + "keybind" : "l" +} +{ + "label" : "hibernate", + "action" : "systemctl hibernate", + "text" : "Hibernate", + "keybind" : "h" +} +{ + "label" : "logout", + "action" : "hyprctl dispatch exit", + "text" : "Logout", + "keybind" : "e" +} +{ + "label" : "shutdown", + "action" : "systemctl poweroff", + "text" : "Shutdown", + "keybind" : "s" +} +{ + "label" : "suspend", + "action" : "systemctl suspend", + "text" : "Suspend", + "keybind" : "u" +} +{ + "label" : "reboot", + "action" : "systemctl reboot", + "text" : "Reboot", + "keybind" : "r" +} diff --git a/wlogout/style.css b/wlogout/style.css new file mode 100644 index 0000000..dbe691a --- /dev/null +++ b/wlogout/style.css @@ -0,0 +1,58 @@ +* { + background-image: none; + transition: 20ms; + box-shadow: none; +} + +window { + background-color: rgba(30, 30, 46, 0.9); +} + +button { + border-radius: 0; + border-color: #89b4fa; + text-decoration-color: #cdd6f4; + color: #cdd6f4; + background-color: #181825; + border-style: solid; + border-width: 1px; + background-repeat: no-repeat; + background-position: center; + background-size: 25%; +} + +button:focus, +button:active, +button:hover { + /* 20% Overlay 2, 80% mantle */ + background-color: rgb(48, 50, 66); + outline-style: none; +} + +#lock { + background-image: image(url('./icons/lock.svg')); + border-radius: 32px 0 0 0; +} + +#logout { + background-image: image(url('./icons/logout.svg')); +} + +#suspend { + background-image: image(url('./icons/suspend.svg')); + border-radius: 0 32px 0 0; +} + +#hibernate { + background-image: image(url('./icons/hibernate.svg')); + border-radius: 0 0 0 32px; +} + +#shutdown { + background-image: image(url('./icons/shutdown.svg')); +} + +#reboot { + background-image: image(url('./icons/reboot.svg')); + border-radius: 0 0 32px 0; +} diff --git a/yazi/bookmark b/yazi/bookmark new file mode 100755 index 0000000..e69de29 diff --git a/yazi/flavors/onedark.yazi/LICENSE b/yazi/flavors/onedark.yazi/LICENSE new file mode 100644 index 0000000..9a5124e --- /dev/null +++ b/yazi/flavors/onedark.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 - sxyazi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/flavors/onedark.yazi/LICENSE-tmtheme b/yazi/flavors/onedark.yazi/LICENSE-tmtheme new file mode 100644 index 0000000..44b4479 --- /dev/null +++ b/yazi/flavors/onedark.yazi/LICENSE-tmtheme @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Himanshu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/flavors/onedark.yazi/README.md b/yazi/flavors/onedark.yazi/README.md new file mode 100644 index 0000000..fe078d7 --- /dev/null +++ b/yazi/flavors/onedark.yazi/README.md @@ -0,0 +1,37 @@ +
+ Yazi logo +
+ +

+ Onedark Flavor for Yazi +

+ +## 👀 Preview + + + +## 🎨 Installation + +```bash +# Linux/macOS +git clone https://github.com/BennyOe/onedark.yazi.git ~/.config/yazi/flavors/onedark.yazi + +# Windows +git clone https://github.com/BennyOe/onedark.yazi.git %AppData%\yazi\config\flavors\onedark.yazi +``` + +## ⚙️ Usage + +Add the these lines to your `theme.toml` configuration file to use it: + + +```toml +[flavor] +dark = "onedark" +``` + +## 📜 License + +The flavor is MIT-licensed, and the included tmTheme is also MIT-licensed. + +Check the [LICENSE](LICENSE) and [LICENSE-tmtheme](LICENSE-tmtheme) file for more details. diff --git a/yazi/flavors/onedark.yazi/flavor.toml b/yazi/flavors/onedark.yazi/flavor.toml new file mode 100644 index 0000000..8bd1615 --- /dev/null +++ b/yazi/flavors/onedark.yazi/flavor.toml @@ -0,0 +1,151 @@ +# : Manager {{{ +[manager] +cwd = { fg = "#61AFEF" } # Blue + +# Hovered +hovered = { bg = "#282C34" } # Darkened background +preview_hovered = { underline = true } + +# Find +find_keyword = { fg = "#E06C75", italic = true, underline = true } # Red +find_position = { fg = "#E5C07B", italic = true } # Orange + +# Marker +marker_copied = { fg = "#ABB2BF", bg = "#98C379" } # Light gray on Green +marker_cut = { fg = "#ABB2BF", bg = "#E06C75" } # Light gray on Red +marker_marked = { fg = "#ABB2BF", bg = "#56B6C2" } # Light gray on cyan +marker_selected = { fg = "#ABB2BF", bg = "#E5C07B" } # Light gray on Orange + +# Tab +tab_active = { bg = "#282C34", fg = "#61AFEF" } # Darkened background, Blue text +tab_inactive = {} +tab_width = 1 + +# Count +count_copied = { fg = "#98C379", bg = "#282C34" } # Green on Darkened background +count_cut = { fg = "#E06C75", bg = "#282C34" } # Red on Darkened background +count_selected = { fg = "#98C379", bg = "#282C34" } # Green on Darkened background + +# Border +border_symbol = "│" +border_style = { fg = "#282C34" } # Darkened background + +# : }}} + +# : Status {{{ +[status] +separator_open = "" +separator_close = "" +separator_style = { fg = "#61AFEF", bg = "#282C34" } # Blue on Darkened background + +# Mode +mode_normal = { fg = "#282C34", bg = "#61AFEF", bold = true } # Dark gray on Blue +mode_select = { fg = "#282C34", bg = "#61AFEF", bold = true } # Dark gray on Blue +mode_unset = { fg = "#282C34", bg = "#61AFEF", bold = true } # Dark gray on Blue + +# Progress +progress_label = { fg = "#ABB2BF", bold = true } # Light gray +progress_normal = { fg = "#98C379", bg = "#282C34" } # Green on Darkened background +progress_error = { fg = "#E06C75", bg = "#282C34" } # Red on Darkened background + +# Permissions +permissions_t = { fg = "#98C379" } # Green +permissions_r = { fg = "#E06C75" } # Red +permissions_w = { fg = "#E5C07B" } # Orange +permissions_x = { fg = "#98C379" } # Green +permissions_s = { fg = "#ABB2BF" } # Light gray + +# : }}} + +# : Select {{{ +[select] +border = { fg = "#98C379" } # Green +active = { fg = "#E5C07B", bold = true } # Orange +inactive = {} + +# : }}} + +# : Input {{{ +[input] +border = { fg = "#98C379" } # Green +title = {} +value = {} +selected = { reversed = true } + +# : }}} + +# : Completion {{{ +[completion] +border = { fg = "#98C379" } # Green + +# : }}} + +# : Tasks {{{ +[tasks] +border = { fg = "#98C379" } # Green +title = {} +hovered = { fg = "#E5C07B", underline = true } # Orange + +# : }}} + +# : Which {{{ +[which] +mask = { bg = "#282C34" } # Darkened background +cand = { fg = "#98C379" } # Green +rest = { fg = "#ABB2BF" } # Light gray +desc = { fg = "#E5C07B" } # Orange +separator = "  " +separator_style = { fg = "#ABB2BF" } # Light gray + +# : }}} + +# : Help {{{ +[help] +on = { fg = "#98C379" } # Green +run = { fg = "#E5C07B" } # Orange +hovered = { reversed = true, bold = true } +footer = { fg = "#ABB2BF", bg = "#000000" } # Light gray on Black + +# : }}} + +# : Notify {{{ +[notify] +title_info = { fg = "#98C379" } # Green +title_warn = { fg = "#E06C75" } # Red +title_error = { fg = "#E5C07B" } # Orange + +# : }}} + +# : File-specific styles {{{ + +[filetype] + +rules = [ + # Images + { mime = "image/*", fg = "#E5C07B" }, # Orange + + # Media + { mime = "video/*", fg = "#E06C75" }, # Red + { mime = "audio/*", fg = "#E06C75" }, # Red + + # Archives + { mime = "application/zip", fg = "#C678DD" }, # Magenta + { mime = "application/x-tar", fg = "#C678DD" }, # Magenta + { mime = "application/x-bzip*", fg = "#C678DD" }, # Magenta + { mime = "application/x-bzip2", fg = "#C678DD" }, # Magenta + { mime = "application/x-7z-compressed", fg = "#C678DD" }, # Magenta + { mime = "application/x-rar", fg = "#C678DD" }, # Magenta + { mime = "application/x-xz", fg = "#C678DD" }, # Magenta + + # Documents + { mime = "application/doc", fg = "#98C379" }, # Green + { mime = "application/pdf", fg = "#98C379" }, # Green + { mime = "application/rtf", fg = "#98C379" }, # Green + { mime = "application/vnd.*", fg = "#98C379" }, # Green + + # Fallback + { name = "*", fg = "#ABB2BF" }, # Blue + { name = "*/", fg = "#61AFEF" } # Blue +] + +# : }}} diff --git a/yazi/flavors/onedark.yazi/preview.png b/yazi/flavors/onedark.yazi/preview.png new file mode 100644 index 0000000..61c9d70 Binary files /dev/null and b/yazi/flavors/onedark.yazi/preview.png differ diff --git a/yazi/flavors/onedark.yazi/tmtheme.xml b/yazi/flavors/onedark.yazi/tmtheme.xml new file mode 100644 index 0000000..3214d2a --- /dev/null +++ b/yazi/flavors/onedark.yazi/tmtheme.xml @@ -0,0 +1,560 @@ + + + + + author + Template: Chris Kempson, Scheme: Lalit Magant (http://github.com/tilal6991) + name + Base16 OneDark + semanticClass + theme.base16.onedark + colorSpaceName + sRGB + gutterSettings + + background + #353b45 + divider + #353b45 + foreground + #545862 + selectionBackground + #3e4451 + selectionForeground + #565c64 + + settings + + + settings + + background + #282c34 + caret + #abb2bf + foreground + #abb2bf + invisibles + #545862 + lineHighlight + #54586255 + selection + #3e4451 + + + + name + Text + scope + variable.parameter.function + settings + + foreground + #abb2bf + + + + name + Comments + scope + comment, punctuation.definition.comment + settings + + foreground + #545862 + + + + name + Punctuation + scope + punctuation.definition.string, punctuation.definition.variable, punctuation.definition.string, punctuation.definition.parameters, punctuation.definition.string, punctuation.definition.array + settings + + foreground + #abb2bf + + + + name + Delimiters + scope + none + settings + + foreground + #abb2bf + + + + name + Operators + scope + keyword.operator + settings + + foreground + #abb2bf + + + + name + Keywords + scope + keyword + settings + + foreground + #c678dd + + + + name + Variables + scope + variable + settings + + foreground + #e06c75 + + + + name + Functions + scope + entity.name.function, meta.require, support.function.any-method, variable.function, variable.annotation, support.macro + settings + + foreground + #61afef + + + + name + Labels + scope + entity.name.label + settings + + foreground + #be5046 + + + + name + Classes + scope + support.class, entity.name.class, entity.name.type.class + settings + + foreground + #e5c07b + + + + name + Classes + scope + meta.class + settings + + foreground + #c8ccd4 + + + + name + Methods + scope + keyword.other.special-method + settings + + foreground + #61afef + + + + name + Storage + scope + storage + settings + + foreground + #c678dd + + + + name + Support + scope + support.function + settings + + foreground + #56b6c2 + + + + name + Strings, Inherited Class + scope + string, constant.other.symbol, entity.other.inherited-class + settings + + foreground + #98c379 + + + + name + Integers + scope + constant.numeric + settings + + foreground + #d19a66 + + + + name + Floats + scope + none + settings + + foreground + #d19a66 + + + + name + Boolean + scope + none + settings + + foreground + #d19a66 + + + + name + Constants + scope + constant + settings + + foreground + #d19a66 + + + + name + Tags + scope + entity.name.tag + settings + + foreground + #e06c75 + + + + name + Attributes + scope + entity.other.attribute-name + settings + + foreground + #d19a66 + + + + name + Attribute IDs + scope + entity.other.attribute-name.id, punctuation.definition.entity + settings + + foreground + #61afef + + + + name + Selector + scope + meta.selector + settings + + foreground + #c678dd + + + + name + Values + scope + none + settings + + foreground + #d19a66 + + + + name + Headings + scope + markup.heading punctuation.definition.heading, entity.name.section + settings + + fontStyle + + foreground + #61afef + + + + name + Units + scope + keyword.other.unit + settings + + foreground + #d19a66 + + + + name + Bold + scope + markup.bold, punctuation.definition.bold + settings + + fontStyle + bold + foreground + #e5c07b + + + + name + Italic + scope + markup.italic, punctuation.definition.italic + settings + + fontStyle + italic + foreground + #c678dd + + + + name + Code + scope + markup.raw.inline + settings + + foreground + #98c379 + + + + name + Link Text + scope + string.other.link, punctuation.definition.string.end.markdown, punctuation.definition.string.begin.markdown + settings + + foreground + #e06c75 + + + + name + Link Url + scope + meta.link + settings + + foreground + #d19a66 + + + + name + Lists + scope + markup.list + settings + + foreground + #e06c75 + + + + name + Quotes + scope + markup.quote + settings + + foreground + #d19a66 + + + + name + Separator + scope + meta.separator + settings + + background + #3e4451 + foreground + #abb2bf + + + + name + Inserted + scope + markup.inserted + settings + + foreground + #98c379 + + + + name + Deleted + scope + markup.deleted + settings + + foreground + #e06c75 + + + + name + Changed + scope + markup.changed + settings + + foreground + #c678dd + + + + name + Colors + scope + constant.other.color + settings + + foreground + #56b6c2 + + + + name + Regular Expressions + scope + string.regexp + settings + + foreground + #56b6c2 + + + + name + Escape Characters + scope + constant.character.escape + settings + + foreground + #56b6c2 + + + + name + Embedded + scope + punctuation.section.embedded, variable.interpolation + settings + + foreground + #c678dd + + + + name + Illegal + scope + invalid.illegal + settings + + background + #e06c75 + foreground + #c8ccd4 + + + + name + Broken + scope + invalid.broken + settings + + background + #d19a66 + foreground + #282c34 + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #be5046 + foreground + #c8ccd4 + + + + name + Unimplemented + scope + invalid.unimplemented + settings + + background + #545862 + foreground + #c8ccd4 + + + + uuid + uuid + + diff --git a/yazi/init.lua b/yazi/init.lua new file mode 100755 index 0000000..14a7171 --- /dev/null +++ b/yazi/init.lua @@ -0,0 +1,29 @@ +require("yaziline"):setup({ + separator_style = "angly", + select_symbol = "", + yank_symbol = "󰆐", + filename_max_length = 24, -- trim when filename > 24 + filename_trim_length = 6, -- trim 6 chars from both ends +}) +-- require("starship"):setup { +-- config_file = "~/.config/yazi/starship.toml", +-- } +require("git"):setup({}) + +Status:children_add(function() + local h = cx.active.current.hovered + if h == nil or ya.target_family() ~= "unix" then + return ui.Line({}) + end + + return ui.Line({ + ui.Span(ya.user_name(h.cha.uid) or tostring(h.cha.uid)):fg("magenta"), + ui.Span(":"), + ui.Span(ya.group_name(h.cha.gid) or tostring(h.cha.gid)):fg("magenta"), + ui.Span(" "), + }) +end, 500, Status.RIGHT) + +require("yamb"):setup({ + cli = "fzf", +}) diff --git a/yazi/keymap.toml b/yazi/keymap.toml new file mode 100755 index 0000000..bb73f6d --- /dev/null +++ b/yazi/keymap.toml @@ -0,0 +1,355 @@ +# A TOML linter such as https://taplo.tamasfe.dev/ can use this schema to validate your config0 +# If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. +"$schema" = "https://yazi-rs.github.io/schemas/keymap.json" + +[mgr] +prepend_keymap = [ + { on = "l", run = 'plugin smart-enter' }, + { on = "", run = 'plugin smart-enter' }, + { on = "S", run = 'shell "$SHELL" --block --confirm' }, + { on = [ + "'", + "a", + ], run = "plugin yamb save", desc = "Add bookmark" }, + { on = [ + "'", + "'", + ], run = "plugin yamb jump_by_fzf", desc = "Jump bookmark by fzf" }, + { on = [ + "'", + "r", + ], run = "plugin yamb delete_by_key", desc = "Delete bookmark by key" }, + { on = [ + "P", + ], run = "spot", desc = "Open spotter" }, + { on = [ + "c", + "a", + ], run = "plugin compress", desc = "Archive selected files" }, +] + +keymap = [ + { on = "", run = "escape", desc = "Exit visual mode, clear selected, or cancel search" }, + { on = "", run = "escape", desc = "Exit visual mode, clear selected, or cancel search" }, + #{ on = "q", run = "quit", desc = "Exit the process" }, + { on = "q", run = "close", desc = "Close the current tab, or quit if it is last tab" }, + { on = "Q", run = "quit --no-cwd-file", desc = "Exit the process without writing cwd-file" }, + { on = "", run = "suspend", desc = "Suspend the process" }, + + { on = "R", run = "reload", desc = "Refresh the current directory" }, + + # Hopping + { on = "k", run = "arrow -1", desc = "Move cursor up" }, + { on = "j", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -50%", desc = "Move cursor up half page" }, + { on = "", run = "arrow 50%", desc = "Move cursor down half page" }, + + { on = "K", run = "arrow -5", desc = "Move cursor up 5 rows" }, + { on = "J", run = "arrow 5", desc = "Move cursor down 5 rows" }, + + { on = "", run = "arrow -50%", desc = "Move cursor up half page" }, + { on = "", run = "arrow 50%", desc = "Move cursor down half page" }, + { on = "", run = "arrow -100%", desc = "Move cursor up one page" }, + { on = "", run = "arrow 100%", desc = "Move cursor down one page" }, + + { on = ["g", "g"], run = "arrow bot", desc = "Move cursor to the top" }, + { on = "G", run = "arrow top", desc = "Move cursor to the bottom" }, + + # Navigation + { on = "h", run = "leave", desc = "Go back to the parent directory" }, + + { on = "", run = "leave", desc = "Go back to the parent directory" }, + { on = "", run = "enter", desc = "Enter the child directory" }, + + { on = "N", run = "back", desc = "Go back to the previous directory" }, + { on = "I", run = "forward", desc = "Go forward to the next directory" }, + + # Selection + { on = "", run = ["toggle", "arrow 1"], desc = "Toggle the current selection state" }, + { on = "v", run = "toggle_all", desc = "Enter visual mode (selection mode)" }, + { on = "V", run = "visual_mode --unset", desc = "Enter visual mode (unset mode)" }, + # { on = "", run = "select_all --state=true", desc = "Select all files" }, + # { on = "", run = "select_all --state=none", desc = "Inverse selection of all files" }, + + # Find + { on = "", run = "plugin fzf", desc = "Jump to a directory or reveal a file using fzf" }, + { on = ["z", "o"], run = "plugin zoxide", desc = "Jump to a directory using zoxide" }, + # { on = "f", run = "search fd", desc = "Search files by name using fd" }, + { on = "F", run = "search rg", desc = "Search files by content using ripgrep" }, + { on = "", run = "escape --search", desc = "Cancel the ongoing search" }, + { on = "f", run = "filter --smart", desc = "Filter files" }, + { on = "/", run = "find --smart", desc = "Find next file" }, + { on = "?", run = "find --previous --smart", desc = "Find previous file" }, + { on = "n", run = "find_arrow", desc = "Go to the next found" }, + { on = "N", run = "find_arrow --previous", desc = "Go to the previous found" }, + + # Shell + { on = "", run = "shell --confirm --block lazygit", desc = "Lazygit" }, + { on = ";", run = "shell --interactive", desc = "Run a shell command" }, + { on = ":", run = "shell --block --interactive", desc = "Run a shell command (block until finishes)" }, + + # Hidden files + { on = ".", run = "hidden toggle", desc = "Toggle the visibility of hidden files" }, + + # Open + { on = "r", run = "open --interactive", desc = "Open selected files interactively" }, + + # Create + { on = "T", run = "create", desc = "Create a file (ends with / for directories)" }, + { on = "M", run = "create --dir", desc = "Create a directory" }, + + # Rename + { on = ["c", "w"], run = "rename --empty=all", desc = "Rename selected file(s)" }, + { on = "k", run = "rename --cursor=start", desc = "Rename selected file(s)" }, + { on = "a", run = "rename --cursor=before_ext", desc = "Rename selected file(s)" }, + { on = "A", run = "rename --cursor=end", desc = "Rename selected file(s)" }, + + # Operation: D + { on = ["d", "d"], run = "yank --cut", desc = "Yank selected files (cut)" }, + # { on = ["d"], run = "remove", desc = "Trash selected files" }, + { on = ["d", "D"], run = "remove --permanently", desc = "Permanently delete selected files" }, + + # Operation: Y + { on = ["y", "y"], run = "yank", desc = "Yank selected files (copy)" }, + { on = ["y", "p"], run = "copy path", desc = "Copy the file path" }, + { on = ["y", "d"], run = "copy dirname", desc = "Copy the directory path" }, + { on = ["y", "f"], run = "copy filename", desc = "Copy the filename" }, + { on = ["y", "n"], run = "copy name_without_ext", desc = "Copy the filename without extension" }, + { on = ["y", "c"], run = "unyank", desc = "Cancel the yank status" }, + + # Operation: P + { on = ["p", "p"], run = "paste", desc = "Paste yanked files" }, + { on = ["p", "P"], run = "paste --force", desc = "Paste yanked files (overwrite if the destination exists)" }, + { on = ["p", "l"], run = "link", desc = "Symlink the absolute path of yanked files" }, + { on = ["p", "L"], run = "link --relative", desc = "Symlink the relative path of yanked files" }, + { on = ["p", "h"], run = "hardlink", desc = "Hardlink yanked files" }, + + # Linemode + { on = ["m", "s"], run = "linemode size", desc = "Set linemode to size" }, + { on = ["m", "p"], run = "linemode perm", desc = "Set linemode to permissions" }, + { on = ["m", "c"], run = "linemode btime", desc = "Set linemode to btime" }, + { on = ["m", "m"], run = "linemode mtime", desc = "Set linemode to mtime" }, + { on = ["m", "o"], run = "linemode owner", desc = "Set linemode to owner" }, + { on = ["m", "n"], run = "linemode none", desc = "Set linemode to none" }, + + + # Sorting + { on = ["o", "M"], run = ["sort mtime --reverse=no", "linemode mtime"], desc = "Sort by modified time" }, + { on = ["o", "m"], run = ["sort mtime --reverse", "linemode mtime"], desc = "Sort by modified time (reverse)" }, + { on = ["o", "C"], run = ["sort btime --reverse=no", "linemode btime"], desc = "Sort by created time" }, + { on = ["o", "c"], run = ["sort btime --reverse", "linemode btime"], desc = "Sort by created time (reverse)" }, + { on = ["o", "E"], run = "sort extension --reverse=no", desc = "Sort by extension" }, + { on = ["o", "e"], run = "sort extension --reverse", desc = "Sort by extension (reverse)" }, + { on = ["o", "a"], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" }, + { on = ["o", "A"], run = "sort alphabetical --reverse", desc = "Sort alphabetically (reverse)" }, + { on = ["o", "n"], run = "sort natural --reverse=no", desc = "Sort naturally" }, + { on = ["o", "N"], run = "sort natural --reverse", desc = "Sort naturally (reverse)" }, + { on = ["o", "s"], run = ["sort size --reverse=no", "linemode size"], desc = "Sort by size" }, + { on = ["o", "S"], run = ["sort size --reverse", "linemode size"], desc = "Sort by size (reverse)" }, + + # Goto + { on = ["g", "r"], run = "cd /", desc = "Go to the root directory" }, + { on = ["g", "h"], run = "cd ~", desc = "Go to the home directory" }, + { on = ["g", "c"], run = "cd ~/.config", desc = "Go to the config directory" }, + { on = ["g", "d"], run = "cd ~/Downloads", desc = "Go to the downloads directory" }, + { on = ["g", "D"], run = "cd ~/Desktop", desc = "Go to the desktop directory" }, + { on = ["g", "i"], run = "cd ~/Github", desc = "Go to the Github directory" }, + { on = ["g", "f", "f"], run = "cd ~/.config" }, + { on = ["g", "f", "n"], run = "cd ~/.config/nvim" }, + { on = ["g", "f", "y"], run = "cd ~/.config/yazi" }, + { on = ["g", "f", "l"], run = "cd ~/.config/jesseduffield/lazygit" }, + { on = ["g", ""], run = "cd --interactive", desc = "Go to a directory interactively" }, + + # Tabs + { on = ["t", "u"], run = "tab_create --current", desc = "Create a new tab with CWD" }, + { on = ["t", "n"], run = "tab_switch -1 --relative", desc = "Switch to the previous tab" }, + { on = ["t", "i"], run = "tab_switch 1 --relative", desc = "Switch to the next tab" }, + #{ on = ["t", ""], run = "tab_swap -1", desc = "Swap current tab with previous tab" }, + #{ on = ["}"], run = "tab_swap 1", desc = "Swap current tab with next tab" }, + { on = "1", run = "tab_switch 0", desc = "Switch to the first tab" }, + { on = "2", run = "tab_switch 1", desc = "Switch to the second tab" }, + { on = "3", run = "tab_switch 2", desc = "Switch to the third tab" }, + { on = "4", run = "tab_switch 3", desc = "Switch to the fourth tab" }, + { on = "5", run = "tab_switch 4", desc = "Switch to the fifth tab" }, + { on = "6", run = "tab_switch 5", desc = "Switch to the sixth tab" }, + { on = "7", run = "tab_switch 6", desc = "Switch to the seventh tab" }, + { on = "8", run = "tab_switch 7", desc = "Switch to the eighth tab" }, + { on = "9", run = "tab_switch 8", desc = "Switch to the ninth tab" }, + + # Tasks + { on = "w", run = "tasks_show", desc = "Show task manager" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[spot] +keymap = [ + # Navigation + { on = "u", run = "arrow -1", desc = "Move up" }, + { on = "e", run = "arrow 1", desc = "Move down" }, + + # Close + { on = "", run = "close", desc = "Close spotter" }, + { on = "q", run = "close", desc = "Close spotter" }, + + # Swipe through files + { on = "", run = "swipe -5", desc = "Swipe 5 files up" }, + { on = "", run = "swipe 5", desc = "Swipe 5 files down" }, + + # Copy content + { on = "y", run = "copy cell", desc = "Copy cell content" }, +] + +[tasks] + +keymap = [ + { on = "", run = "close", desc = "Close task manager" }, + { on = "", run = "close", desc = "Close task manager" }, + { on = "", run = "close", desc = "Close task manager" }, + { on = "w", run = "close", desc = "Close task manager" }, + + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "inspect", desc = "Inspect the task" }, + { on = "x", run = "cancel", desc = "Cancel the task" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[pick] + +keymap = [ + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close --submit", desc = "Submit the selection" }, + + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[input] + +keymap = [ + { on = "", run = "close", desc = "Cancel input" }, + { on = "", run = "close --submit", desc = "Submit the input" }, + { on = "", run = "escape", desc = "Go back the normal mode, or cancel input" }, + { on = "", run = "escape", desc = "Go back the normal mode, or cancel input" }, + + # Mode + { on = "k", run = "insert", desc = "Enter insert mode" }, + { on = "a", run = "insert --append", desc = "Enter append mode" }, + { on = "K", run = ["move -999", "insert"], desc = "Move to the BOL, and enter insert mode" }, + { on = "A", run = ["move 999", "insert --append"], desc = "Move to the EOL, and enter append mode" }, + { on = "v", run = "visual", desc = "Enter visual mode" }, + { on = "V", run = ["move -999", "visual", "move 999"], desc = "Enter visual mode and select all" }, + + # Character-wise movement + { on = "n", run = "move -1", desc = "Move back a character" }, + { on = "i", run = "move 1", desc = "Move forward a character" }, + { on = "", run = "move -1", desc = "Move back a character" }, + { on = "", run = "move 1", desc = "Move forward a character" }, + { on = "", run = "move -1", desc = "Move back a character" }, + { on = "", run = "move 1", desc = "Move forward a character" }, + + # Word-wise movement + { on = "b", run = "backward", desc = "Move back to the start of the current or previous word" }, + { on = "w", run = "forward", desc = "Move forward to the start of the next word" }, + { on = "h", run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" }, + { on = "", run = "backward", desc = "Move back to the start of the current or previous word" }, + { on = "", run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" }, + + # Line-wise movement + { on = "N", run = "move -999", desc = "Move to the BOL" }, + { on = "I", run = "move 999", desc = "Move to the EOL" }, + { on = "", run = "move -999", desc = "Move to the BOL" }, + { on = "", run = "move 999", desc = "Move to the EOL" }, + { on = "", run = "move -999", desc = "Move to the BOL" }, + { on = "", run = "move 999", desc = "Move to the EOL" }, + + # Delete + { on = "", run = "backspace", desc = "Delete the character before the cursor" }, + { on = "", run = "backspace --under", desc = "Delete the character under the cursor" }, + { on = "", run = "backspace", desc = "Delete the character before the cursor" }, + { on = "", run = "backspace --under", desc = "Delete the character under the cursor" }, + + # Kill + { on = "", run = "kill bol", desc = "Kill backwards to the BOL" }, + { on = "", run = "kill eol", desc = "Kill forwards to the EOL" }, + { on = "", run = "kill backward", desc = "Kill backwards to the start of the current word" }, + { on = "", run = "kill forward", desc = "Kill forwards to the end of the current word" }, + + # Cut/Yank/Paste + { on = "d", run = "delete --cut", desc = "Cut the selected characters" }, + { on = "D", run = ["delete --cut", "move 999"], desc = "Cut until the EOL" }, + { on = "c", run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" }, + { on = "C", run = ["delete --cut --insert", "move 999"], desc = "Cut until the EOL, and enter insert mode" }, + { on = "x", run = ["delete --cut", "move 1 --in-operating"], desc = "Cut the current character" }, + { on = "y", run = "yank", desc = "Copy the selected characters" }, + { on = "p", run = "paste", desc = "Paste the copied characters after the cursor" }, + { on = "P", run = "paste --before", desc = "Paste the copied characters before the cursor" }, + + # Undo/Redo + { on = "l", run = "undo", desc = "Undo the last operation" }, + { on = "", run = "redo", desc = "Redo the last operation" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[completion] + +keymap = [ + { on = "", run = "close", desc = "Cancel completion" }, + { on = "", run = "close --submit", desc = "Submit the completion" }, + { on = "", run = ["close --submit", "close_input --submit"], desc = "Submit the completion and input" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[help] + +keymap = [ + { on = "", run = "escape", desc = "Clear the filter, or hide the help" }, + { on = "", run = "escape", desc = "Clear the filter, or hide the help" }, + { on = "q", run = "close", desc = "Exit the process" }, + { on = "", run = "close", desc = "Hide the help" }, + + # Navigation + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Filtering + { on = "f", run = "filter", desc = "Apply a filter for the help items" }, +] diff --git a/yazi/keymap.toml-1748477627476447 b/yazi/keymap.toml-1748477627476447 new file mode 100755 index 0000000..4788e84 --- /dev/null +++ b/yazi/keymap.toml-1748477627476447 @@ -0,0 +1,355 @@ +# A TOML linter such as https://taplo.tamasfe.dev/ can use this schema to validate your config0 +# If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. +"$schema" = "https://yazi-rs.github.io/schemas/keymap.json" + +[manager] +prepend_keymap = [ + { on = "l", run = 'plugin smart-enter' }, + { on = "", run = 'plugin smart-enter' }, + { on = "S", run = 'shell "$SHELL" --block --confirm' }, + { on = [ + "'", + "a", + ], run = "plugin yamb save", desc = "Add bookmark" }, + { on = [ + "'", + "'", + ], run = "plugin yamb jump_by_fzf", desc = "Jump bookmark by fzf" }, + { on = [ + "'", + "r", + ], run = "plugin yamb delete_by_key", desc = "Delete bookmark by key" }, + { on = [ + "P", + ], run = "spot", desc = "Open spotter" }, + { on = [ + "c", + "a", + ], run = "plugin compress", desc = "Archive selected files" }, +] + +keymap = [ + { on = "", run = "escape", desc = "Exit visual mode, clear selected, or cancel search" }, + { on = "", run = "escape", desc = "Exit visual mode, clear selected, or cancel search" }, + #{ on = "q", run = "quit", desc = "Exit the process" }, + { on = "q", run = "close", desc = "Close the current tab, or quit if it is last tab" }, + { on = "Q", run = "quit --no-cwd-file", desc = "Exit the process without writing cwd-file" }, + { on = "", run = "suspend", desc = "Suspend the process" }, + + { on = "R", run = "reload", desc = "Refresh the current directory" }, + + # Hopping + { on = "k", run = "arrow -1", desc = "Move cursor up" }, + { on = "j", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -50%", desc = "Move cursor up half page" }, + { on = "", run = "arrow 50%", desc = "Move cursor down half page" }, + + { on = "K", run = "arrow -5", desc = "Move cursor up 5 rows" }, + { on = "J", run = "arrow 5", desc = "Move cursor down 5 rows" }, + + { on = "", run = "arrow -50%", desc = "Move cursor up half page" }, + { on = "", run = "arrow 50%", desc = "Move cursor down half page" }, + { on = "", run = "arrow -100%", desc = "Move cursor up one page" }, + { on = "", run = "arrow 100%", desc = "Move cursor down one page" }, + + { on = ["g", "g"], run = "arrow bot", desc = "Move cursor to the top" }, + { on = "G", run = "arrow top", desc = "Move cursor to the bottom" }, + + # Navigation + { on = "h", run = "leave", desc = "Go back to the parent directory" }, + + { on = "", run = "leave", desc = "Go back to the parent directory" }, + { on = "", run = "enter", desc = "Enter the child directory" }, + + { on = "N", run = "back", desc = "Go back to the previous directory" }, + { on = "I", run = "forward", desc = "Go forward to the next directory" }, + + # Selection + { on = "", run = ["toggle", "arrow 1"], desc = "Toggle the current selection state" }, + { on = "v", run = "toggle_all", desc = "Enter visual mode (selection mode)" }, + { on = "V", run = "visual_mode --unset", desc = "Enter visual mode (unset mode)" }, + # { on = "", run = "select_all --state=true", desc = "Select all files" }, + # { on = "", run = "select_all --state=none", desc = "Inverse selection of all files" }, + + # Find + { on = "", run = "plugin fzf", desc = "Jump to a directory or reveal a file using fzf" }, + { on = ["z", "o"], run = "plugin zoxide", desc = "Jump to a directory using zoxide" }, + # { on = "f", run = "search fd", desc = "Search files by name using fd" }, + { on = "F", run = "search rg", desc = "Search files by content using ripgrep" }, + { on = "", run = "escape --search", desc = "Cancel the ongoing search" }, + { on = "f", run = "filter --smart", desc = "Filter files" }, + { on = "/", run = "find --smart", desc = "Find next file" }, + { on = "?", run = "find --previous --smart", desc = "Find previous file" }, + { on = "n", run = "find_arrow", desc = "Go to the next found" }, + { on = "N", run = "find_arrow --previous", desc = "Go to the previous found" }, + + # Shell + { on = "", run = "shell --confirm --block lazygit", desc = "Lazygit" }, + { on = ";", run = "shell --interactive", desc = "Run a shell command" }, + { on = ":", run = "shell --block --interactive", desc = "Run a shell command (block until finishes)" }, + + # Hidden files + { on = ".", run = "hidden toggle", desc = "Toggle the visibility of hidden files" }, + + # Open + { on = "r", run = "open --interactive", desc = "Open selected files interactively" }, + + # Create + { on = "T", run = "create", desc = "Create a file (ends with / for directories)" }, + { on = "M", run = "create --dir", desc = "Create a directory" }, + + # Rename + { on = ["c", "w"], run = "rename --empty=all", desc = "Rename selected file(s)" }, + { on = "k", run = "rename --cursor=start", desc = "Rename selected file(s)" }, + { on = "a", run = "rename --cursor=before_ext", desc = "Rename selected file(s)" }, + { on = "A", run = "rename --cursor=end", desc = "Rename selected file(s)" }, + + # Operation: D + { on = ["d", "d"], run = "yank --cut", desc = "Yank selected files (cut)" }, + # { on = ["d"], run = "remove", desc = "Trash selected files" }, + { on = ["d", "D"], run = "remove --permanently", desc = "Permanently delete selected files" }, + + # Operation: Y + { on = ["y", "y"], run = "yank", desc = "Yank selected files (copy)" }, + { on = ["y", "p"], run = "copy path", desc = "Copy the file path" }, + { on = ["y", "d"], run = "copy dirname", desc = "Copy the directory path" }, + { on = ["y", "f"], run = "copy filename", desc = "Copy the filename" }, + { on = ["y", "n"], run = "copy name_without_ext", desc = "Copy the filename without extension" }, + { on = ["y", "c"], run = "unyank", desc = "Cancel the yank status" }, + + # Operation: P + { on = ["p", "p"], run = "paste", desc = "Paste yanked files" }, + { on = ["p", "P"], run = "paste --force", desc = "Paste yanked files (overwrite if the destination exists)" }, + { on = ["p", "l"], run = "link", desc = "Symlink the absolute path of yanked files" }, + { on = ["p", "L"], run = "link --relative", desc = "Symlink the relative path of yanked files" }, + { on = ["p", "h"], run = "hardlink", desc = "Hardlink yanked files" }, + + # Linemode + { on = ["m", "s"], run = "linemode size", desc = "Set linemode to size" }, + { on = ["m", "p"], run = "linemode perm", desc = "Set linemode to permissions" }, + { on = ["m", "c"], run = "linemode btime", desc = "Set linemode to btime" }, + { on = ["m", "m"], run = "linemode mtime", desc = "Set linemode to mtime" }, + { on = ["m", "o"], run = "linemode owner", desc = "Set linemode to owner" }, + { on = ["m", "n"], run = "linemode none", desc = "Set linemode to none" }, + + + # Sorting + { on = ["o", "M"], run = ["sort mtime --reverse=no", "linemode mtime"], desc = "Sort by modified time" }, + { on = ["o", "m"], run = ["sort mtime --reverse", "linemode mtime"], desc = "Sort by modified time (reverse)" }, + { on = ["o", "C"], run = ["sort btime --reverse=no", "linemode btime"], desc = "Sort by created time" }, + { on = ["o", "c"], run = ["sort btime --reverse", "linemode btime"], desc = "Sort by created time (reverse)" }, + { on = ["o", "E"], run = "sort extension --reverse=no", desc = "Sort by extension" }, + { on = ["o", "e"], run = "sort extension --reverse", desc = "Sort by extension (reverse)" }, + { on = ["o", "a"], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" }, + { on = ["o", "A"], run = "sort alphabetical --reverse", desc = "Sort alphabetically (reverse)" }, + { on = ["o", "n"], run = "sort natural --reverse=no", desc = "Sort naturally" }, + { on = ["o", "N"], run = "sort natural --reverse", desc = "Sort naturally (reverse)" }, + { on = ["o", "s"], run = ["sort size --reverse=no", "linemode size"], desc = "Sort by size" }, + { on = ["o", "S"], run = ["sort size --reverse", "linemode size"], desc = "Sort by size (reverse)" }, + + # Goto + { on = ["g", "r"], run = "cd /", desc = "Go to the root directory" }, + { on = ["g", "h"], run = "cd ~", desc = "Go to the home directory" }, + { on = ["g", "c"], run = "cd ~/.config", desc = "Go to the config directory" }, + { on = ["g", "d"], run = "cd ~/Downloads", desc = "Go to the downloads directory" }, + { on = ["g", "D"], run = "cd ~/Desktop", desc = "Go to the desktop directory" }, + { on = ["g", "i"], run = "cd ~/Github", desc = "Go to the Github directory" }, + { on = ["g", "f", "f"], run = "cd ~/.config" }, + { on = ["g", "f", "n"], run = "cd ~/.config/nvim" }, + { on = ["g", "f", "y"], run = "cd ~/.config/yazi" }, + { on = ["g", "f", "l"], run = "cd ~/.config/jesseduffield/lazygit" }, + { on = ["g", ""], run = "cd --interactive", desc = "Go to a directory interactively" }, + + # Tabs + { on = ["t", "u"], run = "tab_create --current", desc = "Create a new tab with CWD" }, + { on = ["t", "n"], run = "tab_switch -1 --relative", desc = "Switch to the previous tab" }, + { on = ["t", "i"], run = "tab_switch 1 --relative", desc = "Switch to the next tab" }, + #{ on = ["t", ""], run = "tab_swap -1", desc = "Swap current tab with previous tab" }, + #{ on = ["}"], run = "tab_swap 1", desc = "Swap current tab with next tab" }, + { on = "1", run = "tab_switch 0", desc = "Switch to the first tab" }, + { on = "2", run = "tab_switch 1", desc = "Switch to the second tab" }, + { on = "3", run = "tab_switch 2", desc = "Switch to the third tab" }, + { on = "4", run = "tab_switch 3", desc = "Switch to the fourth tab" }, + { on = "5", run = "tab_switch 4", desc = "Switch to the fifth tab" }, + { on = "6", run = "tab_switch 5", desc = "Switch to the sixth tab" }, + { on = "7", run = "tab_switch 6", desc = "Switch to the seventh tab" }, + { on = "8", run = "tab_switch 7", desc = "Switch to the eighth tab" }, + { on = "9", run = "tab_switch 8", desc = "Switch to the ninth tab" }, + + # Tasks + { on = "w", run = "tasks_show", desc = "Show task manager" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[spot] +keymap = [ + # Navigation + { on = "u", run = "arrow -1", desc = "Move up" }, + { on = "e", run = "arrow 1", desc = "Move down" }, + + # Close + { on = "", run = "close", desc = "Close spotter" }, + { on = "q", run = "close", desc = "Close spotter" }, + + # Swipe through files + { on = "", run = "swipe -5", desc = "Swipe 5 files up" }, + { on = "", run = "swipe 5", desc = "Swipe 5 files down" }, + + # Copy content + { on = "y", run = "copy cell", desc = "Copy cell content" }, +] + +[tasks] + +keymap = [ + { on = "", run = "close", desc = "Close task manager" }, + { on = "", run = "close", desc = "Close task manager" }, + { on = "", run = "close", desc = "Close task manager" }, + { on = "w", run = "close", desc = "Close task manager" }, + + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "inspect", desc = "Inspect the task" }, + { on = "x", run = "cancel", desc = "Cancel the task" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[pick] + +keymap = [ + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close", desc = "Cancel selection" }, + { on = "", run = "close --submit", desc = "Submit the selection" }, + + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[input] + +keymap = [ + { on = "", run = "close", desc = "Cancel input" }, + { on = "", run = "close --submit", desc = "Submit the input" }, + { on = "", run = "escape", desc = "Go back the normal mode, or cancel input" }, + { on = "", run = "escape", desc = "Go back the normal mode, or cancel input" }, + + # Mode + { on = "k", run = "insert", desc = "Enter insert mode" }, + { on = "a", run = "insert --append", desc = "Enter append mode" }, + { on = "K", run = ["move -999", "insert"], desc = "Move to the BOL, and enter insert mode" }, + { on = "A", run = ["move 999", "insert --append"], desc = "Move to the EOL, and enter append mode" }, + { on = "v", run = "visual", desc = "Enter visual mode" }, + { on = "V", run = ["move -999", "visual", "move 999"], desc = "Enter visual mode and select all" }, + + # Character-wise movement + { on = "n", run = "move -1", desc = "Move back a character" }, + { on = "i", run = "move 1", desc = "Move forward a character" }, + { on = "", run = "move -1", desc = "Move back a character" }, + { on = "", run = "move 1", desc = "Move forward a character" }, + { on = "", run = "move -1", desc = "Move back a character" }, + { on = "", run = "move 1", desc = "Move forward a character" }, + + # Word-wise movement + { on = "b", run = "backward", desc = "Move back to the start of the current or previous word" }, + { on = "w", run = "forward", desc = "Move forward to the start of the next word" }, + { on = "h", run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" }, + { on = "", run = "backward", desc = "Move back to the start of the current or previous word" }, + { on = "", run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" }, + + # Line-wise movement + { on = "N", run = "move -999", desc = "Move to the BOL" }, + { on = "I", run = "move 999", desc = "Move to the EOL" }, + { on = "", run = "move -999", desc = "Move to the BOL" }, + { on = "", run = "move 999", desc = "Move to the EOL" }, + { on = "", run = "move -999", desc = "Move to the BOL" }, + { on = "", run = "move 999", desc = "Move to the EOL" }, + + # Delete + { on = "", run = "backspace", desc = "Delete the character before the cursor" }, + { on = "", run = "backspace --under", desc = "Delete the character under the cursor" }, + { on = "", run = "backspace", desc = "Delete the character before the cursor" }, + { on = "", run = "backspace --under", desc = "Delete the character under the cursor" }, + + # Kill + { on = "", run = "kill bol", desc = "Kill backwards to the BOL" }, + { on = "", run = "kill eol", desc = "Kill forwards to the EOL" }, + { on = "", run = "kill backward", desc = "Kill backwards to the start of the current word" }, + { on = "", run = "kill forward", desc = "Kill forwards to the end of the current word" }, + + # Cut/Yank/Paste + { on = "d", run = "delete --cut", desc = "Cut the selected characters" }, + { on = "D", run = ["delete --cut", "move 999"], desc = "Cut until the EOL" }, + { on = "c", run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" }, + { on = "C", run = ["delete --cut --insert", "move 999"], desc = "Cut until the EOL, and enter insert mode" }, + { on = "x", run = ["delete --cut", "move 1 --in-operating"], desc = "Cut the current character" }, + { on = "y", run = "yank", desc = "Copy the selected characters" }, + { on = "p", run = "paste", desc = "Paste the copied characters after the cursor" }, + { on = "P", run = "paste --before", desc = "Paste the copied characters before the cursor" }, + + # Undo/Redo + { on = "l", run = "undo", desc = "Undo the last operation" }, + { on = "", run = "redo", desc = "Redo the last operation" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[completion] + +keymap = [ + { on = "", run = "close", desc = "Cancel completion" }, + { on = "", run = "close --submit", desc = "Submit the completion" }, + { on = "", run = ["close --submit", "close_input --submit"], desc = "Submit the completion and input" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Help + { on = "~", run = "help", desc = "Open help" }, + { on = "", run = "help", desc = "Open help" }, +] + +[help] + +keymap = [ + { on = "", run = "escape", desc = "Clear the filter, or hide the help" }, + { on = "", run = "escape", desc = "Clear the filter, or hide the help" }, + { on = "q", run = "close", desc = "Exit the process" }, + { on = "", run = "close", desc = "Hide the help" }, + + # Navigation + { on = "u", run = "arrow -1", desc = "Move cursor up" }, + { on = "e", run = "arrow 1", desc = "Move cursor down" }, + + { on = "", run = "arrow -1", desc = "Move cursor up" }, + { on = "", run = "arrow 1", desc = "Move cursor down" }, + + # Filtering + { on = "f", run = "filter", desc = "Apply a filter for the help items" }, +] diff --git a/yazi/package.toml b/yazi/package.toml new file mode 100644 index 0000000..3bbe63b --- /dev/null +++ b/yazi/package.toml @@ -0,0 +1,27 @@ +[[plugin.deps]] +use = "yazi-rs/plugins:git" +rev = "5186af7" +hash = "771f18427fb75fb19990ce602bb322f4" + +[[plugin.deps]] +use = "yazi-rs/plugins:smart-enter" +rev = "5186af7" +hash = "aef2b1a805b80cce573bb766f1459d88" + +[[plugin.deps]] +use = "h-hg/yamb" +rev = "3f7c51f" +hash = "e11b980e5635f0fbabd80931b1a1347e" + +[[plugin.deps]] +use = "KKV9/compress" +rev = "60b24af" +hash = "ee025be766240cc98e671754ac836da3" + +[[plugin.deps]] +use = "llanosrocas/yaziline" +rev = "1342efe" +hash = "a84a339953a568fee1d8beb63e6dca73" + +[flavor] +deps = [] diff --git a/yazi/plugins/compress.yazi/LICENSE b/yazi/plugins/compress.yazi/LICENSE new file mode 100644 index 0000000..7ce7a2f --- /dev/null +++ b/yazi/plugins/compress.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Ciarán O'Brien + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/compress.yazi/README.md b/yazi/plugins/compress.yazi/README.md new file mode 100644 index 0000000..385fe38 --- /dev/null +++ b/yazi/plugins/compress.yazi/README.md @@ -0,0 +1,48 @@ +# ~~archive.yazi~~ compress.yazi + +A Yazi plugin that compresses selected files to an archive. Supporting yazi versions 0.2.5 and up. + +## Supported file types + +| Extention | Unix Command | Windows Command | +| ------------- | ------------- | --------------- | +| .zip | zip -r | 7z a -tzip | +| .7z | 7z a | 7z a | +| .tar | tar rpf | tar rpf | +| .tar.gz | gzip | 7z a -tgzip | +| .tar.xz | xz | 7z a -txz | +| .tar.bz2 | bzip2 | 7z a -tbzip2 | +| .tar.zst | zstd | zstd | + + +**NOTE:** Windows users are required to install 7-Zip and add 7z.exe to the `path` environment variable, only tar archives will be available otherwise. + + +## Install + +```bash +# For Unix platforms +git clone https://github.com/KKV9/compress.yazi.git ~/.config/yazi/plugins/compress.yazi + +## For Windows +git clone https://github.com/KKV9/compress.yazi.git %AppData%\yazi\config\plugins\compress.yazi + +# Or with yazi plugin manager +ya pack -a KKV9/compress +``` + +- Add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = [ "c", "a" ] +run = "plugin compress" +desc = "Archive selected files" +``` + +## Usage + + - Select files or folders to add, then press `c` `a` to create a new archive. + - Type a name for the new file. + - The file extention must match one of the supported filetype extentions. + - The desired archive/compression command must be installed on your system. diff --git a/yazi/plugins/compress.yazi/main.lua b/yazi/plugins/compress.yazi/main.lua new file mode 100644 index 0000000..333587f --- /dev/null +++ b/yazi/plugins/compress.yazi/main.lua @@ -0,0 +1,228 @@ +-- Send error notification +local function notify_error(message, urgency) + ya.notify({ + title = "Archive", + content = message, + level = urgency, + timeout = 5, + }) +end + +-- Check for windows +local is_windows = ya.target_family() == "windows" + +-- Make table of selected or hovered: path = filenames +local selected_or_hovered = ya.sync(function() + local tab, paths, names, path_fnames = cx.active, {}, {}, {} + for _, u in pairs(tab.selected) do + paths[#paths + 1] = tostring(u:parent()) + names[#names + 1] = tostring(u:name()) + end + if #paths == 0 and tab.current.hovered then + paths[1] = tostring(tab.current.hovered.url:parent()) + names[1] = tostring(tab.current.hovered.name) + end + for idx, name in ipairs(names) do + if not path_fnames[paths[idx]] then + path_fnames[paths[idx]] = {} + end + table.insert(path_fnames[paths[idx]], name) + end + return path_fnames, tostring(tab.current.cwd) +end) + +-- Check if archive command is available +local function is_command_available(cmd) + local stat_cmd + + if is_windows then + stat_cmd = string.format("where %s > nul 2>&1", cmd) + else + stat_cmd = string.format("command -v %s >/dev/null 2>&1", cmd) + end + + local cmd_exists = os.execute(stat_cmd) + if cmd_exists then + return true + else + return false + end +end + +-- Archive command list --> string +local function find_binary(cmd_list) + for _, cmd in ipairs(cmd_list) do + if is_command_available(cmd) then + return cmd + end + end + return cmd_list[1] -- Return first command as fallback +end + +-- Check if file exists +local function file_exists(name) + local f = io.open(name, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +-- Append filename to it's parent directory +local function combine_url(path, file) + path, file = Url(path), Url(file) + return tostring(path:join(file)) +end + +return { + entry = function() + -- Exit visual mode + ya.manager_emit("escape", { visual = true }) + + -- Define file table and output_dir (pwd) + local path_fnames, output_dir = selected_or_hovered() + + -- Get input + local output_name, event = ya.input({ + title = "Create archive:", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + + -- Use appropriate archive command + local archive_commands = { + ["%.zip$"] = { command = "zip", args = { "-r" } }, + ["%.7z$"] = { command = { "7z", "7zz" }, args = { "a" } }, + ["%.tar.gz$"] = { command = "tar", args = { "rpf" }, compress = "gzip" }, + ["%.tar.xz$"] = { command = "tar", args = { "rpf" }, compress = "xz" }, + ["%.tar.bz2$"] = { command = "tar", args = { "rpf" }, compress = "bzip2" }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + + if is_windows then + archive_commands = { + ["%.zip$"] = { command = "7z", args = { "a", "-tzip" } }, + ["%.7z$"] = { command = "7z", args = { "a" } }, + ["%.tar.gz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tgzip", "-sdel", output_name }, + }, + ["%.tar.xz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-txz", "-sdel", output_name }, + }, + ["%.tar.bz2$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tbzip2", "-sdel", output_name }, + }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + end + + -- Match user input to archive command + local archive_cmd, archive_args, archive_compress, archive_compress_args + for pattern, cmd_pair in pairs(archive_commands) do + if output_name:match(pattern) then + archive_cmd = cmd_pair.command + archive_args = cmd_pair.args + archive_compress = cmd_pair.compress + archive_compress_args = cmd_pair.compress_args or {} + end + end + + -- Check if archive command has multiple names + if type(archive_cmd) == "table" then + archive_cmd = find_binary(archive_cmd) + end + + -- Check if no archive command is available for the extention + if not archive_cmd then + notify_error("Unsupported file extention", "error") + return + end + + -- Exit if archive command is not available + if not is_command_available(archive_cmd) then + notify_error(string.format("%s not available", archive_cmd), "error") + return + end + + -- Exit if compress command is not available + if archive_compress and not is_command_available(archive_compress) then + notify_error(string.format("%s compression not available", archive_compress), "error") + return + end + + -- If file exists show overwrite prompt + local output_url = combine_url(output_dir, output_name) + while true do + if file_exists(output_url) then + local overwrite_answer = ya.input({ + title = "Overwrite " .. output_name .. "? y/N:", + position = { "top-center", y = 3, w = 40 }, + }) + if overwrite_answer:lower() ~= "y" then + notify_error("Operation canceled", "warn") + return -- If no overwrite selected, exit + else + local rm_status, rm_err = os.remove(output_url) + if not rm_status then + notify_error(string.format("Failed to remove %s, exit code %s", output_name, rm_err), "error") + return + end -- If overwrite fails, exit + end + end + if archive_compress and not output_name:match("%.tar$") then + output_name = output_name:match("(.*%.tar)") -- Test for .tar and .tar.* + output_url = combine_url(output_dir, output_name) -- Update output_url + else + break + end + end + + -- Add to output archive in each path, their respective files + for path, names in pairs(path_fnames) do + local archive_status, archive_err = + Command(archive_cmd):args(archive_args):arg(output_url):args(names):cwd(path):spawn():wait() + if not archive_status or not archive_status.success then + notify_error( + string.format( + "%s with selected files failed, exit code %s", + archive_args, + archive_status and archive_status.code or archive_err + ), + "error" + ) + end + end + + -- Use compress command if needed + if archive_compress then + local compress_status, compress_err = + Command(archive_compress):args(archive_compress_args):arg(output_name):cwd(output_dir):spawn():wait() + if not compress_status or not compress_status.success then + notify_error( + string.format( + "%s with %s failed, exit code %s", + archive_compress, + output_name, + compress_status and compress_status.code or compress_err + ), + "error" + ) + end + end + end, +} diff --git a/yazi/plugins/compress.yazi/main.lua.bak b/yazi/plugins/compress.yazi/main.lua.bak new file mode 100755 index 0000000..333587f --- /dev/null +++ b/yazi/plugins/compress.yazi/main.lua.bak @@ -0,0 +1,228 @@ +-- Send error notification +local function notify_error(message, urgency) + ya.notify({ + title = "Archive", + content = message, + level = urgency, + timeout = 5, + }) +end + +-- Check for windows +local is_windows = ya.target_family() == "windows" + +-- Make table of selected or hovered: path = filenames +local selected_or_hovered = ya.sync(function() + local tab, paths, names, path_fnames = cx.active, {}, {}, {} + for _, u in pairs(tab.selected) do + paths[#paths + 1] = tostring(u:parent()) + names[#names + 1] = tostring(u:name()) + end + if #paths == 0 and tab.current.hovered then + paths[1] = tostring(tab.current.hovered.url:parent()) + names[1] = tostring(tab.current.hovered.name) + end + for idx, name in ipairs(names) do + if not path_fnames[paths[idx]] then + path_fnames[paths[idx]] = {} + end + table.insert(path_fnames[paths[idx]], name) + end + return path_fnames, tostring(tab.current.cwd) +end) + +-- Check if archive command is available +local function is_command_available(cmd) + local stat_cmd + + if is_windows then + stat_cmd = string.format("where %s > nul 2>&1", cmd) + else + stat_cmd = string.format("command -v %s >/dev/null 2>&1", cmd) + end + + local cmd_exists = os.execute(stat_cmd) + if cmd_exists then + return true + else + return false + end +end + +-- Archive command list --> string +local function find_binary(cmd_list) + for _, cmd in ipairs(cmd_list) do + if is_command_available(cmd) then + return cmd + end + end + return cmd_list[1] -- Return first command as fallback +end + +-- Check if file exists +local function file_exists(name) + local f = io.open(name, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +-- Append filename to it's parent directory +local function combine_url(path, file) + path, file = Url(path), Url(file) + return tostring(path:join(file)) +end + +return { + entry = function() + -- Exit visual mode + ya.manager_emit("escape", { visual = true }) + + -- Define file table and output_dir (pwd) + local path_fnames, output_dir = selected_or_hovered() + + -- Get input + local output_name, event = ya.input({ + title = "Create archive:", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + + -- Use appropriate archive command + local archive_commands = { + ["%.zip$"] = { command = "zip", args = { "-r" } }, + ["%.7z$"] = { command = { "7z", "7zz" }, args = { "a" } }, + ["%.tar.gz$"] = { command = "tar", args = { "rpf" }, compress = "gzip" }, + ["%.tar.xz$"] = { command = "tar", args = { "rpf" }, compress = "xz" }, + ["%.tar.bz2$"] = { command = "tar", args = { "rpf" }, compress = "bzip2" }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + + if is_windows then + archive_commands = { + ["%.zip$"] = { command = "7z", args = { "a", "-tzip" } }, + ["%.7z$"] = { command = "7z", args = { "a" } }, + ["%.tar.gz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tgzip", "-sdel", output_name }, + }, + ["%.tar.xz$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-txz", "-sdel", output_name }, + }, + ["%.tar.bz2$"] = { + command = "tar", + args = { "rpf" }, + compress = "7z", + compress_args = { "a", "-tbzip2", "-sdel", output_name }, + }, + ["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } }, + ["%.tar$"] = { command = "tar", args = { "rpf" } }, + } + end + + -- Match user input to archive command + local archive_cmd, archive_args, archive_compress, archive_compress_args + for pattern, cmd_pair in pairs(archive_commands) do + if output_name:match(pattern) then + archive_cmd = cmd_pair.command + archive_args = cmd_pair.args + archive_compress = cmd_pair.compress + archive_compress_args = cmd_pair.compress_args or {} + end + end + + -- Check if archive command has multiple names + if type(archive_cmd) == "table" then + archive_cmd = find_binary(archive_cmd) + end + + -- Check if no archive command is available for the extention + if not archive_cmd then + notify_error("Unsupported file extention", "error") + return + end + + -- Exit if archive command is not available + if not is_command_available(archive_cmd) then + notify_error(string.format("%s not available", archive_cmd), "error") + return + end + + -- Exit if compress command is not available + if archive_compress and not is_command_available(archive_compress) then + notify_error(string.format("%s compression not available", archive_compress), "error") + return + end + + -- If file exists show overwrite prompt + local output_url = combine_url(output_dir, output_name) + while true do + if file_exists(output_url) then + local overwrite_answer = ya.input({ + title = "Overwrite " .. output_name .. "? y/N:", + position = { "top-center", y = 3, w = 40 }, + }) + if overwrite_answer:lower() ~= "y" then + notify_error("Operation canceled", "warn") + return -- If no overwrite selected, exit + else + local rm_status, rm_err = os.remove(output_url) + if not rm_status then + notify_error(string.format("Failed to remove %s, exit code %s", output_name, rm_err), "error") + return + end -- If overwrite fails, exit + end + end + if archive_compress and not output_name:match("%.tar$") then + output_name = output_name:match("(.*%.tar)") -- Test for .tar and .tar.* + output_url = combine_url(output_dir, output_name) -- Update output_url + else + break + end + end + + -- Add to output archive in each path, their respective files + for path, names in pairs(path_fnames) do + local archive_status, archive_err = + Command(archive_cmd):args(archive_args):arg(output_url):args(names):cwd(path):spawn():wait() + if not archive_status or not archive_status.success then + notify_error( + string.format( + "%s with selected files failed, exit code %s", + archive_args, + archive_status and archive_status.code or archive_err + ), + "error" + ) + end + end + + -- Use compress command if needed + if archive_compress then + local compress_status, compress_err = + Command(archive_compress):args(archive_compress_args):arg(output_name):cwd(output_dir):spawn():wait() + if not compress_status or not compress_status.success then + notify_error( + string.format( + "%s with %s failed, exit code %s", + archive_compress, + output_name, + compress_status and compress_status.code or compress_err + ), + "error" + ) + end + end + end, +} diff --git a/yazi/plugins/git.yazi/LICENSE b/yazi/plugins/git.yazi/LICENSE new file mode 100644 index 0000000..fb5b1d6 --- /dev/null +++ b/yazi/plugins/git.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 yazi-rs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/git.yazi/README.md b/yazi/plugins/git.yazi/README.md new file mode 100644 index 0000000..4c5b07c --- /dev/null +++ b/yazi/plugins/git.yazi/README.md @@ -0,0 +1,78 @@ +# git.yazi + +> [!NOTE] +> Yazi v25.2.26 or later is required for this plugin to work. + +Show the status of Git file changes as linemode in the file list. + +https://github.com/user-attachments/assets/34976be9-a871-4ffe-9d5a-c4cdd0bf4576 + +## Installation + +```sh +ya pack -a yazi-rs/plugins:git +``` + +## Setup + +Add the following to your `~/.config/yazi/init.lua`: + +```lua +require("git"):setup() +``` + +And register it as fetchers in your `~/.config/yazi/yazi.toml`: + +```toml +[[plugin.prepend_fetchers]] +id = "git" +name = "*" +run = "git" + +[[plugin.prepend_fetchers]] +id = "git" +name = "*/" +run = "git" +``` + +## Advanced + +You can customize the [Style](https://yazi-rs.github.io/docs/plugins/layout#style) of the status sign with: + +- `th.git.modified` +- `th.git.added` +- `th.git.untracked` +- `th.git.ignored` +- `th.git.deleted` +- `th.git.updated` + +For example: + +```lua +-- ~/.config/yazi/init.lua +th.git = th.git or {} +th.git.modified = ui.Style():fg("blue") +th.git.deleted = ui.Style():fg("red"):bold() +``` + +You can also customize the text of the status sign with: + +- `th.git.modified_sign` +- `th.git.added_sign` +- `th.git.untracked_sign` +- `th.git.ignored_sign` +- `th.git.deleted_sign` +- `th.git.updated_sign` + +For example: + +```lua +-- ~/.config/yazi/init.lua +th.git = th.git or {} +th.git.modified_sign = "M" +th.git.deleted_sign = "D" +``` + +## License + +This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file. diff --git a/yazi/plugins/git.yazi/main.lua b/yazi/plugins/git.yazi/main.lua new file mode 100644 index 0000000..0445ca9 --- /dev/null +++ b/yazi/plugins/git.yazi/main.lua @@ -0,0 +1,228 @@ +--- @since 25.4.4 + +local WINDOWS = ya.target_family() == "windows" + +-- The code of supported git status, +-- also used to determine which status to show for directories when they contain different statuses +-- see `bubble_up` +local CODES = { + excluded = 100, -- ignored directory + ignored = 6, -- ignored file + untracked = 5, + modified = 4, + added = 3, + deleted = 2, + updated = 1, + unknown = 0, +} + +local PATTERNS = { + { "!$", CODES.ignored }, + { "?$", CODES.untracked }, + { "[MT]", CODES.modified }, + { "[AC]", CODES.added }, + { "D", CODES.deleted }, + { "U", CODES.updated }, + { "[AD][AD]", CODES.updated }, +} + +local function match(line) + local signs = line:sub(1, 2) + for _, p in ipairs(PATTERNS) do + local path, pattern, code = nil, p[1], p[2] + if signs:find(pattern) then + path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4) + path = WINDOWS and path:gsub("/", "\\") or path + end + if not path then + elseif path:find("[/\\]$") then + -- Mark the ignored directory as `excluded`, so we can process it further within `propagate_down` + return code == CODES.ignored and CODES.excluded or code, path:sub(1, -2) + else + return code, path + end + end +end + +local function root(cwd) + local is_worktree = function(url) + local file, head = io.open(tostring(url)), nil + if file then + head = file:read(8) + file:close() + end + return head == "gitdir: " + end + + repeat + local next = cwd:join(".git") + local cha = fs.cha(next) + if cha and (cha.is_dir or is_worktree(next)) then + return tostring(cwd) + end + cwd = cwd.parent + until not cwd +end + +local function bubble_up(changed) + local new, empty = {}, Url("") + for path, code in pairs(changed) do + if code ~= CODES.ignored then + local url = Url(path).parent + while url and url ~= empty do + local s = tostring(url) + new[s] = (new[s] or CODES.unknown) > code and new[s] or code + url = url.parent + end + end + end + return new +end + +local function propagate_down(excluded, cwd, repo) + local new, rel = {}, cwd:strip_prefix(repo) + for _, path in ipairs(excluded) do + if rel:starts_with(path) then + -- If `cwd` is a subdirectory of an excluded directory, also mark it as `excluded` + new[tostring(cwd)] = CODES.excluded + elseif cwd == repo:join(path).parent then + -- If `path` is a direct subdirectory of `cwd`, mark it as `ignored` + new[path] = CODES.ignored + else + -- Skipping, we only care about `cwd` itself and its direct subdirectories for maximum performance + end + end + return new +end + +local add = ya.sync(function(st, cwd, repo, changed) + st.dirs[cwd] = repo + st.repos[repo] = st.repos[repo] or {} + for path, code in pairs(changed) do + if code == CODES.unknown then + st.repos[repo][path] = nil + elseif code == CODES.excluded then + -- Mark the directory with a special value `excluded` so that it can be distinguished during UI rendering + st.dirs[path] = CODES.excluded + else + st.repos[repo][path] = code + end + end + ya.render() +end) + +local remove = ya.sync(function(st, cwd) + local repo = st.dirs[cwd] + if not repo then + return + end + + ya.render() + st.dirs[cwd] = nil + if not st.repos[repo] then + return + end + + for _, r in pairs(st.dirs) do + if r == repo then + return + end + end + st.repos[repo] = nil +end) + +local function setup(st, opts) + st.dirs = {} -- Mapping between a directory and its corresponding repository + st.repos = {} -- Mapping between a repository and the status of each of its files + + opts = opts or {} + opts.order = opts.order or 1500 + + local t = th.git or {} + local styles = { + [CODES.ignored] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("darkgray"), + [CODES.untracked] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("magenta"), + [CODES.modified] = t.modified and ui.Style(t.modified) or ui.Style():fg("yellow"), + [CODES.added] = t.added and ui.Style(t.added) or ui.Style():fg("green"), + [CODES.deleted] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("red"), + [CODES.updated] = t.updated and ui.Style(t.updated) or ui.Style():fg("yellow"), + } + local signs = { + [CODES.ignored] = t.ignored_sign or "", + [CODES.untracked] = t.untracked_sign or "?", + [CODES.modified] = t.modified_sign or "", + [CODES.added] = t.added_sign or "", + [CODES.deleted] = t.deleted_sign or "", + [CODES.updated] = t.updated_sign or "", + } + + Linemode:children_add(function(self) + local url = self._file.url + local repo = st.dirs[tostring(url.base)] + local code + if repo then + code = repo == CODES.excluded and CODES.ignored or st.repos[repo][tostring(url):sub(#repo + 2)] + end + + if not code or signs[code] == "" then + return "" + elseif self._file.is_hovered then + return ui.Line { " ", signs[code] } + else + return ui.Line { " ", ui.Span(signs[code]):style(styles[code]) } + end + end, opts.order) +end + +local function fetch(_, job) + local cwd = job.files[1].url.base + local repo = root(cwd) + if not repo then + remove(tostring(cwd)) + return true + end + + local paths = {} + for _, file in ipairs(job.files) do + paths[#paths + 1] = tostring(file.url) + end + + -- stylua: ignore + local output, err = Command("git") + :cwd(tostring(cwd)) + :arg({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" }) + :arg(paths) + :stdout(Command.PIPED) + :output() + if not output then + return true, Err("Cannot spawn `git` command, error: %s", err) + end + + local changed, excluded = {}, {} + for line in output.stdout:gmatch("[^\r\n]+") do + local code, path = match(line) + if code == CODES.excluded then + excluded[#excluded + 1] = path + else + changed[path] = code + end + end + + if job.files[1].cha.is_dir then + ya.dict_merge(changed, bubble_up(changed)) + end + ya.dict_merge(changed, propagate_down(excluded, cwd, Url(repo))) + + -- Reset the status of any files that don't appear in the output of `git status` to `unknown`, + -- so that cleaning up outdated statuses from `st.repos` + for _, path in ipairs(paths) do + local s = path:sub(#repo + 2) + changed[s] = changed[s] or CODES.unknown + end + + add(tostring(cwd), repo, changed) + + return false +end + +return { setup = setup, fetch = fetch } diff --git a/yazi/plugins/git.yazi/main.lua.bak b/yazi/plugins/git.yazi/main.lua.bak new file mode 100755 index 0000000..a64b749 --- /dev/null +++ b/yazi/plugins/git.yazi/main.lua.bak @@ -0,0 +1,211 @@ +local WIN = ya.target_family() == "windows" +local PATS = { + { "[MT]", 6 }, -- Modified + { "[AC]", 5 }, -- Added + { "?$", 4 }, -- Untracked + { "!$", 3 }, -- Ignored + { "D", 2 }, -- Deleted + { "U", 1 }, -- Updated + { "[AD][AD]", 1 }, -- Updated +} + +local function match(line) + local signs = line:sub(1, 2) + for _, p in ipairs(PATS) do + local path + if signs:find(p[1]) then + path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4) + path = WIN and path:gsub("/", "\\") or path + end + if not path then + elseif path:find("[/\\]$") then + return p[2] == 3 and 30 or p[2], path:sub(1, -2) + else + return p[2], path + end + end +end + +local function root(cwd) + local is_worktree = function(url) + local file, head = io.open(tostring(url)), nil + if file then + head = file:read(8) + file:close() + end + return head == "gitdir: " + end + + repeat + local next = cwd:join(".git") + local cha = fs.cha(next) + if cha and (cha.is_dir or is_worktree(next)) then + return tostring(cwd) + end + cwd = cwd:parent() + until not cwd +end + +local function bubble_up(changed) + local new, empty = {}, Url("") + for k, v in pairs(changed) do + if v ~= 3 and v ~= 30 then + local url = Url(k):parent() + while url and url ~= empty do + local s = tostring(url) + new[s] = (new[s] or 0) > v and new[s] or v + url = url:parent() + end + end + end + return new +end + +local function propagate_down(ignored, cwd, repo) + local new, rel = {}, cwd:strip_prefix(repo) + for k, v in pairs(ignored) do + if v == 30 then + if rel:starts_with(k) then + new[tostring(repo:join(rel))] = 30 + elseif cwd == repo:join(k):parent() then + new[k] = 3 + end + end + end + return new +end + +local add = ya.sync(function(st, cwd, repo, changed) + st.dirs[cwd] = repo + st.repos[repo] = st.repos[repo] or {} + for k, v in pairs(changed) do + if v == 0 then + st.repos[repo][k] = nil + elseif v == 30 then + st.dirs[k] = "" + else + st.repos[repo][k] = v + end + end + ya.render() +end) + +local remove = ya.sync(function(st, cwd) + local dir = st.dirs[cwd] + if not dir then + return + end + + ya.render() + st.dirs[cwd] = nil + if not st.repos[dir] then + return + end + + for _, r in pairs(st.dirs) do + if r == dir then + return + end + end + st.repos[dir] = nil +end) + +local function setup(st, opts) + st.dirs = {} + st.repos = {} + + opts = opts or {} + opts.order = opts.order or 1500 + + -- Chosen by ChatGPT fairly, PRs are welcome to adjust them + local t = THEME.git or {} + local styles = { + [6] = t.modified and ui.Style(t.modified) or ui.Style():fg("#ffa500"), + [5] = t.added and ui.Style(t.added) or ui.Style():fg("#32cd32"), + [4] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("#a9a9a9"), + [3] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("#696969"), + [2] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("#ff4500"), + [1] = t.updated and ui.Style(t.updated) or ui.Style():fg("#1e90ff"), + } + local signs = { + [6] = t.modified_sign and t.modified_sign or "", + [5] = t.added_sign and t.added_sign or "", + [4] = t.untracked_sign and t.untracked_sign or "", + [3] = t.ignored_sign and t.ignored_sign or "", + [2] = t.deleted_sign and t.deleted_sign or "", + [1] = t.updated_sign and t.updated_sign or "U", + } + + Linemode:children_add(function(self) + local url = self._file.url + local dir = st.dirs[tostring(url:parent())] + local change + if dir then + change = dir == "" and 3 or st.repos[dir][tostring(url):sub(#dir + 2)] + end + + if not change or signs[change] == "" then + return ui.Line("") + elseif self._file:is_hovered() then + return ui.Line { ui.Span(" "), ui.Span(signs[change]) } + else + return ui.Line { ui.Span(" "), ui.Span(signs[change]):style(styles[change]) } + end + end, opts.order) +end + +local function fetch(self, job) + -- TODO: remove this once Yazi 0.4 is released + job = job or self + + local cwd = job.files[1].url:parent() + local repo = root(cwd) + if not repo then + remove(tostring(cwd)) + return 1 + end + + local paths = {} + for _, f in ipairs(job.files) do + paths[#paths + 1] = tostring(f.url) + end + + -- stylua: ignore + local output, err = Command("git") + :cwd(tostring(cwd)) + :args({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" }) + :args(paths) + :stdout(Command.PIPED) + :output() + if not output then + ya.err("Cannot spawn git command, error code " .. tostring(err)) + return 0 + end + + local changed, ignored = {}, {} + for line in output.stdout:gmatch("[^\r\n]+") do + local sign, path = match(line) + if sign == 30 then + ignored[path] = sign + else + changed[path] = sign + end + end + + if job.files[1].cha.is_dir then + ya.dict_merge(changed, bubble_up(changed)) + ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo))) + else + ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo))) + end + + for _, p in ipairs(paths) do + local s = p:sub(#repo + 2) + changed[s] = changed[s] or 0 + end + add(tostring(cwd), repo, changed) + + return 3 +end + +return { setup = setup, fetch = fetch } diff --git a/yazi/plugins/smart-enter.yazi/LICENSE b/yazi/plugins/smart-enter.yazi/LICENSE new file mode 100644 index 0000000..fb5b1d6 --- /dev/null +++ b/yazi/plugins/smart-enter.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 yazi-rs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/smart-enter.yazi/README.md b/yazi/plugins/smart-enter.yazi/README.md new file mode 100644 index 0000000..d4c6bbd --- /dev/null +++ b/yazi/plugins/smart-enter.yazi/README.md @@ -0,0 +1,40 @@ +# smart-enter.yazi + +[`Open`][open] files or [`enter`][enter] directories all in one key! + +## Installation + +```sh +ya pack -a yazi-rs/plugins:smart-enter +``` + +## Usage + +Bind your l key to the plugin, in your `~/.config/yazi/keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = "l" +run = "plugin smart-enter" +desc = "Enter the child directory, or open the file" +``` + +## Advanced + +By default, `--hovered` is passed to the [`open`][open] command, make the behavior consistent with [`enter`][enter] avoiding accidental triggers, +which means both will only target the currently hovered file. + +If you still want `open` to target multiple selected files, add this to your `~/.config/yazi/init.lua`: + +```lua +require("smart-enter"):setup { + open_multi = true, +} +``` + +## License + +This plugin is MIT-licensed. For more information check the [LICENSE](LICENSE) file. + +[open]: https://yazi-rs.github.io/docs/configuration/keymap/#manager.open +[enter]: https://yazi-rs.github.io/docs/configuration/keymap/#manager.enter diff --git a/yazi/plugins/smart-enter.yazi/main.lua b/yazi/plugins/smart-enter.yazi/main.lua new file mode 100644 index 0000000..8b9ae55 --- /dev/null +++ b/yazi/plugins/smart-enter.yazi/main.lua @@ -0,0 +1,11 @@ +--- @since 25.2.26 +--- @sync entry + +local function setup(self, opts) self.open_multi = opts.open_multi end + +local function entry(self) + local h = cx.active.current.hovered + ya.mgr_emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi }) +end + +return { entry = entry, setup = setup } diff --git a/yazi/plugins/smart-enter.yazi/main.lua.bak b/yazi/plugins/smart-enter.yazi/main.lua.bak new file mode 100755 index 0000000..37a465a --- /dev/null +++ b/yazi/plugins/smart-enter.yazi/main.lua.bak @@ -0,0 +1,10 @@ +--- @sync entry + +local function setup(self, opts) self.open_multi = opts.open_multi end + +local function entry(self) + local h = cx.active.current.hovered + ya.manager_emit(h and h.cha.is_dir and "enter" or "open", { hovered = not self.open_multi }) +end + +return { entry = entry, setup = setup } diff --git a/yazi/plugins/yamb.yazi/LICENSE b/yazi/plugins/yamb.yazi/LICENSE new file mode 100644 index 0000000..12f8c8b --- /dev/null +++ b/yazi/plugins/yamb.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hunter Hwang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/yamb.yazi/README.md b/yazi/plugins/yamb.yazi/README.md new file mode 100644 index 0000000..5f322de --- /dev/null +++ b/yazi/plugins/yamb.yazi/README.md @@ -0,0 +1,112 @@ +# Yet another bookmarks + +A [Yazi](https://github.com/sxyazi/yazi) plugin for bookmark management, supporting the following features + +- Persistent bookmarks. No bookmarks are lost after you close yazi. +- Quickly jump, delete, and rename a bookmark by keymap. +- Support fuzzy search through [fzf](https://github.com/junegunn/fzf). +- Configure your bookmarks using Lua language. + +## Installation + +> [!NOTE] +> Yazi >= 0.25. + +```sh +# Linux/macOS +git clone https://github.com/h-hg/yamb.yazi.git ~/.config/yazi/plugins/yamb.yazi + +# Windows +git clone https://github.com/h-hg/yamb.yazi.git $env:APPDATA\yazi\config\plugins\yamb.yazi + +# if you are using Yazi version >= 3.0 +ya pack -a h-hg/yamb +``` + +## Usage + +Add this to your `init.lua` + +```lua +-- You can configure your bookmarks by lua language +local bookmarks = {} + +local path_sep = package.config:sub(1, 1) +local home_path = ya.target_family() == "windows" and os.getenv("USERPROFILE") or os.getenv("HOME") +if ya.target_family() == "windows" then + table.insert(bookmarks, { + tag = "Scoop Local", + + path = (os.getenv("SCOOP") or home_path .. "\\scoop") .. "\\", + key = "p" + }) + table.insert(bookmarks, { + tag = "Scoop Global", + path = (os.getenv("SCOOP_GLOBAL") or "C:\\ProgramData\\scoop") .. "\\", + key = "P" + }) +end +table.insert(bookmarks, { + tag = "Desktop", + path = home_path .. path_sep .. "Desktop" .. path_sep, + key = "d" +}) + +require("yamb"):setup { + -- Optional, the path ending with path seperator represents folder. + bookmarks = bookmarks, + -- Optional, recieve notification everytime you jump. + jump_notify = true, + -- Optional, the cli of fzf. + cli = "fzf", + -- Optional, a string used for randomly generating keys, where the preceding characters have higher priority. + keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + -- Optional, the path of bookmarks + path = (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or + (os.getenv("HOME") .. "/.config/yazi/bookmark"), +} +``` + +Add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = [ "u", "a" ] +run = "plugin yamb save" +desc = "Add bookmark" + +[[manager.prepend_keymap]] +on = [ "u", "g" ] +run = "plugin yamb jump_by_key" +desc = "Jump bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "G" ] +run = "plugin yamb jump_by_fzf" +desc = "Jump bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "u", "d" ] +run = "plugin yamb delete_by_key" +desc = "Delete bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "D" ] +run = "plugin yamb delete_by_fzf" +desc = "Delete bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "u", "A" ] +run = "plugin yamb delete_all" +desc = "Delete all bookmarks" + +[[manager.prepend_keymap]] +on = [ "u", "r" ] +run = "plugin yamb rename_by_key" +desc = "Rename bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "R" ] +run = "plugin yamb rename_by_fzf" +desc = "Rename bookmark by fzf" +``` diff --git a/yazi/plugins/yamb.yazi/main.lua b/yazi/plugins/yamb.yazi/main.lua new file mode 100644 index 0000000..383b492 --- /dev/null +++ b/yazi/plugins/yamb.yazi/main.lua @@ -0,0 +1,355 @@ +local path_sep = package.config:sub(1, 1) + +local get_hovered_path = ya.sync(function(state) + local h = cx.active.current.hovered + if h then + local path = tostring(h.url) + if h.cha.is_dir then + return path .. path_sep + end + return path + else + return '' + end +end) + +local get_state_attr = ya.sync(function(state, attr) + return state[attr] +end) + +local set_state_attr = ya.sync(function(state, attr, value) + state[attr] = value +end) + +local set_bookmarks = ya.sync(function(state, path, value) + state.bookmarks[path] = value +end) + +local sort_bookmarks = function(bookmarks, key1, key2, reverse) + reverse = reverse or false + table.sort(bookmarks, function(x, y) + if x[key1] == nil and y[key1] == nil then + return x[key2] < y[key2] + elseif x[key1] == nil then + return false + elseif y[key1] == nil then + return true + else + return x[key1] < y[key1] + end + end) + if reverse then + local n = #bookmarks + for i = 1, math.floor(n / 2) do + bookmarks[i], bookmarks[n - i + 1] = bookmarks[n - i + 1], bookmarks[i] + end + end + return bookmarks +end + +local save_to_file = function(mb_path, bookmarks) + local file = io.open(mb_path, "w") + if file == nil then + return + end + local array = {} + for _, item in pairs(bookmarks) do + table.insert(array, item) + end + sort_bookmarks(array, "tag", "key", true) + for _, item in ipairs(array) do + file:write(string.format("%s\t%s\t%s\n", item.tag, item.path, item.key)) + end + file:close() +end + +local fzf_find = function(cli, mb_path) + local permit = ya.hide() + local cmd = string.format("%s < \"%s\"", cli, mb_path) + local handle = io.popen(cmd, "r") + local result = "" + if handle then + -- strip + result = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1") + handle:close() + end + permit:drop() + local tag, path, key = string.match(result or "", "(.-)\t(.-)\t(.*)") + return path +end + +local which_find = function(bookmarks) + local cands = {} + for path, item in pairs(bookmarks) do + if #item.tag ~= 0 then + table.insert(cands, { desc = item.tag, on = item.key, path = item.path }) + end + end + sort_bookmarks(cands, "on", "desc", false) + if #cands == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty bookmarks", + timeout = 2, + level = "info", + } + return nil + end + local idx = ya.which { cands = cands } + if idx == nil then + return nil + end + return cands[idx].path +end + +local action_jump = function(bookmarks, path, jump_notify) + if path == nil then + return + end + local tag = bookmarks[path].tag + if string.sub(path, -1) == path_sep then + ya.manager_emit("cd", { path }) + else + ya.manager_emit("reveal", { path }) + end + if jump_notify then + ya.notify { + title = "Bookmarks", + content = 'Jump to "' .. tag .. '"', + timeout = 2, + level = "info", + } + end +end + +local generate_key = function(bookmarks) + local keys = get_state_attr("keys") + local key2rank = get_state_attr("key2rank") + local mb = {} + for _, item in pairs(bookmarks) do + if #item.key == 1 then + table.insert(mb, item.key) + end + end + if #mb == 0 then + return keys[1] + end + table.sort(mb, function(a, b) + return key2rank[a] < key2rank[b] + end) + local idx = 1 + for _, key in ipairs(keys) do + if idx > #mb or key2rank[key] < key2rank[mb[idx]] then + return key + end + idx = idx + 1 + end + return nil +end + +local action_save = function(mb_path, bookmarks, path) + if path == nil or #path == 0 then + return + end + + local path_obj = bookmarks[path] + -- check tag + local tag = path_obj and path_obj.tag or path:match(".*[\\/]([^\\/]+)[\\/]?$") + while true do + local value, event = ya.input({ + title = "Tag (alias name)", + value = tag, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + tag = value or '' + if #tag == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty tag", + timeout = 2, + level = "info", + } + else + -- check the tag + local tag_obj = nil + for _, item in pairs(bookmarks) do + if item.tag == tag then + tag_obj = item + break + end + end + if tag_obj == nil or tag_obj.path == path then + break + end + ya.notify { + title = "Bookmarks", + content = "Duplicated tag", + timeout = 2, + level = "info", + } + end + end + -- check key + local key = path_obj and path_obj.key or generate_key(bookmarks) + while true do + local value, event = ya.input({ + title = "Key (1 character, optional)", + value = key, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + key = value or "" + if key == "" then + key = "" + break + elseif #key == 1 then + -- check the key + local key_obj = nil + for _, item in pairs(bookmarks) do + if item.key == key then + key_obj = item + break + end + end + if key_obj == nil or key_obj.path == path then + break + else + ya.notify { + title = "Bookmarks", + content = "Duplicated key", + timeout = 2, + level = "info", + } + end + else + ya.notify { + title = "Bookmarks", + content = "The length of key shoule be 1", + timeout = 2, + level = "info", + } + end + end + -- save + set_bookmarks(path, { tag = tag, path = path, key = key }) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" saved"', + timeout = 2, + level = "info", + } +end + +local action_delete = function(mb_path, bookmarks, path) + if path == nil then + return + end + local tag = bookmarks[path].tag + set_bookmarks(path, nil) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" deleted', + timeout = 2, + level = "info", + } +end + +local action_delete_all = function(mb_path) + local value, event = ya.input({ + title = "Delete all bookmarks? (y/n)", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + if string.lower(value) == "y" then + set_state_attr("bookmarks", {}) + save_to_file(mb_path, {}) + ya.notify { + title = "Bookmarks", + content = "All bookmarks deleted", + timeout = 2, + level = "info", + } + else + ya.notify { + title = "Bookmarks", + content = "Cancel delete", + timeout = 2, + level = "info", + } + end +end + +return { + setup = function(state, options) + state.path = options.path or + (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or + (os.getenv("HOME") .. "/.config/yazi/bookmark") + state.cli = options.cli or "fzf" + state.jump_notify = options.jump_notify and true + -- init the keys + local keys = options.keys or "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + state.keys = {} + state.key2rank = {} + for i = 1, #keys do + local char = keys:sub(i, i) + table.insert(state.keys, char) + state.key2rank[char] = i + end + + -- init the bookmarks + local bookmarks = {} + for _, item in pairs(options.bookmarks or {}) do + bookmarks[item.path] = { tag = item.tag, path = item.path, key = item.key } + end + -- load the config + local file = io.open(state.path, "r") + if file ~= nil then + for line in file:lines() do + local tag, path, key = string.match(line, "(.-)\t(.-)\t(.*)") + if tag and path then + key = key or "" + bookmarks[path] = { tag = tag, path = path, key = key } + end + end + file:close() + end + -- create bookmarks file to enable fzf + save_to_file(state.path, bookmarks) + state.bookmarks = bookmarks + end, + entry = function(self, jobs) + local action = jobs.args[1] + if not action then + return + end + local mb_path, cli, bookmarks, jump_notify = get_state_attr("path"), get_state_attr("cli"), get_state_attr("bookmarks"), get_state_attr("jump_notify") + if action == "save" then + action_save(mb_path, bookmarks, get_hovered_path()) + elseif action == "delete_by_key" then + action_delete(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "delete_by_fzf" then + action_delete(mb_path, bookmarks, fzf_find(cli, mb_path)) + elseif action == "delete_all" then + action_delete_all(mb_path) + elseif action == "jump_by_key" then + action_jump(bookmarks, which_find(bookmarks), jump_notify) + elseif action == "jump_by_fzf" then + action_jump(bookmarks, fzf_find(cli, mb_path), jump_notify) + elseif action == "rename_by_key" then + action_save(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "rename_by_fzf" then + action_save(mb_path, bookmarks, fzf_find(cli, mb_path)) + end + end, +} diff --git a/yazi/plugins/yamb.yazi/main.lua.bak b/yazi/plugins/yamb.yazi/main.lua.bak new file mode 100755 index 0000000..f3f46dc --- /dev/null +++ b/yazi/plugins/yamb.yazi/main.lua.bak @@ -0,0 +1,355 @@ +local path_sep = package.config:sub(1, 1) + +local get_hovered_path = ya.sync(function(state) + local h = cx.active.current.hovered + if h then + local path = tostring(h.url) + if h.cha.is_dir then + return path .. path_sep + end + return path + else + return '' + end +end) + +local get_state_attr = ya.sync(function(state, attr) + return state[attr] +end) + +local set_state_attr = ya.sync(function(state, attr, value) + state[attr] = value +end) + +local set_bookmarks = ya.sync(function(state, path, value) + state.bookmarks[path] = value +end) + +local sort_bookmarks = function(bookmarks, key1, key2, reverse) + reverse = reverse or false + table.sort(bookmarks, function(x, y) + if x[key1] == nil and y[key1] == nil then + return x[key2] < y[key2] + elseif x[key1] == nil then + return false + elseif y[key1] == nil then + return true + else + return x[key1] < y[key1] + end + end) + if reverse then + local n = #bookmarks + for i = 1, math.floor(n / 2) do + bookmarks[i], bookmarks[n - i + 1] = bookmarks[n - i + 1], bookmarks[i] + end + end + return bookmarks +end + +local save_to_file = function(mb_path, bookmarks) + local file = io.open(mb_path, "w") + if file == nil then + return + end + local array = {} + for _, item in pairs(bookmarks) do + table.insert(array, item) + end + sort_bookmarks(array, "tag", "key", true) + for _, item in ipairs(array) do + file:write(string.format("%s\t%s\t%s\n", item.tag, item.path, item.key)) + end + file:close() +end + +local fzf_find = function(cli, mb_path) + local permit = ya.hide() + local cmd = string.format("%s < \"%s\"", cli, mb_path) + local handle = io.popen(cmd, "r") + local result = "" + if handle then + -- strip + result = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1") + handle:close() + end + permit:drop() + local tag, path, key = string.match(result or "", "(.-)\t(.-)\t(.*)") + return path +end + +local which_find = function(bookmarks) + local cands = {} + for path, item in pairs(bookmarks) do + if #item.tag ~= 0 then + table.insert(cands, { desc = item.tag, on = item.key, path = item.path }) + end + end + sort_bookmarks(cands, "on", "desc", false) + if #cands == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty bookmarks", + timeout = 2, + level = "info", + } + return nil + end + local idx = ya.which { cands = cands } + if idx == nil then + return nil + end + return cands[idx].path +end + +local action_jump = function(bookmarks, path, jump_notify) + if path == nil then + return + end + local tag = bookmarks[path].tag + if string.sub(path, -1) == path_sep then + ya.manager_emit("cd", { path }) + else + ya.manager_emit("reveal", { path }) + end + if jump_notify then + ya.notify { + title = "Bookmarks", + content = 'Jump to "' .. tag .. '"', + timeout = 2, + level = "info", + } + end +end + +local generate_key = function(bookmarks) + local keys = get_state_attr("keys") + local key2rank = get_state_attr("key2rank") + local mb = {} + for _, item in pairs(bookmarks) do + if #item.key == 1 then + table.insert(mb, item.key) + end + end + if #mb == 0 then + return keys[1] + end + table.sort(mb, function(a, b) + return key2rank[a] < key2rank[b] + end) + local idx = 1 + for _, key in ipairs(keys) do + if key2rank[key] < key2rank[mb[idx]] then + return key + end + idx = idx + 1 + end + return nil +end + +local action_save = function(mb_path, bookmarks, path) + if path == nil or #path == 0 then + return + end + + local path_obj = bookmarks[path] + -- check tag + local tag = path_obj and path_obj.tag or path:match(".*[\\/]([^\\/]+)[\\/]?$") + while true do + local value, event = ya.input({ + title = "Tag (alias name)", + value = tag, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + tag = value or '' + if #tag == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty tag", + timeout = 2, + level = "info", + } + else + -- check the tag + local tag_obj = nil + for _, item in pairs(bookmarks) do + if item.tag == tag then + tag_obj = item + break + end + end + if tag_obj == nil or tag_obj.path == path then + break + end + ya.notify { + title = "Bookmarks", + content = "Duplicated tag", + timeout = 2, + level = "info", + } + end + end + -- check key + local key = path_obj and path_obj.key or generate_key(bookmarks) + while true do + local value, event = ya.input({ + title = "Key (1 character, optional)", + value = key, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + key = value or "" + if key == "" then + key = "" + break + elseif #key == 1 then + -- check the key + local key_obj = nil + for _, item in pairs(bookmarks) do + if item.key == key then + key_obj = item + break + end + end + if key_obj == nil or key_obj.path == path then + break + else + ya.notify { + title = "Bookmarks", + content = "Duplicated key", + timeout = 2, + level = "info", + } + end + else + ya.notify { + title = "Bookmarks", + content = "The length of key shoule be 1", + timeout = 2, + level = "info", + } + end + end + -- save + set_bookmarks(path, { tag = tag, path = path, key = key }) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" saved"', + timeout = 2, + level = "info", + } +end + +local action_delete = function(mb_path, bookmarks, path) + if path == nil then + return + end + local tag = bookmarks[path].tag + set_bookmarks(path, nil) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" deleted', + timeout = 2, + level = "info", + } +end + +local action_delete_all = function(mb_path) + local value, event = ya.input({ + title = "Delete all bookmarks? (y/n)", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + if string.lower(value) == "y" then + set_state_attr("bookmarks", {}) + save_to_file(mb_path, {}) + ya.notify { + title = "Bookmarks", + content = "All bookmarks deleted", + timeout = 2, + level = "info", + } + else + ya.notify { + title = "Bookmarks", + content = "Cancel delete", + timeout = 2, + level = "info", + } + end +end + +return { + setup = function(state, options) + state.path = options.path or + (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or + (os.getenv("HOME") .. "/.config/yazi/bookmark") + state.cli = options.cli or "fzf" + state.jump_notify = options.jump_notify and true + -- init the keys + local keys = options.keys or "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + state.keys = {} + state.key2rank = {} + for i = 1, #keys do + local char = keys:sub(i, i) + table.insert(state.keys, char) + state.key2rank[char] = i + end + + -- init the bookmarks + local bookmarks = {} + for _, item in pairs(options.bookmarks or {}) do + bookmarks[item.path] = { tag = item.tag, path = item.path, key = item.key } + end + -- load the config + local file = io.open(state.path, "r") + if file ~= nil then + for line in file:lines() do + local tag, path, key = string.match(line, "(.-)\t(.-)\t(.*)") + if tag and path then + key = key or "" + bookmarks[path] = { tag = tag, path = path, key = key } + end + end + file:close() + end + -- create bookmarks file to enable fzf + save_to_file(state.path, bookmarks) + state.bookmarks = bookmarks + end, + entry = function(self, jobs) + local action = jobs.args[1] + if not action then + return + end + local mb_path, cli, bookmarks, jump_notify = get_state_attr("path"), get_state_attr("cli"), get_state_attr("bookmarks"), get_state_attr("jump_notify") + if action == "save" then + action_save(mb_path, bookmarks, get_hovered_path()) + elseif action == "delete_by_key" then + action_delete(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "delete_by_fzf" then + action_delete(mb_path, bookmarks, fzf_find(cli, mb_path)) + elseif action == "delete_all" then + action_delete_all(mb_path) + elseif action == "jump_by_key" then + action_jump(bookmarks, which_find(bookmarks), jump_notify) + elseif action == "jump_by_fzf" then + action_jump(bookmarks, fzf_find(cli, mb_path), jump_notify) + elseif action == "rename_by_key" then + action_save(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "rename_by_fzf" then + action_save(mb_path, bookmarks, fzf_find(cli, mb_path)) + end + end, +} diff --git a/yazi/plugins/yaziline.yazi/LICENSE b/yazi/plugins/yaziline.yazi/LICENSE new file mode 100644 index 0000000..82a69f6 --- /dev/null +++ b/yazi/plugins/yaziline.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 llanosrocas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/yaziline.yazi/README.md b/yazi/plugins/yaziline.yazi/README.md new file mode 100644 index 0000000..fedd392 --- /dev/null +++ b/yazi/plugins/yaziline.yazi/README.md @@ -0,0 +1,154 @@ +# yaziline.yazi + +Simple lualine-like status line for yazi. + +Read more about features and configuration [here](#features). + +> ⚠️ **Note**: +> If you experience any issues after updating, please refer to the latest release notes. This repository is continuously synced with the upstream Yazi source code, which is actively maintained and frequently updated. + +![preview](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/preview.png) + +## Requirements + +- yazi version >= [25.4.8](https://github.com/sxyazi/yazi/releases/tag/v25.4.8) +- Font with symbol support. For example [Nerd Fonts](https://www.nerdfonts.com/). + +## Installation + +```sh +ya pack -a llanosrocas/yaziline +``` + +Or manually copy `init.lua` to the `~/.config/yazi/plugins/yaziline.yazi/init.lua` + +## Usage + +Add this to your `~/.config/yazi/init.lua`: + +```lua +require("yaziline"):setup() +``` + +Optionally, configure line: + +```lua +require("yaziline"):setup({ + color = "#98c379", -- main theme color + default_files_color = "darkgray", -- color of the file counter when it's inactive + selected_files_color = "white", + yanked_files_color = "green", + cut_files_color = "red", + + separator_style = "angly", -- "angly" | "curvy" | "liney" | "empty" + separator_open = "", + separator_close = "", + separator_open_thin = "", + separator_close_thin = "", + separator_head = "", + separator_tail = "", + + select_symbol = "", + yank_symbol = "󰆐", + + filename_max_length = 24, -- truncate when filename > 24 + filename_truncate_length = 6, -- leave 6 chars on both sides + filename_truncate_separator = "..." -- the separator of the truncated filename +}) +``` + +## Features + +### Preconfigured separators + +Choose your style: + +- `angly` + ![angly](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/angly.png) +- `curvy` + ![curvy](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/curvy.png) +- `liney` + ![liney](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/liney.png) +- `empty` + ![empty](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/empty.png) + +### Separator customization + +You can provide your own symbols for separators combined with preconfigured separators. For example: + +```lua +require("yaziline"):setup({ + -- Optinal config + separator_style = "angly", -- preconfigured style + separator_open = "", -- instead of  + separator_close = "", -- instead of  + separator_open_thin = "", -- change to anything + separator_close_thin = "", -- change to anything + separator_head = "", -- to match the style + separator_tail = "" -- to match the style +}) +``` + +![empty](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/separator-combination.png) + +_You can find more symbols [here](https://www.nerdfonts.com/cheat-sheet)_ + +### File actions icons + +You can provide your own symbols for `select` and `yank`. For example: + +```lua +require("yaziline"):setup({ + -- Optinal config + select_symbol = "", -- "S" by default + yank_symbol = "󰆐" -- "Y" by default +}) +``` + +![empty](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/file-actions.png) + +_You can find more symbols [here](https://www.nerdfonts.com/cheat-sheet)_ + +### Colors and font weight + +By default yaziline uses color values from your `theme.toml` (or flavor) but you can set custom colors in the `init.lua`: + +```lua +require("yaziline"):setup({ + color = "#98c379", + default_files_color = "darkgray", + selected_files_color = "white", + yanked_files_color = "green", + cut_files_color = "red", +}) +``` + +For example, here is how my line looks like: + +![preview-2](https://github.com/llanosrocas/yaziline.yazi/blob/master/.github/images/preview-2.png) + +### Selected and Yanked Counter + +Displays the number of selected ('S') and yanked ('Y') files on the left. If files are cut, the yank counter changes color, since its `yank --cut` under the hood. + +### Truncated filename + +Displays the truncated filename on the left, which is useful for smaller windows or long filenames. By default, it's 24 characters with trimming to 12 (6 + 6). Adjust in the `setup`. + +```lua +require("yaziline"):setup({ + filename_max_length = 24, -- truncate when filename > 24 + filename_truncate_length = 6, -- leave 6 chars on both sides + filename_truncate_separator = "..." -- the separator of the truncated filename +}) +``` + +### ISO Date for 'Modified' + +On the right, you'll find the date and time the file was modified, formatted in an [ISO](https://en.wikipedia.org/wiki/ISO_8601)-like string for universal date representation. Adjust in the `Status:date` function. + +## Credits + +- [yazi source code](https://github.com/sxyazi/yazi) +- [yatline.yazi](https://github.com/imsi32/yatline.yazi/tree/main) +- [lualine.nvim](https://github.com/nvim-lualine/lualine.nvim) diff --git a/yazi/plugins/yaziline.yazi/main.lua b/yazi/plugins/yaziline.yazi/main.lua new file mode 100644 index 0000000..2f7daac --- /dev/null +++ b/yazi/plugins/yaziline.yazi/main.lua @@ -0,0 +1,199 @@ +local function setup(_, options) + options = options or {} + + local default_separators = { + angly = { "", "", "", "" }, + curvy = { "", "", "", "" }, + liney = { "", "", "|", "|" }, + empty = { "", "", "", "" }, + } + local separators = default_separators[options.separator_style or "angly"] + + local config = { + separator_styles = { + separator_open = options.separator_open or separators[1], + separator_close = options.separator_close or separators[2], + separator_open_thin = options.separator_open_thin or separators[3], + separator_close_thin = options.separator_close_thin or separators[4], + separator_head = options.separator_head or "", + separator_tail = options.separator_tail or "", + }, + select_symbol = options.select_symbol or "S", + yank_symbol = options.yank_symbol or "Y", + + filename_max_length = options.filename_max_length or 24, + filename_truncate_length = options.filename_truncate_length or 6, + filename_truncate_separator = options.filename_truncate_separator or "...", + + color = options.color or nil, + default_files_color = options.default_files_color + or th.which.separator_style.fg + or "darkgray", + selected_files_color = options.selected_files_color + or th.mgr.count_selected.bg + or "white", + yanked_files_color = options.selected_files_color + or th.mgr.count_copied.bg + or "green", + cut_files_color = options.cut_files_color + or th.mgr.count_cut.bg + or "red", + } + + local current_separator_style = config.separator_styles + + function Header:count() + return ui.Line({}) + end + + function Status:mode() + local mode = tostring(self._tab.mode):upper() + + local style = self:style() + return ui.Line({ + ui.Span(current_separator_style.separator_head) + :fg(config.color or style.main.bg), + ui.Span(" " .. mode .. " ") + :fg(th.which.mask.bg) + :bg(config.color or style.main.bg), + }) + end + + function Status:size() + local h = self._current.hovered + local size = h and ya.readable_size(h:size() or h.cha.len) + + local style = self:style() + return ui.Span(current_separator_style.separator_close .. " " .. size .. " ") + :fg(config.color or style.main.bg) + :bg(th.which.separator_style.fg) + end + + function Status:utf8_sub(str, start_char, end_char) + local start_byte = utf8.offset(str, start_char) + local end_byte = end_char and (utf8.offset(str, end_char + 1) - 1) or #str + + if not start_byte or not end_byte then + return "" + end + + return string.sub(str, start_byte, end_byte) + end + + function Status:truncate_name(filename, max_length) + local base_name, extension = filename:match("^(.+)(%.[^%.]+)$") + base_name = base_name or filename + extension = extension or "" + + if utf8.len(base_name) > max_length then + base_name = self:utf8_sub(base_name, 1, config.filename_truncate_length) + .. config.filename_truncate_separator + .. self:utf8_sub(base_name, -config.filename_truncate_length) + end + + return base_name .. extension + end + + function Status:name() + local h = self._current.hovered + if not h then + return "" + end + + local truncated_name = self:truncate_name(h.name, config.filename_max_length) + + local style = self:style() + return ui.Line { + ui.Span(current_separator_style.separator_close .. " ") + :fg(th.which.separator_style.fg), + ui.Span(truncated_name) + :fg(config.color or style.main.bg), + } + end + + function Status:files() + local files_yanked = #cx.yanked + local files_selected = #cx.active.selected + local files_cut = cx.yanked.is_cut + + local selected_fg = files_selected > 0 + and config.selected_files_color + or config.default_files_color + local yanked_fg = files_yanked > 0 + and + (files_cut + and config.cut_files_color + or config.yanked_files_color + ) + or config.default_files_color + + local yanked_text = files_yanked > 0 + and config.yank_symbol .. " " .. files_yanked + or config.yank_symbol .. " 0" + + return ui.Line({ + ui.Span(" " .. current_separator_style.separator_close_thin .. " ") + :fg(th.which.separator_style.fg), + ui.Span(config.select_symbol .. " " .. files_selected .. " ") + :fg(selected_fg), + ui.Span(yanked_text .. " ") + :fg(yanked_fg), + }) + end + + function Status:modified() + local hovered = cx.active.current.hovered + local cha = hovered.cha + local time = (cha.mtime or 0) // 1 + + return ui.Span(os.date("%Y-%m-%d %H:%M", time) .. " " .. current_separator_style.separator_open_thin .. " ") + :fg(th.which.separator_style.fg) + end + + function Status:percent() + local percent = 0 + local cursor = self._tab.current.cursor + local length = #self._tab.current.files + if cursor ~= 0 and length ~= 0 then + percent = math.floor((cursor + 1) * 100 / length) + end + + if percent == 0 then + percent = " Top " + elseif percent == 100 then + percent = " Bot " + else + percent = string.format(" %2d%% ", percent) + end + + local style = self:style() + return ui.Line({ + ui.Span(" " .. current_separator_style.separator_open) + :fg(th.which.separator_style.fg), + ui.Span(percent) + :fg(config.color or style.main.bg) + :bg(th.which.separator_style.fg), + ui.Span(current_separator_style.separator_open) + :fg(config.color or style.main.bg) + :bg(th.which.separator_style.fg), + }) + end + + function Status:position() + local cursor = self._tab.current.cursor + local length = #self._tab.current.files + + local style = self:style() + return ui.Line({ + ui.Span(string.format(" %2d/%-2d ", math.min(cursor + 1, length), length)) + :fg(th.which.mask.bg) + :bg(config.color or style.main.bg), + ui.Span(current_separator_style.separator_tail):fg(config.color or style.main.bg), + }) + end + + Status:children_add(Status.files, 4000, Status.LEFT) + Status:children_add(Status.modified, 0, Status.RIGHT) +end + +return { setup = setup } \ No newline at end of file diff --git a/yazi/starship.toml b/yazi/starship.toml new file mode 100755 index 0000000..928afa4 --- /dev/null +++ b/yazi/starship.toml @@ -0,0 +1,8 @@ +[aws] +disabled = true + +[gcloud] +disabled = true + +[lua] +disabled = true diff --git a/yazi/theme.toml b/yazi/theme.toml new file mode 100755 index 0000000..e5620f9 --- /dev/null +++ b/yazi/theme.toml @@ -0,0 +1,756 @@ +[mgr] +cwd = { fg = "#94e2d5" } + +hovered = { fg = "#1e1e2e", bg = "#89b4fa" } +preview_hovered = { fg = "#1e1e2e", bg = "#cdd6f4" } + +find_keyword = { fg = "#f9e2af", italic = true } +find_position = { fg = "#f5c2e7", bg = "reset", italic = true } + +marker_copied = { fg = "#a6e3a1", bg = "#a6e3a1" } +marker_cut = { fg = "#f38ba8", bg = "#f38ba8" } +marker_marked = { fg = "#94e2d5", bg = "#94e2d5" } +marker_selected = { fg = "#89b4fa", bg = "#89b4fa" } + +tab_active = { fg = "#1e1e2e", bg = "#cdd6f4" } +tab_inactive = { fg = "#cdd6f4", bg = "#45475a" } +tab_width = 1 + +count_copied = { fg = "#1e1e2e", bg = "#a6e3a1" } +count_cut = { fg = "#1e1e2e", bg = "#f38ba8" } +count_selected = { fg = "#1e1e2e", bg = "#89b4fa" } + +border_symbol = "│" +border_style = { fg = "#7f849c" } + +syntect_theme = "~/.config/yazi/Catppuccin-mocha.tmTheme" + +[mode] +normal_main = { fg = "#1e1e2e", bg = "#89b4fa", bold = true } +normal_alt = { fg = "#89b4fa", bg = "#313244" } + +select_main = { fg = "#1e1e2e", bg = "#a6e3a1", bold = true } +select_alt = { fg = "#a6e3a1", bg = "#313244" } + +unset_main = { fg = "#1e1e2e", bg = "#f2cdcd", bold = true } +unset_alt = { fg = "#f2cdcd", bg = "#313244" } + +[status] +separator_open = "" +separator_close = "" + +progress_label = { fg = "#ffffff", bold = true } +progress_normal = { fg = "#89b4fa", bg = "#45475a" } +progress_error = { fg = "#f38ba8", bg = "#45475a" } + +perm_type = { fg = "#89b4fa" } +perm_read = { fg = "#f9e2af" } +perm_write = { fg = "#f38ba8" } +perm_exec = { fg = "#a6e3a1" } +perm_sep = { fg = "#7f849c" } + +[input] +border = { fg = "#89b4fa" } +title = {} +value = {} +selected = { reversed = true } + +[pick] +border = { fg = "#89b4fa" } +active = { fg = "#f5c2e7" } +inactive = {} + +[confirm] +border = { fg = "#89b4fa" } +title = { fg = "#89b4fa" } +content = {} +list = {} +btn_yes = { reversed = true } +btn_no = {} + +[cmp] +border = { fg = "#89b4fa" } + +[tasks] +border = { fg = "#89b4fa" } +title = {} +hovered = { underline = true } + +[which] +mask = { bg = "#313244" } +cand = { fg = "#94e2d5" } +rest = { fg = "#9399b2" } +desc = { fg = "#f5c2e7" } +separator = "  " +separator_style = { fg = "#585b70" } + +[help] +on = { fg = "#94e2d5" } +run = { fg = "#f5c2e7" } +desc = { fg = "#9399b2" } +hovered = { bg = "#585b70", bold = true } +footer = { fg = "#cdd6f4", bg = "#45475a" } + +[notify] +title_info = { fg = "#94e2d5" } +title_warn = { fg = "#f9e2af" } +title_error = { fg = "#f38ba8" } + +[filetype] +rules = [ + # Media + { mime = "image/*", fg = "#94e2d5" }, + { mime = "{audio,video}/*", fg = "#f9e2af" }, + + # Archives + { mime = "application/*zip", fg = "#f5c2e7" }, + { mime = "application/x-{tar,bzip*,7z-compressed,xz,rar}", fg = "#f5c2e7" }, + + # Documents + { mime = "application/{pdf,doc,rtf}", fg = "#a6e3a1" }, + + # Fallback + { name = "*", fg = "#cdd6f4" }, + { name = "*/", fg = "#89b4fa" }, +] + +[spot] +border = { fg = "#89b4fa" } +title = { fg = "#89b4fa" } +tbl_cell = { fg = "#89b4fa", reversed = true } +tbl_col = { bold = true } + +[icon] +files = [ + { name = "kritadisplayrc", text = "", fg = "#cba6f7" }, + { name = ".gtkrc-2.0", text = "", fg = "#f5e0dc" }, + { name = "bspwmrc", text = "", fg = "#313244" }, + { name = "webpack", text = "󰜫", fg = "#74c7ec" }, + { name = "tsconfig.json", text = "", fg = "#74c7ec" }, + { name = ".vimrc", text = "", fg = "#a6e3a1" }, + { name = "gemfile$", text = "", fg = "#313244" }, + { name = "xmobarrc", text = "", fg = "#f38ba8" }, + { name = "avif", text = "", fg = "#7f849c" }, + { name = "fp-info-cache", text = "", fg = "#f5e0dc" }, + { name = ".zshrc", text = "", fg = "#a6e3a1" }, + { name = "robots.txt", text = "󰚩", fg = "#6c7086" }, + { name = "dockerfile", text = "󰡨", fg = "#89b4fa" }, + { name = ".git-blame-ignore-revs", text = "", fg = "#fab387" }, + { name = ".nvmrc", text = "", fg = "#a6e3a1" }, + { name = "hyprpaper.conf", text = "", fg = "#74c7ec" }, + { name = ".prettierignore", text = "", fg = "#89b4fa" }, + { name = "rakefile", text = "", fg = "#313244" }, + { name = "code_of_conduct", text = "", fg = "#f38ba8" }, + { name = "cmakelists.txt", text = "", fg = "#cdd6f4" }, + { name = ".env", text = "", fg = "#f9e2af" }, + { name = "copying.lesser", text = "", fg = "#f9e2af" }, + { name = "readme", text = "󰂺", fg = "#f5e0dc" }, + { name = "settings.gradle", text = "", fg = "#585b70" }, + { name = "gruntfile.coffee", text = "", fg = "#fab387" }, + { name = ".eslintignore", text = "", fg = "#585b70" }, + { name = "kalgebrarc", text = "", fg = "#89b4fa" }, + { name = "kdenliverc", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.cjs", text = "", fg = "#89b4fa" }, + { name = "cantorrc", text = "", fg = "#89b4fa" }, + { name = "rmd", text = "", fg = "#74c7ec" }, + { name = "vagrantfile$", text = "", fg = "#6c7086" }, + { name = ".Xauthority", text = "", fg = "#fab387" }, + { name = "prettier.config.ts", text = "", fg = "#89b4fa" }, + { name = "node_modules", text = "", fg = "#f38ba8" }, + { name = ".prettierrc.toml", text = "", fg = "#89b4fa" }, + { name = "build.zig.zon", text = "", fg = "#fab387" }, + { name = ".ds_store", text = "", fg = "#45475a" }, + { name = "PKGBUILD", text = "", fg = "#89b4fa" }, + { name = ".prettierrc", text = "", fg = "#89b4fa" }, + { name = ".bash_profile", text = "", fg = "#a6e3a1" }, + { name = ".npmignore", text = "", fg = "#f38ba8" }, + { name = ".mailmap", text = "󰊢", fg = "#fab387" }, + { name = ".codespellrc", text = "󰓆", fg = "#a6e3a1" }, + { name = "svelte.config.js", text = "", fg = "#fab387" }, + { name = "eslint.config.ts", text = "", fg = "#585b70" }, + { name = "config", text = "", fg = "#7f849c" }, + { name = ".gitlab-ci.yml", text = "", fg = "#fab387" }, + { name = ".gitconfig", text = "", fg = "#fab387" }, + { name = "_gvimrc", text = "", fg = "#a6e3a1" }, + { name = ".xinitrc", text = "", fg = "#fab387" }, + { name = "checkhealth", text = "󰓙", fg = "#89b4fa" }, + { name = "sxhkdrc", text = "", fg = "#313244" }, + { name = ".bashrc", text = "", fg = "#a6e3a1" }, + { name = "tailwind.config.mjs", text = "󱏿", fg = "#74c7ec" }, + { name = "ext_typoscript_setup.txt", text = "", fg = "#fab387" }, + { name = "commitlint.config.ts", text = "󰜘", fg = "#94e2d5" }, + { name = "py.typed", text = "", fg = "#f9e2af" }, + { name = ".nanorc", text = "", fg = "#313244" }, + { name = "commit_editmsg", text = "", fg = "#fab387" }, + { name = ".luaurc", text = "", fg = "#89b4fa" }, + { name = "fp-lib-table", text = "", fg = "#f5e0dc" }, + { name = ".editorconfig", text = "", fg = "#f5e0dc" }, + { name = "justfile", text = "", fg = "#7f849c" }, + { name = "kdeglobals", text = "", fg = "#89b4fa" }, + { name = "license.md", text = "", fg = "#f9e2af" }, + { name = ".clang-format", text = "", fg = "#7f849c" }, + { name = "docker-compose.yaml", text = "󰡨", fg = "#89b4fa" }, + { name = "copying", text = "", fg = "#f9e2af" }, + { name = "go.mod", text = "", fg = "#74c7ec" }, + { name = "lxqt.conf", text = "", fg = "#89b4fa" }, + { name = "brewfile", text = "", fg = "#313244" }, + { name = "gulpfile.coffee", text = "", fg = "#f38ba8" }, + { name = ".dockerignore", text = "󰡨", fg = "#89b4fa" }, + { name = ".settings.json", text = "", fg = "#6c7086" }, + { name = "tailwind.config.js", text = "󱏿", fg = "#74c7ec" }, + { name = ".clang-tidy", text = "", fg = "#7f849c" }, + { name = ".gvimrc", text = "", fg = "#a6e3a1" }, + { name = "nuxt.config.cjs", text = "󱄆", fg = "#a6e3a1" }, + { name = "xsettingsd.conf", text = "", fg = "#fab387" }, + { name = "nuxt.config.js", text = "󱄆", fg = "#a6e3a1" }, + { name = "eslint.config.cjs", text = "", fg = "#585b70" }, + { name = "sym-lib-table", text = "", fg = "#f5e0dc" }, + { name = ".condarc", text = "", fg = "#a6e3a1" }, + { name = "xmonad.hs", text = "", fg = "#f38ba8" }, + { name = "tmux.conf", text = "", fg = "#a6e3a1" }, + { name = "xmobarrc.hs", text = "", fg = "#f38ba8" }, + { name = ".prettierrc.yaml", text = "", fg = "#89b4fa" }, + { name = ".pre-commit-config.yaml", text = "󰛢", fg = "#fab387" }, + { name = "i3blocks.conf", text = "", fg = "#f5e0dc" }, + { name = "xorg.conf", text = "", fg = "#fab387" }, + { name = ".zshenv", text = "", fg = "#a6e3a1" }, + { name = "vlcrc", text = "󰕼", fg = "#fab387" }, + { name = "license", text = "", fg = "#f9e2af" }, + { name = "unlicense", text = "", fg = "#f9e2af" }, + { name = "tmux.conf.local", text = "", fg = "#a6e3a1" }, + { name = ".SRCINFO", text = "󰣇", fg = "#89b4fa" }, + { name = "tailwind.config.ts", text = "󱏿", fg = "#74c7ec" }, + { name = "security.md", text = "󰒃", fg = "#bac2de" }, + { name = "security", text = "󰒃", fg = "#bac2de" }, + { name = ".eslintrc", text = "", fg = "#585b70" }, + { name = "gradle.properties", text = "", fg = "#585b70" }, + { name = "code_of_conduct.md", text = "", fg = "#f38ba8" }, + { name = "PrusaSlicerGcodeViewer.ini", text = "", fg = "#fab387" }, + { name = "PrusaSlicer.ini", text = "", fg = "#fab387" }, + { name = "procfile", text = "", fg = "#7f849c" }, + { name = "mpv.conf", text = "", fg = "#1e1e2e" }, + { name = ".prettierrc.json5", text = "", fg = "#89b4fa" }, + { name = "i3status.conf", text = "", fg = "#f5e0dc" }, + { name = "prettier.config.mjs", text = "", fg = "#89b4fa" }, + { name = ".pylintrc", text = "", fg = "#7f849c" }, + { name = "prettier.config.cjs", text = "", fg = "#89b4fa" }, + { name = ".luacheckrc", text = "", fg = "#89b4fa" }, + { name = "containerfile", text = "󰡨", fg = "#89b4fa" }, + { name = "eslint.config.mjs", text = "", fg = "#585b70" }, + { name = "gruntfile.js", text = "", fg = "#fab387" }, + { name = "bun.lockb", text = "", fg = "#f5e0dc" }, + { name = ".gitattributes", text = "", fg = "#fab387" }, + { name = "gruntfile.ts", text = "", fg = "#fab387" }, + { name = "pom.xml", text = "", fg = "#313244" }, + { name = "favicon.ico", text = "", fg = "#f9e2af" }, + { name = "package-lock.json", text = "", fg = "#313244" }, + { name = "build", text = "", fg = "#a6e3a1" }, + { name = "package.json", text = "", fg = "#f38ba8" }, + { name = "nuxt.config.ts", text = "󱄆", fg = "#a6e3a1" }, + { name = "nuxt.config.mjs", text = "󱄆", fg = "#a6e3a1" }, + { name = "mix.lock", text = "", fg = "#7f849c" }, + { name = "makefile", text = "", fg = "#7f849c" }, + { name = "gulpfile.js", text = "", fg = "#f38ba8" }, + { name = "lxde-rc.xml", text = "", fg = "#9399b2" }, + { name = "kritarc", text = "", fg = "#cba6f7" }, + { name = "gtkrc", text = "", fg = "#f5e0dc" }, + { name = "ionic.config.json", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.mjs", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.yml", text = "", fg = "#89b4fa" }, + { name = ".npmrc", text = "", fg = "#f38ba8" }, + { name = "weston.ini", text = "", fg = "#f9e2af" }, + { name = "gulpfile.babel.js", text = "", fg = "#f38ba8" }, + { name = "i18n.config.ts", text = "󰗊", fg = "#7f849c" }, + { name = "commitlint.config.js", text = "󰜘", fg = "#94e2d5" }, + { name = ".gitmodules", text = "", fg = "#fab387" }, + { name = "gradle-wrapper.properties", text = "", fg = "#585b70" }, + { name = "hypridle.conf", text = "", fg = "#74c7ec" }, + { name = "vercel.json", text = "▲", fg = "#f5e0dc" }, + { name = "hyprlock.conf", text = "", fg = "#74c7ec" }, + { name = "go.sum", text = "", fg = "#74c7ec" }, + { name = "kdenlive-layoutsrc", text = "", fg = "#89b4fa" }, + { name = "gruntfile.babel.js", text = "", fg = "#fab387" }, + { name = "compose.yml", text = "󰡨", fg = "#89b4fa" }, + { name = "i18n.config.js", text = "󰗊", fg = "#7f849c" }, + { name = "readme.md", text = "󰂺", fg = "#f5e0dc" }, + { name = "gradlew", text = "", fg = "#585b70" }, + { name = "go.work", text = "", fg = "#74c7ec" }, + { name = "gulpfile.ts", text = "", fg = "#f38ba8" }, + { name = "gnumakefile", text = "", fg = "#7f849c" }, + { name = "FreeCAD.conf", text = "", fg = "#f38ba8" }, + { name = "compose.yaml", text = "󰡨", fg = "#89b4fa" }, + { name = "eslint.config.js", text = "", fg = "#585b70" }, + { name = "hyprland.conf", text = "", fg = "#74c7ec" }, + { name = "docker-compose.yml", text = "󰡨", fg = "#89b4fa" }, + { name = "groovy", text = "", fg = "#585b70" }, + { name = "QtProject.conf", text = "", fg = "#a6e3a1" }, + { name = "platformio.ini", text = "", fg = "#fab387" }, + { name = "build.gradle", text = "", fg = "#585b70" }, + { name = ".nuxtrc", text = "󱄆", fg = "#a6e3a1" }, + { name = "_vimrc", text = "", fg = "#a6e3a1" }, + { name = ".zprofile", text = "", fg = "#a6e3a1" }, + { name = ".xsession", text = "", fg = "#fab387" }, + { name = "prettier.config.js", text = "", fg = "#89b4fa" }, + { name = ".babelrc", text = "", fg = "#f9e2af" }, + { name = "workspace", text = "", fg = "#a6e3a1" }, + { name = ".prettierrc.json", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.js", text = "", fg = "#89b4fa" }, + { name = ".Xresources", text = "", fg = "#fab387" }, + { name = ".gitignore", text = "", fg = "#fab387" }, + { name = ".justfile", text = "", fg = "#7f849c" }, +] +exts = [ + { name = "otf", text = "", fg = "#f5e0dc" }, + { name = "import", text = "", fg = "#f5e0dc" }, + { name = "krz", text = "", fg = "#cba6f7" }, + { name = "adb", text = "", fg = "#94e2d5" }, + { name = "ttf", text = "", fg = "#f5e0dc" }, + { name = "webpack", text = "󰜫", fg = "#74c7ec" }, + { name = "dart", text = "", fg = "#585b70" }, + { name = "vsh", text = "", fg = "#7f849c" }, + { name = "doc", text = "󰈬", fg = "#585b70" }, + { name = "zsh", text = "", fg = "#a6e3a1" }, + { name = "ex", text = "", fg = "#7f849c" }, + { name = "hx", text = "", fg = "#fab387" }, + { name = "fodt", text = "", fg = "#74c7ec" }, + { name = "mojo", text = "", fg = "#fab387" }, + { name = "templ", text = "", fg = "#f9e2af" }, + { name = "nix", text = "", fg = "#74c7ec" }, + { name = "cshtml", text = "󱦗", fg = "#585b70" }, + { name = "fish", text = "", fg = "#585b70" }, + { name = "ply", text = "󰆧", fg = "#7f849c" }, + { name = "sldprt", text = "󰻫", fg = "#a6e3a1" }, + { name = "gemspec", text = "", fg = "#313244" }, + { name = "mjs", text = "", fg = "#f9e2af" }, + { name = "csh", text = "", fg = "#585b70" }, + { name = "cmake", text = "", fg = "#cdd6f4" }, + { name = "fodp", text = "", fg = "#fab387" }, + { name = "vi", text = "", fg = "#f9e2af" }, + { name = "msf", text = "", fg = "#89b4fa" }, + { name = "blp", text = "󰺾", fg = "#89b4fa" }, + { name = "less", text = "", fg = "#45475a" }, + { name = "sh", text = "", fg = "#585b70" }, + { name = "odg", text = "", fg = "#f9e2af" }, + { name = "mint", text = "󰌪", fg = "#a6e3a1" }, + { name = "dll", text = "", fg = "#11111b" }, + { name = "odf", text = "", fg = "#f38ba8" }, + { name = "sqlite3", text = "", fg = "#f5e0dc" }, + { name = "Dockerfile", text = "󰡨", fg = "#89b4fa" }, + { name = "ksh", text = "", fg = "#585b70" }, + { name = "rmd", text = "", fg = "#74c7ec" }, + { name = "wv", text = "", fg = "#74c7ec" }, + { name = "xml", text = "󰗀", fg = "#fab387" }, + { name = "markdown", text = "", fg = "#cdd6f4" }, + { name = "qml", text = "", fg = "#a6e3a1" }, + { name = "3gp", text = "", fg = "#fab387" }, + { name = "pxi", text = "", fg = "#89b4fa" }, + { name = "flac", text = "", fg = "#6c7086" }, + { name = "gpr", text = "", fg = "#cba6f7" }, + { name = "huff", text = "󰡘", fg = "#585b70" }, + { name = "json", text = "", fg = "#f9e2af" }, + { name = "gv", text = "󱁉", fg = "#585b70" }, + { name = "bmp", text = "", fg = "#7f849c" }, + { name = "lock", text = "", fg = "#bac2de" }, + { name = "sha384", text = "󰕥", fg = "#7f849c" }, + { name = "cobol", text = "⚙", fg = "#585b70" }, + { name = "cob", text = "⚙", fg = "#585b70" }, + { name = "java", text = "", fg = "#f38ba8" }, + { name = "cjs", text = "", fg = "#f9e2af" }, + { name = "qm", text = "", fg = "#74c7ec" }, + { name = "ebuild", text = "", fg = "#45475a" }, + { name = "mustache", text = "", fg = "#fab387" }, + { name = "terminal", text = "", fg = "#a6e3a1" }, + { name = "ejs", text = "", fg = "#f9e2af" }, + { name = "brep", text = "󰻫", fg = "#a6e3a1" }, + { name = "rar", text = "", fg = "#fab387" }, + { name = "gradle", text = "", fg = "#585b70" }, + { name = "gnumakefile", text = "", fg = "#7f849c" }, + { name = "applescript", text = "", fg = "#7f849c" }, + { name = "elm", text = "", fg = "#74c7ec" }, + { name = "ebook", text = "", fg = "#fab387" }, + { name = "kra", text = "", fg = "#cba6f7" }, + { name = "tf", text = "", fg = "#585b70" }, + { name = "xls", text = "󰈛", fg = "#585b70" }, + { name = "fnl", text = "", fg = "#f9e2af" }, + { name = "kdbx", text = "", fg = "#a6e3a1" }, + { name = "kicad_pcb", text = "", fg = "#f5e0dc" }, + { name = "cfg", text = "", fg = "#7f849c" }, + { name = "ape", text = "", fg = "#74c7ec" }, + { name = "org", text = "", fg = "#94e2d5" }, + { name = "yml", text = "", fg = "#7f849c" }, + { name = "swift", text = "", fg = "#fab387" }, + { name = "eln", text = "", fg = "#7f849c" }, + { name = "sol", text = "", fg = "#74c7ec" }, + { name = "awk", text = "", fg = "#585b70" }, + { name = "7z", text = "", fg = "#fab387" }, + { name = "apl", text = "⍝", fg = "#fab387" }, + { name = "epp", text = "", fg = "#fab387" }, + { name = "app", text = "", fg = "#45475a" }, + { name = "dot", text = "󱁉", fg = "#585b70" }, + { name = "kpp", text = "", fg = "#cba6f7" }, + { name = "eot", text = "", fg = "#f5e0dc" }, + { name = "hpp", text = "", fg = "#7f849c" }, + { name = "spec.tsx", text = "", fg = "#585b70" }, + { name = "hurl", text = "", fg = "#f38ba8" }, + { name = "cxxm", text = "", fg = "#74c7ec" }, + { name = "c", text = "", fg = "#89b4fa" }, + { name = "fcmacro", text = "", fg = "#f38ba8" }, + { name = "sass", text = "", fg = "#f38ba8" }, + { name = "yaml", text = "", fg = "#7f849c" }, + { name = "xz", text = "", fg = "#fab387" }, + { name = "material", text = "󰔉", fg = "#f38ba8" }, + { name = "json5", text = "", fg = "#f9e2af" }, + { name = "signature", text = "λ", fg = "#fab387" }, + { name = "3mf", text = "󰆧", fg = "#7f849c" }, + { name = "jpg", text = "", fg = "#7f849c" }, + { name = "xpi", text = "", fg = "#fab387" }, + { name = "fcmat", text = "", fg = "#f38ba8" }, + { name = "pot", text = "", fg = "#74c7ec" }, + { name = "bin", text = "", fg = "#45475a" }, + { name = "xlsx", text = "󰈛", fg = "#585b70" }, + { name = "aac", text = "", fg = "#74c7ec" }, + { name = "kicad_sym", text = "", fg = "#f5e0dc" }, + { name = "xcstrings", text = "", fg = "#74c7ec" }, + { name = "lff", text = "", fg = "#f5e0dc" }, + { name = "xcf", text = "", fg = "#585b70" }, + { name = "azcli", text = "", fg = "#6c7086" }, + { name = "license", text = "", fg = "#f9e2af" }, + { name = "jsonc", text = "", fg = "#f9e2af" }, + { name = "xaml", text = "󰙳", fg = "#585b70" }, + { name = "md5", text = "󰕥", fg = "#7f849c" }, + { name = "xm", text = "", fg = "#74c7ec" }, + { name = "sln", text = "", fg = "#6c7086" }, + { name = "jl", text = "", fg = "#7f849c" }, + { name = "ml", text = "", fg = "#fab387" }, + { name = "http", text = "", fg = "#89b4fa" }, + { name = "x", text = "", fg = "#89b4fa" }, + { name = "wvc", text = "", fg = "#74c7ec" }, + { name = "wrz", text = "󰆧", fg = "#7f849c" }, + { name = "csproj", text = "󰪮", fg = "#585b70" }, + { name = "wrl", text = "󰆧", fg = "#7f849c" }, + { name = "wma", text = "", fg = "#74c7ec" }, + { name = "woff2", text = "", fg = "#f5e0dc" }, + { name = "woff", text = "", fg = "#f5e0dc" }, + { name = "tscn", text = "", fg = "#7f849c" }, + { name = "webmanifest", text = "", fg = "#f9e2af" }, + { name = "webm", text = "", fg = "#fab387" }, + { name = "fcbak", text = "", fg = "#f38ba8" }, + { name = "log", text = "󰌱", fg = "#cdd6f4" }, + { name = "wav", text = "", fg = "#74c7ec" }, + { name = "wasm", text = "", fg = "#585b70" }, + { name = "styl", text = "", fg = "#a6e3a1" }, + { name = "gif", text = "", fg = "#7f849c" }, + { name = "resi", text = "", fg = "#f38ba8" }, + { name = "aiff", text = "", fg = "#74c7ec" }, + { name = "sha256", text = "󰕥", fg = "#7f849c" }, + { name = "igs", text = "󰻫", fg = "#a6e3a1" }, + { name = "vsix", text = "", fg = "#6c7086" }, + { name = "vim", text = "", fg = "#a6e3a1" }, + { name = "diff", text = "", fg = "#45475a" }, + { name = "drl", text = "", fg = "#eba0ac" }, + { name = "erl", text = "", fg = "#f38ba8" }, + { name = "vhdl", text = "󰍛", fg = "#a6e3a1" }, + { name = "🔥", text = "", fg = "#fab387" }, + { name = "hrl", text = "", fg = "#f38ba8" }, + { name = "fsi", text = "", fg = "#74c7ec" }, + { name = "mm", text = "", fg = "#74c7ec" }, + { name = "bz", text = "", fg = "#fab387" }, + { name = "vh", text = "󰍛", fg = "#a6e3a1" }, + { name = "kdb", text = "", fg = "#a6e3a1" }, + { name = "gz", text = "", fg = "#fab387" }, + { name = "cpp", text = "", fg = "#74c7ec" }, + { name = "ui", text = "", fg = "#6c7086" }, + { name = "txt", text = "󰈙", fg = "#a6e3a1" }, + { name = "spec.ts", text = "", fg = "#74c7ec" }, + { name = "ccm", text = "", fg = "#f38ba8" }, + { name = "typoscript", text = "", fg = "#fab387" }, + { name = "typ", text = "", fg = "#89dceb" }, + { name = "txz", text = "", fg = "#fab387" }, + { name = "test.ts", text = "", fg = "#74c7ec" }, + { name = "tsx", text = "", fg = "#585b70" }, + { name = "mk", text = "", fg = "#7f849c" }, + { name = "webp", text = "", fg = "#7f849c" }, + { name = "opus", text = "", fg = "#6c7086" }, + { name = "bicep", text = "", fg = "#74c7ec" }, + { name = "ts", text = "", fg = "#74c7ec" }, + { name = "tres", text = "", fg = "#7f849c" }, + { name = "torrent", text = "", fg = "#94e2d5" }, + { name = "cxx", text = "", fg = "#74c7ec" }, + { name = "iso", text = "", fg = "#f2cdcd" }, + { name = "ixx", text = "", fg = "#74c7ec" }, + { name = "hxx", text = "", fg = "#7f849c" }, + { name = "gql", text = "", fg = "#f38ba8" }, + { name = "tmux", text = "", fg = "#a6e3a1" }, + { name = "ini", text = "", fg = "#7f849c" }, + { name = "m3u8", text = "󰲹", fg = "#f38ba8" }, + { name = "image", text = "", fg = "#f2cdcd" }, + { name = "tfvars", text = "", fg = "#585b70" }, + { name = "tex", text = "", fg = "#45475a" }, + { name = "cbl", text = "⚙", fg = "#585b70" }, + { name = "flc", text = "", fg = "#f5e0dc" }, + { name = "elc", text = "", fg = "#7f849c" }, + { name = "test.tsx", text = "", fg = "#585b70" }, + { name = "twig", text = "", fg = "#a6e3a1" }, + { name = "sql", text = "", fg = "#f5e0dc" }, + { name = "test.jsx", text = "", fg = "#74c7ec" }, + { name = "htm", text = "", fg = "#fab387" }, + { name = "gcode", text = "󰐫", fg = "#6c7086" }, + { name = "test.js", text = "", fg = "#f9e2af" }, + { name = "ino", text = "", fg = "#74c7ec" }, + { name = "tcl", text = "󰛓", fg = "#585b70" }, + { name = "cljs", text = "", fg = "#74c7ec" }, + { name = "tsconfig", text = "", fg = "#fab387" }, + { name = "img", text = "", fg = "#f2cdcd" }, + { name = "t", text = "", fg = "#74c7ec" }, + { name = "fcstd1", text = "", fg = "#f38ba8" }, + { name = "out", text = "", fg = "#45475a" }, + { name = "jsx", text = "", fg = "#74c7ec" }, + { name = "bash", text = "", fg = "#a6e3a1" }, + { name = "edn", text = "", fg = "#74c7ec" }, + { name = "rss", text = "", fg = "#fab387" }, + { name = "flf", text = "", fg = "#f5e0dc" }, + { name = "cache", text = "", fg = "#f5e0dc" }, + { name = "sbt", text = "", fg = "#f38ba8" }, + { name = "cppm", text = "", fg = "#74c7ec" }, + { name = "svelte", text = "", fg = "#fab387" }, + { name = "mo", text = "∞", fg = "#7f849c" }, + { name = "sv", text = "󰍛", fg = "#a6e3a1" }, + { name = "ko", text = "", fg = "#f5e0dc" }, + { name = "suo", text = "", fg = "#6c7086" }, + { name = "sldasm", text = "󰻫", fg = "#a6e3a1" }, + { name = "icalendar", text = "", fg = "#313244" }, + { name = "go", text = "", fg = "#74c7ec" }, + { name = "sublime", text = "", fg = "#fab387" }, + { name = "stl", text = "󰆧", fg = "#7f849c" }, + { name = "mobi", text = "", fg = "#fab387" }, + { name = "graphql", text = "", fg = "#f38ba8" }, + { name = "m3u", text = "󰲹", fg = "#f38ba8" }, + { name = "cpy", text = "⚙", fg = "#585b70" }, + { name = "kdenlive", text = "", fg = "#89b4fa" }, + { name = "pyo", text = "", fg = "#f9e2af" }, + { name = "po", text = "", fg = "#74c7ec" }, + { name = "scala", text = "", fg = "#f38ba8" }, + { name = "exs", text = "", fg = "#7f849c" }, + { name = "odp", text = "", fg = "#fab387" }, + { name = "dump", text = "", fg = "#f5e0dc" }, + { name = "stp", text = "󰻫", fg = "#a6e3a1" }, + { name = "step", text = "󰻫", fg = "#a6e3a1" }, + { name = "ste", text = "󰻫", fg = "#a6e3a1" }, + { name = "aif", text = "", fg = "#74c7ec" }, + { name = "strings", text = "", fg = "#74c7ec" }, + { name = "cp", text = "", fg = "#74c7ec" }, + { name = "fsscript", text = "", fg = "#74c7ec" }, + { name = "mli", text = "", fg = "#fab387" }, + { name = "bak", text = "󰁯", fg = "#7f849c" }, + { name = "ssa", text = "󰨖", fg = "#f9e2af" }, + { name = "toml", text = "", fg = "#585b70" }, + { name = "makefile", text = "", fg = "#7f849c" }, + { name = "php", text = "", fg = "#7f849c" }, + { name = "zst", text = "", fg = "#fab387" }, + { name = "spec.jsx", text = "", fg = "#74c7ec" }, + { name = "kbx", text = "󰯄", fg = "#6c7086" }, + { name = "fbx", text = "󰆧", fg = "#7f849c" }, + { name = "blend", text = "󰂫", fg = "#fab387" }, + { name = "ifc", text = "󰻫", fg = "#a6e3a1" }, + { name = "spec.js", text = "", fg = "#f9e2af" }, + { name = "so", text = "", fg = "#f5e0dc" }, + { name = "desktop", text = "", fg = "#45475a" }, + { name = "sml", text = "λ", fg = "#fab387" }, + { name = "slvs", text = "󰻫", fg = "#a6e3a1" }, + { name = "pp", text = "", fg = "#fab387" }, + { name = "ps1", text = "󰨊", fg = "#6c7086" }, + { name = "dropbox", text = "", fg = "#6c7086" }, + { name = "kicad_mod", text = "", fg = "#f5e0dc" }, + { name = "bat", text = "", fg = "#a6e3a1" }, + { name = "slim", text = "", fg = "#fab387" }, + { name = "skp", text = "󰻫", fg = "#a6e3a1" }, + { name = "css", text = "", fg = "#89b4fa" }, + { name = "xul", text = "", fg = "#fab387" }, + { name = "ige", text = "󰻫", fg = "#a6e3a1" }, + { name = "glb", text = "", fg = "#fab387" }, + { name = "ppt", text = "󰈧", fg = "#f38ba8" }, + { name = "sha512", text = "󰕥", fg = "#7f849c" }, + { name = "ics", text = "", fg = "#313244" }, + { name = "mdx", text = "", fg = "#74c7ec" }, + { name = "sha1", text = "󰕥", fg = "#7f849c" }, + { name = "f3d", text = "󰻫", fg = "#a6e3a1" }, + { name = "ass", text = "󰨖", fg = "#f9e2af" }, + { name = "godot", text = "", fg = "#7f849c" }, + { name = "ifb", text = "", fg = "#313244" }, + { name = "cson", text = "", fg = "#f9e2af" }, + { name = "lib", text = "", fg = "#11111b" }, + { name = "luac", text = "", fg = "#74c7ec" }, + { name = "heex", text = "", fg = "#7f849c" }, + { name = "scm", text = "󰘧", fg = "#f5e0dc" }, + { name = "psd1", text = "󰨊", fg = "#7f849c" }, + { name = "sc", text = "", fg = "#f38ba8" }, + { name = "scad", text = "", fg = "#f9e2af" }, + { name = "kts", text = "", fg = "#6c7086" }, + { name = "svh", text = "󰍛", fg = "#a6e3a1" }, + { name = "mts", text = "", fg = "#74c7ec" }, + { name = "nfo", text = "", fg = "#f9e2af" }, + { name = "pck", text = "", fg = "#7f849c" }, + { name = "rproj", text = "󰗆", fg = "#a6e3a1" }, + { name = "rlib", text = "", fg = "#fab387" }, + { name = "cljd", text = "", fg = "#74c7ec" }, + { name = "ods", text = "", fg = "#a6e3a1" }, + { name = "res", text = "", fg = "#f38ba8" }, + { name = "apk", text = "", fg = "#a6e3a1" }, + { name = "haml", text = "", fg = "#f5e0dc" }, + { name = "d.ts", text = "", fg = "#fab387" }, + { name = "razor", text = "󱦘", fg = "#585b70" }, + { name = "rake", text = "", fg = "#313244" }, + { name = "patch", text = "", fg = "#45475a" }, + { name = "cuh", text = "", fg = "#7f849c" }, + { name = "d", text = "", fg = "#f38ba8" }, + { name = "query", text = "", fg = "#a6e3a1" }, + { name = "psb", text = "", fg = "#74c7ec" }, + { name = "nu", text = ">", fg = "#a6e3a1" }, + { name = "mov", text = "", fg = "#fab387" }, + { name = "lrc", text = "󰨖", fg = "#f9e2af" }, + { name = "pyx", text = "", fg = "#89b4fa" }, + { name = "pyw", text = "", fg = "#89b4fa" }, + { name = "cu", text = "", fg = "#a6e3a1" }, + { name = "bazel", text = "", fg = "#a6e3a1" }, + { name = "obj", text = "󰆧", fg = "#7f849c" }, + { name = "pyi", text = "", fg = "#f9e2af" }, + { name = "pyd", text = "", fg = "#f9e2af" }, + { name = "exe", text = "", fg = "#45475a" }, + { name = "pyc", text = "", fg = "#f9e2af" }, + { name = "fctb", text = "", fg = "#f38ba8" }, + { name = "part", text = "", fg = "#94e2d5" }, + { name = "blade.php", text = "", fg = "#f38ba8" }, + { name = "git", text = "", fg = "#fab387" }, + { name = "psd", text = "", fg = "#74c7ec" }, + { name = "qss", text = "", fg = "#a6e3a1" }, + { name = "csv", text = "", fg = "#a6e3a1" }, + { name = "psm1", text = "󰨊", fg = "#7f849c" }, + { name = "dconf", text = "", fg = "#f5e0dc" }, + { name = "config.ru", text = "", fg = "#313244" }, + { name = "prisma", text = "", fg = "#6c7086" }, + { name = "conf", text = "", fg = "#7f849c" }, + { name = "clj", text = "", fg = "#a6e3a1" }, + { name = "o", text = "", fg = "#45475a" }, + { name = "mp4", text = "", fg = "#fab387" }, + { name = "cc", text = "", fg = "#f38ba8" }, + { name = "kicad_prl", text = "", fg = "#f5e0dc" }, + { name = "bz3", text = "", fg = "#fab387" }, + { name = "asc", text = "󰦝", fg = "#6c7086" }, + { name = "png", text = "", fg = "#7f849c" }, + { name = "android", text = "", fg = "#a6e3a1" }, + { name = "pm", text = "", fg = "#74c7ec" }, + { name = "h", text = "", fg = "#7f849c" }, + { name = "pls", text = "󰲹", fg = "#f38ba8" }, + { name = "ipynb", text = "", fg = "#fab387" }, + { name = "pl", text = "", fg = "#74c7ec" }, + { name = "ads", text = "", fg = "#f5e0dc" }, + { name = "sqlite", text = "", fg = "#f5e0dc" }, + { name = "pdf", text = "", fg = "#585b70" }, + { name = "pcm", text = "", fg = "#6c7086" }, + { name = "ico", text = "", fg = "#f9e2af" }, + { name = "a", text = "", fg = "#f5e0dc" }, + { name = "R", text = "󰟔", fg = "#6c7086" }, + { name = "ogg", text = "", fg = "#6c7086" }, + { name = "pxd", text = "", fg = "#89b4fa" }, + { name = "kdenlivetitle", text = "", fg = "#89b4fa" }, + { name = "jxl", text = "", fg = "#7f849c" }, + { name = "nswag", text = "", fg = "#a6e3a1" }, + { name = "nim", text = "", fg = "#f9e2af" }, + { name = "bqn", text = "⎉", fg = "#6c7086" }, + { name = "cts", text = "", fg = "#74c7ec" }, + { name = "fcparam", text = "", fg = "#f38ba8" }, + { name = "rs", text = "", fg = "#fab387" }, + { name = "mpp", text = "", fg = "#74c7ec" }, + { name = "fdmdownload", text = "", fg = "#94e2d5" }, + { name = "pptx", text = "󰈧", fg = "#f38ba8" }, + { name = "jpeg", text = "", fg = "#7f849c" }, + { name = "bib", text = "󱉟", fg = "#f9e2af" }, + { name = "vhd", text = "󰍛", fg = "#a6e3a1" }, + { name = "m", text = "", fg = "#89b4fa" }, + { name = "js", text = "", fg = "#f9e2af" }, + { name = "eex", text = "", fg = "#7f849c" }, + { name = "tbc", text = "󰛓", fg = "#585b70" }, + { name = "astro", text = "", fg = "#f38ba8" }, + { name = "sha224", text = "󰕥", fg = "#7f849c" }, + { name = "xcplayground", text = "", fg = "#fab387" }, + { name = "el", text = "", fg = "#7f849c" }, + { name = "m4v", text = "", fg = "#fab387" }, + { name = "m4a", text = "", fg = "#74c7ec" }, + { name = "cs", text = "󰌛", fg = "#585b70" }, + { name = "hs", text = "", fg = "#7f849c" }, + { name = "tgz", text = "", fg = "#fab387" }, + { name = "fs", text = "", fg = "#74c7ec" }, + { name = "luau", text = "", fg = "#89b4fa" }, + { name = "dxf", text = "󰻫", fg = "#a6e3a1" }, + { name = "download", text = "", fg = "#94e2d5" }, + { name = "cast", text = "", fg = "#fab387" }, + { name = "qrc", text = "", fg = "#a6e3a1" }, + { name = "lua", text = "", fg = "#74c7ec" }, + { name = "lhs", text = "", fg = "#7f849c" }, + { name = "md", text = "", fg = "#cdd6f4" }, + { name = "leex", text = "", fg = "#7f849c" }, + { name = "ai", text = "", fg = "#f9e2af" }, + { name = "lck", text = "", fg = "#bac2de" }, + { name = "kt", text = "", fg = "#6c7086" }, + { name = "bicepparam", text = "", fg = "#7f849c" }, + { name = "hex", text = "", fg = "#6c7086" }, + { name = "zig", text = "", fg = "#fab387" }, + { name = "bzl", text = "", fg = "#a6e3a1" }, + { name = "cljc", text = "", fg = "#a6e3a1" }, + { name = "kicad_dru", text = "", fg = "#f5e0dc" }, + { name = "fctl", text = "", fg = "#f38ba8" }, + { name = "f#", text = "", fg = "#74c7ec" }, + { name = "odt", text = "", fg = "#74c7ec" }, + { name = "conda", text = "", fg = "#a6e3a1" }, + { name = "vala", text = "", fg = "#585b70" }, + { name = "erb", text = "", fg = "#313244" }, + { name = "mp3", text = "", fg = "#74c7ec" }, + { name = "bz2", text = "", fg = "#fab387" }, + { name = "coffee", text = "", fg = "#f9e2af" }, + { name = "cr", text = "", fg = "#f5e0dc" }, + { name = "f90", text = "󱈚", fg = "#585b70" }, + { name = "jwmrc", text = "", fg = "#6c7086" }, + { name = "c++", text = "", fg = "#f38ba8" }, + { name = "fcscript", text = "", fg = "#f38ba8" }, + { name = "fods", text = "", fg = "#a6e3a1" }, + { name = "cue", text = "󰲹", fg = "#f38ba8" }, + { name = "srt", text = "󰨖", fg = "#f9e2af" }, + { name = "info", text = "", fg = "#f9e2af" }, + { name = "hh", text = "", fg = "#7f849c" }, + { name = "sig", text = "λ", fg = "#fab387" }, + { name = "html", text = "", fg = "#fab387" }, + { name = "iges", text = "󰻫", fg = "#a6e3a1" }, + { name = "kicad_wks", text = "", fg = "#f5e0dc" }, + { name = "hbs", text = "", fg = "#fab387" }, + { name = "fcstd", text = "", fg = "#f38ba8" }, + { name = "gresource", text = "", fg = "#f5e0dc" }, + { name = "sub", text = "󰨖", fg = "#f9e2af" }, + { name = "ical", text = "", fg = "#313244" }, + { name = "crdownload", text = "", fg = "#94e2d5" }, + { name = "pub", text = "󰷖", fg = "#f9e2af" }, + { name = "vue", text = "", fg = "#a6e3a1" }, + { name = "gd", text = "", fg = "#7f849c" }, + { name = "fsx", text = "", fg = "#74c7ec" }, + { name = "mkv", text = "", fg = "#fab387" }, + { name = "py", text = "", fg = "#f9e2af" }, + { name = "kicad_sch", text = "", fg = "#f5e0dc" }, + { name = "epub", text = "", fg = "#fab387" }, + { name = "env", text = "", fg = "#f9e2af" }, + { name = "magnet", text = "", fg = "#45475a" }, + { name = "elf", text = "", fg = "#45475a" }, + { name = "fodg", text = "", fg = "#f9e2af" }, + { name = "svg", text = "󰜡", fg = "#fab387" }, + { name = "dwg", text = "󰻫", fg = "#a6e3a1" }, + { name = "docx", text = "󰈬", fg = "#585b70" }, + { name = "pro", text = "", fg = "#f9e2af" }, + { name = "db", text = "", fg = "#f5e0dc" }, + { name = "rb", text = "", fg = "#313244" }, + { name = "r", text = "󰟔", fg = "#6c7086" }, + { name = "scss", text = "", fg = "#f38ba8" }, + { name = "cow", text = "󰆚", fg = "#fab387" }, + { name = "gleam", text = "", fg = "#f5c2e7" }, + { name = "v", text = "󰍛", fg = "#a6e3a1" }, + { name = "kicad_pro", text = "", fg = "#f5e0dc" }, + { name = "liquid", text = "", fg = "#a6e3a1" }, + { name = "zip", text = "", fg = "#fab387" }, +] diff --git a/yazi/theme.toml-1748477627539223 b/yazi/theme.toml-1748477627539223 new file mode 100755 index 0000000..94a16e4 --- /dev/null +++ b/yazi/theme.toml-1748477627539223 @@ -0,0 +1,750 @@ +[manager] +cwd = { fg = "#94e2d5" } + +hovered = { fg = "#1e1e2e", bg = "#89b4fa" } +preview_hovered = { fg = "#1e1e2e", bg = "#cdd6f4" } + +find_keyword = { fg = "#f9e2af", italic = true } +find_position = { fg = "#f5c2e7", bg = "reset", italic = true } + +marker_copied = { fg = "#a6e3a1", bg = "#a6e3a1" } +marker_cut = { fg = "#f38ba8", bg = "#f38ba8" } +marker_marked = { fg = "#94e2d5", bg = "#94e2d5" } +marker_selected = { fg = "#89b4fa", bg = "#89b4fa" } + +tab_active = { fg = "#1e1e2e", bg = "#cdd6f4" } +tab_inactive = { fg = "#cdd6f4", bg = "#45475a" } +tab_width = 1 + +count_copied = { fg = "#1e1e2e", bg = "#a6e3a1" } +count_cut = { fg = "#1e1e2e", bg = "#f38ba8" } +count_selected = { fg = "#1e1e2e", bg = "#89b4fa" } + +border_symbol = "│" +border_style = { fg = "#7f849c" } + +syntect_theme = "~/.config/yazi/Catppuccin-mocha.tmTheme" + +[mode] +normal_main = { fg = "#1e1e2e", bg = "#89b4fa", bold = true } +normal_alt = { fg = "#89b4fa", bg = "#313244"} + +select_main = { fg = "#1e1e2e", bg = "#a6e3a1", bold = true } +select_alt = { fg = "#a6e3a1", bg = "#313244"} + +unset_main = { fg = "#1e1e2e", bg = "#f2cdcd", bold = true } +unset_alt = { fg = "#f2cdcd", bg = "#313244"} + +[status] +separator_open = "" +separator_close = "" + +progress_label = { fg = "#ffffff", bold = true } +progress_normal = { fg = "#89b4fa", bg = "#45475a" } +progress_error = { fg = "#f38ba8", bg = "#45475a" } + +perm_type = { fg = "#89b4fa" } +perm_read = { fg = "#f9e2af" } +perm_write = { fg = "#f38ba8" } +perm_exec = { fg = "#a6e3a1" } +perm_sep = { fg = "#7f849c" } + +[input] +border = { fg = "#89b4fa" } +title = {} +value = {} +selected = { reversed = true } + +[pick] +border = { fg = "#89b4fa" } +active = { fg = "#f5c2e7" } +inactive = {} + +[confirm] +border = { fg = "#89b4fa" } +title = { fg = "#89b4fa" } +content = {} +list = {} +btn_yes = { reversed = true } +btn_no = {} + +[completion] +border = { fg = "#89b4fa" } + +[tasks] +border = { fg = "#89b4fa" } +title = {} +hovered = { underline = true } + +[which] +mask = { bg = "#313244" } +cand = { fg = "#94e2d5" } +rest = { fg = "#9399b2" } +desc = { fg = "#f5c2e7" } +separator = "  " +separator_style = { fg = "#585b70" } + +[help] +on = { fg = "#94e2d5" } +run = { fg = "#f5c2e7" } +desc = { fg = "#9399b2" } +hovered = { bg = "#585b70", bold = true } +footer = { fg = "#cdd6f4", bg = "#45475a" } + +[notify] +title_info = { fg = "#94e2d5" } +title_warn = { fg = "#f9e2af" } +title_error = { fg = "#f38ba8" } + +[filetype] +rules = [ + # Media + { mime = "image/*", fg = "#94e2d5" }, + { mime = "{audio,video}/*", fg = "#f9e2af" }, + + # Archives + { mime = "application/*zip", fg = "#f5c2e7" }, + { mime = "application/x-{tar,bzip*,7z-compressed,xz,rar}", fg = "#f5c2e7" }, + + # Documents + { mime = "application/{pdf,doc,rtf}", fg = "#a6e3a1" }, + + # Fallback + { name = "*", fg = "#cdd6f4" }, + { name = "*/", fg = "#89b4fa" } +] + +[icon] +files = [ + { name = "kritadisplayrc", text = "", fg = "#cba6f7" }, + { name = ".gtkrc-2.0", text = "", fg = "#f5e0dc" }, + { name = "bspwmrc", text = "", fg = "#313244" }, + { name = "webpack", text = "󰜫", fg = "#74c7ec" }, + { name = "tsconfig.json", text = "", fg = "#74c7ec" }, + { name = ".vimrc", text = "", fg = "#a6e3a1" }, + { name = "gemfile$", text = "", fg = "#313244" }, + { name = "xmobarrc", text = "", fg = "#f38ba8" }, + { name = "avif", text = "", fg = "#7f849c" }, + { name = "fp-info-cache", text = "", fg = "#f5e0dc" }, + { name = ".zshrc", text = "", fg = "#a6e3a1" }, + { name = "robots.txt", text = "󰚩", fg = "#6c7086" }, + { name = "dockerfile", text = "󰡨", fg = "#89b4fa" }, + { name = ".git-blame-ignore-revs", text = "", fg = "#fab387" }, + { name = ".nvmrc", text = "", fg = "#a6e3a1" }, + { name = "hyprpaper.conf", text = "", fg = "#74c7ec" }, + { name = ".prettierignore", text = "", fg = "#89b4fa" }, + { name = "rakefile", text = "", fg = "#313244" }, + { name = "code_of_conduct", text = "", fg = "#f38ba8" }, + { name = "cmakelists.txt", text = "", fg = "#cdd6f4" }, + { name = ".env", text = "", fg = "#f9e2af" }, + { name = "copying.lesser", text = "", fg = "#f9e2af" }, + { name = "readme", text = "󰂺", fg = "#f5e0dc" }, + { name = "settings.gradle", text = "", fg = "#585b70" }, + { name = "gruntfile.coffee", text = "", fg = "#fab387" }, + { name = ".eslintignore", text = "", fg = "#585b70" }, + { name = "kalgebrarc", text = "", fg = "#89b4fa" }, + { name = "kdenliverc", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.cjs", text = "", fg = "#89b4fa" }, + { name = "cantorrc", text = "", fg = "#89b4fa" }, + { name = "rmd", text = "", fg = "#74c7ec" }, + { name = "vagrantfile$", text = "", fg = "#6c7086" }, + { name = ".Xauthority", text = "", fg = "#fab387" }, + { name = "prettier.config.ts", text = "", fg = "#89b4fa" }, + { name = "node_modules", text = "", fg = "#f38ba8" }, + { name = ".prettierrc.toml", text = "", fg = "#89b4fa" }, + { name = "build.zig.zon", text = "", fg = "#fab387" }, + { name = ".ds_store", text = "", fg = "#45475a" }, + { name = "PKGBUILD", text = "", fg = "#89b4fa" }, + { name = ".prettierrc", text = "", fg = "#89b4fa" }, + { name = ".bash_profile", text = "", fg = "#a6e3a1" }, + { name = ".npmignore", text = "", fg = "#f38ba8" }, + { name = ".mailmap", text = "󰊢", fg = "#fab387" }, + { name = ".codespellrc", text = "󰓆", fg = "#a6e3a1" }, + { name = "svelte.config.js", text = "", fg = "#fab387" }, + { name = "eslint.config.ts", text = "", fg = "#585b70" }, + { name = "config", text = "", fg = "#7f849c" }, + { name = ".gitlab-ci.yml", text = "", fg = "#fab387" }, + { name = ".gitconfig", text = "", fg = "#fab387" }, + { name = "_gvimrc", text = "", fg = "#a6e3a1" }, + { name = ".xinitrc", text = "", fg = "#fab387" }, + { name = "checkhealth", text = "󰓙", fg = "#89b4fa" }, + { name = "sxhkdrc", text = "", fg = "#313244" }, + { name = ".bashrc", text = "", fg = "#a6e3a1" }, + { name = "tailwind.config.mjs", text = "󱏿", fg = "#74c7ec" }, + { name = "ext_typoscript_setup.txt", text = "", fg = "#fab387" }, + { name = "commitlint.config.ts", text = "󰜘", fg = "#94e2d5" }, + { name = "py.typed", text = "", fg = "#f9e2af" }, + { name = ".nanorc", text = "", fg = "#313244" }, + { name = "commit_editmsg", text = "", fg = "#fab387" }, + { name = ".luaurc", text = "", fg = "#89b4fa" }, + { name = "fp-lib-table", text = "", fg = "#f5e0dc" }, + { name = ".editorconfig", text = "", fg = "#f5e0dc" }, + { name = "justfile", text = "", fg = "#7f849c" }, + { name = "kdeglobals", text = "", fg = "#89b4fa" }, + { name = "license.md", text = "", fg = "#f9e2af" }, + { name = ".clang-format", text = "", fg = "#7f849c" }, + { name = "docker-compose.yaml", text = "󰡨", fg = "#89b4fa" }, + { name = "copying", text = "", fg = "#f9e2af" }, + { name = "go.mod", text = "", fg = "#74c7ec" }, + { name = "lxqt.conf", text = "", fg = "#89b4fa" }, + { name = "brewfile", text = "", fg = "#313244" }, + { name = "gulpfile.coffee", text = "", fg = "#f38ba8" }, + { name = ".dockerignore", text = "󰡨", fg = "#89b4fa" }, + { name = ".settings.json", text = "", fg = "#6c7086" }, + { name = "tailwind.config.js", text = "󱏿", fg = "#74c7ec" }, + { name = ".clang-tidy", text = "", fg = "#7f849c" }, + { name = ".gvimrc", text = "", fg = "#a6e3a1" }, + { name = "nuxt.config.cjs", text = "󱄆", fg = "#a6e3a1" }, + { name = "xsettingsd.conf", text = "", fg = "#fab387" }, + { name = "nuxt.config.js", text = "󱄆", fg = "#a6e3a1" }, + { name = "eslint.config.cjs", text = "", fg = "#585b70" }, + { name = "sym-lib-table", text = "", fg = "#f5e0dc" }, + { name = ".condarc", text = "", fg = "#a6e3a1" }, + { name = "xmonad.hs", text = "", fg = "#f38ba8" }, + { name = "tmux.conf", text = "", fg = "#a6e3a1" }, + { name = "xmobarrc.hs", text = "", fg = "#f38ba8" }, + { name = ".prettierrc.yaml", text = "", fg = "#89b4fa" }, + { name = ".pre-commit-config.yaml", text = "󰛢", fg = "#fab387" }, + { name = "i3blocks.conf", text = "", fg = "#f5e0dc" }, + { name = "xorg.conf", text = "", fg = "#fab387" }, + { name = ".zshenv", text = "", fg = "#a6e3a1" }, + { name = "vlcrc", text = "󰕼", fg = "#fab387" }, + { name = "license", text = "", fg = "#f9e2af" }, + { name = "unlicense", text = "", fg = "#f9e2af" }, + { name = "tmux.conf.local", text = "", fg = "#a6e3a1" }, + { name = ".SRCINFO", text = "󰣇", fg = "#89b4fa" }, + { name = "tailwind.config.ts", text = "󱏿", fg = "#74c7ec" }, + { name = "security.md", text = "󰒃", fg = "#bac2de" }, + { name = "security", text = "󰒃", fg = "#bac2de" }, + { name = ".eslintrc", text = "", fg = "#585b70" }, + { name = "gradle.properties", text = "", fg = "#585b70" }, + { name = "code_of_conduct.md", text = "", fg = "#f38ba8" }, + { name = "PrusaSlicerGcodeViewer.ini", text = "", fg = "#fab387" }, + { name = "PrusaSlicer.ini", text = "", fg = "#fab387" }, + { name = "procfile", text = "", fg = "#7f849c" }, + { name = "mpv.conf", text = "", fg = "#1e1e2e" }, + { name = ".prettierrc.json5", text = "", fg = "#89b4fa" }, + { name = "i3status.conf", text = "", fg = "#f5e0dc" }, + { name = "prettier.config.mjs", text = "", fg = "#89b4fa" }, + { name = ".pylintrc", text = "", fg = "#7f849c" }, + { name = "prettier.config.cjs", text = "", fg = "#89b4fa" }, + { name = ".luacheckrc", text = "", fg = "#89b4fa" }, + { name = "containerfile", text = "󰡨", fg = "#89b4fa" }, + { name = "eslint.config.mjs", text = "", fg = "#585b70" }, + { name = "gruntfile.js", text = "", fg = "#fab387" }, + { name = "bun.lockb", text = "", fg = "#f5e0dc" }, + { name = ".gitattributes", text = "", fg = "#fab387" }, + { name = "gruntfile.ts", text = "", fg = "#fab387" }, + { name = "pom.xml", text = "", fg = "#313244" }, + { name = "favicon.ico", text = "", fg = "#f9e2af" }, + { name = "package-lock.json", text = "", fg = "#313244" }, + { name = "build", text = "", fg = "#a6e3a1" }, + { name = "package.json", text = "", fg = "#f38ba8" }, + { name = "nuxt.config.ts", text = "󱄆", fg = "#a6e3a1" }, + { name = "nuxt.config.mjs", text = "󱄆", fg = "#a6e3a1" }, + { name = "mix.lock", text = "", fg = "#7f849c" }, + { name = "makefile", text = "", fg = "#7f849c" }, + { name = "gulpfile.js", text = "", fg = "#f38ba8" }, + { name = "lxde-rc.xml", text = "", fg = "#9399b2" }, + { name = "kritarc", text = "", fg = "#cba6f7" }, + { name = "gtkrc", text = "", fg = "#f5e0dc" }, + { name = "ionic.config.json", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.mjs", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.yml", text = "", fg = "#89b4fa" }, + { name = ".npmrc", text = "", fg = "#f38ba8" }, + { name = "weston.ini", text = "", fg = "#f9e2af" }, + { name = "gulpfile.babel.js", text = "", fg = "#f38ba8" }, + { name = "i18n.config.ts", text = "󰗊", fg = "#7f849c" }, + { name = "commitlint.config.js", text = "󰜘", fg = "#94e2d5" }, + { name = ".gitmodules", text = "", fg = "#fab387" }, + { name = "gradle-wrapper.properties", text = "", fg = "#585b70" }, + { name = "hypridle.conf", text = "", fg = "#74c7ec" }, + { name = "vercel.json", text = "▲", fg = "#f5e0dc" }, + { name = "hyprlock.conf", text = "", fg = "#74c7ec" }, + { name = "go.sum", text = "", fg = "#74c7ec" }, + { name = "kdenlive-layoutsrc", text = "", fg = "#89b4fa" }, + { name = "gruntfile.babel.js", text = "", fg = "#fab387" }, + { name = "compose.yml", text = "󰡨", fg = "#89b4fa" }, + { name = "i18n.config.js", text = "󰗊", fg = "#7f849c" }, + { name = "readme.md", text = "󰂺", fg = "#f5e0dc" }, + { name = "gradlew", text = "", fg = "#585b70" }, + { name = "go.work", text = "", fg = "#74c7ec" }, + { name = "gulpfile.ts", text = "", fg = "#f38ba8" }, + { name = "gnumakefile", text = "", fg = "#7f849c" }, + { name = "FreeCAD.conf", text = "", fg = "#f38ba8" }, + { name = "compose.yaml", text = "󰡨", fg = "#89b4fa" }, + { name = "eslint.config.js", text = "", fg = "#585b70" }, + { name = "hyprland.conf", text = "", fg = "#74c7ec" }, + { name = "docker-compose.yml", text = "󰡨", fg = "#89b4fa" }, + { name = "groovy", text = "", fg = "#585b70" }, + { name = "QtProject.conf", text = "", fg = "#a6e3a1" }, + { name = "platformio.ini", text = "", fg = "#fab387" }, + { name = "build.gradle", text = "", fg = "#585b70" }, + { name = ".nuxtrc", text = "󱄆", fg = "#a6e3a1" }, + { name = "_vimrc", text = "", fg = "#a6e3a1" }, + { name = ".zprofile", text = "", fg = "#a6e3a1" }, + { name = ".xsession", text = "", fg = "#fab387" }, + { name = "prettier.config.js", text = "", fg = "#89b4fa" }, + { name = ".babelrc", text = "", fg = "#f9e2af" }, + { name = "workspace", text = "", fg = "#a6e3a1" }, + { name = ".prettierrc.json", text = "", fg = "#89b4fa" }, + { name = ".prettierrc.js", text = "", fg = "#89b4fa" }, + { name = ".Xresources", text = "", fg = "#fab387" }, + { name = ".gitignore", text = "", fg = "#fab387" }, + { name = ".justfile", text = "", fg = "#7f849c" }, +] +exts = [ + { name = "otf", text = "", fg = "#f5e0dc" }, + { name = "import", text = "", fg = "#f5e0dc" }, + { name = "krz", text = "", fg = "#cba6f7" }, + { name = "adb", text = "", fg = "#94e2d5" }, + { name = "ttf", text = "", fg = "#f5e0dc" }, + { name = "webpack", text = "󰜫", fg = "#74c7ec" }, + { name = "dart", text = "", fg = "#585b70" }, + { name = "vsh", text = "", fg = "#7f849c" }, + { name = "doc", text = "󰈬", fg = "#585b70" }, + { name = "zsh", text = "", fg = "#a6e3a1" }, + { name = "ex", text = "", fg = "#7f849c" }, + { name = "hx", text = "", fg = "#fab387" }, + { name = "fodt", text = "", fg = "#74c7ec" }, + { name = "mojo", text = "", fg = "#fab387" }, + { name = "templ", text = "", fg = "#f9e2af" }, + { name = "nix", text = "", fg = "#74c7ec" }, + { name = "cshtml", text = "󱦗", fg = "#585b70" }, + { name = "fish", text = "", fg = "#585b70" }, + { name = "ply", text = "󰆧", fg = "#7f849c" }, + { name = "sldprt", text = "󰻫", fg = "#a6e3a1" }, + { name = "gemspec", text = "", fg = "#313244" }, + { name = "mjs", text = "", fg = "#f9e2af" }, + { name = "csh", text = "", fg = "#585b70" }, + { name = "cmake", text = "", fg = "#cdd6f4" }, + { name = "fodp", text = "", fg = "#fab387" }, + { name = "vi", text = "", fg = "#f9e2af" }, + { name = "msf", text = "", fg = "#89b4fa" }, + { name = "blp", text = "󰺾", fg = "#89b4fa" }, + { name = "less", text = "", fg = "#45475a" }, + { name = "sh", text = "", fg = "#585b70" }, + { name = "odg", text = "", fg = "#f9e2af" }, + { name = "mint", text = "󰌪", fg = "#a6e3a1" }, + { name = "dll", text = "", fg = "#11111b" }, + { name = "odf", text = "", fg = "#f38ba8" }, + { name = "sqlite3", text = "", fg = "#f5e0dc" }, + { name = "Dockerfile", text = "󰡨", fg = "#89b4fa" }, + { name = "ksh", text = "", fg = "#585b70" }, + { name = "rmd", text = "", fg = "#74c7ec" }, + { name = "wv", text = "", fg = "#74c7ec" }, + { name = "xml", text = "󰗀", fg = "#fab387" }, + { name = "markdown", text = "", fg = "#cdd6f4" }, + { name = "qml", text = "", fg = "#a6e3a1" }, + { name = "3gp", text = "", fg = "#fab387" }, + { name = "pxi", text = "", fg = "#89b4fa" }, + { name = "flac", text = "", fg = "#6c7086" }, + { name = "gpr", text = "", fg = "#cba6f7" }, + { name = "huff", text = "󰡘", fg = "#585b70" }, + { name = "json", text = "", fg = "#f9e2af" }, + { name = "gv", text = "󱁉", fg = "#585b70" }, + { name = "bmp", text = "", fg = "#7f849c" }, + { name = "lock", text = "", fg = "#bac2de" }, + { name = "sha384", text = "󰕥", fg = "#7f849c" }, + { name = "cobol", text = "⚙", fg = "#585b70" }, + { name = "cob", text = "⚙", fg = "#585b70" }, + { name = "java", text = "", fg = "#f38ba8" }, + { name = "cjs", text = "", fg = "#f9e2af" }, + { name = "qm", text = "", fg = "#74c7ec" }, + { name = "ebuild", text = "", fg = "#45475a" }, + { name = "mustache", text = "", fg = "#fab387" }, + { name = "terminal", text = "", fg = "#a6e3a1" }, + { name = "ejs", text = "", fg = "#f9e2af" }, + { name = "brep", text = "󰻫", fg = "#a6e3a1" }, + { name = "rar", text = "", fg = "#fab387" }, + { name = "gradle", text = "", fg = "#585b70" }, + { name = "gnumakefile", text = "", fg = "#7f849c" }, + { name = "applescript", text = "", fg = "#7f849c" }, + { name = "elm", text = "", fg = "#74c7ec" }, + { name = "ebook", text = "", fg = "#fab387" }, + { name = "kra", text = "", fg = "#cba6f7" }, + { name = "tf", text = "", fg = "#585b70" }, + { name = "xls", text = "󰈛", fg = "#585b70" }, + { name = "fnl", text = "", fg = "#f9e2af" }, + { name = "kdbx", text = "", fg = "#a6e3a1" }, + { name = "kicad_pcb", text = "", fg = "#f5e0dc" }, + { name = "cfg", text = "", fg = "#7f849c" }, + { name = "ape", text = "", fg = "#74c7ec" }, + { name = "org", text = "", fg = "#94e2d5" }, + { name = "yml", text = "", fg = "#7f849c" }, + { name = "swift", text = "", fg = "#fab387" }, + { name = "eln", text = "", fg = "#7f849c" }, + { name = "sol", text = "", fg = "#74c7ec" }, + { name = "awk", text = "", fg = "#585b70" }, + { name = "7z", text = "", fg = "#fab387" }, + { name = "apl", text = "⍝", fg = "#fab387" }, + { name = "epp", text = "", fg = "#fab387" }, + { name = "app", text = "", fg = "#45475a" }, + { name = "dot", text = "󱁉", fg = "#585b70" }, + { name = "kpp", text = "", fg = "#cba6f7" }, + { name = "eot", text = "", fg = "#f5e0dc" }, + { name = "hpp", text = "", fg = "#7f849c" }, + { name = "spec.tsx", text = "", fg = "#585b70" }, + { name = "hurl", text = "", fg = "#f38ba8" }, + { name = "cxxm", text = "", fg = "#74c7ec" }, + { name = "c", text = "", fg = "#89b4fa" }, + { name = "fcmacro", text = "", fg = "#f38ba8" }, + { name = "sass", text = "", fg = "#f38ba8" }, + { name = "yaml", text = "", fg = "#7f849c" }, + { name = "xz", text = "", fg = "#fab387" }, + { name = "material", text = "󰔉", fg = "#f38ba8" }, + { name = "json5", text = "", fg = "#f9e2af" }, + { name = "signature", text = "λ", fg = "#fab387" }, + { name = "3mf", text = "󰆧", fg = "#7f849c" }, + { name = "jpg", text = "", fg = "#7f849c" }, + { name = "xpi", text = "", fg = "#fab387" }, + { name = "fcmat", text = "", fg = "#f38ba8" }, + { name = "pot", text = "", fg = "#74c7ec" }, + { name = "bin", text = "", fg = "#45475a" }, + { name = "xlsx", text = "󰈛", fg = "#585b70" }, + { name = "aac", text = "", fg = "#74c7ec" }, + { name = "kicad_sym", text = "", fg = "#f5e0dc" }, + { name = "xcstrings", text = "", fg = "#74c7ec" }, + { name = "lff", text = "", fg = "#f5e0dc" }, + { name = "xcf", text = "", fg = "#585b70" }, + { name = "azcli", text = "", fg = "#6c7086" }, + { name = "license", text = "", fg = "#f9e2af" }, + { name = "jsonc", text = "", fg = "#f9e2af" }, + { name = "xaml", text = "󰙳", fg = "#585b70" }, + { name = "md5", text = "󰕥", fg = "#7f849c" }, + { name = "xm", text = "", fg = "#74c7ec" }, + { name = "sln", text = "", fg = "#6c7086" }, + { name = "jl", text = "", fg = "#7f849c" }, + { name = "ml", text = "", fg = "#fab387" }, + { name = "http", text = "", fg = "#89b4fa" }, + { name = "x", text = "", fg = "#89b4fa" }, + { name = "wvc", text = "", fg = "#74c7ec" }, + { name = "wrz", text = "󰆧", fg = "#7f849c" }, + { name = "csproj", text = "󰪮", fg = "#585b70" }, + { name = "wrl", text = "󰆧", fg = "#7f849c" }, + { name = "wma", text = "", fg = "#74c7ec" }, + { name = "woff2", text = "", fg = "#f5e0dc" }, + { name = "woff", text = "", fg = "#f5e0dc" }, + { name = "tscn", text = "", fg = "#7f849c" }, + { name = "webmanifest", text = "", fg = "#f9e2af" }, + { name = "webm", text = "", fg = "#fab387" }, + { name = "fcbak", text = "", fg = "#f38ba8" }, + { name = "log", text = "󰌱", fg = "#cdd6f4" }, + { name = "wav", text = "", fg = "#74c7ec" }, + { name = "wasm", text = "", fg = "#585b70" }, + { name = "styl", text = "", fg = "#a6e3a1" }, + { name = "gif", text = "", fg = "#7f849c" }, + { name = "resi", text = "", fg = "#f38ba8" }, + { name = "aiff", text = "", fg = "#74c7ec" }, + { name = "sha256", text = "󰕥", fg = "#7f849c" }, + { name = "igs", text = "󰻫", fg = "#a6e3a1" }, + { name = "vsix", text = "", fg = "#6c7086" }, + { name = "vim", text = "", fg = "#a6e3a1" }, + { name = "diff", text = "", fg = "#45475a" }, + { name = "drl", text = "", fg = "#eba0ac" }, + { name = "erl", text = "", fg = "#f38ba8" }, + { name = "vhdl", text = "󰍛", fg = "#a6e3a1" }, + { name = "🔥", text = "", fg = "#fab387" }, + { name = "hrl", text = "", fg = "#f38ba8" }, + { name = "fsi", text = "", fg = "#74c7ec" }, + { name = "mm", text = "", fg = "#74c7ec" }, + { name = "bz", text = "", fg = "#fab387" }, + { name = "vh", text = "󰍛", fg = "#a6e3a1" }, + { name = "kdb", text = "", fg = "#a6e3a1" }, + { name = "gz", text = "", fg = "#fab387" }, + { name = "cpp", text = "", fg = "#74c7ec" }, + { name = "ui", text = "", fg = "#6c7086" }, + { name = "txt", text = "󰈙", fg = "#a6e3a1" }, + { name = "spec.ts", text = "", fg = "#74c7ec" }, + { name = "ccm", text = "", fg = "#f38ba8" }, + { name = "typoscript", text = "", fg = "#fab387" }, + { name = "typ", text = "", fg = "#89dceb" }, + { name = "txz", text = "", fg = "#fab387" }, + { name = "test.ts", text = "", fg = "#74c7ec" }, + { name = "tsx", text = "", fg = "#585b70" }, + { name = "mk", text = "", fg = "#7f849c" }, + { name = "webp", text = "", fg = "#7f849c" }, + { name = "opus", text = "", fg = "#6c7086" }, + { name = "bicep", text = "", fg = "#74c7ec" }, + { name = "ts", text = "", fg = "#74c7ec" }, + { name = "tres", text = "", fg = "#7f849c" }, + { name = "torrent", text = "", fg = "#94e2d5" }, + { name = "cxx", text = "", fg = "#74c7ec" }, + { name = "iso", text = "", fg = "#f2cdcd" }, + { name = "ixx", text = "", fg = "#74c7ec" }, + { name = "hxx", text = "", fg = "#7f849c" }, + { name = "gql", text = "", fg = "#f38ba8" }, + { name = "tmux", text = "", fg = "#a6e3a1" }, + { name = "ini", text = "", fg = "#7f849c" }, + { name = "m3u8", text = "󰲹", fg = "#f38ba8" }, + { name = "image", text = "", fg = "#f2cdcd" }, + { name = "tfvars", text = "", fg = "#585b70" }, + { name = "tex", text = "", fg = "#45475a" }, + { name = "cbl", text = "⚙", fg = "#585b70" }, + { name = "flc", text = "", fg = "#f5e0dc" }, + { name = "elc", text = "", fg = "#7f849c" }, + { name = "test.tsx", text = "", fg = "#585b70" }, + { name = "twig", text = "", fg = "#a6e3a1" }, + { name = "sql", text = "", fg = "#f5e0dc" }, + { name = "test.jsx", text = "", fg = "#74c7ec" }, + { name = "htm", text = "", fg = "#fab387" }, + { name = "gcode", text = "󰐫", fg = "#6c7086" }, + { name = "test.js", text = "", fg = "#f9e2af" }, + { name = "ino", text = "", fg = "#74c7ec" }, + { name = "tcl", text = "󰛓", fg = "#585b70" }, + { name = "cljs", text = "", fg = "#74c7ec" }, + { name = "tsconfig", text = "", fg = "#fab387" }, + { name = "img", text = "", fg = "#f2cdcd" }, + { name = "t", text = "", fg = "#74c7ec" }, + { name = "fcstd1", text = "", fg = "#f38ba8" }, + { name = "out", text = "", fg = "#45475a" }, + { name = "jsx", text = "", fg = "#74c7ec" }, + { name = "bash", text = "", fg = "#a6e3a1" }, + { name = "edn", text = "", fg = "#74c7ec" }, + { name = "rss", text = "", fg = "#fab387" }, + { name = "flf", text = "", fg = "#f5e0dc" }, + { name = "cache", text = "", fg = "#f5e0dc" }, + { name = "sbt", text = "", fg = "#f38ba8" }, + { name = "cppm", text = "", fg = "#74c7ec" }, + { name = "svelte", text = "", fg = "#fab387" }, + { name = "mo", text = "∞", fg = "#7f849c" }, + { name = "sv", text = "󰍛", fg = "#a6e3a1" }, + { name = "ko", text = "", fg = "#f5e0dc" }, + { name = "suo", text = "", fg = "#6c7086" }, + { name = "sldasm", text = "󰻫", fg = "#a6e3a1" }, + { name = "icalendar", text = "", fg = "#313244" }, + { name = "go", text = "", fg = "#74c7ec" }, + { name = "sublime", text = "", fg = "#fab387" }, + { name = "stl", text = "󰆧", fg = "#7f849c" }, + { name = "mobi", text = "", fg = "#fab387" }, + { name = "graphql", text = "", fg = "#f38ba8" }, + { name = "m3u", text = "󰲹", fg = "#f38ba8" }, + { name = "cpy", text = "⚙", fg = "#585b70" }, + { name = "kdenlive", text = "", fg = "#89b4fa" }, + { name = "pyo", text = "", fg = "#f9e2af" }, + { name = "po", text = "", fg = "#74c7ec" }, + { name = "scala", text = "", fg = "#f38ba8" }, + { name = "exs", text = "", fg = "#7f849c" }, + { name = "odp", text = "", fg = "#fab387" }, + { name = "dump", text = "", fg = "#f5e0dc" }, + { name = "stp", text = "󰻫", fg = "#a6e3a1" }, + { name = "step", text = "󰻫", fg = "#a6e3a1" }, + { name = "ste", text = "󰻫", fg = "#a6e3a1" }, + { name = "aif", text = "", fg = "#74c7ec" }, + { name = "strings", text = "", fg = "#74c7ec" }, + { name = "cp", text = "", fg = "#74c7ec" }, + { name = "fsscript", text = "", fg = "#74c7ec" }, + { name = "mli", text = "", fg = "#fab387" }, + { name = "bak", text = "󰁯", fg = "#7f849c" }, + { name = "ssa", text = "󰨖", fg = "#f9e2af" }, + { name = "toml", text = "", fg = "#585b70" }, + { name = "makefile", text = "", fg = "#7f849c" }, + { name = "php", text = "", fg = "#7f849c" }, + { name = "zst", text = "", fg = "#fab387" }, + { name = "spec.jsx", text = "", fg = "#74c7ec" }, + { name = "kbx", text = "󰯄", fg = "#6c7086" }, + { name = "fbx", text = "󰆧", fg = "#7f849c" }, + { name = "blend", text = "󰂫", fg = "#fab387" }, + { name = "ifc", text = "󰻫", fg = "#a6e3a1" }, + { name = "spec.js", text = "", fg = "#f9e2af" }, + { name = "so", text = "", fg = "#f5e0dc" }, + { name = "desktop", text = "", fg = "#45475a" }, + { name = "sml", text = "λ", fg = "#fab387" }, + { name = "slvs", text = "󰻫", fg = "#a6e3a1" }, + { name = "pp", text = "", fg = "#fab387" }, + { name = "ps1", text = "󰨊", fg = "#6c7086" }, + { name = "dropbox", text = "", fg = "#6c7086" }, + { name = "kicad_mod", text = "", fg = "#f5e0dc" }, + { name = "bat", text = "", fg = "#a6e3a1" }, + { name = "slim", text = "", fg = "#fab387" }, + { name = "skp", text = "󰻫", fg = "#a6e3a1" }, + { name = "css", text = "", fg = "#89b4fa" }, + { name = "xul", text = "", fg = "#fab387" }, + { name = "ige", text = "󰻫", fg = "#a6e3a1" }, + { name = "glb", text = "", fg = "#fab387" }, + { name = "ppt", text = "󰈧", fg = "#f38ba8" }, + { name = "sha512", text = "󰕥", fg = "#7f849c" }, + { name = "ics", text = "", fg = "#313244" }, + { name = "mdx", text = "", fg = "#74c7ec" }, + { name = "sha1", text = "󰕥", fg = "#7f849c" }, + { name = "f3d", text = "󰻫", fg = "#a6e3a1" }, + { name = "ass", text = "󰨖", fg = "#f9e2af" }, + { name = "godot", text = "", fg = "#7f849c" }, + { name = "ifb", text = "", fg = "#313244" }, + { name = "cson", text = "", fg = "#f9e2af" }, + { name = "lib", text = "", fg = "#11111b" }, + { name = "luac", text = "", fg = "#74c7ec" }, + { name = "heex", text = "", fg = "#7f849c" }, + { name = "scm", text = "󰘧", fg = "#f5e0dc" }, + { name = "psd1", text = "󰨊", fg = "#7f849c" }, + { name = "sc", text = "", fg = "#f38ba8" }, + { name = "scad", text = "", fg = "#f9e2af" }, + { name = "kts", text = "", fg = "#6c7086" }, + { name = "svh", text = "󰍛", fg = "#a6e3a1" }, + { name = "mts", text = "", fg = "#74c7ec" }, + { name = "nfo", text = "", fg = "#f9e2af" }, + { name = "pck", text = "", fg = "#7f849c" }, + { name = "rproj", text = "󰗆", fg = "#a6e3a1" }, + { name = "rlib", text = "", fg = "#fab387" }, + { name = "cljd", text = "", fg = "#74c7ec" }, + { name = "ods", text = "", fg = "#a6e3a1" }, + { name = "res", text = "", fg = "#f38ba8" }, + { name = "apk", text = "", fg = "#a6e3a1" }, + { name = "haml", text = "", fg = "#f5e0dc" }, + { name = "d.ts", text = "", fg = "#fab387" }, + { name = "razor", text = "󱦘", fg = "#585b70" }, + { name = "rake", text = "", fg = "#313244" }, + { name = "patch", text = "", fg = "#45475a" }, + { name = "cuh", text = "", fg = "#7f849c" }, + { name = "d", text = "", fg = "#f38ba8" }, + { name = "query", text = "", fg = "#a6e3a1" }, + { name = "psb", text = "", fg = "#74c7ec" }, + { name = "nu", text = ">", fg = "#a6e3a1" }, + { name = "mov", text = "", fg = "#fab387" }, + { name = "lrc", text = "󰨖", fg = "#f9e2af" }, + { name = "pyx", text = "", fg = "#89b4fa" }, + { name = "pyw", text = "", fg = "#89b4fa" }, + { name = "cu", text = "", fg = "#a6e3a1" }, + { name = "bazel", text = "", fg = "#a6e3a1" }, + { name = "obj", text = "󰆧", fg = "#7f849c" }, + { name = "pyi", text = "", fg = "#f9e2af" }, + { name = "pyd", text = "", fg = "#f9e2af" }, + { name = "exe", text = "", fg = "#45475a" }, + { name = "pyc", text = "", fg = "#f9e2af" }, + { name = "fctb", text = "", fg = "#f38ba8" }, + { name = "part", text = "", fg = "#94e2d5" }, + { name = "blade.php", text = "", fg = "#f38ba8" }, + { name = "git", text = "", fg = "#fab387" }, + { name = "psd", text = "", fg = "#74c7ec" }, + { name = "qss", text = "", fg = "#a6e3a1" }, + { name = "csv", text = "", fg = "#a6e3a1" }, + { name = "psm1", text = "󰨊", fg = "#7f849c" }, + { name = "dconf", text = "", fg = "#f5e0dc" }, + { name = "config.ru", text = "", fg = "#313244" }, + { name = "prisma", text = "", fg = "#6c7086" }, + { name = "conf", text = "", fg = "#7f849c" }, + { name = "clj", text = "", fg = "#a6e3a1" }, + { name = "o", text = "", fg = "#45475a" }, + { name = "mp4", text = "", fg = "#fab387" }, + { name = "cc", text = "", fg = "#f38ba8" }, + { name = "kicad_prl", text = "", fg = "#f5e0dc" }, + { name = "bz3", text = "", fg = "#fab387" }, + { name = "asc", text = "󰦝", fg = "#6c7086" }, + { name = "png", text = "", fg = "#7f849c" }, + { name = "android", text = "", fg = "#a6e3a1" }, + { name = "pm", text = "", fg = "#74c7ec" }, + { name = "h", text = "", fg = "#7f849c" }, + { name = "pls", text = "󰲹", fg = "#f38ba8" }, + { name = "ipynb", text = "", fg = "#fab387" }, + { name = "pl", text = "", fg = "#74c7ec" }, + { name = "ads", text = "", fg = "#f5e0dc" }, + { name = "sqlite", text = "", fg = "#f5e0dc" }, + { name = "pdf", text = "", fg = "#585b70" }, + { name = "pcm", text = "", fg = "#6c7086" }, + { name = "ico", text = "", fg = "#f9e2af" }, + { name = "a", text = "", fg = "#f5e0dc" }, + { name = "R", text = "󰟔", fg = "#6c7086" }, + { name = "ogg", text = "", fg = "#6c7086" }, + { name = "pxd", text = "", fg = "#89b4fa" }, + { name = "kdenlivetitle", text = "", fg = "#89b4fa" }, + { name = "jxl", text = "", fg = "#7f849c" }, + { name = "nswag", text = "", fg = "#a6e3a1" }, + { name = "nim", text = "", fg = "#f9e2af" }, + { name = "bqn", text = "⎉", fg = "#6c7086" }, + { name = "cts", text = "", fg = "#74c7ec" }, + { name = "fcparam", text = "", fg = "#f38ba8" }, + { name = "rs", text = "", fg = "#fab387" }, + { name = "mpp", text = "", fg = "#74c7ec" }, + { name = "fdmdownload", text = "", fg = "#94e2d5" }, + { name = "pptx", text = "󰈧", fg = "#f38ba8" }, + { name = "jpeg", text = "", fg = "#7f849c" }, + { name = "bib", text = "󱉟", fg = "#f9e2af" }, + { name = "vhd", text = "󰍛", fg = "#a6e3a1" }, + { name = "m", text = "", fg = "#89b4fa" }, + { name = "js", text = "", fg = "#f9e2af" }, + { name = "eex", text = "", fg = "#7f849c" }, + { name = "tbc", text = "󰛓", fg = "#585b70" }, + { name = "astro", text = "", fg = "#f38ba8" }, + { name = "sha224", text = "󰕥", fg = "#7f849c" }, + { name = "xcplayground", text = "", fg = "#fab387" }, + { name = "el", text = "", fg = "#7f849c" }, + { name = "m4v", text = "", fg = "#fab387" }, + { name = "m4a", text = "", fg = "#74c7ec" }, + { name = "cs", text = "󰌛", fg = "#585b70" }, + { name = "hs", text = "", fg = "#7f849c" }, + { name = "tgz", text = "", fg = "#fab387" }, + { name = "fs", text = "", fg = "#74c7ec" }, + { name = "luau", text = "", fg = "#89b4fa" }, + { name = "dxf", text = "󰻫", fg = "#a6e3a1" }, + { name = "download", text = "", fg = "#94e2d5" }, + { name = "cast", text = "", fg = "#fab387" }, + { name = "qrc", text = "", fg = "#a6e3a1" }, + { name = "lua", text = "", fg = "#74c7ec" }, + { name = "lhs", text = "", fg = "#7f849c" }, + { name = "md", text = "", fg = "#cdd6f4" }, + { name = "leex", text = "", fg = "#7f849c" }, + { name = "ai", text = "", fg = "#f9e2af" }, + { name = "lck", text = "", fg = "#bac2de" }, + { name = "kt", text = "", fg = "#6c7086" }, + { name = "bicepparam", text = "", fg = "#7f849c" }, + { name = "hex", text = "", fg = "#6c7086" }, + { name = "zig", text = "", fg = "#fab387" }, + { name = "bzl", text = "", fg = "#a6e3a1" }, + { name = "cljc", text = "", fg = "#a6e3a1" }, + { name = "kicad_dru", text = "", fg = "#f5e0dc" }, + { name = "fctl", text = "", fg = "#f38ba8" }, + { name = "f#", text = "", fg = "#74c7ec" }, + { name = "odt", text = "", fg = "#74c7ec" }, + { name = "conda", text = "", fg = "#a6e3a1" }, + { name = "vala", text = "", fg = "#585b70" }, + { name = "erb", text = "", fg = "#313244" }, + { name = "mp3", text = "", fg = "#74c7ec" }, + { name = "bz2", text = "", fg = "#fab387" }, + { name = "coffee", text = "", fg = "#f9e2af" }, + { name = "cr", text = "", fg = "#f5e0dc" }, + { name = "f90", text = "󱈚", fg = "#585b70" }, + { name = "jwmrc", text = "", fg = "#6c7086" }, + { name = "c++", text = "", fg = "#f38ba8" }, + { name = "fcscript", text = "", fg = "#f38ba8" }, + { name = "fods", text = "", fg = "#a6e3a1" }, + { name = "cue", text = "󰲹", fg = "#f38ba8" }, + { name = "srt", text = "󰨖", fg = "#f9e2af" }, + { name = "info", text = "", fg = "#f9e2af" }, + { name = "hh", text = "", fg = "#7f849c" }, + { name = "sig", text = "λ", fg = "#fab387" }, + { name = "html", text = "", fg = "#fab387" }, + { name = "iges", text = "󰻫", fg = "#a6e3a1" }, + { name = "kicad_wks", text = "", fg = "#f5e0dc" }, + { name = "hbs", text = "", fg = "#fab387" }, + { name = "fcstd", text = "", fg = "#f38ba8" }, + { name = "gresource", text = "", fg = "#f5e0dc" }, + { name = "sub", text = "󰨖", fg = "#f9e2af" }, + { name = "ical", text = "", fg = "#313244" }, + { name = "crdownload", text = "", fg = "#94e2d5" }, + { name = "pub", text = "󰷖", fg = "#f9e2af" }, + { name = "vue", text = "", fg = "#a6e3a1" }, + { name = "gd", text = "", fg = "#7f849c" }, + { name = "fsx", text = "", fg = "#74c7ec" }, + { name = "mkv", text = "", fg = "#fab387" }, + { name = "py", text = "", fg = "#f9e2af" }, + { name = "kicad_sch", text = "", fg = "#f5e0dc" }, + { name = "epub", text = "", fg = "#fab387" }, + { name = "env", text = "", fg = "#f9e2af" }, + { name = "magnet", text = "", fg = "#45475a" }, + { name = "elf", text = "", fg = "#45475a" }, + { name = "fodg", text = "", fg = "#f9e2af" }, + { name = "svg", text = "󰜡", fg = "#fab387" }, + { name = "dwg", text = "󰻫", fg = "#a6e3a1" }, + { name = "docx", text = "󰈬", fg = "#585b70" }, + { name = "pro", text = "", fg = "#f9e2af" }, + { name = "db", text = "", fg = "#f5e0dc" }, + { name = "rb", text = "", fg = "#313244" }, + { name = "r", text = "󰟔", fg = "#6c7086" }, + { name = "scss", text = "", fg = "#f38ba8" }, + { name = "cow", text = "󰆚", fg = "#fab387" }, + { name = "gleam", text = "", fg = "#f5c2e7" }, + { name = "v", text = "󰍛", fg = "#a6e3a1" }, + { name = "kicad_pro", text = "", fg = "#f5e0dc" }, + { name = "liquid", text = "", fg = "#a6e3a1" }, + { name = "zip", text = "", fg = "#fab387" }, +] diff --git a/yazi/yazi.toml b/yazi/yazi.toml new file mode 100755 index 0000000..b7feb12 --- /dev/null +++ b/yazi/yazi.toml @@ -0,0 +1,199 @@ +# A TOML linter such as https://taplo.tamasfe.dev/ can use this schema to validate your config. +# If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. +"$schema" = "https://yazi-rs.github.io/schemas/yazi.json" + +[mgr] +ratio = [1, 3, 4] +sort_by = "alphabetical" +sort_sensitive = false +sort_reverse = false +sort_dir_first = true +sort_translit = false +linemode = "size" +show_hidden = false +show_symlink = true +scrolloff = 5 +mouse_events = ["click", "scroll"] +title_format = "Yazi: {cwd}" + +[preview] +tab_size = 2 +max_width = 600 +max_height = 900 +cache_dir = "" +image_filter = "triangle" +image_quality = 75 +sixel_fraction = 15 +ueberzug_scale = 1 +ueberzug_offset = [0, 0, 0, 0] + +[opener] +edit = [ + { run = '${EDITOR:-vi} "$@"', desc = "$EDITOR", block = true, for = "unix" }, + { run = 'code %*', orphan = true, desc = "code", for = "windows" }, + { run = 'code -w %*', block = true, desc = "code (block)", for = "windows" }, +] +open = [ + { run = 'xdg-open "$1"', desc = "Open", for = "linux" }, + { run = 'open "$@"', desc = "Open", for = "macos" }, + { run = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" }, +] +reveal = [ + { run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" }, + { run = 'open -R "$1"', desc = "Reveal", for = "macos" }, + { run = 'explorer /select,"%1"', orphan = true, desc = "Reveal", for = "windows" }, + { run = '''exiftool "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show EXIF", for = "unix" }, +] +extract = [ + { run = 'ya pub extract --list "$@"', desc = "Extract here", for = "unix" }, + { run = 'ya pub extract --list %*', desc = "Extract here", for = "windows" }, +] +play = [ + { run = 'mpv --force-window "$@"', orphan = true, for = "unix" }, + { run = 'mpv --force-window %*', orphan = true, for = "windows" }, + { run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" }, +] + +[open] +rules = [ + # Folder + { name = "*/", use = ["edit", "open", "reveal"] }, + # Text + { mime = "text/*", use = ["edit", "reveal"] }, + # Image + { mime = "image/*", use = ["open", "reveal"] }, + # Media + { mime = "{audio,video}/*", use = ["play", "reveal"] }, + # Archive + { mime = "application/{,g}zip", use = ["extract", "reveal"] }, + { mime = "application/{tar,bzip*,7z*,xz,rar}", use = ["extract", "reveal"] }, + # JSON + { mime = "application/{json,ndjson}", use = ["edit", "reveal"] }, + { mime = "*/javascript", use = ["edit", "reveal"] }, + # Empty file + { mime = "inode/empty", use = ["edit", "reveal"] }, + # Fallback + { name = "*", use = ["edit", "open", "reveal"] }, +] + +[tasks] +micro_workers = 10 +macro_workers = 25 +bizarre_retry = 5 +image_alloc = 536870912 # 512MB +image_bound = [0, 0] +suppress_preload = false + +[plugin] +fetchers = [ + # Mimetype + { id = "mime", name = "*", run = "mime", if = "!mime", prio = "high" }, + { id = "git", name = "*", run = "git", prio = "normal" }, + { id = "git", name = "*/", run = "git", prio = "normal" }, +] +preloaders = [ + # Image + { mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" }, + { mime = "image/*", run = "image" }, + # Video + { mime = "video/*", run = "video" }, + # PDF + { mime = "application/pdf", run = "pdf" }, + # Font + { mime = "font/*", run = "font" }, + { mime = "application/vnd.ms-opentype", run = "font" }, +] +previewers = [ + { name = "*/", run = "folder", sync = true }, + # Code + { mime = "text/*", run = "code" }, + { mime = "*/{xml,javascript,x-wine-extension-ini}", run = "code" }, + # JSON + { mime = "application/{json,x-ndjson}", run = "json" }, + # Image + { mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" }, + { mime = "image/*", run = "image" }, + # Video + { mime = "video/*", run = "video" }, + # PDF + { mime = "application/pdf", run = "pdf" }, + # Archive + { mime = "application/{,g}zip", run = "archive" }, + { mime = "application/x-{tar,bzip*,7z-compressed,xz,rar,iso9660-image}", run = "archive" }, + # Font + { mime = "font/*", run = "font" }, + { mime = "application/vnd.ms-opentype", run = "font" }, + # Empty file + { mime = "inode/x-empty", run = "empty" }, + # Fallback + { name = "*", run = "file" }, +] + +[input] +cursor_blink = false + +# cd +cd_title = "Change directory:" +cd_origin = "top-center" +cd_offset = [0, 2, 50, 3] + +# create +create_title = ["Create:", "Create (dir):"] +create_origin = "top-center" +create_offset = [0, 2, 50, 3] + +# rename +rename_title = "Rename:" +rename_origin = "hovered" +rename_offset = [0, 1, 50, 3] + +# trash +trash_title = "Move {n} selected file{s} to trash? (y/N)" +trash_origin = "top-center" +trash_offset = [0, 2, 50, 3] + +# delete +delete_title = "Delete {n} selected file{s} permanently? (y/N)" +delete_origin = "top-center" +delete_offset = [0, 2, 50, 3] + +# filter +filter_title = "Filter:" +filter_origin = "top-center" +filter_offset = [0, 2, 50, 3] + +# find +find_title = ["Find next:", "Find previous:"] +find_origin = "top-center" +find_offset = [0, 2, 50, 3] + +# search +search_title = "Search via {n}:" +search_origin = "top-center" +search_offset = [0, 2, 50, 3] + +# shell +shell_title = ["Shell:", "Shell (block):"] +shell_origin = "top-center" +shell_offset = [0, 2, 50, 3] + +# overwrite +overwrite_title = "Overwrite an existing file? (y/N)" +overwrite_origin = "top-center" +overwrite_offset = [0, 2, 50, 3] + +# quit +quit_title = "{n} task{s} running, sure to quit? (y/N)" +quit_origin = "top-center" +quit_offset = [0, 2, 50, 3] + +[pick] +open_title = "Open with:" +open_origin = "hovered" +open_offset = [0, 1, 50, 7] + +[which] +sort_by = "none" +sort_sensitive = false +sort_reverse = false +sort_translit = false diff --git a/yazi/yazi.toml-1748477627471979 b/yazi/yazi.toml-1748477627471979 new file mode 100755 index 0000000..2e6683e --- /dev/null +++ b/yazi/yazi.toml-1748477627471979 @@ -0,0 +1,199 @@ +# A TOML linter such as https://taplo.tamasfe.dev/ can use this schema to validate your config. +# If you encounter any issues, please make an issue at https://github.com/yazi-rs/schemas. +"$schema" = "https://yazi-rs.github.io/schemas/yazi.json" + +[manager] +ratio = [1, 3, 4] +sort_by = "alphabetical" +sort_sensitive = false +sort_reverse = false +sort_dir_first = true +sort_translit = false +linemode = "size" +show_hidden = false +show_symlink = true +scrolloff = 5 +mouse_events = ["click", "scroll"] +title_format = "Yazi: {cwd}" + +[preview] +tab_size = 2 +max_width = 600 +max_height = 900 +cache_dir = "" +image_filter = "triangle" +image_quality = 75 +sixel_fraction = 15 +ueberzug_scale = 1 +ueberzug_offset = [0, 0, 0, 0] + +[opener] +edit = [ + { run = '${EDITOR:-vi} "$@"', desc = "$EDITOR", block = true, for = "unix" }, + { run = 'code %*', orphan = true, desc = "code", for = "windows" }, + { run = 'code -w %*', block = true, desc = "code (block)", for = "windows" }, +] +open = [ + { run = 'xdg-open "$1"', desc = "Open", for = "linux" }, + { run = 'open "$@"', desc = "Open", for = "macos" }, + { run = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" }, +] +reveal = [ + { run = 'xdg-open "$(dirname "$1")"', desc = "Reveal", for = "linux" }, + { run = 'open -R "$1"', desc = "Reveal", for = "macos" }, + { run = 'explorer /select,"%1"', orphan = true, desc = "Reveal", for = "windows" }, + { run = '''exiftool "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show EXIF", for = "unix" }, +] +extract = [ + { run = 'ya pub extract --list "$@"', desc = "Extract here", for = "unix" }, + { run = 'ya pub extract --list %*', desc = "Extract here", for = "windows" }, +] +play = [ + { run = 'mpv --force-window "$@"', orphan = true, for = "unix" }, + { run = 'mpv --force-window %*', orphan = true, for = "windows" }, + { run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" }, +] + +[open] +rules = [ + # Folder + { name = "*/", use = ["edit", "open", "reveal"] }, + # Text + { mime = "text/*", use = ["edit", "reveal"] }, + # Image + { mime = "image/*", use = ["open", "reveal"] }, + # Media + { mime = "{audio,video}/*", use = ["play", "reveal"] }, + # Archive + { mime = "application/{,g}zip", use = ["extract", "reveal"] }, + { mime = "application/{tar,bzip*,7z*,xz,rar}", use = ["extract", "reveal"] }, + # JSON + { mime = "application/{json,ndjson}", use = ["edit", "reveal"] }, + { mime = "*/javascript", use = ["edit", "reveal"] }, + # Empty file + { mime = "inode/empty", use = ["edit", "reveal"] }, + # Fallback + { name = "*", use = ["edit", "open", "reveal"] }, +] + +[tasks] +micro_workers = 10 +macro_workers = 25 +bizarre_retry = 5 +image_alloc = 536870912 # 512MB +image_bound = [0, 0] +suppress_preload = false + +[plugin] +fetchers = [ + # Mimetype + { id = "mime", name = "*", run = "mime", if = "!mime", prio = "high" }, + { id = "git", name = "*", run = "git", prio = "normal" }, + { id = "git", name = "*/", run = "git", prio = "normal" }, +] +preloaders = [ + # Image + { mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" }, + { mime = "image/*", run = "image" }, + # Video + { mime = "video/*", run = "video" }, + # PDF + { mime = "application/pdf", run = "pdf" }, + # Font + { mime = "font/*", run = "font" }, + { mime = "application/vnd.ms-opentype", run = "font" }, +] +previewers = [ + { name = "*/", run = "folder", sync = true }, + # Code + { mime = "text/*", run = "code" }, + { mime = "*/{xml,javascript,x-wine-extension-ini}", run = "code" }, + # JSON + { mime = "application/{json,x-ndjson}", run = "json" }, + # Image + { mime = "image/{avif,hei?,jxl,svg+xml}", run = "magick" }, + { mime = "image/*", run = "image" }, + # Video + { mime = "video/*", run = "video" }, + # PDF + { mime = "application/pdf", run = "pdf" }, + # Archive + { mime = "application/{,g}zip", run = "archive" }, + { mime = "application/x-{tar,bzip*,7z-compressed,xz,rar,iso9660-image}", run = "archive" }, + # Font + { mime = "font/*", run = "font" }, + { mime = "application/vnd.ms-opentype", run = "font" }, + # Empty file + { mime = "inode/x-empty", run = "empty" }, + # Fallback + { name = "*", run = "file" }, +] + +[input] +cursor_blink = false + +# cd +cd_title = "Change directory:" +cd_origin = "top-center" +cd_offset = [0, 2, 50, 3] + +# create +create_title = ["Create:", "Create (dir):"] +create_origin = "top-center" +create_offset = [0, 2, 50, 3] + +# rename +rename_title = "Rename:" +rename_origin = "hovered" +rename_offset = [0, 1, 50, 3] + +# trash +trash_title = "Move {n} selected file{s} to trash? (y/N)" +trash_origin = "top-center" +trash_offset = [0, 2, 50, 3] + +# delete +delete_title = "Delete {n} selected file{s} permanently? (y/N)" +delete_origin = "top-center" +delete_offset = [0, 2, 50, 3] + +# filter +filter_title = "Filter:" +filter_origin = "top-center" +filter_offset = [0, 2, 50, 3] + +# find +find_title = ["Find next:", "Find previous:"] +find_origin = "top-center" +find_offset = [0, 2, 50, 3] + +# search +search_title = "Search via {n}:" +search_origin = "top-center" +search_offset = [0, 2, 50, 3] + +# shell +shell_title = ["Shell:", "Shell (block):"] +shell_origin = "top-center" +shell_offset = [0, 2, 50, 3] + +# overwrite +overwrite_title = "Overwrite an existing file? (y/N)" +overwrite_origin = "top-center" +overwrite_offset = [0, 2, 50, 3] + +# quit +quit_title = "{n} task{s} running, sure to quit? (y/N)" +quit_origin = "top-center" +quit_offset = [0, 2, 50, 3] + +[pick] +open_title = "Open with:" +open_origin = "hovered" +open_offset = [0, 1, 50, 7] + +[which] +sort_by = "none" +sort_sensitive = false +sort_reverse = false +sort_translit = false