litewire 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.MD ADDED
@@ -0,0 +1,263 @@
1
+ # Litewire Framework
2
+
3
+ ## Complete Architecture Manual & Reference Guide
4
+
5
+ A comprehensive technical breakdown of the HTML-driven AJAX engine, dynamic component loader, DOM swapping, state management, and lifecycle events.
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ 1. [Architecture Overview & Lifecycle](#1-architecture-overview--lifecycle)
12
+ 2. [Core Configuration & Initialization](#2-core-configuration--initialization)
13
+ 3. [Attribute Reference API](#3-attribute-reference-api)
14
+ 4. [Dynamic ES Module Loader (`lw-component`)](#4-dynamic-es-module-loader-lw-component)
15
+ 5. [DOM Swapping & Navigation Mechanisms](#5-dom-swapping--navigation-mechanisms)
16
+ 6. [History & State Caching](#6-history--state-caching)
17
+ 7. [Event System & Lifecycle Hooks](#7-event-system--lifecycle-hooks)
18
+ 8. [CSRF & Security Protocols](#8-csrf--security-protocols)
19
+ 9. [Practical Implementation Patterns](#9-practical-implementation-patterns)
20
+
21
+ ---
22
+
23
+ ## 1. Architecture Overview & Lifecycle
24
+
25
+ **Litewire** is an HTML-first AJAX engine and dynamic component loader designed to build modern, interactive single-page-like applications with minimal client-side JavaScript configuration. By extending standard HTML elements with custom `lw-*` attributes, Litewire automatically intercepts user interactions, initiates asynchronous HTTP requests, updates specific DOM regions, and manages dynamic ES Module lifecycles.
26
+
27
+ > **Core Principles**
28
+ > Litewire eliminates the need for full-page reloads and complex SPA frameworks by leveraging declarative markup, dynamic MutationObservers, and native browser features like `fetch()` and `history.pushState()`.
29
+
30
+ ### Lifecycle Flow
31
+
32
+ 1. **Initialization:** The class resolves the application's base URL and attaches DOM observers.
33
+ 2. **Document Scanning:** Existing DOM nodes are scanned for request triggers and dynamic components.
34
+ 3. **Event Binding:** Intercepts clicks, form submissions, and page load triggers automatically.
35
+ 4. **Execution:** Sends non-blocking background HTTP requests with built-in CSRF security headers.
36
+ 5. **Swap & Mount:** Replaces target DOM regions with backend HTML and automatically boots dynamic JS components on newly introduced elements.
37
+
38
+ ---
39
+
40
+ ## 2. Core Configuration & Initialization
41
+
42
+ Litewire auto-instantiates as soon as the DOM is ready, exposing its instance globally on `window.litewire`.
43
+
44
+ ### Base URL Resolution Priority
45
+
46
+ To support deployment in deeply nested directories or custom app sub-paths, Litewire resolves its root URL using a four-tier fallback mechanism:
47
+
48
+ ```text
49
+ 1. Constructor Option: new Litewire({ baseUrl: '[https://example.com/api](https://example.com/api)' })
50
+ 2. Meta Tag Element: <meta name="base-url" content="[https://example.com](https://example.com)">
51
+ 3. Global App Config: window.AppConfig.baseUrl
52
+ 4. Window Location: window.location.origin (Default)
53
+ ```
54
+
55
+ ### Instantiation Example
56
+
57
+ ```javascript
58
+ // Custom manual instantiation with options
59
+ const customLitewire = new Litewire({
60
+ baseUrl: '[https://api.myproject.com](https://api.myproject.com)',
61
+ loadingClass: 'is-loading' // Class applied to active triggers and indicators
62
+ });
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 3. Attribute Reference API
68
+
69
+ All core functionalities are driven by attaching `lw-*` attributes directly to standard HTML tags.
70
+
71
+ | Attribute | Accepted Values | Default | Functional Description |
72
+ |---|---|---|---|
73
+ | `lw-get` | Relative / Absolute Path | None | Executes an HTTP GET request to the specified endpoint. |
74
+ | `lw-post` | Relative / Absolute Path | None | Executes an HTTP POST request. Submits form payload if bound to or inside a `<form>`. |
75
+ | `lw-put` | Relative / Absolute Path | None | Executes an HTTP PUT request with FormData payload attachment. |
76
+ | `lw-delete` | Relative / Absolute Path | None | Executes an HTTP DELETE request. |
77
+ | `lw-trigger` | `click`, `submit`, `load`, custom | Contextual | Overrides trigger event. Defaults to `submit` for forms, `click` for interactive tags. `load` fires instantly. |
78
+ | `lw-target` | CSS Selector | Self Element | Specifies the container element where the returned HTML response will be rendered. |
79
+ | `lw-swap` | `innerHTML`, `outerHTML`, `prepend`, `append` | `innerHTML` | Controls how the received HTML response replaces or integrates into the target element. |
80
+ | `lw-indicator` | CSS Selector | `.litewire-indicator` | Specifies target loading elements. Automatically toggles the active `loadingClass` during request execution. |
81
+ | `lw-push-url` | `true`, `false`, Custom Path | `false` | Pushes a new state to the browser history, caching DOM contents for native back/forward navigation. |
82
+ | `lw-component` | JS File Path | None | Asynchronously imports a JavaScript module and mounts it directly onto the host DOM element. |
83
+
84
+ ---
85
+
86
+ ## 4. Dynamic ES Module Loader (`lw-component`)
87
+
88
+ Litewire features a client-side component loader capable of fetching and initializing JavaScript ES modules on demand without requiring heavy bundle configurations or static page imports.
89
+
90
+ ### Component Mounting Process
91
+
92
+ When an element with `lw-component="path/to/module.js"` is injected into the DOM:
93
+
94
+ 1. Litewire resolves the full script path against `this.baseUrl`.
95
+ 2. Executes a native dynamic `import(fullPath)` statement.
96
+ 3. Extracts component constructors or functions via fallback export resolution:
97
+ `module.default` → `module.imageUploader` → `Object.values(module)[0]`
98
+ 4. Instantiates the module using `new componentFn(el, params)` or direct function execution.
99
+ 5. Passes all `data-*` HTML attributes as an object to the component's `params` argument.
100
+
101
+ ### Component Implementation Example
102
+
103
+ #### HTML Markup
104
+
105
+ ```html
106
+ <!-- Target element containing component directives and dataset parameters -->
107
+ <div
108
+ lw-component="assets/js/uploader.js"
109
+ data-max-files="5"
110
+ data-allowed-types="image/png,image/jpeg">
111
+ </div>
112
+ ```
113
+
114
+ #### JavaScript Module (`assets/js/uploader.js`)
115
+
116
+ ```javascript
117
+ export default class ImageUploader {
118
+ constructor(element, params) {
119
+ this.container = element;
120
+ this.maxFiles = params.maxFiles || 1;
121
+ this.allowedTypes = params.allowedTypes || '*';
122
+
123
+ this.render();
124
+ }
125
+
126
+ render() {
127
+ this.container.innerHTML = `
128
+ <div class="upload-box">
129
+ <p>Upload up to ${this.maxFiles} files (${this.allowedTypes})</p>
130
+ <input type="file" multiple accept="${this.allowedTypes}">
131
+ </div>
132
+ `;
133
+ }
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 5. DOM Swapping & Navigation Mechanisms
140
+
141
+ Litewire supports multiple strategies for swapping returned server HTML responses into target elements using the `lw-swap` attribute.
142
+
143
+ ### Swap Modes
144
+
145
+ - **`innerHTML` (Default):** Replaces the complete inner HTML content of the target container.
146
+ - **`outerHTML`:** Completely replaces the target element itself with the server response.
147
+ - **`prepend`:** Inserts the new server HTML snippet right before the first child inside the target element.
148
+ - **`append`:** Appends the new server HTML snippet right after the last child inside the target element.
149
+
150
+ ### Automated Mutation Monitoring
151
+
152
+ Litewire uses an internal `MutationObserver` attached to `document.body`. Whenever new DOM elements are appended via AJAX swaps, standard page renders, or dynamic JS scripts, Litewire automatically scans and binds all newly discovered `lw-*` elements and mounts dynamic `lw-component` directives seamlessly.
153
+
154
+ ---
155
+
156
+ ## 6. History & State Caching
157
+
158
+ Enabling history tracking via `lw-push-url="true"` allows AJAX-driven applications to retain full browser history support, enabling smooth back-and-forward navigation without page refreshes.
159
+
160
+ ### How State Caching Works
161
+
162
+ 1. When a request completes successfully, Litewire captures the target container's current `innerHTML`.
163
+ 2. Saves an object containing `{ litewireUrl, targetSelector, html }` into `window.history.state`.
164
+ 3. When users press the browser's **Back** or **Forward** buttons, a `popstate` event fires.
165
+ 4. Litewire retrieves the cached HTML snippet directly from history state and restores the DOM instantly without initiating network requests.
166
+ 5. If no cached HTML state exists, Litewire seamlessly falls back to re-fetching the current location URL.
167
+
168
+ ---
169
+
170
+ ## 7. Event System & Lifecycle Hooks
171
+
172
+ Litewire dispatches standard, bubbling DOM events during the request lifecycles. Custom JavaScript code can hook into these lifecycle stages using standard `addEventListener` calls.
173
+
174
+ | Event Name | `event.detail` | Description / Usage |
175
+ |---|---|---|
176
+ | `litewire:beforeRequest` | `null` | Fires immediately before the HTTP request is initiated. Ideal for disabling inputs or custom client validation. |
177
+ | `litewire:afterRequest` | `null` | Fires after the request succeeds and the HTML content swap is complete. Ideal for triggering animations. |
178
+ | `litewire:error` | `{ error: Error }` | Fires if a network error occurs or the HTTP response returns an error status (non-2xx). |
179
+
180
+ ### Lifecycle Hooks Example
181
+
182
+ ```javascript
183
+ // Global logging and notification system integration
184
+ document.addEventListener('litewire:beforeRequest', (e) => {
185
+ console.log('Initiating Litewire request from:', e.target);
186
+ });
187
+
188
+ document.addEventListener('litewire:error', (e) => {
189
+ alert(`Request failed: ${e.detail.error.message}`);
190
+ });
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 8. CSRF & Security Protocols
196
+
197
+ Litewire natively secures outgoing write operations (`POST`, `PUT`, `DELETE`) against Cross-Site Request Forgery (CSRF) attacks.
198
+
199
+ ### Automatic Token Attachment
200
+
201
+ Before dispatching non-GET requests, Litewire scans the host page head for a CSRF meta tag:
202
+
203
+ ```html
204
+ <meta name="csrf-token" content="abc123securehash456">
205
+ ```
206
+
207
+ If detected, Litewire automatically includes the retrieved token into the HTTP request headers:
208
+
209
+ ```text
210
+ X-CSRF-TOKEN: abc123securehash456
211
+ ```
212
+
213
+ ---
214
+
215
+ ## 9. Practical Implementation Patterns
216
+
217
+ ### Pattern A: Instant Dynamic Search Table
218
+
219
+ ```html
220
+ <!-- Live search input updating target table and browser address bar -->
221
+ <input
222
+ type="text"
223
+ name="q"
224
+ placeholder="Search users..."
225
+ lw-get="/users/search"
226
+ lw-trigger="keyup"
227
+ lw-target="#user-table-body"
228
+ lw-push-url="true">
229
+
230
+ <table>
231
+ <tbody id="user-table-body">
232
+ <!-- Table rows updated dynamically -->
233
+ </tbody>
234
+ </table>
235
+ ```
236
+
237
+ ### Pattern B: Form Submission with Indicator & Append Swap
238
+
239
+ ```html
240
+ <form lw-post="/comments/add" lw-target="#comments-list" lw-swap="append" lw-indicator="#spinner">
241
+ <textarea name="comment" required placeholder="Write a comment..."></textarea>
242
+
243
+ <button type="submit">
244
+ Post Comment
245
+ <span id="spinner" class="litewire-indicator hidden">Posting...</span>
246
+ </button>
247
+ </form>
248
+
249
+ <div id="comments-list">
250
+ <!-- New comments prepended or appended dynamically -->
251
+ </div>
252
+ ```
253
+
254
+ ### Pattern C: Lazy-Loading Section on Page Load
255
+
256
+ ```html
257
+ <!-- Automatically fetches and replaces content once page loads -->
258
+ <div lw-get="/analytics/widget" lw-trigger="load" lw-target="#analytics-container">
259
+ <p>Loading real-time analytics data...</p>
260
+ </div>
261
+
262
+ <div id="analytics-container"></div>
263
+ ```
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "litewire",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight HTML-driven AJAX engine and dynamic ES module component loader.",
5
+ "main": "src/litewire.js",
6
+ "module": "src/litewire.js",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": "./src/litewire.js"
10
+ },
11
+ "files": [
12
+ "src/",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "keywords": [
17
+ "ajax",
18
+ "htmx",
19
+ "html-over-the-wire",
20
+ "components",
21
+ "dom-observer"
22
+ ],
23
+ "author": "Zainurrahman <languaojs@gmail.com>",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/languaojs/litewire.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/languaojs/litewire/issues"
31
+ },
32
+ "homepage": "https://github.com/languaojs/litewire#readme"
33
+ }
@@ -0,0 +1,247 @@
1
+ class Litewire {
2
+ constructor(options = {}) {
3
+ const metaBaseUrl = document.querySelector('meta[name="base-url"]')?.getAttribute('content');
4
+ const rawBaseUrl = options.baseUrl
5
+ || metaBaseUrl
6
+ || window.AppConfig?.baseUrl
7
+ || window.location.origin;
8
+ this.baseUrl = rawBaseUrl.replace(/\/+$/, '');
9
+ this.loadingClass = options.loadingClass || 'litewire-request';
10
+ this.init();
11
+ }
12
+
13
+ init() {
14
+ this.scan(document);
15
+ this.loadComponents(document);
16
+ this.observe();
17
+ this.listenToHistory();
18
+ }
19
+
20
+ async loadComponents(root) {
21
+ const selector = '[lw-component]';
22
+ const elements = root.querySelectorAll ? root.querySelectorAll(selector) : [];
23
+
24
+ if (root.nodeType === Node.ELEMENT_NODE && root.matches(selector)) {
25
+ this.mountComponent(root);
26
+ }
27
+ elements.forEach(el => this.mountComponent(el));
28
+ }
29
+
30
+ async mountComponent(el) {
31
+ if (el._litewireComponentMounted) return;
32
+ el._litewireComponentMounted = true;
33
+
34
+ const rawPath = el.getAttribute('lw-component');
35
+ if (!rawPath) return;
36
+
37
+ const cleanPath = rawPath.replace(/^\/+/, '');
38
+ const fullPath = `${this.baseUrl}/${cleanPath}`;
39
+
40
+ try {
41
+ const module = await import(fullPath);
42
+ const params = { ...el.dataset };
43
+
44
+ const componentFn = module.default || module.imageUploader || Object.values(module)[0];
45
+
46
+ if (typeof componentFn === 'function') {
47
+ try {
48
+ new componentFn(el, params);
49
+ } catch {
50
+ componentFn(el, params);
51
+ }
52
+ } else {
53
+ console.error(`[Litewire Error] No valid export found in module: ${fullPath}`);
54
+ }
55
+ } catch (err) {
56
+ console.error(`[Litewire Error] Failed to import component from ${fullPath}:`, err);
57
+ }
58
+ }
59
+
60
+ scan(root) {
61
+ const selector = '[lw-get], [lw-post], [lw-put], [lw-delete], [lw-trigger="load"]';
62
+ const elements = root.querySelectorAll ? root.querySelectorAll(selector) : [];
63
+
64
+ if (root.nodeType === Node.ELEMENT_NODE && root.matches(selector)) {
65
+ this.bindElement(root);
66
+ }
67
+ elements.forEach(el => this.bindElement(el));
68
+ }
69
+
70
+ bindElement(el) {
71
+ if (el._litewireBound) return;
72
+ el._litewireBound = true;
73
+
74
+ const trigger = el.getAttribute('lw-trigger') || (el.tagName === 'FORM' ? 'submit' : 'click');
75
+
76
+ if (trigger === 'load') {
77
+ this.executeRequest(el);
78
+ } else {
79
+ el.addEventListener(trigger, (e) => {
80
+ if (el.tagName === 'FORM' || trigger === 'click') e.preventDefault();
81
+ this.executeRequest(el);
82
+ });
83
+ }
84
+ }
85
+
86
+ getIndicators(el) {
87
+ const indicatorAttr = el.getAttribute('lw-indicator');
88
+ if (!indicatorAttr) {
89
+ return Array.from(el.querySelectorAll('.litewire-indicator'));
90
+ }
91
+ return Array.from(document.querySelectorAll(indicatorAttr));
92
+ }
93
+
94
+ async executeRequest(el, isPopState = false) {
95
+ const method = ['post', 'put', 'delete', 'get'].find(m => el.hasAttribute(`lw-${m}`)) || 'get';
96
+ const path = el.getAttribute(`lw-${method}`);
97
+ if (!path) return;
98
+
99
+ const cleanPath = path.replace(/^\/+/, '');
100
+ const url = `${this.baseUrl}/${cleanPath}`;
101
+
102
+ const options = { method: method.toUpperCase(), headers: {} };
103
+
104
+ const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
105
+ if (csrfToken) {
106
+ options.headers['X-CSRF-TOKEN'] = csrfToken;
107
+ }
108
+
109
+ if (method !== 'get') {
110
+ const form = el.tagName === 'FORM' ? el : el.closest('form');
111
+ if (form) {
112
+ options.body = new FormData(form);
113
+ }
114
+ }
115
+
116
+ const indicators = this.getIndicators(el);
117
+
118
+ try {
119
+ el.classList.add(this.loadingClass);
120
+ indicators.forEach(ind => ind.classList.add(this.loadingClass));
121
+
122
+ el.dispatchEvent(new CustomEvent('litewire:beforeRequest', { bubbles: true }));
123
+
124
+ const response = await fetch(url, options);
125
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
126
+ const html = await response.text();
127
+
128
+ const target = this.swapHTML(el, html);
129
+
130
+ if (!isPopState) {
131
+ this.handleHistoryPush(el, url, target);
132
+ }
133
+
134
+ el.dispatchEvent(new CustomEvent('litewire:afterRequest', { bubbles: true }));
135
+ } catch (err) {
136
+ console.error(`[Litewire Error] ${method.toUpperCase()} ${url} failed:`, err);
137
+ el.dispatchEvent(new CustomEvent('litewire:error', { bubbles: true, detail: { error: err } }));
138
+ } finally {
139
+ el.classList.remove(this.loadingClass);
140
+ indicators.forEach(ind => ind.classList.remove(this.loadingClass));
141
+ }
142
+ }
143
+
144
+ swapHTML(el, html) {
145
+ const targetSelector = el.getAttribute('lw-target');
146
+ const target = targetSelector ? document.querySelector(targetSelector) : el;
147
+ const swapType = el.getAttribute('lw-swap') || 'innerHTML';
148
+
149
+ if (!target) return target;
150
+
151
+ if (swapType === 'outerHTML') {
152
+ const parent = target.parentElement;
153
+ target.outerHTML = html;
154
+ if (parent) {
155
+ this.scan(parent);
156
+ this.loadComponents(parent);
157
+ }
158
+ } else if (swapType === 'prepend') {
159
+ target.insertAdjacentHTML('afterbegin', html);
160
+ this.scan(target);
161
+ this.loadComponents(target);
162
+ } else if (swapType === 'append') {
163
+ target.insertAdjacentHTML('beforeend', html);
164
+ this.scan(target);
165
+ this.loadComponents(target);
166
+ } else {
167
+ target.innerHTML = html;
168
+ this.scan(target);
169
+ this.loadComponents(target);
170
+ }
171
+
172
+ return target;
173
+ }
174
+
175
+ handleHistoryPush(el, requestUrl, target) {
176
+ const pushAttr = el.getAttribute('lw-push-url');
177
+ if (!pushAttr || pushAttr === 'false') return;
178
+
179
+ const newUrl = pushAttr === 'true' ? requestUrl : pushAttr;
180
+ const targetSelector = el.getAttribute('lw-target') || '';
181
+
182
+ if (!history.state) {
183
+ history.replaceState({
184
+ litewireUrl: window.location.href,
185
+ targetSelector: targetSelector,
186
+ html: target ? target.innerHTML : ''
187
+ }, '', window.location.href);
188
+ }
189
+
190
+ history.pushState({
191
+ litewireUrl: newUrl,
192
+ targetSelector: targetSelector,
193
+ html: target ? target.innerHTML : ''
194
+ }, '', newUrl);
195
+ }
196
+
197
+ listenToHistory() {
198
+ window.addEventListener('popstate', (e) => {
199
+ if (!e.state) return;
200
+
201
+ const { targetSelector, html, litewireUrl } = e.state;
202
+
203
+ if (targetSelector && html !== undefined) {
204
+ const target = document.querySelector(targetSelector);
205
+ if (target) {
206
+ target.innerHTML = html;
207
+ this.scan(target);
208
+ this.loadComponents(target);
209
+ return;
210
+ }
211
+ }
212
+
213
+ const fallbackEl = document.createElement('div');
214
+ fallbackEl.setAttribute('lw-get', litewireUrl || window.location.href);
215
+ if (targetSelector) fallbackEl.setAttribute('lw-target', targetSelector);
216
+
217
+ this.executeRequest(fallbackEl, true);
218
+ });
219
+ }
220
+
221
+ observe() {
222
+ const observer = new MutationObserver((mutations) => {
223
+ for (const m of mutations) {
224
+ m.addedNodes.forEach(node => {
225
+ if (node.nodeType === Node.ELEMENT_NODE) {
226
+ this.scan(node);
227
+ this.loadComponents(node);
228
+ }
229
+ });
230
+ }
231
+ });
232
+ observer.observe(document.body, { childList: true, subtree: true });
233
+ }
234
+ }
235
+
236
+ export default Litewire;
237
+
238
+ // Auto-instantiate in browser environments if not loaded as a module
239
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
240
+ if (document.readyState === 'loading') {
241
+ document.addEventListener('DOMContentLoaded', () => {
242
+ if (!window.litewire) window.litewire = new Litewire();
243
+ });
244
+ } else {
245
+ if (!window.litewire) window.litewire = new Litewire();
246
+ }
247
+ }