@ministryofjustice/hmpps-mpop-frontend-components-lib 0.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/README.md +2 -0
- package/dist/MPoPComponents.d.ts +10 -0
- package/dist/SuppressingRestClient.d.ts +8 -0
- package/dist/_all.scss +4 -0
- package/dist/index.cjs.js +54 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.esm.js +52 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/mpop/components/supervision-package/_supervision-package.scss +22 -0
- package/dist/mpop/components/supervision-package/macro.njk +3 -0
- package/dist/mpop/components/supervision-package/template.njk +31 -0
- package/dist/types/MPoPComponentsConfig.d.ts +3 -0
- package/dist/types/TierCalculation.d.ts +11 -0
- package/package.json +96 -0
package/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthOptions } from '@ministryofjustice/hmpps-rest-client';
|
|
2
|
+
import type { AuthenticationClient } from '@ministryofjustice/hmpps-auth-clients';
|
|
3
|
+
import type Logger from 'bunyan';
|
|
4
|
+
import type { MPoPComponentsConfig } from './types/MPoPComponentsConfig';
|
|
5
|
+
import type { LatestTierResponse } from './types/TierCalculation';
|
|
6
|
+
export default class MPoPComponents {
|
|
7
|
+
private readonly tierApiRestClient;
|
|
8
|
+
constructor(authenticationClient: AuthenticationClient, config: MPoPComponentsConfig, logger?: Logger | Console);
|
|
9
|
+
getTierDetails(authOptions: AuthOptions | string, crn: string): Promise<LatestTierResponse>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RestClient, AuthOptions } from '@ministryofjustice/hmpps-rest-client';
|
|
2
|
+
import type Logger from 'bunyan';
|
|
3
|
+
export declare class SuppressingRestClient {
|
|
4
|
+
private readonly restClient;
|
|
5
|
+
private readonly logger;
|
|
6
|
+
constructor(restClient: RestClient, logger: Logger | Console);
|
|
7
|
+
get<T>(path: string, authOptions: AuthOptions | string): Promise<T | null>;
|
|
8
|
+
}
|
package/dist/_all.scss
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var hmppsRestClient = require('@ministryofjustice/hmpps-rest-client');
|
|
4
|
+
|
|
5
|
+
class SuppressingRestClient {
|
|
6
|
+
constructor(restClient, logger) {
|
|
7
|
+
this.restClient = restClient;
|
|
8
|
+
this.logger = logger;
|
|
9
|
+
}
|
|
10
|
+
async get(path, authOptions) {
|
|
11
|
+
return this.restClient.get({
|
|
12
|
+
path,
|
|
13
|
+
errorHandler: (requestPath, method, error) => {
|
|
14
|
+
if (error.responseStatus === 404) {
|
|
15
|
+
this.logger.debug(`API returned 404 (Not Found) for ${method}: ${requestPath}`);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
throw error;
|
|
19
|
+
},
|
|
20
|
+
}, authOptions);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class MPoPComponents {
|
|
25
|
+
constructor(authenticationClient, config, logger = console) {
|
|
26
|
+
this.tierApiRestClient = new SuppressingRestClient(new hmppsRestClient.RestClient('Tier API', config, logger, authenticationClient), logger);
|
|
27
|
+
}
|
|
28
|
+
async getTierDetails(authOptions, crn) {
|
|
29
|
+
var _a;
|
|
30
|
+
try {
|
|
31
|
+
const response = await this.tierApiRestClient.get(`/v3/crn/${crn}/tier`, authOptions);
|
|
32
|
+
if (!response) {
|
|
33
|
+
return {
|
|
34
|
+
calculation: null,
|
|
35
|
+
httpStatus: 404,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
calculation: response,
|
|
40
|
+
httpStatus: 200,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const err = error;
|
|
45
|
+
return {
|
|
46
|
+
calculation: null,
|
|
47
|
+
httpStatus: (_a = err === null || err === void 0 ? void 0 : err.responseStatus) !== null && _a !== void 0 ? _a : 500,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
exports.MPoPComponents = MPoPComponents;
|
|
54
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/SuppressingRestClient.ts","../src/MPoPComponents.ts"],"sourcesContent":[null,null],"names":["RestClient"],"mappings":";;;;MAGa,qBAAqB,CAAA;IAChC,WAAA,CACmB,UAAsB,EACtB,MAAwB,EAAA;QADxB,IAAA,CAAA,UAAU,GAAV,UAAU;QACV,IAAA,CAAA,MAAM,GAAN,MAAM;IACtB;AAEH,IAAA,MAAM,GAAG,CAAI,IAAY,EAAE,WAAiC,EAAA;AAC1D,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CACxB;YACE,IAAI;YACJ,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,KAAI;AAC3C,gBAAA,IAAI,KAAK,CAAC,cAAc,KAAK,GAAG,EAAE;oBAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,iCAAA,EAAoC,MAAM,CAAA,EAAA,EAAK,WAAW,CAAA,CAAE,CAAC;AAC/E,oBAAA,OAAO,IAAI;gBACb;AACA,gBAAA,MAAM,KAAK;YACb,CAAC;SACF,EACD,WAAW,CACZ;IACH;AACD;;ACfa,MAAO,cAAc,CAAA;AAGjC,IAAA,WAAA,CACE,oBAA0C,EAC1C,MAA4B,EAC5B,SAA2B,OAAO,EAAA;QAElC,IAAI,CAAC,iBAAiB,GAAG,IAAI,qBAAqB,CAChD,IAAIA,0BAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAChE,MAAM,CACP;IACH;AAEA,IAAA,MAAM,cAAc,CAAC,WAAiC,EAAE,GAAW,EAAA;;AACjE,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAa,WAAW,GAAG,CAAA,KAAA,CAAO,EAAE,WAAW,CAAC;YAEjG,IAAI,CAAC,QAAQ,EAAE;gBACb,OAAO;AACL,oBAAA,WAAW,EAAE,IAAI;AACjB,oBAAA,UAAU,EAAE,GAAG;iBAChB;YACH;YAEA,OAAO;AACL,gBAAA,WAAW,EAAE,QAAQ;AACrB,gBAAA,UAAU,EAAE,GAAG;aAChB;QACH;QAAE,OAAO,KAAK,EAAE;YACd,MAAM,GAAG,GAAG,KAEJ;YAER,OAAO;AACL,gBAAA,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,CAAA,EAAA,GAAA,GAAG,KAAA,IAAA,IAAH,GAAG,uBAAH,GAAG,CAAE,cAAc,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,GAAG;aACvC;QACH;IACF;AACD;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ApiConfig, AuthOptions } from '@ministryofjustice/hmpps-rest-client';
|
|
2
|
+
import { AuthenticationClient } from '@ministryofjustice/hmpps-auth-clients';
|
|
3
|
+
import Logger from 'bunyan';
|
|
4
|
+
|
|
5
|
+
interface MPoPComponentsConfig extends ApiConfig {
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type LatestTier = {
|
|
9
|
+
tierScore: string;
|
|
10
|
+
calculationId: string;
|
|
11
|
+
calculationDate: string;
|
|
12
|
+
changeReason: string;
|
|
13
|
+
provisional: boolean;
|
|
14
|
+
};
|
|
15
|
+
type LatestTierResponse = {
|
|
16
|
+
calculation: LatestTier | null;
|
|
17
|
+
httpStatus: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
declare class MPoPComponents {
|
|
21
|
+
private readonly tierApiRestClient;
|
|
22
|
+
constructor(authenticationClient: AuthenticationClient, config: MPoPComponentsConfig, logger?: Logger | Console);
|
|
23
|
+
getTierDetails(authOptions: AuthOptions | string, crn: string): Promise<LatestTierResponse>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { MPoPComponents };
|
|
27
|
+
export type { MPoPComponentsConfig };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RestClient } from '@ministryofjustice/hmpps-rest-client';
|
|
2
|
+
|
|
3
|
+
class SuppressingRestClient {
|
|
4
|
+
constructor(restClient, logger) {
|
|
5
|
+
this.restClient = restClient;
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
}
|
|
8
|
+
async get(path, authOptions) {
|
|
9
|
+
return this.restClient.get({
|
|
10
|
+
path,
|
|
11
|
+
errorHandler: (requestPath, method, error) => {
|
|
12
|
+
if (error.responseStatus === 404) {
|
|
13
|
+
this.logger.debug(`API returned 404 (Not Found) for ${method}: ${requestPath}`);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
},
|
|
18
|
+
}, authOptions);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class MPoPComponents {
|
|
23
|
+
constructor(authenticationClient, config, logger = console) {
|
|
24
|
+
this.tierApiRestClient = new SuppressingRestClient(new RestClient('Tier API', config, logger, authenticationClient), logger);
|
|
25
|
+
}
|
|
26
|
+
async getTierDetails(authOptions, crn) {
|
|
27
|
+
var _a;
|
|
28
|
+
try {
|
|
29
|
+
const response = await this.tierApiRestClient.get(`/v3/crn/${crn}/tier`, authOptions);
|
|
30
|
+
if (!response) {
|
|
31
|
+
return {
|
|
32
|
+
calculation: null,
|
|
33
|
+
httpStatus: 404,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
calculation: response,
|
|
38
|
+
httpStatus: 200,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const err = error;
|
|
43
|
+
return {
|
|
44
|
+
calculation: null,
|
|
45
|
+
httpStatus: (_a = err === null || err === void 0 ? void 0 : err.responseStatus) !== null && _a !== void 0 ? _a : 500,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { MPoPComponents };
|
|
52
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/SuppressingRestClient.ts","../src/MPoPComponents.ts"],"sourcesContent":[null,null],"names":[],"mappings":";;MAGa,qBAAqB,CAAA;IAChC,WAAA,CACmB,UAAsB,EACtB,MAAwB,EAAA;QADxB,IAAA,CAAA,UAAU,GAAV,UAAU;QACV,IAAA,CAAA,MAAM,GAAN,MAAM;IACtB;AAEH,IAAA,MAAM,GAAG,CAAI,IAAY,EAAE,WAAiC,EAAA;AAC1D,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CACxB;YACE,IAAI;YACJ,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,KAAI;AAC3C,gBAAA,IAAI,KAAK,CAAC,cAAc,KAAK,GAAG,EAAE;oBAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,iCAAA,EAAoC,MAAM,CAAA,EAAA,EAAK,WAAW,CAAA,CAAE,CAAC;AAC/E,oBAAA,OAAO,IAAI;gBACb;AACA,gBAAA,MAAM,KAAK;YACb,CAAC;SACF,EACD,WAAW,CACZ;IACH;AACD;;ACfa,MAAO,cAAc,CAAA;AAGjC,IAAA,WAAA,CACE,oBAA0C,EAC1C,MAA4B,EAC5B,SAA2B,OAAO,EAAA;QAElC,IAAI,CAAC,iBAAiB,GAAG,IAAI,qBAAqB,CAChD,IAAI,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAChE,MAAM,CACP;IACH;AAEA,IAAA,MAAM,cAAc,CAAC,WAAiC,EAAE,GAAW,EAAA;;AACjE,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAa,WAAW,GAAG,CAAA,KAAA,CAAO,EAAE,WAAW,CAAC;YAEjG,IAAI,CAAC,QAAQ,EAAE;gBACb,OAAO;AACL,oBAAA,WAAW,EAAE,IAAI;AACjB,oBAAA,UAAU,EAAE,GAAG;iBAChB;YACH;YAEA,OAAO;AACL,gBAAA,WAAW,EAAE,QAAQ;AACrB,gBAAA,UAAU,EAAE,GAAG;aAChB;QACH;QAAE,OAAO,KAAK,EAAE;YACd,MAAM,GAAG,GAAG,KAEJ;YAER,OAAO;AACL,gBAAA,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,CAAA,EAAA,GAAA,GAAG,KAAA,IAAA,IAAH,GAAG,uBAAH,GAAG,CAAE,cAAc,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,GAAG;aACvC;QACH;IACF;AACD;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
$supervision-package-border-colour: govuk-colour("mid-grey");
|
|
2
|
+
$supervision-package-accent-colour: govuk-colour("blue");
|
|
3
|
+
|
|
4
|
+
.supervision-package {
|
|
5
|
+
border-top: 5px solid $supervision-package-accent-colour;
|
|
6
|
+
border-right: 1px solid $supervision-package-border-colour;
|
|
7
|
+
border-bottom: 1px solid $supervision-package-border-colour;
|
|
8
|
+
border-left: 1px solid $supervision-package-border-colour;
|
|
9
|
+
|
|
10
|
+
padding-top: govuk-spacing(4);
|
|
11
|
+
padding-right: govuk-spacing(4);
|
|
12
|
+
padding-left: govuk-spacing(4);
|
|
13
|
+
|
|
14
|
+
margin-bottom: govuk-spacing(6);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.app-tier-header {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: govuk-spacing(2);
|
|
21
|
+
margin-bottom: govuk-spacing(3);
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<div class="govuk-width-container supervision-package">
|
|
2
|
+
<h2 class="govuk-heading-m">{{ params.heading or "Supervision package" }}</h2>
|
|
3
|
+
|
|
4
|
+
<div class="govuk-grid-row">
|
|
5
|
+
<div class="govuk-grid-column-two-thirds">
|
|
6
|
+
<div class="app-tier-header">
|
|
7
|
+
<h3 class="govuk-heading-s govuk-!-margin-bottom-0">
|
|
8
|
+
Tier {{ params.tierScore }}
|
|
9
|
+
</h3>
|
|
10
|
+
|
|
11
|
+
{% if params.provisional %}
|
|
12
|
+
<strong class="govuk-tag govuk-tag--orange">Provisional</strong>
|
|
13
|
+
{% endif %}
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
{% if params.provisional %}
|
|
17
|
+
<p class="govuk-body">
|
|
18
|
+
We will calculate the supervision package once the tier is confirmed.
|
|
19
|
+
</p>
|
|
20
|
+
{% endif %}
|
|
21
|
+
|
|
22
|
+
{% if params.historyHref %}
|
|
23
|
+
<p class="govuk-body">
|
|
24
|
+
<a href="{{ params.historyHref }}" class="govuk-link govuk-link--no-visited-state">
|
|
25
|
+
{{ params.historyText or "View tier change history" }}
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
{% endif %}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ministryofjustice/hmpps-mpop-frontend-components-lib",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MPOP front-end components library",
|
|
5
|
+
"main": "./dist/index.cjs.js",
|
|
6
|
+
"module": "./dist/index.esm.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"sass": "./dist/_all.scss",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**/*"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"prepare": "hmpps-precommit-hooks-prepare",
|
|
14
|
+
"build": "rollup -c rollup.config.ts --bundleConfigAsCjs",
|
|
15
|
+
"clean": "rm -rf ./dist/ && find . -name '.eslintcache' -delete",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"test:coverage": "jest --coverage",
|
|
18
|
+
"test:ci": "jest --runInBand --passWithNoTests",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"lint": "eslint . --cache --max-warnings 0",
|
|
21
|
+
"lint:fix": "eslint . --cache --max-warnings 0 --fix",
|
|
22
|
+
"security_audit": "npx audit-ci --config audit-ci.json",
|
|
23
|
+
"setup": "npm ci && hmpps-npm-script-run-allowlist",
|
|
24
|
+
"preview": "tsx scripts/preview.ts",
|
|
25
|
+
"preview:api": "tsx scripts/preview-api.ts"
|
|
26
|
+
},
|
|
27
|
+
"lint-staged": {
|
|
28
|
+
"*.{ts,css}": [
|
|
29
|
+
"prettier --write",
|
|
30
|
+
"eslint --fix"
|
|
31
|
+
],
|
|
32
|
+
"*.json": [
|
|
33
|
+
"prettier --write"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"jest": {
|
|
37
|
+
"transform": {
|
|
38
|
+
"^.+\\.(ts|js|mjs|tsx|jsx)$": "babel-jest"
|
|
39
|
+
},
|
|
40
|
+
"transformIgnorePatterns": [
|
|
41
|
+
"/node_modules/(?!(@exodus|@csstools|jsdom|parse5|abab|entities|nunjucks|@asamuzakjp)/)"
|
|
42
|
+
],
|
|
43
|
+
"testMatch": [
|
|
44
|
+
"<rootDir>/**/**/?(*.)(cy|test).{ts,js,jsx,mjs}"
|
|
45
|
+
],
|
|
46
|
+
"testEnvironment": "node",
|
|
47
|
+
"moduleFileExtensions": [
|
|
48
|
+
"web.js",
|
|
49
|
+
"js",
|
|
50
|
+
"json",
|
|
51
|
+
"node",
|
|
52
|
+
"ts"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"keywords": [],
|
|
56
|
+
"author": "",
|
|
57
|
+
"license": "ISC",
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@babel/core": "^7.29.7",
|
|
60
|
+
"@babel/preset-env": "^7.29.7",
|
|
61
|
+
"@babel/preset-typescript": "^7.29.7",
|
|
62
|
+
"@ministryofjustice/eslint-config-hmpps": "1.0.3",
|
|
63
|
+
"@ministryofjustice/hmpps-npm-script-allowlist": "0.0.6",
|
|
64
|
+
"@ministryofjustice/hmpps-precommit-hooks": "3.0.1",
|
|
65
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
66
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
67
|
+
"@types/bunyan": "^1.8.11",
|
|
68
|
+
"@types/jest": "^30.0.0",
|
|
69
|
+
"@types/jsdom": "^28.0.3",
|
|
70
|
+
"@types/node": "25.9.1",
|
|
71
|
+
"@typescript-eslint/eslint-plugin": "8.60.1",
|
|
72
|
+
"babel-jest": "^30.4.1",
|
|
73
|
+
"dotenv": "17.4.2",
|
|
74
|
+
"eslint-import-resolver-typescript": "4.4.5",
|
|
75
|
+
"eslint-plugin-no-only-tests": "3.4.0",
|
|
76
|
+
"govuk-frontend": "^6.2.0",
|
|
77
|
+
"jest": "^30.4.2",
|
|
78
|
+
"jsdom": "^29.1.1",
|
|
79
|
+
"lint-staged": "17.0.7",
|
|
80
|
+
"nunjucks": "^3.2.4",
|
|
81
|
+
"prettier": "3.8.3",
|
|
82
|
+
"rollup": "^4.61.1",
|
|
83
|
+
"rollup-plugin-copy": "3.5.0",
|
|
84
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
85
|
+
"tslib": "^2.8.1",
|
|
86
|
+
"tsx": "4.22.4",
|
|
87
|
+
"typescript": "^6.0.3"
|
|
88
|
+
},
|
|
89
|
+
"type": "commonjs",
|
|
90
|
+
"dependencies": {
|
|
91
|
+
"@ministryofjustice/hmpps-auth-clients": "^1.0.2",
|
|
92
|
+
"@ministryofjustice/hmpps-rest-client": "^1.2.1",
|
|
93
|
+
"@types/nunjucks": "3.2.6",
|
|
94
|
+
"sass": "^1.100.0"
|
|
95
|
+
}
|
|
96
|
+
}
|