@flightdev/ui 2.0.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 (118) hide show
  1. package/.turbo/turbo-build.log +81 -0
  2. package/.turbo/turbo-lint.log +40 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/LICENSE +21 -0
  5. package/README.md +92 -0
  6. package/TESTING.md +124 -0
  7. package/dist/adapter-MMD-iHNx.d.ts +424 -0
  8. package/dist/adapters/tier-1/angular.d.ts +60 -0
  9. package/dist/adapters/tier-1/angular.js +2 -0
  10. package/dist/adapters/tier-1/index.d.ts +7 -0
  11. package/dist/adapters/tier-1/index.js +7 -0
  12. package/dist/adapters/tier-1/qwik.d.ts +55 -0
  13. package/dist/adapters/tier-1/qwik.js +2 -0
  14. package/dist/adapters/tier-1/react.d.ts +67 -0
  15. package/dist/adapters/tier-1/react.js +2 -0
  16. package/dist/adapters/tier-1/solid.d.ts +45 -0
  17. package/dist/adapters/tier-1/solid.js +2 -0
  18. package/dist/adapters/tier-1/svelte.d.ts +48 -0
  19. package/dist/adapters/tier-1/svelte.js +2 -0
  20. package/dist/adapters/tier-1/vue.d.ts +47 -0
  21. package/dist/adapters/tier-1/vue.js +2 -0
  22. package/dist/adapters/tier-2/index.d.ts +7 -0
  23. package/dist/adapters/tier-2/index.js +7 -0
  24. package/dist/adapters/tier-2/inferno.d.ts +31 -0
  25. package/dist/adapters/tier-2/inferno.js +2 -0
  26. package/dist/adapters/tier-2/lit.d.ts +34 -0
  27. package/dist/adapters/tier-2/lit.js +2 -0
  28. package/dist/adapters/tier-2/marko.d.ts +59 -0
  29. package/dist/adapters/tier-2/marko.js +2 -0
  30. package/dist/adapters/tier-2/mithril.d.ts +31 -0
  31. package/dist/adapters/tier-2/mithril.js +2 -0
  32. package/dist/adapters/tier-2/preact.d.ts +33 -0
  33. package/dist/adapters/tier-2/preact.js +2 -0
  34. package/dist/adapters/tier-2/stencil.d.ts +52 -0
  35. package/dist/adapters/tier-2/stencil.js +2 -0
  36. package/dist/adapters/tier-3/alpine.d.ts +73 -0
  37. package/dist/adapters/tier-3/alpine.js +2 -0
  38. package/dist/adapters/tier-3/hotwire.d.ts +71 -0
  39. package/dist/adapters/tier-3/hotwire.js +2 -0
  40. package/dist/adapters/tier-3/htmx.d.ts +88 -0
  41. package/dist/adapters/tier-3/htmx.js +2 -0
  42. package/dist/adapters/tier-3/index.d.ts +7 -0
  43. package/dist/adapters/tier-3/index.js +7 -0
  44. package/dist/adapters/tier-3/petite-vue.d.ts +56 -0
  45. package/dist/adapters/tier-3/petite-vue.js +2 -0
  46. package/dist/adapters/tier-3/stimulus.d.ts +63 -0
  47. package/dist/adapters/tier-3/stimulus.js +2 -0
  48. package/dist/adapters/tier-3/vanilla.d.ts +63 -0
  49. package/dist/adapters/tier-3/vanilla.js +2 -0
  50. package/dist/chunk-2SNQ6PTM.js +217 -0
  51. package/dist/chunk-3D4XMIZI.js +136 -0
  52. package/dist/chunk-3HU6GSQ4.js +125 -0
  53. package/dist/chunk-4PZDNFL7.js +148 -0
  54. package/dist/chunk-5IBLFTYL.js +114 -0
  55. package/dist/chunk-64JZJ7OK.js +142 -0
  56. package/dist/chunk-7ZJI3QU2.js +132 -0
  57. package/dist/chunk-CE4FJHQJ.js +133 -0
  58. package/dist/chunk-DTCAUBH5.js +87 -0
  59. package/dist/chunk-NTASPOHG.js +106 -0
  60. package/dist/chunk-OI2AMQLG.js +152 -0
  61. package/dist/chunk-Q7HUE44H.js +106 -0
  62. package/dist/chunk-QH3LOWXU.js +155 -0
  63. package/dist/chunk-QIVAK6BH.js +103 -0
  64. package/dist/chunk-V34XPVGK.js +103 -0
  65. package/dist/chunk-VK7ZPMO7.js +221 -0
  66. package/dist/chunk-X6CNUW6T.js +136 -0
  67. package/dist/chunk-XTDK7ME5.js +382 -0
  68. package/dist/chunk-YFGSHW5S.js +121 -0
  69. package/dist/chunk-ZAJVSE7J.js +90 -0
  70. package/dist/core/index.d.ts +161 -0
  71. package/dist/core/index.js +2 -0
  72. package/dist/index.d.ts +103 -0
  73. package/dist/index.js +71 -0
  74. package/docs/ADAPTERS.md +946 -0
  75. package/docs/PATTERNS.md +836 -0
  76. package/package.json +229 -0
  77. package/src/adapters/tier-1/angular.ts +223 -0
  78. package/src/adapters/tier-1/index.ts +12 -0
  79. package/src/adapters/tier-1/qwik.ts +177 -0
  80. package/src/adapters/tier-1/react.ts +330 -0
  81. package/src/adapters/tier-1/solid.ts +222 -0
  82. package/src/adapters/tier-1/svelte.ts +211 -0
  83. package/src/adapters/tier-1/vue.ts +234 -0
  84. package/src/adapters/tier-2/index.ts +12 -0
  85. package/src/adapters/tier-2/inferno.ts +149 -0
  86. package/src/adapters/tier-2/lit.ts +191 -0
  87. package/src/adapters/tier-2/marko.ts +199 -0
  88. package/src/adapters/tier-2/mithril.ts +152 -0
  89. package/src/adapters/tier-2/preact.ts +133 -0
  90. package/src/adapters/tier-2/stencil.ts +214 -0
  91. package/src/adapters/tier-3/alpine.ts +218 -0
  92. package/src/adapters/tier-3/hotwire.ts +254 -0
  93. package/src/adapters/tier-3/htmx.ts +263 -0
  94. package/src/adapters/tier-3/index.ts +12 -0
  95. package/src/adapters/tier-3/petite-vue.ts +163 -0
  96. package/src/adapters/tier-3/stimulus.ts +233 -0
  97. package/src/adapters/tier-3/vanilla.ts +252 -0
  98. package/src/ambient.d.ts +310 -0
  99. package/src/core/adapter.ts +366 -0
  100. package/src/core/index.ts +56 -0
  101. package/src/core/registry.ts +518 -0
  102. package/src/core/types.ts +461 -0
  103. package/src/htmx.ts +134 -0
  104. package/src/index.ts +263 -0
  105. package/test/__mocks__/stencil-core.ts +19 -0
  106. package/test/__mocks__/stencil-hydrate.ts +15 -0
  107. package/test/adapters/tier-1.test.ts +206 -0
  108. package/test/adapters/tier-2.test.ts +175 -0
  109. package/test/adapters/tier-3.test.ts +284 -0
  110. package/test/contracts/adapter.contract.ts +293 -0
  111. package/test/core/core.test.ts +310 -0
  112. package/test/errors/error-handling.test.ts +454 -0
  113. package/test/integration/htmx.integration.test.ts +246 -0
  114. package/test/integration/react.integration.test.ts +271 -0
  115. package/test/integration/registry.integration.test.ts +308 -0
  116. package/tsconfig.json +22 -0
  117. package/tsup.config.ts +93 -0
  118. package/vitest.config.ts +101 -0
