@fluidframework/fluid-runner 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.2.0.153917

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +18 -0
  3. package/dist/exportFile.d.ts +2 -2
  4. package/dist/exportFile.d.ts.map +1 -1
  5. package/dist/exportFile.js +36 -24
  6. package/dist/exportFile.js.map +1 -1
  7. package/dist/fluidRunner.d.ts.map +1 -1
  8. package/dist/fluidRunner.js +7 -2
  9. package/dist/fluidRunner.js.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/logger/fileLogger.d.ts +0 -1
  15. package/dist/logger/fileLogger.d.ts.map +1 -1
  16. package/dist/logger/fileLogger.js.map +1 -1
  17. package/dist/logger/loggerUtils.d.ts +0 -1
  18. package/dist/logger/loggerUtils.d.ts.map +1 -1
  19. package/dist/logger/loggerUtils.js +0 -1
  20. package/dist/logger/loggerUtils.js.map +1 -1
  21. package/dist/parseBundleAndExportFile.d.ts +1 -1
  22. package/dist/parseBundleAndExportFile.d.ts.map +1 -1
  23. package/dist/parseBundleAndExportFile.js +3 -4
  24. package/dist/parseBundleAndExportFile.js.map +1 -1
  25. package/dist/utils.d.ts +8 -0
  26. package/dist/utils.d.ts.map +1 -1
  27. package/dist/utils.js +41 -1
  28. package/dist/utils.js.map +1 -1
  29. package/lib/exportFile.d.ts +2 -2
  30. package/lib/exportFile.d.ts.map +1 -1
  31. package/lib/exportFile.js +37 -25
  32. package/lib/exportFile.js.map +1 -1
  33. package/lib/fluidRunner.d.ts.map +1 -1
  34. package/lib/fluidRunner.js +7 -2
  35. package/lib/fluidRunner.js.map +1 -1
  36. package/lib/index.d.ts +2 -2
  37. package/lib/index.d.ts.map +1 -1
  38. package/lib/index.js +1 -1
  39. package/lib/index.js.map +1 -1
  40. package/lib/logger/fileLogger.d.ts +0 -1
  41. package/lib/logger/fileLogger.d.ts.map +1 -1
  42. package/lib/logger/fileLogger.js.map +1 -1
  43. package/lib/logger/loggerUtils.d.ts +0 -1
  44. package/lib/logger/loggerUtils.d.ts.map +1 -1
  45. package/lib/logger/loggerUtils.js +0 -1
  46. package/lib/logger/loggerUtils.js.map +1 -1
  47. package/lib/parseBundleAndExportFile.d.ts +1 -1
  48. package/lib/parseBundleAndExportFile.d.ts.map +1 -1
  49. package/lib/parseBundleAndExportFile.js +4 -5
  50. package/lib/parseBundleAndExportFile.js.map +1 -1
  51. package/lib/utils.d.ts +8 -0
  52. package/lib/utils.d.ts.map +1 -1
  53. package/lib/utils.js +38 -0
  54. package/lib/utils.js.map +1 -1
  55. package/package.json +12 -12
  56. package/src/exportFile.ts +36 -21
  57. package/src/fluidRunner.ts +7 -0
  58. package/src/index.ts +6 -2
  59. package/src/logger/fileLogger.ts +0 -1
  60. package/src/logger/loggerUtils.ts +0 -1
  61. package/src/parseBundleAndExportFile.ts +4 -3
  62. package/src/utils.ts +55 -0
  63. package/dist/getArgsValidationError.d.ts +0 -6
  64. package/dist/getArgsValidationError.d.ts.map +0 -1
  65. package/dist/getArgsValidationError.js +0 -46
  66. package/dist/getArgsValidationError.js.map +0 -1
  67. package/lib/getArgsValidationError.d.ts +0 -6
  68. package/lib/getArgsValidationError.d.ts.map +0 -1
  69. package/lib/getArgsValidationError.js +0 -23
  70. package/lib/getArgsValidationError.js.map +0 -1
  71. package/src/getArgsValidationError.ts +0 -24
package/src/exportFile.ts CHANGED
@@ -9,10 +9,9 @@ import { LoaderHeader } from "@fluidframework/container-definitions";
9
9
  import { Loader } from "@fluidframework/container-loader";
