@kbve/droid 0.0.5 → 0.1.1

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 (109) hide show
  1. package/README.md +3 -1
  2. package/comlink.js +1 -7
  3. package/droid.mjs +191 -61
  4. package/index.d.ts +29 -0
  5. package/index.js +9054 -2763
  6. package/lib/gateway/SupabaseGateway.d.ts +38 -0
  7. package/lib/gateway/SupabaseGateway.d.ts.map +1 -0
  8. package/lib/gateway/WorkerCommunication.d.ts +39 -0
  9. package/lib/gateway/WorkerCommunication.d.ts.map +1 -0
  10. package/lib/gateway/WorkerPool.d.ts +55 -0
  11. package/lib/gateway/WorkerPool.d.ts.map +1 -0
  12. package/lib/gateway/capabilities.d.ts +23 -0
  13. package/lib/gateway/capabilities.d.ts.map +1 -0
  14. package/lib/gateway/index.d.ts +9 -0
  15. package/lib/gateway/index.d.ts.map +1 -0
  16. package/lib/gateway/strategies/DirectStrategy.d.ts +52 -0
  17. package/lib/gateway/strategies/DirectStrategy.d.ts.map +1 -0
  18. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts +46 -0
  19. package/lib/gateway/strategies/SharedWorkerStrategy.d.ts.map +1 -0
  20. package/lib/gateway/strategies/WebWorkerStrategy.d.ts +45 -0
  21. package/lib/gateway/strategies/WebWorkerStrategy.d.ts.map +1 -0
  22. package/lib/gateway/types.d.ts +81 -0
  23. package/lib/gateway/types.d.ts.map +1 -0
  24. package/lib/workers/canvas-ui-renderer.d.ts +25 -0
  25. package/lib/workers/canvas-ui-renderer.d.ts.map +1 -0
  26. package/lib/workers/canvas-worker.d.ts +14 -0
  27. package/lib/workers/canvas-worker.d.ts.map +1 -0
  28. package/lib/workers/canvas-worker.js +291 -145
  29. package/lib/workers/data.d.ts +40 -0
  30. package/lib/workers/data.d.ts.map +1 -0
  31. package/lib/workers/db-worker.d.ts +69 -0
  32. package/lib/workers/db-worker.d.ts.map +1 -0
  33. package/lib/workers/db-worker.js +2680 -2147
  34. package/lib/workers/events.d.ts +11 -0
  35. package/lib/workers/events.d.ts.map +1 -0
  36. package/lib/workers/flexbuilder.d.ts +4 -0
  37. package/lib/workers/flexbuilder.d.ts.map +1 -0
  38. package/lib/workers/init.d.ts +11 -0
  39. package/lib/workers/init.d.ts.map +1 -0
  40. package/lib/workers/main.d.ts +107 -0
  41. package/lib/workers/main.d.ts.map +1 -0
  42. package/lib/workers/supabase-db-worker.d.ts +2 -0
  43. package/lib/workers/supabase-db-worker.d.ts.map +1 -0
  44. package/lib/workers/supabase-db-worker.js +9337 -0
  45. package/lib/workers/supabase-shared-worker.d.ts +2 -0
  46. package/lib/workers/supabase-shared-worker.d.ts.map +1 -0
  47. package/lib/workers/supabase-shared-worker.js +12635 -0
  48. package/lib/workers/tools.d.ts +4 -0
  49. package/lib/workers/tools.d.ts.map +1 -0
  50. package/lib/workers/validate.d.ts +15 -0
  51. package/lib/workers/validate.d.ts.map +1 -0
  52. package/lib/workers/ws-worker.d.ts +11 -0
  53. package/lib/workers/ws-worker.d.ts.map +1 -0
  54. package/lib/workers/ws-worker.js +174 -115
  55. package/main.js +4875 -0
  56. package/package.json +17 -6
  57. package/reference.js +688 -228
  58. package/src/index.ts +38 -13
  59. package/src/lib/droid.spec.ts +14 -19
  60. package/src/lib/droid.ts +48 -4
  61. package/src/lib/gateway/SupabaseGateway.ts +183 -0
  62. package/src/lib/gateway/WorkerCommunication.ts +132 -0
  63. package/src/lib/gateway/WorkerPool.ts +304 -0
  64. package/src/lib/gateway/capabilities.ts +80 -0
  65. package/src/lib/gateway/index.ts +15 -0
  66. package/src/lib/gateway/strategies/DirectStrategy.ts +443 -0
  67. package/src/lib/gateway/strategies/SharedWorkerStrategy.ts +278 -0
  68. package/src/lib/gateway/strategies/WebWorkerStrategy.ts +278 -0
  69. package/src/lib/gateway/types.ts +112 -0
  70. package/src/lib/mod/mod-manager.ts +13 -8
  71. package/src/lib/mod/module/bento/mod-bento.worker.ts +1 -1
  72. package/src/lib/mod/module/supabase/mod-supabase.spec.ts +21 -25
  73. package/src/lib/mod/module/supabase/mod-supabase.ts +68 -0
  74. package/src/lib/mod/module/supabase/mod-supabase.worker.ts +1 -56
  75. package/src/lib/state/auth.spec.ts +58 -0
  76. package/src/lib/state/auth.ts +30 -0
  77. package/src/lib/state/index.ts +34 -0
  78. package/src/lib/state/overlay-manager.ts +125 -0
  79. package/src/lib/state/router.ts +24 -0
  80. package/src/lib/state/theme-sync.ts +75 -0
  81. package/src/lib/state/toasts.spec.ts +106 -0
  82. package/src/lib/state/toasts.ts +34 -0
  83. package/src/lib/state/ui.spec.ts +148 -0
  84. package/src/lib/state/ui.ts +45 -0
  85. package/src/lib/state/welcome-toast.ts +76 -0
  86. package/src/lib/types/bento.spec.ts +116 -0
  87. package/src/lib/types/bento.ts +94 -55
  88. package/src/lib/types/event-types.spec.ts +93 -0
  89. package/src/lib/types/event-types.ts +39 -3
  90. package/src/lib/types/modules.ts +12 -5
  91. package/src/lib/types/ui-event-types.ts +66 -0
  92. package/src/lib/workers/canvas-ui-renderer.ts +266 -0
  93. package/src/lib/workers/canvas-worker.ts +94 -9
  94. package/src/lib/workers/data.ts +59 -36
  95. package/src/lib/workers/db-worker.ts +79 -32
  96. package/src/lib/workers/events.spec.ts +208 -0
  97. package/src/lib/workers/events.ts +27 -14
  98. package/src/lib/workers/flexbuilder.ts +2 -2
  99. package/src/lib/workers/init.ts +25 -17
  100. package/src/lib/workers/main.ts +509 -272
  101. package/src/lib/workers/supabase-db-worker.ts +221 -0
  102. package/src/lib/workers/supabase-shared-worker.ts +572 -0
  103. package/src/lib/workers/validate.ts +64 -0
  104. package/src/lib/workers/ws-worker.ts +156 -25
  105. package/src/setup-vitest.ts +4 -2
  106. package/src/types.ts +30 -0
  107. package/src/vite-env.d.ts +1 -0
  108. package/workers/main.js +10 -1089
  109. package/src/types.d.ts +0 -31
