@lhncbc/ucum-lhc 5.0.4 → 6.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 +15 -10
- package/browser-dist/ucum-lhc.js +326 -77
- package/data/ucumDefs.min.json +1 -1
- package/package.json +1 -1
- package/source/config.js +18 -0
- package/source/ucumLhcUtils.js +166 -83
- package/source/ucumXmlDocument.js +15 -1
- package/source/unit.js +140 -3
- package/source/unitString.js +11 -3
- package/source-cjs/config.js +12 -0
- package/source-cjs/config.js.map +1 -1
- package/source-cjs/ucumLhcUtils.js +155 -69
- package/source-cjs/ucumLhcUtils.js.map +1 -1
- package/source-cjs/ucumXmlDocument.js +15 -1
- package/source-cjs/ucumXmlDocument.js.map +1 -1
- package/source-cjs/unit.js +139 -3
- package/source-cjs/unit.js.map +1 -1
- package/source-cjs/unitString.js +12 -4
- package/source-cjs/unitString.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lhncbc/ucum-lhc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Implements Unified Code for Units of Measure (UCUM) functions in a javascript library",
|
|
5
5
|
"main": "source-cjs/ucumPkg.js",
|
|
6
6
|
"homepage": "https://lhncbc.github.io/ucum-lhc/",
|
package/source/config.js
CHANGED
|
@@ -90,6 +90,24 @@ export var Ucum = {
|
|
|
90
90
|
'molecular weight of the substance represented by the ' +
|
|
91
91
|
'units is required to perform the conversion.',
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Message that is returned when a mass<->eq conversion is requested
|
|
95
|
+
* (which requires a molecular weight to calculate), but no molecular
|
|
96
|
+
* weight was provided by the user.
|
|
97
|
+
*/
|
|
98
|
+
needEqWeightMsg_ : 'Did you wish to convert with equivalents? The ' +
|
|
99
|
+
'molecular weight of the substance is required to perform ' +
|
|
100
|
+
'the conversion.',
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Message that is returned when a mass<->eq or a mol<->eq conversion
|
|
104
|
+
* is requested (which requires a charge to calculate), but no charge
|
|
105
|
+
* was provided by the user.
|
|
106
|
+
*/
|
|
107
|
+
needEqChargeMsg_ : 'Did you wish to convert with equivalents? The ' +
|
|
108
|
+
'charge of the substance is required to perform ' +
|
|
109
|
+
'the conversion.',
|
|
110
|
+
|
|
93
111
|
/**
|
|
94
112
|
* Hash that matches unit column names to names used in the csv file
|
|
95
113
|
* that is submitted to the data updater.
|
package/source/ucumLhcUtils.js
CHANGED
|
@@ -145,71 +145,143 @@ export class UcumLhcUtils {
|
|
|
145
145
|
} // end validateUnitString
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @typedef {
|
|
151
|
+
* 'normal',
|
|
152
|
+
* 'mol->mass',
|
|
153
|
+
* 'mass->mol',
|
|
154
|
+
* 'eq->mass',
|
|
155
|
+
* 'mass->eq',
|
|
156
|
+
* 'eq->mol',
|
|
157
|
+
* 'mol->eq',
|
|
158
|
+
* } ConversionType
|
|
159
|
+
*/
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Detects the type of conversion between two units.
|
|
163
|
+
*
|
|
164
|
+
* @param {Object} fromUnit - The unit to convert from.
|
|
165
|
+
* @param {Object} toUnit - The unit to convert to.
|
|
166
|
+
* @returns {ConversionType} conversionType - The type of conversion as a string.
|
|
167
|
+
*/
|
|
168
|
+
detectConversionType(fromUnit, toUnit) {
|
|
169
|
+
/** @type {ConversionType} */
|
|
170
|
+
let conversionType = 'normal';
|
|
171
|
+
|
|
172
|
+
// detect mol <-> mass conversions and eq <-> eq conversions,
|
|
173
|
+
// and non-mol <-> eq <-> mass conversions
|
|
174
|
+
if ((fromUnit.isMolarUnit() && toUnit.isMolarUnit()) ||
|
|
175
|
+
(fromUnit.isEquivalentUnit() && toUnit.isEquivalentUnit()) ||
|
|
176
|
+
(!(fromUnit.isMolarUnit() || toUnit.isMolarUnit()) &&
|
|
177
|
+
!(fromUnit.isEquivalentUnit() || toUnit.isEquivalentUnit()))) {
|
|
178
|
+
conversionType = 'normal';
|
|
179
|
+
}
|
|
180
|
+
// handle eq <-> mol/mass conversions
|
|
181
|
+
else if (fromUnit.isEquivalentUnit()) {
|
|
182
|
+
conversionType = toUnit.isMolarUnit() ? 'eq->mol' : 'eq->mass';
|
|
183
|
+
} else if (toUnit.isEquivalentUnit()) {
|
|
184
|
+
conversionType = fromUnit.isMolarUnit() ? 'mol->eq' : 'mass->eq';
|
|
185
|
+
}
|
|
186
|
+
// handle mol <-> mass conversions
|
|
187
|
+
else if (fromUnit.isMolarUnit()) {
|
|
188
|
+
conversionType = 'mol->mass';
|
|
189
|
+
} else if (toUnit.isMolarUnit()) {
|
|
190
|
+
conversionType = 'mass->mol';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return conversionType;
|
|
194
|
+
} // end detectConversionType
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @typedef {{
|
|
198
|
+
* status: 'succeeded' | 'failed' | 'error',
|
|
199
|
+
* toVal: number | null,
|
|
200
|
+
* msg: string[],
|
|
201
|
+
* suggestions: {
|
|
202
|
+
* from: {
|
|
203
|
+
* msg: string,
|
|
204
|
+
* invalidUnit: string,
|
|
205
|
+
* units: string[]
|
|
206
|
+
* },
|
|
207
|
+
* to: {
|
|
208
|
+
* msg: string,
|
|
209
|
+
* invalidUnit: string,
|
|
210
|
+
* units: string[]
|
|
211
|
+
* }
|
|
212
|
+
* },
|
|
213
|
+
* fromUnit: string,
|
|
214
|
+
* toUnit: string
|
|
215
|
+
* }} ConvertUnitResult
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
|
|
148
219
|
/**
|
|
149
220
|
* This method converts one unit to another
|
|
150
221
|
*
|
|
151
|
-
* @param fromUnitCode the unit code/expression/string of the unit to be converted
|
|
152
|
-
* @param fromVal the number of "from" units to be converted to "to" units
|
|
153
|
-
* @param toUnitCode the unit code/expression/string of the unit that the from
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* ignored if neither unit includes a measurement in moles.
|
|
163
|
-
*
|
|
164
|
-
*
|
|
222
|
+
* @param {string} fromUnitCode - the unit code/expression/string of the unit to be converted
|
|
223
|
+
* @param {number | string} fromVal - the number of "from" units to be converted to "to" units
|
|
224
|
+
* @param {string} toUnitCode - the unit code/expression/string of the unit that the from field is to be converted to
|
|
225
|
+
* @param {{
|
|
226
|
+
* suggest?: boolean,
|
|
227
|
+
* molecularWeight?: number
|
|
228
|
+
* charge?: number
|
|
229
|
+
* }} options
|
|
230
|
+
* - suggest: a boolean to indicate whether or not suggestions are requested for a string that cannot be resolved to a valid unit;
|
|
231
|
+
* true indicates suggestions are wanted; false indicates they are not, and is the default if the parameter is not specified;
|
|
232
|
+
* - molecularWeight: the molecular weight of the substance in question when a conversion is being requested from mass to moles and vice versa.
|
|
233
|
+
* This is required when one of the units represents a value in moles. It is ignored if neither unit includes a measurement in moles.
|
|
234
|
+
* - charge: the absolute value of the charge of the substance in question when a conversion is being requested from mass/moles to
|
|
235
|
+
* equivalents and vice versa. It is required when one of the units represents a value in equivalents and the other in mass or moles.
|
|
236
|
+
* It is ignored if neither unit includes an equivalent unit.
|
|
237
|
+
* @returns {ConvertUnitResult}
|
|
238
|
+
* - a hash with six elements:
|
|
239
|
+
* - 'status' that will be: 'succeeded' if the conversion was successfully
|
|
165
240
|
* calculated; 'failed' if the conversion could not be made, e.g., if
|
|
166
241
|
* the units are not commensurable; or 'error' if an error occurred;
|
|
167
|
-
*
|
|
242
|
+
* - 'toVal' the numeric value indicating the conversion amount, or null
|
|
168
243
|
* if the conversion failed (e.g., if the units are not commensurable);
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
244
|
+
* - 'msg' is an array message, if the string is invalid or an error occurred,
|
|
245
|
+
* indicating the problem, or an explanation of a substitution such as
|
|
246
|
+
* the substitution of 'G' for 'Gauss', or an empty array if no
|
|
247
|
+
* messages were generated;
|
|
248
|
+
* - 'suggestions' if suggestions were requested and found, this is a hash
|
|
174
249
|
* that contains at most two elements:
|
|
175
|
-
* 'from' which, if the fromUnitCode input parameter or one or more of
|
|
250
|
+
* - 'from' which, if the fromUnitCode input parameter or one or more of
|
|
176
251
|
* its components could not be found, is an array one or more hash
|
|
177
252
|
* objects. Each hash contains three elements:
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
253
|
+
* - 'msg' which is a message indicating what unit expression the
|
|
254
|
+
* suggestions are for;
|
|
255
|
+
* - 'invalidUnit' which is the unit expression the suggestions
|
|
256
|
+
* are for; and
|
|
257
|
+
* - 'units' which is an array of data for each suggested unit found.
|
|
258
|
+
* Each array will contain the unit code, the unit name and the
|
|
259
|
+
* unit guidance (if any).
|
|
185
260
|
* If no suggestions were found for the fromUnitCode this element
|
|
186
261
|
* will not be included.
|
|
187
|
-
* 'to' which, if the "to" unit expression or one or more of its
|
|
262
|
+
* - 'to' which, if the "to" unit expression or one or more of its
|
|
188
263
|
* components could not be found, is an array one or more hash objects. Each hash
|
|
189
264
|
* contains three elements:
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
265
|
+
* - 'msg' which is a message indicating what toUnitCode input
|
|
266
|
+
* parameter the suggestions are for;
|
|
267
|
+
* - 'invalidUnit' which is the unit expression the suggestions
|
|
268
|
+
* are for; and
|
|
269
|
+
* - 'units' which is an array of data for each suggested unit found.
|
|
270
|
+
* Each array will contain the unit code, the unit name and the
|
|
271
|
+
* unit guidance (if any).
|
|
197
272
|
* If no suggestions were found for the toUnitCode this element
|
|
198
273
|
* will not be included.
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
274
|
+
* No 'suggestions' element will be included in the returned hash
|
|
275
|
+
* object if none were found, whether or not they were requested.
|
|
276
|
+
* - 'fromUnit' the unit object for the fromUnitCode passed in; returned
|
|
202
277
|
* in case it's needed for additional data from the object; and
|
|
203
|
-
*
|
|
278
|
+
* - 'toUnit' the unit object for the toUnitCode passed in; returned
|
|
204
279
|
* in case it's needed for additional data from the object.
|
|
205
280
|
*/
|
|
206
|
-
convertUnitTo(fromUnitCode, fromVal, toUnitCode,
|
|
207
|
-
|
|
208
|
-
suggest = false ;
|
|
209
|
-
|
|
210
|
-
if (molecularWeight === undefined)
|
|
211
|
-
molecularWeight = null ;
|
|
281
|
+
convertUnitTo(fromUnitCode, fromVal, toUnitCode, options = {}) {
|
|
282
|
+
let { suggest = false, molecularWeight = null, charge = null } = options;
|
|
212
283
|
|
|
284
|
+
/** @type {ConvertUnitResult} */
|
|
213
285
|
let returnObj = {'status' : 'failed',
|
|
214
286
|
'toVal' : null,
|
|
215
287
|
'msg' : []} ;
|
|
@@ -263,40 +335,53 @@ export class UcumLhcUtils {
|
|
|
263
335
|
|
|
264
336
|
if (fromUnit && toUnit) {
|
|
265
337
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
`converted to ${toUnitCode}.`));
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// if the "from" unit is a mole-based unit, assume a mole to mass
|
|
287
|
-
// request
|
|
288
|
-
if (fromUnit.moleExp_ !== 0) {
|
|
289
|
-
returnObj['toVal'] =
|
|
290
|
-
fromUnit.convertMolToMass(fromVal, toUnit, molecularWeight);
|
|
291
|
-
}
|
|
292
|
-
// else the "to" unit must be the mole-based unit, so assume a
|
|
293
|
-
// mass to mole request
|
|
294
|
-
else {
|
|
295
|
-
returnObj['toVal'] =
|
|
338
|
+
const convertType = this.detectConversionType(fromUnit, toUnit);
|
|
339
|
+
|
|
340
|
+
switch (convertType) {
|
|
341
|
+
case 'normal':
|
|
342
|
+
returnObj['toVal'] = toUnit.convertFrom(fromVal, fromUnit);
|
|
343
|
+
break;
|
|
344
|
+
case 'mol->mass':
|
|
345
|
+
case 'mass->mol':
|
|
346
|
+
if (!molecularWeight) {
|
|
347
|
+
throw new Error(Ucum.needMoleWeightMsg_);
|
|
348
|
+
}
|
|
349
|
+
if (!fromUnit.isMoleMassCommensurable(toUnit)) {
|
|
350
|
+
throw new Error(`Sorry. ${fromUnitCode} cannot be ` +
|
|
351
|
+
`converted to ${toUnitCode}.`);
|
|
352
|
+
}
|
|
353
|
+
returnObj['toVal'] = convertType === "mol->mass" ?
|
|
354
|
+
fromUnit.convertMolToMass(fromVal, toUnit, molecularWeight) :
|
|
296
355
|
fromUnit.convertMassToMol(fromVal, toUnit, molecularWeight);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
356
|
+
break;
|
|
357
|
+
case 'eq->mass':
|
|
358
|
+
case 'mass->eq':
|
|
359
|
+
if (!molecularWeight) {
|
|
360
|
+
throw new Error(Ucum.needEqWeightMsg_);
|
|
361
|
+
}
|
|
362
|
+
if (!charge) {
|
|
363
|
+
throw new Error(Ucum.needEqChargeMsg_);
|
|
364
|
+
}
|
|
365
|
+
if (!fromUnit.isEqMassCommensurable(toUnit)) {
|
|
366
|
+
throw new Error(`Sorry. ${fromUnitCode} cannot be ` +
|
|
367
|
+
`converted to ${toUnitCode}.`);
|
|
368
|
+
}
|
|
369
|
+
returnObj['toVal'] = convertType === "eq->mass" ?
|
|
370
|
+
fromUnit.convertEqToMass(fromVal, toUnit, molecularWeight, charge) :
|
|
371
|
+
fromUnit.convertMassToEq(fromVal, toUnit, molecularWeight, charge);
|
|
372
|
+
break;
|
|
373
|
+
case 'eq->mol':
|
|
374
|
+
case 'mol->eq':
|
|
375
|
+
if (!charge) {
|
|
376
|
+
throw new Error(Ucum.needEqChargeMsg_);
|
|
377
|
+
}
|
|
378
|
+
returnObj['toVal'] = convertType === "eq->mol" ?
|
|
379
|
+
fromUnit.convertEqToMol(fromVal, toUnit, charge) :
|
|
380
|
+
fromUnit.convertMolToEq(fromVal, toUnit, charge);
|
|
381
|
+
break;
|
|
382
|
+
default:
|
|
383
|
+
throw new Error("Unknown conversion type. No conversion was attempted.");
|
|
384
|
+
}
|
|
300
385
|
// if an error hasn't been thrown - either from convertFrom or here,
|
|
301
386
|
// set the return object to show success
|
|
302
387
|
returnObj['status'] = 'succeeded';
|
|
@@ -307,10 +392,8 @@ export class UcumLhcUtils {
|
|
|
307
392
|
returnObj['status'] = 'failed';
|
|
308
393
|
returnObj['msg'].push(err.message);
|
|
309
394
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
} // end if we have the from and to units
|
|
313
|
-
}
|
|
395
|
+
} // end if we have the from and to units
|
|
396
|
+
}
|
|
314
397
|
catch (err) {
|
|
315
398
|
if (err.message == Ucum.needMoleWeightMsg_)
|
|
316
399
|
returnObj['status'] = 'failed';
|
|
@@ -45,7 +45,11 @@ export class UcumXmlDocument {
|
|
|
45
45
|
// Creation of unit objects after this file is processed will pick up
|
|
46
46
|
// the moleExp_ value from the base mole unit, but the ones defined in
|
|
47
47
|
// this file will not necessarily do that.
|
|
48
|
-
this.moleCodes_ = ['mol', '
|
|
48
|
+
this.moleCodes_ = ['mol', 'osm', 'kat', 'U' ];
|
|
49
|
+
// Works similarly to the moleCodes_ array, but for units that represents
|
|
50
|
+
// equivalent units. For unit codes in the equivCodes_ array, an equivalentExp_
|
|
51
|
+
// attribute flag will be set to 1.
|
|
52
|
+
this.equivCodes_ = ['eq'];
|
|
49
53
|
|
|
50
54
|
// Make this a singleton. See UnitTables constructor for details.
|
|
51
55
|
|
|
@@ -231,10 +235,20 @@ export class UcumXmlDocument {
|
|
|
231
235
|
attrs['class_'] = curUA.attr.class;
|
|
232
236
|
}
|
|
233
237
|
let valNode = curUA.childNamed('value');
|
|
238
|
+
// Note: This currently works as a boolean flag,
|
|
239
|
+
// but it should be used to represent the dimensionality
|
|
240
|
+
// of the unit as an integer instead.
|
|
234
241
|
if (this.moleCodes_.indexOf(curUA.attr.Code) !== -1)
|
|
235
242
|
attrs['moleExp_'] = 1;
|
|
236
243
|
else
|
|
237
244
|
attrs['moleExp_'] = 0;
|
|
245
|
+
// Adds a flag similar to how moleExp_ works, but for units
|
|
246
|
+
// that are equivalent. Note that ideally this should also
|
|
247
|
+
// take values other than 1 or 0, but for now it is a boolean
|
|
248
|
+
// flag.
|
|
249
|
+
if (this.equivCodes_.indexOf(curUA.attr.Code) !== -1) {
|
|
250
|
+
attrs['equivalentExp_'] = 1;
|
|
251
|
+
}
|
|
238
252
|
|
|
239
253
|
|
|
240
254
|
// Process special units
|
package/source/unit.js
CHANGED
|
@@ -151,6 +151,11 @@ export class Unit {
|
|
|
151
151
|
*/
|
|
152
152
|
this.moleExp_ = attrs['moleExp_'] || 0;
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Flag indicating whether or not this is a equivalent mole unit
|
|
156
|
+
*/
|
|
157
|
+
this.equivalentExp_ = attrs['equivalentExp_'] || 0;
|
|
158
|
+
|
|
154
159
|
/*
|
|
155
160
|
* Added when added LOINC list of units
|
|
156
161
|
* synonyms are used by the autocompleter to enhance lookup capabilities
|
|
@@ -546,7 +551,7 @@ export class Unit {
|
|
|
546
551
|
// return the molAmt divided by the molesFactor as the number of moles
|
|
547
552
|
// for the molUnit
|
|
548
553
|
return molAmt/molesFactor ;
|
|
549
|
-
}
|
|
554
|
+
} // end convertMassToMol
|
|
550
555
|
|
|
551
556
|
/**
|
|
552
557
|
* Calculates the number of units that would result from converting a unit
|
|
@@ -559,7 +564,7 @@ export class Unit {
|
|
|
559
564
|
* @param amt the quantity of this unit to be converted
|
|
560
565
|
* @param massUnit the target/to unit for which the converted # is wanted
|
|
561
566
|
* @param molecularWeight the molecular weight of the substance for which the
|
|
562
|
-
*
|
|
567
|
+
* conversion is being made
|
|
563
568
|
* @return the equivalent amount in massUnit
|
|
564
569
|
*/
|
|
565
570
|
convertMolToMass(amt, massUnit, molecularWeight) {
|
|
@@ -581,9 +586,106 @@ export class Unit {
|
|
|
581
586
|
// divided by any effects of prefixes applied to the "to" unit, which
|
|
582
587
|
// is assumed to be some form of a gram unit
|
|
583
588
|
return massAmt / massUnit.magnitude_ ;
|
|
584
|
-
}
|
|
589
|
+
} // end convertMolToMass
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Converts equivalents to mass.
|
|
593
|
+
*
|
|
594
|
+
* @param {number} equivalents - The amount in equivalents to be converted.
|
|
595
|
+
* @param {object} targetUnit - The target/to unit for which the converted number is wanted.
|
|
596
|
+
* @param {number} molecularWeight - The molecular weight of the substance for which the conversion is being made.
|
|
597
|
+
* @param {number} charge - The absolute value of the charge of the substance for which the conversion is being made.
|
|
598
|
+
* @returns {number} - The equivalent mass in the specified mass unit.
|
|
599
|
+
*/
|
|
600
|
+
convertEqToMass(equivalents, targetUnit, molecularWeight, charge) {
|
|
601
|
+
let standardMoleUnit = this._getUnitTables().getUnitByCode('mol');
|
|
602
|
+
const molAmount = this.convertEqToMol(equivalents, standardMoleUnit, charge);
|
|
603
|
+
return this.convertMolToMass(molAmount, targetUnit, molecularWeight);
|
|
604
|
+
} // end convertEqToMass
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Converts mass to equivalents.
|
|
608
|
+
*
|
|
609
|
+
* @param {number} mass - The mass to be converted.
|
|
610
|
+
* @param {object} eqUnit - The target/to unit for which the converted number is wanted.
|
|
611
|
+
* @param {number} molecularWeight - The molecular weight of the substance for which the conversion is being made.
|
|
612
|
+
* @param {number} charge - The absolute value of the charge of the substance for which the conversion is being made.
|
|
613
|
+
* @returns {number} - The equivalent amount in the specified equivalent unit.
|
|
614
|
+
*/
|
|
615
|
+
convertMassToEq(mass, eqUnit, molecularWeight, charge) {
|
|
616
|
+
// Calculate equivalent mass by dividing molecular weight by charge
|
|
617
|
+
let equivalentMass = molecularWeight / charge;
|
|
618
|
+
// Calculate equivalents by dividing mass by equivalent mass
|
|
619
|
+
let equivalents = mass / equivalentMass;
|
|
620
|
+
// Get Avogadro's number from the unit tables
|
|
621
|
+
let avogadroNumber = this._getUnitTables().getUnitByCode('mol').magnitude_ ;
|
|
622
|
+
// Calculate mole factor by dividing the magnitude of the equivalent unit by Avogadro's number
|
|
623
|
+
// eqUnit may have a prefix (e.g. meq) and we need to adjust for that
|
|
624
|
+
let moleFactor = eqUnit.magnitude_ / avogadroNumber ;
|
|
625
|
+
// Adjust equivalents by dividing by the mole factor
|
|
626
|
+
let adjustedEquivalents = equivalents / moleFactor;
|
|
627
|
+
// Return the adjusted equivalents
|
|
628
|
+
return adjustedEquivalents;
|
|
629
|
+
} // end convertMassToEq
|
|
585
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Checks if the given unit is an equivalent unit.
|
|
633
|
+
*
|
|
634
|
+
* Note: equivalent units are also be molar units, so a unit can return true for
|
|
635
|
+
* both isEquivalentUnit and isMolarUnit.
|
|
636
|
+
*
|
|
637
|
+
* @returns {boolean} - Returns true if the unit is an equivalent unit, false otherwise.
|
|
638
|
+
*/
|
|
639
|
+
isEquivalentUnit() {
|
|
640
|
+
return this.equivalentExp_ !== 0;
|
|
641
|
+
} // end isEquivalentUnit
|
|
586
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Checks if the given unit is a molar unit.
|
|
645
|
+
*
|
|
646
|
+
* @returns {boolean} - Returns true if the unit is a molar unit, false otherwise.
|
|
647
|
+
*/
|
|
648
|
+
isMolarUnit() {
|
|
649
|
+
return this.moleExp_ !== 0;
|
|
650
|
+
} // end isMolarUnit
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* This function converts an equivalent amount to moles using the charge of the substance.
|
|
655
|
+
*
|
|
656
|
+
* @param {number} eqFromVal - The equivalent amount for which the conversion is being made.
|
|
657
|
+
* @param {object} molToUnit - The target unit for which the converted number is wanted.
|
|
658
|
+
* @param {number} charge - The absolute value of the charge of the substance for which the conversion is being made.
|
|
659
|
+
* @return {number} - The amount in moles.
|
|
660
|
+
*/
|
|
661
|
+
convertEqToMol(eqFromVal, molToUnit, charge){
|
|
662
|
+
// Check if molToUnit is a molar unit and eqFromVal is a eq unit
|
|
663
|
+
if (!molToUnit.isMolarUnit() || !this.isEquivalentUnit()){
|
|
664
|
+
throw new Error("Invalid units for conversion of Eq to Mol. Please provide an equivalent and a molar unit.");
|
|
665
|
+
}
|
|
666
|
+
// The conversion from equivalents to moles is based on the principle that one equivalent is equal to 1/valencyFactor moles.
|
|
667
|
+
// The relative magnitude is accounted for via the current unit's magnitude (this.magnitude_) and the target unit's magnitude (molToUnit.magnitude_)
|
|
668
|
+
return eqFromVal * (this.magnitude_ / molToUnit.magnitude_) / charge;
|
|
669
|
+
} // end convertEqToMol
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* This function converts moles to equivalent amount using the charge of the substance.
|
|
673
|
+
*
|
|
674
|
+
* @param {number} molFromVal - The mole amount for which the conversion is being made
|
|
675
|
+
* @param {object} eqToUnit - The target unit for which the converted number is wanted
|
|
676
|
+
* @param {number} charge - The absolute value of the charge of the substance for which the conversion is being made
|
|
677
|
+
* @return {number} - The amount in equivalent
|
|
678
|
+
*/
|
|
679
|
+
convertMolToEq(molFromVal, eqToUnit, charge){
|
|
680
|
+
// Check if eqToUnit is an equivalent unit and molFromVal is a molar unit
|
|
681
|
+
if (!eqToUnit.isEquivalentUnit() || !this.isMolarUnit()){
|
|
682
|
+
throw new Error("Invalid units for conversion of Mol to Eq. Please provide a molar and an equivalent unit.");
|
|
683
|
+
}
|
|
684
|
+
// The conversion from moles to equivalents is based on the principle that one equivalent is equal to 1/valencyFactor moles.
|
|
685
|
+
// The relative magnitude is accounted for via the current unit's magnitude (this.magnitude_) and the target unit's magnitude (eqToUnit.magnitude_)
|
|
686
|
+
return molFromVal * charge * (this.magnitude_ / eqToUnit.magnitude_);
|
|
687
|
+
} // end convertMolToEq
|
|
688
|
+
|
|
587
689
|
/**
|
|
588
690
|
* Mutates this unit into a unit on a ratio scale and converts a specified
|
|
589
691
|
* number of units to an appropriate value for this converted unit
|
|
@@ -1016,6 +1118,41 @@ export class Unit {
|
|
|
1016
1118
|
return commensurable ;
|
|
1017
1119
|
}
|
|
1018
1120
|
|
|
1121
|
+
/**
|
|
1122
|
+
* This function tests this unit against the unit passed in to see if the
|
|
1123
|
+
* two are eq to mass commensurable. It assumes that one of the units
|
|
1124
|
+
* is a eq-based unit and the other is a mass-based unit. It also assumes
|
|
1125
|
+
* that the eq-based unit has a single eq unit in the numerator and that
|
|
1126
|
+
* the mass-based unit has a single mass unit in the numerator. It does NOT
|
|
1127
|
+
* check to validate those assumptions.
|
|
1128
|
+
*
|
|
1129
|
+
* The check is made by setting the dimension vector element corresponding
|
|
1130
|
+
* to the base mass unit (gram) in the eq unit, and then comparing the
|
|
1131
|
+
* two dimension vectors. If they match, the units are commensurable.
|
|
1132
|
+
* Otherwise they are not.
|
|
1133
|
+
*
|
|
1134
|
+
* @param {Unit} unit2 the unit to be compared to this one
|
|
1135
|
+
* @returns {boolean} boolean indicating commensurability
|
|
1136
|
+
*/
|
|
1137
|
+
isEqMassCommensurable(unit2) {
|
|
1138
|
+
let tabs = this._getUnitTables();
|
|
1139
|
+
let d = tabs.getMassDimensionIndex();
|
|
1140
|
+
let commensurable = false ;
|
|
1141
|
+
if (this.equivalentExp_ === 1 && unit2.equivalentExp_ === 0) {
|
|
1142
|
+
let testDim = this.dim_.clone();
|
|
1143
|
+
let curVal = testDim.getElementAt(d);
|
|
1144
|
+
testDim.setElementAt(d, (curVal + this.equivalentExp_));
|
|
1145
|
+
commensurable = (testDim.equals(unit2.dim_));
|
|
1146
|
+
}
|
|
1147
|
+
else if (unit2.equivalentExp_ === 1 && this.equivalentExp_ === 0) {
|
|
1148
|
+
let testDim = unit2.dim_.clone();
|
|
1149
|
+
let curVal = testDim.getElementAt(d);
|
|
1150
|
+
testDim.setElementAt(d, (curVal + unit2.equivalentExp_));
|
|
1151
|
+
commensurable = (testDim.equals(this.dim_));
|
|
1152
|
+
}
|
|
1153
|
+
return commensurable;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1019
1156
|
|
|
1020
1157
|
/**
|
|
1021
1158
|
* This returns the UnitTables singleton object. Including the require
|
package/source/unitString.js
CHANGED
|
@@ -1153,10 +1153,17 @@ export class UnitString {
|
|
|
1153
1153
|
// Look first for an exponent. If we got one, separate it out and
|
|
1154
1154
|
// try to get the unit again
|
|
1155
1155
|
let codeAndExp = this._isCodeWithExponent(uCode);
|
|
1156
|
+
let isIntegerUnitWithExp = false;
|
|
1156
1157
|
if (codeAndExp) {
|
|
1157
1158
|
uCode = codeAndExp[0];
|
|
1158
1159
|
exp = codeAndExp[1];
|
|
1159
|
-
|
|
1160
|
+
isIntegerUnitWithExp = intUtils_.isIntegerUnit(uCode);
|
|
1161
|
+
origUnit = isIntegerUnitWithExp ?
|
|
1162
|
+
new Unit({'csCode_' : uCode,
|
|
1163
|
+
'ciCode_' : uCode,
|
|
1164
|
+
'magnitude_' : Number(uCode),
|
|
1165
|
+
'name_' : uCode}) :
|
|
1166
|
+
this.utabs_.getUnitByCode(uCode);
|
|
1160
1167
|
}
|
|
1161
1168
|
|
|
1162
1169
|
// If an exponent is found but it's not a valid number, e.g. "2-1",
|
|
@@ -1294,10 +1301,11 @@ export class UnitString {
|
|
|
1294
1301
|
}
|
|
1295
1302
|
if (exp) {
|
|
1296
1303
|
let expStr = exp.toString();
|
|
1304
|
+
const intergerUnitExpSign = isIntegerUnitWithExp && exp > 0 ? '+' : '';
|
|
1297
1305
|
retUnit.assignVals({
|
|
1298
1306
|
'name_': theName + '<sup>' + expStr + '</sup>',
|
|
1299
|
-
'csCode_': theCode + expStr,
|
|
1300
|
-
'ciCode_': theCiCode + expStr,
|
|
1307
|
+
'csCode_': theCode + intergerUnitExpSign + expStr,
|
|
1308
|
+
'ciCode_': theCiCode + intergerUnitExpSign + expStr,
|
|
1301
1309
|
'printSymbol_': thePrintSymbol + '<sup>' + expStr + '</sup>'
|
|
1302
1310
|
});
|
|
1303
1311
|
}
|
package/source-cjs/config.js
CHANGED
|
@@ -78,6 +78,18 @@ var Ucum = {
|
|
|
78
78
|
* but no molecular weight was specified.
|
|
79
79
|
*/
|
|
80
80
|
needMoleWeightMsg_: 'Did you wish to convert between mass and moles? The ' + 'molecular weight of the substance represented by the ' + 'units is required to perform the conversion.',
|
|
81
|
+
/**
|
|
82
|
+
* Message that is returned when a mass<->eq conversion is requested
|
|
83
|
+
* (which requires a molecular weight to calculate), but no molecular
|
|
84
|
+
* weight was provided by the user.
|
|
85
|
+
*/
|
|
86
|
+
needEqWeightMsg_: 'Did you wish to convert with equivalents? The ' + 'molecular weight of the substance is required to perform ' + 'the conversion.',
|
|
87
|
+
/**
|
|
88
|
+
* Message that is returned when a mass<->eq or a mol<->eq conversion
|
|
89
|
+
* is requested (which requires a charge to calculate), but no charge
|
|
90
|
+
* was provided by the user.
|
|
91
|
+
*/
|
|
92
|
+
needEqChargeMsg_: 'Did you wish to convert with equivalents? The ' + 'charge of the substance is required to perform ' + 'the conversion.',
|
|
81
93
|
/**
|
|
82
94
|
* Hash that matches unit column names to names used in the csv file
|
|
83
95
|
* that is submitted to the data updater.
|
package/source-cjs/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":["Ucum","dimLen_","validOps_","codeSep_","valMsgStart_","valMsgEnd_","cnvMsgStart_","cnvMsgEnd_","openEmph_","closeEmph_","openEmphHTML_","closeEmphHTML_","bracesMsg_","needMoleWeightMsg_","csvCols_","inputKey_","specUnits_","exports"],"sources":["../source/config.js"],"sourcesContent":["/*\n * This defines the namespace for the UCUM classes and provides\n * a place for the definition of global variables and constants.\n *\n * The javascript for this UCUM implementation uses syntax as\n * defined by the ECMAScript 6 standard\n */\n\nexport var Ucum = {\n\n /**\n * Flag indicating whether or not we're using case sensitive labels\n * I don't think we need this. I think we're just going with\n * case sensitive, per Clem. Gunther's code has this flag, but I\n * am removing it, at least for now. lm, 6/2016\n */\n //caseSensitive_: true ,\n\n /**\n * The number of elements in a Dimension array. Currently this\n * is set as a configuration variable, but when we get to the point\n * of loading the unit definitions from a file, this value will be\n * set from that.\n */\n dimLen_: 7,\n\n\n /**\n * The characters used as valid operators in a UCUM unit expression,\n * where '.' is for multiplication and '/' is for division.\n */\n validOps_: ['.', '/'],\n\n\n /**\n * The string used to separate a unit code and unit name when they\n * are displayed together\n */\n codeSep_ : ': ',\n\n // Message text variations for validation methods and conversion methods\n valMsgStart_ : 'Did you mean ',\n valMsgEnd_ : '?' ,\n cnvMsgStart_ : 'We assumed you meant ',\n cnvMsgEnd_ : '.',\n\n\n/**\n * Default opening string used to emphasize portions of error messages.\n * Used when NOT displaying messages on a web site, i.e., for output\n * from the library methods or to a file.\n */\n openEmph_ : ' ->',\n\n /**\n * Default closing string used to emphasize portions of error messages.\n * Used when NOT displaying messages on a web site, i.e., for output\n * from the library methods or to a file.\n */\n closeEmph_ : '<- ' ,\n\n /**\n * Opening HTML used to emphasize portions of error messages. Used when\n * displaying messages on a web site; should be blank when output is\n * to a file.\n */\n openEmphHTML_ : ' <span class=\"emphSpan\">',\n\n /**\n * Closing HTML used to emphasize portions of error messages. Used when\n * displaying messages on a web site; should be blank when output is\n * to a file.\n */\n closeEmphHTML_ : '</span> ' ,\n\n /**\n * Message that is displayed when annotations are included in a unit\n * string, to let the user know how they are interpreted.\n */\n bracesMsg_ : 'FYI - annotations (text in curly braces {}) are ignored, ' +\n 'except that an annotation without a leading symbol implies ' +\n 'the default unit 1 (the unity).',\n\n /**\n * Message that is displayed or returned when a conversion is requested\n * for two units where (only) a mass<->moles conversion is appropriate\n * but no molecular weight was specified.\n */\n needMoleWeightMsg_ : 'Did you wish to convert between mass and moles? The ' +\n 'molecular weight of the substance represented by the ' +\n 'units is required to perform the conversion.',\n\n /**\n * Hash that matches unit column names to names used in the csv file\n * that is submitted to the data updater.\n */\n csvCols_ : {\n 'case-sensitive code' : 'csCode_',\n 'LOINC property' : 'loincProperty_',\n 'name (display)' : 'name_',\n 'synonyms' : 'synonyms_',\n 'source' : 'source_',\n 'category' : 'category_',\n 'Guidance' : 'guidance_'\n } ,\n\n /**\n * Name of the column in the csv file that serves as the key\n */\n inputKey_ : 'case-sensitive code' ,\n\n /**\n * Special codes that contain operators within brackets. The operator\n * within these codes causes them to parse incorrectly if they are preceded\n * by a prefix, because the parsing algorithm splits them up on the operator.\n * So we use this object to identify them and substitute placeholders to\n * avoid that.\n */\n specUnits_ : { 'B[10.nV]' : 'specialUnitOne',\n '[m/s2/Hz^(1/2)]' : 'specialUnitTwo'}\n} ;\n\n\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,IAAIA,IAAI,GAAG;EAEhB;AACF;AACA;AACA;AACA;AACA;EACE;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEC,OAAO,EAAE,CAAC;EAGV;AACF;AACA;AACA;EACEC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;EAGrB;AACF;AACA;AACA;EACEC,QAAQ,EAAG,IAAI;EAEf;EACAC,YAAY,EAAG,eAAe;EAC9BC,UAAU,EAAG,GAAG;EAChBC,YAAY,EAAG,uBAAuB;EACtCC,UAAU,EAAG,GAAG;EAGlB;AACA;AACA;AACA;AACA;EACEC,SAAS,EAAG,KAAK;EAEjB;AACF;AACA;AACA;AACA;EACEC,UAAU,EAAG,KAAK;EAElB;AACF;AACA;AACA;AACA;EACEC,aAAa,EAAG,0BAA0B;EAE1C;AACF;AACA;AACA;AACA;EACEC,cAAc,EAAG,UAAU;EAE3B;AACF;AACA;AACA;EACEC,UAAU,EAAG,2DAA2D,GAC3D,6DAA6D,GAC7D,iCAAiC;EAE9C;AACF;AACA;AACA;AACA;EACEC,kBAAkB,EAAG,uDAAuD,GACvD,uDAAuD,GACvD,8CAA8C;EAEnE;AACF;AACA;AACA;EACEC,QAAQ,EAAG;IACT,qBAAqB,EAAG,SAAS;IACjC,gBAAgB,EAAG,gBAAgB;IACnC,gBAAgB,EAAG,OAAO;IAC1B,UAAU,EAAG,WAAW;IACxB,QAAQ,EAAG,SAAS;IACpB,UAAU,EAAG,WAAW;IACxB,UAAU,EAAG;EACf,CAAC;EAED;AACF;AACA;EACEC,SAAS,EAAG,qBAAqB;EAEjC;AACF;AACA;AACA;AACA;AACA;AACA;EACGC,UAAU,EAAG;IAAE,UAAU,EAAG,gBAAgB;IAC7B,iBAAiB,EAAG;EAAgB;AACtD,CAAC;AAAEC,OAAA,
|
|
1
|
+
{"version":3,"file":"config.js","names":["Ucum","dimLen_","validOps_","codeSep_","valMsgStart_","valMsgEnd_","cnvMsgStart_","cnvMsgEnd_","openEmph_","closeEmph_","openEmphHTML_","closeEmphHTML_","bracesMsg_","needMoleWeightMsg_","needEqWeightMsg_","needEqChargeMsg_","csvCols_","inputKey_","specUnits_","exports"],"sources":["../source/config.js"],"sourcesContent":["/*\n * This defines the namespace for the UCUM classes and provides\n * a place for the definition of global variables and constants.\n *\n * The javascript for this UCUM implementation uses syntax as\n * defined by the ECMAScript 6 standard\n */\n\nexport var Ucum = {\n\n /**\n * Flag indicating whether or not we're using case sensitive labels\n * I don't think we need this. I think we're just going with\n * case sensitive, per Clem. Gunther's code has this flag, but I\n * am removing it, at least for now. lm, 6/2016\n */\n //caseSensitive_: true ,\n\n /**\n * The number of elements in a Dimension array. Currently this\n * is set as a configuration variable, but when we get to the point\n * of loading the unit definitions from a file, this value will be\n * set from that.\n */\n dimLen_: 7,\n\n\n /**\n * The characters used as valid operators in a UCUM unit expression,\n * where '.' is for multiplication and '/' is for division.\n */\n validOps_: ['.', '/'],\n\n\n /**\n * The string used to separate a unit code and unit name when they\n * are displayed together\n */\n codeSep_ : ': ',\n\n // Message text variations for validation methods and conversion methods\n valMsgStart_ : 'Did you mean ',\n valMsgEnd_ : '?' ,\n cnvMsgStart_ : 'We assumed you meant ',\n cnvMsgEnd_ : '.',\n\n\n/**\n * Default opening string used to emphasize portions of error messages.\n * Used when NOT displaying messages on a web site, i.e., for output\n * from the library methods or to a file.\n */\n openEmph_ : ' ->',\n\n /**\n * Default closing string used to emphasize portions of error messages.\n * Used when NOT displaying messages on a web site, i.e., for output\n * from the library methods or to a file.\n */\n closeEmph_ : '<- ' ,\n\n /**\n * Opening HTML used to emphasize portions of error messages. Used when\n * displaying messages on a web site; should be blank when output is\n * to a file.\n */\n openEmphHTML_ : ' <span class=\"emphSpan\">',\n\n /**\n * Closing HTML used to emphasize portions of error messages. Used when\n * displaying messages on a web site; should be blank when output is\n * to a file.\n */\n closeEmphHTML_ : '</span> ' ,\n\n /**\n * Message that is displayed when annotations are included in a unit\n * string, to let the user know how they are interpreted.\n */\n bracesMsg_ : 'FYI - annotations (text in curly braces {}) are ignored, ' +\n 'except that an annotation without a leading symbol implies ' +\n 'the default unit 1 (the unity).',\n\n /**\n * Message that is displayed or returned when a conversion is requested\n * for two units where (only) a mass<->moles conversion is appropriate\n * but no molecular weight was specified.\n */\n needMoleWeightMsg_ : 'Did you wish to convert between mass and moles? The ' +\n 'molecular weight of the substance represented by the ' +\n 'units is required to perform the conversion.',\n\n /**\n * Message that is returned when a mass<->eq conversion is requested \n * (which requires a molecular weight to calculate), but no molecular \n * weight was provided by the user.\n */ \n needEqWeightMsg_ : 'Did you wish to convert with equivalents? The ' +\n 'molecular weight of the substance is required to perform ' + \n 'the conversion.', \n\n /**\n * Message that is returned when a mass<->eq or a mol<->eq conversion \n * is requested (which requires a charge to calculate), but no charge\n * was provided by the user.\n */\n needEqChargeMsg_ : 'Did you wish to convert with equivalents? The ' +\n 'charge of the substance is required to perform ' + \n 'the conversion.', \n\n /**\n * Hash that matches unit column names to names used in the csv file\n * that is submitted to the data updater.\n */\n csvCols_ : {\n 'case-sensitive code' : 'csCode_',\n 'LOINC property' : 'loincProperty_',\n 'name (display)' : 'name_',\n 'synonyms' : 'synonyms_',\n 'source' : 'source_',\n 'category' : 'category_',\n 'Guidance' : 'guidance_'\n } ,\n\n /**\n * Name of the column in the csv file that serves as the key\n */\n inputKey_ : 'case-sensitive code' ,\n\n /**\n * Special codes that contain operators within brackets. The operator\n * within these codes causes them to parse incorrectly if they are preceded\n * by a prefix, because the parsing algorithm splits them up on the operator.\n * So we use this object to identify them and substitute placeholders to\n * avoid that.\n */\n specUnits_ : { 'B[10.nV]' : 'specialUnitOne',\n '[m/s2/Hz^(1/2)]' : 'specialUnitTwo'}\n} ;\n\n\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,IAAIA,IAAI,GAAG;EAEhB;AACF;AACA;AACA;AACA;AACA;EACE;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEC,OAAO,EAAE,CAAC;EAGV;AACF;AACA;AACA;EACEC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;EAGrB;AACF;AACA;AACA;EACEC,QAAQ,EAAG,IAAI;EAEf;EACAC,YAAY,EAAG,eAAe;EAC9BC,UAAU,EAAG,GAAG;EAChBC,YAAY,EAAG,uBAAuB;EACtCC,UAAU,EAAG,GAAG;EAGlB;AACA;AACA;AACA;AACA;EACEC,SAAS,EAAG,KAAK;EAEjB;AACF;AACA;AACA;AACA;EACEC,UAAU,EAAG,KAAK;EAElB;AACF;AACA;AACA;AACA;EACEC,aAAa,EAAG,0BAA0B;EAE1C;AACF;AACA;AACA;AACA;EACEC,cAAc,EAAG,UAAU;EAE3B;AACF;AACA;AACA;EACEC,UAAU,EAAG,2DAA2D,GAC3D,6DAA6D,GAC7D,iCAAiC;EAE9C;AACF;AACA;AACA;AACA;EACEC,kBAAkB,EAAG,uDAAuD,GACvD,uDAAuD,GACvD,8CAA8C;EAEnE;AACF;AACA;AACA;AACA;EACEC,gBAAgB,EAAG,iDAAiD,GAChD,2DAA2D,GAC3D,iBAAiB;EAErC;AACF;AACA;AACA;AACA;EACEC,gBAAgB,EAAG,iDAAiD,GAChD,iDAAiD,GACjD,iBAAiB;EAErC;AACF;AACA;AACA;EACEC,QAAQ,EAAG;IACT,qBAAqB,EAAG,SAAS;IACjC,gBAAgB,EAAG,gBAAgB;IACnC,gBAAgB,EAAG,OAAO;IAC1B,UAAU,EAAG,WAAW;IACxB,QAAQ,EAAG,SAAS;IACpB,UAAU,EAAG,WAAW;IACxB,UAAU,EAAG;EACf,CAAC;EAED;AACF;AACA;EACEC,SAAS,EAAG,qBAAqB;EAEjC;AACF;AACA;AACA;AACA;AACA;AACA;EACGC,UAAU,EAAG;IAAE,UAAU,EAAG,gBAAgB;IAC7B,iBAAiB,EAAG;EAAgB;AACtD,CAAC;AAAEC,OAAA,CAAAnB,IAAA,GAAAA,IAAA"}
|