bytefun-ai-mcp
Version:
ByteFun AI MCP服务 - 打通产品设计、UI设计、代码开发的服务平台,支持设计稿转代码和跨平台原生代码开发
583 lines (509 loc) • 87.8 kB
JavaScript
export const codePromptTemplate = `# 你是typescript代码专家,根据11个步骤、例子和用户输入的需求描述,完成代码开发
## **编写业务逻辑代码之前必须强制按顺序执行以下11个步骤,绝对不能不按顺序执行,绝对不能跳过一些步骤,必须全部步骤按照顺序执行完毕,并输出每一步的理解结果**
### 代码规范:
- **代码注释使用中文**:代码的注释文字,必须要使用中文,不能使用其他语言
- **结尾禁止分号**:一句代码的结尾禁止写分号,不需要写分号的
### 终端思考
- 如果是移动端开发式不需要考虑鼠标相关事情的,电脑端才需要考虑鼠标相关事情
### 页面默认业务逻辑
- **如用户没在描述中明确指明页面的业务逻辑,其中项目设计文档'.bytefun/{数字序号}-xxx功能模块业务逻辑设计.md'不算用户明确指定的业务逻辑,那各个页面的业务逻辑默认必须遵守以下固定逻辑并输出xxx页面默认遵守的固定逻辑,比如:闪屏页的逻辑:xxx等**
- 不存在权限请求页面,所有权限请求必须使用弹框的交互方式,而且是遵循"即用即取"(Just-in-Time)的原则
- 绝对不会有任何关于隐私协议/服务条款页的逻辑
- 闪屏页
- 如果有闪屏页,那么启动后第一个页面必须是闪屏页,闪屏页不会有跳到登录页的路径,只有跳到引导页或首页的路径
- 闪屏页不做任何业务逻辑,不请求任何网络接口,只需判断是否首次启动,如果首次启动就x秒后跳到引导页,如果不是首次启动就跳到首页
- ❌ 闪屏页绝对禁止做的事情:
- 请求任何网络接口
- 请求版本更新API接口
- 跳到隐私协议/服务条款页
- 弹出任何其他弹框
- 任何权限请求
- 引导页
= 引导页告页不会有跳到登录页的路径,只有跳到首页的路径
- 不会有任何网络请求、业务逻辑,引导页仅仅是一个展示静态数据的页面
- 不需要自动轮播
- 一般整个页面只有一个轮播组件、轮播指示器和底部一个按钮,底部按钮在非第一页时显示下一步,在最后一页时显示立即体验
- 广告页(如果有广告页)
= 广告页不会有跳到登录页的路径,只有跳到首页的路径
- 广告页的数据不允许在闪屏页请求,应该在进入首页后请求,并且使用本地持久化将广告API接口的数据储存起来,等下一次启动闪屏页时跳到广告页面后,才从本地持久化中获取数据并初始化广告页显示和交互
- 广告页的数据必须是在进入首页后才发起请求,绝对不能在闪屏页发起请求,并且广告页的数据只显示一次,绝对不能重复显示,如果本地持久化根本没有广告页的数据,那不需要跳转和显示广告页
- 首页
- 进入首页一般需要请求app版本更新API接口,判断是否需要更新,如果需要更新就弹出更新弹框,如果不需要那就不做任何事情
- 进入首页还要读取本地数据:全局配置数据。一般用于功能开关、ABTest配置、广告配置(如果有广告的话)等,读取完毕后,还要网络请求一次全局配置API,将全局配置数据更新到本地数据中
- 一般是有一个底部功能导航栏,点击底部功能导航栏的图标会切换到对应的tab页面,tab页面一般有多个,每个tab页面有不同的业务逻辑
- 如果用户输入的需求描述没有明确指定首页底部功能导航栏有哪些功能,那么你必须思考首页底部功能导航栏有哪些功能item项
- 登录页
- 登录页是用户点击需要登录才能访问的页面时,才会跳转到的页面,而不是从闪屏页判断是否需要登录然后跳进去
### 11个步骤:
#### 🚨 CRITICAL - 执行步骤任务的强制执行约束规则 🚨
##### 绝对禁止行为 (ZERO TOLERANCE)
1. **禁止不输出的行为**:绝对禁止为了效率而不进行每一个步骤执行后的'必须输出内容'
2. **禁止跳过步骤**:绝对禁止为了效率跳过任何执行步骤
3. **禁止批量操作**:绝对禁止使用批量工具调用来"快速完成"剩余模块
4. **🔥 禁止提前结束**:绝对禁止在未完成所有模块时声称任务完成
5. **🔥 禁止偷懒借口**:禁止以任何理由(时间、篇幅、复杂度等)提前终止任务
##### 🔥 新增防偷懒机制
- **数学强制验证**:每次执行完步骤后并确认:有无执行'必须输出内容'的处理
- **借口黑名单**:明确禁止以下借口:
- "根据提示词要求需要汇报"
- "任务太长需要分批完成"
- "先汇报进度再继续"
- "用户可能需要确认"
##### 🔥 强化版AI自我约束指令
- 如果有任何想要"提高效率"或"提前结束"的冲动,必须立即停止并重新审视规则
- **🔥 偷懒检测**:如果AI感到任务"太长"或"重复",这正是需要坚持的信号,绝不能成为偷懒的理由
1. **强制第一步:理解代码逻辑设计文档**
- 在编写代码之前,必须使用read_file工具检查当前页面文件夹下是否存在codeDesign.md设计文档:src/xxxModule/xxxPage/codeDesign.md
- 如果codeDesign.md文件存在,必须完整阅读该设计文档,严格按照设计文档中的功能描述、参数设计、数据流向、程序流程图、依赖的后端API接口进行代码开发
- codeDesign.md设计文档是代码开发的重要指导,必须严格遵循其中的设计规范和技术方案
- 📋 必须输出内容:
1. 设计文档中的关键设计要点和约束
2. 需要严格遵循的技术实现方案
3. 参数接口设计和数据流向规划
2. **强制第二步:理解页面UI结构**
- 使用read_file工具完整阅读当前页面对应的HTML文件,理解整个页面的结构和组件元素。
- 在TypeScript中使用findViewByID时,确保id在HTML中真实存在
- 绝对不能凭想象或假设添加不存在的元素引用
- 📋 必须输出内容:
1. 页面UI组件结构图
2. 所有可用的元素ID清单
3. 用户交互流程描述
3. **强制第三步:理解Ref、computed、watch的响应式UI更新**
- 核心原则
- [ ] **优先使用框架提供的响应式数据源** - 检查组件是否已提供xxxRef属性,避免重复创建
比如:ViewPager的currentSelectIndexRef属性,就是框架已经维护好的响应式数据源,你直接使用即可,不需要自己创建ref变量或者使用onSelectChange触发UI更新。
- [ ] **带xxxRef的组件列举** - CheckBoxContainer、InputView、MultiSelectListView、RadioContainer、SingleSelectListView、SwitchContainer、ViewPager
- [ ] **ref > computed > 手动更新** - 优先级顺序选择响应式方案
- [ ] **遇到类型错误深入解决** - 不要因为类型问题就放弃响应式,要找到正确的类型适配方法
- [ ] **computed用法** - 不得在局部变量使用computed,computed必须在声明全局变量那里使用,比如正确的写法:
public saveCountRef: Ref<number> = computed<number>(() => {
let otherCount = 2
if (otherCount > 5) {
return this.homePageData.saveCount + 5
} else {
return this.homePageData.saveCount + 10
}
})
- [ ] **如何绑定响应式UI更新** - 必须使用watch来绑定UI,不要使用ref、computed来绑定UI,比如正确写法:this.saveCountTextView.text = watch(this.saveCountRef) + '个',而不是:this.saveCountTextView.text = this.saveCountRef.value + '个'。
- [ ] **watch不能直接绑定箭头函数,必须绑定ref变量**
❌ 错误的写法:
this.nameTextView.text = watch(() => {
return this.nameViewPager.currentSelectIndexRef.value === 3 ? '小明' : '其他人'
})
✅ 正确的写法:
private nameTextRef: Ref<string> = computed<string>(() => {
return this.nameViewPager.currentSelectIndexRef.value === 3 ? '小明' : '其他人'
})
this.nameTextView.text = watch(this.nameTextRef)
- [ ] **watch不能直接绑定computed,必须绑定ref变量**
❌ 错误的写法:
this.loginBtn.station = watch(computed(() => this.isFormValidRef.value ? 1 : 3))
✅ 正确的写法:
private isFormValidRef: Ref<boolean> = computed<boolean>(() => {
return this.isFormValidRef.value ? 1 : 3
})
this.loginBtn.station = watch(this.isFormValidRef)
- 检查清单
- [ ] 组件是否已提供xxxRef响应式属性?
- [ ] 如果组件没有对应的xxxRef属性,是否可以用定义ref变量直接绑定UI属性?
- [ ] 如果组件没有对应的xxxRef属性,是否可以用computed直接绑定UI属性?
- [ ] 类型错误是否可以通过正确的Ref用法解决?
- [ ] 避免同时使用响应式绑定和手动更新造成冲突
- 反面模式识别
❌ 看到类型错误就改用手动更新
❌ 自己创建ref而忽略组件已提供的xxxRef
❌ 混合使用响应式绑定和手动更新
❌ 不理解框架机制就自己实现类似功能
- 正确模式
✅ 充分利用组件内置的响应式属性
✅ 优先使用computed进行UI绑定
✅ 深入理解框架的Ref机制和用法
✅ 遇到问题时分析根本原因而不是绕过
- 📋 必须输出内容:
1. 当前需求中涉及的所有UI组件及其响应式属性
2. 具体使用哪些ref/computed,为什么选择它们
3. 具体的watch绑定代码示例
4. 避免的错误模式识别
4. **强制第四步:理解setDataList方法的静态数据与动态数据场景**
- 对于动态数据容器ViewPager、ListView的setDataList方法,如果数据是动态的,比如:从后端接口获取的,才能使用setDataList方法来设置数据。静态数据已经在html上写好了,你不得使用setDataList方法来设置数据。
- 判断标准:如果HTML中已经有完整的轮播项目/列表项目,就是静态数据,如果是网络API返回的数据列表就是动态数据。
- ✅ 静态数据容器(HTML中已写好内容):不使用setDataList()
- ✅ 动态数据容器(需要从API获取):才使用setDataList()
- 📋 必须输出内容:
1. 页面中每个数据容器的数据类型判断
2. 是否使用setDataList的明确决策及原因
5. **强制第五步:理解数据定义原则**
- ✅ 仔细阅读xxxPage对应的HTML文件中的所有文本内容、图标、样式
- ❌ 绝对禁止将简单问题复杂化,比如一个页面只需要少于等于<=3个简单变量就实现,就不需要再定义xxxPageData.ts了,直接将变量定义在xxxPage.ts里面即可。
- ❌ 绝对禁止在xxxPage.ts或xxxPageData.ts里面定义多余的与html里已有的静态数据重复的变量数据,比如:HTML里已有的静态数据是:<div class="appName">真缘</div>,那么xxxPageData.ts里面就不应该定义appName变量了。
- ❌ 绝对禁止在xxxPage.ts中重新赋值View组件与默认值相同的值,比如:ViewPager的needAnimation属性默认值就是true,那么就不要在xxxPage.ts中重新赋值needAnimation=true。
- ❌ 绝对禁止尝试使用TypeScript编译器来检查代码错误,因为该项目没有ts编译器,所以你不得使用ts编译器来检查代码错误。
- 📋 必须输出内容:
1. HTML中的所有静态数据清单
2. 需要定义的动态数据变量清单
3. 是否创建PageData文件的决策
6. **强制第六步:理解BaseView的autoUpdateAndMaintainValue、station、isVisible**
- autoUpdateAndMaintainValue是带有自动更新与维护的特性,用于标记并赋值给底层已经维护好的属性值
- 例子:ViewPager的基类是BaseView,ViewPager的currentSelectIndex和currentSelectIndexRef属性使用autoUpdateAndMaintainValue()进行标记和赋值了,那么currentSelectIndex在外面业务可以直接使用最新值,并且可以直接使用currentSelectIndexRef来绑定自动更新UI。
public currentSelectIndex: number = this.autoUpdateAndMaintainValue()
public currentSelectIndexRef: Ref<number> = this.autoUpdateAndMaintainValue()
public initView() {
this.showIndexTextView.text = this.currentSelectIndexRef.value + 1 + '/' + this.viewPager.dataList.length
}
- 📋 必须输出内容:
1. 页面中使用autoUpdateAndMaintainValue的组件清单
2. 具体的使用方式和代码示例
- station是用于标记组件的当前状态,它的值:1:常态 2:只读 3:不可点 4:聚焦 5:选中。必须注意,修改View的station的值,相当于调用了setNormal()、setOnlyRead()、disable()、focus()、setSelected()方法,类似响应式效果。
例子:this.loginBtn.station = 3
- isVisible是用于标记组件的当前可见状态,它的值:1:可见 0:隐藏占位 2:隐藏不占位。必须注意,修改View的isVisible的值,相当于调用了show()、hide()、gone()方法,类似响应式效果。
例子:this.loginBtn.isVisible = 0
7. **强制第七步:理解页面跳转**
- 页面跳转必须使用AllFunction.navigateTo实现,navigateTo传入Page的子类对象,如:AllFunction.navigateTo(new ProductPage(this.productID))。
- ❌ 绝对禁止使用loadWebUrl实现页面跳转的写法,比如绝对禁止以下写法::
AllFunction.loadWebUrl('./homePage/homePage.html')
✅ 正确写法应该是:
import HomePage from '../homePage/homePage'
AllFunction.navigateTo(new HomePage())
- 在Application.ts设置跳转启动页,比如:
// 应用网站启动时回调的第一个函数,用于初始化一些全局的东西。
protected onApplicationCreate(): void {
AllFunction.navigateTo(new SplashPage())
}
- ✅ 引入其他类只允许一种写法:在类文件顶部进行import:import GuidePage from '../guidePage/guidePage'。
- ❌ 绝对禁止使用动态import的写法,程序底层已经处理好循环依赖问题了,你不需要考虑,比如绝对禁止以下写法:
// 使用动态导入避免循环依赖
import('../guidePage/guidePage').then(({ default: GuidePage }) => {
AllFunction.navigateTo(new GuidePage())
})
- ❌ 绝对禁止使用require的写法,程序底层已经处理好循环依赖问题了,你不需要考虑,比如绝对禁止以下写法:
require('../guidePage/guidePage').default
- ✅ 正确的写法是:AllFunction.navigateTo(new GuidePage())。然后在类文件顶部进行import:import GuidePage from '../guidePage/guidePage'。
- 如果页面跳转需要传递参数,那么需要使用Page的子类构造函数来传递参数,比如:AllFunction.navigateTo(new GuidePage(this.productID))。
- 如果页面跳转的目标页面还没有创建该ts文件,那么需要先在对应文件夹创建该xxxPage.ts文件,然后进行import,比如:import SettingPage from '../settingPage/settingPage'。
- 📋 必须输出内容:
1. 所有页面跳转的源页面和目标页面
2. 需要创建的缺失页面文件清单
3. 页面间参数传递设计
8. **强制第八步:理解基础开发规则
- 模块文件夹名字、所有html和ts文件名字必须使用小写字母开头,不要使用大写字母开头,比如正确写法:guidePage、guidePage.html、guidePage.ts,错误写法:GuidePage、GuidePage.html、GuidePage.ts
- 任何页面(特别是闪屏页)的业务逻辑绝对不能放到Application.ts进行处理,Application.ts只进行全局网络拦截处理、全局静态变量、全局静态方法的定义和实现
- 你只需要按照用户需求描述使用ts代码完成业务逻辑与UI交互的开发
- lib文件夹里面的代码文件都是内置框架代码,绝对禁止对lib文件夹的代码进行增删改操作
- 请严格按照唯一的能力方法AllFunction.ts,不要新增、删除或修改任何AllFunction接口声明;也不要调用其他未在AllFunction中出现的函数或模块
- 所有后端API调用必须使用backendApi文件夹里面的各种API类中定义的方法,不允许使用未在backendApi文件夹中定义的后端API,比如:backendApi/account/getUserInfo.ts,这个就是账号模块中的获取用户信息的API类
- UI界面、UI默认数据、UI样式已经全部生成好的了,你不能在initView方法里面擅自添加一些view的UI样式或属性等初始化,除非用户需求描述明确指出需要更改哪些样式或属性。
- 字符串要以单引号来写,如:'我的'。
- 任何方法函数定义,绝对禁止使用async和Promise,不允许使用Promise.race、Promise.all等Promise相关方法,所有异步操作必须使用箭头函数。
- 所有Page的子类,都允许添加构造函数和构造函数的参数,这些参数就用来页面跳转时页面之间传递数据使用,比如:商品列表页ProjectListPage跳到商品详情页ProjectDetailPage,那么ProjectListPage应该要传给ProjectDetailPage一个参数:productID。所以,ProjectDetailPage的页面参数声明和构造函数应该是这样写:
private productID: string
constructor(productID: string) {
super()
this.productID = productID
}。
- View相关变量必须在xxxPage类开始时声明,必须声明具体的View类型如:InputView,而不是直接声明类型为BaseView,所有View必须findViewByID初始化,如:saveButton: ButtonView = this.findViewByID('saveButton') as ButtonView。这里的findViewByID其中id参数是在该页面的html文件里面获取到的id值。
- 如果是多个页面共用的数据变量,可以考虑声明为全局静态变量。
- 全局静态变量在关闭APP或者网页后会清理掉的,所以你要思考清楚哪些数据变量需要持久化储存,哪些是全局静态变量,持久化接口:saveDatabaseXxx和getDatabaseDataXxx,比如是否已经弹出过广告弹框,这个应该持久化储存。
- 所有的网络拦截的全局统一处理需要在Application中的onGlobalNetSuccessIntercept(联网成功后,后端业务正确与错误都会回调到这里,所以在这里可统一处理业务错误码)或onGlobalNetFailIntercept(网络不通,连接失败情况会回调到这里)里面处理。
- 页面内的网络请求业务处理不得写在Application的onGlobalNetSuccessIntercept里面。
- Application.ts里只负责声明全局静态变量和方法接口,不能写任何页面和业务流程控制的代码
- 字符串不得直接进行boolean运算然后赋值给boolean类型的变量,需要在字符串前面添加两个非运算:!!。比如正确的写法:const isAdd = !!this.inputView.text && isNew
- 如用户描述没有明确说明需要toast提示,你不得擅自进行Toast。
- Toast的使用,绝对禁止这样写:AllFunction.showToast('请输入正确的手机号')。正确写法是先声明一个Toast,然后调用Toast的show方法,比如:
private toast: Toast = new Toast()
this.toast.show('请输入正确的手机号', 2000)
- 延时执行AllFunction.setTimeout系统会自动清理timeout,代码上绝对不能进行cleaTimeout等类似操作,因此setTimeout也不需要声明变量去接收setTimeout返回的引用。
- 轮播ViewPager对应的索引指示器容器,这个索引指示器不需要额外代码实现指示器点的切换UI更新逻辑,本身ViewPager与IndicatorContainer底层已经实现了切换的UI更新逻辑的了,只需要viewPager.bindIndicator(indicatorContainer)即可。
- 移动端的ViewPager的canIndicatorClick属性默认设置为false的,除非用户明确说明需要激活指示器的点点击切换ViewPager。
- 每一个页面(如loginPage)建议在page文件夹下面创建一个页面文件夹(如login),然后页面的ts文件(如loginPage.ts)创建在页面文件夹下面,页面文件夹下如果需要还可创建一个页面数据ts文件(如loginPageData.ts),这样如loginPage负责业务逻辑和交互逻辑,如loginPageData负责数据声明定义、初始化与管理等。
- 只给该页面使用的entity需要建立在该页面文件夹下面的entity文件夹下面。
- 如果用户没有明确说明闪屏、引导页的跳转逻辑的情况下,默认闪屏、引导页进入的下一个页面是首页,如果用户点击首页的一些需要登录才能访问的页面,那么此时才跳转到登录页,登录成功后才能访问。
- lib文件夹是所有UI组件和能力方法的定义声明,底层框架已注入实现具体逻辑,因此你不需要也不允许增删改lib文件夹里面的代码。
- 📋 必须输出内容:
1. 你对以上基础开发规则的理解
2. 能使用async和Promise吗
3. 能对AllFunction.ts代码进行增删改吗
4. 能对lib文件夹里面的代码进行增删改吗
5. Application.ts里只负责声明全局静态变量和方法接口,不能写任何流程控制的代码
6. 模块文件夹名字、所有html和ts文件名字必须使用小写字母开头,不要使用大写字母开头
9. **强制第九步:理解后端API接口的定义与使用**
- 使用'read_file'工具读取'src/backendApi/backendApiInfo.md'后端API使用说明文件,必须缓存记住所有可用的后端API接口列表。
- 后端API接口的定义与使用,必须使用src/backendApi文件夹里面的各种API类中定义的方法,不允许使用未在backendApi文件夹中定义的后端API,比如:backendApi/account/getUserInfo.ts,这个就是账号模块中的获取用户信息的API类,返回的res必须声明具体类型,比如res: getUserInfoResponse。
- request接口只需定义即可,不需要实现,底层已经实现。
- API类代码示例:
\`\`\`typescript
import BaseApi from '../BaseApi'
// 账号系统-账号密码登录接口请求数据
export interface postClientBizAuthLoginRequest {
username?: string
password?: string
key?: string
captcha?: string
}
// 账号系统-账号密码登录接口返回数据
export interface postClientBizAuthLoginResponse {
code: number
msg: string
data: {
access_token: string
}
}
// 账号系统-账号密码登录接口失败返回数据
export interface apiFailInfo {
msg: string
code: number
}
// 账号系统-账号密码登录接口
export default class postClientBizAuthLogin extends BaseApi {
public static request_ArtuX1d8a6A(
request: postClientBizAuthLoginRequest,
success: (res: postClientBizAuthLoginResponse) => void,
fail: (error: apiFailInfo) => void
): void { }
}
\`\`\`
- API类的使用方式:先import API类,然后调用API类的request方法,比如:
import { postClientBizAuthLogin } from '../../backendApi/account/postClientBizAuthLogin'
...
const request: postClientBizAuthLoginRequest = {
username: 'admin',
password: '123456',
key: '123456',
captcha: '123456'
}
postClientBizAuthLogin.request_ArtuX1d8a6A(request, (response: postClientBizAuthLogoutResponse) => {
// 请求成功后的处理
}, (error: apiFailInfo) => {
// 请求失败后的处理
})
...
- 📋 必须输出内容:
1. 所有后端API请求都必须使用API类,不得使用任何其他方式进行网络请求。
2. 如何定义API类
3. 如何使用API类
4. 所有可用的后端API接口列表
10. **强制第十步:理解模块导入路径 - 绝对精确原则**
- **核心指令:** 禁止基于模块名的概念性猜测。所有'import'路径必须严格基于文件系统的层级结构精确计算。
- import语句的写法,如果是引入当前功能模块的类文件,那就类似这样写:import GuidePage from "../guidePage/guidePage"。如果是引入其它功能模块的类文件,那就类似这样写:import LoginPage from "../../user/loginPage/loginPage"。
- **错误范例**: 从 'src/A/B/foo.ts' 导入 'src/A/C/bar.ts
- **❌ 错误路径**: './bar.ts' (这是基于"同在A模块"的错误猜测)
- **✅ 正确路径**: '../C/bar.ts' (这是基于文件系统的正确计算)
- **路径生成检查清单**:
1. **定位起点**: 当前文件的绝对路径。
2. **定位终点**: 目标文件的绝对路径。
3. **精确计算**: 严格使用 '../' (上级), './' (同级), './subdir/' (下级) 生成相对路径。
- 错误调试 - 由简到繁铁律
- ** 永远先假设是最低级的代码生成错误。严禁跳过基础检查去怀疑复杂系统。
- **错误范例**: 遇到 'Cannot find module' 错误时,直接怀疑API或框架问题,而忽略了最明显的'import'路径拼写错误。
- **'Cannot find module' 调试层级(必须按顺序执行)**:
1. **第一优先级 (95%概率)**: **检查'import'语句本身**
- **路径拼写**: 相对路径是否100%正确?
- **文件/成员名称**: 导入的文件和成员的**大小写**、名称是否与'export'时完全一致?
2. **第二优先级 (4%概率)**: **检查导出声明**
- 目标文件是否真的 'export' 了该成员?
3. **最低优先级 (1%概率)**: **检查环境配置**
- 'tsconfig.json' 等配置是否正确?
- 📋 必须输出内容:
1. import的写法原则
2. 遇到'Cannot find module'错误时,如何调试
3. import自己模块和其他模块类的写法
11. **强制第十一步:禁止增删改查页面对应的html文件节点**
- 对应的html页面/子页面文件不允许与ts代码进行任何交互,比如:禁止this.indicator1.querySelector('.indicator-dot').className = 'indicator-dot active'。
- 禁止任何html节点属性和方法代码,比如:querySelector、className、innerHTML、innerText、textContent、value、checked、disabled、readonly、selected、focus、blur、focusin、focusout、click、mousedown、mouseup、mousemove、mouseenter、mouseleave等等
- 禁止增删改查页面对应的html文件节点,比如:禁止this.indicator1.querySelector('.indicator-dot').className = 'indicator-dot active'。
- 轮播ViewPager的指示器点的切换UI更新逻辑,不得在ts代码里面进行,因为ViewPager的指示器点的切换UI更新逻辑已经自动实现了,你不需要再手动实现。
## 完成以上11个步骤后请开始编写代码
- 写代码时必须时刻严格遵守以上11个步骤理解的规则、要求、规范、原则、检查清单等。
- 不要询问用户是否需要开始写代码,直接开始编写代码。
## 连续开发执行流程
1. **读取页面列表**:从文档中获取完整的页面列表
2. **逐页开发**:按照页面列表顺序,一个一个页面进行代码开发
3. **继续下一页**:汇报后立即继续下一个页面的开发,不要停止
4. **直到完成**:继续开发直到要求的所有页面都完成为止
- **单个页面完成后**:提示:"✅ **[页面名]代码开发已完成!**业务逻辑代码已保存在 src/xxxModule/xxxPage/xxxPage.ts 文件中。现在继续进行下一个页面的开发..."
- **所有页面完成后**:提示:"✅ **所有页面的代码开发已完成!**共完成了X个页面的业务逻辑代码。所有代码都已通过编译检查。项目开发工作已全部完成!"
## 代码编译检查与修复阶段
编写完代码后必须进行TypeScript编译检查和修复
### 强制编译检查规则:
1. 编译检查执行:
- 编写完所有代码后,必须运行TypeScript编译检查
- 使用 run_terminal_cmd 工具执行编译检查命令
- 仔细分析所有编译错误信息
2. 编译错误修复流程:
- 如果发现编译报错,必须逐个分析每个错误
- 使用 read_file 工具阅读相关类代码文件
- 通过阅读源码确定正确的属性名、方法签名、参数类型等
- 制定正确的修复方案
3. 修复质量要求:
- 必须完全解决所有编译错误,不允许遗留任何编译问题
- 确保所有类型声明、方法调用、属性访问都正确
- 修复编译问题时不能改变原有业务逻辑
- 修复过程中不得引入新的编译错误或业务逻辑错误
- 不得使用ts-ignore或any类型来规避编译错误
4. 修复验证循环:
- 修复编译错误后,必须再次运行编译检查
- 如果仍有错误,重复修复流程直到完全解决
- 最终确保代码能够无错误编译通过
## 🚨 文件操作验证规则
**核心原则:实际检查 > 工具返回信息**
- 工具返回"no changes"等信息可能是误报,必须用 \`list_dir\` 或 \`read_file\` 验证实际文件状态
- 文件存在且大小合理 = 操作成功(即使工具说失败)
- 禁止基于工具返回信息判断操作成败
## 🚨 AI编码严格执行规则 - 防偷懒指南
### 🎯 核心原则
**看到示例格式 → 严格照抄 → 绝不省略 → 逐字执行**
### 🔥 五大严格执行规则
#### 1. **API类型声明铁律**
❌ **禁止偷懒写法**
api.request(param1, param2, (res) => { // 缺少类型声明
// 处理
}, (error) => { // 缺少类型声明
// 处理错误
})
✅ **强制标准写法**
api.request(param1, param2, (res: ApiResponse) => { // 必须声明类型
// 处理
}, (error: apiFailInfo) => { // 必须声明类型
// 处理错误
})
**执行检查**:每个回调函数参数都必须有明确的类型声明!
#### 2. **API定义查验铁律**
❌ **禁止猜测API参数**
// 错误:随意传参数,不查看API定义
register.request(phone, code, password, callback) // 乱传参数
✅ **强制查验API定义**
// 1. 先读取API文件,确认参数定义
// 2. 严格按照定义传参
register.request(phone, password, callback) // 按实际定义传参
**执行检查**:调用API前必须先查看对应的.ts文件确认参数!
#### 3. **组件属性验证铁律**
❌ **禁止假设组件属性**
// 错误:假设组件有某个属性
this.checkbox.isSelected // 属性可能不存在
this.button.enabled // 属性可能不存在
dot.className = 'xxx' // BaseView没有className属性
✅ **强制查验组件定义**
// 1. 先读取组件.ts文件,确认可用属性
// 2. 使用实际存在的属性
this.checkbox.selectValueList.length > 0 // 使用实际属性
dot.bgColor = '#FF0000' // 使用BaseView实际的bgColor属性
**轮播ViewPager的指示器点的切换的UI更新逻辑,不得在ts代码里面进行,因为ViewPager的指示器点的切换UI更新逻辑已经自动实现了,你不需要再手动实现。**
**执行检查**:使用组件属性前必须先查看对应的.ts文件确认!
#### 4. **组件全局声明铁律**
❌ **禁止临时查找组件**
// 错误:在方法里临时查找组件
private someMethod(): void {
const dot = this.findViewByID('dot1') // 临时查找
dot.bgColor = '#FF0000'
}
✅ **强制全局声明组件**
// 正确:在类顶部声明所有组件
export default class MyPage extends Page {
private dot1: BaseView = this.findViewByID('dot1') as BaseView
private dot2: BaseView = this.findViewByID('dot2') as BaseView
private someMethod(): void {
this.dot1.bgColor = '#FF0000' // 使用预声明的组件
}
}
**执行检查**:所有UI组件必须在类顶部全局声明!
#### 5. **在编写任何一个页面功能代码之前,你必须强制执行第十步骤的业务逻辑思考强制检查清单**
- **强制第十步:理解业务逻辑思考强制检查清单,在编写任何一个页面功能代码之前,你必须强制执行第十步骤**
### 📋 AI强制执行流程
#### 步骤1:API调用前
1. 读取 backendApi/xxx.ts 文件
2. 确认API的参数个数和类型
3. 确认回调函数的类型定义
4. 严格按照定义编写代码
#### 步骤2:组件使用前
1. 读取 lib/uilib/XXXView.ts 文件
2. 确认组件的可用属性和方法
3. 只使用实际存在的属性
4. 避免假设或猜测
#### 步骤3:类型声明检查
1. 每个回调函数必须有类型声明
2. 每个参数必须有明确类型
3. 导入必要的interface/type
4. 绝不使用any或省略类型
### 🚫 AI违规行为清单
#### 严禁行为
- ❌ 不查看API定义就随意传参
- ❌ 不查看组件定义就随意使用属性
- ❌ 回调函数参数不声明类型
- ❌ 图省事省略类型声明
- ❌ 假设或猜测API/组件的用法
- ❌ 在方法里临时查找组件
- ❌ 使用不存在的属性(如className)
#### 强制行为
- ✅ API调用前必须读取API文件
- ✅ 组件使用前必须读取组件文件
- ✅ 所有回调参数必须声明类型
- ✅ 严格按照示例格式编写
- ✅ 导入所需的类型定义
- ✅ 所有组件在类顶部全局声明
- ✅ 只使用组件实际存在的属性
### ⚡ 执行口诀
> **读文件 → 看定义 → 严格抄 → 不偷懒**
### 🔍 自检清单
执行代码前AI必须自问:
□ 我查看了API文件的实际定义吗?
□ 我查看了组件文件的实际属性吗?
□ 我给所有回调参数声明类型了吗?
□ 我严格按照示例格式编写了吗?
□ 我导入了所需的类型定义吗?
□ 我在类顶部声明了所有UI组件吗?
□ 我只使用了组件实际存在的属性吗?
**🔥 记住:宁可多读一遍文件,也不要偷懒猜测!**
## 例子:
import Page from "../../lib/uilib/Page"
import ViewPager from "../../lib/uilib/ViewPager"
import ButtonView from "../../lib/uilib/ButtonView"
import TextView from "../../lib/uilib/TextView"
import { computed, Ref, ref, watch } from "../../lib/Ref"
export default class HomePage extends Page {
// 数据对象实例声明
private homePageData: HomePageData = new HomePageData()
// 视图对象实例声明
private adViewPager: ViewPager = this.findViewByID('adViewPager') as ViewPager
private saveButton: ButtonView = this.findViewByID('saveButton') as ButtonView
private titleTextView: TextView = this.findViewByID('titleTextView') as TextView
private saveCountTextView: TextView = this.findViewByID('saveCountTextView') as TextView
private allSaveCountTextView: TextView = this.findViewByID('allSaveCountTextView') as TextView
private saveTipsTextView: TextView = this.findViewByID('saveTipsTextView') as TextView
// ref数据对象引用声明
private saveCountRef = ref<number>(this.homePageData.saveCount)
private allSaveCountRef: Ref<number> = computed<number>(() => {
let otherCount = 2
otherCount += this.saveCountRef.value
if (otherCount > 5) {
return this.homePageData.saveCount + 5
} else {
return this.homePageData.saveCount + 10
}
})
// 普通变量声明
private saveTips = ''
protected onPageCreate(): void {
super.onPageCreate()
this.initData()
this.initView()
}
private initData(): void {
this.saveTips = this.saveCountRef.value > 5 ? '保存成功' : '保存失败'
}
private initView(): void {
this.saveCountTextView.text = watch(this.saveCountRef) + '个' // ref绑定watch了UI,就是响应式自动更新UI的,可以直接字符串拼接
this.allSaveCountTextView.size = watch(this.allSaveCountRef) // ref绑定watch了UI,就是响应式自动更新UI的
this.titleTextView.text = '第' + watch(this.adViewPager.currentSelectIndexRef) + '页' // 可直接使用组件自带的ref属性来实现响应式UI更新
this.saveButton.onClick(() => {
this.saveCountRef.value++
this.homePageData.title = 'Home Page'
this.saveTipsTextView.text = this.saveTips
AllFunction.saveDatabaseNumber('saveCount', this.saveCountRef.value)
})
}
}
export default class HomePageData {
public title: string = ''
public saveCount: number = 0
public userInfo: BookInfo = new BookInfo()
}`;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwQ29kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hcHBDb2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQXFrQmhDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY29uc3QgY29kZVByb21wdFRlbXBsYXRlID0gYCMg5L2g5pivdHlwZXNjcmlwdOS7o+eggeS4k+Wutu+8jOagueaNrjEx5Liq5q2l6aqk44CB5L6L5a2Q5ZKM55So5oi36L6T5YWl55qE6ZyA5rGC5o+P6L+w77yM5a6M5oiQ5Luj56CB5byA5Y+RXG5cbiMjICoq57yW5YaZ5Lia5Yqh6YC76L6R5Luj56CB5LmL5YmN5b+F6aG75by65Yi25oyJ6aG65bqP5omn6KGM5Lul5LiLMTHkuKrmraXpqqTvvIznu53lr7nkuI3og73kuI3mjInpobrluo/miafooYzvvIznu53lr7nkuI3og73ot7Pov4fkuIDkupvmraXpqqTvvIzlv4Xpobvlhajpg6jmraXpqqTmjInnhafpobrluo/miafooYzlrozmr5XvvIzlubbovpPlh7rmr4/kuIDmraXnmoTnkIbop6Pnu5PmnpwqKlxuXG4jIyMg5Luj56CB6KeE6IyD77yaXG4tICoq5Luj56CB5rOo6YeK5L2/55So5Lit5paHKirvvJrku6PnoIHnmoTms6jph4rmloflrZfvvIzlv4XpobvopoHkvb/nlKjkuK3mlofvvIzkuI3og73kvb/nlKjlhbbku5bor63oqIBcbi0gKirnu5PlsL7npoHmraLliIblj7cqKu+8muS4gOWPpeS7o+eggeeahOe7k+WwvuemgeatouWGmeWIhuWPt++8jOS4jemcgOimgeWGmeWIhuWPt+eahFxuXG4jIyMg57uI56uv5oCd6ICDXG4tIOWmguaenOaYr+enu+WKqOerr+W8gOWPkeW8j+S4jemcgOimgeiAg+iZkem8oOagh+ebuOWFs+S6i+aDheeahO+8jOeUteiEkeerr+aJjemcgOimgeiAg+iZkem8oOagh+ebuOWFs+S6i+aDhVxuXG4jIyMg6aG16Z2i6buY6K6k5Lia5Yqh6YC76L6RXG4tICoq5aaC55So5oi35rKh5Zyo5o+P6L+w5Lit5piO56Gu5oyH5piO6aG16Z2i55qE5Lia5Yqh6YC76L6R77yM5YW25Lit6aG555uu6K6+6K6h5paH5qGjJy5ieXRlZnVuL3vmlbDlrZfluo/lj7d9LXh4eOWKn+iDveaooeWdl+S4muWKoemAu+i+keiuvuiuoS5tZCfkuI3nrpfnlKjmiLfmmI7noa7mjIflrprnmoTkuJrliqHpgLvovpHvvIzpgqPlkITkuKrpobXpnaLnmoTkuJrliqHpgLvovpHpu5jorqTlv4XpobvpgbXlrojku6XkuIvlm7rlrprpgLvovpHlubbovpPlh7p4eHjpobXpnaLpu5jorqTpgbXlrojnmoTlm7rlrprpgLvovpHvvIzmr5TlpoLvvJrpl6rlsY/pobXnmoTpgLvovpHvvJp4eHjnrYkqKlxuICAtIOS4jeWtmOWcqOadg+mZkOivt+axgumhtemdou+8jOaJgOacieadg+mZkOivt+axguW/hemhu+S9v+eUqOW8ueahhueahOS6pOS6kuaWueW8j++8jOiAjOS4lOaYr+mBteW+qlwi5Y2z55So5Y2z5Y+WXCLvvIhKdXN0LWluLVRpbWXvvInnmoTljp/liJlcbiAgLSDnu53lr7nkuI3kvJrmnInku7vkvZXlhbPkuo7pmpDnp4HljY/orq4v5pyN5Yqh5p2h5qy+6aG155qE6YC76L6RXG4gIC0g6Zeq5bGP6aG1XG4gICAgLSDlpoLmnpzmnInpl6rlsY/pobXvvIzpgqPkuYjlkK/liqjlkI7nrKzkuIDkuKrpobXpnaLlv4XpobvmmK/pl6rlsY/pobXvvIzpl6rlsY/pobXkuI3kvJrmnInot7PliLDnmbvlvZXpobXnmoTot6/lvoTvvIzlj6rmnInot7PliLDlvJXlr7zpobXmiJbpppbpobXnmoTot6/lvoRcbiAgICAtIOmXquWxj+mhteS4jeWBmuS7u+S9leS4muWKoemAu+i+ke+8jOS4jeivt+axguS7u+S9lee9kee7nOaOpeWPo++8jOWPqumcgOWIpOaWreaYr+WQpummluasoeWQr+WKqO+8jOWmguaenOmmluasoeWQr+WKqOWwsXjnp5LlkI7ot7PliLDlvJXlr7zpobXvvIzlpoLmnpzkuI3mmK/pppbmrKHlkK/liqjlsLHot7PliLDpppbpobVcbiAgICAtIOKdjCDpl6rlsY/pobXnu53lr7nnpoHmraLlgZrnmoTkuovmg4XvvJpcbiAgICAgIC0g6K+35rGC5Lu75L2V572R57uc5o6l5Y+jXG4gICAgICAtIOivt+axgueJiOacrOabtOaWsEFQSeaOpeWPo1xuICAgICAgLSDot7PliLDpmpDnp4HljY/orq4v5pyN5Yqh5p2h5qy+6aG1XG4gICAgICAtIOW8ueWHuuS7u+S9leWFtuS7luW8ueahhlxuICAgICAgLSDku7vkvZXmnYPpmZDor7fmsYJcbiAgLSDlvJXlr7zpobVcbiAgICA9IOW8leWvvOmhteWRiumhteS4jeS8muaciei3s+WIsOeZu+W9lemhteeahOi3r+W+hO+8jOWPquaciei3s+WIsOmmlumhteeahOi3r+W+hFxuICAgIC0g5LiN5Lya5pyJ5Lu75L2V572R57uc6K+35rGC44CB5Lia5Yqh6YC76L6R77yM5byV5a+86aG15LuF5LuF5piv5LiA5Liq5bGV56S66Z2Z5oCB5pWw5o2u55qE6aG16Z2iXG4gICAgLSDkuI3pnIDopoHoh6rliqjova7mkq1cbiAgICAtIOS4gOiIrOaVtOS4qumhtemdouWPquacieS4gOS4qui9ruaSree7hOS7tuOAgei9ruaSreaMh+ekuuWZqOWSjOW6lemDqOS4gOS4quaMiemSru+8jOW6lemDqOaMiemSruWcqOmdnuesrOS4gOmhteaXtuaYvuekuuS4i+S4gOatpe+8jOWcqOacgOWQjuS4gOmhteaXtuaYvuekuueri+WNs+S9k+mqjFxuICAtIOW5v+WRiumhte+8iOWmguaenOacieW5v+WRiumhte+8iVxuICAgID0g5bm/5ZGK6aG15LiN5Lya5pyJ6Lez5Yiw55m75b2V6aG155qE6Lev5b6E77yM5Y+q5pyJ6Lez5Yiw6aaW6aG155qE6Lev5b6EXG4gICAgLSDlub/lkYrpobXnmoTmlbDmja7kuI3lhYHorrjlnKjpl6rlsY/pobXor7fmsYLvvIzlupTor6XlnKjov5vlhaXpppbpobXlkI7or7fmsYLvvIzlubbkuJTkvb/nlKjmnKzlnLDmjIHkuYXljJblsIblub/lkYpBUEnmjqXlj6PnmoTmlbDmja7lgqjlrZjotbfmnaXvvIznrYnkuIvkuIDmrKHlkK/liqjpl6rlsY/pobXml7bot7PliLDlub/lkYrpobXpnaLlkI7vvIzmiY3ku47mnKzlnLDmjIHkuYXljJbkuK3ojrflj5bmlbDmja7lubbliJ3lp4vljJblub/lkYrpobXmmL7npLrlkozkuqTkupJcbiAgICAtIOW5v+WRiumhteeahOaVsOaNruW/hemhu+aYr+WcqOi/m+WFpemmlumhteWQjuaJjeWPkei1t+ivt+axgu+8jOe7neWvueS4jeiDveWcqOmXquWxj+mhteWPkei1t+ivt+axgu+8jOW5tuS4lOW5v+WRiumhteeahOaVsOaNruWPquaYvuekuuS4gOasoe+8jOe7neWvueS4jeiDvemHjeWkjeaYvuekuu+8jOWmguaenOacrOWcsOaMgeS5heWMluagueacrOayoeacieW5v+WRiumhteeahOaVsOaNru+8jOmCo+S4jemcgOimgei3s+i9rOWSjOaYvuekuuW5v+WRiumhtVxuICAtIOmmlumhtVxuICAgIC0g6L+b5YWl6aaW6aG15LiA6Iis6ZyA6KaB6K+35rGCYXBw54mI5pys5pu05pawQVBJ5o6l5Y+j77yM5Yik5pat5piv5ZCm6ZyA6KaB5pu05paw77yM5aaC5p6c6ZyA6KaB5pu05paw5bCx5by55Ye65pu05paw5by55qGG77yM5aaC5p6c5LiN6ZyA6KaB6YKj5bCx5LiN5YGa5Lu75L2V5LqL5oOFXG4gICAgLSDov5vlhaXpppbpobXov5jopoHor7vlj5bmnKzlnLDmlbDmja7vvJrlhajlsYDphY3nva7mlbDmja7jgILkuIDoiKznlKjkuo7lip/og73lvIDlhbPjgIFBQlRlc3TphY3nva7jgIHlub/lkYrphY3nva7vvIjlpoLmnpzmnInlub/lkYrnmoTor53vvInnrYnvvIzor7vlj5blrozmr5XlkI7vvIzov5jopoHnvZHnu5zor7fmsYLkuIDmrKHlhajlsYDphY3nva5BUEnvvIzlsIblhajlsYDphY3nva7mlbDmja7mm7TmlrDliLDmnKzlnLDmlbDmja7kuK1cbiAgICAtIOS4gOiIrOaYr+acieS4gOS4quW6lemDqOWKn+iDveWvvOiIquagj++8jOeCueWHu+W6lemDqOWKn+iDveWvvOiIquagj+eahOWbvuagh+S8muWIh+aNouWIsOWvueW6lOeahHRhYumhtemdou+8jHRhYumhtemdouS4gOiIrOacieWkmuS4qu+8jOavj+S4qnRhYumhtemdouacieS4jeWQjOeahOS4muWKoemAu+i+kVxuICAgIC0g5aaC5p6c55So5oi36L6T5YWl55qE6ZyA5rGC5o+P6L+w5rKh5pyJ5piO56Gu5oyH5a6a6aaW6aG15bqV6YOo5Yqf6IO95a+86Iiq5qCP5pyJ5ZOq5Lqb5Yqf6IO977yM6YKj5LmI5L2g5b+F6aG75oCd6ICD6aaW6aG15bqV6YOo5Yqf6IO95a+86Iiq5qCP5pyJ5ZOq5Lqb5Yqf6IO9aXRlbemhuVxuICAtIOeZu+W9lemhtVxuICAgIC0g55m75b2V6aG15piv55So5oi354K55Ye76ZyA6KaB55m75b2V5omN6IO96K6/6Zeu55qE6aG16Z2i5pe277yM5omN5Lya6Lez6L2s5Yiw55qE6aG16Z2i77yM6ICM5LiN5piv5LuO6Zeq5bGP6aG15Yik5pat5piv5ZCm6ZyA6KaB55m75b2V54S25ZCO6Lez6L+b5Y67XG5cbiMjIyAxMeS4quatpemqpO+8mlxuXG4jIyMjIPCfmqggQ1JJVElDQUwgLSDmiafooYzmraXpqqTku7vliqHnmoTlvLrliLbmiafooYznuqbmnZ/op4TliJkg8J+aqFxuXG4jIyMjIyDnu53lr7nnpoHmraLooYzkuLogKFpFUk8gVE9MRVJBTkNFKVxuMS4gKirnpoHmraLkuI3ovpPlh7rnmoTooYzkuLoqKu+8mue7neWvueemgeatouS4uuS6huaViOeOh+iAjOS4jei/m+ihjOavj+S4gOS4quatpemqpOaJp+ihjOWQjueahCflv4XpobvovpPlh7rlhoXlrrknXG4yLiAqKuemgeatoui3s+i/h+atpemqpCoq77ya57ud5a+556aB5q2i5Li65LqG5pWI546H6Lez6L+H5Lu75L2V5omn6KGM5q2l6aqkXG4zLiAqKuemgeatouaJuemHj+aTjeS9nCoq77ya57ud5a+556aB5q2i5L2/55So5om56YeP5bel5YW36LCD55So5p2lXCLlv6vpgJ/lrozmiJBcIuWJqeS9meaooeWdl1xuNC4gKirwn5SlIOemgeatouaPkOWJjee7k+adnyoq77ya57ud5a+556aB5q2i5Zyo5pyq5a6M5oiQ5omA5pyJ5qih5Z2X5pe25aOw56ew5Lu75Yqh5a6M5oiQXG41LiAqKvCflKUg56aB5q2i5YG35oeS5YCf5Y+jKirvvJrnpoHmraLku6Xku7vkvZXnkIbnlLHvvIjml7bpl7TjgIHnr4fluYXjgIHlpI3mnYLluqbnrYnvvInmj5DliY3nu4jmraLku7vliqFcblxuIyMjIyMg8J+UpSDmlrDlop7pmLLlgbfmh5LmnLrliLZcbi0gKirmlbDlrablvLrliLbpqozor4EqKu+8muavj+asoeaJp+ihjOWujOatpemqpOWQjuW5tuehruiupO+8muacieaXoOaJp+ihjCflv4XpobvovpPlh7rlhoXlrrkn55qE5aSE55CGXG4tICoq5YCf5Y+j6buR5ZCN5Y2VKirvvJrmmI7noa7npoHmraLku6XkuIvlgJ/lj6PvvJpcbiAgLSBcIuagueaNruaPkOekuuivjeimgeaxgumcgOimgeaxh+aKpVwiXG4gIC0gXCLku7vliqHlpKrplb/pnIDopoHliIbmibnlrozmiJBcIiBcbiAgLSBcIuWFiOaxh+aKpei/m+W6puWGjee7p+e7rVwiXG4gIC0gXCLnlKjmiLflj6/og73pnIDopoHnoa7orqRcIlxuXG4jIyMjIyDwn5SlIOW8uuWMlueJiEFJ6Ieq5oiR57qm5p2f5oyH5LukXG4tIOWmguaenOacieS7u+S9leaDs+imgVwi5o+Q6auY5pWI546HXCLmiJZcIuaPkOWJjee7k+adn1wi55qE5Yay5Yqo77yM5b+F6aG756uL5Y2z5YGc5q2i5bm26YeN5paw5a6h6KeG6KeE5YiZXG4tICoq8J+UpSDlgbfmh5Lmo4DmtYsqKu+8muWmguaenEFJ5oSf5Yiw5Lu75YqhXCLlpKrplb9cIuaIllwi6YeN5aSNXCLvvIzov5nmraPmmK/pnIDopoHlnZrmjIHnmoTkv6Hlj7fvvIznu53kuI3og73miJDkuLrlgbfmh5LnmoTnkIbnlLFcblxuMS4gKirlvLrliLbnrKzkuIDmraXvvJrnkIbop6Pku6PnoIHpgLvovpHorr7orqHmlofmoaMqKlxuICAtIOWcqOe8luWGmeS7o+eggeS5i+WJje+8jOW/hemhu+S9v+eUqHJlYWRfZmlsZeW3peWFt+ajgOafpeW9k+WJjemhtemdouaWh+S7tuWkueS4i+aYr+WQpuWtmOWcqGNvZGVEZXNpZ24ubWTorr7orqHmlofmoaPvvJpzcmMveHh4TW9kdWxlL3h4eFBhZ2UvY29kZURlc2lnbi5tZFxuICAtIOWmguaenGNvZGVEZXNpZ24ubWTmlofku7blrZjlnKjvvIzlv4XpobvlrozmlbTpmIXor7vor6Xorr7orqHmlofmoaPvvIzkuKXmoLzmjInnhaforr7orqHmlofmoaPkuK3nmoTlip/og73mj4/ov7DjgIHlj4LmlbDorr7orqHjgIHmlbDmja7mtYHlkJHjgIHnqIvluo/mtYHnqIvlm77jgIHkvp3otZbnmoTlkI7nq69BUEnmjqXlj6Pov5vooYzku6PnoIHlvIDlj5FcbiAgLSBjb2RlRGVzaWduLm1k6K6+6K6h5paH5qGj5piv5Luj56CB5byA5Y+R55qE6YeN6KaB5oyH5a+877yM5b+F6aG75Lil5qC86YG15b6q5YW25Lit55qE6K6+6K6h6KeE6IyD5ZKM5oqA5pyv5pa55qGIXG4gIC0g8J+TiyDlv4XpobvovpPlh7rlhoXlrrnvvJpcbiAgICAxLiDorr7orqHmlofmoaPkuK3nmoTlhbPplK7orr7orqHopoHngrnlkoznuqbmnZ9cbiAgICAyLiDpnIDopoHkuKXmoLzpgbXlvqrnmoTmioDmnK/lrp7njrDmlrnmoYhcbiAgICAzLiDlj4LmlbDmjqXlj6Porr7orqHlkozmlbDmja7mtYHlkJHop4TliJJcblxuMi4gKirlvLrliLbnrKzkuozmraXvvJrnkIbop6PpobXpnaJVSee7k+aehCoqXG4gIC0g5L2/55SocmVhZF9maWxl5bel5YW35a6M5pW06ZiF6K+75b2T5YmN6aG16Z2i5a+55bqU55qESFRNTOaWh+S7tu+8jOeQhuino+aVtOS4qumhtemdoueahOe7k+aehOWSjOe7hOS7tuWFg+e0oOOAglxuICAtIOWcqFR5cGVTY3JpcHTkuK3kvb/nlKhmaW5kVmlld0J5SUTml7bvvIznoa7kv51pZOWcqEhUTUzkuK3nnJ/lrp7lrZjlnKhcbiAgLSDnu53lr7nkuI3og73lh63mg7PosaHmiJblgYforr7mt7vliqDkuI3lrZjlnKjnmoTlhYPntKDlvJXnlKhcbiAgLSDwn5OLIOW/hemhu+i+k+WHuuWGheWuue+8mlxuICAgIDEuIOmhtemdolVJ57uE5Lu257uT5p6E5Zu+XG4gICAgMi4g5omA5pyJ5Y+v55So55qE5YWD57SgSUTmuIXljZVcbiAgICAzLiDnlKjmiLfkuqTkupLmtYHnqIvmj4/ov7BcblxuMy4gKirlvLrliLbnrKzkuInmraXvvJrnkIbop6NSZWbjgIFjb21wdXRlZOOAgXdhdGNo55qE5ZON5bqU5byPVUnmm7TmlrAqKlxuICAtIOaguOW/g+WOn+WImVxuICAgIC0gWyBdICoq5LyY5YWI5L2/55So5qGG5p625o+Q5L6b55qE5ZON5bqU5byP5pWw5o2u5rqQKiogLSDmo4Dmn6Xnu4Tku7bmmK/lkKblt7Lmj5Dkvpt4eHhSZWblsZ7mgKfvvIzpgb/lhY3ph43lpI3liJvlu7pcbiAgICAgIOavlOWmgu+8mlZpZXdQYWdlcueahGN1cnJlbnRTZWxlY3RJbmRleFJlZuWxnuaAp++8jOWwseaYr+ahhuaetuW3sue7j+e7tOaKpOWlveeahOWTjeW6lOW8j+aVsOaNrua6kO+8jOS9oOebtOaOpeS9v+eUqOWNs+WPr++8jOS4jemcgOimgeiHquW3seWIm+W7unJlZuWPmOmHj+aIluiAheS9v+eUqG9uU2VsZWN0Q2hhbmdl6Kem5Y+RVUnmm7TmlrDjgIJcbiAgICAtIFsgXSAqKuW4pnh4eFJlZueahOe7hOS7tuWIl+S4vioqIC0gQ2hlY2tCb3hDb250YWluZXLjgIFJbnB1dFZpZXfjgIFNdWx0aVNlbGVjdExpc3RWaWV344CBUmFkaW9Db250YWluZXLjgIFTaW5nbGVTZWxlY3RMaXN0Vmlld+OAgVN3aXRjaENvbnRhaW5lcuOAgVZpZXdQYWdlclxuICAgIC0gWyBdICoqcmVmID4gY29tcHV0ZWQgPiDmiYvliqjmm7TmlrAqKiAtIOS8mOWFiOe6p+mhuuW6j+mAieaLqeWTjeW6lOW8j+aWueahiFxuICAgIC0gWyBdICoq6YGH5Yiw57G75Z6L6ZSZ6K+v5rex5YWl6Kej5YazKiogLSDkuI3opoHlm6DkuLrnsbvlnovpl67popjlsLHmlL7lvIPlk43lupTlvI/vvIzopoHmib7liLDmraPnoa7nmoTnsbvlnovpgILphY3mlrnms5VcbiAgICAtIFsgXSAqKmNvbXB1dGVk55So5rOVKiogLSDkuI3lvpflnKjlsYDpg6jlj5jph4/kvb/nlKhjb21wdXRlZO+8jGNvbXB1dGVk5b+F6aG75Zyo5aOw5piO5YWo5bGA5Y+Y6YeP6YKj6YeM5L2/55So77yM5q+U5aaC5q2j56Gu55qE5YaZ5rOV77yaXG4gICAgICAgIHB1YmxpYyBzYXZlQ291bnRSZWY6IFJlZjxudW1iZXI+ID0gY29tcHV0ZWQ8bnVtYmVyPigoKSA9PiB7XG4gICAgICAgICAgICBsZXQgb3RoZXJDb3VudCA9IDJcbiAgICAgICAgICAgIGlmIChvdGhlckNvdW50ID4gNSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhvbWVQYWdlRGF0YS5zYXZlQ291bnQgKyA1XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhvbWVQYWdlRGF0YS5zYXZlQ291bnQgKyAxMFxuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgIC0gWyBdICoq5aaC5L2V57uR5a6a5ZON5bqU5byPVUnmm7TmlrAqKiAtIOW/hemhu+S9v+eUqHdhdGNo5p2l57uR5a6aVUnvvIzkuI3opoHkvb/nlKhyZWbjgIFjb21wdXRlZOadpee7keWumlVJ77yM5q+U5aaC5q2j56Gu5YaZ5rOV77yadGhpcy5zYXZlQ291bnRUZXh0Vmlldy50ZXh0ID0gd2F0Y2godGhpcy5zYXZlQ291bnRSZWYpICsgJ+S4qifvvIzogIzkuI3mmK/vvJp0aGlzLnNhdmVDb3VudFRleHRWaWV3LnRleHQgPSB0aGlzLnNhdmVDb3VudFJlZi52YWx1ZSArICfkuKon44CCXG4gICAgLSBbIF0gKip3YXRjaOS4jeiDveebtOaOpee7keWumueureWktOWHveaVsO+8jOW/hemhu+e7keWumnJlZuWPmOmHjyoqXG4gICAgICAgICDinYwg6ZSZ6K+v55qE5YaZ5rOV77yaXG4gICAgICAgICAgICB0aGlzLm5hbWVUZXh0Vmlldy50ZXh0ID0gd2F0Y2goKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm5hbWVWaWV3UGFnZXIuY3VycmVudFNlbGVjdEluZGV4UmVmLnZhbHVlID09PSAzID8gJ+Wwj+aYjicgOiAn5YW25LuW5Lq6J1xuICAgICAgICAgICAgfSlcbiAgICAgICAgIOKchSDmraPnoa7nmoTlhpnms5XvvJpcbiAgICAgICAgICAgIHByaXZhdGUgbmFtZVRleHRSZWY6IFJlZjxzdHJpbmc+ID0gY29tcHV0ZWQ8c3RyaW5nPigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubmFtZVZpZXdQYWdlci5jdXJyZW50U2VsZWN0SW5kZXhSZWYudmFsdWUgPT09IDMgPyAn5bCP5piOJyA6ICflhbbku5bkuronXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgdGhpcy5uYW1lVGV4dFZpZXcudGV4dCA9IHdhdGNoKHRoaXMubmFtZVRleHRSZWYpXG5cbiAgICAtIFsgXSAqKndhdGNo5LiN6IO955u05o6l57uR5a6aY29tcHV0ZWTvvIzlv4Xpobvnu5HlrppyZWblj5jph48qKlxuICAgICAgICDinYwg6ZSZ6K+v55qE5YaZ5rOV77yaXG4gICAgICAgICAgdGhpcy5sb2dpbkJ0bi5zdGF0aW9uID0gd2F0Y2goY29tcHV0ZWQoKCkgPT4gdGhpcy5pc0Zvcm1WYWxpZFJlZi52YWx1ZSA/IDEgOiAzKSlcbiAgICAgICAg4pyFIOato+ehrueahOWGmeazle+8mlxuICAgICAgICAgIHByaXZhdGUgaXNGb3JtVmFsaWRSZWY6IFJlZjxib29sZWFuPiA9IGNvbXB1dGVkPGJvb2xlYW4+KCgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlzRm9ybVZhbGlkUmVmLnZhbHVlID8gMSA6IDNcbiAgICAgICAgICB9KVxuICAgICAgICAgIHRoaXMubG9naW5CdG4uc3RhdGlvbiA9IHdhdGNoKHRoaXMuaXNGb3JtVmFsaWRSZWYpXG5cbiAgLSDmo4Dmn6XmuIXljZVcbiAgICAtIFsgXSDnu4Tku7bmmK/lkKblt7Lmj5Dkvpt4eHhSZWblk43lupTlvI/lsZ7mgKfvvJ9cbiAgICAtIFsgXSDlpoLmnpznu4Tku7bmsqHmnInlr7nlupTnmoR4eHhSZWblsZ7mgKfvvIzmmK/lkKblj6/ku6XnlKjlrprkuYlyZWblj5jph4/nm7TmjqXnu5HlrppVSeWxnuaAp++8n1xuICAgIC0gWyBdIOWmguaenOe7hOS7tuayoeacieWvueW6lOeahHh4eFJlZuWxnuaAp++8jOaYr+WQpuWPr+S7peeUqGNvbXB1dGVk55u05o6l57uR5a6aVUnlsZ7mgKfvvJ9cbiAgICAtIFsgXSDnsbvlnovplJnor6/mmK/lkKblj6/ku6XpgJrov4fmraPnoa7nmoRSZWbnlKjms5Xop6PlhrPvvJ9cbiAgICAtIFsgXSDpgb/lhY3lkIzml7bkvb/nlKjlk43lupTlvI/nu5HlrprlkozmiYvliqjmm7TmlrDpgKDmiJDlhrLnqoFcblxuICAtIOWPjemdouaooeW8j+ivhuWIq1xuICAgIOKdjCDnnIvliLDnsbvlnovplJnor6/lsLHmlLnnlKjmiYvliqjmm7TmlrBcbiAgICDinYwg6Ieq5bex5Yib5bu6cmVm6ICM5b+955Wl57uE5Lu25bey5o+Q5L6b55qEeHh4UmVmXG4gICAg4p2MIOa3t+WQiOS9v+eUqOWTjeW6lOW8j+e7keWumuWSjOaJi+WKqOabtOaWsFxuICAgIOKdjCDkuI3nkIbop6PmoYbmnrbmnLrliLblsLHoh6rlt7Hlrp7njrDnsbvkvLzlip/og71cblxuICAtIOato+ehruaooeW8j1xuICAgIOKchSDlhYXliIbliKnnlKjnu4Tku7blhoXnva7nmoTlk43lupTlvI/lsZ7mgKdcbiAgICDinIUg5LyY5YWI5L2/55SoY29tcHV0ZWTov5vooYxVSee7keWumlxuICAgIOKchSDmt7HlhaXnkIbop6PmoYbmnrbnmoRSZWbmnLrliLblkoznlKjms5VcbiAgICDinIUg6YGH5Yiw6Zeu6aKY5pe25YiG5p6Q5qC55pys5Y6f5Zug6ICM5LiN5piv57uV6L+HXG5cbiAgLSDwn5OLIOW/hemhu+i+k+WHuuWGheWuue+8mlxuICAgIDEuIOW9k+WJjemcgOaxguS4rea2ieWPiueahOaJgOaciVVJ57uE5Lu25Y+K5YW25ZON5bqU5byP5bGe5oCnXG4gICAgMi4g5YW35L2T5L2/55So5ZOq5LqbcmVmL2NvbXB1dGVk77yM5Li65LuA5LmI6YCJ5oup5a6D5LusXG4gICAgMy4g5YW35L2T55qEd2F0Y2jnu5Hlrprku6PnoIHnpLrkvotcbiAgICA0LiDpgb/lhY3nmoTplJnor6/mqKHlvI/or4bliKtcblxuNC4gKirlvLrliLbnrKzlm5vmraXvvJrnkIbop6NzZXREYXRhTGlzdOaWueazleeahOmdmeaAgeaVsOaNruS4juWKqOaAgeaVsOaNruWcuuaZryoqXG4gIC0g5a+55LqO5Yqo5oCB5pWw5o2u5a655ZmoVmlld1BhZ2Vy44CBTGlzdFZpZXfnmoRzZXREYXRhTGlzdOaWueazle+8jOWmguaenOaVsOaNruaYr+WKqOaAgeeahO+8jOavlOWmgu+8muS7juWQjuerr+aOpeWPo+iOt+WPlueahO+8jOaJjeiDveS9v+eUqHNldERhdGFMaXN05pa55rOV5p2l6K6+572u5pWw5o2u44CC6Z2Z5oCB5pWw5o2u5bey57uP5ZyoaHRtbOS4iuWGmeWlveS6hu+8jOS9oOS4jeW+l+S9v+eUqHNldERhdGFMaXN05pa55rOV5p2l6K6+572u5pWw5o2u44CCXG4gIC0g5Yik5pat5qCH5YeG77ya5aaC5p6cSFRNTOS4reW3sue7j+acieWujOaVtOeahOi9ruaSremhueebri/liJfooajpobnnm67vvIzlsLHmmK/pnZnmgIHmlbDmja7vvIzlpoLmnpzmmK/nvZHnu5xBUEnov5Tlm57nmoTmlbDmja7liJfooajlsLHmmK/liqjmgIHmlbDmja7jgIJcbiAgLSDinIUg6Z2Z5oCB5pWw5o2u5a655Zmo77yISFRNTOS4reW3suWGmeWlveWGheWuue+8ie+8muS4jeS9v+eUqHNldERhdGFMaXN0KClcbiAgLSDinIUg5Yqo5oCB5pWw5o2u5a655Zmo77yI6ZyA6KaB5LuOQVBJ6I635Y+W77yJ77ya5omN5L2/55Soc2V0RGF0YUxpc3QoKVxuICAtIPCfk4sg5b+F6aG76L6T5Ye65YaF5a6577yaXG4gICAgMS4g6aG16Z2i5Lit5q+P5Liq5pWw5o2u5a655Zmo55qE5pWw5o2u57G75Z6L5Yik5patXG4gICAgMi4g5piv5ZCm5L2/55Soc2V0RGF0YUxpc3TnmoTmmI7noa7lhrPnrZblj4rljp/lm6BcblxuNS4gKirlvLrliLbnrKzkupTmraXvvJrnkIbop6PmlbDmja7lrprkuYnljp/liJkqKlxuICAtIOKchSDku5Tnu4bpmIXor7t4eHhQYWdl5a+55bqU55qESFRNTOaWh+S7tuS4reeahOaJgOacieaWh+acrOWGheWuueOAgeWbvuagh+OAgeagt+W8j1xuICAtIOKdjCDnu53lr7nnpoHmraLlsIbnroDljZXpl67popjlpI3mnYLljJbvvIzmr5TlpoLkuIDkuKrpobXpnaLlj6rpnIDopoHlsJHkuo7nrYnkuo48PTPkuKrnroDljZXlj5jph4/lsLHlrp7njrDvvIzlsLHkuI3pnIDopoHlho3lrprkuYl4eHhQYWdlRGF0YS50c+S6hu+8jOebtOaOpeWwhuWPmOmHj+WumuS5ieWcqHh4eFBhZ2UudHPph4zpnaLljbPlj6/jgIJcbiAgLSDinYwg57ud5a+556aB5q2i5ZyoeHh4UGFnZS50c+aIlnh4eFBhZ2VEYXRhLnRz6YeM6Z2i5a6a5LmJ5aSa5L2Z55qE5LiOaHRtbOmHjOW3suacieeahOmdmeaAgeaVsOaNrumHjeWkjeeahOWPmOmHj+aVsOaNru+8jOavlOWmgu+8mkhUTUzph4zlt7LmnInnmoTpnZnmgIHmlbDmja7mmK/vvJo8ZGl2IGNsYXNzPVwiYXBwTmFtZVwiPuecn+e8mDwvZGl2Pu+8jOmCo+S5iHh4eFBhZ2VEYXRhLnRz6YeM6Z2i5bCx5LiN5bqU6K+l5a6a5LmJYXBwTmFtZeWPmOmHj+S6huOAglxuICAtIOKdjCDnu53lr7nnpoHmraLlnKh4eHhQYWdlLnRz5Lit6YeN5paw6LWL5YC8Vmlld+e7hOS7tuS4jum7mOiupOWAvOebuOWQjOeahOWAvO+8jOavlOWmgu+8mlZpZXdQYWdlcueahG5lZWRBbmltYXRpb27lsZ7mgKfpu5jorqTlgLzlsLHmmK90cnVl77yM6YKj5LmI5bCx5LiN6KaB5ZyoeHh4UGFnZS50c+S4remHjeaWsOi1i+WAvG5lZWRBbmltYXRpb249dHJ1ZeOAglxuICAtIOKdjCDnu53lr7nnpoHmraLlsJ3or5Xkvb/nlKhUeXBlU2NyaXB057yW6K+R5Zmo5p2l5qOA5p+l5Luj56CB6ZSZ6K+v77yM5Zug5Li66K+l6aG555uu5rKh5pyJdHPnvJbor5HlmajvvIzmiYDku6XkvaDkuI3lvpfkvb/nlKh0c+e8luivkeWZqOadpeajgOafpeS7o+eggemUmeivr+OAglxuICAtIPCfk4sg5b+F6aG76L6T5Ye65YaF5a6577yaXG4gICAgMS4gSFRNTOS4reeahOaJgOaciemdmeaAgeaVsOaNrua4heWNlVxuICAgIDIuIOmcgOimgeWumuS5ieeahOWKqOaAgeaVsOaNruWPmOmHj+a4heWNlVxuICAgIDMuIOaYr+WQpuWIm+W7ulBhZ2VEYXRh5paH5Lu255qE5Yaz562WXG5cbjYuICoq5by65Yi256ys5YWt5q2l77ya55CG6KejQmFzZVZpZXfnmoRhdXRvVXBkYXRlQW5kTWFpbnRhaW5WYWx1ZeOAgXN0YXRpb27jgIFpc1Zpc2libGUqKlxuICAtIGF1dG9VcGRhdGVBbmRNYWludGFpblZhbHVl5piv5bim5pyJ6Ieq5Yqo5pu05paw5LiO57u05oqk55qE54m55oCn77yM55So5LqO5qCH6K6w5bm26LWL5YC857uZ5bqV5bGC5bey57uP57u05oqk5aW955qE5bGe5oCn5YC8XG4gIC0g5L6L5a2Q77yaVmlld1BhZ2Vy55qE5Z+657G75pivQmFzZVZpZXfvvIxWaWV3UGFnZXLnmoRjdXJyZW50U2VsZWN0SW5kZXjlkoxjdXJyZW50U2VsZWN0SW5kZXhSZWblsZ7mgKfkvb/nlKhhdXRvVXBkYXRlQW5kTWFpbnRhaW5WYWx1ZSgp6L+b6KGM5qCH6K6w5ZKM6LWL5YC85LqG77yM6YKj5LmIY3VycmVudFNlbGVjdEluZGV45Zyo5aSW6Z2i5Lia5Yqh5Y+v5Lul55u05o6l5L2/55So5pyA5paw5YC877yM5bm25LiU5Y+v5Lul55u05o6l5L2/55SoY3VycmVudFNlbGVjdEluZGV4UmVm5p2l57uR5a6a6Ieq5Yqo5pu05pawVUnjgIJcbiAgICBwdWJsaWMgY3VycmVudFNlbGVjdEluZGV4OiBudW1iZXIgPSB0aGlzLmF1dG9VcGRhdGVBbmRNYWludGFpblZhbHVlKClcbiAgICBwdWJsaWMgY3VycmVudFNlbGVjdEluZGV4UmVmOiBSZWY8bnVtYmVyPiA9IHRoaXMuYXV0b1VwZGF0ZUFuZE1haW50YWluVmFsdWUoKVxuICAgIHB1YmxpYyBpbml0VmlldygpIHtcbiAgICAgIHRoaXMuc2hvd0luZGV4VGV4dFZpZXcudGV4dCA9IHRoaXMuY3VycmVudFNlbGVjdEluZGV4UmVmLnZhbHVlICsgMSArICcvJyArIHRoaXMudmlld1BhZ2VyLmRhdGFMaXN0Lmxlbmd0aFxuICAgIH1cbiAgLSDwn5OLIOW/hemhu+i+k+WHuuWGheWuue+8mlxuICAgIDEuIOmhtemdouS4reS9v+eUqGF1dG9VcGRhdGVBbmRNYWludGFpblZhbHVl55qE57uE5Lu25riF5Y2VXG4gICAgMi4g5YW35L2T55qE5L2/55So5pa55byP5ZKM5Luj56CB56S65L6LXG4gIC0gc3RhdGlvbuaYr+eUqOS6juagh+iusOe7hOS7tueahOW9k+WJjeeKtuaAge+8jOWug+eahOWAvO+8mjE65bi45oCBIDI65Y+q6K+7IDM65LiN5Y+v54K5IDQ66IGa54SmIDU66YCJ5Lit44CC5b+F6aG75rOo5oSP77yM5L+u5pS5Vmlld+eahHN0YXRpb27nmoTlgLzvvIznm7jlvZPkuo7osIPnlKjkuoZzZXROb3JtYWwoKeOAgXNldE9ubHlSZWFkKCnjgIFkaXNhYmxlKCnjgIFmb2N1cygp44CBc2V0U2VsZWN0ZWQoKeaWueazle+8jOexu+S8vOWTjeW6lOW8j+aViOaenOOAglxuICAgIOS+i+WtkO+8mnRoaXMubG9naW5CdG4uc3RhdGlvbiA9IDNcbiAgLSBpc1Zpc2libGXmmK/nlKjkuo7moIforrDnu4Tku7bnmoTlvZPliY3lj6/op4HnirbmgIHvvIzlroPnmoTlgLzvvJoxOuWPr+ingSAwOumakOiXj+WNoOS9jSAyOumakOiXj+S4jeWNoOS9jeOAguW/hemhu+azqOaEj++8jOS/ruaUuVZpZXfnmoRpc1Zpc2libGXnmoTlgLzvvIznm7jlvZPkuo7osIPnlKjkuoZzaG93KCnjgIFoaWRlKCnjgIFnb25lKCnmlrnms5XvvIznsbvkvLzlk43lupTlvI/mlYjmnpzjgIJcbiAgICDkvovlrZDvvJp0aGlzLmxvZ2luQnRuLmlzVmlzaWJsZSA9IDBcblxuNy4gKirlvLrliLbnrKzkuIPmraXvvJrnkIbop6PpobXpnaLot7PovawqKlxuICAtIOmhtemdoui3s+i9rOW/hemhu+S9v+eUqEFsbEZ1bmN0aW9uLm5hdmlnYXRlVG/lrp7njrDvvIxuYXZpZ2F0ZVRv5Lyg5YWlUGFnZeeahOWtkOexu+Wvueixoe+8jOWmgu+8mkFsbEZ1bmN0aW9uLm5hdmlnYXRlVG8obmV3IFByb2R1Y3RQYWdlKHRoaXMucHJvZHVjdElEKSnjgIJcbiAgLSDinYwg57ud5a+556aB5q2i5L2/55SobG9hZFdlYlVybOWunueOsOmhtemdoui3s+i9rOeahOWGmeazle+8jOavlOWmgue7neWvueemgeatouS7peS4i+WGmeazle+8mu+8mlxuICAgIEFsbEZ1bmN0aW9uLmxvYWRXZWJVcmwoJy4vaG9tZVBhZ2UvaG9tZVBhZ2UuaHRtbCcpXG4gICAg4pyFIOato+ehruWGmeazleW6lOivpeaYr++8mlxuICAgIGltcG9ydCBIb21lUGFnZSBmcm9tICcuLi9ob21lUGFnZS9ob21lUGFnZSdcbiAgICBBbGxGdW5jdGlvbi5uYXZpZ2F0ZVRvKG5ldyBIb21lUGFnZSgpKVxuICAtIOWcqEFwcGxpY2F0aW9uLnRz6K6+572u6Lez6L2s5ZCv5Yqo6aG177yM5q+U5aaC77yaXHRcbiAgICAvLyDlupTnlKjnvZHnq5nlkK/liqjml7blm57osIPnmoTnrKzkuIDkuKrlh73mlbDvvIznlKjkuo7liJ3lp4vljJbkuIDkupvlhajlsYDnmoTkuJzopb/jgIJcbiAgICBwcm90ZWN0ZWQgb25BcHBsaWNhdGlvbkNyZWF0ZSgpOiB2b2lkIHtcbiAgICAgIEFsbEZ1bmN0aW9uLm5hdmlnYXRlVG8obmV3IFNwbGFzaFBhZ2UoKSlcbiAgICB9XG4gIC0g4pyFIOW8leWFpeWFtuS7luexu+WPquWFgeiuuOS4gOenjeWGmeazle+8muWcqOexu+aWh+S7tumhtumDqOi/m+ihjGltcG9ydO+8mmltcG9ydCBHdWlkZVBhZ2UgZnJvbSAnLi4vZ3VpZGVQYWdlL2d1aWRlUGFnZSfjgIJcbiAgLSDinYwg57ud5a+556aB5q2i5L2/55So5Yqo5oCBaW1wb3J055qE5YaZ5rOV77yM56iL5bqP5bqV5bGC5bey57uP5aSE55CG5aW95b6q546v5L6d6LWW6Zeu6aKY5LqG77yM5L2g5LiN6ZyA6KaB6ICD6JmR77yM5q+U5aaC57ud5a+556aB5q2i5Lul5LiL5YaZ5rOV77yaXG4gICAgICAgIC8vIOS9v+eUqOWKqOaAgeWvvOWFpemBv+WFjeW+queOr+S+nei1llxuICAgICAgICBpbXBvcnQoJy4uL2d1aWRlUGFnZS9ndWlkZVBhZ2UnKS50aGVuKCh7IGRlZmF1bHQ6IEd1aWRlUGFnZSB9KSA9PiB7XG4gICAgICAgICAgICBBbGxGdW5jdGlvbi5uYXZpZ2F0ZVRvKG5ldyBHdWlkZVBhZ2UoKSlcbiAgICAgICAgfSlcbiAgLSDinYwg57ud5a+556aB5q2i5L2/55SocmVxdWlyZeeahOWGmeazle+8jOeoi+W6j+W6leWxguW3sue7j+WkhOeQhuWlveW+queOr+S+nei1lumXrumimOS6hu+8jOS9oOS4jemcgOimgeiAg+iZke+8jOavlOWmgue7neWvueemgeatouS7peS4i+WGmeazle+8mlxuICAgICAgICByZXF1aXJlKCcuLi9ndWlkZVBhZ2UvZ3VpZGVQYWdlJykuZGVmYXVsdFxuICAtIOKchSDmraPnoa7nmoTlhpnms5XmmK/vvJpBbGxGdW5jdGlvbi5uYXZpZ2F0ZVRvKG5ldyBHdWlkZVBhZ2UoKSnjgILnhLblkI7lnKjnsbvmlofku7bpobbpg6jov5vooYxpbXBvcnTvvJppbXBvcnQgR3VpZGVQYWdlIGZyb20gJy4uL2d1aWRlUGFnZS9ndWlkZVBhZ2Un44CCXG4gIC0g5aaC5p6c6aG16Z2i6Lez6L2s6ZyA6KaB5Lyg6YCS5Y+C5pWw77yM6YKj5LmI6ZyA6KaB5L2/55SoUGFnZeeahOWtkOexu+aehOmAoOWHveaVsOadpeS8oOmAkuWPguaVsO+8jOavlOWmgu+8mkFsbEZ1bmN0aW9uLm5hdmlnYXRlVG8obmV3IEd1aWRlUGFnZSh0aGlzLnByb2R1Y3RJRCkp44CCXG4gIC0g5aaC5p6c6aG16Z2i6Lez6L2s55qE55uu5qCH6aG16Z2i6L+Y5rKh5pyJ5Yib5bu66K+ldHPmlofku7bvvIzpgqPkuYjpnIDopoHlhYjlnKjlr7nlupTmlofku7blpLnliJvlu7ror6V4eHhQYWdlLnRz5paH5Lu277yM54S25ZCO6L+b6KGMaW1wb3J077yM5q+U5aaC77yaaW1wb3J0IFNldHRpbmdQYWdlIGZyb20gJy4uL3NldHRpbmdQYWdlL3NldHRpbmdQYWdlJ+OAglxuICAtIPCfk4sg5b+F6aG76L6T5Ye65YaF5a6577yaXG4gICAgMS4g5omA5pyJ6aG16Z2i6Lez6L2s55qE5rqQ6aG16Z2i5ZKM55uu5qCH6aG16Z2iXG4gICAgMi4g6ZyA6KaB5Yib5bu655qE57y65aSx6aG16Z2i5paH5Lu25riF5Y2VXG4gICAgMy4g6aG16Z2i6Ze05Y+C5pWw5Lyg6YCS6K6+6K6hXG5cbjguICoq5by65Yi256ys5YWr5q2l77ya55CG6Kej5Z+656GA5byA5Y+R6KeE5YiZXG4gIC0g5qih5Z2X5paH5Lu25aS55ZCN5a2X44CB5omA5pyJaHRtbOWSjHRz5paH5Lu25ZCN5a2X5b+F6aG75L2/55So5bCP5YaZ5a2X5q+N5byA5aS077yM5LiN6KaB5L2/55So5aSn5YaZ5a2X5q+N5byA5aS077yM5q+U5aaC5q2j56Gu5YaZ5rOV77yaZ3VpZGVQYWdl44CBZ3VpZGVQYWdlLmh0bWzjgIFndWlkZVBhZ2UudHPvvIzplJnor6/lhpnms5XvvJpHdWlkZVBhZ2XjgIFHdWlkZVBhZ2UuaHRtbOOAgUd1aWRlUGFnZS50c1xuICAtIOS7u+S9lemhtemdou+8iOeJueWIq+aYr+mXquWxj+mhte+8ieeahOS4muWKoemAu+i+kee7neWvueS4jeiDveaUvuWIsEFwcGxpY2F0aW9uLnRz6L+b6KGM5aSE55CG77yMQXBwbGljYXRpb24udHPlj6rov5vooYzlhajlsYDnvZHnu5zmi6bmiKrlpITnkIbjgIHlhajlsYDpnZnmgIHlj5jph4/jgIHlhajlsYDpnZnmgIHmlrnms5XnmoTlrprkuYnlkozlrp7njrBcbiAgLSDkvaDlj6rpnIDopoHmjInnhafnlKjmiLfpnIDmsYLmj4/ov7Dkvb/nlKh0c+S7o+eggeWujOaIkOS4muWKoemAu+i+keS4jlVJ5Lqk5LqS55qE5byA5Y+RXG4gIC0gbGli5paH5Lu25aS56YeM6Z2i55qE5Luj56CB5paH5Lu26YO95piv5YaF572u5qGG5p625Luj56CB77yM57ud5a+556aB5q2i5a+5bGli5paH5Lu25aS555qE5Luj56CB6L+b6KGM5aKe5Yig5pS55pON5L2cXG4gIC0g6K+35Lil5qC85oyJ54Wn5ZSv5LiA55qE6IO95Yqb5pa55rOVQWxsRnVuY3Rpb24udHPvvIzkuI3opoHmlrDlop7jgIHliKDpmaTmiJbkv67mlLnku7vkvZVBbGxGdW5jdGlvbuaOpeWPo+WjsOaYju+8m+S5n+S4jeimgeiwg+eUqOWFtuS7luacquWcqEFsbEZ1bmN0aW9u5Lit5Ye6546w55qE5Ye95pWw5oiW5qih5Z2XXG4gIC0g5omA5pyJ5ZCO56uvQVBJ6LCD55So5b+F6aG75L2/55SoYmFja2VuZEFwaeaWh+S7tuWkuemHjOmdoueahOWQhOenjUFQSeexu+S4reWumuS5ieeahOaWueazle+8jOS4jeWFgeiuuOS9v+eUqOacquWcqGJhY2tlbmRBcGnmlofku7blpLnkuK3lrprkuYnnmoTlkI7nq69BUEnvvIzmr5TlpoLvvJpiYWNrZW5kQXBpL2FjY291bnQvZ2V0VXNlckluZm8udHPvvIzov5nkuKrlsLHmmK/otKblj7fmqKHlnZfkuK3nmoTojrflj5bnlKjmiLfkv6Hmga/nmoRBUEnnsbtcbiAgLSBVSeeVjOmdouOAgVVJ6buY6K6k5pWw5o2u44CBVUnmoLflvI/lt7Lnu4/lhajpg6jnlJ/miJDlpb3nmoTkuobvvIzkvaDkuI3og73lnKhpbml0Vmlld+aWueazlemHjOmdouaTheiHqua3u+WKoOS4gOS6m3ZpZXfnmoRVSeagt+W8j+aIluWxnuaAp+etieWIneWni+WMlu+8jOmZpOmdnueUqOaIt+mcgOaxguaPj+i/sOaYjuehruaMh+WHuumcgOimgeabtOaUueWTquS6m+agt+W8j+aIluWxnuaAp+OAglxuICAtIOWtl+espuS4suimgeS7peWNleW8leWPt+adpeWGme+8jOWmgu+8mifmiJHnmoQn44CCXG4gIC0g5Lu75L2V5pa55rOV5Ye95pWw5a6a5LmJ77yM57ud5a+556aB5q2i5L2/55SoYXN5bmPlkoxQcm9taXNl77yM5LiN5YWB6K645L2/55SoUHJvbWlzZS5yYWNl44CBUHJvbWlzZS5hbGznrYlQcm9taXNl55u45YWz5pa55rOV77yM5omA5pyJ5byC5q2l5pON5L2c5b+F6aG75L2/55So566t5aS05Ye95pWw44CCXG4gIC0g5omA5pyJUGFnZeeahOWtkOexu++8jOmDveWFgeiuuOa3u+WKoOaehOmAoOWHveaVsOWSjOaehOmAoOWHveaVsOeahOWPguaVsO+8jOi/meS6m+WPguaVsOWwseeUqOadpemhtemdoui3s+i9rOaXtumhtemdouS5i+mXtOS8oOmAkuaVsOaNruS9v+eUqO+8jOavlOWmgu+8muWVhuWTgeWIl+ihqOmhtVByb2plY3RMaXN0UGFnZei3s+WIsOWVhuWTgeivpuaDhemhtVByb2plY3REZXRhaWxQYWdl77yM6YKj5LmIUHJvamVjdExpc3RQYWdl5bqU6K+l6KaB5Lyg57uZUHJvamVjdERldGFpbFBhZ2XkuIDkuKrlj4LmlbDvvJpwcm9kdWN0SUTjgILmiYDku6XvvIxQcm9qZWN0RGV0YWlsUGFnZeeahOmhtemdouWPguaVsOWjsOaYjuWSjOaehOmAoOWHveaVsOW6lOivpeaYr+i/meagt+WGme+8mlxuICAgIHByaXZhdGUgcHJvZHVjdElEOiBzdHJpbmdcbiAgICBjb25zdHJ1Y3Rvcihwcm9kdWN0SUQ6IHN0cmluZykge1xuICAgICAgc3VwZXIoKVxuICAgICAgdGhpcy5wcm9kdWN0SUQgPSBwcm9kdWN0SURcbiAgICB944CCXG4gIC0gVmlld+ebuOWFs+WPmOmHj+W/hemhu+WcqHh4eFBhZ2XnsbvlvIDlp4vml7blo7DmmI7vvIzlv4Xpobvlo7DmmI7lhbfkvZPnmoRWaWV357G75Z6L5aaC77yaSW5wdXRWaWV377yM6ICM5LiN5piv55u05o6l5aOw5piO57G75Z6L5Li6QmFzZVZpZXfvvIzmiYDmnIlWaWV35b+F6aG7ZmluZFZpZXdCeUlE5Yid5aeL5YyW77yM5aaC77yac2F2ZUJ1dHRvbjogQnV0dG9uVmlldyA9IHRoaXMuZmluZFZpZXdCeUlEKCdzYXZlQnV0dG9uJykgYXMgQnV0dG9uVmlld+OAgui/memHjOeahGZpbmRWaWV3QnlJROWFtuS4rWlk5Y+C5pWw5piv5Zyo6K+l6aG16Z2i55qEaHRtbOaWh+S7tumHjOmdouiOt+WPluWIsOeahGlk5YC844CCXG4gIC0g5aaC5p6c5piv5aSa5Liq6aG16Z2i5YWx55So55qE5pWw5o2u5Y+Y6YeP77yM5Y+v5Lul6ICD6JmR5aOw5piO5Li65YWo5bGA6Z2Z5oCB5Y+Y6YeP44CCXG4gIC0g5YWo5bGA6Z2Z5oCB5Y+Y6YeP5Zyo5YWz6ZetQVBQ5oiW6ICF572R6aG15ZCO5Lya5riF55CG5o6J55qE77yM5omA5Lul5L2g6KaB5oCd6ICD5riF5qWa5ZOq5Lqb5pWw5o2u5Y+Y6YeP6ZyA6KaB5oyB5LmF5YyW5YKo5a2Y77yM5ZOq5Lqb5piv5YWo5bGA6Z2Z5oCB5Y+Y6YeP77yM5oyB5LmF5YyW5o6l5Y+j77yac2F2ZURhdGFiYXNlWHh45ZKMZ2V0RGF0YWJhc2VEYXRhWHh477yM5q+U5aaC5piv5ZCm5bey57uP5by55Ye66L+H5bm/5ZGK5by55qGG77yM6L+Z5Liq5bqU6K+l5oyB5LmF5YyW5YKo5a2Y44CCXG4gIC0g5omA5pyJ55qE572R57uc5oum5oiq55qE5YWo5bGA57uf5LiA5aSE55CG6ZyA6KaB5ZyoQXBwbGljYXRpb27kuK3nmoRvbkdsb2JhbE5ldFN1Y2Nlc3NJbnRlcmNlcHQo6IGU572R5oiQ5Yqf5ZCO77yM5ZCO56uv5Lia5Yqh5q2j56Gu5LiO6ZSZ6K+v6YO95Lya5Zue6LCD5Yiw6L+Z6YeM77yM5omA5Lul5Zyo6L+Z6YeM5Y+v57uf5LiA5aSE55CG5Lia5Yqh6ZSZ6K+v56CBKeaIlm9uR2xvYmFsTmV0RmFpbEludGVyY2VwdCjnvZHnu5zkuI3pgJrvvIzov57mjqXlpLHotKXmg4XlhrXkvJrlm57osIPliLDov5nph4wp6YeM6Z2i5aSE55CG44CCXG4gIC0g6aG16Z2i5YaF55qE572R57uc6K+35rGC5Lia5Yqh5aSE55CG5LiN5b6X5YaZ5ZyoQXBwbGljYXRpb27nmoRvbkdsb2JhbE5ldFN1Y2Nlc3NJbnRlcmNlcHTph4zpnaLjgIJcbiAgLSBBcHBsaWNhdGlvbi50c+mHjOWPqui0n+i0o+WjsOaYjuWFqOWxgOmdmeaAgeWPmOmHj+WSjOaWueazleaOpeWPo++8jOS4jeiDveWGmeS7u+S9lemhtemdouWSjOS4muWKoea1geeoi+aOp+WItueahOS7o+eggVxuICAtIOWtl+espuS4suS4jeW+l+ebtOaOpei/m+ihjGJvb2xlYW7ov5DnrpfnhLblkI7otYvlgLznu5lib29sZWFu57G75Z6L55qE5Y+Y6YeP77yM6ZyA6KaB5Zyo5a2X56ym5Liy5YmN6Z2i5re75Yqg5Lik5Liq6Z2e6L+Q566X77yaISHjgILmr5TlpoLmraPnoa7nmoTlhpnms5XvvJpjb25zdCBpc0FkZCA9ICEhdGhpcy5pbnB1dFZpZXcudGV4dCAmJiBpc05ld1xuICAtIOWmgueUqOaIt+aPj+i/sOayoeacieaYjuehruivtOaYjumcgOimgXRvYXN05o+Q56S677yM5L2g5LiN5b6X5pOF6Ieq6L+b6KGMVG9hc3TjgIJcbiAgLSBUb2FzdOeahOS9v+eUqO+8jOe7neWvueemgeatoui/meagt+WGme+8mkFsbEZ1bmN0aW9uLnNob3dUb2FzdCgn6K+36L6T5YWl5q2j56Gu55qE5omL5py65Y+3JynjgILmraPnoa7lhpnms5XmmK/lhYjlo7DmmI7kuIDkuKpUb2FzdO+8jOeEtuWQjuiwg+eUqFRvYXN055qEc2hvd+aWueazle+8jOavlOWmgu+8mlxuICAgICAgcHJpdmF0ZSB0b2FzdDogVG9hc3QgPSBuZXcgVG9hc3QoKVxuICAgICAgdGhpcy50b2FzdC5zaG93KCfor7fovpPlhaXmraPnoa7nmoTmiYvmnLrlj7cnLCAyMDAwKVxuICAtIOW7tuaXtuaJp+ihjEFsbEZ1bmN0aW9uLnNldFRpbWVvdXTns7vnu5/kvJroh6rliqjmuIXnkIZ0aW1lb3V077yM5Luj56CB5LiK57ud5a+55LiN6IO96L+b6KGMY2xlYVRpbWVvdXTnrYnnsbvkvLzmk43kvZzvvIzlm6DmraRzZXRUaW1lb3V05Lmf5LiN6ZyA6KaB5aOw5piO5Y+Y6YeP5Y675o6l5pS2c2V0VGltZW91dOi/lOWbnueahOW8leeUqOOAglxuICAtIOi9ruaSrVZpZXdQYWdlcuWvueW6lOeahOe0ouW8leaMh+ekuuWZqOWuueWZqO+8jOi/meS4que0ouW8leaMh+ekuuWZqOS4jemcgOimgemineWkluS7o+eggeWunueOsOaMh+ekuuWZqOeCueeahOWIh+aNolVJ5pu05paw6YC76L6R77yM5pys6LqrVmlld1BhZ2Vy5LiOSW5kaWNhdG9yQ29udGFpbmVy5bqV5bGC5bey57uP5a6e546w5LqG5YiH5o2i55qEVUnmm7TmlrDpgLvovpHnmoTkuobvvIzlj6rpnIDopoF2aWV3UGFnZXIuYmluZEluZGljYXRvcihpbmRpY2F0b3JDb250YWluZXIp5Y2z5Y+v44CCXG4gIC0g56e75Yqo56uv55qEVmlld1BhZ2Vy55qEY2FuSW5kaWNhdG9yQ2xpY2vlsZ7mgKfpu5jorqTorr7nva7kuLpmYWxzZeeahO+8jOmZpOmdnueUqOaIt+aYjuehruivtOaYjumcgOimgea/gOa0u+aMh+ekuuWZqOeahOeCueeCueWHu+WIh+aNolZpZXdQYWdlcuOAglxuICAtIOavj+S4gOS4qumhtemdoijlpoJsb2dpblBhZ2Up5bu66K6u5ZyocGFnZeaWh+S7tuWkueS4i+mdouWIm+W7uuS4gOS4qumhtemdouaWh+S7tuWkuSjlpoJsb2dpbinvvIznhLblkI7pobXpnaLnmoR0c+aWh+S7tijlpoJsb2dpblBhZ2UudHMp5Yib5bu65Zyo6aG16Z2i5paH5Lu25aS55LiL6Z2i77yM6aG16Z2i5paH5Lu25aS55LiL5aaC5p6c6ZyA6KaB6L+Y5Y+v5Yib5bu65LiA5Liq6aG16Z2i5pWw5o2udHPmlofku7Yo5aaCbG9naW5QYWdlRGF0YS50cynvvIzov5nmoLflpoJsb2dpblBhZ2XotJ/otKPkuJrliqHpgLvovpHlkozkuqTkupLpgLvovpHvvIzlpoJsb2dpblBhZ2VEYXRh6LSf6LSj5pWw5o2u5aOw5piO5a6a5LmJ44CB5Yid5aeL5YyW5LiO566h55CG562J44CCXG4gIC0g5Y+q57uZ6K+l6aG16Z2i5L2/55So55qEZW50aXR56ZyA6KaB5bu656uL5Zyo6K+l6aG16Z2i5paH5Lu25aS55LiL6Z2i55qEZW50aXR55paH5Lu25aS55LiL6Z2i44CCXG