@cedarjs/vite 0.9.1-next.0 → 0.9.1-next.19
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/dist/cjs/plugins/vite-plugin-cedar-cell.js +2 -2
- package/dist/cjs/plugins/vite-plugin-cedarjs-job-path-injector.js +63 -81
- package/dist/cjs/plugins/vite-plugin-swap-apollo-provider.js +1 -1
- package/dist/plugins/vite-plugin-cedar-cell.d.ts.map +1 -1
- package/dist/plugins/vite-plugin-cedar-cell.js +2 -2
- package/dist/plugins/vite-plugin-cedarjs-job-path-injector.d.ts.map +1 -1
- package/dist/plugins/vite-plugin-cedarjs-job-path-injector.js +63 -81
- package/dist/plugins/vite-plugin-swap-apollo-provider.js +1 -1
- package/package.json +11 -10
|
@@ -35,8 +35,8 @@ var import_node_path = require("node:path");
|
|
|
35
35
|
var import_generator = __toESM(require("@babel/generator"), 1);
|
|
36
36
|
var import_parser = require("@babel/parser");
|
|
37
37
|
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
38
|
-
const traverse = import_traverse.default.default;
|
|
39
|
-
const generate = import_generator.default.default;
|
|
38
|
+
const traverse = import_traverse.default.default || import_traverse.default;
|
|
39
|
+
const generate = import_generator.default.default || import_generator.default;
|
|
40
40
|
const EXPECTED_EXPORTS_FROM_CELL = [
|
|
41
41
|
"beforeQuery",
|
|
42
42
|
"QUERY",
|
|
@@ -32,7 +32,7 @@ __export(vite_plugin_cedarjs_job_path_injector_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(vite_plugin_cedarjs_job_path_injector_exports);
|
|
34
34
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
35
|
-
var
|
|
35
|
+
var import_napi = require("@ast-grep/napi");
|
|
36
36
|
var import_project_config = require("@cedarjs/project-config");
|
|
37
37
|
function cedarjsJobPathInjectorPlugin() {
|
|
38
38
|
return {
|
|
@@ -42,103 +42,85 @@ function cedarjsJobPathInjectorPlugin() {
|
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
44
|
const isTypescript = id.endsWith(".ts") || id.endsWith(".tsx");
|
|
45
|
+
const language = isTypescript ? import_napi.Lang.TypeScript : import_napi.Lang.JavaScript;
|
|
45
46
|
let ast;
|
|
46
47
|
try {
|
|
47
|
-
ast =
|
|
48
|
-
target: "es2022",
|
|
49
|
-
syntax: isTypescript ? "typescript" : "ecmascript",
|
|
50
|
-
tsx: id.endsWith(".tsx"),
|
|
51
|
-
jsx: id.endsWith(".jsx")
|
|
52
|
-
});
|
|
48
|
+
ast = (0, import_napi.parse)(language, code);
|
|
53
49
|
} catch (error) {
|
|
54
50
|
console.warn("Failed to parse file:", id);
|
|
55
51
|
console.warn(error);
|
|
56
52
|
return null;
|
|
57
53
|
}
|
|
58
54
|
const paths = (0, import_project_config.getPaths)();
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
const edits = [];
|
|
56
|
+
const root = ast.root();
|
|
57
|
+
const createJobCalls = root.findAll({
|
|
58
|
+
rule: {
|
|
59
|
+
pattern: "export const $VAR_NAME = $OBJ.createJob({ $$$PROPS })"
|
|
64
60
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const firstArg = init.arguments[0];
|
|
85
|
-
if (firstArg?.expression?.type === "ObjectExpression") {
|
|
86
|
-
const objectExpr = firstArg.expression;
|
|
87
|
-
const properties = objectExpr.properties;
|
|
88
|
-
let insertPosition;
|
|
89
|
-
if (properties.length > 0) {
|
|
90
|
-
const lastProperty = properties[properties.length - 1];
|
|
91
|
-
if (lastProperty.type === "KeyValueProperty") {
|
|
92
|
-
insertPosition = lastProperty.value.span.end;
|
|
93
|
-
} else {
|
|
94
|
-
insertPosition = objectExpr.span.end - 1;
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
insertPosition = objectExpr.span.start + 1;
|
|
98
|
-
}
|
|
99
|
-
const pathProperty = `path: ${JSON.stringify(importPathWithoutExtension)}`;
|
|
100
|
-
const nameProperty = `name: ${JSON.stringify(importName)}`;
|
|
101
|
-
let insertText = "";
|
|
102
|
-
if (properties.length > 0) {
|
|
103
|
-
insertText = `, ${pathProperty}, ${nameProperty}`;
|
|
104
|
-
} else {
|
|
105
|
-
insertText = `${pathProperty}, ${nameProperty}`;
|
|
106
|
-
}
|
|
107
|
-
modifications.push({
|
|
108
|
-
start: insertPosition,
|
|
109
|
-
end: insertPosition,
|
|
110
|
-
replacement: insertText
|
|
111
|
-
});
|
|
112
|
-
hasModifications = true;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
61
|
+
});
|
|
62
|
+
for (const callNode of createJobCalls) {
|
|
63
|
+
const varNameNode = callNode.getMatch("VAR_NAME");
|
|
64
|
+
const propsNodes = callNode.getMultipleMatches("PROPS");
|
|
65
|
+
if (!varNameNode) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const importName = varNameNode.text();
|
|
69
|
+
const importPath = import_node_path.default.relative(paths.api.jobs, id);
|
|
70
|
+
const importPathWithoutExtension = importPath.replace(/\.[^/.]+$/, "");
|
|
71
|
+
const pathProperty = `path: ${JSON.stringify(importPathWithoutExtension)}`;
|
|
72
|
+
const nameProperty = `name: ${JSON.stringify(importName)}`;
|
|
73
|
+
let insertText = "";
|
|
74
|
+
if (propsNodes.length > 0) {
|
|
75
|
+
const objectLiteral = callNode.find({
|
|
76
|
+
rule: {
|
|
77
|
+
kind: "object",
|
|
78
|
+
inside: {
|
|
79
|
+
kind: "arguments"
|
|
117
80
|
}
|
|
118
81
|
}
|
|
82
|
+
});
|
|
83
|
+
if (objectLiteral) {
|
|
84
|
+
insertText = `, ${pathProperty}, ${nameProperty}`;
|
|
85
|
+
const objectText = objectLiteral.text();
|
|
86
|
+
const closeBraceIndex = objectText.lastIndexOf("}");
|
|
87
|
+
if (closeBraceIndex !== -1) {
|
|
88
|
+
const range = objectLiteral.range();
|
|
89
|
+
edits.push({
|
|
90
|
+
startPos: range.start.index + closeBraceIndex,
|
|
91
|
+
endPos: range.start.index + closeBraceIndex,
|
|
92
|
+
insertedText: insertText
|
|
93
|
+
});
|
|
94
|
+
}
|
|
119
95
|
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
96
|
+
} else {
|
|
97
|
+
const objectLiteral = callNode.find({
|
|
98
|
+
rule: {
|
|
99
|
+
kind: "object",
|
|
100
|
+
inside: {
|
|
101
|
+
kind: "arguments"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
if (objectLiteral) {
|
|
106
|
+
insertText = `${pathProperty}, ${nameProperty}`;
|
|
107
|
+
const objectText = objectLiteral.text();
|
|
108
|
+
const openBraceIndex = objectText.indexOf("{");
|
|
109
|
+
if (openBraceIndex !== -1) {
|
|
110
|
+
const range = objectLiteral.range();
|
|
111
|
+
edits.push({
|
|
112
|
+
startPos: range.start.index + openBraceIndex + 1,
|
|
113
|
+
endPos: range.start.index + openBraceIndex + 1,
|
|
114
|
+
insertedText: insertText
|
|
115
|
+
});
|
|
116
|
+
}
|
|
130
117
|
}
|
|
131
118
|
}
|
|
132
119
|
}
|
|
133
|
-
|
|
134
|
-
if (!hasModifications) {
|
|
120
|
+
if (edits.length === 0) {
|
|
135
121
|
return null;
|
|
136
122
|
}
|
|
137
|
-
|
|
138
|
-
let modifiedCode = code;
|
|
139
|
-
for (const mod of modifications) {
|
|
140
|
-
modifiedCode = modifiedCode.slice(0, mod.start) + mod.replacement + modifiedCode.slice(mod.end);
|
|
141
|
-
}
|
|
123
|
+
const modifiedCode = root.commitEdits(edits);
|
|
142
124
|
return {
|
|
143
125
|
code: modifiedCode,
|
|
144
126
|
map: null
|
|
@@ -23,7 +23,7 @@ __export(vite_plugin_swap_apollo_provider_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(vite_plugin_swap_apollo_provider_exports);
|
|
24
24
|
var import_project_config = require("@cedarjs/project-config");
|
|
25
25
|
function cedarSwapApolloProvider() {
|
|
26
|
-
const streamingEnabled = (0, import_project_config.getConfig)().experimental
|
|
26
|
+
const streamingEnabled = (0, import_project_config.getConfig)().experimental?.streamingSsr?.enabled;
|
|
27
27
|
if (!streamingEnabled) {
|
|
28
28
|
return void 0;
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin-cedar-cell.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-cedar-cell.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"vite-plugin-cedar-cell.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-cedar-cell.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAoBlC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAmK3C"}
|
|
@@ -2,8 +2,8 @@ import { parse as parsePath } from "node:path";
|
|
|
2
2
|
import babelGenerator from "@babel/generator";
|
|
3
3
|
import { parse } from "@babel/parser";
|
|
4
4
|
import babelTraverse from "@babel/traverse";
|
|
5
|
-
const traverse = babelTraverse.default;
|
|
6
|
-
const generate = babelGenerator.default;
|
|
5
|
+
const traverse = babelTraverse.default || babelTraverse;
|
|
6
|
+
const generate = babelGenerator.default || babelGenerator;
|
|
7
7
|
const EXPECTED_EXPORTS_FROM_CELL = [
|
|
8
8
|
"beforeQuery",
|
|
9
9
|
"QUERY",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin-cedarjs-job-path-injector.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-cedarjs-job-path-injector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAIlC,wBAAgB,4BAA4B,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"vite-plugin-cedarjs-job-path-injector.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-cedarjs-job-path-injector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAIlC,wBAAgB,4BAA4B,IAAI,MAAM,CAqHrD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import
|
|
2
|
+
import { parse, Lang } from "@ast-grep/napi";
|
|
3
3
|
import { getPaths } from "@cedarjs/project-config";
|
|
4
4
|
function cedarjsJobPathInjectorPlugin() {
|
|
5
5
|
return {
|
|
@@ -9,103 +9,85 @@ function cedarjsJobPathInjectorPlugin() {
|
|
|
9
9
|
return null;
|
|
10
10
|
}
|
|
11
11
|
const isTypescript = id.endsWith(".ts") || id.endsWith(".tsx");
|
|
12
|
+
const language = isTypescript ? Lang.TypeScript : Lang.JavaScript;
|
|
12
13
|
let ast;
|
|
13
14
|
try {
|
|
14
|
-
ast =
|
|
15
|
-
target: "es2022",
|
|
16
|
-
syntax: isTypescript ? "typescript" : "ecmascript",
|
|
17
|
-
tsx: id.endsWith(".tsx"),
|
|
18
|
-
jsx: id.endsWith(".jsx")
|
|
19
|
-
});
|
|
15
|
+
ast = parse(language, code);
|
|
20
16
|
} catch (error) {
|
|
21
17
|
console.warn("Failed to parse file:", id);
|
|
22
18
|
console.warn(error);
|
|
23
19
|
return null;
|
|
24
20
|
}
|
|
25
21
|
const paths = getPaths();
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
const edits = [];
|
|
23
|
+
const root = ast.root();
|
|
24
|
+
const createJobCalls = root.findAll({
|
|
25
|
+
rule: {
|
|
26
|
+
pattern: "export const $VAR_NAME = $OBJ.createJob({ $$$PROPS })"
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const firstArg = init.arguments[0];
|
|
52
|
-
if (firstArg?.expression?.type === "ObjectExpression") {
|
|
53
|
-
const objectExpr = firstArg.expression;
|
|
54
|
-
const properties = objectExpr.properties;
|
|
55
|
-
let insertPosition;
|
|
56
|
-
if (properties.length > 0) {
|
|
57
|
-
const lastProperty = properties[properties.length - 1];
|
|
58
|
-
if (lastProperty.type === "KeyValueProperty") {
|
|
59
|
-
insertPosition = lastProperty.value.span.end;
|
|
60
|
-
} else {
|
|
61
|
-
insertPosition = objectExpr.span.end - 1;
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
insertPosition = objectExpr.span.start + 1;
|
|
65
|
-
}
|
|
66
|
-
const pathProperty = `path: ${JSON.stringify(importPathWithoutExtension)}`;
|
|
67
|
-
const nameProperty = `name: ${JSON.stringify(importName)}`;
|
|
68
|
-
let insertText = "";
|
|
69
|
-
if (properties.length > 0) {
|
|
70
|
-
insertText = `, ${pathProperty}, ${nameProperty}`;
|
|
71
|
-
} else {
|
|
72
|
-
insertText = `${pathProperty}, ${nameProperty}`;
|
|
73
|
-
}
|
|
74
|
-
modifications.push({
|
|
75
|
-
start: insertPosition,
|
|
76
|
-
end: insertPosition,
|
|
77
|
-
replacement: insertText
|
|
78
|
-
});
|
|
79
|
-
hasModifications = true;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
28
|
+
});
|
|
29
|
+
for (const callNode of createJobCalls) {
|
|
30
|
+
const varNameNode = callNode.getMatch("VAR_NAME");
|
|
31
|
+
const propsNodes = callNode.getMultipleMatches("PROPS");
|
|
32
|
+
if (!varNameNode) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const importName = varNameNode.text();
|
|
36
|
+
const importPath = path.relative(paths.api.jobs, id);
|
|
37
|
+
const importPathWithoutExtension = importPath.replace(/\.[^/.]+$/, "");
|
|
38
|
+
const pathProperty = `path: ${JSON.stringify(importPathWithoutExtension)}`;
|
|
39
|
+
const nameProperty = `name: ${JSON.stringify(importName)}`;
|
|
40
|
+
let insertText = "";
|
|
41
|
+
if (propsNodes.length > 0) {
|
|
42
|
+
const objectLiteral = callNode.find({
|
|
43
|
+
rule: {
|
|
44
|
+
kind: "object",
|
|
45
|
+
inside: {
|
|
46
|
+
kind: "arguments"
|
|
84
47
|
}
|
|
85
48
|
}
|
|
49
|
+
});
|
|
50
|
+
if (objectLiteral) {
|
|
51
|
+
insertText = `, ${pathProperty}, ${nameProperty}`;
|
|
52
|
+
const objectText = objectLiteral.text();
|
|
53
|
+
const closeBraceIndex = objectText.lastIndexOf("}");
|
|
54
|
+
if (closeBraceIndex !== -1) {
|
|
55
|
+
const range = objectLiteral.range();
|
|
56
|
+
edits.push({
|
|
57
|
+
startPos: range.start.index + closeBraceIndex,
|
|
58
|
+
endPos: range.start.index + closeBraceIndex,
|
|
59
|
+
insertedText: insertText
|
|
60
|
+
});
|
|
61
|
+
}
|
|
86
62
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
63
|
+
} else {
|
|
64
|
+
const objectLiteral = callNode.find({
|
|
65
|
+
rule: {
|
|
66
|
+
kind: "object",
|
|
67
|
+
inside: {
|
|
68
|
+
kind: "arguments"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
if (objectLiteral) {
|
|
73
|
+
insertText = `${pathProperty}, ${nameProperty}`;
|
|
74
|
+
const objectText = objectLiteral.text();
|
|
75
|
+
const openBraceIndex = objectText.indexOf("{");
|
|
76
|
+
if (openBraceIndex !== -1) {
|
|
77
|
+
const range = objectLiteral.range();
|
|
78
|
+
edits.push({
|
|
79
|
+
startPos: range.start.index + openBraceIndex + 1,
|
|
80
|
+
endPos: range.start.index + openBraceIndex + 1,
|
|
81
|
+
insertedText: insertText
|
|
82
|
+
});
|
|
83
|
+
}
|
|
97
84
|
}
|
|
98
85
|
}
|
|
99
86
|
}
|
|
100
|
-
|
|
101
|
-
if (!hasModifications) {
|
|
87
|
+
if (edits.length === 0) {
|
|
102
88
|
return null;
|
|
103
89
|
}
|
|
104
|
-
|
|
105
|
-
let modifiedCode = code;
|
|
106
|
-
for (const mod of modifications) {
|
|
107
|
-
modifiedCode = modifiedCode.slice(0, mod.start) + mod.replacement + modifiedCode.slice(mod.end);
|
|
108
|
-
}
|
|
90
|
+
const modifiedCode = root.commitEdits(edits);
|
|
109
91
|
return {
|
|
110
92
|
code: modifiedCode,
|
|
111
93
|
map: null
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getConfig } from "@cedarjs/project-config";
|
|
2
2
|
function cedarSwapApolloProvider() {
|
|
3
|
-
const streamingEnabled = getConfig().experimental
|
|
3
|
+
const streamingEnabled = getConfig().experimental?.streamingSsr?.enabled;
|
|
4
4
|
if (!streamingEnabled) {
|
|
5
5
|
return void 0;
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/vite",
|
|
3
|
-
"version": "0.9.1-next.
|
|
3
|
+
"version": "0.9.1-next.19+544e70282",
|
|
4
4
|
"description": "Vite configuration package for CedarJS",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -60,17 +60,18 @@
|
|
|
60
60
|
"test:watch": "vitest watch"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
+
"@ast-grep/napi": "0.39.3",
|
|
63
64
|
"@babel/generator": "7.27.5",
|
|
64
65
|
"@babel/parser": "7.27.5",
|
|
65
66
|
"@babel/traverse": "7.27.4",
|
|
66
|
-
"@cedarjs/auth": "0.9.1-next.
|
|
67
|
-
"@cedarjs/babel-config": "0.9.1-next.
|
|
68
|
-
"@cedarjs/cookie-jar": "0.9.1-next.
|
|
69
|
-
"@cedarjs/internal": "0.9.1-next.
|
|
70
|
-
"@cedarjs/project-config": "0.9.1-next.
|
|
71
|
-
"@cedarjs/server-store": "0.9.1-next.
|
|
72
|
-
"@cedarjs/testing": "0.9.1-next.
|
|
73
|
-
"@cedarjs/web": "0.9.1-next.
|
|
67
|
+
"@cedarjs/auth": "0.9.1-next.19+544e70282",
|
|
68
|
+
"@cedarjs/babel-config": "0.9.1-next.19+544e70282",
|
|
69
|
+
"@cedarjs/cookie-jar": "0.9.1-next.19+544e70282",
|
|
70
|
+
"@cedarjs/internal": "0.9.1-next.19+544e70282",
|
|
71
|
+
"@cedarjs/project-config": "0.9.1-next.19+544e70282",
|
|
72
|
+
"@cedarjs/server-store": "0.9.1-next.19+544e70282",
|
|
73
|
+
"@cedarjs/testing": "0.9.1-next.19+544e70282",
|
|
74
|
+
"@cedarjs/web": "0.9.1-next.19+544e70282",
|
|
74
75
|
"@swc/core": "1.13.3",
|
|
75
76
|
"@vitejs/plugin-react": "4.3.4",
|
|
76
77
|
"@whatwg-node/fetch": "0.9.21",
|
|
@@ -117,5 +118,5 @@
|
|
|
117
118
|
"publishConfig": {
|
|
118
119
|
"access": "public"
|
|
119
120
|
},
|
|
120
|
-
"gitHead": "
|
|
121
|
+
"gitHead": "544e7028280e2c57542214c6b39f012921b53382"
|
|
121
122
|
}
|