@sd-jwt/sd-jwt-vc 0.17.1-next.0 → 0.17.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/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.17.1](https://github.com/openwallet-foundation/sd-jwt-js/compare/v0.17.0...v0.17.1) (2025-11-18)
7
+
8
+ **Note:** Version bump only for package @sd-jwt/sd-jwt-vc
9
+
10
+
11
+
12
+
13
+
6
14
  # [0.17.0](https://github.com/openwallet-foundation/sd-jwt-js/compare/v0.16.0...v0.17.0) (2025-10-23)
7
15
 
8
16
  **Note:** Version bump only for package @sd-jwt/sd-jwt-vc
package/dist/index.d.mts CHANGED
@@ -131,18 +131,6 @@ type TypeMetadataFormat = {
131
131
  display?: Display[];
132
132
  /** OPTIONAL. Array of claim metadata. */
133
133
  claims?: Claim[];
134
- /**
135
- * OPTIONAL. Embedded JSON Schema describing the VC structure.
136
- * Must not be present if schema_uri is provided.
137
- */
138
- schema?: object;
139
- /**
140
- * OPTIONAL. URI pointing to a JSON Schema for the VC structure.
141
- * Must not be present if schema is provided.
142
- */
143
- schema_uri?: string;
144
- /** OPTIONAL. Integrity metadata for the schema_uri field. */
145
- 'schema_uri#Integrity'?: string;
146
134
  };
147
135
 
148
136
  type VcTFetcher = (uri: string, integrity?: string) => Promise<TypeMetadataFormat>;
@@ -238,13 +226,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
238
226
  */
239
227
  private fetch;
240
228
  /**
241
- * Loads the schema either from the object or as fallback from the uri.
242
- * @param typeMetadataFormat
243
- * @returns
244
- */
245
- private loadSchema;
246
- /**
247
- * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format. If the schema does not match, an error is thrown. If it matches, it will return the type metadata format.
229
+ * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format.
248
230
  * @param result
249
231
  * @returns
250
232
  */
package/dist/index.d.ts CHANGED
@@ -131,18 +131,6 @@ type TypeMetadataFormat = {
131
131
  display?: Display[];
132
132
  /** OPTIONAL. Array of claim metadata. */
133
133
  claims?: Claim[];
134
- /**
135
- * OPTIONAL. Embedded JSON Schema describing the VC structure.
136
- * Must not be present if schema_uri is provided.
137
- */
138
- schema?: object;
139
- /**
140
- * OPTIONAL. URI pointing to a JSON Schema for the VC structure.
141
- * Must not be present if schema is provided.
142
- */
143
- schema_uri?: string;
144
- /** OPTIONAL. Integrity metadata for the schema_uri field. */
145
- 'schema_uri#Integrity'?: string;
146
134
  };
147
135
 
148
136
  type VcTFetcher = (uri: string, integrity?: string) => Promise<TypeMetadataFormat>;
@@ -238,13 +226,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
238
226
  */
239
227
  private fetch;
240
228
  /**
241
- * Loads the schema either from the object or as fallback from the uri.
242
- * @param typeMetadataFormat
243
- * @returns
244
- */
245
- private loadSchema;
246
- /**
247
- * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format. If the schema does not match, an error is thrown. If it matches, it will return the type metadata format.
229
+ * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format.
248
230
  * @param result
249
231
  * @returns
250
232
  */
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -18,14 +17,6 @@ var __copyProps = (to, from, except, desc) => {
18
17
  }
19
18
  return to;
20
19
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
21
  var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
31
22
  var __async = (__this, __arguments, generator) => {
@@ -60,8 +51,6 @@ module.exports = __toCommonJS(index_exports);
60
51
  var import_core = require("@sd-jwt/core");
61
52
  var import_jwt_status_list = require("@sd-jwt/jwt-status-list");
62
53
  var import_utils = require("@sd-jwt/utils");
63
- var import_ajv = __toESM(require("ajv"));
64
- var import_ajv_formats = __toESM(require("ajv-formats"));
65
54
  var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
66
55
  constructor(userConfig) {
67
56
  super(userConfig);
@@ -219,25 +208,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
219
208
  });
220
209
  }