package/src/index.ts CHANGED
@@ -1,21 +1,46 @@
1
+ export type { KBVEGlobal } from './types';
2
+
1
3
  export * from './lib/droid';
2
4
  export * from './lib/types/bento';
5
+ export * from './lib/types/event-types';
6
+ export * from './lib/types/panel-types';
7
+ export * from './lib/types/ui-event-types';
8
+ export * from './lib/workers/events';
3
9
  export * from './lib/mod/mod-urls';
10
+ export * from './lib/gateway';
11
+ export * from './lib/state';
12
+
13
+ export type { VirtualNode } from './lib/types/modules';
14
+
15
+ // Worker-side validation
16
+ export { validateUIMessage } from './lib/workers/validate';
17
+ export type {
18
+ ValidatedWorkerMessage,
19
+ UIMessageType,
20
+ } from './lib/workers/validate';
21
+
22
+ // Canvas UI renderer (for direct worker usage)
23
+ export { CanvasUIRenderer } from './lib/workers/canvas-ui-renderer';
24
+
25
+ // Vite ?worker&url imports — bundles each worker as JS and returns the URL string
26
+ import canvasWorkerUrl from './lib/workers/canvas-worker?worker&url';
27
+ import dbWorkerUrl from './lib/workers/db-worker?worker&url';
28
+ import wsWorkerUrl from './lib/workers/ws-worker?worker&url';
29
+ import supabaseSharedWorkerUrl from './lib/workers/supabase-shared-worker?worker&url';
30
+ import supabaseDbWorkerUrl from './lib/workers/supabase-db-worker?worker&url';
4
31
 
