@highstate/k8s.obfuscators 0.9.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/chunk-7WZGOXSB.js +52 -0
- package/dist/chunk-7WZGOXSB.js.map +1 -0
- package/dist/highstate.manifest.json +6 -0
- package/dist/phantun/deobfuscator/index.js +41 -0
- package/dist/phantun/deobfuscator/index.js.map +1 -0
- package/dist/phantun/obfuscator/index.js +47 -0
- package/dist/phantun/obfuscator/index.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { parseL4Endpoint } from '@highstate/common';
|
|
2
|
+
import { Namespace, requireBestEndpoint } from '@highstate/k8s';
|
|
3
|
+
import { toPromise } from '@highstate/pulumi';
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// assets/images.json
|
|
12
|
+
var images_exports = {};
|
|
13
|
+
__export(images_exports, {
|
|
14
|
+
default: () => images_default,
|
|
15
|
+
phantun: () => phantun
|
|
16
|
+
});
|
|
17
|
+
var phantun = {
|
|
18
|
+
name: "ghcr.io/exeteres/highstate/phantun",
|
|
19
|
+
tag: "latest",
|
|
20
|
+
image: "ghcr.io/exeteres/highstate/phantun:latest@sha256:898b1b96b9af91f06899b77b1a33d58d0a4de2fb57a60ad0cf611c64fb1d9298"
|
|
21
|
+
};
|
|
22
|
+
var images_default = {
|
|
23
|
+
phantun
|
|
24
|
+
};
|
|
25
|
+
async function getDeobfuscatorComponents(type, name, args, inputs) {
|
|
26
|
+
const appName = args.appName ?? `deobfs-${type}-${name.replaceAll(".", "-")}`;
|
|
27
|
+
const cluster = await toPromise(inputs.k8sCluster);
|
|
28
|
+
const namespace = Namespace.create(appName, {
|
|
29
|
+
cluster,
|
|
30
|
+
privileged: true
|
|
31
|
+
});
|
|
32
|
+
const resolvedTargetInputs = await toPromise(inputs.targetEndpoints);
|
|
33
|
+
const targetEndpoints = [...args.targetEndpoints.map(parseL4Endpoint), ...resolvedTargetInputs];
|
|
34
|
+
const bestTargetEndpoint = requireBestEndpoint(targetEndpoints, cluster);
|
|
35
|
+
return { appName, namespace, targetEndpoints, bestTargetEndpoint };
|
|
36
|
+
}
|
|
37
|
+
async function getObfuscatorComponents(type, name, args, inputs) {
|
|
38
|
+
const appName = args.appName ?? `obfs-${type}-${name.replaceAll(".", "-")}`;
|
|
39
|
+
const cluster = await toPromise(inputs.k8sCluster);
|
|
40
|
+
const namespace = Namespace.create(appName, {
|
|
41
|
+
cluster,
|
|
42
|
+
privileged: true
|
|
43
|
+
});
|
|
44
|
+
const resolvedEndpoints = await toPromise(inputs.endpoints);
|
|
45
|
+
const endpoints = [...args.endpoints.map(parseL4Endpoint), ...resolvedEndpoints];
|
|
46
|
+
const bestEndpoint = requireBestEndpoint(endpoints, cluster);
|
|
47
|
+
return { appName, namespace, endpoints, bestEndpoint };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { getDeobfuscatorComponents, getObfuscatorComponents, images_exports };
|
|
51
|
+
//# sourceMappingURL=chunk-7WZGOXSB.js.map
|
|
52
|
+
//# sourceMappingURL=chunk-7WZGOXSB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../assets/images.json","../src/shared.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,IAAA,cAAA,GAAA;AAAA,QAAA,CAAA,cAAA,EAAA;AAAA,EAAA,OAAA,EAAA,MAAA,cAAA;AAAA,EAAA,OAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AACE,IAAA,OAAA,GAAW;AAAA,EACT,IAAA,EAAQ,oCAAA;AAAA,EACR,GAAA,EAAO,QAAA;AAAA,EACP,KAAA,EAAS;AACX,CAAA;AALF,IAAA,cAAA,GAAA;AAAA,EACE;AAKF,CAAA;ACWA,eAAsB,yBAAA,CACpB,IAAA,EACA,IAAA,EACA,IAAA,EACA,MAAA,EACA;AACA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,CAAA,OAAA,EAAU,IAAI,IAAI,IAAA,CAAK,UAAA,CAAW,GAAA,EAAK,GAAG,CAAC,CAAA,CAAA;AAC3E,EAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,MAAA,CAAO,UAAU,CAAA;AAEjD,EAAA,MAAM,SAAA,GAAY,SAAA,CAAU,MAAA,CAAO,OAAA,EAAS;AAAA,IAC1C,OAAA;AAAA,IACA,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,MAAM,oBAAA,GAAuB,MAAM,SAAA,CAAU,MAAA,CAAO,eAAe,CAAA;AACnE,EAAA,MAAM,eAAA,GAAkB,CAAC,GAAG,IAAA,CAAK,gBAAgB,GAAA,CAAI,eAAe,CAAA,EAAG,GAAG,oBAAoB,CAAA;AAE9F,EAAA,MAAM,kBAAA,GAAqB,mBAAA,CAAoB,eAAA,EAAiB,OAAO,CAAA;AAEvE,EAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,eAAA,EAAiB,kBAAA,EAAmB;AACnE;AAEA,eAAsB,uBAAA,CACpB,IAAA,EACA,IAAA,EACA,IAAA,EACA,MAAA,EACA;AACA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,CAAA,KAAA,EAAQ,IAAI,IAAI,IAAA,CAAK,UAAA,CAAW,GAAA,EAAK,GAAG,CAAC,CAAA,CAAA;AACzE,EAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,MAAA,CAAO,UAAU,CAAA;AAEjD,EAAA,MAAM,SAAA,GAAY,SAAA,CAAU,MAAA,CAAO,OAAA,EAAS;AAAA,IAC1C,OAAA;AAAA,IACA,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,MAAM,iBAAA,GAAoB,MAAM,SAAA,CAAU,MAAA,CAAO,SAAS,CAAA;AAC1D,EAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAA,CAAK,UAAU,GAAA,CAAI,eAAe,CAAA,EAAG,GAAG,iBAAiB,CAAA;AAE/E,EAAA,MAAM,YAAA,GAAe,mBAAA,CAAoB,SAAA,EAAW,OAAO,CAAA;AAE3D,EAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,SAAA,EAAW,YAAA,EAAa;AACvD","file":"chunk-7WZGOXSB.js","sourcesContent":["{\n \"phantun\": {\n \"name\": \"ghcr.io/exeteres/highstate/phantun\",\n \"tag\": \"latest\",\n \"image\": \"ghcr.io/exeteres/highstate/phantun:latest@sha256:898b1b96b9af91f06899b77b1a33d58d0a4de2fb57a60ad0cf611c64fb1d9298\"\n }\n}\n","import type { Input } from \"@pulumi/pulumi\"\nimport type { k8s, network } from \"@highstate/library\"\nimport { parseL4Endpoint } from \"@highstate/common\"\nimport { Namespace, requireBestEndpoint } from \"@highstate/k8s\"\nimport { toPromise } from \"@highstate/pulumi\"\nimport * as images from \"../assets/images.json\"\n\ntype DeobfuscatorInputs = {\n k8sCluster: Input<k8s.Cluster>\n targetEndpoints: Input<network.L4Endpoint[]>\n}\n\ntype ObfuscatorInputs = {\n k8sCluster: Input<k8s.Cluster>\n endpoints: Input<network.L4Endpoint[]>\n}\n\nexport async function getDeobfuscatorComponents(\n type: string,\n name: string,\n args: k8s.obfuscators.DeobfuscatorArgs,\n inputs: DeobfuscatorInputs,\n) {\n const appName = args.appName ?? `deobfs-${type}-${name.replaceAll(\".\", \"-\")}`\n const cluster = await toPromise(inputs.k8sCluster)\n\n const namespace = Namespace.create(appName, {\n cluster,\n privileged: true,\n })\n\n const resolvedTargetInputs = await toPromise(inputs.targetEndpoints)\n const targetEndpoints = [...args.targetEndpoints.map(parseL4Endpoint), ...resolvedTargetInputs]\n\n const bestTargetEndpoint = requireBestEndpoint(targetEndpoints, cluster)\n\n return { appName, namespace, targetEndpoints, bestTargetEndpoint }\n}\n\nexport async function getObfuscatorComponents(\n type: string,\n name: string,\n args: k8s.obfuscators.ObfuscatorArgs,\n inputs: ObfuscatorInputs,\n) {\n const appName = args.appName ?? `obfs-${type}-${name.replaceAll(\".\", \"-\")}`\n const cluster = await toPromise(inputs.k8sCluster)\n\n const namespace = Namespace.create(appName, {\n cluster,\n privileged: true,\n })\n\n const resolvedEndpoints = await toPromise(inputs.endpoints)\n const endpoints = [...args.endpoints.map(parseL4Endpoint), ...resolvedEndpoints]\n\n const bestEndpoint = requireBestEndpoint(endpoints, cluster)\n\n return { appName, namespace, endpoints, bestEndpoint }\n}\n\nexport { images }\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getDeobfuscatorComponents, images_exports } from '../../chunk-7WZGOXSB.js';
|
|
2
|
+
import { l4EndpointToString } from '@highstate/common';
|
|
3
|
+
import { Deployment } from '@highstate/k8s';
|
|
4
|
+
import { k8s } from '@highstate/library';
|
|
5
|
+
import { forUnit } from '@highstate/pulumi';
|
|
6
|
+
import { map } from 'remeda';
|
|
7
|
+
|
|
8
|
+
var { name, args, inputs, outputs } = forUnit(k8s.obfuscators.phantun.deobfuscator);
|
|
9
|
+
var { appName, namespace, bestTargetEndpoint } = await getDeobfuscatorComponents(
|
|
10
|
+
"phantun",
|
|
11
|
+
name,
|
|
12
|
+
args,
|
|
13
|
+
inputs
|
|
14
|
+
);
|
|
15
|
+
var deployment = Deployment.create(appName, {
|
|
16
|
+
namespace,
|
|
17
|
+
container: {
|
|
18
|
+
image: images_exports.phantun.image,
|
|
19
|
+
args: ["phantun-server", "--local", "4567", "--remote", l4EndpointToString(bestTargetEndpoint)],
|
|
20
|
+
port: {
|
|
21
|
+
containerPort: 4567,
|
|
22
|
+
protocol: "TCP"
|
|
23
|
+
},
|
|
24
|
+
allowedEndpoints: [bestTargetEndpoint],
|
|
25
|
+
enableTun: true
|
|
26
|
+
},
|
|
27
|
+
service: {
|
|
28
|
+
external: args.external
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
var deobfuscator_default = outputs({
|
|
32
|
+
endpoints: deployment.service.endpoints,
|
|
33
|
+
$statusFields: {
|
|
34
|
+
endpoints: deployment.service.endpoints.apply(map(l4EndpointToString))
|
|
35
|
+
},
|
|
36
|
+
$terminals: [deployment.terminal]
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export { deobfuscator_default as default };
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/phantun/deobfuscator/index.ts"],"names":[],"mappings":";;;;;;;AAOA,IAAM,EAAE,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,OAAA,KAAY,OAAA,CAAQ,GAAA,CAAI,WAAA,CAAY,OAAA,CAAQ,YAAY,CAAA;AAEpF,IAAM,EAAE,OAAA,EAAS,SAAA,EAAW,kBAAA,KAAuB,MAAM,yBAAA;AAAA,EACvD,SAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,UAAA,GAAa,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAAA,EAC5C,SAAA;AAAA,EAEA,SAAA,EAAW;AAAA,IACT,KAAA,EAAO,eAAO,OAAA,CAAQ,KAAA;AAAA,IACtB,IAAA,EAAM,CAAC,gBAAA,EAAkB,SAAA,EAAW,QAAQ,UAAA,EAAY,kBAAA,CAAmB,kBAAkB,CAAC,CAAA;AAAA,IAE9F,IAAA,EAAM;AAAA,MACJ,aAAA,EAAe,IAAA;AAAA,MACf,QAAA,EAAU;AAAA,KACZ;AAAA,IAEA,gBAAA,EAAkB,CAAC,kBAAkB,CAAA;AAAA,IACrC,SAAA,EAAW;AAAA,GACb;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,UAAU,IAAA,CAAK;AAAA;AAEnB,CAAC,CAAA;AAED,IAAO,uBAAQ,OAAA,CAAQ;AAAA,EACrB,SAAA,EAAW,WAAW,OAAA,CAAQ,SAAA;AAAA,EAE9B,aAAA,EAAe;AAAA,IACb,WAAW,UAAA,CAAW,OAAA,CAAQ,UAAU,KAAA,CAAM,GAAA,CAAI,kBAAkB,CAAC;AAAA,GACvE;AAAA,EAEA,UAAA,EAAY,CAAC,UAAA,CAAW,QAAQ;AAClC,CAAC","file":"index.js","sourcesContent":["import { l4EndpointToString } from \"@highstate/common\"\nimport { Deployment } from \"@highstate/k8s\"\nimport { k8s } from \"@highstate/library\"\nimport { forUnit } from \"@highstate/pulumi\"\nimport { map } from \"remeda\"\nimport { getDeobfuscatorComponents, images } from \"../../shared\"\n\nconst { name, args, inputs, outputs } = forUnit(k8s.obfuscators.phantun.deobfuscator)\n\nconst { appName, namespace, bestTargetEndpoint } = await getDeobfuscatorComponents(\n \"phantun\",\n name,\n args,\n inputs,\n)\n\nconst deployment = Deployment.create(appName, {\n namespace,\n\n container: {\n image: images.phantun.image,\n args: [\"phantun-server\", \"--local\", \"4567\", \"--remote\", l4EndpointToString(bestTargetEndpoint)],\n\n port: {\n containerPort: 4567,\n protocol: \"TCP\",\n },\n\n allowedEndpoints: [bestTargetEndpoint],\n enableTun: true,\n },\n\n service: {\n external: args.external,\n },\n})\n\nexport default outputs({\n endpoints: deployment.service.endpoints,\n\n $statusFields: {\n endpoints: deployment.service.endpoints.apply(map(l4EndpointToString)),\n },\n\n $terminals: [deployment.terminal],\n})\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getObfuscatorComponents, images_exports } from '../../chunk-7WZGOXSB.js';
|
|
2
|
+
import { l4EndpointToString } from '@highstate/common';
|
|
3
|
+
import { Deployment } from '@highstate/k8s';
|
|
4
|
+
import { k8s } from '@highstate/library';
|
|
5
|
+
import { forUnit } from '@highstate/pulumi';
|
|
6
|
+
import { map } from 'remeda';
|
|
7
|
+
|
|
8
|
+
var { name, args, inputs, outputs } = forUnit(k8s.obfuscators.phantun.obfuscator);
|
|
9
|
+
var { appName, namespace, bestEndpoint } = await getObfuscatorComponents(
|
|
10
|
+
"phantun",
|
|
11
|
+
name,
|
|
12
|
+
args,
|
|
13
|
+
inputs
|
|
14
|
+
);
|
|
15
|
+
var deployment = Deployment.create(appName, {
|
|
16
|
+
namespace,
|
|
17
|
+
container: {
|
|
18
|
+
image: images_exports.phantun.image,
|
|
19
|
+
args: [
|
|
20
|
+
"phantun-client",
|
|
21
|
+
"--local",
|
|
22
|
+
"0.0.0.0:1234",
|
|
23
|
+
"--remote",
|
|
24
|
+
l4EndpointToString(bestEndpoint)
|
|
25
|
+
],
|
|
26
|
+
port: {
|
|
27
|
+
containerPort: 1234,
|
|
28
|
+
protocol: "UDP"
|
|
29
|
+
},
|
|
30
|
+
allowedEndpoints: [bestEndpoint],
|
|
31
|
+
enableTun: true
|
|
32
|
+
},
|
|
33
|
+
service: {
|
|
34
|
+
external: args.external
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
var obfuscator_default = outputs({
|
|
38
|
+
entryEndpoints: deployment.service.endpoints,
|
|
39
|
+
$statusFields: {
|
|
40
|
+
entryEndpoints: deployment.service.endpoints.apply(map(l4EndpointToString))
|
|
41
|
+
},
|
|
42
|
+
$terminals: [deployment.terminal]
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export { obfuscator_default as default };
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/phantun/obfuscator/index.ts"],"names":[],"mappings":";;;;;;;AAOA,IAAM,EAAE,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,OAAA,KAAY,OAAA,CAAQ,GAAA,CAAI,WAAA,CAAY,OAAA,CAAQ,UAAU,CAAA;AAElF,IAAM,EAAE,OAAA,EAAS,SAAA,EAAW,YAAA,KAAiB,MAAM,uBAAA;AAAA,EACjD,SAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,UAAA,GAAa,UAAA,CAAW,MAAA,CAAO,OAAA,EAAS;AAAA,EAC5C,SAAA;AAAA,EAEA,SAAA,EAAW;AAAA,IACT,KAAA,EAAO,eAAO,OAAA,CAAQ,KAAA;AAAA,IAEtB,IAAA,EAAM;AAAA,MACJ,gBAAA;AAAA,MACA,SAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,MACA,mBAAmB,YAAY;AAAA,KACjC;AAAA,IAEA,IAAA,EAAM;AAAA,MACJ,aAAA,EAAe,IAAA;AAAA,MACf,QAAA,EAAU;AAAA,KACZ;AAAA,IAEA,gBAAA,EAAkB,CAAC,YAAY,CAAA;AAAA,IAC/B,SAAA,EAAW;AAAA,GACb;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,UAAU,IAAA,CAAK;AAAA;AAEnB,CAAC,CAAA;AAED,IAAO,qBAAQ,OAAA,CAAQ;AAAA,EACrB,cAAA,EAAgB,WAAW,OAAA,CAAQ,SAAA;AAAA,EAEnC,aAAA,EAAe;AAAA,IACb,gBAAgB,UAAA,CAAW,OAAA,CAAQ,UAAU,KAAA,CAAM,GAAA,CAAI,kBAAkB,CAAC;AAAA,GAC5E;AAAA,EAEA,UAAA,EAAY,CAAC,UAAA,CAAW,QAAQ;AAClC,CAAC","file":"index.js","sourcesContent":["import { l4EndpointToString } from \"@highstate/common\"\nimport { Deployment } from \"@highstate/k8s\"\nimport { k8s } from \"@highstate/library\"\nimport { forUnit } from \"@highstate/pulumi\"\nimport { map } from \"remeda\"\nimport { getObfuscatorComponents, images } from \"../../shared\"\n\nconst { name, args, inputs, outputs } = forUnit(k8s.obfuscators.phantun.obfuscator)\n\nconst { appName, namespace, bestEndpoint } = await getObfuscatorComponents(\n \"phantun\",\n name,\n args,\n inputs,\n)\n\nconst deployment = Deployment.create(appName, {\n namespace,\n\n container: {\n image: images.phantun.image,\n\n args: [\n \"phantun-client\",\n \"--local\",\n \"0.0.0.0:1234\",\n \"--remote\",\n l4EndpointToString(bestEndpoint),\n ],\n\n port: {\n containerPort: 1234,\n protocol: \"UDP\",\n },\n\n allowedEndpoints: [bestEndpoint],\n enableTun: true,\n },\n\n service: {\n external: args.external,\n },\n})\n\nexport default outputs({\n entryEndpoints: deployment.service.endpoints,\n\n $statusFields: {\n entryEndpoints: deployment.service.endpoints.apply(map(l4EndpointToString)),\n },\n\n $terminals: [deployment.terminal],\n})\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@highstate/k8s.obfuscators",
|
|
3
|
+
"version": "0.9.19",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"exports": {
|
|
9
|
+
"./phantun/deobfuscator": "./dist/phantun/deobfuscator/index.js",
|
|
10
|
+
"./phantun/obfuscator": "./dist/phantun/obfuscator/index.js"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "highstate build",
|
|
17
|
+
"update-images": "../../scripts/update-images.sh ./assets/images.json"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@highstate/cert-manager": "^0.9.19",
|
|
21
|
+
"@highstate/common": "^0.9.19",
|
|
22
|
+
"@highstate/contract": "^0.9.19",
|
|
23
|
+
"@highstate/k8s": "^0.9.19",
|
|
24
|
+
"@highstate/library": "^0.9.19",
|
|
25
|
+
"@highstate/pulumi": "^0.9.19",
|
|
26
|
+
"@pulumi/kubernetes": "^4.18.0",
|
|
27
|
+
"@pulumi/pulumi": "^3.184.0",
|
|
28
|
+
"remeda": "^2.21.3"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@highstate/cli": "^0.9.19"
|
|
32
|
+
},
|
|
33
|
+
"gitHead": "e77d292335556c6e5b6275acda1a3d1609d786a1"
|
|
34
|
+
}
|