221
210
  /**
222
- * Loads the schema either from the object or as fallback from the uri.
223
- * @param typeMetadataFormat
224
- * @returns
225
- */
226
- loadSchema(typeMetadataFormat) {
227
- return __async(this, null, function* () {
228
- if (typeMetadataFormat.schema) return typeMetadataFormat.schema;
229
- if (typeMetadataFormat.schema_uri) {
230
- const schema = yield this.fetch(
231
- typeMetadataFormat.schema_uri,
232
- typeMetadataFormat["schema_uri#Integrity"]
233
- );
234
- return schema;
235
- }
236
- throw new Error("No schema or schema_uri found");
237
- });
238
- }
239
- /**
240
- * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format. If the schema does not match, an error is thrown. If it matches, it will return the type metadata format.
211
+ * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format.
241
212
  * @param result
242
213
  * @returns
243
214
  */
@@ -246,31 +217,6 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
246
217
  const typeMetadataFormat = yield this.fetchVct(result);
247
218
  if (typeMetadataFormat.extends) {
248
219
  }
249
- const schema = yield this.loadSchema(typeMetadataFormat);
250
- const loadedSchemas = /* @__PURE__ */ new Set();
251
- const ajv = new import_ajv.default({
252
- loadSchema: (uri) => __async(this, null, function* () {
253
- if (loadedSchemas.has(uri)) {
254
- return {};
255
- }
256
- const response = yield fetch(uri);
257
- if (!response.ok) {
258
- throw new Error(
259
- `Error fetching schema: ${response.status} ${yield response.text()}`
260
- );
261
- }
262
- loadedSchemas.add(uri);
263
- return response.json();
264
- })
265
- });
266
- (0, import_ajv_formats.default)(ajv);
267
- const validate = yield ajv.compileAsync(schema);
268
- const valid = validate(result.payload);
269
- if (!valid) {
270
- throw new import_utils.SDJWTException(
271
- `Payload does not match the schema: ${JSON.stringify(validate.errors)}`
272
- );
273
- }
274
220
  return typeMetadataFormat;
275
221
  });
276
222
  }
@@ -325,7 +271,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
325
271
  */
326
272
  verifyStatus(result, options) {
327
273
  return __async(this, null, function* () {
328
- var _a, _b, _c, _d, _e;
274
+ var _a, _b, _c;
329
275
  if (result.payload.status) {
330
276
  if (result.payload.status.status_list) {
331
277
  const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
@@ -336,16 +282,17 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
336
282
  yield slJWT.verify(
337
283
  (_b = this.userConfig.statusVerifier) != null ? _b : this.userConfig.verifier,
338
284
  options
339
- );
340
- const currentDate = (_c = options == null ? void 0 : options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
341
- if (((_d = slJWT.payload) == null ? void 0 : _d.exp) && slJWT.payload.exp < currentDate) {
342
- throw new import_utils.SDJWTException("Status list is expired");
343
- }
285
+ ).catch((err) => {
286
+ throw new import_jwt_status_list.SLException(
287
+ `Status List JWT verification failed: ${err.message}`,
288
+ err.details
289
+ );
290
+ });
344
291
  const statusList = (0, import_jwt_status_list.getListFromStatusListJWT)(statusListJWT);
345
292
  const status = statusList.getStatus(
346
293
  result.payload.status.status_list.idx
347
294
  );
348
- const statusValidator = (_e = this.userConfig.statusValidator) != null ? _e : this.statusValidator.bind(this);
295
+ const statusValidator = (_c = this.userConfig.statusValidator) != null ? _c : this.statusValidator.bind(this);
349
296
  yield statusValidator(status);
350
297
  }
351
298
  }
package/dist/index.mjs CHANGED
@@ -25,11 +25,10 @@ var __async = (__this, __arguments, generator) => {
25
25
  // src/sd-jwt-vc-instance.ts
26
26
  import { Jwt, SDJwt, SDJwtInstance } from "@sd-jwt/core";
27
27
  import {
28
- getListFromStatusListJWT
28
+ getListFromStatusListJWT,
29
+ SLException
29
30
  } from "@sd-jwt/jwt-status-list";
30
31
  import { base64urlDecode, SDJWTException } from "@sd-jwt/utils";
31
- import Ajv from "ajv";
32
- import addFormats from "ajv-formats";
33
32
  var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
34
33
  constructor(userConfig) {
35
34
  super(userConfig);
@@ -187,25 +186,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
187
186
  });
188
187
  }
189
188
  /**
190
- * Loads the schema either from the object or as fallback from the uri.
191
- * @param typeMetadataFormat
192
- * @returns
193
- */
194
- loadSchema(typeMetadataFormat) {
195
- return __async(this, null, function* () {
196
- if (typeMetadataFormat.schema) return typeMetadataFormat.schema;
197
- if (typeMetadataFormat.schema_uri) {
198
- const schema = yield this.fetch(
199
- typeMetadataFormat.schema_uri,
200
- typeMetadataFormat["schema_uri#Integrity"]
201
- );
202
- return schema;
203
- }
204
- throw new Error("No schema or schema_uri found");
205
- });
206
- }
207
- /**
208
- * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format. If the schema does not match, an error is thrown. If it matches, it will return the type metadata format.
189
+ * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format.
209
190
  * @param result
210
191
  * @returns
211
192
  */
@@ -214,31 +195,6 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
214
195
  const typeMetadataFormat = yield this.fetchVct(result);
215
196
  if (typeMetadataFormat.extends) {
216
197
  }
217
- const schema = yield this.loadSchema(typeMetadataFormat);
218
- const loadedSchemas = /* @__PURE__ */ new Set();
219
- const ajv = new Ajv({
220
- loadSchema: (uri) => __async(this, null, function* () {
221
- if (loadedSchemas.has(uri)) {
222
- return {};
223
- }
224
- const response = yield fetch(uri);
225
- if (!response.ok) {
226
- throw new Error(
227
- `Error fetching schema: ${response.status} ${yield response.text()}`
228
- );
229
- }
230
- loadedSchemas.add(uri);
231
- return response.json();
232
- })
233
- });
234
- addFormats(ajv);
235
- const validate = yield ajv.compileAsync(schema);
236
- const valid = validate(result.payload);
237
- if (!valid) {
238
- throw new SDJWTException(
239
- `Payload does not match the schema: ${JSON.stringify(validate.errors)}`
240
- );
241
- }
242
198
  return typeMetadataFormat;
243
199
  });
