泰坦失足 发表于 2026-5-4 15:43

感谢AI Coding, 约一个小时搞定了RetroArch的AI翻译

本帖最后由 泰坦失足 于 2026-5-4 16:24 编辑

事前准备:
V P S主机一个: 可以去Oracle申请永久免费的X86主机. 国内直接搜"国内 免费 **"吧. 注意需要公网IP.
AI Coding 软件一个: 我用Codex, 国内免费的Trae大概也行. 毕竟我前半段是基于GPT 5.4 mini跑的, 后面才切到GPT 5.5来debug.
AI API一个: 两个路线, 如果走 V P S端把图片翻译为文字, LLM只负责日文->中文的翻译, 那就任意模型API都行. 如果是要LLM直接完成输入 游戏截图->中文. 那就需要支持图片输入的模型.

几个细节:
1 AI服务器URL必须是 http://xxx.xxx.xxx.xxx:xxx/ 直接复制进去, 只输IP地址:端口 莫名其妙的会失效. 2 可以在服务器端把图片压缩后再给LLM翻译, 使用token量会大幅度缩小 3 V P S端可以做各种预处理, 比如让系统保存过去几次的翻译记录来保证流畅性. 或者导入专门的文本作为词典.



如何工作:
1 打开AI Coding软件, 连接上**. 给AI API充钱
2. RetroArch-输入-快捷键-AI服务RetroArch-设置-无障碍-AI服务-准备接下来的设置.
3. 把以下的话输入给AI Coding软件, 然后听天由命吧.. Debug的方式是你配置好AI服务URL, 按下AI服务键. 然后问AI是否在**上正常收到截图.

RetroArch AI Service 图像翻译服务器复现规格书

本文是给 LLM agent 或开发者复现一个 RetroArch AI Service 图像翻译服务器用的技术说明。目标是从零实现一个 HTTP 服务,接收 RetroArch 发来的游戏截图,压缩到不超过 1920x1080,调用 OpenAI 兼容的多模态 LLM API 做 OCR 和翻译,再返回 RetroArch Image Mode 可显示的透明 PNG 覆盖图。本文不包含个人路径、真实公网 IP、真实用户名或真实密钥,所有敏感内容均使用占位符。

一、最终目标和约束

服务需要监听 0.0.0.0:43302 或用户指定端口,并允许公网访问。RetroArch 客户端的 AI Service URL 填 http://你的公网IP或域名:端口/。服务不要求 RetroArch 传鉴权 token,但服务端必须实现每日额度上限,默认一天最多 10.0 额度,用于防止公网滥用。服务主链路必须使用支持图像输入的 OpenAI 兼容 chat completions API,让模型直接看截图进行 OCR 和翻译。服务必须支持 RetroArch Image Mode 返回格式,即返回 JSON,其中包含透明 PNG base64 覆盖图。服务还应提供 /health 和 /last 诊断接口,方便判断问题发生在 RetroArch 客户端、网络、服务端、OCR、翻译还是覆盖图显示环节。

二、建议目录结构

在目标 ** 上创建一个独立项目目录,例如 /opt/retroarch-ai-bridge。目录结构建议为:src/ 存放 Python 源码,spec.yaml 存放配置,cache/ 存放每日额度状态,result/ 存放 latest_request.json 和 requests.jsonl,log/ 存放日志。API 密钥不写入源码和 spec.yaml,而是通过环境变量或 systemd EnvironmentFile 注入。例如 EnvironmentFile 可以放在用户 home 下的 .config 目录中,内容形如 LLM_API_KEY=你的API密钥。不要把密钥文件提交到仓库。

三、推荐技术栈

推荐使用 Python 3 实现。HTTP 服务可以用标准库 http.server 中的 ThreadingHTTPServer 和 BaseHTTPRequestHandler,避免引入 Web 框架。图片处理使用 Pillow。可选安装 pytesseract 和系统 tesseract,作为视觉模型失败时的本地 OCR fallback。配置文件使用 YAML,Python 中用 PyYAML 读取。如果环境不方便安装 PyYAML,也可以改用 JSON 配置。HTTP 请求 LLM 后端可以用 urllib.request 或 requests;为了减少依赖,标准库 urllib.request 足够。

四、配置文件字段

spec.yaml 至少应包含以下字段。server.host 设置为 0.0.0.0,server.port 设置为 43302 或其他端口。api.base_url 设置为 OpenAI 兼容 API 地址,注意通常应是 https://你的API域名/v1,不要在这里包含 /chat/completions。api.model 设置为支持图像输入的模型名。api.api_key_env 设置为环境变量名,例如 LLM_API_KEY。api.request_timeout_seconds 建议 180。api.max_completion_tokens 建议 512。api.prompt_per_mtoken 和 api.completion_per_mtoken 用来估算额度费用,可按供应商价格填写。quota.daily_credit_limit 默认 10.0。llm_image.max_width 设置 1920,llm_image.max_height 设置 1080,llm_image.format 设置 png,llm_image.jpeg_quality 可设置 92。ocr.lang 可设置 jpn+eng,ocr.config 可设置 --psm 6,ocr.fallback_to_tesseract 设置 true。retroarch.default_output 设置 text 或 image,retroarch.default_text_position 设置 1,retroarch.default_target_language 设置 Simplified Chinese。

五、HTTP 路由

必须实现 GET /health、GET /metrics、GET /last、POST /、POST /translate、POST /ai-service。GET /health 返回服务状态、模型名、额度状态、OCR 依赖状态、请求计数、成功计数、错误计数和 uptime。GET /metrics 可以直接复用 /health。GET /last 返回最近一次请求的完整诊断结果,如果没有请求则返回 {"status":"empty"}。POST /、POST /translate、POST /ai-service 都走同一个处理函数,兼容不同 RetroArch 或插件配置。

六、RetroArch 请求解析

POST 请求体是 JSON 对象。需要从 JSON 中读取 image、format、output、source_lang、target_lang、label、viewport。image 是截图 base64,可能是裸 base64,也可能是 data:image/png;base64,开头的 data URL。format 通常是 png,如果 image 是 data URL,应从 data URL 中解析真实格式。output 可能是字符串 image,png,png-a,也可能是数组,也可能只出现在 query string 中。source_lang 可能是 Japanese,也可能是 Don't care。target_lang 可能在 JSON 中,也可能在 query string 的 target_lang 参数中。label 是游戏或核心标签,只用于提示词上下文和诊断记录。viewport 可能是 数组,也可能是 {"width":宽,"height":高} 对象。

解析 output 的规则建议为:如果 payload.output 是字符串,则按逗号切分并 strip;如果是数组,则逐项转字符串;如果 payload 没有 output,则读取 query string 中的 output;如果仍没有,则使用配置 retroarch.default_output。判断是否需要返回图片时,只要 output_modes 中任一项以 image 开头,就认为是 Image Mode 请求。

七、LLM 图片预处理

实现 prepare_image_for_llm(image_b64, image_format, config)。该函数只处理发给 LLM 后端的图片,不改变原始 image_b64,也不影响返回覆盖图尺寸。步骤是:先去掉 data URL 前缀并 base64 解码;用 Pillow 打开图片;记录 original_width 和 original_height;读取 max_width=1920 和 max_height=1080;计算 scale=min(1.0, max_width/original_width, max_height/original_height);如果 scale 小于 1,则用 LANCZOS 等高质量采样缩放到 new_width=int(original_width*scale)、new_height=int(original_height*scale);根据配置输出 PNG 或 JPEG;PNG 用 optimize=True;JPEG 需要把 RGBA 合成到白底 RGB 后保存,quality 默认 92,optimize=True;重新 base64 编码。若原图未缩放且重编码后 base64 更长,则保留原图,避免“压缩”反而变大。返回值应为 llm_image_b64、llm_image_format、llm_image_meta。meta 至少记录 max_width、max_height、original_width、original_height、llm_width、llm_height、resized、reencoded、llm_image_format、llm_image_base64_chars。

八、视觉模型提示词

构造视觉提示词 build_visual_translation_prompt(source_lang, target_lang, label, output_modes)。提示词应明确告诉模型:你是 RetroArch AI Service 的实时游戏截图 OCR 与翻译引擎;当前内容标签是什么;源语言是什么;目标语言是什么;请求输出模式是什么;请直接查看截图,识别所有可见文字并翻译为目标语言;优先识别游戏菜单、对白、按钮、状态栏文字;忽略扫描线、图标、边框和非文字纹理;翻译要短,适合实时覆盖显示;不要解释;不要 Markdown;不要代码块;只返回紧凑 JSON;JSON 必须是 {"original":"识别到的原文","translation":"目标语言译文"};如果没有可读文字,返回 {"original":"","translation":""}。

九、OpenAI 兼容视觉 payload

很多第三方 OpenAI 兼容平台对图片输入格式有差异。复现时必须先用 1x1 PNG 或写有 HELLO WORLD 的小图测试。已知一种常见可用格式如下:POST 到 base_url.rstrip("/") + "/chat/completions";请求头包含 Authorization: Bearer 你的API密钥,Content-Type: application/json,Accept: application/json,User-Agent: RetroArch-AI-Bridge/1.0。JSON body 包含 model、stream:false、max_completion_tokens、messages。messages 是一个数组,里面有一个 user 消息。该 user 消息的 content 是数组,第一项为 {"type":"input_text","text":提示词},第二项为 {"type":"input_image","image_url":"data:image/png;base64,图片base64"}。注意这里 image_url 是字符串,不是 {"url":...} 对象。某些平台要求 {"type":"image_url","image_url":{"url":...}},但也有平台会因此报 unknown parameter 或 invalid type,所以必须实际测试你所用平台。

十、调用 LLM 后端

实现 request_llm_completion(config, api_key, payload)。该函数把 payload 用 json.dumps ensure_ascii=False 编码为 UTF-8,POST 到 /chat/completions。超时时间使用配置 api.request_timeout_seconds。HTTPError 时读取响应体,抛出包含状态码和响应体前 2000 字符的 RuntimeError。URLError 时抛出请求失败。成功后解析 JSON,并检查返回是 dict。不要在日志中打印 API key。为了兼容第三方平台,解析响应文本时从 choices.message.content 读取,如果 content 是字符串就 strip;如果 content 是数组,则拼接其中 type 为 text 或 output_text 的 text 字段;如果 choices.text 存在,也可以作为兜底。

十一、解析模型返回

实现 parse_visual_translation(content)。先去掉可能的 Markdown JSON fence,例如 ```json 和 ```。如果整段是 JSON 对象,则直接 json.loads;否则提取第一个从 { 到最后一个 } 的片段再尝试 json.loads。成功后读取 original、ocr 或 source 作为原文,读取 translation、translated_text 或 text 作为译文。失败时返回 original="",translation=原始 content。实现 looks_like_vision_failure(original, translation),如果内容包含“看不到图片”“无法查看图片”“不能查看图片”“i can't see”“i cannot see”“cannot view”“unable to view”“no image”等字样,则认为视觉链路失败,触发 fallback。

十二、Tesseract fallback

如果视觉请求失败,或者模型明显表示看不到图片,并且配置 ocr.fallback_to_tesseract 为 true,则走本地 OCR 兜底。实现 ocr_image_text(image_b64, image_format, config):解码原始截图,不要用压缩后的 LLM 图;Pillow 打开后转灰度;如果最大边小于 1600,则放大 2 倍;应用 SHARPEN;应用 autocontrast;调用 pytesseract.image_to_string(image, lang="jpn+eng", config="--psm 6");strip 后得到 OCR 文本。随后构造文本翻译 prompt,调用同一个 chat completions 接口,但 content 用普通字符串,不带图片。fallback 的 ocr_engine 记录为 tesseract_fallback,vision_error 记录视觉链路失败原因。

十三、额度估算和计费

