@linkpane/newsletter-subscribe 0.1.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/README.md +34 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +52 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist-cjs/client.js +52 -0
- package/dist-cjs/client.js.map +1 -0
- package/dist-cjs/index.js +19 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/types.js +3 -0
- package/dist-cjs/types.js.map +1 -0
- package/package.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @linkpane/newsletter-subscribe
|
|
2
|
+
|
|
3
|
+
Subscribe-only SDK for Linkpane Newsletter endpoints.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @linkpane/newsletter-subscribe
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { subscribeNewsletter } from '@linkpane/newsletter-subscribe'
|
|
15
|
+
|
|
16
|
+
const result = await subscribeNewsletter({
|
|
17
|
+
apiBaseUrl: 'https://api.linkpane.com',
|
|
18
|
+
username: 'my-newsletter',
|
|
19
|
+
data: {
|
|
20
|
+
email: 'subscriber@example.com',
|
|
21
|
+
firstName: 'Ada',
|
|
22
|
+
lastName: 'Lovelace'
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
if (!result.ok) {
|
|
27
|
+
console.error(result.message, result.errors)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Notes
|
|
32
|
+
|
|
33
|
+
- For browser usage, ensure the request Origin matches the configured source domain.
|
|
34
|
+
- You can supply a custom `fetch` for server environments.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAQ9E,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CA8CpC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.subscribeNewsletter = subscribeNewsletter;
|
|
4
|
+
function getFetchImpl(explicitFetch) {
|
|
5
|
+
if (explicitFetch)
|
|
6
|
+
return explicitFetch;
|
|
7
|
+
if (typeof fetch !== 'undefined')
|
|
8
|
+
return fetch;
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
async function subscribeNewsletter(params) {
|
|
12
|
+
const fetchImpl = getFetchImpl(params.fetch);
|
|
13
|
+
if (!fetchImpl) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
message: 'Fetch API is not available. Provide a fetch implementation via options.fetch.',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const url = `${params.apiBaseUrl.replace(/\/+$/, '')}/mailer/newsletter/${encodeURIComponent(params.username)}/subscribe`;
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetchImpl(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
Accept: 'application/json',
|
|
26
|
+
...params.headers,
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(params.data),
|
|
29
|
+
});
|
|
30
|
+
const contentType = response.headers?.get?.('content-type') || '';
|
|
31
|
+
if (contentType.includes('application/json')) {
|
|
32
|
+
const payload = await response.json().catch(() => null);
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
message: payload?.message || 'Subscription failed',
|
|
37
|
+
errors: payload?.errors,
|
|
38
|
+
status: response.status,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { ok: true, message: payload?.message, status: response.status, data: payload };
|
|
42
|
+
}
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
return { ok: false, message: 'Subscription failed', status: response.status };
|
|
45
|
+
}
|
|
46
|
+
return { ok: true, status: response.status };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return { ok: false, message: error?.message || 'Subscription failed' };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AAQA,kDAgDC;AAtDD,SAAS,YAAY,CAAC,aAA4B;IAChD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAA;IACvC,IAAI,OAAO,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAEM,KAAK,UAAU,mBAAmB,CACvC,MAAiC;IAEjC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,+EAA+E;SACzF,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,kBAAkB,CAC1F,MAAM,CAAC,QAAQ,CAChB,YAAY,CAAA;IAEb,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;gBAC1B,GAAG,MAAM,CAAC,OAAO;aAClB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;SAClC,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;QACjE,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YACvD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,qBAAqB;oBAClD,MAAM,EAAE,OAAO,EAAE,MAAM;oBACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;iBACxB,CAAA;YACH,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QACxF,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC/E,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,qBAAqB,EAAE,CAAA;IACxE,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./client"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,2CAAwB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type SubscribeNewsletterParams = {
|
|
2
|
+
apiBaseUrl: string;
|
|
3
|
+
username: string;
|
|
4
|
+
data: Record<string, any>;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
};
|
|
8
|
+
export type NewsletterSubscribeResult = {
|
|
9
|
+
ok: true;
|
|
10
|
+
message?: string;
|
|
11
|
+
status: number;
|
|
12
|
+
data?: any;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
message: string;
|
|
16
|
+
status?: number;
|
|
17
|
+
errors?: any;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAA;CAAE,GAC1D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.subscribeNewsletter = subscribeNewsletter;
|
|
4
|
+
function getFetchImpl(explicitFetch) {
|
|
5
|
+
if (explicitFetch)
|
|
6
|
+
return explicitFetch;
|
|
7
|
+
if (typeof fetch !== 'undefined')
|
|
8
|
+
return fetch;
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
async function subscribeNewsletter(params) {
|
|
12
|
+
const fetchImpl = getFetchImpl(params.fetch);
|
|
13
|
+
if (!fetchImpl) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
message: 'Fetch API is not available. Provide a fetch implementation via options.fetch.',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const url = `${params.apiBaseUrl.replace(/\/+$/, '')}/mailer/newsletter/${encodeURIComponent(params.username)}/subscribe`;
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetchImpl(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
Accept: 'application/json',
|
|
26
|
+
...params.headers,
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(params.data),
|
|
29
|
+
});
|
|
30
|
+
const contentType = response.headers?.get?.('content-type') || '';
|
|
31
|
+
if (contentType.includes('application/json')) {
|
|
32
|
+
const payload = await response.json().catch(() => null);
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
message: payload?.message || 'Subscription failed',
|
|
37
|
+
errors: payload?.errors,
|
|
38
|
+
status: response.status,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { ok: true, message: payload?.message, status: response.status, data: payload };
|
|
42
|
+
}
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
return { ok: false, message: 'Subscription failed', status: response.status };
|
|
45
|
+
}
|
|
46
|
+
return { ok: true, status: response.status };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return { ok: false, message: error?.message || 'Subscription failed' };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AAQA,kDAgDC;AAtDD,SAAS,YAAY,CAAC,aAA4B;IAChD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAA;IACvC,IAAI,OAAO,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAEM,KAAK,UAAU,mBAAmB,CACvC,MAAiC;IAEjC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,+EAA+E;SACzF,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,kBAAkB,CAC1F,MAAM,CAAC,QAAQ,CAChB,YAAY,CAAA;IAEb,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;gBAC1B,GAAG,MAAM,CAAC,OAAO;aAClB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;SAClC,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;QACjE,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YACvD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,qBAAqB;oBAClD,MAAM,EAAE,OAAO,EAAE,MAAM;oBACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;iBACxB,CAAA;YACH,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QACxF,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC/E,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,qBAAqB,EAAE,CAAA;IACxE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./client"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,2CAAwB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@linkpane/newsletter-subscribe",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Subscribe-only SDK for Linkpane Newsletter endpoints",
|
|
5
|
+
"main": "dist-cjs/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"dist-cjs"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json",
|
|
15
|
+
"dev": "tsc -p tsconfig.esm.json --watch",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=16"
|
|
21
|
+
}
|
|
22
|
+
}
|