@@ -0,0 +1,518 @@
1
+ /**
2
+ * @flightdev/ui - Adapter Registry
3
+ *
4
+ * Global registry for dynamic adapter loading and discovery.
5
+ * Enables lazy loading of adapters to minimize bundle size.
6
+ *
7
+ * @module @flightdev/ui/core/registry
8
+ * @version 2.0.0
9
+ */
10
+
11
+ import type { UIAdapterV2, AdapterTier, AdapterCapabilities } from './types.js';
12
+
13
+ // ============================================================================
14
+ // Types
15
+ // ============================================================================
16
+
17
+ /**
18
+ * Lazy loader function for an adapter
19
+ */
20
+ export type AdapterLoader = () => Promise<UIAdapterV2>;
21
+
22
+ /**
23
+ * Adapter metadata for registry
24
+ */
25
+ export interface AdapterMetadata {
26
+ /** Unique adapter ID */
27
+ id: string;
28
+
29
+ /** Human-readable name */
30
+ name: string;
31
+
32
+ /** Framework name */
33
+ framework: string;
34
+
35
+ /** Tier classification */
36
+ tier: AdapterTier;
37
+
38
+ /** Capability hints (may be incomplete until loaded) */
39
+ capabilities?: Partial<AdapterCapabilities>;
40
+
41
+ /** Peer dependencies required */
42
+ peerDependencies?: string[];
43
+
44
+ /** Lazy loader function */
45
+ loader: AdapterLoader;
46
+ }
47
+
48
+ /**
49
+ * Registry query options
50
+ */
51
+ export interface RegistryQueryOptions {
52
+ /** Filter by tier */
53
+ tier?: AdapterTier;
54
+
55
+ /** Filter by capability */
56
+ capability?: keyof AdapterCapabilities;
57
+
58
+ /** Filter by framework name pattern */
59
+ framework?: string | RegExp;
60
+ }
61
+
62
+ // ============================================================================
63
+ // Adapter Registry Class
64
+ // ============================================================================
65
+
66
+ /**
67
+ * Global adapter registry for dynamic loading and discovery.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * import { adapterRegistry } from '@flightdev/ui';
72
+ *
73
+ * // Register an adapter
74
+ * adapterRegistry.register({
75
+ * id: 'react',
76
+ * name: 'React',
77
+ * framework: 'react',
78
+ * tier: 'tier-1',
79
+ * loader: () => import('./adapters/tier-1/react.js').then(m => m.react()),
80
+ * });
81
+ *
82
+ * // Get an adapter
83
+ * const reactAdapter = await adapterRegistry.get('react');
84
+ *
85
+ * // List all adapters
86
+ * const allAdapters = adapterRegistry.list();
87
+ * ```
88
+ */
89
+ class AdapterRegistry {
90
+ private metadata = new Map<string, AdapterMetadata>();
91
+ private instances = new Map<string, UIAdapterV2>();
92
+ private loading = new Map<string, Promise<UIAdapterV2>>();
93
+
94
+ /**
95
+ * Register an adapter with the registry.
96
+ */
97
+ register(metadata: AdapterMetadata): void {
98
+ if (this.metadata.has(metadata.id)) {
99
+ console.warn(`[AdapterRegistry] Overwriting existing adapter: ${metadata.id}`);
100
+ }
101
+ this.metadata.set(metadata.id, metadata);
102
+ }
103
+
104
+ /**
105
+ * Register multiple adapters at once.
106
+ */
107
+ registerAll(adapters: AdapterMetadata[]): void {
108
+ for (const adapter of adapters) {
109
+ this.register(adapter);
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Unregister an adapter.
115
+ */
116
+ unregister(id: string): boolean {
117
+ this.instances.delete(id);
118
+ this.loading.delete(id);
119
+ return this.metadata.delete(id);
120
+ }
121
+
122
+ /**
123
+ * Check if an adapter is registered.
124
+ */
125
+ has(id: string): boolean {
126
+ return this.metadata.has(id);
127
+ }
128
+
129
+ /**
130
+ * Get an adapter by ID (lazy loads if not already loaded).
131
+ */
132
+ async get(id: string): Promise<UIAdapterV2 | undefined> {
133
+ // Check if already loaded
134
+ const existing = this.instances.get(id);
135
+ if (existing) {
136
+ return existing;
137
+ }
138
+
139
+ // Check if currently loading
140
+ const loadingPromise = this.loading.get(id);
141
+ if (loadingPromise) {
142
+ return loadingPromise;
143
+ }
144
+
145
+ // Check if registered
146
+ const meta = this.metadata.get(id);
147
+ if (!meta) {
148
+ return undefined;
149
+ }
150
+
151
+ // Load the adapter
152
+ const promise = this.loadAdapter(meta);
153
+ this.loading.set(id, promise);
154
+
155
+ try {
156
+ const adapter = await promise;
157
+ this.instances.set(id, adapter);
158
+ this.loading.delete(id);
159
+ return adapter;
160
+ } catch (error) {
161
+ this.loading.delete(id);
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get an adapter synchronously (only if already loaded).
168
+ */
169
+ getSync(id: string): UIAdapterV2 | undefined {
170
+ return this.instances.get(id);
171
+ }
172
+
173
+ /**
174
+ * Get adapter metadata without loading.
175
+ */
176
+ getMetadata(id: string): AdapterMetadata | undefined {
177
+ return this.metadata.get(id);
178
+ }
179
+
180
+ /**
181
+ * List all registered adapter IDs.
182
+ */
183
+ list(): string[] {
184
+ return Array.from(this.metadata.keys());
185
+ }
186
+
187
+ /**
188
+ * List adapters matching query options.
189
+ */
190
+ query(options: RegistryQueryOptions): AdapterMetadata[] {
191
+ const results: AdapterMetadata[] = [];
192
+
193
+ for (const meta of this.metadata.values()) {
194
+ // Filter by tier
195
+ if (options.tier && meta.tier !== options.tier) {
196
+ continue;
197
+ }
198
+
199
+ // Filter by capability
200
+ if (options.capability && !meta.capabilities?.[options.capability]) {
201
+ continue;
202
+ }
203
+
204
+ // Filter by framework
205
+ if (options.framework) {
206
+ if (typeof options.framework === 'string') {
207
+ if (!meta.framework.includes(options.framework)) {
208
+ continue;
209
+ }
210
+ } else if (!options.framework.test(meta.framework)) {
211
+ continue;
212
+ }
213
+ }
214
+
215
+ results.push(meta);
216
+ }
217
+
218
+ return results;
219
+ }
220
+
221
+ /**
222
+ * List adapters by tier.
223
+ */
224
+ listByTier(tier: AdapterTier): string[] {
225
+ return this.query({ tier }).map((m) => m.id);
226
+ }
227
+
228
+ /**
229
+ * List adapters by capability.
230
+ */
231
+ listByCapability(capability: keyof AdapterCapabilities): string[] {
232
+ return this.query({ capability }).map((m) => m.id);
233
+ }
234
+
235
+ /**
236
+ * Preload adapters for faster access later.
237
+ */
238
+ async preload(ids: string[]): Promise<void> {
239
+ await Promise.all(ids.map((id) => this.get(id)));
240
+ }
241
+
242
+ /**
243
+ * Get all loaded adapters.
244
+ */
245
+ getLoaded(): Map<string, UIAdapterV2> {
246
+ return new Map(this.instances);
247
+ }
248
+
249
+ /**
250
+ * Clear all cached adapter instances (but keep registrations).
251
+ */
252
+ clearCache(): void {
253
+ this.instances.clear();
254
+ this.loading.clear();
255
+ }
256
+
257
+ /**
258
+ * Clear everything (registrations and cache).
259
+ */
260
+ clear(): void {
261
+ this.metadata.clear();
262
+ this.instances.clear();
263
+ this.loading.clear();
264
+ }
265
+
266
+ /**
267
+ * Get registry statistics.
268
+ */
269
+ stats(): {
270
+ registered: number;
271
+ loaded: number;
272
+ loading: number;
273
+ byTier: Record<AdapterTier, number>;
274
+ } {
275
+ const byTier: Record<AdapterTier, number> = {
276
+ 'tier-1': 0,
277
+ 'tier-2': 0,
278
+ 'tier-3': 0,
279
+ };
280
+
281
+ for (const meta of this.metadata.values()) {
282
+ byTier[meta.tier]++;
283
+ }
284
+
285
+ return {
286
+ registered: this.metadata.size,
287
+ loaded: this.instances.size,
288
+ loading: this.loading.size,
289
+ byTier,
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Load an adapter from metadata.
295
+ */
296
+ private async loadAdapter(meta: AdapterMetadata): Promise<UIAdapterV2> {
297
+ try {
298
+ const adapter = await meta.loader();
299
+
300
+ // Initialize if needed
301
+ if (adapter.init) {
302
+ await adapter.init();
303
+ }
304
+
305
+ return adapter;
306
+ } catch (error) {
307
+ const message = error instanceof Error ? error.message : String(error);
308
+ throw new Error(
309
+ `[AdapterRegistry] Failed to load adapter '${meta.id}': ${message}\n` +
310
+ `Required peer dependencies: ${meta.peerDependencies?.join(', ') ?? 'none'}`
311
+ );
312
+ }
313
+ }
314
+ }
315
+
316
+ // ============================================================================
317
+ // Global Registry Instance
318
+ // ============================================================================
319
+
320
+ /**
321
+ * Global adapter registry instance.
322
+ *
323
+ * Use this to register and retrieve UI adapters.
324
+ */
325
+ export const adapterRegistry = new AdapterRegistry();
326
+
327
+ // ============================================================================
328
+ // Built-in Adapter Registrations
329
+ // ============================================================================
330
+
331
+ /**
332
+ * Register all built-in adapters.
333
+ * Called automatically when the package is imported.
334
+ */
335
+ export function registerBuiltinAdapters(): void {
336
+ // Tier 1: Full Support
337
+ adapterRegistry.register({
338
+ id: 'react',
339
+ name: 'React',
340
+ framework: 'react',
341
+ tier: 'tier-1',
342
+ capabilities: { streaming: true, partialHydration: true, serverComponents: true },
343
+ peerDependencies: ['react', 'react-dom'],
344
+ loader: () => import('../adapters/tier-1/react.js').then((m) => m.default()),
345
+ });
346
+
347
+ adapterRegistry.register({
348
+ id: 'vue',
349
+ name: 'Vue',
350
+ framework: 'vue',
351
+ tier: 'tier-1',
352
+ capabilities: { streaming: true, partialHydration: true },
353
+ peerDependencies: ['vue'],
354
+ loader: () => import('../adapters/tier-1/vue.js').then((m) => m.default()),
355
+ });
356
+
357
+ adapterRegistry.register({
358
+ id: 'svelte',
359
+ name: 'Svelte',
360
+ framework: 'svelte',
361
+ tier: 'tier-1',
362
+ capabilities: { streaming: false, partialHydration: true },
363
+ peerDependencies: ['svelte'],
364
+ loader: () => import('../adapters/tier-1/svelte.js').then((m) => m.default()),
365
+ });
366
+
367
+ adapterRegistry.register({
368
+ id: 'solid',
369
+ name: 'Solid',
370
+ framework: 'solid',
371
+ tier: 'tier-1',
372
+ capabilities: { streaming: true, partialHydration: true },
373
+ peerDependencies: ['solid-js'],
374
+ loader: () => import('../adapters/tier-1/solid.js').then((m) => m.default()),
375
+ });
376
+
377
+ adapterRegistry.register({
378
+ id: 'angular',
379
+ name: 'Angular',
380
+ framework: 'angular',
381
+ tier: 'tier-1',
382
+ capabilities: { streaming: true, partialHydration: true },
383
+ peerDependencies: ['@angular/core', '@angular/platform-server', '@angular/platform-browser'],
384
+ loader: () => import('../adapters/tier-1/angular.js').then((m) => m.default()),
385
+ });
386
+
387
+ adapterRegistry.register({
388
+ id: 'qwik',
389
+ name: 'Qwik',
390
+ framework: 'qwik',
391
+ tier: 'tier-1',
392
+ capabilities: { streaming: true, resumable: true, partialHydration: true },
393
+ peerDependencies: ['@builder.io/qwik'],
394
+ loader: () => import('../adapters/tier-1/qwik.js').then((m) => m.default()),
395
+ });
396
+
397
+ // Tier 2: Standard Support
398
+ adapterRegistry.register({
399
+ id: 'preact',
400
+ name: 'Preact',
401
+ framework: 'preact',
402
+ tier: 'tier-2',
403
+ capabilities: { streaming: false, partialHydration: true },
404
+ peerDependencies: ['preact'],
405
+ loader: () => import('../adapters/tier-2/preact.js').then((m) => m.default()),
406
+ });
407
+
408
+ adapterRegistry.register({
409
+ id: 'lit',
410
+ name: 'Lit',
411
+ framework: 'lit',
412
+ tier: 'tier-2',
413
+ capabilities: { islands: true },
414
+ peerDependencies: ['lit'],
415
+ loader: () => import('../adapters/tier-2/lit.js').then((m) => m.default()),
416
+ });
417
+
418
+ adapterRegistry.register({
419
+ id: 'marko',
420
+ name: 'Marko',
421
+ framework: 'marko',
422
+ tier: 'tier-2',
423
+ capabilities: { streaming: true, partialHydration: true, islands: true },
424
+ peerDependencies: ['marko'],
425
+ loader: () => import('../adapters/tier-2/marko.js').then((m) => m.default()),
426
+ });
427
+
428
+ adapterRegistry.register({
429
+ id: 'stencil',
430
+ name: 'Stencil',
431
+ framework: 'stencil',
432
+ tier: 'tier-2',
433
+ capabilities: { islands: true },
434
+ peerDependencies: ['@stencil/core'],
435
+ loader: () => import('../adapters/tier-2/stencil.js').then((m) => m.default()),
436
+ });
437
+
438
+ adapterRegistry.register({
439
+ id: 'mithril',
440
+ name: 'Mithril',
441
+ framework: 'mithril',
442
+ tier: 'tier-2',
443
+ capabilities: {},
444
+ peerDependencies: ['mithril'],
445
+ loader: () => import('../adapters/tier-2/mithril.js').then((m) => m.default()),
446
+ });
447
+
448
+ adapterRegistry.register({
449
+ id: 'inferno',
450
+ name: 'Inferno',
451
+ framework: 'inferno',
452
+ tier: 'tier-2',
453
+ capabilities: { streaming: false },
454
+ peerDependencies: ['inferno'],
455
+ loader: () => import('../adapters/tier-2/inferno.js').then((m) => m.default()),
456
+ });
457
+
458
+ // Tier 3: HTML-First
459
+ adapterRegistry.register({
460
+ id: 'htmx',
461
+ name: 'HTMX',
462
+ framework: 'htmx',
463
+ tier: 'tier-3',
464
+ capabilities: {},
465
+ peerDependencies: [],
466
+ loader: () => import('../adapters/tier-3/htmx.js').then((m) => m.default()),
467
+ });
468
+
469
+ adapterRegistry.register({
470
+ id: 'alpine',
471
+ name: 'Alpine.js',
472
+ framework: 'alpine',
473
+ tier: 'tier-3',
474
+ capabilities: {},
475
+ peerDependencies: [],
476
+ loader: () => import('../adapters/tier-3/alpine.js').then((m) => m.default()),
477
+ });
478
+
479
+ adapterRegistry.register({
480
+ id: 'hotwire',
481
+ name: 'Hotwire',
482
+ framework: 'hotwire',
483
+ tier: 'tier-3',
484
+ capabilities: {},
485
+ peerDependencies: ['@hotwired/turbo'],
486
+ loader: () => import('../adapters/tier-3/hotwire.js').then((m) => m.default()),
487
+ });
488
+
489
+ adapterRegistry.register({
490
+ id: 'stimulus',
491
+ name: 'Stimulus',
492
+ framework: 'stimulus',
493
+ tier: 'tier-3',
494
+ capabilities: {},
495
+ peerDependencies: ['@hotwired/stimulus'],
496
+ loader: () => import('../adapters/tier-3/stimulus.js').then((m) => m.default()),
497
+ });
498
+
499
+ adapterRegistry.register({
500
+ id: 'petite-vue',
501
+ name: 'Petite-vue',
502
+ framework: 'petite-vue',
503
+ tier: 'tier-3',
504
+ capabilities: {},
505
+ peerDependencies: ['petite-vue'],
506
+ loader: () => import('../adapters/tier-3/petite-vue.js').then((m) => m.default()),
507
+ });
508
+
509
+ adapterRegistry.register({
510
+ id: 'vanilla',
511
+ name: 'Vanilla Web Components',
512
+ framework: 'vanilla',
513
+ tier: 'tier-3',
514
+ capabilities: { islands: true },
515
+ peerDependencies: [],
516
+ loader: () => import('../adapters/tier-3/vanilla.js').then((m) => m.default()),
517
+ });
518
+ }