@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +44 -54
  2. package/bin/cli.js +1 -115
  3. package/bin/loxia-terminal-v2.js +3 -0
  4. package/bin/loxia-terminal.js +3 -0
  5. package/bin/start-with-terminal.js +3 -0
  6. package/package.json +15 -15
  7. package/scripts/install-scanners.js +1 -235
  8. package/src/analyzers/CSSAnalyzer.js +1 -297
  9. package/src/analyzers/ConfigValidator.js +1 -690
  10. package/src/analyzers/ESLintAnalyzer.js +1 -320
  11. package/src/analyzers/JavaScriptAnalyzer.js +1 -261
  12. package/src/analyzers/PrettierFormatter.js +1 -247
  13. package/src/analyzers/PythonAnalyzer.js +1 -266
  14. package/src/analyzers/SecurityAnalyzer.js +1 -729
  15. package/src/analyzers/TypeScriptAnalyzer.js +1 -247
  16. package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
  17. package/src/analyzers/codeCloneDetector/detector.js +1 -203
  18. package/src/analyzers/codeCloneDetector/index.js +1 -160
  19. package/src/analyzers/codeCloneDetector/parser.js +1 -199
  20. package/src/analyzers/codeCloneDetector/reporter.js +1 -148
  21. package/src/analyzers/codeCloneDetector/scanner.js +1 -59
  22. package/src/core/agentPool.js +1 -1474
  23. package/src/core/agentScheduler.js +1 -2147
  24. package/src/core/contextManager.js +1 -709
  25. package/src/core/messageProcessor.js +1 -732
  26. package/src/core/orchestrator.js +1 -548
  27. package/src/core/stateManager.js +1 -877
  28. package/src/index.js +1 -631
  29. package/src/interfaces/cli.js +1 -549
  30. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
  31. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
  32. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
  33. package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
  34. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
  35. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
  36. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
  37. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
  38. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
  39. package/src/interfaces/terminal/api/apiClient.js +1 -0
  40. package/src/interfaces/terminal/api/messageRouter.js +1 -0
  41. package/src/interfaces/terminal/api/session.js +1 -0
  42. package/src/interfaces/terminal/api/websocket.js +1 -0
  43. package/src/interfaces/terminal/components/AgentCreator.js +1 -0
  44. package/src/interfaces/terminal/components/AgentEditor.js +1 -0
  45. package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
  46. package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
  47. package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
  48. package/src/interfaces/terminal/components/Header.js +1 -0
  49. package/src/interfaces/terminal/components/HelpPanel.js +1 -0
  50. package/src/interfaces/terminal/components/InputBox.js +1 -0
  51. package/src/interfaces/terminal/components/Layout.js +1 -0
  52. package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
  53. package/src/interfaces/terminal/components/MessageList.js +1 -0
  54. package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
  55. package/src/interfaces/terminal/components/SearchPanel.js +1 -0
  56. package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
  57. package/src/interfaces/terminal/components/StatusBar.js +1 -0
  58. package/src/interfaces/terminal/components/TextInput.js +1 -0
  59. package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
  60. package/src/interfaces/terminal/config/constants.js +1 -0
  61. package/src/interfaces/terminal/index.js +1 -0
  62. package/src/interfaces/terminal/state/useAgentControl.js +1 -0
  63. package/src/interfaces/terminal/state/useAgents.js +1 -0
  64. package/src/interfaces/terminal/state/useConnection.js +1 -0
  65. package/src/interfaces/terminal/state/useMessages.js +1 -0
  66. package/src/interfaces/terminal/state/useTools.js +1 -0
  67. package/src/interfaces/terminal/utils/debugLogger.js +1 -0
  68. package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
  69. package/src/interfaces/terminal/utils/theme.js +1 -0
  70. package/src/interfaces/webServer.js +1 -2162
  71. package/src/modules/fileExplorer/controller.js +1 -280
  72. package/src/modules/fileExplorer/index.js +1 -37
  73. package/src/modules/fileExplorer/middleware.js +1 -92
  74. package/src/modules/fileExplorer/routes.js +1 -125
  75. package/src/modules/fileExplorer/types.js +1 -44
  76. package/src/services/aiService.js +1 -1232
  77. package/src/services/apiKeyManager.js +1 -164
  78. package/src/services/benchmarkService.js +1 -366
  79. package/src/services/budgetService.js +1 -539
  80. package/src/services/contextInjectionService.js +1 -247
  81. package/src/services/conversationCompactionService.js +1 -637
  82. package/src/services/errorHandler.js +1 -810
  83. package/src/services/fileAttachmentService.js +1 -544
  84. package/src/services/modelRouterService.js +1 -366
  85. package/src/services/modelsService.js +1 -322
  86. package/src/services/qualityInspector.js +1 -796
  87. package/src/services/tokenCountingService.js +1 -536
  88. package/src/tools/agentCommunicationTool.js +1 -1344
  89. package/src/tools/agentDelayTool.js +1 -485
  90. package/src/tools/asyncToolManager.js +1 -604
  91. package/src/tools/baseTool.js +1 -800
  92. package/src/tools/browserTool.js +1 -920
  93. package/src/tools/cloneDetectionTool.js +1 -621
  94. package/src/tools/dependencyResolverTool.js +1 -1215
  95. package/src/tools/fileContentReplaceTool.js +1 -875
  96. package/src/tools/fileSystemTool.js +1 -1107
  97. package/src/tools/fileTreeTool.js +1 -853
  98. package/src/tools/imageTool.js +1 -901
  99. package/src/tools/importAnalyzerTool.js +1 -1060
  100. package/src/tools/jobDoneTool.js +1 -248
  101. package/src/tools/seekTool.js +1 -956
  102. package/src/tools/staticAnalysisTool.js +1 -1778
  103. package/src/tools/taskManagerTool.js +1 -2873
  104. package/src/tools/terminalTool.js +1 -2304
  105. package/src/tools/webTool.js +1 -1430
  106. package/src/types/agent.js +1 -519
  107. package/src/types/contextReference.js +1 -972
  108. package/src/types/conversation.js +1 -730
  109. package/src/types/toolCommand.js +1 -747
  110. package/src/utilities/attachmentValidator.js +1 -292
  111. package/src/utilities/configManager.js +1 -582
  112. package/src/utilities/constants.js +1 -722
  113. package/src/utilities/directoryAccessManager.js +1 -535
  114. package/src/utilities/fileProcessor.js +1 -307
  115. package/src/utilities/logger.js +1 -436
  116. package/src/utilities/tagParser.js +1 -1246
  117. package/src/utilities/toolConstants.js +1 -317
  118. package/web-ui/build/index.html +2 -2
  119. package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
  120. package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
