外观
火焰与爆炸
普通火焰、营火和火药桶都会提供热量或破坏能力,但它们不是同一种机制。若混为一谈,容易造成木屋失火、掉落物被烧毁,或在狭窄矿道内被爆炸波及。
先在测试世界验证
爆炸会永久改变地形并可能引发连锁火灾。第一次使用某种火药桶、燃烧弹或电起爆结构时,应在创造测试世界远离建筑与动物验证,不要直接在主存档试验。
三种机制先分开
| 机制 | 主要用途 | 核心风险 |
|---|---|---|
| 普通火焰 | 燃烧可燃方块、伤害实体 | 蔓延、烧毁建筑和掉落物 |
| 营火 | 提供热量、照明并驱赶部分捕食者 | 靠得太近会受热或着火,需要持续补充燃料 |
| 爆炸物 | 快速破坏地形、机关或战斗用途 | 方块破坏、火灾与连锁爆炸 |


营火是相对可控的热源,不等于可以在任何位置安全放置。普通火焰则可能由火柴、岩浆、雷击、燃烧弹药或爆炸引起,并沿可燃材料继续扩散。
火焰系统
火焰是游戏中最具扩散性的危险源。一旦点燃,它会沿着可燃物向四周蔓延,烧毁木屋、森林乃至整个基地。但火焰也有规律可循——理解它的传播方式和可燃物数据,你就能有效防火。
火焰的诞生与存在形式
- 火焰方块编号为 104,它不是独立存在的方块,而是附着在可燃方块表面的火焰面。
- 当火焰方块数据值为 0 且下方方块的火焰持续时间为 0 时,火焰方块会被移除(自然熄灭)。
- 每个火焰点都维护一组燃烧计时器,分别对应四个水平方向和向下方烧穿。计时器的初始值等于方块的火焰持续时间,但有 ±25% 的随机波动,使每次火灾的蔓延速度都不完全相同。
火焰传播机制
火焰传播有两种方式:直接烧穿和概率蔓延。
直接烧穿:当某个方向的燃烧计时器归零时,该方向相邻的可燃方块会被直接摧毁(变为空气),并在其周围生成新的火焰。新火焰的蔓延能力每次传播衰减 15%,初始为 1.0,当降至 0.25 以下时烧穿的方块不再生成新火焰。
概率蔓延:火焰在烧穿方块的同时,还会以一定概率向附近的方块扩散。关键规律:
- 向上蔓延最快:正上方 1 格每次扫描有 4% 概率被引燃
- 向下蔓延最慢:正下方 1 格每次扫描只有 2% 概率——向上蔓延速度是向下的两倍
- 水平方向居中:侧面 1 格约 2% 概率
- 最大蔓延范围:向上和水平方向最远 2.5 格,向下最远 1.5 格
烧毁操作每 5 游戏秒(约 4 现实秒)批量处理一次,届时所有排队等待烧毁的方块会被同时摧毁。
可燃物数据
不同方块的火焰持续时间和爆炸抗性各不相同。火焰持续时间越长,方块烧穿所需的时间越久。
常见可燃方块一览:
| 方块 | 火焰持续时间 | 爆炸抗性 | 说明 |
|---|---|---|---|
| 各种原木 | 20 | 20 | 燃烧较慢,是建筑主要可燃物 |
| 木板 | 20 | 20 | 与原木相同 |
| 各种树叶 | 8 | 2 | 燃烧快,极易引燃 |
| 草、花、黑麦 | 6 | 2 | 燃烧极快,火焰瞬间扩散 |
| 树苗 | 8 | 2 | |
| 仙人掌 | 10 | 10 | |
| 木门 | 12 | 3 | |
| 木栅栏 | 15 | 3 | |
| 木楼梯/台阶 | 15 | 5 | |
| 工作台/箱子 | 20 | 5 | |
| 玻璃窗 | 15 | 2 | 受热碎裂 |
| 煤炭块 | 999999 | 50 | 几乎永不烧尽 |
| 南瓜 | 10 | 2 | |
| 藤蔓 | 6 | 1 |
注意:火焰持续时间为 0 的方块(如石头、泥土)不会被火焰点燃,火焰遇到它们会停止蔓延。
失火时怎么处理
- 快速离开燃烧方块和可能倒塌、爆炸的区域。
- 使用水或移除仍在燃烧的方块切断火势;不要站在火焰中操作。
- 把未被点燃的燃料、火药桶和贵重掉落物移出传播方向。
- 火熄灭后检查屋顶、夹层、树叶和相邻木结构,防止遗漏火点。
- 雷雨期间不要立刻在高处修复可燃屋顶,先等待环境
被火焰杀死的动物可能留下熟肉,但皮革、羽毛、鞍具等其他掉落物也可能被烧毁。
火焰防护建议
根据火焰传播规律,玩家可以采取以下措施:
- 防火隔离带:在木建筑周围留出 3 格以上的非可燃区域(石头、泥土等),因为火焰最大水平蔓延范围为 2.5 格
- 注意上方空间:火焰向上蔓延概率是向下的两倍,木屋顶上方不要有树叶等易燃物
- 雨天安全:雨水会浇灭火焰,雨天火灾风险大幅降低
- 水桶备用:水可以直接扑灭火焰方块
营火系统
营火是玩家可控的火源,用于照明和烹饪。与自然火焰不同,营火不会蔓延,但需要持续添加燃料才能维持。理解营火的燃料机制,你就能高效利用每一块木材。
营火基础
营火方块的尺寸存储在数据值中,范围为 0~15,其中 0 表示熄灭,15 表示最大火力。尺寸越大火焰粒子越大,从微弱火苗到旺盛篝火线性变化。
添加燃料
玩家可以通过以下方式添加燃料:
- 手持燃料右键点击营火
- 将燃料物品投掷到营火上(投射物命中)
添加燃料时,系统按以下逻辑处理:
- 爆炸物检查:如果投入的物品是爆炸物(如火药桶),直接触发爆炸
- 灭火物检查:如果投入雪块、雪球或冰块,营火尺寸减小 1
- 燃料计算:如果物品有燃料热值(>0),每个燃料可增加的营火尺寸 = 燃料燃烧时间 ÷ 5(但燃烧时间超过 20 的只按 20 算)。小数部分按概率进位(如 2.3 步有 30% 概率变为 3 步)。
常见燃料效率对比:
| 燃料 | 燃料热值 | 燃料燃烧时间 | 每个增加步数 | 说明 |
|---|---|---|---|---|
| 煤炭块 | 2 | 600 | 4 | 最持久的燃料(被限制为 20/5=4) |
| 煤炭 | 2 | 80 | 4 | 同样被限制为 4 步 |
| 硫磺 | 2 | 10 | 2 | |
| 原木 | 1 | 20 | 4 | 性价比高 |
| 木板 | 1 | 10 | 2 | |
| 木棍 | 1 | 5 | 1 | |
| 树叶 | 1 | 1 | 0.2 | 几乎无用 |
| 草 | 1 | 0.5 | 0.1 | 可忽略 |
| 树苗 | 1 | 0.5 | 0.1 | 可忽略 |
| 仙人掌 | 1 | 5 | 1 | |
| 工作台/箱子 | 1 | 5 | 1 | 紧急时可拆家具当柴烧 |
提示:1 个原木 = 4 步营火增量,意味着 4 个原木就能把营火从 0 加满到 15。而煤炭块虽然燃烧时间长达 600,但受上限 20 的限制,每个也只能增加 4 步,与原木效率相同。因此原木是性价比最高的营火燃料。
营火衰减与熄灭
营火会自然衰减,衰减有两种触发方式:
雨水浇灭:每 5 游戏秒检查一次,如果营火所在位置正在降雨(降水强度 > 0)且营火高度 >= 降水高度上限 - 1,营火尺寸减 1。这意味着露天的营火在雨天会逐渐熄灭。
自然衰减:每 6 次检查周期(即每 30 游戏秒,约 24 现实秒),无论天气如何,营火尺寸都会减 1。这是营火的自然消耗。
营火防雨
露天的营火会因为降雨而熄灭,可以在营火上面搭建遮蔽物来防止被雨水浇灭。
营火的正确定位
营火适合早期取暖、烘干和照明。燃料可以通过投入可燃物补充,雨雪会让维持火势更困难。布置时至少做到:
- 周围留出不可燃操作区;
- 不挡住门口和唯一撤退通道;
- 不把爆炸物当燃料投入;
- 睡前评估剩余火势和室内温度,不假设它会整夜保持;
- 体温过高时立刻拉开距离。
即使旁边有热源,露天、潮湿或不符合睡眠条件的位置仍可能无法安全休息。
爆炸系统
爆炸是游戏中最具破坏力的瞬间事件。火药桶、雷管和燃烧桶都能引发爆炸,摧毁方块、伤害生物、甚至引发连环火灾。理解爆炸的压力传播和连锁机制,你才能安全使用爆炸物,也能在爆炸中幸存。
爆炸物种类
游戏中的爆炸物分为两大类:火药桶和雷管。
火药桶数据:
| 名称 | 爆炸压力 | 是否引燃 | 引信时间 | 说明 |
|---|---|---|---|---|
| 小火药桶 | 60 | 否 | 6~7 秒 | 基础爆炸物 |
| 中火药桶 | 360 | 否 | 6~7 秒 | 中等威力 |
| 大火药桶 | 2160 | 否 | 6~7 秒 | 大规模破坏 |
| 小燃烧桶 | 50 | 是 | 6~7 秒 | 爆炸后引发火灾 |
| 中燃烧桶 | 300 | 是 | 6~7 秒 | |
| 大燃烧桶 | 1800 | 是 | 6~7 秒 |
引信时间:从点燃到爆炸的现实秒数,在 6~7 秒之间随机。这段时间内会播放引信燃烧的嘶嘶声和火花粒子效果。
雷管:
| 名称 | 爆炸压力 | 是否引燃 | 引信时间 |
|---|---|---|---|
| 雷管 | 10 | 否 | 0.8~1.2 秒 |
雷管引信极短,几乎瞬间爆炸,通常用于电气电路触发的精确爆破。
投掷型爆炸武器
与火药桶需要放置后引燃不同,炸弹和燃烧弹是投掷后自动定时爆炸的武器,适合战斗中快速使用。
火药桶是"放置型"爆炸物——你得先放好再点火。而炸弹和燃烧弹属于"投掷型",扔出去后5 秒自动爆炸,无需额外点火。此外,火药本身也可以投掷,但性质有所不同。
投掷型爆炸物数据:
| 名称 | 分类 | 爆炸压力 | 是否引燃 | 投掷速度 | 最大堆叠 | 特殊说明 |
|---|---|---|---|---|---|---|
| 炸弹 | 武器 | 60 | 否 | 14 | 24 | 投出后 5 秒自动爆炸,白色烟雾尾迹 |
| 燃烧弹 | 武器 | 50 | 是 | 14 | 24 | 投出后 5 秒自动爆炸,粉红色烟雾尾迹,爆炸后引发火灾 |
| 火药 | 物品 | 60 | 否 | 14 | 40 | 可投掷但不会自动爆炸,主要用作燃料或合成材料 |
炸弹 vs 火药桶对比:
| 特性 | 炸弹 / 燃烧弹 | 火药桶 / 燃烧桶 |
|---|---|---|
| 使用方式 | 投掷后自动定时爆炸 | 放置后需火焰/电路/爆炸引燃 |
| 引爆延迟 | 固定 5 秒(投出后计时) | 6~7 秒引信(点燃后计时) |
| 爆炸压力 | 60 / 50 | 60~2160 / 50~1800(分大中小三档) |
| 撞击爆炸 | 不会(落地后等计时器) | 会(火药桶带撞击爆炸行为) |
| 可放置 | 否(投掷物) | 是(可作为方块放置) |
| 烟雾尾迹 | 有(白色/粉红色) | 无 |
| 适用场景 | 战斗中快速投掷 | 定点爆破、陷阱、电路控制 |
炸弹的定时机制:炸弹投出后开始计时,5 秒后在当前位置爆炸。期间炸弹会拖曳烟雾尾迹(普通炸弹白色,燃烧弹粉红色),方便你判断爆炸时机。炸弹落地后不会像火药桶那样撞击爆炸,而是静静等待计时器归零。
燃烧弹的特殊之处:燃烧弹爆炸压力比炸弹略低(50 vs 60),但爆炸后会以 50% 概率引燃周围可燃方块,火焰扩散能力为满值(1.0),极易引发大面积火灾。适合用来烧毁木制建筑或森林。
火药的定位:火药虽然也有爆炸压力 60,但它只具有投掷行为,没有炸弹的定时爆炸行为,因此投掷后不会爆炸。火药的主要用途是作为燃料(热值 2,燃烧时间 10)和合成材料(制作火药桶、炸弹等)。
引爆方式
爆炸物有以下几种引爆途径:
- 火焰引燃:当爆炸物相邻方块着火时,自动点燃引信
- 爆炸波及:当爆炸压力波及到爆炸物时,有 50% 概率点燃引信(前提是压力/爆炸抗性 > 0.01)
- 电气触发:火药桶可作为电气元件,通过电路信号远程引爆
- 投射物撞击:带有撞击爆炸行为的方块(如箭矢、子弹)命中时可直接触发
火药桶有不同规格,威力和影响范围随规格增大。它们可被火焰、弹药、其他爆炸或电气装置触发;电气起爆适合把玩家与爆心分开,但接线错误、区块状态和联机延迟仍可能造成误触发。





