""" DARKROOM — Hugging Face Space (ZeroGPU, free, no card, not Colab) ================================================================ One Space serves the DARKROOM web tool at "/" AND runs the real HandRefiner pipeline on a free, on-demand ZeroGPU (NVIDIA H200 slice) via @spaces.GPU. You set it up once; it stays up at a permanent URL. WHY THIS SHAPE: ZeroGPU only allocates a GPU inside functions decorated with @spaces.GPU, and historically only for Gradio apps. We use `gradio.Server`, which keeps our custom HTML frontend while giving us Gradio's queue + automatic ZeroGPU allocation. (Ref: HF "Introducing gradio.Server".) -------------------------------------------------------------------------- DEPLOY (browser only, ~5 min, free) -------------------------------------------------------------------------- 1. huggingface.co -> New Space -> SDK: **Gradio**, Hardware: **ZeroGPU** (ZeroGPU shows up free; a free account gets a few GPU-minutes/day.) 2. Upload these two files to the Space: app.py (this file) requirements.txt (provided alongside) 3. Wait for it to build. Open the Space — that's DARKROOM, hands fixed on GPU. No token, no tunnel, no localhost. The Space URL is permanent. -------------------------------------------------------------------------- HONEST LIMITS -------------------------------------------------------------------------- * Free ZeroGPU has a small daily quota (a few minutes). Each hand-fix is a few GPU-seconds, so light personal use fits; heavy batch use will hit the cap. * First call after the Space sleeps has a cold start while models load. * Stock depth ControlNet is okay-not-perfect; swap CONTROLNET_ID to hr16/ControlNet-HandRefiner-pruned for the finetuned quality. * MeshGraphormer can't fix unreadable hands or crossed fingers (method limit). * ZeroGPU requires the Gradio SDK; this won't run as-is on a plain CPU Space. """ import io, base64 import spaces import torch from PIL import Image, ImageFilter from fastapi import Request, Response from fastapi.responses import HTMLResponse, JSONResponse import gradio as gr SD_INPAINT_ID = "runwayml/stable-diffusion-inpainting" CONTROLNET_ID = "lllyasviel/control_v11f1p_sd15_depth" # -> hr16/ControlNet-HandRefiner-pruned for best quality MESHGRAPHORMER_ID = "hr16/ControlNet-HandRefiner-pruned" MAX_SIDE = 768 DEFAULT_PROMPT = "a detailed, anatomically correct hand with five fingers, natural proportions, same art style and lighting" NEG = "extra fingers, fused fingers, missing fingers, deformed, mutated, blurry, low quality" FRONTEND_HTML = base64.b64decode("PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CjxtZXRhIGNoYXJzZXQ9IlVURi04Ij4KPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiPgo8dGl0bGU+REFSS1JPT00g4oCUIHBhZ2UgcmVzdG9yZXI8L3RpdGxlPgo8bGluayByZWw9InByZWNvbm5lY3QiIGhyZWY9Imh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20iPgo8bGluayByZWw9InByZWNvbm5lY3QiIGhyZWY9Imh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20iIGNyb3Nzb3JpZ2luPgo8bGluayBocmVmPSJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2NzczI/ZmFtaWx5PUJyaWNvbGFnZStHcm90ZXNxdWU6b3Bzeix3Z2h0QDEyLi45Niw0MDA7MTIuLjk2LDYwMDsxMi4uOTYsODAwJmZhbWlseT1JQk0rUGxleCtNb25vOndnaHRANDAwOzUwMDs2MDAmZGlzcGxheT1zd2FwIiByZWw9InN0eWxlc2hlZXQiPgo8c3R5bGU+CiAgOnJvb3R7LS1iZzojMGMwYjBhOy0tcGFuZWw6IzE0MTMxMTstLXBhbmVsLTI6IzFiMTkxNjstLWxpbmU6IzJhMjcyMzstLWluazojZWNlNmRhOy0tbXV0ZWQ6IzhhODM3NzstLWZhaW50OiM1YjU1NDk7LS1hbWJlcjojZmZiNDU0Oy0tYW1iZXItZGltOiNjOThhM2E7LS1jeWFuOiM1ZmQwYzU7LS1yZWQ6I2U4NjQzY30KICAqe2JveC1zaXppbmc6Ym9yZGVyLWJveDttYXJnaW46MDtwYWRkaW5nOjB9CiAgaHRtbCxib2R5e2hlaWdodDoxMDAlfQogIGJvZHl7YmFja2dyb3VuZDp2YXIoLS1iZyk7Y29sb3I6dmFyKC0taW5rKTtmb250LWZhbWlseTonSUJNIFBsZXggTW9ubycsbW9ub3NwYWNlO2ZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjEuNTtvdmVyZmxvdy14OmhpZGRlbjtiYWNrZ3JvdW5kLWltYWdlOnJhZGlhbC1ncmFkaWVudChlbGxpcHNlIDgwJSA1MCUgYXQgNTAlIC0xMCUsIHJnYmEoMjU1LDE4MCw4NCwwLjA2KSwgdHJhbnNwYXJlbnQgNjAlKX0KICBib2R5OjphZnRlcntjb250ZW50OiIiO3Bvc2l0aW9uOmZpeGVkO2luc2V0OjA7cG9pbnRlci1ldmVudHM6bm9uZTt6LWluZGV4Ojk5OTk7b3BhY2l0eTowLjAzNTtiYWNrZ3JvdW5kLWltYWdlOnVybCgiZGF0YTppbWFnZS9zdmcreG1sLCUzQ3N2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMjAnIGhlaWdodD0nMTIwJyUzRSUzQ2ZpbHRlciBpZD0nbiclM0UlM0NmZVR1cmJ1bGVuY2UgdHlwZT0nZnJhY3RhbE5vaXNlJyBiYXNlRnJlcXVlbmN5PScwLjknIG51bU9jdGF2ZXM9JzMnLyUzRSUzQy9maWx0ZXIlM0UlM0NyZWN0IHdpZHRoPScxMDAlMjUnIGhlaWdodD0nMTAwJTI1JyBmaWx0ZXI9J3VybCglMjNuKScvJTNFJTNDL3N2ZyUzRSIpfQogIC53cmFwe21heC13aWR0aDoxMjAwcHg7bWFyZ2luOjAgYXV0bztwYWRkaW5nOjAgMjJweCA4MHB4fQogIGhlYWRlcntwYWRkaW5nOjM0cHggMCAyNnB4O2JvcmRlci1ib3R0b206MXB4IHNvbGlkIHZhcigtLWxpbmUpO2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpmbGV4LWVuZDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtnYXA6MjBweDtmbGV4LXdyYXA6d3JhcH0KICAuYnJhbmQgaDF7Zm9udC1mYW1pbHk6J0JyaWNvbGFnZSBHcm90ZXNxdWUnLHNhbnMtc2VyaWY7Zm9udC13ZWlnaHQ6ODAwO2ZvbnQtc2l6ZTpjbGFtcCgzMHB4LDZ2dyw1NnB4KTtsZXR0ZXItc3BhY2luZzotMC4wM2VtO2xpbmUtaGVpZ2h0OjAuOTJ9CiAgLmJyYW5kIGgxIHNwYW57Y29sb3I6dmFyKC0tYW1iZXIpfQogIC5icmFuZCBwe2NvbG9yOnZhcigtLW11dGVkKTttYXJnaW4tdG9wOjhweDttYXgtd2lkdGg6NTQwcHg7Zm9udC1zaXplOjEyLjVweH0KICAuYmFkZ2V7Zm9udC1zaXplOjExcHg7Y29sb3I6dmFyKC0tY3lhbik7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtwYWRkaW5nOjdweCAxMnB4O2JvcmRlci1yYWRpdXM6MnB4O3doaXRlLXNwYWNlOm5vd3JhcDtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo4cHg7YmFja2dyb3VuZDp2YXIoLS1wYW5lbCl9CiAgLmRvdHt3aWR0aDo2cHg7aGVpZ2h0OjZweDtib3JkZXItcmFkaXVzOjUwJTtiYWNrZ3JvdW5kOnZhcigtLWN5YW4pO2JveC1zaGFkb3c6MCAwIDhweCB2YXIoLS1jeWFuKX0KICAuZHJvcHttYXJnaW4tdG9wOjI0cHg7Ym9yZGVyOjEuNXB4IGRhc2hlZCB2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjRweDtiYWNrZ3JvdW5kOnZhcigtLXBhbmVsKTtwYWRkaW5nOjM4cHggMjRweDt0ZXh0LWFsaWduOmNlbnRlcjtjdXJzb3I6cG9pbnRlcjt0cmFuc2l0aW9uOi4xOHM7cG9zaXRpb246cmVsYXRpdmV9CiAgLmRyb3A6aG92ZXIsLmRyb3AuaG90e2JvcmRlci1jb2xvcjp2YXIoLS1hbWJlcik7YmFja2dyb3VuZDp2YXIoLS1wYW5lbC0yKX0KICAuZHJvcCBoMntmb250LWZhbWlseTonQnJpY29sYWdlIEdyb3Rlc3F1ZScsc2Fucy1zZXJpZjtmb250LXdlaWdodDo2MDA7Zm9udC1zaXplOjE4cHg7bWFyZ2luLWJvdHRvbTo2cHh9CiAgLmRyb3AgcHtjb2xvcjp2YXIoLS1tdXRlZCk7Zm9udC1zaXplOjEycHh9LmRyb3AgLmtleXtjb2xvcjp2YXIoLS1hbWJlcil9CiAgaW5wdXRbdHlwZT1maWxlXXtkaXNwbGF5Om5vbmV9CiAgLnN0YWdle2Rpc3BsYXk6bm9uZTttYXJnaW4tdG9wOjI2cHg7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjMwOHB4IDFmcjtnYXA6MjJweDthbGlnbi1pdGVtczpzdGFydH0KICAuc3RhZ2Uub257ZGlzcGxheTpncmlkfQogIC50b29sc3twb3NpdGlvbjpzdGlja3k7dG9wOjE4cHh9CiAgLnRvb2x7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjRweDtiYWNrZ3JvdW5kOnZhcigtLXBhbmVsKTttYXJnaW4tYm90dG9tOjEycHg7b3ZlcmZsb3c6aGlkZGVufQogIC50b29sLnByaW1hcnl7Ym9yZGVyLWNvbG9yOnZhcigtLWFtYmVyLWRpbSk7Ym94LXNoYWRvdzowIDAgMCAxcHggcmdiYSgyNTUsMTgwLDg0LC4xNSl9CiAgLnRvb2wgPiBidXR0b24uaGVhZHt3aWR0aDoxMDAlO3RleHQtYWxpZ246bGVmdDtiYWNrZ3JvdW5kOm5vbmU7Ym9yZGVyOm5vbmU7Y29sb3I6dmFyKC0taW5rKTtjdXJzb3I6cG9pbnRlcjtwYWRkaW5nOjEzcHggMTVweDtmb250LWZhbWlseTonQnJpY29sYWdlIEdyb3Rlc3F1ZScsc2Fucy1zZXJpZjtmb250LXdlaWdodDo2MDA7Zm9udC1zaXplOjE0cHg7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjtnYXA6MTBweH0KICAudG9vbCAuaGVhZDpob3Zlcntjb2xvcjp2YXIoLS1hbWJlcil9CiAgLnRvb2wgLmhlYWQgLmlkeHtmb250LWZhbWlseTonSUJNIFBsZXggTW9ubyc7Zm9udC1zaXplOjEwcHg7Y29sb3I6dmFyKC0tZmFpbnQpO2ZvbnQtd2VpZ2h0OjQwMH0KICAudG9vbCAuYm9keXtkaXNwbGF5Om5vbmU7cGFkZGluZzowIDE1cHggMTZweDtib3JkZXItdG9wOjFweCBzb2xpZCB2YXIoLS1saW5lKX0KICAudG9vbC5vcGVuIC5ib2R5e2Rpc3BsYXk6YmxvY2t9LnRvb2wub3BlbiAuaGVhZCAuaWR4e2NvbG9yOnZhcigtLWFtYmVyKX0KICAuZGVzY3tmb250LXNpemU6MTFweDtjb2xvcjp2YXIoLS1tdXRlZCk7bGluZS1oZWlnaHQ6MS41NTttYXJnaW4tdG9wOjEycHh9CiAgLnNlZ3tkaXNwbGF5OmZsZXg7Z2FwOjZweDttYXJnaW4tdG9wOjExcHg7ZmxleC13cmFwOndyYXB9CiAgLnNlZyAubGJse3dpZHRoOjEwMCU7Zm9udC1zaXplOjEwcHg7Y29sb3I6dmFyKC0tZmFpbnQpO2xldHRlci1zcGFjaW5nOi4wNmVtO21hcmdpbi1ib3R0b206MXB4fQogIC5zZWcgYnV0dG9ue2ZsZXg6MTttaW4td2lkdGg6NDhweDtiYWNrZ3JvdW5kOnZhcigtLXBhbmVsLTIpO2JvcmRlcjoxcHggc29saWQgdmFyKC0tbGluZSk7Y29sb3I6dmFyKC0tbXV0ZWQpO3BhZGRpbmc6N3B4IDRweDtib3JkZXItcmFkaXVzOjNweDtjdXJzb3I6cG9pbnRlcjtmb250LWZhbWlseTonSUJNIFBsZXggTW9ubyc7Zm9udC1zaXplOjExcHg7dHJhbnNpdGlvbjouMTVzfQogIC5zZWcgYnV0dG9uLnNlbHtiYWNrZ3JvdW5kOnZhcigtLWFtYmVyKTtjb2xvcjojMWExNDA3O2JvcmRlci1jb2xvcjp2YXIoLS1hbWJlcik7Zm9udC13ZWlnaHQ6NjAwfQogIC5zZWcgYnV0dG9uOmhvdmVyOm5vdCguc2VsKXtjb2xvcjp2YXIoLS1pbmspO2JvcmRlci1jb2xvcjp2YXIoLS1mYWludCl9CiAgbGFiZWwuY3Rse2Rpc3BsYXk6YmxvY2s7bWFyZ2luLXRvcDoxM3B4O2ZvbnQtc2l6ZToxMXB4O2NvbG9yOnZhcigtLW11dGVkKX0KICBsYWJlbC5jdGwgLnZhbHtmbG9hdDpyaWdodDtjb2xvcjp2YXIoLS1hbWJlcik7Zm9udC13ZWlnaHQ6NTAwfQogIGlucHV0W3R5cGU9cmFuZ2Vdey13ZWJraXQtYXBwZWFyYW5jZTpub25lO2FwcGVhcmFuY2U6bm9uZTt3aWR0aDoxMDAlO2hlaWdodDozcHg7YmFja2dyb3VuZDp2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjJweDttYXJnaW4tdG9wOjdweDtjdXJzb3I6cG9pbnRlcn0KICBpbnB1dFt0eXBlPXJhbmdlXTo6LXdlYmtpdC1zbGlkZXItdGh1bWJ7LXdlYmtpdC1hcHBlYXJhbmNlOm5vbmU7d2lkdGg6MTRweDtoZWlnaHQ6MTRweDtib3JkZXItcmFkaXVzOjUwJTtiYWNrZ3JvdW5kOnZhcigtLWFtYmVyKTtib3JkZXI6MnB4IHNvbGlkIHZhcigtLWJnKTtib3gtc2hhZG93OjAgMCAwIDFweCB2YXIoLS1hbWJlci1kaW0pfQogIGlucHV0W3R5cGU9cmFuZ2VdOjotbW96LXJhbmdlLXRodW1ie3dpZHRoOjE0cHg7aGVpZ2h0OjE0cHg7Ym9yZGVyLXJhZGl1czo1MCU7YmFja2dyb3VuZDp2YXIoLS1hbWJlcik7Ym9yZGVyOjJweCBzb2xpZCB2YXIoLS1iZyl9CiAgLnJ1bnt3aWR0aDoxMDAlO21hcmdpbi10b3A6MTVweDtiYWNrZ3JvdW5kOnZhcigtLWFtYmVyKTtjb2xvcjojMWExNDA3O2JvcmRlcjpub25lO2JvcmRlci1yYWRpdXM6M3B4O3BhZGRpbmc6MTFweDtmb250LWZhbWlseTonQnJpY29sYWdlIEdyb3Rlc3F1ZScsc2Fucy1zZXJpZjtmb250LXdlaWdodDo3MDA7Zm9udC1zaXplOjEzcHg7Y3Vyc29yOnBvaW50ZXI7bGV0dGVyLXNwYWNpbmc6MC4wMmVtO3RyYW5zaXRpb246LjE1c30KICAucnVuOmhvdmVye2JhY2tncm91bmQ6I2ZmYzc3NDt0cmFuc2Zvcm06dHJhbnNsYXRlWSgtMXB4KX0KICAucnVuLnN1YntiYWNrZ3JvdW5kOnZhcigtLXBhbmVsLTIpO2NvbG9yOnZhcigtLWluayk7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtmb250LXdlaWdodDo2MDB9CiAgLnJ1bi5zdWI6aG92ZXJ7Ym9yZGVyLWNvbG9yOnZhcigtLWFtYmVyKTtjb2xvcjp2YXIoLS1hbWJlcik7dHJhbnNmb3JtOm5vbmV9CiAgLmhpZGV7ZGlzcGxheTpub25lfQogIGlucHV0LnR4dHt3aWR0aDoxMDAlO21hcmdpbi10b3A6OXB4O2JhY2tncm91bmQ6dmFyKC0tcGFuZWwtMik7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtjb2xvcjp2YXIoLS1pbmspO2JvcmRlci1yYWRpdXM6M3B4O3BhZGRpbmc6OHB4O2ZvbnQtZmFtaWx5OidJQk0gUGxleCBNb25vJztmb250LXNpemU6MTFweH0KICBpbnB1dC50eHQ6Zm9jdXN7b3V0bGluZTpub25lO2JvcmRlci1jb2xvcjp2YXIoLS1hbWJlcil9CiAgLmNoazJ7ZGlzcGxheTpmbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6OHB4O21hcmdpbi10b3A6MTFweDtjdXJzb3I6cG9pbnRlcjtmb250LXNpemU6MTFweDtjb2xvcjp2YXIoLS1tdXRlZCl9CiAgLmNoazIgaW5wdXR7YWNjZW50LWNvbG9yOnZhcigtLWFtYmVyKX0KICAud2Fybntmb250LXNpemU6MTAuNXB4O2NvbG9yOnZhcigtLWFtYmVyLWRpbSk7YmFja2dyb3VuZDpyZ2JhKDI1NSwxODAsODQsLjA2KTtib3JkZXI6MXB4IHNvbGlkIHJnYmEoMjU1LDE4MCw4NCwuMik7Ym9yZGVyLXJhZGl1czozcHg7cGFkZGluZzo5cHggMTBweDttYXJnaW4tdG9wOjEycHg7bGluZS1oZWlnaHQ6MS41NX0KICAud2FybiBie2NvbG9yOnZhcigtLWFtYmVyKX0KICAudmlld3tib3JkZXI6MXB4IHNvbGlkIHZhcigtLWxpbmUpO2JvcmRlci1yYWRpdXM6NHB4O2JhY2tncm91bmQ6dmFyKC0tcGFuZWwpO292ZXJmbG93OmhpZGRlbn0KICAudmlldyAudG9wYmFye2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW47Z2FwOjEwcHg7cGFkZGluZzoxMXB4IDE1cHg7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgdmFyKC0tbGluZSk7YmFja2dyb3VuZDp2YXIoLS1wYW5lbC0yKTtmbGV4LXdyYXA6d3JhcH0KICAudmlldyAudG9wYmFyIC50aXRsZXtmb250LWZhbWlseTonQnJpY29sYWdlIEdyb3Rlc3F1ZSc7Zm9udC13ZWlnaHQ6NjAwO2ZvbnQtc2l6ZToxM3B4fQogIC52aWV3IC50b3BiYXIgLm1ldGF7Zm9udC1zaXplOjEwLjVweDtjb2xvcjp2YXIoLS1mYWludCl9CiAgLmNhbnZhcy1ob3N0e3Bvc2l0aW9uOnJlbGF0aXZlO21pbi1oZWlnaHQ6MzQwcHg7bWF4LWhlaWdodDo2OHZoO2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtwYWRkaW5nOjE4cHg7b3ZlcmZsb3c6YXV0bztiYWNrZ3JvdW5kOnJlcGVhdGluZy1jb25pYy1ncmFkaWVudCgjMTUxNDBmIDAlIDI1JSwgIzFhMTgxMyAwJSA1MCUpIDUwJSAvIDIycHggMjJweH0KICAjY3Z3cmFwe3Bvc2l0aW9uOnJlbGF0aXZlO2Rpc3BsYXk6aW5saW5lLWJsb2NrO2xpbmUtaGVpZ2h0OjA7bWFyZ2luOmF1dG99CiAgY2FudmFzI2N2e2Rpc3BsYXk6YmxvY2s7Ym9yZGVyLXJhZGl1czoycHg7Ym94LXNoYWRvdzowIDhweCAzMHB4IHJnYmEoMCwwLDAsLjUpfQogICNjdndyYXAuZml0IGNhbnZhcyNjdnttYXgtd2lkdGg6MTAwJTttYXgtaGVpZ2h0OjYwdmh9CiAgY2FudmFzI21hc2t7cG9zaXRpb246YWJzb2x1dGU7aW5zZXQ6MDt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO2N1cnNvcjpjcm9zc2hhaXI7dG91Y2gtYWN0aW9uOm5vbmU7ZGlzcGxheTpub25lO2JvcmRlci1yYWRpdXM6MnB4fQogICNjdndyYXAucGFpbnRpbmcgY2FudmFzI21hc2t7ZGlzcGxheTpibG9ja30KICAudG9vbGJhcntkaXNwbGF5OmZsZXg7Z2FwOjhweDtwYWRkaW5nOjEycHggMTVweDtib3JkZXItdG9wOjFweCBzb2xpZCB2YXIoLS1saW5lKTtmbGV4LXdyYXA6d3JhcDthbGlnbi1pdGVtczpjZW50ZXJ9CiAgLnRvb2xiYXIgLnNwYWNlcntmbGV4OjF9CiAgLnRvb2xiYXIgLnpvb217ZGlzcGxheTpmbGV4O2dhcDo0cHg7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtib3JkZXItcmFkaXVzOjNweDtwYWRkaW5nOjNweDtiYWNrZ3JvdW5kOnZhcigtLXBhbmVsLTIpfQogIC50b29sYmFyIC56b29tIGJ1dHRvbntiYWNrZ3JvdW5kOm5vbmU7Ym9yZGVyOm5vbmU7Y29sb3I6dmFyKC0tbXV0ZWQpO2ZvbnQtZmFtaWx5OidJQk0gUGxleCBNb25vJztmb250LXNpemU6MTFweDtwYWRkaW5nOjRweCA4cHg7Ym9yZGVyLXJhZGl1czoycHg7Y3Vyc29yOnBvaW50ZXJ9CiAgLnRvb2xiYXIgLnpvb20gYnV0dG9uLnNlbHtiYWNrZ3JvdW5kOnZhcigtLWFtYmVyKTtjb2xvcjojMWExNDA3O2ZvbnQtd2VpZ2h0OjYwMH0KICAuYnRue2JhY2tncm91bmQ6dmFyKC0tcGFuZWwtMik7Ym9yZGVyOjFweCBzb2xpZCB2YXIoLS1saW5lKTtjb2xvcjp2YXIoLS1pbmspO3BhZGRpbmc6OHB4IDEzcHg7Ym9yZGVyLXJhZGl1czozcHg7Y3Vyc29yOnBvaW50ZXI7Zm9udC1mYW1pbHk6J0lCTSBQbGV4IE1vbm8nO2ZvbnQtc2l6ZToxMS41cHg7dHJhbnNpdGlvbjouMTVzO2Rpc3BsYXk6ZmxleDtnYXA6N3B4O2FsaWduLWl0ZW1zOmNlbnRlcn0KICAuYnRuOmhvdmVye2JvcmRlci1jb2xvcjp2YXIoLS1hbWJlcik7Y29sb3I6dmFyKC0tYW1iZXIpfS5idG4uZ2hvc3R7Y29sb3I6dmFyKC0tbXV0ZWQpfS5idG4ub257Ym9yZGVyLWNvbG9yOnZhcigtLWN5YW4pO2NvbG9yOnZhcigtLWN5YW4pfQogIC5jbXBiYXJ7ZGlzcGxheTpub25lO3BhZGRpbmc6MTFweCAxNXB4O2JvcmRlci10b3A6MXB4IHNvbGlkIHZhcigtLWxpbmUpO2JhY2tncm91bmQ6dmFyKC0tcGFuZWwtMik7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDoxNHB4O2ZsZXgtd3JhcDp3cmFwfQogIC5jbXBiYXIub257ZGlzcGxheTpmbGV4fQogIC5jbXBiYXIgLmxhYntmb250LXNpemU6MTAuNXB4O2NvbG9yOnZhcigtLWZhaW50KTtsZXR0ZXItc3BhY2luZzowLjA4ZW19LmNtcGJhciAubGFiIGJ7Y29sb3I6dmFyKC0tY3lhbil9CiAgLmNtcGJhciBpbnB1dFt0eXBlPXJhbmdlXXtmbGV4OjE7bWluLXdpZHRoOjEyMHB4O21hcmdpbi10b3A6MH0KICAucHJvY2Vzc2luZ3twb3NpdGlvbjphYnNvbHV0ZTtpbnNldDowO2JhY2tncm91bmQ6cmdiYSgxMiwxMSwxMCwuODIpO2Rpc3BsYXk6bm9uZTthbGlnbi1pdGVtczpjZW50ZXI7anVzdGlmeS1jb250ZW50OmNlbnRlcjtmbGV4LWRpcmVjdGlvbjpjb2x1bW47Z2FwOjE0cHg7ei1pbmRleDo1fQogIC5wcm9jZXNzaW5nLm9ue2Rpc3BsYXk6ZmxleH0KICAuc3Bpbm5lcnt3aWR0aDozNHB4O2hlaWdodDozNHB4O2JvcmRlcjozcHggc29saWQgdmFyKC0tbGluZSk7Ym9yZGVyLXRvcC1jb2xvcjp2YXIoLS1hbWJlcik7Ym9yZGVyLXJhZGl1czo1MCU7YW5pbWF0aW9uOnNwaW4gLjhzIGxpbmVhciBpbmZpbml0ZX0KICBAa2V5ZnJhbWVzIHNwaW57dG97dHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpfX0KICAucHJvY2Vzc2luZyBwe2ZvbnQtc2l6ZToxMXB4O2NvbG9yOnZhcigtLWFtYmVyKTtsZXR0ZXItc3BhY2luZzowLjA1ZW07dGV4dC1hbGlnbjpjZW50ZXI7cGFkZGluZzowIDIwcHg7d2hpdGUtc3BhY2U6cHJlLWxpbmU7bGluZS1oZWlnaHQ6MS43fQogICNib290e3Bvc2l0aW9uOmZpeGVkO2luc2V0OjA7ei1pbmRleDoxMDAwMDtiYWNrZ3JvdW5kOnZhcigtLWJnKTtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2p1c3RpZnktY29udGVudDpjZW50ZXI7dHJhbnNpdGlvbjpvcGFjaXR5IC41NXMgZWFzZTtiYWNrZ3JvdW5kLWltYWdlOnJhZGlhbC1ncmFkaWVudChlbGxpcHNlIDcwJSA1MCUgYXQgNTAlIDM4JSwgcmdiYSgyNTUsMTgwLDg0LDAuMDgpLCB0cmFuc3BhcmVudCA2MCUpfQogICNib290LmdvbmV7b3BhY2l0eTowO3BvaW50ZXItZXZlbnRzOm5vbmV9CiAgLmJvb3QtaW5uZXJ7dGV4dC1hbGlnbjpjZW50ZXJ9CiAgLmJvb3QtbG9nb3tmb250LWZhbWlseTonQnJpY29sYWdlIEdyb3Rlc3F1ZScsc2Fucy1zZXJpZjtmb250LXdlaWdodDo4MDA7Zm9udC1zaXplOmNsYW1wKDM0cHgsOXZ3LDUycHgpO2xldHRlci1zcGFjaW5nOi0wLjAzZW07bGluZS1oZWlnaHQ6MX0KICAuYm9vdC1sb2dvIHNwYW57Y29sb3I6dmFyKC0tYW1iZXIpfQogIC5ib290LWJhcnt3aWR0aDoxOTBweDtoZWlnaHQ6M3B4O2JhY2tncm91bmQ6dmFyKC0tbGluZSk7Ym9yZGVyLXJhZGl1czoycHg7bWFyZ2luOjIwcHggYXV0byAxM3B4O292ZXJmbG93OmhpZGRlbjtwb3NpdGlvbjpyZWxhdGl2ZX0KICAuYm9vdC1iYXIgaXtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0Oi00MiU7d2lkdGg6NDIlO2hlaWdodDoxMDAlO2JhY2tncm91bmQ6dmFyKC0tYW1iZXIpO2JvcmRlci1yYWRpdXM6MnB4O2JveC1zaGFkb3c6MCAwIDEwcHggdmFyKC0tYW1iZXIpO2FuaW1hdGlvbjpzbGlkZSAxLjFzIGluZmluaXRlIGVhc2UtaW4tb3V0fQogIEBrZXlmcmFtZXMgc2xpZGV7MCV7bGVmdDotNDIlfTEwMCV7bGVmdDoxMDAlfX0KICAuYm9vdC1tc2d7Zm9udC1zaXplOjExcHg7Y29sb3I6dmFyKC0tbXV0ZWQpO2xldHRlci1zcGFjaW5nOi4xMmVtO3RleHQtdHJhbnNmb3JtOnVwcGVyY2FzZX0KICBmb290ZXJ7bWFyZ2luLXRvcDo0MHB4O3BhZGRpbmctdG9wOjIwcHg7Ym9yZGVyLXRvcDoxcHggc29saWQgdmFyKC0tbGluZSk7Y29sb3I6dmFyKC0tZmFpbnQpO2ZvbnQtc2l6ZToxMXB4O2xpbmUtaGVpZ2h0OjEuN30KICBmb290ZXIgYntjb2xvcjp2YXIoLS1tdXRlZCl9CiAgQG1lZGlhKG1heC13aWR0aDo4NjBweCl7CiAgICAuc3RhZ2V7Z3JpZC10ZW1wbGF0ZS1jb2x1bW5zOjFmcjtnYXA6MTRweH0KICAgIC52aWV3e29yZGVyOi0xfS50b29sc3twb3NpdGlvbjpzdGF0aWN9CiAgICAud3JhcHtwYWRkaW5nOjAgMTRweCA2MHB4fQogICAgYm9keXtmb250LXNpemU6MTJweH0KICAgIGhlYWRlcntwYWRkaW5nOjI0cHggMCAxOHB4fS5icmFuZCBwe2ZvbnQtc2l6ZToxMnB4fQogICAgLmNhbnZhcy1ob3N0e21heC1oZWlnaHQ6NTR2aH0jY3Z3cmFwLmZpdCBjYW52YXMjY3Z7bWF4LWhlaWdodDo0NnZofQogICAgLnRvb2xiYXJ7Z2FwOjZweH0uYnRue3BhZGRpbmc6OXB4IDEwcHg7Zm9udC1zaXplOjExcHh9CiAgfQo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5Pgo8ZGl2IGlkPSJib290Ij48ZGl2IGNsYXNzPSJib290LWlubmVyIj48ZGl2IGNsYXNzPSJib290LWxvZ28iPkRBUks8c3Bhbj5ST09NPC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9ImJvb3QtYmFyIj48aT48L2k+PC9kaXY+PGRpdiBjbGFzcz0iYm9vdC1tc2ciIGlkPSJib290X21zZyI+aW5pdGlhbGl6aW5nPC9kaXY+PC9kaXY+PC9kaXY+CjxkaXYgY2xhc3M9IndyYXAiPgogIDxoZWFkZXI+CiAgICA8ZGl2IGNsYXNzPSJicmFuZCI+CiAgICAgIDxoMT5EQVJLPHNwYW4+Uk9PTTwvc3Bhbj48L2gxPgogICAgICA8cD5UZWNobmljYWwgcmVzdG9yZXIgKyB1cHNjYWxlciBmb3IgQUkgYXJ0LiBEZWJsdXJzLCBjcmlzcHMgbGluZXdvcmssIGNsZWFucyBjb2xvciBub2lzZSwgdXBzY2FsZXMsIGFuZCBhdXRvLXRhcmdldHMgdGhlIHNvZnQgcmVnaW9ucyB3aGVyZSBoYW5kcyAvIGV5ZXMgLyBmZWV0IHVzdWFsbHkgZmFpbC4gRnVsbHkgbG9jYWwg4oCUIG5vIHVwbG9hZCwgbm8gcHJvbXB0cywgbm8ga2V5cy48L3A+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImJhZGdlIj48c3BhbiBjbGFzcz0iZG90Ij48L3NwYW4+IExPQ0FMIMK3IEFVVE88L2Rpdj4KICA8L2hlYWRlcj4KCiAgPGRpdiBjbGFzcz0iZHJvcCIgaWQ9ImRyb3AiPgogICAgPGgyPkRyb3AgYSBwYWdlIGhlcmU8L2gyPgogICAgPHA+b3IgPHNwYW4gY2xhc3M9ImtleSI+Y2xpY2sgdG8gYnJvd3NlPC9zcGFuPiDCtyBvciA8c3BhbiBjbGFzcz0ia2V5Ij5wYXN0ZTwvc3Bhbj4gKEN0cmwvQ21kK1YpPC9wPgogICAgPGlucHV0IHR5cGU9ImZpbGUiIGlkPSJmaWxlIiBhY2NlcHQ9ImltYWdlLyoiPgogIDwvZGl2PgoKICA8ZGl2IGNsYXNzPSJzdGFnZSIgaWQ9InN0YWdlIj4KICAgIDxkaXYgY2xhc3M9InRvb2xzIj4KCiAgICAgIDxkaXYgY2xhc3M9InRvb2wgcHJpbWFyeSBvcGVuIiBkYXRhLXRvb2w9ImF1dG8iPgogICAgICAgIDxidXR0b24gY2xhc3M9ImhlYWQiPkF1dG8tcmVzdG9yZSA8c3BhbiBjbGFzcz0iaWR4Ij4wMSAvIE9ORS1DTElDSzwvc3Bhbj48L2J1dHRvbj4KICAgICAgICA8ZGl2IGNsYXNzPSJib2R5Ij4KICAgICAgICAgIDxwIGNsYXNzPSJkZXNjIj5Fc3RpbWF0ZXMgc29mdG5lc3MgKyBub2lzZSwgdGhlbiBydW5zIGNsZWFuIOKGkiBkZWJsdXIg4oaSIGNyaXNwIOKGkiBzaGFycGVuIGF0IGJlc3QtanVkZ21lbnQgc2V0dGluZ3MuIFN0YXJ0IGhlcmUsIHRoZW4gem9vbSB0byAxMDAlIHRvIHNlZSB0aGUgcmVzdWx0LjwvcD4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9InNfYXV0byI+PHNwYW4gY2xhc3M9ImxibCI+SU5URU5TSVRZPC9zcGFuPjxidXR0b24gZGF0YS12PSJsaWdodCI+TGlnaHQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0ic3RhbmRhcmQiIGNsYXNzPSJzZWwiPlN0YW5kYXJkPC9idXR0b24+PGJ1dHRvbiBkYXRhLXY9InN0cm9uZyI+U3Ryb25nPC9idXR0b24+PC9kaXY+CiAgICAgICAgICA8YnV0dG9uIGNsYXNzPSJydW4iIGRhdGEtcnVuPSJhdXRvIj7impkgQXV0by1yZXN0b3JlIHBhZ2U8L2J1dHRvbj4KICAgICAgICA8L2Rpdj4KICAgICAgPC9kaXY+CgogICAgICA8ZGl2IGNsYXNzPSJ0b29sIiBkYXRhLXRvb2w9ImRldGFpbCI+CiAgICAgICAgPGJ1dHRvbiBjbGFzcz0iaGVhZCI+RGV0YWlsIHJlY292ZXJ5IDxzcGFuIGNsYXNzPSJpZHgiPjAyIC8gQVVUTy1UQVJHRVQ8L3NwYW4+PC9idXR0b24+CiAgICAgICAgPGRpdiBjbGFzcz0iYm9keSI+CiAgICAgICAgICA8cCBjbGFzcz0iZGVzYyI+QXV0by1maW5kcyBibHVycnkgLyBsb3ctZGV0YWlsIHJlZ2lvbnMg4oCUIHNraW4tdG9uZSB3ZWlnaHRlZCwgc28gaXQgZmF2b3JzIGhhbmRzLCBsaW1icyBhbmQgZmVldCDigJQgYW5kIGFwcGxpZXMgYW4gaW50ZW5zaWZpZWQgcmVwYWlyIG9ubHkgdGhlcmUuIE1hc2tpbmcgaXMgdGhlIGZhbGxiYWNrLjwvcD4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9ImR0X21vZGUiPjxzcGFuIGNsYXNzPSJsYmwiPlRBUkdFVElORzwvc3Bhbj48YnV0dG9uIGRhdGEtdj0iYXV0byIgY2xhc3M9InNlbCI+QXV0by1kZXRlY3Q8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0ibWFzayI+TWFudWFsIG1hc2s8L2J1dHRvbj48L2Rpdj4KICAgICAgICAgIDxkaXYgaWQ9ImR0X21hc2tib3giIGNsYXNzPSJoaWRlIj4KICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz0icnVuIHN1YiIgaWQ9ImR0X3BhaW50IiBzdHlsZT0ibWFyZ2luLXRvcDoxMXB4Ij7inI4gRW50ZXIgbWFzayBtb2RlPC9idXR0b24+CiAgICAgICAgICAgIDxsYWJlbCBjbGFzcz0iY3RsIj5CcnVzaCBzaXplIDxzcGFuIGNsYXNzPSJ2YWwiIGlkPSJkdF9icnVzaF92Ij40MDwvc3Bhbj48aW5wdXQgdHlwZT0icmFuZ2UiIGlkPSJkdF9icnVzaCIgbWluPSI2IiBtYXg9IjE4MCIgc3RlcD0iMiIgdmFsdWU9IjQwIj48L2xhYmVsPgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWciIGRhdGEtc2VnPSJkdF9icnVzaG1vZGUiPjxzcGFuIGNsYXNzPSJsYmwiPkJSVVNIPC9zcGFuPjxidXR0b24gZGF0YS12PSJwYWludCIgY2xhc3M9InNlbCI+UGFpbnQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0iZXJhc2UiPkVyYXNlPC9idXR0b24+PC9kaXY+CiAgICAgICAgICAgIDxidXR0b24gY2xhc3M9InJ1biBzdWIiIGlkPSJkdF9jbGVhciIgc3R5bGU9Im1hcmdpbi10b3A6OHB4Ij5DbGVhciBtYXNrPC9idXR0b24+CiAgICAgICAgICA8L2Rpdj4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9InNfZGV0YWlsIj48c3BhbiBjbGFzcz0ibGJsIj5JTlRFTlNJVFk8L3NwYW4+PGJ1dHRvbiBkYXRhLXY9InN0YW5kYXJkIj5TdGFuZGFyZDwvYnV0dG9uPjxidXR0b24gZGF0YS12PSJzdHJvbmciIGNsYXNzPSJzZWwiPlN0cm9uZzwvYnV0dG9uPjwvZGl2PgogICAgICAgICAgPGxhYmVsIGNsYXNzPSJjaGsiIHN0eWxlPSJkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyO2dhcDo4cHg7bWFyZ2luLXRvcDoxMnB4O2N1cnNvcjpwb2ludGVyO2ZvbnQtc2l6ZToxMXB4O2NvbG9yOnZhcigtLW11dGVkKSI+PGlucHV0IHR5cGU9ImNoZWNrYm94IiBpZD0iZHRfcHJldmlldyIgc3R5bGU9ImFjY2VudC1jb2xvcjp2YXIoLS1jeWFuKSI+IFNob3cgZGV0ZWN0ZWQgcmVnaW9ucyAocHJldmlldyBvdmVybGF5KTwvbGFiZWw+CiAgICAgICAgICA8YnV0dG9uIGNsYXNzPSJydW4iIGRhdGEtcnVuPSJkZXRhaWwiPlJlY292ZXIgZGV0YWlsPC9idXR0b24+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJ3YXJuIj48Yj5Ib25lc3QgbGltaXQ6PC9iPiB0aGlzIHRhcmdldHMgPGI+c29mdC9sb3ctZGV0YWlsIGFyZWFzPC9iPiBieSBpbWFnZSBhbmFseXNpcyDigJQgaXQgZG9lcyBub3QgPGk+cmVjb2duaXplPC9pPiBib2R5IHBhcnRzLCBhbmQgaXQgY2FuJ3QgcmVzdHJ1Y3R1cmUgYnJva2VuIGFuYXRvbXkgKGFkZCBhIG1pc3NpbmcgZmluZ2VyLCByZWJ1aWxkIGEgbWVsdGVkIGV5ZSkuIEl0IHNoYXJwZW5zIGFuZCBjbGVhbnMgaG93IHRoZXkgcmVuZGVyLiBTdHJ1Y3R1cmFsIGZpeGVzIG5lZWQgYSBnZW5lcmF0aXZlIHRvb2wuPC9kaXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgoKICAgICAgPGRpdiBjbGFzcz0idG9vbCIgZGF0YS10b29sPSJ1cHNjYWxlIj4KICAgICAgICA8YnV0dG9uIGNsYXNzPSJoZWFkIj5VcHNjYWxlIDxzcGFuIGNsYXNzPSJpZHgiPjAzIC8gUkVTSVpFPC9zcGFuPjwvYnV0dG9uPgogICAgICAgIDxkaXYgY2xhc3M9ImJvZHkiPgogICAgICAgICAgPHAgY2xhc3M9ImRlc2MiPkxhbmN6b3MgcmVzYW1wbGluZyArIGVkZ2UgcmUtc2hhcnBlbmluZy4gSGlnaC1xdWFsaXR5IGVubGFyZ2VtZW50IGZvciBsaW5lYXJ0IGFuZCBmbGF0cy4gKENsYXNzaWNhbCByZXNpemUsIG5vdCBkZXRhaWwtaW52ZW50aW5nIHN1cGVyLXJlc29sdXRpb24uKTwvcD4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9InVwX2ZhY3RvciI+PHNwYW4gY2xhc3M9ImxibCI+U0NBTEU8L3NwYW4+PGJ1dHRvbiBkYXRhLXY9IjIiIGNsYXNzPSJzZWwiPjLDlzwvYnV0dG9uPjxidXR0b24gZGF0YS12PSIzIj4zw5c8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0iNCI+NMOXPC9idXR0b24+PC9kaXY+CiAgICAgICAgICA8cCBjbGFzcz0iZGVzYyIgaWQ9InVwX3RhcmdldCI+PC9wPgogICAgICAgICAgPGJ1dHRvbiBjbGFzcz0icnVuIiBkYXRhLXJ1bj0idXBzY2FsZSI+VXBzY2FsZTwvYnV0dG9uPgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj4KCiAgICAgIDxkaXYgY2xhc3M9InRvb2wiIGRhdGEtdG9vbD0iZGVibHVyIj4KICAgICAgICA8YnV0dG9uIGNsYXNzPSJoZWFkIj5EZWJsdXIgPHNwYW4gY2xhc3M9ImlkeCI+MDQgLyBERUNPTlZPTFZFPC9zcGFuPjwvYnV0dG9uPgogICAgICAgIDxkaXYgY2xhc3M9ImJvZHkiPgogICAgICAgICAgPHAgY2xhc3M9ImRlc2MiPlJpY2hhcmRzb27igJNMdWN5IGRlY29udm9sdXRpb24g4oCUIHJldmVyc2VzIHNvZnQgQUkgaGF6ZS4gUmVjb3ZlcnMgYXBwYXJlbnQgZGV0YWlsIGluIGZhY2VzIGFuZCBleWVzLjwvcD4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9InNfZGVibHVyIj48c3BhbiBjbGFzcz0ibGJsIj5JTlRFTlNJVFk8L3NwYW4+PGJ1dHRvbiBkYXRhLXY9ImxpZ2h0Ij5MaWdodDwvYnV0dG9uPjxidXR0b24gZGF0YS12PSJzdGFuZGFyZCIgY2xhc3M9InNlbCI+U3RhbmRhcmQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0ic3Ryb25nIj5TdHJvbmc8L2J1dHRvbj48L2Rpdj4KICAgICAgICAgIDxidXR0b24gY2xhc3M9InJ1biIgZGF0YS1ydW49ImRlYmx1ciI+RGVibHVyPC9idXR0b24+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgoKICAgICAgPGRpdiBjbGFzcz0idG9vbCIgZGF0YS10b29sPSJjcmlzcCI+CiAgICAgICAgPGJ1dHRvbiBjbGFzcz0iaGVhZCI+Q3Jpc3AgbGluZXMgPHNwYW4gY2xhc3M9ImlkeCI+MDUgLyBFREdFPC9zcGFuPjwvYnV0dG9uPgogICAgICAgIDxkaXYgY2xhc3M9ImJvZHkiPgogICAgICAgICAgPHAgY2xhc3M9ImRlc2MiPkRhcmtlbnMgKyBzaGFycGVucyBleGlzdGluZyBsaW5ld29yayBpbiBwbGFjZSwgbGVhdmluZyBmbGF0IGNvbG9yIHVudG91Y2hlZC48L3A+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWciIGRhdGEtc2VnPSJzX2NyaXNwIj48c3BhbiBjbGFzcz0ibGJsIj5JTlRFTlNJVFk8L3NwYW4+PGJ1dHRvbiBkYXRhLXY9ImxpZ2h0Ij5MaWdodDwvYnV0dG9uPjxidXR0b24gZGF0YS12PSJzdGFuZGFyZCIgY2xhc3M9InNlbCI+U3RhbmRhcmQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0ic3Ryb25nIj5TdHJvbmc8L2J1dHRvbj48L2Rpdj4KICAgICAgICAgIDxidXR0b24gY2xhc3M9InJ1biIgZGF0YS1ydW49ImNyaXNwIj5DcmlzcCBsaW5lczwvYnV0dG9uPgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj4KCiAgICAgIDxkaXYgY2xhc3M9InRvb2wiIGRhdGEtdG9vbD0iY2xlYW4iPgogICAgICAgIDxidXR0b24gY2xhc3M9ImhlYWQiPkNsZWFuIC8gY29uc2lzdGVuY3kgPHNwYW4gY2xhc3M9ImlkeCI+MDYgLyBERU5PSVNFPC9zcGFuPjwvYnV0dG9uPgogICAgICAgIDxkaXYgY2xhc3M9ImJvZHkiPgogICAgICAgICAgPHAgY2xhc3M9ImRlc2MiPkNocm9tYSBkZW5vaXNlIOKAlCByZW1vdmVzIGNvbG9yIGJsb3RjaGluZy9iYW5kaW5nIHdoaWxlIGtlZXBpbmcgbHVtaW5hbmNlIGRldGFpbCBzaGFycC48L3A+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJzZWciIGRhdGEtc2VnPSJzX2NsZWFuIj48c3BhbiBjbGFzcz0ibGJsIj5JTlRFTlNJVFk8L3NwYW4+PGJ1dHRvbiBkYXRhLXY9ImxpZ2h0Ij5MaWdodDwvYnV0dG9uPjxidXR0b24gZGF0YS12PSJzdGFuZGFyZCIgY2xhc3M9InNlbCI+U3RhbmRhcmQ8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0ic3Ryb25nIj5TdHJvbmc8L2J1dHRvbj48L2Rpdj4KICAgICAgICAgIDxidXR0b24gY2xhc3M9InJ1biIgZGF0YS1ydW49ImNsZWFuIj5DbGVhbiBwYWdlPC9idXR0b24+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgoKICAgICAgPGRpdiBjbGFzcz0idG9vbCIgZGF0YS10b29sPSJmaXgiPgogICAgICAgIDxidXR0b24gY2xhc3M9ImhlYWQiPkZpeCBzdHJ1Y3R1cmUgPHNwYW4gY2xhc3M9ImlkeCI+MDcgLyBCUklER0U8L3NwYW4+PC9idXR0b24+CiAgICAgICAgPGRpdiBjbGFzcz0iYm9keSI+CiAgICAgICAgICA8cCBjbGFzcz0iZGVzYyI+U2VuZHMgdGhlIHBhZ2UgdG8gYSBsb2NhbCA8Yj5IYW5kUmVmaW5lcjwvYj4gc2VydmVyIChDb250cm9sTmV0ICsgTWVzaEdyYXBob3JtZXIpIHRoYXQgcmVnZW5lcmF0ZXMgbWFsZm9ybWVkIGhhbmRzIGZvbGxvd2luZyBjb3JyZWN0IDNEIGhhbmQgZ2VvbWV0cnkg4oCUIHRoZSByZWFsIDxiPnN0cnVjdHVyYWw8L2I+IGZpeCwgbm90IGEgZmlsdGVyLiBSZXN1bHQgcmV0dXJucyB0byB0aGUgY29tcGFyZSBnYXRlLjwvcD4KICAgICAgICAgIDxkaXYgY2xhc3M9InNlZyIgZGF0YS1zZWc9ImZ4X21vZGUiPjxzcGFuIGNsYXNzPSJsYmwiPlRBUkdFVDwvc3Bhbj48YnV0dG9uIGRhdGEtdj0iaGFuZHMiIGNsYXNzPSJzZWwiPkhhbmRzIChIYW5kUmVmaW5lcik8L2J1dHRvbj48YnV0dG9uIGRhdGEtdj0iZ2VuZXJpYyI+R2VuZXJpYyBpbnBhaW50PC9idXR0b24+PC9kaXY+CiAgICAgICAgICA8bGFiZWwgY2xhc3M9ImNoazIiPjxpbnB1dCBpZD0iZnhfdXNlbWFzayIgdHlwZT0iY2hlY2tib3giPiBTZW5kIG15IG1hc2tlZCByZWdpb24gKGVsc2UgTWVzaEdyYXBob3JtZXIgYXV0by1maW5kcyBoYW5kcyk8L2xhYmVsPgogICAgICAgICAgPGlucHV0IGNsYXNzPSJ0eHQiIGlkPSJmeF9lbmRwb2ludCIgdHlwZT0idGV4dCIgdmFsdWU9Ii9yZWZpbmUiIHBsYWNlaG9sZGVyPSJlbmRwb2ludCAoZGVmYXVsdHMgdG8gdGhpcyBhcHAncyAvcmVmaW5lKSI+CiAgICAgICAgICA8aW5wdXQgY2xhc3M9InR4dCIgaWQ9ImZ4X3Rva2VuIiB0eXBlPSJwYXNzd29yZCIgcGxhY2Vob2xkZXI9IkF1dGggdG9rZW4gKG1hdGNoZXMgREFSS1JPT01fVE9LRU4gc2VjcmV0KSI+CiAgICAgICAgICA8YnV0dG9uIGNsYXNzPSJydW4iIGlkPSJmeF9zZW5kIj7impkgU2VuZCB0byByZWZpbmVyPC9idXR0b24+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJ3YXJuIj48Yj5DbG91ZCBHUFUgYmFja2VuZC48L2I+IFRoaXMgcGFnZSBpcyBzZXJ2ZWQgYnkgeW91ciBNb2RhbCBhcHAsIHNvIHRoZSByZWZpbmVyIGlzIHRoZSBzYW1lIGFwcCBhdCA8Yj4vcmVmaW5lPC9iPiDigJQganVzdCBlbnRlciB5b3VyIHRva2VuLiBGaXJzdCBmaXggYWZ0ZXIgaWRsZSB3YWtlcyB0aGUgR1BVIChjb2xkIHN0YXJ0LCB1cCB0byB+NDBzKTsgbGF0ZXIgZml4ZXMgdGFrZSBhIGZldyBzZWNvbmRzLiBIYW5kUmVmaW5lciBjYW4ndCBmaXggdW5yZWFkYWJsZSBoYW5kcyBvciBjcm9zc2VkIGZpbmdlcnMuPC9kaXY+CiAgICAgICAgPC9kaXY+CiAgICAgIDwvZGl2PgogICAgPC9kaXY+CgogICAgPGRpdiBjbGFzcz0idmlldyI+CiAgICAgIDxkaXYgY2xhc3M9InRvcGJhciI+PHNwYW4gY2xhc3M9InRpdGxlIiBpZD0idl90aXRsZSI+T3JpZ2luYWw8L3NwYW4+PHNwYW4gY2xhc3M9Im1ldGEiIGlkPSJ2X21ldGEiPjwvc3Bhbj48L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iY2FudmFzLWhvc3QiPgogICAgICAgIDxkaXYgaWQ9ImN2d3JhcCIgY2xhc3M9ImZpdCI+PGNhbnZhcyBpZD0iY3YiPjwvY2FudmFzPjxjYW52YXMgaWQ9Im1hc2siPjwvY2FudmFzPjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9InByb2Nlc3NpbmciIGlkPSJwcm9jIj48ZGl2IGNsYXNzPSJzcGlubmVyIj48L2Rpdj48cCBpZD0icHJvY190Ij5QUk9DRVNTSU5HPC9wPjwvZGl2PgogICAgICA8L2Rpdj4KICAgICAgPGRpdiBjbGFzcz0iY21wYmFyIiBpZD0iY21wYmFyIj4KICAgICAgICA8c3BhbiBjbGFzcz0ibGFiIj48Yj7il4QgT1JJR0lOQUw8L2I+PC9zcGFuPgogICAgICAgIDxpbnB1dCB0eXBlPSJyYW5nZSIgaWQ9ImNtcF9zbGlkZXIiIG1pbj0iMCIgbWF4PSIxMDAiIHZhbHVlPSI1MCI+CiAgICAgICAgPHNwYW4gY2xhc3M9ImxhYiI+PGI+UkVTVE9SRUQg4pa6PC9iPjwvc3Bhbj4KICAgICAgICA8YnV0dG9uIGNsYXNzPSJidG4iIGlkPSJjbXBfZG9uZSI+4pyVIENsb3NlPC9idXR0b24+CiAgICAgIDwvZGl2PgogICAgICA8ZGl2IGNsYXNzPSJ0b29sYmFyIj4KICAgICAgICA8YnV0dG9uIGNsYXNzPSJidG4gZ2hvc3QiIGlkPSJiX29yaWciPuKGuiBSZXNldDwvYnV0dG9uPgogICAgICAgIDxidXR0b24gY2xhc3M9ImJ0biIgaWQ9ImJfdXNlcmVzIiB0aXRsZT0iU3RhY2sgdGhlIHJlc3VsdCBhcyB0aGUgbmV3IGJhc2UiPuKHqiBVc2UgYXMgYmFzZTwvYnV0dG9uPgogICAgICAgIDxidXR0b24gY2xhc3M9ImJ0biIgaWQ9ImJfY21wIj7ih4QgQ29tcGFyZTwvYnV0dG9uPgogICAgICAgIDxkaXYgY2xhc3M9Inpvb20iPjxidXR0b24gZGF0YS16PSJmaXQiIGNsYXNzPSJzZWwiPkZpdDwvYnV0dG9uPjxidXR0b24gZGF0YS16PSIxMDAiPjEwMCU8L2J1dHRvbj48YnV0dG9uIGRhdGEtej0iMjAwIj4yMDAlPC9idXR0b24+PC9kaXY+CiAgICAgICAgPHNwYW4gY2xhc3M9InNwYWNlciI+PC9zcGFuPgogICAgICAgIDxidXR0b24gY2xhc3M9ImJ0biIgaWQ9ImJfZGwiPuKGkyBQTkc8L2J1dHRvbj4KICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICA8L2Rpdj4KCiAgPGZvb3Rlcj4KICAgIDxiPk1ldGhvZHMuPC9iPiBEZWJsdXIgPSBSaWNoYXJkc29u4oCTTHVjeSBkZWNvbnZvbHV0aW9uIMK3IENyaXNwID0gbGluZS1tYXNrICsgZWRnZS1saW1pdGVkIHVuc2hhcnAgwrcgQ2xlYW4gPSBZQ2JDciBjaHJvbWEgZGVub2lzZSDCtyBVcHNjYWxlID0gc2VwYXJhYmxlIExhbmN6b3MtMyArIHNoYXJwZW4gwrcgRGV0YWlsIHJlY292ZXJ5ID0gbG9jYWwtc2hhcnBuZXNzICsgc2tpbi10b25lIGhldXJpc3RpYyBtYXNrLiBBbGwgbG9jYWwsIGRldGVybWluaXN0aWMgaW1hZ2UgcHJvY2Vzc2luZyDigJQgbm8gbW9kZWwsIG5vIHVwbG9hZC4gU3RydWN0dXJhbCBhbmF0b215IGNvcnJlY3Rpb24gaXMgb3V0IG9mIHNjb3BlIGJ5IGRlc2lnbi4KICA8L2Zvb3Rlcj4KPC9kaXY+Cgo8c2NyaXB0PgoidXNlIHN0cmljdCI7CihmdW5jdGlvbigpewogIGNvbnN0ICQ9cz0+ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihzKTsKICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsKCk9Pntjb25zdCBiPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdib290Jyk7aWYoIWIpcmV0dXJuO3NldFRpbWVvdXQoKCk9PntiLmNsYXNzTGlzdC5hZGQoJ2dvbmUnKTtzZXRUaW1lb3V0KCgpPT5iLnJlbW92ZSgpLDY1MCk7fSw0MjApO30pOwogIGNvbnN0IGN2PSQoJyNjdicpLGN0eD1jdi5nZXRDb250ZXh0KCcyZCcse3dpbGxSZWFkRnJlcXVlbnRseTp0cnVlfSk7CiAgY29uc3QgbWFzaz0kKCcjbWFzaycpLG1jdHg9bWFzay5nZXRDb250ZXh0KCcyZCcse3dpbGxSZWFkRnJlcXVlbnRseTp0cnVlfSk7CiAgY29uc3QgY3Z3cmFwPSQoJyNjdndyYXAnKTsKICBsZXQgb3JpZ2luYWw9bnVsbCxiYXNlPW51bGwsbGFzdFJlc3VsdD1udWxsLGNvbXBhcmluZz1mYWxzZSx6b29tPSdmaXQnOwogIGNvbnN0IHN0YXRlPXtzX2F1dG86J3N0YW5kYXJkJyxzX2RldGFpbDonc3Ryb25nJyxzX2RlYmx1cjonc3RhbmRhcmQnLHNfY3Jpc3A6J3N0YW5kYXJkJyxzX2NsZWFuOidzdGFuZGFyZCcsdXBfZmFjdG9yOicyJyxkdF9tb2RlOidhdXRvJyxkdF9icnVzaG1vZGU6J3BhaW50JyxwYWludGluZzpmYWxzZX07CiAgY29uc3QgTVVMVD17bGlnaHQ6MC42LHN0YW5kYXJkOjEsc3Ryb25nOjEuNn07CgogIC8qIC0tLS0gbG9hZCAtLS0tICovCiAgY29uc3QgZHJvcD0kKCcjZHJvcCcpLGZpbGVJbnB1dD0kKCcjZmlsZScpLHN0YWdlPSQoJyNzdGFnZScpOwogIGRyb3AuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT5maWxlSW5wdXQuY2xpY2soKSk7CiAgZmlsZUlucHV0LmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsZT0+e2lmKGUudGFyZ2V0LmZpbGVzWzBdKWxvYWRGaWxlKGUudGFyZ2V0LmZpbGVzWzBdKTt9KTsKICBbJ2RyYWdlbnRlcicsJ2RyYWdvdmVyJ10uZm9yRWFjaChldj0+ZHJvcC5hZGRFdmVudExpc3RlbmVyKGV2LGU9PntlLnByZXZlbnREZWZhdWx0KCk7ZHJvcC5jbGFzc0xpc3QuYWRkKCdob3QnKTt9KSk7CiAgWydkcmFnbGVhdmUnLCdkcm9wJ10uZm9yRWFjaChldj0+ZHJvcC5hZGRFdmVudExpc3RlbmVyKGV2LGU9PntlLnByZXZlbnREZWZhdWx0KCk7ZHJvcC5jbGFzc0xpc3QucmVtb3ZlKCdob3QnKTt9KSk7CiAgZHJvcC5hZGRFdmVudExpc3RlbmVyKCdkcm9wJyxlPT57Y29uc3QgZj1lLmRhdGFUcmFuc2Zlci5maWxlc1swXTtpZihmKWxvYWRGaWxlKGYpO30pOwogIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdwYXN0ZScsZT0+e2Zvcihjb25zdCBpdCBvZihlLmNsaXBib2FyZERhdGE/Lml0ZW1zfHxbXSkpe2lmKGl0LnR5cGUuc3RhcnRzV2l0aCgnaW1hZ2UvJykpe2xvYWRGaWxlKGl0LmdldEFzRmlsZSgpKTticmVhazt9fX0pOwogIGZ1bmN0aW9uIGxvYWRGaWxlKGZpbGUpe2NvbnN0IGltZz1uZXcgSW1hZ2UoKTtpbWcub25sb2FkPSgpPT57Y29uc3QgbWF4PTIwNDg7bGV0IHc9aW1nLm5hdHVyYWxXaWR0aCxoPWltZy5uYXR1cmFsSGVpZ2h0O2lmKE1hdGgubWF4KHcsaCk+bWF4KXtjb25zdCBzPW1heC9NYXRoLm1heCh3LGgpO3c9TWF0aC5yb3VuZCh3KnMpO2g9TWF0aC5yb3VuZChoKnMpO31jdi53aWR0aD13O2N2LmhlaWdodD1oO2N0eC5kcmF3SW1hZ2UoaW1nLDAsMCx3LGgpO29yaWdpbmFsPWNsb25lKGN0eC5nZXRJbWFnZURhdGEoMCwwLHcsaCkpO2Jhc2U9Y2xvbmUob3JpZ2luYWwpO2xhc3RSZXN1bHQ9bnVsbDtzeW5jTWFza0RpbXMoKTtzdGFnZS5jbGFzc0xpc3QuYWRkKCdvbicpO2Ryb3Auc3R5bGUuZGlzcGxheT0nbm9uZSc7c2V0VGl0bGUoJ09yaWdpbmFsJyx3KyfDlycraCsncHgnKTtlbmRDb21wYXJlKCk7ZXhpdFBhaW50KCk7YXBwbHlab29tKCdmaXQnKTt1cGRhdGVVcFRhcmdldCgpO307aW1nLnNyYz1VUkwuY3JlYXRlT2JqZWN0VVJMKGZpbGUpO30KICBmdW5jdGlvbiBzZXRUaXRsZSh0LG0peyQoJyN2X3RpdGxlJykudGV4dENvbnRlbnQ9dDskKCcjdl9tZXRhJykudGV4dENvbnRlbnQ9bXx8Jyc7fQogIGZ1bmN0aW9uIGNsb25lKGQpe3JldHVybiBuZXcgSW1hZ2VEYXRhKG5ldyBVaW50OENsYW1wZWRBcnJheShkLmRhdGEpLGQud2lkdGgsZC5oZWlnaHQpO30KICBmdW5jdGlvbiBzeW5jTWFza0RpbXMoKXttYXNrLndpZHRoPWJhc2Uud2lkdGg7bWFzay5oZWlnaHQ9YmFzZS5oZWlnaHQ7bWN0eC5jbGVhclJlY3QoMCwwLG1hc2sud2lkdGgsbWFzay5oZWlnaHQpO30KICBmdW5jdGlvbiBwdXRSZXN1bHQoZCl7Y3Yud2lkdGg9ZC53aWR0aDtjdi5oZWlnaHQ9ZC5oZWlnaHQ7Y3R4LnB1dEltYWdlRGF0YShkLDAsMCk7YXBwbHlab29tKHpvb20pO30KICBmdW5jdGlvbiBvZmZzY3JlZW4oZCl7Y29uc3QgYz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtjLndpZHRoPWQud2lkdGg7Yy5oZWlnaHQ9ZC5oZWlnaHQ7Yy5nZXRDb250ZXh0KCcyZCcpLnB1dEltYWdlRGF0YShkLDAsMCk7cmV0dXJuIGM7fQoKICAvKiAtLS0tIHpvb20gLS0tLSAqLwogIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy56b29tIGJ1dHRvbicpLmZvckVhY2goYj0+Yi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9PmFwcGx5Wm9vbShiLmRhdGFzZXQueikpKTsKICBmdW5jdGlvbiBhcHBseVpvb20oeil7em9vbT16O2RvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy56b29tIGJ1dHRvbicpLmZvckVhY2goYj0+Yi5jbGFzc0xpc3QudG9nZ2xlKCdzZWwnLGIuZGF0YXNldC56PT09eikpOwogICAgaWYoej09PSdmaXQnKXtjdndyYXAuY2xhc3NMaXN0LmFkZCgnZml0Jyk7Y3Yuc3R5bGUud2lkdGg9Jyc7Y3Yuc3R5bGUuaGVpZ2h0PScnO2N2LnN0eWxlLm1heFdpZHRoPScnO2N2LnN0eWxlLm1heEhlaWdodD0nJzt9CiAgICBlbHNle2N2d3JhcC5jbGFzc0xpc3QucmVtb3ZlKCdmaXQnKTtjb25zdCBmPXo9PT0nMjAwJz8yOjE7Y3Yuc3R5bGUubWF4V2lkdGg9J25vbmUnO2N2LnN0eWxlLm1heEhlaWdodD0nbm9uZSc7Y3Yuc3R5bGUud2lkdGg9KGN2LndpZHRoKmYpKydweCc7Y3Yuc3R5bGUuaGVpZ2h0PSdhdXRvJzt9fQoKICAvKiAtLS0tIFVJIC0tLS0gKi8KICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcudG9vbCAuaGVhZCcpLmZvckVhY2goaD0+aC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9Pntjb25zdCB0PWgucGFyZW50RWxlbWVudDtjb25zdCB3YXM9dC5jbGFzc0xpc3QuY29udGFpbnMoJ29wZW4nKTtkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcudG9vbCcpLmZvckVhY2goeD0+eC5jbGFzc0xpc3QucmVtb3ZlKCdvcGVuJykpO2lmKCF3YXMpdC5jbGFzc0xpc3QuYWRkKCdvcGVuJyk7aWYodC5kYXRhc2V0LnRvb2whPT0nZGV0YWlsJyYmc3RhdGUucGFpbnRpbmcpZXhpdFBhaW50KCk7fSkpOwogIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5zZWdbZGF0YS1zZWddJykuZm9yRWFjaChzZWc9Pntjb25zdCBrZXk9c2VnLmRhdGFzZXQuc2VnO3NlZy5xdWVyeVNlbGVjdG9yQWxsKCdidXR0b24nKS5mb3JFYWNoKGI9PmIuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT57c2VnLnF1ZXJ5U2VsZWN0b3JBbGwoJ2J1dHRvbicpLmZvckVhY2goeD0+eC5jbGFzc0xpc3QucmVtb3ZlKCdzZWwnKSk7Yi5jbGFzc0xpc3QuYWRkKCdzZWwnKTtzdGF0ZVtrZXldPWIuZGF0YXNldC52O2lmKGtleT09PSd1cF9mYWN0b3InKXVwZGF0ZVVwVGFyZ2V0KCk7aWYoa2V5PT09J2R0X21vZGUnKXskKCcjZHRfbWFza2JveCcpLmNsYXNzTGlzdC50b2dnbGUoJ2hpZGUnLGIuZGF0YXNldC52IT09J21hc2snKTtpZihiLmRhdGFzZXQudiE9PSdtYXNrJylleGl0UGFpbnQoKTt9fSkpO30pOwogICQoJyNkdF9icnVzaCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywoKT0+JCgnI2R0X2JydXNoX3YnKS50ZXh0Q29udGVudD0kKCcjZHRfYnJ1c2gnKS52YWx1ZSk7CiAgZnVuY3Rpb24gdXBkYXRlVXBUYXJnZXQoKXtpZighYmFzZSlyZXR1cm47Y29uc3QgZj1wYXJzZUludChzdGF0ZS51cF9mYWN0b3IpOyQoJyN1cF90YXJnZXQnKS50ZXh0Q29udGVudD0n4oaSICcrKGJhc2Uud2lkdGgqZikrJ8OXJysoYmFzZS5oZWlnaHQqZikrJ3B4Jzt9CiAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnJ1bltkYXRhLXJ1bl0nKS5mb3JFYWNoKGI9PmIuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT5ydW5Ub29sKGIuZGF0YXNldC5ydW4pKSk7CiAgJCgnI2Jfb3JpZycpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+e2lmKCFvcmlnaW5hbClyZXR1cm47ZW5kQ29tcGFyZSgpO2Jhc2U9Y2xvbmUob3JpZ2luYWwpO2xhc3RSZXN1bHQ9bnVsbDtzeW5jTWFza0RpbXMoKTtwdXRSZXN1bHQoY2xvbmUob3JpZ2luYWwpKTtzZXRUaXRsZSgnT3JpZ2luYWwnLG9yaWdpbmFsLndpZHRoKyfDlycrb3JpZ2luYWwuaGVpZ2h0KydweCcpO3VwZGF0ZVVwVGFyZ2V0KCk7fSk7CiAgJCgnI2JfdXNlcmVzJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCgpPT57aWYoIWxhc3RSZXN1bHQpcmV0dXJuO2Jhc2U9Y2xvbmUobGFzdFJlc3VsdCk7c3luY01hc2tEaW1zKCk7ZW5kQ29tcGFyZSgpO3NldFRpdGxlKCdCYXNlIChzdGFja2VkKScsYmFzZS53aWR0aCsnw5cnK2Jhc2UuaGVpZ2h0KydweCcpO3VwZGF0ZVVwVGFyZ2V0KCk7fSk7CiAgJCgnI2JfZGwnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9Pntjb25zdCBhPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTthLmRvd25sb2FkPSdkYXJrcm9vbS1yZXN0b3JlZC5wbmcnO2EuaHJlZj1jdi50b0RhdGFVUkwoJ2ltYWdlL3BuZycpO2EuY2xpY2soKTt9KTsKICAkKCcjYl9jbXAnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9Pntjb21wYXJpbmc/ZW5kQ29tcGFyZSgpOnN0YXJ0Q29tcGFyZSgpO30pOwoKICBmdW5jdGlvbiBydW5Ub29sKG5hbWUpewogICAgaWYoY29tcGFyaW5nKWVuZENvbXBhcmUoKTsKICAgIGNvbnN0IHByb2M9JCgnI3Byb2MnKTtwcm9jLmNsYXNzTGlzdC5hZGQoJ29uJyk7CiAgICAkKCcjcHJvY190JykudGV4dENvbnRlbnQ9KHthdXRvOidBTkFMWVpJTkcgKyBSRVNUT1JJTkcnLGRlYmx1cjonREVDT05WT0xWSU5HJyxjcmlzcDonQ1JJU1BJTkcgTElORVMnLGNsZWFuOidDTEVBTklORycsdXBzY2FsZTonVVBTQ0FMSU5HIChMYW5jem9zKScsZGV0YWlsOnN0YXRlLmR0X21vZGU9PT0nYXV0byc/J0RFVEVDVElORyArIFJFQ09WRVJJTkcnOidSRUNPVkVSSU5HIERFVEFJTCd9KVtuYW1lXXx8J1BST0NFU1NJTkcnOwogICAgc2V0VGltZW91dCgoKT0+e3RyeXsKICAgICAgbGV0IG91dDtjb25zdCBzcmM9Y2xvbmUoYmFzZSk7CiAgICAgIGlmKG5hbWU9PT0nYXV0bycpb3V0PWRvQXV0byhzcmMsTVVMVFtzdGF0ZS5zX2F1dG9dKTsKICAgICAgZWxzZSBpZihuYW1lPT09J2RlYmx1cicpb3V0PXJsRGVjb252KHNyYywxLjE1LE1hdGgucm91bmQoNypNVUxUW3N0YXRlLnNfZGVibHVyXSkpOwogICAgICBlbHNlIGlmKG5hbWU9PT0nY3Jpc3AnKW91dD1jcmlzcExpbmVzKHNyYywxLjEqTVVMVFtzdGF0ZS5zX2NyaXNwXSk7CiAgICAgIGVsc2UgaWYobmFtZT09PSdjbGVhbicpb3V0PWNsZWFuUGFnZShzcmMsTVVMVFtzdGF0ZS5zX2NsZWFuXSk7CiAgICAgIGVsc2UgaWYobmFtZT09PSd1cHNjYWxlJylvdXQ9ZG9VcHNjYWxlKHNyYyxwYXJzZUludChzdGF0ZS51cF9mYWN0b3IpKTsKICAgICAgZWxzZSBpZihuYW1lPT09J2RldGFpbCcpb3V0PWRldGFpbFJlY292ZXJ5KHNyYyxNVUxUW3N0YXRlLnNfZGV0YWlsXSk7CiAgICAgIGxhc3RSZXN1bHQ9Y2xvbmUob3V0KTtwdXRSZXN1bHQob3V0KTsKICAgICAgY29uc3QgZGltPW91dC53aWR0aCsnw5cnK291dC5oZWlnaHQrJ3B4JzsKICAgICAgc2V0VGl0bGUoKHthdXRvOidBdXRvLXJlc3RvcmVkJyxkZWJsdXI6J0RlYmx1cnJlZCcsY3Jpc3A6J0xpbmVzIGNyaXNwZWQnLGNsZWFuOidDbGVhbmVkJyx1cHNjYWxlOidVcHNjYWxlZCcsZGV0YWlsOidEZXRhaWwgcmVjb3ZlcmVkJ30pW25hbWVdLGRpbSsnIMK3IHpvb20gMTAwJSAvIENvbXBhcmUgdG8gaW5zcGVjdCcpOwogICAgfWNhdGNoKGVycil7Y29uc29sZS5lcnJvcihlcnIpO2FsZXJ0KGVyci5tZXNzYWdlKTt9cHJvYy5jbGFzc0xpc3QucmVtb3ZlKCdvbicpO30sMzApOwogIH0KCiAgLyogLS0tLSBtYXNrIChtYW51YWwgZmFsbGJhY2spIC0tLS0gKi8KICAkKCcjZHRfcGFpbnQnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsKCk9PntzdGF0ZS5wYWludGluZz9leGl0UGFpbnQoKTplbnRlclBhaW50KCk7fSk7CiAgZnVuY3Rpb24gZW50ZXJQYWludCgpe2lmKCFvcmlnaW5hbClyZXR1cm47aWYoY29tcGFyaW5nKWVuZENvbXBhcmUoKTtzdGF0ZS5wYWludGluZz10cnVlO2N2d3JhcC5jbGFzc0xpc3QuYWRkKCdwYWludGluZycpOyQoJyNkdF9wYWludCcpLnRleHRDb250ZW50PSfinJMgRXhpdCBtYXNrIG1vZGUnO3NldFRpdGxlKCdNYXNrIG1vZGUg4oCUIHBhaW50IHRoZSBhcmVhIHRvIHJlcGFpcicpO30KICBmdW5jdGlvbiBleGl0UGFpbnQoKXtzdGF0ZS5wYWludGluZz1mYWxzZTtjdndyYXAuY2xhc3NMaXN0LnJlbW92ZSgncGFpbnRpbmcnKTskKCcjZHRfcGFpbnQnKS50ZXh0Q29udGVudD0n4pyOIEVudGVyIG1hc2sgbW9kZSc7fQogICQoJyNkdF9jbGVhcicpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywoKT0+bWN0eC5jbGVhclJlY3QoMCwwLG1hc2sud2lkdGgsbWFzay5oZWlnaHQpKTsKICBsZXQgZHJhd2luZz1mYWxzZTsKICBmdW5jdGlvbiBtcG9zKGUpe2NvbnN0IHI9bWFzay5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtjb25zdCBwPWUudG91Y2hlcz9lLnRvdWNoZXNbMF06ZTtyZXR1cm57eDoocC5jbGllbnRYLXIubGVmdCkqKG1hc2sud2lkdGgvci53aWR0aCkseToocC5jbGllbnRZLXIudG9wKSoobWFzay5oZWlnaHQvci5oZWlnaHQpLHNjOm1hc2sud2lkdGgvci53aWR0aH07fQogIGZ1bmN0aW9uIHN0cm9rZShlKXtjb25zdCBtPW1wb3MoZSk7Y29uc3Qgc3o9cGFyc2VJbnQoJCgnI2R0X2JydXNoJykudmFsdWUpKm0uc2M7bWN0eC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249c3RhdGUuZHRfYnJ1c2htb2RlPT09J2VyYXNlJz8nZGVzdGluYXRpb24tb3V0Jzonc291cmNlLW92ZXInO21jdHguZmlsbFN0eWxlPSdyZ2JhKDk1LDIwOCwxOTcsMC41KSc7bWN0eC5iZWdpblBhdGgoKTttY3R4LmFyYyhtLngsbS55LHN6LzIsMCw3KTttY3R4LmZpbGwoKTt9CiAgbWFzay5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsZT0+e2RyYXdpbmc9dHJ1ZTttYXNrLnNldFBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtzdHJva2UoZSk7fSk7CiAgbWFzay5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsZT0+e2lmKGRyYXdpbmcpc3Ryb2tlKGUpO30pOwogIG1hc2suYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywoKT0+ZHJhd2luZz1mYWxzZSk7bWFzay5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyY2FuY2VsJywoKT0+ZHJhd2luZz1mYWxzZSk7CiAgZnVuY3Rpb24gbWFza0FscGhhKCl7Y29uc3Qgbj1tYXNrLndpZHRoKm1hc2suaGVpZ2h0LGE9bmV3IEZsb2F0MzJBcnJheShuKSxkPW1jdHguZ2V0SW1hZ2VEYXRhKDAsMCxtYXNrLndpZHRoLG1hc2suaGVpZ2h0KS5kYXRhO2xldCBhbnk9ZmFsc2U7Zm9yKGxldCBpPTA7aTxuO2krKyl7YVtpXT1kW2kqNCszXT4xMD8xOjA7aWYoYVtpXSlhbnk9dHJ1ZTt9cmV0dXJuIGFueT9hOm51bGw7fQoKICAvKiAtLS0tIGNvbXBhcmUgLS0tLSAqLwogIGxldCBzcmNPZmY9bnVsbCxyZXNPZmY9bnVsbDsKICBmdW5jdGlvbiBzdGFydENvbXBhcmUoKXtpZighbGFzdFJlc3VsdCl7YWxlcnQoJ1J1biBhIHBhc3MgZmlyc3QuJyk7cmV0dXJuO31pZihzdGF0ZS5wYWludGluZylleGl0UGFpbnQoKTtjb21wYXJpbmc9dHJ1ZTskKCcjYl9jbXAnKS5jbGFzc0xpc3QuYWRkKCdvbicpO3NyY09mZj1vZmZzY3JlZW4oYmFzZS53aWR0aD09PWxhc3RSZXN1bHQud2lkdGg/YmFzZTpyZXNpemVUbyhiYXNlLGxhc3RSZXN1bHQud2lkdGgsbGFzdFJlc3VsdC5oZWlnaHQpKTtyZXNPZmY9b2Zmc2NyZWVuKGxhc3RSZXN1bHQpO2N2LndpZHRoPWxhc3RSZXN1bHQud2lkdGg7Y3YuaGVpZ2h0PWxhc3RSZXN1bHQuaGVpZ2h0O2FwcGx5Wm9vbSh6b29tKTskKCcjY21wYmFyJykuY2xhc3NMaXN0LmFkZCgnb24nKTskKCcjY21wX3NsaWRlcicpLnZhbHVlPTUwO3JlbmRlckNvbXBhcmUoNTApO30KICBmdW5jdGlvbiByZW5kZXJDb21wYXJlKHBjdCl7aWYoIWNvbXBhcmluZylyZXR1cm47Y29uc3Qgdz1jdi53aWR0aCxoPWN2LmhlaWdodCxzcGxpdD13KnBjdC8xMDA7Y3R4LmNsZWFyUmVjdCgwLDAsdyxoKTtjdHguZHJhd0ltYWdlKHJlc09mZiwwLDApO2N0eC5zYXZlKCk7Y3R4LmJlZ2luUGF0aCgpO2N0eC5yZWN0KDAsMCxzcGxpdCxoKTtjdHguY2xpcCgpO2N0eC5kcmF3SW1hZ2Uoc3JjT2ZmLDAsMCk7Y3R4LnJlc3RvcmUoKTtjdHguZmlsbFN0eWxlPScjZmZiNDU0JztjdHguZmlsbFJlY3Qoc3BsaXQtMSwwLDIsaCk7Y3R4LmJlZ2luUGF0aCgpO2N0eC5hcmMoc3BsaXQsaC8yLDEwLDAsNyk7Y3R4LmZpbGxTdHlsZT0nIzFhMTQwNyc7Y3R4LmZpbGwoKTtjdHguYmVnaW5QYXRoKCk7Y3R4LmFyYyhzcGxpdCxoLzIsOCwwLDcpO2N0eC5maWxsU3R5bGU9JyNmZmI0NTQnO2N0eC5maWxsKCk7fQogICQoJyNjbXBfc2xpZGVyJykuYWRkRXZlbnRMaXN0ZW5lcignaW5wdXQnLGU9PnJlbmRlckNvbXBhcmUocGFyc2VJbnQoZS50YXJnZXQudmFsdWUpKSk7CiAgY3YuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcmRvd24nLGU9PntpZighY29tcGFyaW5nKXJldHVybjtjb25zdCByPWN2LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO2NvbnN0IHBjdD1NYXRoLm1heCgwLE1hdGgubWluKDEwMCwoZS5jbGllbnRYLXIubGVmdCkvci53aWR0aCoxMDApKTskKCcjY21wX3NsaWRlcicpLnZhbHVlPXBjdDtyZW5kZXJDb21wYXJlKHBjdCk7fSk7CiAgZnVuY3Rpb24gZW5kQ29tcGFyZSgpe2lmKCFjb21wYXJpbmcpcmV0dXJuO2NvbXBhcmluZz1mYWxzZTskKCcjYl9jbXAnKS5jbGFzc0xpc3QucmVtb3ZlKCdvbicpOyQoJyNjbXBiYXInKS5jbGFzc0xpc3QucmVtb3ZlKCdvbicpO2lmKGxhc3RSZXN1bHQpcHV0UmVzdWx0KGNsb25lKGxhc3RSZXN1bHQpKTt9CiAgJCgnI2NtcF9kb25lJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLGVuZENvbXBhcmUpOwoKICAvKiA9PT09PT09PT09PT09PT09PSBDT1JFID09PT09PT09PT09PT09PT09ICovCiAgZnVuY3Rpb24gZ2F1c3NpYW4ocGxhbmUsdyxoLHNpZ21hKXtpZihzaWdtYTw9MC4wMSlyZXR1cm4gcGxhbmUuc2xpY2UoKTtjb25zdCByPU1hdGgubWF4KDEsTWF0aC5jZWlsKHNpZ21hKjMpKSxrPW5ldyBGbG9hdDMyQXJyYXkoMipyKzEpO2xldCBzdW09MDtmb3IobGV0IGk9LXI7aTw9cjtpKyspe2NvbnN0IHY9TWF0aC5leHAoLShpKmkpLygyKnNpZ21hKnNpZ21hKSk7a1tpK3JdPXY7c3VtKz12O31mb3IobGV0IGk9MDtpPGsubGVuZ3RoO2krKylrW2ldLz1zdW07Y29uc3QgdG1wPW5ldyBGbG9hdDMyQXJyYXkodypoKSxvdXQ9bmV3IEZsb2F0MzJBcnJheSh3KmgpO2ZvcihsZXQgeT0wO3k8aDt5Kyspe2NvbnN0IHJvdz15Knc7Zm9yKGxldCB4PTA7eDx3O3grKyl7bGV0IGE9MDtmb3IobGV0IGk9LXI7aTw9cjtpKyspe2xldCB4eD14K2k7aWYoeHg8MCl4eD0wO2Vsc2UgaWYoeHg+PXcpeHg9dy0xO2ErPXBsYW5lW3Jvdyt4eF0qa1tpK3JdO310bXBbcm93K3hdPWE7fX1mb3IobGV0IHg9MDt4PHc7eCsrKXtmb3IobGV0IHk9MDt5PGg7eSsrKXtsZXQgYT0wO2ZvcihsZXQgaT0tcjtpPD1yO2krKyl7bGV0IHl5PXkraTtpZih5eTwwKXl5PTA7ZWxzZSBpZih5eT49aCl5eT1oLTE7YSs9dG1wW3l5KncreF0qa1tpK3JdO31vdXRbeSp3K3hdPWE7fX1yZXR1cm4gb3V0O30KICBjb25zdCBMVU1BPShyLGcsYik9PjAuMjEyNipyKzAuNzE1MipnKzAuMDcyMipiOwogIGNvbnN0IGNsYW1wMjU1PXY9PnY8MD8wOnY+MjU1PzI1NTp2OwogIGZ1bmN0aW9uIGNoYW5uZWxzKGQpe2NvbnN0IG49ZC53aWR0aCpkLmhlaWdodCxSPW5ldyBGbG9hdDMyQXJyYXkobiksRz1uZXcgRmxvYXQzMkFycmF5KG4pLEI9bmV3IEZsb2F0MzJBcnJheShuKSxweD1kLmRhdGE7Zm9yKGxldCBpPTAsaj0wO2k8bjtpKyssais9NCl7UltpXT1weFtqXS8yNTU7R1tpXT1weFtqKzFdLzI1NTtCW2ldPXB4W2orMl0vMjU1O31yZXR1cm57UixHLEIsbn07fQogIGZ1bmN0aW9uIHBhY2soUixHLEIsdyxoLGEpe2NvbnN0IG91dD1uZXcgSW1hZ2VEYXRhKHcsaCksbz1vdXQuZGF0YTtmb3IobGV0IGk9MCxqPTA7aTx3Kmg7aSsrLGorPTQpe29bal09Y2xhbXAyNTUoUltpXSoyNTUpO29baisxXT1jbGFtcDI1NShHW2ldKjI1NSk7b1tqKzJdPWNsYW1wMjU1KEJbaV0qMjU1KTtvW2orM109YT9hW2ldOjI1NTt9cmV0dXJuIG91dDt9CiAgZnVuY3Rpb24gYWxwaGFPZihkKXtjb25zdCBuPWQud2lkdGgqZC5oZWlnaHQsYT1uZXcgVWludDhDbGFtcGVkQXJyYXkobik7Zm9yKGxldCBpPTA7aTxuO2krKylhW2ldPWQuZGF0YVtpKjQrM107cmV0dXJuIGE7fQoKICBmdW5jdGlvbiBybERlY29udihkLHNpZ21hLGl0ZXJzKXtpdGVycz1NYXRoLm1heCgxLE1hdGgubWluKDE2LGl0ZXJzKSk7Y29uc3Qgdz1kLndpZHRoLGg9ZC5oZWlnaHQse1IsRyxCLG59PWNoYW5uZWxzKGQpLGE9YWxwaGFPZihkKTtbUixHLEJdLmZvckVhY2gob2JzPT57Y29uc3QgZXN0PW9icy5zbGljZSgpO2ZvcihsZXQgaXQ9MDtpdDxpdGVycztpdCsrKXtjb25zdCBjMT1nYXVzc2lhbihlc3QsdyxoLHNpZ21hKTtjb25zdCByYXRpbz1uZXcgRmxvYXQzMkFycmF5KG4pO2ZvcihsZXQgaT0wO2k8bjtpKyspcmF0aW9baV09b2JzW2ldLyhjMVtpXSsxZS00KTtjb25zdCBjMj1nYXVzc2lhbihyYXRpbyx3LGgsc2lnbWEpO2ZvcihsZXQgaT0wO2k8bjtpKyspe2xldCB2PWVzdFtpXSpjMltpXTtlc3RbaV09djwwPzA6dj4xLjI/MS4yOnY7fX1mb3IobGV0IGk9MDtpPG47aSsrKW9ic1tpXT1lc3RbaV07fSk7cmV0dXJuIHBhY2soUixHLEIsdyxoLGEpO30KICBmdW5jdGlvbiB1bnNoYXJwKGQscmFkaXVzLGFtb3VudCl7Y29uc3Qgdz1kLndpZHRoLGg9ZC5oZWlnaHQse1IsRyxCLG59PWNoYW5uZWxzKGQpLGE9YWxwaGFPZihkKTtbUixHLEJdLmZvckVhY2goY2g9Pntjb25zdCBibD1nYXVzc2lhbihjaCx3LGgscmFkaXVzKTtmb3IobGV0IGk9MDtpPG47aSsrKXtsZXQgdj1jaFtpXSthbW91bnQqKGNoW2ldLWJsW2ldKTtjaFtpXT12PDA/MDp2PjE/MTp2O319KTtyZXR1cm4gcGFjayhSLEcsQix3LGgsYSk7fQogIGZ1bmN0aW9uIGNyaXNwTGluZXMoZCxzdHJlbmd0aCl7Y29uc3Qgdz1kLndpZHRoLGg9ZC5oZWlnaHQsbj13KmgsYT1hbHBoYU9mKGQpO2NvbnN0IHNoYXJwPXVuc2hhcnAoZCwxLjEsMC44KnN0cmVuZ3RoKSxzcD1zaGFycC5kYXRhLG9wPWQuZGF0YTtjb25zdCBncmF5PW5ldyBGbG9hdDMyQXJyYXkobik7Zm9yKGxldCBpPTAsaj0wO2k8bjtpKyssais9NClncmF5W2ldPUxVTUEob3Bbal0sb3BbaisxXSxvcFtqKzJdKS8yNTU7Y29uc3QgbG9jYWw9Z2F1c3NpYW4oZ3JheSx3LGgsMy4wKTtjb25zdCBvdXQ9bmV3IEltYWdlRGF0YSh3LGgpLG89b3V0LmRhdGE7Zm9yKGxldCBpPTAsaj0wO2k8bjtpKyssais9NCl7bGV0IG09KGxvY2FsW2ldLWdyYXlbaV0pKjMuNDttPW08MD8wOm0+MT8xOm07Y29uc3QgZGFyaz0xLWdyYXlbaV07Y29uc3QgbWM9TWF0aC5taW4oMSxtKjEuMTUpO2NvbnN0IGZhYz0xLTAuNipzdHJlbmd0aCptKmRhcms7Zm9yKGxldCBjPTA7YzwzO2MrKylvW2orY109Y2xhbXAyNTUoKG9wW2orY10qKDEtbWMpK3NwW2orY10qbWMpKmZhYyk7b1tqKzNdPWFbaV07fXJldHVybiBvdXQ7fQogIGZ1bmN0aW9uIGNsZWFuUGFnZShkLHN0cmVuZ3RoKXtjb25zdCB3PWQud2lkdGgsaD1kLmhlaWdodCxuPXcqaCxweD1kLmRhdGEsYT1hbHBoYU9mKGQpO2NvbnN0IFk9bmV3IEZsb2F0MzJBcnJheShuKSxDYj1uZXcgRmxvYXQzMkFycmF5KG4pLENyPW5ldyBGbG9hdDMyQXJyYXkobik7Zm9yKGxldCBpPTAsaj0wO2k8bjtpKyssais9NCl7Y29uc3Qgcj1weFtqXSxnPXB4W2orMV0sYj1weFtqKzJdO1lbaV09MC4yOTkqciswLjU4NypnKzAuMTE0KmI7Q2JbaV09MTI4LTAuMTY4NzM2KnItMC4zMzEyNjQqZyswLjUqYjtDcltpXT0xMjgrMC41KnItMC40MTg2ODgqZy0wLjA4MTMxMipiO31jb25zdCBjYlM9Z2F1c3NpYW4oQ2IsdyxoLDEuNipzdHJlbmd0aCswLjYpLGNyUz1nYXVzc2lhbihDcix3LGgsMS42KnN0cmVuZ3RoKzAuNik7bGV0IFlvPVk7aWYoc3RyZW5ndGg+MS4xKVlvPW1lZGlhblBsYW5lKFksdyxoLDEpO2NvbnN0IG91dD1uZXcgSW1hZ2VEYXRhKHcsaCksbz1vdXQuZGF0YTtmb3IobGV0IGk9MCxqPTA7aTxuO2krKyxqKz00KXtjb25zdCB5PVlvW2ldLGNiPWNiU1tpXS0xMjgsY3I9Y3JTW2ldLTEyODtvW2pdPWNsYW1wMjU1KHkrMS40MDIqY3IpO29baisxXT1jbGFtcDI1NSh5LTAuMzQ0MTM2KmNiLTAuNzE0MTM2KmNyKTtvW2orMl09Y2xhbXAyNTUoeSsxLjc3MipjYik7b1tqKzNdPWFbaV07fXJldHVybiBvdXQ7fQogIGZ1bmN0aW9uIG1lZGlhblBsYW5lKHAsdyxoLHJhZCl7Y29uc3Qgb3V0PW5ldyBGbG9hdDMyQXJyYXkodypoKSx3aW49W107Zm9yKGxldCB5PTA7eTxoO3krKylmb3IobGV0IHg9MDt4PHc7eCsrKXt3aW4ubGVuZ3RoPTA7Zm9yKGxldCBkeT0tcmFkO2R5PD1yYWQ7ZHkrKylmb3IobGV0IGR4PS1yYWQ7ZHg8PXJhZDtkeCsrKXtsZXQgeHg9eCtkeCx5eT15K2R5O2lmKHh4PDApeHg9MDtlbHNlIGlmKHh4Pj13KXh4PXctMTtpZih5eTwwKXl5PTA7ZWxzZSBpZih5eT49aCl5eT1oLTE7d2luLnB1c2gocFt5eSp3K3h4XSk7fXdpbi5zb3J0KChhLGIpPT5hLWIpO291dFt5KncreF09d2luW3dpbi5sZW5ndGg+PjFdO31yZXR1cm4gb3V0O30KICBmdW5jdGlvbiBhbmFseXplKGQpe2NvbnN0IHc9ZC53aWR0aCxoPWQuaGVpZ2h0LHB4PWQuZGF0YTtsZXQgZ3JhZD0wLGNudD0wO2NvbnN0IHN0ZXA9TWF0aC5tYXgoMSxNYXRoLmZsb29yKE1hdGguc3FydCh3KmgvNDAwMDApKSk7Zm9yKGxldCB5PTE7eTxoLTE7eSs9c3RlcClmb3IobGV0IHg9MTt4PHctMTt4Kz1zdGVwKXtjb25zdCBpPSh5KncreCkqNCxneD1MVU1BKHB4W2krNF0scHhbaSs1XSxweFtpKzZdKS1MVU1BKHB4W2ktNF0scHhbaS0zXSxweFtpLTJdKTtncmFkKz1NYXRoLmFicyhneCk7Y250Kys7fWNvbnN0IGc9Z3JhZC8oY250fHwxKTtyZXR1cm57c29mdDpNYXRoLm1heCgwLE1hdGgubWluKDEsKDE0LWcpLzE0KSl9O30KICBmdW5jdGlvbiBkb0F1dG8oZCxtdWx0KXtjb25zdCB7c29mdH09YW5hbHl6ZShkKTtsZXQgcj1jbGVhblBhZ2UoZCwwLjgqbXVsdCk7Y29uc3QgaXRlcnM9TWF0aC5yb3VuZCgoNCtzb2Z0KjgpKm11bHQpO3I9cmxEZWNvbnYociwxLjErc29mdCowLjQsTWF0aC5tYXgoMyxNYXRoLm1pbigxNCxpdGVycykpKTtyPWNyaXNwTGluZXMociwoMC44K3NvZnQqMC41KSptdWx0KTtyPXVuc2hhcnAociwxLjAsMC4zNSptdWx0KTtyZXR1cm4gcjt9CgogIC8qIC0tLS0gTGFuY3pvcyB1cHNjYWxlIC0tLS0gKi8KICBmdW5jdGlvbiBsYW5jem9zMyh4KXtpZih4PT09MClyZXR1cm4gMTtpZih4PD0tM3x8eD49MylyZXR1cm4gMDtjb25zdCBweD1NYXRoLlBJKng7cmV0dXJuIDMqTWF0aC5zaW4ocHgpKk1hdGguc2luKHB4LzMpLyhweCpweCk7fQogIGZ1bmN0aW9uIHJlc2l6ZVRvKGQsVzIsSDIpe2NvbnN0IHc9ZC53aWR0aCxoPWQuaGVpZ2h0LHNyYz1kLmRhdGE7Y29uc3QgdG1wPW5ldyBGbG9hdDMyQXJyYXkoVzIqaCo0KSxzeD13L1cyO2ZvcihsZXQgb3g9MDtveDxXMjtveCsrKXtjb25zdCBjZW50ZXI9KG94KzAuNSkqc3gtMC41LGxlZnQ9TWF0aC5mbG9vcihjZW50ZXItMykscmlnaHQ9TWF0aC5jZWlsKGNlbnRlciszKSxpZHg9W10sd3Q9W107bGV0IHdzPTA7Zm9yKGxldCBpeD1sZWZ0O2l4PD1yaWdodDtpeCsrKXtsZXQgY3g9aXg7aWYoY3g8MCljeD0wO2Vsc2UgaWYoY3g+PXcpY3g9dy0xO2NvbnN0IHd2PWxhbmN6b3MzKGNlbnRlci1peCk7aWR4LnB1c2goY3gpO3d0LnB1c2god3YpO3dzKz13djt9Zm9yKGxldCB5PTA7eTxoO3krKyl7bGV0IHI9MCxnPTAsYj0wLGFsPTA7Zm9yKGxldCBrPTA7azxpZHgubGVuZ3RoO2srKyl7Y29uc3Qgaj0oeSp3K2lkeFtrXSkqNCx3dj13dFtrXTtyKz1zcmNbal0qd3Y7Zys9c3JjW2orMV0qd3Y7Yis9c3JjW2orMl0qd3Y7YWwrPXNyY1tqKzNdKnd2O31jb25zdCBvPSh5KlcyK294KSo0O3RtcFtvXT1yL3dzO3RtcFtvKzFdPWcvd3M7dG1wW28rMl09Yi93czt0bXBbbyszXT1hbC93czt9fWNvbnN0IG91dD1uZXcgSW1hZ2VEYXRhKFcyLEgyKSxvcD1vdXQuZGF0YSxzeT1oL0gyO2ZvcihsZXQgb3k9MDtveTxIMjtveSsrKXtjb25zdCBjZW50ZXI9KG95KzAuNSkqc3ktMC41LHRvcD1NYXRoLmZsb29yKGNlbnRlci0zKSxib3Q9TWF0aC5jZWlsKGNlbnRlciszKSxpZHg9W10sd3Q9W107bGV0IHdzPTA7Zm9yKGxldCBpeT10b3A7aXk8PWJvdDtpeSsrKXtsZXQgY3k9aXk7aWYoY3k8MCljeT0wO2Vsc2UgaWYoY3k+PWgpY3k9aC0xO2NvbnN0IHd2PWxhbmN6b3MzKGNlbnRlci1peSk7aWR4LnB1c2goY3kpO3d0LnB1c2god3YpO3dzKz13djt9Zm9yKGxldCB4PTA7eDxXMjt4Kyspe2xldCByPTAsZz0wLGI9MCxhbD0wO2ZvcihsZXQgaz0wO2s8aWR4Lmxlbmd0aDtrKyspe2NvbnN0IGo9KGlkeFtrXSpXMit4KSo0LHd2PXd0W2tdO3IrPXRtcFtqXSp3djtnKz10bXBbaisxXSp3djtiKz10bXBbaisyXSp3djthbCs9dG1wW2orM10qd3Y7fWNvbnN0IG89KG95KlcyK3gpKjQ7b3Bbb109Y2xhbXAyNTUoci93cyk7b3BbbysxXT1jbGFtcDI1NShnL3dzKTtvcFtvKzJdPWNsYW1wMjU1KGIvd3MpO29wW28rM109Y2xhbXAyNTUoYWwvd3MpO319cmV0dXJuIG91dDt9CiAgZnVuY3Rpb24gZG9VcHNjYWxlKGQsZmFjdG9yKXtsZXQgVzI9TWF0aC5yb3VuZChkLndpZHRoKmZhY3RvciksSDI9TWF0aC5yb3VuZChkLmhlaWdodCpmYWN0b3IpO2NvbnN0IE1BWE1QPTIwZTY7aWYoVzIqSDI+TUFYTVApe2NvbnN0IHM9TWF0aC5zcXJ0KE1BWE1QLyhkLndpZHRoKmQuaGVpZ2h0KSk7VzI9TWF0aC5yb3VuZChkLndpZHRoKnMpO0gyPU1hdGgucm91bmQoZC5oZWlnaHQqcyk7fWxldCByPXJlc2l6ZVRvKGQsVzIsSDIpO3I9dW5zaGFycChyLDEuMCwwLjQpO3I9Y3Jpc3BMaW5lcyhyLDAuNik7cmV0dXJuIHI7fQoKICAvKiAtLS0tIGF1dG8tZGV0ZWN0IHNvZnQgLyBza2luIHJlZ2lvbnMgLS0tLSAqLwogIGZ1bmN0aW9uIGlzU2tpbihyLGcsYil7Y29uc3QgY2I9MTI4LTAuMTY4NzM2KnItMC4zMzEyNjQqZyswLjUqYixjcj0xMjgrMC41KnItMC40MTg2ODgqZy0wLjA4MTMxMipiLHk9MC4yOTkqciswLjU4NypnKzAuMTE0KmI7cmV0dXJuIHk+NDAmJmNiPj04MCYmY2I8PTEzNSYmY3I+PTEzNSYmY3I8PTE4MDt9CiAgZnVuY3Rpb24gZGV0ZWN0QWxwaGEoZCl7Y29uc3Qgdz1kLndpZHRoLGg9ZC5oZWlnaHQsbj13KmgscHg9ZC5kYXRhO2NvbnN0IGdyYXk9bmV3IEZsb2F0MzJBcnJheShuKTtmb3IobGV0IGk9MCxqPTA7aTxuO2krKyxqKz00KWdyYXlbaV09TFVNQShweFtqXSxweFtqKzFdLHB4W2orMl0pLzI1NTtjb25zdCBibHVyPWdhdXNzaWFuKGdyYXksdyxoLDEuNik7Y29uc3QgZGV0YWlsPW5ldyBGbG9hdDMyQXJyYXkobik7Zm9yKGxldCBpPTA7aTxuO2krKylkZXRhaWxbaV09TWF0aC5hYnMoZ3JheVtpXS1ibHVyW2ldKTtjb25zdCBlbmVyZ3k9Z2F1c3NpYW4oZGV0YWlsLHcsaCxNYXRoLm1heCg2LE1hdGgubWluKHcsaCkvNTUpKTtsZXQgbWF4RT0xZS02O2ZvcihsZXQgaT0wO2k8bjtpKyspaWYoZW5lcmd5W2ldPm1heEUpbWF4RT1lbmVyZ3lbaV07Y29uc3Qgd2d0PW5ldyBGbG9hdDMyQXJyYXkobik7Zm9yKGxldCBpPTAsaj0wO2k8bjtpKyssais9NCl7Y29uc3QgbHVtPWdyYXlbaV07Y29uc3QgY29udGVudD1sdW0+MC45Mz8wOjE7Y29uc3Qgc2tpbj1pc1NraW4ocHhbal0scHhbaisxXSxweFtqKzJdKT8xOjA7Y29uc3Qgc29mdD0xLU1hdGgubWluKDEsZW5lcmd5W2ldLyhtYXhFKjAuNSkpO3dndFtpXT1jb250ZW50KnNvZnQqKDAuNTUrMC44KnNraW4pO31sZXQgbXg9MWUtNjtmb3IobGV0IGk9MDtpPG47aSsrKWlmKHdndFtpXT5teClteD13Z3RbaV07Zm9yKGxldCBpPTA7aTxuO2krKyl7bGV0IHY9KHdndFtpXS9teC0wLjQ1KS8wLjQ7dj12PDA/MDp2PjE/MTp2O3dndFtpXT12KnYqKDMtMip2KTt9bGV0IGZlYXQ9Z2F1c3NpYW4od2d0LHcsaCxNYXRoLm1heCgzLE1hdGgucm91bmQoTWF0aC5taW4odyxoKS8xMzApKSk7bGV0IGNvdmVyPTA7Zm9yKGxldCBpPTA7aTxuO2krKyljb3Zlcis9ZmVhdFtpXTtyZXR1cm57YWxwaGE6ZmVhdCxjb3ZlcmFnZTpjb3Zlci9ufTt9CiAgZnVuY3Rpb24gb3ZlcmxheURldGVjdChkLGFscGhhKXtjb25zdCBvdXQ9Y2xvbmUoZCksbz1vdXQuZGF0YTtmb3IobGV0IGk9MCxqPTA7aTxkLndpZHRoKmQuaGVpZ2h0O2krKyxqKz00KXtjb25zdCBhPU1hdGgubWluKDEsYWxwaGFbaV0pO29bal09Y2xhbXAyNTUob1tqXSooMS1hKSs5NSphKTtvW2orMV09Y2xhbXAyNTUob1tqKzFdKigxLWEpKzIwOCphKTtvW2orMl09Y2xhbXAyNTUob1tqKzJdKigxLWEpKzE5NyphKTt9cmV0dXJuIG91dDt9CiAgZnVuY3Rpb24gZGV0YWlsUmVjb3ZlcnkoZCxtdWx0KXsKICAgIGNvbnN0IHc9ZC53aWR0aCxoPWQuaGVpZ2h0LG49dypoO2xldCBhbHBoYTsKICAgIGlmKHN0YXRlLmR0X21vZGU9PT0nbWFzaycpe2NvbnN0IG09bWFza0FscGhhKCk7aWYoIW0pdGhyb3cgbmV3IEVycm9yKCdNYW51YWwgbW9kZTogcGFpbnQgYSByZWdpb24gZmlyc3QgKEVudGVyIG1hc2sgbW9kZSkuJyk7YWxwaGE9Z2F1c3NpYW4obSx3LGgsTWF0aC5tYXgoMixNYXRoLnJvdW5kKE1hdGgubWluKHcsaCkvMTIwKSkpO30KICAgIGVsc2V7Y29uc3QgZGV0PWRldGVjdEFscGhhKGQpO2lmKGRldC5jb3ZlcmFnZTwwLjAwMDgpdGhyb3cgbmV3IEVycm9yKCdObyBjbGVhcmx5IHNvZnQgcmVnaW9ucyBkZXRlY3RlZC4gVHJ5IHRoZSBTdHJvbmcgaW50ZW5zaXR5LCBydW4gQXV0by1yZXN0b3JlIG9uIHRoZSB3aG9sZSBwYWdlLCBvciBzd2l0Y2ggdG8gTWFudWFsIG1hc2suJyk7YWxwaGE9ZGV0LmFscGhhO30KICAgIGlmKCQoJyNkdF9wcmV2aWV3JykuY2hlY2tlZClyZXR1cm4gb3ZlcmxheURldGVjdChkLGFscGhhKTsKICAgIGxldCByZXA9Y2xlYW5QYWdlKGQsMS4wKm11bHQpO3JlcD1ybERlY29udihyZXAsMS4yLE1hdGgucm91bmQoOSptdWx0KSk7cmVwPWNyaXNwTGluZXMocmVwLDEuMCptdWx0KTtyZXA9dW5zaGFycChyZXAsMS4xLDAuNDUqbXVsdCk7CiAgICBjb25zdCBvdXQ9bmV3IEltYWdlRGF0YSh3LGgpLG89b3V0LmRhdGEsb3A9ZC5kYXRhLHJwPXJlcC5kYXRhO2ZvcihsZXQgaT0wLGo9MDtpPG47aSsrLGorPTQpe2NvbnN0IGE9YWxwaGFbaV0+MT8xOmFscGhhW2ldO2ZvcihsZXQgYz0wO2M8MztjKyspb1tqK2NdPWNsYW1wMjU1KG9wW2orY10qKDEtYSkrcnBbaitjXSphKTtvW2orM109b3BbaiszXTt9cmV0dXJuIG91dDt9CiAgLyogLS0tLSBIYW5kUmVmaW5lciBicmlkZ2UgLS0tLSAqLwogIHN0YXRlLmZ4X21vZGU9J2hhbmRzJzsKICBmdW5jdGlvbiBzb3VyY2VCbG9iUE5HKCl7cmV0dXJuIG5ldyBQcm9taXNlKHJlcz0+b2Zmc2NyZWVuKGJhc2UpLnRvQmxvYihyZXMsJ2ltYWdlL3BuZycpKTt9CiAgZnVuY3Rpb24gbWFza0Jsb2JXaGl0ZSgpe3JldHVybiBuZXcgUHJvbWlzZShyZXM9Pntjb25zdCBtPW1hc2tBbHBoYSgpO2NvbnN0IGM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7Yy53aWR0aD1iYXNlLndpZHRoO2MuaGVpZ2h0PWJhc2UuaGVpZ2h0O2NvbnN0IHg9Yy5nZXRDb250ZXh0KCcyZCcpO2NvbnN0IG91dD14LmNyZWF0ZUltYWdlRGF0YShjLndpZHRoLGMuaGVpZ2h0KTtmb3IobGV0IGk9MDtpPGMud2lkdGgqYy5oZWlnaHQ7aSsrKXtjb25zdCB2PShtJiZtW2ldKT8yNTU6MDtvdXQuZGF0YVtpKjRdPW91dC5kYXRhW2kqNCsxXT1vdXQuZGF0YVtpKjQrMl09djtvdXQuZGF0YVtpKjQrM109MjU1O314LnB1dEltYWdlRGF0YShvdXQsMCwwKTtjLnRvQmxvYihyZXMsJ2ltYWdlL3BuZycpO30pO30KICAkKCcjZnhfc2VuZCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJyxzZW5kUmVmaW5lcik7CiAgbGV0IHJlZlRpbWVyPW51bGw7CiAgZnVuY3Rpb24gc3RhcnRSZWZQcm9ncmVzcygpe2NvbnN0IHByb2M9JCgnI3Byb2MnKSx0PSQoJyNwcm9jX3QnKTtwcm9jLmNsYXNzTGlzdC5hZGQoJ29uJyk7Y29uc3QgdDA9RGF0ZS5ub3coKTtjb25zdCB0aWNrPSgpPT57Y29uc3Qgcz1NYXRoLnJvdW5kKChEYXRlLm5vdygpLXQwKS8xMDAwKTtsZXQgbXNnO2lmKHM8OCltc2c9J1NFTkRJTkcgVE8gSEFORFJFRklORVLigKYnO2Vsc2UgaWYoczwyNSltc2c9J1dBS0lORyBDTE9VRCBHUFUgKGNvbGQgc3RhcnQp4oCmXG5maXJzdCBmaXggYWZ0ZXIgaWRsZSBpcyBzbG93JztlbHNlIG1zZz0nU1RJTEwgV09SS0lORyDigJQgcmVmaW5pbmcgaGFuZHPigKYnO3QudGV4dENvbnRlbnQ9bXNnKydcblxuJytzKydzIGVsYXBzZWQnO307dGljaygpO3JlZlRpbWVyPXNldEludGVydmFsKHRpY2ssMTAwMCk7fQogIGZ1bmN0aW9uIHN0b3BSZWZQcm9ncmVzcygpe2lmKHJlZlRpbWVyKXtjbGVhckludGVydmFsKHJlZlRpbWVyKTtyZWZUaW1lcj1udWxsO30kKCcjcHJvYycpLmNsYXNzTGlzdC5yZW1vdmUoJ29uJyk7fQogIGFzeW5jIGZ1bmN0aW9uIHNlbmRSZWZpbmVyKCl7CiAgICBpZighYmFzZSlyZXR1cm47CiAgICBjb25zdCBlcD0kKCcjZnhfZW5kcG9pbnQnKS52YWx1ZS50cmltKCl8fCcvcmVmaW5lJzsKICAgIGNvbnN0IHVzZU1hc2s9JCgnI2Z4X3VzZW1hc2snKS5jaGVja2VkOwogICAgaWYoKHVzZU1hc2t8fHN0YXRlLmZ4X21vZGU9PT0nZ2VuZXJpYycpJiYhbWFza0FscGhhKCkpe2FsZXJ0KCdObyBtYXNrIHBhaW50ZWQuIE9wZW4gRGV0YWlsIHJlY292ZXJ5IOKGkiBNYW51YWwgbWFzayB0byBwYWludCBhIHJlZ2lvbiDigJQgb3IgZm9yIEhhbmRzIG1vZGUsIHVuY2hlY2sgdGhlIGJveCB0byBsZXQgTWVzaEdyYXBob3JtZXIgYXV0by1maW5kIGhhbmRzLicpO3JldHVybjt9CiAgICBpZihzdGF0ZS5wYWludGluZylleGl0UGFpbnQoKTtpZihjb21wYXJpbmcpZW5kQ29tcGFyZSgpOwogICAgc3RhcnRSZWZQcm9ncmVzcygpOwogICAgdHJ5ewogICAgICBjb25zdCBmZD1uZXcgRm9ybURhdGEoKTsKICAgICAgZmQuYXBwZW5kKCdpbWFnZScsYXdhaXQgc291cmNlQmxvYlBORygpLCdpbWFnZS5wbmcnKTsKICAgICAgZmQuYXBwZW5kKCdtb2RlJyxzdGF0ZS5meF9tb2RlKTsKICAgICAgaWYodXNlTWFza3x8c3RhdGUuZnhfbW9kZT09PSdnZW5lcmljJylmZC5hcHBlbmQoJ21hc2snLGF3YWl0IG1hc2tCbG9iV2hpdGUoKSwnbWFzay5wbmcnKTsKICAgICAgY29uc3QgaGVhZGVycz17fTtjb25zdCB0b2s9JCgnI2Z4X3Rva2VuJykudmFsdWUudHJpbSgpO2lmKHRvayloZWFkZXJzWyd4LWRhcmtyb29tLXRva2VuJ109dG9rOwogICAgICBjb25zdCByPWF3YWl0IGZldGNoKGVwLHttZXRob2Q6J1BPU1QnLGhlYWRlcnMsYm9keTpmZH0pOwogICAgICBpZighci5vayl7bGV0IHQ9Jyc7dHJ5e3Q9YXdhaXQgci50ZXh0KCk7fWNhdGNoKGUpe310aHJvdyBuZXcgRXJyb3IoJ1NlcnZlciAnK3Iuc3RhdHVzKyh0Pyc6ICcrdC5zbGljZSgwLDE4MCk6JycpKTt9CiAgICAgIGNvbnN0IGJsb2I9YXdhaXQgci5ibG9iKCk7CiAgICAgIGNvbnN0IGltZz1uZXcgSW1hZ2UoKTsKICAgICAgaW1nLm9ubG9hZD0oKT0+e2NvbnN0IGM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7Yy53aWR0aD1iYXNlLndpZHRoO2MuaGVpZ2h0PWJhc2UuaGVpZ2h0O2MuZ2V0Q29udGV4dCgnMmQnKS5kcmF3SW1hZ2UoaW1nLDAsMCxjLndpZHRoLGMuaGVpZ2h0KTtsYXN0UmVzdWx0PWMuZ2V0Q29udGV4dCgnMmQnKS5nZXRJbWFnZURhdGEoMCwwLGMud2lkdGgsYy5oZWlnaHQpO3N0b3BSZWZQcm9ncmVzcygpO3B1dFJlc3VsdChsYXN0UmVzdWx0KTtzdGFydENvbXBhcmUoKTtzZXRUaXRsZSgnSGFuZFJlZmluZXIgcmVzdWx0JyxiYXNlLndpZHRoKyfDlycrYmFzZS5oZWlnaHQrJ3B4IMK3IHJldmlldyB0aGVuIEFjY2VwdCcpO307CiAgICAgIGltZy5vbmVycm9yPSgpPT57c3RvcFJlZlByb2dyZXNzKCk7YWxlcnQoJ1NlcnZlciByZXNwb25kZWQgYnV0IHRoZSBpbWFnZSBjb3VsZCBub3QgYmUgZGVjb2RlZC4nKTt9OwogICAgICBpbWcuc3JjPVVSTC5jcmVhdGVPYmplY3RVUkwoYmxvYik7CiAgICB9Y2F0Y2goZXJyKXtzdG9wUmVmUHJvZ3Jlc3MoKTtjb25zb2xlLmVycm9yKGVycik7YWxlcnQoJ1JlZmluZXIgY2FsbCBmYWlsZWQ6XG4nK2Vyci5tZXNzYWdlKydcblxuQ2hlY2tsaXN0OiAoMSkgaXMgdGhlIE1vZGFsIGFwcCBkZXBsb3llZCBhbmQgdGhpcyBwYWdlIHNlcnZlZCBmcm9tIGl0PyAoMikgdG9rZW4gbWF0Y2hlcyB5b3VyIERBUktST09NX1RPS0VOIHNlY3JldD8gKDMpIGZvciBoYW5kcyBhdXRvLW1vZGUsIGxlYXZlIHRoZSBtYXNrIGJveCB1bmNoZWNrZWQuJyk7fQogIH0KfSkoKTsKPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPgo=").decode() # ---- lazy singletons (loaded on first GPU call) ---- _PIPE = None _MESH = None def _load(): global _PIPE, _MESH if _PIPE is not None: return from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler from controlnet_aux import MeshGraphormerDetector _MESH = MeshGraphormerDetector.from_pretrained(MESHGRAPHORMER_ID).to("cuda") cn = ControlNetModel.from_pretrained(CONTROLNET_ID, torch_dtype=torch.float16) pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained( SD_INPAINT_ID, controlnet=cn, torch_dtype=torch.float16, safety_checker=None ) pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) _PIPE = pipe.to("cuda") def _fit(img): w, h = img.size s = min(1.0, MAX_SIDE / max(w, h)) return img.resize((max(8, int(round(w*s/8))*8), max(8, int(round(h*s/8))*8)), Image.LANCZOS), (w, h) @spaces.GPU(duration=90) def refine_image(image: Image.Image, mask: Image.Image, mode: str): """The GPU-allocated worker. ZeroGPU grants a GPU for the duration of this call.""" _load() init, (ow, oh) = _fit(image.convert("RGB")) W, H = init.size sent_mask = mask.convert("L").resize((W, H), Image.LANCZOS) if mask is not None else None if mode == "hands": mg = _MESH(init) if isinstance(mg, tuple): depth_img, auto_mask = mg[0], (mg[1] if len(mg) > 1 else None) else: depth_img, auto_mask = mg, None depth_img = depth_img.convert("RGB").resize((W, H), Image.LANCZOS) mask_img = sent_mask or (auto_mask.convert("L").resize((W, H), Image.LANCZOS) if auto_mask else None) if mask_img is None: raise ValueError("No hands detected and no mask supplied.") cscale = 0.7 else: if sent_mask is None: raise ValueError("Generic mode requires a mask.") mask_img, depth_img, cscale = sent_mask, Image.new("RGB", (W, H), (0, 0, 0)), 0.0 mask_img = mask_img.filter(ImageFilter.GaussianBlur(2)) out = _PIPE( prompt=DEFAULT_PROMPT, negative_prompt=NEG, image=init, mask_image=mask_img, control_image=depth_img, num_inference_steps=30, strength=0.75, guidance_scale=7.5, controlnet_conditioning_scale=cscale, ).images[0] return out.resize((ow, oh), Image.LANCZOS) # ---- gradio.Server: custom frontend + queued API + ZeroGPU ---- app = gr.Server() @app.get("/") def index(): return HTMLResponse(FRONTEND_HTML) # our existing frontend POSTs multipart to /refine; keep that contract exactly. @app.post("/refine") async def refine(request: Request): form = await request.form() img = Image.open(io.BytesIO(await form["image"].read())) mode = form.get("mode", "hands") mask = None if form.get("mask") is not None: mask = Image.open(io.BytesIO(await form["mask"].read())) try: out = refine_image(img, mask, mode) # routed through Gradio queue + ZeroGPU except Exception as e: return JSONResponse(status_code=422, content={"error": str(e)}, headers={"Access-Control-Allow-Origin": "*"}) buf = io.BytesIO(); out.save(buf, format="PNG") return Response(content=buf.getvalue(), media_type="image/png", headers={"Access-Control-Allow-Origin": "*"}) if __name__ == "__main__": app.launch()