@grnsft/if 0.0.6 → 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.
Files changed (147) hide show
  1. package/.examples/ompls/azure.yml +205 -0
  2. package/.github/workflows/nodejs-ci.yml +0 -8
  3. package/README.md +48 -9
  4. package/build/index.js +1 -2
  5. package/examples/impls/test/azure.yml +8 -8
  6. package/examples/impls/test/ccf.yml +5 -3
  7. package/examples/impls/test/if-demo.yml +19 -9
  8. package/examples/impls/test/metadata.yml +3 -2
  9. package/examples/impls/test/nesting.yml +10 -13
  10. package/examples/impls/test/sci-e.yml +1 -1
  11. package/examples/impls/test/sci-m.yml +2 -2
  12. package/examples/impls/test/sci-o.yml +2 -4
  13. package/examples/impls/test/sci.yml +1 -2
  14. package/examples/impls/test/shell.yml +2 -1
  15. package/examples/impls/{tdp-finder-test.yml → test/tdp-finder.yml} +8 -8
  16. package/examples/ompls/ccf.yml +3 -1
  17. package/examples/ompls/if-demo.yml +46 -22
  18. package/package.json +12 -5
  19. package/tsconfig.build.json +7 -0
  20. package/tsconfig.build.tsbuildinfo +1 -0
  21. package/build/__mocks__/azure/index.d.ts +0 -11
  22. package/build/__mocks__/azure/index.js +0 -132
  23. package/build/__mocks__/boavizta/countries.json +0 -138
  24. package/build/__mocks__/boavizta/instance_types.json +0 -625
  25. package/build/__mocks__/boavizta/providers.json +0 -1
  26. package/build/__mocks__/fs/index.d.ts +0 -3
  27. package/build/__mocks__/fs/index.js +0 -56
  28. package/build/__mocks__/model-universe/index.d.ts +0 -31
  29. package/build/__mocks__/model-universe/index.js +0 -64
  30. package/build/__mocks__/watt-time/data.json +0 -119
  31. package/build/__tests__/integration/ompl/index.test.d.ts +0 -1
  32. package/build/__tests__/integration/ompl/index.test.js +0 -61
  33. package/build/__tests__/unit/lib/azure-importer/index.test.d.ts +0 -1
  34. package/build/__tests__/unit/lib/azure-importer/index.test.js +0 -152
  35. package/build/__tests__/unit/lib/boavizta/index.test.d.ts +0 -1
  36. package/build/__tests__/unit/lib/boavizta/index.test.js +0 -579
  37. package/build/__tests__/unit/lib/case-studies/aveva.test.d.ts +0 -1
  38. package/build/__tests__/unit/lib/case-studies/aveva.test.js +0 -36
  39. package/build/__tests__/unit/lib/case-studies/emem.test.d.ts +0 -1
  40. package/build/__tests__/unit/lib/case-studies/emem.test.js +0 -108
  41. package/build/__tests__/unit/lib/case-studies/eshoppen.test.d.ts +0 -1
  42. package/build/__tests__/unit/lib/case-studies/eshoppen.test.js +0 -53
  43. package/build/__tests__/unit/lib/case-studies/sci-accenture.test.d.ts +0 -1
  44. package/build/__tests__/unit/lib/case-studies/sci-accenture.test.js +0 -23
  45. package/build/__tests__/unit/lib/ccf/index.test.d.ts +0 -1
  46. package/build/__tests__/unit/lib/ccf/index.test.js +0 -223
  47. package/build/__tests__/unit/lib/cloud-instance-metadata/index.test.d.ts +0 -1
  48. package/build/__tests__/unit/lib/cloud-instance-metadata/index.test.js +0 -73
  49. package/build/__tests__/unit/lib/models-universe.test.d.ts +0 -1
  50. package/build/__tests__/unit/lib/models-universe.test.js +0 -193
  51. package/build/__tests__/unit/lib/observatory.test.d.ts +0 -1
  52. package/build/__tests__/unit/lib/observatory.test.js +0 -99
  53. package/build/__tests__/unit/lib/sci/index.test.d.ts +0 -1
  54. package/build/__tests__/unit/lib/sci/index.test.js +0 -106
  55. package/build/__tests__/unit/lib/sci-e/index.test.d.ts +0 -1
  56. package/build/__tests__/unit/lib/sci-e/index.test.js +0 -30
  57. package/build/__tests__/unit/lib/sci-m/index.test.d.ts +0 -1
  58. package/build/__tests__/unit/lib/sci-m/index.test.js +0 -58
  59. package/build/__tests__/unit/lib/sci-o/index.test.d.ts +0 -1
  60. package/build/__tests__/unit/lib/sci-o/index.test.js +0 -42
  61. package/build/__tests__/unit/lib/shell-imp/index.test.d.ts +0 -1
  62. package/build/__tests__/unit/lib/shell-imp/index.test.js +0 -21
  63. package/build/__tests__/unit/lib/supercomputer.test.d.ts +0 -1
  64. package/build/__tests__/unit/lib/supercomputer.test.js +0 -231
  65. package/build/__tests__/unit/lib/tdp-finder/index.test.d.ts +0 -1
  66. package/build/__tests__/unit/lib/tdp-finder/index.test.js +0 -62
  67. package/build/__tests__/unit/lib/teads-aws/index.test.d.ts +0 -1
  68. package/build/__tests__/unit/lib/teads-aws/index.test.js +0 -170
  69. package/build/__tests__/unit/lib/teads-curve/index.test.d.ts +0 -1
  70. package/build/__tests__/unit/lib/teads-curve/index.test.js +0 -146
  71. package/build/__tests__/unit/lib/watt-time/index.test.d.ts +0 -1
  72. package/build/__tests__/unit/lib/watt-time/index.test.js +0 -106
  73. package/build/__tests__/unit/util/args.test.d.ts +0 -1
  74. package/build/__tests__/unit/util/args.test.js +0 -92
  75. package/build/__tests__/unit/util/models-universe.test.d.ts +0 -1
  76. package/build/__tests__/unit/util/models-universe.test.js +0 -193
  77. package/build/__tests__/unit/util/observatory.test.d.ts +0 -1
  78. package/build/__tests__/unit/util/observatory.test.js +0 -99
  79. package/build/__tests__/unit/util/supercomputer.test.d.ts +0 -1
  80. package/build/__tests__/unit/util/supercomputer.test.js +0 -231
  81. package/build/__tests__/unit/util/yaml.test.d.ts +0 -1
  82. package/build/__tests__/unit/util/yaml.test.js +0 -59
  83. package/build/lib/azure-importer/index.d.ts +0 -55
  84. package/build/lib/azure-importer/index.js +0 -314
  85. package/build/lib/boavizta/index.d.ts +0 -53
  86. package/build/lib/boavizta/index.js +0 -254
  87. package/build/lib/case-studies/aveva-model.d.ts +0 -29
  88. package/build/lib/case-studies/aveva-model.js +0 -53
  89. package/build/lib/case-studies/emem-model.d.ts +0 -42
  90. package/build/lib/case-studies/emem-model.js +0 -93
  91. package/build/lib/case-studies/eshoppen-model.d.ts +0 -24
  92. package/build/lib/case-studies/eshoppen-model.js +0 -123
  93. package/build/lib/case-studies/index.d.ts +0 -4
  94. package/build/lib/case-studies/index.js +0 -21
  95. package/build/lib/case-studies/sci-accenture-model.d.ts +0 -10
  96. package/build/lib/case-studies/sci-accenture-model.js +0 -37
  97. package/build/lib/ccf/aws-embodied.json +0 -5591
  98. package/build/lib/ccf/aws-instances.json +0 -21116
  99. package/build/lib/ccf/aws-use.json +0 -79
  100. package/build/lib/ccf/azure-embodied.json +0 -6547
  101. package/build/lib/ccf/azure-instances.json +0 -8332
  102. package/build/lib/ccf/azure-use.json +0 -58
  103. package/build/lib/ccf/gcp-embodied.json +0 -3049
  104. package/build/lib/ccf/gcp-instances.json +0 -3880
  105. package/build/lib/ccf/gcp-use.json +0 -58
  106. package/build/lib/ccf/index.d.ts +0 -63
  107. package/build/lib/ccf/index.js +0 -338
  108. package/build/lib/cloud-instance-metadata/aws-instances.json +0 -1
  109. package/build/lib/cloud-instance-metadata/azure-instances.json +0 -1
  110. package/build/lib/cloud-instance-metadata/index.d.ts +0 -15
  111. package/build/lib/cloud-instance-metadata/index.js +0 -104
  112. package/build/lib/index.d.ts +0 -14
  113. package/build/lib/index.js +0 -32
  114. package/build/lib/interfaces/ccf.d.ts +0 -19
  115. package/build/lib/interfaces/ccf.js +0 -3
  116. package/build/lib/interfaces/index.d.ts +0 -7
  117. package/build/lib/interfaces/index.js +0 -18
  118. package/build/lib/sci/index.d.ts +0 -13
  119. package/build/lib/sci/index.js +0 -131
  120. package/build/lib/sci-e/index.d.ts +0 -38
  121. package/build/lib/sci-e/index.js +0 -85
  122. package/build/lib/sci-m/index.d.ts +0 -10
  123. package/build/lib/sci-m/index.js +0 -124
  124. package/build/lib/sci-o/index.d.ts +0 -17
  125. package/build/lib/sci-o/index.js +0 -52
  126. package/build/lib/shell-imp/index.d.ts +0 -32
  127. package/build/lib/shell-imp/index.js +0 -82
  128. package/build/lib/tdp-finder/index.d.ts +0 -19
  129. package/build/lib/tdp-finder/index.js +0 -98
  130. package/build/lib/teads-aws/aws-embodied.json +0 -1
  131. package/build/lib/teads-aws/aws-instances.json +0 -1
  132. package/build/lib/teads-aws/index.d.ts +0 -58
  133. package/build/lib/teads-aws/index.js +0 -208
  134. package/build/lib/teads-curve/index.d.ts +0 -52
  135. package/build/lib/teads-curve/index.js +0 -158
  136. package/build/lib/watt-time/index.d.ts +0 -18
  137. package/build/lib/watt-time/index.js +0 -204
  138. package/build/util/models-universe.d.ts +0 -28
  139. package/build/util/models-universe.js +0 -95
  140. package/build/util/observatory.d.ts +0 -20
  141. package/build/util/observatory.js +0 -31
  142. package/build/util/supercomputer.d.ts +0 -30
  143. package/build/util/supercomputer.js +0 -109
  144. package/docs/implementations/tdp-finder.md +0 -36
  145. package/examples/impls/test/complex-pipeline.yml +0 -67
  146. package/examples/impls/test/toto.yaml +0 -22
  147. package/tsconfig.tsbuildinfo +0 -1
