@willwade/aac-processors 0.0.29 → 0.1.0

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 (92) hide show
  1. package/README.md +52 -852
  2. package/dist/browser/core/baseProcessor.js +241 -0
  3. package/dist/browser/core/stringCasing.js +179 -0
  4. package/dist/browser/core/treeStructure.js +255 -0
  5. package/dist/browser/index.browser.js +73 -0
  6. package/dist/browser/processors/applePanelsProcessor.js +582 -0
  7. package/dist/browser/processors/astericsGridProcessor.js +1509 -0
  8. package/dist/browser/processors/dotProcessor.js +221 -0
  9. package/dist/browser/processors/gridset/commands.js +962 -0
  10. package/dist/browser/processors/gridset/crypto.js +53 -0
  11. package/dist/browser/processors/gridset/password.js +43 -0
  12. package/dist/browser/processors/gridset/pluginTypes.js +277 -0
  13. package/dist/browser/processors/gridset/resolver.js +137 -0
  14. package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
  15. package/dist/browser/processors/gridset/symbols.js +421 -0
  16. package/dist/browser/processors/gridsetProcessor.js +2002 -0
  17. package/dist/browser/processors/obfProcessor.js +705 -0
  18. package/dist/browser/processors/opmlProcessor.js +274 -0
  19. package/dist/browser/types/aac.js +38 -0
  20. package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
  21. package/dist/browser/utilities/translation/translationProcessor.js +200 -0
  22. package/dist/browser/utils/io.js +95 -0
  23. package/dist/browser/validation/baseValidator.js +156 -0
  24. package/dist/browser/validation/gridsetValidator.js +355 -0
  25. package/dist/browser/validation/obfValidator.js +500 -0
  26. package/dist/browser/validation/validationTypes.js +46 -0
  27. package/dist/cli/index.js +5 -5
  28. package/dist/core/analyze.d.ts +2 -2
  29. package/dist/core/analyze.js +2 -2
  30. package/dist/core/baseProcessor.d.ts +5 -4
  31. package/dist/core/baseProcessor.js +22 -27
  32. package/dist/core/treeStructure.d.ts +5 -5
  33. package/dist/core/treeStructure.js +1 -4
  34. package/dist/index.browser.d.ts +37 -0
  35. package/dist/index.browser.js +99 -0
  36. package/dist/index.d.ts +1 -48
  37. package/dist/index.js +1 -136
  38. package/dist/index.node.d.ts +48 -0
  39. package/dist/index.node.js +152 -0
  40. package/dist/processors/applePanelsProcessor.d.ts +5 -4
  41. package/dist/processors/applePanelsProcessor.js +58 -62
  42. package/dist/processors/astericsGridProcessor.d.ts +7 -6
  43. package/dist/processors/astericsGridProcessor.js +31 -42
  44. package/dist/processors/dotProcessor.d.ts +5 -4
  45. package/dist/processors/dotProcessor.js +25 -33
  46. package/dist/processors/excelProcessor.d.ts +4 -3
  47. package/dist/processors/excelProcessor.js +6 -3
  48. package/dist/processors/gridset/crypto.d.ts +18 -0
  49. package/dist/processors/gridset/crypto.js +57 -0
  50. package/dist/processors/gridset/helpers.d.ts +1 -1
  51. package/dist/processors/gridset/helpers.js +18 -8
  52. package/dist/processors/gridset/password.d.ts +20 -3
  53. package/dist/processors/gridset/password.js +17 -3
  54. package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
  55. package/dist/processors/gridset/wordlistHelpers.js +21 -20
  56. package/dist/processors/gridsetProcessor.d.ts +7 -12
  57. package/dist/processors/gridsetProcessor.js +118 -77
  58. package/dist/processors/obfProcessor.d.ts +9 -7
  59. package/dist/processors/obfProcessor.js +131 -56
  60. package/dist/processors/obfsetProcessor.d.ts +5 -4
  61. package/dist/processors/obfsetProcessor.js +10 -16
  62. package/dist/processors/opmlProcessor.d.ts +5 -4
  63. package/dist/processors/opmlProcessor.js +27 -34
  64. package/dist/processors/snapProcessor.d.ts +8 -7
  65. package/dist/processors/snapProcessor.js +15 -12
  66. package/dist/processors/touchchatProcessor.d.ts +8 -7
  67. package/dist/processors/touchchatProcessor.js +22 -17
  68. package/dist/types/aac.d.ts +0 -2
  69. package/dist/types/aac.js +2 -0
  70. package/dist/utils/io.d.ts +12 -0
  71. package/dist/utils/io.js +107 -0
  72. package/dist/validation/gridsetValidator.js +7 -7
  73. package/dist/validation/snapValidator.js +28 -35
  74. package/docs/BROWSER_USAGE.md +618 -0
  75. package/examples/README.md +77 -0
  76. package/examples/browser-test-server.js +81 -0
  77. package/examples/browser-test.html +331 -0
  78. package/examples/vitedemo/QUICKSTART.md +74 -0
  79. package/examples/vitedemo/README.md +157 -0
  80. package/examples/vitedemo/index.html +376 -0
  81. package/examples/vitedemo/package-lock.json +1221 -0
  82. package/examples/vitedemo/package.json +18 -0
  83. package/examples/vitedemo/src/main.ts +519 -0
  84. package/examples/vitedemo/test-files/example.dot +14 -0
  85. package/examples/vitedemo/test-files/example.grd +1 -0
  86. package/examples/vitedemo/test-files/example.gridset +0 -0
  87. package/examples/vitedemo/test-files/example.obz +0 -0
  88. package/examples/vitedemo/test-files/example.opml +18 -0
  89. package/examples/vitedemo/test-files/simple.obf +53 -0
  90. package/examples/vitedemo/tsconfig.json +24 -0
  91. package/examples/vitedemo/vite.config.ts +34 -0
  92. package/package.json +20 -4
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "aac-processors-vite-demo",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "devDependencies": {
12
+ "typescript": "^5.6.3",
13
+ "vite": "^6.0.1"
14
+ },
15
+ "dependencies": {
16
+ "jszip": "^3.10.1"
17
+ }
18
+ }
@@ -0,0 +1,519 @@
1
+ /**
2
+ * AAC Processors Browser Demo
3
+ *
4
+ * This demo uses Vite to bundle AACProcessors for browser use.
5
+ * It tests all browser-compatible processors with real file uploads.
6
+ */
7
+
8
+ // Polyfill Buffer for browser environment
9
+ if (typeof (window as any).Buffer === 'undefined') {
10
+ // Create a proper Buffer wrapper class that extends Uint8Array
11
+ class BufferWrapper extends Uint8Array {
12
+ constructor(data: any, byteOffset?: number, length?: number) {
13
+ if (typeof data === 'number') {
14
+ // Alloc case: data is the size
15
+ super(data);
16
+ } else if (Array.isArray(data)) {
17
+ super(data);
18
+ } else if (data instanceof ArrayBuffer) {
19
+ super(data, byteOffset || 0, length);
20
+ } else if (data instanceof Uint8Array) {
21
+ super(data.buffer, data.byteOffset, data.length);
22
+ } else if (typeof data === 'string') {
23
+ const encoder = new TextEncoder();
24
+ super(encoder.encode(data));
25
+ } else {
26
+ super(0);
27
+ }
28
+ }
29
+
30
+ toString(encoding: string = 'utf8'): string {
31
+ if (encoding === 'utf8' || encoding === 'utf-8') {
32
+ const decoder = new TextDecoder('utf-8');
33
+ return decoder.decode(this);
34
+ }
35
+ throw new Error(`Buffer.toString: encoding ${encoding} not supported`);
36
+ }
37
+
38
+ static from(data: any, encoding?: string): BufferWrapper {
39
+ return new BufferWrapper(data);
40
+ }
41
+
42
+ static alloc(size: number): BufferWrapper {
43
+ return new BufferWrapper(size);
44
+ }
45
+
46
+ static allocUnsafe(size: number): BufferWrapper {
47
+ return new BufferWrapper(size);
48
+ }
49
+
50
+ static concat(list: Uint8Array[], totalLength?: number): BufferWrapper {
51
+ const result = new Uint8Array(totalLength || list.reduce((sum, arr) => sum + arr.length, 0));
52
+ let offset = 0;
53
+ for (const arr of list) {
54
+ result.set(arr, offset);
55
+ offset += arr.length;
56
+ }
57
+ return new BufferWrapper(result.buffer, result.byteOffset, result.length);
58
+ }
59
+
60
+ static isBuffer(obj: any): boolean {
61
+ return obj instanceof BufferWrapper;
62
+ }
63
+ }
64
+
65
+ (window as any).Buffer = BufferWrapper as any;
66
+ }
67
+
68
+ import {
69
+ getProcessor,
70
+ getSupportedExtensions,
71
+ DotProcessor,
72
+ OpmlProcessor,
73
+ ObfProcessor,
74
+ GridsetProcessor,
75
+ ApplePanelsProcessor,
76
+ AstericsGridProcessor,
77
+ type AACTree,
78
+ type AACPage,
79
+ type AACButton
80
+ } from 'aac-processors';
81
+
82
+ // UI Elements
83
+ const dropArea = document.getElementById('dropArea') as HTMLElement;
84
+ const fileInput = document.getElementById('fileInput') as HTMLInputElement;
85
+ const processBtn = document.getElementById('processBtn') as HTMLButtonElement;
86
+ const runTestsBtn = document.getElementById('runTestsBtn') as HTMLButtonElement;
87
+ const clearBtn = document.getElementById('clearBtn') as HTMLButtonElement;
88
+ const fileInfo = document.getElementById('fileInfo') as HTMLElement;
89
+ const processorName = document.getElementById('processorName') as HTMLElement;
90
+ const fileDetails = document.getElementById('fileDetails') as HTMLElement;
91
+ const stats = document.getElementById('stats') as HTMLElement;
92
+ const results = document.getElementById('results') as HTMLElement;
93
+ const logPanel = document.getElementById('logPanel') as HTMLElement;
94
+ const testResults = document.getElementById('testResults') as HTMLElement;
95
+ const testList = document.getElementById('testList') as HTMLElement;
96
+
97
+ // State
98
+ let currentFile: File | null = null;
99
+ let currentProcessor: any = null;
100
+ let currentTree: AACTree | null = null;
101
+
102
+ // Logging
103
+ function log(message: string, type: 'info' | 'success' | 'error' | 'warn' = 'info') {
104
+ const entry = document.createElement('div');
105
+ entry.className = `log-entry log-${type}`;
106
+ entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
107
+ logPanel.appendChild(entry);
108
+ logPanel.scrollTop = logPanel.scrollHeight;
109
+ console.log(`[${type.toUpperCase()}]`, message);
110
+ }
111
+
112
+ // Get file extension
113
+ function getFileExtension(filename: string): string {
114
+ const match = filename.toLowerCase().match(/\.\w+$/);
115
+ return match ? match[0] : '';
116
+ }
117
+
118
+ // Format file size
119
+ function formatFileSize(bytes: number): string {
120
+ if (bytes < 1024) return bytes + ' B';
121
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
122
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
123
+ }
124
+
125
+ // Handle file selection
126
+ function handleFile(file: File) {
127
+ currentFile = file;
128
+ const extension = getFileExtension(file.name);
129
+
130
+ log(`Selected file: ${file.name} (${formatFileSize(file.size)})`, 'info');
131
+
132
+ // Check if extension is supported
133
+ if (!getSupportedExtensions().includes(extension)) {
134
+ log(`Unsupported file type: ${extension}`, 'error');
135
+ processorName.textContent = '❌ Unsupported file type';
136
+ fileDetails.textContent = extension;
137
+ fileInfo.style.display = 'block';
138
+ processBtn.disabled = true;
139
+ return;
140
+ }
141
+
142
+ // Get processor
143
+ try {
144
+ currentProcessor = getProcessor(extension);
145
+ processorName.textContent = `✅ ${currentProcessor.constructor.name}`;
146
+ fileDetails.textContent = `${file.name} • ${formatFileSize(file.size)}`;
147
+ fileInfo.style.display = 'block';
148
+ processBtn.disabled = false;
149
+
150
+ log(`Using processor: ${currentProcessor.constructor.name}`, 'success');
151
+ } catch (error) {
152
+ log(`Error getting processor: ${(error as Error).message}`, 'error');
153
+ processBtn.disabled = true;
154
+ }
155
+ }
156
+
157
+ // Drag and drop handlers
158
+ dropArea.addEventListener('dragover', (e) => {
159
+ e.preventDefault();
160
+ dropArea.classList.add('dragover');
161
+ });
162
+
163
+ dropArea.addEventListener('dragleave', () => {
164
+ dropArea.classList.remove('dragover');
165
+ });
166
+
167
+ dropArea.addEventListener('drop', (e) => {
168
+ e.preventDefault();
169
+ dropArea.classList.remove('dragover');
170
+
171
+ const file = e.dataTransfer?.files[0];
172
+ if (file) {
173
+ fileInput.files = e.dataTransfer!.files;
174
+ handleFile(file);
175
+ }
176
+ });
177
+
178
+ dropArea.addEventListener('click', () => {
179
+ fileInput.click();
180
+ });
181
+
182
+ fileInput.addEventListener('change', (e) => {
183
+ const file = (e.target as HTMLInputElement).files?.[0];
184
+ if (file) {
185
+ handleFile(file);
186
+ }
187
+ });
188
+
189
+ // Process file
190
+ processBtn.addEventListener('click', async () => {
191
+ if (!currentFile || !currentProcessor) return;
192
+
193
+ const startTime = performance.now();
194
+ log('Processing file...', 'info');
195
+
196
+ try {
197
+ processBtn.disabled = true;
198
+ results.innerHTML = '<p style="text-align: center; padding: 40px;">⏳ Loading...</p>';
199
+
200
+ // Read file as ArrayBuffer
201
+ const arrayBuffer = await currentFile.arrayBuffer();
202
+
203
+ // Load into tree
204
+ log('Loading tree structure...', 'info');
205
+ currentTree = await currentProcessor.loadIntoTree(arrayBuffer);
206
+
207
+ const loadTime = performance.now() - startTime;
208
+ log(`Tree loaded in ${loadTime.toFixed(0)}ms`, 'success');
209
+
210
+ // Extract texts
211
+ log('Extracting texts...', 'info');
212
+ const texts = await currentProcessor.extractTexts(arrayBuffer);
213
+ log(`Extracted ${texts.length} texts`, 'success');
214
+
215
+ // Update stats
216
+ const pageCount = Object.keys(currentTree.pages).length;
217
+ const buttonCount = Object.values(currentTree.pages).reduce(
218
+ (sum: number, page: AACPage) => sum + page.buttons.length,
219
+ 0
220
+ );
221
+
222
+ document.getElementById('pageCount')!.textContent = pageCount.toString();
223
+ document.getElementById('buttonCount')!.textContent = buttonCount.toString();
224
+ document.getElementById('textCount')!.textContent = texts.length.toString();
225
+ document.getElementById('loadTime')!.textContent = `${loadTime.toFixed(0)}ms`;
226
+ stats.style.display = 'grid';
227
+
228
+ // Display results
229
+ displayResults(currentTree);
230
+
231
+ log(`✅ Successfully processed ${pageCount} pages with ${buttonCount} buttons`, 'success');
232
+ } catch (error) {
233
+ const errorMsg = (error as Error).message;
234
+ log(`❌ Error: ${errorMsg}`, 'error');
235
+ results.innerHTML = `<p style="color: #f48771; text-align: center; padding: 40px;">
236
+ ❌ Error: ${errorMsg}
237
+ </p>`;
238
+ } finally {
239
+ processBtn.disabled = false;
240
+ }
241
+ });
242
+
243
+ // Display results
244
+ function displayResults(tree: AACTree) {
245
+ results.innerHTML = '';
246
+
247
+ const sortedPageIds = Object.keys(tree.pages).sort((a, b) => {
248
+ // Show root page first
249
+ if (a === tree.rootId) return -1;
250
+ if (b === tree.rootId) return 1;
251
+ return a.localeCompare(b);
252
+ });
253
+
254
+ sortedPageIds.forEach((pageId) => {
255
+ const page = tree.pages[pageId];
256
+ const pageCard = document.createElement('div');
257
+ pageCard.className = 'page-card';
258
+
259
+ const pageTitle = document.createElement('div');
260
+ pageTitle.className = 'page-title';
261
+ pageTitle.textContent = `${page.name} ${pageId === tree.rootId ? '🏠' : ''}`;
262
+ pageCard.appendChild(pageTitle);
263
+
264
+ if (page.buttons.length > 0) {
265
+ const buttonGrid = document.createElement('div');
266
+ buttonGrid.className = 'button-grid';
267
+
268
+ page.buttons.forEach((button) => {
269
+ const buttonItem = document.createElement('div');
270
+ buttonItem.className = 'button-item';
271
+
272
+ const label = document.createElement('div');
273
+ label.className = 'button-label';
274
+ label.textContent = button.label || '(no label)';
275
+ buttonItem.appendChild(label);
276
+
277
+ if (button.message) {
278
+ const message = document.createElement('div');
279
+ message.className = 'button-message';
280
+ message.textContent = button.message;
281
+ buttonItem.appendChild(message);
282
+ }
283
+
284
+ const type = document.createElement('div');
285
+ type.className = 'button-type';
286
+ type.textContent = button.type;
287
+
288
+ switch (button.type) {
289
+ case 'SPEAK':
290
+ type.classList.add('type-speak');
291
+ break;
292
+ case 'NAVIGATE':
293
+ type.classList.add('type-navigate');
294
+ break;
295
+ default:
296
+ type.classList.add('type-other');
297
+ }
298
+
299
+ buttonItem.appendChild(type);
300
+
301
+ // Click handler
302
+ buttonItem.addEventListener('click', () => {
303
+ if (button.type === 'SPEAK' && button.message) {
304
+ log(`🔊 Speaking: "${button.message}"`, 'info');
305
+ if ('speechSynthesis' in window) {
306
+ const utterance = new SpeechSynthesisUtterance(button.message);
307
+ speechSynthesis.speak(utterance);
308
+ }
309
+ } else if (button.type === 'NAVIGATE' && button.targetPageId) {
310
+ const targetPage = tree.pages[button.targetPageId];
311
+ if (targetPage) {
312
+ log(`🔗 Navigating to: ${targetPage.name}`, 'info');
313
+ // Scroll to page
314
+ const targetCard = Array.from(results.querySelectorAll('.page-card')).find((card) =>
315
+ card.querySelector('.page-title')?.textContent?.includes(targetPage.name)
316
+ );
317
+ if (targetCard) {
318
+ targetCard.scrollIntoView({ behavior: 'smooth', block: 'center' });
319
+ targetCard.style.animation = 'highlight 1s';
320
+ }
321
+ }
322
+ }
323
+ });
324
+
325
+ buttonGrid.appendChild(buttonItem);
326
+ });
327
+
328
+ pageCard.appendChild(buttonGrid);
329
+ } else {
330
+ const noButtons = document.createElement('p');
331
+ noButtons.textContent = 'No buttons';
332
+ noButtons.style.color = '#999';
333
+ noButtons.style.fontSize = '12px';
334
+ pageCard.appendChild(noButtons);
335
+ }
336
+
337
+ results.appendChild(pageCard);
338
+ });
339
+ }
340
+
341
+ // Clear results
342
+ clearBtn.addEventListener('click', () => {
343
+ currentFile = null;
344
+ currentProcessor = null;
345
+ currentTree = null;
346
+ fileInput.value = '';
347
+ fileInfo.style.display = 'none';
348
+ stats.style.display = 'none';
349
+ results.innerHTML = '<p style="color: #999; text-align: center; padding: 40px;">Load a file to see its contents here</p>';
350
+ testResults.style.display = 'none';
351
+ logPanel.innerHTML = '<div class="log-entry log-info">Cleared. Ready to process files...</div>';
352
+ });
353
+
354
+ // Run compatibility tests
355
+ runTestsBtn.addEventListener('click', async () => {
356
+ log('Running compatibility tests...', 'info');
357
+ testResults.style.display = 'block';
358
+ testList.innerHTML = '';
359
+
360
+ const tests: { name: string; fn: () => Promise<boolean> }[] = [
361
+ {
362
+ name: 'getProcessor() factory function',
363
+ fn: async () => {
364
+ const dotProc = getProcessor('.dot');
365
+ const opmlProc = getProcessor('.opml');
366
+ const obfProc = getProcessor('.obf');
367
+ const gridsetProc = getProcessor('.gridset');
368
+ return (
369
+ dotProc instanceof DotProcessor &&
370
+ opmlProc instanceof OpmlProcessor &&
371
+ obfProc instanceof ObfProcessor &&
372
+ gridsetProc instanceof GridsetProcessor
373
+ );
374
+ }
375
+ },
376
+ {
377
+ name: 'getSupportedExtensions() returns all extensions',
378
+ fn: async () => {
379
+ const extensions = getSupportedExtensions();
380
+ const expected = ['.dot', '.opml', '.obf', '.obz', '.gridset', '.plist', '.grd'];
381
+ return expected.every((ext) => extensions.includes(ext));
382
+ }
383
+ },
384
+ {
385
+ name: 'DotProcessor instantiation',
386
+ fn: async () => {
387
+ try {
388
+ new DotProcessor();
389
+ return true;
390
+ } catch {
391
+ return false;
392
+ }
393
+ }
394
+ },
395
+ {
396
+ name: 'OpmlProcessor instantiation',
397
+ fn: async () => {
398
+ try {
399
+ new OpmlProcessor();
400
+ return true;
401
+ } catch {
402
+ return false;
403
+ }
404
+ }
405
+ },
406
+ {
407
+ name: 'ObfProcessor instantiation',
408
+ fn: async () => {
409
+ try {
410
+ new ObfProcessor();
411
+ return true;
412
+ } catch {
413
+ return false;
414
+ }
415
+ }
416
+ },
417
+ {
418
+ name: 'GridsetProcessor instantiation',
419
+ fn: async () => {
420
+ try {
421
+ new GridsetProcessor();
422
+ return true;
423
+ } catch {
424
+ return false;
425
+ }
426
+ }
427
+ },
428
+ {
429
+ name: 'ApplePanelsProcessor instantiation',
430
+ fn: async () => {
431
+ try {
432
+ new ApplePanelsProcessor();
433
+ return true;
434
+ } catch {
435
+ return false;
436
+ }
437
+ }
438
+ },
439
+ {
440
+ name: 'AstericsGridProcessor instantiation',
441
+ fn: async () => {
442
+ try {
443
+ new AstericsGridProcessor();
444
+ return true;
445
+ } catch {
446
+ return false;
447
+ }
448
+ }
449
+ },
450
+ {
451
+ name: 'Processors accept ArrayBuffer type',
452
+ fn: async () => {
453
+ try {
454
+ const proc = new DotProcessor();
455
+ const buffer = new Uint8Array([123, 125]); // Invalid but tests type acceptance
456
+ await proc.loadIntoTree(buffer); // Will fail but tests that it accepts the type
457
+ return true;
458
+ } catch {
459
+ return true; // Expected to fail with invalid data, but type was accepted
460
+ }
461
+ }
462
+ }
463
+ ];
464
+
465
+ let passed = 0;
466
+ let failed = 0;
467
+
468
+ for (const test of tests) {
469
+ const item = document.createElement('div');
470
+ item.className = 'test-item';
471
+
472
+ const status = document.createElement('div');
473
+ status.className = 'test-status test-pending';
474
+ status.textContent = '⏳';
475
+
476
+ const name = document.createElement('div');
477
+ name.className = 'test-name';
478
+ name.textContent = test.name;
479
+
480
+ item.appendChild(status);
481
+ item.appendChild(name);
482
+ testList.appendChild(item);
483
+
484
+ try {
485
+ const result = await test.fn();
486
+ if (result) {
487
+ status.className = 'test-status test-pass';
488
+ status.textContent = '✓';
489
+ passed++;
490
+ log(`✓ ${test.name}`, 'success');
491
+ } else {
492
+ status.className = 'test-status test-fail';
493
+ status.textContent = '✗';
494
+ failed++;
495
+ log(`✗ ${test.name}`, 'error');
496
+ }
497
+ } catch (error) {
498
+ status.className = 'test-status test-fail';
499
+ status.textContent = '✗';
500
+ failed++;
501
+ log(`✗ ${test.name}: ${(error as Error).message}`, 'error');
502
+ }
503
+ }
504
+
505
+ log(`Tests complete: ${passed} passed, ${failed} failed`, passed === tests.length ? 'success' : 'warn');
506
+
507
+ const summary = document.createElement('div');
508
+ summary.style.marginTop = '15px';
509
+ summary.style.paddingTop = '15px';
510
+ summary.style.borderTop = '2px solid #e0e0e0';
511
+ summary.style.fontWeight = '600';
512
+ summary.textContent = `📊 Summary: ${passed}/${tests.length} tests passed`;
513
+ testList.appendChild(summary);
514
+ });
515
+
516
+ // Log initialization
517
+ log('✅ AAC Processors Browser Demo initialized', 'success');
518
+ log('📋 Supported extensions: ' + getSupportedExtensions().join(', '), 'info');
519
+ log('💡 Drop a file or click to upload', 'info');
@@ -0,0 +1,14 @@
1
+ digraph G {
2
+ node1 [label="Home Page"];
3
+ node2 [label="About"];
4
+ node3 [label="Contact"];
5
+ node4 [label="Products"];
6
+
7
+ node1 -> node2 [label="Go to About"];
8
+ node1 -> node3 [label="Go to Contact"];
9
+ node1 -> node4 [label="View Products"];
10
+
11
+ node2 -> node1 [label="Back to Home"];
12
+ node3 -> node1 [label="Back to Home"];
13
+ node4 -> node1 [label="Back to Home"];
14
+ }
@@ -0,0 +1 @@
1
+ {"grids":[{"_id":"grid-data-1539356255177-62","_rev":"5-43251534c36905adb9d67b17a47f2fce","id":"grid-data-1539356255177-62","modelName":"GridData","label":"SubTV","rowCount":2,"gridElements":[{"id":"grid-element-1544626437548-5","width":2,"height":1,"x":0,"y":0,"label":"On/Off","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781575807-6","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E5004200AD2504000000000000000001B0002F002B002F00000000000000000383885330313030303030303030303030313030303030303030303130303030303030303130313131313030313031313131303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437548-6","width":2,"height":1,"x":0,"y":1,"label":"Back","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544626450196-13","modelName":"GridActionNavigate","toGridId":"grid-data-1539356201843-61"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-7","width":2,"height":1,"x":2,"y":0,"label":"Input","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781696077-8","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E3004200AB2502000000000000000001B1002F002D003000000000000000000382835330313030303030303030303030313030303030303030303130303030303030303130313030303030313031303030303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-8","width":2,"height":1,"x":2,"y":1,"label":"Vol.Mute","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781785507-14","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E5003E00AD2504000000000000000001B00030002F003000000000000000000382845330313030303030303030303030313030303030303030303130303030303030303031303031313030303130303131303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-9","width":2,"height":1,"x":4,"y":0,"label":"Vol.Up","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781726453-10","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E3004200AD2505000000000000000001B10030002D003000000000000000000382825330313030303030303030303030313030303030303030303130303030303030303030303030313030303030303031303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-10","width":2,"height":1,"x":4,"y":1,"label":"Vol.Down","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781812160-16","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E4003E00AC2505000000000000000001B000300030003000000000000000000383825330313030303030303030303030313030303030303030303130303030303030303130303030313030313030303031303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-11","width":2,"height":1,"x":6,"y":0,"label":"Ch.Up","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781758612-12","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E4003F00AD2504000000000000000001B0002F0030002F00000000000000000382845330313030303030303030303030313030303030303030303130303030303030303030313031313030303031303131303130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-12","width":2,"height":1,"x":6,"y":1,"label":"Ch.Down","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781833396-18","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-USB@IRTRANS:sndhex H5E010000000032260300E4003E00AB2504000000000000000001B0002F0031003000000000000000000382855330313030303030303030303030313030303030303030303130303030303030303130313031313030313031303131303130"}],"type":"ELEMENT_TYPE_NORMAL"}]},{"_id":"grid-data-1539356265418-63","_rev":"5-0be213cb8df13127c1b93b5e77575d5d","id":"grid-data-1539356265418-63","modelName":"GridData","label":"SubHifi","rowCount":2,"gridElements":[{"id":"grid-element-1544626533739-14","width":2,"height":1,"x":0,"y":0,"label":"On/Off","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687033214-6","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010237004900D8011E137800000000000004600044004304610043000000000000050100533031313131313130313030303030303130313031303130303130313031303131333230 "}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533739-15","width":2,"height":1,"x":0,"y":1,"label":"Back","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544626557506-22","modelName":"GridActionNavigate","toGridId":"grid-data-1539356201843-61"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533739-16","width":2,"height":1,"x":2,"y":0,"label":"Radio","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687069230-8","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010236004A00D7011E137800000000000004610044004304600042000000000000050100533031303131313130313031303030303130313130313030303130303130313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533739-17","width":2,"height":1,"x":2,"y":1,"label":"Vol.Mute","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687170078-14","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002425010233004600D3011A137400000000000004640047004804640047000000000000050100533031303131313130313031303030303130303131313030303131303030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533740-18","width":2,"height":1,"x":4,"y":0,"label":"Vol.Up","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687100974-10","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010237004300D1011D13720000000000000460004B00490461004A000000000000050100533031303131313130313031303030303130313031313030303130313030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533740-19","width":2,"height":1,"x":4,"y":1,"label":"Vol.Down","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687185046-16","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010237004A00D7011E137800000000000004610043004304600043000000000000050100533031303131313130313031303030303131313031313030303030313030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533740-20","width":2,"height":1,"x":6,"y":0,"label":"Next","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687152446-12","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002425010233004600D3011A140200000000000004640048004704650047000000000000050100533131313131313130313030303030303031313031313031303030313030313030333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626533740-21","width":2,"height":1,"x":6,"y":1,"label":"Previous","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687204030-18","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002425010233004600D3011A140000000000000004640047004704640048000000000000050100533131313131313130313030303030303030313131313031303130303030313030333230"}],"type":"ELEMENT_TYPE_NORMAL"}]},{"_id":"grid-data-1539356271849-64","_rev":"5-fd95e89ece512e06017f4b3fddf10dde","id":"grid-data-1539356271849-64","modelName":"GridData","label":"SubDvd","rowCount":2,"gridElements":[{"id":"grid-element-1544626610219-23","width":2,"height":1,"x":0,"y":0,"label":"On/Off","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544782942873-3","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H530100000000272603023A004900C3023A1C24000000000000022F0038003400350039000000000000048278533030303030313030303030303030303032313131303030303030303030313131313131313130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626610219-24","width":2,"height":1,"x":0,"y":1,"label":"Back","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544626618650-29","modelName":"GridActionNavigate","toGridId":"grid-data-1539356201843-61"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626610219-25","width":2,"height":1,"x":2,"y":0,"label":"Previous","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544782974641-5","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H530100000000272603023A004500C202391C2500000000000002300038003900390038000000000000048278533030303030313030303030303030303032313131303130313130303030303130303131313130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626610219-26","width":2,"height":1,"x":2,"y":1,"label":"Stop","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544783013413-9","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H530100000000272603023A004800C4023A1C24000000000000022F0039003400350039000000000000048278533030303030313030303030303030303032313131303131303031303030303031313031313130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626610220-27","width":2,"height":1,"x":4,"y":0,"label":"Next","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544782986382-7","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H530100000000272603023A004600C3023A1C24000000000000022F0038003800390039000000000000048278533030303030313030303030303030303032313131303130303031303030303131313031313130"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626610220-28","width":2,"height":1,"x":4,"y":1,"label":"Play/Pause","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544783039344-11","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5301000000002726030239004600C2023B1C2400000000000002300038003900380038000000000000048278533030303030313030303030303030303032313131303030313031303030313130313031313130"}],"type":"ELEMENT_TYPE_NORMAL"}]},{"_id":"grid-data-1539356278386-65","_rev":"5-c9c837ca93dd91ed55ca217dea4f9ee5","id":"grid-data-1539356278386-65","modelName":"GridData","label":"SubSmarthome","rowCount":2,"gridElements":[{"id":"grid-element-1544626940836-3","width":2,"height":1,"x":0,"y":0,"label":"Back","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544626963516-10","modelName":"GridActionNavigate","toGridId":"grid-data-1539356201843-61"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940836-4","width":2,"height":1,"x":2,"y":0,"label":"Livingroom On","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687418301-20","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:11/0/0,1.001,on","areURL":"http://172.22.0.166:8081/rest/"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940837-5","width":2,"height":1,"x":2,"y":1,"label":"Livingroom Off","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687470317-26","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:11/0/0,1.001,off"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940837-6","width":2,"height":1,"x":4,"y":0,"label":"Kitchen On","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687435623-22","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:11/0/8,1.001,on"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940838-7","width":2,"height":1,"x":4,"y":1,"label":"Kitchen Off","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687493854-28","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:11/0/8,1.001,off"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940838-8","width":2,"height":1,"x":6,"y":0,"label":"Temp Up","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687454470-24","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:12/1/1,9.002,+1"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626940839-9","width":2,"height":1,"x":6,"y":1,"label":"Temp Down","actions":[{"id":"grid-action-speak-1544626835480-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544687505661-30","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"@KNX:12/1/1,9.002,-1"}],"type":"ELEMENT_TYPE_NORMAL"}]},{"_id":"grid-data-1544783930791-13","_rev":"3-6f73312a63bb45f780700db2b9126dc6","id":"grid-data-1544783930791-13","modelName":"GridData","label":"SubTVBedroom","rowCount":2,"gridElements":[{"id":"grid-element-1544626437548-5","width":2,"height":1,"x":0,"y":0,"label":"On/Off","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781575807-6","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010233004B00D4011D1367000000000000045A00420043045A0042000000000000050100533030303030303130313131313131303130313030313030303130313130313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437548-6","width":2,"height":1,"x":0,"y":1,"label":"Back","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544626450196-13","modelName":"GridActionNavigate","toGridId":"grid-data-1539356201843-61"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-7","width":2,"height":1,"x":2,"y":0,"label":"Input","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781696077-8","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010233004B00D5011C1367000000000000045B00420042045B0042000000000000050100533030303030303130313131313131303130303130313030303131303130313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-8","width":2,"height":1,"x":2,"y":1,"label":"Vol.Mute","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781785507-14","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010234004B00D5011D1367000000000000045A00420042045A0042000000000000050100533030303030303130313131313131303130303030313030303131313130313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-9","width":2,"height":1,"x":4,"y":0,"label":"Vol.Up","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781726453-10","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010234004C00D5011D1367000000000000045A00410042045A0042000000000000050100533030303030303130313131313131303130313031313030303130313030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-10","width":2,"height":1,"x":4,"y":1,"label":"Vol.Down","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781812160-16","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010233004B00D5011D1368000000000000045B00420042045A0041000000000000050100533030303030303130313131313131303130313131313030303130303030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-11","width":2,"height":1,"x":6,"y":0,"label":"Ch.Up","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781758612-12","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010232004B00D4011E1367000000000000045B00420042045A0041000000000000050100533030303030303130313131313131303131313031313030303030313030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"},{"id":"grid-element-1544626437549-12","width":2,"height":1,"x":6,"y":1,"label":"Ch.Down","actions":[{"id":"grid-action-speak-1544617557563-1","modelName":"GridActionSpeak","speakLanguage":"en"},{"id":"grid-action-navigate-1544781833396-18","modelName":"GridActionARE","areModelGridFileName":"allinone-grid-raspi.acs","componentId":"CommandInput","dataPortId":"in","dataPortSendData":"IRTRANS-WEB@IRTRANS:sndhex H5001000000002426010233004B00D4011C1367000000000000045B00420043045B0042000000000000050100533030303030303130313131313131303131313131313030303030303030313131333230"}],"type":"ELEMENT_TYPE_NORMAL"}]}]}
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <opml version="2.0">
3
+ <head>
4
+ <title>Test OPML</title>
5
+ </head>
6
+ <body>
7
+ <outline text="Main Page">
8
+ <outline text="Category 1">
9
+ <outline text="Item 1" />
10
+ <outline text="Item 2" />
11
+ </outline>
12
+ <outline text="Category 2">
13
+ <outline text="Item 3" />
14
+ <outline text="Item 4" />
15
+ </outline>
16
+ </outline>
17
+ </body>
18
+ </opml>