lemonade-sdk 9.1.1__py3-none-any.whl

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 (84) hide show
  1. lemonade/__init__.py +5 -0
  2. lemonade/api.py +180 -0
  3. lemonade/cache.py +92 -0
  4. lemonade/cli.py +173 -0
  5. lemonade/common/__init__.py +0 -0
  6. lemonade/common/build.py +176 -0
  7. lemonade/common/cli_helpers.py +139 -0
  8. lemonade/common/exceptions.py +98 -0
  9. lemonade/common/filesystem.py +368 -0
  10. lemonade/common/inference_engines.py +408 -0
  11. lemonade/common/network.py +93 -0
  12. lemonade/common/printing.py +110 -0
  13. lemonade/common/status.py +471 -0
  14. lemonade/common/system_info.py +1411 -0
  15. lemonade/common/test_helpers.py +28 -0
  16. lemonade/profilers/__init__.py +1 -0
  17. lemonade/profilers/agt_power.py +437 -0
  18. lemonade/profilers/hwinfo_power.py +429 -0
  19. lemonade/profilers/memory_tracker.py +259 -0
  20. lemonade/profilers/profiler.py +58 -0
  21. lemonade/sequence.py +363 -0
  22. lemonade/state.py +159 -0
  23. lemonade/tools/__init__.py +1 -0
  24. lemonade/tools/accuracy.py +432 -0
  25. lemonade/tools/adapter.py +114 -0
  26. lemonade/tools/bench.py +302 -0
  27. lemonade/tools/flm/__init__.py +1 -0
  28. lemonade/tools/flm/utils.py +305 -0
  29. lemonade/tools/huggingface/bench.py +187 -0
  30. lemonade/tools/huggingface/load.py +235 -0
  31. lemonade/tools/huggingface/utils.py +359 -0
  32. lemonade/tools/humaneval.py +264 -0
  33. lemonade/tools/llamacpp/bench.py +255 -0
  34. lemonade/tools/llamacpp/load.py +222 -0
  35. lemonade/tools/llamacpp/utils.py +1260 -0
  36. lemonade/tools/management_tools.py +319 -0
  37. lemonade/tools/mmlu.py +319 -0
  38. lemonade/tools/oga/__init__.py +0 -0
  39. lemonade/tools/oga/bench.py +120 -0
  40. lemonade/tools/oga/load.py +804 -0
  41. lemonade/tools/oga/migration.py +403 -0
  42. lemonade/tools/oga/utils.py +462 -0
  43. lemonade/tools/perplexity.py +147 -0
  44. lemonade/tools/prompt.py +263 -0
  45. lemonade/tools/report/__init__.py +0 -0
  46. lemonade/tools/report/llm_report.py +203 -0
  47. lemonade/tools/report/table.py +899 -0
  48. lemonade/tools/server/__init__.py +0 -0
  49. lemonade/tools/server/flm.py +133 -0
  50. lemonade/tools/server/llamacpp.py +320 -0
  51. lemonade/tools/server/serve.py +2123 -0
  52. lemonade/tools/server/static/favicon.ico +0 -0
  53. lemonade/tools/server/static/index.html +279 -0
  54. lemonade/tools/server/static/js/chat.js +1059 -0
  55. lemonade/tools/server/static/js/model-settings.js +183 -0
  56. lemonade/tools/server/static/js/models.js +1395 -0
  57. lemonade/tools/server/static/js/shared.js +556 -0
  58. lemonade/tools/server/static/logs.html +191 -0
  59. lemonade/tools/server/static/styles.css +2654 -0
  60. lemonade/tools/server/static/webapp.html +321 -0
  61. lemonade/tools/server/tool_calls.py +153 -0
  62. lemonade/tools/server/tray.py +664 -0
  63. lemonade/tools/server/utils/macos_tray.py +226 -0
  64. lemonade/tools/server/utils/port.py +77 -0
  65. lemonade/tools/server/utils/thread.py +85 -0
  66. lemonade/tools/server/utils/windows_tray.py +408 -0
  67. lemonade/tools/server/webapp.py +34 -0
  68. lemonade/tools/server/wrapped_server.py +559 -0
  69. lemonade/tools/tool.py +374 -0
  70. lemonade/version.py +1 -0
  71. lemonade_install/__init__.py +1 -0
  72. lemonade_install/install.py +239 -0
  73. lemonade_sdk-9.1.1.dist-info/METADATA +276 -0
  74. lemonade_sdk-9.1.1.dist-info/RECORD +84 -0
  75. lemonade_sdk-9.1.1.dist-info/WHEEL +5 -0
  76. lemonade_sdk-9.1.1.dist-info/entry_points.txt +5 -0
  77. lemonade_sdk-9.1.1.dist-info/licenses/LICENSE +201 -0
  78. lemonade_sdk-9.1.1.dist-info/licenses/NOTICE.md +47 -0
  79. lemonade_sdk-9.1.1.dist-info/top_level.txt +3 -0
  80. lemonade_server/cli.py +805 -0
  81. lemonade_server/model_manager.py +758 -0
  82. lemonade_server/pydantic_models.py +159 -0
  83. lemonade_server/server_models.json +643 -0
  84. lemonade_server/settings.py +39 -0
