diff --git a/.gitignore b/.gitignore
index 2ccbe46..24ab254 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
/node_modules/
+.project
+.idea
+.vscode
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index 5c95938..0000000
--- a/.project
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- node-exif
-
-
-
-
-
- com.eclipsesource.jshint.ui.builder
-
-
-
-
-
- org.nodeclipse.ui.NodeNature
- org.eclipse.wst.jsdt.core.jsNature
- tern.eclipse.ide.core.ternnature
-
-
diff --git a/README.md b/README.md
index b4e868a..a7c1f44 100644
--- a/README.md
+++ b/README.md
@@ -29,15 +29,11 @@ If you don't have npm installed or don't want to use it:
Easy. Just require _node-exif_ and throw an image at it. If _node-exif_ is able to extract data from the image it does so and returns an object with all the information found, if an error occurs you will receive an error message. To prove that it really is easy please see the following example.
```javascript
-var ExifImage = require('exif').ExifImage;
+import ExifImage from 'exif'
try {
- new ExifImage({ image : 'myImage.jpg' }, function (error, exifData) {
- if (error)
- console.log('Error: '+error.message);
- else
- console.log(exifData); // Do something with your data!
- });
+ const exifData = await ExifImage({ image : 'myImage.jpg' })
+ console.log(exifData); // Do something with your data!
} catch (error) {
console.log('Error: ' + error.message);
}
diff --git a/index.js b/index.js
deleted file mode 100644
index bde72eb..0000000
--- a/index.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = require('./lib/exif');
\ No newline at end of file
diff --git a/lib/exif/ExifImage.js b/lib/exif/ExifImage.js
deleted file mode 100644
index 247953b..0000000
--- a/lib/exif/ExifImage.js
+++ /dev/null
@@ -1,1068 +0,0 @@
-/*jslint node: true */
-"use strict";
-
-var assert = require('assert');
-var fs = require('fs');
-var util = require('util');
-var BufferExtender = require('./Buffer'); // bad idea
-var debug = require('debug')('exif');
-
-var DEFAULT_MAX_ENTRIES=128;
-
-/**
- * Represents an image with Exif information. When instantiating it you have to
- * provide an image and a callback function which is called once all metadata
- * is extracted from the image.
- *
- * Available options are:
- * - image The image to get Exif data from can be either a filesystem path or
- * a Buffer.
- * - tiffOffsets (boolean) an object named "offsets" is added to exifData
- * and contains lot of offsets needed to get thumbnail and other things.
- * - fixThumbnailOffset: node-exif corrects the thumbnail offset in order to have an offset from the start of the buffer/file.
- * - maxEntries: Specifies the maximum entries to be parsed
- * - ifd0MaxEntries
- * - ifd1MaxEntries
- * - maxGpsEntries
- * - maxInteroperabilityEntries
- * - agfaMaxEntries
- * - epsonMaxEntries
- * - fujifilmMaxEntries
- * - olympusMaxEntries
- * - panasonicMaxEntries
- * - sanyoMaxEntries
- * - noPadding
- *
- * If you don't set the image field, you might call exifImage.loadImage(image, callback) to get exif datas.
- *
- * @param options Configuration options as described above
- * @param callback Function to call when data is extracted or an error occurred
- * @return Nothing of importance, calls the specified callback function instead
- */
-function ExifImage (options, callback) {
- if (!(this instanceof ExifImage)) {
- if (typeof(options)==="string") {
- options = {
- image: options
- }
- }
-
- assert(typeof(options)==="object", "Invalid options object");
-
- var exifImage = new ExifImage(options, function(error, data) {
- if (error) {
- return callback(error);
- }
-
- callback(null, data, options.image);
- });
-
- return exifImage;
- }
-
- if (typeof(options)==="string") {
- options= {
- image: options
- }
- } else if (options instanceof Buffer) {
- options= {
- image: options
- }
- }
-
- var ops={};
- if (options) {
- for(var k in options) {
- ops[k]=options[k];
- }
- }
- this.options=ops;
-
- // Default option values
- ["ifd0MaxEntries", "ifd1MaxEntries", "maxGpsEntries", "maxInteroperabilityEntries", "agfaMaxEntries", "epsonMaxEntries",
- "fujifilmMaxEntries", "olympusMaxEntries", "panasonicMaxEntries", "sanyoMaxEntries"].forEach(function(p) {
- if (ops[p]===undefined) {
- ops[p]=DEFAULT_MAX_ENTRIES;
- }
- });
-
- this.exifData = {
- image : {}, // Information about the main image
- thumbnail : {}, // Information about the thumbnail
- exif : {}, // Exif information
- gps : {}, // GPS information
- interoperability: {}, // Exif Interoperability information
- makernote : {} // Makernote information
- };
-
- this.offsets={};
- if (ops.tiffOffsets) {
- exifData.offsets=offsets;
- }
-
- debug("New ExifImage options=",options);
-
- if (!ops.image) {
- // If options image is not specified, the developper must call loadImage() to parse the image.
-// callback(new Error('You have to provide an image, it is pretty hard to extract Exif data from nothing...'));
- return;
- }
-
- if (typeof callback !== 'function') {
- throw new Error('You have to provide a callback function.');
- }
-
- var self=this;
- setImmediate(function() {
- self.loadImage(ops.image, function (error, exifData) {
- if (error) {
- return callback(error);
- }
-
- callback(null, exifData, ops.image);
- });
- });
-}
-
-ExifImage.ExifImage=ExifImage;
-
-module.exports = ExifImage;
-
-/**
- * Load image and parse exifDatas
- *
- * @param [String|Buffer] image the image
- * @param callback a callback which is called when exif datas are parsed.
- * @return Nothing
- */
-ExifImage.prototype.loadImage = function (image, callback) {
- assert(typeof(callback)==="function", "Callback must be a function");
-
- var self = this;
-
- debug("loadImage image=", image);
-
- if (image.constructor.name === 'Buffer') {
- this.processImage("Buffer", image, callback);
- return;
- }
-
- if (image.constructor.name === 'String') {
- fs.readFile(image, function (error, data) {
- if (error) {
- callback(new Error('Encountered the following error while trying to read given image: '+error));
- return;
- }
-
- self.processImage("File: "+image, data, callback);
- });
- return;
- }
-
- callback(new Error('Given image is neither a buffer nor a file, please provide one of these.'));
-};
-
-ExifImage.prototype.processImage = function (source, data, callback) {
- assert(typeof(source)==="string", "Source must be a string");
- assert(typeof(callback)==="function", "Callback must be a function");
-
- var offset = 0;
-
- if (data[offset++] != 0xFF || data[offset++] != 0xD8) {
- var e=new Error('The given image is not a JPEG and thus unsupported right now.');
- e.source=source;
- e.code="NOT_A_JPEG";
- callback(e);
- return;
- }
-
- this.imageType = 'JPEG';
-
- while (offset < data.length) {
-
- if (data[offset++] != 0xFF) {
- break;
- }
-
- if (data[offset++] == 0xE1) {
- try {
- this.extractExifData(data, offset + 2, data.getShort(offset, true) - 2);
-
- } catch (error) {
- error.code="PARSING_ERROR";
- error.source=source;
-
- debug("Extract exif data error source=", source, "offset=", offset, "error=",error);
-
- callback(error);
- return;
- }
-
- debug("Extract exif data success source=", source, "exifData=",this.exifData);
-
- callback(null, this.exifData);
- return;
- }
-
- offset += data.getShort(offset, true);
- }
-
- var e2=new Error('No Exif segment found in the given image.');
- e2.source=source;
- e2.code="NO_EXIF_SEGMENT";
-
- callback(e2);
-};
-
-ExifImage.prototype.extractExifData = function (data, start, length) {
-
- var exifData=this.exifData;
- var tiffOffset = start + 6;
- var ifdOffset, numberOfEntries;
- var noPadding = (this.options.noPadding!==false);
-
- this.offsets.tiff=tiffOffset;
-
- // Exif data always starts with Exif\0\0
- if (data.toString('utf8', start, tiffOffset) != 'Exif\0\0') {
- throw new Error('The Exif data is not valid.');
- }
-
- // After the Exif start we either have 0x4949 if the following data is
- // stored in big endian or 0x4D4D if it is stored in little endian
- if (data.getShort(tiffOffset) == 0x4949) {
- this.isBigEndian = false;
-
- } else if (data.getShort(tiffOffset) == 0x4D4D) {
- this.isBigEndian = true;
-
- } else {
- throw new Error('Invalid TIFF data! Expected 0x4949 or 0x4D4D at offset '+(tiffOffset)+' but found 0x'+data[tiffOffset].toString(16).toUpperCase()+data[tiffOffset + 1].toString(16).toUpperCase()+".");
- }
-
- debug("BigEndian=",this.isBigEndian);
-
- // Valid TIFF headers always have 0x002A here
- if (data.getShort(tiffOffset + 2, this.isBigEndian) != 0x002A) {
- var expected = (this.isBigEndian) ? '0x002A' : '0x2A00';
- throw new Error('Invalid TIFF data! Expected '+expected+' at offset '+(tiffOffset + 2)+' but found 0x'+data[tiffOffset + 2].toString(16).toUpperCase()+data[tiffOffset + 3].toString(16).toUpperCase()+".");
- }
-
- /********************************* IFD0 **********************************/
-
- // Offset to IFD0 which is always followed by two bytes with the amount of
- // entries in this IFD
- ifdOffset = tiffOffset + data.getLong(tiffOffset + 4, this.isBigEndian);
- this.offsets.ifd0=ifdOffset;
-
- numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
- if (this.options.ifd0MaxEntries) {
- numberOfEntries=Math.min(numberOfEntries, this.options.ifd0MaxEntries);
- }
-
- debug("IFD0 ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries);
-
- // Each IFD entry consists of 12 bytes which we loop through and extract
- // the data from
- for (var i = 0; i < numberOfEntries; i++) {
- var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif);
- if (!exifEntry) {
- continue;
- }
-
- if (exifEntry.tagId===0xEA1C && noPadding) {
- continue;
- }
-
- exifData.image[exifEntry.tagName] = exifEntry.value;
- }
-
- debug("IFD0 parsed", exifData.image);
-
- /********************************* IFD1 **********************************/
-
- // Check if there is an offset for IFD1. If so it is always followed by two
- // bytes with the amount of entries in this IFD, if not there is no IFD1
- var nextIfdOffset = data.getLong(ifdOffset + 2 + (numberOfEntries * 12), this.isBigEndian)
- if (nextIfdOffset != 0x00000000) {
- ifdOffset = tiffOffset + nextIfdOffset;
- this.offsets.ifd1=ifdOffset;
- numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
- if (this.options.ifd1MaxEntries) {
- numberOfEntries=Math.min(numberOfEntries, this.options.ifd1MaxEntries);
- }
-
- debug("IFD1 ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries);
-
- // Each IFD entry consists of 12 bytes which we loop through and extract
- // the data from
- for (var i = 0; i < numberOfEntries; i++) {
- var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif);
- if (!exifEntry) {
- continue;
- }
-
- if (exifEntry.tagId===0xEA1C && noPadding) {
- continue;
- }
-
- exifData.thumbnail[exifEntry.tagName] = exifEntry.value;
- }
-
- if (this.options.fixThumbnailOffset) {
- var thumbnailOffset=exifData.thumbnail[ExifImage.TAGS.exif[0x0201]];
- if (thumbnailOffset) {
- debug("IFD1 fix thumbnail offset, add=",this.offsets.tiff);
-
- exifData.thumbnail[ExifImage.TAGS.exif[0x0201]]+=this.offsets.tiff;
- }
- }
-
- debug("IFD1 parsed", exifData.thumbnail);
- }
-
- /******************************* EXIF IFD ********************************/
-
- // Look for a pointer to the Exif IFD in IFD0 and extract information from
- // it if available
- if (exifData.image[ExifImage.TAGS.exif[0x8769]]) {
-
- ifdOffset = tiffOffset + exifData.image[ExifImage.TAGS.exif[0x8769]];
- this.offsets.tags=ifdOffset;
-
- numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
- if (this.options.maxEntries) {
- numberOfEntries=Math.min(numberOfEntries, this.options.maxEntries);
- }
-
- debug("EXIF IFD ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries);
-
- // Each IFD entry consists of 12 bytes which we loop through and extract
- // the data from
- for (var i = 0; i < numberOfEntries; i++) {
- var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif);
- if (!exifEntry) {
- continue;
- }
-
- if (exifEntry.tagId===0xEA1C && noPadding) {
- continue;
- }
-
- exifData.exif[exifEntry.tagName] = exifEntry.value;
- }
-
- debug("EXIF IFD parsed",exifData.exif);
- }
-
- /******************************** GPS IFD ********************************/
-
- // Look for a pointer to the GPS IFD in IFD0 and extract information from
- // it if available
- if (exifData.image[ExifImage.TAGS.exif[0x8825]]) {
-
- ifdOffset = tiffOffset + exifData.image[ExifImage.TAGS.exif[0x8825]];
- this.offsets.gps=ifdOffset;
-
- numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
- if (this.options.maxGpsEntries) {
- numberOfEntries=Math.min(numberOfEntries, this.options.maxGpsEntries);
- }
-
- debug("GPS IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
-
- // Each IFD entry consists of 12 bytes which we loop through and extract
- // the data from
- for (var i = 0; i < numberOfEntries; i++) {
- var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.gps);
- if (!exifEntry) {
- continue;
- }
-
- if (exifEntry.tagId===0xEA1C && noPadding) {
- continue;
- }
-
- exifData.gps[exifEntry.tagName] = exifEntry.value;
- }
-
- debug("GPS IFD parsed",exifData.gps);
- }
-
- /************************* Interoperability IFD **************************/
-
- // Look for a pointer to the interoperatbility IFD in the Exif IFD and
- // extract information from it if available
- if (exifData.exif[ExifImage.TAGS.exif[0xA005]]) {
-
- ifdOffset = tiffOffset + exifData.exif[ExifImage.TAGS.exif[0xA005]];
- this.offsets.interoperability=ifdOffset;
-
- numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
- if (this.options.maxInteroperabilityEntries) {
- numberOfEntries=Math.min(numberOfEntries, this.options.maxInteroperabilityEntries);
- }
-
- debug("Interoperability IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
-
- // Each IFD entry consists of 12 bytes which we loop through and extract
- // the data from
- for (var i = 0; i < numberOfEntries; i++) {
- var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif);
- if (!exifEntry) {
- break;
- }
-
- if (exifEntry.tagId===0xEA1C && noPadding) {
- continue;
- }
-
- exifData.interoperability[exifEntry.tagName] = exifEntry.value;
- }
-
- debug("Interoperability IFD parsed",exifData.gps);
- }
-
- /***************************** Makernote IFD *****************************/
-
- // Look for Makernote data in the Exif IFD, check which type of proprietary
- // Makernotes the image contains, load the respective functionality and
- // start the extraction
- if (typeof exifData.exif[ExifImage.TAGS.exif[0x927C]] != "undefined") {
-
- var type;
- // Check the header to see what kind of Makernote we are dealing with
- if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x01" || exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x02") {
- type="olympus"
-
- } else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "AGFA \x00\x01") {
- type="agfa";
-
- } else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "EPSON\x00\x01\x00") {
- type="epson";
-
- } else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "FUJIFILM") {
- type="fujifilm";
-
- } else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 9) === "Panasonic") {
- type="panasonic";
-
- } else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 5) === "SANYO") {
- type="sanyo";
- }
-
-
- debug("Makernote IFD ifdOffset=", ifdOffset, "type=", type);
-
- if (type) {
- var extractMakernotes = require('./makernotes/'+type).extractMakernotes;
-
- exifData.makernote = extractMakernotes.call(this, data, this.offsets.makernoteOffset, tiffOffset);
-
- } else {
- // Makernotes are available but the format is not recognized so
- // an error message is pushed instead, this ain't the best
- // solution but should do for now
- exifData.makernote['error'] = 'Unable to extract Makernote information as it is in an unsupported or unrecognized format.';
- }
-
- debug("Makernote IFD parsed",exifData.makernote);
- }
-};
-
-ExifImage.prototype.extractExifEntry = function (data, entryOffset, tiffOffset, isBigEndian, tags) {
-
- var entry = {
- tag : data.slice(entryOffset, entryOffset + 2),
- tagId : null,
- tagName : null,
- format : data.getShort(entryOffset + 2, isBigEndian),
- components : data.getLong(entryOffset + 4, isBigEndian),
- valueOffset: null,
- value : []
- }
-
- entry.tagId = entry.tag.getShort(0, isBigEndian);
-
- // The tagId may correspond to more then one tagName so check which
- if (tags && tags[entry.tagId] && typeof tags[entry.tagId] == "function") {
- entry.tagName = tags[entry.tagId].call(this, entry);
- if (!entry.tagName) {
- return false;
- }
-
- // The tagId corresponds to exactly one tagName
- } else if (tags && tags[entry.tagId]) {
- entry.tagName = tags[entry.tagId];
- if (entry.tagName===undefined) {
- return false;
- }
-
- // The tagId is not recognized
- } else {
- return false;
- }
-
- switch (entry.format) {
-
- case 0x0001: // unsigned byte, 1 byte per component
- entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getByte(entry.valueOffset + i));
- break;
-
- case 0x0002: // ascii strings, 1 byte per component
- entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- entry.value = data.getString(entry.valueOffset, entry.components);
- if (entry.value[entry.value.length - 1] === "\u0000") // Trim null terminated strings
- entry.value = entry.value.substring(0, entry.value.length - 1);
- break;
-
- case 0x0003: // unsigned short, 2 byte per component
- entry.valueOffset = (entry.components <= 2) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getShort(entry.valueOffset + i * 2, isBigEndian));
- break;
-
- case 0x0004: // unsigned long, 4 byte per component
- entry.valueOffset = (entry.components == 1) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getLong(entry.valueOffset + i * 4, isBigEndian));
- break;
-
- case 0x0005: // unsigned rational, 8 byte per component (4 byte numerator and 4 byte denominator)
- entry.valueOffset = data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getLong(entry.valueOffset + i * 8, isBigEndian) / data.getLong(entry.valueOffset + i * 8 + 4, isBigEndian));
- break;
-
- case 0x0006: // signed byte, 1 byte per component
- entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getSignedByte(entry.valueOffset + i));
- break;
-
- case 0x0007: // undefined, 1 byte per component
- entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- entry.value.push(data.slice(entry.valueOffset, entry.valueOffset + entry.components));
- break;
-
- case 0x0008: // signed short, 2 byte per component
- entry.valueOffset = (entry.components <= 2) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getSignedShort(entry.valueOffset + i * 2, isBigEndian));
- break;
-
- case 0x0009: // signed long, 4 byte per component
- entry.valueOffset = (entry.components == 1) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getSignedLong(entry.valueOffset + i * 4, isBigEndian));
- break;
-
- case 0x000A: // signed rational, 8 byte per component (4 byte numerator and 4 byte denominator)
- entry.valueOffset = data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
- for (var i = 0; i < entry.components; i++)
- entry.value.push(data.getSignedLong(entry.valueOffset + i * 8, isBigEndian) / data.getSignedLong(entry.valueOffset + i * 8 + 4, isBigEndian));
- break;
-
- default:
- return false;
-
- }
-
- // If this is the Makernote tag save its offset for later use
- if (entry.tagName === "MakerNote") {
- this.offsets.makernoteOffset = entry.valueOffset;
- }
-
- // If the value array has only one element we don't need an array
- if (entry.value.length == 1) {
- entry.value = entry.value[0];
- }
-
- return entry;
-};
-
-/**
- * Comprehensive list of TIFF and Exif tags found on
- * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
- */
-ExifImage.TAGS = {
-
- // Exif tags
- exif : {
-
- 0x0001 : "InteropIndex",
- 0x0002 : "InteropVersion",
- 0x000B : "ProcessingSoftware",
- 0x00FE : "SubfileType",
- 0x00FF : "OldSubfileType",
- 0x0100 : "ImageWidth",
- 0x0101 : "ImageHeight",
- 0x0102 : "BitsPerSample",
- 0x0103 : "Compression",
- 0x0106 : "PhotometricInterpretation",
- 0x0107 : "Thresholding",
- 0x0108 : "CellWidth",
- 0x0109 : "CellLength",
- 0x010A : "FillOrder",
- 0x010D : "DocumentName",
- 0x010E : "ImageDescription",
- 0x010F : "Make",
- 0x0110 : "Model",
- 0x0111 : "StripOffsets",
- 0x0112 : "Orientation",
- 0x0115 : "SamplesPerPixel",
- 0x0116 : "RowsPerStrip",
- 0x0117 : "StripByteCounts",
- 0x0118 : "MinSampleValue",
- 0x0119 : "MaxSampleValue",
- 0x011A : "XResolution",
- 0x011B : "YResolution",
- 0x011C : "PlanarConfiguration",
- 0x011D : "PageName",
- 0x011E : "XPosition",
- 0x011F : "YPosition",
- 0x0120 : "FreeOffsets",
- 0x0121 : "FreeByteCounts",
- 0x0122 : "GrayResponseUnit",
- 0x0123 : "GrayResponseCurve",
- 0x0124 : "T4Options",
- 0x0125 : "T6Options",
- 0x0128 : "ResolutionUnit",
- 0x0129 : "PageNumber",
- 0x012C : "ColorResponseUnit",
- 0x012D : "TransferFunction",
- 0x0131 : "Software",
- 0x0132 : "ModifyDate",
- 0x013B : "Artist",
- 0x013C : "HostComputer",
- 0x013D : "Predictor",
- 0x013E : "WhitePoint",
- 0x013F : "PrimaryChromaticities",
- 0x0140 : "ColorMap",
- 0x0141 : "HalftoneHints",
- 0x0142 : "TileWidth",
- 0x0143 : "TileLength",
- 0x0144 : "TileOffsets",
- 0x0145 : "TileByteCounts",
- 0x0146 : "BadFaxLines",
- 0x0147 : "CleanFaxData",
- 0x0148 : "ConsecutiveBadFaxLines",
- 0x014A : "SubIFD",
- 0x014C : "InkSet",
- 0x014D : "InkNames",
- 0x014E : "NumberofInks",
- 0x0150 : "DotRange",
- 0x0151 : "TargetPrinter",
- 0x0152 : "ExtraSamples",
- 0x0153 : "SampleFormat",
- 0x0154 : "SMinSampleValue",
- 0x0155 : "SMaxSampleValue",
- 0x0156 : "TransferRange",
- 0x0157 : "ClipPath",
- 0x0158 : "XClipPathUnits",
- 0x0159 : "YClipPathUnits",
- 0x015A : "Indexed",
- 0x015B : "JPEGTables",
- 0x015F : "OPIProxy",
- 0x0190 : "GlobalParametersIFD",
- 0x0191 : "ProfileType",
- 0x0192 : "FaxProfile",
- 0x0193 : "CodingMethods",
- 0x0194 : "VersionYear",
- 0x0195 : "ModeNumber",
- 0x01B1 : "Decode",
- 0x01B2 : "DefaultImageColor",
- 0x01B3 : "T82Options",
- 0x01B5 : "JPEGTables",
- 0x0200 : "JPEGProc",
- 0x0201 : "ThumbnailOffset",
- 0x0202 : "ThumbnailLength",
- 0x0203 : "JPEGRestartInterval",
- 0x0205 : "JPEGLosslessPredictors",
- 0x0206 : "JPEGPointTransforms",
- 0x0207 : "JPEGQTables",
- 0x0208 : "JPEGDCTables",
- 0x0209 : "JPEGACTables",
- 0x0211 : "YCbCrCoefficients",
- 0x0212 : "YCbCrSubSampling",
- 0x0213 : "YCbCrPositioning",
- 0x0214 : "ReferenceBlackWhite",
- 0x022F : "StripRowCounts",
- 0x02BC : "ApplicationNotes",
- 0x03E7 : "USPTOMiscellaneous",
- 0x1000 : "RelatedImageFileFormat",
- 0x1001 : "RelatedImageWidth",
- 0x1002 : "RelatedImageHeight",
- 0x4746 : "Rating",
- 0x4747 : "XP_DIP_XML",
- 0x4748 : "StitchInfo",
- 0x4749 : "RatingPercent",
- 0x800D : "ImageID",
- 0x80A3 : "WangTag1",
- 0x80A4 : "WangAnnotation",
- 0x80A5 : "WangTag3",
- 0x80A6 : "WangTag4",
- 0x80E3 : "Matteing",
- 0x80E4 : "DataType",
- 0x80E5 : "ImageDepth",
- 0x80E6 : "TileDepth",
- 0x827D : "Model2",
- 0x828D : "CFARepeatPatternDim",
- 0x828E : "CFAPattern2",
- 0x828F : "BatteryLevel",
- 0x8290 : "KodakIFD",
- 0x8298 : "Copyright",
- 0x829A : "ExposureTime",
- 0x829D : "FNumber",
- 0x82A5 : "MDFileTag",
- 0x82A6 : "MDScalePixel",
- 0x82A7 : "MDColorTable",
- 0x82A8 : "MDLabName",
- 0x82A9 : "MDSampleInfo",
- 0x82AA : "MDPrepDate",
- 0x82AB : "MDPrepTime",
- 0x82AC : "MDFileUnits",
- 0x830E : "PixelScale",
- 0x8335 : "AdventScale",
- 0x8336 : "AdventRevision",
- 0x835C : "UIC1Tag",
- 0x835D : "UIC2Tag",
- 0x835E : "UIC3Tag",
- 0x835F : "UIC4Tag",
- 0x83BB : "IPTC-NAA",
- 0x847E : "IntergraphPacketData",
- 0x847F : "IntergraphFlagRegisters",
- 0x8480 : "IntergraphMatrix",
- 0x8481 : "INGRReserved",
- 0x8482 : "ModelTiePoint",
- 0x84E0 : "Site",
- 0x84E1 : "ColorSequence",
- 0x84E2 : "IT8Header",
- 0x84E3 : "RasterPadding",
- 0x84E4 : "BitsPerRunLength",
- 0x84E5 : "BitsPerExtendedRunLength",
- 0x84E6 : "ColorTable",
- 0x84E7 : "ImageColorIndicator",
- 0x84E8 : "BackgroundColorIndicator",
- 0x84E9 : "ImageColorValue",
- 0x84EA : "BackgroundColorValue",
- 0x84EB : "PixelIntensityRange",
- 0x84EC : "TransparencyIndicator",
- 0x84ED : "ColorCharacterization",
- 0x84EE : "HCUsage",
- 0x84EF : "TrapIndicator",
- 0x84F0 : "CMYKEquivalent",
- 0x8546 : "SEMInfo",
- 0x8568 : "AFCP_IPTC",
- 0x85B8 : "PixelMagicJBIGOptions",
- 0x85D8 : "ModelTransform",
- 0x8602 : "WB_GRGBLevels",
- 0x8606 : "LeafData",
- 0x8649 : "PhotoshopSettings",
- 0x8769 : "ExifOffset",
- 0x8773 : "ICC_Profile",
- 0x877F : "TIFF_FXExtensions",
- 0x8780 : "MultiProfiles",
- 0x8781 : "SharedData",
- 0x8782 : "T88Options",
- 0x87AC : "ImageLayer",
- 0x87AF : "GeoTiffDirectory",
- 0x87B0 : "GeoTiffDoubleParams",
- 0x87B1 : "GeoTiffAsciiParams",
- 0x8822 : "ExposureProgram",
- 0x8824 : "SpectralSensitivity",
- 0x8825 : "GPSInfo",
- 0x8827 : "ISO",
- 0x8828 : "Opto-ElectricConvFactor",
- 0x8829 : "Interlace",
- 0x882A : "TimeZoneOffset",
- 0x882B : "SelfTimerMode",
- 0x8830 : "SensitivityType",
- 0x8831 : "StandardOutputSensitivity",
- 0x8832 : "RecommendedExposureIndex",
- 0x8833 : "ISOSpeed",
- 0x8834 : "ISOSpeedLatitudeyyy",
- 0x8835 : "ISOSpeedLatitudezzz",
- 0x885C : "FaxRecvParams",
- 0x885D : "FaxSubAddress",
- 0x885E : "FaxRecvTime",
- 0x888A : "LeafSubIFD",
- 0x9000 : "ExifVersion",
- 0x9003 : "DateTimeOriginal",
- 0x9004 : "CreateDate",
- 0x9010 : "OffsetTime",
- 0x9011 : "OffsetTimeOriginal",
- 0x9012 : "OffsetTimeDigitized",
- 0x9101 : "ComponentsConfiguration",
- 0x9102 : "CompressedBitsPerPixel",
- 0x9201 : "ShutterSpeedValue",
- 0x9202 : "ApertureValue",
- 0x9203 : "BrightnessValue",
- 0x9204 : "ExposureCompensation",
- 0x9205 : "MaxApertureValue",
- 0x9206 : "SubjectDistance",
- 0x9207 : "MeteringMode",
- 0x9208 : "LightSource",
- 0x9209 : "Flash",
- 0x920A : "FocalLength",
- 0x920B : "FlashEnergy",
- 0x920C : "SpatialFrequencyResponse",
- 0x920D : "Noise",
- 0x920E : "FocalPlaneXResolution",
- 0x920F : "FocalPlaneYResolution",
- 0x9210 : "FocalPlaneResolutionUnit",
- 0x9211 : "ImageNumber",
- 0x9212 : "SecurityClassification",
- 0x9213 : "ImageHistory",
- 0x9214 : "SubjectArea",
- 0x9215 : "ExposureIndex",
- 0x9216 : "TIFF-EPStandardID",
- 0x9217 : "SensingMethod",
- 0x923A : "CIP3DataFile",
- 0x923B : "CIP3Sheet",
- 0x923C : "CIP3Side",
- 0x923F : "StoNits",
- 0x927C : "MakerNote",
- 0x9286 : "UserComment",
- 0x9290 : "SubSecTime",
- 0x9291 : "SubSecTimeOriginal",
- 0x9292 : "SubSecTimeDigitized",
- 0x932F : "MSDocumentText",
- 0x9330 : "MSPropertySetStorage",
- 0x9331 : "MSDocumentTextPosition",
- 0x935C : "ImageSourceData",
- 0x9C9B : "XPTitle",
- 0x9C9C : "XPComment",
- 0x9C9D : "XPAuthor",
- 0x9C9E : "XPKeywords",
- 0x9C9F : "XPSubject",
- 0xA000 : "FlashpixVersion",
- 0xA001 : "ColorSpace",
- 0xA002 : "ExifImageWidth",
- 0xA003 : "ExifImageHeight",
- 0xA004 : "RelatedSoundFile",
- 0xA005 : "InteropOffset",
- 0xA20B : "FlashEnergy",
- 0xA20C : "SpatialFrequencyResponse",
- 0xA20D : "Noise",
- 0xA20E : "FocalPlaneXResolution",
- 0xA20F : "FocalPlaneYResolution",
- 0xA210 : "FocalPlaneResolutionUnit",
- 0xA211 : "ImageNumber",
- 0xA212 : "SecurityClassification",
- 0xA213 : "ImageHistory",
- 0xA214 : "SubjectLocation",
- 0xA215 : "ExposureIndex",
- 0xA216 : "TIFF-EPStandardID",
- 0xA217 : "SensingMethod",
- 0xA300 : "FileSource",
- 0xA301 : "SceneType",
- 0xA302 : "CFAPattern",
- 0xA401 : "CustomRendered",
- 0xA402 : "ExposureMode",
- 0xA403 : "WhiteBalance",
- 0xA404 : "DigitalZoomRatio",
- 0xA405 : "FocalLengthIn35mmFormat",
- 0xA406 : "SceneCaptureType",
- 0xA407 : "GainControl",
- 0xA408 : "Contrast",
- 0xA409 : "Saturation",
- 0xA40A : "Sharpness",
- 0xA40B : "DeviceSettingDescription",
- 0xA40C : "SubjectDistanceRange",
- 0xA420 : "ImageUniqueID",
- 0xA430 : "OwnerName",
- 0xA431 : "SerialNumber",
- 0xA432 : "LensInfo",
- 0xA433 : "LensMake",
- 0xA434 : "LensModel",
- 0xA435 : "LensSerialNumber",
- 0xA480 : "GDALMetadata",
- 0xA481 : "GDALNoData",
- 0xA500 : "Gamma",
- 0xAFC0 : "ExpandSoftware",
- 0xAFC1 : "ExpandLens",
- 0xAFC2 : "ExpandFilm",
- 0xAFC3 : "ExpandFilterLens",
- 0xAFC4 : "ExpandScanner",
- 0xAFC5 : "ExpandFlashLamp",
- 0xBC01 : "PixelFormat",
- 0xBC02 : "Transformation",
- 0xBC03 : "Uncompressed",
- 0xBC04 : "ImageType",
- 0xBC80 : "ImageWidth",
- 0xBC81 : "ImageHeight",
- 0xBC82 : "WidthResolution",
- 0xBC83 : "HeightResolution",
- 0xBCC0 : "ImageOffset",
- 0xBCC1 : "ImageByteCount",
- 0xBCC2 : "AlphaOffset",
- 0xBCC3 : "AlphaByteCount",
- 0xBCC4 : "ImageDataDiscard",
- 0xBCC5 : "AlphaDataDiscard",
- 0xC427 : "OceScanjobDesc",
- 0xC428 : "OceApplicationSelector",
- 0xC429 : "OceIDNumber",
- 0xC42A : "OceImageLogic",
- 0xC44F : "Annotations",
- 0xC4A5 : "PrintIM",
- 0xC580 : "USPTOOriginalContentType",
- 0xC612 : "DNGVersion",
- 0xC613 : "DNGBackwardVersion",
- 0xC614 : "UniqueCameraModel",
- 0xC615 : "LocalizedCameraModel",
- 0xC616 : "CFAPlaneColor",
- 0xC617 : "CFALayout",
- 0xC618 : "LinearizationTable",
- 0xC619 : "BlackLevelRepeatDim",
- 0xC61A : "BlackLevel",
- 0xC61B : "BlackLevelDeltaH",
- 0xC61C : "BlackLevelDeltaV",
- 0xC61D : "WhiteLevel",
- 0xC61E : "DefaultScale",
- 0xC61F : "DefaultCropOrigin",
- 0xC620 : "DefaultCropSize",
- 0xC621 : "ColorMatrix1",
- 0xC622 : "ColorMatrix2",
- 0xC623 : "CameraCalibration1",
- 0xC624 : "CameraCalibration2",
- 0xC625 : "ReductionMatrix1",
- 0xC626 : "ReductionMatrix2",
- 0xC627 : "AnalogBalance",
- 0xC628 : "AsShotNeutral",
- 0xC629 : "AsShotWhiteXY",
- 0xC62A : "BaselineExposure",
- 0xC62B : "BaselineNoise",
- 0xC62C : "BaselineSharpness",
- 0xC62D : "BayerGreenSplit",
- 0xC62E : "LinearResponseLimit",
- 0xC62F : "CameraSerialNumber",
- 0xC630 : "DNGLensInfo",
- 0xC631 : "ChromaBlurRadius",
- 0xC632 : "AntiAliasStrength",
- 0xC633 : "ShadowScale",
- 0xC634 : "DNGPrivateData",
- 0xC635 : "MakerNoteSafety",
- 0xC640 : "RawImageSegmentation",
- 0xC65A : "CalibrationIlluminant1",
- 0xC65B : "CalibrationIlluminant2",
- 0xC65C : "BestQualityScale",
- 0xC65D : "RawDataUniqueID",
- 0xC660 : "AliasLayerMetadata",
- 0xC68B : "OriginalRawFileName",
- 0xC68C : "OriginalRawFileData",
- 0xC68D : "ActiveArea",
- 0xC68E : "MaskedAreas",
- 0xC68F : "AsShotICCProfile",
- 0xC690 : "AsShotPreProfileMatrix",
- 0xC691 : "CurrentICCProfile",
- 0xC692 : "CurrentPreProfileMatrix",
- 0xC6BF : "ColorimetricReference",
- 0xC6D2 : "PanasonicTitle",
- 0xC6D3 : "PanasonicTitle2",
- 0xC6F3 : "CameraCalibrationSig",
- 0xC6F4 : "ProfileCalibrationSig",
- 0xC6F5 : "ProfileIFD",
- 0xC6F6 : "AsShotProfileName",
- 0xC6F7 : "NoiseReductionApplied",
- 0xC6F8 : "ProfileName",
- 0xC6F9 : "ProfileHueSatMapDims",
- 0xC6FA : "ProfileHueSatMapData1",
- 0xC6FB : "ProfileHueSatMapData2",
- 0xC6FC : "ProfileToneCurve",
- 0xC6FD : "ProfileEmbedPolicy",
- 0xC6FE : "ProfileCopyright",
- 0xC714 : "ForwardMatrix1",
- 0xC715 : "ForwardMatrix2",
- 0xC716 : "PreviewApplicationName",
- 0xC717 : "PreviewApplicationVersion",
- 0xC718 : "PreviewSettingsName",
- 0xC719 : "PreviewSettingsDigest",
- 0xC71A : "PreviewColorSpace",
- 0xC71B : "PreviewDateTime",
- 0xC71C : "RawImageDigest",
- 0xC71D : "OriginalRawFileDigest",
- 0xC71E : "SubTileBlockSize",
- 0xC71F : "RowInterleaveFactor",
- 0xC725 : "ProfileLookTableDims",
- 0xC726 : "ProfileLookTableData",
- 0xC740 : "OpcodeList1",
- 0xC741 : "OpcodeList2",
- 0xC74E : "OpcodeList3",
- 0xC761 : "NoiseProfile",
- 0xC763 : "TimeCodes",
- 0xC764 : "FrameRate",
- 0xC772 : "TStop",
- 0xC789 : "ReelName",
- 0xC791 : "OriginalDefaultFinalSize",
- 0xC792 : "OriginalBestQualitySize",
- 0xC793 : "OriginalDefaultCropSize",
- 0xC7A1 : "CameraLabel",
- 0xC7A3 : "ProfileHueSatMapEncoding",
- 0xC7A4 : "ProfileLookTableEncoding",
- 0xC7A5 : "BaselineExposureOffset",
- 0xC7A6 : "DefaultBlackRender",
- 0xC7A7 : "NewRawImageDigest",
- 0xC7A8 : "RawToPreviewGain",
- 0xC7B5 : "DefaultUserCrop",
- 0xEA1C : "Padding",
- 0xEA1D : "OffsetSchema",
- 0xFDE8 : "OwnerName",
- 0xFDE9 : "SerialNumber",
- 0xFDEA : "Lens",
- 0xFE00 : "KDC_IFD",
- 0xFE4C : "RawFile",
- 0xFE4D : "Converter",
- 0xFE4E : "WhiteBalance",
- 0xFE51 : "Exposure",
- 0xFE52 : "Shadows",
- 0xFE53 : "Brightness",
- 0xFE54 : "Contrast",
- 0xFE55 : "Saturation",
- 0xFE56 : "Sharpness",
- 0xFE57 : "Smoothness",
- 0xFE58 : "MoireFilter"
-
- },
-
- // GPS Tags
- gps : {
-
- 0x0000 : 'GPSVersionID',
- 0x0001 : 'GPSLatitudeRef',
- 0x0002 : 'GPSLatitude',
- 0x0003 : 'GPSLongitudeRef',
- 0x0004 : 'GPSLongitude',
- 0x0005 : 'GPSAltitudeRef',
- 0x0006 : 'GPSAltitude',
- 0x0007 : 'GPSTimeStamp',
- 0x0008 : 'GPSSatellites',
- 0x0009 : 'GPSStatus',
- 0x000A : 'GPSMeasureMode',
- 0x000B : 'GPSDOP',
- 0x000C : 'GPSSpeedRef',
- 0x000D : 'GPSSpeed',
- 0x000E : 'GPSTrackRef',
- 0x000F : 'GPSTrack',
- 0x0010 : 'GPSImgDirectionRef',
- 0x0011 : 'GPSImgDirection',
- 0x0012 : 'GPSMapDatum',
- 0x0013 : 'GPSDestLatitudeRef',
- 0x0014 : 'GPSDestLatitude',
- 0x0015 : 'GPSDestLongitudeRef',
- 0x0016 : 'GPSDestLongitude',
- 0x0017 : 'GPSDestBearingRef',
- 0x0018 : 'GPSDestBearing',
- 0x0019 : 'GPSDestDistanceRef',
- 0x001A : 'GPSDestDistance',
- 0x001B : 'GPSProcessingMethod',
- 0x001C : 'GPSAreaInformation',
- 0x001D : 'GPSDateStamp',
- 0x001E : 'GPSDifferential',
- 0x001F : 'GPSHPositioningError'
-
- }
-
-};
diff --git a/lib/exif/index.js b/lib/exif/index.js
deleted file mode 100644
index ee8af71..0000000
--- a/lib/exif/index.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = require('./ExifImage');
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f7b420a
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1735 @@
+{
+ "name": "node-exif",
+ "version": "0.7.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "node-exif",
+ "version": "0.7.0",
+ "dependencies": {
+ "debug": "^2.2"
+ },
+ "devDependencies": {
+ "chai": "^4.3.7",
+ "mocha": "^10.2.0"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/chai": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+ "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+ "dev": true,
+ "dependencies": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.2",
+ "deep-eql": "^4.1.2",
+ "get-func-name": "^2.0.0",
+ "loupe": "^2.3.1",
+ "pathval": "^1.1.1",
+ "type-detect": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-eql": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true,
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/loupe": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+ "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+ "dev": true,
+ "dependencies": {
+ "get-func-name": "^2.0.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.2.0",
+ "he": "1.2.0",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
+ "ms": "2.1.3",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "workerpool": "6.2.1",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha.js"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mochajs"
+ }
+ },
+ "node_modules/mocha/node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/mocha/node_modules/debug/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "dev": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pathval": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/serialize-javascript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/workerpool": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ },
+ "dependencies": {
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true
+ },
+ "chai": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+ "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+ "dev": true,
+ "requires": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.2",
+ "deep-eql": "^4.1.2",
+ "get-func-name": "^2.0.0",
+ "loupe": "^2.3.1",
+ "pathval": "^1.1.1",
+ "type-detect": "^4.0.5"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
+ "dev": true
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
+ },
+ "deep-eql": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+ "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "dev": true,
+ "requires": {
+ "type-detect": "^4.0.0"
+ }
+ },
+ "diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true
+ },
+ "is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ }
+ },
+ "loupe": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+ "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+ "dev": true,
+ "requires": {
+ "get-func-name": "^2.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "mocha": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.2.0",
+ "he": "1.2.0",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
+ "ms": "2.1.3",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "workerpool": "6.2.1",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "nanoid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true
+ },
+ "pathval": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ },
+ "serialize-javascript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true
+ },
+ "workerpool": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true
+ },
+ "yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ }
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
index 3de8dbb..fe77ecf 100644
--- a/package.json
+++ b/package.json
@@ -1,21 +1,35 @@
{
- "name" : "exif",
- "version" : "0.6.0",
- "description" : "A node.js library to extract Exif metadata from images.",
- "author" : [ "Daniel Leinich ", "Olivier Oeuillot " ],
- "keywords" : ["exif", "image", "jpeg", "jpg", "makernotes", "gps"],
- "main" : "./lib/exif",
- "repository" : {
- "type" : "git",
- "url" : "http://github.com/gomfunkel/node-exif.git"
+ "name": "node-exif",
+ "version": "0.7.0",
+ "description": "A node.js library to extract Exif metadata from images.",
+ "author" : "Daniel Leinich ",
+ "contributors": [
+ "Olivier Oeuillot ",
+ "Ruurd Bijlsma "
+ ],
+ "type": "module",
+ "keywords": [
+ "exif",
+ "image",
+ "jpeg",
+ "jpg",
+ "makernotes",
+ "gps"
+ ],
+ "main": "./src/ExifImage.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/gomfunkel/node-exif.git"
},
"dependencies": {
"debug": "^2.2"
},
"devDependencies": {
- "mocha": "^2.4"
+ "chai": "^4.3.7",
+ "mocha": "^10.2.0"
},
"scripts": {
- "test": "node_modules/.bin/mocha --reporter spec test/*-test.js"
+ "test-debug": "set DEBUG=* && mocha --reporter spec test/*-test.js",
+ "test": "mocha --reporter spec test/*-test.js"
}
}
\ No newline at end of file
diff --git a/lib/exif/Buffer.js b/src/Buffer.js
similarity index 97%
rename from lib/exif/Buffer.js
rename to src/Buffer.js
index ff8cc3b..ab57eb6 100644
--- a/lib/exif/Buffer.js
+++ b/src/Buffer.js
@@ -1,39 +1,41 @@
-//
-// A couple of methods that make working with buffers more easy.
-//
-
-Buffer.prototype.getByte = function (offset) {
- return this[offset];
-};
-
-Buffer.prototype.getSignedByte = function (offset) {
- return (this[offset] > 127) ? this[offset] - 256 : this[offset];
-};
-
-Buffer.prototype.getShort = function (offset, bigEndian) {
- var shortVal = (bigEndian) ? (this[offset] << 8) + this[offset + 1] : (this[offset + 1] << 8) + this[offset];
- return (shortVal < 0) ? shortVal + 65536 : shortVal;
-};
-
-Buffer.prototype.getSignedShort = function (offset, bigEndian) {
- var shortVal = (bigEndian) ? (this[offset] << 8) + this[offset + 1] : (this[offset + 1] << 8) + this[offset];
- return (shortVal > 32767) ? shortVal - 65536 : shortVal;
-};
-
-Buffer.prototype.getLong = function (offset, bigEndian) {
- var longVal = (bigEndian) ? (((((this[offset] << 8) + this[offset + 1]) << 8) + this[offset + 2]) << 8) + this[offset + 3] : (((((this[offset + 3] << 8) + this[offset + 2]) << 8) + this[offset + 1]) << 8) + this[offset];
- return (longVal < 0) ? longVal + 4294967296 : longVal;
-};
-
-Buffer.prototype.getSignedLong = function (offset, bigEndian) {
- var longVal = (bigEndian) ? (((((this[offset] << 8) + this[offset + 1]) << 8) + this[offset + 2]) << 8) + this[offset + 3] : (((((this[offset + 3] << 8) + this[offset + 2]) << 8) + this[offset + 1]) << 8) + this[offset];
- return (longVal > 2147483647) ? longVal - 4294967296 : longVal;
-};
-
-Buffer.prototype.getString = function (offset, length) {
- var string = [];
- for (var i = offset; i < offset + length; i++) {
- string.push(String.fromCharCode(this[i]));
- }
- return string.join('');
-};
\ No newline at end of file
+//
+// A couple of methods that make working with buffers more easy.
+//
+
+Buffer.prototype.getByte = function (offset) {
+ return this[offset];
+};
+
+Buffer.prototype.getSignedByte = function (offset) {
+ return (this[offset] > 127) ? this[offset] - 256 : this[offset];
+};
+
+Buffer.prototype.getShort = function (offset, bigEndian) {
+ var shortVal = (bigEndian) ? (this[offset] << 8) + this[offset + 1] : (this[offset + 1] << 8) + this[offset];
+ return (shortVal < 0) ? shortVal + 65536 : shortVal;
+};
+
+Buffer.prototype.getSignedShort = function (offset, bigEndian) {
+ var shortVal = (bigEndian) ? (this[offset] << 8) + this[offset + 1] : (this[offset + 1] << 8) + this[offset];
+ return (shortVal > 32767) ? shortVal - 65536 : shortVal;
+};
+
+Buffer.prototype.getLong = function (offset, bigEndian) {
+ var longVal = (bigEndian) ? (((((this[offset] << 8) + this[offset + 1]) << 8) + this[offset + 2]) << 8) + this[offset + 3] : (((((this[offset + 3] << 8) + this[offset + 2]) << 8) + this[offset + 1]) << 8) + this[offset];
+ return (longVal < 0) ? longVal + 4294967296 : longVal;
+};
+
+Buffer.prototype.getSignedLong = function (offset, bigEndian) {
+ var longVal = (bigEndian) ? (((((this[offset] << 8) + this[offset + 1]) << 8) + this[offset + 2]) << 8) + this[offset + 3] : (((((this[offset + 3] << 8) + this[offset + 2]) << 8) + this[offset + 1]) << 8) + this[offset];
+ return (longVal > 2147483647) ? longVal - 4294967296 : longVal;
+};
+
+Buffer.prototype.getString = function (offset, length) {
+ var string = [];
+ for (var i = offset; i < offset + length; i++) {
+ string.push(String.fromCharCode(this[i]));
+ }
+ return string.join('');
+};
+
+export default Buffer
\ No newline at end of file
diff --git a/src/ExifImage.js b/src/ExifImage.js
new file mode 100644
index 0000000..3b18567
--- /dev/null
+++ b/src/ExifImage.js
@@ -0,0 +1,1056 @@
+/*jslint node: true */
+"use strict";
+
+import assert from 'assert'
+import fs from 'fs/promises'
+import dbg from 'debug'
+import BufferExtender from "./Buffer.js" // bad idea
+var debug = dbg('exif')
+const DEFAULT_MAX_ENTRIES = 128;
+
+/**
+ * Represents an image with Exif information. When instantiating it you have to
+ * provide an image and a callback function which is called once all metadata
+ * is extracted from the image.
+ *
+ * Available options are:
+ * - image The image to get Exif data from can be either a filesystem path or
+ * a Buffer.
+ * - tiffOffsets (boolean) an object named "offsets" is added to exifData
+ * and contains lot of offsets needed to get thumbnail and other things.
+ * - fixThumbnailOffset: node-exif corrects the thumbnail offset in order to have an offset from the start of the buffer/file.
+ * - maxEntries: Specifies the maximum entries to be parsed
+ * - ifd0MaxEntries
+ * - ifd1MaxEntries
+ * - maxGpsEntries
+ * - maxInteroperabilityEntries
+ * - agfaMaxEntries
+ * - epsonMaxEntries
+ * - fujifilmMaxEntries
+ * - olympusMaxEntries
+ * - panasonicMaxEntries
+ * - sanyoMaxEntries
+ * - noPadding
+ *
+ * If you don't set the image field, you might call exifImage.loadImage(image, callback) to get exif datas.
+ *
+ * @param options Configuration options as described above
+ * @return Extracted exif data object
+ */
+export default async function (options) {
+ let instance = new ExifImage(options);
+ if (!instance.options.image) {
+ return false;
+ }
+ return await instance.loadImage(instance.options.image);
+}
+
+/**
+ * Represents an image with Exif information. When instantiating it you have to
+ * provide an image and a callback function which is called once all metadata
+ * is extracted from the image.
+ *
+ * Available options are:
+ * - image The image to get Exif data from can be either a filesystem path or
+ * a Buffer.
+ * - tiffOffsets (boolean) an object named "offsets" is added to exifData
+ * and contains lot of offsets needed to get thumbnail and other things.
+ * - fixThumbnailOffset: node-exif corrects the thumbnail offset in order to have an offset from the start of the buffer/file.
+ * - maxEntries: Specifies the maximum entries to be parsed
+ * - ifd0MaxEntries
+ * - ifd1MaxEntries
+ * - maxGpsEntries
+ * - maxInteroperabilityEntries
+ * - agfaMaxEntries
+ * - epsonMaxEntries
+ * - fujifilmMaxEntries
+ * - olympusMaxEntries
+ * - panasonicMaxEntries
+ * - sanyoMaxEntries
+ * - noPadding
+ *
+ * If you don't set the image field, you might call exifImage.loadImage(image, callback) to get exif datas.
+ *
+ * @param options Configuration options as described above
+ * @return Extracted exif data object
+ */
+export class ExifImage {
+ constructor(options) {
+ if (typeof (options) === "string") {
+ options = {
+ image: options
+ }
+ } else if (options instanceof Buffer) {
+ options = {
+ image: options
+ }
+ }
+
+ var ops = {};
+ if (options) {
+ for (var k in options) {
+ ops[k] = options[k];
+ }
+ }
+ this.options = ops;
+
+ // Default option values
+ for (let p of ["ifd0MaxEntries", "ifd1MaxEntries", "maxGpsEntries", "maxInteroperabilityEntries", "agfaMaxEntries", "epsonMaxEntries",
+ "fujifilmMaxEntries", "olympusMaxEntries", "panasonicMaxEntries", "sanyoMaxEntries"]) {
+ if (ops[p] === undefined) {
+ ops[p] = DEFAULT_MAX_ENTRIES;
+ }
+ };
+
+ this.exifData = {
+ image: {}, // Information about the main image
+ thumbnail: {}, // Information about the thumbnail
+ exif: {}, // Exif information
+ gps: {}, // GPS information
+ interoperability: {}, // Exif Interoperability information
+ makernote: {} // Makernote information
+ };
+
+ this.offsets = {};
+ if (ops.tiffOffsets) {
+ exifData.offsets = offsets;
+ }
+
+ debug("New ExifImage options=", options);
+
+ if (!ops.image) {
+ // If options image is not specified, the developper must call loadImage() to parse the image.
+ // throw new Error('You have to provide an image, it is pretty hard to extract Exif data from nothing...');
+ return;
+ }
+ }
+
+ /**
+ * Load image and parse exifDatas
+ *
+ * @param [String|Buffer] image the image
+ * @return Nothing
+ */
+ async loadImage(image) {
+ debug("loadImage image=", image);
+
+ if (image.constructor.name === 'Buffer') {
+ return await this.processImage("Buffer", image);
+ }
+
+ if (image.constructor.name === 'String') {
+ let data = await fs.readFile(image);
+ return await this.processImage("File: " + image, data);
+ }
+
+ throw new Error('Given image is neither a buffer nor a file, please provide one of these.');
+ };
+
+ async processImage(source, data) {
+ assert(typeof (source) === "string", "Source must be a string");
+
+ var offset = 0;
+
+ if (data[offset++] != 0xFF || data[offset++] != 0xD8) {
+ var e = new Error('The given image is not a JPEG and thus unsupported right now.');
+ e.source = source;
+ e.code = "NOT_A_JPEG";
+ throw e;
+ }
+
+ this.imageType = 'JPEG';
+
+ while (offset < data.length) {
+
+ if (data[offset++] != 0xFF) {
+ break;
+ }
+
+ if (data[offset++] == 0xE1) {
+ try {
+ await this.extractExifData(data, offset + 2);
+ } catch (error) {
+ error.code = "PARSING_ERROR";
+ error.source = source;
+
+ debug("Extract exif data error source=", source, "offset=", offset, "error=", error);
+ throw error;
+ }
+
+ debug("Extract exif data success source=", source, "exifData=", this.exifData);
+
+ return this.exifData;
+ }
+
+ offset += data.getShort(offset, true);
+ }
+
+ var e2 = new Error('No Exif segment found in the given image.');
+ e2.source = source;
+ e2.code = "NO_EXIF_SEGMENT";
+ throw e2;
+ };
+
+ async extractExifData(data, start) {
+
+ var exifData = this.exifData;
+ var tiffOffset = start + 6;
+ var ifdOffset, numberOfEntries;
+ var noPadding = (this.options.noPadding !== false);
+
+ this.offsets.tiff = tiffOffset;
+
+ // Exif data always starts with Exif\0\0
+ if (data.toString('utf8', start, tiffOffset) != 'Exif\0\0') {
+ throw new Error('The Exif data is not valid.');
+ }
+
+ // After the Exif start we either have 0x4949 if the following data is
+ // stored in big endian or 0x4D4D if it is stored in little endian
+ if (data.getShort(tiffOffset) == 0x4949) {
+ this.isBigEndian = false;
+
+ } else if (data.getShort(tiffOffset) == 0x4D4D) {
+ this.isBigEndian = true;
+
+ } else {
+ throw new Error('Invalid TIFF data! Expected 0x4949 or 0x4D4D at offset ' + (tiffOffset) + ' but found 0x' + data[tiffOffset].toString(16).toUpperCase() + data[tiffOffset + 1].toString(16).toUpperCase() + ".");
+ }
+
+ debug("BigEndian=", this.isBigEndian);
+
+ // Valid TIFF headers always have 0x002A here
+ if (data.getShort(tiffOffset + 2, this.isBigEndian) != 0x002A) {
+ var expected = (this.isBigEndian) ? '0x002A' : '0x2A00';
+ throw new Error('Invalid TIFF data! Expected ' + expected + ' at offset ' + (tiffOffset + 2) + ' but found 0x' + data[tiffOffset + 2].toString(16).toUpperCase() + data[tiffOffset + 3].toString(16).toUpperCase() + ".");
+ }
+
+ /********************************* IFD0 **********************************/
+
+ // Offset to IFD0 which is always followed by two bytes with the amount of
+ // entries in this IFD
+ ifdOffset = tiffOffset + data.getLong(tiffOffset + 4, this.isBigEndian);
+ this.offsets.ifd0 = ifdOffset;
+
+ numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
+ if (this.options.ifd0MaxEntries) {
+ numberOfEntries = Math.min(numberOfEntries, this.options.ifd0MaxEntries);
+ }
+
+ debug("IFD0 ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
+
+ // Each IFD entry consists of 12 bytes which we loop through and extract
+ // the data from
+ for (var i = 0; i < numberOfEntries; i++) {
+ var exifEntry = await this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, TAGS.exif);
+ if (!exifEntry) {
+ continue;
+ }
+
+ if (exifEntry.tagId === 0xEA1C && noPadding) {
+ continue;
+ }
+
+ exifData.image[exifEntry.tagName] = exifEntry.value;
+ }
+
+ debug("IFD0 parsed", exifData.image);
+
+ /********************************* IFD1 **********************************/
+
+ // Check if there is an offset for IFD1. If so it is always followed by two
+ // bytes with the amount of entries in this IFD, if not there is no IFD1
+ var nextIfdOffset = data.getLong(ifdOffset + 2 + (numberOfEntries * 12), this.isBigEndian)
+ if (nextIfdOffset != 0x00000000) {
+ ifdOffset = tiffOffset + nextIfdOffset;
+ this.offsets.ifd1 = ifdOffset;
+ numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
+ if (this.options.ifd1MaxEntries) {
+ numberOfEntries = Math.min(numberOfEntries, this.options.ifd1MaxEntries);
+ }
+
+ debug("IFD1 ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
+
+ // Each IFD entry consists of 12 bytes which we loop through and extract
+ // the data from
+ for (var i = 0; i < numberOfEntries; i++) {
+ var exifEntry = await this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, TAGS.exif);
+ if (!exifEntry) {
+ continue;
+ }
+
+ if (exifEntry.tagId === 0xEA1C && noPadding) {
+ continue;
+ }
+
+ exifData.thumbnail[exifEntry.tagName] = exifEntry.value;
+ }
+
+ if (this.options.fixThumbnailOffset) {
+ var thumbnailOffset = exifData.thumbnail[TAGS.exif[0x0201]];
+ if (thumbnailOffset) {
+ debug("IFD1 fix thumbnail offset, add=", this.offsets.tiff);
+
+ exifData.thumbnail[TAGS.exif[0x0201]] += this.offsets.tiff;
+ }
+ }
+
+ debug("IFD1 parsed", exifData.thumbnail);
+ }
+
+ /******************************* EXIF IFD ********************************/
+
+ // Look for a pointer to the Exif IFD in IFD0 and extract information from
+ // it if available
+ if (exifData.image[TAGS.exif[0x8769]]) {
+
+ ifdOffset = tiffOffset + exifData.image[TAGS.exif[0x8769]];
+ this.offsets.tags = ifdOffset;
+
+ numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
+ if (this.options.maxEntries) {
+ numberOfEntries = Math.min(numberOfEntries, this.options.maxEntries);
+ }
+
+ debug("EXIF IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
+
+ // Each IFD entry consists of 12 bytes which we loop through and extract
+ // the data from
+ for (var i = 0; i < numberOfEntries; i++) {
+ var exifEntry = await this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, TAGS.exif);
+ if (!exifEntry) {
+ continue;
+ }
+
+ if (exifEntry.tagId === 0xEA1C && noPadding) {
+ continue;
+ }
+
+ exifData.exif[exifEntry.tagName] = exifEntry.value;
+ }
+
+ debug("EXIF IFD parsed", exifData.exif);
+ }
+
+ /******************************** GPS IFD ********************************/
+
+ // Look for a pointer to the GPS IFD in IFD0 and extract information from
+ // it if available
+ if (exifData.image[TAGS.exif[0x8825]]) {
+
+ ifdOffset = tiffOffset + exifData.image[TAGS.exif[0x8825]];
+ this.offsets.gps = ifdOffset;
+
+ numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
+ if (this.options.maxGpsEntries) {
+ numberOfEntries = Math.min(numberOfEntries, this.options.maxGpsEntries);
+ }
+
+ debug("GPS IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
+
+ // Each IFD entry consists of 12 bytes which we loop through and extract
+ // the data from
+ for (var i = 0; i < numberOfEntries; i++) {
+ var exifEntry = await this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, TAGS.gps);
+ if (!exifEntry) {
+ continue;
+ }
+
+ if (exifEntry.tagId === 0xEA1C && noPadding) {
+ continue;
+ }
+
+ exifData.gps[exifEntry.tagName] = exifEntry.value;
+ }
+
+ debug("GPS IFD parsed", exifData.gps);
+ }
+
+ /************************* Interoperability IFD **************************/
+
+ // Look for a pointer to the interoperatbility IFD in the Exif IFD and
+ // extract information from it if available
+ if (exifData.exif[TAGS.exif[0xA005]]) {
+
+ ifdOffset = tiffOffset + exifData.exif[TAGS.exif[0xA005]];
+ this.offsets.interoperability = ifdOffset;
+
+ numberOfEntries = data.getShort(ifdOffset, this.isBigEndian);
+ if (this.options.maxInteroperabilityEntries) {
+ numberOfEntries = Math.min(numberOfEntries, this.options.maxInteroperabilityEntries);
+ }
+
+ debug("Interoperability IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries);
+
+ // Each IFD entry consists of 12 bytes which we loop through and extract
+ // the data from
+ for (var i = 0; i < numberOfEntries; i++) {
+ var exifEntry = await this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, TAGS.exif);
+ if (!exifEntry) {
+ break;
+ }
+
+ if (exifEntry.tagId === 0xEA1C && noPadding) {
+ continue;
+ }
+
+ exifData.interoperability[exifEntry.tagName] = exifEntry.value;
+ }
+
+ debug("Interoperability IFD parsed", exifData.gps);
+ }
+
+ /***************************** Makernote IFD *****************************/
+
+ // Look for Makernote data in the Exif IFD, check which type of proprietary
+ // Makernotes the image contains, load the respective functionality and
+ // start the extraction
+ if (typeof exifData.exif[TAGS.exif[0x927C]] != "undefined") {
+
+ var type;
+ // Check the header to see what kind of Makernote we are dealing with
+ if (exifData.exif[TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x01" || exifData.exif[TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x02") {
+ type = "olympus"
+
+ } else if (exifData.exif[TAGS.exif[0x927C]].getString(0, 7) === "AGFA \x00\x01") {
+ type = "agfa";
+
+ } else if (exifData.exif[TAGS.exif[0x927C]].getString(0, 8) === "EPSON\x00\x01\x00") {
+ type = "epson";
+
+ } else if (exifData.exif[TAGS.exif[0x927C]].getString(0, 8) === "FUJIFILM") {
+ type = "fujifilm";
+
+ } else if (exifData.exif[TAGS.exif[0x927C]].getString(0, 9) === "Panasonic") {
+ type = "panasonic";
+
+ } else if (exifData.exif[TAGS.exif[0x927C]].getString(0, 5) === "SANYO") {
+ type = "sanyo";
+ }
+
+
+ debug("Makernote IFD ifdOffset=", ifdOffset, "type=", type);
+
+ if (type) {
+ const emn = await import('./makernotes/' + type)
+ var extractMakernotes = emn.extractMakernotes;
+
+ exifData.makernote = extractMakernotes.call(this, data, this.offsets.makernoteOffset, tiffOffset);
+ } else {
+ // Makernotes are available but the format is not recognized so
+ // an error message is pushed instead, this ain't the best
+ // solution but should do for now
+ exifData.makernote['error'] = 'Unable to extract Makernote information as it is in an unsupported or unrecognized format.';
+ }
+
+ debug("Makernote IFD parsed", exifData.makernote);
+ }
+ };
+
+ async extractExifEntry(data, entryOffset, tiffOffset, isBigEndian, tags) {
+
+ var entry = {
+ tag: data.slice(entryOffset, entryOffset + 2),
+ tagId: null,
+ tagName: null,
+ format: data.getShort(entryOffset + 2, isBigEndian),
+ components: data.getLong(entryOffset + 4, isBigEndian),
+ valueOffset: null,
+ value: []
+ }
+
+ // if(entryOffset === 3082){
+ // console.log("Error coming")
+ // }
+ // console.log({entryOffset, entryComponents: entry.components})
+ entry.tagId = entry.tag.getShort(0, isBigEndian);
+
+ // The tagId may correspond to more then one tagName so check which
+ if (tags && tags[entry.tagId] && typeof tags[entry.tagId] == "function") {
+ entry.tagName = tags[entry.tagId].call(this, entry);
+ if (!entry.tagName) {
+ return false;
+ }
+
+ // The tagId corresponds to exactly one tagName
+ } else if (tags && tags[entry.tagId]) {
+ entry.tagName = tags[entry.tagId];
+ if (entry.tagName === undefined) {
+ return false;
+ }
+
+ // The tagId is not recognized
+ } else {
+ return false;
+ }
+
+ // make sure index in subsequent loops can't exceed data length
+ if (entry.valueOffset + entry.components * 4 >= data.length) {
+ return false
+ }
+
+ switch (entry.format) {
+
+ case 0x0001: // unsigned byte, 1 byte per component
+ entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getByte(entry.valueOffset + i));
+ break;
+
+ case 0x0002: // ascii strings, 1 byte per component
+ entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ entry.value = data.getString(entry.valueOffset, entry.components);
+ if (entry.value[entry.value.length - 1] === "\u0000") // Trim null terminated strings
+ entry.value = entry.value.substring(0, entry.value.length - 1);
+ break;
+
+ case 0x0003: // unsigned short, 2 byte per component
+ entry.valueOffset = (entry.components <= 2) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getShort(entry.valueOffset + i * 2, isBigEndian));
+ break;
+
+ case 0x0004: // unsigned long, 4 byte per component
+ entry.valueOffset = (entry.components == 1) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getLong(entry.valueOffset + i * 4, isBigEndian));
+ break;
+
+ case 0x0005: // unsigned rational, 8 byte per component (4 byte numerator and 4 byte denominator)
+ entry.valueOffset = data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getLong(entry.valueOffset + i * 8, isBigEndian) / data.getLong(entry.valueOffset + i * 8 + 4, isBigEndian));
+ break;
+
+ case 0x0006: // signed byte, 1 byte per component
+ entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getSignedByte(entry.valueOffset + i));
+ break;
+
+ case 0x0007: // undefined, 1 byte per component
+ entry.valueOffset = (entry.components <= 4) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ entry.value.push(data.slice(entry.valueOffset, entry.valueOffset + entry.components));
+ break;
+
+ case 0x0008: // signed short, 2 byte per component
+ entry.valueOffset = (entry.components <= 2) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getSignedShort(entry.valueOffset + i * 2, isBigEndian));
+ break;
+
+ case 0x0009: // signed long, 4 byte per component
+ entry.valueOffset = (entry.components == 1) ? entryOffset + 8 : data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getSignedLong(entry.valueOffset + i * 4, isBigEndian));
+ break;
+
+ case 0x000A: // signed rational, 8 byte per component (4 byte numerator and 4 byte denominator)
+ entry.valueOffset = data.getLong(entryOffset + 8, isBigEndian) + tiffOffset;
+ for (var i = 0; i < entry.components; i++)
+ entry.value.push(data.getSignedLong(entry.valueOffset + i * 8, isBigEndian) / data.getSignedLong(entry.valueOffset + i * 8 + 4, isBigEndian));
+ break;
+
+ default:
+ return false;
+
+ }
+
+ // If this is the Makernote tag save its offset for later use
+ if (entry.tagName === "MakerNote") {
+ this.offsets.makernoteOffset = entry.valueOffset;
+ }
+
+ // If the value array has only one element we don't need an array
+ if (entry.value.length == 1) {
+ entry.value = entry.value[0];
+ }
+
+ return entry;
+ };
+
+
+}
+
+/**
+* Comprehensive list of TIFF and Exif tags found on
+* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
+*/
+const TAGS = {
+
+ // Exif tags
+ exif: {
+
+ 0x0001: "InteropIndex",
+ 0x0002: "InteropVersion",
+ 0x000B: "ProcessingSoftware",
+ 0x00FE: "SubfileType",
+ 0x00FF: "OldSubfileType",
+ 0x0100: "ImageWidth",
+ 0x0101: "ImageHeight",
+ 0x0102: "BitsPerSample",
+ 0x0103: "Compression",
+ 0x0106: "PhotometricInterpretation",
+ 0x0107: "Thresholding",
+ 0x0108: "CellWidth",
+ 0x0109: "CellLength",
+ 0x010A: "FillOrder",
+ 0x010D: "DocumentName",
+ 0x010E: "ImageDescription",
+ 0x010F: "Make",
+ 0x0110: "Model",
+ 0x0111: "StripOffsets",
+ 0x0112: "Orientation",
+ 0x0115: "SamplesPerPixel",
+ 0x0116: "RowsPerStrip",
+ 0x0117: "StripByteCounts",
+ 0x0118: "MinSampleValue",
+ 0x0119: "MaxSampleValue",
+ 0x011A: "XResolution",
+ 0x011B: "YResolution",
+ 0x011C: "PlanarConfiguration",
+ 0x011D: "PageName",
+ 0x011E: "XPosition",
+ 0x011F: "YPosition",
+ 0x0120: "FreeOffsets",
+ 0x0121: "FreeByteCounts",
+ 0x0122: "GrayResponseUnit",
+ 0x0123: "GrayResponseCurve",
+ 0x0124: "T4Options",
+ 0x0125: "T6Options",
+ 0x0128: "ResolutionUnit",
+ 0x0129: "PageNumber",
+ 0x012C: "ColorResponseUnit",
+ 0x012D: "TransferFunction",
+ 0x0131: "Software",
+ 0x0132: "ModifyDate",
+ 0x013B: "Artist",
+ 0x013C: "HostComputer",
+ 0x013D: "Predictor",
+ 0x013E: "WhitePoint",
+ 0x013F: "PrimaryChromaticities",
+ 0x0140: "ColorMap",
+ 0x0141: "HalftoneHints",
+ 0x0142: "TileWidth",
+ 0x0143: "TileLength",
+ 0x0144: "TileOffsets",
+ 0x0145: "TileByteCounts",
+ 0x0146: "BadFaxLines",
+ 0x0147: "CleanFaxData",
+ 0x0148: "ConsecutiveBadFaxLines",
+ 0x014A: "SubIFD",
+ 0x014C: "InkSet",
+ 0x014D: "InkNames",
+ 0x014E: "NumberofInks",
+ 0x0150: "DotRange",
+ 0x0151: "TargetPrinter",
+ 0x0152: "ExtraSamples",
+ 0x0153: "SampleFormat",
+ 0x0154: "SMinSampleValue",
+ 0x0155: "SMaxSampleValue",
+ 0x0156: "TransferRange",
+ 0x0157: "ClipPath",
+ 0x0158: "XClipPathUnits",
+ 0x0159: "YClipPathUnits",
+ 0x015A: "Indexed",
+ 0x015B: "JPEGTables",
+ 0x015F: "OPIProxy",
+ 0x0190: "GlobalParametersIFD",
+ 0x0191: "ProfileType",
+ 0x0192: "FaxProfile",
+ 0x0193: "CodingMethods",
+ 0x0194: "VersionYear",
+ 0x0195: "ModeNumber",
+ 0x01B1: "Decode",
+ 0x01B2: "DefaultImageColor",
+ 0x01B3: "T82Options",
+ 0x01B5: "JPEGTables",
+ 0x0200: "JPEGProc",
+ 0x0201: "ThumbnailOffset",
+ 0x0202: "ThumbnailLength",
+ 0x0203: "JPEGRestartInterval",
+ 0x0205: "JPEGLosslessPredictors",
+ 0x0206: "JPEGPointTransforms",
+ 0x0207: "JPEGQTables",
+ 0x0208: "JPEGDCTables",
+ 0x0209: "JPEGACTables",
+ 0x0211: "YCbCrCoefficients",
+ 0x0212: "YCbCrSubSampling",
+ 0x0213: "YCbCrPositioning",
+ 0x0214: "ReferenceBlackWhite",
+ 0x022F: "StripRowCounts",
+ 0x02BC: "ApplicationNotes",
+ 0x03E7: "USPTOMiscellaneous",
+ 0x1000: "RelatedImageFileFormat",
+ 0x1001: "RelatedImageWidth",
+ 0x1002: "RelatedImageHeight",
+ 0x4746: "Rating",
+ 0x4747: "XP_DIP_XML",
+ 0x4748: "StitchInfo",
+ 0x4749: "RatingPercent",
+ 0x800D: "ImageID",
+ 0x80A3: "WangTag1",
+ 0x80A4: "WangAnnotation",
+ 0x80A5: "WangTag3",
+ 0x80A6: "WangTag4",
+ 0x80E3: "Matteing",
+ 0x80E4: "DataType",
+ 0x80E5: "ImageDepth",
+ 0x80E6: "TileDepth",
+ 0x827D: "Model2",
+ 0x828D: "CFARepeatPatternDim",
+ 0x828E: "CFAPattern2",
+ 0x828F: "BatteryLevel",
+ 0x8290: "KodakIFD",
+ 0x8298: "Copyright",
+ 0x829A: "ExposureTime",
+ 0x829D: "FNumber",
+ 0x82A5: "MDFileTag",
+ 0x82A6: "MDScalePixel",
+ 0x82A7: "MDColorTable",
+ 0x82A8: "MDLabName",
+ 0x82A9: "MDSampleInfo",
+ 0x82AA: "MDPrepDate",
+ 0x82AB: "MDPrepTime",
+ 0x82AC: "MDFileUnits",
+ 0x830E: "PixelScale",
+ 0x8335: "AdventScale",
+ 0x8336: "AdventRevision",
+ 0x835C: "UIC1Tag",
+ 0x835D: "UIC2Tag",
+ 0x835E: "UIC3Tag",
+ 0x835F: "UIC4Tag",
+ 0x83BB: "IPTC-NAA",
+ 0x847E: "IntergraphPacketData",
+ 0x847F: "IntergraphFlagRegisters",
+ 0x8480: "IntergraphMatrix",
+ 0x8481: "INGRReserved",
+ 0x8482: "ModelTiePoint",
+ 0x84E0: "Site",
+ 0x84E1: "ColorSequence",
+ 0x84E2: "IT8Header",
+ 0x84E3: "RasterPadding",
+ 0x84E4: "BitsPerRunLength",
+ 0x84E5: "BitsPerExtendedRunLength",
+ 0x84E6: "ColorTable",
+ 0x84E7: "ImageColorIndicator",
+ 0x84E8: "BackgroundColorIndicator",
+ 0x84E9: "ImageColorValue",
+ 0x84EA: "BackgroundColorValue",
+ 0x84EB: "PixelIntensityRange",
+ 0x84EC: "TransparencyIndicator",
+ 0x84ED: "ColorCharacterization",
+ 0x84EE: "HCUsage",
+ 0x84EF: "TrapIndicator",
+ 0x84F0: "CMYKEquivalent",
+ 0x8546: "SEMInfo",
+ 0x8568: "AFCP_IPTC",
+ 0x85B8: "PixelMagicJBIGOptions",
+ 0x85D8: "ModelTransform",
+ 0x8602: "WB_GRGBLevels",
+ 0x8606: "LeafData",
+ 0x8649: "PhotoshopSettings",
+ 0x8769: "ExifOffset",
+ 0x8773: "ICC_Profile",
+ 0x877F: "TIFF_FXExtensions",
+ 0x8780: "MultiProfiles",
+ 0x8781: "SharedData",
+ 0x8782: "T88Options",
+ 0x87AC: "ImageLayer",
+ 0x87AF: "GeoTiffDirectory",
+ 0x87B0: "GeoTiffDoubleParams",
+ 0x87B1: "GeoTiffAsciiParams",
+ 0x8822: "ExposureProgram",
+ 0x8824: "SpectralSensitivity",
+ 0x8825: "GPSInfo",
+ 0x8827: "ISO",
+ 0x8828: "Opto-ElectricConvFactor",
+ 0x8829: "Interlace",
+ 0x882A: "TimeZoneOffset",
+ 0x882B: "SelfTimerMode",
+ 0x8830: "SensitivityType",
+ 0x8831: "StandardOutputSensitivity",
+ 0x8832: "RecommendedExposureIndex",
+ 0x8833: "ISOSpeed",
+ 0x8834: "ISOSpeedLatitudeyyy",
+ 0x8835: "ISOSpeedLatitudezzz",
+ 0x885C: "FaxRecvParams",
+ 0x885D: "FaxSubAddress",
+ 0x885E: "FaxRecvTime",
+ 0x888A: "LeafSubIFD",
+ 0x9000: "ExifVersion",
+ 0x9003: "DateTimeOriginal",
+ 0x9004: "CreateDate",
+ 0x9010: "OffsetTime",
+ 0x9011: "OffsetTimeOriginal",
+ 0x9012: "OffsetTimeDigitized",
+ 0x9101: "ComponentsConfiguration",
+ 0x9102: "CompressedBitsPerPixel",
+ 0x9201: "ShutterSpeedValue",
+ 0x9202: "ApertureValue",
+ 0x9203: "BrightnessValue",
+ 0x9204: "ExposureCompensation",
+ 0x9205: "MaxApertureValue",
+ 0x9206: "SubjectDistance",
+ 0x9207: "MeteringMode",
+ 0x9208: "LightSource",
+ 0x9209: "Flash",
+ 0x920A: "FocalLength",
+ 0x920B: "FlashEnergy",
+ 0x920C: "SpatialFrequencyResponse",
+ 0x920D: "Noise",
+ 0x920E: "FocalPlaneXResolution",
+ 0x920F: "FocalPlaneYResolution",
+ 0x9210: "FocalPlaneResolutionUnit",
+ 0x9211: "ImageNumber",
+ 0x9212: "SecurityClassification",
+ 0x9213: "ImageHistory",
+ 0x9214: "SubjectArea",
+ 0x9215: "ExposureIndex",
+ 0x9216: "TIFF-EPStandardID",
+ 0x9217: "SensingMethod",
+ 0x923A: "CIP3DataFile",
+ 0x923B: "CIP3Sheet",
+ 0x923C: "CIP3Side",
+ 0x923F: "StoNits",
+ 0x927C: "MakerNote",
+ 0x9286: "UserComment",
+ 0x9290: "SubSecTime",
+ 0x9291: "SubSecTimeOriginal",
+ 0x9292: "SubSecTimeDigitized",
+ 0x932F: "MSDocumentText",
+ 0x9330: "MSPropertySetStorage",
+ 0x9331: "MSDocumentTextPosition",
+ 0x935C: "ImageSourceData",
+ 0x9C9B: "XPTitle",
+ 0x9C9C: "XPComment",
+ 0x9C9D: "XPAuthor",
+ 0x9C9E: "XPKeywords",
+ 0x9C9F: "XPSubject",
+ 0xA000: "FlashpixVersion",
+ 0xA001: "ColorSpace",
+ 0xA002: "ExifImageWidth",
+ 0xA003: "ExifImageHeight",
+ 0xA004: "RelatedSoundFile",
+ 0xA005: "InteropOffset",
+ 0xA20B: "FlashEnergy",
+ 0xA20C: "SpatialFrequencyResponse",
+ 0xA20D: "Noise",
+ 0xA20E: "FocalPlaneXResolution",
+ 0xA20F: "FocalPlaneYResolution",
+ 0xA210: "FocalPlaneResolutionUnit",
+ 0xA211: "ImageNumber",
+ 0xA212: "SecurityClassification",
+ 0xA213: "ImageHistory",
+ 0xA214: "SubjectLocation",
+ 0xA215: "ExposureIndex",
+ 0xA216: "TIFF-EPStandardID",
+ 0xA217: "SensingMethod",
+ 0xA300: "FileSource",
+ 0xA301: "SceneType",
+ 0xA302: "CFAPattern",
+ 0xA401: "CustomRendered",
+ 0xA402: "ExposureMode",
+ 0xA403: "WhiteBalance",
+ 0xA404: "DigitalZoomRatio",
+ 0xA405: "FocalLengthIn35mmFormat",
+ 0xA406: "SceneCaptureType",
+ 0xA407: "GainControl",
+ 0xA408: "Contrast",
+ 0xA409: "Saturation",
+ 0xA40A: "Sharpness",
+ 0xA40B: "DeviceSettingDescription",
+ 0xA40C: "SubjectDistanceRange",
+ 0xA420: "ImageUniqueID",
+ 0xA430: "OwnerName",
+ 0xA431: "SerialNumber",
+ 0xA432: "LensInfo",
+ 0xA433: "LensMake",
+ 0xA434: "LensModel",
+ 0xA435: "LensSerialNumber",
+ 0xA480: "GDALMetadata",
+ 0xA481: "GDALNoData",
+ 0xA500: "Gamma",
+ 0xAFC0: "ExpandSoftware",
+ 0xAFC1: "ExpandLens",
+ 0xAFC2: "ExpandFilm",
+ 0xAFC3: "ExpandFilterLens",
+ 0xAFC4: "ExpandScanner",
+ 0xAFC5: "ExpandFlashLamp",
+ 0xBC01: "PixelFormat",
+ 0xBC02: "Transformation",
+ 0xBC03: "Uncompressed",
+ 0xBC04: "ImageType",
+ 0xBC80: "ImageWidth",
+ 0xBC81: "ImageHeight",
+ 0xBC82: "WidthResolution",
+ 0xBC83: "HeightResolution",
+ 0xBCC0: "ImageOffset",
+ 0xBCC1: "ImageByteCount",
+ 0xBCC2: "AlphaOffset",
+ 0xBCC3: "AlphaByteCount",
+ 0xBCC4: "ImageDataDiscard",
+ 0xBCC5: "AlphaDataDiscard",
+ 0xC427: "OceScanjobDesc",
+ 0xC428: "OceApplicationSelector",
+ 0xC429: "OceIDNumber",
+ 0xC42A: "OceImageLogic",
+ 0xC44F: "Annotations",
+ 0xC4A5: "PrintIM",
+ 0xC580: "USPTOOriginalContentType",
+ 0xC612: "DNGVersion",
+ 0xC613: "DNGBackwardVersion",
+ 0xC614: "UniqueCameraModel",
+ 0xC615: "LocalizedCameraModel",
+ 0xC616: "CFAPlaneColor",
+ 0xC617: "CFALayout",
+ 0xC618: "LinearizationTable",
+ 0xC619: "BlackLevelRepeatDim",
+ 0xC61A: "BlackLevel",
+ 0xC61B: "BlackLevelDeltaH",
+ 0xC61C: "BlackLevelDeltaV",
+ 0xC61D: "WhiteLevel",
+ 0xC61E: "DefaultScale",
+ 0xC61F: "DefaultCropOrigin",
+ 0xC620: "DefaultCropSize",
+ 0xC621: "ColorMatrix1",
+ 0xC622: "ColorMatrix2",
+ 0xC623: "CameraCalibration1",
+ 0xC624: "CameraCalibration2",
+ 0xC625: "ReductionMatrix1",
+ 0xC626: "ReductionMatrix2",
+ 0xC627: "AnalogBalance",
+ 0xC628: "AsShotNeutral",
+ 0xC629: "AsShotWhiteXY",
+ 0xC62A: "BaselineExposure",
+ 0xC62B: "BaselineNoise",
+ 0xC62C: "BaselineSharpness",
+ 0xC62D: "BayerGreenSplit",
+ 0xC62E: "LinearResponseLimit",
+ 0xC62F: "CameraSerialNumber",
+ 0xC630: "DNGLensInfo",
+ 0xC631: "ChromaBlurRadius",
+ 0xC632: "AntiAliasStrength",
+ 0xC633: "ShadowScale",
+ 0xC634: "DNGPrivateData",
+ 0xC635: "MakerNoteSafety",
+ 0xC640: "RawImageSegmentation",
+ 0xC65A: "CalibrationIlluminant1",
+ 0xC65B: "CalibrationIlluminant2",
+ 0xC65C: "BestQualityScale",
+ 0xC65D: "RawDataUniqueID",
+ 0xC660: "AliasLayerMetadata",
+ 0xC68B: "OriginalRawFileName",
+ 0xC68C: "OriginalRawFileData",
+ 0xC68D: "ActiveArea",
+ 0xC68E: "MaskedAreas",
+ 0xC68F: "AsShotICCProfile",
+ 0xC690: "AsShotPreProfileMatrix",
+ 0xC691: "CurrentICCProfile",
+ 0xC692: "CurrentPreProfileMatrix",
+ 0xC6BF: "ColorimetricReference",
+ 0xC6D2: "PanasonicTitle",
+ 0xC6D3: "PanasonicTitle2",
+ 0xC6F3: "CameraCalibrationSig",
+ 0xC6F4: "ProfileCalibrationSig",
+ 0xC6F5: "ProfileIFD",
+ 0xC6F6: "AsShotProfileName",
+ 0xC6F7: "NoiseReductionApplied",
+ 0xC6F8: "ProfileName",
+ 0xC6F9: "ProfileHueSatMapDims",
+ 0xC6FA: "ProfileHueSatMapData1",
+ 0xC6FB: "ProfileHueSatMapData2",
+ 0xC6FC: "ProfileToneCurve",
+ 0xC6FD: "ProfileEmbedPolicy",
+ 0xC6FE: "ProfileCopyright",
+ 0xC714: "ForwardMatrix1",
+ 0xC715: "ForwardMatrix2",
+ 0xC716: "PreviewApplicationName",
+ 0xC717: "PreviewApplicationVersion",
+ 0xC718: "PreviewSettingsName",
+ 0xC719: "PreviewSettingsDigest",
+ 0xC71A: "PreviewColorSpace",
+ 0xC71B: "PreviewDateTime",
+ 0xC71C: "RawImageDigest",
+ 0xC71D: "OriginalRawFileDigest",
+ 0xC71E: "SubTileBlockSize",
+ 0xC71F: "RowInterleaveFactor",
+ 0xC725: "ProfileLookTableDims",
+ 0xC726: "ProfileLookTableData",
+ 0xC740: "OpcodeList1",
+ 0xC741: "OpcodeList2",
+ 0xC74E: "OpcodeList3",
+ 0xC761: "NoiseProfile",
+ 0xC763: "TimeCodes",
+ 0xC764: "FrameRate",
+ 0xC772: "TStop",
+ 0xC789: "ReelName",
+ 0xC791: "OriginalDefaultFinalSize",
+ 0xC792: "OriginalBestQualitySize",
+ 0xC793: "OriginalDefaultCropSize",
+ 0xC7A1: "CameraLabel",
+ 0xC7A3: "ProfileHueSatMapEncoding",
+ 0xC7A4: "ProfileLookTableEncoding",
+ 0xC7A5: "BaselineExposureOffset",
+ 0xC7A6: "DefaultBlackRender",
+ 0xC7A7: "NewRawImageDigest",
+ 0xC7A8: "RawToPreviewGain",
+ 0xC7B5: "DefaultUserCrop",
+ 0xEA1C: "Padding",
+ 0xEA1D: "OffsetSchema",
+ 0xFDE8: "OwnerName",
+ 0xFDE9: "SerialNumber",
+ 0xFDEA: "Lens",
+ 0xFE00: "KDC_IFD",
+ 0xFE4C: "RawFile",
+ 0xFE4D: "Converter",
+ 0xFE4E: "WhiteBalance",
+ 0xFE51: "Exposure",
+ 0xFE52: "Shadows",
+ 0xFE53: "Brightness",
+ 0xFE54: "Contrast",
+ 0xFE55: "Saturation",
+ 0xFE56: "Sharpness",
+ 0xFE57: "Smoothness",
+ 0xFE58: "MoireFilter"
+
+ },
+
+ // GPS Tags
+ gps: {
+
+ 0x0000: 'GPSVersionID',
+ 0x0001: 'GPSLatitudeRef',
+ 0x0002: 'GPSLatitude',
+ 0x0003: 'GPSLongitudeRef',
+ 0x0004: 'GPSLongitude',
+ 0x0005: 'GPSAltitudeRef',
+ 0x0006: 'GPSAltitude',
+ 0x0007: 'GPSTimeStamp',
+ 0x0008: 'GPSSatellites',
+ 0x0009: 'GPSStatus',
+ 0x000A: 'GPSMeasureMode',
+ 0x000B: 'GPSDOP',
+ 0x000C: 'GPSSpeedRef',
+ 0x000D: 'GPSSpeed',
+ 0x000E: 'GPSTrackRef',
+ 0x000F: 'GPSTrack',
+ 0x0010: 'GPSImgDirectionRef',
+ 0x0011: 'GPSImgDirection',
+ 0x0012: 'GPSMapDatum',
+ 0x0013: 'GPSDestLatitudeRef',
+ 0x0014: 'GPSDestLatitude',
+ 0x0015: 'GPSDestLongitudeRef',
+ 0x0016: 'GPSDestLongitude',
+ 0x0017: 'GPSDestBearingRef',
+ 0x0018: 'GPSDestBearing',
+ 0x0019: 'GPSDestDistanceRef',
+ 0x001A: 'GPSDestDistance',
+ 0x001B: 'GPSProcessingMethod',
+ 0x001C: 'GPSAreaInformation',
+ 0x001D: 'GPSDateStamp',
+ 0x001E: 'GPSDifferential',
+ 0x001F: 'GPSHPositioningError'
+
+ }
+}
\ No newline at end of file
diff --git a/lib/exif/makernotes/agfa.js b/src/makernotes/agfa.js
similarity index 100%
rename from lib/exif/makernotes/agfa.js
rename to src/makernotes/agfa.js
diff --git a/lib/exif/makernotes/epson.js b/src/makernotes/epson.js
similarity index 100%
rename from lib/exif/makernotes/epson.js
rename to src/makernotes/epson.js
diff --git a/lib/exif/makernotes/fujifilm.js b/src/makernotes/fujifilm.js
similarity index 100%
rename from lib/exif/makernotes/fujifilm.js
rename to src/makernotes/fujifilm.js
diff --git a/lib/exif/makernotes/olympus.js b/src/makernotes/olympus.js
similarity index 100%
rename from lib/exif/makernotes/olympus.js
rename to src/makernotes/olympus.js
diff --git a/lib/exif/makernotes/panasonic.js b/src/makernotes/panasonic.js
similarity index 100%
rename from lib/exif/makernotes/panasonic.js
rename to src/makernotes/panasonic.js
diff --git a/lib/exif/makernotes/sanyo.js b/src/makernotes/sanyo.js
similarity index 100%
rename from lib/exif/makernotes/sanyo.js
rename to src/makernotes/sanyo.js
diff --git a/test/.DS_Store b/test/.DS_Store
new file mode 100644
index 0000000..af7d2c4
Binary files /dev/null and b/test/.DS_Store differ
diff --git a/test/api-test.js b/test/api-test.js
index 1e54033..9bde20d 100644
--- a/test/api-test.js
+++ b/test/api-test.js
@@ -1,129 +1,48 @@
-var assert = require('assert');
-var fs=require('fs');
-var Path = require('path');
+import { assert } from 'chai'
+import fs from 'fs/promises'
+import Path from 'path'
+import { fileURLToPath } from 'url';
+import { dirname } from 'path';
+import ExifImage from '../src/ExifImage.js'
-describe('node-exif API', function() {
-
- var path=Path.join(__dirname, "evil1.jpg");
- var json='{"image":{"Make":"Canon","Model":"Canon PowerShot S400","Orientation":1,"XResolution":180,"YResolution":180,"ResolutionUnit":2,"Software":"Adobe Photoshop 7.0","ModifyDate":"2003:05:25 11:11:41","YCbCrPositioning":1,"ExifOffset":217},"thumbnail":{"Compression":6,"XResolution":72,"YResolution":72,"ResolutionUnit":2,"ThumbnailOffset":1057,"ThumbnailLength":6298},"exif":{"ExposureTime":0.125,"FNumber":2.8,"ExifVersion":{"type":"Buffer","data":[48,50,50,48]},"DateTimeOriginal":"2003:05:24 16:40:33","CreateDate":"2003:05:24 16:40:33","ComponentsConfiguration":{"type":"Buffer","data":[1,2,3,0]},"CompressedBitsPerPixel":3,"ShutterSpeedValue":3,"ApertureValue":2.96875,"ExposureCompensation":0,"MaxApertureValue":2.96875,"MeteringMode":5,"Flash":16,"FocalLength":7.40625,"UserComment":{"type":"Buffer","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"FlashpixVersion":{"type":"Buffer","data":[48,49,48,48]},"ColorSpace":1,"ExifImageWidth":400,"ExifImageHeight":300,"FocalPlaneXResolution":8114.285714285715,"FocalPlaneYResolution":8114.285714285715,"FocalPlaneResolutionUnit":2,"SensingMethod":2,"FileSource":{"type":"Buffer","data":[3]},"CustomRendered":0,"ExposureMode":0,"WhiteBalance":0,"DigitalZoomRatio":1,"SceneCaptureType":0},"gps":{},"interoperability":{},"makernote":{}}';
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
-
- it('test constructor (filename)', function(done) {
+describe('node-exif API', function () {
- var ExifImage = require('..').ExifImage;
+ var path = Path.join(__dirname, "evil1.jpg");
+ var json = '{"image":{"Make":"Canon","Model":"Canon PowerShot S400","Orientation":1,"XResolution":180,"YResolution":180,"ResolutionUnit":2,"Software":"Adobe Photoshop 7.0","ModifyDate":"2003:05:25 11:11:41","YCbCrPositioning":1,"ExifOffset":217},"thumbnail":{"Compression":6,"XResolution":72,"YResolution":72,"ResolutionUnit":2,"ThumbnailOffset":1057,"ThumbnailLength":6298},"exif":{"ExposureTime":0.125,"FNumber":2.8,"ExifVersion":{"type":"Buffer","data":[48,50,50,48]},"DateTimeOriginal":"2003:05:24 16:40:33","CreateDate":"2003:05:24 16:40:33","ComponentsConfiguration":{"type":"Buffer","data":[1,2,3,0]},"CompressedBitsPerPixel":3,"ShutterSpeedValue":3,"ApertureValue":2.96875,"ExposureCompensation":0,"MaxApertureValue":2.96875,"MeteringMode":5,"Flash":16,"FocalLength":7.40625,"UserComment":{"type":"Buffer","data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"FlashpixVersion":{"type":"Buffer","data":[48,49,48,48]},"ColorSpace":1,"ExifImageWidth":400,"ExifImageHeight":300,"FocalPlaneXResolution":8114.285714285715,"FocalPlaneYResolution":8114.285714285715,"FocalPlaneResolutionUnit":2,"SensingMethod":2,"FileSource":{"type":"Buffer","data":[3]},"CustomRendered":0,"ExposureMode":0,"WhiteBalance":0,"DigitalZoomRatio":1,"SceneCaptureType":0},"gps":{},"interoperability":{},"makernote":{}}';
- new ExifImage({image: path }, function(error, data) {
- if (error) {
- throw error;
- }
-
- assert.equal(JSON.stringify(data), json, "Not same datas ?");
-
- done();
- });
- });
-
- it('test constructor (buffer)', function(done) {
- var ExifImage = require('..').ExifImage;
-
- var buffer=fs.readFileSync(path);
-
- new ExifImage({image: buffer }, function(error, data) {
- if (error) {
- throw error;
- }
-
- assert.equal(JSON.stringify(data), json, "Not same datas ?");
-
- done();
- });
+ it('test constructor (filename)', async function () {
+ let data = await ExifImage({ image: path });
+ assert.equal(JSON.stringify(data), json, "Not same datas ?");
});
- it('test loadImage (filename)', function(done) {
-
- var ExifImage = require('..').ExifImage;
-
- var exif=new ExifImage();
-
- exif.loadImage(path, function(error, data) {
- if (error) {
- throw error;
- }
-
- assert.equal(JSON.stringify(data), json, "Not same datas ?");
-
- done();
- });
- });
-
- it('test loadImage (buffer)', function(done) {
-
- var ExifImage = require('..').ExifImage;
-
- var buffer=fs.readFileSync(path);
-
- var exif=new ExifImage();
-
- exif.loadImage(buffer , function(error, data) {
- if (error) {
- throw error;
- }
-
- assert.equal(JSON.stringify(data), json, "Not same datas");
-
- done();
- });
+ it('test constructor (buffer)', async function () {
+ var buffer = await fs.readFile(path);
+ let data = await ExifImage({ image: buffer });
+ assert.equal(JSON.stringify(data), json, "Not same datas ?");
});
+});
- it('test wrapper', function(done) {
+describe('node-exif tests', async function () {
+ var files = await fs.readdir(__dirname);
- var Exif = require('..');
+ for (let file of files) {
+ if (!/\.jpg$/.exec(file)) {
+ continue;
+ }
- Exif(path, function(error, data, dataPath) {
- if (error) {
- throw error;
- }
-
- assert.equal(dataPath, path, "Not same path");
- delete data.path;
-
- assert.equal(JSON.stringify(data), json, "Not same datas ?");
-
- done();
- });
- });
-});
+ var path = Path.join(__dirname, file);
-describe('node-exif tests', function() {
- var ExifImage = require('..').ExifImage;
+ it('test ' + file, async function () {
+ var expected = String(await fs.readFile(path + ".json"));
- var files=fs.readdirSync(__dirname);
-
- files.forEach(function(f) {
- if (!/\.jpg$/.exec(f)) {
- return;
- }
-
- var path=Path.join(__dirname, f);
-
- it('test '+f, function(done) {
- var expected=String(fs.readFileSync(path+".json"));
-
- new ExifImage({image: path }, function(error, data) {
- if (error) {
- throw error;
- }
+ let data = await ExifImage({ image: path });
+ var json = JSON.stringify(data);
- var json=JSON.stringify(data);
-
- //console.log(" data=", json, json.length);
- // console.log("expected=", expected, expected.length);
-
- assert.equal(json, expected, "Data are not the same");
-
- done();
- });
+ assert.equal(json, expected, "Data are not the same");
});
- });
+ }
});