244
200
  }
@@ -293,7 +249,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
293
249
  */
294
250
  verifyStatus(result, options) {
295
251
  return __async(this, null, function* () {
296
- var _a, _b, _c, _d, _e;
252
+ var _a, _b, _c;
297
253
  if (result.payload.status) {
298
254
  if (result.payload.status.status_list) {
299
255
  const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
@@ -304,16 +260,17 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
304
260
  yield slJWT.verify(
305
261
  (_b = this.userConfig.statusVerifier) != null ? _b : this.userConfig.verifier,
306
262
  options
307
- );
308
- const currentDate = (_c = options == null ? void 0 : options.currentDate) != null ? _c : Math.floor(Date.now() / 1e3);
309
- if (((_d = slJWT.payload) == null ? void 0 : _d.exp) && slJWT.payload.exp < currentDate) {
310
- throw new SDJWTException("Status list is expired");
311
- }
263
+ ).catch((err) => {
264
+ throw new SLException(
265
+ `Status List JWT verification failed: ${err.message}`,
266
+ err.details
267
+ );
268
+ });
312
269
  const statusList = getListFromStatusListJWT(statusListJWT);
313
270
  const status = statusList.getStatus(
314
271
  result.payload.status.status_list.idx
315
272
  );
316
- const statusValidator = (_e = this.userConfig.statusValidator) != null ? _e : this.statusValidator.bind(this);
273
+ const statusValidator = (_c = this.userConfig.statusValidator) != null ? _c : this.statusValidator.bind(this);
317
274
  yield statusValidator(status);
318
275
  }
319
276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-jwt/sd-jwt-vc",
3
- "version": "0.17.1-next.0+9f37cdf",
3
+ "version": "0.17.1",
4
4
  "description": "sd-jwt draft 7 implementation in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -38,15 +38,13 @@
38
38
  },
39
39
  "license": "Apache-2.0",
40
40
  "dependencies": {
41
- "@sd-jwt/core": "0.17.1-next.0+9f37cdf",
42
- "@sd-jwt/jwt-status-list": "0.17.1-next.0+9f37cdf",
43
- "@sd-jwt/utils": "0.17.1-next.0+9f37cdf",
44
- "ajv": "^8.17.1",
45
- "ajv-formats": "^3.0.1"
41
+ "@sd-jwt/core": "0.17.0",
42
+ "@sd-jwt/jwt-status-list": "0.17.1",
43
+ "@sd-jwt/utils": "0.17.0"
46
44
  },
47
45
  "devDependencies": {
48
- "@sd-jwt/crypto-nodejs": "0.17.1-next.0+9f37cdf",
49
- "@sd-jwt/types": "0.17.1-next.0+9f37cdf",
46
+ "@sd-jwt/crypto-nodejs": "0.17.0",
47
+ "@sd-jwt/types": "0.17.0",
50
48
  "jose": "^6.1.0",
51
49
  "msw": "^2.11.3"
52
50
  },
@@ -66,5 +64,5 @@
66
64
  "esm"
67
65
  ]
68
66
  },