5
32
  export const workerURLs = {
6
- canvasWorker: new URL(
7
- './lib/workers/canvas-worker.js',
8
- import.meta.url,
9
- ),
10
- dbWorker: new URL('./lib/workers/db-worker.js', import.meta.url),
11
- wsWorker: new URL('./lib/workers/ws-worker.js', import.meta.url),
33
+ canvasWorker: canvasWorkerUrl,
34
+ dbWorker: dbWorkerUrl,
35
+ wsWorker: wsWorkerUrl,
36
+ supabaseSharedWorker: supabaseSharedWorkerUrl,
37
+ supabaseDbWorker: supabaseDbWorkerUrl,
12
38
  };
13
39
 
14
40
  export const workerStrings = {
15
- canvasWorker: new URL(
16
- './lib/workers/canvas-worker.js',
17
- import.meta.url,
18
- ).toString(),
19
- dbWorker: new URL('./lib/workers/db-worker.js', import.meta.url).toString(),
20
- wsWorker: new URL('./lib/workers/ws-worker.js', import.meta.url).toString(),
21
- };
41
+ canvasWorker: canvasWorkerUrl,
42
+ dbWorker: dbWorkerUrl,
43
+ wsWorker: wsWorkerUrl,
44
+ supabaseSharedWorker: supabaseSharedWorkerUrl,
45
+ supabaseDbWorker: supabaseDbWorkerUrl,
46
+ };
@@ -1,26 +1,21 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
2
  import { droid } from './droid';
3
3
 
4
4
  beforeEach(() => {
5
- delete (window as any).kbve;
5
+ delete (window as unknown as { kbve?: unknown }).kbve;
6
6
  });
7
7
 