@@ -1,58 +0,0 @@
1
- [
2
- {
3
- "": "0",
4
- "Architecture": "Skylake",
5
- "Min Watts": "0.6446044454253452",
6
- "Max Watts": "3.8984738056304855",
7
- "GB/Chip": "80.43037974683544"
8
- },
9
- {
10
- "": "1",
11
- "Architecture": "Broadwell",
12
- "Min Watts": "0.7128342245989304",
13
- "Max Watts": "3.3857473048128344",
14
- "GB/Chip": "69.6470588235294"
15
- },
16
- {
17
- "": "2",
18
- "Architecture": "Haswell",
19
- "Min Watts": "1.9005681818181814",
20
- "Max Watts": "5.9688982156043195",
21
- "GB/Chip": "27.310344827586206"
22
- },
23
- {
24
- "": "3",
25
- "Architecture": "EPYC 2nd Gen",
26
- "Min Watts": "0.4742621527777778",
27
- "Max Watts": "1.5751872939814815",
28
- "GB/Chip": "129.77777777777777"
29
- },
30
- {
31
- "": "4",
32
- "Architecture": "Cascade Lake",
33
- "Min Watts": "0.6389493581523519",
34
- "Max Watts": "3.6424520285114035",
35
- "GB/Chip": "98.11764705882354"
36
- },
37
- {
38
- "": "5",
39
- "Architecture": "EPYC 3rd Gen",
40
- "Min Watts": "0.44538981119791665",
41
- "Max Watts": "1.8719357994791666",
42
- "GB/Chip": "128.0"
43
- },
44
- {
45
- "": "6",
46
- "Architecture": "Ivy Bridge",
47
- "Min Watts": "3.0369270833333335",
48
- "Max Watts": "8.199689511111112",
49
- "GB/Chip": "14.933333333333334"
50
- },
51
- {
52
- "": "7",
53
- "Architecture": "Sandy Bridge",
54
- "Min Watts": "2.1694411458333334",
55
- "Max Watts": "8.550185877430936",
56
- "GB/Chip": "16.480916030534353"
57
- }
58
- ]
@@ -1,63 +0,0 @@
1
- import { IOutputModelInterface } from '../interfaces';
2
- export declare class CloudCarbonFootprint implements IOutputModelInterface {
3
- authParams: object | undefined;
4
- name: string | undefined;
5
- private computeInstances;
6
- private computeInstanceUsageByArchitecture;
7
- private vendor;
8
- private instanceType;
9
- private expectedLifespan;
10
- private interpolation;
11
- constructor();
12
- /**
13
- * Defined for compatibility. Not used in CCF.
14
- */
15
- authenticate(authParams: object): void;
16
- /**
17
- * Configures the CCF Plugin for IEF
18
- * @param {string} name name of the resource
19
- * @param {Object} staticParams static parameters for the resource
20
- * @param {("aws"|"gcp"|"azure")} staticParams.vendor aws, gcp, azure
21
- * @param {string} staticParams.'instance-type' instance type from the list of supported instances
22
- * @param {number} staticParams.'expected-lifespan' expected lifespan of the instance in years
23
- * @param {Interpolation} staticParams.interpolation linear(All Clouds), spline (only for AWS)
24
- */
25
- configure(name: string, staticParams?: object | undefined): Promise<IOutputModelInterface>;
26
- /**
27
- * Calculate the total emissions for a list of inputs
28
- *
29
- * Each input require:
30
- * @param {Object[]} inputs ISO 8601 timestamp string
31
- * @param {string} inputs[].timestamp ISO 8601 timestamp string
32
- * @param {number} inputs[].duration input duration in seconds
33
- * @param {number} inputs[].cpu-util percentage cpu usage
34
- */
35
- execute(inputs: object | object[] | undefined): Promise<any[]>;
36
- /**
37
- * Calculates the energy consumption for a single input
38
- * requires
39
- *
40
- * duration: duration of the input in seconds
41
- * cpu-util: cpu usage in percentage
42
- * timestamp: ISO 8601 timestamp string
43
- *
44
- * Uses a spline method for AWS and linear interpolation for GCP and Azure
45
- */
46
- private calculateEnergy;
47
- /**
48
- * Returns model identifier
49
- */
50
- modelIdentifier(): string;
51
- /**
52
- * Standardize the instance metrics for all the vendors
53
- *
54
- * Maps the instance metrics to a standard format (min, max, idle, 10%, 50%, 100%) for all the vendors
55
- */
56
- standardizeInstanceMetrics(): void;
57
- private calculateAverage;
58
- resolveAwsArchitecture(architecture: string): string;
59
- /**
60
- * Calculates the embodied emissions for a given input
61
- */
62
- private embodiedEmissions;
63
- }
@@ -1,338 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CloudCarbonFootprint = void 0;
4
- const typescript_cubic_spline_1 = require("typescript-cubic-spline");
5
- const AWSInstanceTypes_1 = require("@cloud-carbon-footprint/aws/dist/lib/AWSInstanceTypes");
6
- const config_1 = require("../../config");
7
- const AWS_INSTANCES = require("./aws-instances.json");
8
- const GCP_INSTANCES = require("./gcp-instances.json");
9
- const AZURE_INSTANCES = require("./azure-instances.json");
10
- const GCP_USE = require("./gcp-use.json");
11
- const AWS_USE = require("./aws-use.json");
12
- const AZURE_USE = require("./azure-use.json");
13
- const GCP_EMBODIED = require("./gcp-embodied.json");
14
- const AWS_EMBODIED = require("./aws-embodied.json");
15
- const AZURE_EMBODIED = require("./azure-embodied.json");
16
- const common_1 = require("../../types/common");
17
- const { MODEL_IDS } = config_1.CONFIG;
18
- const { CCF } = MODEL_IDS;
19
- class CloudCarbonFootprint {
20
- constructor() {
21
- // compute instances grouped by the vendor with usage data
22
- this.computeInstances = {};
23
- // list of all the by Architecture
24
- this.computeInstanceUsageByArchitecture = {
25
- gcp: {},
26
- aws: {},
27
- azure: {},
28
- };
29
- this.vendor = '';
30
- this.instanceType = '';
31
- this.expectedLifespan = 4;
32
- this.interpolation = common_1.Interpolation.LINEAR;
33
- this.standardizeInstanceMetrics();
34
- }
35
- /**
36
- * Defined for compatibility. Not used in CCF.
37
- */
38
- authenticate(authParams) {
39
- this.authParams = authParams;
40
- }
41
- /**
42
- * Configures the CCF Plugin for IEF
43
- * @param {string} name name of the resource
44
- * @param {Object} staticParams static parameters for the resource
45
- * @param {("aws"|"gcp"|"azure")} staticParams.vendor aws, gcp, azure
46
- * @param {string} staticParams.'instance-type' instance type from the list of supported instances
47
- * @param {number} staticParams.'expected-lifespan' expected lifespan of the instance in years
48
- * @param {Interpolation} staticParams.interpolation linear(All Clouds), spline (only for AWS)
49
- */
50
- async configure(name, staticParams = undefined) {
51
- this.name = name;
52
- if (staticParams === undefined) {
53
- throw new Error('Required Parameters not provided');
54
- }
55
- if ('vendor' in staticParams) {
56
- const vendor = staticParams?.vendor;
57
- if (['aws', 'gcp', 'azure'].includes(vendor)) {
58
- this.vendor = vendor;
59
- }
60
- else {
61
- throw new Error('vendor not supported');
62
- }
63
- }
64
- else {
65
- throw new Error('vendor not provided');
66
- }
67
- if ('instance-type' in staticParams) {
68
- const instanceType = staticParams['instance-type'];
69
- if (instanceType in this.computeInstances[this.vendor]) {
70
- this.instanceType = instanceType;
71
- }
72
- else {
73
- throw new Error('Instance Type not supported');
74
- }
75
- }
76
- else {
77
- throw new Error('Instance Type not provided');
78
- }
79
- if ('expected-lifespan' in staticParams) {
80
- this.expectedLifespan = staticParams['expected-lifespan'];
81
- }
82
- if ('interpolation' in staticParams) {
83
- if (this.vendor !== 'aws') {
84
- throw new Error('Interpolation method not supported');
85
- }
86
- const interpolation = staticParams?.interpolation;
87
- if (Object.values(common_1.Interpolation).includes(interpolation)) {
88
- this.interpolation = interpolation;
89
- }
90
- else {
91
- throw new Error('Interpolation method not supported');
92
- }
93
- }
94
- return this;
95
- }
96
- /**
97
- * Calculate the total emissions for a list of inputs
98
- *
99
- * Each input require:
100
- * @param {Object[]} inputs ISO 8601 timestamp string
101
- * @param {string} inputs[].timestamp ISO 8601 timestamp string
102
- * @param {number} inputs[].duration input duration in seconds
103
- * @param {number} inputs[].cpu-util percentage cpu usage
104
- */
105
- async execute(inputs) {
106
- if (inputs === undefined) {
107
- throw new Error('Required Parameters not provided');
108
- }
109
- if (!Array.isArray(inputs)) {
110
- throw new Error('inputs should be an array');
111
- }
112
- if (this.instanceType === '' || this.vendor === '') {
113
- throw new Error('Configuration is incomplete');
114
- }
115
- inputs.map((input) => {
116
- input['energy'] = this.calculateEnergy(input);
117
- input['embodied-carbon'] = this.embodiedEmissions(input);
118
- return input;
119
- });
120
- return inputs;
121
- }
122
- /**
123
- * Calculates the energy consumption for a single input
124
- * requires
125
- *
126
- * duration: duration of the input in seconds
127
- * cpu-util: cpu usage in percentage
128
- * timestamp: ISO 8601 timestamp string
129
- *
130
- * Uses a spline method for AWS and linear interpolation for GCP and Azure
131
- */
132
- calculateEnergy(input) {
133
- if (!('duration' in input) ||
134
- !('cpu-util' in input) ||
135
- !('timestamp' in input)) {
136
- throw new Error('Required Parameters duration,cpu,timestamp not provided for input');
137
- }
138
- const duration = input['duration'];
139
- const cpu = input['cpu-util'];
140
- // get the wattage for the instance type
141
- let wattage;
142
- if (this.vendor === 'aws' && this.interpolation === 'spline') {
143
- const x = [0, 10, 50, 100];
144
- const y = [
145
- this.computeInstances['aws'][this.instanceType].consumption.idle ?? 0,
146
- this.computeInstances['aws'][this.instanceType].consumption
147
- .tenPercent ?? 0,
148
- this.computeInstances['aws'][this.instanceType].consumption
149
- .fiftyPercent ?? 0,
150
- this.computeInstances['aws'][this.instanceType].consumption
151
- .hundredPercent ?? 0,
152
- ];
153
- const spline = new typescript_cubic_spline_1.default(x, y);
154
- wattage = spline.at(cpu);
155
- }
156
- else {
157
- const idle = this.computeInstances[this.vendor][this.instanceType].consumption
158
- .minWatts ?? 0;
159
- const max = this.computeInstances[this.vendor][this.instanceType].consumption
160
- .maxWatts ?? 0;
161
- // linear interpolation
162
- wattage = idle + (max - idle) * (cpu / 100);
163
- }
164
- // duration is in seconds
165
- // wattage is in watts
166
- // eg: 30W x 300s = 9000 J
167
- // 1 Wh = 3600 J
168
- // 9000 J / 3600 = 2.5 Wh
169
- // J / 3600 = Wh
170
- // 2.5 Wh / 1000 = 0.0025 kWh
171
- // Wh / 1000 = kWh
172
- // (wattage * duration) / (seconds in an hour) / 1000 = kWh
173
- return (wattage * duration) / 3600 / 1000;
174
- }
175
- /**
176
- * Returns model identifier
177
- */
178
- modelIdentifier() {
179
- return CCF;
180
- }
181
- /**
182
- * Standardize the instance metrics for all the vendors
183
- *
184
- * Maps the instance metrics to a standard format (min, max, idle, 10%, 50%, 100%) for all the vendors
185
- */
186
- standardizeInstanceMetrics() {
187
- this.computeInstances['aws'] = {};
188
- this.computeInstances['gcp'] = {};
189
- this.computeInstances['azure'] = {};
190
- this.calculateAverage('gcp', GCP_USE);
191
- this.calculateAverage('azure', AZURE_USE);
192
- this.calculateAverage('aws', AWS_USE);
193
- AWS_INSTANCES.forEach((instance) => {
194
- const cpus = parseInt(instance['Instance vCPU'], 10);
195
- const architectures = AWSInstanceTypes_1.INSTANCE_TYPE_COMPUTE_PROCESSOR_MAPPING[instance['Instance type']] ?? ['Average'];
196
- let minWatts = 0.0;
197
- let maxWatts = 0.0;
198
- let count = 0;
199
- architectures.forEach((architecture) => {
200
- architecture = this.resolveAwsArchitecture(architecture);
201
- minWatts +=
202
- this.computeInstanceUsageByArchitecture['aws'][architecture]['Min Watts'] ?? 0;
203
- maxWatts +=
204
- this.computeInstanceUsageByArchitecture['aws'][architecture]['Max Watts'] ?? 0;
205
- count += 1;
206
- });
207
- minWatts = minWatts / count;
208
- maxWatts = maxWatts / count;
209
- this.computeInstances['aws'][instance['Instance type']] = {
210
- consumption: {
211
- idle: parseFloat(instance['Instance @ Idle'].replace(',', '.')),
212
- tenPercent: parseFloat(instance['Instance @ 10%'].replace(',', '.')),
213
- fiftyPercent: parseFloat(instance['Instance @ 50%'].replace(',', '.')),
214
- hundredPercent: parseFloat(instance['Instance @ 100%'].replace(',', '.')),
215
- minWatts: minWatts * cpus,
216
- maxWatts: maxWatts * cpus,
217
- },
218
- vCPUs: cpus,
219
- maxvCPUs: parseInt(instance['Platform Total Number of vCPU'], 10),
220
- name: instance['Instance type'],
221
- };
222
- });
223
- GCP_INSTANCES.forEach((instance) => {
224
- const cpus = parseInt(instance['Instance vCPUs'], 10);
225
- let architecture = instance['Microarchitecture'];
226
- if (!(architecture in this.computeInstanceUsageByArchitecture['gcp'])) {
227
- architecture = 'Average';
228
- }
229
- this.computeInstances['gcp'][instance['Machine type']] = {
230
- name: instance['Machine type'],
231
- vCPUs: cpus,
232
- consumption: {
233
- minWatts: this.computeInstanceUsageByArchitecture['gcp'][architecture]['Min Watts'] * cpus,
234
- maxWatts: this.computeInstanceUsageByArchitecture['gcp'][architecture]['Max Watts'] * cpus,
235
- },
236
- maxvCPUs: parseInt(instance['Platform vCPUs (highest vCPU possible)'], 10),
237
- };
238
- });
239
- AZURE_INSTANCES.forEach((instance) => {
240
- const cpus = parseInt(instance['Instance vCPUs'], 10);
241
- let architecture = instance['Microarchitecture'];
242
- if (!(architecture in this.computeInstanceUsageByArchitecture['azure'])) {
243
- architecture = 'Average';
244
- }
245
- this.computeInstances['azure'][instance['Virtual Machine']] = {
246
- consumption: {
247
- minWatts: this.computeInstanceUsageByArchitecture['azure'][architecture]['Min Watts'] * cpus,
248
- maxWatts: this.computeInstanceUsageByArchitecture['azure'][architecture]['Max Watts'] * cpus,
249
- },
250
- name: instance['Virtual Machine'],
251
- vCPUs: instance['Instance vCPUs'],
252
- maxvCPUs: parseInt(instance['Platform vCPUs (highest vCPU possible)'], 10),
253
- };
254
- });
255
- AWS_EMBODIED.forEach((instance) => {
256
- this.computeInstances['aws'][instance['type']].embodiedEmission =
257
- instance['total'];
258
- });
259
- GCP_EMBODIED.forEach((instance) => {
260
- this.computeInstances['gcp'][instance['type']].embodiedEmission =
261
- instance['total'];
262
- });
263
- AZURE_EMBODIED.forEach((instance) => {
264
- this.computeInstances['azure'][instance['type']].embodiedEmission =
265
- instance['total'];
266
- });
267
- }
268
- calculateAverage(vendor, instanceList) {
269
- let min = 0.0;
270
- let max = 0.0;
271
- let count = 0.0;
272
- instanceList.forEach((instance) => {
273
- this.computeInstanceUsageByArchitecture[vendor][instance['Architecture']] = instance;
274
- min += parseFloat(instance['Min Watts']);
275
- max += parseFloat(instance['Max Watts']);
276
- count += 1.0;
277
- });
278
- const avgMin = min / count;
279
- const avgMax = max / count;
280
- this.computeInstanceUsageByArchitecture[vendor]['Average'] = {
281
- 'Min Watts': avgMin,
282
- 'Max Watts': avgMax,
283
- Architecture: 'Average',
284
- };
285
- }
286
- // Architecture strings are different between Instances-Use.JSON and the bundled Typescript from CCF.
287
- // This function resolves the differences.
288
- resolveAwsArchitecture(architecture) {
289
- if (architecture.includes('AMD ')) {
290
- architecture = architecture.substring(4);
291
- }
292
- if (architecture.includes('Skylake')) {
293
- architecture = 'Sky Lake';
294
- }
295
- if (architecture.includes('Graviton')) {
296
- if (architecture.includes('2')) {
297
- architecture = 'Graviton2';
298
- }
299
- else {
300
- architecture = 'Graviton';
301
- }
302
- }
303
- if (architecture.includes('Unknown')) {
304
- architecture = 'Average';
305
- }
306
- if (!(architecture in this.computeInstanceUsageByArchitecture['aws'])) {
307
- throw new Error(`${architecture} not supported`);
308
- }
309
- return architecture;
310
- }
311
- /**
312
- * Calculates the embodied emissions for a given input
313
- */
314
- embodiedEmissions(input) {
315
- // duration
316
- const durationInHours = input['duration'] / 3600;
317
- // M = TE * (TR/EL) * (RR/TR)
318
- // Where:
319
- // TE = Total Embodied Emissions, the sum of Life Cycle Assessment(LCA) emissions for all hardware components
320
- // TR = Time Reserved, the length of time the hardware is reserved for use by the software
321
- // EL = Expected Lifespan, the anticipated time that the equipment will be installed
322
- // RR = Resources Reserved, the number of resources reserved for use by the software.
323
- // TR = Total Resources, the total number of resources available.
324
- const totalEmissions = this.computeInstances[this.vendor][this.instanceType].embodiedEmission ??
325
- 0;
326
- const timeReserved = durationInHours;
327
- const expectedLifespan = 8760 * this.expectedLifespan;
328
- const reservedResources = this.computeInstances[this.vendor][this.instanceType].vCPUs ?? 1.0;
329
- const totalResources = this.computeInstances[this.vendor][this.instanceType].maxVCPUs ?? 1.0;
330
- // Multiply totalEmissions by 1000 to convert from kgCO2e to gCO2e
331
- return (totalEmissions *
332
- 1000 *
333
- (timeReserved / expectedLifespan) *
334
- (reservedResources / totalResources));
335
- }
336
- }
337
- exports.CloudCarbonFootprint = CloudCarbonFootprint;
338
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2NjZi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxRUFBNkM7QUFHN0MsNEZBQThHO0FBRTlHLHlDQUFvQztBQUVwQyxzREFBc0Q7QUFDdEQsc0RBQXNEO0FBQ3RELDBEQUEwRDtBQUMxRCwwQ0FBMEM7QUFDMUMsMENBQTBDO0FBQzFDLDhDQUE4QztBQUM5QyxvREFBb0Q7QUFDcEQsb0RBQW9EO0FBQ3BELHdEQUF3RDtBQUV4RCwrQ0FBK0Q7QUFFL0QsTUFBTSxFQUFDLFNBQVMsRUFBQyxHQUFHLGVBQU0sQ0FBQztBQUMzQixNQUFNLEVBQUMsR0FBRyxFQUFDLEdBQUcsU0FBUyxDQUFDO0FBRXhCLE1BQWEsb0JBQW9CO0lBd0IvQjtRQW5CQSwwREFBMEQ7UUFDbEQscUJBQWdCLEdBSXBCLEVBQUUsQ0FBQztRQUVQLGtDQUFrQztRQUMxQix1Q0FBa0MsR0FBaUI7WUFDekQsR0FBRyxFQUFFLEVBQUU7WUFDUCxHQUFHLEVBQUUsRUFBRTtZQUNQLEtBQUssRUFBRSxFQUFFO1NBQ1YsQ0FBQztRQUNNLFdBQU0sR0FBRyxFQUFFLENBQUM7UUFDWixpQkFBWSxHQUFHLEVBQUUsQ0FBQztRQUNsQixxQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFFckIsa0JBQWEsR0FBRyxzQkFBYSxDQUFDLE1BQU0sQ0FBQztRQUczQyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxZQUFZLENBQUMsVUFBa0I7UUFDN0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsS0FBSyxDQUFDLFNBQVMsQ0FDYixJQUFZLEVBQ1osZUFBbUMsU0FBUztRQUU1QyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUVqQixJQUFJLFlBQVksS0FBSyxTQUFT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QUFjLENBQUMsQ0FDckMsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQTNZRCxvREEyWUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgU3BsaW5lIGZyb20gJ3R5cGVzY3JpcHQtY3ViaWMtc3BsaW5lJztcblxuaW1wb3J0IHtJQ29tcHV0ZUluc3RhbmNlLCBJT3V0cHV0TW9kZWxJbnRlcmZhY2V9IGZyb20gJy4uL2ludGVyZmFjZXMnO1xuaW1wb3J0IHtJTlNUQU5DRV9UWVBFX0NPTVBVVEVfUFJPQ0VTU09SX01BUFBJTkd9IGZyb20gJ0BjbG91ZC1jYXJib24tZm9vdHByaW50L2F3cy9kaXN0L2xpYi9BV1NJbnN0YW5jZVR5cGVzJztcblxuaW1wb3J0IHtDT05GSUd9IGZyb20gJy4uLy4uL2NvbmZpZyc7XG5cbmltcG9ydCAqIGFzIEFXU19JTlNUQU5DRVMgZnJvbSAnLi9hd3MtaW5zdGFuY2VzLmpzb24nO1xuaW1wb3J0ICogYXMgR0NQX0lOU1RBTkNFUyBmcm9tICcuL2djcC1pbnN0YW5jZXMuanNvbic7XG5pbXBvcnQgKiBhcyBBWlVSRV9JTlNUQU5DRVMgZnJvbSAnLi9henVyZS1pbnN0YW5jZXMuanNvbic7XG5pbXBvcnQgKiBhcyBHQ1BfVVNFIGZyb20gJy4vZ2NwLXVzZS5qc29uJztcbmltcG9ydCAqIGFzIEFXU19VU0UgZnJvbSAnLi9hd3MtdXNlLmpzb24nO1xuaW1wb3J0ICogYXMgQVpVUkVfVVNFIGZyb20gJy4vYXp1cmUtdXNlLmpzb24nO1xuaW1wb3J0ICogYXMgR0NQX0VNQk9ESUVEIGZyb20gJy4vZ2NwLWVtYm9kaWVkLmpzb24nO1xuaW1wb3J0ICogYXMgQVdTX0VNQk9ESUVEIGZyb20gJy4vYXdzLWVtYm9kaWVkLmpzb24nO1xuaW1wb3J0ICogYXMgQVpVUkVfRU1CT0RJRUQgZnJvbSAnLi9henVyZS1lbWJvZGllZC5qc29uJztcblxuaW1wb3J0IHtLZXlWYWx1ZVBhaXIsIEludGVycG9sYXRpb259IGZyb20gJy4uLy4uL3R5cGVzL2NvbW1vbic7XG5cbmNvbnN0IHtNT0RFTF9JRFN9ID0gQ09ORklHO1xuY29uc3Qge0NDRn0gPSBNT0RFTF9JRFM7XG5cbmV4cG9ydCBjbGFzcyBDbG91ZENhcmJvbkZvb3RwcmludCBpbXBsZW1lbnRzIElPdXRwdXRNb2RlbEludGVyZmFjZSB7XG4gIC8vIERlZmluZWQgZm9yIGNvbXBhdGliaWxpdHkuIE5vdCB1c2VkIGluIENDRi5cbiAgYXV0aFBhcmFtczogb2JqZWN0IHwgdW5kZWZpbmVkO1xuICAvLyBuYW1lIG9mIHRoZSBkYXRhIHNvdXJjZVxuICBuYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8vIGNvbXB1dGUgaW5zdGFuY2VzIGdyb3VwZWQgYnkgdGhlIHZlbmRvciB3aXRoIHVzYWdlIGRhdGFcbiAgcHJpdmF0ZSBjb21wdXRlSW5zdGFuY2VzOiB7XG4gICAgW2tleTogc3RyaW5nXToge1xuICAgICAgW2tleTogc3RyaW5nXTogSUNvbXB1dGVJbnN0YW5jZTtcbiAgICB9O1xuICB9ID0ge307XG5cbiAgLy8gbGlzdCBvZiBhbGwgdGhlIGJ5IEFyY2hpdGVjdHVyZVxuICBwcml2YXRlIGNvbXB1dGVJbnN0YW5jZVVzYWdlQnlBcmNoaXRlY3R1cmU6IEtleVZhbHVlUGFpciA9IHtcbiAgICBnY3A6IHt9LFxuICAgIGF3czoge30sXG4gICAgYXp1cmU6IHt9LFxuICB9O1xuICBwcml2YXRlIHZlbmRvciA9ICcnO1xuICBwcml2YXRlIGluc3RhbmNlVHlwZSA9ICcnO1xuICBwcml2YXRlIGV4cGVjdGVkTGlmZXNwYW4gPSA0O1xuXG4gIHByaXZhdGUgaW50ZXJwb2xhdGlvbiA9IEludGVycG9sYXRpb24uTElORUFSO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuc3RhbmRhcmRpemVJbnN0YW5jZU1ldHJpY3MoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZpbmVkIGZvciBjb21wYXRpYmlsaXR5LiBOb3QgdXNlZCBpbiBDQ0YuXG4gICAqL1xuICBhdXRoZW50aWNhdGUoYXV0aFBhcmFtczogb2JqZWN0KTogdm9pZCB7XG4gICAgdGhpcy5hdXRoUGFyYW1zID0gYXV0aFBhcmFtcztcbiAgfVxuXG4gIC8qKlxuICAgKiAgQ29uZmlndXJlcyB0aGUgQ0NGIFBsdWdpbiBmb3IgSUVGXG4gICAqICBAcGFyYW0ge3N0cmluZ30gbmFtZSBuYW1lIG9mIHRoZSByZXNvdXJjZVxuICAgKiAgQHBhcmFtIHtPYmplY3R9IHN0YXRpY1BhcmFtcyBzdGF0aWMgcGFyYW1ldGVycyBmb3IgdGhlIHJlc291cmNlXG4gICAqICBAcGFyYW0geyhcImF3c1wifFwiZ2NwXCJ8XCJhenVyZVwiKX0gc3RhdGljUGFyYW1zLnZlbmRvciBhd3MsIGdjcCwgYXp1cmVcbiAgICogIEBwYXJhbSB7c3RyaW5nfSBzdGF0aWNQYXJhbXMuJ2luc3RhbmNlLXR5cGUnIGluc3RhbmNlIHR5cGUgZnJvbSB0aGUgbGlzdCBvZiBzdXBwb3J0ZWQgaW5zdGFuY2VzXG4gICAqICBAcGFyYW0ge251bWJlcn0gc3RhdGljUGFyYW1zLidleHBlY3RlZC1saWZlc3BhbicgZXhwZWN0ZWQgbGlmZXNwYW4gb2YgdGhlIGluc3RhbmNlIGluIHllYXJzXG4gICAqICBAcGFyYW0ge0ludGVycG9sYXRpb259IHN0YXRpY1BhcmFtcy5pbnRlcnBvbGF0aW9uIGxpbmVhcihBbGwgQ2xvdWRzKSwgc3BsaW5lIChvbmx5IGZvciBBV1MpXG4gICAqL1xuICBhc3luYyBjb25maWd1cmUoXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIHN0YXRpY1BhcmFtczogb2JqZWN0IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG4gICk6IFByb21pc2U8SU91dHB1dE1vZGVsSW50ZXJmYWNlPiB7XG4gICAgdGhpcy5uYW1lID0gbmFtZTtcblxuICAgIGlmIChzdGF0aWNQYXJhbXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZXF1aXJlZCBQYXJhbWV0ZXJzIG5vdCBwcm92aWRlZCcpO1xuICAgIH1cblxuICAgIGlmICgndmVuZG9yJyBpbiBzdGF0aWNQYXJhbXMpIHtcbiAgICAgIGNvbnN0IHZlbmRvciA9IHN0YXRpY1BhcmFtcz8udmVuZG9yIGFzIHN0cmluZztcbiAgICAgIGlmIChbJ2F3cycsICdnY3AnLCAnYXp1cmUnXS5pbmNsdWRlcyh2ZW5kb3IpKSB7XG4gICAgICAgIHRoaXMudmVuZG9yID0gdmVuZG9yO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZW5kb3Igbm90IHN1cHBvcnRlZCcpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlbmRvciBub3QgcHJvdmlkZWQnKTtcbiAgICB9XG5cbiAgICBpZiAoJ2luc3RhbmNlLXR5cGUnIGluIHN0YXRpY1BhcmFtcykge1xuICAgICAgY29uc3QgaW5zdGFuY2VUeXBlID0gc3RhdGljUGFyYW1zWydpbnN0YW5jZS10eXBlJ10gYXMgc3RyaW5nO1xuICAgICAgaWYgKGluc3RhbmNlVHlwZSBpbiB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbdGhpcy52ZW5kb3JdKSB7XG4gICAgICAgIHRoaXMuaW5zdGFuY2VUeXBlID0gaW5zdGFuY2VUeXBlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnN0YW5jZSBUeXBlIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnN0YW5jZSBUeXBlIG5vdCBwcm92aWRlZCcpO1xuICAgIH1cblxuICAgIGlmICgnZXhwZWN0ZWQtbGlmZXNwYW4nIGluIHN0YXRpY1BhcmFtcykge1xuICAgICAgdGhpcy5leHBlY3RlZExpZmVzcGFuID0gc3RhdGljUGFyYW1zWydleHBlY3RlZC1saWZlc3BhbiddIGFzIG51bWJlcjtcbiAgICB9XG5cbiAgICBpZiAoJ2ludGVycG9sYXRpb24nIGluIHN0YXRpY1BhcmFtcykge1xuICAgICAgaWYgKHRoaXMudmVuZG9yICE9PSAnYXdzJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVycG9sYXRpb24gbWV0aG9kIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGludGVycG9sYXRpb24gPSBzdGF0aWNQYXJhbXM/LmludGVycG9sYXRpb24gYXMgSW50ZXJwb2xhdGlvbjtcbiAgICAgIGlmIChPYmplY3QudmFsdWVzKEludGVycG9sYXRpb24pLmluY2x1ZGVzKGludGVycG9sYXRpb24pKSB7XG4gICAgICAgIHRoaXMuaW50ZXJwb2xhdGlvbiA9IGludGVycG9sYXRpb247XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludGVycG9sYXRpb24gbWV0aG9kIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgdGhlIHRvdGFsIGVtaXNzaW9ucyBmb3IgYSBsaXN0IG9mIGlucHV0c1xuICAgKlxuICAgKiBFYWNoIGlucHV0IHJlcXVpcmU6XG4gICAqICBAcGFyYW0ge09iamVjdFtdfSBpbnB1dHMgIElTTyA4NjAxIHRpbWVzdGFtcCBzdHJpbmdcbiAgICogIEBwYXJhbSB7c3RyaW5nfSBpbnB1dHNbXS50aW1lc3RhbXAgSVNPIDg2MDEgdGltZXN0YW1wIHN0cmluZ1xuICAgKiAgQHBhcmFtIHtudW1iZXJ9IGlucHV0c1tdLmR1cmF0aW9uIGlucHV0IGR1cmF0aW9uIGluIHNlY29uZHNcbiAgICogIEBwYXJhbSB7bnVtYmVyfSBpbnB1dHNbXS5jcHUtdXRpbCBwZXJjZW50YWdlIGNwdSB1c2FnZVxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZShpbnB1dHM6IG9iamVjdCB8IG9iamVjdFtdIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxhbnlbXT4ge1xuICAgIGlmIChpbnB1dHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZXF1aXJlZCBQYXJhbWV0ZXJzIG5vdCBwcm92aWRlZCcpO1xuICAgIH1cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoaW5wdXRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnB1dHMgc2hvdWxkIGJlIGFuIGFycmF5Jyk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuaW5zdGFuY2VUeXBlID09PSAnJyB8fCB0aGlzLnZlbmRvciA9PT0gJycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ29uZmlndXJhdGlvbiBpcyBpbmNvbXBsZXRlJyk7XG4gICAgfVxuICAgIGlucHV0cy5tYXAoKGlucHV0OiBLZXlWYWx1ZVBhaXIpID0+IHtcbiAgICAgIGlucHV0WydlbmVyZ3knXSA9IHRoaXMuY2FsY3VsYXRlRW5lcmd5KGlucHV0KTtcbiAgICAgIGlucHV0WydlbWJvZGllZC1jYXJib24nXSA9IHRoaXMuZW1ib2RpZWRFbWlzc2lvbnMoaW5wdXQpO1xuICAgICAgcmV0dXJuIGlucHV0O1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGlucHV0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBlbmVyZ3kgY29uc3VtcHRpb24gZm9yIGEgc2luZ2xlIGlucHV0XG4gICAqIHJlcXVpcmVzXG4gICAqXG4gICAqIGR1cmF0aW9uOiBkdXJhdGlvbiBvZiB0aGUgaW5wdXQgaW4gc2Vjb25kc1xuICAgKiBjcHUtdXRpbDogY3B1IHVzYWdlIGluIHBlcmNlbnRhZ2VcbiAgICogdGltZXN0YW1wOiBJU08gODYwMSB0aW1lc3RhbXAgc3RyaW5nXG4gICAqXG4gICAqIFVzZXMgYSBzcGxpbmUgbWV0aG9kIGZvciBBV1MgYW5kIGxpbmVhciBpbnRlcnBvbGF0aW9uIGZvciBHQ1AgYW5kIEF6dXJlXG4gICAqL1xuICBwcml2YXRlIGNhbGN1bGF0ZUVuZXJneShpbnB1dDogS2V5VmFsdWVQYWlyKSB7XG4gICAgaWYgKFxuICAgICAgISgnZHVyYXRpb24nIGluIGlucHV0KSB8fFxuICAgICAgISgnY3B1LXV0aWwnIGluIGlucHV0KSB8fFxuICAgICAgISgndGltZXN0YW1wJyBpbiBpbnB1dClcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1JlcXVpcmVkIFBhcmFtZXRlcnMgZHVyYXRpb24sY3B1LHRpbWVzdGFtcCBub3QgcHJvdmlkZWQgZm9yIGlucHV0J1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBkdXJhdGlvbiA9IGlucHV0WydkdXJhdGlvbiddO1xuICAgIGNvbnN0IGNwdSA9IGlucHV0WydjcHUtdXRpbCddO1xuXG4gICAgLy8gIGdldCB0aGUgd2F0dGFnZSBmb3IgdGhlIGluc3RhbmNlIHR5cGVcbiAgICBsZXQgd2F0dGFnZTtcblxuICAgIGlmICh0aGlzLnZlbmRvciA9PT0gJ2F3cycgJiYgdGhpcy5pbnRlcnBvbGF0aW9uID09PSAnc3BsaW5lJykge1xuICAgICAgY29uc3QgeCA9IFswLCAxMCwgNTAsIDEwMF07XG5cbiAgICAgIGNvbnN0IHk6IG51bWJlcltdID0gW1xuICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbJ2F3cyddW3RoaXMuaW5zdGFuY2VUeXBlXS5jb25zdW1wdGlvbi5pZGxlID8/IDAsXG4gICAgICAgIHRoaXMuY29tcHV0ZUluc3RhbmNlc1snYXdzJ11bdGhpcy5pbnN0YW5jZVR5cGVdLmNvbnN1bXB0aW9uXG4gICAgICAgICAgLnRlblBlcmNlbnQgPz8gMCxcbiAgICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydhd3MnXVt0aGlzLmluc3RhbmNlVHlwZV0uY29uc3VtcHRpb25cbiAgICAgICAgICAuZmlmdHlQZXJjZW50ID8/IDAsXG4gICAgICAgIHRoaXMuY29tcHV0ZUluc3RhbmNlc1snYXdzJ11bdGhpcy5pbnN0YW5jZVR5cGVdLmNvbnN1bXB0aW9uXG4gICAgICAgICAgLmh1bmRyZWRQZXJjZW50ID8/IDAsXG4gICAgICBdO1xuXG4gICAgICBjb25zdCBzcGxpbmUgPSBuZXcgU3BsaW5lKHgsIHkpO1xuXG4gICAgICB3YXR0YWdlID0gc3BsaW5lLmF0KGNwdSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGlkbGUgPVxuICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbdGhpcy52ZW5kb3JdW3RoaXMuaW5zdGFuY2VUeXBlXS5jb25zdW1wdGlvblxuICAgICAgICAgIC5taW5XYXR0cyA/PyAwO1xuICAgICAgY29uc3QgbWF4ID1cbiAgICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzW3RoaXMudmVuZG9yXVt0aGlzLmluc3RhbmNlVHlwZV0uY29uc3VtcHRpb25cbiAgICAgICAgICAubWF4V2F0dHMgPz8gMDtcblxuICAgICAgLy8gbGluZWFyIGludGVycG9sYXRpb25cbiAgICAgIHdhdHRhZ2UgPSBpZGxlICsgKG1heCAtIGlkbGUpICogKGNwdSAvIDEwMCk7XG4gICAgfVxuICAgIC8vICBkdXJhdGlvbiBpcyBpbiBzZWNvbmRzXG4gICAgLy8gIHdhdHRhZ2UgaXMgaW4gd2F0dHNcbiAgICAvLyAgZWc6IDMwVyB4IDMwMHMgPSA5MDAwIEpcbiAgICAvLyAgMSBXaCA9IDM2MDAgSlxuICAgIC8vICA5MDAwIEogLyAzNjAwID0gMi41IFdoXG4gICAgLy8gIEogLyAzNjAwID0gV2hcbiAgICAvLyAgMi41IFdoIC8gMTAwMCA9IDAuMDAyNSBrV2hcbiAgICAvLyAgV2ggLyAxMDAwID0ga1doXG4gICAgLy8gKHdhdHRhZ2UgKiBkdXJhdGlvbikgLyAoc2Vjb25kcyBpbiBhbiBob3VyKSAvIDEwMDAgPSBrV2hcbiAgICByZXR1cm4gKHdhdHRhZ2UgKiBkdXJhdGlvbikgLyAzNjAwIC8gMTAwMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIG1vZGVsIGlkZW50aWZpZXJcbiAgICovXG4gIG1vZGVsSWRlbnRpZmllcigpOiBzdHJpbmcge1xuICAgIHJldHVybiBDQ0Y7XG4gIH1cblxuICAvKipcbiAgICogU3RhbmRhcmRpemUgdGhlIGluc3RhbmNlIG1ldHJpY3MgZm9yIGFsbCB0aGUgdmVuZG9yc1xuICAgKlxuICAgKiBNYXBzIHRoZSBpbnN0YW5jZSBtZXRyaWNzIHRvIGEgc3RhbmRhcmQgZm9ybWF0IChtaW4sIG1heCwgaWRsZSwgMTAlLCA1MCUsIDEwMCUpIGZvciBhbGwgdGhlIHZlbmRvcnNcbiAgICovXG4gIHN0YW5kYXJkaXplSW5zdGFuY2VNZXRyaWNzKCkge1xuICAgIHRoaXMuY29tcHV0ZUluc3RhbmNlc1snYXdzJ10gPSB7fTtcbiAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbJ2djcCddID0ge307XG4gICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydhenVyZSddID0ge307XG4gICAgdGhpcy5jYWxjdWxhdGVBdmVyYWdlKCdnY3AnLCBHQ1BfVVNFKTtcbiAgICB0aGlzLmNhbGN1bGF0ZUF2ZXJhZ2UoJ2F6dXJlJywgQVpVUkVfVVNFKTtcbiAgICB0aGlzLmNhbGN1bGF0ZUF2ZXJhZ2UoJ2F3cycsIEFXU19VU0UpO1xuICAgIEFXU19JTlNUQU5DRVMuZm9yRWFjaCgoaW5zdGFuY2U6IEtleVZhbHVlUGFpcikgPT4ge1xuICAgICAgY29uc3QgY3B1cyA9IHBhcnNlSW50KGluc3RhbmNlWydJbnN0YW5jZSB2Q1BVJ10sIDEwKTtcbiAgICAgIGNvbnN0IGFyY2hpdGVjdHVyZXMgPSBJTlNUQU5DRV9UWVBFX0NPTVBVVEVfUFJPQ0VTU09SX01BUFBJTkdbXG4gICAgICAgIGluc3RhbmNlWydJbnN0YW5jZSB0eXBlJ11cbiAgICAgIF0gPz8gWydBdmVyYWdlJ107XG4gICAgICBsZXQgbWluV2F0dHMgPSAwLjA7XG4gICAgICBsZXQgbWF4V2F0dHMgPSAwLjA7XG4gICAgICBsZXQgY291bnQgPSAwO1xuICAgICAgYXJjaGl0ZWN0dXJlcy5mb3JFYWNoKChhcmNoaXRlY3R1cmU6IHN0cmluZykgPT4ge1xuICAgICAgICBhcmNoaXRlY3R1cmUgPSB0aGlzLnJlc29sdmVBd3NBcmNoaXRlY3R1cmUoYXJjaGl0ZWN0dXJlKTtcbiAgICAgICAgbWluV2F0dHMgKz1cbiAgICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZVVzYWdlQnlBcmNoaXRlY3R1cmVbJ2F3cyddW2FyY2hpdGVjdHVyZV1bXG4gICAgICAgICAgICAnTWluIFdhdHRzJ1xuICAgICAgICAgIF0gPz8gMDtcbiAgICAgICAgbWF4V2F0dHMgKz1cbiAgICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZVVzYWdlQnlBcmNoaXRlY3R1cmVbJ2F3cyddW2FyY2hpdGVjdHVyZV1bXG4gICAgICAgICAgICAnTWF4IFdhdHRzJ1xuICAgICAgICAgIF0gPz8gMDtcbiAgICAgICAgY291bnQgKz0gMTtcbiAgICAgIH0pO1xuICAgICAgbWluV2F0dHMgPSBtaW5XYXR0cyAvIGNvdW50O1xuICAgICAgbWF4V2F0dHMgPSBtYXhXYXR0cyAvIGNvdW50O1xuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydhd3MnXVtpbnN0YW5jZVsnSW5zdGFuY2UgdHlwZSddXSA9IHtcbiAgICAgICAgY29uc3VtcHRpb246IHtcbiAgICAgICAgICBpZGxlOiBwYXJzZUZsb2F0KGluc3RhbmNlWydJbnN0YW5jZSBAIElkbGUnXS5yZXBsYWNlKCcsJywgJy4nKSksXG4gICAgICAgICAgdGVuUGVyY2VudDogcGFyc2VGbG9hdChpbnN0YW5jZVsnSW5zdGFuY2UgQCAxMCUnXS5yZXBsYWNlKCcsJywgJy4nKSksXG4gICAgICAgICAgZmlmdHlQZXJjZW50OiBwYXJzZUZsb2F0KFxuICAgICAgICAgICAgaW5zdGFuY2VbJ0luc3RhbmNlIEAgNTAlJ10ucmVwbGFjZSgnLCcsICcuJylcbiAgICAgICAgICApLFxuICAgICAgICAgIGh1bmRyZWRQZXJjZW50OiBwYXJzZUZsb2F0KFxuICAgICAgICAgICAgaW5zdGFuY2VbJ0luc3RhbmNlIEAgMTAwJSddLnJlcGxhY2UoJywnLCAnLicpXG4gICAgICAgICAgKSxcbiAgICAgICAgICBtaW5XYXR0czogbWluV2F0dHMgKiBjcHVzLFxuICAgICAgICAgIG1heFdhdHRzOiBtYXhXYXR0cyAqIGNwdXMsXG4gICAgICAgIH0sXG4gICAgICAgIHZDUFVzOiBjcHVzLFxuICAgICAgICBtYXh2Q1BVczogcGFyc2VJbnQoaW5zdGFuY2VbJ1BsYXRmb3JtIFRvdGFsIE51bWJlciBvZiB2Q1BVJ10sIDEwKSxcbiAgICAgICAgbmFtZTogaW5zdGFuY2VbJ0luc3RhbmNlIHR5cGUnXSxcbiAgICAgIH0gYXMgSUNvbXB1dGVJbnN0YW5jZTtcbiAgICB9KTtcbiAgICBHQ1BfSU5TVEFOQ0VTLmZvckVhY2goKGluc3RhbmNlOiBLZXlWYWx1ZVBhaXIpID0+IHtcbiAgICAgIGNvbnN0IGNwdXMgPSBwYXJzZUludChpbnN0YW5jZVsnSW5zdGFuY2UgdkNQVXMnXSwgMTApO1xuICAgICAgbGV0IGFyY2hpdGVjdHVyZSA9IGluc3RhbmNlWydNaWNyb2FyY2hpdGVjdHVyZSddO1xuXG4gICAgICBpZiAoIShhcmNoaXRlY3R1cmUgaW4gdGhpcy5jb21wdXRlSW5zdGFuY2VVc2FnZUJ5QXJjaGl0ZWN0dXJlWydnY3AnXSkpIHtcbiAgICAgICAgYXJjaGl0ZWN0dXJlID0gJ0F2ZXJhZ2UnO1xuICAgICAgfVxuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydnY3AnXVtpbnN0YW5jZVsnTWFjaGluZSB0eXBlJ11dID0ge1xuICAgICAgICBuYW1lOiBpbnN0YW5jZVsnTWFjaGluZSB0eXBlJ10sXG4gICAgICAgIHZDUFVzOiBjcHVzLFxuICAgICAgICBjb25zdW1wdGlvbjoge1xuICAgICAgICAgIG1pbldhdHRzOlxuICAgICAgICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VVc2FnZUJ5QXJjaGl0ZWN0dXJlWydnY3AnXVthcmNoaXRlY3R1cmVdW1xuICAgICAgICAgICAgICAnTWluIFdhdHRzJ1xuICAgICAgICAgICAgXSAqIGNwdXMsXG4gICAgICAgICAgbWF4V2F0dHM6XG4gICAgICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZVVzYWdlQnlBcmNoaXRlY3R1cmVbJ2djcCddW2FyY2hpdGVjdHVyZV1bXG4gICAgICAgICAgICAgICdNYXggV2F0dHMnXG4gICAgICAgICAgICBdICogY3B1cyxcbiAgICAgICAgfSxcbiAgICAgICAgbWF4dkNQVXM6IHBhcnNlSW50KFxuICAgICAgICAgIGluc3RhbmNlWydQbGF0Zm9ybSB2Q1BVcyAoaGlnaGVzdCB2Q1BVIHBvc3NpYmxlKSddLFxuICAgICAgICAgIDEwXG4gICAgICAgICksXG4gICAgICB9IGFzIElDb21wdXRlSW5zdGFuY2U7XG4gICAgfSk7XG4gICAgQVpVUkVfSU5TVEFOQ0VTLmZvckVhY2goKGluc3RhbmNlOiBLZXlWYWx1ZVBhaXIpID0+IHtcbiAgICAgIGNvbnN0IGNwdXMgPSBwYXJzZUludChpbnN0YW5jZVsnSW5zdGFuY2UgdkNQVXMnXSwgMTApO1xuICAgICAgbGV0IGFyY2hpdGVjdHVyZSA9IGluc3RhbmNlWydNaWNyb2FyY2hpdGVjdHVyZSddO1xuICAgICAgaWYgKCEoYXJjaGl0ZWN0dXJlIGluIHRoaXMuY29tcHV0ZUluc3RhbmNlVXNhZ2VCeUFyY2hpdGVjdHVyZVsnYXp1cmUnXSkpIHtcbiAgICAgICAgYXJjaGl0ZWN0dXJlID0gJ0F2ZXJhZ2UnO1xuICAgICAgfVxuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydhenVyZSddW2luc3RhbmNlWydWaXJ0dWFsIE1hY2hpbmUnXV0gPSB7XG4gICAgICAgIGNvbnN1bXB0aW9uOiB7XG4gICAgICAgICAgbWluV2F0dHM6XG4gICAgICAgICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZVVzYWdlQnlBcmNoaXRlY3R1cmVbJ2F6dXJlJ11bYXJjaGl0ZWN0dXJlXVtcbiAgICAgICAgICAgICAgJ01pbiBXYXR0cydcbiAgICAgICAgICAgIF0gKiBjcHVzLFxuICAgICAgICAgIG1heFdhdHRzOlxuICAgICAgICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VVc2FnZUJ5QXJjaGl0ZWN0dXJlWydhenVyZSddW2FyY2hpdGVjdHVyZV1bXG4gICAgICAgICAgICAgICdNYXggV2F0dHMnXG4gICAgICAgICAgICBdICogY3B1cyxcbiAgICAgICAgfSxcbiAgICAgICAgbmFtZTogaW5zdGFuY2VbJ1ZpcnR1YWwgTWFjaGluZSddLFxuICAgICAgICB2Q1BVczogaW5zdGFuY2VbJ0luc3RhbmNlIHZDUFVzJ10sXG4gICAgICAgIG1heHZDUFVzOiBwYXJzZUludChcbiAgICAgICAgICBpbnN0YW5jZVsnUGxhdGZvcm0gdkNQVXMgKGhpZ2hlc3QgdkNQVSBwb3NzaWJsZSknXSxcbiAgICAgICAgICAxMFxuICAgICAgICApLFxuICAgICAgfSBhcyBJQ29tcHV0ZUluc3RhbmNlO1xuICAgIH0pO1xuICAgIEFXU19FTUJPRElFRC5mb3JFYWNoKChpbnN0YW5jZTogS2V5VmFsdWVQYWlyKSA9PiB7XG4gICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbJ2F3cyddW2luc3RhbmNlWyd0eXBlJ11dLmVtYm9kaWVkRW1pc3Npb24gPVxuICAgICAgICBpbnN0YW5jZVsndG90YWwnXTtcbiAgICB9KTtcbiAgICBHQ1BfRU1CT0RJRUQuZm9yRWFjaCgoaW5zdGFuY2U6IEtleVZhbHVlUGFpcikgPT4ge1xuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydnY3AnXVtpbnN0YW5jZVsndHlwZSddXS5lbWJvZGllZEVtaXNzaW9uID1cbiAgICAgICAgaW5zdGFuY2VbJ3RvdGFsJ107XG4gICAgfSk7XG4gICAgQVpVUkVfRU1CT0RJRUQuZm9yRWFjaCgoaW5zdGFuY2U6IEtleVZhbHVlUGFpcikgPT4ge1xuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzWydhenVyZSddW2luc3RhbmNlWyd0eXBlJ11dLmVtYm9kaWVkRW1pc3Npb24gPVxuICAgICAgICBpbnN0YW5jZVsndG90YWwnXTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlQXZlcmFnZSh2ZW5kb3I6IHN0cmluZywgaW5zdGFuY2VMaXN0OiBLZXlWYWx1ZVBhaXJbXSkge1xuICAgIGxldCBtaW4gPSAwLjA7XG4gICAgbGV0IG1heCA9IDAuMDtcbiAgICBsZXQgY291bnQgPSAwLjA7XG4gICAgaW5zdGFuY2VMaXN0LmZvckVhY2goKGluc3RhbmNlOiBLZXlWYWx1ZVBhaXIpID0+IHtcbiAgICAgIHRoaXMuY29tcHV0ZUluc3RhbmNlVXNhZ2VCeUFyY2hpdGVjdHVyZVt2ZW5kb3JdW1xuICAgICAgICBpbnN0YW5jZVsnQXJjaGl0ZWN0dXJlJ11cbiAgICAgIF0gPSBpbnN0YW5jZTtcbiAgICAgIG1pbiArPSBwYXJzZUZsb2F0KGluc3RhbmNlWydNaW4gV2F0dHMnXSk7XG4gICAgICBtYXggKz0gcGFyc2VGbG9hdChpbnN0YW5jZVsnTWF4IFdhdHRzJ10pO1xuICAgICAgY291bnQgKz0gMS4wO1xuICAgIH0pO1xuICAgIGNvbnN0IGF2Z01pbiA9IG1pbiAvIGNvdW50O1xuICAgIGNvbnN0IGF2Z01heCA9IG1heCAvIGNvdW50O1xuICAgIHRoaXMuY29tcHV0ZUluc3RhbmNlVXNhZ2VCeUFyY2hpdGVjdHVyZVt2ZW5kb3JdWydBdmVyYWdlJ10gPSB7XG4gICAgICAnTWluIFdhdHRzJzogYXZnTWluLFxuICAgICAgJ01heCBXYXR0cyc6IGF2Z01heCxcbiAgICAgIEFyY2hpdGVjdHVyZTogJ0F2ZXJhZ2UnLFxuICAgIH07XG4gIH1cblxuICAvLyBBcmNoaXRlY3R1cmUgc3RyaW5ncyBhcmUgZGlmZmVyZW50IGJldHdlZW4gSW5zdGFuY2VzLVVzZS5KU09OIGFuZCB0aGUgYnVuZGxlZCBUeXBlc2NyaXB0IGZyb20gQ0NGLlxuICAvLyBUaGlzIGZ1bmN0aW9uIHJlc29sdmVzIHRoZSBkaWZmZXJlbmNlcy5cbiAgcmVzb2x2ZUF3c0FyY2hpdGVjdHVyZShhcmNoaXRlY3R1cmU6IHN0cmluZykge1xuICAgIGlmIChhcmNoaXRlY3R1cmUuaW5jbHVkZXMoJ0FNRCAnKSkge1xuICAgICAgYXJjaGl0ZWN0dXJlID0gYXJjaGl0ZWN0dXJlLnN1YnN0cmluZyg0KTtcbiAgICB9XG5cbiAgICBpZiAoYXJjaGl0ZWN0dXJlLmluY2x1ZGVzKCdTa3lsYWtlJykpIHtcbiAgICAgIGFyY2hpdGVjdHVyZSA9ICdTa3kgTGFrZSc7XG4gICAgfVxuXG4gICAgaWYgKGFyY2hpdGVjdHVyZS5pbmNsdWRlcygnR3Jhdml0b24nKSkge1xuICAgICAgaWYgKGFyY2hpdGVjdHVyZS5pbmNsdWRlcygnMicpKSB7XG4gICAgICAgIGFyY2hpdGVjdHVyZSA9ICdHcmF2aXRvbjInO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXJjaGl0ZWN0dXJlID0gJ0dyYXZpdG9uJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoYXJjaGl0ZWN0dXJlLmluY2x1ZGVzKCdVbmtub3duJykpIHtcbiAgICAgIGFyY2hpdGVjdHVyZSA9ICdBdmVyYWdlJztcbiAgICB9XG5cbiAgICBpZiAoIShhcmNoaXRlY3R1cmUgaW4gdGhpcy5jb21wdXRlSW5zdGFuY2VVc2FnZUJ5QXJjaGl0ZWN0dXJlWydhd3MnXSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHthcmNoaXRlY3R1cmV9IG5vdCBzdXBwb3J0ZWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJjaGl0ZWN0dXJlO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZXMgdGhlIGVtYm9kaWVkIGVtaXNzaW9ucyBmb3IgYSBnaXZlbiBpbnB1dFxuICAgKi9cbiAgcHJpdmF0ZSBlbWJvZGllZEVtaXNzaW9ucyhpbnB1dDogS2V5VmFsdWVQYWlyKTogbnVtYmVyIHtcbiAgICAvLyBkdXJhdGlvblxuICAgIGNvbnN0IGR1cmF0aW9uSW5Ib3VycyA9IGlucHV0WydkdXJhdGlvbiddIC8gMzYwMDtcbiAgICAvLyBNID0gVEUgKiAoVFIvRUwpICogKFJSL1RSKVxuICAgIC8vIFdoZXJlOlxuICAgIC8vIFRFID0gVG90YWwgRW1ib2RpZWQgRW1pc3Npb25zLCB0aGUgc3VtIG9mIExpZmUgQ3ljbGUgQXNzZXNzbWVudChMQ0EpIGVtaXNzaW9ucyBmb3IgYWxsIGhhcmR3YXJlIGNvbXBvbmVudHNcbiAgICAvLyBUUiA9IFRpbWUgUmVzZXJ2ZWQsIHRoZSBsZW5ndGggb2YgdGltZSB0aGUgaGFyZHdhcmUgaXMgcmVzZXJ2ZWQgZm9yIHVzZSBieSB0aGUgc29mdHdhcmVcbiAgICAvLyBFTCA9IEV4cGVjdGVkIExpZmVzcGFuLCB0aGUgYW50aWNpcGF0ZWQgdGltZSB0aGF0IHRoZSBlcXVpcG1lbnQgd2lsbCBiZSBpbnN0YWxsZWRcbiAgICAvLyBSUiA9IFJlc291cmNlcyBSZXNlcnZlZCwgdGhlIG51bWJlciBvZiByZXNvdXJjZXMgcmVzZXJ2ZWQgZm9yIHVzZSBieSB0aGUgc29mdHdhcmUuXG4gICAgLy8gVFIgPSBUb3RhbCBSZXNvdXJjZXMsIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGF2YWlsYWJsZS5cbiAgICBjb25zdCB0b3RhbEVtaXNzaW9ucyA9XG4gICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbdGhpcy52ZW5kb3JdW3RoaXMuaW5zdGFuY2VUeXBlXS5lbWJvZGllZEVtaXNzaW9uID8/XG4gICAgICAwO1xuICAgIGNvbnN0IHRpbWVSZXNlcnZlZCA9IGR1cmF0aW9uSW5Ib3VycztcbiAgICBjb25zdCBleHBlY3RlZExpZmVzcGFuID0gODc2MCAqIHRoaXMuZXhwZWN0ZWRMaWZlc3BhbjtcbiAgICBjb25zdCByZXNlcnZlZFJlc291cmNlcyA9XG4gICAgICB0aGlzLmNvbXB1dGVJbnN0YW5jZXNbdGhpcy52ZW5kb3JdW3RoaXMuaW5zdGFuY2VUeXBlXS52Q1BVcyA/PyAxLjA7XG4gICAgY29uc3QgdG90YWxSZXNvdXJjZXMgPVxuICAgICAgdGhpcy5jb21wdXRlSW5zdGFuY2VzW3RoaXMudmVuZG9yXVt0aGlzLmluc3RhbmNlVHlwZV0ubWF4VkNQVXMgPz8gMS4wO1xuICAgIC8vIE11bHRpcGx5IHRvdGFsRW1pc3Npb25zIGJ5IDEwMDAgdG8gY29udmVydCBmcm9tIGtnQ08yZSB0byBnQ08yZVxuICAgIHJldHVybiAoXG4gICAgICB0b3RhbEVtaXNzaW9ucyAqXG4gICAgICAxMDAwICpcbiAgICAgICh0aW1lUmVzZXJ2ZWQgLyBleHBlY3RlZExpZmVzcGFuKSAqXG4gICAgICAocmVzZXJ2ZWRSZXNvdXJjZXMgLyB0b3RhbFJlc291cmNlcylcbiAgICApO1xuICB9XG59XG4iXX0=