69
- "gitHead": "9f37cdfbae982a647e61589fd88dfd79305105c1"
67
+ "gitHead": "1301a03484b285711d7afd7448457348bad96569"
70
68
  }
@@ -1,13 +1,12 @@
1
1
  import { Jwt, SDJwt, SDJwtInstance, type VerifierOptions } from '@sd-jwt/core';
2
2
  import {
3
3
  getListFromStatusListJWT,
4
+ SLException,
4
5
  type StatusListJWTHeaderParameters,
5
6
  type StatusListJWTPayload,
6
7
  } from '@sd-jwt/jwt-status-list';
7
8
  import type { DisclosureFrame, Hasher, Verifier } from '@sd-jwt/types';
8
9
  import { base64urlDecode, SDJWTException } from '@sd-jwt/utils';
9
- import Ajv, { type SchemaObject } from 'ajv';
10
- import addFormats from 'ajv-formats';
11
10
  import type {
12
11
  SDJWTVCConfig,
13
12
  StatusListFetcher,
@@ -210,25 +209,7 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
210
209
  }
211
210
 
212
211
  /**
213
- * Loads the schema either from the object or as fallback from the uri.
214
- * @param typeMetadataFormat
215
- * @returns
216
- */
217
- private async loadSchema(typeMetadataFormat: TypeMetadataFormat) {
218
- //if schema is present, return it
219
- if (typeMetadataFormat.schema) return typeMetadataFormat.schema;
220
- if (typeMetadataFormat.schema_uri) {
221
- const schema = await this.fetch<SchemaObject>(
222
- typeMetadataFormat.schema_uri,
223
- typeMetadataFormat['schema_uri#Integrity'],
224
- );
225
- return schema;
226
- }
227
- throw new Error('No schema or schema_uri found');
228
- }
229
-
230
- /**
231
- * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format. If the schema does not match, an error is thrown. If it matches, it will return the type metadata format.
212
+ * Verifies the VCT of the SD-JWT-VC. Returns the type metadata format.
232
213
  * @param result
233
214
  * @returns
234
215
  */
@@ -241,38 +222,6 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
241
222
  // implement based on https://www.ietf.org/archive/id/draft-ietf-oauth-sd-jwt-vc-08.html#name-extending-type-metadata
242
223
  //TODO: needs to be implemented. Unclear at this point which values will overwrite the values from the extended type metadata format
243
224
  }
244
-
245
- //init the json schema validator, load referenced schemas on demand
246
- const schema = await this.loadSchema(typeMetadataFormat);
247
- const loadedSchemas = new Set<string>();
248
- // init the json schema validator
249
- const ajv = new Ajv({
250
- loadSchema: async (uri: string) => {
251
- if (loadedSchemas.has(uri)) {
252
- return {};
253
- }
254
- const response = await fetch(uri);
255
- if (!response.ok) {
256
- throw new Error(
257
- `Error fetching schema: ${
258
- response.status
259
- } ${await response.text()}`,
260
- );
261
- }
262
- loadedSchemas.add(uri);
263
- return response.json();
264
- },
265
- });
266
- addFormats(ajv);
267
- const validate = await ajv.compileAsync(schema);
268
- const valid = validate(result.payload);
269
-
270
- if (!valid) {
271
- throw new SDJWTException(
272
- `Payload does not match the schema: ${JSON.stringify(validate.errors)}`,
273
- );
274
- }
275
-
276
225
  return typeMetadataFormat;