8
8
  describe('droid', () => {
9
- it(
10
- 'should initialize and attach to window.kbve',
11
- async () => {
12
- const result = await droid();
9
+ it('should initialize and attach to window.kbve', async () => {
10
+ const result = await droid();
13
11
 
14
- expect(result).toEqual({ initialized: true });
15
- expect(window.kbve).toBeDefined();
16
- expect(window.kbve?.api).toBeDefined();
17
- expect(window.kbve?.i18n).toBeDefined();
18
- expect(window.kbve?.uiux).toBeDefined();
19
- expect(window.kbve?.ws).toBeDefined();
20
- expect(window.kbve?.data).toBeDefined();
21
- expect(window.kbve?.mod).toBeDefined();
22
-
23
- },
24
- 10_000,
25
- );
26
- });
12
+ expect(result).toEqual({ initialized: true });
13
+ expect(window.kbve).toBeDefined();
14
+ expect(window.kbve?.api).toBeDefined();
15
+ expect(window.kbve?.i18n).toBeDefined();
16
+ expect(window.kbve?.uiux).toBeDefined();
17
+ expect(window.kbve?.ws).toBeDefined();
18
+ expect(window.kbve?.data).toBeDefined();
19
+ expect(window.kbve?.mod).toBeDefined();
20
+ }, 10_000);
21
+ });
package/src/lib/droid.ts CHANGED
@@ -1,7 +1,51 @@
1
- export async function droid(opts?: { workerURLs?: Record<string, string> }): Promise<{ initialized: boolean }> {
1
+ export {
2
+ downscale,
3
+ upscale,
4
+ getScaleLevel,
5
+ type DroidScaleLevel,
6
+ } from './workers/main.js';
7
+
8
+ export async function droid(opts?: {
9
+ workerURLs?: Record<string, string>;
10
+ workerRefs?: {
11
+ canvasWorker?: Worker;
12
+ dbWorker?: SharedWorker;
13
+ wsWorker?: SharedWorker;
14
+ };
15
+ i18nPath?: string;
16
+ dataPath?: string;
17
+ /** Maximum time (ms) to wait for worker initialization before rejecting. Default: no timeout. */
18
+ initTimeout?: number;
19
+ }): Promise<{ initialized: boolean }> {
2
20
  console.log('[DROID]: droid<T>');
21
+
3
22
  const { main } = await import('./workers/main.js');
4
- await main({ workerURLs: opts?.workerURLs });
5
- console.log('[DROID]: droid<T> => await WorkerURLs');
23
+
24
+ const initPromise = main({
25
+ workerURLs: opts?.workerURLs,
26
+ workerRefs: opts?.workerRefs,
27
+ i18nPath: opts?.i18nPath,
28
+ dataPath: opts?.dataPath,
29
+ });
30
+
31
+ if (opts?.initTimeout && opts.initTimeout > 0) {
32
+ const timeout = new Promise<never>((_, reject) =>
33
+ setTimeout(
34
+ () =>
35
+ reject(
36
+ new Error(
37
+ `[DROID] Worker init timed out after ${opts.initTimeout}ms`,
38
+ ),
39
+ ),
40
+ opts.initTimeout,
41
+ ),
42
+ );
43
+ await Promise.race([initPromise, timeout]);
44
+ } else {
45
+ await initPromise;
46
+ }
47
+
48
+ console.log('[DROID]: droid<T> => await WorkerRefs + URLs');
49
+
6
50
  return { initialized: true };
7
- }
51
+ }
@@ -0,0 +1,183 @@
1
+ // Unified gateway for Supabase operations with automatic strategy selection
2
+
3
+ import type {
4
+ ISupabaseStrategy,
5
+ SelectOptions,
6
+ SessionResponse,
7
+ WebSocketStatus,
8
+ StrategyType,
9
+ GatewayConfig,
10
+ } from './types';
11
+ import {
12
+ detectCapabilities,
13
+ selectStrategy,
14
+ logCapabilities,
15
+ getStrategyDescription,
16
+ } from './capabilities';
17
+ import { SharedWorkerStrategy } from './strategies/SharedWorkerStrategy';
18
+ import { WebWorkerStrategy } from './strategies/WebWorkerStrategy';
19
+ import { DirectStrategy } from './strategies/DirectStrategy';
20
+
21
+ // Vite ?worker&url imports — bundles workers as JS and returns their URL
22
+ import defaultSharedWorkerUrl from '../workers/supabase-shared-worker?worker&url';
23
+ import defaultDbWorkerUrl from '../workers/supabase-db-worker?worker&url';
24
+
25
+ /**
26
+ * SupabaseGateway: Unified interface for all Supabase operations
27
+ *
28
+ * Automatically selects the best strategy based on browser capabilities:
29
+ * 1. SharedWorker + DB Worker Pool (desktop: Chrome, Firefox, Edge)
30
+ * 2. WebSocket Worker + DB Worker Pool (Android, Safari)
31
+ * 3. Direct/Main thread (fallback)
32
+ *
33
+ * All strategies implement the same interface, so application code is unchanged.
34
+ */
35
+ export class SupabaseGateway implements ISupabaseStrategy {
36
+ private strategy: ISupabaseStrategy;
37
+ private strategyType: StrategyType;
38
+
39
+ constructor(config: GatewayConfig = {}) {
40
+ const capabilities = detectCapabilities();
41
+ logCapabilities(capabilities);
42
+
43
+ this.strategyType =
44
+ config.forceStrategy || selectStrategy(capabilities);
45
+ console.log(
46
+ `[SupabaseGateway] Selected strategy: ${getStrategyDescription(this.strategyType)}`,
47
+ );
48
+
49
+ const poolSize = config.poolSize ?? 3;
50
+ const workerUrls = config.workerUrls ?? {};
51
+
52
+ switch (this.strategyType) {
53
+ case 'shared-worker': {
54
+ const sharedUrl =
55
+ workerUrls.sharedWorker ?? defaultSharedWorkerUrl;
56
+ const dbUrl = workerUrls.dbWorker ?? defaultDbWorkerUrl;
57
+ this.strategy = new SharedWorkerStrategy(
58
+ sharedUrl,
59
+ dbUrl,
60
+ poolSize,
61
+ );
62
+ break;
63
+ }
64
+ case 'web-worker': {
65
+ const wsUrl =
66
+ workerUrls.webSocketWorker ?? defaultSharedWorkerUrl;
67
+ const dbUrl = workerUrls.dbWorker ?? defaultDbWorkerUrl;
68
+ this.strategy = new WebWorkerStrategy(wsUrl, dbUrl, poolSize);
69
+ break;
70
+ }
71
+ case 'direct':
72
+ this.strategy = new DirectStrategy();
73
+ break;
74
+ }
75
+ }
76
+
77
+ getStrategyType(): StrategyType {
78
+ return this.strategyType;
79
+ }
80
+
81
+ getStrategyDescription(): string {
82
+ return getStrategyDescription(this.strategyType);
83
+ }
84
+
85
+ // Delegate all methods to the selected strategy
86
+
87
+ init(
88
+ url: string,
89
+ anonKey: string,
90
+ options?: Record<string, unknown>,
91
+ ): Promise<SessionResponse> {
92
+ return this.strategy.init(url, anonKey, options);
93
+ }
94
+
95
+ on(event: string, callback: (payload: unknown) => void): () => void {
96
+ return this.strategy.on(event, callback);
97
+ }
98
+
99
+ getSession(): Promise<SessionResponse> {
100
+ return this.strategy.getSession();
101
+ }
102
+
103
+ signInWithPassword(
104
+ email: string,
105
+ password: string,
106
+ ): Promise<SessionResponse> {
107
+ return this.strategy.signInWithPassword(email, password);
108
+ }
109
+
110
+ signOut(): Promise<void> {
111
+ return this.strategy.signOut();
112
+ }
113
+
114
+ select(table: string, opts?: SelectOptions): Promise<unknown[]> {
115
+ return this.strategy.select(table, opts);
116
+ }
117
+
118
+ insert(
119
+ table: string,
120
+ data: Record<string, unknown> | Record<string, unknown>[],
121
+ ): Promise<unknown[]> {
122
+ return this.strategy.insert(table, data);
123
+ }
124
+
125
+ update(
126
+ table: string,
127
+ data: Record<string, unknown>,
128
+ match: Record<string, unknown>,
129
+ ): Promise<unknown[]> {
130
+ return this.strategy.update(table, data, match);
131
+ }
132
+
133
+ upsert(
134
+ table: string,
135
+ data: Record<string, unknown> | Record<string, unknown>[],
136
+ ): Promise<unknown[]> {
137
+ return this.strategy.upsert(table, data);
138
+ }
139
+
140
+ delete(table: string, match: Record<string, unknown>): Promise<unknown[]> {
141
+ return this.strategy.delete(table, match);
142
+ }
143
+
144
+ rpc(fn: string, args?: Record<string, unknown>): Promise<unknown> {
145
+ return this.strategy.rpc(fn, args);
146
+ }
147
+
148
+ subscribePostgres(
149
+ key: string,
150
+ params: Record<string, unknown>,
151
+ callback: (payload: unknown) => void,
152
+ ): () => void {
153
+ return this.strategy.subscribePostgres(key, params, callback);
154
+ }
155
+
156
+ connectWebSocket(wsUrl?: string): Promise<WebSocketStatus> {
157
+ return this.strategy.connectWebSocket(wsUrl);
158
+ }
159
+
160
+ disconnectWebSocket(): Promise<void> {
161
+ return this.strategy.disconnectWebSocket();
162
+ }
163
+
164
+ sendWebSocketMessage(data: unknown): Promise<void> {
165
+ return this.strategy.sendWebSocketMessage(data);
166
+ }
167
+
168
+ getWebSocketStatus(): Promise<WebSocketStatus> {
169
+ return this.strategy.getWebSocketStatus();
170
+ }
171
+
172
+ onWebSocketMessage(callback: (message: unknown) => void): () => void {
173
+ return this.strategy.onWebSocketMessage(callback);
174
+ }
175
+
176
+ onWebSocketStatus(callback: (status: WebSocketStatus) => void): () => void {
177
+ return this.strategy.onWebSocketStatus(callback);
178
+ }
179
+
180
+ terminate() {
181
+ this.strategy.terminate();
182
+ }
183
+ }
@@ -0,0 +1,132 @@
1
+ // Unified communication layer for all workers (SharedWorker, WebWorker, main thread)
2
+ // Uses BroadcastChannel for real-time events
3
+
4
+ import type { BroadcastEvent } from './types';
5
+
6
+ /**
7
+ * WorkerCommunication: Unified communication layer for workers
8
+ *
9
+ * Features:
10
+ * - BroadcastChannel for real-time events
11
+ * - Works in SharedWorker, WebWorker, and main thread
12
+ *
13
+ * Note: This layer does NOT open IndexedDB. The SharedWorker is the single
14
+ * writer to the auth database (sb-auth-v2). All other contexts receive
15
+ * auth state via BroadcastChannel or postMessage.
16
+ */
17
+ export class WorkerCommunication {
18
+ private bc: BroadcastChannel | null = null;
19
+ private listeners = new Map<string, Set<(payload: unknown) => void>>();
20
+ private channelName: string;
21
+
22
+ constructor(channelName = 'supabase_events') {
23
+ this.channelName = channelName;
24
+ this.initBroadcastChannel();
25
+ }
26
+
27
+ private initBroadcastChannel() {
28
+ try {
29
+ if (typeof BroadcastChannel !== 'undefined') {
30
+ this.bc = new BroadcastChannel(this.channelName);
31
+ this.bc.onmessage = (e: MessageEvent) =>
32
+ this.handleBroadcast(e.data);
33
+ }
34
+ } catch (err) {
35
+ console.error(
36
+ '[WorkerCommunication] Failed to initialize BroadcastChannel:',
37
+ err,
38
+ );
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Broadcast an event to all workers and tabs
44
+ */
45
+ broadcast(event: BroadcastEvent) {
46
+ if (this.bc) {
47
+ try {
48
+ this.bc.postMessage(event);
49
+ } catch (err) {
50
+ console.error('[WorkerCommunication] Broadcast failed:', err);
51
+ }
52
+ }
53
+ }
54
+
55
+ private handleBroadcast(event: BroadcastEvent) {
56
+ const { type, key } = event;
57
+
58
+ if (type === 'realtime' && key) {
59
+ this.emit(`realtime:${key}`, event.payload);
60
+ } else {
61
+ this.emit(type, event);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Subscribe to events (local and broadcast)
67
+ */
68
+ on(event: string, callback: (payload: unknown) => void): () => void {
69
+ if (!this.listeners.has(event)) {
70
+ this.listeners.set(event, new Set());
71
+ }
72
+ this.listeners.get(event)?.add(callback);
73
+
74
+ return () => {
75
+ const set = this.listeners.get(event);
76
+ if (set) {
77
+ set.delete(callback);
78
+ if (set.size === 0) {
79
+ this.listeners.delete(event);
80
+ }
81
+ }
82
+ };
83
+ }
84
+
85
+ private emit(event: string, payload: unknown) {
86
+ const listeners = this.listeners.get(event);
87
+ if (listeners) {
88
+ listeners.forEach((cb) => {
89
+ try {
90
+ cb(payload);
91
+ } catch (err) {
92
+ console.error(
93
+ `[WorkerCommunication] Listener error for ${event}:`,
94
+ err,
95
+ );
96
+ }
97
+ });
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Check if BroadcastChannel is available
103
+ */
104
+ hasBroadcastChannel(): boolean {
105
+ return this.bc !== null;
106
+ }
107
+
108
+ /**
109
+ * Close connections
110
+ */
111
+ close() {
112
+ if (this.bc) {
113
+ this.bc.close();
114
+ this.bc = null;
115
+ }
116
+ this.listeners.clear();
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Create a singleton instance for use across workers
122
+ */
123
+ let _instance: WorkerCommunication | null = null;
124
+
125
+ export function getWorkerCommunication(
126
+ channelName?: string,
127
+ ): WorkerCommunication {
128
+ if (!_instance) {
129
+ _instance = new WorkerCommunication(channelName);
130
+ }
131
+ return _instance;
132
+ }