{\n child.on(\"close\", resolve);\n });\n if (exitCode) throw new SubprocessError(exitCode, error || data);\n\n return data;\n}\n\nmodule.exports = async (cmd, params=[]) => {\n return spawnChild(cmd, params)\n .then(data => data.split(\"\\r\\n\").filter(el => el));\n}","data_name":"AMNodeProcess","data_type":1,"language_name":"Node","language_version":"12.18.3"},{"data":"class AMError extends Error {\n constructor(message) {\n super(message[AMConfig.lang]);\n this.name = this.constructor.name;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nclass SubprocessError extends AMError {\n constructor(code, error) {\n super({\n ru: `Процесс завершился с кодом: ${code}. Ошибка: ${error}`,\n en: `Subprocess finished with code ${code}. Error: ${error}`\n });\n }\n}\n\nclass DeviceNotFoundError extends AMError {\n constructor(serial) {\n super({\n ru: `Объект устройства ${serial} не создан. Используйте действие \"Подключить устройство\"`,\n en: `Device object ${serial} not created. Use \"Connect device\" action`\n });\n }\n}\n\nclass DeviceIsNotRunningError extends AMError {\n constructor(serial) {\n super({\n ru: `Устройство ${serial} не найдено или находится оффлайн`,\n en: `Device ${serial} not found or offline`\n });\n }\n}\n\nclass PathNotFoundError extends AMError {\n constructor(path) {\n super({\n ru: `Указанный путь \"${path}\" не найден`,\n en: `The path \"${path}\" not found`\n });\n }\n}\n\nclass SelectorIndexError extends AMError {\n constructor(index, len) {\n super({\n ru: `Не удалось получить элемент по индексу ${index}, только ${len} элементов найдено`,\n en: `Failed to get element by index ${index}, only ${len} elements found`\n });\n }\n}\n\nclass ScrollableElementNotFoundError extends AMError {\n constructor(xpath) {\n super({\n ru: `Не удалось найти область скроллинга по xpath \"${xpath}\"`,\n en: `Failed to find scrollable area by xpath \"${xpath}\"`\n });\n }\n}\n\nclass ServerConnectionError extends AMError {\n constructor(tries) {\n super({\n ru: `Не удалось подключиться к серверу Appium за ${tries} попыток`,\n en: `Failed to establish a connection with Apiium server for ${tries} attempts`\n });\n }\n}\n\nclass ServerNotFoudError extends AMError {\n constructor(error) {\n super({\n ru: 'Сервер Appium не запущен. Сначала выполните действие \"Запустить сервер\".',\n en: 'Appium server is not running. You should execute \"Run server\" action first.'\n });\n }\n}\n\nclass HTTPClientError extends AMError {\n constructor(url, response) {\n super({\n ru: `Произошла ошибка во время отправки запроса на URL: ${url}. Код: ${response.status}. ${response.statusText}`,\n en: `An error occurred while sending the request to URL: ${url}. Code: ${response.status}. ${response.statusText}`\n });\n }\n}\n\nclass CaptchaFrameNotFoundError extends AMError {\n constructor(xpath) {\n super({\n ru: `Не удалось найти frame Recaptcha по xpath: \"${xpath}\". Попробуйте увеличить время ожидания элемента и убедитесь, что xpath корректный.`,\n en: `Failed to find Recaptcha frame by xpath: \"${xpath}\". Try to increase timeout to waitting for the element and make sure the xpath is correct.`\n });\n }\n}\n\nclass CaptchaImageNotFoundError extends AMError {\n constructor(xpath) {\n super({\n ru: `Не удалось найти изображения на капче по xpath: \"${xpath}\". Убедитесь, что xpath корректный.`,\n en: `Failed to find images on captcha by xpath: \"${xpath}\". Make sure the xpath is correct.`\n });\n }\n}\n\nclass CaptchaDescriptionNotFoundError extends AMError {\n constructor(xpath) {\n super({\n ru: `Не удалось найти описание капчи по xpath: \"${xpath}\". Убедитесь, что xpath корректный.`,\n en: `Failed to find captcha description by xpath: \"${xpath}\". Make sure the xpath is correct.`\n });\n }\n}\n\nclass CaptchaButtonNotFoundError extends AMError {\n constructor(xpath) {\n super({\n ru: `Не удалось найти кнопку отправки результата капчи по xpath: \"${xpath}\". Убедитесь, что xpath корректный.`,\n en: `Failed to find button to send captcha result by xpath: \"${xpath}\". Make sure the xpath is correct.`\n });\n }\n}\n\nclass CaptchaCreateTaskError extends AMError {\n constructor(error, description) {\n super({\n ru: `${error}: ${description}`,\n en: `${error}: ${description}`\n });\n }\n}\n\nclass CaptchaGetTaskResultError extends AMError {\n constructor(error) {\n super({\n ru: `Ошибка во время получения результата решения капчи: ${error}`,\n en: `Error while getting the result of captcha solving: ${error}`\n });\n }\n}\n\nmodule.exports = {\n SubprocessError,\n DeviceNotFoundError,\n DeviceIsNotRunningError,\n PathNotFoundError,\n SelectorIndexError,\n ScrollableElementNotFoundError,\n ServerConnectionError,\n ServerNotFoudError,\n HTTPClientError,\n CaptchaCreateTaskError,\n CaptchaGetTaskResultError,\n CaptchaFrameNotFoundError,\n CaptchaImageNotFoundError,\n CaptchaDescriptionNotFoundError,\n CaptchaButtonNotFoundError\n};","data_name":"AMError","data_type":1,"language_name":"Node","language_version":"12.18.3"},{"data":"// dumpHierarchy\r\n\r\nconst config = require(\"../AMConfig\");\r\n\r\n\r\nconst [lang, serial] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst device = config.getDevice(serial);\r\n[[AM_NODE_RESULT]] = await device.getPageSource();","data_name":"udsxl40qfxa","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// takeScreenshot\r\n\r\nconst config = require(\"../AMConfig\");\r\n\r\n\r\nconst [lang, serial] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst device = config.getDevice(serial);\r\n[[AM_NODE_RESULT]] = await device.takeScreenshot();","data_name":"fkov0izvfk7","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// pushToDevice\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, inputPath, outputPath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.push(inputPath, outputPath);","data_name":"ge5mdmtfpf","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"const fs = require(\"fs\").promises;\n\n\nconst utils = {\n normalizePath: path => path.replace(/\\\\/g, \"/\"),\n isPathExists: async path => !!(await fs.stat(path).catch(e => false)),\n randRange: (min, max) => Math.floor(min + Math.random() * (max + 1 - min)),\n convertBool: val => [true, \"true\"].includes(val) ? true : [false, \"false\"].includes(val) ? false : null,\n convertBoolReverse: val => [true, \"true\"].includes(val) ? false : [false, \"false\"].includes(val) ? true : null\n};\n\nmodule.exports = utils;","data_name":"AMUtils","data_type":1,"language_name":"Node","language_version":"12.18.3"},{"data":"// pullFromDevice\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, inputPath, outputPath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.pull(inputPath, outputPath);","data_name":"111iyuludhd","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// openApp\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.openApp(appName);","data_name":"4avrqxrc4k9","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getCurrentActivity\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\n[[AM_NODE_RESULT]] = await adb.currentActivity();","data_name":"h50svr7glic","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// closeApp\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nconst adb = await adbUtils(serial);\r\nawait adb.closeApp(appName);","data_name":"34jg1t0yn9f","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// clearAppCache\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nconst adb = await adbUtils(serial);\r\nawait adb.clearApp(appName);","data_name":"l8zwcshcoy","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// installApp\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appPath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\n[[AM_NODE_RESULT]] = await adb.install(appPath);","data_name":"n00a9i9lk6","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// uninstallApp\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\n[[AM_NODE_RESULT]] = await adb.uninstall(appName);","data_name":"jif71870vh7","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// runProcess\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst process = require(\"../AMNodeProcess\");\r\nconst { convertBool } = require(\"../AMUtils\");\r\n\r\nconst [lang, command, resultAsList] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nlet result = await process(command);\r\nif (convertBool(resultAsList)) {\r\n [[AM_NODE_RESULT]] = result;\r\n} else {\r\n [[AM_NODE_RESULT]] = typeof result == \"object\" ? result.join(\"\\r\\n\") : result;\r\n}","data_name":"v4dm2lh3p8","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// openUrl\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, url] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.shell(`am start -a android.intent.action.VIEW -d \"${url}\"`);","data_name":"y3wpjdrmkr","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getInstalledApps\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\n[[AM_NODE_RESULT]] = await adb.listPackages();","data_name":"n9vyf1jzjl","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// inputKeyEvent\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, event] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst keyEvents = {\r\n \"home\": \"3\",\r\n \"back\": \"4\",\r\n \"volume up\": \"24\",\r\n \"volume down\": \"25\",\r\n \"power\": \"26\",\r\n \"camera\": \"27\",\r\n \"volume mute\": \"164\",\r\n \"sleep\": \"223\",\r\n \"wake up\": \"224\"\r\n}\r\nconst adb = await adbUtils(serial);\r\nawait adb.keyEvent(keyEvents[event] || event);","data_name":"etn0a8o0wpe","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// swipeByCoordinates\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, sx, sy, ex, ey, steps] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.swipe(sx, sy, ex, ey, steps || 30);","data_name":"y1fftvvion8","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// dragByCoordinates\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, sx, sy, ex, ey] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nconst adb = await adbUtils(serial);\r\nawait adb.drag(sx, sy, ex, ey);","data_name":"a3e2nuv6nhk","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"const parser = require(\"xpath\");\nconst dom = require(\"xmldom\").DOMParser;\nconst config = require(\"./AMConfig\");\nconst utils = require(\"./AMUtils\");\nconst adbUtils = require(\"./AMAdbUtils\");\nconst { SelectorIndexError,\n ScrollableElementNotFoundError } = require(\"./AMError\");\n\n\nclass Selector {\n constructor(serial) {\n /* @param serial [string] : device serial number */\n this._serial = serial;\n return (async () => {\n this._adb = await adbUtils(this._serial);\n return this;\n })();\n }\n\n _getNodes(xpath) {\n /* @param xpath [string] : xpath to check\n Return : Array[string] */\n const doc = new dom().parseFromString(this._xml);\n const nodes = parser.select(xpath, doc);\n return nodes.map(el => el.toString());\n }\n\n _getValue(options, index=0) {\n /* @param options [object] : { xpath, attr, randBounds, position }\n @property options.xpath [string]\n @property options.attr [string] : element attribute to get its value\n @property options.randBounds=false [boolean] :\n actual only for \"bounds\" value of \"attr\" property\n if (true) - return random bounds,\n if (false) - return default bounds\n @property options.position=false :\n Array[\"left\" | \"right\", \"top\" | \"bottom\"],\n element position\n\n @param index=0 [number] : the ordinal number of the found element\n\n Return :\n options {..., attr: \"bounds\", position} ->\n Array[number, number]\n options {..., attr: \"bounds\", randBounds: true} ->\n Array[number, number]\n options {..., attr: \"bounds\", randBounds: false} ->\n Array[number, number, number, number]\n options {..., attr: \"index\"} -> [number]\n other -> [string] */\n const attr = options.attr;\n const randBounds = options.randBounds || false;\n const position = options.position || false;\n \n const nodes = this._getNodes(options.xpath);\n if (nodes.length === 0) return false;\n let node = nodes[index];\n const doc = new dom().parseFromString(node);\n let elem = parser.select(`string(//*/@${attr})`, doc);\n\n let bounds;\n if (elem) {\n switch (true) {\n case attr == \"bounds\" && position:\n bounds = this._convertBounds(elem);\n return this._getPosition(bounds, position);\n case attr == \"bounds\" && !randBounds:\n return this._convertBounds(elem);\n case attr == \"bounds\" && randBounds:\n bounds = this._convertBounds(elem);\n return this._getRandomPoint(bounds);\n case attr == \"index\":\n return Number(elem);\n default:\n return elem;\n }\n }\n }\n\n _convertBounds(bounds) {\n /* @param bounds [string]\n Return Array[number, number, number, number] */\n let [start, end] = bounds.split(\"][\");\n let [sx, sy] = start.replace(\"[\", \"\").split(\",\");\n let [ex, ey] = end.replace(\"]\", \"\").split(\",\");\n return [sx, sy, ex, ey].map(el => Number(el));\n }\n\n _getRandomPoint(bounds) {\n /* @param bounds Array[number, number, number, number]\n Return Array[number, number] */\n const [sx, sy, ex, ey] = bounds;\n let x = utils.randRange(sx, ex);\n let y = utils.randRange(sy, ey);\n return [x, y];\n }\n\n _getPosition(bounds, pos) {\n /* @param bounds Array[number, number, number, number]\n @param pos Array[\"left\" | \"right\", \"top\" | \"bottom\"] :\n element position\n Example: _getPosition([300, 500], [\"right\", \"bottom\"])\n ```````\n Return Array[number, number] : coordinates */\n const [sx, sy, ex, ey] = bounds;\n let x, y;\n switch(pos[0]) {\n case \"center\":\n x = ex - Math.floor((ex-sx) / 2);\n break;\n case \"left\":\n x = sx;\n break;\n case \"right\":\n x = ex;\n break;\n default:\n throw new Error(`Invalid position value \"${pos[0]}\", expected \"center\", \"left\" or \"right\"`);\n }\n switch(pos[1]) {\n case \"center\":\n y = ey - Math.floor((ey-sy) / 2);\n break;\n case \"top\":\n y = sy;\n break;\n case \"bottom\":\n y = ey;\n break;\n default:\n throw new Error(`Invalid position value \"${pos[1]}\", expected \"center\", \"top\" or \"bottom\"`);\n }\n return [x, y];\n }\n\n async _getDump() {\n if (!this.hasOwnProperty(\"_device\")) {\n this._device = config.getDevice(this._serial);\n }\n return await this._device.getPageSource();\n }\n\n async isSelectorExists(xpath) {\n /* @param xpath [string] : xpath to check\n Return [boolean] : (true) if selector exists, (false) if not */\n this._xml = await this._getDump();\n return this._getNodes(xpath).length > 0;\n }\n\n async getSelectorsArray(xpath) {\n /* @param xpath [string]\n Return Array[string] | false */\n this._xml = await this._getDump();\n const nodes = this._getNodes(xpath);\n return nodes.length > 0 ? nodes : false;\n }\n\n async getALLSelectorsAttrs(xpath, attr) {\n /* @param xpath [string]\n @param attr [string] : element attribute to get its value\n Return Array[string] | false */\n const count = await this.getSelectorsCount(xpath);\n let result = [];\n for (let index=0; index < count; index++) {\n let attrValue = this._getValue({ xpath, attr }, index);\n let value;\n switch (attrValue) {\n case \"true\":\n value = true;\n case \"false\":\n value = false;\n case undefined:\n continue;\n default:\n value = attrValue;\n }\n result.push(value);\n }\n return result;\n }\n\n async getSelectorsCount(xpath) {\n /* @param xpath [string] : xpath to check\n Return Array[...string] */\n this._xml = await this._getDump();\n const nodes = this._getNodes(xpath);\n return nodes.length;\n }\n\n async getSelector(xpath, index=0) {\n /* @param xpath [string] : xpath to check\n @param index [number] : selector index\n Return [string] | false */\n this._xml = await this._getDump();\n const nodes = this._getNodes(xpath);\n return nodes.length > 0 ? nodes[index] : false;\n }\n\n async getElementAttribute(xpath, attr, index) {\n /* @param xpath [string]\n @param attr [string] : element attribute\n @param index [number] : the ordinal number of the found element\n Return [string | boolean | null] */\n const exists = await this.isSelectorExists(xpath);\n if (!exists) return null;\n let attrValue = this._getValue({ xpath, attr }, index);\n switch (attrValue) {\n case \"true\":\n return true;\n case \"false\":\n return false;\n case undefined:\n return null;\n default:\n return attrValue;\n }\n }\n\n async getAllElementAttributes(xpath, index) {\n /* @param xpath [string]\n @param index [number] : the ordinal number of the found element\n Return Array[string | boolean | null] */\n const attributes = [\"text\", \"resource-id\", \"class\", \"content-desc\",\n \"checkable\", \"checked\", \"clickable\", \"long-clickable\", \"scrollable\",\n \"enabled\", \"focusable\", \"focused\", \"selected\", \"package\", \"index\", \"bounds\"]\n const exists = await this.isSelectorExists(xpath);\n if (!exists) return null;\n\n let attrsObj = {};\n attributes.forEach(attr => {\n let attrValue = this._getValue({ xpath, attr }, index);\n switch (attrValue) {\n case \"true\":\n attrsObj[attr] = true;\n break;\n case \"false\":\n attrsObj[attr] = false;\n break;\n case undefined:\n attrsObj[attr] = null;\n break;\n default:\n attrsObj[attr] = attrValue;\n }\n });\n return attrsObj || false;\n }\n\n async waitForSelector(xpath, duration, delay, options) {\n /* @param xpath [string]\n @param duration [number] : maximum timeout for waiting selector, ms\n @param delay [number] : delay between checks\n\n @property options [object] : { instantly, index, randBounds }\n @property options.instantly=false [boolean] :\n wait for a @duration time (false) or not (true)\n @property options.index=0 [number] : selector index to get\n @property options.randBounds=false [boolean] :\n if (true) - one random [x, y] point will return,\n if (false) - return an array of points [startX, startY, endX, endY]\n\n Return Array[number, number] |\n Array[number, number, number, number] |\n false */\n const instantly = options && options.instantly || false;\n const randBounds = options && options.randBounds || false;\n const index = options && options.index || 0;\n const ts = Date.now();\n do {\n let exists = await this.isSelectorExists(xpath);\n if (exists) {\n let bounds = this._getValue(\n { xpath, attr: \"bounds\", randBounds },\n index\n );\n return bounds;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n } while (Date.now() - ts < duration && !instantly);\n return false;\n }\n\n async waitForIDLE(xpath, duration, delay) {\n /* @param xpath [string]\n @param duration [number] : maximum selector disappear timeout, ms\n @param delay [number] : delay between checks\n Return Array[number, number] |\n Array[number, number, number, number] |\n false */\n const ts = Date.now();\n while (Date.now() - ts < duration) {\n let exists = await this.isSelectorExists(xpath);\n if (!exists) {\n return true;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n return false;\n }\n\n async scrollTo(scrollable, target, options) {\n /* @param scrollable [string] : xpath of the scrollable element\n @param target [string | optional] : xpath of the element to find\n\n @param options [object] : { index, direction, duration, delay }\n @property options.index=0 [number] : selector index to scroll\n @property options.direction [\"up\" | \"down\" | \"left\" | \"right\"] :\n direction of scrolling\n @property options.duration=60000 [number] :\n maximum timeout for scrolling, ms\n @property options.delay=200 [number] : delay between scrollings, ms\n\n Return Array[number, number] | false */\n const index = options.index || 0;\n const direction = options.direction;\n const duration = options.duration || 60000;\n const delay = options.delay || 200;\n\n let exists = await this.isSelectorExists(scrollable);\n if (!exists) {\n throw new ScrollableElementNotFoundError(scrollable);\n }\n const scrollableBounds = this._getValue({\n xpath: scrollable,\n attr: \"bounds\"\n });\n\n let scrlSX, scrlSY;\n\n // end point\n let [scrlEX, scrlEY] = this._getPosition(scrollableBounds, [\"center\", \"center\"]);\n\n // start point\n switch(direction) {\n case \"up\":\n [scrlSX, scrlSY] = this._getPosition(scrollableBounds, [\"center\", \"top\"]);\n scrlSY += 10; // +10 px from the top border\n break;\n case \"down\":\n [scrlSX, scrlSY] = this._getPosition(scrollableBounds, [\"center\", \"bottom\"]);\n scrlSY -= 10; // -10 px from the bottom border\n break;\n case \"left\":\n [scrlSX, scrlSY] = this._getPosition(scrollableBounds, [\"right\", \"center\"]);\n scrlEX -= 10; // -10 px from the right border\n break;\n case \"right\":\n [scrlSX, scrlSY] = this._getPosition(scrollableBounds, [\"left\", \"center\"]);\n scrlSX += 10; // +10 px from the left border\n break;\n default:\n throw new Error(`Invalid param direction \"${direction}\", expected \"up\", \"down\", \"left\" or \"right\"`)\n }\n\n const ts = Date.now();\n // counter to compare with selector index\n let i = 0;\n // collect unique selectors to compare with counter\n let foundElements = new Set();\n\n while (Date.now() - ts < duration) {\n if (target) {\n let exists = await this.isSelectorExists(target);\n if (exists) {\n let items = this._getNodes(target);\n items.forEach(el => foundElements.add(el));\n i += foundElements.size;\n if (i >= index + 1) {\n let targetBounds = this._getValue({\n xpath: target,\n attr: \"bounds\"\n });\n return targetBounds;\n }\n }\n } else {\n this._xml = await this._getDump();\n }\n await this._adb.swipe(scrlSX, scrlSY, scrlEX, scrlEY, 30);\n\n // XML has not changed, thus scrolled to the end\n if (await this._getDump() == this._xml) {\n return false;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n return false;\n }\n}\n\nmodule.exports = async serial => await new Selector(serial);","data_name":"AMSelector","data_type":1,"language_name":"Node","language_version":"12.18.3"},{"data":"// clickByXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst { convertBoolReverse } = require(\"../AMUtils\");\r\nconst AMSelector = require(\"../AMSelector\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, waitForElement, index,\r\n xpath, maxDuration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nasync function clickBySelector() {\r\n const instantly = convertBoolReverse(waitForElement);\r\n const options = {instantly, index, randBounds: true};\r\n \r\n const selector = await AMSelector(serial);\r\n const bounds = await selector.waitForSelector(xpath, maxDuration, delay, options);\r\n if (!bounds) return false;\r\n\r\n const adb = await adbUtils(serial)\r\n await adb.click(...bounds);\r\n return true;\r\n}\r\n\r\n[[AM_NODE_RESULT]] = await clickBySelector();","data_name":"wqy09gk0hmh","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// clearTextByXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst { convertBoolReverse } = require(\"../AMUtils\");\r\nconst AMSelector = require(\"../AMSelector\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, waitForElement, index,\r\n xpath, maxDuration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst instantly = convertBoolReverse(waitForElement);\r\nconst options = {device, instantly, index, randBounds: false};\r\n\r\nasync function clearText() {\r\n const selector = await AMSelector(serial);\r\n const bounds = await selector.waitForSelector(xpath, maxDuration, delay, options);\r\n if (!bounds) return false;\r\n let [sx, sy, ex, ey] = bounds;\r\n const x = sx + 1;\r\n const y = ey - Math.floor((ey-sy) / 2);\r\n\r\n const adb = await adbUtils(serial);\r\n await adb.swipe(x, y, ex, y, 500);\r\n // key del\r\n await adb.keyEvent(\"67\");\r\n return true;\r\n}\r\n\r\n[[AM_NODE_RESULT]] = await clearText();","data_name":"rcukavhz0kp","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// setTextByXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst { convertBool, convertBoolReverse } = require(\"../AMUtils\");\r\nconst AMSelector = require(\"../AMSelector\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, clearText, waitForElement,\r\n index, xpath, maxDuration,\r\n delay, text, projectDirectory] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst instantly = convertBoolReverse(waitForElement);\r\nconst clear = convertBool(clearText);\r\nconst options = { instantly, randBounds: false, index };\r\n\r\nasync function setText() {\r\n const selector = await AMSelector(serial);\r\n const bounds = await selector.waitForSelector(xpath, maxDuration, delay, options);\r\n if(!bounds) return false;\r\n\r\n let [sx, sy, ex, ey] = bounds;\r\n const x = sx + 1;\r\n const y = ey - Math.floor((ey-sy) / 2);\r\n\r\n const adb = await adbUtils(serial);\r\n if (clear) {\r\n await adb.swipe(x, y, ex, y, 500);\r\n // key del\r\n await adb.keyEvent(\"67\");\r\n } else {\r\n await adb.click(x, y);\r\n // move to the end of field\r\n await adb.keyEvent(\"123\");\r\n }\r\n await adb.inputText(text, projectDirectory);\r\n return true;\r\n}\r\n\r\n[[AM_NODE_RESULT]] = await setText();","data_name":"38eg1isysfp","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// waitForXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, maxDuration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst options = {instantly: false, randBounds: false};\r\n\r\nconst selector = await AMSelector(serial);\r\nconst found = await selector.waitForSelector(xpath, maxDuration, delay, options);\r\n[[AM_NODE_RESULT]] = !!found;","data_name":"eenbzn58uar","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// existsByXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst options = {instantly: true, randBounds: false};\r\n\r\nconst selector = await AMSelector(serial);\r\nconst found = await selector.isSelectorExists(xpath);\r\n[[AM_NODE_RESULT]] = !!found;","data_name":"3i3q2p9g1sr","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// waitForActivity\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, maxDuration, delay, activity] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nasync function waitActivity() {\r\n const adb = await adbUtils(serial);\r\n const ts = Date.now();\r\n while (Date.now() - ts < maxDuration) {\r\n if (activity = await adb.currentActivity()) {\r\n return true;\r\n }\r\n await new Promise(resolve => setTimeout(resolve, delay));\r\n }\r\n return false;\r\n}\r\n\r\n[[AM_NODE_RESULT]] = await waitActivity();","data_name":"9twj7amyb0j","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getElementAttribute\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, attribute, index] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getElementAttribute(xpath, attribute, index);","data_name":"to41qlzw5xg","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getAllElementAttributes\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, index] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getAllElementAttributes(xpath, index);","data_name":"saby3a7luff","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// scrollToElement\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, scrollableElement, targetElement,\r\n index, direction, duration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst options = { index, direction, duration, delay };\r\n\r\nconst selector = await AMSelector(serial);\r\nconst found = await selector.scrollTo(scrollableElement, targetElement, options);\r\n[[AM_NODE_RESULT]] = !!found;","data_name":"o2j85iyy1b","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// connectDevice\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst { convertBool } = require(\"../AMUtils\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, configConnection, newCommandTimeout] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nconst addr = config.server;\r\n\r\nlet connType = convertBool(configConnection);\r\nconnType = typeof connType == \"boolean\" ? connType : \"auto\";\r\n\r\nconst options = {\r\n host: addr.host,\r\n port: addr.port,\r\n capabilities: {\r\n platformName: \"android\",\r\n \"appium:udid\": serial,\r\n \"appium:automationName\": \"UiAutomator2\",\r\n \"appium:newCommandTimeout\": newCommandTimeout\r\n }\r\n};\r\n\r\nawait adbUtils(serial);\r\nawait config.setDevice(options, connType);","data_name":"8pwf8xbkfqr","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// waitForIDLE\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, maxDuration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\nconst found = await selector.waitForIDLE(xpath, maxDuration, delay);\r\n[[AM_NODE_RESULT]] = !!found;","data_name":"h8eh6m8yxvi","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// longClickByXpath\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst { convertBoolReverse } = require(\"../AMUtils\");\r\nconst AMSelector = require(\"../AMSelector\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, waitForElement, index,\r\n xpath, steps, maxDuration, delay] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nasync function longClickBySelector() {\r\n const instantly = convertBoolReverse(waitForElement);\r\n const options = {instantly, index, randBounds: true};\r\n \r\n const selector = await AMSelector(serial);\r\n const bounds = await selector.waitForSelector(xpath, maxDuration, delay, options);\r\n if (!bounds) return false;\r\n\r\n const adb = await adbUtils(serial);\r\n await adb.swipe(...bounds, ...bounds, steps);\r\n return true;\r\n}\r\n\r\n[[AM_NODE_RESULT]] = await longClickBySelector();","data_name":"rmzl9z6548j","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// longClickByCoordinates\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, x, y, steps] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nawait adb.swipe(x, y, x, y, steps);","data_name":"zxb6e1ovmm9","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"const path = require(\"path\");\nconst process = require(\"./AMNodeProcess\");\nconst { normalizePath, isPathExists } = require(\"./AMUtils\");\nconst http = require(\"./AMHTTPClient\");\nconst { DeviceIsNotRunningError, PathNotFoundError } = require(\"./AMError\");\n\n\nclass ADB {\n constructor(serial) {\n this._serial = serial;\n if (this._serial) {\n return (async () => {\n const devices = await this.devices();\n if (!devices.includes(this._serial)) {\n throw new DeviceIsNotRunningError(this._serial);\n }\n return this;\n })(); \n }\n }\n\n async devices() {\n const output = await process(\"adb devices\");\n let devices = [];\n output.forEach(el => {\n let [serial, status] = el.split(\"\\t\");\n if (status !== undefined && status.indexOf(\"device\") > -1) {\n devices.push(serial);\n }\n })\n return devices;\n }\n\n async shell(cmd) {\n const params = [\"adb\", \"-s\", this._serial, \"shell\", cmd];\n return await process(params.join(\" \"));\n }\n\n async push(inputPath, outputPath) {\n const input = normalizePath(inputPath);\n const output = normalizePath(outputPath);\n const isInputPathExists = await isPathExists(input);\n if (!isInputPathExists) throw new PathNotFoundError(input);\n await process(`adb -s ${this._serial} push \"${input}\" ${output}`);\n }\n\n async pull(inputPath, outputPath) {\n const input = normalizePath(inputPath);\n const output = normalizePath(outputPath);\n const isoutputPathExists = await isPathExists(output);\n if (!isoutputPathExists) throw new PathNotFoundError(input);\n await process(`adb -s ${this._serial} pull ${input} \"${output}\"`);\n }\n\n async click(x, y) {\n await this.shell(`input tap ${x} ${y}`);\n }\n\n async swipe(sx, sy, ex, ey, steps) {\n await this.shell(`input swipe ${sx} ${sy} ${ex} ${ey} ${steps}`);\n }\n\n async drag(sx, sy, ex, ey) {\n await this.shell(`input draganddrop ${sx} ${sy} ${ex} ${ey}`);\n }\n\n async keyEvent(event) {\n await this.shell(`input keyevent ${event}`);\n }\n\n async install(location, source=\"file\", directory=null) {\n let targetPath, isPath;\n switch (source) {\n case \"url\":\n const appName = location.split(\"/\").at(-1);\n targetPath = normalizePath(\n path.resolve(directory || __dirname, appName)\n );\n isPath = await isPathExists(targetPath);\n if (!isPath) {\n await http.download(location, targetPath);\n }\n break;\n case \"file\":\n targetPath = normalizePath(location);\n isPath = await isPathExists(targetPath);\n if (!isPath) throw new PathNotFoundError(targetPath);\n break;\n }\n const output = await process(`adb -s ${this._serial} install \"${targetPath}\"`);\n return output.some(el => el.indexOf(\"Success\") > -1);\n }\n\n async uninstall(appName) {\n const output = await process(`adb -s ${this._serial} uninstall ${appName}`);\n return output.some(el => el.indexOf(\"Success\") > -1);\n }\n\n async openApp(appName) {\n await this.shell(`am start -n ${appName}`);\n }\n\n async closeApp(appName) {\n await this.shell(`am force-stop ${appName}`);\n }\n\n async clearApp(appName) {\n await this.closeApp(appName);\n await this.shell(`pm clear ${appName}`);\n }\n\n async listPackages() {\n let packages = await this.shell(\"pm list packages\");\n return packages.map(el => el.replace(/^package:/g, \"\")).sort();\n }\n\n async isPackage(appName) {\n let packages = await this.shell(\"pm list packages\");\n return packages\n .filter(el => el.indexOf(appName) > -1)\n .length > 0;\n }\n\n async currentActivity() {\n const cmd = 'dumpsys activity activities | grep mResumedActivity | cut -d \"{\" -f2 | cut -d \" \" -f3';\n const activity = await this.shell(cmd);\n return activity[0];\n }\n\n async inputText(text, directory) {\n const keyboards = await this.shell(\"ime list -s\");\n if (!keyboards.includes(\"com.android.adbkeyboard/.AdbIME\")) {\n await this.install(\n \"https://github.com/senzhk/ADBKeyBoard/raw/master/ADBKeyboard.apk\",\n \"url\",\n directory\n );\n }\n await this.shell(\"ime enable com.android.adbkeyboard/.AdbIME\");\n await this.shell(\"ime set com.android.adbkeyboard/.AdbIME\");\n const chars = [...text]\n .map(s => s.charCodeAt(0))\n .join(\",\");\n await this.shell(`am broadcast -a ADB_INPUT_CHARS --eia chars '${chars}'`);\n }\n}\n\nmodule.exports = async serial => await new ADB(serial);","data_name":"AMAdbUtils","data_type":1,"language_name":"Node","language_version":"12.18.3"},{"data":"// clickByCoordinates\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, x, y] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\nconst adb = await adbUtils(serial);\r\nawait adb.click(x, y);","data_name":"w5n75awe3xc","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"const { SubProcess } = require(\"teen_process\");\nconst config = require(\"./AMConfig\");\nconst process = require(\"./AMNodeProcess\");\nconst { ServerConnectionError } = require(\"./AMError\");\n\n\nclass Server {\n constructor(host, port, maxDuration, connMaxTries) {\n this.host = host;\n this.port = port;\n this._maxDuration = maxDuration;\n this._connMaxTries = connMaxTries;\n }\n\n async _spawn() {\n const child = new SubProcess(\n \"appium.cmd\",\n [\"-a\", this.host, \"-p\", this.port]\n );\n const success = /listener started on/g;\n const fail = /port may already be in use|address already in use/g;\n let sd = (stdout, stderr) => {\n if (success.test(stdout)) {\n return;\n }\n if (fail.test(stderr)) {\n return;\n }\n return stdout || stderr;\n };\n\n await child.start(sd, this._maxDuration);\n }\n\n async _check() {\n /* Return process PID */\n try {\n const output = await process(`netstat -a -n -o | find \"${this.port}\"`);\n const data = output[0].split(\" \");\n return data.at(-1);\n } catch (e) {\n return false;\n }\n }\n\n async start() {\n for (let i=0; i < this._connMaxTries; i++) {\n await this._spawn();\n let status = await this._check();\n if (status) {\n config.server = {\n host: this.host,\n port: this.port\n };\n return;\n }\n }\n throw new ServerConnectionError(this._connMaxTries);\n }\n\n async stop() {\n const pid = await this._check();\n if (!pid) return;\n await process(`taskkill /PID ${pid} /F`);\n }\n}\n\nmodule.exports = (host, port, maxDuration, connMaxTries) => new Server(host, port, maxDuration, connMaxTries);","data_name":"AMServer","data_type":1,"language_name":"Node","language_version":"18.10.0"},{"data":"// startAppiumServer\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst Server = require(\"../AMServer\");\r\n\r\nconst [lang, host, port, maxDuration, connMaxTries] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst server = Server(host, port, maxDuration || 60000, connMaxTries || 3);\r\nawait server.start();","data_name":"8ppqydx8f9n","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// stopAppiumServer\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst Server = require(\"../AMServer\");\r\n\r\n\r\nconfig.lang = [[AM_NODE_PARAMS]];\r\nconst addr = config.server;\r\nif (addr) {\r\n const server = Server(addr.host, addr.port);\r\n await server.stop();\r\n}","data_name":"9c1kl3xuuv5","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// openNotifications\r\n\r\nconst config = require(\"../AMConfig\");\r\n\r\n\r\nconst [lang, serial] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst device = config.getDevice(serial);\r\nawait device.openNotifications();","data_name":"viovixhw7z","data_type":0,"language_name":"Node","language_version":"18.10.0"},{"data":"// isAppInstalled\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\n[[AM_NODE_RESULT]] = await adb.isPackage(appName);","data_name":"mztkjjui19b","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// isAppRunning\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst adbUtils = require(\"../AMAdbUtils\");\r\n\r\n\r\nconst [lang, serial, appName] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst adb = await adbUtils(serial);\r\nconst activity = await adb.currentActivity();\r\n[[AM_NODE_RESULT]] = activity.indexOf(appName) > -1;","data_name":"vjkqu1ltkna","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// solveCaptcha\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst CapSolver = require(\"../AMCapSolver\");\r\n\r\n\r\nconst [lang, serial, service, apiKey, attempts, waitDuration,\r\n solvingDuration, screenDelay, mainSelector, textSelector,\r\n imageSelector, buttonSelector] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst options = { serial, service, apiKey, attempts,\r\n waitDuration, solvingDuration,\r\n screenDelay, mainSelector, textSelector,\r\n imageSelector, buttonSelector };\r\nconst solver = await CapSolver(options);\r\n[[AM_NODE_RESULT]] = await solver.solve();","data_name":"4crdsbaoy3r","data_type":0,"language_name":"Node","language_version":"18.10.0"},{"data":"const sharp = require(\"sharp\");\r\nconst config = require(\"./AMConfig\");\r\nconst AMSelector = require(\"./AMSelector\");\r\nconst AdbUtils = require(\"./AMAdbUtils\");\r\nconst http = require(\"./AMHTTPClient\");\r\nconst { CaptchaCreateTaskError,\r\n CaptchaGetTaskResultError,\r\n CaptchaFrameNotFoundError,\r\n CaptchaImageNotFoundError,\r\n CaptchaDescriptionNotFoundError,\r\n CaptchaButtonNotFoundError } = require(\"./AMError\");\r\n\r\n\r\nclass API {\r\n constructor(service, apiKey) {\r\n /* @param service [string] : captcha solving service\r\n @param apiKey [string] : API key for captcha solving service */\r\n this._service = service;\r\n this._url = this._getServiceURL();\r\n this._apiKey = apiKey;\r\n }\r\n\r\n _getServiceURL() {\r\n const urls = {\r\n \"2captcha\": \"https://2captcha.com\",\r\n \"captcha.guru\": \"http://api.captcha.guru\",\r\n \"rucaptcha\": \"http://rucaptcha.com\"\r\n }\r\n return urls[this._service];\r\n }\r\n\r\n _response(resp, source) {\r\n switch (source) {\r\n case \"createTask\":\r\n if(resp.status === 0) {\r\n throw new CaptchaCreateTaskError(resp.request, resp.error_text);\r\n } else {\r\n return resp.request;\r\n }\r\n case \"getTaskResult\":\r\n if (resp.request === \"CAPCHA_NOT_READY\") {\r\n return resp.request;\r\n } else if (resp.status === 1) {\r\n if (!resp.request || resp.request == \"notpic\") {\r\n return [];\r\n }\r\n if (typeof resp.request == \"string\") {\r\n return resp.request\r\n .replace(\"coordinates:\", \"\")\r\n .split(\";\")\r\n .map(el => {\r\n const pairs = el.match(/\\d+/g);\r\n return { \"x\": pairs[0], \"y\": pairs[1] };\r\n });\r\n } else {\r\n return resp.request;\r\n }\r\n } else {\r\n throw new CaptchaGetTaskResultError(resp.request);\r\n }\r\n }\r\n }\r\n\r\n async createTask(text, image) {\r\n const url = `${this._url}/in.php`;\r\n const common = {\r\n key: this._apiKey,\r\n method: \"base64\",\r\n textinstructions: text,\r\n body: image,\r\n json: 1\r\n };\r\n let additional = {};\r\n switch (this._service) {\r\n case \"2captcha\":\r\n case \"rucaptcha\":\r\n additional.coordinatescaptcha = 1;\r\n additional.softid = 2985;\r\n break;\r\n case \"captcha.guru\":\r\n additional.click = \"recap\";\r\n break;\r\n default:\r\n throw new Error(`Service ${this._service} not supported`);\r\n }\r\n const body = Object.assign({}, common, additional);\r\n const response = await http.POST(url, body);\r\n return this._response(response, \"createTask\");\r\n }\r\n\r\n async getTaskResult(taskId) {\r\n const url = `${this._url}/res.php?key=${this._apiKey}&action=get&id=${taskId}&json=1`;\r\n const response = await http.GET(url);\r\n return this._response(response, \"getTaskResult\");\r\n }\r\n}\r\n\r\n\r\nclass CapSolver {\r\n constructor(options) {\r\n /* @param options [object]\r\n @property options.serial [string] : device serial number\r\n @property options.service [string] : captcha solving service\r\n @property options.apiKey [string] : API key for captcha solving service\r\n @property options.attempts [number] : amount of captchas to solve\r\n @property options.waitDuration [number] :\r\n timeout for waiting of the main captcha selector, ms\r\n @property options.solvingDuration [number] :\r\n timeout for solving each captcha, ms\r\n @property options.screenDelay [number] :\r\n delay before the next captcha will loaded, ms\r\n @property options.mainSelector [string] :\r\n xpath for main frame selector with captcha\r\n @property options.textSelector [string] :\r\n xpath for selector with text description,\r\n can contain multiple text lines\r\n @property options.imageSelector [string] :\r\n xpath for selector with captcha image\r\n @property options.buttonSelector [string] :\r\n xpath for submit button,\r\n should not contain @text attribute in xpath request\r\n */\r\n this._serial = options.serial;\r\n this._service = options.service;\r\n this._apiKey = options.apiKey;\r\n this._attempts = options.attempts;\r\n this._waitDuration = options.waitDuration || 60000;\r\n this._solvingDuration = options.solvingDuration || 60000;\r\n this._screenDelay = options.screenDelay || 7000;\r\n this._mainSelector = options.mainSelector || '//*[@resource-id=\"rc-imageselect\"]';\r\n this._textSelector = options.textSelector || '//*[@resource-id=\"rc-imageselect\"]/*[@class=\"android.view.View\" and @index=\"1\"]//*[@text]/@text';\r\n this._imageSelector = options.imageSelector || '//*[@resource-id=\"rc-imageselect\"]/*[@class=\"android.view.View\" and @index=\"2\"]';\r\n this._buttonSelector = options.buttonSelector || '//*[@resource-id=\"rc-imageselect\"]//*[@resource-id=\"recaptcha-verify-button\"]';\r\n return (async () => {\r\n this._adb = await AdbUtils(this._serial);\r\n return this;\r\n })();\r\n }\r\n \r\n async _getGrid() {\r\n if (!this.hasOwnProperty(\"_device\")) {\r\n this._device = config.getDevice(this._serial);\r\n }\r\n const b64Image = await this._device.takeScreenshot();\r\n const buff = Buffer.from(b64Image, \"base64\");\r\n const bounds = await this._selector.getElementAttribute(\r\n this._imageSelector,\r\n \"bounds\"\r\n );\r\n if (!bounds) {\r\n throw new CaptchaImageNotFoundError(this._imageSelector);\r\n }\r\n const [sx, sy, ex, ey] = bounds;\r\n this._gridShift = { x: sx, y: sy };\r\n\r\n const stream = await sharp(buff)\r\n .extract({\r\n left: sx,\r\n top: sy,\r\n width: ex - sx,\r\n height: ey - sy\r\n })\r\n .jpeg({ mozjpeg: true })\r\n .toBuffer();\r\n return await stream.toString(\"base64\");\r\n }\r\n\r\n async _getText() {\r\n const elements = await this._selector.getSelectorsArray(this._textSelector);\r\n if (!elements) {\r\n throw new CaptchaDescriptionNotFoundError(this._textSelector);\r\n }\r\n let texts = [];\r\n elements.forEach(el => {\r\n const result = el.match(/(?<=text=\")(.+?)(?=\")/);\r\n if (result) texts.push(result[1]);\r\n });\r\n return texts[1];\r\n }\r\n\r\n async _solveCurrent() {\r\n const image = await this._getGrid();\r\n const text = await this._getText();\r\n\r\n const solver = new API(this._service, this._apiKey);\r\n const captchaId = await solver.createTask(text, image);\r\n\r\n const ts = Date.now();\r\n while (Date.now() - ts < this._solvingDuration) {\r\n let result = await solver.getTaskResult(captchaId);\r\n if (result != \"CAPCHA_NOT_READY\") {\r\n return result;\r\n }\r\n await new Promise(resolve => setTimeout(resolve, 1000));\r\n \r\n }\r\n return false;\r\n }\r\n\r\n async solve() {\r\n this._selector = await AMSelector(this._serial);\r\n let status = await this._selector.waitForSelector(\r\n this._mainSelector,\r\n this._waitDuration,\r\n 200\r\n );\r\n if (!status) {\r\n throw new CaptchaFrameNotFoundError(this._mainSelector);\r\n }\r\n for (let i=0; i < this._attempts; i++) {\r\n let boundsArray = await this._solveCurrent();\r\n if (boundsArray === false) return false;\r\n if (boundsArray.length > 0) {\r\n for (const el of boundsArray) {\r\n let x = this._gridShift.x + Number(el.x);\r\n let y = this._gridShift.y + Number(el.y);\r\n await this._adb.click(x, y);\r\n };\r\n }\r\n\r\n const btnBounds = await this._selector.waitForSelector(\r\n this._buttonSelector,\r\n 1000,\r\n 200,\r\n { instantly: true, randBounds: true }\r\n );\r\n if (!btnBounds) {\r\n throw new CaptchaButtonNotFoundError(this._buttonSelector);\r\n }\r\n let btnText = await this._selector.getElementAttribute(\r\n this._buttonSelector,\r\n \"text\"\r\n )\r\n btnText = btnText.toLowerCase();\r\n if ([\"next\", \"далее\"].includes(btnText) || boundsArray.length === 0) {\r\n await this._adb.click(...btnBounds);\r\n }\r\n await new Promise(resolve => setTimeout(resolve, this._screenDelay));\r\n\r\n let status = await this._selector.waitForSelector(\r\n this._mainSelector,\r\n 5000,\r\n 200\r\n );\r\n if (!status) return true;\r\n }\r\n return false;\r\n }\r\n}\r\n\r\nmodule.exports = async options => await new CapSolver(options);","data_name":"AMCapSolver","data_type":1,"language_name":"Node","language_version":"18.10.0"},{"data":"const fetch = require(\"node-fetch\");\nconst { writeFile } = require(\"fs\").promises;\nconst { HTTPClientError } = require(\"./AMError\");\n\n\nclass httpClient {\n _response(url, response) {\n if (response.ok) {\n if (this._jsonResponse) {\n return response.json();\n }\n return response.text();\n } else {\n throw new HTTPClientError(url, response);\n }\n }\n\n async GET(url, json=true) {\n this._jsonResponse = json;\n const response = await fetch(url);\n return await this._response(url, response);\n }\n\n async POST(url, body, json=true) {\n this._jsonResponse = json;\n const response = await fetch(\n url,\n {\n method: \"post\",\n body: JSON.stringify(body),\n headers: {\"Content-Type\": \"application/json\"}\n }\n );\n return await this._response(url, response);\n }\n\n async download(url, path) {\n const response = await fetch(url);\n if (!response.ok) {\n throw new HTTPClientError(url, response);\n }\n const buffer = await response.buffer();\n await writeFile(path, buffer);\n }\n}\n\nmodule.exports = new httpClient();","data_name":"AMHTTPClient","data_type":1,"language_name":"Node","language_version":"18.10.0"},{"data":"// getXpathSelector\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, index] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getSelector(xpath, index);","data_name":"dhacor6a3q","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getAllXpathSelectors\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getSelectorsArray(xpath);","data_name":"b9spcc51oy9","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getXpathSelectorsCount\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getSelectorsCount(xpath);","data_name":"cfdhzlhc8mo","data_type":0,"language_name":"Node","language_version":"12.18.3"},{"data":"// getAllSelectorsAttribute\r\n\r\nconst config = require(\"../AMConfig\");\r\nconst AMSelector = require(\"../AMSelector\");\r\n\r\n\r\nconst [lang, serial, xpath, attr] = [[AM_NODE_PARAMS]];\r\nconfig.lang = lang;\r\n\r\nconst selector = await AMSelector(serial);\r\n[[AM_NODE_RESULT]] = await selector.getALLSelectorsAttrs(xpath, attr);","data_name":"q2lyw2533nr","data_type":0,"language_name":"Node","language_version":"12.18.3"}]]]>
Database.26732
false
ScriptName
4
InMail;URL;ClickCaptcha;Path;JSON;PhoneVerification;String;MailDeprecated
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
false
false
false
false
false
false
PrivateScriptUserEnterPass
1.0.0
en,ru
25.3.8
EnableFlash=false
EnableWidevine=false
AutostartDebug=false
SaveBrowserLog=false
ProfilesCaching=true
ToolboxHeight=663
MaxBrowserStartSimultaneously=3
MinFreeMemoryToStartBrowser=1500
MinUnusedCpu=35
ScenarioWidth=474
Zoom=100
IsMaximized=false
Restart=true
UseHumanLikeMouseMoves=true
DebugToolbox=false
DebugScenario=false
Languages="Node,18.10.0"
Modules="Node,18.10.0,child_process,*;Node,18.10.0,fs,*;Node,18.10.0,xpath,*;Node,18.10.0,xmldom,*;Node,18.10.0,teen_process,*;Node,18.10.0,webdriverio,*;Node,18.10.0,node-fetch,*;Node,18.10.0,sharp,*"
Canvas="enable"
CanvasNoise=""
Audio="enable"
QUIC="disable"
AudioNoise=""
MaxFPS=30
Webrtc="enable"
WebrtcIps=""
Webgl="enable"
WebglNoise=""
WebglRenderer=""
WebglVendor=""
Detector=true
--disk-cache-size=1
--disable-gpu-program-cache
--disable-gpu-shader-disk-cache
--disable-component-update
--disable-features=GpuProcessHighPriorityWin,GpuUseDisplayThreadPriority
--enable-features=ViewportHeightClientHintHeader
--lang=en
--disable-auto-reload
--reduce-user-agent-minor-version
{
"AndroidManager": true,
"Archive": false,
"Checksum": false,
"Excel": false,
"FTP": false,
"FunCaptcha": false,
"HCaptcha": false,
"Logger": false,
"MailDeprecated": true,
"ReCaptcha": false,
"SQL": true,
"SmsReceive": false,
"logger": true,
"waitingSelectors": false
}
{"variables":{"sortings":[{"name":"frequency","active":false},{"name":"dateModified","active":false},{"name":"dateCreated","active":false},{"name":"alphabetically","active":true}],"filters":[{"name":"undefined","active":true},{"name":"boolean","active":true},{"name":"object","active":true},{"name":"string","active":true},{"name":"number","active":true},{"name":"array","active":true},{"name":"date","active":true},{"name":"null","active":true}],"options":[{"name":"groups","active":false}],"groups":[{"id":0,"name":"Main","color":"brown","expanded":true,"items":[{"key":"AM_NODE_PARAMS","fixed":false},{"key":"AM_NODE_RESULT","fixed":false}]}],"nodes":{"[\"AM_NODE_RESULT\"]":false}},"resources":{"sortings":[],"filters":[],"options":[],"groups":[{"id":0,"name":"Main","color":"brown","expanded":true,"items":[]}],"nodes":{}},"callstack":{"filters":[]}}
1
1
1
0
0
0
0
0
0