277
226
  }
278
227
 
@@ -358,18 +307,18 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
358
307
  StatusListJWTPayload
359
308
  >(statusListJWT);
360
309
  // check if the status list has a valid signature. The presence of the verifier is checked in the parent class.
361
- await slJWT.verify(
362
- this.userConfig.statusVerifier ??
363
- (this.userConfig.verifier as Verifier),
364
- options,
365
- );
366
-
367
- const currentDate =
368
- options?.currentDate ?? Math.floor(Date.now() / 1000);
369
- //check if the status list is expired
370
- if (slJWT.payload?.exp && (slJWT.payload.exp as number) < currentDate) {
371
- throw new SDJWTException('Status list is expired');
372
- }
310
+ await slJWT
311
+ .verify(
312
+ this.userConfig.statusVerifier ??
313
+ (this.userConfig.verifier as Verifier),
314
+ options,
315
+ )
316
+ .catch((err: SLException) => {
317
+ throw new SLException(
318
+ `Status List JWT verification failed: ${err.message}`,
319
+ err.details,
320
+ );
321
+ });
373
322
 
374
323
  // get the status list from the status list JWT
375
324
  const statusList = getListFromStatusListJWT(statusListJWT);
@@ -141,16 +141,4 @@ export type TypeMetadataFormat = {
141
141
  display?: Display[];
142
142
  /** OPTIONAL. Array of claim metadata. */
143
143
  claims?: Claim[];
144
- /**
145
- * OPTIONAL. Embedded JSON Schema describing the VC structure.
146
- * Must not be present if schema_uri is provided.
147
- */
148
- schema?: object;
149
- /**
150
- * OPTIONAL. URI pointing to a JSON Schema for the VC structure.
151
- * Must not be present if schema is provided.
152
- */
153
- schema_uri?: string;
154
- /** OPTIONAL. Integrity metadata for the schema_uri field. */
155
- 'schema_uri#Integrity'?: string;
156
144
  };
@@ -13,44 +13,9 @@ const exampleVctm = {
13
13
  vct: 'http://example.com/example',
14
14
  name: 'ExampleCredentialType',
15
15
  description: 'An example credential type',
16
- schema_uri: 'http://example.com/schema/example',
17
- //this value could be generated on demand to make it easier when changing the values
18
- 'schema_uri#Integrity':
19
- 'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
20
16
  };
21
17
 
22
18
  const restHandlers = [
23
- http.get('http://example.com/schema/example', () => {
24
- const res = {
25
- $schema: 'https://json-schema.org/draft/2020-12/schema',
26
- type: 'object',
27
- properties: {
28
- vct: {
29
- type: 'string',
30
- },
31
- iss: {
32
- type: 'string',
33
- },
34
- nbf: {
35
- type: 'number',
36
- },
37
- exp: {
38
- type: 'number',
39
- },
40
- cnf: {
41
- type: 'object',
42
- },
43
- status: {
44
- type: 'object',
45
- },
46
- firstName: {
47
- type: 'string',
48
- },
49
- },
50
- required: ['iss', 'vct'],
51
- };
52
- return HttpResponse.json(res);
53
- }),
54
19
  http.get('http://example.com/example', () => {
55
20
  const res: TypeMetadataFormat = exampleVctm;
56
21
  return HttpResponse.json(res);
@@ -66,7 +31,7 @@ const restHandlers = [
66
31
 
67
32
  //this value could be generated on demand to make it easier when changing the values
68
33
  const vctIntegrity =
69
- 'sha256-96bed58130a44af05ae8970aa9caa0bf0135cd15afe721ea29f553394692acef';
34
+ 'sha256-e8bf419e6b860595f385611fc6172f1e95c18de3c80eef57c865f49e03747637';
70
35
 
71
36
  const server = setupServer(...restHandlers);
72
37
 
@@ -190,9 +155,6 @@ describe('App', () => {
190
155
  expect(typeMetadataFormat).to.deep.eq({
191
156
  description: 'An example credential type',
192
157
  name: 'ExampleCredentialType',
193
- schema_uri: 'http://example.com/schema/example',
194
- 'schema_uri#Integrity':
195
- 'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
196
158
  vct: 'http://example.com/example',
197
159
  });
198
160
  });