10
10
  import { createLocalOdspDocumentServiceFactory } from "@fluidframework/odsp-driver";
11
11
  import { PerformanceEvent } from "@fluidframework/telemetry-utils";
12
- import { getArgsValidationError } from "./getArgsValidationError";
13
12
  import { IFluidFileConverter } from "./codeLoaderBundle";
14
13
  import { FakeUrlResolver } from "./fakeUrlResolver";
15
- import { getSnapshotFileContent } from "./utils";
14
+ import { getSnapshotFileContent, timeoutPromise, getArgsValidationError } from "./utils";
16
15
  /* eslint-disable import/no-internal-modules */
17
16
  import { ITelemetryOptions } from "./logger/fileLogger";
18
17
  import { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils";
@@ -43,6 +42,7 @@ export async function exportFile(
43
42
  telemetryFile: string,
44
43
  options?: string,
45
44
  telemetryOptions?: ITelemetryOptions,
45
+ timeout?: number,
46
46
  ): Promise<IExportFileResponse> {
47
47
  const telemetryArgError = getTelemetryFileValidationError(telemetryFile);
48
48
  if (telemetryArgError) {
@@ -56,7 +56,7 @@ export async function exportFile(
56
56
  logger,
57
57
  { eventName: "ExportFile" },
58
58
  async () => {
59
- const argsValidationError = getArgsValidationError(inputFile, outputFile);
59
+ const argsValidationError = getArgsValidationError(inputFile, outputFile, timeout);
60
60
  if (argsValidationError) {
61
61
  const eventName = clientArgsValidationError;
62
62
  logger.sendErrorEvent({ eventName, message: argsValidationError });
@@ -70,6 +70,7 @@ export async function exportFile(
70
70
  fluidFileConverter,
71
71
  logger,
72
72
  options,
73
+ timeout,
73
74
  ),
74
75
  );
75
76
 
@@ -94,25 +95,39 @@ export async function createContainerAndExecute(
94
95
  fluidFileConverter: IFluidFileConverter,
95
96
  logger: ITelemetryLogger,
96
97
  options?: string,
98
+ timeout?: number,
97
99
  ): Promise<string> {
98
- const loader = new Loader({
99
- urlResolver: new FakeUrlResolver(),
100
- documentServiceFactory: createLocalOdspDocumentServiceFactory(localOdspSnapshot),
101
- codeLoader: await fluidFileConverter.getCodeLoader(logger),
102
- scope: await fluidFileConverter.getScope?.(logger),
103
- logger,
104
- });
100
+ const fn = async () => {
101
+ const loader = new Loader({
102
+ urlResolver: new FakeUrlResolver(),
103
+ documentServiceFactory: createLocalOdspDocumentServiceFactory(localOdspSnapshot),
104
+ codeLoader: await fluidFileConverter.getCodeLoader(logger),
105
+ scope: await fluidFileConverter.getScope?.(logger),
106
+ logger,
107
+ });
108
+
109
+ const container = await loader.resolve({
110
+ url: "/fakeUrl/",
111
+ headers: {
112
+ [LoaderHeader.loadMode]: { opsBeforeReturn: "cached" },
113
+ },
114
+ });
105
115
 
106
- const container = await loader.resolve({
107
- url: "/fakeUrl/",
108
- headers: {
109
- [LoaderHeader.loadMode]: { opsBeforeReturn: "cached" },
110
- },
111
- });
116
+ return PerformanceEvent.timedExecAsync(logger, { eventName: "ExportFile" }, async () => {
117
+ const result = await fluidFileConverter.execute(container, options);
118
+ container.close();
119
+ return result;
120
+ });
121
+ };
112
122
 
113
- return PerformanceEvent.timedExecAsync(logger, { eventName: "ExportFile" }, async () => {
114
- const result = await fluidFileConverter.execute(container, options);
115
- container.close();
116
- return result;
117
- });
123
+ // eslint-disable-next-line unicorn/prefer-ternary
124
+ if (timeout !== undefined) {
125
+ return timeoutPromise<string>((resolve, reject) => {
126
+ fn()
127
+ .then((value) => resolve(value))
128
+ .catch((error) => reject(error));
129
+ }, timeout);
130
+ } else {
131
+ return fn();
132
+ }
118
133
  }
@@ -71,6 +71,11 @@ export function fluidRunner(fluidFileConverter?: IFluidFileConverter) {
71
71
  "Number of telemetry events per flush to telemetryFile (only applicable for JSON format)",
72
72
  type: "number",
73
73
  demandOption: false,
74
+ })
75
+ .option("timeout", {
76
+ describe: "Allowed timeout in ms before process is automatically cancelled",
77
+ type: "number",
78
+ demandOption: false,
74
79
  }),
75
80
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
76
81
  async (argv) => {
@@ -97,6 +102,7 @@ export function fluidRunner(fluidFileConverter?: IFluidFileConverter) {
97
102
  argv.telemetryFile,
98
103
  argv.options,
99
104
  telemetryOptionsResult.telemetryOptions,
105
+ argv.timeout,
100
106
  )
101
107
  : exportFile(
102
108
  fluidFileConverter!,
@@ -105,6 +111,7 @@ export function fluidRunner(fluidFileConverter?: IFluidFileConverter) {
105
111
  argv.telemetryFile,
106
112
  argv.options,
107
113
  telemetryOptionsResult.telemetryOptions,
114
+ argv.timeout,
108
115
  ));
109
116
 
110
117
  if (!result.success) {
package/src/index.ts CHANGED
@@ -7,8 +7,12 @@
7
7
  export { ICodeLoaderBundle, IFluidFileConverter } from "./codeLoaderBundle";
8
8
  export { createContainerAndExecute, exportFile, IExportFileResponse } from "./exportFile";
9
9
  export { fluidRunner } from "./fluidRunner";
10
- export { OutputFormat } from "./logger/fileLogger";
11
- export { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils";
10
+ export { OutputFormat, ITelemetryOptions } from "./logger/fileLogger";
11
+ export {
12
+ createLogger,
13
+ getTelemetryFileValidationError,
14
+ validateAndParseTelemetryOptions,
15
+ } from "./logger/loggerUtils";
12
16
  export { parseBundleAndExportFile } from "./parseBundleAndExportFile";
13
17
  export { getSnapshotFileContent } from "./utils";
14
18
  /* eslint-enable import/no-internal-modules */
@@ -27,7 +27,6 @@ export enum OutputFormat {
27
27
  /* eslint-disable tsdoc/syntax */
28
28
  /**
29
29
  * Options to provide upon creation of IFileLogger
30
- * @internal
31
30
  */
32
31
  export interface ITelemetryOptions {
33
32
  /** Desired output format used to create a specific IFileLogger implementation */
@@ -51,7 +51,6 @@ export function getTelemetryFileValidationError(telemetryFile: string): string |
51
51
  * Validate the provided output format and default properties
52
52
  * @param format - desired output format of the telemetry
53
53
  * @param props - default properties to be added to every telemetry entry
54
- * @internal
55
54
  */
56
55
  export function validateAndParseTelemetryOptions(
57
56
  format?: string,
@@ -7,12 +7,11 @@ import * as fs from "fs";
7
7
  import { PerformanceEvent } from "@fluidframework/telemetry-utils";
8
8
  import { isCodeLoaderBundle, isFluidFileConverter } from "./codeLoaderBundle";
9
9
  import { createContainerAndExecute, IExportFileResponse } from "./exportFile";
10
- import { getArgsValidationError } from "./getArgsValidationError";
11
10
  /* eslint-disable import/no-internal-modules */
12
11
  import { ITelemetryOptions } from "./logger/fileLogger";
13
12
  import { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils";
14
13
  /* eslint-enable import/no-internal-modules */
15
- import { getSnapshotFileContent } from "./utils";
14
+ import { getSnapshotFileContent, getArgsValidationError } from "./utils";
16
15
 
17
16
  const clientArgsValidationError = "Client_ArgsValidationError";
18
17
 
@@ -27,6 +26,7 @@ export async function parseBundleAndExportFile(
27
26
  telemetryFile: string,
28
27
  options?: string,
29
28
  telemetryOptions?: ITelemetryOptions,
29
+ timeout?: number,
30
30
  ): Promise<IExportFileResponse> {
31
31
  const telemetryArgError = getTelemetryFileValidationError(telemetryFile);
32
32
  if (telemetryArgError) {
@@ -58,7 +58,7 @@ export async function parseBundleAndExportFile(
58
58
  return { success: false, eventName, errorMessage };
59
59
  }
60
60
 
61
- const argsValidationError = getArgsValidationError(inputFile, outputFile);
61
+ const argsValidationError = getArgsValidationError(inputFile, outputFile, timeout);
62
62
  if (argsValidationError) {
63
63
  const eventName = clientArgsValidationError;
64
64
  logger.sendErrorEvent({ eventName, message: argsValidationError });
@@ -72,6 +72,7 @@ export async function parseBundleAndExportFile(
72
72
  fluidExport,
73
73
  logger,
74
74
  options,
75
+ timeout,
75
76
  ),
76
77
  );
77
78
 
package/src/utils.ts CHANGED
@@ -42,3 +42,58 @@ export function validateCommandLineArgs(
42
42
  }
43
43
  return undefined;
44
44
  }
45
+
46
+ /**
47
+ * @internal
48
+ */
49
+ export function getArgsValidationError(
50
+ inputFile: string,
51
+ outputFile: string,
52
+ timeout?: number,
53
+ ): string | undefined {
54
+ // Validate input file
55
+ if (!inputFile) {
56
+ return "Input file name argument is missing.";
57
+ } else if (!fs.existsSync(inputFile)) {
58
+ return "Input file does not exist.";
59
+ }
60
+
61
+ // Validate output file
62
+ if (!outputFile) {
63
+ return "Output file argument is missing.";
64
+ } else if (fs.existsSync(outputFile)) {
65
+ return `Output file already exists [${outputFile}].`;
66
+ }
67
+
68
+ if (timeout !== undefined && (isNaN(timeout) || timeout < 0)) {
69
+ return "Invalid timeout";
70
+ }
71
+
72
+ return undefined;
73
+ }
74
+
75
+ /**
76
+ * @internal
77
+ */
78
+ export async function timeoutPromise<T = void>(
79
+ executor: (
80
+ resolve: (value: T | PromiseLike<T>) => void,
81
+ reject: (reason?: any) => void,
82
+ ) => void,
83
+ timeout: number,
84
+ ): Promise<T> {
85
+ return new Promise<T>((resolve, reject) => {
86
+ const timer = setTimeout(() => reject(new Error(`Timed out (${timeout}ms)`)), timeout);
87
+
88
+ executor(
89
+ (value) => {
90
+ clearTimeout(timer);
91
+ resolve(value);
92
+ },
93
+ (reason) => {
94
+ clearTimeout(timer);
95
+ reject(reason);
96
+ },
97
+ );
98
+ });
99
+ }
@@ -1,6 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- export declare function getArgsValidationError(inputFile: string, outputFile: string): string | undefined;
6
- //# sourceMappingURL=getArgsValidationError.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getArgsValidationError.d.ts","sourceRoot":"","sources":["../src/getArgsValidationError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBhG"}
@@ -1,46 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
- if (k2 === undefined) k2 = k;
8
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.getArgsValidationError = void 0;
27
- const fs = __importStar(require("fs"));
28
- function getArgsValidationError(inputFile, outputFile) {
29
- // Validate input file
30
- if (!inputFile) {
31
- return "Input file name argument is missing.";
32
- }
33
- else if (!fs.existsSync(inputFile)) {
34
- return "Input file does not exist.";
35
- }
36
- // Validate output file
37
- if (!outputFile) {
38
- return "Output file argument is missing.";
39
- }
40
- else if (fs.existsSync(outputFile)) {
41
- return `Output file already exists [${outputFile}].`;
42
- }
43
- return undefined;
44
- }
45
- exports.getArgsValidationError = getArgsValidationError;
46
- //# sourceMappingURL=getArgsValidationError.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getArgsValidationError.js","sourceRoot":"","sources":["../src/getArgsValidationError.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AAEzB,SAAgB,sBAAsB,CAAC,SAAiB,EAAE,UAAkB;IAC3E,sBAAsB;IACtB,IAAI,CAAC,SAAS,EAAE;QACf,OAAO,sCAAsC,CAAC;KAC9C;SAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACrC,OAAO,4BAA4B,CAAC;KACpC;IAED,uBAAuB;IACvB,IAAI,CAAC,UAAU,EAAE;QAChB,OAAO,kCAAkC,CAAC;KAC1C;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACrC,OAAO,+BAA+B,UAAU,IAAI,CAAC;KACrD;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAhBD,wDAgBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as fs from \"fs\";\n\nexport function getArgsValidationError(inputFile: string, outputFile: string): string | undefined {\n\t// Validate input file\n\tif (!inputFile) {\n\t\treturn \"Input file name argument is missing.\";\n\t} else if (!fs.existsSync(inputFile)) {\n\t\treturn \"Input file does not exist.\";\n\t}\n\n\t// Validate output file\n\tif (!outputFile) {\n\t\treturn \"Output file argument is missing.\";\n\t} else if (fs.existsSync(outputFile)) {\n\t\treturn `Output file already exists [${outputFile}].`;\n\t}\n\n\treturn undefined;\n}\n"]}
@@ -1,6 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- export declare function getArgsValidationError(inputFile: string, outputFile: string): string | undefined;
6
- //# sourceMappingURL=getArgsValidationError.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getArgsValidationError.d.ts","sourceRoot":"","sources":["../src/getArgsValidationError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBhG"}
@@ -1,23 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import * as fs from "fs";
6
- export function getArgsValidationError(inputFile, outputFile) {
7
- // Validate input file
8
- if (!inputFile) {
9
- return "Input file name argument is missing.";
10
- }
11
- else if (!fs.existsSync(inputFile)) {
12
- return "Input file does not exist.";
13
- }
14
- // Validate output file
15
- if (!outputFile) {
16
- return "Output file argument is missing.";
17
- }
18
- else if (fs.existsSync(outputFile)) {
19
- return `Output file already exists [${outputFile}].`;
20
- }
21
- return undefined;
22
- }
23
- //# sourceMappingURL=getArgsValidationError.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getArgsValidationError.js","sourceRoot":"","sources":["../src/getArgsValidationError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,UAAkB;IAC3E,sBAAsB;IACtB,IAAI,CAAC,SAAS,EAAE;QACf,OAAO,sCAAsC,CAAC;KAC9C;SAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACrC,OAAO,4BAA4B,CAAC;KACpC;IAED,uBAAuB;IACvB,IAAI,CAAC,UAAU,EAAE;QAChB,OAAO,kCAAkC,CAAC;KAC1C;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACrC,OAAO,+BAA+B,UAAU,IAAI,CAAC;KACrD;IAED,OAAO,SAAS,CAAC;AAClB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as fs from \"fs\";\n\nexport function getArgsValidationError(inputFile: string, outputFile: string): string | undefined {\n\t// Validate input file\n\tif (!inputFile) {\n\t\treturn \"Input file name argument is missing.\";\n\t} else if (!fs.existsSync(inputFile)) {\n\t\treturn \"Input file does not exist.\";\n\t}\n\n\t// Validate output file\n\tif (!outputFile) {\n\t\treturn \"Output file argument is missing.\";\n\t} else if (fs.existsSync(outputFile)) {\n\t\treturn `Output file already exists [${outputFile}].`;\n\t}\n\n\treturn undefined;\n}\n"]}
@@ -1,24 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- import * as fs from "fs";
7
-
8
- export function getArgsValidationError(inputFile: string, outputFile: string): string | undefined {
9
- // Validate input file
10
- if (!inputFile) {
11
- return "Input file name argument is missing.";
12
- } else if (!fs.existsSync(inputFile)) {
13
- return "Input file does not exist.";
14
- }
15
-
16
- // Validate output file
17
- if (!outputFile) {
18
- return "Output file argument is missing.";
19
- } else if (fs.existsSync(outputFile)) {
20
- return `Output file already exists [${outputFile}].`;
21
- }
22
-
23
- return undefined;
24
- }