@borta/user-pictures 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/dist/index.cjs +85 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
buildImageUrl: () => buildImageUrl,
|
|
24
|
+
getAllImageUrls: () => getAllImageUrls,
|
|
25
|
+
getPreviewImageUrl: () => getPreviewImageUrl,
|
|
26
|
+
getProfile: () => getProfile,
|
|
27
|
+
getPublicPictures: () => getPublicPictures,
|
|
28
|
+
getSafePictures: () => getSafePictures
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/api/index.ts
|
|
33
|
+
var DEFAULT_BASE_URL = "https://www.hunqz.com/api/opengrid";
|
|
34
|
+
var DEFAULT_PROFILE_SLUG = "msescortplus";
|
|
35
|
+
var DEFAULT_TIMEOUT = 1e4;
|
|
36
|
+
var getProfile = async (slug = DEFAULT_PROFILE_SLUG, config) => {
|
|
37
|
+
const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
|
|
38
|
+
const timeout = config?.timeout || DEFAULT_TIMEOUT;
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(`${baseUrl}/profiles/${slug}`, {
|
|
43
|
+
signal: controller.signal
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
return await response.json();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
51
|
+
throw new Error(`Request timeout after ${timeout}ms`);
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
} finally {
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/utils/index.ts
|
|
60
|
+
var buildImageUrl = (urlToken) => {
|
|
61
|
+
return `https://www.hunqz.com/img/usr/original/0x0/${urlToken}.jpg`;
|
|
62
|
+
};
|
|
63
|
+
var getPublicPictures = (profile) => {
|
|
64
|
+
return profile.pictures.filter((picture) => picture.is_public);
|
|
65
|
+
};
|
|
66
|
+
var getSafePictures = (profile) => {
|
|
67
|
+
return profile.pictures.filter((picture) => picture.rating === "APP_SAFE" || picture.rating === "NEUTRAL");
|
|
68
|
+
};
|
|
69
|
+
var getPreviewImageUrl = (profile) => {
|
|
70
|
+
return profile.preview_pic ? buildImageUrl(profile.preview_pic.url_token) : null;
|
|
71
|
+
};
|
|
72
|
+
var getAllImageUrls = (profile, onlyPublic = true) => {
|
|
73
|
+
const pictures = onlyPublic ? getPublicPictures(profile) : profile.pictures;
|
|
74
|
+
return pictures.map((picture) => buildImageUrl(picture.url_token));
|
|
75
|
+
};
|
|
76
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
77
|
+
0 && (module.exports = {
|
|
78
|
+
buildImageUrl,
|
|
79
|
+
getAllImageUrls,
|
|
80
|
+
getPreviewImageUrl,
|
|
81
|
+
getProfile,
|
|
82
|
+
getPublicPictures,
|
|
83
|
+
getSafePictures
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/api/index.ts","../src/utils/index.ts"],"sourcesContent":["// API\nexport { getProfile } from './api/index.js';\n\n// Utility\nexport { \n buildImageUrl, \n getPublicPictures, \n getSafePictures,\n getPreviewImageUrl,\n getAllImageUrls\n} from './utils/index.js';\n\n// Types\nexport type { ApiConfig, Profile, Picture } from './types/index.js';\n","import type { ApiConfig, Profile } from \"../types\";\n\nconst DEFAULT_BASE_URL = 'https://www.hunqz.com/api/opengrid';\nconst DEFAULT_PROFILE_SLUG = 'msescortplus';\nconst DEFAULT_TIMEOUT = 10000;\n\nexport const getProfile = async (slug = DEFAULT_PROFILE_SLUG, config?: ApiConfig): Promise<Profile> => {\n const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;\n const timeout = config?.timeout || DEFAULT_TIMEOUT;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(`${baseUrl}/profiles/${slug}`, {\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! Status: ${response.status}`);\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timeout after ${timeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}","import { Picture, Profile } from \"../types\"\n\nexport const buildImageUrl = (urlToken: string): string => {\n return `https://www.hunqz.com/img/usr/original/0x0/${urlToken}.jpg`\n}\n\nexport const getPublicPictures = (profile: Profile): Picture[] => {\n return profile.pictures.filter(picture => picture.is_public);\n}\n\nexport const getSafePictures = (profile: Profile) => {\n return profile.pictures.filter(picture => picture.rating === \"APP_SAFE\" || picture.rating === \"NEUTRAL\" );\n}\n\nexport const getPreviewImageUrl = (profile: Profile): string | null => {\n return profile.preview_pic ? buildImageUrl(profile.preview_pic.url_token) : null;\n}\n\nexport const getAllImageUrls = (profile: Profile, onlyPublic = true): string[] => {\n const pictures = onlyPublic ? getPublicPictures(profile) : profile.pictures;\n return pictures.map(picture => buildImageUrl(picture.url_token));\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AAEjB,IAAM,aAAa,OAAO,OAAO,sBAAsB,WAAyC;AACpG,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,UAAU,QAAQ,WAAW;AAEnC,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAE9D,MAAI;AACC,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,aAAa,IAAI,IAAI;AAAA,MACxD,QAAQ,WAAW;AAAA,IACvB,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,EAAE;AAAA,IAC5D;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAChC,SAAS,OAAO;AACX,QAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACvD,YAAM,IAAI,MAAM,yBAAyB,OAAO,IAAI;AAAA,IACxD;AACA,UAAM;AAAA,EACZ,UAAE;AACI,iBAAa,SAAS;AAAA,EAC5B;AACF;;;AC7BO,IAAM,gBAAgB,CAAC,aAA6B;AACvD,SAAO,8CAA8C,QAAQ;AACjE;AAEO,IAAM,oBAAoB,CAAC,YAAgC;AAC9D,SAAO,QAAQ,SAAS,OAAO,aAAW,QAAQ,SAAS;AAC/D;AAEO,IAAM,kBAAkB,CAAC,YAAqB;AACjD,SAAO,QAAQ,SAAS,OAAO,aAAW,QAAQ,WAAW,cAAc,QAAQ,WAAW,SAAU;AAC5G;AAEO,IAAM,qBAAqB,CAAC,YAAoC;AACnE,SAAO,QAAQ,cAAc,cAAc,QAAQ,YAAY,SAAS,IAAI;AAChF;AAEO,IAAM,kBAAkB,CAAC,SAAkB,aAAa,SAAmB;AAC9E,QAAM,WAAW,aAAa,kBAAkB,OAAO,IAAI,QAAQ;AACnE,SAAO,SAAS,IAAI,aAAW,cAAc,QAAQ,SAAS,CAAC;AACnE;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface Picture {
|
|
2
|
+
id: string;
|
|
3
|
+
url_token: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
rating: 'NEUTRAL' | 'EROTIC' | 'APP_SAFE';
|
|
7
|
+
is_public: boolean;
|
|
8
|
+
comment?: string;
|
|
9
|
+
}
|
|
10
|
+
interface Profile {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
headline?: string;
|
|
14
|
+
preview_pic?: Picture;
|
|
15
|
+
pictures: Picture[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface ApiConfig {
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare const getProfile: (slug?: string, config?: ApiConfig) => Promise<Profile>;
|
|
24
|
+
|
|
25
|
+
declare const buildImageUrl: (urlToken: string) => string;
|
|
26
|
+
declare const getPublicPictures: (profile: Profile) => Picture[];
|
|
27
|
+
declare const getSafePictures: (profile: Profile) => Picture[];
|
|
28
|
+
declare const getPreviewImageUrl: (profile: Profile) => string | null;
|
|
29
|
+
declare const getAllImageUrls: (profile: Profile, onlyPublic?: boolean) => string[];
|
|
30
|
+
|
|
31
|
+
export { type ApiConfig, type Picture, type Profile, buildImageUrl, getAllImageUrls, getPreviewImageUrl, getProfile, getPublicPictures, getSafePictures };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface Picture {
|
|
2
|
+
id: string;
|
|
3
|
+
url_token: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
rating: 'NEUTRAL' | 'EROTIC' | 'APP_SAFE';
|
|
7
|
+
is_public: boolean;
|
|
8
|
+
comment?: string;
|
|
9
|
+
}
|
|
10
|
+
interface Profile {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
headline?: string;
|
|
14
|
+
preview_pic?: Picture;
|
|
15
|
+
pictures: Picture[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface ApiConfig {
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare const getProfile: (slug?: string, config?: ApiConfig) => Promise<Profile>;
|
|
24
|
+
|
|
25
|
+
declare const buildImageUrl: (urlToken: string) => string;
|
|
26
|
+
declare const getPublicPictures: (profile: Profile) => Picture[];
|
|
27
|
+
declare const getSafePictures: (profile: Profile) => Picture[];
|
|
28
|
+
declare const getPreviewImageUrl: (profile: Profile) => string | null;
|
|
29
|
+
declare const getAllImageUrls: (profile: Profile, onlyPublic?: boolean) => string[];
|
|
30
|
+
|
|
31
|
+
export { type ApiConfig, type Picture, type Profile, buildImageUrl, getAllImageUrls, getPreviewImageUrl, getProfile, getPublicPictures, getSafePictures };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/api/index.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://www.hunqz.com/api/opengrid";
|
|
3
|
+
var DEFAULT_PROFILE_SLUG = "msescortplus";
|
|
4
|
+
var DEFAULT_TIMEOUT = 1e4;
|
|
5
|
+
var getProfile = async (slug = DEFAULT_PROFILE_SLUG, config) => {
|
|
6
|
+
const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
|
|
7
|
+
const timeout = config?.timeout || DEFAULT_TIMEOUT;
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
10
|
+
try {
|
|
11
|
+
const response = await fetch(`${baseUrl}/profiles/${slug}`, {
|
|
12
|
+
signal: controller.signal
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
16
|
+
}
|
|
17
|
+
return await response.json();
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
20
|
+
throw new Error(`Request timeout after ${timeout}ms`);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
} finally {
|
|
24
|
+
clearTimeout(timeoutId);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/utils/index.ts
|
|
29
|
+
var buildImageUrl = (urlToken) => {
|
|
30
|
+
return `https://www.hunqz.com/img/usr/original/0x0/${urlToken}.jpg`;
|
|
31
|
+
};
|
|
32
|
+
var getPublicPictures = (profile) => {
|
|
33
|
+
return profile.pictures.filter((picture) => picture.is_public);
|
|
34
|
+
};
|
|
35
|
+
var getSafePictures = (profile) => {
|
|
36
|
+
return profile.pictures.filter((picture) => picture.rating === "APP_SAFE" || picture.rating === "NEUTRAL");
|
|
37
|
+
};
|
|
38
|
+
var getPreviewImageUrl = (profile) => {
|
|
39
|
+
return profile.preview_pic ? buildImageUrl(profile.preview_pic.url_token) : null;
|
|
40
|
+
};
|
|
41
|
+
var getAllImageUrls = (profile, onlyPublic = true) => {
|
|
42
|
+
const pictures = onlyPublic ? getPublicPictures(profile) : profile.pictures;
|
|
43
|
+
return pictures.map((picture) => buildImageUrl(picture.url_token));
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
buildImageUrl,
|
|
47
|
+
getAllImageUrls,
|
|
48
|
+
getPreviewImageUrl,
|
|
49
|
+
getProfile,
|
|
50
|
+
getPublicPictures,
|
|
51
|
+
getSafePictures
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/index.ts","../src/utils/index.ts"],"sourcesContent":["import type { ApiConfig, Profile } from \"../types\";\n\nconst DEFAULT_BASE_URL = 'https://www.hunqz.com/api/opengrid';\nconst DEFAULT_PROFILE_SLUG = 'msescortplus';\nconst DEFAULT_TIMEOUT = 10000;\n\nexport const getProfile = async (slug = DEFAULT_PROFILE_SLUG, config?: ApiConfig): Promise<Profile> => {\n const baseUrl = config?.baseUrl || DEFAULT_BASE_URL;\n const timeout = config?.timeout || DEFAULT_TIMEOUT;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(`${baseUrl}/profiles/${slug}`, {\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! Status: ${response.status}`);\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timeout after ${timeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}","import { Picture, Profile } from \"../types\"\n\nexport const buildImageUrl = (urlToken: string): string => {\n return `https://www.hunqz.com/img/usr/original/0x0/${urlToken}.jpg`\n}\n\nexport const getPublicPictures = (profile: Profile): Picture[] => {\n return profile.pictures.filter(picture => picture.is_public);\n}\n\nexport const getSafePictures = (profile: Profile) => {\n return profile.pictures.filter(picture => picture.rating === \"APP_SAFE\" || picture.rating === \"NEUTRAL\" );\n}\n\nexport const getPreviewImageUrl = (profile: Profile): string | null => {\n return profile.preview_pic ? buildImageUrl(profile.preview_pic.url_token) : null;\n}\n\nexport const getAllImageUrls = (profile: Profile, onlyPublic = true): string[] => {\n const pictures = onlyPublic ? getPublicPictures(profile) : profile.pictures;\n return pictures.map(picture => buildImageUrl(picture.url_token));\n}"],"mappings":";AAEA,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AAEjB,IAAM,aAAa,OAAO,OAAO,sBAAsB,WAAyC;AACpG,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,UAAU,QAAQ,WAAW;AAEnC,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAE9D,MAAI;AACC,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,aAAa,IAAI,IAAI;AAAA,MACxD,QAAQ,WAAW;AAAA,IACvB,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,EAAE;AAAA,IAC5D;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAChC,SAAS,OAAO;AACX,QAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACvD,YAAM,IAAI,MAAM,yBAAyB,OAAO,IAAI;AAAA,IACxD;AACA,UAAM;AAAA,EACZ,UAAE;AACI,iBAAa,SAAS;AAAA,EAC5B;AACF;;;AC7BO,IAAM,gBAAgB,CAAC,aAA6B;AACvD,SAAO,8CAA8C,QAAQ;AACjE;AAEO,IAAM,oBAAoB,CAAC,YAAgC;AAC9D,SAAO,QAAQ,SAAS,OAAO,aAAW,QAAQ,SAAS;AAC/D;AAEO,IAAM,kBAAkB,CAAC,YAAqB;AACjD,SAAO,QAAQ,SAAS,OAAO,aAAW,QAAQ,WAAW,cAAc,QAAQ,WAAW,SAAU;AAC5G;AAEO,IAAM,qBAAqB,CAAC,YAAoC;AACnE,SAAO,QAAQ,cAAc,cAAc,QAAQ,YAAY,SAAS,IAAI;AAChF;AAEO,IAAM,kBAAkB,CAAC,SAAkB,aAAa,SAAmB;AAC9E,QAAM,WAAW,aAAa,kBAAkB,OAAO,IAAI,QAAQ;AACnE,SAAO,SAAS,IAAI,aAAW,cAAc,QAAQ,SAAS,CAAC;AACnE;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@borta/user-pictures",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared user pictures SDK for Erasys Test",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/borta/erasys-test.git",
|
|
14
|
+
"directory": "packages/user-pictures"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs",
|
|
24
|
+
"types": "./dist/index.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
29
|
+
"tsup": "^8.5.1",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vitest": "^4.0.18"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"dev": "tsup --watch",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"test:coverage": "vitest run --coverage"
|
|
39
|
+
}
|
|
40
|
+
}
|