实现 DailyQuotaStore,状态文件为 cache/daily_quota.json。状态包含 day、spent、reserved、updated_at。按服务器配置的时区或本地日期分桶,如果日期变化,自动重置 spent 和 reserved。reserve(estimated_units) 时需要加文件锁,读取状态,检查 spent + reserved + estimated_units 是否超过 daily_credit_limit,超过则抛 QuotaExceededError,HTTP 返回 429。未超过则增加 reserved 并保存。finalize(reserved_units, actual_units) 时再次加锁,reserved 减去本次预留,spent 增加 actual_units。如果 LLM 返回 usage,则按 prompt_tokens/1_000_000*prompt_per_mtoken + completion_tokens/1_000_000*completion_per_mtoken 计算真实费用;如果没有 usage,则用预估费用。预估费用可以用 token_count_estimate(prompt_text)=max(1,len(prompt_text)//4),image_token_estimate(image_b64)=max(256,len(image_b64)//220),再加 max_completion_tokens 的费用,最后乘 1.2 安全系数。注意预估时应使用压缩后的 llm_image_b64,而不是原始截图 base64。

十四、生成 RetroArch 覆盖图

实现 render_overlay_image(translated_text, target_lang, viewport)。如果 viewport 合法,画布尺寸使用 viewport,否则使用 1920x1080。创建 RGBA 透明画布。字体大小可以设置为 max(28, min(58, height//18))。字体优先选择 Noto Sans CJK,其次 DejaVu Sans,如果系统没有 CJK 字体,可用 fc-match 搜索。底部绘制一个半透明黄色或深色圆角矩形,留 padding,文字用黑色或白色。实现 wrap_text_for_width,逐字符测量 textbbox,超过最大宽度就换行。绘制完后用 PNG 保存到 BytesIO,再 base64 编码返回。Image Mode 返回 JSON 应包含 image、text、text_position、auto。text_position 可用配置 default_text_position,auto 可以固定为 continue。即使返回 image,也保留 text 字段用于兼容和调试。

十五、请求处理主流程

handle_retroarch_request 的主流程如下:请求计数加一;解析 image 和 format;调用 prepare_image_for_llm 得到 llm_image_b64、llm_image_format、llm_image_meta;解析 source_lang、target_lang、label、output_modes、viewport;构造视觉 prompt;根据 prompt 和 llm_image_b64 估算费用并 reserve;默认 ocr_engine 为 packy_vision,vision_error 为空;先调用 build_visual_chat_payload 和 request_llm_completion;解析 original 和 translation;如果模型看不到图片则抛错进入 fallback;如果视觉失败且允许 fallback,则对原始 image_b64 做 Tesseract OCR,再调用文本翻译;如果最终 translated_text 为空,则抛错;根据 usage 计算 actual_units 并 finalize;记录 latest_request.json 和 requests.jsonl;如果 output_modes 需要 image,则返回覆盖图 JSON,否则返回纯 text JSON;如果任意异常发生,释放或 finalize 额度,错误计数加一,HTTP 返回 500,QuotaExceededError 返回 429。

十六、/last 诊断记录

每次成功请求都写 result/latest_request.json,并追加 result/requests.jsonl。latest_request.json 应至少包含 status、client_ip、path、output_modes、target_lang、source_lang、label、image_format、image_base64_chars、llm_image、ocr_engine、ocr_text、translated_text、vision_error、response_kind、usage、usage_units、ts。写 JSON 文件时建议先写临时文件,再原子 replace,权限可设置为仅当前用户可读写。追加 jsonl 时可用文件锁,避免并发写交错。/last 直接读取 latest_request.json 返回,如果不存在则返回 {"status":"empty"}。

十七、HTTP 响应细节

所有 JSON 响应使用 Content-Type: application/json; charset=utf-8,Cache-Control: no-store,并设置正确 Content-Length。POST 请求读取 Content-Length,如果没有 body 则当作空 JSON,但 RetroArch 正常会发送 image。JSON 解析失败时返回 500 或 400 均可,建议返回 {"error":"请求体不是合法 JSON"}。路径不匹配时返回 404 和 {"error":"not_found","path":路径}。额度不足时返回 429 和 {"error":"今日额度不足...","auto":"continue"}。服务端日志不要输出 base64 全图,也不要输出 API key。

十八、systemd 部署模板

建议创建 systemd service,WorkingDirectory 指向项目目录,EnvironmentFile 指向密钥文件,ExecStart 使用 /usr/bin/python3 -u 项目目录/src/服务脚本.py --config 项目目录/spec.yaml serve。Restart 设置为 always,RestartSec 设置为 3,KillSignal 设置为 SIGINT 或 SIGTERM,TimeoutStopSec 设置为 30。使用 ThreadingHTTPServer 时,signal handler 中不要直接同步调用 server.shutdown,因为它可能让 systemd restart 等待很久。正确做法是在 signal handler 里启动 daemon 线程执行 server.shutdown。安装后执行 systemctl daemon-reload 或 systemctl --user daemon-reload,再 enable --now 服务。重启测试时记录 restart_seconds,正常应接近 0 秒。

十九、防火墙和公网访问

服务必须监听 0.0.0.0:端口。本机测试访问 http://127.0.0.1:端口/health,公网测试访问 http://你的公网IP或域名:端口/health。如果本机通但公网不通,检查系统防火墙和云平台安全组。系统防火墙需要放行 端口/tcp;云平台 Security List、NSG 或安全组也要放行同样端口。RetroArch AI Service URL 填 http://你的公网IP或域名:端口/,不要误填 https,除非你确实配置了 TLS 反向代理。

二十、RetroArch 客户端配置

打开 RetroArch 的 AI Service 设置。AI Service Enabled 设置为 ON。AI Service URL 设置为 http://你的公网IP或域名:端口/。AI Service Output 设置为 Image Mode。Source Language 可设置 Japanese 或 Don't care。Target Language 设置 zh-CN 或你需要的目标语言。进入游戏后按 AI 翻译热键。若音乐短暂停顿,通常说明 RetroArch 正在截图并发 HTTP 请求。此时立即访问 /last,检查 ts 是否更新。

二十一、端到端验证

第一步访问 /health,确认 status 为 ok,模型名正确,remaining 大于 0。第二步用人工图片测试:生成一张 2560x1440 白底 PNG,上面写 HELLO WORLD,base64 后 POST 到 /?output=image,png,png-a&target_lang=zh-CN,请求体包含 image、format:"png"、output:"image,png,png-a"、source_lang:"en"、target_lang:"zh-CN"、label:"test"、viewport:。期望响应 JSON 包含 image 和 text,text 应类似“你好,世界”。第三步访问 /last,确认 ocr_engine 为视觉模型,ocr_text 为 HELLO WORLD,translated_text 为你好,世界,llm_image.original_width 为 2560,llm_image.original_height 为 1440,llm_image.llm_width 为 1920,llm_image.llm_height 为 1080,resized 为 true。第四步在 RetroArch 中真实按热键,再看 /last 是否更新为真实游戏 label 和真实截图 OCR。

二十二、常见错误判断

如果 /last 没更新,说明 RetroArch 请求没有到服务器,检查 URL、端口、防火墙、云安全组、AI Service Enabled 和是否填错 http/https。如果 /last 更新但 image_base64_chars 为 0 或缺失,说明请求格式不符合预期,需要检查 image 字段解析。如果 /last 中 vision_error 非空且 ocr_engine 为 tesseract_fallback,说明视觉链路失败但 fallback 生效。如果 translated_text 正常但 RetroArch 屏幕不显示,说明服务器端已经完成,重点检查 RetroArch 是否是 Image Mode、当前核心是否支持 AI overlay、覆盖图是否被 UI 设置遮挡。如果 HTTP 429,说明每日额度用尽。如果 LLM 返回看不到图片,优先检查视觉 payload 格式,尤其 image_url 是字符串还是对象。

二十三、安全和隐私注意事项

不要把真实 API key 写入源码、README、日志或诊断接口。不要在 /last 中记录 Authorization header。不要保存完整原始截图,除非用户明确需要,因为游戏截图可能包含隐私信息;通常只保存 OCR 文本、译文和图片尺寸即可。公网无鉴权服务必须有每日额度限制。更严格的部署可以加 IP 白名单、简单 token、反向代理限流或只绑定内网再通过 ** 访问。

二十四、最小可交付标准

一个复现成功的版本应满足:服务能启动并监听 0.0.0.0:端口;/health 返回 ok;POST 人工图片能得到正确翻译;/last 能记录最近请求;大于 1080p 的输入图在发给 LLM 前被压缩到不超过 1920x1080;Image Mode 返回 JSON 中有 image 字段;超过每日额度返回 429;systemd restart 后服务能自动恢复;RetroArch 真实按键后 /last 会更新。如果这些条件都满足,服务器端功能就已经完成。若屏幕仍不显示,应继续排查 RetroArch 客户端显示设置,而不是优先怀疑 OCR 或翻译链路。




时空之旅 发表于 2026-5-4 17:28

本帖最后由 时空之旅 于 2026-5-4 17:32 编辑

感谢,先收藏,以后试试
略好奇,pc98这一块难道可以畅玩了?

精钢魔像 发表于 2026-5-4 18:06

时空之旅 发表于 2026-5-4 17:28
感谢,先收藏,以后试试
略好奇,pc98这一块难道可以畅玩了?
用之前的ocr 翻译就可以了吧,主要还是要求翻译端能联系上下文。

ai 眼镜应该也行。

pf67 发表于 2026-5-4 18:32

这一套做完的翻译时延呢?用多模态还要重新复写图片感觉快不了

—— 来自 Xiaomi 25042PN24C, Android 16, 鹅球 v3.5.99

时空之旅 发表于 2026-5-4 20:14

精钢魔像 发表于 2026-5-4 18:06
用之前的ocr 翻译就可以了吧,主要还是要求翻译端能联系上下文。

ai 眼镜应该也行。


不知道现在能不能实现语音翻译,有些老游戏比如是互动类的,或者没字幕,这一类不知道能不能翻译出来

精钢魔像 发表于 2026-5-4 20:20

时空之旅 发表于 2026-5-4 20:14
不知道现在能不能实现语音翻译,有些老游戏比如是互动类的,或者没字幕,这一类不知道能不能翻译出来 ...

ai 眼镜是可以的。

2026-03-29注册 发表于 2026-5-5 03:32

厉害,收藏了

泰坦失足 发表于 2026-5-5 05:50

pf67 发表于 2026-5-4 18:32
这一套做完的翻译时延呢?用多模态还要重新复写图片感觉快不了

—— 来自 Xiaomi 25042PN24C, Android 16, ...

凑合吧, 毕竟我玩Avg也不在乎时延. 还有就是RetroArch不像SakuraTranslator支持实时翻译, 必须按一下AI翻译快捷键进行一次翻译, 所以天生的就有时延.
在**端你也可以修改配置, 让图片本地OCR后走LLM翻译, 然后选择返回文本, RetroArch支持图片和文本两种回传模式(虽然iOS端我只看到图片/语音/讲述人三个模式).
如果是电脑上跑SakuraTranslator可能是更优解, 这套解决方案主要可以给手机平板等非PC设备使用

泰坦失足 发表于 2026-5-5 05:52

本帖最后由 泰坦失足 于 2026-5-5 06:28 编辑

时空之旅 发表于 2026-5-4 20:14
不知道现在能不能实现语音翻译,有些老游戏比如是互动类的,或者没字幕,这一类不知道能不能翻译出来 ...
市面上挺多实现实时字幕和翻译的软件, PC和非PC上都有.

lion_or_judas 发表于 2026-5-5 12:16

好奇楼主这一套下来开销多少,现在我就用trae薅薅免费羊毛,让ai改改自己写的py脚本

泰坦失足 发表于 2026-5-5 12:32

本帖最后由 泰坦失足 于 2026-5-5 12:34 编辑

lion_or_judas 发表于 2026-5-5 12:16
好奇楼主这一套下来开销多少,现在我就用trae薅薅免费羊毛,让ai改改自己写的py脚本 ...系统构建:
Cached input: 50.95M tokens
Uncached input: 2.36M tokens
Output: 235.94K tokens
Reasoning: 89.99K tokens
按GPT 5.5 原生API定价的话是$44, 中转站就会便宜的多.
一次截图并翻译的任务. 按之前1080p时候是按一下AI翻译, 中转站扣了0.02rmb, 意识到模拟器截图压根不需要那么高分辨率后, 价格应该会便宜很多. 毕竟token量大幅度降低了

mario21a 发表于 2026-5-14 02:55

楼主可以分享下目前配置好的Python Code并推荐一个API吗
自己按照这里的教程https://blog.ocam.live/archives/4860尝试了一下,能跑但效果不太尽人意
谢了

泰坦失足 发表于 2026-5-14 05:22

本帖最后由 泰坦失足 于 2026-5-14 05:28 编辑

mario21a 发表于 2026-5-14 02:55
楼主可以分享下目前配置好的Python Code并推荐一个API吗
自己按照这里的教程https://blog.ocam.live/archiv ...
我目前用的是GPT 5.4 Mini 大概1~1.5秒完成翻译. GPT 5.5 明显更贵, 效果却差不多, 而且要8~10秒给出结果. 小米的MIMO家族里带多模态功能的虽然也能识图明显不如GPT 5.4 mini.
API使用中转站就行了, 小红书上搜下就有. 随便充个10块钱能用很久. 官方API也行, 也不贵.
几个核心: 1: 把之前的文字/翻译提供给当前画面的翻译Prompt里, 这样保持一致性. 2: Prompt里提供词典, 介绍这个游戏的常见名词和官方翻译. 用不了多少Token. 3 原版游戏多少分辨率, 就让LLM后端接收到这个分辨率, 节省Token. 然后Prompt里说"这是一个低分辨率的XXX主机游戏, 文字是低像素风格的X文. 对话框经常出现在XX区域, (呈现半透明背景)[这个根据游戏而定]" 4 调节Reasoning effort可以调节翻译速度. 还要留下足够的token给Reasoning token
你把这些要求提供给AI Code Agent, 让它来做就行.
data:;base64,IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwojIEZpbGU6IHJldHJvYXJjaF9vcGVuYWlfYnJpZGdlLnB5CiMgRGVzY3JpcHRpb246IFJldHJvQXJjaCBBSSBTZXJ2aWNlIGJyaWRnZSB0aGF0IHJlY2VpdmVzIGVtdWxhdG9yIHNjcmVlbnNob3RzLCBjYWxscyBhbiBPcGVuQUktY29tcGF0aWJsZSB2aXNpb24gbW9kZWwsIGFuZCByZXR1cm5zIHRyYW5zbGF0ZWQgdGV4dCBvciBpbWFnZSBvdmVybGF5cy4KIyBLZXl3b3JkczogUmV0cm9BcmNoLCBBSSBTZXJ2aWNlLCBPcGVuQUksIE9DUiwgdHJhbnNsYXRpb24sIHF1b3RhCiMKIyBXb3JrZmxvdzoKIyAxLiBTdGFydCBhIHN0YW5kYXJkLWxpYnJhcnkgSFRUUCBzZXJ2ZXIgb24gdGhlIGNvbmZpZ3VyZWQgaG9zdCBhbmQgcG9ydC4KIyAyLiBBY2NlcHQgUmV0cm9BcmNoIEFJIFNlcnZpY2Ugc2NyZWVuc2hvdCBQT1NUIHJlcXVlc3RzLgojIDMuIFNlbmQgYSByZXNpemVkIHNjcmVlbnNob3QgdG8gdGhlIGNvbmZpZ3VyZWQgT3BlbkFJLWNvbXBhdGlibGUgdmlzaW9uIG1vZGVsIGZvciBPQ1IgYW5kIHRyYW5zbGF0aW9uLgojIDQuIEZhbGwgYmFjayB0byBsb2NhbCBUZXNzZXJhY3QgT0NSIHBsdXMgdGV4dCB0cmFuc2xhdGlvbiBpZiBjb25maWd1cmVkIGFuZCBhdmFpbGFibGUuCiMgNS4gRW5mb3JjZSBhIGxvY2FsIGRhaWx5IHNwZW5kaW5nIHF1b3RhIGJlZm9yZSBzZXJ2aW5nIHB1YmxpYyB1bmF1dGhlbnRpY2F0ZWQgdHJhZmZpYy4KCmZyb20gX19mdXR1cmVfXyBpbXBvcnQgYW5ub3RhdGlvbnMKCmltcG9ydCBhcmdwYXJzZQppbXBvcnQgYmFzZTY0CmltcG9ydCBkYXRldGltZSBhcyBkdAppbXBvcnQgZmNudGwKaW1wb3J0IGlvCmltcG9ydCBqc29uCmltcG9ydCBvcwppbXBvcnQgcmUKaW1wb3J0IHNpZ25hbAppbXBvcnQgc29ja2V0c2VydmVyCmltcG9ydCBzdGF0CmltcG9ydCBzeXMKaW1wb3J0IHRocmVhZGluZwppbXBvcnQgdGltZQppbXBvcnQgdHJhY2ViYWNrCmltcG9ydCBzaHV0aWwKaW1wb3J0IHN1YnByb2Nlc3MKaW1wb3J0IHVybGxpYi5lcnJvcgppbXBvcnQgdXJsbGliLnBhcnNlCmltcG9ydCB1cmxsaWIucmVxdWVzdApmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MKZnJvbSBodHRwIGltcG9ydCBIVFRQU3RhdHVzCmZyb20gaHR0cC5zZXJ2ZXIgaW1wb3J0IEJhc2VIVFRQUmVxdWVzdEhhbmRsZXIsIFRocmVhZGluZ0hUVFBTZXJ2ZXIKZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCmZyb20gdHlwaW5nIGltcG9ydCBBbnkKZnJvbSB6b25laW5mbyBpbXBvcnQgWm9uZUluZm8KCmltcG9ydCB5YW1sCgp0cnk6CiAgICBmcm9tIFBJTCBpbXBvcnQgSW1hZ2UsIEltYWdlRHJhdywgSW1hZ2VGaWx0ZXIsIEltYWdlRm9udCwgSW1hZ2VPcHMKZXhjZXB0IEV4Y2VwdGlvbjogICMgcHJhZ21hOiBubyBjb3ZlciAtIOi/kOihjOeOr+Wig+acquWuieijheaXtue7meWHuuS8mOmbhemZjee6pwogICAgSW1hZ2UgPSBOb25lICAjIHR5cGU6IGlnbm9yZVthc3NpZ25tZW50XQogICAgSW1hZ2VEcmF3ID0gTm9uZSAgIyB0eXBlOiBpZ25vcmVbYXNzaWdubWVudF0KICAgIEltYWdlRmlsdGVyID0gTm9uZSAgIyB0eXBlOiBpZ25vcmVbYXNzaWdubWVudF0KICAgIEltYWdlRm9udCA9IE5vbmUgICMgdHlwZTogaWdub3JlW2Fzc2lnbm1lbnRdCiAgICBJbWFnZU9wcyA9IE5vbmUgICMgdHlwZTogaWdub3JlW2Fzc2lnbm1lbnRdCgp0cnk6CiAgICBpbXBvcnQgcHl0ZXNzZXJhY3QKZXhjZXB0IEV4Y2VwdGlvbjogICMgcHJhZ21hOiBubyBjb3ZlcgogICAgcHl0ZXNzZXJhY3QgPSBOb25lICAjIHR5cGU6IGlnbm9yZVthc3NpZ25tZW50XQoKClBST0pFQ1RfUk9PVCA9IFBhdGgoX19maWxlX18pLnJlc29sdmUoKS5wYXJlbnRzWzFdCkRFRkFVTFRfQ09ORklHID0gUFJPSkVDVF9ST09UIC8gInNwZWMueWFtbCIKUFJFRkVSUkVEX1RaID0gWm9uZUluZm8oIkFtZ**Y2EvUGhvZW5peCIpCgoKZGVmIGxvZyhtc2c6IHN0cikgLT4gTm9uZToKICAgIHRzID0gZHQuZGF0ZXRpbWUubm93KFBSRUZFUlJFRF9UWikuc3RyZnRpbWUoIiVZLSVtLSVkICVIOiVNOiVTIikKICAgIHByaW50KGYiW3t0c31dIHttc2d9IiwgZmx1c2g9VHJ1ZSkKCgpkZWYgbG9hZF9jb25maWcocGF0aDogc3RyIHwgUGF0aCkgLT4gZGljdFtzdHIsIEFueV06CiAgICBjb25maWdfcGF0aCA9IFBhdGgocGF0aCkKICAgIGlmIG5vdCBjb25maWdfcGF0aC5pc19hYnNvbHV0ZSgpOgogICAgICAgIGNvbmZpZ19wYXRoID0gUFJPSkVDVF9ST09UIC8gY29uZmlnX3BhdGgKICAgIHdpdGggY29uZmlnX3BhdGgub3BlbigiciIsIGVuY29kaW5nPSJ1dGYtOCIpIGFzIGY6CiAgICAgICAgZGF0YSA9IHlhbWwuc2FmZV9sb2FkKGYpIG9yIHt9CiAgICBkYXRhWyJfY29uZmlnX3BhdGgiXSA9IHN0cihjb25maWdfcGF0aCkKICAgIHJldHVybiBkYXRhCgoKZGVmIGVuc3VyZV9wYXJlbnRfZGlyKHBhdGg6IFBhdGgpIC0+IE5vbmU6CiAgICBwYXRoLnBhcmVudC5ta2RpcihwYXJlbnRzPVRydWUsIGV4aXN0X29rPVRydWUpCgoKZGVmIHNlY3VyZV93cml0ZV9qc29uKHBhdGg6IFBhdGgsIHBheWxvYWQ6IGRpY3Rbc3RyLCBBbnldKSAtPiBOb25lOgogICAgZW5zdXJlX3BhcmVudF9kaXIocGF0aCkKICAgIHRtcCA9IHBhdGgud2l0aF9zdWZmaXgocGF0aC5zdWZmaXggKyAiLnRtcCIpCiAgICB0bXAud3JpdGVfdGV4dChqc29uLmR1bXBzKHBheWxvYWQsIGVuc3VyZV9hc2NpaT1GYWxzZSwgaW5kZW50PTIpICsgIlxuIiwgZW5jb2Rpbmc9InV0Zi04IikKICAgIG9zLmNobW9kKHRtcCwgc3RhdC5TX0lSVVNSIHwgc3RhdC5TX0lXVVNSKQogICAgdG1wLnJlcGxhY2UocGF0aCkKICAgIG9zLmNobW9kKHBhdGgsIHN0YXQuU19JUlVTUiB8IHN0YXQuU19JV1VTUikKCgpkZWYgYXBwZW5kX2pzb25sKHBhdGg6IFBhdGgsIHBheWxvYWQ6IGRpY3Rbc3RyLCBBbnldKSAtPiBOb25lOgogICAgZW5zdXJlX3BhcmVudF9kaXIocGF0aCkKICAgIGxvY2sgPSBhdG9taWNfbG9ja19wYXRoKHBhdGgud2l0aF9zdWZmaXgocGF0aC5zdWZmaXggKyAiLmxvY2siKSkKICAgIHRyeToKICAgICAgICB3aXRoIHBhdGgub3BlbigiYSIsIGVuY29kaW5nPSJ1dGYtOCIpIGFzIGY6CiAgICAgICAgICAgIGYud3JpdGUoanNvbi5kdW1wcyhwYXlsb2FkLCBlbnN1cmVfYXNjaWk9RmFsc2UpICsgIlxuIikKICAgIGZpbmFsbHk6CiAgICAgICAgcmVsZWFzZV9sb2NrKGxvY2spCgoKZGVmIG5vd19idWNrZXRfZGF0ZSgpIC0+IHN0cjoKICAgIHJldHVybiBkdC5kYXRldGltZS5ub3coUFJFRkVSUkVEX1RaKS5kYXRlKCkuaXNvZm9ybWF0KCkKCgpkZWYgYXRvbWljX2xvY2tfcGF0aChwYXRoOiBQYXRoKToKICAgIGVuc3VyZV9wYXJlbnRfZGlyKHBhdGgpCiAgICBoYW5kbGUgPSBwYXRoLm9wZW4oImErIiwgZW5jb2Rpbmc9InV0Zi04IikKICAgIGZjbnRsLmZsb2NrKGhhbmRsZS5maWxlbm8oKSwgZmNudGwuTE9DS19FWCkKICAgIHJldHVybiBoYW5kbGUKCgpkZWYgcmVsZWFzZV9sb2NrKGhhbmRsZSkgLT4gTm9uZToKICAgIHRyeToKICAgICAgICBmY250bC5mbG9jayhoYW5kbGUuZmlsZW5vKCksIGZjbnRsLkxPQ0tfVU4pCiAgICBmaW5hbGx5OgogICAgICAgIGhhbmRsZS5jbG9zZSgpCgoKZGVmIGxvYWRfanNvbl9vcl9kZWZhdWx0KHBhdGg6IFBhdGgsIGRlZmF1bHQ6IGRpY3Rbc3RyLCBBbnldKSAtPiBkaWN0W3N0ciwgQW55XToKICAgIGlmIG5vdCBwYXRoLmV4aXN0cygpOgogICAgICAgIHJldHVybiBkaWN0KGRlZmF1bHQpCiAgICB0cnk6CiAgICAgICAgZGF0YSA9IGpzb24ubG9hZHMocGF0aC5yZWFkX3RleHQoZW5jb2Rpbmc9InV0Zi04IikpCiAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgIHJldHVybiBkaWN0KGRlZmF1bHQpCiAgICBpZiBub3QgaXNpbnN0YW5jZShkYXRhLCBkaWN0KToKICAgICAgICByZXR1cm4gZGljdChkZWZhdWx0KQogICAgcmV0dXJuIGRhdGEKCgpkZWYgbm9ybWFsaXplX3RleHQodmFsdWU6IEFueSkgLT4gc3RyOgogICAgaWYgdmFsdWUgaXMgTm9uZToKICAgICAgICByZXR1cm4gIiIKICAgIGlmIGlzaW5zdGFuY2UodmFsdWUsIHN0cik6CiAgICAgICAgcmV0dXJuIHZhbHVlLnN0cmlwKCkKICAgIHJldHVybiBzdHIodmFsdWUpLnN0cmlwKCkKCgpkZWYgbGxtX2NvbmZpZyhjb25maWc6IGRpY3Rbc3RyLCBBbnldKSAtPiBkaWN0W3N0ciwgQW55XToKICAgIHJldHVybiBjb25maWcuZ2V0KCJvcGVuYWkiKSBvciB7fQoKCmRlZiBsb2FkX2xsbV9hcGlfa2V5KGNvbmZpZzogZGljdFtzdHIsIEFueV0pIC0+IHN0cjoKICAgIGFwaV9**cgPSBsbG1fY29uZmlnKGNvbmZpZykKICAgIGVudl9uYW1lcyA9IGxpc3QoYXBpX2NmZy5nZXQoImFwaV9rZXlfZW52Iikgb3IgWyJPUEVOQUlfQVBJX0tFWSJdKQogICAgZm9yIG5hbWUgaW4gZW52X25hbWVzOgogICAgICAgIHRva2VuID0gb3MuZW52aXJvbi5nZXQobmFtZSwgIiIpLnN0cmlwKCkKICAgICAgICBpZiB0b2tlbjoKICAgICAgICAgICAgcmV0dXJuIHRva2VuCiAgICBqb2luZWQgPSAiIC8gIi5qb2luKGVudl9uYW1lcykKICAgIHJhaXNlIFJ1bnRpbWVFcnJvcihmIk1pc3NpbmcgT3BlbkFJIEFQSSBrZXkuIFNldCBvbmUgb2Y6IHtqb2luZWR9LiIpCgoKZGVmIHRva2VuX2NvdW50X2VzdGltYXRlKHRleHQ6IHN0cikgLT4gaW50OgogICAgaWYgbm90IHRleHQ6CiAgICAgICAgcmV0dXJuIDAKICAgIHJldHVybiBtYXgoMSwgbGVuKHRleHQpIC8vIDQpCgoKZGVmIGltYWdlX3Rva2VuX2VzdGltYXRlKGltYWdlX2I2NDogc3RyKSAtPiBpbnQ6CiAgICBpZiBub3QgaW1hZ2VfYjY0OgogICAgICAgIHJldHVybiAwCiAgICAjIOS/neWuiOS8sOiuoe+8muaIquWbvuavlOe6r+aWh+acrOi0te+8jOS9huS4jemcgOimgeeyvueul+WIsOWDj+e0oOe6p+OAggogICAgcmV0dXJuIG1heCgyNTYsIGxlbihpbWFnZV9iNjQpIC8vIDIyMCkKCgpAZGF0YWNsYXNzCmNsYXNzIFF1b3RhU25hcHNob3Q6CiAgICBkYXk6IHN0cgogICAgc3BlbnQ6IGZsb2F0CiAgICByZXNlcnZlZDogZmxvYXQKICAgIHVwZGF0ZWRfYXQ6IGZsb2F0CgoKY2xhc3MgRGFpbHlRdW90YVN0b3JlOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHBhdGg6IFBhdGgsIGxpbWl0OiBmbG9hdCk6CiAgICAgICAgc2VsZi5wYXRoID0gcGF0aAogICAgICAgIHNlbGYubGltaXQgPSBmbG9hdChsaW1pdCkKCiAgICBkZWYgX2RlZmF1bHRfc3RhdGUoc2VsZikgLT4gZGljdFtzdHIsIEFueV06CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgImRheSI6IG5vd19idWNrZXRfZGF0ZSgpLAogICAgICAgICAgICAic3BlbnQiOiAwLjAsCiAgICAgICAgICAgICJyZXNlcnZlZCI6IDAuMCwKICAgICAgICAgICAgInVwZGF0ZWRfYXQiOiB0aW1lLnRpbWUoKSwKICAgICAgICB9CgogICAgZGVmIHNuYXBzaG90KHNlbGYpIC0+IFF1b3RhU25hcHNob3Q6CiAgICAgICAgc3RhdGUgPSBsb2FkX2pzb25fb3JfZGVmYXVsdChzZWxmLnBhdGgsIHNlbGYuX2RlZmF1bHRfc3RhdGUoKSkKICAgICAgICBkYXkgPSBub3JtYWxpemVfdGV4dChzdGF0ZS5nZXQoImRheSIpKSBvciBub3dfYnVja2V0X2RhdGUoKQogICAgICAgIHJldHVybiBRdW90YVNuYXBzaG90KAogICAgICAgICAgICBkYXk9ZGF5LAogICAgICAgICAgICBzcGVudD1mbG9hdChzdGF0ZS5nZXQoInNwZW50Iikgb3IgMC4wKSwKICAgICAgICAgICAgcmVzZXJ2ZWQ9ZmxvYXQoc3RhdGUuZ2V0KCJyZXNlcnZlZCIpIG9yIDAuMCksCiAgICAgICAgICAgIHVwZGF0ZWRfYXQ9ZmxvYXQoc3RhdGUuZ2V0KCJ1cGRhdGVkX2F0Iikgb3IgMC4wKSwKICAgICAgICApCgogICAgZGVmIF9zYXZlX2xvY2tlZChzZWxmLCBzdGF0ZTogZGljdFtzdHIsIEFueV0pIC0+IE5vbmU6CiAgICAgICAgc3RhdGVbInVwZGF0ZWRfYXQiXSA9IHRpbWUudGltZSgpCiAgICAgICAgc2VjdXJlX3dyaXRlX2pzb24oc2VsZi5wYXRoLCBzdGF0ZSkKCiAgICBkZWYgX2xvYWRfbG9ja2VkKHNlbGYpIC0+IGRpY3Rbc3RyLCBBbnldOgogICAgICAgIHN0YXRlID0gbG9hZF9qc29uX29yX2RlZmF1bHQoc2VsZi5wYXRoLCBzZWxmLl9kZWZhdWx0X3N0YXRlKCkpCiAgICAgICAgY3VycmVudF9kYXkgPSBub3dfYnVja2V0X2RhdGUoKQogICAgICAgIGlmIG5vcm1hbGl6ZV90ZXh0KHN0YXRlLmdldCgiZGF5IikpICE9IGN1cnJlbnRfZGF5OgogICAgICAgICAgICBzdGF0ZSA9IHNlbGYuX2RlZmF1bHRfc3RhdGUoKQogICAgICAgIHN0YXRlLnNldGRlZmF1bHQoInNwZW50IiwgMC4wKQogICAgICAgIHN0YXRlLnNldGRlZmF1bHQoInJlc2VydmVkIiwgMC4wKQogICAgICAgIHN0YXRlWyJkYXkiXSA9IGN1cnJlbnRfZGF5CiAgICAgICAgcmV0dXJuIHN0YXRlCgogICAgZGVmIHJlc2VydmUoc2VsZiwgZXN0aW1hdGVkX3VuaXRzOiBmbG9hdCkgLT4gTm9uZToKICAgICAgICBoYW5kbGUgPSBhdG9taWNfbG9ja19wYXRoKHNlbGYucGF0aC53aXRoX3N1ZmZpeChzZWxmLnBhdGguc3VmZml4ICsgIi5sb2NrIikpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBzdGF0ZSA9IHNlbGYuX2xvYWRfbG9ja2VkKCkKICAgICAgICAgICAgc3BlbnQgPSBmbG9hdChzdGF0ZS5nZXQoInNwZW50Iikgb3IgMC4wKQogICAgICAgICAgICByZXNlcnZlZCA9IGZsb2F0KHN0YXRlLmdldCgicmVzZXJ2ZWQiKSBvciAwLjApCiAgICAgICAgICAgIGlmIHNwZW50ICsgcmVzZXJ2ZWQgKyBlc3RpbWF0ZWRfdW5pdHMgPiBzZWxmLmxpbWl0ICsgMWUtOToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIuS7iuaXpemineW6puS4jei2s++8muW3sueUqCB7c3BlbnQ6LjRmfe+8jOW3sumihOeVmSB7cmVzZXJ2ZWQ6LjRmfe+8jCIKICAgICAgICAgICAgICAgICAgICBmIuacrOasoemihOS8sCB7ZXN0aW1hdGVkX3VuaXRzOi40Zn3vvIzkuIrpmZAge3NlbGYubGltaXQ6LjRmfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgc3RhdGVbInJlc2VydmVkIl0gPSByZXNlcnZlZCArIGVzdGltYXRlZF91bml0cwogICAgICAgICAgICBzZWxmLl9zYXZlX2xvY2tlZChzdGF0ZSkKICAgICAgICBmaW5hbGx5OgogICAgICAgICAgICByZWxlYXNlX2xvY2soaGFuZGxlKQoKICAgIGRlZiBmaW5hbGl6ZShzZWxmLCByZXNlcnZlZF91bml0czogZmxvYXQsIGFjdHVhbF91bml0czogZmxvYXQgfCBOb25lKSAtPiBOb25lOgogICAgICAgIGhhbmRsZSA9IGF0b21pY19sb2NrX3BhdGgoc2VsZi5wYXRoLndpdGhfc3VmZml4KHNlbGYucGF0aC5zdWZmaXggKyAiLmxvY2siKSkKICAgICAgICB0cnk6CiAgICAgICAgICAgIHN0YXRlID0gc2VsZi5fbG9hZF9sb2NrZWQoKQogICAgICAgICAgICByZXNlcnZlZCA9IGZsb2F0KHN0YXRlLmdldCgicmVzZXJ2ZWQiKSBvciAwLjApCiAgICAgICAgICAgIHNwZW50ID0gZmxvYXQoc3RhdGUuZ2V0KCJzcGVudCIpIG9yIDAuMCkKICAgICAgICAgICAgc3RhdGVbInJlc2VydmVkIl0gPSBtYXgoMC4wLCByZXNlcnZlZCAtIHJlc2VydmVkX3VuaXRzKQogICAgICAgICAgICBpZiBhY3R1YWxfdW5pdHMgaXMgTm9uZToKICAgICAgICAgICAgICAgIGFjdHVhbF91bml0cyA9IHJlc2VydmVkX3VuaXRzCiAgICAgICAgICAgIHN0YXRlWyJzcGVudCJdID0gc3BlbnQgKyBmbG9hdChhY3R1YWxfdW5pdHMpCiAgICAgICAgICAgIHNlbGYuX3NhdmVfbG9ja2VkKHN0YXRlKQogICAgICAgIGZpbmFsbHk6CiAgICAgICAgICAgIHJlbGVhc2VfbG9jayhoYW5kbGUpCgoKZGVmIGJ1aWxkX3RyYW5zbGF0aW9uX3Byb21wdChzb3VyY2VfbGFuZzogc3RyLCB0YXJnZXRfbGFuZzogc3RyLCBsYWJlbDogc3RyLCBvdXRwdXRfbW9kZXM6IGxpc3Rbc3RyXSkgLT4gc3RyOgogICAgc291cmNlX2xhbmcgPSBzb3VyY2VfbGFuZyBvciAiRG9uJ3QgY2FyZSIKICAgIHRhcmdldF9sYW5nID0gdGFyZ2V0X2xhbmcgb3IgIkRvbid0IGNhcmUiCiAgICBpZiB0YXJnZXRfbGFuZy5zdHJpcCgpLmxvd2VyKCkgaW4geyJkb24ndCBjYXJlIiwgImRvbnQgY2FyZSIsICJhdXRvIiwgImF1dG9tYXRpYyJ9OgogICAgICAgIHRhcmdldF9sYW5nID0gIlNpbXBsaWZpZWQgQ2hpbmVzZSIKICAgIGxhYmVsID0gbGFiZWwgb3IgInVua25vd24iCiAgICBtb2RlcyA9ICIsICIuam9pbihvdXRwdXRfbW9kZXMpIGlmIG91dHB1dF9tb2RlcyBlbHNlICJ0ZXh0IgogICAgcmV0dXJuICgKICAgICAgICAi5L2g5pivIFJldHJvQXJjaCBBSSBTZXJ2aWNlIOeahOWunuaXtue/u+ivkeW8leaTjuOAglxuIgogICAgICAgIGYi5b2T5YmN5YaF5a655qCH562+OiB7bGFiZWx9XG4iCiAgICAgICAgZiLor7fmsYLovpPlh7rmqKHlvI86IHttb2Rlc31cbiIKICAgICAgICBmIua6kOivreiogDoge3NvdXJjZV9sYW5nfVxuIgogICAgICAgIGYi55uu5qCH6K+t6KiAOiB7dGFyZ2V0X2xhbmd9XG4iCiAgICAgICAgIuS7u+WKoTpcbiIKICAgICAgICAiMS4g6K+G5Yir5oiq5Zu+6YeM5omA5pyJ5Y+v6KeB5paH5a2X44CCXG4iCiAgICAgICAgIjIuIOWPqui+k+WHuuebruagh+ivreiogOeahOiHqueEtuivkeaWh++8jOS4jeimgeWbnuaYviBPQ1Ig5Y6f5paH44CCXG4iCiAgICAgICAgIjMuIOS/neeVmea4uOaIj+S4k+acieWQjeivjeOAgeaMiemSruWQjeOAgemBk+WFt+WQjeeahOiHqueEtuihqOi+vuOAglxuIgogICAgICAgICI0LiDkuI3opoHop6Pph4rvvIzkuI3opoHliIbmnpDvvIzkuI3opoHovpPlh7rlpJrkvZnliY3nvIDvvIzkuI3opoHovpPlh7ogSlNPTuOAglxuIgogICAgICAgICI1LiDlpoLmnpznlL**aLph4zmsqHmnInlj6/or7vmloflrZfvvIzov5Tlm57nqbrlrZfnrKbkuLLmiJbmnIDnn63mj5DnpLrjgIJcbiIKICAgICkKCgpkZWYgYnVpbGRfdmlzdWFsX3RyYW5zbGF0aW9uX3Byb21wdCgKICAgIHNvdXJjZV9sYW5nOiBzdHIsCiAgICB0YXJnZXRfbGFuZzogc3RyLAogICAgbGFiZWw6IHN0ciwKICAgIG91dHB1dF9tb2RlczogbGlzdFtzdHJdLAogICAgY2hhcmFjdGVyX2RpY3Q6IGRpY3Rbc3RyLCBzdHJdIHwgTm9uZSA9IE5vbmUsCiAgICBjb250ZXh0X2hpc3Rvcnk6IGxpc3RbZGljdFtzdHIsIHN0cl1dIHwgTm9uZSA9IE5vbmUsCikgLT4gc3RyOgogICAgc291cmNlX2xhbmcgPSBzb3VyY2VfbGFuZyBvciAiSmFwYW5lc2UiCiAgICB0YXJnZXRfbGFuZyA9IHRhcmdldF9sYW5nIG9yICJTaW1wbGlmaWVkIENoaW5lc2UiCiAgICBsYWJlbCA9IGxhYmVsIG9yICJ1bmtub3duIgogICAgbW9kZXMgPSAiLCAiLmpvaW4ob3V0cHV0X21vZGVzKSBpZiBvdXRwdXRfbW9kZXMgZWxzZSAidGV4dCIKICAgIHByb21wdCA9ICgKICAgICAgICAi5L2g5pivIFJldHJvQXJjaCBBSSBTZXJ2aWNlIOeahOWunuaXtuaXpeaWh+a4uOaIj+aIquWbviBPQ1Ig5LiO5Lit5paH57+76K+R5byV5pOO44CCXG4iCiAgICAgICAgZiLlvZPliY3lhoXlrrnmoIfnrb46IHtsYWJlbH1cbiIKICAgICAgICBmIuivt+axgui+k+WHuuaooeW8jzoge21vZGVzfVxuIgogICAgICAgIGYi5rqQ6K+t6KiAOiB7c291cmNlX2xhbmd9XG4iCiAgICAgICAgZiLnm67moIfor63oqIA6IHt0YXJnZXRfbGFuZ31cbiIKICAgICAgICAi6K+355u05o6l5p+l55yL6ZqP6ZmE5oiq5Zu+77yM6K+G5Yir55S76Z2i5Lit5omA5pyJ5Y+v6KeB5pel5paH5ri45oiP5paH5a2X77yM54S25ZCO57+76K+R5Li66Ieq54S244CB566A5rSB55qE566A5L2T5Lit5paH44CCXG4iCiAgICAgICAgIumHjeimgeaPkOekujog6L+Z5piv5p2l6Ieq5qih5ouf5Zmo77yI5aaCUmV0cm9BcmNoL1BTMS9TUy9EQ++8ieeahOS9juWIhui+qOeOh+a4uOaIj+aIquWbvu+8jOeUu+mdouWPr+iDveWtmOWcqOaJq+aPj+e6v+OAgeWDj+e0oOWMluOAgeiJsuWdl+WZqueCueWSjOS6pOmUmeS8quW9seOAguivt+W/veeVpeeUu+mdoumil+eykuaEn++8jOiBmueEpuS6juWPr+ivhuWIq+eahOaXpeaWh+aWh+Wtl+OAglxuIgogICAgICAgICLnlL**aLnibnlvoE6XG4iCiAgICAgICAgIi0g5a+56K+d5qGG6YCa5bi45L2N5LqO5bGP5bmV5bqV6YOo77yM5piv5Y2K6YCP5piO6IOM5pmv55qE5paH5a2X5qGG44CCXG4iCiAgICAgICAgIi0g5YW45Z6L5qC85byPOiDjgIzop5LoibLlkI3jgI3miJbop5LoibLlkI3lkI7ot5/lhpLlj7cv5o2i6KGM77yM54S25ZCO5piv5a+555m95YaF5a6577yM5Y+v6IO96Leo5aSa6KGM44CCXG4iCiAgICAgICAgIi0gUFMxIOaXtuS7o+a4uOaIj+WIhui+qOeOh+W+iOS9ju+8iDMyMMOXMjQwIOaIliA1MTLDlzI0MO+8ie+8jOaXpeaWh+aWh+Wtl+WDj+e0oOWMluS4pemHje+8jOmDqOWIhuWBh+WQjeWPr+iDveaooeeziuOAglxuIgogICAgICAgICItIOmZpOS6huW6lemDqOWvueivneahhu+8jOWxj+W5leS4iuaWueaIluS4reWkruS5n+WPr+iDveWHuueOsOezu+e7n+iPnOWNleOAgeeKtuaAgeagj+OAgemAiemhueaMiemSruetieaWh+Wtl+OAglxuIgogICAgICAgICLopoHmsYI6XG4iCiAgICAgICAgIjEuIOacrOacjeWKoeS4k+mXqOeUqOS6juaXpeaWh+a4uOaIj+axieWMlui+heWKqe+8m+m7mOiupOaKiuaIquWbvuS4reeahOaXpeaWh+e/u+ivkeaIkOeugOS9k+S4reaWh++8jOWNs+S9vyBzb3VyY2VfbGFuZyDlhpnnnYAgRG9uJ3QgY2FyZSDkuZ/mjInml6XmloflpITnkIbjgIJcbiIKICAgICAgICAiMi4g5LyY5YWI6K+G5Yir5bqV6YOo5a+56K+d5qGG5Lit55qE6KeS6Imy5ZCN5ZKM5a+555m977yM5YaN6K+G5Yir6I+c5Y2V44CB5oyJ6ZKu44CB54q25oCB5qCP562JIFVJIOaWh+Wtl+OAglxuIgogICAgICAgICIzLiDlr7nnmb3ljp/mlofkv53nlZnljp/lp4vmjaLooYznu5PmnoTvvIzop5LoibLlkI3kuI7lr7nnmb3nlKjjgIzjgI3miJblhpLlj7fliIbpmpTvvIzlpJrooYzlr7nnmb3nlKjmjaLooYznrKbliIbpmpTjgIJcbiIKICAgICAgICAiNC4g5b+955Wl5peg5oSP5LmJ5Zmq5aOw44CB5omr5o+P57q/44CB5Zu+5qCH44CB6L655qGG5ZKM6Z2e5paH5a2X57q555CG44CCXG4iCiAgICAgICAgIjUuIOe/u+ivkeimgeefre+8jOmAguWQiOWunuaXtuimhuebluaYvuekuu+8m+S/neeVmeinkuiJsuWQjeOAgeS4k+acieWQjeivjeWSjOaMiemSruivreawlO+8jOS4jeimgeino+mHiuOAglxuIgogICAgICAgICI2LiDop5LoibLlkI3lv4XpobvkuKXmoLzmjInnhafkuIvmlrnor43lhbjnv7vor5HvvIznpoHmraLoh6rooYznv7vor5Hop5LoibLlkI3jgIJcbiIKICAgICAgICAiNy4g5Y+q6L+U5Zue57Sn5YeRIEpTT07vvIzkuI3opoEgTWFya2Rvd27vvIzkuI3opoHku6PnoIHlnZfvvIzkuI3opoHpop3lpJbliY3nvIDjgIJcbiIKICAgICAgICAiOC4gSlNPTiDmoLzlvI/lv4XpobvmmK86IHtcIm9yaWdpbmFsXCI6XCLor4bliKvliLDnmoTml6Xmlofljp/mlofvvIjkv53nlZnmjaLooYzvvIlcIixcInRyYW5zbGF0aW9uXCI6XCLnroDkvZPkuK3mlofor5HmlofvvIjkv53nlZnmjaLooYzvvIlcIn1cbiIKICAgICAgICAiOS4g5aaC5p6c56Gu5a6e5rKh5pyJ5Y+v6K+75pel5paH5paH5a2X77yM6L+U5ZueIHtcIm9yaWdpbmFsXCI6XCJcIixcInRyYW5zbGF0aW9uXCI6XCJcIn3jgIJcbiIKICAgICkKICAgIGlmIGNoYXJhY3Rlcl9kaWN0OgogICAgICAgIGRpY3RfbGluZXMgPSAiXG4iLmpvaW4oZiIgIHtqcH0g4oaSIHt6aH0iIGZvciBqcCwgemggaW4gY2hhcmFjdGVyX2RpY3QuaXRlbXMoKSkKICAgICAgICBwcm9tcHQgKz0gZiJcbuinkuiJsuWQjeivjeWFuO+8iOaXpeaWhyDihpIg5Lit5paH77yM5b+F6aG75Lil5qC85L2/55So77yJOlxue2RpY3RfbGluZXN9XG4iCiAgICBpZiBjb250ZXh0X2hpc3Rvcnk6CiAgICAgICAgY3R4X2xpbmVzID0gW10KICAgICAgICBmb3IgaSwgZW50cnkgaW4gZW51bWVyYXRlKGNvbnRleHRfaGlzdG9yeVstODpdLCAxKToKICAgICAgICAgICAgb3JpZyA9IGVudHJ5LmdldCgib3JpZ2luYWwiLCAiIikucmVwbGFjZSgiXG4iLCAiIC8gIikKICAgICAgICAgICAgdHJhbnMgPSBlbnRyeS5nZXQoInRyYW5zbGF0aW9uIiwgIiIpLnJlcGxhY2UoIlxuIiwgIiAvICIpCiAgICAgICAgICAgIGN0eF9saW5lcy5hcHBlbmQoZiIgIFt7aX1dIHtvcmlnfSDihpIge3RyYW5zfSIpCiAgICAgICAgcHJvbXB0ICs9IGYiXG7mnIDov5Hnv7vor5HkuIrkuIvmlofvvIjkv53mjIHop5LoibLlkI3lkozpo47moLzkuIDoh7TvvIk6XG4iICsgIlxuIi5qb2luKGN0eF9saW5lcykgKyAiXG4iCiAgICByZXR1cm4gcHJvbXB0CgoKZGVmIGlzX2Nqa190ZXh0KHRleHQ6IHN0cikgLT4gYm9vbDoKICAgIHJldHVybiBib29sKHJlLnNlYXJjaChyIltcdTMwNDAtXHUzMGZmXHUzNDAwLVx1OWZmZlx1YWMwMC1cdWQ3YWZdIiwgdGV4dCBvciAiIikpCgoKZGVmIGdldF9yZXF1ZXN0ZWRfdGFyZ2V0X2xhbmd1YWdlKHRhcmdldF9sYW5nOiBzdHIsIGRlZmF1bHRfdGFyZ2V0X2xhbmd1YWdlOiBzdHIpIC0+IHN0cjoKICAgIHZhbHVlID0gbm9ybWFsaXplX3RleHQodGFyZ2V0X2xhbmcpIG9yIG5vcm1hbGl6ZV90ZXh0KGRlZmF1bHRfdGFyZ2V0X2xhbmd1YWdlKSBvciAiU2ltcGxpZmllZCBDaGluZXNlIgogICAgbG93ZXJlZCA9IHZhbHVlLmxvd2VyKCkKICAgIGlmIGxvd2VyZWQgaW4geyJkb24ndCBjYXJlIiwgImRvbnQgY2FyZSIsICJhdXRvIiwgImF1dG9tYXRpYyJ9OgogICAgICAgIHJldHVybiAiU2ltcGxpZmllZCBDaGluZXNlIgogICAgcmV0dXJuIHZhbHVlCgoKZGVmIGdldF9yZXF1ZXN0ZWRfc291cmNlX2xhbmd1YWdlKHNvdXJjZV9sYW5nOiBzdHIpIC0+IHN0cjoKICAgIHZhbHVlID0gbm9ybWFsaXplX3RleHQoc291cmNlX2xhbmcpIG9yICJKYXBhbmVzZSIKICAgIGxvd2VyZWQgPSB2YWx1ZS5sb3dlcigpCiAgICBpZiBsb3dlcmVkIGluIHsiZG9uJ3QgY2FyZSIsICJkb250IGNhcmUiLCAiYXV0byIsICJhdXRvbWF0aWMifToKICAgICAgICByZXR1cm4gIkphcGFuZXNlIgogICAgcmV0dXJuIHZhbHVlCgoKZGVmIGRlY29kZV9pbWFnZV9ieXRlcyhpbWFnZV9iNjQ6IHN0cikgLT4gYnl0ZXM6CiAgICBpZiBpbWFnZV9iNjQuc3RhcnRzd2l0aCgiZGF0YToiKToKICAgICAgICBfLCBfLCBpbWFnZV9iNjQgPSBpbWFnZV9iNjQucGFydGl0aW9uKCIsIikKICAgIHJldHVybiBiYXNlNjQuYjY0ZGVjb2RlKGltYWdlX2I2NCwgdmFsaWRhdGU9RmFsc2UpCgoKZGVmIHByZXByb2Nlc3NfaW1hZ2VfZm9yX29jcihyYXdfYnl0ZXM6IGJ5dGVzKSAtPiBBbnk6CiAgICBpZiBJbWFnZSBpcyBOb25lOgogICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcigiUGlsbG93IOacquWuieijhe+8jOaXoOazleaJp+ihjOacrOWcsCBPQ1LjgIIiKQogICAgd2l0aCBJbWFnZS5vcGVuKGlvLkJ5dGVzSU8ocmF3X2J5dGVzKSkgYXMgaW1nOgogICAgICAgIGltYWdlID0gaW1nLmNvbnZlcnQoIkwiKQogICAgIyDlhYjmlL7lpKflho3plJDljJbvvIzog73mmI7mmL7mlLnlloTmuLjmiI/miKrlm77ph4znmoTnu4blrZfor4bliKvnjofjgIIKICAgIHdpZHRoLCBoZWlnaHQgPSBpbWFnZS5zaXplCiAgICBpZiB3aWR0aCA+IDAgYW5kIGhlaWdodCA+IDA6CiAgICAgICAgc2NhbGUgPSAyIGlmIG1heCh3aWR0aCwgaGVpZ2h0KSA8IDE2MDAgZWxzZSAxCiAgICAgICAgaWYgc2NhbGUgPiAxOgogICAgICAgICAgICBpbWFnZSA9IGltYWdlLnJlc2l6ZSgod2lkdGggKiBzY2FsZSwgaGVpZ2h0ICogc2NhbGUpKQogICAgaWYgSW1hZ2VGaWx0ZXIgaXMgbm90IE5vbmU6CiAgICAgICAgaW1hZ2UgPSBpbWFnZS5maWx0ZXIoSW1hZ2VGaWx0ZXIuU0hBUlBFTikKICAgIGlmIEltYWdlT3BzIGlzIG5vdCBOb25lOgogICAgICAgIGltYWdlID0gSW1hZ2VPcHMuYXV0b2NvbnRyYXN0KGltYWdlKQogICAgcmV0dXJuIGltYWdlCgoKZGVmIHJlc2FtcGxlX2ZpbHRlcigpIC0+IEFueToKICAgIGlmIEltYWdlIGlzIE5vbmU6CiAgICAgICAgcmV0dXJuIE5vbmUKICAgIHRyeToKICAgICAgICByZXR1cm4gSW1hZ2UuUmVzYW1wbGluZy5MQU5DWk9TCiAgICBleGNlcHQgQXR0cmlidXRlRXJyb3I6CiAgICAgICAgcmV0dXJuIEltYWdlLkxBTkNaT1MKCgpkZWYgcHJlcGFyZV9pbWFnZV9mb3JfbGxtKGltYWdlX2I2NDogc3RyLCBpbWFnZV9mb3JtYXQ6IHN0ciwgY29uZmlnOiBkaWN0W3N0ciwgQW55XSkgLT4gdHVwbGVbc3RyLCBzdHIsIGRpY3Rbc3RyLCBBbnldXToKICAgIHNldHRpbmdzID0gY29uZmlnLmdldCgibGxtX2ltYWdlIiwge30pIG9yIHt9CiAgICBtYXhfd2lkdGggPSBpbnQoc2V0dGluZ3MuZ2V0KCJtYXhfd2lkdGgiLCAxMjgwKSBvciAxMjgwKQogICAgbWF4X2hlaWdodCA9IGludChzZXR0aW5ncy5nZXQoIm1heF9oZWlnaHQiLCA3MjApIG9yIDcyMCkKICAgIG91dHB1dF9mb3JtYXQgPSBub3JtYWxpemVfaW1hZ2VfbWltZV9mb3JtYXQoc2V0dGluZ3MuZ2V0KCJmb3JtYXQiKSBvciBpbWFnZV9mb3JtYXQgb3IgInBuZyIpCiAgICBtZXRhOiBkaWN0W3N0ciwgQW55XSA9IHsKICAgICAgICAibWF4X3dpZHRoIjogbWF4X3dpZHRoLAogICAgICAgICJtYXhfaGVpZ2h0IjogbWF4X2hlaWdodCwKICAgICAgICAicmVxdWVzdGVkX2Zvcm1hdCI6IG91dHB1dF9mb3JtYXQsCiAgICAgICAgInJlc2l6ZWQiOiBGYWxzZSwKICAgICAgICAicmVlbmNvZGVkIjogRmFsc2UsCiAgICB9CiAgICBpZiBJbWFnZSBpcyBOb25lOgogICAgICAgIG1ldGFbImVycm9yIl0gPSAiUGlsbG93IOacquWuieijhe+8jExMTSDlm77niYfljovnvKnot7Pov4fjgIIiCiAgICAgICAgbWV0YVsibGxtX2ltYWdlX2Zvcm1hdCJdID0gbm9ybWFsaXplX2ltYWdlX21pbWVfZm9ybWF0KGltYWdlX2Zvcm1hdCkKICAgICAgICBtZXRhWyJsbG1faW1hZ2VfYmFzZTY0X2NoYXJzIl0gPSBsZW4oaW1hZ2VfYjY0KQogICAgICAgIHJldHVybiBpbWFnZV9iNjQsIG5vcm1hbGl6ZV9pbWFnZV9taW1lX2Zvcm1hdChpbWFnZV9mb3JtYXQpLCBtZXRhCgogICAgcmF3X2J5dGVzID0gZGVjb2RlX2ltYWdlX2J5dGVzKGltYWdlX2I2NCkKICAgIHdpdGggSW1hZ2Uub3Blbihpby5CeXRlc0lPKHJhd19ieXRlcykpIGFzIGltZzoKICAgICAgICBvcmlnaW5hbF93aWR0aCwgb3JpZ2luYWxfaGVpZ2h0ID0gaW1nLnNpemUKICAgICAgICBtZXRhWyJvcmlnaW5hbF93aWR0aCJdID0gb3JpZ2luYWxfd2lkdGgKICAgICAgICBtZXRhWyJvcmlnaW5hbF9oZWlnaHQiXSA9IG9yaWdpbmFsX2hlaWdodAogICAgICAgIGFsbG93X3Vwc2NhbGUgPSBib29sKHNldHRpbmdzLmdldCgiYWxsb3dfdXBzY2FsZSIsIEZhbHNlKSkKICAgICAgICBzY2FsZV9jYW5kaWRhdGVzID0gWwogICAgICAgICAgICBtYXhfd2lkdGggLyBvcmlnaW5hbF93aWR0aCBpZiBvcmlnaW5hbF93aWR0aCA+IDAgZWxzZSAxLjAsCiAgICAgICAgICAgIG1heF9oZWlnaHQgLyBvcmlnaW5hbF9oZWlnaHQgaWYgb3JpZ2luYWxfaGVpZ2h0ID4gMCBlbHNlIDEuMCwKICAgICAgICBdCiAgICAgICAgc2NhbGUgPSBtaW4oc2NhbGVfY2FuZGlkYXRlcykgaWYgYWxsb3dfdXBzY2FsZSBlbHNlIG1pbigxLjAsICpzY2FsZV9jYW5kaWRhdGVzKQogICAgICAgIGltYWdlID0gaW1nLmNvcHkoKQogICAgICAgIG1ldGFbInVwc2NhbGVkIl0gPSBGYWxzZQogICAgICAgIGlmIGFicyhzY2FsZSAtIDEuMCkgPiAxZS02OgogICAgICAgICAgICBuZXdfc2l6ZSA9IChtYXgoMSwgaW50KG9yaWdpbmFsX3dpZHRoICogc2NhbGUpKSwgbWF4KDEsIGludChvcmlnaW5hbF9oZWlnaHQgKiBzY2FsZSkpKQogICAgICAgICAgICBpbWFnZSA9IGltYWdlLnJlc2l6ZShuZXdfc2l6ZSwgcmVzYW1wbGVfZmlsdGVyKCkpCiAgICAgICAgICAgIG1ldGFbInJlc2l6ZWQiXSA9IHNjYWxlIDwgMS4wCiAgICAgICAgICAgIG1ldGFbInVwc2NhbGVkIl0gPSBzY2FsZSA+IDEuMAogICAgICAgIG1ldGFbImxsbV93aWR0aCJdLCBtZXRhWyJsbG1faGVpZ2h0Il0gPSBpbWFnZS5zaXplCgogICAgICAgIGJ1ZmZlciA9IGlvLkJ5dGVzSU8oKQogICAgICAgIGlmIG91dHB1dF9mb3JtYXQgPT0gImpwZWciOgogICAgICAgICAgICBpZiBpbWFnZS5tb2RlIGluIHsiUkdCQSIsICJMQSJ9OgogICAgICAgICAgICAgICAgYmFja2dyb3VuZCA9IEltYWdlLm5ldygiUkdCIiwgaW1hZ2Uuc2l6ZSwgKDI1NSwgMjU1LCAyNTUpKQogICAgICAgICAgICAgICAgYWxwaGEgPSBpbWFnZS5nZXRjaGFubmVsKCJBIikgaWYgIkEiIGluIGltYWdlLmdldGJhbmRzKCkgZWxzZSBOb25lCiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLnBhc3RlKGltYWdlLmNvbnZlcnQoIlJHQkEiKSwgbWFzaz1hbHBoYSkKICAgICAgICAgICAgICAgIGltYWdlID0gYmFja2dyb3VuZAogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgaW1hZ2UgPSBpbWFnZS5jb252ZXJ0KCJSR0IiKQogICAgICAgICAgICBpbWFnZS5zYXZlKGJ1ZmZlciwgZm9ybWF0PSJKUEVHIiwgcXVhbGl0eT1pbnQoc2V0dGluZ3MuZ2V0KCJqcGVnX3F1YWxpdHkiLCA5Mikgb3IgOTIpLCBvcHRpbWl6ZT1UcnVlKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIG91dHB1dF9mb3JtYXQgPSAicG5nIgogICAgICAgICAgICBpZiBpbWFnZS5tb2RlIG5vdCBpbiB7IlJHQiIsICJSR0JBIiwgIkwiLCAiUCJ9OgogICAgICAgICAgICAgICAgaW1hZ2UgPSBpbWFnZS5jb252ZXJ0KCJSR0JBIikKICAgICAgICAgICAgaW1hZ2Uuc2F2ZShidWZmZXIsIGZvcm1hdD0iUE5HIiwgb3B0aW1pemU9VHJ1ZSkKCiAgICBlbmNvZGVkID0gYmFzZTY0LmI2NGVuY29kZShidWZmZXIuZ2V0dmFsdWUoKSkuZGVjb2RlKCJ1dGYtOCIpCiAgICAjIOWmguaenOWOn+WbvuW3sue7j+Wwj+S6jiBMTE0g55uu5qCH5bC65a+477yM5LiU6YeN57yW56CB5Y+N6ICM5pu05aSn77yM5bCx5L+d5oyB5Y6f5Zu+77yM6YG/5YWN4oCc5Y6L57yp4oCd5a+86Ie05Lyg6L6T6Iao6IOA44CCCiAgICBpZiBub3QgbWV0YVsicmVzaXplZCJdIGFuZCBsZW4oZW5jb2RlZCkgPiBsZW4oaW1hZ2VfYjY0KToKICAgICAgICBtZXRhWyJrZXB0X29yaWdpbmFsX3JlYXNvbiJdID0gInJlZW5jb2RlZF9pbWFnZV9pc19sYXJnZXIiCiAgICAgICAgbWV0YVsibGxtX2ltYWdlX2Zvcm1hdCJdID0gbm9ybWFsaXplX2ltYWdlX21pbWVfZm9ybWF0KGltYWdlX2Zvcm1hdCkKICAgICAgICBtZXRhWyJsbG1faW1hZ2VfYmFzZTY0X2NoYXJzIl0gPSBsZW4oaW1hZ2VfYjY0KQogICAgICAgIHJldHVybiBpbWFnZV9iNjQsIG5vcm1hbGl6ZV9pbWFnZV9taW1lX2Zvcm1hdChpbWFnZV9mb3JtYXQpLCBtZXRhCgogICAgbWV0YVsicmVlbmNvZGVkIl0gPSBUcnVlCiAgICBtZXRhWyJsbG1faW1hZ2VfZm9ybWF0Il0gPSBvdXRwdXRfZm9ybWF0CiAgICBtZXRhWyJsbG1faW1hZ2VfYmFzZTY0X2NoYXJzIl0gPSBsZW4oZW5jb2RlZCkKICAgIHJldHVybiBlbmNvZGVkLCBvdXRwdXRfZm9ybWF0LCBtZXRhCgoKZGVmIGNob29zZV9mb250X3BhdGgoKSAtPiBzdHIgfCBOb25lOgogICAgY2FuZGlkYXRlcyA9IFsKICAgICAgICAiL3Vzci9zaGFyZS9mb250cy9nb29nbGUtbm90by1jamsvTm90b1NhbnNDSkstUmVndWxhci50dGMiLAogICAgICAgICIvdXNyL3NoYXJlL2ZvbnRzL2dvb2dsZS1ub3RvLWNqay9Ob3RvU2Fuc0NKSy1SZWd1bGFyLnR0YyIsCiAgICAgICAgIi91c3Ivc2hhcmUvZm9udHMvZ29vZ2xlLW5vdG8tY2prL05vdG9TYW5zQ0pLc2MtUmVndWxhci5vdGYiLAogICAgICAgICIvdXNyL3NoYXJlL2ZvbnRzL2dvb2dsZS1ub3RvLWNqay9Ob3RvU2Fuc0NKS2pwLVJlZ3VsYXIub3RmIiwKICAgICAgICAiL3Vzci9zaGFyZS9mb250cy9kZWphdnUtc2Fucy1mb250cy9EZWphVnVTYW5zLnR0ZiIsCiAgICAgICAgIi91c3Ivc2hhcmUvZm9udHMvZGVqYXZ1LXNhbnMtZm9udHMvRGVqYVZ1U2Fuc0NvbmRlbnNlZC50dGYiLAogICAgXQogICAgZm9yIGNhbmRpZGF0ZSBpbiBjYW5kaWRhdGVzOgogICAgICAgIGlmIFBhdGgoY2FuZGlkYXRlKS5leGlzdHMoKToKICAgICAgICAgICAgcmV0dXJuIGNhbmRpZGF0ZQogICAgZmNfbWF0Y2ggPSBzaHV0aWwud2hpY2goImZjLW1hdGNoIikKICAgIGlmIGZjX21hdGNoOgogICAgICAgIGZvciBmYW1pbHkgaW4gKCJOb3RvIFNhbnMgQ0pLIFNDIiwgIk5vdG8gU2FucyBDSksgSlAiLCAiRGVqYVZ1IFNhbnMiKToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVzdWx0ID0gc3VicHJvY2Vzcy5ydW4oCiAgICAgICAgICAgICAgICAgICAgW2ZjX21hdGNoLCAiLWYiLCAiJXtmaWxlfVxuIiwgZmFtaWx5XSwKICAgICAgICAgICAgICAgICAgICBjaGVjaz1GYWxzZSwKICAgICAgICAgICAgICAgICAgICBjYXB0dXJlX291dHB1dD1UcnVlLAogICAgICAgICAgICAgICAgICAgIHRleHQ9VHJ1ZSwKICAgICAgICAgICAgICAgICAgICB0aW1lb3V0PTUsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBjYW5kaWRhdGUgPSByZXN1bHQuc3Rkb3V0LnN0cmlwKCkuc3BsaXRsaW5lcygpWzBdIGlmIHJlc3VsdC5zdGRvdXQuc3RyaXAoKSBlbHNlICIiCiAgICAgICAgICAgICAgICBpZiBjYW5kaWRhdGUgYW5kIFBhdGgoY2FuZGlkYXRlKS5leGlzdHMoKToKICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FuZGlkYXRlCiAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgcmV0dXJuIE5vbmUKCgpkZWYgbG9hZF9mb250KHNpemU6IGludCkgLT4gQW55OgogICAgaWYgSW1hZ2VGb250IGlzIE5vbmU6CiAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCJQaWxsb3cg5a2X5L2T5qih5Z2X5LiN5Y+v55So44CCIikKICAgIGZvbnRfcGF0aCA9IGNob29zZV9mb250X3BhdGgoKQogICAgaWYgZm9udF9wYXRoOgogICAgICAgIHRyeToKICAgICAgICAgICAgcmV0dXJuIEltYWdlRm9udC50cnVldHlwZShmb250X3BhdGgsIHNpemU9c2l6ZSkKICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICBwYXNzCiAgICByZXR1cm4gSW1hZ2VGb250LmxvYWRfZGVmYXVsdCgpCgoKZGVmIHdyYXBfdGV4dF9mb3Jfd2lkdGgoZHJhdzogQW55LCB0ZXh0OiBzdHIsIGZvbnQ6IEFueSwgbWF4X3dpZHRoOiBpbnQpIC0+IGxpc3Rbc3RyXToKICAgIGxpbmVzOiBsaXN0W3N0cl0gPSBbXQogICAgZm9yIHBhcmFncmFwaCBpbiAodGV4dCBvciAiIikuc3BsaXRsaW5lcygpIG9yIFsiIl06CiAgICAgICAgaWYgbm90IHBhcmFncmFwaC5zdHJpcCgpOgogICAgICAgICAgICBsaW5lcy5hcHBlbmQoIiIpCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgY3VycmVudCA9ICIiCiAgICAgICAgZm9yIGNoIGluIHBhcmFncmFwaDoKICAgICAgICAgICAgdHJpYWwgPSBjdXJyZW50ICsgY2gKICAgICAgICAgICAgbGVmdCwgdG9wLCByaWdodCwgYm90dG9tID0gZHJhdy50ZXh0YmJveCgoMCwgMCksIHRyaWFsLCBmb250PWZvbnQpCiAgICAgICAgICAgIGlmIHJpZ2h0IC0gbGVmdCA8PSBtYXhfd2lkdGggb3Igbm90IGN1cnJlbnQ6CiAgICAgICAgICAgICAgICBjdXJyZW50ID0gdHJpYWwKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGxpbmVzLmFwcGVuZChjdXJyZW50KQogICAgICAgICAgICAgICAgY3VycmVudCA9IGNoCiAgICAgICAgaWYgY3VycmVudDoKICAgICAgICAgICAgbGluZXMuYXBwZW5kKGN1cnJlbnQpCiAgICByZXR1cm4gbGluZXMgb3IgWyIiXQoKCmRlZiByZW5kZXJfb3ZlcmxheV9pbWFnZSh0cmFuc2xhdGVkX3RleHQ6IHN0ciwgdGFyZ2V0X2xhbmc6IHN0ciwgdmlld3BvcnQ6IHR1cGxlW2ludCwgaW50XSB8IE5vbmUgPSBOb25lKSAtPiBzdHI6CiAgICBpZiBJbWFnZSBpcyBOb25lIG9yIEltYWdlRHJhdyBpcyBOb25lOgogICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcigiUGlsbG93IOacquWuieijhe+8jOaXoOazlea4suafk+WbvuWDj+OAgiIpCiAgICB3aWR0aCwgaGVpZ2h0ID0gdmlld3BvcnQgaWYgdmlld3BvcnQgYW5kIHZpZXdwb3J0WzBdID4gMCBhbmQgdmlld3BvcnRbMV0gPiAwIGVsc2UgKDE5MjAsIDEwODApCiAgICBjYW52YXMgPSBJbWFnZS5uZXcoIlJHQkEiLCAod2lkdGgsIGhlaWdodCksICgwLCAwLCAwLCAwKSkKICAgIGRyYXcgPSBJbWFnZURyYXcuRHJhdyhjYW52YXMpCgogICAgYmFzZV9mb250X3NpemUgPSBtYXgoMjgsIG1pbig1OCwgaGVpZ2h0IC8vIDE4KSkKICAgIGZvbnQgPSBsb2FkX2ZvbnQoYmFzZV9mb250X3NpemUpCiAgICBwYWRkaW5nX3ggPSBtYXgoMjQsIHdpZHRoIC8vIDQwKQogICAgcGFkZGluZ195ID0gbWF4KDE4LCBoZWlnaHQgLy8gNjApCiAgICBtYXhfdGV4dF93aWR0aCA9IG1heCgyMjAsIHdpZHRoIC0gcGFkZGluZ194ICogMikKICAgIGxpbmVzID0gd3JhcF90ZXh0X2Zvcl93aWR0aChkcmF3LCB0cmFuc2xhdGVkX3RleHQuc3RyaXAoKSwgZm9udCwgbWF4X3RleHRfd2lkdGgpCiAgICBsaW5lX2JveGVzID0gW2RyYXcudGV4dGJib3goKDAsIDApLCBsaW5lIG9yICJBIiwgZm9udD1mb250KSBmb3IgbGluZSBpbiBsaW5lc10KICAgIGxpbmVfaGVpZ2h0ID0gbWF4KChib3hbM10gLSBib3hbMV0gZm9yIGJveCBpbiBsaW5lX2JveGVzKSwgZGVmYXVsdD1iYXNlX2ZvbnRfc2l6ZSkKICAgIGJsb2NrX2hlaWdodCA9IGxpbmVfaGVpZ2h0ICogbGVuKGxpbmVzKSArIHBhZGRpbmdfeSAqIDIKICAgIHkwID0gbWF4KDAsIGhlaWdodCAtIGJsb2NrX2hlaWdodCAtIHBhZGRpbmdfeSAqIDIpCiAgICB4MCA9IHBhZGRpbmdfeAogICAgeDEgPSB3aWR0aCAtIHBhZGRpbmdfeAogICAgeTEgPSBtaW4oaGVpZ2h0LCB5MCArIGJsb2NrX2hlaWdodCkKCiAgICBkcmF3LnJvdW5kZWRfcmVjdGFuZ2xlKCh4MCwgeTAsIHgxLCB5MSksIHJhZGl1cz1tYXgoMTIsIGJhc2VfZm9udF9zaXplIC8vIDMpLCBmaWxsPSgyNTUsIDIzNSwgNTksIDIzMCksIG91dGxpbmU9KDAsIDAsIDAsIDI1NSksIHdpZHRoPW1heCgzLCBiYXNlX2ZvbnRfc2l6ZSAvLyAxOCkpCiAgICBmaWxsID0gKDAsIDAsIDAsIDI1NSkKICAgIGN1cnNvcl95ID0geTAgKyBwYWRkaW5nX3kKICAgIGZvciBsaW5lIGluIGxpbmVzOgogICAgICAgIGRyYXcudGV4dCgoeDAgKyBwYWRkaW5nX3gsIGN1cnNvcl95KSwgbGluZSwgZmlsbD1maWxsLCBmb250PWZvbnQpCiAgICAgICAgY3Vyc29yX3kgKz0gbGluZV9oZWlnaHQKCiAgICBidWZmZXIgPSBpby5CeXRlc0lPKCkKICAgIGNhbnZhcy5zYXZlKGJ1ZmZlciwgZm9ybWF0PSJQTkciKQogICAgcmV0dXJuIGJhc2U2NC5iNjRlbmNvZGUoYnVmZmVyLmdldHZhbHVlKCkpLmRlY29kZSgidXRmLTgiKQoKCmRlZiBvY3JfaW1hZ2VfdGV4dChpbWFnZV9iNjQ6IHN0ciwgaW1hZ2VfZm9ybWF0OiBzdHIsIGNvbmZpZzogZGljdFtzdHIsIEFueV0pIC0+IHN0cjoKICAgIGlmIHB5dGVzc2VyYWN0IGlzIE5vbmU6CiAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCJweXRlc3NlcmFjdCDmnKrlronoo4XvvIzml6Dms5XmiafooYzmnKzlnLAgT0NS44CCIikKICAgIHJhd19ieXRlcyA9IGRlY29kZV9pbWFnZV9ieXRlcyhpbWFnZV9iNjQpCiAgICBpbWFnZSA9IHByZXByb2Nlc3NfaW1hZ2VfZm9yX29jcihyYXdfYnl0ZXMpCiAgICBvY3JfbGFuZyA9IG5vcm1hbGl6ZV90ZXh0KGNvbmZpZy5nZXQoIm9jciIsIHt9KS5nZXQoImxhbmciKSkgb3IgImVuZyIKICAgIG9jcl9jb25maWcgPSBub3JtYWxpemVfdGV4dChjb25maWcuZ2V0KCJvY3IiLCB7fSkuZ2V0KCJjb25maWciKSkgb3IgIi0tcHNtIDYiCiAgICB0cnk6CiAgICAgICAgdGV4dCA9IHB5dGVzc2VyYWN0LmltYWdlX3RvX3N0cmluZyhpbWFnZSwgbGFuZz1vY3JfbGFuZywgY29uZmlnPW9jcl9jb25maWcpCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoZiLmnKzlnLAgT0NSIOWksei0pToge2V4Y30iKSBmcm9tIGV4YwogICAgcmV0dXJuIG5vcm1hbGl6ZV90ZXh0KHRleHQpCgoKZGVmIGJ1aWxkX2NoYXRfcGF5bG9hZChjb25maWc6IGRpY3Rbc3RyLCBBbnldLCBvY3JfdGV4dDogc3RyLCBwcm9tcHRfdGV4dDogc3RyKSAtPiBkaWN0W3N0ciwgQW55XToKICAgIGFwaV9**cgPSBsbG1fY29uZmlnKGNvbmZpZykKICAgIHVzZXJfY29udGVudCA9IHByb21wdF90ZXh0CiAgICBpZiBvY3JfdGV4dDoKICAgICAgICB1c2VyX2NvbnRlbnQgKz0gIlxuXG5PQ1Lnu5Pmnpw6XG48PDxcbiIgKyBvY3JfdGV4dCArICJcbj4+PlxuIgogICAgZWxzZToKICAgICAgICB1c2VyX2NvbnRlbnQgKz0gIlxuXG5PQ1Lnu5PmnpzkuLrnqbrvvIzor7fnm7TmjqXov5Tlm57nqbrlrZfnrKbkuLLjgIIiCiAgICByZXR1cm4gewogICAgICAgICJtb2RlbCI6IGFwaV9**dbIm1vZGVsIl0sCiAgICAgICAgInN0cmVhbSI6IEZhbHNlLAogICAgICAgICJtYXhfY29tcGxldGlvbl90b2tlbnMiOiBpbnQoYXBpX2NmZy5nZXQoIm1heF9jb21wbGV0aW9uX3Rva2VucyIsIDUxMikpLAogICAgICAgICJtZXNzYWdlcyI6IFt7InJvbGUiOiAidXNlciIsICJjb250ZW50IjogdXNlcl9jb250ZW50fV0sCiAgICB9CgoKZGVmIG5vcm1hbGl6ZV9pbWFnZV9taW1lX2Zvcm1hdChpbWFnZV9mb3JtYXQ6IHN0cikgLT4gc3RyOgogICAgdmFsdWUgPSAoaW1hZ2VfZm9ybWF0IG9yICJwbmciKS5zdHJpcCgpLmxvd2VyKCkKICAgIGlmIHZhbHVlIGluIHsianBnIiwgImpwZWcifToKICAgICAgICByZXR1cm4gImpwZWciCiAgICBpZiB2YWx1ZSBpbiB7IndlYnAiLCAiZ2lmIiwgImJtcCJ9OgogICAgICAgIHJldHVybiB2YWx1ZQogICAgcmV0dXJuICJwbmciCgoKZGVmIGJ1aWxkX3Zpc3VhbF9jaGF0X3BheWxvYWQoY29uZmlnOiBkaWN0W3N0ciwgQW55XSwgaW1hZ2VfYjY0OiBzdHIsIGltYWdlX2Zvcm1hdDogc3RyLCBwcm9tcHRfdGV4dDogc3RyKSAtPiBkaWN0W3N0ciwgQW55XToKICAgIGFwaV9**cgPSBsbG1fY29uZmlnKGNvbmZpZykKICAgIGZtdCA9IG5vcm1hbGl6ZV9pbWFnZV9taW1lX2Zvcm1hdChpbWFnZV9mb3JtYXQpCiAgICBpbWFnZV91cmwgPSBpbWFnZV9iNjQgaWYgaW1hZ2VfYjY0LnN0YXJ0c3dpdGgoImRhdGE6IikgZWxzZSBmImRhdGE6aW1hZ2Uve2ZtdH07YmFzZTY0LHtpbWFnZV9iNjR9IgogICAgcGF5bG9hZCA9IHsKICAgICAgICAibW9kZWwiOiBhcGlfY2ZnWyJtb2RlbCJdLAogICAgICAgICJzdHJlYW0iOiBGYWxzZSwKICAgICAgICAibWF4X2NvbXBsZXRpb25fdG9rZW5zIjogaW50KGFwaV9**cuZ2V0KCJtYXhfY29tcGxldGlvbl90b2tlbnMiLCA1MTIpKSwKICAgICAgICAibWVzc2FnZXMiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJyb2xlIjogInVzZXIiLAogICAgICAgICAgICAgICAgImNvbnRlbnQiOiBbCiAgICAgICAgICAgICAgICAgICAgeyJ0eXBlIjogInRleHQiLCAidGV4dCI6IHByb21wdF90ZXh0fSwKICAgICAgICAgICAgICAgICAgICB7InR5cGUiOiAiaW1hZ2VfdXJsIiwgImltYWdlX3VybCI6IHsidXJsIjogaW1hZ2VfdXJsfX0sCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgIH0KICAgIHJlYXNvbmluZ19lZmZvcnQgPSBhcGlfY2ZnLmdldCgicmVhc29uaW5nX2VmZm9ydCIpCiAgICBpZiByZWFzb25pbmdfZWZmb3J0OgogICAgICAgIHBheWxvYWRbInJlYXNvbmluZyJdID0geyJlZmZvcnQiOiByZWFzb25pbmdfZWZmb3J0fQogICAgcmV0dXJuIHBheWxvYWQKCgpkZWYgcmVxdWVzdF9sbG1fY29tcGxldGlvbihjb25maWc6IGRpY3Rbc3RyLCBBbnldLCBhcGlfa2V5OiBzdHIsIHBheWxvYWQ6IGRpY3Rbc3RyLCBBbnldKSAtPiBkaWN0W3N0ciwgQW55XToKICAgIGFwaV9**cgPSBsbG1fY29uZmlnKGNvbmZpZykKICAgIGJhc2VfdXJsID0gYXBpX2NmZ1siYmFzZV91cmwiXS5yc3RyaXAoIi8iKQogICAgdXJsID0gZiJ7YmFzZV91cmx9L2NoYXQvY29tcGxldGlvbnMiCiAgICBib2R5ID0ganNvbi5kdW1wcyhwYXlsb2FkLCBlbnN1cmVfYXNjaWk9RmFsc2UpLmVuY29kZSgidXRmLTgiKQogICAgcmVxID0gdXJsbGliLnJlcXVlc3QuUmVxdWVzdCgKICAgICAgICB1cmwsCiAgICAgICAgZGF0YT1ib2R5LAogICAgICAgIG1ldGhvZD0iUE9TVCIsCiAgICAgICAgaGVhZGVycz17CiAgICAgICAgICAgICJBdXRob3JpemF0aW9uIjogZiJCZWFyZXIge2FwaV9rZXl9IiwKICAgICAgICAgICAgIkNvbnRlbnQtVHlwZSI6ICJhcHBsaWNhdGlvbi9qc29uIiwKICAgICAgICAgICAgIkFjY2VwdCI6ICJhcHBsaWNhdGlvbi9qc29uIiwKICAgICAgICAgICAgIlVzZXItQWdlbnQiOiAiUmV0cm9BcmNoLU9wZW5BSS1CcmlkZ2UvMS4wIiwKICAgICAgICB9LAogICAgKQogICAgdGltZW91dCA9IGZsb2F0KGFwaV9**cuZ2V0KCJyZXF1ZXN0X3RpbWVvdXRfc2Vjb25kcyIsIDE4MCkpCiAgICB0cnk6CiAgICAgICAgd2l0aCB1cmxsaWIucmVxdWVzdC51cmxvcGVuKHJlcSwgdGltZW91dD10aW1lb3V0KSBhcyByZXNwOgogICAgICAgICAgICByYXcgPSByZXNwLnJlYWQoKS5kZWNvZGUoInV0Zi04IiwgZXJyb3JzPSJyZXBsYWNlIikKICAgIGV4Y2VwdCB1cmxsaWIuZXJyb3IuSFRUUEVycm9yIGFzIGV4YzoKICAgICAgICBib2R5ID0gZXhjLnJlYWQoKS5kZWNvZGUoInV0Zi04IiwgZXJyb3JzPSJyZXBsYWNlIikgaWYgaGFzYXR0cihleGMsICJyZWFkIikgZWxzZSAiIgogICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcihmIk9wZW5BSSBBUEkgSFRUUCB7ZXhjLmNvZGV9OiB7Ym9keVs6MjAwMF19IikgZnJvbSBleGMKICAgIGV4Y2VwdCB1cmxsaWIuZXJyb3IuVVJMRXJyb3IgYXMgZXhjOgogICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcihmIk9wZW5BSSBBUEkg6K+35rGC5aSx6LSlOiB7ZXhjfSIpIGZyb20gZXhjCiAgICBkYXRhID0ganNvbi5sb2FkcyhyYXcpCiAgICBpZiBub3QgaXNpbnN0YW5jZShkYXRhLCBkaWN0KToKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoZiJPcGVuQUkgQVBJIOi/lOWbnueahOS4jeaYryBKU09OIOWvueixoToge3R5cGUoZGF0YSkuX19uYW1lX199IikKICAgIHJldHVybiBkYXRhCgoKZGVmIGV4dHJhY3RfbWVzc2FnZV90ZXh0KHJlc3BvbnNlX2pzb246IGRpY3Rbc3RyLCBBbnldKSAtPiBzdHI6CiAgICBjaG9pY2VzID0gcmVzcG9uc2VfanNvbi5nZXQoImNob2ljZXMiKSBvciBbXQogICAgaWYgbm90IGNob2ljZXM6CiAgICAgICAgcmV0dXJuICIiCiAgICBmaXJzdCA9IGNob2ljZXNbMF0gaWYgaXNpbnN0YW5jZShjaG9pY2VzWzBdLCBkaWN0KSBlbHNlIHt9CiAgICBtZXNzYWdlID0gZmlyc3QuZ2V0KCJtZXNzYWdlIikgaWYgaXNpbnN0YW5jZShmaXJzdCwgZGljdCkgZWxzZSB7fQogICAgaWYgaXNpbnN0YW5jZShtZXNzYWdlLCBkaWN0KToKICAgICAgICBjb250ZW50ID0gbWVzc2FnZS5nZXQoImNvbnRlbnQiKQogICAgICAgIGlmIGlzaW5zdGFuY2UoY29udGVudCwgc3RyKToKICAgICAgICAgICAgcmV0dXJuIGNvbnRlbnQuc3RyaXAoKQogICAgICAgIGlmIGlzaW5zdGFuY2UoY29udGVudCwgbGlzdCk6CiAgICAgICAgICAgIHBhcnRzOiBsaXN0W3N0cl0gPSBbXQogICAgICAgICAgICBmb3IgaXRlbSBpbiBjb250ZW50OgogICAgICAgICAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UoaXRlbSwgZGljdCk6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIGlmIGl0ZW0uZ2V0KCJ0eXBlIikgaW4geyJ0ZXh0IiwgIm91dHB1dF90ZXh0In0gYW5kIG5vcm1hbGl6ZV90ZXh0KGl0ZW0uZ2V0KCJ0ZXh0IikpOgogICAgICAgICAgICAgICAgICAgIHBhcnRzLmFwcGVuZChub3JtYWxpemVfdGV4dChpdGVtLmdldCgidGV4dCIpKSkKICAgICAgICAgICAgICAgIGVsaWYgbm9ybWFsaXplX3RleHQoaXRlbS5nZXQoImNvbnRlbnQiKSk6CiAgICAgICAgICAgICAgICAgICAgcGFydHMuYXBwZW5kKG5vcm1hbGl6ZV90ZXh0KGl0ZW0uZ2V0KCJjb250ZW50IikpKQogICAgICAgICAgICBpZiBwYXJ0czoKICAgICAgICAgICAgICAgIHJldHVybiAiXG4iLmpvaW4ocGFydHMpLnN0cmlwKCkKICAgICAgICBpZiBub3JtYWxpemVfdGV4dChtZXNzYWdlLmdldCgidGV4dCIpKToKICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZV90ZXh0KG1lc3NhZ2UuZ2V0KCJ0ZXh0IikpCiAgICBpZiBpc2luc3RhbmNlKGZpcnN0LCBkaWN0KSBhbmQgbm9ybWFsaXplX3RleHQoZmlyc3QuZ2V0KCJ0ZXh0IikpOgogICAgICAgIHJldHVybiBub3JtYWxpemVfdGV4dChmaXJzdC5nZXQoInRleHQiKSkKICAgIHJldHVybiAiIgoKCmRlZiBzdHJpcF9tYXJrZG93bl9qc29uX2ZlbmNlKHRleHQ6IHN0cikgLT4gc3RyOgogICAgdmFsdWUgPSBub3JtYWxpemVfdGV4dCh0ZXh0KQogICAgaWYgdmFsdWUuc3RhcnRzd2l0aCgiYGBgIik6CiAgICAgICAgdmFsdWUgPSByZS5zdWIociJeYGBgKD86anNvbik/XHMqIiwgIiIsIHZhbHVlLCBmbGFncz1yZS5JKQogICAgICAgIHZhbHVlID0gcmUuc3ViKHIiXHMqYGBgJCIsICIiLCB2YWx1ZSkKICAgIHJldHVybiB2YWx1ZS5zdHJpcCgpCgoKZGVmIGV4dHJhY3RfZmlyc3RfanNvbl9vYmplY3QodGV4dDogc3RyKSAtPiBzdHI6CiAgICB2YWx1ZSA9IHN0cmlwX21hcmtkb3duX2pzb25fZmVuY2UodGV4dCkKICAgIGlmIHZhbHVlLnN0YXJ0c3dpdGgoInsiKSBhbmQgdmFsdWUuZW5kc3dpdGgoIn0iKToKICAgICAgICByZXR1cm4gdmFsdWUKICAgIHN0YXJ0ID0gdmFsdWUuZmluZCgieyIpCiAgICBlbmQgPSB2YWx1ZS5yZmluZCgifSIpCiAgICBpZiBzdGFydCA+PSAwIGFuZCBlbmQgPiBzdGFydDoKICAgICAgICByZXR1cm4gdmFsdWVbc3RhcnQgOiBlbmQgKyAxXQogICAgcmV0dXJuICIiCgoKZGVmIHBhcnNlX3Zpc3VhbF90cmFuc2xhdGlvbihjb250ZW50OiBzdHIpIC0+IHR1cGxlW3N0ciwgc3RyXToKICAgIHZhbHVlID0gbm9ybWFsaXplX3RleHQoY29udGVudCkKICAgIGpzb25fdGV4dCA9IGV4dHJhY3RfZmlyc3RfanNvbl9vYmplY3QodmFsdWUpCiAgICBpZiBqc29uX3RleHQ6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBkYXRhID0ganNvbi5sb2Fkcyhqc29uX3RleHQpCiAgICAgICAgICAgIGlmIGlzaW5zdGFuY2UoZGF0YSwgZGljdCk6CiAgICAgICAgICAgICAgICBvcmlnaW5hbCA9IG5vcm1hbGl6ZV90ZXh0KGRhdGEuZ2V0KCJvcmlnaW5hbCIpIG9yIGRhdGEuZ2V0KCJvY3IiKSBvciBkYXRhLmdldCgic291cmNlIikpCiAgICAgICAgICAgICAgICB0cmFuc2xhdGlvbiA9IG5vcm1hbGl6ZV90ZXh0KGRhdGEuZ2V0KCJ0cmFuc2xhdGlvbiIpIG9yIGRhdGEuZ2V0KCJ0cmFuc2xhdGVkX3RleHQiKSBvciBkYXRhLmdldCgidGV4dCIpKQogICAgICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsLCB0cmFuc2xhdGlvbgogICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgIHBhc3MKICAgIHJldHVybiAiIiwgdmFsdWUKCgpkZWYgbG9va3NfbGlrZV92aXNpb25fZmFpbHVyZShvcmlnaW5hbF90ZXh0OiBzdHIsIHRyYW5zbGF0ZWRfdGV4dDogc3RyKSAtPiBib29sOgogICAgY29tYmluZWQgPSBmIntvcmlnaW5hbF90ZXh0fVxue3RyYW5zbGF0ZWRfdGV4dH0iLmxvd2VyKCkKICAgIGZhaWx1cmVfbWFya2VycyA9IFsKICAgICAgICAi55yL5LiN5Yiw5Zu+54mHIiwKICAgICAgICAi5peg5rOV5p+l55yL5Zu+54mHIiwKICAgICAgICAi5LiN6IO95p+l55yL5Zu+54mHIiwKICAgICAgICAi5peg5rOV6K+G5Yir5Zu+54mHIiwKICAgICAgICAiaSBjYW4ndCBzZWUiLAogICAgICAgICJpIGNhbm5vdCBzZWUiLAogICAgICAgICJjYW4ndCB2aWV3IiwKICAgICAgICAiY2Fubm90IHZpZXciLAogICAgICAgICJ1bmFibGUgdG8gdmlldyIsCiAgICAgICAgIm5vIGltYWdlIiwKICAgIF0KICAgIHJldHVybiBhbnkobWFya2VyIGluIGNvbWJpbmVkIGZvciBtYXJrZXIgaW4gZmFpbHVyZV9tYXJrZXJzKQoKCmRlZiBlc3RpbWF0ZV9xdW90YV91bml0cyhjb25maWc6IGRpY3Rbc3RyLCBBbnldLCBwcm9tcHRfdGV4dDogc3RyLCBpbWFnZV9iNjQ6IHN0cikgLT4gZmxvYXQ6CiAgICBhcGlfY2ZnID0gbGxtX2NvbmZpZyhjb25maWcpCiAgICBwcm9tcHRfdG9rZW5zID0gdG9rZW5fY291bnRfZXN0aW1hdGUocHJvbXB0X3RleHQpICsgaW1hZ2VfdG9rZW5fZXN0aW1hdGUoaW1hZ2VfYjY0KQogICAgbWF4X2NvbXBsZXRpb25fdG9rZW5zID0gaW50KGFwaV9**cuZ2V0KCJtYXhfY29tcGxldGlvbl90b2tlbnMiLCA1MTIpKQogICAgcHJvbXB0X3Blcl9tdG9rZW4gPSBmbG9hdChhcGlfY2ZnLmdldCgicHJvbXB0X3Blcl9tdG9rZW4iLCAwLjApKQogICAgY29tcGxldGlvbl9wZXJfbXRva2VuID0gZmxvYXQoYXBpX2NmZy5nZXQoImNvbXBsZXRpb25fcGVyX210b2tlbiIsIDAuMCkpCiAgICBzYWZldHkgPSAxLjIKICAgIHByb21wdF91bml0cyA9IHByb21wdF90b2tlbnMgLyAxXzAwMF8wMDAuMCAqIHByb21wdF9wZXJfbXRva2VuCiAgICBjb21wbGV0aW9uX3VuaXRzID0gbWF4X2NvbXBsZXRpb25fdG9rZW5zIC8gMV8wMDBfMDAwLjAgKiBjb21wbGV0aW9uX3Blcl9tdG9rZW4KICAgIHJldHVybiAocHJvbXB0X3VuaXRzICsgY29tcGxldGlvbl91bml0cykgKiBzYWZldHkKCgpkZWYgYWN0dWFsX3F1b3RhX3VuaXRzKGNvbmZpZzogZGljdFtzdHIsIEFueV0sIHVzYWdlOiBkaWN0W3N0ciwgQW55XSB8IE5vbmUsIHJlc2VydmVkX3VuaXRzOiBmbG9hdCkgLT4gZmxvYXQ6CiAgICBpZiBpc2luc3RhbmNlKHVzYWdlLCBkaWN0KToKICAgICAgICBwcm9tcHRfdG9rZW5zID0gaW50KHVzYWdlLmdldCgicHJvbXB0X3Rva2VucyIpIG9yIDApCiAgICAgICAgY29tcGxldGlvbl90b2tlbnMgPSBpbnQodXNhZ2UuZ2V0KCJjb21wbGV0aW9uX3Rva2VucyIpIG9yIDApCiAgICAgICAgaWYgcHJvbXB0X3Rva2VucyBvciBjb21wbGV0aW9uX3Rva2VuczoKICAgICAgICAgICAgYXBpX2NmZyA9IGxsbV9jb25maWcoY29uZmlnKQogICAgICAgICAgICBwcm9tcHRfcGVyX210b2tlbiA9IGZsb2F0KGFwaV9**cuZ2V0KCJwcm9tcHRfcGVyX210b2tlbiIsIDAuMCkpCiAgICAgICAgICAgIGNvbXBsZXRpb25fcGVyX210b2tlbiA9IGZsb2F0KGFwaV9**cuZ2V0KCJjb21wbGV0aW9uX3Blcl9tdG9rZW4iLCAwLjApKQogICAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgcHJvbXB0X3Rva2VucyAvIDFfMDAwXzAwMC4wICogcHJvbXB0X3Blcl9tdG9rZW4KICAgICAgICAgICAgICAgICsgY29tcGxldGlvbl90b2tlbnMgLyAxXzAwMF8wMDAuMCAqIGNvbXBsZXRpb25fcGVyX210b2tlbgogICAgICAgICAgICApCiAgICByZXR1cm4gcmVzZXJ2ZWRfdW5pdHMKCgpjbGFzcyBSZXRyb0FyY2hCcmlkZ2VIYW5kbGVyKEJhc2VIVFRQUmVxdWVzdEhhbmRsZXIpOgogICAgc2VydmVyX3ZlcnNpb24gPSAiUmV0cm9BcmNoT3BlbkFJQnJpZGdlLzEuMCIKCiAgICBAcHJvcGVydHkKICAgIGRlZiBicmlkZ2Uoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuc2VydmVyLmJyaWRnZSAgIyB0eXBlOiBpZ25vcmVbYXR0ci1kZWZpbmVkXQoKICAgIGRlZiBfc2VuZF9qc29uKHNlbGYsIHBheWxvYWQ6IGRpY3Rbc3RyLCBBbnldLCBzdGF0dXM6IGludCA9IDIwMCkgLT4gTm9uZToKICAgICAgICByYXcgPSBqc29uLmR1bXBzKHBheWxvYWQsIGVuc3VyZV9hc2NpaT1GYWxzZSkuZW5jb2RlKCJ1dGYtOCIpCiAgICAgICAgc2VsZi5zZW5kX3Jlc3BvbnNlKHN0YXR1cykKICAgICAgICBzZWxmLnNlbmRfaGVhZGVyKCJDb250ZW50LVR5cGUiLCAiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOCIpCiAgICAgICAgc2VsZi5zZW5kX2hlYWRlcigiQ29udGVudC1MZW5ndGgiLCBzdHIobGVuKHJhdykpKQogICAgICAgIHNlbGYuc2VuZF9oZWFkZXIoIkNhY2hlLUNvbnRyb2wiLCAibm8tc3RvcmUiKQogICAgICAgIHNlbGYuZW5kX2hlYWRlcnMoKQogICAgICAgIHNlbGYud2ZpbGUud3JpdGUocmF3KQoKICAgIGRlZiBfcmVhZF9qc29uKHNlbGYpIC0+IGRpY3Rbc3RyLCBBbnldOgogICAgICAgIGxlbmd0aCA9IGludChzZWxmLmhlYWRlcnMuZ2V0KCJDb250ZW50LUxlbmd0aCIpIG9yIDApCiAgICAgICAgYm9keSA9IHNlbGYucmZpbGUucmVhZChsZW5ndGgpIGlmIGxlbmd0aCA+IDAgZWxzZSBiInt9IgogICAgICAgIHRyeToKICAgICAgICAgICAgZGF0YSA9IGpzb24ubG9hZHMoYm9keS5kZWNvZGUoInV0Zi04IikpCiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBleGM6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZiLor7fmsYLkvZPkuI3mmK/lkIjms5UgSlNPTjoge2V4Y30iKSBmcm9tIGV4YwogICAgICAgIGlmIG5vdCBpc2luc3RhbmNlKGRhdGEsIGRpY3QpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCLor7fmsYLkvZPlv4XpobvmmK8gSlNPTiDlr7nosaEiKQogICAgICAgIHJldHVybiBkYXRhCgogICAgZGVmIGxvZ19tZXNzYWdlKHNlbGYsIGZvcm1hdDogc3RyLCAqYXJnczogQW55KSAtPiBOb25lOgogICAgICAgIGxvZyhmIntzZWxmLmNsaWVudF9hZGRyZXNzWzBdfSAtIHtmb3JtYXQgJSBhcmdzfSIpCgogICAgZGVmIGRvX0dFVChzZWxmKSAtPiBOb25lOgogICAgICAgIHBhcnNlZCA9IHVybGxpYi5wYXJzZS51cmxzcGxpdChzZWxmLnBhdGgpCiAgICAgICAgaWYgcGFyc2VkLnBhdGggaW4geyIvIiwgIi9oZWFsdGgifToKICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKHNlbGYuYnJpZGdlLmhlYWx0aF9wYXlsb2FkKCkpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlmIHBhcnNlZC5wYXRoIGluIHsiL3dob2FtaSIsICIvY2xpZW50LWlwIn06CiAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbigKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAic3RhdHVzIjogIm9rIiwKICAgICAgICAgICAgICAgICAgICAiY2xpZW50X2lwIjogc2VsZi5jbGllbnRfYWRkcmVzc1swXSwKICAgICAgICAgICAgICAgICAgICAidXNlcl9hZ2VudCI6IG5vcm1hbGl6ZV90ZXh0KHNlbGYuaGVhZGVycy5nZXQoIlVzZXItQWdlbnQiKSksCiAgICAgICAgICAgICAgICAgICAgInBhdGgiOiBwYXJzZWQucGF0aCwKICAgICAgICAgICAgICAgICAgICAidHMiOiBkdC5kYXRldGltZS5ub3coUFJFRkVSUkVEX1RaKS5pc29mb3JtYXQoKSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBpZiBwYXJzZWQucGF0aCA9PSAiL21ldHJpY3MiOgogICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24oc2VsZi5icmlkZ2UubWV0cmljc19wYXlsb2FkKCkpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlmIHBhcnNlZC5wYXRoID09ICIvbGFzdCI6CiAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbihzZWxmLmJyaWRnZS5sYXRlc3RfcGF5bG9hZCgpKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBpZiBwYXJzZWQucGF0aCBpbiB7Ii9sYXN0LWF0dGVtcHQiLCAiL2xhc3RfYXR0ZW1wdCJ9OgogICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24oc2VsZi5icmlkZ2UubGF0ZXN0X2F0dGVtcHRfcGF5bG9hZCgpKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBzZWxmLl9zZW5kX2pzb24oeyJlcnJvciI6ICJub3RfZm91bmQiLCAicGF0aCI6IHBhcnNlZC5wYXRofSwgc3RhdHVzPTQwNCkKCiAgICBkZWYgZG9fUE9TVChzZWxmKSAtPiBOb25lOgogICAgICAgIHBhcnNlZCA9IHVybGxpYi5wYXJzZS51cmxzcGxpdChzZWxmLnBhdGgpCiAgICAgICAgcXVlcnkgPSB1cmxsaWIucGFyc2UucGFyc2VfcXMocGFyc2VkLnF1ZXJ5KQogICAgICAgIGF0dGVtcHRfYmFzZSA9IHsKICAgICAgICAgICAgInN0YXR1cyI6ICJzZWVuIiwKICAgICAgICAgICAgImNsaWVudF9pcCI6IHNlbGYuY2xpZW50X2FkZHJlc3NbMF0sCiAgICAgICAgICAgICJwYXRoIjogcGFyc2VkLnBhdGgsCiAgICAgICAgICAgICJxdWVyeSI6IHtrZXk6IHZhbHVlIGZvciBrZXksIHZhbHVlIGluIHF1ZXJ5Lml0ZW1zKCl9LAogICAgICAgICAgICAiY29udGVudF9sZW5ndGgiOiBpbnQoc2VsZi5oZWFkZXJzLmdldCgiQ29udGVudC1MZW5ndGgiKSBvciAwKSwKICAgICAgICAgICAgImNvbnRlbnRfdHlwZSI6IG5vcm1hbGl6ZV90ZXh0KHNlbGYuaGVhZGVycy5nZXQoIkNvbnRlbnQtVHlwZSIpKSwKICAgICAgICAgICAgInVzZXJfYWdlbnQiOiBub3JtYWxpemVfdGV4dChzZWxmLmhlYWRlcnMuZ2V0KCJVc2VyLUFnZW50IikpLAogICAgICAgIH0KICAgICAgICBzZWxmLmJyaWRnZS5yZWNvcmRfcG9zdF9hdHRlbXB0KGF0dGVtcHRfYmFzZSkKICAgICAgICBpZiBwYXJzZWQucGF0aCBub3QgaW4geyIvIiwgIi90cmFuc2xhdGUiLCAiL2FpLXNlcnZpY2UifToKICAgICAgICAgICAgc2VsZi5icmlkZ2UucmVjb3JkX3Bvc3RfYXR0ZW1wdCh7KiphdHRlbXB0X2Jhc2UsICJzdGF0dXMiOiAibm90X2ZvdW5kIn0pCiAgICAgICAgICAgIHNlbGYuX3NlbmRfanNvbih7ImVycm9yIjogIm5vdF9mb3VuZCIsICJwYXRoIjogcGFyc2VkLnBhdGh9LCBzdGF0dXM9NDA0KQogICAgICAgICAgICByZXR1cm4KICAgICAgICB0cnk6CiAgICAgICAgICAgIHBheWxvYWQgPSBzZWxmLl9yZWFkX2pzb24oKQogICAgICAgICAgICBzZWxmLmJyaWRnZS5yZWNvcmRfcG9zdF9hdHRlbXB0KHsqKmF0dGVtcHRfYmFzZSwgInN0YXR1cyI6ICJqc29uX29rIiwgImpzb25fa2V5cyI6IHNvcnRlZChzdHIoa2V5KSBmb3Iga2V5IGluIHBheWxvYWQua2V5cygpKX0pCiAgICAgICAgICAgIHJlc3BvbnNlID0gc2VsZi5icmlkZ2UuaGFuZGxlX3JldHJvYXJjaF9yZXF1ZXN0KAogICAgICAgICAgICAgICAgc2VsZi5oZWFkZXJzLAogICAgICAgICAgICAgICAgcGF5bG9hZCwKICAgICAgICAgICAgICAgIHBhcnNlZC5wYXRoLAogICAgICAgICAgICAgICAgcXVlcnksCiAgICAgICAgICAgICAgICBzZWxmLmNsaWVudF9hZGRyZXNzWzBdLAogICAgICAgICAgICApCiAgICAgICAgICAgIHNlbGYuYnJpZGdlLnJlY29yZF9wb3N0X2F0dGVtcHQoeyoqYXR0ZW1wdF9iYXNlLCAic3RhdHVzIjogImhhbmRsZWRfb2sifSkKICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKHJlc3BvbnNlLCBzdGF0dXM9MjAwKQogICAgICAgIGV4Y2VwdCBRdW90YUV4Y2VlZGVkRXJyb3IgYXMgZXhjOgogICAgICAgICAgICBzZWxmLmJyaWRnZS5yZWNvcmRfcG9zdF9hdHRlbXB0KHsqKmF0dGVtcHRfYmFzZSwgInN0YXR1cyI6ICJxdW90YV9leGNlZWRlZCIsICJlcnJvciI6IHN0cihleGMpfSkKICAgICAgICAgICAgc2VsZi5fc2VuZF9qc29uKHsiZXJyb3IiOiBzdHIoZXhjKSwgImF1dG8iOiAiY29udGludWUifSwgc3RhdHVzPTQyOSkKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKICAgICAgICAgICAgbG9nKCLinYwg6K+35rGC5aSE55CG5aSx6LSlOlxuIiArIHRyYWNlYmFjay5mb3JtYXRfZXhjKCkpCiAgICAgICAgICAgIHNlbGYuYnJpZGdlLnJlY29yZF9wb3N0X2F0dGVtcHQoeyoqYXR0ZW1wdF9iYXNlLCAic3RhdHVzIjogImVycm9yIiwgImVycm9yIjogc3RyKGV4Yyl9KQogICAgICAgICAgICBzZWxmLl9zZW5kX2pzb24oeyJlcnJvciI6IHN0cihleGMpfSwgc3RhdHVzPTUwMCkKCgpjbGFzcyBRdW90YUV4Y2VlZGVkRXJyb3IoUnVudGltZUVycm9yKToKICAgIHBhc3MKCgpjbGFzcyBSZXRyb0FyY2hPcGVuQUlCcmlkZ2U6CiAgICBkZWYgX19pbml0X18oc2VsZiwgY29uZmlnOiBkaWN0W3N0ciwgQW55XSk6CiAgICAgICAgc2VsZi5jb25maWcgPSBjb25maWcKICAgICAgICBzZWxmLmxvY2sgPSB0aHJlYWRpbmcuTG9jaygpCiAgICAgICAgcXVvdGFfZmlsZSA9IFBST0pFQ1RfUk9PVCAvIGNvbmZpZ1sic3RhdGUiXVsicXVvdGFfZmlsZSJdCiAgICAgICAgYXBpX2NmZyA9IGxsbV9jb25maWcoY29uZmlnKQogICAgICAgIHNlbGYucXVvdGEgPSBEYWlseVF1b3RhU3RvcmUocXVvdGFfZmlsZSwgYXBpX2NmZ1siZGFpbHlfY3JlZGl0X2xpbWl0Il0pCiAgICAgICAgc2VsZi5hcGlfa2V5ID0gbG9hZF9sbG1fYXBpX2tleShjb25maWcpCiAgICAgICAgc2VsZi5yZXF1ZXN0X2NvdW50ID0gMAogICAgICAgIHNlbGYuc3VjY2Vzc19jb3VudCA9IDAKICAgICAgICBzZWxmLmVycm9yX2NvdW50ID0gMAogICAgICAgIHNlbGYuc3RhcnRfdHMgPSB0aW1lLnRpbWUoKQogICAgICAgIHNlbGYubGF0ZXN0X3JlcXVlc3RfcGF0aCA9IFBST0pFQ1RfUk9PVCAvICJyZXN1bHQiIC8gImxhdGVzdF9yZXF1ZXN0Lmpzb24iCiAgICAgICAgc2VsZi5yZXF1ZXN0X2hpc3RvcnlfcGF0aCA9IFBST0pFQ1RfUk9PVCAvICJyZXN1bHQiIC8gInJlcXVlc3RzLmpzb25sIgogICAgICAgIHNlbGYubGF0ZXN0X2F0dGVtcHRfcGF0aCA9IFBST0pFQ1RfUk9PVCAvICJyZXN1bHQiIC8gImxhdGVzdF9wb3N0X2F0dGVtcHQuanNvbiIKICAgICAgICBzZWxmLmF0dGVtcHRfaGlzdG9yeV9wYXRoID0gUFJPSkVDVF9ST09UIC8gInJlc3VsdCIgLyAicG9zdF9hdHRlbXB0cy5qc29ubCIKICAgICAgICBzZWxmLmltYWdlX2NvdW50ZXIgPSAwCiAgICAgICAgc2VsZi5sYXN0X2ltYWdlc19kaXIgPSBQUk9KRUNUX1JPT1QgLyBjb25maWdbInN0YXRlIl0uZ2V0KCJsYXN0X2ltYWdlc19kaXIiLCAiY2FjaGUvbGFzdF9pbWFnZXMiKQogICAgICAgIHNlbGYubGFzdF9pbWFnZXNfY291bnQgPSBpbnQoY29uZmlnWyJzdGF0ZSJdLmdldCgibGFzdF9pbWFnZXNfY291bnQiLCAxMCkpCiAgICAgICAgc2VsZi5jaGFyYWN0ZXJfZGljdDogZGljdFtzdHIsIHN0cl0gPSBjb25maWcuZ2V0KCJjaGFyYWN0ZXJfZGljdCIsIHt9KQogICAgICAgIHNlbGYuY29udGV4dF9oaXN0b3J5OiBsaXN0W2RpY3Rbc3RyLCBzdHJdXSA9IFtdCiAgICAgICAgc2VsZi5jb250ZXh0X21heCA9IGludChjb25maWcuZ2V0KCJjb250ZXh0X21heCIsIDgpKQoKICAgIGRlZiBoZWFsdGhfcGF5bG9hZChzZWxmKSAtPiBkaWN0W3N0ciwgQW55XToKICAgICAgICBzbmFwID0gc2VsZi5xdW90YS5zbmFwc2hvdCgpCiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgInN0YXR1cyI6ICJvayIsCiAgICAgICAgICAgICJzZXJ2aWNlIjogInJldHJvYXJjaF9vcGVuYWlfYnJpZGdlIiwKICAgICAgICAgICAgIm1vZGVsIjogbGxtX2NvbmZpZyhzZWxmLmNvbmZpZylbIm1vZGVsIl0sCiAgICAgICAgICAgICJwcm92aWRlciI6IGxsbV9jb25maWcoc2VsZi5jb25maWcpLmdldCgicHJvdmlkZXIiLCAib3BlbmFpIiksCiAgICAgICAgICAgICJvY3IiOiB7CiAgICAgICAgICAgICAgICAicGlsbG93IjogSW1hZ2UgaXMgbm90IE5vbmUsCiAgICAgICAgICAgICAgICAicHl0ZXNzZXJhY3QiOiBweXRlc3NlcmFjdCBpcyBub3QgTm9uZSwKICAgICAgICAgICAgICAgICJ0ZXNzZXJhY3RfYmluYXJ5IjogYm9vbChzaHV0aWwud2hpY2goInRlc3NlcmFjdCIpKSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgImxpbWl0Ijogc2VsZi5xdW90YS5saW1pdCwKICAgICAgICAgICAgImRheSI6IHNuYXAuZGF5LAogICAgICAgICAgICAic3BlbnQiOiByb3VuZChzbmFwLnNwZW50LCA2KSwKICAgICAgICAgICAgInJlc2VydmVkIjogcm91bmQoc25hcC5yZXNlcnZlZCwgNiksCiAgICAgICAgICAgICJyZW1haW5pbmciOiByb3VuZChtYXgoMC4wLCBzZWxmLnF1b3RhLmxpbWl0IC0gc25hcC5zcGVudCAtIHNuYXAucmVzZXJ2ZWQpLCA2KSwKICAgICAgICAgICAgInJlcXVlc3RzIjogc2VsZi5yZXF1ZXN0X2NvdW50LAogICAgICAgICAgICAic3VjY2VzcyI6IHNlbGYuc3VjY2Vzc19jb3VudCwKICAgICAgICAgICAgImVycm9ycyI6IHNlbGYuZXJyb3JfY291bnQsCiAgICAgICAgICAgICJ1cHRpbWVfc2Vjb25kcyI6IHJvdW5kKHRpbWUudGltZSgpIC0gc2VsZi5zdGFydF90cywgMiksCiAgICAgICAgfQoKICAgIGRlZiBtZXRyaWNzX3BheWxvYWQoc2VsZikgLT4gZGljdFtzdHIsIEFueV06CiAgICAgICAgcmV0dXJuIHNlbGYuaGVhbHRoX3BheWxvYWQoKQoKICAgIGRlZiBsYXRlc3RfcGF5bG9hZChzZWxmKSAtPiBkaWN0W3N0ciwgQW55XToKICAgICAgICByZXR1cm4gbG9hZF9qc29uX29yX2RlZmF1bHQoc2VsZi5sYXRlc3RfcmVxdWVzdF9wYXRoLCB7InN0YXR1cyI6ICJlbXB0eSJ9KQoKICAgIGRlZiBsYXRlc3RfYXR0ZW1wdF9wYXlsb2FkKHNlbGYpIC0+IGRpY3Rbc3RyLCBBbnldOgogICAgICAgIHJldHVybiBsb2FkX2pzb25fb3JfZGVmYXVsdChzZWxmLmxhdGVzdF9hdHRlbXB0X3BhdGgsIHsic3RhdHVzIjogImVtcHR5In0pCgogICAgZGVmIHJlY29yZF9yZXF1ZXN0X3Jlc3VsdChzZWxmLCByZWNvcmQ6IGRpY3Rbc3RyLCBBbnldKSAtPiBOb25lOgogICAgICAgIHNhZmVfcmVjb3JkID0gZGljdChyZWNvcmQpCiAgICAgICAgc2FmZV9yZWNvcmRbInRzIl0gPSBkdC5kYXRldGltZS5ub3coUFJFRkVSUkVEX1RaKS5pc29mb3JtYXQoKQogICAgICAgIHNlY3VyZV93cml0ZV9qc29uKHNlbGYubGF0ZXN0X3JlcXVlc3RfcGF0aCwgc2FmZV9yZWNvcmQpCiAgICAgICAgYXBwZW5kX2pzb25sKHNlbGYucmVxdWVzdF9oaXN0b3J5X3BhdGgsIHNhZmVfcmVjb3JkKQoKICAgIGRlZiByZWNvcmRfcG9zdF9hdHRlbXB0KHNlbGYsIHJlY29yZDogZGljdFtzdHIsIEFueV0pIC0+IE5vbmU6CiAgICAgICAgc2FmZV9yZWNvcmQgPSBkaWN0KHJlY29yZCkKICAgICAgICBzYWZlX3JlY29yZFsidHMiXSA9IGR0LmRhdGV0aW1lLm5vdyhQUkVGRVJSRURfVFopLmlzb2Zvcm1hdCgpCiAgICAgICAgc2VjdXJlX3dyaXRlX2pzb24oc2VsZi5sYXRlc3RfYXR0ZW1wdF9wYXRoLCBzYWZlX3JlY29yZCkKICAgICAgICBhcHBlbmRfanNvbmwoc2VsZi5hdHRlbXB0X2hpc3RvcnlfcGF0aCwgc2FmZV9yZWNvcmQpCgogICAgZGVmIF9wYXJzZV9vdXRwdXRfbW9kZXMoc2VsZiwgcGF5bG9hZDogZGljdFtzdHIsIEFueV0sIHF1ZXJ5OiBkaWN0W3N0ciwgbGlzdFtzdHJdXSkgLT4gbGlzdFtzdHJdOgogICAgICAgIHJhdyA9IHBheWxvYWQuZ2V0KCJvdXRwdXQiKQogICAgICAgIGlmIG5vdCByYXcgYW5kIHF1ZXJ5LmdldCgib3V0cHV0Iik6CiAgICAgICAgICAgIHJhdyA9ICIsIi5qb2luKHF1ZXJ5LmdldCgib3V0cHV0Iikgb3IgW10pCiAgICAgICAgaWYgaXNpbnN0YW5jZShyYXcsIHN0cik6CiAgICAgICAgICAgIHJldHVybiBbaXRlbS5zdHJpcCgpIGZvciBpdGVtIGluIHJhdy5zcGxpdCgiLCIpIGlmIGl0ZW0uc3RyaXAoKV0KICAgICAgICBpZiBpc2luc3RhbmNlKHJhdywgbGlzdCk6CiAgICAgICAgICAgIHJldHVybiBbbm9ybWFsaXplX3RleHQoaXRlbSkgZm9yIGl0ZW0gaW4gcmF3IGlmIG5vcm1hbGl6ZV90ZXh0KGl0ZW0pXQogICAgICAgIHJldHVybiBbc2VsZi5jb25maWdbInJldHJvYXJjaCJdWyJkZWZhdWx0X291dHB1dCJdXQoKICAgIGRlZiBfZXh0cmFjdF9pbWFnZShzZWxmLCBwYXlsb2FkOiBkaWN0W3N0ciwgQW55XSkgLT4gdHVwbGVbc3RyLCBzdHJdOgogICAgICAgIGltYWdlID0gbm9ybWFsaXplX3RleHQocGF5bG9hZC5nZXQoImltYWdlIikpCiAgICAgICAgZm10ID0gbm9ybWFsaXplX3RleHQocGF5bG9hZC5nZXQoImZvcm1hdCIpKSBvciAicG5nIgogICAgICAgIGlmIGltYWdlLnN0YXJ0c3dpdGgoImRhdGE6Iik6CiAgICAgICAgICAgIG1hdGNoID0gcmUubWF0Y2gociJeZGF0YTppbWFnZS8oW147XSspO2Jhc2U2NCwoLispJCIsIGltYWdlLCByZS5JIHwgcmUuUykKICAgICAgICAgICAgaWYgbWF0Y2g6CiAgICAgICAgICAgICAgICBmbXQgPSBtYXRjaC5ncm91cCgxKS5sb3dlcigpCiAgICAgICAgICAgICAgICBpbWFnZSA9IG1hdGNoLmdyb3VwKDIpCiAgICAgICAgaWYgbm90IGltYWdlOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCLnvLrlsJEgUmV0cm9BcmNoIOWPkemAgeeahCBpbWFnZSDlrZfmrrUiKQogICAgICAgIHJldHVybiBpbWFnZSwgZm10CgogICAgZGVmIF9zYXZlX2lucHV0X2ltYWdlKHNlbGYsIGltYWdlX2I2NDogc3RyLCBpbWFnZV9mb3JtYXQ6IHN0cikgLT4gTm9uZToKICAgICAgICBzZWxmLmxhc3RfaW1hZ2VzX2Rpci5ta2RpcihwYXJlbnRzPVRydWUsIGV4aXN0X29rPVRydWUpCiAgICAgICAgcmF3X2J5dGVzID0gZGVjb2RlX2ltYWdlX2J5dGVzKGltYWdlX2I2NCkKICAgICAgICBpZHggPSBzZWxmLmltYWdlX2NvdW50ZXIgJSBzZWxmLmxhc3RfaW1hZ2VzX2NvdW50CiAgICAgICAgZXh0ID0gbm9ybWFsaXplX2ltYWdlX21pbWVfZm9ybWF0KGltYWdlX2Zvcm1hdCkKICAgICAgICBleHQgPSAianBnIiBpZiBleHQgPT0gImpwZWciIGVsc2UgZXh0CiAgICAgICAgZmlsZXBhdGggPSBzZWxmLmxhc3RfaW1hZ2VzX2RpciAvIGYie2lkeH0ue2V4dH0iCiAgICAgICAgZmlsZXBhdGgud3JpdGVfYnl0ZXMocmF3X2J5dGVzKQogICAgICAgIGZpbGVwYXRoLmNobW9kKDBvNjAwKQogICAgICAgIHNlbGYuaW1hZ2VfY291bnRlciArPSAxCgogICAgZGVmIF90cmFuc2xhdGVfdGV4dF9vbmx5KHNlbGYsIG9jcl90ZXh0OiBzdHIsIHNvdXJjZV9sYW5nOiBzdHIsIHRhcmdldF9sYW5nOiBzdHIsIGxhYmVsOiBzdHIsIG91dHB1dF9tb2RlczogbGlzdFtzdHJdKSAtPiBzdHI6CiAgICAgICAgcHJvbXB0X3RleHQgPSBidWlsZF90cmFuc2xhdGlvbl9wcm9tcHQoc291cmNlX2xhbmcsIHRhcmdldF9sYW5nLCBsYWJlbCwgb3V0cHV0X21vZGVzKQogICAgICAgIGlmIG9jcl90ZXh0OgogICAgICAgICAgICBwcm9tcHRfdGV4dCArPSAiXG5cbuivt+WPquagueaNruS7peS4iyBPQ1Ig5paH5pys6L+b6KGM57+76K+R77yM5LiN6KaB6YeN5aSNIE9DUiDljp/mlofvvIzkuI3opoHop6Pph4rvvJpcbiIKICAgICAgICAgICAgcHJvbXB0X3RleHQgKz0gb2NyX3RleHQKICAgICAgICBlbHNlOgogICAgICAgICAgICBwcm9tcHRfdGV4dCArPSAiXG5cbuW9k+WJjeaIquWbvuayoeacieivhuWIq+WHuuS7u+S9leaWh+Wtl++8jOebtOaOpei/lOWbnuepuuWtl+espuS4suOAglxuIgogICAgICAgIHJldHVybiBwcm9tcHRfdGV4dAoKICAgIGRlZiBoYW5kbGVfcmV0cm9hcmNoX3JlcXVlc3QoCiAgICAgICAgc2VsZiwKICAgICAgICBoZWFkZXJzOiBBbnksCiAgICAgICAgcGF5bG9hZDogZGljdFtzdHIsIEFueV0sCiAgICAgICAgcGF0aDogc3RyLAogICAgICAgIHF1ZXJ5OiBkaWN0W3N0ciwgbGlzdFtzdHJdXSwKICAgICAgICBjbGllbnRfaXA6IHN0ciwKICAgICkgLT4gZGljdFtzdHIsIEFueV06CiAgICAgICAgd2l0aCBzZWxmLmxvY2s6CiAgICAgICAgICAgIHNlbGYucmVxdWVzdF9jb3VudCArPSAxCgogICAgICAgIGltYWdlX2I2NCwgaW1hZ2VfZm9ybWF0ID0gc2VsZi5fZXh0cmFjdF9pbWFnZShwYXlsb2FkKQogICAgICAgIHNlbGYuX3NhdmVfaW5wdXRfaW1hZ2UoaW1hZ2VfYjY0LCBpbWFnZV9mb3JtYXQpCiAgICAgICAgbGxtX2ltYWdlX2I2NCwgbGxtX2ltYWdlX2Zvcm1hdCwgbGxtX2ltYWdlX21ldGEgPSBwcmVwYXJlX2ltYWdlX2Zvcl9sbG0oaW1hZ2VfYjY0LCBpbWFnZV9mb3JtYXQsIHNlbGYuY29uZmlnKQogICAgICAgIHNvdXJjZV9sYW5nID0gZ2V0X3JlcXVlc3RlZF9zb3VyY2VfbGFuZ3VhZ2Uobm9ybWFsaXplX3RleHQocGF5bG9hZC5nZXQoInNvdXJjZV9sYW5nIikpKQogICAgICAgIHF1ZXJ5X3RhcmdldCA9IG5vcm1hbGl6ZV90ZXh0KChxdWVyeS5nZXQoInRhcmdldF9sYW5nIikgb3IgWyIiXSlbMF0pCiAgICAgICAgdGFyZ2V0X2xhbmcgPSBnZXRfcmVxdWVzdGVkX3RhcmdldF9sYW5ndWFnZSgKICAgICAgICAgICAgbm9ybWFsaXplX3RleHQocGF5bG9hZC5nZXQoInRhcmdldF9sYW5nIikpIG9yIHF1ZXJ5X3RhcmdldCwKICAgICAgICAgICAgc2VsZi5jb25maWdbInJldHJvYXJjaCJdWyJkZWZhdWx0X3RhcmdldF9sYW5ndWFnZSJdLAogICAgICAgICkKICAgICAgICBsYWJlbCA9IG5vcm1hbGl6ZV90ZXh0KHBheWxvYWQuZ2V0KCJsYWJlbCIpKQogICAgICAgIG91dHB1dF9tb2RlcyA9IHNlbGYuX3BhcnNlX291dHB1dF9tb2RlcyhwYXlsb2FkLCBxdWVyeSkKICAgICAgICB2aWV3cG9ydCA9IE5vbmUKICAgICAgICB2aWV3cG9ydF9yYXcgPSBwYXlsb2FkLmdldCgidmlld3BvcnQiKQogICAgICAgIGlmIGlzaW5zdGFuY2Uodmlld3BvcnRfcmF3LCBsaXN0KSBhbmQgbGVuKHZpZXdwb3J0X3JhdykgPj0gMjoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgdmlld3BvcnQgPSAoaW50KHZpZXdwb3J0X3Jhd1swXSksIGludCh2aWV3cG9ydF9yYXdbMV0pKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICAgICAgdmlld3BvcnQgPSBOb25lCiAgICAgICAgaWYgdmlld3BvcnQgaXMgTm9uZSBhbmQgaXNpbnN0YW5jZSh2aWV3cG9ydF9yYXcsIGRpY3QpOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICB2aWV3cG9ydCA9IChpbnQodmlld3BvcnRfcmF3LmdldCgid2lkdGgiKSBvciAwKSwgaW50KHZpZXdwb3J0X3Jhdy5nZXQoImhlaWdodCIpIG9yIDApKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICAgICAgdmlld3BvcnQgPSBOb25lCiAgICAgICAgcHJvbXB0X3RleHQgPSBidWlsZF92aXN1YWxfdHJhbnNsYXRpb25fcHJvbXB0KAogICAgICAgICAgICBzb3VyY2VfbGFuZywgdGFyZ2V0X2xhbmcsIGxhYmVsLCBvdXRwdXRfbW9kZXMsCiAgICAgICAgICAgIGNoYXJhY3Rlcl9kaWN0PXNlbGYuY2hhcmFjdGVyX2RpY3QsCiAgICAgICAgICAgIGNvbnRleHRfaGlzdG9yeT1zZWxmLmNvbnRleHRfaGlzdG9yeSwKICAgICAgICApCiAgICAgICAgbG9nKGYi8J+TpSByZXF1ZXN0IHBhdGg9e3BhdGh9IG91dHB1dF9tb2Rlcz17b3V0cHV0X21vZGVzfSB0YXJnZXQ9e3RhcmdldF9sYW5nfSBsYWJlbD17bGFiZWx9IikKICAgICAgICBlc3RpbWF0ZWRfdW5pdHMgPSBlc3RpbWF0ZV9xdW90YV91bml0cyhzZWxmLmNvbmZpZywgcHJvbXB0X3RleHQsIGxsbV9pbWFnZV9iNjQpCiAgICAgICAgc2VsZi5xdW90YS5yZXNlcnZlKGVzdGltYXRlZF91bml0cykKCiAgICAgICAgdXNhZ2VfdW5pdHMgPSBOb25lCiAgICAgICAgcmVzcG9uc2VfanNvbjogZGljdFtzdHIsIEFueV0gPSB7fQogICAgICAgIG9jcl9lbmdpbmUgPSAib3BlbmFpX3Zpc2lvbiIKICAgICAgICBvY3JfdGV4dCA9ICIiCiAgICAgICAgdmlzaW9uX2Vycm9yID0gIiIKICAgICAgICB0cnk6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGxsbV9wYXlsb2FkID0gYnVpbGRfdmlzdWFsX2NoYXRfcGF5bG9hZChzZWxmLmNvbmZpZywgbGxtX2ltYWdlX2I2NCwgbGxtX2ltYWdlX2Zvcm1hdCwgcHJvbXB0X3RleHQpCiAgICAgICAgICAgICAgICByZXNwb25zZV9qc29uID0gcmVxdWVzdF9sbG1fY29tcGxldGlvbihzZWxmLmNvbmZpZywgc2VsZi5hcGlfa2V5LCBsbG1fcGF5bG9hZCkKICAgICAgICAgICAgICAgIHJhd190ZXh0ID0gZXh0cmFjdF9tZXNzYWdlX3RleHQocmVzcG9uc2VfanNvbikKICAgICAgICAgICAgICAgIG9jcl90ZXh0LCB0cmFuc2xhdGVkX3RleHQgPSBwYXJzZV92aXN1YWxfdHJhbnNsYXRpb24ocmF3X3RleHQpCiAgICAgICAgICAgICAgICBpZiBsb29rc19saWtlX3Zpc2lvbl9mYWlsdXJlKG9jcl90ZXh0LCB0cmFuc2xhdGVkX3RleHQpOgogICAgICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcihmIk9wZW5BSSDop4bop4npk77ot6/mnKror7vlj5bliLDlm77niYc6IHtyYXdfdGV4dFs6MzAwXX0iKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGV4YzoKICAgICAgICAgICAgICAgIHZpc2lvbl9lcnJvciA9IHN0cihleGMpCiAgICAgICAgICAgICAgICBpZiBub3QgYm9vbChzZWxmLmNvbmZpZy5nZXQoIm9jciIsIHt9KS5nZXQoImZhbGxiYWNrX3RvX3Rlc3NlcmFjdCIsIFRydWUpKToKICAgICAgICAgICAgICAgICAgICByYWlzZQogICAgICAgICAgICAgICAgb2NyX2VuZ2luZSA9ICJ0ZXNzZXJhY3RfZmFsbGJhY2siCiAgICAgICAgICAgICAgICBvY3JfdGV4dCA9IG9jcl9pbWFnZV90ZXh0KGltYWdlX2I2NCwgaW1hZ2VfZm9ybWF0LCBzZWxmLmNvbmZpZykKICAgICAgICAgICAgICAgIGZhbGxiYWNrX3Byb21wdCA9IHNlbGYuX3RyYW5zbGF0ZV90ZXh0X29ubHkob2NyX3RleHQsIHNvdXJjZV9sYW5nLCB0YXJnZXRfbGFuZywgbGFiZWwsIG91dHB1dF9tb2RlcykKICAgICAgICAgICAgICAgIGZhbGxiYWNrX3BheWxvYWQgPSBidWlsZF9jaGF0X3BheWxvYWQoc2VsZi5jb25maWcsIG9jcl90ZXh0LCBmYWxsYmFja19wcm9tcHQpCiAgICAgICAgICAgICAgICByZXNwb25zZV9qc29uID0gcmVxdWVzdF9sbG1fY29tcGxldGlvbihzZWxmLmNvbmZpZywgc2VsZi5hcGlfa2V5LCBmYWxsYmFja19wYXlsb2FkKQogICAgICAgICAgICAgICAgdHJhbnNsYXRlZF90ZXh0ID0gZXh0cmFjdF9tZXNzYWdlX3RleHQocmVzcG9uc2VfanNvbikKICAgICAgICAgICAgaWYgbm90IHRyYW5zbGF0ZWRfdGV4dDoKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcigiT3BlbkFJIEFQSSDmsqHmnInov5Tlm57lj6/nlKjmlofmnKwiKQogICAgICAgICAgICB1c2FnZV91bml0cyA9IGFjdHVhbF9xdW90YV91bml0cyhzZWxmLmNvbmZpZywgcmVzcG9uc2VfanNvbi5nZXQoInVzYWdlIiksIGVzdGltYXRlZF91bml0cykKICAgICAgICAgICAgc2VsZi5xdW90YS5maW5hbGl6ZShlc3RpbWF0ZWRfdW5pdHMsIHVzYWdlX3VuaXRzKQogICAgICAgICAgICB3aXRoIHNlbGYubG9jazoKICAgICAgICAgICAgICAgIHNlbGYuc3VjY2Vzc19jb3VudCArPSAxCiAgICAgICAgICAgICAgICBpZiBvY3JfdGV4dCBhbmQgdHJhbnNsYXRlZF90ZXh0OgogICAgICAgICAgICAgICAgICAgIHNlbGYuY29udGV4dF9oaXN0b3J5LmFwcGVuZCh7Im9yaWdpbmFsIjogb2NyX3RleHQsICJ0cmFuc2xhdGlvbiI6IHRyYW5zbGF0ZWRfdGV4dH0pCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKHNlbGYuY29udGV4dF9oaXN0b3J5KSA+IHNlbGYuY29udGV4dF9tYXg6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY29udGV4dF9oaXN0b3J5ID0gc2VsZi5jb250ZXh0X2hpc3RvcnlbLXNlbGYuY29udGV4dF9tYXg6XQogICAgICAgICAgICB3YW50X2ltYWdlID0gYW55KHN0cihpdGVtKS5zdHJpcCgpLmxvd2VyKCkuc3RhcnRzd2l0aCgiaW1hZ2UiKSBmb3IgaXRlbSBpbiBvdXRwdXRfbW9kZXMpCiAgICAgICAgICAgIHNlbGYucmVjb3JkX3JlcXVlc3RfcmVzdWx0KAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICJzdGF0dXMiOiAib2siLAogICAgICAgICAgICAgICAgICAgICJjbGllbnRfaXAiOiBjbGllbnRfaXAsCiAgICAgICAgICAgICAgICAgICAgInBhdGgiOiBwYXRoLAogICAgICAgICAgICAgICAgICAgICJvdXRwdXRfbW9kZXMiOiBvdXRwdXRfbW9kZXMsCiAgICAgICAgICAgICAgICAgICAgInRhcmdldF9sYW5nIjogdGFyZ2V0X2xhbmcsCiAgICAgICAgICAgICAgICAgICAgInNvdXJjZV9sYW5nIjogc291cmNlX2xhbmcsCiAgICAgICAgICAgICAgICAgICAgImxhYmVsIjogbGFiZWwsCiAgICAgICAgICAgICAgICAgICAgImltYWdlX2Zvcm1hdCI6IGltYWdlX2Zvcm1hdCwKICAgICAgICAgICAgICAgICAgICAiaW1hZ2VfYmFzZTY0X2NoYXJzIjogbGVuKGltYWdlX2I2NCksCiAgICAgICAgICAgICAgICAgICAgImxsbV9pbWFnZSI6IGxsbV9pbWFnZV9tZXRhLAogICAgICAgICAgICAgICAgICAgICJvY3JfZW5naW5lIjogb2NyX2VuZ2luZSwKICAgICAgICAgICAgICAgICAgICAib2NyX3RleHQiOiBvY3JfdGV4dCwKICAgICAgICAgICAgICAgICAgICAidHJhbnNsYXRlZF90ZXh0IjogdHJhbnNsYXRlZF90ZXh0LAogICAgICAgICAgICAgICAgICAgICJ2aXNpb25fZXJyb3IiOiB2aXNpb25fZXJyb3IsCiAgICAgICAgICAgICAgICAgICAgInJlc3BvbnNlX2tpbmQiOiAiaW1hZ2UiIGlmIHdhbnRfaW1hZ2UgZWxzZSAidGV4dCIsCiAgICAgICAgICAgICAgICAgICAgInVzYWdlIjogcmVzcG9uc2VfanNvbi5nZXQoInVzYWdlIiksCiAgICAgICAgICAgICAgICAgICAgInVzYWdlX3VuaXRzIjogdXNhZ2VfdW5pdHMsCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgd2FudF9pbWFnZToKICAgICAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgICAgICAgImltYWdlIjogcmVuZGVyX292ZXJsYXlfaW1hZ2UodHJhbnNsYXRlZF90ZXh0LCB0YXJnZXRfbGFuZywgdmlld3BvcnQpLAogICAgICAgICAgICAgICAgICAgICJ0ZXh0IjogdHJhbnNsYXRlZF90ZXh0LAogICAgICAgICAgICAgICAgICAgICJ0ZXh0X3Bvc2l0aW9uIjogaW50KHNlbGYuY29uZmlnWyJyZXRyb2FyY2giXS5nZXQoImRlZmF1bHRfdGV4dF9wb3NpdGlvbiIsIDEpKSwKICAgICAgICAgICAgICAgICAgICAiYXV0byI6ICJjb250aW51ZSIgaWYgc2VsZi5jb25maWdbInJldHJvYXJjaCJdLmdldCgiYWxsb3dfYXV0b19tb2RlIiwgRmFsc2UpIGVsc2UgImNvbnRpbnVlIiwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgICJ0ZXh0IjogdHJhbnNsYXRlZF90ZXh0LAogICAgICAgICAgICAgICAgInRleHRfcG9zaXRpb24iOiBpbnQoc2VsZi5jb25maWdbInJldHJvYXJjaCJdLmdldCgiZGVmYXVsdF90ZXh0X3Bvc2l0aW9uIiwgMSkpLAogICAgICAgICAgICAgICAgImF1dG8iOiAiY29udGludWUiIGlmIHNlbGYuY29uZmlnWyJyZXRyb2FyY2giXS5nZXQoImFsbG93X2F1dG9fbW9kZSIsIEZhbHNlKSBlbHNlICJjb250aW51ZSIsCiAgICAgICAgICAgIH0KICAgICAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgICAgICBzZWxmLnF1b3RhLmZpbmFsaXplKGVzdGltYXRlZF91bml0cywgdXNhZ2VfdW5pdHMgb3IgMC4wKQogICAgICAgICAgICB3aXRoIHNlbGYubG9jazoKICAgICAgICAgICAgICAgIHNlbGYuZXJyb3JfY291bnQgKz0gMQogICAgICAgICAgICByYWlzZQoKCmRlZiBidWlsZF9zZXJ2ZXIoY29uZmlnOiBkaWN0W3N0ciwgQW55XSkgLT4gVGhyZWFkaW5nSFRUUFNlcnZlcjoKICAgIGhvc3QgPSBzdHIoY29uZmlnWyJzZXJ2ZXIiXVsiaG9zdCJdKQogICAgcG9ydCA9IGludChjb25maWdbInNlcnZlciJdWyJwb3J0Il0pCiAgICBzZXJ2ZXIgPSBUaHJlYWRpbmdIVFRQU2VydmVyKChob3N0LCBwb3J0KSwgUmV0cm9BcmNoQnJpZGdlSGFuZGxlcikKICAgIHNlcnZlci5icmlkZ2UgPSBSZXRyb0FyY2hPcGVuQUlCcmlkZ2UoY29uZmlnKSAgIyB0eXBlOiBpZ25vcmVbYXR0ci1kZWZpbmVkXQogICAgcmV0dXJuIHNlcnZlcgoKCmRlZiBpbnN0YWxsX3N5c3RlbWRfdW5pdChjb25maWc6IGRpY3Rbc3RyLCBBbnldKSAtPiBQYXRoOgogICAgdW5pdF9uYW1lID0gY29uZmlnLmdldCgic3lzdGVtZCIsIHt9KS5nZXQoInVuaXRfbmFtZSIsICJyZXRyb2FyY2gtb3BlbmFpLWJyaWRnZS5zZXJ2aWNlIikKICAgIHNjcmlwdF9wYXRoID0gUGF0aChfX2ZpbGVfXykucmVzb2x2ZSgpCiAgICBjb25maWdfcGF0aCA9IFBhdGgoY29uZmlnWyJfY29uZmlnX3BhdGgiXSkucmVzb2x2ZSgpCiAgICB3b3JraW5nX2RpciA9IFBST0pFQ1RfUk9PVAogICAgdW5pdF9wYXRoID0gUGF0aC5ob21lKCkgLyAiLmNvbmZpZyIgLyAic3lzdGVtZCIgLyAidXNlciIgLyB1bml0X25hbWUKICAgIGVuc3VyZV9wYXJlbnRfZGlyKHVuaXRfcGF0aCkKICAgIGVudl9maWxlID0gUGF0aC5ob21lKCkgLyAiLmNvbmZpZyIgLyAicmV0cm9hcmNoLW9wZW5haS1icmlkZ2UuZW52IgogICAgdW5pdCA9IGYiIiJbVW5pdF0KRGVzY3JpcHRpb249UmV0cm9BcmNoIE9wZW5BSSBBSSBCcmlkZ2UKQWZ0ZXI9bmV0d29yay1vbmxpbmUudGFyZ2V0CldhbnRzPW5ldHdvcmstb25saW5lLnRhcmdldAoKW1NlcnZpY2VdClR5cGU9c2ltcGxlCldvcmtpbmdEaXJlY3Rvcnk9e3dvcmtpbmdfZGlyfQpFbnZpcm9ubWVudEZpbGU9LXtlbnZfZmlsZX0KRXhlY1N0YXJ0PS91c3IvYmluL3B5dGhvbjMgLXUge3NjcmlwdF9wYXRofSAtLWNvbmZpZyB7Y29uZmlnX3BhdGh9IHNlcnZlClJlc3RhcnQ9YWx3YXlzClJlc3RhcnRTZWM9MwpLaWxsU2lnbmFsPVNJR0lOVApUaW1lb3V0U3RvcFNlYz0zMAoKW0luc3RhbGxdCldhbnRlZEJ5PWRlZmF1bHQudGFyZ2V0CiIiIgogICAgdW5pdF9wYXRoLndyaXRlX3RleHQodW5pdCwgZW5jb2Rpbmc9InV0Zi04IikKICAgIHJldHVybiB1bml0X3BhdGgKCgpkZWYgbWF5YmVfc2hvd19zZWxmX3Rlc3QoY29uZmlnOiBkaWN0W3N0ciwgQW55XSkgLT4gaW50OgogICAgYnJpZGdlID0gUmV0cm9BcmNoT3BlbkFJQnJpZGdlKGNvbmZpZykKICAgIHByaW50KGpzb24uZHVtcHMoYnJpZGdlLmhlYWx0aF9wYXlsb2FkKCksIGVuc3VyZV9hc2NpaT1GYWxzZSwgaW5kZW50PTIpKQogICAgcmV0dXJuIDAKCgpkZWYgc3BsaXRfY29uZmlnX2Zyb21fYXJndihhcmd2OiBsaXN0W3N0cl0pIC0+IHR1cGxlW3N0ciwgbGlzdFtzdHJdXToKICAgIGNvbmZpZ19wYXRoID0gc3RyKERFRkFVTFRfQ09ORklHKQogICAgY2xlYW5lZDogbGlzdFtzdHJdID0gW10KICAgIGkgPSAwCiAgICB3aGlsZSBpIDwgbGVuKGFyZ3YpOgogICAgICAgIGl0ZW0gPSBhcmd2W2ldCiAgICAgICAgaWYgaXRlbSA9PSAiLS1jb25maWciOgogICAgICAgICAgICBpZiBpICsgMSA+PSBsZW4oYXJndik6CiAgICAgICAgICAgICAgICByYWlzZSBTeXN0ZW1FeGl0KCItLWNvbmZpZyDlkI7nvLrlsJHot6/lvoQiKQogICAgICAgICAgICBjb25maWdfcGF0aCA9IGFyZ3ZbaSArIDFdCiAgICAgICAgICAgIGkgKz0gMgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGNsZWFuZWQuYXBwZW5kKGl0ZW0pCiAgICAgICAgaSArPSAxCiAgICByZXR1cm4gY29uZmlnX3BhdGgsIGNsZWFuZWQKCgpkZWYgbWFpbihhcmd2OiBsaXN0W3N0cl0gfCBOb25lID0gTm9uZSkgLT4gaW50OgogICAgcmF3X2FyZ3YgPSBsaXN0KHN5cy5hcmd2WzE6XSBpZiBhcmd2IGlzIE5vbmUgZWxzZSBhcmd2KQogICAgY29uZmlnX3BhdGgsIGNsZWFuZWRfYXJndiA9IHNwbGl0X2NvbmZpZ19mcm9tX2FyZ3YocmF3X2FyZ3YpCgogICAgcGFyc2VyID0gYXJncGFyc2UuQXJndW1lbnRQYXJzZXIoZGVzY3JpcHRpb249IlJldHJvQXJjaCBBSSBTZXJ2aWNlIGJyaWRnZSBiYWNrZWQgYnkgb2ZmaWNpYWwgT3BlbkFJIGdwdC01LjQtbmFuby4iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1jb25maWciLCBkZWZhdWx0PXN0cihERUZBVUxUX0NPTkZJRyksIGhlbHA9IllBTUwg6YWN572u5paH5Lu26Lev5b6EIikKICAgIHN1YiA9IHBhcnNlci5hZGRfc3VicGFyc2VycyhkZXN0PSJjbWQiKQogICAgc3ViLmFkZF9wYXJzZXIoInNlcnZlIiwgaGVscD0i5ZCv5YqoIEhUVFAg5pyN5YqhIikKICAgIHN1Yi5hZGRfcGFyc2VyKCJzZWxmLXRlc3QiLCBoZWxwPSLmiZPljbDmnKzlnLDlgaXlurfmo4Dmn6Xkv6Hmga8iKQogICAgc3ViLmFkZF9wYXJzZXIoImluc3RhbGwtc3lzdGVtZCIsIGhlbHA9IuWGmeWFpSBzeXN0ZW1kIHVzZXIgc2VydmljZSDmlofku7YiKQogICAgYXJncyA9IHBhcnNlci5wYXJzZV9hcmdzKGNsZWFuZWRfYXJndikKCiAgICBjb25maWcgPSBsb2FkX2NvbmZpZyhjb25maWdfcGF0aCkKICAgIGlmIGFyZ3MuY21kIGlzIE5vbmU6CiAgICAgICAgYXJncy5jbWQgPSAic2VydmUiCgogICAgaWYgYXJncy5jbWQgPT0gInNlbGYtdGVzdCI6CiAgICAgICAgcmV0dXJuIG1heWJlX3Nob3dfc2VsZl90ZXN0KGNvbmZpZykKCiAgICBpZiBhcmdzLmNtZCA9PSAiaW5zdGFsbC1zeXN0ZW1kIjoKICAgICAgICB1bml0X3BhdGggPSBpbnN0YWxsX3N5c3RlbWRfdW5pdChjb25maWcpCiAgICAgICAgcHJpbnQoc3RyKHVuaXRfcGF0aCkpCiAgICAgICAgcmV0dXJuIDAKCiAgICBpZiBhcmdzLmNtZCA9PSAic2VydmUiOgogICAgICAgIHNlcnZlciA9IGJ1aWxkX3NlcnZlcihjb25maWcpCiAgICAgICAgaG9zdCwgcG9ydCA9IHNlcnZlci5zZXJ2ZXJfYWRkcmVzcwogICAgICAgIGxvZyhmIvCfmoAgUmV0cm9BcmNoIGJyaWRnZSBsaXN0ZW5pbmcgb24gaHR0cDovL3tob3N0fTp7cG9ydH0iKQoKICAgICAgICBkZWYgX3NodXRkb3duKCpfc2lnOiBBbnkpIC0+IE5vbmU6CiAgICAgICAgICAgIGxvZygi8J+nryDmlLbliLDlgZzmraLkv6Hlj7fvvIzlh4blpIfpgIDlh7oiKQogICAgICAgICAgICB0aHJlYWRpbmcuVGhyZWFkKHRhcmdldD1zZXJ2ZXIuc2h1dGRvd24sIGRhZW1vbj1UcnVlKS5zdGFydCgpCgogICAgICAgIHNpZ25hbC5zaWduYWwoc2lnbmFsLlNJR1RFUk0sIF9zaHV0ZG93bikKICAgICAgICBzaWduYWwuc2lnbmFsKHNpZ25hbC5TSUdJTlQsIF9zaHV0ZG93bikKICAgICAgICB0cnk6CiAgICAgICAgICAgIHNlcnZlci5zZXJ2ZV9mb3JldmVyKHBvbGxfaW50ZXJ2YWw9MC41KQogICAgICAgIGZpbmFsbHk6CiAgICAgICAgICAgIHNlcnZlci5zZXJ2ZXJfY2xvc2UoKQogICAgICAgICAgICBsb2coIuKchSDmnI3liqHlt7LpgIDlh7oiKQogICAgICAgIHJldHVybiAwCgogICAgcGFyc2VyLmVycm9yKGYi5pyq55+l5ZG95LukOiB7YXJncy5jbWR9IikKICAgIHJldHVybiAyCgoKaWYgX19uYW1lX18gPT0gIl9fbWFpbl9fIjoKICAgIHJhaXNlIFN5c3RlbUV4aXQobWFpbigpKQo=

mario21a 发表于 2026-5-14 23:18

泰坦失足 发表于 2026-5-14 05:22
我目前用的是GPT 5.4 Mini 大概1~1.5秒完成翻译. GPT 5.5 明显更贵, 效果却差不多, 而且要8~10秒给出结果. ...

非常感谢,回去试一下效果
在玩一个只有日版的NGC老游戏,分辨率可以压缩一下再上传
页: [1]
查看完整版本: 感谢AI Coding, 约一个小时搞定了RetroArch的AI翻译