runtime-compiler 3.2.0 → 4.0.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.
- package/LICENSE +21 -0
- package/README.md +28 -12
- package/build/index.d.ts +6 -0
- package/build/index.js +1 -0
- package/build/rolldown.d.ts +3 -0
- package/build/rolldown.js +1 -0
- package/env/aot.js +1 -0
- package/env/build.js +1 -0
- package/env/index.d.ts +3 -0
- package/env/index.js +1 -0
- package/globals.d.ts +8 -0
- package/globals.js +1 -0
- package/package.json +1 -1
- package/scope.d.ts +13 -0
- package/scope.js +1 -0
- package/utils.d.ts +1 -43
- package/utils.js +1 -1
- package/config/index.d.ts +0 -8
- package/config/index.js +0 -1
- package/config/loader/build.d.ts +0 -1
- package/config/loader/build.js +0 -1
- package/config/loader/hydrate.d.ts +0 -1
- package/config/loader/hydrate.js +0 -1
- package/config/mode/build.d.ts +0 -2
- package/config/mode/build.js +0 -1
- package/config/mode/hydrate.d.ts +0 -2
- package/config/mode/hydrate.js +0 -1
- package/index.d.ts +0 -119
- package/index.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aquapi
|
|
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
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
A code generation system for JS.
|
|
3
|
-
|
|
4
|
-
## Modes
|
|
5
|
-
- `default`: Build & run.
|
|
6
|
-
- `build`: Build only.
|
|
7
|
-
- `hydrate`: Run only.
|
|
1
|
+
A code generation system.
|
|
8
2
|
|
|
3
|
+
# Usage
|
|
9
4
|
```ts
|
|
10
|
-
import {
|
|
5
|
+
import { IS_AOT, IS_BUILD } from 'runtime-compiler/env';
|
|
6
|
+
import { emit, evaluate } from 'runtime-compiler/globals';
|
|
7
|
+
|
|
8
|
+
// Only emit code if not in AOT mode
|
|
9
|
+
IS_AOT || emit(`return()=>console.log("Hi")`);
|
|
11
10
|
|
|
12
|
-
//
|
|
13
|
-
|
|
11
|
+
// Only log when building
|
|
12
|
+
IS_BUILD && console.log('Building...');
|
|
14
13
|
|
|
15
|
-
//
|
|
16
|
-
|
|
14
|
+
// Run emitted code
|
|
15
|
+
const fn = evaluate<() => void>();
|
|
16
|
+
fn();
|
|
17
17
|
```
|
|
18
|
+
|
|
19
|
+
Build with `rolldown` or `vite`:
|
|
20
|
+
```ts
|
|
21
|
+
...
|
|
22
|
+
import rtc from 'runtime-compiler/build/rolldown';
|
|
23
|
+
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
...,
|
|
26
|
+
plugins: [
|
|
27
|
+
...,
|
|
28
|
+
rtc()
|
|
29
|
+
]
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
You only need to build when the target runtime doesn't allow `eval()`.
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const getPromiseResolvers: (res: any, rej: any) => void;
|
|
2
|
+
export declare const runInWorker: (code: string) => Promise<string[]>;
|
|
3
|
+
/**
|
|
4
|
+
* Requires code to not bundle "runtime-compiler/env" and "runtime-compiler/globals"
|
|
5
|
+
*/
|
|
6
|
+
export declare const compile: (code: string) => Promise<string>;
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Worker}from"node:worker_threads";let curRes,curRej;export const getPromiseResolvers=(res,rej)=>{curRes=res;curRej=rej};let workerOptions={eval:!0};export const runInWorker=code=>{let p=new Promise(getPromiseResolvers),worker=new Worker(`import"runtime-compiler/env/build";import{__rtcpl_ct__}from"runtime-compiler/globals";import{parentPort as __rtcpl_pp__}from"node:worker_threads";${code};\n__rtcpl_pp__.postMessage(__rtcpl_ct__)`,workerOptions);worker.once("message",curRes);worker.once("error",curRej);return p};export const compile=async code=>{let str='import"runtime-compiler/env/aot";import{__rtcpl_setup_aot__}from"runtime-compiler/globals";';for(let i=0,codes=await runInWorker(code);i<codes.length;i++)str+=`__rtcpl_setup_aot__($=>{${codes[i]}});`;return str+code};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{runInWorker}from"./index.js";let parseImportBindings=(code,start,end)=>{let startSpecs=code.indexOf("{",start),endSpecs=code.lastIndexOf("}",end);if(-1===start&&-1===end)throw new Error("Only named imports replacement is supported!");let bindings=[];for(let i=0,specifiers=code.slice(startSpecs+1,endSpecs-1).split(",");i<specifiers.length;i++){let specifier=specifiers[i].trim();if(""===specifier)continue;let parts=specifier.split(" as ",2);if(1===parts.length){let name=parts[0].trim();bindings.push({name,alias:name})}else bindings.push({name:parts[0].trim(),alias:parts[1].trim()})}return{bindings,start,end}};export default(()=>({name:"rolldown-plugin-runtime-compiler",resolveId:{filter:{id:/^runtime-compiler\/(?:env|globals)$/},handler:()=>!1},renderChunk:async(code,{imports})=>{let globalsImportIdx=imports.indexOf("runtime-compiler/globals");if(-1===globalsImportIdx)return null;imports.splice(globalsImportIdx);let envImportIdx=imports.indexOf("runtime-compiler/env"),envImport=null,globalsImport=null;-1===envImportIdx?envImport={bindings:[],start:0,end:0}:imports.splice(envImportIdx,1);for(let start=0,eol=code.indexOf("\n");eol>-1&&(null==envImport||null==globalsImport);eol=code.indexOf("\n",start=eol+1))code.startsWith("import",start)&&(code.endsWith('"runtime-compiler/env";',eol)?envImport=parseImportBindings(code,start,eol):code.endsWith('"runtime-compiler/globals";',eol)&&(globalsImport=parseImportBindings(code,start,eol)));let aotCode="const __rtcpl_atf__=[],__rtcpl_aot_fns__=[],__rtcpl_setup_aot__=f=>{__rtcpl_aot_fns__.push(f)};let __rtcpl_aot_fn_idx__=0;";for(let i=0,{bindings}=envImport;i<bindings.length;i++){let{name,alias}=bindings[i];aotCode+="IS_AOT"===name?`const ${alias}=true;`:"IS_BUILD"===name||"IS_JIT"===name?`const ${alias}=false;`:""}for(let i=0,{bindings}=globalsImport;i<bindings.length;i++){let{name,alias}=bindings[i];aotCode+="deref"===name?`const ${alias}=i=>__rtcpl_atf__[i];`:"emit"===name?`const ${alias}=()=>{};`:"evaluate"===name?`const ${alias}=()=>__rtcpl_aot_fns__[__rtcpl_aot_fn_idx__++](__rtcpl_atf__);`:"createRef"===name?`const ${alias}=()=>__rtcpl_atf__.push(undefined)-1;`:"importRef"===name?`const ${alias}=v=>__rtcpl_atf__.push(v)-1;`:""}for(let i=0,codes=await runInWorker(code);i<codes.length;i++)aotCode+=`__rtcpl_setup_aot__($=>{${codes[i]}});`;aotCode+=envImport.start<globalsImport.start?code.slice(0,envImport.start)+code.slice(envImport.end,globalsImport.start)+code.slice(globalsImport.end):code.slice(0,globalsImport.start)+code.slice(globalsImport.end,envImport.start)+code.slice(envImport.end);return{code:aotCode}}}));
|
package/env/aot.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setAOT}from"./index.js";setAOT();
|
package/env/build.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setBuild}from"./index.js";setBuild();
|
package/env/index.d.ts
ADDED
package/env/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export let IS_JIT=!0;export let IS_BUILD=!1;export let IS_AOT=!1;export const setBuild=()=>{IS_JIT=!1;IS_BUILD=!0;IS_AOT=!1};export const setAOT=()=>{IS_JIT=!1;IS_BUILD=!1;IS_AOT=!0};
|
package/globals.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Ref<T> = number & {
|
|
2
|
+
"~": T;
|
|
3
|
+
};
|
|
4
|
+
export declare const importRef: <T>(value: T) => Ref<T>;
|
|
5
|
+
export declare const createRef: <T>() => Ref<T>;
|
|
6
|
+
export declare let evaluate: <T>() => T;
|
|
7
|
+
export declare const emit: (code: string) => void;
|
|
8
|
+
export declare const deref: <T>(id: Ref<T>) => T;
|
package/globals.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{IS_AOT,IS_BUILD}from"./env/index.js";import{emptyFn}from"./utils.js";let refs=[];export const importRef=value=>refs.push(value)-1;export const createRef=()=>refs.push(void 0)-1;let content="";export let __rtcpl_ct__=[];export let evaluate=IS_AOT?()=>__rtcpl_aot_fns__[__rtcpl_aot_fn_idx__++](refs):IS_BUILD?()=>{__rtcpl_ct__.push(content);let currentContent=content;content="";if(currentContent.length>0)return(0,eval)(`$=>{${currentContent}}`)(refs)}:()=>{let currentContent=content;content="";if(currentContent.length>0)return(0,eval)(`$=>{${currentContent}}`)(refs)};export const emit=IS_AOT?emptyFn:code=>{content+=code};let __rtcpl_aot_fns__=[],__rtcpl_aot_fn_idx__=0;export const __rtcpl_setup_aot__=fn=>{__rtcpl_aot_fns__.push(fn)};export const deref=id=>refs[id];
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"runtime-compiler","version":"
|
|
1
|
+
{"name":"runtime-compiler","version":"4.0.1","description":"A compiler system.","keywords":[],"homepage":"","license":"MIT","repository":"","type":"module","exports":{"./*":"./*.js","./build":"./build/index.js","./env":"./env/index.js"}}
|
package/scope.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Scope = [start: string, end: string, nextId: number];
|
|
2
|
+
/**
|
|
3
|
+
* Get next available id in a scope.
|
|
4
|
+
*/
|
|
5
|
+
export declare const scopeNextId: (scope: Scope) => number;
|
|
6
|
+
/**
|
|
7
|
+
* Get scope content.
|
|
8
|
+
*/
|
|
9
|
+
export declare const scopeContent: (scope: Scope) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Fork a new scope.
|
|
12
|
+
*/
|
|
13
|
+
export declare const scopeFork: <T extends Scope>(scope: T) => T;
|
package/scope.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const scopeNextId=scope=>scope[2]++;export const scopeContent=scope=>`{${scope[0]+scope[1]}}`;export const scopeFork=scope=>scope.slice();
|
package/utils.d.ts
CHANGED
|
@@ -1,43 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Placeholder for `hydrate` mode.
|
|
4
|
-
*/
|
|
5
|
-
export declare const noOp: () => string;
|
|
6
|
-
/**
|
|
7
|
-
* Async function constructor
|
|
8
|
-
*/
|
|
9
|
-
export declare const AsyncFunction: typeof Function;
|
|
10
|
-
/**
|
|
11
|
-
* Derive a value from other expressions.
|
|
12
|
-
* Use in `default` and `build` mode.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* const newValue = derive(
|
|
16
|
-
* ['Math.random()' as Expression<number>],
|
|
17
|
-
* (rand) => rand * 10
|
|
18
|
-
* ); // '$[0](Math.random())'
|
|
19
|
-
*
|
|
20
|
-
* // In hydrate mode
|
|
21
|
-
* injectExternal((rand) => rand * 10);
|
|
22
|
-
*/
|
|
23
|
-
export declare const derive: <
|
|
24
|
-
const Expressions extends Expression<any>[],
|
|
25
|
-
R
|
|
26
|
-
>(values: Expressions, fn: (...args: { [K in keyof Expressions] : Expressions[K]["~type"] }) => R) => Value<R>;
|
|
27
|
-
/**
|
|
28
|
-
* Derive a value from other expressions.
|
|
29
|
-
* Use in `default` and `build` mode.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* const newValue = deriveAsync(
|
|
33
|
-
* ['await fetch("http://example.com")' as Expression<Response>],
|
|
34
|
-
* async (res) => await res.text()
|
|
35
|
-
* ); // 'await $[0](await fetch("http://example.com"))'
|
|
36
|
-
*
|
|
37
|
-
* // In hydrate mode
|
|
38
|
-
* injectExternal((rand) => rand * 10);
|
|
39
|
-
*/
|
|
40
|
-
export declare const deriveAsync: <
|
|
41
|
-
const Expressions extends Expression<any>[],
|
|
42
|
-
R
|
|
43
|
-
>(values: Expressions, fn: (...args: { [K in keyof Expressions] : Expressions[K]["~type"] }) => Promise<R>) => Expression<R>;
|
|
1
|
+
export declare const emptyFn: () => void;
|
package/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export const emptyFn=()=>{};
|
package/config/index.d.ts
DELETED
package/config/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=false;export let onlyBuild=false;export let hydrating=()=>{isHydrating=true};export let building=()=>{onlyBuild=true};
|
package/config/loader/build.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/config/loader/build.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{building}from"../index.js";building();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/config/loader/hydrate.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{hydrating}from"../index.js";hydrating();
|
package/config/mode/build.d.ts
DELETED
package/config/mode/build.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=false;export let onlyBuild=true;
|
package/config/mode/hydrate.d.ts
DELETED
package/config/mode/hydrate.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=true;export let onlyBuild=false;
|
package/index.d.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
export type Expression<T> = string & {
|
|
2
|
-
"~type": T
|
|
3
|
-
};
|
|
4
|
-
export type Value<T> = Expression<T> & {
|
|
5
|
-
"~value": 0
|
|
6
|
-
};
|
|
7
|
-
export type Identifier<T> = Value<T> & {
|
|
8
|
-
"~id": 0
|
|
9
|
-
};
|
|
10
|
-
export type ExportedDependency<T> = number & {
|
|
11
|
-
"~type": T
|
|
12
|
-
};
|
|
13
|
-
export interface Scope {
|
|
14
|
-
/**
|
|
15
|
-
* Current scope content.
|
|
16
|
-
*/
|
|
17
|
-
0: string;
|
|
18
|
-
/**
|
|
19
|
-
* Next available id.
|
|
20
|
-
*/
|
|
21
|
-
1: number;
|
|
22
|
-
/**
|
|
23
|
-
* End scope content.
|
|
24
|
-
*/
|
|
25
|
-
2: string;
|
|
26
|
-
slice: () => this;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* External dependencies
|
|
30
|
-
*/
|
|
31
|
-
export declare const $: any[];
|
|
32
|
-
/**
|
|
33
|
-
* Inject an external dependency.
|
|
34
|
-
*/
|
|
35
|
-
export declare const injectExternal: <T>(val: T) => Value<T>;
|
|
36
|
-
/**
|
|
37
|
-
* Get next available identifier name in a scope
|
|
38
|
-
*/
|
|
39
|
-
export declare const nextId: <T>(scope: Scope) => Identifier<T>;
|
|
40
|
-
export declare const content: <T>(scope: Scope) => string;
|
|
41
|
-
/**
|
|
42
|
-
* Declare a new variable in a scope
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* declareLocal(scope, '1;');
|
|
46
|
-
*/
|
|
47
|
-
export declare const declareLocal: <T>(scope: Scope, str: string) => Identifier<T>;
|
|
48
|
-
/**
|
|
49
|
-
* Declare a new variable in a scope
|
|
50
|
-
*/
|
|
51
|
-
export declare const declareExternal: <T>(scope: Scope, val: T) => Identifier<T>;
|
|
52
|
-
interface ExportToParent {
|
|
53
|
-
<T>(scope: Scope, expr: Expression<T>, parentScope: Scope): Identifier<T>;
|
|
54
|
-
(scope: Scope, expr: string, parentScope: Scope): string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Export a local expression to a parent local variable.
|
|
58
|
-
* Use in `default` and `build` mode.
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* // Fork scope
|
|
62
|
-
* const childScope = ['', parentScope.id];
|
|
63
|
-
* // let d0;{let d1=1;d0=d1}
|
|
64
|
-
* const id = exportTo(childScope, declareLocal(childScope, '1'), parentScope); // d0
|
|
65
|
-
*/
|
|
66
|
-
export declare const exportToParent: ExportToParent;
|
|
67
|
-
/**
|
|
68
|
-
* Mark current available variable id to be already in use.
|
|
69
|
-
* Use in `hydrate` mode.
|
|
70
|
-
* @param scope
|
|
71
|
-
*/
|
|
72
|
-
export declare const markDeclared: (scope: Scope) => void;
|
|
73
|
-
export declare let statements: string;
|
|
74
|
-
interface ExportScope {
|
|
75
|
-
<T>(scope: Scope, value: Expression<T>): ExportedDependency<T>;
|
|
76
|
-
<T>(scope: Scope, value: string): ExportedDependency<T>;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Export a local dependency of a scope.
|
|
80
|
-
* Use in `default` and `build` mode.
|
|
81
|
-
*/
|
|
82
|
-
export declare const exportScope: ExportScope;
|
|
83
|
-
/**
|
|
84
|
-
* Export a value.
|
|
85
|
-
* Use in `default` and `build` mode.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* exportLocal('1;');
|
|
89
|
-
*/
|
|
90
|
-
export declare const exportLocal: <T>(value: string) => ExportedDependency<T>;
|
|
91
|
-
/**
|
|
92
|
-
* Mark a slot to export a dependency.
|
|
93
|
-
* Use in `hydrate` mode.
|
|
94
|
-
*/
|
|
95
|
-
export declare const markExported: <T>() => ExportedDependency<T>;
|
|
96
|
-
/**
|
|
97
|
-
* Get the value of an exported dependency.
|
|
98
|
-
* Use in `default` mode.
|
|
99
|
-
* @param idx
|
|
100
|
-
*/
|
|
101
|
-
export declare const getDependency: <T>(idx: ExportedDependency<T>) => T;
|
|
102
|
-
/**
|
|
103
|
-
* Get built statements and reset for next build.
|
|
104
|
-
* Use in `build` mode.
|
|
105
|
-
*/
|
|
106
|
-
export declare const getStatements: () => string;
|
|
107
|
-
/**
|
|
108
|
-
* Store temporary build data.
|
|
109
|
-
*/
|
|
110
|
-
export declare let buildData: any[];
|
|
111
|
-
/**
|
|
112
|
-
* @example
|
|
113
|
-
* const slot = createBuildSlot();
|
|
114
|
-
*
|
|
115
|
-
* // Reset after every build
|
|
116
|
-
* buildData[slot] ??= data;
|
|
117
|
-
*/
|
|
118
|
-
export declare const createBuildSlot: () => number;
|
|
119
|
-
export {};
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
;export let $=[];export let injectExternal=f=>`$[${$.push(f)-1}]`;export let nextId=e=>`d`+ e[1]++;export let content=e=>e[0]+e[2];export let declareLocal=(e,f)=>{let m=nextId(e);e[0]+=`let ${m}=`+f;return m};export let declareExternal=(f,m)=>{let h=nextId(f);f[0]+=`let ${h}=$[${$.push(m)-1}];`;return h};export let exportToParent=(e,f,h)=>{let g=nextId(h);h[0]+=`let ${g};{${content(e)+g}=${f}}`;return g};export let markDeclared=e=>{e[1]++};export let statements=``;export let exportScope=(f,p)=>(statements+=`{${content(f)}$[${$.length}]=${p}}`,$.length++);export let exportLocal=f=>(statements+=`$[${$.length}]=${f}`,$.length++);export let markExported=()=>$.length++;export let getDependency=f=>{if(statements.length>0){globalThis.__rt_externals__=$;(0,eval)(`{let $=__rt_externals__;`+statements+`}`);globalThis.__rt_externals__=null;statements=``;buildData=[]}return $[f]};export let getStatements=()=>{let e=statements;statements=``;buildData=[];return e};export let buildData=[];let nextSlot=0;export let createBuildSlot=()=>nextSlot++;
|