@@ -1,920 +1 @@
1
- /**
2
- * BrowserTool - Handle browser automation and web interaction tasks
3
- *
4
- * Purpose:
5
- * - Automate web browser interactions
6
- * - Navigate websites and extract data
7
- * - Fill forms and interact with web elements
8
- * - Take screenshots and analyze web content
9
- * - Handle authentication and sessions
10
- */
11
-
12
- import { BaseTool } from './baseTool.js';
13
- import TagParser from '../utilities/tagParser.js';
14
- import puppeteer from 'puppeteer';
15
- import fs from 'fs/promises';
16
- import path from 'path';
17
-
18
- import {
19
- TOOL_STATUS,
20
- SYSTEM_DEFAULTS
21
- } from '../utilities/constants.js';
22
-
23
- class BrowserTool extends BaseTool {
24
- constructor(config = {}, logger = null) {
25
- super(config, logger);
26
-
27
- // Tool metadata
28
- this.requiresProject = false;
29
- this.isAsync = true; // Browser operations can be slow
30
- this.timeout = config.timeout || 60000; // 1 minute default
31
- this.maxConcurrentOperations = config.maxConcurrentOperations || 2;
32
-
33
- // Browser configuration
34
- this.browserConfig = {
35
- headless: config.headless !== false, // Default to headless
36
- viewport: config.viewport || { width: 1280, height: 720 },
37
- userAgent: config.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
38
- timeout: config.pageTimeout || 30000
39
- };
40
-
41
- // Active browser instances
42
- this.browserInstances = new Map();
43
-
44
- // Security settings
45
- this.allowedDomains = config.allowedDomains || null; // null = all allowed
46
- this.blockedDomains = config.blockedDomains || [];
47
- this.maxScreenshotSize = config.maxScreenshotSize || 5 * 1024 * 1024; // 5MB
48
-
49
- // Operation history
50
- this.operationHistory = [];
51
- }
52
-
53
- /**
54
- * Get tool description for LLM consumption
55
- * @returns {string} Tool description
56
- */
57
- getDescription() {
58
- return `
59
- Browser Tool: Automate web browser interactions, navigation, and data extraction.
60
-
61
- IMPORTANT - SYNTAX: Use self-closing tags with angle brackets < >, not square brackets [ ].
62
-
63
- XML USAGE (Recommended):
64
- <browser>
65
- <navigate url="https://example.com" />
66
- <wait wait-time="2000" />
67
- <click selector="button.submit" />
68
- <screenshot output-path="screenshot.png" />
69
- </browser>
70
-
71
- JSON USAGE (Alternative):
72
- \`\`\`json
73
- {
74
- "toolId": "browser",
75
- "actions": [
76
- { "type": "navigate", "url": "https://example.com" },
77
- { "type": "wait", "waitTime": 2000 },
78
- { "type": "click", "selector": "button.submit" },
79
- { "type": "screenshot", "outputPath": "screenshot.png" }
80
- ]
81
- }
82
- \`\`\`
83
-
84
- SUPPORTED ACTIONS:
85
- - navigate: Navigate to a URL (requires: url)
86
- - click: Click on an element (requires: selector)
87
- - type: Type text into an input field (requires: selector, text)
88
- - wait: Wait for element or time (requires: wait-time OR wait-selector)
89
- - screenshot: Take screenshot of page (requires: output-path)
90
- - extract: Extract text/data from elements (requires: selector, attribute)
91
- - scroll: Scroll page or element (requires: direction)
92
- - close: Close browser instance (no parameters)
93
-
94
- PARAMETER REFERENCE:
95
- - url: Target URL for navigation
96
- - selector: CSS selector for element targeting (e.g., "#id", ".class", "button[type='submit']")
97
- - text: Text content to type
98
- - output-path: File path for screenshots (kebab-case in XML, outputPath in JSON)
99
- - wait-time: Time to wait in milliseconds (100-30000, kebab-case in XML, waitTime in JSON)
100
- - wait-selector: Element selector to wait for (kebab-case in XML, waitSelector in JSON)
101
- - wait-type: Wait type - "visible" or "hidden" (default: "visible")
102
- - attribute: HTML attribute to extract (default: "text")
103
- - direction: Scroll direction - "up", "down", "left", "right"
104
- - pixels: Scroll distance in pixels (default: 300)
105
- - full-page: Take full page screenshot - "true" or "false"
106
-
107
- EXAMPLES:
108
-
109
- Example 1 - Research and screenshot:
110
- <browser>
111
- <navigate url="https://github.com/trending" />
112
- <wait wait-time="2000" />
113
- <screenshot output-path="trending.png" />
114
- <extract selector="h2.h3" attribute="text" />
115
- <close />
116
- </browser>
117
-
118
- Example 2 - Form automation:
119
- <browser>
120
- <navigate url="https://example.com/login" />
121
- <wait wait-selector="input#username" />
122
- <type selector="input#username" text="myuser" />
123
- <type selector="input#password" text="mypass" />
124
- <click selector="button[type='submit']" />
125
- <wait wait-selector=".success-message" />
126
- <close />
127
- </browser>
128
-
129
- Example 3 - Data extraction:
130
- <browser>
131
- <navigate url="https://example.com/products" />
132
- <wait wait-time="1000" />
133
- <extract selector="h1.product-title" attribute="text" />
134
- <extract selector="span.price" attribute="text" />
135
- <extract selector="img.product" attribute="src" />
136
- <close />
137
- </browser>
138
-
139
- Example 4 - Scrolling and waiting:
140
- <browser>
141
- <navigate url="https://example.com/long-page" />
142
- <scroll direction="down" pixels="500" />
143
- <wait wait-time="1000" />
144
- <scroll direction="down" pixels="500" />
145
- <screenshot output-path="scrolled.png" full-page="true" />
146
- <close />
147
- </browser>
148
-
149
- SYNTAX RULES:
150
- ✅ DO: <navigate url="..." /> (self-closing with />)
151
- ✅ DO: <navigate url="..."> (can omit /> if preferred)
152
- ❌ DON'T: <navigate url="..."></navigate> (no closing tag needed)
153
- ❌ DON'T: [navigate url="..." /] (square brackets not supported)
154
-
155
- ATTRIBUTE NAMING:
156
- - XML uses kebab-case: wait-time, output-path, wait-selector
157
- - JSON uses camelCase: waitTime, outputPath, waitSelector
158
- - Parser auto-converts kebab-case to camelCase internally
159
-
160
- SECURITY:
161
- - Restricted to allowed domains (if configured)
162
- - Blocked domains enforced for security
163
- - Screenshot size limits enforced (max 5MB)
164
- - Automatic cleanup of browser instances after 10 minutes
165
- - Sandboxed browser execution
166
-
167
- BROWSER SESSION:
168
- The tool maintains browser instances per agent context.
169
- Use <close /> action to explicitly cleanup, or instances auto-cleanup after timeout.
170
-
171
- VIEWPORT: ${this.browserConfig.viewport.width}x${this.browserConfig.viewport.height}
172
- TIMEOUT: ${this.browserConfig.timeout}ms per operation
173
- MAX WAIT TIME: 30 seconds (30000ms)
174
- `;
175
- }
176
-
177
- /**
178
- * Parse parameters from tool command content
179
- * @param {string} content - Raw tool command content
180
- * @returns {Object} Parsed parameters
181
- */
182
- parseParameters(content) {
183
- try {
184
- // Try JSON first (for JSON in code blocks)
185
- if (content.trim().startsWith('{')) {
186
- const parsed = JSON.parse(content);
187
- // Ensure actions is an array
188
- if (!parsed.actions) {
189
- parsed.actions = [];
190
- }
191
- if (!Array.isArray(parsed.actions)) {
192
- parsed.actions = [parsed.actions];
193
- }
194
- return parsed;
195
- }
196
-
197
- const params = {};
198
- const actions = [];
199
-
200
- // Extract self-closing tags (e.g., <navigate url="..." />)
201
- const selfClosingTags = [
202
- 'navigate', 'click', 'type', 'wait', 'screenshot',
203
- 'extract', 'scroll', 'close'
204
- ];
205
-
206
- for (const tagName of selfClosingTags) {
207
- // Extract self-closing tags using regex
208
- const selfClosingPattern = new RegExp(
209
- `<${tagName}\\s+([^>]*?)\\s*\\/?>`,
210
- 'gi'
211
- );
212
-
213
- let match;
214
- while ((match = selfClosingPattern.exec(content)) !== null) {
215
- const attributeString = match[1];
216
- const attributes = this.parseAttributes(attributeString);
217
-
218
- const action = {
219
- type: tagName,
220
- ...attributes
221
- };
222
-
223
- // Normalize common attribute names (kebab-case to camelCase)
224
- if (action['output-path']) {
225
- action.outputPath = action['output-path'];
226
- delete action['output-path'];
227
- }
228
- if (action['wait-time']) {
229
- action.waitTime = parseInt(action['wait-time'], 10);
230
- delete action['wait-time'];
231
- }
232
- if (action['wait-selector']) {
233
- action.waitSelector = action['wait-selector'];
234
- delete action['wait-selector'];
235
- }
236
- if (action['wait-type']) {
237
- action.waitType = action['wait-type'];
238
- delete action['wait-type'];
239
- }
240
- if (action['full-page']) {
241
- action.fullPage = action['full-page'] === 'true';
242
- delete action['full-page'];
243
- }
244
-
245
- actions.push(action);
246
- }
247
- }
248
-
249
- // Ensure actions is always an array (even if empty)
250
- params.actions = Array.isArray(actions) ? actions : [];
251
- params.rawContent = content.trim();
252
-
253
- return params;
254
-
255
- } catch (error) {
256
- // If JSON parsing fails, return a structure with empty actions
257
- // This prevents "actions is not iterable" errors
258
- this.logger?.error('Failed to parse browser parameters', { error: error.message });
259
- return {
260
- actions: [], // Always return an array
261
- rawContent: content.trim(),
262
- parseError: error.message
263
- };
264
- }
265
- }
266
-
267
- /**
268
- * Parse attributes from attribute string
269
- * @param {string} attributeString - String containing attributes
270
- * @returns {Object} Parsed attributes object
271
- * @private
272
- */
273
- parseAttributes(attributeString) {
274
- const attributes = {};
275
-
276
- if (!attributeString) return attributes;
277
-
278
- // Match attribute="value" or attribute='value'
279
- const attrPattern = /([\w-]+)\s*=\s*["']([^"']*)["']/g;
280
- let match;
281
-
282
- while ((match = attrPattern.exec(attributeString)) !== null) {
283
- const attrName = match[1];
284
- const attrValue = match[2];
285
- attributes[attrName] = attrValue;
286
- }
287
-
288
- return attributes;
289
- }
290
-
291
- /**
292
- * Get required parameters
293
- * @returns {Array<string>} Array of required parameter names
294
- */
295
- getRequiredParameters() {
296
- return ['actions'];
297
- }
298
-
299
- /**
300
- * Custom parameter validation
301
- * @param {Object} params - Parameters to validate
302
- * @returns {Object} Validation result
303
- */
304
- customValidateParameters(params) {
305
- const errors = [];
306
-
307
- if (!params.actions || !Array.isArray(params.actions) || params.actions.length === 0) {
308
- errors.push('At least one action is required');
309
- } else {
310
- // Validate each action
311
- for (const [index, action] of params.actions.entries()) {
312
- if (!action.type) {
313
- errors.push(`Action ${index + 1}: type is required`);
314
- continue;
315
- }
316
-
317
- switch (action.type) {
318
- case 'navigate':
319
- if (!action.url) {
320
- errors.push(`Action ${index + 1}: url is required for navigate`);
321
- } else if (!this.isAllowedUrl(action.url)) {
322
- errors.push(`Action ${index + 1}: URL not allowed: ${action.url}`);
323
- }
324
- break;
325
-
326
- case 'click':
327
- case 'extract':
328
- if (!action.selector) {
329
- errors.push(`Action ${index + 1}: selector is required for ${action.type}`);
330
- }
331
- break;
332
-
333
- case 'type':
334
- if (!action.selector) {
335
- errors.push(`Action ${index + 1}: selector is required for type`);
336
- }
337
- if (!action.text && action.text !== '') {
338
- errors.push(`Action ${index + 1}: text is required for type`);
339
- }
340
- break;
341
-
342
- case 'wait':
343
- if (!action.waitTime && !action.waitSelector) {
344
- errors.push(`Action ${index + 1}: either wait-time or wait-selector is required`);
345
- }
346
- if (action.waitTime && (action.waitTime < 100 || action.waitTime > 30000)) {
347
- errors.push(`Action ${index + 1}: wait-time must be between 100 and 30000 milliseconds`);
348
- }
349
- break;
350
-
351
- case 'screenshot':
352
- if (!action.outputPath) {
353
- errors.push(`Action ${index + 1}: output-path is required for screenshot`);
354
- }
355
- break;
356
-
357
- case 'scroll':
358
- if (!action.direction) {
359
- errors.push(`Action ${index + 1}: direction is required for scroll`);
360
- } else if (!['up', 'down', 'left', 'right'].includes(action.direction)) {
361
- errors.push(`Action ${index + 1}: invalid scroll direction: ${action.direction}`);
362
- }
363
- break;
364
-
365
- case 'close':
366
- // No additional validation needed
367
- break;
368
-
369
- default:
370
- errors.push(`Action ${index + 1}: unknown action type: ${action.type}`);
371
- }
372
- }
373
- }
374
-
375
- return {
376
- valid: errors.length === 0,
377
- errors
378
- };
379
- }
380
-
381
- /**
382
- * Execute tool with parsed parameters
383
- * @param {Object} params - Parsed parameters
384
- * @param {Object} context - Execution context
385
- * @returns {Promise<Object>} Execution result
386
- */
387
- async execute(params, context) {
388
- const { actions } = params;
389
- const { agentId, projectDir } = context;
390
-
391
- const browserKey = `${agentId}-${projectDir || 'default'}`;
392
- const results = [];
393
-
394
- for (const action of actions) {
395
- try {
396
- let result;
397
-
398
- switch (action.type) {
399
- case 'navigate':
400
- result = await this.navigate(action.url, browserKey);
401
- break;
402
-
403
- case 'click':
404
- result = await this.click(action.selector, browserKey);
405
- break;
406
-
407
- case 'type':
408
- result = await this.type(action.selector, action.text, browserKey);
409
- break;
410
-
411
- case 'wait':
412
- result = await this.wait(action, browserKey);
413
- break;
414
-
415
- case 'screenshot':
416
- result = await this.screenshot(action.outputPath, projectDir, browserKey, action);
417
- break;
418
-
419
- case 'extract':
420
- result = await this.extract(action.selector, action.attribute || 'text', browserKey);
421
- break;
422
-
423
- case 'scroll':
424
- result = await this.scroll(action, browserKey);
425
- break;
426
-
427
- case 'close':
428
- result = await this.closeBrowser(browserKey);
429
- break;
430
-
431
- default:
432
- throw new Error(`Unknown action type: ${action.type}`);
433
- }
434
-
435
- results.push(result);
436
- this.addToHistory(action, result, agentId);
437
-
438
- } catch (error) {
439
- const errorResult = {
440
- success: false,
441
- action: action.type,
442
- error: error.message,
443
- selector: action.selector || action.url
444
- };
445
-
446
- results.push(errorResult);
447
- this.addToHistory(action, errorResult, agentId);
448
- }
449
- }
450
-
451
- return {
452
- success: true,
453
- actions: results,
454
- executedActions: actions.length,
455
- toolUsed: 'browser'
456
- };
457
- }
458
-
459
- /**
460
- * Navigate to URL
461
- * @private
462
- */
463
- async navigate(url, browserKey) {
464
- const browser = await this.getBrowser(browserKey);
465
- const page = await this.getPage(browserKey);
466
-
467
- const startTime = Date.now();
468
-
469
- try {
470
- await page.goto(url, {
471
- waitUntil: 'networkidle0',
472
- timeout: this.browserConfig.timeout
473
- });
474
-
475
- const title = await page.title();
476
- const currentUrl = page.url();
477
-
478
- return {
479
- success: true,
480
- action: 'navigate',
481
- url: currentUrl,
482
- originalUrl: url,
483
- title,
484
- loadTime: Date.now() - startTime,
485
- message: `Navigated to ${url}`
486
- };
487
-
488
- } catch (error) {
489
- throw new Error(`Navigation failed: ${error.message}`);
490
- }
491
- }
492
-
493
- /**
494
- * Click on element
495
- * @private
496
- */
497
- async click(selector, browserKey) {
498
- const page = await this.getPage(browserKey);
499
-
500
- try {
501
- await page.waitForSelector(selector, { timeout: 5000 });
502
- await page.click(selector);
503
-
504
- return {
505
- success: true,
506
- action: 'click',
507
- selector,
508
- message: `Clicked on ${selector}`
509
- };
510
-
511
- } catch (error) {
512
- throw new Error(`Click failed on ${selector}: ${error.message}`);
513
- }
514
- }
515
-
516
- /**
517
- * Type text into element
518
- * @private
519
- */
520
- async type(selector, text, browserKey) {
521
- const page = await this.getPage(browserKey);
522
-
523
- try {
524
- await page.waitForSelector(selector, { timeout: 5000 });
525
- await page.focus(selector);
526
- await page.keyboard.selectAll();
527
- await page.type(selector, text);
528
-
529
- return {
530
- success: true,
531
- action: 'type',
532
- selector,
533
- text,
534
- textLength: text.length,
535
- message: `Typed ${text.length} characters into ${selector}`
536
- };
537
-
538
- } catch (error) {
539
- throw new Error(`Type failed on ${selector}: ${error.message}`);
540
- }
541
- }
542
-
543
- /**
544
- * Wait for condition
545
- * @private
546
- */
547
- async wait(action, browserKey) {
548
- const page = await this.getPage(browserKey);
549
-
550
- try {
551
- if (action.waitTime) {
552
- await page.waitForTimeout(action.waitTime);
553
- return {
554
- success: true,
555
- action: 'wait',
556
- waitTime: action.waitTime,
557
- message: `Waited ${action.waitTime}ms`
558
- };
559
- }
560
-
561
- if (action.waitSelector) {
562
- const waitType = action.waitType || 'visible';
563
- const options = { timeout: 10000 };
564
-
565
- if (waitType === 'hidden') {
566
- await page.waitForSelector(action.waitSelector, { ...options, hidden: true });
567
- } else {
568
- await page.waitForSelector(action.waitSelector, options);
569
- }
570
-
571
- return {
572
- success: true,
573
- action: 'wait',
574
- waitSelector: action.waitSelector,
575
- waitType,
576
- message: `Waited for ${action.waitSelector} to be ${waitType}`
577
- };
578
- }
579
-
580
- } catch (error) {
581
- throw new Error(`Wait failed: ${error.message}`);
582
- }
583
- }
584
-
585
- /**
586
- * Take screenshot
587
- * @private
588
- */
589
- async screenshot(outputPath, projectDir, browserKey, options = {}) {
590
- const page = await this.getPage(browserKey);
591
-
592
- try {
593
- const fullPath = projectDir ? path.resolve(projectDir, outputPath) : path.resolve(outputPath);
594
-
595
- // Ensure directory exists
596
- const dir = path.dirname(fullPath);
597
- await fs.mkdir(dir, { recursive: true });
598
-
599
- const screenshotOptions = {
600
- path: fullPath,
601
- type: 'png'
602
- };
603
-
604
- if (options.fullPage) {
605
- screenshotOptions.fullPage = true;
606
- }
607
-
608
- await page.screenshot(screenshotOptions);
609
-
610
- const stats = await fs.stat(fullPath);
611
-
612
- if (stats.size > this.maxScreenshotSize) {
613
- throw new Error(`Screenshot too large: ${stats.size} bytes (max ${this.maxScreenshotSize})`);
614
- }
615
-
616
- return {
617
- success: true,
618
- action: 'screenshot',
619
- outputPath: path.relative(projectDir || process.cwd(), fullPath),
620
- size: stats.size,
621
- fullPage: !!options.fullPage,
622
- message: `Screenshot saved: ${outputPath}`
623
- };
624
-
625
- } catch (error) {
626
- throw new Error(`Screenshot failed: ${error.message}`);
627
- }
628
- }
629
-
630
- /**
631
- * Extract data from elements
632
- * @private
633
- */
634
- async extract(selector, attribute, browserKey) {
635
- const page = await this.getPage(browserKey);
636
-
637
- try {
638
- await page.waitForSelector(selector, { timeout: 5000 });
639
-
640
- let data;
641
- if (attribute === 'text') {
642
- data = await page.$eval(selector, el => el.textContent.trim());
643
- } else {
644
- data = await page.$eval(selector, (el, attr) => el.getAttribute(attr), attribute);
645
- }
646
-
647
- return {
648
- success: true,
649
- action: 'extract',
650
- selector,
651
- attribute,
652
- data,
653
- message: `Extracted ${attribute} from ${selector}`
654
- };
655
-
656
- } catch (error) {
657
- throw new Error(`Extract failed on ${selector}: ${error.message}`);
658
- }
659
- }
660
-
661
- /**
662
- * Scroll page or element
663
- * @private
664
- */
665
- async scroll(action, browserKey) {
666
- const page = await this.getPage(browserKey);
667
-
668
- try {
669
- const { direction, pixels = 300, selector } = action;
670
-
671
- if (selector) {
672
- // Scroll specific element
673
- await page.evaluate((sel, dir, px) => {
674
- const element = document.querySelector(sel);
675
- if (element) {
676
- if (dir === 'down') element.scrollTop += px;
677
- else if (dir === 'up') element.scrollTop -= px;
678
- else if (dir === 'right') element.scrollLeft += px;
679
- else if (dir === 'left') element.scrollLeft -= px;
680
- }
681
- }, selector, direction, pixels);
682
- } else {
683
- // Scroll page
684
- await page.evaluate((dir, px) => {
685
- if (dir === 'down') window.scrollBy(0, px);
686
- else if (dir === 'up') window.scrollBy(0, -px);
687
- else if (dir === 'right') window.scrollBy(px, 0);
688
- else if (dir === 'left') window.scrollBy(-px, 0);
689
- }, direction, pixels);
690
- }
691
-
692
- return {
693
- success: true,
694
- action: 'scroll',
695
- direction,
696
- pixels,
697
- selector: selector || 'page',
698
- message: `Scrolled ${direction} by ${pixels}px`
699
- };
700
-
701
- } catch (error) {
702
- throw new Error(`Scroll failed: ${error.message}`);
703
- }
704
- }
705
-
706
- /**
707
- * Get or create browser instance
708
- * @private
709
- */
710
- async getBrowser(browserKey) {
711
- if (this.browserInstances.has(browserKey)) {
712
- const instance = this.browserInstances.get(browserKey);
713
- if (!instance.browser.isConnected()) {
714
- this.browserInstances.delete(browserKey);
715
- } else {
716
- return instance.browser;
717
- }
718
- }
719
-
720
- const browser = await puppeteer.launch({
721
- headless: this.browserConfig.headless,
722
- args: [
723
- '--no-sandbox',
724
- '--disable-setuid-sandbox',
725
- '--disable-dev-shm-usage',
726
- '--disable-gpu'
727
- ]
728
- });
729
-
730
- const page = await browser.newPage();
731
- await page.setViewport(this.browserConfig.viewport);
732
- await page.setUserAgent(this.browserConfig.userAgent);
733
-
734
- this.browserInstances.set(browserKey, {
735
- browser,
736
- page,
737
- created: Date.now()
738
- });
739
-
740
- // Auto-cleanup after 10 minutes of inactivity
741
- setTimeout(() => {
742
- this.cleanupBrowser(browserKey);
743
- }, 10 * 60 * 1000);
744
-
745
- return browser;
746
- }
747
-
748
- /**
749
- * Get page instance
750
- * @private
751
- */
752
- async getPage(browserKey) {
753
- await this.getBrowser(browserKey);
754
- return this.browserInstances.get(browserKey).page;
755
- }
756
-
757
- /**
758
- * Close browser instance
759
- * @private
760
- */
761
- async closeBrowser(browserKey) {
762
- const instance = this.browserInstances.get(browserKey);
763
-
764
- if (instance) {
765
- try {
766
- await instance.browser.close();
767
- this.browserInstances.delete(browserKey);
768
-
769
- return {
770
- success: true,
771
- action: 'close',
772
- browserKey,
773
- message: 'Browser instance closed'
774
- };
775
- } catch (error) {
776
- throw new Error(`Failed to close browser: ${error.message}`);
777
- }
778
- }
779
-
780
- return {
781
- success: true,
782
- action: 'close',
783
- browserKey,
784
- message: 'Browser instance not found (already closed)'
785
- };
786
- }
787
-
788
- /**
789
- * Cleanup browser instance
790
- * @private
791
- */
792
- async cleanupBrowser(browserKey) {
793
- const instance = this.browserInstances.get(browserKey);
794
-
795
- if (instance) {
796
- try {
797
- await instance.browser.close();
798
- } catch (error) {
799
- // Ignore cleanup errors
800
- } finally {
801
- this.browserInstances.delete(browserKey);
802
- }
803
- }
804
- }
805
-
806
- /**
807
- * Check if URL is allowed
808
- * @private
809
- */
810
- isAllowedUrl(url) {
811
- try {
812
- const urlObj = new URL(url);
813
- const hostname = urlObj.hostname.toLowerCase();
814
-
815
- // Check blocked domains
816
- if (this.blockedDomains.some(blocked => hostname.includes(blocked.toLowerCase()))) {
817
- return false;
818
- }
819
-
820
- // Check allowed domains if specified
821
- if (this.allowedDomains && this.allowedDomains.length > 0) {
822
- return this.allowedDomains.some(allowed => hostname.includes(allowed.toLowerCase()));
823
- }
824
-
825
- return true;
826
- } catch {
827
- return false;
828
- }
829
- }
830
-
831
- /**
832
- * Add operation to history
833
- * @private
834
- */
835
- addToHistory(action, result, agentId) {
836
- const historyEntry = {
837
- timestamp: new Date().toISOString(),
838
- agentId,
839
- action: action.type,
840
- selector: action.selector || action.url,
841
- success: result.success,
842
- loadTime: result.loadTime || 0
843
- };
844
-
845
- this.operationHistory.push(historyEntry);
846
-
847
- // Keep only last 100 entries
848
- if (this.operationHistory.length > 100) {
849
- this.operationHistory = this.operationHistory.slice(-100);
850
- }
851
- }
852
-
853
- /**
854
- * Get supported actions for this tool
855
- * @returns {Array<string>} Array of supported action names
856
- */
857
- getSupportedActions() {
858
- return ['navigate', 'click', 'type', 'wait', 'screenshot', 'extract', 'scroll', 'close'];
859
- }
860
-
861
- /**
862
- * Get parameter schema for validation
863
- * @returns {Object} Parameter schema
864
- */
865
- getParameterSchema() {
866
- return {
867
- type: 'object',
868
- properties: {
869
- actions: {
870
- type: 'array',
871
- minItems: 1,
872
- items: {
873
- type: 'object',
874
- properties: {
875
- type: {
876
- type: 'string',
877
- enum: this.getSupportedActions()
878
- },
879
- url: { type: 'string' },
880
- selector: { type: 'string' },
881
- text: { type: 'string' },
882
- outputPath: { type: 'string' },
883
- waitTime: { type: 'integer' },
884
- waitSelector: { type: 'string' },
885
- attribute: { type: 'string' },
886
- direction: { type: 'string' },
887
- pixels: { type: 'integer' }
888
- },
889
- required: ['type']
890
- }
891
- }
892
- },
893
- required: ['actions']
894
- };
895
- }
896
-
897
- /**
898
- * Resource cleanup
899
- * @param {string} operationId - Operation identifier
900
- */
901
- async cleanup(operationId) {
902
- // Close all browser instances
903
- for (const [browserKey] of this.browserInstances) {
904
- await this.cleanupBrowser(browserKey);
905
- }
906
- }
907
-
908
- /**
909
- * Get operation history for debugging
910
- * @returns {Array} Operation history
911
- */
912
- getOperationHistory(agentId = null) {
913
- if (agentId) {
914
- return this.operationHistory.filter(entry => entry.agentId === agentId);
915
- }
916
- return [...this.operationHistory];
917
- }
918
- }
919
-
920
- export default BrowserTool;
1
+ const a0_0x546e41=a0_0x2727;(function(_0x3e69fa,_0x5d5338){const _0x54db74=a0_0x2727,_0x15bfb0=_0x3e69fa();while(!![]){try{const _0xb9983c=-parseInt(_0x54db74(0xff))/0x1*(-parseInt(_0x54db74(0x12d))/0x2)+parseInt(_0x54db74(0x100))/0x3*(parseInt(_0x54db74(0x114))/0x4)+-parseInt(_0x54db74(0x125))/0x5*(parseInt(_0x54db74(0xdc))/0x6)+parseInt(_0x54db74(0xd3))/0x7+parseInt(_0x54db74(0x13d))/0x8+-parseInt(_0x54db74(0x119))/0x9*(-parseInt(_0x54db74(0x103))/0xa)+-parseInt(_0x54db74(0xf5))/0xb;if(_0xb9983c===_0x5d5338)break;else _0x15bfb0['push'](_0x15bfb0['shift']());}catch(_0x4ba9ad){_0x15bfb0['push'](_0x15bfb0['shift']());}}}(a0_0x5638,0xbb214));import{BaseTool}from'./baseTool.js';import a0_0x4bf1a5 from'../utilities/tagParser.js';import a0_0x367d2a from'puppeteer';import a0_0x2a2cf4 from'fs/promises';import a0_0x5aa45f from'path';import{TOOL_STATUS,SYSTEM_DEFAULTS}from'../utilities/constants.js';class BrowserTool extends BaseTool{constructor(_0x4b9f5a={},_0x4959b9=null){const _0x15ccb8=a0_0x2727;super(_0x4b9f5a,_0x4959b9),this[_0x15ccb8(0x123)]=![],this[_0x15ccb8(0xe8)]=!![],this['timeout']=_0x4b9f5a[_0x15ccb8(0xd4)]||0xea60,this[_0x15ccb8(0xd8)]=_0x4b9f5a['maxConcurrentOperations']||0x2,this[_0x15ccb8(0xf4)]={'headless':_0x4b9f5a['headless']!==![],'viewport':_0x4b9f5a['viewport']||{'width':0x500,'height':0x2d0},'userAgent':_0x4b9f5a['userAgent']||_0x15ccb8(0xf1),'timeout':_0x4b9f5a[_0x15ccb8(0x107)]||0x7530},this['browserInstances']=new Map(),this[_0x15ccb8(0x10d)]=_0x4b9f5a['allowedDomains']||null,this[_0x15ccb8(0x137)]=_0x4b9f5a['blockedDomains']||[],this['maxScreenshotSize']=_0x4b9f5a[_0x15ccb8(0x11d)]||0x5*0x400*0x400,this[_0x15ccb8(0xe9)]=[];}['getDescription'](){const _0x2e1350=a0_0x2727;return'\x0aBrowser\x20Tool:\x20Automate\x20web\x20browser\x20interactions,\x20navigation,\x20and\x20data\x20extraction.\x0a\x0aIMPORTANT\x20-\x20SYNTAX:\x20Use\x20self-closing\x20tags\x20with\x20angle\x20brackets\x20<\x20>,\x20not\x20square\x20brackets\x20[\x20].\x0a\x0aXML\x20USAGE\x20(Recommended):\x0a<browser>\x0a\x20\x20<navigate\x20url=\x22https://example.com\x22\x20/>\x0a\x20\x20<wait\x20wait-time=\x222000\x22\x20/>\x0a\x20\x20<click\x20selector=\x22button.submit\x22\x20/>\x0a\x20\x20<screenshot\x20output-path=\x22screenshot.png\x22\x20/>\x0a</browser>\x0a\x0aJSON\x20USAGE\x20(Alternative):\x0a```json\x0a{\x0a\x20\x20\x22toolId\x22:\x20\x22browser\x22,\x0a\x20\x20\x22actions\x22:\x20[\x0a\x20\x20\x20\x20{\x20\x22type\x22:\x20\x22navigate\x22,\x20\x22url\x22:\x20\x22https://example.com\x22\x20},\x0a\x20\x20\x20\x20{\x20\x22type\x22:\x20\x22wait\x22,\x20\x22waitTime\x22:\x202000\x20},\x0a\x20\x20\x20\x20{\x20\x22type\x22:\x20\x22click\x22,\x20\x22selector\x22:\x20\x22button.submit\x22\x20},\x0a\x20\x20\x20\x20{\x20\x22type\x22:\x20\x22screenshot\x22,\x20\x22outputPath\x22:\x20\x22screenshot.png\x22\x20}\x0a\x20\x20]\x0a}\x0a```\x0a\x0aSUPPORTED\x20ACTIONS:\x0a-\x20navigate:\x20Navigate\x20to\x20a\x20URL\x20(requires:\x20url)\x0a-\x20click:\x20Click\x20on\x20an\x20element\x20(requires:\x20selector)\x0a-\x20type:\x20Type\x20text\x20into\x20an\x20input\x20field\x20(requires:\x20selector,\x20text)\x0a-\x20wait:\x20Wait\x20for\x20element\x20or\x20time\x20(requires:\x20wait-time\x20OR\x20wait-selector)\x0a-\x20screenshot:\x20Take\x20screenshot\x20of\x20page\x20(requires:\x20output-path)\x0a-\x20extract:\x20Extract\x20text/data\x20from\x20elements\x20(requires:\x20selector,\x20attribute)\x0a-\x20scroll:\x20Scroll\x20page\x20or\x20element\x20(requires:\x20direction)\x0a-\x20close:\x20Close\x20browser\x20instance\x20(no\x20parameters)\x0a\x0aPARAMETER\x20REFERENCE:\x0a-\x20url:\x20Target\x20URL\x20for\x20navigation\x0a-\x20selector:\x20CSS\x20selector\x20for\x20element\x20targeting\x20(e.g.,\x20\x22#id\x22,\x20\x22.class\x22,\x20\x22button[type=\x27submit\x27]\x22)\x0a-\x20text:\x20Text\x20content\x20to\x20type\x0a-\x20output-path:\x20File\x20path\x20for\x20screenshots\x20(kebab-case\x20in\x20XML,\x20outputPath\x20in\x20JSON)\x0a-\x20wait-time:\x20Time\x20to\x20wait\x20in\x20milliseconds\x20(100-30000,\x20kebab-case\x20in\x20XML,\x20waitTime\x20in\x20JSON)\x0a-\x20wait-selector:\x20Element\x20selector\x20to\x20wait\x20for\x20(kebab-case\x20in\x20XML,\x20waitSelector\x20in\x20JSON)\x0a-\x20wait-type:\x20Wait\x20type\x20-\x20\x22visible\x22\x20or\x20\x22hidden\x22\x20(default:\x20\x22visible\x22)\x0a-\x20attribute:\x20HTML\x20attribute\x20to\x20extract\x20(default:\x20\x22text\x22)\x0a-\x20direction:\x20Scroll\x20direction\x20-\x20\x22up\x22,\x20\x22down\x22,\x20\x22left\x22,\x20\x22right\x22\x0a-\x20pixels:\x20Scroll\x20distance\x20in\x20pixels\x20(default:\x20300)\x0a-\x20full-page:\x20Take\x20full\x20page\x20screenshot\x20-\x20\x22true\x22\x20or\x20\x22false\x22\x0a\x0aEXAMPLES:\x0a\x0aExample\x201\x20-\x20Research\x20and\x20screenshot:\x0a<browser>\x0a\x20\x20<navigate\x20url=\x22https://github.com/trending\x22\x20/>\x0a\x20\x20<wait\x20wait-time=\x222000\x22\x20/>\x0a\x20\x20<screenshot\x20output-path=\x22trending.png\x22\x20/>\x0a\x20\x20<extract\x20selector=\x22h2.h3\x22\x20attribute=\x22text\x22\x20/>\x0a\x20\x20<close\x20/>\x0a</browser>\x0a\x0aExample\x202\x20-\x20Form\x20automation:\x0a<browser>\x0a\x20\x20<navigate\x20url=\x22https://example.com/login\x22\x20/>\x0a\x20\x20<wait\x20wait-selector=\x22input#username\x22\x20/>\x0a\x20\x20<type\x20selector=\x22input#username\x22\x20text=\x22myuser\x22\x20/>\x0a\x20\x20<type\x20selector=\x22input#password\x22\x20text=\x22mypass\x22\x20/>\x0a\x20\x20<click\x20selector=\x22button[type=\x27submit\x27]\x22\x20/>\x0a\x20\x20<wait\x20wait-selector=\x22.success-message\x22\x20/>\x0a\x20\x20<close\x20/>\x0a</browser>\x0a\x0aExample\x203\x20-\x20Data\x20extraction:\x0a<browser>\x0a\x20\x20<navigate\x20url=\x22https://example.com/products\x22\x20/>\x0a\x20\x20<wait\x20wait-time=\x221000\x22\x20/>\x0a\x20\x20<extract\x20selector=\x22h1.product-title\x22\x20attribute=\x22text\x22\x20/>\x0a\x20\x20<extract\x20selector=\x22span.price\x22\x20attribute=\x22text\x22\x20/>\x0a\x20\x20<extract\x20selector=\x22img.product\x22\x20attribute=\x22src\x22\x20/>\x0a\x20\x20<close\x20/>\x0a</browser>\x0a\x0aExample\x204\x20-\x20Scrolling\x20and\x20waiting:\x0a<browser>\x0a\x20\x20<navigate\x20url=\x22https://example.com/long-page\x22\x20/>\x0a\x20\x20<scroll\x20direction=\x22down\x22\x20pixels=\x22500\x22\x20/>\x0a\x20\x20<wait\x20wait-time=\x221000\x22\x20/>\x0a\x20\x20<scroll\x20direction=\x22down\x22\x20pixels=\x22500\x22\x20/>\x0a\x20\x20<screenshot\x20output-path=\x22scrolled.png\x22\x20full-page=\x22true\x22\x20/>\x0a\x20\x20<close\x20/>\x0a</browser>\x0a\x0aSYNTAX\x20RULES:\x0a✅\x20DO:\x20<navigate\x20url=\x22...\x22\x20/>\x20\x20(self-closing\x20with\x20/>)\x0a✅\x20DO:\x20<navigate\x20url=\x22...\x22>\x20\x20\x20\x20\x20(can\x20omit\x20/>\x20if\x20preferred)\x0a❌\x20DON\x27T:\x20<navigate\x20url=\x22...\x22></navigate>\x20\x20(no\x20closing\x20tag\x20needed)\x0a❌\x20DON\x27T:\x20[navigate\x20url=\x22...\x22\x20/]\x20\x20(square\x20brackets\x20not\x20supported)\x0a\x0aATTRIBUTE\x20NAMING:\x0a-\x20XML\x20uses\x20kebab-case:\x20wait-time,\x20output-path,\x20wait-selector\x0a-\x20JSON\x20uses\x20camelCase:\x20waitTime,\x20outputPath,\x20waitSelector\x0a-\x20Parser\x20auto-converts\x20kebab-case\x20to\x20camelCase\x20internally\x0a\x0aSECURITY:\x0a-\x20Restricted\x20to\x20allowed\x20domains\x20(if\x20configured)\x0a-\x20Blocked\x20domains\x20enforced\x20for\x20security\x0a-\x20Screenshot\x20size\x20limits\x20enforced\x20(max\x205MB)\x0a-\x20Automatic\x20cleanup\x20of\x20browser\x20instances\x20after\x2010\x20minutes\x0a-\x20Sandboxed\x20browser\x20execution\x0a\x0aBROWSER\x20SESSION:\x0aThe\x20tool\x20maintains\x20browser\x20instances\x20per\x20agent\x20context.\x0aUse\x20<close\x20/>\x20action\x20to\x20explicitly\x20cleanup,\x20or\x20instances\x20auto-cleanup\x20after\x20timeout.\x0a\x0aVIEWPORT:\x20'+this['browserConfig']['viewport']['width']+'x'+this[_0x2e1350(0xf4)]['viewport'][_0x2e1350(0x14a)]+'\x0aTIMEOUT:\x20'+this['browserConfig'][_0x2e1350(0xd4)]+_0x2e1350(0x118);}[a0_0x546e41(0x143)](_0x5d497c){const _0x1c771c=a0_0x546e41;try{if(_0x5d497c['trim']()[_0x1c771c(0x112)]('{')){const _0x27116a=JSON[_0x1c771c(0xde)](_0x5d497c);return!_0x27116a['actions']&&(_0x27116a['actions']=[]),!Array['isArray'](_0x27116a[_0x1c771c(0x12e)])&&(_0x27116a[_0x1c771c(0x12e)]=[_0x27116a['actions']]),_0x27116a;}const _0x3ff084={},_0x351b2d=[],_0x27873c=[_0x1c771c(0x12c),_0x1c771c(0x134),_0x1c771c(0x148),'wait','screenshot','extract',_0x1c771c(0x147),'close'];for(const _0x271972 of _0x27873c){const _0x1c83de=new RegExp('<'+_0x271972+'\x5cs+([^>]*?)\x5cs*\x5c/?>','gi');let _0x1689b4;while((_0x1689b4=_0x1c83de[_0x1c771c(0x129)](_0x5d497c))!==null){const _0x5dd8dc=_0x1689b4[0x1],_0x638b0=this['parseAttributes'](_0x5dd8dc),_0x59b467={'type':_0x271972,..._0x638b0};_0x59b467['output-path']&&(_0x59b467[_0x1c771c(0x13e)]=_0x59b467['output-path'],delete _0x59b467[_0x1c771c(0x10c)]),_0x59b467['wait-time']&&(_0x59b467['waitTime']=parseInt(_0x59b467[_0x1c771c(0x141)],0xa),delete _0x59b467[_0x1c771c(0x141)]),_0x59b467['wait-selector']&&(_0x59b467[_0x1c771c(0x14b)]=_0x59b467[_0x1c771c(0xe1)],delete _0x59b467[_0x1c771c(0xe1)]),_0x59b467[_0x1c771c(0x138)]&&(_0x59b467['waitType']=_0x59b467['wait-type'],delete _0x59b467['wait-type']),_0x59b467[_0x1c771c(0xf8)]&&(_0x59b467[_0x1c771c(0xf6)]=_0x59b467[_0x1c771c(0xf8)]===_0x1c771c(0x13a),delete _0x59b467[_0x1c771c(0xf8)]),_0x351b2d['push'](_0x59b467);}}return _0x3ff084[_0x1c771c(0x12e)]=Array['isArray'](_0x351b2d)?_0x351b2d:[],_0x3ff084[_0x1c771c(0xfd)]=_0x5d497c['trim'](),_0x3ff084;}catch(_0x54dd84){return this['logger']?.['error'](_0x1c771c(0x14c),{'error':_0x54dd84['message']}),{'actions':[],'rawContent':_0x5d497c['trim'](),'parseError':_0x54dd84[_0x1c771c(0x117)]};}}[a0_0x546e41(0xd7)](_0x18217d){const _0x1ab79c={};if(!_0x18217d)return _0x1ab79c;const _0x4281d3=/([\w-]+)\s*=\s*["']([^"']*)["']/g;let _0x1e5ab5;while((_0x1e5ab5=_0x4281d3['exec'](_0x18217d))!==null){const _0x31d910=_0x1e5ab5[0x1],_0x473867=_0x1e5ab5[0x2];_0x1ab79c[_0x31d910]=_0x473867;}return _0x1ab79c;}['getRequiredParameters'](){const _0x37b9b3=a0_0x546e41;return[_0x37b9b3(0x12e)];}[a0_0x546e41(0x146)](_0x343812){const _0x4ed62e=a0_0x546e41,_0x53d6cd=[];if(!_0x343812['actions']||!Array['isArray'](_0x343812['actions'])||_0x343812['actions']['length']===0x0)_0x53d6cd['push']('At\x20least\x20one\x20action\x20is\x20required');else for(const [_0x21ac65,_0xc8a1a7]of _0x343812['actions'][_0x4ed62e(0xf2)]()){if(!_0xc8a1a7['type']){_0x53d6cd[_0x4ed62e(0x127)]('Action\x20'+(_0x21ac65+0x1)+':\x20type\x20is\x20required');continue;}switch(_0xc8a1a7['type']){case'navigate':if(!_0xc8a1a7[_0x4ed62e(0xf3)])_0x53d6cd['push'](_0x4ed62e(0xd5)+(_0x21ac65+0x1)+_0x4ed62e(0x126));else!this[_0x4ed62e(0xe6)](_0xc8a1a7['url'])&&_0x53d6cd['push']('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0x110)+_0xc8a1a7[_0x4ed62e(0xf3)]);break;case _0x4ed62e(0x134):case'extract':!_0xc8a1a7[_0x4ed62e(0x128)]&&_0x53d6cd[_0x4ed62e(0x127)]('Action\x20'+(_0x21ac65+0x1)+':\x20selector\x20is\x20required\x20for\x20'+_0xc8a1a7[_0x4ed62e(0x148)]);break;case _0x4ed62e(0x148):!_0xc8a1a7['selector']&&_0x53d6cd[_0x4ed62e(0x127)](_0x4ed62e(0xd5)+(_0x21ac65+0x1)+_0x4ed62e(0x11a));!_0xc8a1a7[_0x4ed62e(0x106)]&&_0xc8a1a7[_0x4ed62e(0x106)]!==''&&_0x53d6cd['push']('Action\x20'+(_0x21ac65+0x1)+':\x20text\x20is\x20required\x20for\x20type');break;case'wait':!_0xc8a1a7[_0x4ed62e(0x11f)]&&!_0xc8a1a7[_0x4ed62e(0x14b)]&&_0x53d6cd[_0x4ed62e(0x127)]('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0xed));_0xc8a1a7['waitTime']&&(_0xc8a1a7[_0x4ed62e(0x11f)]<0x64||_0xc8a1a7['waitTime']>0x7530)&&_0x53d6cd['push']('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0x130));break;case _0x4ed62e(0x108):!_0xc8a1a7[_0x4ed62e(0x13e)]&&_0x53d6cd[_0x4ed62e(0x127)]('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0xe3));break;case _0x4ed62e(0x147):if(!_0xc8a1a7[_0x4ed62e(0x11c)])_0x53d6cd[_0x4ed62e(0x127)]('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0x113));else!['up','down',_0x4ed62e(0x14e),_0x4ed62e(0x104)][_0x4ed62e(0xe4)](_0xc8a1a7[_0x4ed62e(0x11c)])&&_0x53d6cd['push']('Action\x20'+(_0x21ac65+0x1)+':\x20invalid\x20scroll\x20direction:\x20'+_0xc8a1a7['direction']);break;case'close':break;default:_0x53d6cd['push']('Action\x20'+(_0x21ac65+0x1)+_0x4ed62e(0xfe)+_0xc8a1a7['type']);}}return{'valid':_0x53d6cd[_0x4ed62e(0x140)]===0x0,'errors':_0x53d6cd};}async[a0_0x546e41(0x13f)](_0x10265a,_0x4be34b){const _0x56ec34=a0_0x546e41,{actions:_0x126887}=_0x10265a,{agentId:_0x424058,projectDir:_0x137034}=_0x4be34b,_0xaf52fe=_0x424058+'-'+(_0x137034||'default'),_0x1ebc5d=[];for(const _0x41b421 of _0x126887){try{let _0x3eb3de;switch(_0x41b421['type']){case _0x56ec34(0x12c):_0x3eb3de=await this[_0x56ec34(0x12c)](_0x41b421[_0x56ec34(0xf3)],_0xaf52fe);break;case _0x56ec34(0x134):_0x3eb3de=await this[_0x56ec34(0x134)](_0x41b421[_0x56ec34(0x128)],_0xaf52fe);break;case _0x56ec34(0x148):_0x3eb3de=await this['type'](_0x41b421['selector'],_0x41b421[_0x56ec34(0x106)],_0xaf52fe);break;case'wait':_0x3eb3de=await this[_0x56ec34(0x109)](_0x41b421,_0xaf52fe);break;case'screenshot':_0x3eb3de=await this[_0x56ec34(0x108)](_0x41b421['outputPath'],_0x137034,_0xaf52fe,_0x41b421);break;case'extract':_0x3eb3de=await this[_0x56ec34(0x150)](_0x41b421[_0x56ec34(0x128)],_0x41b421['attribute']||_0x56ec34(0x106),_0xaf52fe);break;case'scroll':_0x3eb3de=await this[_0x56ec34(0x147)](_0x41b421,_0xaf52fe);break;case _0x56ec34(0x12b):_0x3eb3de=await this['closeBrowser'](_0xaf52fe);break;default:throw new Error('Unknown\x20action\x20type:\x20'+_0x41b421[_0x56ec34(0x148)]);}_0x1ebc5d['push'](_0x3eb3de),this['addToHistory'](_0x41b421,_0x3eb3de,_0x424058);}catch(_0x216c88){const _0xfcf1ba={'success':![],'action':_0x41b421['type'],'error':_0x216c88['message'],'selector':_0x41b421['selector']||_0x41b421[_0x56ec34(0xf3)]};_0x1ebc5d[_0x56ec34(0x127)](_0xfcf1ba),this['addToHistory'](_0x41b421,_0xfcf1ba,_0x424058);}}return{'success':!![],'actions':_0x1ebc5d,'executedActions':_0x126887[_0x56ec34(0x140)],'toolUsed':_0x56ec34(0xef)};}async[a0_0x546e41(0x12c)](_0x2fbab5,_0x191722){const _0x52e862=a0_0x546e41,_0xdb8a50=await this[_0x52e862(0xd9)](_0x191722),_0x5822b9=await this['getPage'](_0x191722),_0x5c1f4b=Date[_0x52e862(0x111)]();try{await _0x5822b9[_0x52e862(0x12f)](_0x2fbab5,{'waitUntil':'networkidle0','timeout':this['browserConfig'][_0x52e862(0xd4)]});const _0x3a3377=await _0x5822b9['title'](),_0x4ffbcd=_0x5822b9['url']();return{'success':!![],'action':_0x52e862(0x12c),'url':_0x4ffbcd,'originalUrl':_0x2fbab5,'title':_0x3a3377,'loadTime':Date['now']()-_0x5c1f4b,'message':_0x52e862(0xfc)+_0x2fbab5};}catch(_0x1c849e){throw new Error('Navigation\x20failed:\x20'+_0x1c849e['message']);}}async[a0_0x546e41(0x134)](_0xb44d68,_0x5646b3){const _0xf9354e=a0_0x546e41,_0x1c4dd1=await this[_0xf9354e(0x13c)](_0x5646b3);try{return await _0x1c4dd1[_0xf9354e(0xf9)](_0xb44d68,{'timeout':0x1388}),await _0x1c4dd1['click'](_0xb44d68),{'success':!![],'action':'click','selector':_0xb44d68,'message':'Clicked\x20on\x20'+_0xb44d68};}catch(_0x3e9292){throw new Error(_0xf9354e(0x11e)+_0xb44d68+':\x20'+_0x3e9292[_0xf9354e(0x117)]);}}async['type'](_0x311bed,_0x199a4a,_0x2ec704){const _0x343bf3=a0_0x546e41,_0xc5a2ba=await this['getPage'](_0x2ec704);try{return await _0xc5a2ba['waitForSelector'](_0x311bed,{'timeout':0x1388}),await _0xc5a2ba[_0x343bf3(0xee)](_0x311bed),await _0xc5a2ba['keyboard'][_0x343bf3(0x11b)](),await _0xc5a2ba['type'](_0x311bed,_0x199a4a),{'success':!![],'action':'type','selector':_0x311bed,'text':_0x199a4a,'textLength':_0x199a4a['length'],'message':'Typed\x20'+_0x199a4a['length']+_0x343bf3(0xdb)+_0x311bed};}catch(_0x1633be){throw new Error('Type\x20failed\x20on\x20'+_0x311bed+':\x20'+_0x1633be['message']);}}async['wait'](_0x26c69f,_0x3e602d){const _0x50250e=a0_0x546e41,_0x5c91a7=await this[_0x50250e(0x13c)](_0x3e602d);try{if(_0x26c69f['waitTime'])return await _0x5c91a7['waitForTimeout'](_0x26c69f[_0x50250e(0x11f)]),{'success':!![],'action':'wait','waitTime':_0x26c69f[_0x50250e(0x11f)],'message':_0x50250e(0xd2)+_0x26c69f[_0x50250e(0x11f)]+'ms'};if(_0x26c69f[_0x50250e(0x14b)]){const _0x48f0d3=_0x26c69f[_0x50250e(0x12a)]||'visible',_0xb92b5b={'timeout':0x2710};return _0x48f0d3==='hidden'?await _0x5c91a7[_0x50250e(0xf9)](_0x26c69f['waitSelector'],{..._0xb92b5b,'hidden':!![]}):await _0x5c91a7['waitForSelector'](_0x26c69f[_0x50250e(0x14b)],_0xb92b5b),{'success':!![],'action':_0x50250e(0x109),'waitSelector':_0x26c69f[_0x50250e(0x14b)],'waitType':_0x48f0d3,'message':_0x50250e(0x14d)+_0x26c69f['waitSelector']+'\x20to\x20be\x20'+_0x48f0d3};}}catch(_0x48cbad){throw new Error(_0x50250e(0x10f)+_0x48cbad['message']);}}async[a0_0x546e41(0x108)](_0x2d0807,_0x3ce0b0,_0x4b7b81,_0x25b3bb={}){const _0x525591=a0_0x546e41,_0x19e568=await this[_0x525591(0x13c)](_0x4b7b81);try{const _0x408a9d=_0x3ce0b0?a0_0x5aa45f[_0x525591(0xfb)](_0x3ce0b0,_0x2d0807):a0_0x5aa45f[_0x525591(0xfb)](_0x2d0807),_0x228a61=a0_0x5aa45f['dirname'](_0x408a9d);await a0_0x2a2cf4[_0x525591(0x142)](_0x228a61,{'recursive':!![]});const _0x2669d0={'path':_0x408a9d,'type':'png'};_0x25b3bb[_0x525591(0xf6)]&&(_0x2669d0[_0x525591(0xf6)]=!![]);await _0x19e568['screenshot'](_0x2669d0);const _0x8b74ec=await a0_0x2a2cf4['stat'](_0x408a9d);if(_0x8b74ec['size']>this['maxScreenshotSize'])throw new Error(_0x525591(0xe0)+_0x8b74ec['size']+_0x525591(0x145)+this[_0x525591(0x11d)]+')');return{'success':!![],'action':'screenshot','outputPath':a0_0x5aa45f[_0x525591(0x116)](_0x3ce0b0||process['cwd'](),_0x408a9d),'size':_0x8b74ec['size'],'fullPage':!!_0x25b3bb[_0x525591(0xf6)],'message':'Screenshot\x20saved:\x20'+_0x2d0807};}catch(_0x177b5d){throw new Error(_0x525591(0x10b)+_0x177b5d[_0x525591(0x117)]);}}async['extract'](_0x53a689,_0x222996,_0x3074de){const _0x556ccc=a0_0x546e41,_0x44e409=await this[_0x556ccc(0x13c)](_0x3074de);try{await _0x44e409[_0x556ccc(0xf9)](_0x53a689,{'timeout':0x1388});let _0x417c30;return _0x222996==='text'?_0x417c30=await _0x44e409[_0x556ccc(0x133)](_0x53a689,_0x588fa6=>_0x588fa6[_0x556ccc(0x135)][_0x556ccc(0x14f)]()):_0x417c30=await _0x44e409['$eval'](_0x53a689,(_0x1093d0,_0x3827e8)=>_0x1093d0['getAttribute'](_0x3827e8),_0x222996),{'success':!![],'action':_0x556ccc(0x150),'selector':_0x53a689,'attribute':_0x222996,'data':_0x417c30,'message':_0x556ccc(0x10e)+_0x222996+'\x20from\x20'+_0x53a689};}catch(_0x4bc559){throw new Error('Extract\x20failed\x20on\x20'+_0x53a689+':\x20'+_0x4bc559['message']);}}async[a0_0x546e41(0x147)](_0x19debc,_0x1c31e3){const _0x4c4d6c=a0_0x546e41,_0x2508da=await this['getPage'](_0x1c31e3);try{const {direction:_0x200632,pixels:pixels=0x12c,selector:_0x135371}=_0x19debc;return _0x135371?await _0x2508da[_0x4c4d6c(0xdf)]((_0x33171e,_0x175c47,_0x108a4)=>{const _0x437428=_0x4c4d6c,_0x25a976=document['querySelector'](_0x33171e);if(_0x25a976){if(_0x175c47===_0x437428(0x131))_0x25a976[_0x437428(0xd6)]+=_0x108a4;else{if(_0x175c47==='up')_0x25a976['scrollTop']-=_0x108a4;else{if(_0x175c47==='right')_0x25a976[_0x437428(0xdd)]+=_0x108a4;else{if(_0x175c47==='left')_0x25a976['scrollLeft']-=_0x108a4;}}}}},_0x135371,_0x200632,pixels):await _0x2508da['evaluate']((_0x37ede1,_0x2911fa)=>{const _0xd734b8=_0x4c4d6c;if(_0x37ede1==='down')window['scrollBy'](0x0,_0x2911fa);else{if(_0x37ede1==='up')window[_0xd734b8(0xe7)](0x0,-_0x2911fa);else{if(_0x37ede1===_0xd734b8(0x104))window['scrollBy'](_0x2911fa,0x0);else{if(_0x37ede1===_0xd734b8(0x14e))window['scrollBy'](-_0x2911fa,0x0);}}}},_0x200632,pixels),{'success':!![],'action':'scroll','direction':_0x200632,'pixels':pixels,'selector':_0x135371||'page','message':_0x4c4d6c(0xec)+_0x200632+'\x20by\x20'+pixels+'px'};}catch(_0x5c1a6d){throw new Error(_0x4c4d6c(0xe5)+_0x5c1a6d[_0x4c4d6c(0x117)]);}}async[a0_0x546e41(0xd9)](_0x17275b){const _0x56fa6f=a0_0x546e41;if(this['browserInstances']['has'](_0x17275b)){const _0x588dd4=this[_0x56fa6f(0x121)]['get'](_0x17275b);if(!_0x588dd4[_0x56fa6f(0xef)]['isConnected']())this['browserInstances'][_0x56fa6f(0xda)](_0x17275b);else return _0x588dd4[_0x56fa6f(0xef)];}const _0x3b81a0=await a0_0x367d2a['launch']({'headless':this[_0x56fa6f(0xf4)]['headless'],'args':['--no-sandbox','--disable-setuid-sandbox',_0x56fa6f(0x105),'--disable-gpu']}),_0x5903e1=await _0x3b81a0['newPage']();return await _0x5903e1[_0x56fa6f(0x115)](this[_0x56fa6f(0xf4)][_0x56fa6f(0xe2)]),await _0x5903e1[_0x56fa6f(0x13b)](this[_0x56fa6f(0xf4)][_0x56fa6f(0x10a)]),this[_0x56fa6f(0x121)]['set'](_0x17275b,{'browser':_0x3b81a0,'page':_0x5903e1,'created':Date['now']()}),setTimeout(()=>{this['cleanupBrowser'](_0x17275b);},0xa*0x3c*0x3e8),_0x3b81a0;}async['getPage'](_0x5186fa){const _0x496eda=a0_0x546e41;return await this[_0x496eda(0xd9)](_0x5186fa),this['browserInstances']['get'](_0x5186fa)[_0x496eda(0x132)];}async['closeBrowser'](_0x171d6d){const _0x35d495=a0_0x546e41,_0x37d502=this['browserInstances'][_0x35d495(0x149)](_0x171d6d);if(_0x37d502)try{return await _0x37d502['browser']['close'](),this[_0x35d495(0x121)][_0x35d495(0xda)](_0x171d6d),{'success':!![],'action':_0x35d495(0x12b),'browserKey':_0x171d6d,'message':_0x35d495(0x144)};}catch(_0x523ecc){throw new Error('Failed\x20to\x20close\x20browser:\x20'+_0x523ecc['message']);}return{'success':!![],'action':_0x35d495(0x12b),'browserKey':_0x171d6d,'message':'Browser\x20instance\x20not\x20found\x20(already\x20closed)'};}async[a0_0x546e41(0xfa)](_0x2099c5){const _0x37964c=a0_0x546e41,_0x244f96=this[_0x37964c(0x121)][_0x37964c(0x149)](_0x2099c5);if(_0x244f96)try{await _0x244f96['browser']['close']();}catch(_0x570416){}finally{this['browserInstances']['delete'](_0x2099c5);}}['isAllowedUrl'](_0x4c2a2c){const _0x377066=a0_0x546e41;try{const _0x3d9085=new URL(_0x4c2a2c),_0x317a7d=_0x3d9085['hostname'][_0x377066(0x122)]();if(this['blockedDomains'][_0x377066(0x139)](_0x4f74fd=>_0x317a7d[_0x377066(0xe4)](_0x4f74fd[_0x377066(0x122)]())))return![];if(this[_0x377066(0x10d)]&&this[_0x377066(0x10d)][_0x377066(0x140)]>0x0)return this['allowedDomains']['some'](_0x342a98=>_0x317a7d['includes'](_0x342a98['toLowerCase']()));return!![];}catch{return![];}}['addToHistory'](_0x47332b,_0x1c26dc,_0x205eef){const _0x4be336=a0_0x546e41,_0x1286e3={'timestamp':new Date()[_0x4be336(0x101)](),'agentId':_0x205eef,'action':_0x47332b['type'],'selector':_0x47332b['selector']||_0x47332b['url'],'success':_0x1c26dc[_0x4be336(0xea)],'loadTime':_0x1c26dc['loadTime']||0x0};this[_0x4be336(0xe9)]['push'](_0x1286e3),this[_0x4be336(0xe9)]['length']>0x64&&(this['operationHistory']=this['operationHistory']['slice'](-0x64));}[a0_0x546e41(0x102)](){const _0x1d2ff5=a0_0x546e41;return['navigate',_0x1d2ff5(0x134),_0x1d2ff5(0x148),'wait','screenshot',_0x1d2ff5(0x150),_0x1d2ff5(0x147),_0x1d2ff5(0x12b)];}['getParameterSchema'](){const _0x29383b=a0_0x546e41;return{'type':'object','properties':{'actions':{'type':_0x29383b(0x151),'minItems':0x1,'items':{'type':_0x29383b(0x136),'properties':{'type':{'type':'string','enum':this['getSupportedActions']()},'url':{'type':'string'},'selector':{'type':'string'},'text':{'type':'string'},'outputPath':{'type':'string'},'waitTime':{'type':_0x29383b(0xf0)},'waitSelector':{'type':_0x29383b(0xeb)},'attribute':{'type':'string'},'direction':{'type':_0x29383b(0xeb)},'pixels':{'type':'integer'}},'required':[_0x29383b(0x148)]}}},'required':['actions']};}async[a0_0x546e41(0x120)](_0x2d7278){const _0x14acfc=a0_0x546e41;for(const [_0xfda46d]of this[_0x14acfc(0x121)]){await this['cleanupBrowser'](_0xfda46d);}}['getOperationHistory'](_0xd73f3c=null){const _0x43ac60=a0_0x546e41;if(_0xd73f3c)return this[_0x43ac60(0xe9)][_0x43ac60(0x124)](_0x29f5ad=>_0x29f5ad[_0x43ac60(0xf7)]===_0xd73f3c);return[...this['operationHistory']];}}export default BrowserTool;function a0_0x2727(_0x1075b3,_0x51b8c3){_0x1075b3=_0x1075b3-0xd2;const _0x5638c5=a0_0x5638();let _0x2727b7=_0x5638c5[_0x1075b3];if(a0_0x2727['nLQFuE']===undefined){var _0x5dc962=function(_0x1815f7){const _0x2e0b63='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4bf1a5='',_0x367d2a='';for(let _0x2a2cf4=0x0,_0x5aa45f,_0x4b9f5a,_0x4959b9=0x0;_0x4b9f5a=_0x1815f7['charAt'](_0x4959b9++);~_0x4b9f5a&&(_0x5aa45f=_0x2a2cf4%0x4?_0x5aa45f*0x40+_0x4b9f5a:_0x4b9f5a,_0x2a2cf4++%0x4)?_0x4bf1a5+=String['fromCharCode'](0xff&_0x5aa45f>>(-0x2*_0x2a2cf4&0x6)):0x0){_0x4b9f5a=_0x2e0b63['indexOf'](_0x4b9f5a);}for(let _0x5d497c=0x0,_0x3ff084=_0x4bf1a5['length'];_0x5d497c<_0x3ff084;_0x5d497c++){_0x367d2a+='%'+('00'+_0x4bf1a5['charCodeAt'](_0x5d497c)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x367d2a);};a0_0x2727['laZPWy']=_0x5dc962,a0_0x2727['vPgXZq']={},a0_0x2727['nLQFuE']=!![];}const _0x40b4e0=_0x5638c5[0x0],_0x125a44=_0x1075b3+_0x40b4e0,_0x266b4a=a0_0x2727['vPgXZq'][_0x125a44];return!_0x266b4a?(_0x2727b7=a0_0x2727['laZPWy'](_0x2727b7),a0_0x2727['vPgXZq'][_0x125a44]=_0x2727b7):_0x2727b7=_0x266b4a,_0x2727b7;}function a0_0x5638(){const _0x1943f6=['D2fPDa','DxnLCKfNzw50','u2nYzwvUC2HVDcbMywLSzwq6ia','B3v0Chv0lxbHDgG','ywXSB3DLzerVBwfPBNm','rxH0CMfJDgvKia','v2fPDcbMywLSzwq6ia','oIbvuKWGBM90igfSBg93zwq6ia','BM93','C3rHCNrZv2L0Aa','oIbKAxjLy3rPB24GAxmGCMvXDwLYzwqGzM9YihnJCM9SBa','mZu5nLzYDMHSvW','C2v0vMLLD3bVCNq','CMvSyxrPDMu','BwvZC2fNzq','BxmGCgvYig9WzxjHDgLVBGPnqvGGv0fjvcbusu1foIaZmcbZzwnVBMrZicGZmdaWmg1ZkqOGicaG','mJaZodvPtwftAhm','oIbZzwXLy3rVCIbPCYbYzxf1AxjLzcbMB3iGDhLWzq','C2vSzwn0qwXS','zgLYzwn0Aw9U','Bwf4u2nYzwvUC2HVDfnPEMu','q2XPy2SGzMfPBgvKig9Uia','D2fPDfrPBwu','y2XLyw51Ca','yNjVD3nLCKLUC3rHBMnLCW','Dg9mB3DLCKnHC2u','CMvXDwLYzxnqCM9Qzwn0','zMLSDgvY','mtq0mZbPshDcuKK','oIb1CMWGAxmGCMvXDwLYzwqGzM9Yig5HDMLNyxrL','ChvZAa','C2vSzwn0B3i','zxHLyW','D2fPDfr5Cgu','y2XVC2u','BMf2AwDHDgu','ofvTBfryqq','ywn0Aw9UCW','z290BW','oIb3ywL0lxrPBwuGBxvZDcbIzsbIzxr3zwvUideWmcbHBMqGmZaWmdaGBwLSBgLZzwnVBMrZ','zg93BG','CgfNzq','jgv2ywW','y2XPy2S','Dgv4DenVBNrLBNq','B2jQzwn0','yMXVy2TLzerVBwfPBNm','D2fPDc10ExbL','C29Tzq','Dhj1zq','C2v0vxnLCKfNzw50','z2v0ugfNzq','ote2odHhBwnpqu0','B3v0Chv0ugf0Aa','zxHLy3v0zq','BgvUz3rO','D2fPDc10Aw1L','BwTKAxi','CgfYC2vqyxjHBwv0zxjZ','qNjVD3nLCIbPBNn0yw5JzsbJBg9Zzwq','igj5DgvZicHTyxGG','y3vZDg9TvMfSAwrHDgvqyxjHBwv0zxjZ','C2nYB2XS','DhLWzq','z2v0','AgvPz2H0','D2fPDfnLBgvJDg9Y','rMfPBgvKihrVihbHCNnLigjYB3DZzxiGCgfYyw1LDgvYCW','v2fPDgvKigzVCIa','BgvMDa','DhjPBq','zxH0CMfJDa','yxjYyxK','v2fPDgvKia','mtK5mdq3ogDJDNHWEa','DgLTzw91Da','qwn0Aw9Uia','C2nYB2XSvg9W','CgfYC2vbDhrYAwj1DgvZ','Bwf4q29Uy3vYCMvUDe9WzxjHDgLVBNm','z2v0qNjVD3nLCG','zgvSzxrL','ignOyxjHy3rLCNmGAw50BYa','odGYEu5hBMPY','C2nYB2XStgvMDa','CgfYC2u','zxzHBhvHDgu','u2nYzwvUC2HVDcb0B28GBgfYz2u6ia','D2fPDc1ZzwXLy3rVCG','DMLLD3bVCNq','oIbVDxrWDxqTCgf0AcbPCYbYzxf1AxjLzcbMB3iGC2nYzwvUC2HVDa','Aw5JBhvKzxm','u2nYB2XSigzHAwXLzdOG','AxnbBgXVD2vKvxjS','C2nYB2XSqNK','AxnbC3LUyW','B3bLCMf0Aw9UsgLZDg9YEq','C3vJy2vZCW','C3rYAw5N','u2nYB2XSzwqG','oIbLAxrOzxiGD2fPDc10Aw1Lig9YihDHAxqTC2vSzwn0B3iGAxmGCMvXDwLYzwq','zM9JDxm','yNjVD3nLCG','Aw50zwDLCG','tw96AwXSys81lJaGkfDPBMrVD3mGtLqGmtaUmdSGv2LUnJq7ihG2ncKGqxbWBgvxzwjlAxqVntm3lJm2','zw50CMLLCW','DxjS','yNjVD3nLCKnVBMzPzW','mZKXntu2menVEeXOyW','zNvSBfbHz2u','ywDLBNrjza','zNvSBc1WywDL','D2fPDezVCLnLBgvJDg9Y','y2XLyw51CejYB3DZzxi','CMvZB2X2zq','tMf2AwDHDgvKihrVia','CMf3q29UDgvUDa','oIb1BMTUB3DUigfJDgLVBIb0ExbLoIa','ote3ngvurxHIqG','mZGYnuLPswjQrW','Dg9ju09tDhjPBMC','z2v0u3vWCg9YDgvKqwn0Aw9UCW','mZaWtMXWy2Dt','CMLNAhq','ls1KAxnHyMXLlwrLDI1ZAg0TDxnHz2u','Dgv4Da','CgfNzvrPBwvVDxq','C2nYzwvUC2HVDa'];a0_0x5638=function(){return _0x1943f6;};return a0_0x5638();}