模型图用于区分尺寸与燃烧变体,不表示安全距离。火药桶越大或越集中,越需要扩大撤离范围。
不要把旧维基给出的固定“安全距离”当成保证。封闭空间、多个爆炸物、飞散燃烧方块、地形高度和版本参数都会改变风险。实际操作应使用更远距离、实体掩体和不与爆心相连的撤退路线。
为什么不推荐用爆炸物精细采矿
爆炸擅长清除体积,不擅长保证矿石回收。它可能摧毁矿物、破坏安全通道、打开岩浆或水体,并把燃烧碎片抛到视野外。需要取得资源时优先使用正确等级的镐;只有在明确接受材料损失、并完成测试后,才把爆炸用于大面积清障。
爆炸传播机制
爆炸模拟从爆炸中心向外逐层扩散,每扩散一层压力就快速衰减。核心规律:
- 传播停止条件:当压力衰减到约 1 时停止传播。爆炸压力越大,传播得越远——小火药桶(压力 60)的阈值约 1,大火药桶(压力 2160)的阈值约 6。
- 压力衰减:随着波及的方块越来越多,压力快速衰减,第 7 轮之后还会额外加速衰减。这意味着爆炸破坏力随距离急剧下降。
- 方块破坏判定:当某方块周围 6 个面的总压力超过其爆炸抗性时,方块被摧毁。同一位置的爆炸效果相对一致但有随机性——每个方块的抗性有 1~2 倍的随机波动,少数方块(约 12.5%)抗性甚至高达 3 倍。
- 方块破坏判定:当某方块周围 6 个面的总压力超过其爆炸抗性时,方块被摧毁。同一位置的爆炸效果相对一致但有随机性——每个方块的抗性有 1~2 倍的随机波动,少数方块(约 12.5%)抗性甚至高达 3 倍。
- 连锁爆炸概率:当方块被爆炸摧毁后,如果该方块本身是爆炸物,有概率被引爆——压力极大时 95%,一般情况 75%。这就是为什么火药桶要分散摆放,紧挨着放容易全部连锁引爆。
爆炸威力的方块破坏范围
不同爆炸物的实际破坏范围取决于周围方块的爆炸抗性。以下是在纯泥土环境(爆炸抗性 25)中的近似破坏半径:
| 爆炸物 | 爆炸压力 | 近似破坏半径(格) |
|---|---|---|
| 雷管 | 10 | ~1 |
| 小燃烧桶 | 50 | ~2 |
| 小火药桶 | 60 | ~2 |
| 中燃烧桶 | 300 | ~3 |
| 中火药桶 | 360 | ~4 |
| 大燃烧桶 | 1800 | ~6 |
| 大火药桶 | 2160 | ~7 |
注意:实际破坏范围受方块硬度影响极大。在石头环境(抗性 50)中,破坏半径约为泥土环境的一半;而在玻璃环境(抗性 2)中,破坏范围会大幅扩大。
常见方块爆炸抗性:
| 方块 | 爆炸抗性 | 抗爆等级 |
|---|---|---|
| 玻璃 | 2 | 极脆 |
| 雪块 | 2 | 极脆 |
| 树叶 | 2 | 极脆 |
| 营火 | 1 | 极脆 |
| 火把 | 5 | 脆弱 |
| 木栅栏 | 3 | 脆弱 |
| 泥土/沙子/沙砾 | 25 | 普通 |
| 冰 | 25 | 普通 |
| 石灰岩/砂岩 | 50 | 坚固 |
| 水/岩浆 | 50 | 坚固 |
| 花岗岩 | 75 | 坚固 |
| 砖块 | 75 | 坚固 |
| 玄武岩 | 80 | 坚固 |
| 鹅卵石 | 140 | 非常坚固 |
| 石砖 | 160 | 非常坚固 |
| 铁块 | 2000 | 极度坚固 |
| 钻石块 | 8000 | 近乎无敌 |
| 基岩 | ∞ | 无敌 |
爆炸伤害
爆炸对生物和玩家的伤害与周围压力成正比:压力越大伤害越高,且生物质量越大受到的伤害越小(穿盔甲的玩家更耐炸)。爆炸还会产生击退效果,把生物推开。
爆炸与火焰的联动
爆炸与火焰系统存在密切联动:
爆炸引发火灾:在爆炸的后处理阶段,对于未被摧毁但受到压力波及的可燃方块,有概率被点燃:
| 爆炸类型 | 点燃概率 | 点燃后火焰扩散能力 |
|---|---|---|
| 燃烧桶爆炸 | 50% | 1.0(满扩散) |
| 普通爆炸 | 20% | 0.3(弱扩散) |
点燃条件:只要方块可燃且承受了足够的爆炸压力,就可能被点燃。即使是普通爆炸,也有可能在废墟中引发火灾。
火焰引爆爆炸物:当爆炸物相邻方块着火时,自动点燃引信,6~7 秒后爆炸。这是最常见的连锁爆炸触发方式——先放火,再爆炸。
爆炸弹射物
爆炸摧毁方块时,会生成弹射物(飞溅的方块碎片):
- 弹射物数量随爆炸规模增加,但概率递减(超过 25 个后概率开始下降)
- 弹射物带有随机速度和旋转,落地后可能变为可拾取物品或直接消失
- 燃烧桶爆炸生成的弹射物有概率变为燃烧弹射物,落地后点燃周围方块
- 50% 的弹射物会拖曳烟雾尾迹,燃烧弹射物的烟雾呈粉红色
爆炸音效分级
爆炸音效根据总压力值分为 7 个等级,压力越大音效传播越远:
| 总压力 | 音效 | 噪音范围(格) |
|---|---|---|
| > 2,000,000 | Explosion7 | 130 |
| > 400,000 | Explosion6 | 100 |
| > 80,000 | Explosion5 | 70 |
| > 16,000 | Explosion4 | 50 |
| > 3,500 | Explosion3 | 40 |
| > 80 | Explosion2 | 35 |
| > 0 | Explosion1 | 30 |
噪音:爆炸会产生噪音,吸引附近的生物。压力越大的爆炸吸引范围越广,最大可达 130 格——这意味着一个大爆炸可能惊动整个区域的生物。
电路起爆检查表
- 起爆电源默认保持断开,最后一步才连接。
- 导线与按钮远离爆炸影响区,并保留物理掩体。
- 先用灯替代电雷管测试信号方向、延迟和复位。
- 确认没有相邻线路、传感器或雷雨造成意外输入。
- 联机服由一人统一倒计时,确认附近玩家和坐骑已经撤离。
写给开发者
资料暂存
本小节内容暂时存放于此,后续会移动至"MOD开发"章节。
开发概览
火焰方块行为(SubsystemFireBlockBehavior.cs)
FireData类:存储每个火焰点的运行时数据。Point为火焰坐标;Time0~Time3为四个水平方向的燃烧计时器;Time5为向下烧穿计时器;FireExpandability为火焰扩散能力。
csharp
// 火焰方块编号为 104
public override int[] HandledBlocks => [104];
// 火焰蔓延概率的初始化(在 Load 方法中)
// 遍历 -2~2 的 x、-1~2 的 y、-2~2 的 z 偏移
for (int i = -2; i <= 2; i++) { // i = X 偏移
for (int j = -1; j <= 2; j++) { // j = Y 偏移
for (int k = -2; k <= 2; k++) { // k = Z 偏移
if (i != 0 || j != 0 || k != 0) {
// num = 最大距离:向下(j<0)为 1.5,向上/水平为 2.5
float num = j < 0 ? 1.5f : 2.5f;
if (MathF.Sqrt(i*i + j*j + k*k) <= num) {
// num2 = 水平距离 sqrt(i² + k²)
float num2 = MathF.Sqrt(i*i + k*k);
// num3 = 垂直因子:向上为 0.5*j,向下为 -j
float num3 = j > 0 ? 0.5f * j : -j;
// 蔓延概率 = 0.02 / (水平距离 + 垂直因子)
m_expansionProbabilities[new Point3(i, j, k)] = 0.02f / (num2 + num3);
}
}
}
}
}csharp
// 燃烧计时器初始化
// face = 方向索引(0=+Z, 1=+X, 2=-Z, 3=-X, 5=-Y)
// GetFireDuration = 方块的火焰持续时间
// m_random.Float(0.75f, 1.25f) = 随机系数,使传播时间有 ±25% 的波动
public void InitializeFireDataTime(FireData fireData, int face) {
Point3 point = CellFace.FaceToPoint3(face);
int cellValue = SubsystemTerrain.Terrain.GetCellValue(
fireData.Point.X + point.X, fireData.Point.Y + point.Y, fireData.Point.Z + point.Z);
Block block = BlocksManager.Blocks[Terrain.ExtractContents(cellValue)];
switch (face) {
case 0: fireData.Time0 = block.GetFireDuration(cellValue) * m_random.Float(0.75f, 1.25f); break;
case 1: fireData.Time1 = block.GetFireDuration(cellValue) * m_random.Float(0.75f, 1.25f); break;
case 2: fireData.Time2 = block.GetFireDuration(cellValue) * m_random.Float(0.75f, 1.25f); break;
case 3: fireData.Time3 = block.GetFireDuration(cellValue) * m_random.Float(0.75f, 1.25f); break;
case 5: fireData.Time5 = block.GetFireDuration(cellValue) * m_random.Float(0.75f, 1.25f); break;
}
}csharp
// Update 方法中的火焰传播逻辑(简化版)
// 每次扫描检查所有火焰点,减少计时器
// num4 = 火焰方块的数据值(位标志)
// m_lastScanDuration = 上次扫描到现在的时间间隔
// 方向 0(+Z)的燃烧逻辑
if ((num4 & 1) != 0) {
value.Time0 -= m_lastScanDuration; // 计时器递减
if (value.Time0 <= 0f) {
// 计时器归零,烧毁 +Z 方向的方块
// 新火焰扩散能力 = 原扩散能力 × 0.85
QueueBurnAway(x, y, z + 1, value.FireExpandability * 0.85f);
}
// 概率蔓延:对每个可能的偏移方向
foreach (var expansionProbability in m_expansionProbabilities) {
// 随机数 < 概率 × 时间 × 扩散能力 → 蔓延
if (m_random.Float(0f, 1f) < expansionProbability.Value * m_lastScanDuration * value.FireExpandability) {
m_toExpand[new Point3(
x + expansionProbability.Key.X,
y + expansionProbability.Key.Y,
z + 1 + expansionProbability.Key.Z
)] = value.FireExpandability * 0.85f; // 新扩散能力衰减 15%
}
}
}csharp
// 烧毁处理(每 5 游戏秒执行一次)
// m_toBurnAway = 待烧毁方块队列
// m_toExpand = 待蔓延方块队列
if (m_subsystemTime.PeriodicGameTimeEvent(5.0, 0.0)) {
foreach (var item in m_toBurnAway) {
// 摧毁方块(变为空气)
SubsystemTerrain.ChangeCell(item.Key.X, item.Key.Y, item.Key.Z, Terrain.ReplaceContents(0));
// 如果扩散能力 > 0.25,向周围 5 个面扩散火焰
if (item.Value > 0.25f) {
for (int i = 0; i < 5; i++) {
Point3 point = CellFace.FaceToPoint3(i);
SetCellOnFire(item.Key.X + point.X, item.Key.Y + point.Y, item.Key.Z + point.Z, item.Value);
}
}
}
// 处理蔓延队列
foreach (var item2 in m_toExpand) {
SetCellOnFire(item2.Key.X, item2.Key.Y, item2.Key.Z, item2.Value);
}
m_toBurnAway.Clear();
m_toExpand.Clear();
}营火方块行为(SubsystemCampfireBlockBehavior.cs)
csharp
// 营火尺寸范围:0(熄灭)~ 15(最大)
// 营火粒子大小随尺寸线性插值
public void AddCampfireParticleSystem(int value, int x, int y, int z) {
int num = Terrain.ExtractData(value); // num = 营火尺寸(0~15)
if (num > 0) {
// size = 粒子大小,从 0.2 到 0.5 线性插值
float size = MathUtils.Lerp(0.2f, 0.5f, num / 15f);
FireParticleSystem fireParticleSystem = new(new Vector3(x, y, z) + v, size, 256f);
m_subsystemParticles.AddParticleSystem(fireParticleSystem);
m_particleSystemsByCell[new Point3(x, y, z)] = fireParticleSystem;
}
}csharp
// 添加燃料的核心逻辑
public bool AddFuel(int x, int y, int z, int value, int count) {
if (Terrain.ExtractData(SubsystemTerrain.Terrain.GetCellValue(x, y, z)) > 0) {
Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
// 1. 先检查是否为爆炸物
if (Project.FindSubsystem<SubsystemExplosions>(true).TryExplodeBlock(x, y, z, value)) {
return true;
}
// 2. 雪/雪球/冰块 → 减小营火
if (block is SnowBlock || block is SnowballBlock || block is IceBlock) {
return ResizeCampfire(x, y, z, -1, true);
}
// 3. 有燃料热值 → 计算增加步数
if (block.GetFuelHeatLevel(value) > 0f) {
// num2 = 增加步数 = 数量 × min(燃料燃烧时间, 20) / 5
float num2 = count * MathUtils.Min(block.GetFuelFireDuration(value), 20f) / 5f;
int num3 = (int)num2; // 整数部分
float num4 = num2 - num3; // 小数部分
if (m_random.Float(0f, 1f) < num4) num3++; // 概率进位
if (num3 > 0) {
return ResizeCampfire(x, y, z, num3, true);
}
return true;
}
}
return false;
}csharp
// 营火尺寸调整
public bool ResizeCampfire(int x, int y, int z, int steps, bool playSound) {
int num = Terrain.ExtractData(cellValue); // 当前尺寸
if (num > 0) {
// 新尺寸 = clamp(当前尺寸 + 步数, 0, 15)
int num2 = Math.Clamp(num + steps, 0, 15);
if (num2 != num) {
SubsystemTerrain.ChangeCell(x, y, z, Terrain.ReplaceData(cellValue, num2));
if (playSound) {
if (steps >= 0) {
// 添加燃料:播放放置音效
m_subsystemAmbientSounds.SubsystemAudio.PlaySound("Audio/BlockPlaced", 1f, 0f, ...);
} else {
// 衰减/熄灭:播放嘶嘶声
m_subsystemAmbientSounds.SubsystemAudio.PlayRandomSound("Audio/Sizzles", 1f, 0f, ...);
}
}
return true;
}
}
return false;
}csharp
// 营火自然衰减与雨水浇灭
public virtual void Update(float dt) {
// 每 5 游戏秒检查一次
if (m_subsystemTime.PeriodicGameTimeEvent(5.0, 0.0)) {
m_updateIndex++;
foreach (Point3 key in m_particleSystemsByCell.Keys) {
// 获取降水信息
PrecipitationShaftInfo precipitationShaftInfo = m_subsystemWeather.GetPrecipitationShaftInfo(key.X, key.Z);
// 条件1:正在下雨且营火暴露在雨中
// 条件2:每 6 次检查(30 游戏秒)自然衰减一次
if ((precipitationShaftInfo.Intensity > 0f && key.Y >= precipitationShaftInfo.YLimit - 1)
|| m_updateIndex % 6 == 0) {
m_toReduce.Add(key);
}
}
foreach (Point3 item in m_toReduce) {
ResizeCampfire(item.X, item.Y, item.Z, -1, true); // 尺寸减 1
}
m_toReduce.Clear();
}
}爆炸物方块行为(SubsystemExplosivesBlockBehavior.cs)
csharp
// 点燃引信
public bool IgniteFuse(int x, int y, int z) {
int cellContents = m_subsystemTerrain.Terrain.GetCellContents(x, y, z);
if (BlocksManager.Blocks[cellContents] is GunpowderKegBlock) {
// 火药桶:引信时间 6~7 秒
AddExplosive(new Point3(x, y, z), m_random.Float(6f, 7f));
return true;
}
if (BlocksManager.Blocks[cellContents] is DetonatorBlock) {
// 雷管:引信时间 0.8~1.2 秒
AddExplosive(new Point3(x, y, z), m_random.Float(0.8f, 1.2f));
return true;
}
return false;
}csharp
// 引信倒计时与引爆
public virtual void Update(float dt) {
foreach (ExplosiveData explosiveData in array) {
// 引信时间递减
explosiveData.TimeToExplosion -= dt;
if (explosiveData.TimeToExplosion <= 0f) {
// 引信归零,触发爆炸
m_subsystemExplosions.TryExplodeBlock(
explosiveData.Point.X, explosiveData.Point.Y, explosiveData.Point.Z, cellValue);
}
}
}csharp
// 邻居方块变化时检查火焰
public override void OnNeighborBlockChanged(int x, int y, int z, int neighborX, int neighborY, int neighborZ) {
// 如果相邻方块着火,点燃引信
if (m_subsystemFireBlockBehavior.IsCellOnFire(x, y, z)) {
IgniteFuse(x, y, z);
}
}
// 被爆炸波及时有概率连锁引爆
public override void OnExplosion(int value, int x, int y, int z, float damage) {
Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
if (block.GetExplosionPressure(value) > 0f
&& MathUtils.Saturate(damage / block.ExplosionResilience) > 0.01f
&& m_random.Float(0f, 1f) < 0.5f) { // 50% 概率连锁引爆
IgniteFuse(x, y, z);
}
}爆炸系统核心(SubsystemExplosions.cs)
csharp
// 尝试引爆方块
public bool TryExplodeBlock(int x, int y, int z, int value) {
Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
// 获取方块的爆炸压力和是否引燃
float explosionPressure = block.GetExplosionPressure(value);
bool explosionIncendiary = block.GetExplosionIncendiary(value);
if (explosionPressure > 0f) {
AddExplosion(x, y, z, explosionPressure, explosionIncendiary, false);
return true;
}
return false;
}csharp
// 爆炸模拟核心算法
public void SimulateExplosion(int x, int y, int z, float pressure, bool isIncendiary) {
// 最小传播阈值 = max(0.13 × sqrt(压力), 1)
float num = MathUtils.Max(0.13f * MathF.Pow(pressure, 0.5f), 1f);
// BFS 传播
int explosionPower = 0; // 累计已处理点数
int num3 = 0; // 迭代轮数
while (list.Count > 0 || list2.Count > 0) {
explosionPower += list.Count;
num3++;
// 第 7 轮后额外衰减
float num4 = 5f * MathUtils.Max(num3 - 7, 0);
// 本轮压力 = 初始压力 / (累计点数^0.66 + 额外衰减)
float num5 = pressure / (MathF.Pow(explosionPower, 0.66f) + num4);
if (num5 >= num) { // 压力仍大于阈值,继续传播
foreach (ProcessPoint item in list) {
float num7 = num5 + m_pressureByPoint.Get(item.X, item.Y, item.Z);
m_pressureByPoint.Set(item.X, item.Y, item.Z, num7);
// 向 6 个方向继续传播...
}
}
}
}csharp
// 方块破坏判定
public void TryAddPoint(int x, int y, int z, int axis, float currentPressure,
bool isIncendiary, List<ProcessPoint> toProcess, SparseSpatialArray<bool> processed) {
int cellValue = m_subsystemTerrain.Terrain.GetCellValue(x, y, z);
Block block = BlocksManager.Blocks[Terrain.ExtractContents(cellValue)];
// 基于坐标哈希的随机系数(1.0~2.0)
int explosionPower = (int)(MathUtils.Hash((uint)(x + 913 * y + 217546 * z)) % 100u);
float num3 = MathUtils.Lerp(1f, 2f, explosionPower / 100f);
if (explosionPower % 8 == 0) num3 *= 3f; // 12.5% 概率 ×3
// 周围 6 面的总压力
float num4 = m_pressureByPoint.Get(x-1,y,z) + m_pressureByPoint.Get(x+1,y,z)
+ m_pressureByPoint.Get(x,y-1,z) + m_pressureByPoint.Get(x,y+1,z)
+ m_pressureByPoint.Get(x,y,z-1) + m_pressureByPoint.Get(x,y,z+1);
// 破坏条件:总压力 / (爆炸抗性 × 随机系数) > 1
float num5 = MathUtils.Max(block.GetExplosionResilience(cellValue) * num3, 1f);
float num6 = num4 / num5;
if (num6 > 1f) {
// 方块被摧毁
m_subsystemTerrain.DestroyCell(0, x, y, z, Terrain.MakeBlockValue(0), true, true);
// 连锁爆炸:压力/抗性 > 5 时 95% 概率,否则 75%
float probability = num6 > 5f ? 0.95f : 0.75f;
if (m_random.Bool(probability)) {
TryExplodeBlock(x, y, z, cellValue);
}
}
}csharp
// 爆炸后处理:火焰引燃与伤害计算
public virtual void PostprocessExplosions(bool playExplosionSound) {
// 对受压力波及但未被摧毁的方块
foreach (var item2 in m_surroundingPressureByPoint.ToDictionary()) {
int cellValue = m_subsystemTerrain.Terrain.GetCellValue(item2.Key.X, item2.Key.Y, item2.Key.Z);
Block block = BlocksManager.Blocks[Terrain.ExtractContents(cellValue)];
// 火焰引燃概率
float probability = item2.Value.IsIncendiary ? 0.5f : 0.2f;
// 条件:方块可燃 且 压力/抗性 > 0.2
if (block.GetFireDuration(cellValue) > 0f
&& item2.Value.Pressure / block.GetExplosionResilience(cellValue) > 0.2f
&& m_random.Bool(probability)) {
// 引燃方块:燃烧桶扩散能力 1.0,普通爆炸 0.3
m_subsystemFireBlockBehavior.SetCellOnFire(
item2.Key.X, item2.Key.Y, item2.Key.Z,
item2.Value.IsIncendiary ? 1f : 0.3f);
}
}
// 对所有生物计算冲击力和伤害
foreach (ComponentBody body in m_subsystemBodies.Bodies) {
CalculateImpulseAndDamage(body, null, out Vector3 impulse, out float damage);
body.UnderExplosion(impulse, damage);
}
}csharp
// 爆炸伤害与冲击力计算
public virtual void CalculateImpulseAndDamage(Vector3 position, float mass,
float? obstaclePressure, out Vector3 impulse, out float damage) {
// 遍历周围 3×3×3 的压力点
float num = 0f; // 总压力
Vector3 zero = Vector3.Zero; // 压力方向
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
for (int k = -1; k <= 1; k++) {
float num5 = /* 获取该点压力 */;
zero += num5 * Vector3.Normalize(/* 远离爆炸中心的方向 */);
num += num5;
}
// 质量因子 = max(sqrt(质量), 1)
float num6 = MathUtils.Max(MathF.Pow(mass, 0.5f), 1f);
// 冲击力 = 5.56 × 方向 × sqrt(方向长度) / 质量因子
impulse = 5.5555553f * Vector3.Normalize(zero) * MathF.Sqrt(zero.Length()) / num6;
// 伤害 = 2.59 × sqrt(总压力) / 质量因子
damage = 2.59259248f * MathF.Sqrt(num) / num6;
}爆炸音效分级(SubsystemExplosions.cs)
csharp
// 根据总压力选择爆炸音效和噪音范围
if (pressure > 2000000f) {
m_subsystemAudio.PlaySound("Audio/Explosion7", 1f, ...); // 最大爆炸
m_subsystemNoise.MakeNoise(position, 1f, 130f); // 噪音范围 130 格
}
else if (pressure > 400000f) {
m_subsystemAudio.PlaySound("Audio/Explosion6", 1f, ...);
m_subsystemNoise.MakeNoise(position, 1f, 100f);
}
else if (pressure > 80000f) {
m_subsystemAudio.PlaySound("Audio/Explosion5", 1f, ...);
m_subsystemNoise.MakeNoise(position, 1f, 70f);
}
else if (pressure > 16000f) {
m_subsystemAudio.PlaySound("Audio/Explosion4", 1f, ...);
m_subsystemNoise.MakeNoise(position, 1f, 50f);
}
else if (pressure > 3500f) {
m_subsystemAudio.PlaySound("Audio/Explosion3", 1f, ...);
m_subsystemNoise.MakeNoise(position, 1f, 40f);
}
else if (pressure > 80f) {
m_subsystemAudio.PlaySound("Audio/Explosion2", 1f, ...);
m_subsystemNoise.MakeNoise(position, 1f, 35f);
}
else if (pressure > 0f) {
m_subsystemAudio.PlaySound("Audio/Explosion1", 1f, ...); // 最小爆炸
m_subsystemNoise.MakeNoise(position, 1f, 30f);
}Block.cs 虚方法定义
以下虚方法定义了方块与火焰/爆炸系统交互的接口。子类可覆盖这些方法来自定义行为。
csharp
// 火焰持续时间:方块被火焰烧穿所需的时间(游戏秒)
// 值为 0 表示方块不可燃
public float FireDuration;
public virtual float GetFireDuration(int value) => FireDuration;
// 燃料热值:作为营火燃料时的热量等级
// 值为 0 表示不能作为燃料
public float FuelHeatLevel;
public virtual float GetFuelHeatLevel(int value) => FuelHeatLevel;
// 燃料燃烧时间:作为营火燃料时能维持的燃烧时间(游戏秒)
public float FuelFireDuration;
public virtual float GetFuelFireDuration(int value) => FuelFireDuration;
// 爆炸抗性:方块抵抗爆炸的能力
// 值为 Infinity 表示不可被爆炸摧毁
public float ExplosionResilience;
public virtual float GetExplosionResilience(int value) => ExplosionResilience;
// 默认爆炸压力:方块被引爆时产生的爆炸压力
// 值为 0 表示方块不可爆炸
public float DefaultExplosionPressure;
public virtual float GetExplosionPressure(int value) => DefaultExplosionPressure;
// 默认是否引燃:爆炸是否附带火焰引燃效果
public bool DefaultExplosionIncendiary;
public virtual bool GetExplosionIncendiary(int value) => DefaultExplosionIncendiary;
// 爆炸是否保留掉落物:爆炸摧毁该方块时是否保留掉落物
public bool ExplosionKeepsPickables;参考资料
- Miraheze Survivalcraft Wiki:Fire
- Miraheze Survivalcraft Wiki:Campfire
- Miraheze Survivalcraft Wiki:Gunpowder Kegs
- Fandom 西语维基:Fuego
- Fandom 西语维基:Barril de pólvora
- 建筑与取暖
- 电路入门
IyDngavnhLDkuI7niIbngrgKCuaZrumAmueBq+eEsOOAgeiQpeeBq+WSjOeBq+iNr+ahtumDveS8muaPkOS+m+eDremHj+aIluegtOWdj+iDveWKm++8jOS9huWug+S7rOS4jeaYr+WQjOS4gOenjeacuuWItuOAguiLpea3t+S4uuS4gOiwiO+8jOWuueaYk+mAoOaIkOacqOWxi+WkseeBq+OAgeaOieiQveeJqeiiq+eDp+avge+8jOaIluWcqOeLreeqhOefv+mBk+WGheiiq+eIhueCuOazouWPiuOAggoKOjo6IGRhbmdlciDlhYjlnKjmtYvor5XkuJbnlYzpqozor4EK54iG54K45Lya5rC45LmF5pS55Y+Y5Zyw5b2i5bm25Y+v6IO95byV5Y+R6L+e6ZSB54Gr54G+44CC56ys5LiA5qyh5L2/55So5p+Q56eN54Gr6I2v5qG244CB54eD54On5by55oiW55S16LW354iG57uT5p6E5pe277yM5bqU5Zyo5Yib6YCg5rWL6K+V5LiW55WM6L+c56a75bu6562R5LiO5Yqo54mp6aqM6K+B77yM5LiN6KaB55u05o6l5Zyo5Li75a2Y5qGj6K+V6aqM44CCCjo6OgoKIyMg5LiJ56eN5py65Yi25YWI5YiG5byACgp8IOacuuWItiB8IOS4u+imgeeUqOmAlCB8IOaguOW/g+mjjumZqSB8CnwgLS0tIHwgLS0tIHwgLS0tIHwKfCDmma7pgJrngavnhLAgfCDnh4Png6flj6/nh4PmlrnlnZfjgIHkvKTlrrPlrp7kvZMgfCDolJPlu7bjgIHng6fmr4Hlu7rnrZHlkozmjonokL3niakgfAp8IOiQpeeBqyB8IOaPkOS+m+eDremHj+OAgeeFp+aYjuW5tumpsei1tumDqOWIhuaNlemjn+iAhSB8IOmdoOW+l+Wkqui/keS8muWPl+eDreaIluedgOeBq++8jOmcgOimgeaMgee7reihpeWFheeHg+aWmSB8Cnwg54iG54K454mpIHwg5b+r6YCf56C05Z2P5Zyw5b2i44CB5py65YWz5oiW5oiY5paX55So6YCUIHwg5pa55Z2X56C05Z2P44CB54Gr54G+5LiO6L+e6ZSB54iG54K4IHwKCjxkaXYgY2xhc3M9Im1vZGVsLWdhbGxlcnkgY29tcGFjdC1tb2RlbC1nYWxsZXJ5Ij4KICA8ZmlndXJlPjxpbWcgc3JjPSIvYXJjaGl2ZS1pbWFnZXMvZXh0ZXJuYWwtd2lraS9maXJlLWZhbmRvbS1lcy5wbmciIGFsdD0iRmFuZG9tIOilv+ivree7tOWfuuaUtuW9leeahOaZrumAmueBq+eEsOWbvuaghyI+PGZpZ2NhcHRpb24+5pmu6YCa54Gr54SwPC9maWdjYXB0aW9uPjwvZmlndXJlPgogIDxmaWd1cmU+PGltZyBzcmM9Ii9hcmNoaXZlLWltYWdlcy9leHRlcm5hbC13aWtpL2NhbXBmaXJlLWZhbmRvbS1lcy5wbmciIGFsdD0iRmFuZG9tIOilv+ivree7tOWfuuaUtuW9leeahOiQpeeBq+aooeWeiyI+PGZpZ2NhcHRpb24+6JCl54GrPC9maWdjYXB0aW9uPjwvZmlndXJlPgo8L2Rpdj4KCuiQpeeBq+aYr+ebuOWvueWPr+aOp+eahOeDrea6kO+8jOS4jeetieS6juWPr+S7peWcqOS7u+S9leS9jee9ruWuieWFqOaUvue9ruOAguaZrumAmueBq+eEsOWImeWPr+iDveeUseeBq+aftOOAgeWyqea1huOAgembt+WHu+OAgeeHg+eDp+W8ueiNr+aIlueIhueCuOW8lei1t++8jOW5tuayv+WPr+eHg+adkOaWmee7p+e7reaJqeaVo+OAggoKIyMg54Gr54Sw57O757ufCgo+IOeBq+eEsOaYr+a4uOaIj+S4reacgOWFt+aJqeaVo+aAp+eahOWNsemZqea6kOOAguS4gOaXpueCueeHg++8jOWug+S8muayv+edgOWPr+eHg+eJqeWQkeWbm+WRqOiUk+W7tu+8jOeDp+avgeacqOWxi+OAgeajruael+S5g+iHs+aVtOS4quWfuuWcsOOAguS9hueBq+eEsOS5n+acieinhOW+i+WPr+W+quKAlOKAlOeQhuino+Wug+eahOS8oOaSreaWueW8j+WSjOWPr+eHg+eJqeaVsOaNru+8jOS9oOWwseiDveacieaViOmYsueBq+OAggoKIyMjIOeBq+eEsOeahOivnueUn+S4juWtmOWcqOW9ouW8jwoKLSDngavnhLDmlrnlnZfnvJblj7fkuLogKioxMDQqKu+8jOWug+S4jeaYr+eLrOeri+WtmOWcqOeahOaWueWdl++8jOiAjOaYryoq6ZmE552A5Zyo5Y+v54eD5pa55Z2X6KGo6Z2iKirnmoTngavnhLDpnaLjgIIKLSDlvZPngavnhLDmlrnlnZfmlbDmja7lgLzkuLogMCDkuJTkuIvmlrnmlrnlnZfnmoTngavnhLDmjIHnu63ml7bpl7TkuLogMCDml7bvvIzngavnhLDmlrnlnZfkvJrooqvnp7vpmaTvvIjoh6rnhLbnhoTnga3vvInjgIIKLSDmr4/kuKrngavnhLDngrnpg73nu7TmiqTkuIDnu4QqKueHg+eDp+iuoeaXtuWZqCoq77yM5YiG5Yir5a+55bqU5Zub5Liq5rC05bmz5pa55ZCR5ZKM5ZCR5LiL5pa554On56m/44CC6K6h5pe25Zmo55qE5Yid5aeL5YC8562J5LqO5pa55Z2X55qE54Gr54Sw5oyB57ut5pe26Ze077yM5L2G5pyJIMKxMjUlIOeahOmaj+acuuazouWKqO+8jOS9v+avj+asoeeBq+eBvueahOiUk+W7tumAn+W6pumDveS4jeWujOWFqOebuOWQjOOAggoKIyMjIOeBq+eEsOS8oOaSreacuuWItgoK54Gr54Sw5Lyg5pKt5pyJ5Lik56eN5pa55byP77yaKirnm7TmjqXng6fnqb8qKuWSjCoq5qaC546H6JST5bu2KirjgIIKCioq55u05o6l54On56m/KirvvJrlvZPmn5DkuKrmlrnlkJHnmoTnh4Png6forqHml7blmajlvZLpm7bml7bvvIzor6XmlrnlkJHnm7jpgrvnmoTlj6/nh4PmlrnlnZfkvJrooqvnm7TmjqXmkafmr4HvvIjlj5jkuLrnqbrmsJTvvInvvIzlubblnKjlhbblkajlm7TnlJ/miJDmlrDnmoTngavnhLDjgILmlrDngavnhLDnmoTolJPlu7bog73lipvmr4/mrKHkvKDmkq0qKuihsOWHjyAxNSUqKu+8jOWIneWni+S4uiAxLjDvvIzlvZPpmY3oh7MgMC4yNSDku6XkuIvml7bng6fnqb/nmoTmlrnlnZfkuI3lho3nlJ/miJDmlrDngavnhLDjgIIKCioq5qaC546H6JST5bu2KirvvJrngavnhLDlnKjng6fnqb/mlrnlnZfnmoTlkIzml7bvvIzov5jkvJrku6XkuIDlrprmpoLnjoflkJHpmYTov5HnmoTmlrnlnZfmianmlaPjgIIqKuWFs+mUruinhOW+iyoq77yaCgotICoq5ZCR5LiK6JST5bu25pyA5b+rKirvvJrmraPkuIrmlrkgMSDmoLzmr4/mrKHmiavmj4/mnIkgNCUg5qaC546H6KKr5byV54eDCi0gKirlkJHkuIvolJPlu7bmnIDmhaIqKu+8muato+S4i+aWuSAxIOagvOavj+asoeaJq+aPj+WPquaciSAyJSDmpoLnjofigJTigJTlkJHkuIrolJPlu7bpgJ/luqbmmK/lkJHkuIvnmoQqKuS4pOWAjSoqCi0gKirmsLTlubPmlrnlkJHlsYXkuK0qKu+8muS+p+mdoiAxIOagvOe6piAyJSDmpoLnjocKLSAqKuacgOWkp+iUk+W7tuiMg+WbtCoq77ya5ZCR5LiK5ZKM5rC05bmz5pa55ZCR5pyA6L+cIDIuNSDmoLzvvIzlkJHkuIvmnIDov5wgMS41IOagvAoK54On5q+B5pON5L2c5q+PICoqNSDmuLjmiI/np5IqKu+8iOe6piA0IOeOsOWunuenku+8ieaJuemHj+WkhOeQhuS4gOasoe+8jOWxiuaXtuaJgOacieaOkumYn+etieW+heeDp+avgeeahOaWueWdl+S8muiiq+WQjOaXtuaRp+avgeOAggoKIyMjIOWPr+eHg+eJqeaVsOaNrgoK5LiN5ZCM5pa55Z2X55qE54Gr54Sw5oyB57ut5pe26Ze05ZKM54iG54K45oqX5oCn5ZCE5LiN55u45ZCM44CC54Gr54Sw5oyB57ut5pe26Ze06LaK6ZW/77yM5pa55Z2X54On56m/5omA6ZyA55qE5pe26Ze06LaK5LmF44CCCgoqKuW4uOingeWPr+eHg+aWueWdl+S4gOiniCoq77yaCgp8IOaWueWdlyB8IOeBq+eEsOaMgee7reaXtumXtCB8IOeIhueCuOaKl+aApyB8IOivtOaYjiB8CnwtLS0tLS18LS0tLS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS18Cnwg5ZCE56eN5Y6f5pyoIHwgMjAgfCAyMCB8IOeHg+eDp+i+g+aFou+8jOaYr+W7uuetkeS4u+imgeWPr+eHg+eJqSB8Cnwg5pyo5p2/IHwgMjAgfCAyMCB8IOS4juWOn+acqOebuOWQjCB8Cnwg5ZCE56eN5qCR5Y+2IHwgOCB8IDIgfCDnh4Png6flv6vvvIzmnoHmmJPlvJXnh4MgfAp8IOiNieOAgeiKseOAgem7kem6piB8IDYgfCAyIHwg54eD54On5p6B5b+r77yM54Gr54Sw556s6Ze05omp5pWjIHwKfCDmoJHoi5cgfCA4IHwgMiB8IHwKfCDku5nkurrmjowgfCAxMCB8IDEwIHwgfAp8IOacqOmXqCB8IDEyIHwgMyB8IHwKfCDmnKjmoIXmoI8gfCAxNSB8IDMgfCB8Cnwg5pyo5qW85qKvL+WPsOmYtiB8IDE1IHwgNSB8IHwKfCDlt6XkvZzlj7Av566x5a2QIHwgMjAgfCA1IHwgfAp8IOeOu+eSg+eqlyB8IDE1IHwgMiB8IOWPl+eDreeijuijgiB8Cnwg54Wk54Kt5Z2XIHwgOTk5OTk5IHwgNTAgfCDlh6DkuY7msLjkuI3ng6flsL0gfAp8IOWNl+eTnCB8IDEwIHwgMiB8IHwKfCDol6TolJMgfCA2IHwgMSB8IHwKCj4gKirms6jmhI8qKu+8mueBq+eEsOaMgee7reaXtumXtOS4uiAwIOeahOaWueWdl++8iOWmguefs+WktOOAgeazpeWcn++8ieS4jeS8muiiq+eBq+eEsOeCueeHg++8jOeBq+eEsOmBh+WIsOWug+S7rOS8muWBnOatouiUk+W7tuOAggoKIyMg5aSx54Gr5pe25oCO5LmI5aSE55CGCgoxLiDlv6vpgJ/nprvlvIDnh4Png6fmlrnlnZflkozlj6/og73lgJLloYzjgIHniIbngrjnmoTljLrln5/jgIIKMi4g5L2/55So5rC05oiW56e76Zmk5LuN5Zyo54eD54On55qE5pa55Z2X5YiH5pat54Gr5Yq/77yb5LiN6KaB56uZ5Zyo54Gr54Sw5Lit5pON5L2c44CCCjMuIOaKiuacquiiq+eCueeHg+eahOeHg+aWmeOAgeeBq+iNr+ahtuWSjOi0temHjeaOieiQveeJqeenu+WHuuS8oOaSreaWueWQkeOAggo0LiDngavnhoTnga3lkI7mo4Dmn6XlsYvpobbjgIHlpLnlsYLjgIHmoJHlj7blkoznm7jpgrvmnKjnu5PmnoTvvIzpmLLmraLpgZfmvI/ngavngrnjgIIKNS4g6Zu36Zuo5pyf6Ze05LiN6KaB56uL5Yi75Zyo6auY5aSE5L+u5aSN5Y+v54eD5bGL6aG277yM5YWI562J5b6F546v5aKDCgo+IOiiq+eBq+eEsOadgOatu+eahOWKqOeJqeWPr+iDveeVmeS4i+eGn+iCie+8jOS9huearumdqeOAgee+veavm+OAgemejeWFt+etieWFtuS7luaOieiQveeJqeS5n+WPr+iDveiiq+eDp+avgeOAggoKIyMjIOeBq+eEsOmYsuaKpOW7uuiurgoK5qC55o2u54Gr54Sw5Lyg5pKt6KeE5b6L77yM546p5a625Y+v5Lul6YeH5Y+W5Lul5LiL5o6q5pa977yaCgotICoq6Ziy54Gr6ZqU56a75bimKirvvJrlnKjmnKjlu7rnrZHlkajlm7TnlZnlh7ogMyDmoLzku6XkuIrnmoTpnZ7lj6/nh4PljLrln5/vvIjnn7PlpLTjgIHms6XlnJ/nrYnvvInvvIzlm6DkuLrngavnhLDmnIDlpKfmsLTlubPolJPlu7bojIPlm7TkuLogMi41IOagvAotICoq5rOo5oSP5LiK5pa556m66Ze0KirvvJrngavnhLDlkJHkuIrolJPlu7bmpoLnjofmmK/lkJHkuIvnmoTkuKTlgI3vvIzmnKjlsYvpobbkuIrmlrnkuI3opoHmnInmoJHlj7bnrYnmmJPnh4PniakKLSAqKumbqOWkqeWuieWFqCoq77ya6Zuo5rC05Lya5rWH54Gt54Gr54Sw77yM6Zuo5aSp54Gr54G+6aOO6Zmp5aSn5bmF6ZmN5L2OCi0gKirmsLTmobblpIfnlKgqKu+8muawtOWPr+S7peebtOaOpeaJkeeBreeBq+eEsOaWueWdlwoKIyMg6JCl54Gr57O757ufCgo+IOiQpeeBq+aYr+eOqeWutuWPr+aOp+eahOeBq+a6kO+8jOeUqOS6jueFp+aYjuWSjOeDuemlquOAguS4juiHqueEtueBq+eEsOS4jeWQjO+8jOiQpeeBq+S4jeS8muiUk+W7tu+8jOS9humcgOimgeaMgee7rea3u+WKoOeHg+aWmeaJjeiDvee7tOaMgeOAgueQhuino+iQpeeBq+eahOeHg+aWmeacuuWItu+8jOS9oOWwseiDvemrmOaViOWIqeeUqOavj+S4gOWdl+acqOadkOOAggoKIyMjIOiQpeeBq+WfuuehgAoK6JCl54Gr5pa55Z2X55qE5bC65a+45a2Y5YKo5Zyo5pWw5o2u5YC85Lit77yM6IyD5Zu05Li6ICoqMH4xNSoq77yM5YW25LitIDAg6KGo56S654aE54Gt77yMMTUg6KGo56S65pyA5aSn54Gr5Yqb44CC5bC65a+46LaK5aSn54Gr54Sw57KS5a2Q6LaK5aSn77yM5LuO5b6u5byx54Gr6IuX5Yiw5pe655ub56+d54Gr57q/5oCn5Y+Y5YyW44CCCgojIyMg5re75Yqg54eD5paZCgrnjqnlrrblj6/ku6XpgJrov4fku6XkuIvmlrnlvI/mt7vliqDnh4PmlpnvvJoKLSAqKuaJi+aMgeeHg+aWmeWPs+mUrueCueWHuyoq6JCl54GrCi0gKirlsIbnh4Pmlpnnianlk4HmipXmjrcqKuWIsOiQpeeBq+S4iu+8iOaKleWwhOeJqeWRveS4re+8iQoK5re75Yqg54eD5paZ5pe277yM57O757uf5oyJ5Lul5LiL6YC76L6R5aSE55CG77yaCgoxLiAqKueIhueCuOeJqeajgOafpSoq77ya5aaC5p6c5oqV5YWl55qE54mp5ZOB5piv54iG54K454mp77yI5aaC54Gr6I2v5qG277yJ77yM55u05o6l6Kem5Y+R54iG54K4CjIuICoq54Gt54Gr54mp5qOA5p+lKirvvJrlpoLmnpzmipXlhaXpm6rlnZfjgIHpm6rnkIPmiJblhrDlnZfvvIzokKXngavlsLrlr7jlh4/lsI8gMQozLiAqKueHg+aWmeiuoeeulyoq77ya5aaC5p6c54mp5ZOB5pyJ54eD5paZ54Ot5YC877yIPjDvvInvvIzmr4/kuKrnh4Pmlpnlj6/lop7liqDnmoTokKXngavlsLrlr7ggPSDnh4Pmlpnnh4Png6fml7bpl7Qgw7cgNe+8iOS9hueHg+eDp+aXtumXtOi2hei/hyAyMCDnmoTlj6rmjIkgMjAg566X77yJ44CC5bCP5pWw6YOo5YiG5oyJ5qaC546H6L+b5L2N77yI5aaCIDIuMyDmraXmnIkgMzAlIOamgueOh+WPmOS4uiAzIOatpe+8ieOAggoKKirluLjop4Hnh4PmlpnmlYjnjoflr7nmr5QqKu+8mgoKfCDnh4PmlpkgfCDnh4Pmlpnng63lgLwgfCDnh4Pmlpnnh4Png6fml7bpl7QgfCDmr4/kuKrlop7liqDmraXmlbAgfCDor7TmmI4gfAp8LS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tfC0tLS0tLXwKfCDnhaTngq3lnZcgfCAyIHwgNjAwIHwgNCB8IOacgOaMgeS5heeahOeHg+aWme+8iOiiq+mZkOWItuS4uiAyMC81PTTvvIkgfAp8IOeFpOeCrSB8IDIgfCA4MCB8IDQgfCDlkIzmoLfooqvpmZDliLbkuLogNCDmraUgfAp8IOehq+ejuiB8IDIgfCAxMCB8IDIgfCB8Cnwg5Y6f5pyoIHwgMSB8IDIwIHwgNCB8IOaAp+S7t+avlOmrmCB8Cnwg5pyo5p2/IHwgMSB8IDEwIHwgMiB8IHwKfCDmnKjmo40gfCAxIHwgNSB8IDEgfCB8Cnwg5qCR5Y+2IHwgMSB8IDEgfCAwLjIgfCDlh6DkuY7ml6DnlKggfAp8IOiNiSB8IDEgfCAwLjUgfCAwLjEgfCDlj6/lv73nlaUgfAp8IOagkeiLlyB8IDEgfCAwLjUgfCAwLjEgfCDlj6/lv73nlaUgfAp8IOS7meS6uuaOjCB8IDEgfCA1IHwgMSB8IHwKfCDlt6XkvZzlj7Av566x5a2QIHwgMSB8IDUgfCAxIHwg57Sn5oCl5pe25Y+v5ouG5a625YW35b2T5p+054OnIHwKCj4gKirmj5DnpLoqKu+8mjEg5Liq5Y6f5pyoID0gNCDmraXokKXngavlop7ph4/vvIzmhI/lkbPnnYAgNCDkuKrljp/mnKjlsLHog73miorokKXngavku44gMCDliqDmu6HliLAgMTXjgILogIznhaTngq3lnZfomb3nhLbnh4Png6fml7bpl7Tplb/ovr4gNjAw77yM5L2G5Y+X5LiK6ZmQIDIwIOeahOmZkOWItu+8jOavj+S4quS5n+WPquiDveWinuWKoCA0IOatpe+8jOS4juWOn+acqOaViOeOh+ebuOWQjOOAguWboOatpCoq5Y6f5pyo5piv5oCn5Lu35q+U5pyA6auY55qE6JCl54Gr54eD5paZKirjgIIKCiMjIyDokKXngavoobDlh4/kuI7nhoTnga0KCuiQpeeBq+S8muiHqueEtuihsOWHj++8jOihsOWHj+acieS4pOenjeinpuWPkeaWueW8j++8mgoKKirpm6jmsLTmtYfnga0qKu+8muavjyA1IOa4uOaIj+enkuajgOafpeS4gOasoe+8jOWmguaenOiQpeeBq+aJgOWcqOS9jee9ruato+WcqOmZjembqO+8iOmZjeawtOW8uuW6piA+IDDvvInkuJTokKXngavpq5jluqYgPj0g6ZmN5rC06auY5bqm5LiK6ZmQIC0gMe+8jOiQpeeBq+WwuuWvuOWHjyAx44CC6L+Z5oSP5ZGz552AKirpnLLlpKnnmoTokKXngavlnKjpm6jlpKnkvJrpgJDmuJDnhoTnga0qKuOAggoKKiroh6rnhLboobDlh48qKu+8muavjyA2IOasoeajgOafpeWRqOacn++8iOWNs+avjyAzMCDmuLjmiI/np5LvvIznuqYgMjQg546w5a6e56eS77yJ77yM5peg6K665aSp5rCU5aaC5L2V77yM6JCl54Gr5bC65a+46YO95Lya5YePIDHjgILov5nmmK/okKXngavnmoToh6rnhLbmtojogJfjgIIKCjo6OiB0aXAg6JCl54Gr6Ziy6ZuoCumcsuWkqeeahOiQpeeBq+S8muWboOS4uumZjembqOiAjOeGhOeBre+8jOWPr+S7peWcqOiQpeeBq+S4iumdouaQreW7uumBruiUveeJqeadpemYsuatouiiq+mbqOawtOa1h+eBreOAggo6OjoKCiMjIyDokKXngavnmoTmraPnoa7lrprkvY0KCuiQpeeBq+mAguWQiOaXqeacn+WPluaaluOAgeeDmOW5suWSjOeFp+aYjuOAgueHg+aWmeWPr+S7pemAmui/h+aKleWFpeWPr+eHg+eJqeihpeWFhe+8jOmbqOmbquS8muiuqee7tOaMgeeBq+WKv+abtOWbsOmavuOAguW4g+e9ruaXtuiHs+WwkeWBmuWIsO+8mgoKLSDlkajlm7TnlZnlh7rkuI3lj6/nh4Pmk43kvZzljLrvvJsKLSDkuI3mjKHkvY/pl6jlj6PlkozllK/kuIDmkqTpgIDpgJrpgZPvvJsKLSDkuI3miorniIbngrjnianlvZPnh4PmlpnmipXlhaXvvJsKLSDnnaHliY3or4TkvLDliankvZnngavlir/lkozlrqTlhoXmuKnluqbvvIzkuI3lgYforr7lroPkvJrmlbTlpJzkv53mjIHvvJsKLSDkvZPmuKnov4fpq5jml7bnq4vliLvmi4nlvIDot53nprvjgIIKCuWNs+S9v+aXgei+ueacieeDrea6kO+8jOmcsuWkqeOAgea9rua5v+aIluS4jeespuWQiOedoeecoOadoeS7tueahOS9jee9ruS7jeWPr+iDveaXoOazleWuieWFqOS8keaBr+OAggoKIyMg54iG54K457O757ufCgo+IOeIhueCuOaYr+a4uOaIj+S4reacgOWFt+egtOWdj+WKm+eahOeerOmXtOS6i+S7tuOAgueBq+iNr+ahtuOAgembt+euoeWSjOeHg+eDp+ahtumDveiDveW8leWPkeeIhueCuO+8jOaRp+avgeaWueWdl+OAgeS8pOWus+eUn+eJqeOAgeeUmuiHs+W8leWPkei/nueOr+eBq+eBvuOAgueQhuino+eIhueCuOeahOWOi+WKm+S8oOaSreWSjOi/numUgeacuuWItu+8jOS9oOaJjeiDveWuieWFqOS9v+eUqOeIhueCuOeJqe+8jOS5n+iDveWcqOeIhueCuOS4reW5uOWtmOOAggoKIyMjIOeIhueCuOeJqeenjeexuwoK5ri45oiP5Lit55qE54iG54K454mp5YiG5Li65Lik5aSn57G777ya54Gr6I2v5qG25ZKM6Zu3566h44CCCgoqKueBq+iNr+ahtuaVsOaNrioq77yaCgp8IOWQjeensCB8IOeIhueCuOWOi+WKmyB8IOaYr+WQpuW8leeHgyB8IOW8leS/oeaXtumXtCB8IOivtOaYjiB8CnwtLS0tLS18LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS18LS0tLS0tfAp8IOWwj+eBq+iNr+ahtiB8IDYwIHwg5ZCmIHwgNn43IOenkiB8IOWfuuehgOeIhueCuOeJqSB8Cnwg5Lit54Gr6I2v5qG2IHwgMzYwIHwg5ZCmIHwgNn43IOenkiB8IOS4reetieWogeWKmyB8Cnwg5aSn54Gr6I2v5qG2IHwgMjE2MCB8IOWQpiB8IDZ+NyDnp5IgfCDlpKfop4TmqKHnoLTlnY8gfAp8IOWwj+eHg+eDp+ahtiB8IDUwIHwg5pivIHwgNn43IOenkiB8IOeIhueCuOWQjuW8leWPkeeBq+eBviB8Cnwg5Lit54eD54On5qG2IHwgMzAwIHwg5pivIHwgNn43IOenkiB8IHwKfCDlpKfnh4Png6fmobYgfCAxODAwIHwg5pivIHwgNn43IOenkiB8IHwKCj4gKirlvJXkv6Hml7bpl7QqKu+8muS7jueCueeHg+WIsOeIhueCuOeahOeOsOWunuenkuaVsO+8jOWcqCA2fjcg56eS5LmL6Ze06ZqP5py644CC6L+Z5q615pe26Ze05YaF5Lya5pKt5pS+5byV5L+h54eD54On55qE5Zi25Zi25aOw5ZKM54Gr6Iqx57KS5a2Q5pWI5p6c44CCCgoqKumbt+euoSoq77yaCgp8IOWQjeensCB8IOeIhueCuOWOi+WKmyB8IOaYr+WQpuW8leeHgyB8IOW8leS/oeaXtumXtCB8CnwtLS0tLS18LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS18Cnwg6Zu3566hIHwgMTAgfCDlkKYgfCAwLjh+MS4yIOenkiB8Cgo+IOmbt+euoeW8leS/oeaegeefre+8jOWHoOS5jueerOmXtOeIhueCuO+8jOmAmuW4uOeUqOS6jueUteawlOeUtei3r+inpuWPkeeahOeyvuehrueIhuegtOOAggoKIyMjIOaKleaOt+Wei+eIhueCuOatpuWZqAoKPiDkuI7ngavoja/mobbpnIDopoHmlL7nva7lkI7lvJXnh4PkuI3lkIzvvIzngrjlvLnlkoznh4Png6flvLnmmK8qKuaKleaOt+WQjuiHquWKqOWumuaXtueIhueCuCoq55qE5q2m5Zmo77yM6YCC5ZCI5oiY5paX5Lit5b+r6YCf5L2/55So44CCCgrngavoja/mobbmmK8i5pS+572u5Z6LIueIhueCuOeJqeKAlOKAlOS9oOW+l+WFiOaUvuWlveWGjeeCueeBq+OAguiAjOeCuOW8ueWSjOeHg+eDp+W8ueWxnuS6jiLmipXmjrflnosi77yM5omU5Ye65Y675ZCOKio1IOenkuiHquWKqOeIhueCuCoq77yM5peg6ZyA6aKd5aSW54K554Gr44CC5q2k5aSW77yM54Gr6I2v5pys6Lqr5Lmf5Y+v5Lul5oqV5o6377yM5L2G5oCn6LSo5pyJ5omA5LiN5ZCM44CCCgoqKuaKleaOt+Wei+eIhueCuOeJqeaVsOaNrioq77yaCgp8IOWQjeensCB8IOWIhuexuyB8IOeIhueCuOWOi+WKmyB8IOaYr+WQpuW8leeHgyB8IOaKleaOt+mAn+W6piB8IOacgOWkp+WghuWPoCB8IOeJueauiuivtOaYjiB8CnwtLS0tLS18LS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS18LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS18Cnwg54K45by5IHwg5q2m5ZmoIHwgNjAgfCDlkKYgfCAxNCB8IDI0IHwg5oqV5Ye65ZCOIDUg56eS6Ieq5Yqo54iG54K477yM55m96Imy54Of6Zu+5bC+6L+5IHwKfCDnh4Png6flvLkgfCDmrablmaggfCA1MCB8IOaYryB8IDE0IHwgMjQgfCDmipXlh7rlkI4gNSDnp5Loh6rliqjniIbngrjvvIznsonnuqLoibLng5/pm77lsL7ov7nvvIzniIbngrjlkI7lvJXlj5Hngavngb4gfAp8IOeBq+iNryB8IOeJqeWTgSB8IDYwIHwg5ZCmIHwgMTQgfCA0MCB8IOWPr+aKleaOt+S9huS4jeS8muiHquWKqOeIhueCuO+8jOS4u+imgeeUqOS9nOeHg+aWmeaIluWQiOaIkOadkOaWmSB8CgoqKueCuOW8uSB2cyDngavoja/mobblr7nmr5QqKu+8mgoKfCDnibnmgKcgfCDngrjlvLkgLyDnh4Png6flvLkgfCDngavoja/mobYgLyDnh4Png6fmobYgfAp8LS0tLS0tfC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLXwKfCDkvb/nlKjmlrnlvI8gfCDmipXmjrflkI7oh6rliqjlrprml7bniIbngrggfCDmlL7nva7lkI7pnIDngavnhLAv55S16LevL+eIhueCuOW8leeHgyB8Cnwg5byV54iG5bu26L+fIHwg5Zu65a6aIDUg56eS77yI5oqV5Ye65ZCO6K6h5pe277yJIHwgNn43IOenkuW8leS/oe+8iOeCueeHg+WQjuiuoeaXtu+8iSB8Cnwg54iG54K45Y6L5YqbIHwgNjAgLyA1MCB8IDYwfjIxNjAgLyA1MH4xODAw77yI5YiG5aSn5Lit5bCP5LiJ5qGj77yJIHwKfCDmkp7lh7vniIbngrggfCDkuI3kvJrvvIjokL3lnLDlkI7nrYnorqHml7blmajvvIkgfCDkvJrvvIjngavoja/mobbluKbmkp7lh7vniIbngrjooYzkuLrvvIkgfAp8IOWPr+aUvue9riB8IOWQpu+8iOaKleaOt+eJqe+8iSB8IOaYr++8iOWPr+S9nOS4uuaWueWdl+aUvue9ru+8iSB8Cnwg54Of6Zu+5bC+6L+5IHwg5pyJ77yI55m96ImyL+eyiee6ouiJsu+8iSB8IOaXoCB8Cnwg6YCC55So5Zy65pmvIHwg5oiY5paX5Lit5b+r6YCf5oqV5o63IHwg5a6a54K554iG56C044CB6Zm36Zix44CB55S16Lev5o6n5Yi2IHwKCj4gKirngrjlvLnnmoTlrprml7bmnLrliLYqKu+8mueCuOW8ueaKleWHuuWQjuW8gOWni+iuoeaXtu+8jDUg56eS5ZCO5Zyo5b2T5YmN5L2N572u54iG54K444CC5pyf6Ze054K45by55Lya5ouW5puz54Of6Zu+5bC+6L+577yI5pmu6YCa54K45by555m96Imy77yM54eD54On5by557KJ57qi6Imy77yJ77yM5pa55L6/5L2g5Yik5pat54iG54K45pe25py644CC54K45by56JC95Zyw5ZCO5LiN5Lya5YOP54Gr6I2v5qG26YKj5qC35pKe5Ye754iG54K477yM6ICM5piv6Z2Z6Z2Z562J5b6F6K6h5pe25Zmo5b2S6Zu244CCCgo+ICoq54eD54On5by555qE54m55q6K5LmL5aSEKirvvJrnh4Png6flvLnniIbngrjljovlipvmr5TngrjlvLnnlaXkvY7vvIg1MCB2cyA2MO+8ie+8jOS9hueIhueCuOWQjuS8muS7pSA1MCUg5qaC546H5byV54eD5ZGo5Zu05Y+v54eD5pa55Z2X77yM54Gr54Sw5omp5pWj6IO95Yqb5Li65ruh5YC877yIMS4w77yJ77yM5p6B5piT5byV5Y+R5aSn6Z2i56ev54Gr54G+44CC6YCC5ZCI55So5p2l54On5q+B5pyo5Yi25bu6562R5oiW5qOu5p6X44CCCgo+ICoq54Gr6I2v55qE5a6a5L2NKirvvJrngavoja/omb3nhLbkuZ/mnInniIbngrjljovlipsgNjDvvIzkvYblroPlj6rlhbfmnInmipXmjrfooYzkuLrvvIzmsqHmnInngrjlvLnnmoTlrprml7bniIbngrjooYzkuLrvvIzlm6DmraTmipXmjrflkI7kuI3kvJrniIbngrjjgILngavoja/nmoTkuLvopoHnlKjpgJTmmK/kvZzkuLrnh4PmlpnvvIjng63lgLwgMu+8jOeHg+eDp+aXtumXtCAxMO+8ieWSjOWQiOaIkOadkOaWme+8iOWItuS9nOeBq+iNr+ahtuOAgeeCuOW8ueetie+8ieOAggoKIyMjIOW8leeIhuaWueW8jwoK54iG54K454mp5pyJ5Lul5LiL5Yeg56eN5byV54iG6YCU5b6E77yaCgoxLiAqKueBq+eEsOW8leeHgyoq77ya5b2T54iG54K454mp55u46YK75pa55Z2X552A54Gr5pe277yM6Ieq5Yqo54K554eD5byV5L+hCjIuICoq54iG54K45rOi5Y+KKirvvJrlvZPniIbngrjljovlipvms6Llj4rliLDniIbngrjnianml7bvvIzmnIkgNTAlIOamgueOh+eCueeHg+W8leS/oe+8iOWJjeaPkOaYr+WOi+WKmy/niIbngrjmipfmgKcgPiAwLjAx77yJCjMuICoq55S15rCU6Kem5Y+RKirvvJrngavoja/mobblj6/kvZzkuLrnlLXmsJTlhYPku7bvvIzpgJrov4fnlLXot6/kv6Hlj7fov5znqIvlvJXniIYKNC4gKirmipXlsITnianmkp7lh7sqKu+8muW4puacieaSnuWHu+eIhueCuOihjOS4uueahOaWueWdl++8iOWmgueureefouOAgeWtkOW8ue+8ieWRveS4reaXtuWPr+ebtOaOpeinpuWPkQoK54Gr6I2v5qG25pyJ5LiN5ZCM6KeE5qC877yM5aiB5Yqb5ZKM5b2x5ZON6IyD5Zu06ZqP6KeE5qC85aKe5aSn44CC5a6D5Lus5Y+v6KKr54Gr54Sw44CB5by56I2v44CB5YW25LuW54iG54K45oiW55S15rCU6KOF572u6Kem5Y+R77yb55S15rCU6LW354iG6YCC5ZCI5oqK546p5a625LiO54iG5b+D5YiG5byA77yM5L2G5o6l57q/6ZSZ6K+v44CB5Yy65Z2X54q25oCB5ZKM6IGU5py65bu26L+f5LuN5Y+v6IO96YCg5oiQ6K+v6Kem5Y+R44CCCgo8ZGl2IGNsYXNzPSJtb2RlbC1nYWxsZXJ5IGV4cGxvc2l2ZS1nYWxsZXJ5Ij4KICA8ZmlndXJlPjxpbWcgc3JjPSIvYXJjaGl2ZS1pbWFnZXMvZXh0ZXJuYWwtd2lraS9rZWctc21hbGwtZmFuZG9tLWVzLnBuZyIgYWx0PSLlsI/lnovngavoja/mobbmqKHlnosiPjxmaWdjYXB0aW9uPuWwj+Wei+eBq+iNr+ahtjwvZmlnY2FwdGlvbj48L2ZpZ3VyZT4KICA8ZmlndXJlPjxpbWcgc3JjPSIvYXJjaGl2ZS1pbWFnZXMvZXh0ZXJuYWwtd2lraS9rZWctbWVkaXVtLWZhbmRvbS1lcy5wbmciIGFsdD0i5Lit5Z6L54Gr6I2v5qG25qih5Z6LIj48ZmlnY2FwdGlvbj7kuK3lnovngavoja/mobY8L2ZpZ2NhcHRpb24+PC9maWd1cmU+CiAgPGZpZ3VyZT48aW1nIHNyYz0iL2FyY2hpdmUtaW1hZ2VzL2V4dGVybmFsLXdpa2kva2VnLWxhcmdlLWZhbmRvbS1lcy5wbmciIGFsdD0i5aSn5Z6L54Gr6I2v5qG25qih5Z6LIj48ZmlnY2FwdGlvbj7lpKflnovngavoja/mobY8L2ZpZ2NhcHRpb24+PC9maWd1cmU+CiAgPGZpZ3VyZT48aW1nIHNyYz0iL2FyY2hpdmUtaW1hZ2VzL2V4dGVybmFsLXdpa2kva2VnLWluY2VuZGlhcnktZmFuZG9tLWVzLnBuZyIgYWx0PSLlpKflnovnh4Png6fngavoja/mobbmqKHlnosiPjxmaWdjYXB0aW9uPuWkp+Wei+eHg+eDp+eBq+iNr+ahtjwvZmlnY2FwdGlvbj48L2ZpZ3VyZT4KICA8ZmlndXJlPjxpbWcgc3JjPSIvYXJjaGl2ZS1pbWFnZXMvZXh0ZXJuYWwtd2lraS9kZXRvbmF0b3ItZmFuZG9tLWVzLnBuZyIgYWx0PSLnlLXpm7fnrqHmqKHlnosiPjxmaWdjYXB0aW9uPueUtembt+euoTwvZmlnY2FwdGlvbj48L2ZpZ3VyZT4KPC9kaXY+CgrmqKHlnovlm77nlKjkuo7ljLrliIblsLrlr7jkuI7nh4Png6flj5jkvZPvvIzkuI3ooajnpLrlronlhajot53nprvjgILngavoja/mobbotorlpKfmiJbotorpm4bkuK3vvIzotorpnIDopoHmianlpKfmkqTnprvojIPlm7TjgIIKCuS4jeimgeaKiuaXp+e7tOWfuue7meWHuueahOWbuuWumuKAnOWuieWFqOi3neemu+KAneW9k+aIkOS/neivgeOAguWwgemXreepuumXtOOAgeWkmuS4queIhueCuOeJqeOAgemjnuaVo+eHg+eDp+aWueWdl+OAgeWcsOW9oumrmOW6puWSjOeJiOacrOWPguaVsOmDveS8muaUueWPmOmjjumZqeOAguWunumZheaTjeS9nOW6lOS9v+eUqOabtOi/nOi3neemu+OAgeWunuS9k+aOqeS9k+WSjOS4jeS4jueIhuW/g+ebuOi/nueahOaSpOmAgOi3r+e6v+OAggoKOjo6IHRpcCDkuLrku4DkuYjkuI3mjqjojZDnlKjniIbngrjniannsr7nu4bph4fnn78K54iG54K45pOF6ZW/5riF6Zmk5L2T56ev77yM5LiN5pOF6ZW/5L+d6K+B55+/55+z5Zue5pS244CC5a6D5Y+v6IO95pGn5q+B55+/54mp44CB56C05Z2P5a6J5YWo6YCa6YGT44CB5omT5byA5bKp5rWG5oiW5rC05L2T77yM5bm25oqK54eD54On56KO54mH5oqb5Yiw6KeG6YeO5aSW44CC6ZyA6KaB5Y+W5b6X6LWE5rqQ5pe25LyY5YWI5L2/55So5q2j56Gu562J57qn55qE6ZWQ77yb5Y+q5pyJ5Zyo5piO56Gu5o6l5Y+X5p2Q5paZ5o2f5aSx44CB5bm25a6M5oiQ5rWL6K+V5ZCO77yM5omN5oqK54iG54K455So5LqO5aSn6Z2i56ev5riF6Zqc44CCCjo6OgoKIyMjIOeIhueCuOS8oOaSreacuuWItgoK54iG54K45qih5ouf5LuO54iG54K45Lit5b+D5ZCR5aSW6YCQ5bGC5omp5pWj77yM5q+P5omp5pWj5LiA5bGC5Y6L5Yqb5bCx5b+r6YCf6KGw5YeP44CC5qC45b+D6KeE5b6L77yaCgotICoq5Lyg5pKt5YGc5q2i5p2h5Lu2KirvvJrlvZPljovlipvoobDlh4/liLDnuqYgMSDml7blgZzmraLkvKDmkq3jgILniIbngrjljovlipvotorlpKfvvIzkvKDmkq3lvpfotorov5zigJTigJTlsI/ngavoja/mobbvvIjljovlipsgNjDvvInnmoTpmIjlgLznuqYgMe+8jOWkp+eBq+iNr+ahtu+8iOWOi+WKmyAyMTYw77yJ55qE6ZiI5YC857qmIDbjgIIKLSAqKuWOi+WKm+ihsOWHjyoq77ya6ZqP552A5rOi5Y+K55qE5pa55Z2X6LaK5p2l6LaK5aSa77yM5Y6L5Yqb5b+r6YCf6KGw5YeP77yM56ysIDcg6L2u5LmL5ZCO6L+Y5Lya6aKd5aSW5Yqg6YCf6KGw5YeP44CC6L+Z5oSP5ZGz552A54iG54K456C05Z2P5Yqb6ZqP6Led56a75oCl5Ymn5LiL6ZmN44CCCi0gKirmlrnlnZfnoLTlnY/liKTlrpoqKu+8muW9k+afkOaWueWdl+WRqOWbtCA2IOS4qumdoueahOaAu+WOi+WKm+i2hei/h+WFtueIhueCuOaKl+aAp+aXtu+8jOaWueWdl+iiq+aRp+avgeOAguWQjOS4gOS9jee9rueahOeIhueCuOaViOaenOebuOWvueS4gOiHtOS9huaciemaj+acuuaAp+KAlOKAlOavj+S4quaWueWdl+eahOaKl+aAp+aciSAxfjIg5YCN55qE6ZqP5py65rOi5Yqo77yM5bCR5pWw5pa55Z2X77yI57qmIDEyLjUl77yJ5oqX5oCn55Sa6Iez6auY6L6+IDMg5YCN44CCCi0gKirmlrnlnZfnoLTlnY/liKTlrpoqKu+8muW9k+afkOaWueWdl+WRqOWbtCA2IOS4qumdoueahOaAu+WOi+WKm+i2hei/h+WFtueIhueCuOaKl+aAp+aXtu+8jOaWueWdl+iiq+aRp+avgeOAguWQjOS4gOS9jee9rueahOeIhueCuOaViOaenOebuOWvueS4gOiHtOS9huaciemaj+acuuaAp+KAlOKAlOavj+S4quaWueWdl+eahOaKl+aAp+aciSAxfjIg5YCN55qE6ZqP5py65rOi5Yqo77yM5bCR5pWw5pa55Z2X77yI57qmIDEyLjUl77yJ5oqX5oCn55Sa6Iez6auY6L6+IDMg5YCN44CCCi0gKirov57plIHniIbngrjmpoLnjocqKu+8muW9k+aWueWdl+iiq+eIhueCuOaRp+avgeWQju+8jOWmguaenOivpeaWueWdl+acrOi6q+aYr+eIhueCuOeJqe+8jOacieamgueOh+iiq+W8leeIhuKAlOKAlOWOi+WKm+aegeWkp+aXtiA5NSXvvIzkuIDoiKzmg4XlhrUgNzUl44CC6L+Z5bCx5piv5Li65LuA5LmIKirngavoja/mobbopoHliIbmlaPmkYbmlL4qKu+8jOe0p+aMqOedgOaUvuWuueaYk+WFqOmDqOi/numUgeW8leeIhuOAggoKIyMjIOeIhueCuOWogeWKm+eahOaWueWdl+egtOWdj+iMg+WbtAoK5LiN5ZCM54iG54K454mp55qE5a6e6ZmF56C05Z2P6IyD5Zu05Y+W5Yaz5LqO5ZGo5Zu05pa55Z2X55qE54iG54K45oqX5oCn44CC5Lul5LiL5piv5ZyoKirnuq/ms6XlnJ/njq/looMqKu+8iOeIhueCuOaKl+aApyAyNe+8ieS4reeahOi/keS8vOegtOWdj+WNiuW+hO+8mgoKfCDniIbngrjniakgfCDniIbngrjljovlipsgfCDov5HkvLznoLTlnY/ljYrlvoTvvIjmoLzvvIkgfAp8LS0tLS0tLS18LS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwKfCDpm7fnrqEgfCAxMCB8IH4xIHwKfCDlsI/nh4Png6fmobYgfCA1MCB8IH4yIHwKfCDlsI/ngavoja/mobYgfCA2MCB8IH4yIHwKfCDkuK3nh4Png6fmobYgfCAzMDAgfCB+MyB8Cnwg5Lit54Gr6I2v5qG2IHwgMzYwIHwgfjQgfAp8IOWkp+eHg+eDp+ahtiB8IDE4MDAgfCB+NiB8Cnwg5aSn54Gr6I2v5qG2IHwgMjE2MCB8IH43IHwKCj4gKirms6jmhI8qKu+8muWunumZheegtOWdj+iMg+WbtOWPl+aWueWdl+ehrOW6puW9seWTjeaegeWkp+OAguWcqOefs+WktOeOr+Wig++8iOaKl+aApyA1MO+8ieS4re+8jOegtOWdj+WNiuW+hOe6puS4uuazpeWcn+eOr+Wig+eahOS4gOWNiu+8m+iAjOWcqOeOu+eSg+eOr+Wig++8iOaKl+aApyAy77yJ5Lit77yM56C05Z2P6IyD5Zu05Lya5aSn5bmF5omp5aSn44CCCgoqKuW4uOingeaWueWdl+eIhueCuOaKl+aApyoq77yaCgp8IOaWueWdlyB8IOeIhueCuOaKl+aApyB8IOaKl+eIhuetiee6pyB8CnwtLS0tLS18LS0tLS0tLS0tfC0tLS0tLS0tLXwKfCDnjrvnkoMgfCAyIHwg5p6B6ISGIHwKfCDpm6rlnZcgfCAyIHwg5p6B6ISGIHwKfCDmoJHlj7YgfCAyIHwg5p6B6ISGIHwKfCDokKXngasgfCAxIHwg5p6B6ISGIHwKfCDngavmioogfCA1IHwg6ISG5byxIHwKfCDmnKjmoIXmoI8gfCAzIHwg6ISG5byxIHwKfCDms6XlnJ8v5rKZ5a2QL+aymeegviB8IDI1IHwg5pmu6YCaIHwKfCDlhrAgfCAyNSB8IOaZrumAmiB8Cnwg55+z54Gw5bKpL+egguWyqSB8IDUwIHwg5Z2a5Zu6IHwKfCDmsLQv5bKp5rWGIHwgNTAgfCDlnZrlm7ogfAp8IOiKseWyl+WyqSB8IDc1IHwg5Z2a5Zu6IHwKfCDnoJblnZcgfCA3NSB8IOWdmuWbuiB8Cnwg546E5q2m5bKpIHwgODAgfCDlnZrlm7ogfAp8IOm5heWNteefsyB8IDE0MCB8IOmdnuW4uOWdmuWbuiB8Cnwg55+z56CWIHwgMTYwIHwg6Z2e5bi45Z2a5Zu6IHwKfCDpk4HlnZcgfCAyMDAwIHwg5p6B5bqm5Z2a5Zu6IHwKfCDpkrvnn7PlnZcgfCA4MDAwIHwg6L+R5LmO5peg5pWMIHwKfCDln7rlsqkgfCDiiJ4gfCDml6DmlYwgfAoKIyMjIOeIhueCuOS8pOWuswoK54iG54K45a+555Sf54mp5ZKM546p5a6255qE5Lyk5a6z5LiO5ZGo5Zu05Y6L5Yqb5oiQ5q2j5q+U77yaKirljovlipvotorlpKfkvKTlrrPotorpq5gqKu+8jOS4lOeUn+eJqei0qOmHj+i2iuWkp+WPl+WIsOeahOS8pOWus+i2iuWwj++8iOepv+eblOeUsueahOeOqeWutuabtOiAkOeCuO+8ieOAgueIhueCuOi/mOS8muS6p+eUnyoq5Ye76YCA5pWI5p6cKirvvIzmiornlJ/nianmjqjlvIDjgIIKCiMjIyDniIbngrjkuI7ngavnhLDnmoTogZTliqgKCueIhueCuOS4jueBq+eEsOezu+e7n+WtmOWcqOWvhuWIh+iBlOWKqO+8mgoKKirniIbngrjlvJXlj5Hngavngb4qKu+8muWcqOeIhueCuOeahOWQjuWkhOeQhumYtuaute+8jOWvueS6juacquiiq+aRp+avgeS9huWPl+WIsOWOi+WKm+azouWPiueahOWPr+eHg+aWueWdl++8jOacieamgueOh+iiq+eCueeHg++8mgoKfCDniIbngrjnsbvlnosgfCDngrnnh4PmpoLnjocgfCDngrnnh4PlkI7ngavnhLDmianmlaPog73lipsgfAp8LS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18Cnwg54eD54On5qG254iG54K4IHwgNTAlIHwgMS4w77yI5ruh5omp5pWj77yJIHwKfCDmma7pgJrniIbngrggfCAyMCUgfCAwLjPvvIjlvLHmianmlaPvvIkgfAoKPiAqKueCueeHg+adoeS7tioq77ya5Y+q6KaB5pa55Z2X5Y+v54eD5LiU5om/5Y+X5LqG6Laz5aSf55qE54iG54K45Y6L5Yqb77yM5bCx5Y+v6IO96KKr54K554eD44CC5Y2z5L2/5piv5pmu6YCa54iG54K477yM5Lmf5pyJ5Y+v6IO95Zyo5bqf5aKf5Lit5byV5Y+R54Gr54G+44CCCgoqKueBq+eEsOW8leeIhueIhueCuOeJqSoq77ya5b2T54iG54K454mp55u46YK75pa55Z2X552A54Gr5pe277yM6Ieq5Yqo54K554eD5byV5L+h77yMNn43IOenkuWQjueIhueCuOOAgui/meaYr+acgOW4uOingeeahOi/numUgeeIhueCuOinpuWPkeaWueW8j+KAlOKAlCoq5YWI5pS+54Gr77yM5YaN54iG54K4KirjgIIKCiMjIyDniIbngrjlvLnlsITniakKCueIhueCuOaRp+avgeaWueWdl+aXtu+8jOS8mueUn+aIkCoq5by55bCE54mpKirvvIjpo57muoXnmoTmlrnlnZfnoo7niYfvvInvvJoKCi0g5by55bCE54mp5pWw6YeP6ZqP54iG54K46KeE5qih5aKe5Yqg77yM5L2G5qaC546H6YCS5YeP77yI6LaF6L+HIDI1IOS4quWQjuamgueOh+W8gOWni+S4i+mZje+8iQotIOW8ueWwhOeJqeW4puaciemaj+acuumAn+W6puWSjOaXi+i9rO+8jOiQveWcsOWQjuWPr+iDveWPmOS4uuWPr+aLvuWPlueJqeWTgeaIluebtOaOpea2iOWksQotIOeHg+eDp+ahtueIhueCuOeUn+aIkOeahOW8ueWwhOeJqeacieamgueOh+WPmOS4uioq54eD54On5by55bCE54mpKirvvIzokL3lnLDlkI7ngrnnh4Plkajlm7TmlrnlnZcKLSA1MCUg55qE5by55bCE54mp5Lya5ouW5puz54Of6Zu+5bC+6L+577yM54eD54On5by55bCE54mp55qE54Of6Zu+5ZGI57KJ57qi6ImyCgojIyMg54iG54K46Z+z5pWI5YiG57qnCgrniIbngrjpn7PmlYjmoLnmja7mgLvljovlipvlgLzliIbkuLogNyDkuKrnrYnnuqfvvIzljovlipvotorlpKfpn7PmlYjkvKDmkq3otorov5zvvJoKCnwg5oC75Y6L5YqbIHwg6Z+z5pWIIHwg5Zmq6Z+z6IyD5Zu077yI5qC877yJIHwKfC0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tfAp8ID4gMiwwMDAsMDAwIHwgRXhwbG9zaW9uNyB8IDEzMCB8CnwgPiA0MDAsMDAwIHwgRXhwbG9zaW9uNiB8IDEwMCB8CnwgPiA4MCwwMDAgfCBFeHBsb3Npb241IHwgNzAgfAp8ID4gMTYsMDAwIHwgRXhwbG9zaW9uNCB8IDUwIHwKfCA+IDMsNTAwIHwgRXhwbG9zaW9uMyB8IDQwIHwKfCA+IDgwIHwgRXhwbG9zaW9uMiB8IDM1IHwKfCA+IDAgfCBFeHBsb3Npb24xIHwgMzAgfAoKPiAqKuWZqumfsyoq77ya54iG54K45Lya5Lqn55Sf5Zmq6Z+z77yM5ZC45byV6ZmE6L+R55qE55Sf54mp44CC5Y6L5Yqb6LaK5aSn55qE54iG54K45ZC45byV6IyD5Zu06LaK5bm/77yM5pyA5aSn5Y+v6L6+IDEzMCDmoLzigJTigJTov5nmhI/lkbPnnYDkuIDkuKrlpKfniIbngrjlj6/og73mg4rliqjmlbTkuKrljLrln5/nmoTnlJ/nianjgIIKCiMjIyDnlLXot6/otbfniIbmo4Dmn6XooagKCjEuIOi1t+eIhueUtea6kOm7mOiupOS/neaMgeaWreW8gO+8jOacgOWQjuS4gOatpeaJjei/nuaOpeOAggoyLiDlr7znur/kuI7mjInpkq7ov5znprvniIbngrjlvbHlk43ljLrvvIzlubbkv53nlZnniannkIbmjqnkvZPjgIIKMy4g5YWI55So54Gv5pu/5Luj55S16Zu3566h5rWL6K+V5L+h5Y+35pa55ZCR44CB5bu26L+f5ZKM5aSN5L2N44CCCjQuIOehruiupOayoeacieebuOmCu+e6v+i3r+OAgeS8oOaEn+WZqOaIlumbt+mbqOmAoOaIkOaEj+Wklui+k+WFpeOAggo1LiDogZTmnLrmnI3nlLHkuIDkurrnu5/kuIDlgJLorqHml7bvvIznoa7orqTpmYTov5HnjqnlrrblkozlnZDpqpHlt7Lnu4/mkqTnprvjgIIKCiMjIOWGmee7meW8gOWPkeiAhQoKOjo6IGluZm8g6LWE5paZ5pqC5a2YCuacrOWwj+iKguWGheWuueaaguaXtuWtmOaUvuS6juatpO+8jOWQjue7reS8muenu+WKqOiHsyJNT0TlvIDlj5Ei56ug6IqC44CCCjo6OgoKPGRldGFpbHM+CjxzdW1tYXJ5PuW8gOWPkeamguiniDwvc3VtbWFyeT4KCiMjIyDngavnhLDmlrnlnZfooYzkuLrvvIhgU3Vic3lzdGVtRmlyZUJsb2NrQmVoYXZpb3IuY3Ng77yJCgo+ICoqYEZpcmVEYXRhYCDnsbsqKu+8muWtmOWCqOavj+S4queBq+eEsOeCueeahOi/kOihjOaXtuaVsOaNruOAgmBQb2ludGAg5Li654Gr54Sw5Z2Q5qCH77ybYFRpbWUwYH5gVGltZTNgIOS4uuWbm+S4quawtOW5s+aWueWQkeeahOeHg+eDp+iuoeaXtuWZqO+8m2BUaW1lNWAg5Li65ZCR5LiL54On56m/6K6h5pe25Zmo77ybYEZpcmVFeHBhbmRhYmlsaXR5YCDkuLrngavnhLDmianmlaPog73lipvjgIIKCmBgYGNzaGFycAovLyDngavnhLDmlrnlnZfnvJblj7fkuLogMTA0CnB1YmxpYyBvdmVycmlkZSBpbnRbXSBIYW5kbGVkQmxvY2tzID0+IFsxMDRdOwoKLy8g54Gr54Sw6JST5bu25qaC546H55qE5Yid5aeL5YyW77yI5ZyoIExvYWQg5pa55rOV5Lit77yJCi8vIOmBjeWOhiAtMn4yIOeahCB444CBLTF+MiDnmoQgeeOAgS0yfjIg55qEIHog5YGP56e7CmZvciAoaW50IGkgPSAtMjsgaSA8PSAyOyBpKyspIHsgICAgICAgLy8gaSA9IFgg5YGP56e7CiAgICBmb3IgKGludCBqID0gLTE7IGogPD0gMjsgaisrKSB7ICAgLy8gaiA9IFkg5YGP56e7CiAgICAgICAgZm9yIChpbnQgayA9IC0yOyBrIDw9IDI7IGsrKykgeyAvLyBrID0gWiDlgY/np7sKICAgICAgICAgICAgaWYgKGkgIT0gMCB8fCBqICE9IDAgfHwgayAhPSAwKSB7CiAgICAgICAgICAgICAgICAvLyBudW0gPSDmnIDlpKfot53nprvvvJrlkJHkuIsoajwwKeS4uiAxLjXvvIzlkJHkuIov5rC05bmz5Li6IDIuNQogICAgICAgICAgICAgICAgZmxvYXQgbnVtID0gaiA8IDAgPyAxLjVmIDogMi41ZjsKICAgICAgICAgICAgICAgIGlmIChNYXRoRi5TcXJ0KGkqaSArIGoqaiArIGsqaykgPD0gbnVtKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gbnVtMiA9IOawtOW5s+i3neemuyBzcXJ0KGnCsiArIGvCsikKICAgICAgICAgICAgICAgICAgICBmbG9hdCBudW0yID0gTWF0aEYuU3FydChpKmkgKyBrKmspOwogICAgICAgICAgICAgICAgICAgIC8vIG51bTMgPSDlnoLnm7Tlm6DlrZDvvJrlkJHkuIrkuLogMC41KmrvvIzlkJHkuIvkuLogLWoKICAgICAgICAgICAgICAgICAgICBmbG9hdCBudW0zID0gaiA+IDAgPyAwLjVmICogaiA6IC1qOwogICAgICAgICAgICAgICAgICAgIC8vIOiUk+W7tuamgueOhyA9IDAuMDIgLyAo5rC05bmz6Led56a7ICsg5Z6C55u05Zug5a2QKQogICAgICAgICAgICAgICAgICAgIG1fZXhwYW5zaW9uUHJvYmFiaWxpdGllc1tuZXcgUG9pbnQzKGksIGosIGspXSA9IDAuMDJmIC8gKG51bTIgKyBudW0zKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KfQpgYGAKCmBgYGNzaGFycAovLyDnh4Png6forqHml7blmajliJ3lp4vljJYKLy8gZmFjZSA9IOaWueWQkee0ouW8le+8iDA9K1osIDE9K1gsIDI9LVosIDM9LVgsIDU9LVnvvIkKLy8gR2V0RmlyZUR1cmF0aW9uID0g5pa55Z2X55qE54Gr54Sw5oyB57ut5pe26Ze0Ci8vIG1fcmFuZG9tLkZsb2F0KDAuNzVmLCAxLjI1ZikgPSDpmo/mnLrns7vmlbDvvIzkvb/kvKDmkq3ml7bpl7TmnIkgwrEyNSUg55qE5rOi5YqoCnB1YmxpYyB2b2lkIEluaXRpYWxpemVGaXJlRGF0YVRpbWUoRmlyZURhdGEgZmlyZURhdGEsIGludCBmYWNlKSB7CiAgICBQb2ludDMgcG9pbnQgPSBDZWxsRmFjZS5GYWNlVG9Qb2ludDMoZmFjZSk7CiAgICBpbnQgY2VsbFZhbHVlID0gU3Vic3lzdGVtVGVycmFpbi5UZXJyYWluLkdldENlbGxWYWx1ZSgKICAgICAgICBmaXJlRGF0YS5Qb2ludC5YICsgcG9pbnQuWCwgZmlyZURhdGEuUG9pbnQuWSArIHBvaW50LlksIGZpcmVEYXRhLlBvaW50LlogKyBwb2ludC5aKTsKICAgIEJsb2NrIGJsb2NrID0gQmxvY2tzTWFuYWdlci5CbG9ja3NbVGVycmFpbi5FeHRyYWN0Q29udGVudHMoY2VsbFZhbHVlKV07CiAgICBzd2l0Y2ggKGZhY2UpIHsKICAgICAgICBjYXNlIDA6IGZpcmVEYXRhLlRpbWUwID0gYmxvY2suR2V0RmlyZUR1cmF0aW9uKGNlbGxWYWx1ZSkgKiBtX3JhbmRvbS5GbG9hdCgwLjc1ZiwgMS4yNWYpOyBicmVhazsKICAgICAgICBjYXNlIDE6IGZpcmVEYXRhLlRpbWUxID0gYmxvY2suR2V0RmlyZUR1cmF0aW9uKGNlbGxWYWx1ZSkgKiBtX3JhbmRvbS5GbG9hdCgwLjc1ZiwgMS4yNWYpOyBicmVhazsKICAgICAgICBjYXNlIDI6IGZpcmVEYXRhLlRpbWUyID0gYmxvY2suR2V0RmlyZUR1cmF0aW9uKGNlbGxWYWx1ZSkgKiBtX3JhbmRvbS5GbG9hdCgwLjc1ZiwgMS4yNWYpOyBicmVhazsKICAgICAgICBjYXNlIDM6IGZpcmVEYXRhLlRpbWUzID0gYmxvY2suR2V0RmlyZUR1cmF0aW9uKGNlbGxWYWx1ZSkgKiBtX3JhbmRvbS5GbG9hdCgwLjc1ZiwgMS4yNWYpOyBicmVhazsKICAgICAgICBjYXNlIDU6IGZpcmVEYXRhLlRpbWU1ID0gYmxvY2suR2V0RmlyZUR1cmF0aW9uKGNlbGxWYWx1ZSkgKiBtX3JhbmRvbS5GbG9hdCgwLjc1ZiwgMS4yNWYpOyBicmVhazsKICAgIH0KfQpgYGAKCmBgYGNzaGFycAovLyBVcGRhdGUg5pa55rOV5Lit55qE54Gr54Sw5Lyg5pKt6YC76L6R77yI566A5YyW54mI77yJCi8vIOavj+asoeaJq+aPj+ajgOafpeaJgOacieeBq+eEsOeCue+8jOWHj+WwkeiuoeaXtuWZqAovLyBudW00ID0g54Gr54Sw5pa55Z2X55qE5pWw5o2u5YC877yI5L2N5qCH5b+X77yJCi8vIG1fbGFzdFNjYW5EdXJhdGlvbiA9IOS4iuasoeaJq+aPj+WIsOeOsOWcqOeahOaXtumXtOmXtOmalAoKLy8g5pa55ZCRIDDvvIgrWu+8ieeahOeHg+eDp+mAu+i+kQppZiAoKG51bTQgJiAxKSAhPSAwKSB7CiAgICB2YWx1ZS5UaW1lMCAtPSBtX2xhc3RTY2FuRHVyYXRpb247ICAvLyDorqHml7blmajpgJLlh48KICAgIGlmICh2YWx1ZS5UaW1lMCA8PSAwZikgewogICAgICAgIC8vIOiuoeaXtuWZqOW9kumbtu+8jOeDp+avgSArWiDmlrnlkJHnmoTmlrnlnZcKICAgICAgICAvLyDmlrDngavnhLDmianmlaPog73lipsgPSDljp/mianmlaPog73lipsgw5cgMC44NQogICAgICAgIFF1ZXVlQnVybkF3YXkoeCwgeSwgeiArIDEsIHZhbHVlLkZpcmVFeHBhbmRhYmlsaXR5ICogMC44NWYpOwogICAgfQogICAgLy8g5qaC546H6JST5bu277ya5a+55q+P5Liq5Y+v6IO955qE5YGP56e75pa55ZCRCiAgICBmb3JlYWNoICh2YXIgZXhwYW5zaW9uUHJvYmFiaWxpdHkgaW4gbV9leHBhbnNpb25Qcm9iYWJpbGl0aWVzKSB7CiAgICAgICAgLy8g6ZqP5py65pWwIDwg5qaC546HIMOXIOaXtumXtCDDlyDmianmlaPog73lipsg4oaSIOiUk+W7tgogICAgICAgIGlmIChtX3JhbmRvbS5GbG9hdCgwZiwgMWYpIDwgZXhwYW5zaW9uUHJvYmFiaWxpdHkuVmFsdWUgKiBtX2xhc3RTY2FuRHVyYXRpb24gKiB2YWx1ZS5GaXJlRXhwYW5kYWJpbGl0eSkgewogICAgICAgICAgICBtX3RvRXhwYW5kW25ldyBQb2ludDMoCiAgICAgICAgICAgICAgICB4ICsgZXhwYW5zaW9uUHJvYmFiaWxpdHkuS2V5LlgsCiAgICAgICAgICAgICAgICB5ICsgZXhwYW5zaW9uUHJvYmFiaWxpdHkuS2V5LlksCiAgICAgICAgICAgICAgICB6ICsgMSArIGV4cGFuc2lvblByb2JhYmlsaXR5LktleS5aCiAgICAgICAgICAgICldID0gdmFsdWUuRmlyZUV4cGFuZGFiaWxpdHkgKiAwLjg1ZjsgIC8vIOaWsOaJqeaVo+iDveWKm+ihsOWHjyAxNSUKICAgICAgICB9CiAgICB9Cn0KYGBgCgpgYGBjc2hhcnAKLy8g54On5q+B5aSE55CG77yI5q+PIDUg5ri45oiP56eS5omn6KGM5LiA5qyh77yJCi8vIG1fdG9CdXJuQXdheSA9IOW+heeDp+avgeaWueWdl+mYn+WIlwovLyBtX3RvRXhwYW5kID0g5b6F6JST5bu25pa55Z2X6Zif5YiXCmlmIChtX3N1YnN5c3RlbVRpbWUuUGVyaW9kaWNHYW1lVGltZUV2ZW50KDUuMCwgMC4wKSkgewogICAgZm9yZWFjaCAodmFyIGl0ZW0gaW4gbV90b0J1cm5Bd2F5KSB7CiAgICAgICAgLy8g5pGn5q+B5pa55Z2X77yI5Y+Y5Li656m65rCU77yJCiAgICAgICAgU3Vic3lzdGVtVGVycmFpbi5DaGFuZ2VDZWxsKGl0ZW0uS2V5LlgsIGl0ZW0uS2V5LlksIGl0ZW0uS2V5LlosIFRlcnJhaW4uUmVwbGFjZUNvbnRlbnRzKDApKTsKICAgICAgICAvLyDlpoLmnpzmianmlaPog73lipsgPiAwLjI177yM5ZCR5ZGo5Zu0IDUg5Liq6Z2i5omp5pWj54Gr54SwCiAgICAgICAgaWYgKGl0ZW0uVmFsdWUgPiAwLjI1ZikgewogICAgICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IDU7IGkrKykgewogICAgICAgICAgICAgICAgUG9pbnQzIHBvaW50ID0gQ2VsbEZhY2UuRmFjZVRvUG9pbnQzKGkpOwogICAgICAgICAgICAgICAgU2V0Q2VsbE9uRmlyZShpdGVtLktleS5YICsgcG9pbnQuWCwgaXRlbS5LZXkuWSArIHBvaW50LlksIGl0ZW0uS2V5LlogKyBwb2ludC5aLCBpdGVtLlZhbHVlKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIC8vIOWkhOeQhuiUk+W7tumYn+WIlwogICAgZm9yZWFjaCAodmFyIGl0ZW0yIGluIG1fdG9FeHBhbmQpIHsKICAgICAgICBTZXRDZWxsT25GaXJlKGl0ZW0yLktleS5YLCBpdGVtMi5LZXkuWSwgaXRlbTIuS2V5LlosIGl0ZW0yLlZhbHVlKTsKICAgIH0KICAgIG1fdG9CdXJuQXdheS5DbGVhcigpOwogICAgbV90b0V4cGFuZC5DbGVhcigpOwp9CmBgYAoKIyMjIOiQpeeBq+aWueWdl+ihjOS4uu+8iGBTdWJzeXN0ZW1DYW1wZmlyZUJsb2NrQmVoYXZpb3IuY3Ng77yJCgpgYGBjc2hhcnAKLy8g6JCl54Gr5bC65a+46IyD5Zu077yaMO+8iOeGhOeBre+8iX4gMTXvvIjmnIDlpKfvvIkKLy8g6JCl54Gr57KS5a2Q5aSn5bCP6ZqP5bC65a+457q/5oCn5o+S5YC8CnB1YmxpYyB2b2lkIEFkZENhbXBmaXJlUGFydGljbGVTeXN0ZW0oaW50IHZhbHVlLCBpbnQgeCwgaW50IHksIGludCB6KSB7CiAgICBpbnQgbnVtID0gVGVycmFpbi5FeHRyYWN0RGF0YSh2YWx1ZSk7ICAvLyBudW0gPSDokKXngavlsLrlr7jvvIgwfjE177yJCiAgICBpZiAobnVtID4gMCkgewogICAgICAgIC8vIHNpemUgPSDnspLlrZDlpKflsI/vvIzku44gMC4yIOWIsCAwLjUg57q/5oCn5o+S5YC8CiAgICAgICAgZmxvYXQgc2l6ZSA9IE1hdGhVdGlscy5MZXJwKDAuMmYsIDAuNWYsIG51bSAvIDE1Zik7CiAgICAgICAgRmlyZVBhcnRpY2xlU3lzdGVtIGZpcmVQYXJ0aWNsZVN5c3RlbSA9IG5ldyhuZXcgVmVjdG9yMyh4LCB5LCB6KSArIHYsIHNpemUsIDI1NmYpOwogICAgICAgIG1fc3Vic3lzdGVtUGFydGljbGVzLkFkZFBhcnRpY2xlU3lzdGVtKGZpcmVQYXJ0aWNsZVN5c3RlbSk7CiAgICAgICAgbV9wYXJ0aWNsZVN5c3RlbXNCeUNlbGxbbmV3IFBvaW50Myh4LCB5LCB6KV0gPSBmaXJlUGFydGljbGVTeXN0ZW07CiAgICB9Cn0KYGBgCgpgYGBjc2hhcnAKLy8g5re75Yqg54eD5paZ55qE5qC45b+D6YC76L6RCnB1YmxpYyBib29sIEFkZEZ1ZWwoaW50IHgsIGludCB5LCBpbnQgeiwgaW50IHZhbHVlLCBpbnQgY291bnQpIHsKICAgIGlmIChUZXJyYWluLkV4dHJhY3REYXRhKFN1YnN5c3RlbVRlcnJhaW4uVGVycmFpbi5HZXRDZWxsVmFsdWUoeCwgeSwgeikpID4gMCkgewogICAgICAgIEJsb2NrIGJsb2NrID0gQmxvY2tzTWFuYWdlci5CbG9ja3NbVGVycmFpbi5FeHRyYWN0Q29udGVudHModmFsdWUpXTsKICAgICAgICAvLyAxLiDlhYjmo4Dmn6XmmK/lkKbkuLrniIbngrjniakKICAgICAgICBpZiAoUHJvamVjdC5GaW5kU3Vic3lzdGVtPFN1YnN5c3RlbUV4cGxvc2lvbnM+KHRydWUpLlRyeUV4cGxvZGVCbG9jayh4LCB5LCB6LCB2YWx1ZSkpIHsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIC8vIDIuIOmbqi/pm6rnkIMv5Yaw5Z2XIOKGkiDlh4/lsI/okKXngasKICAgICAgICBpZiAoYmxvY2sgaXMgU25vd0Jsb2NrIHx8IGJsb2NrIGlzIFNub3diYWxsQmxvY2sgfHwgYmxvY2sgaXMgSWNlQmxvY2spIHsKICAgICAgICAgICAgcmV0dXJuIFJlc2l6ZUNhbXBmaXJlKHgsIHksIHosIC0xLCB0cnVlKTsKICAgICAgICB9CiAgICAgICAgLy8gMy4g5pyJ54eD5paZ54Ot5YC8IOKGkiDorqHnrpflop7liqDmraXmlbAKICAgICAgICBpZiAoYmxvY2suR2V0RnVlbEhlYXRMZXZlbCh2YWx1ZSkgPiAwZikgewogICAgICAgICAgICAvLyBudW0yID0g5aKe5Yqg5q2l5pWwID0g5pWw6YePIMOXIG1pbijnh4Pmlpnnh4Png6fml7bpl7QsIDIwKSAvIDUKICAgICAgICAgICAgZmxvYXQgbnVtMiA9IGNvdW50ICogTWF0aFV0aWxzLk1pbihibG9jay5HZXRGdWVsRmlyZUR1cmF0aW9uKHZhbHVlKSwgMjBmKSAvIDVmOwogICAgICAgICAgICBpbnQgbnVtMyA9IChpbnQpbnVtMjsgICAgICAgICAgIC8vIOaVtOaVsOmDqOWIhgogICAgICAgICAgICBmbG9hdCBudW00ID0gbnVtMiAtIG51bTM7ICAgICAgICAvLyDlsI/mlbDpg6jliIYKICAgICAgICAgICAgaWYgKG1fcmFuZG9tLkZsb2F0KDBmLCAxZikgPCBudW00KSBudW0zKys7ICAvLyDmpoLnjofov5vkvY0KICAgICAgICAgICAgaWYgKG51bTMgPiAwKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gUmVzaXplQ2FtcGZpcmUoeCwgeSwgeiwgbnVtMywgdHJ1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgfQogICAgcmV0dXJuIGZhbHNlOwp9CmBgYAoKYGBgY3NoYXJwCi8vIOiQpeeBq+WwuuWvuOiwg+aVtApwdWJsaWMgYm9vbCBSZXNpemVDYW1wZmlyZShpbnQgeCwgaW50IHksIGludCB6LCBpbnQgc3RlcHMsIGJvb2wgcGxheVNvdW5kKSB7CiAgICBpbnQgbnVtID0gVGVycmFpbi5FeHRyYWN0RGF0YShjZWxsVmFsdWUpOyAgLy8g5b2T5YmN5bC65a+4CiAgICBpZiAobnVtID4gMCkgewogICAgICAgIC8vIOaWsOWwuuWvuCA9IGNsYW1wKOW9k+WJjeWwuuWvuCArIOatpeaVsCwgMCwgMTUpCiAgICAgICAgaW50IG51bTIgPSBNYXRoLkNsYW1wKG51bSArIHN0ZXBzLCAwLCAxNSk7CiAgICAgICAgaWYgKG51bTIgIT0gbnVtKSB7CiAgICAgICAgICAgIFN1YnN5c3RlbVRlcnJhaW4uQ2hhbmdlQ2VsbCh4LCB5LCB6LCBUZXJyYWluLlJlcGxhY2VEYXRhKGNlbGxWYWx1ZSwgbnVtMikpOwogICAgICAgICAgICBpZiAocGxheVNvdW5kKSB7CiAgICAgICAgICAgICAgICBpZiAoc3RlcHMgPj0gMCkgewogICAgICAgICAgICAgICAgICAgIC8vIOa3u+WKoOeHg+aWme+8muaSreaUvuaUvue9rumfs+aViAogICAgICAgICAgICAgICAgICAgIG1fc3Vic3lzdGVtQW1iaWVudFNvdW5kcy5TdWJzeXN0ZW1BdWRpby5QbGF5U291bmQoIkF1ZGlvL0Jsb2NrUGxhY2VkIiwgMWYsIDBmLCAuLi4pOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvLyDoobDlh48v54aE54Gt77ya5pKt5pS+5Zi25Zi25aOwCiAgICAgICAgICAgICAgICAgICAgbV9zdWJzeXN0ZW1BbWJpZW50U291bmRzLlN1YnN5c3RlbUF1ZGlvLlBsYXlSYW5kb21Tb3VuZCgiQXVkaW8vU2l6emxlcyIsIDFmLCAwZiwgLi4uKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gZmFsc2U7Cn0KYGBgCgpgYGBjc2hhcnAKLy8g6JCl54Gr6Ieq54S26KGw5YeP5LiO6Zuo5rC05rWH54GtCnB1YmxpYyB2aXJ0dWFsIHZvaWQgVXBkYXRlKGZsb2F0IGR0KSB7CiAgICAvLyDmr48gNSDmuLjmiI/np5Lmo4Dmn6XkuIDmrKEKICAgIGlmIChtX3N1YnN5c3RlbVRpbWUuUGVyaW9kaWNHYW1lVGltZUV2ZW50KDUuMCwgMC4wKSkgewogICAgICAgIG1fdXBkYXRlSW5kZXgrKzsKICAgICAgICBmb3JlYWNoIChQb2ludDMga2V5IGluIG1fcGFydGljbGVTeXN0ZW1zQnlDZWxsLktleXMpIHsKICAgICAgICAgICAgLy8g6I635Y+W6ZmN5rC05L+h5oGvCiAgICAgICAgICAgIFByZWNpcGl0YXRpb25TaGFmdEluZm8gcHJlY2lwaXRhdGlvblNoYWZ0SW5mbyA9IG1fc3Vic3lzdGVtV2VhdGhlci5HZXRQcmVjaXBpdGF0aW9uU2hhZnRJbmZvKGtleS5YLCBrZXkuWik7CiAgICAgICAgICAgIC8vIOadoeS7tjHvvJrmraPlnKjkuIvpm6jkuJTokKXngavmmrTpnLLlnKjpm6jkuK0KICAgICAgICAgICAgLy8g5p2h5Lu2Mu+8muavjyA2IOasoeajgOafpe+8iDMwIOa4uOaIj+enku+8ieiHqueEtuihsOWHj+S4gOasoQogICAgICAgICAgICBpZiAoKHByZWNpcGl0YXRpb25TaGFmdEluZm8uSW50ZW5zaXR5ID4gMGYgJiYga2V5LlkgPj0gcHJlY2lwaXRhdGlvblNoYWZ0SW5mby5ZTGltaXQgLSAxKQogICAgICAgICAgICAgICAgfHwgbV91cGRhdGVJbmRleCAlIDYgPT0gMCkgewogICAgICAgICAgICAgICAgbV90b1JlZHVjZS5BZGQoa2V5KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBmb3JlYWNoIChQb2ludDMgaXRlbSBpbiBtX3RvUmVkdWNlKSB7CiAgICAgICAgICAgIFJlc2l6ZUNhbXBmaXJlKGl0ZW0uWCwgaXRlbS5ZLCBpdGVtLlosIC0xLCB0cnVlKTsgIC8vIOWwuuWvuOWHjyAxCiAgICAgICAgfQogICAgICAgIG1fdG9SZWR1Y2UuQ2xlYXIoKTsKICAgIH0KfQpgYGAKCiMjIyDniIbngrjnianmlrnlnZfooYzkuLrvvIhgU3Vic3lzdGVtRXhwbG9zaXZlc0Jsb2NrQmVoYXZpb3IuY3Ng77yJCgpgYGBjc2hhcnAKLy8g54K554eD5byV5L+hCnB1YmxpYyBib29sIElnbml0ZUZ1c2UoaW50IHgsIGludCB5LCBpbnQgeikgewogICAgaW50IGNlbGxDb250ZW50cyA9IG1fc3Vic3lzdGVtVGVycmFpbi5UZXJyYWluLkdldENlbGxDb250ZW50cyh4LCB5LCB6KTsKICAgIGlmIChCbG9ja3NNYW5hZ2VyLkJsb2Nrc1tjZWxsQ29udGVudHNdIGlzIEd1bnBvd2RlcktlZ0Jsb2NrKSB7CiAgICAgICAgLy8g54Gr6I2v5qG277ya5byV5L+h5pe26Ze0IDZ+NyDnp5IKICAgICAgICBBZGRFeHBsb3NpdmUobmV3IFBvaW50Myh4LCB5LCB6KSwgbV9yYW5kb20uRmxvYXQoNmYsIDdmKSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICBpZiAoQmxvY2tzTWFuYWdlci5CbG9ja3NbY2VsbENvbnRlbnRzXSBpcyBEZXRvbmF0b3JCbG9jaykgewogICAgICAgIC8vIOmbt+euoe+8muW8leS/oeaXtumXtCAwLjh+MS4yIOenkgogICAgICAgIEFkZEV4cGxvc2l2ZShuZXcgUG9pbnQzKHgsIHksIHopLCBtX3JhbmRvbS5GbG9hdCgwLjhmLCAxLjJmKSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICByZXR1cm4gZmFsc2U7Cn0KYGBgCgpgYGBjc2hhcnAKLy8g5byV5L+h5YCS6K6h5pe25LiO5byV54iGCnB1YmxpYyB2aXJ0dWFsIHZvaWQgVXBkYXRlKGZsb2F0IGR0KSB7CiAgICBmb3JlYWNoIChFeHBsb3NpdmVEYXRhIGV4cGxvc2l2ZURhdGEgaW4gYXJyYXkpIHsKICAgICAgICAvLyDlvJXkv6Hml7bpl7TpgJLlh48KICAgICAgICBleHBsb3NpdmVEYXRhLlRpbWVUb0V4cGxvc2lvbiAtPSBkdDsKICAgICAgICBpZiAoZXhwbG9zaXZlRGF0YS5UaW1lVG9FeHBsb3Npb24gPD0gMGYpIHsKICAgICAgICAgICAgLy8g5byV5L+h5b2S6Zu277yM6Kem5Y+R54iG54K4CiAgICAgICAgICAgIG1fc3Vic3lzdGVtRXhwbG9zaW9ucy5UcnlFeHBsb2RlQmxvY2soCiAgICAgICAgICAgICAgICBleHBsb3NpdmVEYXRhLlBvaW50LlgsIGV4cGxvc2l2ZURhdGEuUG9pbnQuWSwgZXhwbG9zaXZlRGF0YS5Qb2ludC5aLCBjZWxsVmFsdWUpOwogICAgICAgIH0KICAgIH0KfQpgYGAKCmBgYGNzaGFycAovLyDpgrvlsYXmlrnlnZflj5jljJbml7bmo4Dmn6XngavnhLAKcHVibGljIG92ZXJyaWRlIHZvaWQgT25OZWlnaGJvckJsb2NrQ2hhbmdlZChpbnQgeCwgaW50IHksIGludCB6LCBpbnQgbmVpZ2hib3JYLCBpbnQgbmVpZ2hib3JZLCBpbnQgbmVpZ2hib3JaKSB7CiAgICAvLyDlpoLmnpznm7jpgrvmlrnlnZfnnYDngavvvIzngrnnh4PlvJXkv6EKICAgIGlmIChtX3N1YnN5c3RlbUZpcmVCbG9ja0JlaGF2aW9yLklzQ2VsbE9uRmlyZSh4LCB5LCB6KSkgewogICAgICAgIElnbml0ZUZ1c2UoeCwgeSwgeik7CiAgICB9Cn0KCi8vIOiiq+eIhueCuOazouWPiuaXtuacieamgueOh+i/numUgeW8leeIhgpwdWJsaWMgb3ZlcnJpZGUgdm9pZCBPbkV4cGxvc2lvbihpbnQgdmFsdWUsIGludCB4LCBpbnQgeSwgaW50IHosIGZsb2F0IGRhbWFnZSkgewogICAgQmxvY2sgYmxvY2sgPSBCbG9ja3NNYW5hZ2VyLkJsb2Nrc1tUZXJyYWluLkV4dHJhY3RDb250ZW50cyh2YWx1ZSldOwogICAgaWYgKGJsb2NrLkdldEV4cGxvc2lvblByZXNzdXJlKHZhbHVlKSA+IDBmCiAgICAgICAgJiYgTWF0aFV0aWxzLlNhdHVyYXRlKGRhbWFnZSAvIGJsb2NrLkV4cGxvc2lvblJlc2lsaWVuY2UpID4gMC4wMWYKICAgICAgICAmJiBtX3JhbmRvbS5GbG9hdCgwZiwgMWYpIDwgMC41ZikgeyAgLy8gNTAlIOamgueOh+i/numUgeW8leeIhgogICAgICAgIElnbml0ZUZ1c2UoeCwgeSwgeik7CiAgICB9Cn0KYGBgCgojIyMg54iG54K457O757uf5qC45b+D77yIYFN1YnN5c3RlbUV4cGxvc2lvbnMuY3Ng77yJCgpgYGBjc2hhcnAKLy8g5bCd6K+V5byV54iG5pa55Z2XCnB1YmxpYyBib29sIFRyeUV4cGxvZGVCbG9jayhpbnQgeCwgaW50IHksIGludCB6LCBpbnQgdmFsdWUpIHsKICAgIEJsb2NrIGJsb2NrID0gQmxvY2tzTWFuYWdlci5CbG9ja3NbVGVycmFpbi5FeHRyYWN0Q29udGVudHModmFsdWUpXTsKICAgIC8vIOiOt+WPluaWueWdl+eahOeIhueCuOWOi+WKm+WSjOaYr+WQpuW8leeHgwogICAgZmxvYXQgZXhwbG9zaW9uUHJlc3N1cmUgPSBibG9jay5HZXRFeHBsb3Npb25QcmVzc3VyZSh2YWx1ZSk7CiAgICBib29sIGV4cGxvc2lvbkluY2VuZGlhcnkgPSBibG9jay5HZXRFeHBsb3Npb25JbmNlbmRpYXJ5KHZhbHVlKTsKICAgIGlmIChleHBsb3Npb25QcmVzc3VyZSA+IDBmKSB7CiAgICAgICAgQWRkRXhwbG9zaW9uKHgsIHksIHosIGV4cGxvc2lvblByZXNzdXJlLCBleHBsb3Npb25JbmNlbmRpYXJ5LCBmYWxzZSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICByZXR1cm4gZmFsc2U7Cn0KYGBgCgpgYGBjc2hhcnAKLy8g54iG54K45qih5ouf5qC45b+D566X5rOVCnB1YmxpYyB2b2lkIFNpbXVsYXRlRXhwbG9zaW9uKGludCB4LCBpbnQgeSwgaW50IHosIGZsb2F0IHByZXNzdXJlLCBib29sIGlzSW5jZW5kaWFyeSkgewogICAgLy8g5pyA5bCP5Lyg5pKt6ZiI5YC8ID0gbWF4KDAuMTMgw5cgc3FydCjljovlipspLCAxKQogICAgZmxvYXQgbnVtID0gTWF0aFV0aWxzLk1heCgwLjEzZiAqIE1hdGhGLlBvdyhwcmVzc3VyZSwgMC41ZiksIDFmKTsKICAgIAogICAgLy8gQkZTIOS8oOaSrQogICAgaW50IGV4cGxvc2lvblBvd2VyID0gMDsgIC8vIOe0r+iuoeW3suWkhOeQhueCueaVsAogICAgaW50IG51bTMgPSAwOyAgICAgICAgICAgIC8vIOi/reS7o+i9ruaVsAogICAgd2hpbGUgKGxpc3QuQ291bnQgPiAwIHx8IGxpc3QyLkNvdW50ID4gMCkgewogICAgICAgIGV4cGxvc2lvblBvd2VyICs9IGxpc3QuQ291bnQ7CiAgICAgICAgbnVtMysrOwogICAgICAgIC8vIOesrCA3IOi9ruWQjumineWkluihsOWHjwogICAgICAgIGZsb2F0IG51bTQgPSA1ZiAqIE1hdGhVdGlscy5NYXgobnVtMyAtIDcsIDApOwogICAgICAgIC8vIOacrOi9ruWOi+WKmyA9IOWIneWni+WOi+WKmyAvICjntK/orqHngrnmlbBeMC42NiArIOmineWkluihsOWHjykKICAgICAgICBmbG9hdCBudW01ID0gcHJlc3N1cmUgLyAoTWF0aEYuUG93KGV4cGxvc2lvblBvd2VyLCAwLjY2ZikgKyBudW00KTsKICAgICAgICBpZiAobnVtNSA+PSBudW0pIHsgIC8vIOWOi+WKm+S7jeWkp+S6jumYiOWAvO+8jOe7p+e7reS8oOaSrQogICAgICAgICAgICBmb3JlYWNoIChQcm9jZXNzUG9pbnQgaXRlbSBpbiBsaXN0KSB7CiAgICAgICAgICAgICAgICBmbG9hdCBudW03ID0gbnVtNSArIG1fcHJlc3N1cmVCeVBvaW50LkdldChpdGVtLlgsIGl0ZW0uWSwgaXRlbS5aKTsKICAgICAgICAgICAgICAgIG1fcHJlc3N1cmVCeVBvaW50LlNldChpdGVtLlgsIGl0ZW0uWSwgaXRlbS5aLCBudW03KTsKICAgICAgICAgICAgICAgIC8vIOWQkSA2IOS4quaWueWQkee7p+e7reS8oOaSrS4uLgogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CmBgYAoKYGBgY3NoYXJwCi8vIOaWueWdl+egtOWdj+WIpOWumgpwdWJsaWMgdm9pZCBUcnlBZGRQb2ludChpbnQgeCwgaW50IHksIGludCB6LCBpbnQgYXhpcywgZmxvYXQgY3VycmVudFByZXNzdXJlLAogICAgYm9vbCBpc0luY2VuZGlhcnksIExpc3Q8UHJvY2Vzc1BvaW50PiB0b1Byb2Nlc3MsIFNwYXJzZVNwYXRpYWxBcnJheTxib29sPiBwcm9jZXNzZWQpIHsKICAgIAogICAgaW50IGNlbGxWYWx1ZSA9IG1fc3Vic3lzdGVtVGVycmFpbi5UZXJyYWluLkdldENlbGxWYWx1ZSh4LCB5LCB6KTsKICAgIEJsb2NrIGJsb2NrID0gQmxvY2tzTWFuYWdlci5CbG9ja3NbVGVycmFpbi5FeHRyYWN0Q29udGVudHMoY2VsbFZhbHVlKV07CiAgICAKICAgIC8vIOWfuuS6juWdkOagh+WTiOW4jOeahOmaj+acuuezu+aVsO+8iDEuMH4yLjDvvIkKICAgIGludCBleHBsb3Npb25Qb3dlciA9IChpbnQpKE1hdGhVdGlscy5IYXNoKCh1aW50KSh4ICsgOTEzICogeSArIDIxNzU0NiAqIHopKSAlIDEwMHUpOwogICAgZmxvYXQgbnVtMyA9IE1hdGhVdGlscy5MZXJwKDFmLCAyZiwgZXhwbG9zaW9uUG93ZXIgLyAxMDBmKTsKICAgIGlmIChleHBsb3Npb25Qb3dlciAlIDggPT0gMCkgbnVtMyAqPSAzZjsgIC8vIDEyLjUlIOamgueOhyDDlzMKICAgIAogICAgLy8g5ZGo5Zu0IDYg6Z2i55qE5oC75Y6L5YqbCiAgICBmbG9hdCBudW00ID0gbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgtMSx5LHopICsgbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgrMSx5LHopCiAgICAgICAgICAgICAgICsgbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgseS0xLHopICsgbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgseSsxLHopCiAgICAgICAgICAgICAgICsgbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgseSx6LTEpICsgbV9wcmVzc3VyZUJ5UG9pbnQuR2V0KHgseSx6KzEpOwogICAgCiAgICAvLyDnoLTlnY/mnaHku7bvvJrmgLvljovlipsgLyAo54iG54K45oqX5oCnIMOXIOmaj+acuuezu+aVsCkgPiAxCiAgICBmbG9hdCBudW01ID0gTWF0aFV0aWxzLk1heChibG9jay5HZXRFeHBsb3Npb25SZXNpbGllbmNlKGNlbGxWYWx1ZSkgKiBudW0zLCAxZik7CiAgICBmbG9hdCBudW02ID0gbnVtNCAvIG51bTU7CiAgICAKICAgIGlmIChudW02ID4gMWYpIHsKICAgICAgICAvLyDmlrnlnZfooqvmkafmr4EKICAgICAgICBtX3N1YnN5c3RlbVRlcnJhaW4uRGVzdHJveUNlbGwoMCwgeCwgeSwgeiwgVGVycmFpbi5NYWtlQmxvY2tWYWx1ZSgwKSwgdHJ1ZSwgdHJ1ZSk7CiAgICAgICAgLy8g6L+e6ZSB54iG54K477ya5Y6L5YqbL+aKl+aApyA+IDUg5pe2IDk1JSDmpoLnjofvvIzlkKbliJkgNzUlCiAgICAgICAgZmxvYXQgcHJvYmFiaWxpdHkgPSBudW02ID4gNWYgPyAwLjk1ZiA6IDAuNzVmOwogICAgICAgIGlmIChtX3JhbmRvbS5Cb29sKHByb2JhYmlsaXR5KSkgewogICAgICAgICAgICBUcnlFeHBsb2RlQmxvY2soeCwgeSwgeiwgY2VsbFZhbHVlKTsKICAgICAgICB9CiAgICB9Cn0KYGBgCgpgYGBjc2hhcnAKLy8g54iG54K45ZCO5aSE55CG77ya54Gr54Sw5byV54eD5LiO5Lyk5a6z6K6h566XCnB1YmxpYyB2aXJ0dWFsIHZvaWQgUG9zdHByb2Nlc3NFeHBsb3Npb25zKGJvb2wgcGxheUV4cGxvc2lvblNvdW5kKSB7CiAgICAvLyDlr7nlj5fljovlipvms6Llj4rkvYbmnKrooqvmkafmr4HnmoTmlrnlnZcKICAgIGZvcmVhY2ggKHZhciBpdGVtMiBpbiBtX3N1cnJvdW5kaW5nUHJlc3N1cmVCeVBvaW50LlRvRGljdGlvbmFyeSgpKSB7CiAgICAgICAgaW50IGNlbGxWYWx1ZSA9IG1fc3Vic3lzdGVtVGVycmFpbi5UZXJyYWluLkdldENlbGxWYWx1ZShpdGVtMi5LZXkuWCwgaXRlbTIuS2V5LlksIGl0ZW0yLktleS5aKTsKICAgICAgICBCbG9jayBibG9jayA9IEJsb2Nrc01hbmFnZXIuQmxvY2tzW1RlcnJhaW4uRXh0cmFjdENvbnRlbnRzKGNlbGxWYWx1ZSldOwogICAgICAgIAogICAgICAgIC8vIOeBq+eEsOW8leeHg+amgueOhwogICAgICAgIGZsb2F0IHByb2JhYmlsaXR5ID0gaXRlbTIuVmFsdWUuSXNJbmNlbmRpYXJ5ID8gMC41ZiA6IDAuMmY7CiAgICAgICAgLy8g5p2h5Lu277ya5pa55Z2X5Y+v54eDIOS4lCDljovlipsv5oqX5oCnID4gMC4yCiAgICAgICAgaWYgKGJsb2NrLkdldEZpcmVEdXJhdGlvbihjZWxsVmFsdWUpID4gMGYKICAgICAgICAgICAgJiYgaXRlbTIuVmFsdWUuUHJlc3N1cmUgLyBibG9jay5HZXRFeHBsb3Npb25SZXNpbGllbmNlKGNlbGxWYWx1ZSkgPiAwLjJmCiAgICAgICAgICAgICYmIG1fcmFuZG9tLkJvb2wocHJvYmFiaWxpdHkpKSB7CiAgICAgICAgICAgIC8vIOW8leeHg+aWueWdl++8mueHg+eDp+ahtuaJqeaVo+iDveWKmyAxLjDvvIzmma7pgJrniIbngrggMC4zCiAgICAgICAgICAgIG1fc3Vic3lzdGVtRmlyZUJsb2NrQmVoYXZpb3IuU2V0Q2VsbE9uRmlyZSgKICAgICAgICAgICAgICAgIGl0ZW0yLktleS5YLCBpdGVtMi5LZXkuWSwgaXRlbTIuS2V5LlosCiAgICAgICAgICAgICAgICBpdGVtMi5WYWx1ZS5Jc0luY2VuZGlhcnkgPyAxZiA6IDAuM2YpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLy8g5a+55omA5pyJ55Sf54mp6K6h566X5Yay5Ye75Yqb5ZKM5Lyk5a6zCiAgICBmb3JlYWNoIChDb21wb25lbnRCb2R5IGJvZHkgaW4gbV9zdWJzeXN0ZW1Cb2RpZXMuQm9kaWVzKSB7CiAgICAgICAgQ2FsY3VsYXRlSW1wdWxzZUFuZERhbWFnZShib2R5LCBudWxsLCBvdXQgVmVjdG9yMyBpbXB1bHNlLCBvdXQgZmxvYXQgZGFtYWdlKTsKICAgICAgICBib2R5LlVuZGVyRXhwbG9zaW9uKGltcHVsc2UsIGRhbWFnZSk7CiAgICB9Cn0KYGBgCgpgYGBjc2hhcnAKLy8g54iG54K45Lyk5a6z5LiO5Yay5Ye75Yqb6K6h566XCnB1YmxpYyB2aXJ0dWFsIHZvaWQgQ2FsY3VsYXRlSW1wdWxzZUFuZERhbWFnZShWZWN0b3IzIHBvc2l0aW9uLCBmbG9hdCBtYXNzLAogICAgZmxvYXQ/IG9ic3RhY2xlUHJlc3N1cmUsIG91dCBWZWN0b3IzIGltcHVsc2UsIG91dCBmbG9hdCBkYW1hZ2UpIHsKICAgIAogICAgLy8g6YGN5Y6G5ZGo5Zu0IDPDlzPDlzMg55qE5Y6L5Yqb54K5CiAgICBmbG9hdCBudW0gPSAwZjsgICAgICAvLyDmgLvljovlipsKICAgIFZlY3RvcjMgemVybyA9IFZlY3RvcjMuWmVybzsgIC8vIOWOi+WKm+aWueWQkQogICAgCiAgICBmb3IgKGludCBpID0gLTE7IGkgPD0gMTsgaSsrKQogICAgICAgIGZvciAoaW50IGogPSAtMTsgaiA8PSAxOyBqKyspCiAgICAgICAgICAgIGZvciAoaW50IGsgPSAtMTsgayA8PSAxOyBrKyspIHsKICAgICAgICAgICAgICAgIGZsb2F0IG51bTUgPSAvKiDojrflj5bor6XngrnljovlipsgKi87CiAgICAgICAgICAgICAgICB6ZXJvICs9IG51bTUgKiBWZWN0b3IzLk5vcm1hbGl6ZSgvKiDov5znprvniIbngrjkuK3lv4PnmoTmlrnlkJEgKi8pOwogICAgICAgICAgICAgICAgbnVtICs9IG51bTU7CiAgICAgICAgICAgIH0KICAgIAogICAgLy8g6LSo6YeP5Zug5a2QID0gbWF4KHNxcnQo6LSo6YePKSwgMSkKICAgIGZsb2F0IG51bTYgPSBNYXRoVXRpbHMuTWF4KE1hdGhGLlBvdyhtYXNzLCAwLjVmKSwgMWYpOwogICAgCiAgICAvLyDlhrLlh7vlipsgPSA1LjU2IMOXIOaWueWQkSDDlyBzcXJ0KOaWueWQkemVv+W6pikgLyDotKjph4/lm6DlrZAKICAgIGltcHVsc2UgPSA1LjU1NTU1NTNmICogVmVjdG9yMy5Ob3JtYWxpemUoemVybykgKiBNYXRoRi5TcXJ0KHplcm8uTGVuZ3RoKCkpIC8gbnVtNjsKICAgIC8vIOS8pOWusyA9IDIuNTkgw5cgc3FydCjmgLvljovlipspIC8g6LSo6YeP5Zug5a2QCiAgICBkYW1hZ2UgPSAyLjU5MjU5MjQ4ZiAqIE1hdGhGLlNxcnQobnVtKSAvIG51bTY7Cn0KYGBgCgojIyMg54iG54K46Z+z5pWI5YiG57qn77yIYFN1YnN5c3RlbUV4cGxvc2lvbnMuY3Ng77yJCgpgYGBjc2hhcnAKLy8g5qC55o2u5oC75Y6L5Yqb6YCJ5oup54iG54K46Z+z5pWI5ZKM5Zmq6Z+z6IyD5Zu0CmlmIChwcmVzc3VyZSA+IDIwMDAwMDBmKSB7CiAgICBtX3N1YnN5c3RlbUF1ZGlvLlBsYXlTb3VuZCgiQXVkaW8vRXhwbG9zaW9uNyIsIDFmLCAuLi4pOyAgLy8g5pyA5aSn54iG54K4CiAgICBtX3N1YnN5c3RlbU5vaXNlLk1ha2VOb2lzZShwb3NpdGlvbiwgMWYsIDEzMGYpOyAgLy8g5Zmq6Z+z6IyD5Zu0IDEzMCDmoLwKfQplbHNlIGlmIChwcmVzc3VyZSA+IDQwMDAwMGYpIHsKICAgIG1fc3Vic3lzdGVtQXVkaW8uUGxheVNvdW5kKCJBdWRpby9FeHBsb3Npb242IiwgMWYsIC4uLik7CiAgICBtX3N1YnN5c3RlbU5vaXNlLk1ha2VOb2lzZShwb3NpdGlvbiwgMWYsIDEwMGYpOwp9CmVsc2UgaWYgKHByZXNzdXJlID4gODAwMDBmKSB7CiAgICBtX3N1YnN5c3RlbUF1ZGlvLlBsYXlTb3VuZCgiQXVkaW8vRXhwbG9zaW9uNSIsIDFmLCAuLi4pOwogICAgbV9zdWJzeXN0ZW1Ob2lzZS5NYWtlTm9pc2UocG9zaXRpb24sIDFmLCA3MGYpOwp9CmVsc2UgaWYgKHByZXNzdXJlID4gMTYwMDBmKSB7CiAgICBtX3N1YnN5c3RlbUF1ZGlvLlBsYXlTb3VuZCgiQXVkaW8vRXhwbG9zaW9uNCIsIDFmLCAuLi4pOwogICAgbV9zdWJzeXN0ZW1Ob2lzZS5NYWtlTm9pc2UocG9zaXRpb24sIDFmLCA1MGYpOwp9CmVsc2UgaWYgKHByZXNzdXJlID4gMzUwMGYpIHsKICAgIG1fc3Vic3lzdGVtQXVkaW8uUGxheVNvdW5kKCJBdWRpby9FeHBsb3Npb24zIiwgMWYsIC4uLik7CiAgICBtX3N1YnN5c3RlbU5vaXNlLk1ha2VOb2lzZShwb3NpdGlvbiwgMWYsIDQwZik7Cn0KZWxzZSBpZiAocHJlc3N1cmUgPiA4MGYpIHsKICAgIG1fc3Vic3lzdGVtQXVkaW8uUGxheVNvdW5kKCJBdWRpby9FeHBsb3Npb24yIiwgMWYsIC4uLik7CiAgICBtX3N1YnN5c3RlbU5vaXNlLk1ha2VOb2lzZShwb3NpdGlvbiwgMWYsIDM1Zik7Cn0KZWxzZSBpZiAocHJlc3N1cmUgPiAwZikgewogICAgbV9zdWJzeXN0ZW1BdWRpby5QbGF5U291bmQoIkF1ZGlvL0V4cGxvc2lvbjEiLCAxZiwgLi4uKTsgIC8vIOacgOWwj+eIhueCuAogICAgbV9zdWJzeXN0ZW1Ob2lzZS5NYWtlTm9pc2UocG9zaXRpb24sIDFmLCAzMGYpOwp9CmBgYAoKIyMjIGBCbG9jay5jc2Ag6Jma5pa55rOV5a6a5LmJCgo+IOS7peS4i+iZmuaWueazleWumuS5ieS6huaWueWdl+S4jueBq+eEsC/niIbngrjns7vnu5/kuqTkupLnmoTmjqXlj6PjgILlrZDnsbvlj6/opobnm5bov5nkupvmlrnms5XmnaXoh6rlrprkuYnooYzkuLrjgIIKCmBgYGNzaGFycAovLyDngavnhLDmjIHnu63ml7bpl7TvvJrmlrnlnZfooqvngavnhLDng6fnqb/miYDpnIDnmoTml7bpl7TvvIjmuLjmiI/np5LvvIkKLy8g5YC85Li6IDAg6KGo56S65pa55Z2X5LiN5Y+v54eDCnB1YmxpYyBmbG9hdCBGaXJlRHVyYXRpb247CnB1YmxpYyB2aXJ0dWFsIGZsb2F0IEdldEZpcmVEdXJhdGlvbihpbnQgdmFsdWUpID0+IEZpcmVEdXJhdGlvbjsKCi8vIOeHg+aWmeeDreWAvO+8muS9nOS4uuiQpeeBq+eHg+aWmeaXtueahOeDremHj+etiee6pwovLyDlgLzkuLogMCDooajnpLrkuI3og73kvZzkuLrnh4PmlpkKcHVibGljIGZsb2F0IEZ1ZWxIZWF0TGV2ZWw7CnB1YmxpYyB2aXJ0dWFsIGZsb2F0IEdldEZ1ZWxIZWF0TGV2ZWwoaW50IHZhbHVlKSA9PiBGdWVsSGVhdExldmVsOwoKLy8g54eD5paZ54eD54On5pe26Ze077ya5L2c5Li66JCl54Gr54eD5paZ5pe26IO957u05oyB55qE54eD54On5pe26Ze077yI5ri45oiP56eS77yJCnB1YmxpYyBmbG9hdCBGdWVsRmlyZUR1cmF0aW9uOwpwdWJsaWMgdmlydHVhbCBmbG9hdCBHZXRGdWVsRmlyZUR1cmF0aW9uKGludCB2YWx1ZSkgPT4gRnVlbEZpcmVEdXJhdGlvbjsKCi8vIOeIhueCuOaKl+aAp++8muaWueWdl+aKteaKl+eIhueCuOeahOiDveWKmwovLyDlgLzkuLogSW5maW5pdHkg6KGo56S65LiN5Y+v6KKr54iG54K45pGn5q+BCnB1YmxpYyBmbG9hdCBFeHBsb3Npb25SZXNpbGllbmNlOwpwdWJsaWMgdmlydHVhbCBmbG9hdCBHZXRFeHBsb3Npb25SZXNpbGllbmNlKGludCB2YWx1ZSkgPT4gRXhwbG9zaW9uUmVzaWxpZW5jZTsKCi8vIOm7mOiupOeIhueCuOWOi+WKm++8muaWueWdl+iiq+W8leeIhuaXtuS6p+eUn+eahOeIhueCuOWOi+WKmwovLyDlgLzkuLogMCDooajnpLrmlrnlnZfkuI3lj6/niIbngrgKcHVibGljIGZsb2F0IERlZmF1bHRFeHBsb3Npb25QcmVzc3VyZTsKcHVibGljIHZpcnR1YWwgZmxvYXQgR2V0RXhwbG9zaW9uUHJlc3N1cmUoaW50IHZhbHVlKSA9PiBEZWZhdWx0RXhwbG9zaW9uUHJlc3N1cmU7CgovLyDpu5jorqTmmK/lkKblvJXnh4PvvJrniIbngrjmmK/lkKbpmYTluKbngavnhLDlvJXnh4PmlYjmnpwKcHVibGljIGJvb2wgRGVmYXVsdEV4cGxvc2lvbkluY2VuZGlhcnk7CnB1YmxpYyB2aXJ0dWFsIGJvb2wgR2V0RXhwbG9zaW9uSW5jZW5kaWFyeShpbnQgdmFsdWUpID0+IERlZmF1bHRFeHBsb3Npb25JbmNlbmRpYXJ5OwoKLy8g54iG54K45piv5ZCm5L+d55WZ5o6J6JC954mp77ya54iG54K45pGn5q+B6K+l5pa55Z2X5pe25piv5ZCm5L+d55WZ5o6J6JC954mpCnB1YmxpYyBib29sIEV4cGxvc2lvbktlZXBzUGlja2FibGVzOwpgYGAKCgo8L2RldGFpbHM+CgojIyDlj4LogIPotYTmlpkKCi0gW01pcmFoZXplIFN1cnZpdmFsY3JhZnQgV2lrae+8mkZpcmVdKGh0dHBzOi8vc3Vydml2YWxjcmFmdC5taXJhaGV6ZS5vcmcvd2lraS9GaXJlKQotIFtNaXJhaGV6ZSBTdXJ2aXZhbGNyYWZ0IFdpa2nvvJpDYW1wZmlyZV0oaHR0cHM6Ly9zdXJ2aXZhbGNyYWZ0Lm1pcmFoZXplLm9yZy93aWtpL0NhbXBmaXJlKQotIFtNaXJhaGV6ZSBTdXJ2aXZhbGNyYWZ0IFdpa2nvvJpHdW5wb3dkZXIgS2Vnc10oaHR0cHM6Ly9zdXJ2aXZhbGNyYWZ0Lm1pcmFoZXplLm9yZy93aWtpL0d1bnBvd2Rlcl9LZWdzKQotIFtGYW5kb20g6KW/6K+t57u05Z+677yaRnVlZ29dKGh0dHBzOi8vc3Vydml2YWxjcmFmdC5mYW5kb20uY29tL2VzL3dpa2kvRnVlZ28pCi0gW0ZhbmRvbSDopb/or63nu7Tln7rvvJpCYXJyaWwgZGUgcMOzbHZvcmFdKGh0dHBzOi8vc3Vydml2YWxjcmFmdC5mYW5kb20uY29tL2VzL3dpa2kvQmFycmlsX2RlX3AlQzMlQjNsdm9yYSkKLSBb5bu6562R5LiO5Y+W5pqWXSgvZ3VpZGUvYnVpbGRpbmcpCi0gW+eUtei3r+WFpemXqF0oL3RoZW9yeS9jaXJjdWl0cykK