@@ -0,0 +1,556 @@
1
+ // Configure MathJax
2
+ window.MathJax = {
3
+ tex: {
4
+ inlineMath: [['\\(', '\\)'], ['$', '$']],
5
+ displayMath: [['\\[', '\\]'], ['$$', '$$']],
6
+ processEscapes: true,
7
+ processEnvironments: true
8
+ },
9
+ options: {
10
+ skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
11
+ }
12
+ };
13
+
14
+ // Configure marked.js for safe HTML rendering
15
+ marked.setOptions({
16
+ breaks: true,
17
+ gfm: true,
18
+ sanitize: false,
19
+ smartLists: true,
20
+ smartypants: true
21
+ });
22
+
23
+ // Function to unescape JSON strings
24
+ function unescapeJsonString(str) {
25
+ try {
26
+ return str.replace(/\\n/g, '\n')
27
+ .replace(/\\t/g, '\t')
28
+ .replace(/\\r/g, '\r')
29
+ .replace(/\\"/g, '"')
30
+ .replace(/\\\\/g, '\\');
31
+ } catch (error) {
32
+ console.error('Error unescaping string:', error);
33
+ return str;
34
+ }
35
+ }
36
+
37
+ // Function to safely render markdown with MathJax support
38
+ function renderMarkdown(text) {
39
+ try {
40
+ const html = marked.parse(text);
41
+ // Trigger MathJax to process the new content
42
+ if (window.MathJax && window.MathJax.typesetPromise) {
43
+ // Use a timeout to ensure DOM is updated before typesetting
44
+ setTimeout(() => {
45
+ window.MathJax.typesetPromise();
46
+ }, 0);
47
+ }
48
+ return html;
49
+ } catch (error) {
50
+ console.error('Error rendering markdown:', error);
51
+ return text; // fallback to plain text
52
+ }
53
+ }
54
+
55
+ // Display an error message in the banner
56
+ function showErrorBanner(msg) {
57
+ showBanner(msg, 'error');
58
+ }
59
+
60
+ // Display a banner with a specific type (error, warning, success)
61
+ function showBanner(msg, type = 'error') {
62
+ // If DOM isn't ready, wait for it
63
+ if (document.readyState === 'loading') {
64
+ document.addEventListener('DOMContentLoaded', () => {
65
+ showBanner(msg, type);
66
+ });
67
+ return;
68
+ }
69
+
70
+ const banner = document.getElementById('error-banner');
71
+ if (!banner) return;
72
+ const msgEl = document.getElementById('error-banner-msg');
73
+ const logsUrl = window.location.origin + '/static/logs.html';
74
+
75
+ // Determine the full message and styling based on type
76
+ let fullMsg = msg;
77
+ let backgroundColor, color;
78
+
79
+ switch(type) {
80
+ case 'success':
81
+ backgroundColor = '#27ae60'; // green
82
+ color = '#ffffff';
83
+ break;
84
+ case 'warning':
85
+ backgroundColor = '#8d5803ff'; // yellow/orange
86
+ color = '#ffffff';
87
+ break;
88
+ case 'error':
89
+ default:
90
+ backgroundColor = '#b10819ff'; // red
91
+ color = '#ffffff';
92
+ fullMsg = `${msg}<br>Check the Lemonade Server logs <a href="${logsUrl}" target="_blank" rel="noopener noreferrer">on the browser</a> or via the system tray app for more information.`;
93
+ break;
94
+ }
95
+
96
+ if (msgEl) {
97
+ msgEl.innerHTML = fullMsg;
98
+ } else {
99
+ banner.innerHTML = fullMsg;
100
+ }
101
+
102
+ banner.style.backgroundColor = backgroundColor;
103
+ banner.style.color = color;
104
+ banner.style.display = 'flex';
105
+ }
106
+
107
+ function hideErrorBanner() {
108
+ const banner = document.getElementById('error-banner');
109
+ if (banner) banner.style.display = 'none';
110
+ }
111
+
112
+ // Helper fetch wrappers that surface server error details
113
+ async function httpRequest(url, options = {}) {
114
+ const resp = await fetch(url, options);
115
+ if (!resp.ok) {
116
+ let detail = resp.statusText || 'Request failed';
117
+ try {
118
+ const contentType = resp.headers.get('content-type') || '';
119
+ if (contentType.includes('application/json')) {
120
+ const data = await resp.json();
121
+ if (data && data.detail) detail = data.detail;
122
+ } else {
123
+ const text = await resp.text();
124
+ if (text) detail = text.trim();
125
+ }
126
+ } catch (_) {}
127
+ throw new Error(detail);
128
+ }
129
+ return resp;
130
+ }
131
+
132
+ async function httpJson(url, options = {}) {
133
+ const resp = await httpRequest(url, options);
134
+ return await resp.json();
135
+ }
136
+
137
+ // Centralized function to update the status indicator
138
+ function updateStatusIndicator(text, state = 'default') {
139
+ const statusText = document.getElementById('model-status-text');
140
+ const statusLight = document.getElementById('status-light');
141
+ const indicator = document.getElementById('model-status-indicator');
142
+
143
+ if (statusText) {
144
+ statusText.textContent = text;
145
+ }
146
+
147
+ if (statusLight) {
148
+ // Set the status light class based on state
149
+ switch (state) {
150
+ case 'loading':
151
+ statusLight.className = 'status-light loading';
152
+ break;
153
+ case 'loaded':
154
+ case 'online':
155
+ statusLight.className = 'status-light online';
156
+ break;
157
+ case 'offline':
158
+ statusLight.className = 'status-light offline';
159
+ break;
160
+ case 'error':
161
+ statusLight.className = 'status-light offline'; // Use offline styling for errors
162
+ break;
163
+ default:
164
+ statusLight.className = 'status-light';
165
+ break;
166
+ }
167
+ }
168
+
169
+ if (indicator) {
170
+ // Also update the indicator container class for consistent styling
171
+ switch (state) {
172
+ case 'loading':
173
+ indicator.className = 'model-status-indicator loading';
174
+ break;
175
+ case 'loaded':
176
+ indicator.className = 'model-status-indicator loaded';
177
+ break;
178
+ case 'online':
179
+ indicator.className = 'model-status-indicator online';
180
+ break;
181
+ case 'offline':
182
+ indicator.className = 'model-status-indicator offline';
183
+ break;
184
+ case 'error':
185
+ indicator.className = 'model-status-indicator offline';
186
+ break;
187
+ default:
188
+ indicator.className = 'model-status-indicator';
189
+ break;
190
+ }
191
+ }
192
+ }
193
+
194
+ // Make status update function globally accessible
195
+ window.updateStatusIndicator = updateStatusIndicator;
196
+
197
+ // Centralized model loading function that can be used across tabs
198
+ async function loadModelStandardized(modelId, options = {}) {
199
+ const {
200
+ loadButton = null, // Optional load button to update
201
+ onLoadingStart = null, // Optional callback for custom loading UI
202
+ onLoadingEnd = null, // Optional callback for custom cleanup
203
+ onSuccess = null, // Optional callback on successful load
204
+ onError = null // Optional callback on error
205
+ } = options;
206
+
207
+ // Store original states for restoration on error
208
+ const originalStatusText = document.getElementById('model-status-text')?.textContent || '';
209
+
210
+ // Track this load operation as active to prevent polling interference
211
+ if (window.activeOperations) {
212
+ window.activeOperations.add(modelId);
213
+ }
214
+
215
+ try {
216
+ // Update load button if provided
217
+ if (loadButton) {
218
+ loadButton.disabled = true;
219
+ loadButton.textContent = '⏳';
220
+ }
221
+
222
+ // Update status indicator to show loading state
223
+ updateStatusIndicator(`Loading ${modelId}...`, 'loading');
224
+
225
+ // Update chat dropdown and send button to show loading state
226
+ const modelSelect = document.getElementById('model-select');
227
+ const sendBtn = document.getElementById('toggle-btn');
228
+ if (modelSelect && sendBtn) {
229
+ // Ensure the model exists in the dropdown options
230
+ let modelOption = modelSelect.querySelector(`option[value="${modelId}"]`);
231
+ if (!modelOption && window.installedModels && window.installedModels.has(modelId)) {
232
+ // Add the model to the dropdown if it doesn't exist but is installed
233
+ modelOption = document.createElement('option');
234
+ modelOption.value = modelId;
235
+ modelOption.textContent = modelId;
236
+ modelSelect.appendChild(modelOption);
237
+ }
238
+
239
+ // Set the dropdown to the new model and disable it
240
+ if (modelOption) {
241
+ modelSelect.value = modelId;
242
+ }
243
+ modelSelect.disabled = true;
244
+ sendBtn.disabled = true;
245
+ sendBtn.textContent = 'Loading...';
246
+
247
+ // Update the loading option text
248
+ const loadingOption = modelSelect.querySelector('option[value=""]');
249
+ if (loadingOption) {
250
+ loadingOption.textContent = `Loading ${modelId}...`;
251
+ }
252
+ }
253
+
254
+ // Call custom loading start callback
255
+ if (onLoadingStart) {
256
+ onLoadingStart(modelId);
257
+ }
258
+
259
+ // Make the API call to load the model
260
+ // Include mmproj if the model has it defined
261
+ const loadPayload = { model_name: modelId };
262
+ const allModels = window.SERVER_MODELS || {};
263
+ const modelData = allModels[modelId];
264
+ if (modelData && modelData.mmproj) {
265
+ loadPayload.mmproj = modelData.mmproj;
266
+ }
267
+
268
+ await httpRequest(getServerBaseUrl() + '/api/v1/load', {
269
+ method: 'POST',
270
+ headers: { 'Content-Type': 'application/json' },
271
+ body: JSON.stringify(loadPayload)
272
+ });
273
+
274
+ // Update model status indicator after successful load
275
+ if (window.updateModelStatusIndicator) {
276
+ await window.updateModelStatusIndicator();
277
+ }
278
+
279
+ // Update chat dropdown value
280
+ if (window.updateModelSelectValue) {
281
+ window.updateModelSelectValue();
282
+ }
283
+
284
+ // Update attachment button state
285
+ if (window.updateAttachmentButtonState) {
286
+ window.updateAttachmentButtonState();
287
+ }
288
+
289
+ // Reset load button if provided
290
+ if (loadButton) {
291
+ loadButton.disabled = false;
292
+ loadButton.textContent = '🚀';
293
+ loadButton.classList.remove('loading');
294
+ }
295
+
296
+ // Reset chat controls
297
+ if (modelSelect && sendBtn) {
298
+ modelSelect.disabled = false;
299
+ sendBtn.disabled = false;
300
+ sendBtn.textContent = 'Send';
301
+
302
+ // Reset the default option text
303
+ const defaultOption = modelSelect.querySelector('option[value=""]');
304
+ if (defaultOption) {
305
+ defaultOption.textContent = 'Click to select a model ▼';
306
+ }
307
+ }
308
+
309
+ // Call custom loading end callback
310
+ if (onLoadingEnd) {
311
+ onLoadingEnd(modelId, true);
312
+ }
313
+
314
+ // Call success callback
315
+ if (onSuccess) {
316
+ onSuccess(modelId);
317
+ }
318
+
319
+ // Remove from active operations on success
320
+ if (window.activeOperations) {
321
+ window.activeOperations.delete(modelId);
322
+ }
323
+
324
+ return true;
325
+
326
+ } catch (error) {
327
+ console.error('Error loading model:', error);
328
+
329
+ // Reset load button if provided
330
+ if (loadButton) {
331
+ loadButton.disabled = false;
332
+ loadButton.textContent = '🚀';
333
+ loadButton.classList.remove('loading');
334
+ }
335
+
336
+ // Reset status indicator on error
337
+ updateStatusIndicator(originalStatusText, 'error');
338
+
339
+ // Reset chat controls on error
340
+ const modelSelect = document.getElementById('model-select');
341
+ const sendBtn = document.getElementById('toggle-btn');
342
+ if (modelSelect && sendBtn) {
343
+ modelSelect.disabled = false;
344
+ sendBtn.disabled = false;
345
+ sendBtn.textContent = 'Send';
346
+
347
+ // Reset dropdown value
348
+ if (window.updateModelSelectValue) {
349
+ window.updateModelSelectValue();
350
+ }
351
+
352
+ // Reset the default option text
353
+ const defaultOption = modelSelect.querySelector('option[value=""]');
354
+ if (defaultOption) {
355
+ defaultOption.textContent = 'Click to select a model ▼';
356
+ }
357
+ }
358
+
359
+ // Call custom loading end callback
360
+ if (onLoadingEnd) {
361
+ onLoadingEnd(modelId, false);
362
+ }
363
+
364
+ // Call error callback and always show default error banner as fallback
365
+ if (onError) {
366
+ onError(error, modelId);
367
+ }
368
+ // Always show error banner to ensure user sees the error
369
+ showErrorBanner('Failed to load model: ' + error.message);
370
+
371
+ // Remove from active operations on error too
372
+ if (window.activeOperations) {
373
+ window.activeOperations.delete(modelId);
374
+ }
375
+
376
+ return false;
377
+ }
378
+ }
379
+
380
+ // Make standardized load function globally accessible
381
+ window.loadModelStandardized = loadModelStandardized;
382
+
383
+ // Tab switching logic
384
+ function showTab(tab, updateHash = true) {
385
+ document.getElementById('tab-chat').classList.remove('active');
386
+ document.getElementById('tab-models').classList.remove('active');
387
+ document.getElementById('tab-model-settings').classList.remove('active');
388
+ document.getElementById('content-chat').classList.remove('active');
389
+ document.getElementById('content-models').classList.remove('active');
390
+ document.getElementById('content-settings').classList.remove('active');
391
+
392
+ if (tab === 'chat') {
393
+ document.getElementById('tab-chat').classList.add('active');
394
+ document.getElementById('content-chat').classList.add('active');
395
+ if (updateHash) {
396
+ window.location.hash = 'llm-chat';
397
+ }
398
+ } else if (tab === 'models') {
399
+ document.getElementById('tab-models').classList.add('active');
400
+ document.getElementById('content-models').classList.add('active');
401
+ if (updateHash) {
402
+ window.location.hash = 'model-management';
403
+ }
404
+ // Ensure model management UI is refreshed with latest data when tab is shown
405
+ // Use setTimeout to ensure this runs after any pending initialization
406
+ setTimeout(() => {
407
+ if (window.refreshModelMgmtUI) {
408
+ window.refreshModelMgmtUI();
409
+ }
410
+ }, 0);
411
+ } else if (tab === 'settings') {
412
+ document.getElementById('tab-model-settings').classList.add('active');
413
+ document.getElementById('content-settings').classList.add('active');
414
+ if (updateHash) {
415
+ window.location.hash = 'model-settings';
416
+ }
417
+ }
418
+ }
419
+
420
+ // Handle hash changes for anchor navigation
421
+ function handleHashChange() {
422
+ const hash = window.location.hash.slice(1); // Remove the # symbol
423
+ if (hash === 'llm-chat') {
424
+ showTab('chat', false);
425
+ } else if (hash === 'model-management') {
426
+ showTab('models', false);
427
+ } else if (hash === 'model-settings') {
428
+ showTab('settings', false);
429
+ }
430
+ }
431
+
432
+ // Initialize tab based on URL hash on page load
433
+ function initializeTabFromHash() {
434
+ const hash = window.location.hash.slice(1);
435
+ if (hash === 'llm-chat') {
436
+ showTab('chat', false);
437
+ } else if (hash === 'model-management') {
438
+ showTab('models', false);
439
+ } else if (hash === 'model-settings') {
440
+ showTab('settings', false);
441
+ }
442
+ // If no hash or unrecognized hash, keep default (chat tab is already active)
443
+ }
444
+
445
+ // Listen for hash changes
446
+ window.addEventListener('hashchange', handleHashChange);
447
+
448
+ // Initialize on page load
449
+ document.addEventListener('DOMContentLoaded', initializeTabFromHash);
450
+
451
+ // Handle image load failures for app logos
452
+ function handleImageFailure(img) {
453
+ const logoItem = img.closest('.app-logo-item');
454
+ if (logoItem) {
455
+ logoItem.classList.add('image-failed');
456
+ }
457
+ }
458
+
459
+ // Set up image error handlers when DOM is loaded
460
+ document.addEventListener('DOMContentLoaded', function() {
461
+ const logoImages = document.querySelectorAll('.app-logo-img');
462
+ logoImages.forEach(function(img) {
463
+ let imageLoaded = false;
464
+
465
+ img.addEventListener('load', function() {
466
+ imageLoaded = true;
467
+ });
468
+
469
+ img.addEventListener('error', function() {
470
+ if (!imageLoaded) {
471
+ handleImageFailure(this);
472
+ }
473
+ });
474
+
475
+ // Also check if image is already broken (cached failure)
476
+ if (img.complete && img.naturalWidth === 0) {
477
+ handleImageFailure(img);
478
+ }
479
+
480
+ // Timeout fallback for slow connections (5 seconds)
481
+ setTimeout(function() {
482
+ if (!imageLoaded && !img.complete) {
483
+ handleImageFailure(img);
484
+ }
485
+ }, 5000);
486
+ });
487
+ });
488
+
489
+ // Helper to get server base URL
490
+ function getServerBaseUrl() {
491
+ const port = window.SERVER_PORT || 8000;
492
+ const host = window.location.hostname || 'localhost';
493
+ return `http://${host}:${port}`;
494
+ }
495
+
496
+ // Check if current model supports vision
497
+ function isVisionModel(modelId) {
498
+ const allModels = window.SERVER_MODELS || {};
499
+ const modelData = allModels[modelId];
500
+ if (modelData && modelData.labels && Array.isArray(modelData.labels)) {
501
+ return modelData.labels.some(label => label.toLowerCase() === 'vision');
502
+ }
503
+ return false;
504
+ }
505
+
506
+ // Helper function to create model name with labels (moved from models.js for chat use)
507
+ function createModelNameWithLabels(modelId, allModels) {
508
+ // Create container for model name and labels
509
+ const container = document.createElement('div');
510
+ container.className = 'model-labels-container';
511
+
512
+ // Add model name
513
+ const nameSpan = document.createElement('span');
514
+ nameSpan.textContent = modelId;
515
+ container.appendChild(nameSpan);
516
+
517
+ // Add labels if they exist
518
+ const modelData = allModels[modelId];
519
+ if (modelData && modelData.labels && Array.isArray(modelData.labels)) {
520
+ modelData.labels.forEach(label => {
521
+ const labelLower = label.toLowerCase();
522
+
523
+ // Skip "hot" labels since they have their own section
524
+ if (labelLower === 'hot') {
525
+ return;
526
+ }
527
+
528
+ const labelSpan = document.createElement('span');
529
+ let labelClass = 'other';
530
+ if (labelLower === 'vision') {
531
+ labelClass = 'vision';
532
+ } else if (labelLower === 'embeddings') {
533
+ labelClass = 'embeddings';
534
+ } else if (labelLower === 'reasoning') {
535
+ labelClass = 'reasoning';
536
+ } else if (labelLower === 'reranking') {
537
+ labelClass = 'reranking';
538
+ } else if (labelLower === 'coding') {
539
+ labelClass = 'coding';
540
+ } else if (labelLower === 'tool-calling') {
541
+ labelClass = 'tool-calling';
542
+ }
543
+ labelSpan.className = `model-label ${labelClass}`;
544
+ labelSpan.textContent = label;
545
+ container.appendChild(labelSpan);
546
+ });
547
+ }
548
+
549
+ return container;
550
+ }
551
+
552
+ // Initialize everything when DOM is loaded
553
+ document.addEventListener('DOMContentLoaded', function() {
554
+ // Model status and browser management is now handled by models.js
555
+ // This shared initialization only handles truly shared functionality
556
+ });