3dmol
Version:
Object oriented Javascript molecular visualization library
1,771 lines (1,544 loc) • 98.3 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define('netcdfjs',[], factory);
else if(typeof exports === 'object')
exports["netcdfjs"] = factory();
else
root["netcdfjs"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Throws a non-valid NetCDF exception if the statement it's true
* @ignore
* @param {boolean} statement - Throws if true
* @param {string} reason - Reason to throw
*/
function notNetcdf(statement, reason) {
if (statement) {
throw new TypeError('Not a valid NetCDF v3.x file: ' + reason);
}
}
/**
* Moves 1, 2, or 3 bytes to next 4-byte boundary
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
*/
function padding(buffer) {
if (buffer.offset % 4 !== 0) {
buffer.skip(4 - buffer.offset % 4);
}
}
/**
* Reads the name
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {string} - Name
*/
function readName(buffer) {
// Read name
var nameLength = buffer.readUint32();
var name = buffer.readChars(nameLength);
// validate name
// TODO
// Apply padding
padding(buffer);
return name;
}
module.exports.notNetcdf = notNetcdf;
module.exports.padding = padding;
module.exports.readName = readName;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const notNetcdf = __webpack_require__(0).notNetcdf;
const types = {
BYTE: 1,
CHAR: 2,
SHORT: 3,
INT: 4,
FLOAT: 5,
DOUBLE: 6
};
/**
* Parse a number into their respective type
* @ignore
* @param {number} type - integer that represents the type
* @return {string} - parsed value of the type
*/
function num2str(type) {
switch (Number(type)) {
case types.BYTE:
return 'byte';
case types.CHAR:
return 'char';
case types.SHORT:
return 'short';
case types.INT:
return 'int';
case types.FLOAT:
return 'float';
case types.DOUBLE:
return 'double';
/* istanbul ignore next */
default:
return 'undefined';
}
}
/**
* Parse a number type identifier to his size in bytes
* @ignore
* @param {number} type - integer that represents the type
* @return {number} -size of the type
*/
function num2bytes(type) {
switch (Number(type)) {
case types.BYTE:
return 1;
case types.CHAR:
return 1;
case types.SHORT:
return 2;
case types.INT:
return 4;
case types.FLOAT:
return 4;
case types.DOUBLE:
return 8;
/* istanbul ignore next */
default:
return -1;
}
}
/**
* Reverse search of num2str
* @ignore
* @param {string} type - string that represents the type
* @return {number} - parsed value of the type
*/
function str2num(type) {
switch (String(type)) {
case 'byte':
return types.BYTE;
case 'char':
return types.CHAR;
case 'short':
return types.SHORT;
case 'int':
return types.INT;
case 'float':
return types.FLOAT;
case 'double':
return types.DOUBLE;
/* istanbul ignore next */
default:
return -1;
}
}
/**
* Auxiliary function to read numeric data
* @ignore
* @param {number} size - Size of the element to read
* @param {function} bufferReader - Function to read next value
* @return {Array<number>|number}
*/
function readNumber(size, bufferReader) {
if (size !== 1) {
var numbers = new Array(size);
for (var i = 0; i < size; i++) {
numbers[i] = bufferReader();
}
return numbers;
} else {
return bufferReader();
}
}
/**
* Given a type and a size reads the next element
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} type - Type of the data to read
* @param {number} size - Size of the element to read
* @return {string|Array<number>|number}
*/
function readType(buffer, type, size) {
switch (type) {
case types.BYTE:
return buffer.readBytes(size);
case types.CHAR:
return trimNull(buffer.readChars(size));
case types.SHORT:
return readNumber(size, buffer.readInt16.bind(buffer));
case types.INT:
return readNumber(size, buffer.readInt32.bind(buffer));
case types.FLOAT:
return readNumber(size, buffer.readFloat32.bind(buffer));
case types.DOUBLE:
return readNumber(size, buffer.readFloat64.bind(buffer));
/* istanbul ignore next */
default:
notNetcdf(true, 'non valid type ' + type);
return undefined;
}
}
/**
* Removes null terminate value
* @ignore
* @param {string} value - String to trim
* @return {string} - Trimmed string
*/
function trimNull(value) {
if (value.charCodeAt(value.length - 1) === 0) {
return value.substring(0, value.length - 1);
}
return value;
}
module.exports = types;
module.exports.num2str = num2str;
module.exports.num2bytes = num2bytes;
module.exports.str2num = str2num;
module.exports.readType = readType;
/***/ }),
/* 2 */
/***/ (function(module, exports) {
var g;
// This works in non-strict mode
g = (function() {
return this;
})();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const types = __webpack_require__(1);
// const STREAMING = 4294967295;
/**
* Read data for the given non-record variable
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {object} variable - Variable metadata
* @return {Array} - Data of the element
*/
function nonRecord(buffer, variable) {
// variable type
const type = types.str2num(variable.type);
// size of the data
var size = variable.size / types.num2bytes(type);
// iterates over the data
var data = new Array(size);
for (var i = 0; i < size; i++) {
data[i] = types.readType(buffer, type, 1);
}
return data;
}
/**
* Read data for the given record variable
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {object} variable - Variable metadata
* @param {object} recordDimension - Record dimension metadata
* @return {Array} - Data of the element
*/
function record(buffer, variable, recordDimension) {
// variable type
const type = types.str2num(variable.type);
const width = variable.size ? variable.size / types.num2bytes(type) : 1;
// size of the data
// TODO streaming data
var size = recordDimension.length;
// iterates over the data
var data = new Array(size);
const step = recordDimension.recordStep;
for (var i = 0; i < size; i++) {
var currentOffset = buffer.offset;
data[i] = types.readType(buffer, type, width);
buffer.seek(currentOffset + step);
}
return data;
}
module.exports.nonRecord = nonRecord;
module.exports.record = record;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const utils = __webpack_require__(0);
const types = __webpack_require__(1);
// Grammar constants
const ZERO = 0;
const NC_DIMENSION = 10;
const NC_VARIABLE = 11;
const NC_ATTRIBUTE = 12;
/**
* Read the header of the file
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} version - Version of the file
* @return {object} - Object with the fields:
* * `recordDimension`: Number with the length of record dimension
* * `dimensions`: List of dimensions
* * `globalAttributes`: List of global attributes
* * `variables`: List of variables
*/
function header(buffer, version) {
// Length of record dimension
// sum of the varSize's of all the record variables.
var header = { recordDimension: { length: buffer.readUint32() } };
// Version
header.version = version;
// List of dimensions
var dimList = dimensionsList(buffer);
header.recordDimension.id = dimList.recordId;
header.recordDimension.name = dimList.recordName;
header.dimensions = dimList.dimensions;
// List of global attributes
header.globalAttributes = attributesList(buffer);
// List of variables
var variables = variablesList(buffer, dimList.recordId, version);
header.variables = variables.variables;
header.recordDimension.recordStep = variables.recordStep;
return header;
}
/**
* List of dimensions
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {object} - List of dimensions and record dimension with:
* * `name`: String with the name of the dimension
* * `size`: Number with the size of the dimension
*/
function dimensionsList(buffer) {
var recordId, recordName;
const dimList = buffer.readUint32();
if (dimList === ZERO) {
utils.notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of dimensions');
return [];
} else {
utils.notNetcdf(dimList !== NC_DIMENSION, 'wrong tag for list of dimensions');
// Length of dimensions
const dimensionSize = buffer.readUint32();
var dimensions = new Array(dimensionSize);
for (var dim = 0; dim < dimensionSize; dim++) {
// Read name
var name = utils.readName(buffer);
// Read dimension size
const size = buffer.readUint32();
if (size === 0) {
recordId = dim;
recordName = name;
}
dimensions[dim] = {
name: name,
size: size
};
}
}
return {
dimensions: dimensions,
recordId: recordId,
recordName: recordName
};
}
/**
* List of attributes
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @return {Array<object>} - List of attributes with:
* * `name`: String with the name of the attribute
* * `type`: String with the type of the attribute
* * `value`: A number or string with the value of the attribute
*/
function attributesList(buffer) {
const gAttList = buffer.readUint32();
if (gAttList === ZERO) {
utils.notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of attributes');
return [];
} else {
utils.notNetcdf(gAttList !== NC_ATTRIBUTE, 'wrong tag for list of attributes');
// Length of attributes
const attributeSize = buffer.readUint32();
var attributes = new Array(attributeSize);
for (var gAtt = 0; gAtt < attributeSize; gAtt++) {
// Read name
var name = utils.readName(buffer);
// Read type
var type = buffer.readUint32();
utils.notNetcdf(type < 1 || type > 6, 'non valid type ' + type);
// Read attribute
var size = buffer.readUint32();
var value = types.readType(buffer, type, size);
// Apply padding
utils.padding(buffer);
attributes[gAtt] = {
name: name,
type: types.num2str(type),
value: value
};
}
}
return attributes;
}
/**
* List of variables
* @ignore
* @param {IOBuffer} buffer - Buffer for the file data
* @param {number} recordId - Id if the record dimension
* @param {number} version - Version of the file
* @return {object} - Number of recordStep and list of variables with:
* * `name`: String with the name of the variable
* * `dimensions`: Array with the dimension IDs of the variable
* * `attributes`: Array with the attributes of the variable
* * `type`: String with the type of the variable
* * `size`: Number with the size of the variable
* * `offset`: Number with the offset where of the variable begins
* * `record`: True if is a record variable, false otherwise
*/
function variablesList(buffer, recordId, version) {
const varList = buffer.readUint32();
var recordStep = 0;
if (varList === ZERO) {
utils.notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of variables');
return [];
} else {
utils.notNetcdf(varList !== NC_VARIABLE, 'wrong tag for list of variables');
// Length of variables
const variableSize = buffer.readUint32();
var variables = new Array(variableSize);
for (var v = 0; v < variableSize; v++) {
// Read name
var name = utils.readName(buffer);
// Read dimensionality of the variable
const dimensionality = buffer.readUint32();
// Index into the list of dimensions
var dimensionsIds = new Array(dimensionality);
for (var dim = 0; dim < dimensionality; dim++) {
dimensionsIds[dim] = buffer.readUint32();
}
// Read variables size
var attributes = attributesList(buffer);
// Read type
var type = buffer.readUint32();
utils.notNetcdf(type < 1 && type > 6, 'non valid type ' + type);
// Read variable size
// The 32-bit varSize field is not large enough to contain the size of variables that require
// more than 2^32 - 4 bytes, so 2^32 - 1 is used in the varSize field for such variables.
const varSize = buffer.readUint32();
// Read offset
var offset = buffer.readUint32();
if (version === 2) {
utils.notNetcdf(offset > 0, 'offsets larger than 4GB not supported');
offset = buffer.readUint32();
}
// Count amount of record variables
if (dimensionsIds[0] === recordId) {
recordStep += varSize;
}
variables[v] = {
name: name,
dimensions: dimensionsIds,
attributes: attributes,
type: types.num2str(type),
size: varSize,
offset: offset,
record: dimensionsIds[0] === recordId
};
}
}
return {
variables: variables,
recordStep: recordStep
};
}
module.exports = header;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(Buffer) {
const utf8 = __webpack_require__(11);
const defaultByteLength = 1024 * 8;
const charArray = [];
/**
* IOBuffer
* @constructor
* @param {undefined|number|ArrayBuffer|TypedArray|IOBuffer|Buffer} data - The data to construct the IOBuffer with.
*
* If it's a number, it will initialize the buffer with the number as the buffer's length<br>
* If it's undefined, it will initialize the buffer with a default length of 8 Kb<br>
* If its an ArrayBuffer, a TypedArray, an IOBuffer instance,
* or a Node.js Buffer, it will create a view over the underlying ArrayBuffer.
* @param {object} [options]
* @param {number} [options.offset=0] - Ignore the first n bytes of the ArrayBuffer
* @property {ArrayBuffer} buffer - Reference to the internal ArrayBuffer object
* @property {number} length - Byte length of the internal ArrayBuffer
* @property {number} offset - The current offset of the buffer's pointer
* @property {number} byteLength - Byte length of the internal ArrayBuffer
* @property {number} byteOffset - Byte offset of the internal ArrayBuffer
*/
class IOBuffer {
constructor(data, options) {
options = options || {};
var dataIsGiven = false;
if (data === undefined) {
data = defaultByteLength;
}
if (typeof data === 'number') {
data = new ArrayBuffer(data);
} else {
dataIsGiven = true;
this._lastWrittenByte = data.byteLength;
}
const offset = options.offset ? options.offset >>> 0 : 0;
let byteLength = data.byteLength - offset;
let dvOffset = offset;
if (data.buffer) {
if (data.byteLength !== data.buffer.byteLength) {
dvOffset = data.byteOffset + offset;
}
data = data.buffer;
}
if (dataIsGiven) {
this._lastWrittenByte = byteLength;
} else {
this._lastWrittenByte = 0;
}
this.buffer = data;
this.length = byteLength;
this.byteLength = byteLength;
this.byteOffset = dvOffset;
this.offset = 0;
this.littleEndian = true;
this._data = new DataView(this.buffer, dvOffset, byteLength);
this._mark = 0;
this._marks = [];
}
/**
* Checks if the memory allocated to the buffer is sufficient to store more bytes after the offset
* @param {number} [byteLength=1] The needed memory in bytes
* @return {boolean} Returns true if there is sufficient space and false otherwise
*/
available(byteLength) {
if (byteLength === undefined) byteLength = 1;
return (this.offset + byteLength) <= this.length;
}
/**
* Check if little-endian mode is used for reading and writing multi-byte values
* @return {boolean} Returns true if little-endian mode is used, false otherwise
*/
isLittleEndian() {
return this.littleEndian;
}
/**
* Set little-endian mode for reading and writing multi-byte values
* @return {IOBuffer}
*/
setLittleEndian() {
this.littleEndian = true;
return this;
}
/**
* Check if big-endian mode is used for reading and writing multi-byte values
* @return {boolean} Returns true if big-endian mode is used, false otherwise
*/
isBigEndian() {
return !this.littleEndian;
}
/**
* Switches to big-endian mode for reading and writing multi-byte values
* @return {IOBuffer}
*/
setBigEndian() {
this.littleEndian = false;
return this;
}
/**
* Move the pointer n bytes forward
* @param {number} n
* @return {IOBuffer}
*/
skip(n) {
if (n === undefined) n = 1;
this.offset += n;
return this;
}
/**
* Move the pointer to the given offset
* @param {number} offset
* @return {IOBuffer}
*/
seek(offset) {
this.offset = offset;
return this;
}
/**
* Store the current pointer offset.
* @see {@link IOBuffer#reset}
* @return {IOBuffer}
*/
mark() {
this._mark = this.offset;
return this;
}
/**
* Move the pointer back to the last pointer offset set by mark
* @see {@link IOBuffer#mark}
* @return {IOBuffer}
*/
reset() {
this.offset = this._mark;
return this;
}
/**
* Push the current pointer offset to the mark stack
* @see {@link IOBuffer#popMark}
* @return {IOBuffer}
*/
pushMark() {
this._marks.push(this.offset);
return this;
}
/**
* Pop the last pointer offset from the mark stack, and set the current pointer offset to the popped value
* @see {@link IOBuffer#pushMark}
* @return {IOBuffer}
*/
popMark() {
const offset = this._marks.pop();
if (offset === undefined) throw new Error('Mark stack empty');
this.seek(offset);
return this;
}
/**
* Move the pointer offset back to 0
* @return {IOBuffer}
*/
rewind() {
this.offset = 0;
return this;
}
/**
* Make sure the buffer has sufficient memory to write a given byteLength at the current pointer offset
* If the buffer's memory is insufficient, this method will create a new buffer (a copy) with a length
* that is twice (byteLength + current offset)
* @param {number} [byteLength = 1]
* @return {IOBuffer}
*/
ensureAvailable(byteLength) {
if (byteLength === undefined) byteLength = 1;
if (!this.available(byteLength)) {
const lengthNeeded = this.offset + byteLength;
const newLength = lengthNeeded * 2;
const newArray = new Uint8Array(newLength);
newArray.set(new Uint8Array(this.buffer));
this.buffer = newArray.buffer;
this.length = this.byteLength = newLength;
this._data = new DataView(this.buffer);
}
return this;
}
/**
* Read a byte and return false if the byte's value is 0, or true otherwise
* Moves pointer forward
* @return {boolean}
*/
readBoolean() {
return this.readUint8() !== 0;
}
/**
* Read a signed 8-bit integer and move pointer forward
* @return {number}
*/
readInt8() {
return this._data.getInt8(this.offset++);
}
/**
* Read an unsigned 8-bit integer and move pointer forward
* @return {number}
*/
readUint8() {
return this._data.getUint8(this.offset++);
}
/**
* Alias for {@link IOBuffer#readUint8}
* @return {number}
*/
readByte() {
return this.readUint8();
}
/**
* Read n bytes and move pointer forward.
* @param {number} n
* @return {Uint8Array}
*/
readBytes(n) {
if (n === undefined) n = 1;
var bytes = new Uint8Array(n);
for (var i = 0; i < n; i++) {
bytes[i] = this.readByte();
}
return bytes;
}
/**
* Read a 16-bit signed integer and move pointer forward
* @return {number}
*/
readInt16() {
var value = this._data.getInt16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 16-bit unsigned integer and move pointer forward
* @return {number}
*/
readUint16() {
var value = this._data.getUint16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 32-bit signed integer and move pointer forward
* @return {number}
*/
readInt32() {
var value = this._data.getInt32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 32-bit unsigned integer and move pointer forward
* @return {number}
*/
readUint32() {
var value = this._data.getUint32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 32-bit floating number and move pointer forward
* @return {number}
*/
readFloat32() {
var value = this._data.getFloat32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 64-bit floating number and move pointer forward
* @return {number}
*/
readFloat64() {
var value = this._data.getFloat64(this.offset, this.littleEndian);
this.offset += 8;
return value;
}
/**
* Read 1-byte ascii character and move pointer forward
* @return {string}
*/
readChar() {
return String.fromCharCode(this.readInt8());
}
/**
* Read n 1-byte ascii characters and move pointer forward
* @param {number} n
* @return {string}
*/
readChars(n) {
if (n === undefined) n = 1;
charArray.length = n;
for (var i = 0; i < n; i++) {
charArray[i] = this.readChar();
}
return charArray.join('');
}
/**
* Read the next n bytes, return a UTF-8 decoded string and move pointer forward
* @param {number} n
* @return {string}
*/
readUtf8(n) {
if (n === undefined) n = 1;
const bString = this.readChars(n);
return utf8.decode(bString);
}
/**
* Write 0xff if the passed value is truthy, 0x00 otherwise
* @param {any} value
* @return {IOBuffer}
*/
writeBoolean(value) {
this.writeUint8(value ? 0xff : 0x00);
return this;
}
/**
* Write value as an 8-bit signed integer
* @param {number} value
* @return {IOBuffer}
*/
writeInt8(value) {
this.ensureAvailable(1);
this._data.setInt8(this.offset++, value);
this._updateLastWrittenByte();
return this;
}
/**
* Write value as a 8-bit unsigned integer
* @param {number} value
* @return {IOBuffer}
*/
writeUint8(value) {
this.ensureAvailable(1);
this._data.setUint8(this.offset++, value);
this._updateLastWrittenByte();
return this;
}
/**
* An alias for {@link IOBuffer#writeUint8}
* @param {number} value
* @return {IOBuffer}
*/
writeByte(value) {
return this.writeUint8(value);
}
/**
* Write bytes
* @param {Array|Uint8Array} bytes
* @return {IOBuffer}
*/
writeBytes(bytes) {
this.ensureAvailable(bytes.length);
for (var i = 0; i < bytes.length; i++) {
this._data.setUint8(this.offset++, bytes[i]);
}
this._updateLastWrittenByte();
return this;
}
/**
* Write value as an 16-bit signed integer
* @param {number} value
* @return {IOBuffer}
*/
writeInt16(value) {
this.ensureAvailable(2);
this._data.setInt16(this.offset, value, this.littleEndian);
this.offset += 2;
this._updateLastWrittenByte();
return this;
}
/**
* Write value as a 16-bit unsigned integer
* @param {number} value
* @return {IOBuffer}
*/
writeUint16(value) {
this.ensureAvailable(2);
this._data.setUint16(this.offset, value, this.littleEndian);
this.offset += 2;
this._updateLastWrittenByte();
return this;
}
/**
* Write a 32-bit signed integer at the current pointer offset
* @param {number} value
* @return {IOBuffer}
*/
writeInt32(value) {
this.ensureAvailable(4);
this._data.setInt32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write a 32-bit unsigned integer at the current pointer offset
* @param {number} value - The value to set
* @return {IOBuffer}
*/
writeUint32(value) {
this.ensureAvailable(4);
this._data.setUint32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write a 32-bit floating number at the current pointer offset
* @param {number} value - The value to set
* @return {IOBuffer}
*/
writeFloat32(value) {
this.ensureAvailable(4);
this._data.setFloat32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write a 64-bit floating number at the current pointer offset
* @param {number} value
* @return {IOBuffer}
*/
writeFloat64(value) {
this.ensureAvailable(8);
this._data.setFloat64(this.offset, value, this.littleEndian);
this.offset += 8;
this._updateLastWrittenByte();
return this;
}
/**
* Write the charCode of the passed string's first character to the current pointer offset
* @param {string} str - The character to set
* @return {IOBuffer}
*/
writeChar(str) {
return this.writeUint8(str.charCodeAt(0));
}
/**
* Write the charCodes of the passed string's characters to the current pointer offset
* @param {string} str
* @return {IOBuffer}
*/
writeChars(str) {
for (var i = 0; i < str.length; i++) {
this.writeUint8(str.charCodeAt(i));
}
return this;
}
/**
* UTF-8 encode and write the passed string to the current pointer offset
* @param {string} str
* @return {IOBuffer}
*/
writeUtf8(str) {
const bString = utf8.encode(str);
return this.writeChars(bString);
}
/**
* Export a Uint8Array view of the internal buffer.
* The view starts at the byte offset and its length
* is calculated to stop at the last written byte or the original length.
* @return {Uint8Array}
*/
toArray() {
return new Uint8Array(this.buffer, this.byteOffset, this._lastWrittenByte);
}
/**
* Same as {@link IOBuffer#toArray} but returns a Buffer if possible. Otherwise returns a Uint8Array.
* @return {Buffer|Uint8Array}
*/
getBuffer() {
if (typeof Buffer !== 'undefined') {
return Buffer.from(this.toArray());
} else {
return this.toArray();
}
}
/**
* Update the last written byte offset
* @private
*/
_updateLastWrittenByte() {
if (this.offset > this._lastWrittenByte) {
this._lastWrittenByte = this.offset;
}
}
}
module.exports = IOBuffer;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(8).Buffer))
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
const IOBuffer = __webpack_require__(5);
const utils = __webpack_require__(0);
const data = __webpack_require__(3);
const readHeader = __webpack_require__(4);
/**
* Reads a NetCDF v3.x file
* https://www.unidata.ucar.edu/software/netcdf/docs/file_format_specifications.html
* @param {ArrayBuffer} data - ArrayBuffer or any Typed Array (including Node.js' Buffer from v4) with the data
* @constructor
*/
class NetCDFReader {
constructor(data) {
const buffer = new IOBuffer(data);
buffer.setBigEndian();
// Validate that it's a NetCDF file
utils.notNetcdf(buffer.readChars(3) !== 'CDF', 'should start with CDF');
// Check the NetCDF format
const version = buffer.readByte();
utils.notNetcdf(version > 2, 'unknown version');
// Read the header
this.header = readHeader(buffer, version);
this.buffer = buffer;
}
/**
* @return {string} - Version for the NetCDF format
*/
get version() {
if (this.header.version === 1) {
return 'classic format';
} else {
return '64-bit offset format';
}
}
/**
* @return {object} - Metadata for the record dimension
* * `length`: Number of elements in the record dimension
* * `id`: Id number in the list of dimensions for the record dimension
* * `name`: String with the name of the record dimension
* * `recordStep`: Number with the record variables step size
*/
get recordDimension() {
return this.header.recordDimension;
}
/**
* @return {Array<object>} - List of dimensions with:
* * `name`: String with the name of the dimension
* * `size`: Number with the size of the dimension
*/
get dimensions() {
return this.header.dimensions;
}
/**
* @return {Array<object>} - List of global attributes with:
* * `name`: String with the name of the attribute
* * `type`: String with the type of the attribute
* * `value`: A number or string with the value of the attribute
*/
get globalAttributes() {
return this.header.globalAttributes;
}
/**
* @return {Array<object>} - List of variables with:
* * `name`: String with the name of the variable
* * `dimensions`: Array with the dimension IDs of the variable
* * `attributes`: Array with the attributes of the variable
* * `type`: String with the type of the variable
* * `size`: Number with the size of the variable
* * `offset`: Number with the offset where of the variable begins
* * `record`: True if is a record variable, false otherwise
*/
get variables() {
return this.header.variables;
}
/**
* Retrieves the data for a given variable
* @param {string|object} variableName - Name of the variable to search or variable object
* @return {Array} - List with the variable values
*/
getDataVariable(variableName) {
var variable;
if (typeof variableName === 'string') {
// search the variable
variable = this.header.variables.find(function (val) {
return val.name === variableName;
});
} else {
variable = variableName;
}
// throws if variable not found
utils.notNetcdf(variable === undefined, 'variable not found');
// go to the offset position
this.buffer.seek(variable.offset);
if (variable.record) {
// record variable case
return data.record(this.buffer, variable, this.header.recordDimension);
} else {
// non-record variable case
return data.nonRecord(this.buffer, variable);
}
}
}
module.exports = NetCDFReader;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray
var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i]
revLookup[code.charCodeAt(i)] = i
}
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function placeHoldersCount (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
}
function byteLength (b64) {
// base64 is 4/3 + up to two characters of the original data
return b64.length * 3 / 4 - placeHoldersCount(b64)
}
function toByteArray (b64) {
var i, j, l, tmp, placeHolders, arr
var len = b64.length
placeHolders = placeHoldersCount(b64)
arr = new Arr(len * 3 / 4 - placeHolders)
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? len - 4 : len
var L = 0
for (i = 0, j = 0; i < l; i += 4, j += 3) {
tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
arr[L++] = (tmp >> 16) & 0xFF
arr[L++] = (tmp >> 8) & 0xFF
arr[L++] = tmp & 0xFF
}
if (placeHolders === 2) {
tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[L++] = tmp & 0xFF
} else if (placeHolders === 1) {
tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[L++] = (tmp >> 8) & 0xFF
arr[L++] = tmp & 0xFF
}
return arr
}
function tripletToBase64 (num) {
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
}
function encodeChunk (uint8, start, end) {
var tmp
var output = []
for (var i = start; i < end; i += 3) {
tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
output.push(tripletToBase64(tmp))
}
return output.join('')
}
function fromByteArray (uint8) {
var tmp
var len = uint8.length
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
var output = ''
var parts = []
var maxChunkLength = 16383 // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1) {
tmp = uint8[len - 1]
output += lookup[tmp >> 2]
output += lookup[(tmp << 4) & 0x3F]
output += '=='
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
output += lookup[tmp >> 10]
output += lookup[(tmp >> 4) & 0x3F]
output += lookup[(tmp << 2) & 0x3F]
output += '='
}
parts.push(output)
return parts.join('')
}
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(global) {/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/* eslint-disable no-proto */
var base64 = __webpack_require__(7)
var ieee754 = __webpack_require__(9)
var isArray = __webpack_require__(10)
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50
/**
* If `Buffer.TYPED_ARRAY_SUPPORT`:
* === true Use Uint8Array implementation (fastest)
* === false Use Object implementation (most compatible, even IE6)
*
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
* Opera 11.6+, iOS 4.2+.
*
* Due to various browser bugs, sometimes the Object implementation will be used even
* when the browser supports typed arrays.
*
* Note:
*
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
*
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
*
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
* incorrect length in some situations.
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
* get the Object implementation, which is slower but behaves correctly.
*/
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
? global.TYPED_ARRAY_SUPPORT
: typedArraySupport()
/*
* Export kMaxLength after typed array support is determined.
*/
exports.kMaxLength = kMaxLength()
function typedArraySupport () {
try {
var arr = new Uint8Array(1)
arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
return arr.foo() === 42 && // typed array instances can be augmented
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
} catch (e) {
return false
}
}
function kMaxLength () {
return Buffer.TYPED_ARRAY_SUPPORT
? 0x7fffffff
: 0x3fffffff
}
function createBuffer (that, length) {
if (kMaxLength() < length) {
throw new RangeError('Invalid typed array length')
}
if (Buffer.TYPED_ARRAY_SUPPORT) {
// Return an augmented `Uint8Array` instance, for best performance
that = new Uint8Array(length)
that.__proto__ = Buffer.prototype
} else {
// Fallback: Return an object instance of the Buffer class
if (that === null) {
that = new Buffer(length)
}
that.length = length
}
return that
}
/**
* The Buffer constructor returns instances of `Uint8Array` that have their
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
* returns a single octet.
*
* The `Uint8Array` prototype remains unmodified.
*/
function Buffer (arg, encodingOrOffset, length) {
if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
return new Buffer(arg, encodingOrOffset, length)
}
// Common case.
if (typeof arg === 'number') {
if (typeof encodingOrOffset === 'string') {
throw new Error(
'If encoding is specified then the first argument must be a string'
)
}
return allocUnsafe(this, arg)
}
return from(this, arg, encodingOrOffset, length)
}
Buffer.poolSize = 8192 // not used by this implementation
// TODO: Legacy, not needed anymore. Remove in next major version.
Buffer._augment = function (arr) {
arr.__proto__ = Buffer.prototype
return arr
}
function from (that, value, encodingOrOffset, length) {
if (typeof value === 'number') {
throw new TypeError('"value" argument must not be a number')
}
if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
return fromArrayBuffer(that, value, encodingOrOffset, length)
}
if (typeof value === 'string') {
return fromString(that, value, encodingOrOffset)
}
return fromObject(that, value)
}
/**
* Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
* if value is a number.
* Buffer.from(str[, encoding])
* Buffer.from(array)
* Buffer.from(buffer)
* Buffer.from(arrayBuffer[, byteOffset[, length]])
**/
Buffer.from = function (value, encodingOrOffset, length) {
return from(null, value, encodingOrOffset, length)
}
if (Buffer.TYPED_ARRAY_SUPPORT) {
Buffer.prototype.__proto__ = Uint8Array.prototype
Buffer.__proto__ = Uint8Array
if (typeof Symbol !== 'undefined' && Symbol.species &&
Buffer[Symbol.species] === Buffer) {
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
Object.defineProperty(Buffer, Symbol.species, {
value: null,
configurable: true
})
}
}
function assertSize (size) {
if (typeof size !== 'number') {
throw new TypeError('"size" argument must be a number')
} else if (size < 0) {
throw new RangeError('"size" argument must not be negative')
}
}
function alloc (that, size, fill, encoding) {
assertSize(size)
if (size <= 0) {
return createBuffer(that, size)
}
if (fill !== undefined) {
// Only pay attention to encoding if it's a string. This
// prevents accidentally sending in a number that would
// be interpretted as a start offset.
return typeof encoding === 'string'
? createBuffer(that, size).fill(fill, encoding)
: createBuffer(that, size).fill(fill)
}
return createBuffer(that, size)
}
/**
* Creates a new filled Buffer instance.
* alloc(size[, fill[, encoding]])
**/
Buffer.alloc = function (size, fill, encoding) {
return alloc(null, size, fill, encoding)
}
function allocUnsafe (that, size) {
assertSize(size)
that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
if (!Buffer.TYPED_ARRAY_SUPPORT) {
for (var i = 0; i < size; ++i) {
that[i] = 0
}
}
return that
}
/**
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
* */
Buffer.allocUnsafe = function (size) {
return allocUnsafe(null, size)
}
/**
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
*/
Buffer.allocUnsafeSlow = function (size) {
return allocUnsafe(null, size)
}
function fromString (that, string, encoding) {
if (typeof encoding !== 'string' || encoding === '') {
encoding = 'utf8'
}
if (!Buffer.isEncoding(encoding)) {
throw new TypeError('"encoding" must be a valid string encoding')
}
var length = byteLength(string, encoding) | 0
that = createBuffer(that, length)
var actual = that.write(string, encoding)
if (actual !== length) {
// Writing a hex string, for example, that contains invalid characters will
// cause everything after the first invalid character to be ignored. (e.g.
// 'abxxcd' will be treated as 'ab')
that = that.slice(0, actual)
}
return that
}
function fromArrayLike (that, array) {
var length = array.length < 0 ? 0 : checked(array.length) | 0
that = createBuffer(that, length)
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
function fromArrayBuffer (that, array, byteOffset, length) {
array.byteLength // this throws if `array` is not a valid ArrayBuffer
if (byteOffset < 0 || array.byteLength < byteOffset) {
throw new RangeError('\'offset\' is out of bounds')
}
if (array.byteLength < byteOffset + (length || 0)) {
throw new RangeError('\'length\' is out of bounds')
}
if (byteOffset === undefined && length === undefined) {
array = new Uint8Array(array)
} else if (length === undefined) {
array = new Uint8Array(array, byteOffset)
} else {
array = new Uint8Array(array, byteOffset, length)
}
if (Buffer.TYPED_ARRAY_SUPPORT) {
// Return an augmented `Uint8Array` instance, for best performance
that = array
that.__proto__ = Buffer.prototype
} else {
// Fallback: Return an object instance of the Buffer class
that = fromArrayLike(that, array)
}
return that
}
function fromObject (that, obj) {
if (Buffer.isBuffer(obj)) {
var len = checked(obj.length) | 0
that = createBuffer(that, len)
if (that.length === 0) {
return that
}
obj.copy(that, 0, 0, len)
return that
}
if (obj) {
if ((typeof ArrayBuffer !== 'undefined' &&
obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
if (typeof obj.length !== 'number' || isnan(obj.length)) {
return createBuffer(that, 0)
}
return fromArrayLike(that, obj)
}
if (obj.type === 'Buffer' && isArray(obj.data)) {
return fromArrayLike(that, obj.data)
}
}
throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
}
function checked (length) {
// Note: cannot use `length < kMaxLength()` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if (length >= kMaxLength()) {
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
'size: 0x' + kMaxLength().toString(16) + ' bytes')
}
return length | 0
}
function SlowBuffer (length) {
if (+length != length) { // eslint-disable-line eqeqeq
length = 0
}
return Buffer.alloc(+length)
}
Buffer.isBuffer = function isBuffer (b) {
return !!(b != null && b._isBuffer)
}
Buffer.compare = function compare (a, b) {
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
throw new TypeError('Arguments must be Buffers')
}
if (a === b) return 0
var x = a.length
var y = b.length
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
if (a[i] !== b[i]) {
x = a[i]
y = b[i]
break
}
}
if (x < y) return -1
if (y < x) return 1
return 0
}
Buffer.isEncoding = function isEncoding (encoding) {
switch (String(encoding).toLowerCa