Skip to content

Instantly share code, notes, and snippets.

@hthetiot
Last active July 13, 2018 22:13
Show Gist options
  • Save hthetiot/9bc89a3c19ca4e7ea9d159754b6bf298 to your computer and use it in GitHub Desktop.
Save hthetiot/9bc89a3c19ca4e7ea9d159754b6bf298 to your computer and use it in GitHub Desktop.
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.http2Cache = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var http2 = require('http2.js');
// TODO extend AGENT
function Http2CacheAgent() {
http2.Agent.apply(this, arguments);
}
Http2CacheAgent.prototype = Object.create(http2.Agent.prototype, {
// TODO override http2.Agent
});
exports.Agent = Http2CacheAgent;
},{"http2.js":82}],2:[function(require,module,exports){
var EventEmitter = require('events').EventEmitter,
util = require('util'),
redefine = require('./utils').redefine;
function CacheListener(configuration) {
var cl = this;
redefine(configuration.cache, 'put', function (k, v) {
var self = this;
return new Promise(function (resolve, reject) {
self._put(k, v).then(function () {
if (self.debug) {
self._log.debug("Cached response: " + k.href);
}
cl.emit('cached', k.href);
resolve();
}).catch(reject);
});
});
redefine(configuration.cache, 'match', function (k) {
var self = this;
return new Promise(function (resolve, reject) {
self._match(k).then(function (response) {
if (self.debug) {
if(response){
self._log.debug("Using cached response for request to: " + k.href);
}else{
self._log.debug("Cache miss for request: " + k.href);
}
}
resolve(response);
}).catch(reject);
});
});
EventEmitter.call(this);
}
util.inherits(CacheListener, EventEmitter);
module.exports = {
CacheListener: CacheListener
};
},{"./utils":7,"events":16,"util":56}],3:[function(require,module,exports){
var Dict = require("collections/dict"),
logger = require('./logger'),
keys = require('object-keys'),
Map = require("collections/map");
// https://github.com/roryf/parse-cache-control/blob/master/LICENSE
/*
Cache-Control = 1#cache-directive
cache-directive = token [ "=" ( token / quoted-string ) ]
token = [^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+
quoted-string = "(?:[^"\\]|\\.)*"
*/
// 1: directive = 2: token 3: quoted-string
function parseMaxAge(maxAge) {
// Only parse once
if (typeof maxAge === 'number') {
return maxAge;
}
return parseInt(maxAge, 10);
}
function getMaxAgeHeaderName(header) {
if (header['max-age'] && header['s-maxage']) {
// Get bigest value of both
return parseInt(header['max-age'], 10) < parseInt(header['s-maxage'], 10) ? 's-maxage' : 'max-age';
} else {
return 'max-age';
}
}
var PARSE_CACHE_CONTROL_REG = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
function parseCacheControl(field) {
if (typeof field !== 'string') {
return null;
}
var header = {};
var error = field.replace(PARSE_CACHE_CONTROL_REG, function ($0, $1, $2, $3) {
var value = $2 || $3;
header[$1] = value ? value.toLowerCase() : true;
return '';
});
var maxAgeHeaderName = getMaxAgeHeaderName(header),
maxAge = header[maxAgeHeaderName];
if (maxAge) {
maxAge = parseMaxAge(maxAge);
if (isNaN(maxAge)) {
return null;
} else if (maxAge) {
if (header['s-maxage']) {
header['s-maxage'] = maxAge;
}
header['max-age'] = maxAge;
}
}
return (error ? null : header);
}
function getCacheControlHeaders(response) {
return response.headers['cache-control'];
}
//////////////////////////////////////////// Request Info ////////////////////////////////////////////
function getRequestInfoHeaders(requestInfo, headers) {
// Make headers and Object to match response (see parseCacheControl and getCacheControlHeaders)
if (headers instanceof Map) {
var headerMap = headers;
headers = {};
headerMap.forEach(function(value, key) {
headers[key] = value;
});
}
// Create read-only prop on headers Object
var requestInfoHeaders = requestInfo.headers || {};
if (headers) {
Object.keys(headers).forEach(function(key) {
Object.defineProperty(requestInfoHeaders, key, {
configurable: false,
writable: false,
value: headers[key]
});
});
}
return requestInfoHeaders;
}
var RequestInfo = function (method, href, headers) {
var self = this;
self.method = method;
self.href = href;
self.headers = getRequestInfoHeaders(self, headers);
var cacheControlHeader = getCacheControlHeaders(self);
self.cacheDirectives = parseCacheControl(cacheControlHeader);
self.hash = self.method + '^' + self.href;
};
//////////////////////////////////////////// Cache ////////////////////////////////////////////
function Cache(options) {
var self = this;
options = options || {};
// Init debug/log
self.debug = options.debug;
self._log = options.log || (self.debug ? logger.consoleLogger : logger.defaultLogger);
// mapping from hash of request info to time ordered list or responses
this._requestInfoToResponses = new Dict();
this._requestInfoRevalidating = new Dict();
}
var cp = Cache.prototype;
cp.setDebug = function (debug) {
this._debug = debug;
};
function getExpireTime(response, cacheDirectives, revalidating) {
var maxAgeAt = -1,
staleButRevalidateAt = -1;
var date = response.headers.date;
if (!date) {
// TODO RFC error here, maybe we should ignore the request
date = new Date().getTime();
} else {
date = new Date(date).getTime();
}
if (cacheDirectives['max-age']) {
maxAgeAt = date + (cacheDirectives['max-age'] * 1000);
}
if (revalidating && cacheDirectives['stale-while-revalidate']) {
staleButRevalidateAt = date + (cacheDirectives['stale-while-revalidate'] * 1000);
}
return maxAgeAt > staleButRevalidateAt ? maxAgeAt : staleButRevalidateAt;
}
function satisfiesRequest(requestInfo, candidate, candidateHash, revalidating) {
var currentTime = new Date().getTime(), // TODO get time from requestInfo ?
cacheControlHeaders = getCacheControlHeaders(candidate),
cacheResponseDirectives = parseCacheControl(cacheControlHeaders);
return getExpireTime(candidate, cacheResponseDirectives, revalidating) > currentTime &&
requestInfo.hash === candidateHash;
}
var CACHEABLE_BY_DEFAULT_STATUS_CODES = [200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501];
function isCacheableResponse(response, cacheResponseDirectives) {
if (CACHEABLE_BY_DEFAULT_STATUS_CODES.indexOf(response.statusCode) === -1) {
return false;
}
var cacheControlHeaders = getCacheControlHeaders(response);
if (cacheControlHeaders) {
cacheResponseDirectives = cacheResponseDirectives || parseCacheControl(cacheControlHeaders);
if (cacheResponseDirectives['max-age']) {
return true;
} else if(cacheResponseDirectives['stale-while-revalidate']) {
return true;
}
}
return false;
}
cp.match = function (requestInfo/*, options*/) {
var self = this;
return new Promise(function (resolve, reject) {
var response = null;
if (!(requestInfo instanceof RequestInfo)) {
reject(new TypeError("Invalid requestInfo argument"));
} else {
var requestCacheDirectives = requestInfo.cacheDirectives,
requestIsRevalidating = self.isRevalidating(requestInfo);
if (
// Cache by default
// TODO why ?
requestCacheDirectives === null ||
// Bypass cache
(!requestCacheDirectives['no-cache'] && !requestCacheDirectives['no-store'])
) {
var candidate, candidateHash,
candidates = self._requestInfoToResponses.get(requestInfo.hash) || new Dict(),
cadidatesHashs = candidates.keys();
while (
response === null &&
(candidateHash = cadidatesHashs.next()) &&
(candidateHash.done === false)
) {
candidate = candidateHash.value &&
candidates.get(candidateHash.value);
if (
candidate &&
satisfiesRequest(requestInfo, candidate, candidateHash.value, requestIsRevalidating)
) {
response = candidate;
}
}
}
resolve(response);
}
});
};
function isExpired(candidate, currentTime) {
var cacheControlHeaders = getCacheControlHeaders(candidate),
cacheResponseDirectives = parseCacheControl(cacheControlHeaders);
return getExpireTime(candidate, cacheResponseDirectives) < currentTime;
}
cp.clearExpired = function () {
var self = this;
self._requestInfoToResponses.forEach(function (candidates) {
candidates.forEach(function (response, requestInfoHash) {
var currentTime = new Date().getTime();
if (isExpired(response, currentTime)) {
if (self._debug) {
self._log.debug("Evicted Response from cache for requestInfo Hash: " + requestInfoHash);
}
self._requestInfoToResponses.delete(requestInfoHash);
}
});
});
};
/**
* Clear all requestInfos from revalidation.
*/
cp.clearRevalidates = function () {
this._requestInfoRevalidating = new Dict();
};
/**
* Check if a given requestInfo is currently revalidating.
*/
cp.isRevalidating = function (requestInfo) {
return !!this._requestInfoRevalidating.get(requestInfo.hash);
};
/**
* Add given requestInfo to revalidating.
*/
cp.revalidate = function (requestInfo) {
var self = this,
revalidate = self._requestInfoRevalidating.get(requestInfo.hash) || 0;
// TODO special behavior ?
if (self._requestInfoRevalidating.get(requestInfo.hash)) {
if (self._debug) {
self._log.debug("Updated requestInfo for revalidating with hash: " + requestInfo.hash);
}
} else {
if (self._debug) {
self._log.debug("Added requestInfo to revalidate with hash: " + requestInfo.hash);
}
}
revalidate++;
self._requestInfoRevalidating.set(requestInfo.hash, revalidate);
};
/**
* Clear given requestInfo from revalidation.
*/
cp.validated = function (requestInfo) {
var self = this,
revalidate = self._requestInfoRevalidating.get(requestInfo.hash) || 0;
if (revalidate > 0) {
revalidate--;
if (self._debug) {
self._log.debug("Evicted requestInfo from revalidate with hash: " + requestInfo.hash);
}
if (revalidate > 0) {
self._requestInfoRevalidating.set(requestInfo.hash, revalidate);
} else {
self._requestInfoRevalidating.delete(requestInfo.hash);
}
}
};
/**
* Check requestInfo response for cache update, then update cache if cachable.
*/
cp.put = function (requestInfo, response) {
var self = this;
return new Promise(function (resolve, reject) {
// Check requestInfo type
if (!(requestInfo instanceof RequestInfo)) {
reject(new TypeError("Invalid requestInfo argument"));
} else {
var cacheControlHeaders = getCacheControlHeaders(response),
cacheResponseDirectives = parseCacheControl(cacheControlHeaders);
if (isCacheableResponse(response, cacheResponseDirectives) === false) {
reject(new Error("Not Cacheable response"));
} else {
var candidates = self._requestInfoToResponses.get(requestInfo.hash) || new Dict(),
responseHash = requestInfo.hash;
if (self._debug) {
self._log.debug("Adding cache entry to:" + requestInfo.hash + '/' + responseHash);
}
candidates.set(responseHash, response);
self._requestInfoToResponses.set(requestInfo.hash, candidates);
resolve();
}
}
});
};
//////////////////////////////////////////// Exports ////////////////////////////////////////////
module.exports = {
RequestInfo: RequestInfo,
Cache: Cache,
parseCacheControl: parseCacheControl,
satisfiesRequest: satisfiesRequest,
isCacheableResponse: isCacheableResponse,
};
},{"./logger":6,"collections/dict":63,"collections/map":72,"object-keys":100}],4:[function(require,module,exports){
var websocket = require('websocket-stream'),
keys = require('object-keys'),
assign = require('object-assign'),
http2 = require('http2.js'),
util = require('util'),
EventEmitter = require('events').EventEmitter,
InvalidStateError = require('./errors.js').InvalidStateError,
RequestInfo = require('./cache.js').RequestInfo,
Cache = require('./cache.js').Cache,
Agent = require('./agent').Agent,
logger = require('./logger'),
parseUrl = require('./utils').parseUrl,
getOrigin = require('./utils.js').getOrigin,
mergeTypedArrays = require('./utils.js').mergeTypedArrays,
defaultPort = require('./utils.js').defaultPort,
CacheListener = require('./cache-listener').CacheListener;
//////////////////////////////////////////// Configuration ////////////////////////////////////////////
function Configuration(options) {
var that = this;
// Init default options
that.options = assign({}, that.defaultOptions);
// Set options
this.setOptions(options);
EventEmitter.call(this);
// Map of Url to transport
that._proxyMap = {};
// Map of PushUrl ro PushRequest
that._pushRequests = {};
that._activeConfigurationCnt = 0;
that._activeTransportConnections = {};
// Init debug/log
that._log = logger.consoleLogger;
that.setDebugLevel(that.options.clientLogLevel || that.options.debug);
// Init Cache
that.cache = options.cache || new Cache({
debug: that.debug,
log: that._log
});
that.cacheListener = new CacheListener(that);
that.agent = new Agent({
log: that._log
});
}
util.inherits(Configuration, EventEmitter);
var confProto = Configuration.prototype;
confProto.defaultOptions = {
// Logger debugLevel true='info' or (info|debug|trace)
debug: false,
// Reconnect settings
reconnect: true,
reconnectInterval: 100,
maximumReconnectInterval: 4000,
// AccelerationStrategy could be "always" or "connected"
// Value always means always/don't make requests if they are proxied but no ws connection is open. Wait for the connection to open instead.
// Value connected means make requests when connected via websocket.
accelerationStrategy: 'always',
};
confProto.setOptions = function (options) {
assign(this.options, options);
return this;
};
confProto.debug = false;
confProto.setDebugLevel = function (level) {
var that = this;
level = typeof level === 'string' ? level : level === true ? 'info' : null;
// Init debug/log
if (that._log && that._log.hasOwnProperty('debugLevel')) {
that._log.debugLevel = level;
}
// Sync current options value
that.options.debug = level;
// Sync and cast has boolean
that.debug = !!that.options.debug;
};
confProto.configuring = function () {
this._activeConfigurationCnt++;
};
confProto.configured = function () {
this._activeConfigurationCnt--;
if (this._activeConfigurationCnt === 0) {
this.emit('completed');
}
};
confProto.isConfiguring = function () {
return this._activeConfigurationCnt > 0;
};
confProto.getTransport = function (url) {
var that = this,
uri = parseUrl(url),
activeTransportConnections = that._activeTransportConnections,
hasExistingTransport = activeTransportConnections.hasOwnProperty(uri.href),
hasActiveTransport = hasExistingTransport && !!activeTransportConnections[uri.href].writable;
if (
hasExistingTransport === false ||
hasActiveTransport === false
) {
// Cleanup on first existing transtort re-connection attempt.
if (hasExistingTransport) {
if (that.debug) {
that._log.info("Re-Opening transport: " + uri.href);
}
// Clear pending revalidates
that.cache.clearRevalidates();
} else {
if (that.debug) {
that._log.info("Opening transport: " + uri.href);
}
}
if (uri.protocol === 'ws:' || uri.protocol === 'wss:') {
activeTransportConnections[uri.href] = websocket(uri.href, "h2", {
// TODO, maybe enable perMessageDeflate in production or on debug??
perMessageDeflate: that.debug === false
});
} else if(uri.protocol === 'tcp:') {
activeTransportConnections[uri.href] = require('net').connect({
'host' : uri.hostname,
'port' : uri.port
});
} else {
throw new Error('Unrecognized transport protocol: ' + uri.protocol + ', for transport: ' + uri.href);
}
// On transport error remove Urls attached to transport and add on re-open
var transport = activeTransportConnections[uri.href];
transport.on('error', function () {
// Clear urls attached to proxyTransportUrl
if (that.options.accelerationStrategy === 'connected') {
var proxyUrls = that.getTransportUrls(url);
// Remove urls transport
proxyUrls.forEach(that.removeTransportUrl.bind(that));
// Restore urls for that transport once on connected again
transport.on('open', function () {
that.addTransportUrls(proxyUrls, url);
});
}
});
}
return activeTransportConnections[uri.href];
};
confProto.addTransportUrl = function (url, transport) {
var uri = parseUrl(url); // Enforce
this._proxyMap[uri.href] = transport;
return this;
};
confProto.addTransportUrls = function (urls, transport) {
var that = this;
urls.forEach(function (url) {
that.addTransportUrl(url, transport);
});
return this;
};
confProto.removeTransportUrl = function (url) {
var uri = parseUrl(url); // Enforce
delete this._proxyMap[uri.href];
return this;
};
confProto.getTransportUrl = function (url) {
var uri = parseUrl(url); // Enforce
var proxyUrl = keys(this._proxyMap).reduce(function (result, value) {
// Check that transport uri match beginning of uri
return uri.href.indexOf(value) === 0 ? value : result;
}, false);
return proxyUrl && this._proxyMap[proxyUrl];
};
confProto.getTransportUrls = function (transport) {
var _proxyMap = this._proxyMap,
proxyUrls = keys(_proxyMap).filter(function (url) {
return transport === _proxyMap[url];
});
return proxyUrls;
};
confProto.onPush = function (pushRequest) {
var that = this,
cache = that.cache,
origin = getOrigin(pushRequest.scheme + "://" + pushRequest.headers.host);
// Create href
pushRequest.href = origin + pushRequest.url;
if (that.debug) {
that._log.info("Received push promise for: " + pushRequest.href);
}
// TODO pass pushRequest for future dedup pending requestInfo
var requestInfo = new RequestInfo(pushRequest.method, pushRequest.href, pushRequest.headers);
cache.revalidate(requestInfo);
pushRequest.on('response', function (response) {
// TODO match or partial move to _sendViaHttp2 xhr.js to avoid maintain both
response.on('data', function (data) {
response.data = mergeTypedArrays(response.data, data);
});
response.on('end', function () {
cache.put(requestInfo, response).then(function () {
that._log.debug("Cache updated via push for proxied XHR(" + pushRequest.href + ")");
}, function (cacheError) {
that._log.debug("Cache error via push for proxied XHR(" + pushRequest.href + "):" + cacheError.message);
}).then(function () {
// Clear requestInfo revalidate state
cache.validated(requestInfo);
});
});
response.on('error', function (e) {
that._log.warn("Server push stream error: " + e);
// Clear requestInfo revalidate state
cache.validated(requestInfo);
});
});
};
// open h2 pull channel
confProto.openH2StreamForPush = function (pushUrl, proxyTransportUrl) {
var that = this,
options = that.options,
pushUri = parseUrl(pushUrl);
that._log.debug('Opening h2 channel for Push Promises: ' + pushUri.href);
var transport = that.getTransport(proxyTransportUrl),
// Create _pushRequests entry with failures and connect states
pushRequest = that._pushRequests[pushUri.href] = that._pushRequests[pushUri.href] || {
failures: [],
reconnectTimer: null,
opened: false,
connecting: false
},
reopenH2StreamForPush = function (reason) {
that._log.info(pushUrl + " push channel closed.");
// Mark as closed
pushRequest.opened = false;
// Clear pending revalidates
that.cache.clearRevalidates();
// Will reconnect only if reason provided
if (reason) {
that._log.warn("Push channel stream reason: " + reason);
pushRequest.failures.push(reason);
if (options.reconnect && !pushRequest.connecting) {
// Get min time between maximumReconnectInterval and failures*reconnectInterval
var reOpendelay = Math.min(
pushRequest.failures.length * options.reconnectInterval,
options.maximumReconnectInterval
);
that._log.info("Push channel stream will re-open in " + reOpendelay + "ms .");
clearTimeout(pushRequest.reconnectTimer);
pushRequest.reconnectTimer = setTimeout(
that.openH2StreamForPush.bind(that, pushUrl, proxyTransportUrl),
reOpendelay
);
} else {
that._log.warn("Push channel stream already connecting.");
}
}
},
openH2StreamForPush = function () {
that._log.info("Push channel will open: " + pushUri.href);
if (pushRequest.opened) {
throw new Error("Server push stream already opened for push "+ pushUri.href);
} else if (pushRequest.connecting) {
throw new Error("Server push stream is already connecting for push "+ pushUri.href);
}
pushRequest.connecting = true;
pushRequest.opened = false;
var request = http2.raw.request({
hostname: pushUri.hostname,
port: pushUri.port,
path: pushUri.path,
transportUrl: proxyTransportUrl,
transport: transport,
agent: that.agent
}, function (response) {
that._log.debug("Push channel connected: " + pushUri.href);
// Set push request connected (not open)
pushRequest.connecting = false;
response.on('open', function () {
// Reset failures on push open not before
pushRequest.opened = true;
pushRequest.failures.length = 0;
});
response.on('finish', function (err) {
// Reconnect on finish
reopenH2StreamForPush(err);
});
response.on('close', function (err) {
// Reconnect on finish
reopenH2StreamForPush(err);
});
response.on('error', function (err) {
that._log.error("Push channel response closed: ", err);
// Reconnect on error
reopenH2StreamForPush(err);
});
});
// Reconnect on error
request.on('error', function (err) {
that._log.error("Push channel request error: ", err);
pushRequest.connecting = false;
reopenH2StreamForPush(err);
});
// add to cache when receive pushRequest
request.on('push', function (request) {
that._log.debug("Push channel received: " + request);
// Trigger Configuration default push listener
that.onPush(request);
// Allow to subscribe to push from configuration for debug
that.emit('push', request);
});
request.end();
// Reconnect on trasnport close
transport.on('close', function (err) {
// TODO err can be null, can reopenH2StreamForPush only reopen with reason
// Should reopenH2StreamForPush re-open even on proper close ?
that._log.debug("Push channel request transport closed: ", err);
pushRequest.connecting = false;
reopenH2StreamForPush(err);
});
pushRequest.request = request;
return pushRequest.request;
};
return openH2StreamForPush();
};
// parse config json
confProto.parseConfig = function (config) {
try {
config = typeof config === 'string' ? JSON.parse(config) : config;
} catch (JsonErr) {
throw new Error('Unable to parse config: ' + config);
}
return config;
};
// add config by json
/*
{
// Logger debugLevel true='info' or (info|debug|trace)
"clientLogLevel": false,
// Transport endpoint
"transport": "wss://where-the-underlying-ws-transport-connects:443/",
// Transport push path
"push": "optional-path-that-is-connected-for-pushes",
// Transport reconnect settings
"reconnect": true,
"reconnectInterval": 100,
"maximumReconnectInterval": 4000,
// AccelerationStrategy could be "always" or "connected"
// Value always means always/don't make requests if they are proxied but no ws connection is open. Wait for the connection to open instead.
// Value connected means make requests when connected via websocket.
"accelerationStrategy": "always",
"proxy": [
"http://origin-to-send-via-http2:80/path/",
"http://origin-to-send-via-http2:80/path2/",
"http://other-origin-to-send-via-http2:80"
]
}
*/
confProto.addConfig = function (config) {
var that = this;
// Decode config
config = that.parseConfig(config);
// Legacy with warning
if (config.pushURL) {
that._log.warn('XMLHttpRequest Http2-Cache configuration "pushURL" is now "push"');
config.push = config.pushURL;
delete config.pushURL;
}
// Update clientLogLevel
if (config.hasOwnProperty('clientLogLevel')) {
that.setDebugLevel(config.clientLogLevel);
// Update option to reflect client state
that.options.clientLogLevel = config.clientLogLevel;
}
// Lookup for defaultOptions keys in config
keys(that.defaultOptions).forEach(function (configOption) {
if (config.hasOwnProperty(configOption)) {
// Create config.options if do not exit only if mapping match once at least
config.options = config.options || {};
config.options[configOption] = config[configOption];
}
});
// Merge config options
if (config.hasOwnProperty('options') && config.options) {
that.setOptions(config.options);
}
// Install transport
if (config.hasOwnProperty('transport') && config.transport) {
// Validate transport
try {
var transportUri = parseUrl(config.transport);
// Add transport proxyfied urls
if (config.hasOwnProperty('proxy')) {
that.addTransportUrls(config.proxy, transportUri);
}
// Connect transport to push url
if (config.hasOwnProperty('push') && config.push) {
that.openH2StreamForPush(parseUrl(config.push), transportUri);
}
} catch (err) {
that._log.error('XMLHttpRequest Http2-Cache configuration "transport" error', err);
}
}
};
// add config by url
confProto.fetchConfig = function (url) {
// TODO, consider using semi-public API??
var that = this;
var xhr = new XMLHttpRequest();
xhr._open('GET', url);
that.configuring();
xhr.addEventListener("load", function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
var status = xhr.status;
if (status !== 200) {
// Prevent configuration to be stale on config load failure
that.configured();
throw new InvalidStateError('Failed to load configuration ' + url + ', status code: ' + status);
} else {
that.addConfig(xhr.response);
that.configured();
}
}
}, true);
// TODO, consider using semi-public API??
xhr._send();
};
// add configs by an array of urls
confProto.configure = function (urls) {
if (urls instanceof Array) {
var cntI = urls.length;
for (var i = 0; i < cntI; i++) {
if (typeof urls[i] === 'string') {
this.fetchConfig(urls[i]);
} else if (typeof urls[i] === 'object') {
this.configuring();
this.addConfig(urls[i]);
this.configured();
} else {
throw new SyntaxError('Invalid arg: ' + urls);
}
}
} else {
throw new SyntaxError('Invalid arg: ' + urls);
}
};
module.exports = Configuration;
},{"./agent":1,"./cache-listener":2,"./cache.js":3,"./errors.js":5,"./logger":6,"./utils":7,"./utils.js":7,"events":16,"http2.js":82,"net":10,"object-assign":99,"object-keys":100,"util":56,"websocket-stream":159}],5:[function(require,module,exports){
function InvalidStateError(message) {
this.name = 'InvalidStateError';
this.message = message;
this.stack = (new Error()).stack;
}
function TypeError(message) {
this.name = 'TypeError';
this.message = message;
this.stack = (new Error()).stack;
}
module.exports = {
InvalidStateError: InvalidStateError,
TypeError: TypeError
};
},{}],6:[function(require,module,exports){
/* global console */
// Logger shim, used when no logger is provided by the user.
function noop() {}
var defaultLogger = {
fatal: noop,
error: noop,
warn : noop,
info : noop,
debug: noop,
trace: noop,
child: function() { return this; }
};
var consoleLogger = {
debugLevel: 'info', // 'info|debug|trace'
fatal: console.error,
error: console.error,
warn : console.warning || console.info,
info : function (data, ctx) {
var debug = console.debug || console.info;
if (
consoleLogger.debugLevel === 'info' ||
consoleLogger.debugLevel === 'trace' ||
consoleLogger.debugLevel === 'debug'
) {
var args = (typeof ctx === 'string' ? [ctx, data] : arguments);
debug.apply(console, args);
}
},
debug: function (data, ctx) {
var debug = console.debug || console.info;
if (
consoleLogger.debugLevel === 'trace' ||
consoleLogger.debugLevel === 'debug'
) {
var args = (typeof ctx === 'string' ? [ctx, data] : arguments);
debug.apply(console, args);
}
},
// Trace only
trace: function (data, ctx) {
var debug = console.debug || console.info;
if (consoleLogger.debugLevel === 'trace') {
consoleLogger.debug(data, ctx);
}
},
// Trace only
child: function(msg) {
if (consoleLogger.debugLevel === 'trace') {
console.info(msg);
}
return this;
}
};
module.exports = {
consoleLogger: consoleLogger,
defaultLogger: defaultLogger
};
},{}],7:[function(require,module,exports){
var url = require('url'),
util = require("util"),
InvalidStateError = require('./errors').InvalidStateError;
var resolvePort = function (u) {
u = (u instanceof url.constructor) ? u : url.parse(u);
var port = u.port;
if (port === null) {
if (u.protocol === "ws:" || u.protocol === "http:") {
port = 80;
} else {
port = 443;
}
}
return port;
};
/* global console */
var parseUrl = function (href) {
var uri = (href instanceof url.constructor) ? href : url.parse(href);
uri.port = resolvePort(uri);
if (
uri.hostname === null &&
typeof window !== 'undefined'
) {
uri.protocol = window.location.protocol;
uri.hostname = window.location.hostname;
uri.port = window.location.port;
uri.host = uri.hostname + ':' + uri.port;
uri.href = uri.protocol + "//" + uri.host + uri.href;
}
// Define uri.origin
uri.origin = uri.hostname + ":" + uri.port;
// Check if host match origin (example.com vs example.com:80)
if (uri.host !== uri.origin) {
// Fix href to include default port
uri.href = uri.href.replace(uri.protocol + "//" + uri.host, uri.protocol + "//" + uri.origin);
// Fix host to include default port
uri.host = uri.hostname + ":" + uri.port;
}
return uri;
};
var redefine = function (obj, prop, value) {
if (obj[prop]) {
// TODO, consider erasing scope/hiding (enumerable: false)
obj["_" + prop] = obj[prop];
}
Object.defineProperty(obj, prop, {
value: value,
enumerable: obj.propertyIsEnumerable(prop),
configurable: true
});
};
var defineGetter = function (obj, prop, getter) {
if (obj[prop]) {
// TODO, consider erasing scope/hiding (enumerable: false)
obj["_" + prop] = obj[prop];
}
Object.defineProperty(obj, prop, {
enumerable: true,
configurable: true,
get: getter
});
};
var definePrivate = function (obj, prop, value) {
Object.defineProperty(obj, prop, {
value: value,
enumerable: false,
configurable: true
});
};
var definePublic = function (obj, prop, value) {
Object.defineProperty(obj, prop, {
value: value,
enumerable: true,
configurable: true
});
};
var getOrigin = function (u) {
u = (u instanceof url.constructor) ? u : parseUrl(u);
return u.protocol + '//' + u.hostname + ':' + resolvePort(u);
};
var defaultPort = function (u, port) {
var parse = (u instanceof url.constructor) ? u : parseUrl(u);
if (!port) {
port = resolvePort(u);
}
u = (u instanceof url.constructor) ? u : parseUrl(u);
return u.protocol + '//' + u.hostname + ':' + port + parse.path;
};
// Import String.fromCodePoint polyfill
require('string.fromcodepoint');
var Utf8ArrayToStr = function (array) {
var c, char2, char3, char4,
out = "",
len = array.length,
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12:
case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
case 15:
// 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
char4 = array[i++];
out += String.fromCodePoint(((c & 0x07) << 18) | ((char2 & 0x3F) << 12) | ((char3 & 0x3F) << 6) | (char4 & 0x3F));
break;
}
}
return out;
};
var mergeTypedArrays = function (a, b) {
// Checks for truthy values on both arrays
if(!a && !b) {
throw 'Please specify valid arguments for parameters a and b.';
}
// Checks for truthy values or empty arrays on each argument
// to avoid the unnecessary construction of a new array and
// the type comparison
if(!b || b.length === 0) {
return a;
}
if(!a || a.length === 0) {
return b;
}
// Make sure that both typed arrays are of the same type
if(Object.prototype.toString.call(a) !== Object.prototype.toString.call(b)) {
throw 'The types of the two arguments passed for parameters a and b do not match.';
}
var c = new a.constructor(a.length + b.length);
// On NodeJS < v4 TypeArray.set is not working as expected,
// starting NodeJS 6+ TypeArray.set.length is 1 and works properly.
if (c.set.length > 0) {
c.set(a, 0);
c.set(b, a.length);
// TypedArray.set relly on deprecated Buffer.set on NodeJS < 6 and producing bad merge
// Using forEach and Native Setter instead
} else {
a.forEach(function (byte, index) { c[index] = byte; });
b.forEach(function (byte, index) { c[a.length + index] = byte; });
}
return c;
};
var toArrayBuffer = function (buf) {
var ab = new ArrayBuffer(buf.length),
view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
};
var dataToType = function (data, type) {
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
switch (type) {
case "":
case "text":
if (data instanceof Uint8Array) {
return Utf8ArrayToStr(data);
}
return data;
case "json":
return JSON.parse(data);
case "arraybuffer":
return toArrayBuffer(data);
case "blob":
if (typeof Blob !== 'undefined') {
return new Blob(data);
} else {
throw new InvalidStateError("Unsupported Response Type: " + type);
}
break;
case "document":
if (
typeof document !== 'undefined' &&
typeof document.implementation !== 'undefined' &&
typeof document.implementation.createDocument === 'function'
) {
return document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', data);
} else {
throw new InvalidStateError("Unsupported Response Type: " + type);
}
break;
default:
throw new InvalidStateError("Unexpected Response Type: " + type);
}
};
var caseInsensitiveEquals = function (str1, str2) {
return str1.toUpperCase() === str2.toUpperCase();
};
var serializeXhrBody = function (headers, body) {
if (typeof body === 'object') {
// Display the key/value pairs
var bodyParts = [],
pairEntry, partPair;
// TODO detect FormData vs POST
// FormData serialization
// application/x-www-form-urlencoded and multipart/form-data.
// https://gist.github.com/joyrexus/524c7e811e4abf9afe56
if (typeof body.entries === 'function') {
var key, value,
iterator = body.entries(),
boundary = "----webkitformboundary";
// Use body._boundary if provided for unit-test and custom value
boundary += body._TestBoundary || (+(new Date())).toString(16);
while (
(pairEntry = iterator.next()) &&
pairEntry.done === false
) {
value = pairEntry.value[1];
key = pairEntry.value[0];
if (typeof value !== "string") {
throw new Error("FormData limited support, only string supported (" + typeof value + ')');
}
var field = util.format("\r\n--%s\r\n", boundary);
field += util.format("Content-Disposition: form-data; name=\"%s\"\r\n\r\n", key);
field += value;
bodyParts.push(field);
}
bodyParts.push(util.format("\r\n--%s--", boundary));
body = bodyParts.join('');
// Refused to set unsafe header "Content-Length"
//headers.set('Content-Length', body.length);
headers.set('Content-Type', 'multipart/form-data; boundary=' + boundary);
} else {
Object.keys(body).forEach(function (key) {
var value = body[key];
if (typeof value !== "string") {
throw new Error("FormData limited support, only string supported (" + typeof value + ')');
}
bodyParts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
});
body = bodyParts.join('&');
}
//headers.set('Content-Type', 'application/x-www-form-urlencoded');
}
return body;
};
module.exports = {
parseUrl: parseUrl,
redefine: redefine,
defineGetter: defineGetter,
definePrivate: definePrivate,
definePublic: definePublic,
resolvePort: resolvePort,
getOrigin: getOrigin,
dataToType: dataToType,
defaultPort: defaultPort,
serializeXhrBody: serializeXhrBody,
caseInsensitiveEquals: caseInsensitiveEquals,
mergeTypedArrays: mergeTypedArrays,
Utf8ArrayToStr: Utf8ArrayToStr
};
},{"./errors":5,"string.fromcodepoint":119,"url":52,"util":56}],8:[function(require,module,exports){
/**
* Weak hashmap from instance to properties, so internal properties aren't exposed
*/
var WeakMap = require("collections/weak-map");
var XhrInfo = function () {
this.storage = new WeakMap();
};
XhrInfo.prototype.get = function (k, p, d) {
if (!this.storage.has(k)) {
return null;
} else {
return this.storage.get(k, d)[p];
}
};
XhrInfo.prototype.put = function (k, p, v) {
if (!this.storage.has(k)) {
// lazy init
this.storage.set(k, {});
}
this.storage.get(k)[p] = v;
return v;
};
XhrInfo.prototype.clean = function (k) {
this.storage.delete(k);
};
module.exports = XhrInfo;
},{"collections/weak-map":80}],9:[function(require,module,exports){
var http2 = require('http2.js'),
keys = require('object-keys'),
redefine = require('./utils').redefine,
defineGetter = require('./utils').defineGetter,
definePublic = require('./utils').definePublic,
definePrivate = require('./utils').definePrivate,
dataToType = require('./utils').dataToType,
defaultPort = require('./utils').defaultPort,
RequestInfo = require('./cache.js').RequestInfo,
parseUrl = require('./utils').parseUrl,
serializeXhrBody = require('./utils').serializeXhrBody,
getOrigin = require('./utils').getOrigin,
mergeTypedArrays = require('./utils').mergeTypedArrays,
InvalidStateError = require('./errors.js').InvalidStateError,
XhrInfo = require('./xhr-info.js'),
Map = require("collections/map");
var HTTP2_FORBIDDEN_HEADERS = ['accept-charset',
'accept-encoding',
'access-control-request-headers',
'access-control-request-method',
'connection',
'content-length',
'cookie',
'cookie2',
'date',
'dnt',
'expect',
'host',
'keep-alive',
'origin',
'referer',
'te',
'trailer',
'transfer-encoding',
'upgrade',
'via'];
var HTTP_METHODS = [
'GET',
'OPTIONS',
'HEAD',
'POST',
'PUT',
'DELETE',
'TRACE',
'CONNECT'
];
// ProgressEvent
function ProgressEvent(type) {
this.type = type;
this.target = null;
}
ProgressEvent.prototype.bubbles = false;
ProgressEvent.prototype.cancelable = false;
ProgressEvent.prototype.target = null;
function enableXHROverH2(XMLHttpRequest, configuration) {
var xhrProto = XMLHttpRequest.prototype;
var xhrInfo = new XhrInfo();
definePublic(XMLHttpRequest, 'configuration', configuration);
definePublic(XMLHttpRequest, 'proxy', function (configs) {
return configuration.configure(configs);
});
function redefineProtoInfo(xhrProto, xhrInfo, property, initalValue) {
var originalProperty = "_" + property;
Object.defineProperty(xhrProto, originalProperty, Object.getOwnPropertyDescriptor(xhrProto, property));
Object.defineProperty(xhrProto, property, {
get: function () {
return xhrInfo.get(this, property) || this[originalProperty] || initalValue;
},
set: function (value) {
xhrInfo.put(this, property, value);
}
});
}
redefineProtoInfo(xhrProto, xhrInfo, "responseType", '');
redefineProtoInfo(xhrProto, xhrInfo, "readyState", 0);
redefineProtoInfo(xhrProto, xhrInfo, "timeout");
redefine(xhrProto, 'open', function (method, url, async, username, password) {
// https://xhr.spec.whatwg.org/#the-open%28%29-method
method = method.toUpperCase();
if (HTTP_METHODS.indexOf(method.toUpperCase()) < 0) {
throw new SyntaxError("Invalid method: " + method);
}
// parse so we know it is valid
var parseurl = parseUrl(url);
if (async === undefined) {
async = true;
} else if (async === false) {
throw new SyntaxError("Synchronous is not supported");
}
xhrInfo.put(this, 'method', method);
xhrInfo.put(this, 'url', url);
xhrInfo.put(this, 'async', async);
xhrInfo.put(this, 'headers', new Map());
if (parseurl.host && username && password) {
xhrInfo.put(this, 'username', username);
xhrInfo.put(this, 'password', password);
}
var self = this;
/*
* We need to fire opened event here but native library might
* recall open, so we do this
*/
if (self.onreadystatechange) {
var orscDelegate = self.onreadystatechange;
self.onreadystatechange = function () {
if (xhrInfo.get(this, 'lastreadystate') !== 1 || self.readyState !== 1) {
xhrInfo.put(this, 'lastreadystate', self.readyState);
orscDelegate();
}
};
}
// Reset ready state
xhrInfo.put(this, 'lastreadystate', XMLHttpRequest.OPENED);
this._changeState(XMLHttpRequest.OPENED);
});
redefine(xhrProto, 'setRequestHeader', function (name, value) {
if (this.readyState > 2) {
throw new InvalidStateError("Can not setRequestHeader on unopened XHR");
}
var lcname = name.toLowerCase();
if (HTTP2_FORBIDDEN_HEADERS.indexOf(lcname) > 0 || (lcname.lastIndexOf('sec-', 0) === 0 && lcname.replace('sec-', '').indexOf(lcname) > 0) || (lcname.lastIndexOf('proxy-', 0) === 0 && lcname.replace('proxy-', '').indexOf(lcname) > 0)) {
throw new SyntaxError("Forbidden Header: " + name);
}
// Each header field consists of a name followed by a colon (":") and the field value. Field names are
// case-insensitive.
// We standardize to lowercase for ease
var headers = xhrInfo.get(this, 'headers');
if (!headers) {
headers = new Map();
xhrInfo.put(this, 'headers', headers);
}
headers.set(lcname, value);
});
definePrivate(xhrProto, '_changeState', function (state, options) {
var self = this;
switch (state) {
case XMLHttpRequest.UNSENT:
break;
case XMLHttpRequest.OPENED:
break;
case XMLHttpRequest.HEADERS_RECEIVED:
var statusCode = options.response.statusCode;
defineGetter(this, 'status', function () {
return statusCode;
});
var statusMessage = http2.STATUS_CODES[statusCode];
if (statusMessage) {
this.statusText = statusMessage;
} else {
configuration._log.warn('Unknown STATUS CODE: ' + statusCode);
}
break;
case XMLHttpRequest.LOADING:
this.__dispatchEvent(new ProgressEvent('progress'));
break;
case XMLHttpRequest.DONE:
redefine(this, 'getResponseHeader', function(header) {
return options.response.headers[header.toLowerCase()];
});
redefine(this, 'getAllResponseHeaders', function() {
var responseHeaders = options.response.headers;
return keys(responseHeaders).filter(function (responseHeader) {
return responseHeader !== 'toString';
}).map(function (responseHeader) {
return responseHeader + ': ' + responseHeaders[responseHeader];
}).join("\n");
});
this.__dispatchEvent(new ProgressEvent('load'));
this.__dispatchEvent(new ProgressEvent('loadend'));
break;
default:
throw new InvalidStateError("Unexpected XHR _changeState: " + state);
}
switch (state) {
case XMLHttpRequest.UNSENT:
case XMLHttpRequest.OPENED:
break;
default:
this.readyState = state;
if (this.readyState !== state) {
throw new Error('Unable to update readyState ' + this.readyState + ' vs ' + state);
}
}
this.__dispatchEvent(new ProgressEvent('readystatechange'));
});
// Expose response and responseText with cached dataToType
function defineXhrResponse(xhr, response) {
defineGetter(xhr, 'response', function () {
// Render as responseType
var responseType = xhrInfo.get(xhr, 'responseType') || '';
return dataToType(response.data, responseType);
});
defineGetter(xhr, 'responseText', function () {
var responseType = xhrInfo.get(xhr, 'responseType') || '';
if (responseType !== '' && responseType !== 'text') {
throw new InvalidStateError("Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was '" + responseType + "')");
}
// Force text rendering
return dataToType(response.data, 'text');
});
}
definePrivate(xhrProto, '_sendViaHttp2', function (destination, body, proxyTransportUrl) {
var self = this,
options = configuration.options,
cache = configuration.cache,
requestUrl = getOrigin(destination.href) + destination.path,
requestMethod = xhrInfo.get(self, 'method'),
requestHeaders = xhrInfo.get(self, 'headers'),
requestInfo = new RequestInfo(requestMethod, requestUrl, requestHeaders);
// TODO reset response
// TODO change getCache to readonly property
cache.match(requestInfo).then(function (response) {
if (response) {
if (configuration.debug) {
configuration._log.debug("Using cache result for XHR(" + destination.href + ")");
}
// Export cached response
defineXhrResponse(self, response);
self.__dispatchEvent(new ProgressEvent('loadstart'));
self._changeState(XMLHttpRequest.HEADERS_RECEIVED, {'response': response});
self._changeState(XMLHttpRequest.LOADING, {'response': response});
self._changeState(XMLHttpRequest.DONE, {'response': response});
} else {
// Need to make the request your self
if (body) {
// https://xhr.spec.whatwg.org/#the-send%28%29-method
if (
typeof HTMLElement !== 'undefined' &&
body instanceof HTMLElement
) {
if (!requestHeaders.has('content-encoding')) {
requestHeaders.set('content-encoding', 'UTF-8');
}
if (!requestHeaders.has('content-type')) {
requestHeaders.set('content-type', 'text/html; charset=utf-8');
}
} else {
// Set default encoding
// TODO use document encoding
if (!requestHeaders.has('content-encoding')) {
requestHeaders.set('content-encoding', 'UTF-8');
}
}
// only other option in spec is a String
// inject content-length TODO remove this as should not be required
requestHeaders.set('content-length', body.toString().length);
}
// TODO use isRevalidating and store request in cache.revalidate
// cache.isRevalidating(requestInfo)
// Naive Timeout implementation
var timeout = xhrInfo.get(self, 'timeout'),
timeoutTimer = xhrInfo.get(self, 'timeoutTimer');
if (timeout) {
var otoDelegate = self.ontimeout;
self.ontimeout = function () {
// Clear requestInfo revalidate state
cache.validated(requestInfo);
// TODO abort
xhrInfo.put(self, 'timeoutOccured', true);
otoDelegate();
};
clearTimeout(timeoutTimer);
xhrInfo.put(self, 'timeoutOccured', false);
timeoutTimer = setTimeout(self.ontimeout, timeout);
xhrInfo.put(self, 'timeoutTimer', timeoutTimer);
}
var transport = configuration.getTransport(proxyTransportUrl);
var request = http2.raw.request({
agent: configuration.agent,
// protocol has already been matched by getting transport url
// protocol: destination.protocol,
hostname: destination.hostname,
port: destination.port,
path: destination.path,
method: requestMethod,
headers: requestHeaders.toObject(),
// auth: self.__headers // TODO AUTH
// TODO, change transport to createConnection
transport: transport,
transportUrl: proxyTransportUrl
// TODO timeout if syncronization set
// timeout: self.__timeout
}, function (response) {
var timeoutOccured = xhrInfo.get(self, 'timeoutOccured'),
timeoutTimer = xhrInfo.get(self, 'timeoutTimer');
// Naive Timeout implementation
if (timeoutOccured) {
return;
}
clearTimeout(timeoutTimer);
// Export live response
defineXhrResponse(self, response);
self._changeState(XMLHttpRequest.HEADERS_RECEIVED, {'response': response});
response.on('data', function (data) {
response.data = mergeTypedArrays(response.data, data);
self._changeState(XMLHttpRequest.LOADING, {'response': response});
});
response.on('finish', function () {
if (configuration.debug) {
configuration._log.debug("Got response for proxied XHR(" + destination.href + ")");
}
cache.put(requestInfo, response).then(function () {
configuration._log.debug("Cache updated for proxied XHR(" + destination.href + ")");
}).catch(function (cacheError) {
configuration._log.debug("Cache error for proxied XHR(" + destination.href + "):" + cacheError.message);
}).then(function () {
self._changeState(XMLHttpRequest.DONE, {
'response': response
});
// Clear requestInfo revalidate state
cache.validated(requestInfo);
});
});
});
// Handle request error
request.on('error', function (/*e*/) {
// Clear requestInfo revalidate state
cache.validated(requestInfo);
// Only propagate error if accelerationStrategy is always
if (options.accelerationStrategy === 'always') {
self.__dispatchEvent(new ProgressEvent('error'));
}
});
// Handle transport error and fallback
transport.on('error', function (/*e*/) {
if (
self.readyState === XMLHttpRequest.UNSENT &&
options.accelerationStrategy === 'connected'
) {
self.send();
}
});
// Update cache when receive pushRequest
request.on('push', function(respo) {
configuration.onPush(respo);
});
request.end(body || null);
// Set requestInfo revalidate state
// TODO pass request for future dedup pending requestInfo
cache.revalidate(requestInfo);
self.__dispatchEvent(new ProgressEvent('loadstart'));
}
});
});
redefine(xhrProto, 'send', function (body) {
var self = this,
url = xhrInfo.get(self, 'url'),
headers = xhrInfo.get(self, 'headers');
// Wait while addConfig complete and initial transport connection
if (configuration.isConfiguring()) {
if (configuration.debug) {
configuration._log.debug("Delaying XHR(" + url + ") until configuration completes");
}
// Once addConfig completed and initial transport connection attempt completed
configuration.once('completed', function () {
// Re-attempt send request
self.send(body);
});
} else {
var destination = parseUrl(url),
proxyTransportUrl = configuration.getTransportUrl(destination);
if (proxyTransportUrl) {
if (configuration.debug) {
configuration._log.debug("Proxying XHR(" + url + ") via " + proxyTransportUrl);
}
// Fix support for FormData if not null and object
if (body && typeof body === "object") {
body = serializeXhrBody(headers, body);
}
self._sendViaHttp2(destination, body, proxyTransportUrl);
} else {
if (configuration.debug) {
configuration._log.debug("Sending XHR(" + url + ") via native stack");
}
self._open(xhrInfo.get(self, 'method'),
url,
xhrInfo.get(self, 'async'),
xhrInfo.get(self, 'username'),
xhrInfo.get(self, 'password')
);
// Restore responseType
self._responseType = xhrInfo.get(self, 'responseType') || '';
// Fix support for http2.js only if FormData is not defined and not null
if (body && typeof FormData === "undefined") {
body = serializeXhrBody(headers, body);
}
// Reset Headers
headers.forEach(function (value, key) {
self._setRequestHeader(key, value);
}, self);
self._send(body);
}
}
});
redefine(xhrProto, 'addEventListener', function (eventType, listener) {
if (!this.__listeners) {
this.__listeners = {};
this.__listenedToEvents = new Set();
}
eventType = eventType.toLowerCase();
if (!this.__listeners[eventType]) {
this.__listeners[eventType] = [];
}
this.__listeners[eventType].push(listener);
this.__listenedToEvents.add(eventType);
// TODO try catch addEventListener?? for browsers that don't support it
this._addEventListener(eventType, listener);
return void 0;
});
redefine(xhrProto, 'removeEventListener', function (eventType, listener) {
var index;
eventType = eventType.toLowerCase();
if (this.__listeners[eventType]) {
index = this.__listeners[eventType].indexOf(listener);
if (index !== -1) {
this.__listeners[eventType].splice(index, 1);
}
}
// TODO try catch _removeEventListener?? for browsers that don't support it
this._removeEventListener(eventType, listener);
return void 0;
});
definePrivate(xhrProto, '__dispatchEvent', function (event) {
var eventType, j, len, listener, listeners;
event.currentTarget = event.target = this;
eventType = event.type;
if (this.__listeners) {
if ((listeners = this.__listeners[eventType])) {
for (j = 0, len = listeners.length; j < len; j++) {
listener = listeners[j];
listener.call(this, event);
}
}
}
if ((listener = this["on" + eventType])) {
listener.call(this, event);
}
return void 0;
});
/*
* Maybe in the future this will be made public, but it is needed for testing now
* TODO Work in Progress (Design needed)
*/
definePrivate(xhrProto, 'subscribe', function (cb) {
// assert this._state === XMLHttpRequest.OPENED
var url = defaultPort(xhrInfo.get(this, 'url'));
// once? or do we have API for unsubscribe?
// https://nodejs.org/api/events.html#events_emitter_removelistener_eventname_listener
var subscription = function (requestUrl) {
// TODO should we go through xhr lifecycle again ??
if (requestUrl === url) {
cb();
}
};
configuration.cacheListener.on('cached', subscription);
// TODO: Will only works once, not with multiple subscription
definePrivate(xhrProto, 'unsubscribe', function () {
configuration.cacheListener.removeListener('cached', subscription);
});
});
}
module.exports = {
enableXHROverH2: enableXHROverH2
};
},{"./cache.js":3,"./errors.js":5,"./utils":7,"./xhr-info.js":8,"collections/map":72,"http2.js":82,"object-keys":100}],10:[function(require,module,exports){
},{}],11:[function(require,module,exports){
(function (global){
'use strict';
// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js
// original notice:
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
function compare(a, b) {
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;
}
function isBuffer(b) {
if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {
return global.Buffer.isBuffer(b);
}
return !!(b != null && b._isBuffer);
}
// based on node assert, original notice:
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var util = require('util/');
var hasOwn = Object.prototype.hasOwnProperty;
var pSlice = Array.prototype.slice;
var functionsHaveNames = (function () {
return function foo() {}.name === 'foo';
}());
function pToString (obj) {
return Object.prototype.toString.call(obj);
}
function isView(arrbuf) {
if (isBuffer(arrbuf)) {
return false;
}
if (typeof global.ArrayBuffer !== 'function') {
return false;
}
if (typeof ArrayBuffer.isView === 'function') {
return ArrayBuffer.isView(arrbuf);
}
if (!arrbuf) {
return false;
}
if (arrbuf instanceof DataView) {
return true;
}
if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
return true;
}
return false;
}
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = module.exports = ok;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected })
var regex = /\s*function\s+([^\(\s]*)\s*/;
// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
function getName(func) {
if (!util.isFunction(func)) {
return;
}
if (functionsHaveNames) {
return func.name;
}
var str = func.toString();
var match = str.match(regex);
return match && match[1];
}
assert.AssertionError = function AssertionError(options) {
this.name = 'AssertionError';
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
if (options.message) {
this.message = options.message;
this.generatedMessage = false;
} else {
this.message = getMessage(this);
this.generatedMessage = true;
}
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
} else {
// non v8 browsers so we can have a stacktrace
var err = new Error();
if (err.stack) {
var out = err.stack;
// try to strip useless frames
var fn_name = getName(stackStartFunction);
var idx = out.indexOf('\n' + fn_name);
if (idx >= 0) {
// once we have located the function frame
// we need to strip out everything before it (and its line)
var next_line = out.indexOf('\n', idx + 1);
out = out.substring(next_line + 1);
}
this.stack = out;
}
}
};
// assert.AssertionError instanceof Error
util.inherits(assert.AssertionError, Error);
function truncate(s, n) {
if (typeof s === 'string') {
return s.length < n ? s : s.slice(0, n);
} else {
return s;
}
}
function inspect(something) {
if (functionsHaveNames || !util.isFunction(something)) {
return util.inspect(something);
}
var rawname = getName(something);
var name = rawname ? ': ' + rawname : '';
return '[Function' + name + ']';
}
function getMessage(self) {
return truncate(inspect(self.actual), 128) + ' ' +
self.operator + ' ' +
truncate(inspect(self.expected), 128);
}
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, !!guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
function ok(value, message) {
if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok = ok;
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
}
};
assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
}
};
function _deepEqual(actual, expected, strict, memos) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (isBuffer(actual) && isBuffer(expected)) {
return compare(actual, expected) === 0;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (util.isDate(actual) && util.isDate(expected)) {
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (util.isRegExp(actual) && util.isRegExp(expected)) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if ((actual === null || typeof actual !== 'object') &&
(expected === null || typeof expected !== 'object')) {
return strict ? actual === expected : actual == expected;
// If both values are instances of typed arrays, wrap their underlying
// ArrayBuffers in a Buffer each to increase performance
// This optimization requires the arrays to have the same type as checked by
// Object.prototype.toString (aka pToString). Never perform binary
// comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
// bit patterns are not identical.
} else if (isView(actual) && isView(expected) &&
pToString(actual) === pToString(expected) &&
!(actual instanceof Float32Array ||
actual instanceof Float64Array)) {
return compare(new Uint8Array(actual.buffer),
new Uint8Array(expected.buffer)) === 0;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else if (isBuffer(actual) !== isBuffer(expected)) {
return false;
} else {
memos = memos || {actual: [], expected: []};
var actualIndex = memos.actual.indexOf(actual);
if (actualIndex !== -1) {
if (actualIndex === memos.expected.indexOf(expected)) {
return true;
}
}
memos.actual.push(actual);
memos.expected.push(expected);
return objEquiv(actual, expected, strict, memos);
}
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv(a, b, strict, actualVisitedObjects) {
if (a === null || a === undefined || b === null || b === undefined)
return false;
// if one is a primitive, the other must be same
if (util.isPrimitive(a) || util.isPrimitive(b))
return a === b;
if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
return false;
var aIsArgs = isArguments(a);
var bIsArgs = isArguments(b);
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
return false;
if (aIsArgs) {
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b, strict);
}
var ka = objectKeys(a);
var kb = objectKeys(b);
var key, i;
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length !== kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] !== kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
}
};
assert.notDeepStrictEqual = notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message) {
if (_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
}
}
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, '!==', assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (Object.prototype.toString.call(expected) == '[object RegExp]') {
return expected.test(actual);
}
try {
if (actual instanceof expected) {
return true;
}
} catch (e) {
// Ignore. The instanceof check doesn't work for arrow functions.
}
if (Error.isPrototypeOf(expected)) {
return false;
}
return expected.call({}, actual) === true;
}
function _tryBlock(block) {
var error;
try {
block();
} catch (e) {
error = e;
}
return error;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof block !== 'function') {
throw new TypeError('"block" argument must be a function');
}
if (typeof expected === 'string') {
message = expected;
expected = null;
}
actual = _tryBlock(block);
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail(actual, expected, 'Missing expected exception' + message);
}
var userProvidedMessage = typeof message === 'string';
var isUnwantedException = !shouldThrow && util.isError(actual);
var isUnexpectedException = !shouldThrow && actual && !expected;
if ((isUnwantedException &&
userProvidedMessage &&
expectedException(actual, expected)) ||
isUnexpectedException) {
fail(actual, expected, 'Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws(true, block, error, message);
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws(false, block, error, message);
};
assert.ifError = function(err) { if (err) throw err; };
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
if (hasOwn.call(obj, key)) keys.push(key);
}
return keys;
};
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"util/":56}],12:[function(require,module,exports){
arguments[4][10][0].apply(exports,arguments)
},{"dup":10}],13:[function(require,module,exports){
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/* eslint-disable no-proto */
'use strict'
var base64 = require('base64-js')
var ieee754 = require('ieee754')
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50
var K_MAX_LENGTH = 0x7fffffff
exports.kMaxLength = K_MAX_LENGTH
/**
* If `Buffer.TYPED_ARRAY_SUPPORT`:
* === true Use Uint8Array implementation (fastest)
* === false Print warning and recommend using `buffer` v4.x which has an 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+.
*
* We report that the browser does not support typed arrays if the are not subclassable
* using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
* (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
* for __proto__ and has a buggy typed array implementation.
*/
Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
typeof console.error === 'function') {
console.error(
'This browser lacks typed array (Uint8Array) support which is required by ' +
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
)
}
function typedArraySupport () {
// Can typed array instances can be augmented?
try {
var arr = new Uint8Array(1)
arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
return arr.foo() === 42
} catch (e) {
return false
}
}
function createBuffer (length) {
if (length > K_MAX_LENGTH) {
throw new RangeError('Invalid typed array length')
}
// Return an augmented `Uint8Array` instance
var buf = new Uint8Array(length)
buf.__proto__ = Buffer.prototype
return buf
}
/**
* 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) {
// 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(arg)
}
return from(arg, encodingOrOffset, length)
}
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
if (typeof Symbol !== 'undefined' && Symbol.species &&
Buffer[Symbol.species] === Buffer) {
Object.defineProperty(Buffer, Symbol.species, {
value: null,
configurable: true,
enumerable: false,
writable: false
})
}
Buffer.poolSize = 8192 // not used by this implementation
function from (value, encodingOrOffset, length) {
if (typeof value === 'number') {
throw new TypeError('"value" argument must not be a number')
}
if (isArrayBuffer(value)) {
return fromArrayBuffer(value, encodingOrOffset, length)
}
if (typeof value === 'string') {
return fromString(value, encodingOrOffset)
}
return fromObject(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(value, encodingOrOffset, length)
}
// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
// https://github.com/feross/buffer/pull/148
Buffer.prototype.__proto__ = Uint8Array.prototype
Buffer.__proto__ = Uint8Array
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 (size, fill, encoding) {
assertSize(size)
if (size <= 0) {
return createBuffer(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(size).fill(fill, encoding)
: createBuffer(size).fill(fill)
}
return createBuffer(size)
}
/**
* Creates a new filled Buffer instance.
* alloc(size[, fill[, encoding]])
**/
Buffer.alloc = function (size, fill, encoding) {
return alloc(size, fill, encoding)
}
function allocUnsafe (size) {
assertSize(size)
return createBuffer(size < 0 ? 0 : checked(size) | 0)
}
/**
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
* */
Buffer.allocUnsafe = function (size) {
return allocUnsafe(size)
}
/**
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
*/
Buffer.allocUnsafeSlow = function (size) {
return allocUnsafe(size)
}
function fromString (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
var buf = createBuffer(length)
var actual = buf.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')
buf = buf.slice(0, actual)
}
return buf
}
function fromArrayLike (array) {
var length = array.length < 0 ? 0 : checked(array.length) | 0
var buf = createBuffer(length)
for (var i = 0; i < length; i += 1) {
buf[i] = array[i] & 255
}
return buf
}
function fromArrayBuffer (array, byteOffset, length) {
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')
}
var buf
if (byteOffset === undefined && length === undefined) {
buf = new Uint8Array(array)
} else if (length === undefined) {
buf = new Uint8Array(array, byteOffset)
} else {
buf = new Uint8Array(array, byteOffset, length)
}
// Return an augmented `Uint8Array` instance
buf.__proto__ = Buffer.prototype
return buf
}
function fromObject (obj) {
if (Buffer.isBuffer(obj)) {
var len = checked(obj.length) | 0
var buf = createBuffer(len)
if (buf.length === 0) {
return buf
}
obj.copy(buf, 0, 0, len)
return buf
}
if (obj) {
if (isArrayBufferView(obj) || 'length' in obj) {
if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
return createBuffer(0)
}
return fromArrayLike(obj)
}
if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
return fromArrayLike(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 < K_MAX_LENGTH` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if (length >= K_MAX_LENGTH) {
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
'size: 0x' + K_MAX_LENGTH.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 === true
}
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).toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'latin1':
case 'binary':
case 'base64':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return true
default:
return false
}
}
Buffer.concat = function concat (list, length) {
if (!Array.isArray(list)) {
throw new TypeError('"list" argument must be an Array of Buffers')
}
if (list.length === 0) {
return Buffer.alloc(0)
}
var i
if (length === undefined) {
length = 0
for (i = 0; i < list.length; ++i) {
length += list[i].length
}
}
var buffer = Buffer.allocUnsafe(length)
var pos = 0
for (i = 0; i < list.length; ++i) {
var buf = list[i]
if (!Buffer.isBuffer(buf)) {
throw new TypeError('"list" argument must be an Array of Buffers')
}
buf.copy(buffer, pos)
pos += buf.length
}
return buffer
}
function byteLength (string, encoding) {
if (Buffer.isBuffer(string)) {
return string.length
}
if (isArrayBufferView(string) || isArrayBuffer(string)) {
return string.byteLength
}
if (typeof string !== 'string') {
string = '' + string
}
var len = string.length
if (len === 0) return 0
// Use a for loop to avoid recursion
var loweredCase = false
for (;;) {
switch (encoding) {
case 'ascii':
case 'latin1':
case 'binary':
return len
case 'utf8':
case 'utf-8':
case undefined:
return utf8ToBytes(string).length
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return len * 2
case 'hex':
return len >>> 1
case 'base64':
return base64ToBytes(string).length
default:
if (loweredCase) return utf8ToBytes(string).length // assume utf8
encoding = ('' + encoding).toLowerCase()
loweredCase = true
}
}
}
Buffer.byteLength = byteLength
function slowToString (encoding, start, end) {
var loweredCase = false
// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
// property of a typed array.
// This behaves neither like String nor Uint8Array in that we set start/end
// to their upper/lower bounds if the value passed is out of range.
// undefined is handled specially as per ECMA-262 6th Edition,
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
if (start === undefined || start < 0) {
start = 0
}
// Return early if start > this.length. Done here to prevent potential uint32
// coercion fail below.
if (start > this.length) {
return ''
}
if (end === undefined || end > this.length) {
end = this.length
}
if (end <= 0) {
return ''
}
// Force coersion to uint32. This will also coerce falsey/NaN values to 0.
end >>>= 0
start >>>= 0
if (end <= start) {
return ''
}
if (!encoding) encoding = 'utf8'
while (true) {
switch (encoding) {
case 'hex':
return hexSlice(this, start, end)
case 'utf8':
case 'utf-8':
return utf8Slice(this, start, end)
case 'ascii':
return asciiSlice(this, start, end)
case 'latin1':
case 'binary':
return latin1Slice(this, start, end)
case 'base64':
return base64Slice(this, start, end)
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return utf16leSlice(this, start, end)
default:
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
encoding = (encoding + '').toLowerCase()
loweredCase = true
}
}
}
// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
// reliably in a browserify context because there could be multiple different
// copies of the 'buffer' package in use. This method works even for Buffer
// instances that were created from another copy of the `buffer` package.
// See: https://github.com/feross/buffer/issues/154
Buffer.prototype._isBuffer = true
function swap (b, n, m) {
var i = b[n]
b[n] = b[m]
b[m] = i
}
Buffer.prototype.swap16 = function swap16 () {
var len = this.length
if (len % 2 !== 0) {
throw new RangeError('Buffer size must be a multiple of 16-bits')
}
for (var i = 0; i < len; i += 2) {
swap(this, i, i + 1)
}
return this
}
Buffer.prototype.swap32 = function swap32 () {
var len = this.length
if (len % 4 !== 0) {
throw new RangeError('Buffer size must be a multiple of 32-bits')
}
for (var i = 0; i < len; i += 4) {
swap(this, i, i + 3)
swap(this, i + 1, i + 2)
}
return this
}
Buffer.prototype.swap64 = function swap64 () {
var len = this.length
if (len % 8 !== 0) {
throw new RangeError('Buffer size must be a multiple of 64-bits')
}
for (var i = 0; i < len; i += 8) {
swap(this, i, i + 7)
swap(this, i + 1, i + 6)
swap(this, i + 2, i + 5)
swap(this, i + 3, i + 4)
}
return this
}
Buffer.prototype.toString = function toString () {
var length = this.length
if (length === 0) return ''
if (arguments.length === 0) return utf8Slice(this, 0, length)
return slowToString.apply(this, arguments)
}
Buffer.prototype.equals = function equals (b) {
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
if (this === b) return true
return Buffer.compare(this, b) === 0
}
Buffer.prototype.inspect = function inspect () {
var str = ''
var max = exports.INSPECT_MAX_BYTES
if (this.length > 0) {
str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
if (this.length > max) str += ' ... '
}
return '<Buffer ' + str + '>'
}
Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
if (!Buffer.isBuffer(target)) {
throw new TypeError('Argument must be a Buffer')
}
if (start === undefined) {
start = 0
}
if (end === undefined) {
end = target ? target.length : 0
}
if (thisStart === undefined) {
thisStart = 0
}
if (thisEnd === undefined) {
thisEnd = this.length
}
if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
throw new RangeError('out of range index')
}
if (thisStart >= thisEnd && start >= end) {
return 0
}
if (thisStart >= thisEnd) {
return -1
}
if (start >= end) {
return 1
}
start >>>= 0
end >>>= 0
thisStart >>>= 0
thisEnd >>>= 0
if (this === target) return 0
var x = thisEnd - thisStart
var y = end - start
var len = Math.min(x, y)
var thisCopy = this.slice(thisStart, thisEnd)
var targetCopy = target.slice(start, end)
for (var i = 0; i < len; ++i) {
if (thisCopy[i] !== targetCopy[i]) {
x = thisCopy[i]
y = targetCopy[i]
break
}
}
if (x < y) return -1
if (y < x) return 1
return 0
}
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
// Empty buffer means no match
if (buffer.length === 0) return -1
// Normalize byteOffset
if (typeof byteOffset === 'string') {
encoding = byteOffset
byteOffset = 0
} else if (byteOffset > 0x7fffffff) {
byteOffset = 0x7fffffff
} else if (byteOffset < -0x80000000) {
byteOffset = -0x80000000
}
byteOffset = +byteOffset // Coerce to Number.
if (numberIsNaN(byteOffset)) {
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
byteOffset = dir ? 0 : (buffer.length - 1)
}
// Normalize byteOffset: negative offsets start from the end of the buffer
if (byteOffset < 0) byteOffset = buffer.length + byteOffset
if (byteOffset >= buffer.length) {
if (dir) return -1
else byteOffset = buffer.length - 1
} else if (byteOffset < 0) {
if (dir) byteOffset = 0
else return -1
}
// Normalize val
if (typeof val === 'string') {
val = Buffer.from(val, encoding)
}
// Finally, search either indexOf (if dir is true) or lastIndexOf
if (Buffer.isBuffer(val)) {
// Special case: looking for empty string/buffer always fails
if (val.length === 0) {
return -1
}
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
} else if (typeof val === 'number') {
val = val & 0xFF // Search for a byte value [0-255]
if (typeof Uint8Array.prototype.indexOf === 'function') {
if (dir) {
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
} else {
return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
}
}
return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
}
throw new TypeError('val must be string, number or Buffer')
}
function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
var indexSize = 1
var arrLength = arr.length
var valLength = val.length
if (encoding !== undefined) {
encoding = String(encoding).toLowerCase()
if (encoding === 'ucs2' || encoding === 'ucs-2' ||
encoding === 'utf16le' || encoding === 'utf-16le') {
if (arr.length < 2 || val.length < 2) {
return -1
}
indexSize = 2
arrLength /= 2
valLength /= 2
byteOffset /= 2
}
}
function read (buf, i) {
if (indexSize === 1) {
return buf[i]
} else {
return buf.readUInt16BE(i * indexSize)
}
}
var i
if (dir) {
var foundIndex = -1
for (i = byteOffset; i < arrLength; i++) {
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
if (foundIndex === -1) foundIndex = i
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
} else {
if (foundIndex !== -1) i -= i - foundIndex
foundIndex = -1
}
}
} else {
if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
for (i = byteOffset; i >= 0; i--) {
var found = true
for (var j = 0; j < valLength; j++) {
if (read(arr, i + j) !== read(val, j)) {
found = false
break
}
}
if (found) return i
}
}
return -1
}
Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
return this.indexOf(val, byteOffset, encoding) !== -1
}
Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
}
Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}
function hexWrite (buf, string, offset, length) {
offset = Number(offset) || 0
var remaining = buf.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
// must be an even number of digits
var strLen = string.length
if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
if (length > strLen / 2) {
length = strLen / 2
}
for (var i = 0; i < length; ++i) {
var parsed = parseInt(string.substr(i * 2, 2), 16)
if (numberIsNaN(parsed)) return i
buf[offset + i] = parsed
}
return i
}
function utf8Write (buf, string, offset, length) {
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
}
function asciiWrite (buf, string, offset, length) {
return blitBuffer(asciiToBytes(string), buf, offset, length)
}
function latin1Write (buf, string, offset, length) {
return asciiWrite(buf, string, offset, length)
}
function base64Write (buf, string, offset, length) {
return blitBuffer(base64ToBytes(string), buf, offset, length)
}
function ucs2Write (buf, string, offset, length) {
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
}
Buffer.prototype.write = function write (string, offset, length, encoding) {
// Buffer#write(string)
if (offset === undefined) {
encoding = 'utf8'
length = this.length
offset = 0
// Buffer#write(string, encoding)
} else if (length === undefined && typeof offset === 'string') {
encoding = offset
length = this.length
offset = 0
// Buffer#write(string, offset[, length][, encoding])
} else if (isFinite(offset)) {
offset = offset >>> 0
if (isFinite(length)) {
length = length >>> 0
if (encoding === undefined) encoding = 'utf8'
} else {
encoding = length
length = undefined
}
} else {
throw new Error(
'Buffer.write(string, encoding, offset[, length]) is no longer supported'
)
}
var remaining = this.length - offset
if (length === undefined || length > remaining) length = remaining
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
throw new RangeError('Attempt to write outside buffer bounds')
}
if (!encoding) encoding = 'utf8'
var loweredCase = false
for (;;) {
switch (encoding) {
case 'hex':
return hexWrite(this, string, offset, length)
case 'utf8':
case 'utf-8':
return utf8Write(this, string, offset, length)
case 'ascii':
return asciiWrite(this, string, offset, length)
case 'latin1':
case 'binary':
return latin1Write(this, string, offset, length)
case 'base64':
// Warning: maxLength not taken into account in base64Write
return base64Write(this, string, offset, length)
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return ucs2Write(this, string, offset, length)
default:
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
encoding = ('' + encoding).toLowerCase()
loweredCase = true
}
}
}
Buffer.prototype.toJSON = function toJSON () {
return {
type: 'Buffer',
data: Array.prototype.slice.call(this._arr || this, 0)
}
}
function base64Slice (buf, start, end) {
if (start === 0 && end === buf.length) {
return base64.fromByteArray(buf)
} else {
return base64.fromByteArray(buf.slice(start, end))
}
}
function utf8Slice (buf, start, end) {
end = Math.min(buf.length, end)
var res = []
var i = start
while (i < end) {
var firstByte = buf[i]
var codePoint = null
var bytesPerSequence = (firstByte > 0xEF) ? 4
: (firstByte > 0xDF) ? 3
: (firstByte > 0xBF) ? 2
: 1
if (i + bytesPerSequence <= end) {
var secondByte, thirdByte, fourthByte, tempCodePoint
switch (bytesPerSequence) {
case 1:
if (firstByte < 0x80) {
codePoint = firstByte
}
break
case 2:
secondByte = buf[i + 1]
if ((secondByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
if (tempCodePoint > 0x7F) {
codePoint = tempCodePoint
}
}
break
case 3:
secondByte = buf[i + 1]
thirdByte = buf[i + 2]
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
codePoint = tempCodePoint
}
}
break
case 4:
secondByte = buf[i + 1]
thirdByte = buf[i + 2]
fourthByte = buf[i + 3]
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
codePoint = tempCodePoint
}
}
}
}
if (codePoint === null) {
// we did not generate a valid codePoint so insert a
// replacement char (U+FFFD) and advance only 1 byte
codePoint = 0xFFFD
bytesPerSequence = 1
} else if (codePoint > 0xFFFF) {
// encode to utf16 (surrogate pair dance)
codePoint -= 0x10000
res.push(codePoint >>> 10 & 0x3FF | 0xD800)
codePoint = 0xDC00 | codePoint & 0x3FF
}
res.push(codePoint)
i += bytesPerSequence
}
return decodeCodePointsArray(res)
}
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
var MAX_ARGUMENTS_LENGTH = 0x1000
function decodeCodePointsArray (codePoints) {
var len = codePoints.length
if (len <= MAX_ARGUMENTS_LENGTH) {
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
}
// Decode in chunks to avoid "call stack size exceeded".
var res = ''
var i = 0
while (i < len) {
res += String.fromCharCode.apply(
String,
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
)
}
return res
}
function asciiSlice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i] & 0x7F)
}
return ret
}
function latin1Slice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i])
}
return ret
}
function hexSlice (buf, start, end) {
var len = buf.length
if (!start || start < 0) start = 0
if (!end || end < 0 || end > len) end = len
var out = ''
for (var i = start; i < end; ++i) {
out += toHex(buf[i])
}
return out
}
function utf16leSlice (buf, start, end) {
var bytes = buf.slice(start, end)
var res = ''
for (var i = 0; i < bytes.length; i += 2) {
res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
}
return res
}
Buffer.prototype.slice = function slice (start, end) {
var len = this.length
start = ~~start
end = end === undefined ? len : ~~end
if (start < 0) {
start += len
if (start < 0) start = 0
} else if (start > len) {
start = len
}
if (end < 0) {
end += len
if (end < 0) end = 0
} else if (end > len) {
end = len
}
if (end < start) end = start
var newBuf = this.subarray(start, end)
// Return an augmented `Uint8Array` instance
newBuf.__proto__ = Buffer.prototype
return newBuf
}
/*
* Need to make sure that buffer isn't trying to write out of bounds.
*/
function checkOffset (offset, ext, length) {
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
}
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var val = this[offset]
var mul = 1
var i = 0
while (++i < byteLength && (mul *= 0x100)) {
val += this[offset + i] * mul
}
return val
}
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
checkOffset(offset, byteLength, this.length)
}
var val = this[offset + --byteLength]
var mul = 1
while (byteLength > 0 && (mul *= 0x100)) {
val += this[offset + --byteLength] * mul
}
return val
}
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 1, this.length)
return this[offset]
}
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
return this[offset] | (this[offset + 1] << 8)
}
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
return (this[offset] << 8) | this[offset + 1]
}
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ((this[offset]) |
(this[offset + 1] << 8) |
(this[offset + 2] << 16)) +
(this[offset + 3] * 0x1000000)
}
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset] * 0x1000000) +
((this[offset + 1] << 16) |
(this[offset + 2] << 8) |
this[offset + 3])
}
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var val = this[offset]
var mul = 1
var i = 0
while (++i < byteLength && (mul *= 0x100)) {
val += this[offset + i] * mul
}
mul *= 0x80
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
return val
}
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var i = byteLength
var mul = 1
var val = this[offset + --i]
while (i > 0 && (mul *= 0x100)) {
val += this[offset + --i] * mul
}
mul *= 0x80
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
return val
}
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 1, this.length)
if (!(this[offset] & 0x80)) return (this[offset])
return ((0xff - this[offset] + 1) * -1)
}
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
var val = this[offset] | (this[offset + 1] << 8)
return (val & 0x8000) ? val | 0xFFFF0000 : val
}
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
var val = this[offset + 1] | (this[offset] << 8)
return (val & 0x8000) ? val | 0xFFFF0000 : val
}
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset]) |
(this[offset + 1] << 8) |
(this[offset + 2] << 16) |
(this[offset + 3] << 24)
}
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset] << 24) |
(this[offset + 1] << 16) |
(this[offset + 2] << 8) |
(this[offset + 3])
}
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ieee754.read(this, offset, true, 23, 4)
}
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ieee754.read(this, offset, false, 23, 4)
}
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 8, this.length)
return ieee754.read(this, offset, true, 52, 8)
}
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 8, this.length)
return ieee754.read(this, offset, false, 52, 8)
}
function checkInt (buf, value, offset, ext, max, min) {
if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
if (offset + ext > buf.length) throw new RangeError('Index out of range')
}
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
var maxBytes = Math.pow(2, 8 * byteLength) - 1
checkInt(this, value, offset, byteLength, maxBytes, 0)
}
var mul = 1
var i = 0
this[offset] = value & 0xFF
while (++i < byteLength && (mul *= 0x100)) {
this[offset + i] = (value / mul) & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
var maxBytes = Math.pow(2, 8 * byteLength) - 1
checkInt(this, value, offset, byteLength, maxBytes, 0)
}
var i = byteLength - 1
var mul = 1
this[offset + i] = value & 0xFF
while (--i >= 0 && (mul *= 0x100)) {
this[offset + i] = (value / mul) & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
this[offset] = (value & 0xff)
return offset + 1
}
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
return offset + 2
}
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
this[offset] = (value >>> 8)
this[offset + 1] = (value & 0xff)
return offset + 2
}
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
this[offset + 3] = (value >>> 24)
this[offset + 2] = (value >>> 16)
this[offset + 1] = (value >>> 8)
this[offset] = (value & 0xff)
return offset + 4
}
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
this[offset] = (value >>> 24)
this[offset + 1] = (value >>> 16)
this[offset + 2] = (value >>> 8)
this[offset + 3] = (value & 0xff)
return offset + 4
}
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
var limit = Math.pow(2, (8 * byteLength) - 1)
checkInt(this, value, offset, byteLength, limit - 1, -limit)
}
var i = 0
var mul = 1
var sub = 0
this[offset] = value & 0xFF
while (++i < byteLength && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
sub = 1
}
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
var limit = Math.pow(2, (8 * byteLength) - 1)
checkInt(this, value, offset, byteLength, limit - 1, -limit)
}
var i = byteLength - 1
var mul = 1
var sub = 0
this[offset + i] = value & 0xFF
while (--i >= 0 && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
sub = 1
}
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
if (value < 0) value = 0xff + value + 1
this[offset] = (value & 0xff)
return offset + 1
}
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
return offset + 2
}
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
this[offset] = (value >>> 8)
this[offset + 1] = (value & 0xff)
return offset + 2
}
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
this[offset + 2] = (value >>> 16)
this[offset + 3] = (value >>> 24)
return offset + 4
}
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
if (value < 0) value = 0xffffffff + value + 1
this[offset] = (value >>> 24)
this[offset + 1] = (value >>> 16)
this[offset + 2] = (value >>> 8)
this[offset + 3] = (value & 0xff)
return offset + 4
}
function checkIEEE754 (buf, value, offset, ext, max, min) {
if (offset + ext > buf.length) throw new RangeError('Index out of range')
if (offset < 0) throw new RangeError('Index out of range')
}
function writeFloat (buf, value, offset, littleEndian, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
}
ieee754.write(buf, value, offset, littleEndian, 23, 4)
return offset + 4
}
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
return writeFloat(this, value, offset, true, noAssert)
}
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
return writeFloat(this, value, offset, false, noAssert)
}
function writeDouble (buf, value, offset, littleEndian, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
}
ieee754.write(buf, value, offset, littleEndian, 52, 8)
return offset + 8
}
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
return writeDouble(this, value, offset, true, noAssert)
}
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
return writeDouble(this, value, offset, false, noAssert)
}
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
if (!start) start = 0
if (!end && end !== 0) end = this.length
if (targetStart >= target.length) targetStart = target.length
if (!targetStart) targetStart = 0
if (end > 0 && end < start) end = start
// Copy 0 bytes; we're done
if (end === start) return 0
if (target.length === 0 || this.length === 0) return 0
// Fatal error conditions
if (targetStart < 0) {
throw new RangeError('targetStart out of bounds')
}
if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
if (end < 0) throw new RangeError('sourceEnd out of bounds')
// Are we oob?
if (end > this.length) end = this.length
if (target.length - targetStart < end - start) {
end = target.length - targetStart + start
}
var len = end - start
var i
if (this === target && start < targetStart && targetStart < end) {
// descending copy from end
for (i = len - 1; i >= 0; --i) {
target[i + targetStart] = this[i + start]
}
} else if (len < 1000) {
// ascending copy from start
for (i = 0; i < len; ++i) {
target[i + targetStart] = this[i + start]
}
} else {
Uint8Array.prototype.set.call(
target,
this.subarray(start, start + len),
targetStart
)
}
return len
}
// Usage:
// buffer.fill(number[, offset[, end]])
// buffer.fill(buffer[, offset[, end]])
// buffer.fill(string[, offset[, end]][, encoding])
Buffer.prototype.fill = function fill (val, start, end, encoding) {
// Handle string cases:
if (typeof val === 'string') {
if (typeof start === 'string') {
encoding = start
start = 0
end = this.length
} else if (typeof end === 'string') {
encoding = end
end = this.length
}
if (val.length === 1) {
var code = val.charCodeAt(0)
if (code < 256) {
val = code
}
}
if (encoding !== undefined && typeof encoding !== 'string') {
throw new TypeError('encoding must be a string')
}
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
throw new TypeError('Unknown encoding: ' + encoding)
}
} else if (typeof val === 'number') {
val = val & 255
}
// Invalid ranges are not set to a default, so can range check early.
if (start < 0 || this.length < start || this.length < end) {
throw new RangeError('Out of range index')
}
if (end <= start) {
return this
}
start = start >>> 0
end = end === undefined ? this.length : end >>> 0
if (!val) val = 0
var i
if (typeof val === 'number') {
for (i = start; i < end; ++i) {
this[i] = val
}
} else {
var bytes = Buffer.isBuffer(val)
? val
: new Buffer(val, encoding)
var len = bytes.length
for (i = 0; i < end - start; ++i) {
this[i + start] = bytes[i % len]
}
}
return this
}
// HELPER FUNCTIONS
// ================
var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
function base64clean (str) {
// Node strips out invalid characters like \n and \t from the string, base64-js does not
str = str.trim().replace(INVALID_BASE64_RE, '')
// Node converts strings with length < 2 to ''
if (str.length < 2) return ''
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
while (str.length % 4 !== 0) {
str = str + '='
}
return str
}
function toHex (n) {
if (n < 16) return '0' + n.toString(16)
return n.toString(16)
}
function utf8ToBytes (string, units) {
units = units || Infinity
var codePoint
var length = string.length
var leadSurrogate = null
var bytes = []
for (var i = 0; i < length; ++i) {
codePoint = string.charCodeAt(i)
// is surrogate component
if (codePoint > 0xD7FF && codePoint < 0xE000) {
// last char was a lead
if (!leadSurrogate) {
// no lead yet
if (codePoint > 0xDBFF) {
// unexpected trail
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
continue
} else if (i + 1 === length) {
// unpaired lead
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
continue
}
// valid lead
leadSurrogate = codePoint
continue
}
// 2 leads in a row
if (codePoint < 0xDC00) {
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
leadSurrogate = codePoint
continue
}
// valid surrogate pair
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
} else if (leadSurrogate) {
// valid bmp char, but last char was a lead
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
}
leadSurrogate = null
// encode utf8
if (codePoint < 0x80) {
if ((units -= 1) < 0) break
bytes.push(codePoint)
} else if (codePoint < 0x800) {
if ((units -= 2) < 0) break
bytes.push(
codePoint >> 0x6 | 0xC0,
codePoint & 0x3F | 0x80
)
} else if (codePoint < 0x10000) {
if ((units -= 3) < 0) break
bytes.push(
codePoint >> 0xC | 0xE0,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
)
} else if (codePoint < 0x110000) {
if ((units -= 4) < 0) break
bytes.push(
codePoint >> 0x12 | 0xF0,
codePoint >> 0xC & 0x3F | 0x80,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
)
} else {
throw new Error('Invalid code point')
}
}
return bytes
}
function asciiToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; ++i) {
// Node's code seems to be doing this and not & 0x7F..
byteArray.push(str.charCodeAt(i) & 0xFF)
}
return byteArray
}
function utf16leToBytes (str, units) {
var c, hi, lo
var byteArray = []
for (var i = 0; i < str.length; ++i) {
if ((units -= 2) < 0) break
c = str.charCodeAt(i)
hi = c >> 8
lo = c % 256
byteArray.push(lo)
byteArray.push(hi)
}
return byteArray
}
function base64ToBytes (str) {
return base64.toByteArray(base64clean(str))
}
function blitBuffer (src, dst, offset, length) {
for (var i = 0; i < length; ++i) {
if ((i + offset >= dst.length) || (i >= src.length)) break
dst[i + offset] = src[i]
}
return i
}
// ArrayBuffers from another context (i.e. an iframe) do not pass the `instanceof` check
// but they should be treated as valid. See: https://github.com/feross/buffer/issues/166
function isArrayBuffer (obj) {
return obj instanceof ArrayBuffer ||
(obj != null && obj.constructor != null && obj.constructor.name === 'ArrayBuffer' &&
typeof obj.byteLength === 'number')
}
// Node 0.10 supports `ArrayBuffer` but lacks `ArrayBuffer.isView`
function isArrayBufferView (obj) {
return (typeof ArrayBuffer.isView === 'function') && ArrayBuffer.isView(obj)
}
function numberIsNaN (obj) {
return obj !== obj // eslint-disable-line no-self-compare
}
},{"base64-js":14,"ieee754":15}],14:[function(require,module,exports){
'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, 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; i < l; i += 4) {
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('')
}
},{}],15:[function(require,module,exports){
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
var e, m
var eLen = nBytes * 8 - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var nBits = -7
var i = isLE ? (nBytes - 1) : 0
var d = isLE ? -1 : 1
var s = buffer[offset + i]
i += d
e = s & ((1 << (-nBits)) - 1)
s >>= (-nBits)
nBits += eLen
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
m = e & ((1 << (-nBits)) - 1)
e >>= (-nBits)
nBits += mLen
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
if (e === 0) {
e = 1 - eBias
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity)
} else {
m = m + Math.pow(2, mLen)
e = e - eBias
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
}
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
var e, m, c
var eLen = nBytes * 8 - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
var i = isLE ? 0 : (nBytes - 1)
var d = isLE ? 1 : -1
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
value = Math.abs(value)
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0
e = eMax
} else {
e = Math.floor(Math.log(value) / Math.LN2)
if (value * (c = Math.pow(2, -e)) < 1) {
e--
c *= 2
}
if (e + eBias >= 1) {
value += rt / c
} else {
value += rt * Math.pow(2, 1 - eBias)
}
if (value * c >= 2) {
e++
c /= 2
}
if (e + eBias >= eMax) {
m = 0
e = eMax
} else if (e + eBias >= 1) {
m = (value * c - 1) * Math.pow(2, mLen)
e = e + eBias
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
e = 0
}
}
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
e = (e << mLen) | m
eLen += mLen
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
buffer[offset + i - d] |= s * 128
}
},{}],16:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],17:[function(require,module,exports){
var http = require('http')
var url = require('url')
var https = module.exports
for (var key in http) {
if (http.hasOwnProperty(key)) https[key] = http[key]
}
https.request = function (params, cb) {
params = validateParams(params)
return http.request.call(this, params, cb)
}
https.get = function (params, cb) {
params = validateParams(params)
return http.get.call(this, params, cb)
}
function validateParams (params) {
if (typeof params === 'string') {
params = url.parse(params)
}
if (!params.protocol) {
params.protocol = 'https:'
}
if (params.protocol !== 'https:') {
throw new Error('Protocol "' + params.protocol + '" not supported. Expected "https:"')
}
return params
}
},{"http":44,"url":52}],18:[function(require,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],19:[function(require,module,exports){
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
},{}],20:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
},{}],21:[function(require,module,exports){
(function (global){
/*! https://mths.be/punycode v1.4.1 by @mathias */
;(function(root) {
/** Detect free variables */
var freeExports = typeof exports == 'object' && exports &&
!exports.nodeType && exports;
var freeModule = typeof module == 'object' && module &&
!module.nodeType && module;
var freeGlobal = typeof global == 'object' && global;
if (
freeGlobal.global === freeGlobal ||
freeGlobal.window === freeGlobal ||
freeGlobal.self === freeGlobal
) {
root = freeGlobal;
}
/**
* The `punycode` object.
* @name punycode
* @type Object
*/
var punycode,
/** Highest positive signed 32-bit float value */
maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
/** Bootstring parameters */
base = 36,
tMin = 1,
tMax = 26,
skew = 38,
damp = 700,
initialBias = 72,
initialN = 128, // 0x80
delimiter = '-', // '\x2D'
/** Regular expressions */
regexPunycode = /^xn--/,
regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
/** Error messages */
errors = {
'overflow': 'Overflow: input needs wider integers to process',
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
'invalid-input': 'Invalid input'
},
/** Convenience shortcuts */
baseMinusTMin = base - tMin,
floor = Math.floor,
stringFromCharCode = String.fromCharCode,
/** Temporary variable */
key;
/*--------------------------------------------------------------------------*/
/**
* A generic error utility function.
* @private
* @param {String} type The error type.
* @returns {Error} Throws a `RangeError` with the applicable error message.
*/
function error(type) {
throw new RangeError(errors[type]);
}
/**
* A generic `Array#map` utility function.
* @private
* @param {Array} array The array to iterate over.
* @param {Function} callback The function that gets called for every array
* item.
* @returns {Array} A new array of values returned by the callback function.
*/
function map(array, fn) {
var length = array.length;
var result = [];
while (length--) {
result[length] = fn(array[length]);
}
return result;
}
/**
* A simple `Array#map`-like wrapper to work with domain name strings or email
* addresses.
* @private
* @param {String} domain The domain name or email address.
* @param {Function} callback The function that gets called for every
* character.
* @returns {Array} A new string of characters returned by the callback
* function.
*/
function mapDomain(string, fn) {
var parts = string.split('@');
var result = '';
if (parts.length > 1) {
// In email addresses, only the domain name should be punycoded. Leave
// the local part (i.e. everything up to `@`) intact.
result = parts[0] + '@';
string = parts[1];
}
// Avoid `split(regex)` for IE8 compatibility. See #17.
string = string.replace(regexSeparators, '\x2E');
var labels = string.split('.');
var encoded = map(labels, fn).join('.');
return result + encoded;
}
/**
* Creates an array containing the numeric code points of each Unicode
* character in the string. While JavaScript uses UCS-2 internally,
* this function will convert a pair of surrogate halves (each of which
* UCS-2 exposes as separate characters) into a single code point,
* matching UTF-16.
* @see `punycode.ucs2.encode`
* @see <https://mathiasbynens.be/notes/javascript-encoding>
* @memberOf punycode.ucs2
* @name decode
* @param {String} string The Unicode input string (UCS-2).
* @returns {Array} The new array of code points.
*/
function ucs2decode(string) {
var output = [],
counter = 0,
length = string.length,
value,
extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
/**
* Creates a string based on an array of numeric code points.
* @see `punycode.ucs2.decode`
* @memberOf punycode.ucs2
* @name encode
* @param {Array} codePoints The array of numeric code points.
* @returns {String} The new Unicode string (UCS-2).
*/
function ucs2encode(array) {
return map(array, function(value) {
var output = '';
if (value > 0xFFFF) {
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
return output;
}).join('');
}
/**
* Converts a basic code point into a digit/integer.
* @see `digitToBasic()`
* @private
* @param {Number} codePoint The basic numeric code point value.
* @returns {Number} The numeric value of a basic code point (for use in
* representing integers) in the range `0` to `base - 1`, or `base` if
* the code point does not represent a value.
*/
function basicToDigit(codePoint) {
if (codePoint - 48 < 10) {
return codePoint - 22;
}
if (codePoint - 65 < 26) {
return codePoint - 65;
}
if (codePoint - 97 < 26) {
return codePoint - 97;
}
return base;
}
/**
* Converts a digit/integer into a basic code point.
* @see `basicToDigit()`
* @private
* @param {Number} digit The numeric value of a basic code point.
* @returns {Number} The basic code point whose value (when used for
* representing integers) is `digit`, which needs to be in the range
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
* used; else, the lowercase form is used. The behavior is undefined
* if `flag` is non-zero and `digit` has no uppercase form.
*/
function digitToBasic(digit, flag) {
// 0..25 map to ASCII a..z or A..Z
// 26..35 map to ASCII 0..9
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
}
/**
* Bias adaptation function as per section 3.4 of RFC 3492.
* https://tools.ietf.org/html/rfc3492#section-3.4
* @private
*/
function adapt(delta, numPoints, firstTime) {
var k = 0;
delta = firstTime ? floor(delta / damp) : delta >> 1;
delta += floor(delta / numPoints);
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
delta = floor(delta / baseMinusTMin);
}
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
}
/**
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
* symbols.
* @memberOf punycode
* @param {String} input The Punycode string of ASCII-only symbols.
* @returns {String} The resulting string of Unicode symbols.
*/
function decode(input) {
// Don't use UCS-2
var output = [],
inputLength = input.length,
out,
i = 0,
n = initialN,
bias = initialBias,
basic,
j,
index,
oldi,
w,
k,
digit,
t,
/** Cached calculation results */
baseMinusT;
// Handle the basic code points: let `basic` be the number of input code
// points before the last delimiter, or `0` if there is none, then copy
// the first basic code points to the output.
basic = input.lastIndexOf(delimiter);
if (basic < 0) {
basic = 0;
}
for (j = 0; j < basic; ++j) {
// if it's not a basic code point
if (input.charCodeAt(j) >= 0x80) {
error('not-basic');
}
output.push(input.charCodeAt(j));
}
// Main decoding loop: start just after the last delimiter if any basic code
// points were copied; start at the beginning otherwise.
for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
// `index` is the index of the next character to be consumed.
// Decode a generalized variable-length integer into `delta`,
// which gets added to `i`. The overflow checking is easier
// if we increase `i` as we go, then subtract off its starting
// value at the end to obtain `delta`.
for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
if (index >= inputLength) {
error('invalid-input');
}
digit = basicToDigit(input.charCodeAt(index++));
if (digit >= base || digit > floor((maxInt - i) / w)) {
error('overflow');
}
i += digit * w;
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
if (digit < t) {
break;
}
baseMinusT = base - t;
if (w > floor(maxInt / baseMinusT)) {
error('overflow');
}
w *= baseMinusT;
}
out = output.length + 1;
bias = adapt(i - oldi, out, oldi == 0);
// `i` was supposed to wrap around from `out` to `0`,
// incrementing `n` each time, so we'll fix that now:
if (floor(i / out) > maxInt - n) {
error('overflow');
}
n += floor(i / out);
i %= out;
// Insert `n` at position `i` of the output
output.splice(i++, 0, n);
}
return ucs2encode(output);
}
/**
* Converts a string of Unicode symbols (e.g. a domain name label) to a
* Punycode string of ASCII-only symbols.
* @memberOf punycode
* @param {String} input The string of Unicode symbols.
* @returns {String} The resulting Punycode string of ASCII-only symbols.
*/
function encode(input) {
var n,
delta,
handledCPCount,
basicLength,
bias,
j,
m,
q,
k,
t,
currentValue,
output = [],
/** `inputLength` will hold the number of code points in `input`. */
inputLength,
/** Cached calculation results */
handledCPCountPlusOne,
baseMinusT,
qMinusT;
// Convert the input in UCS-2 to Unicode
input = ucs2decode(input);
// Cache the length
inputLength = input.length;
// Initialize the state
n = initialN;
delta = 0;
bias = initialBias;
// Handle the basic code points
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < 0x80) {
output.push(stringFromCharCode(currentValue));
}
}
handledCPCount = basicLength = output.length;
// `handledCPCount` is the number of code points that have been handled;
// `basicLength` is the number of basic code points.
// Finish the basic string - if it is not empty - with a delimiter
if (basicLength) {
output.push(delimiter);
}
// Main encoding loop:
while (handledCPCount < inputLength) {
// All non-basic code points < n have been handled already. Find the next
// larger one:
for (m = maxInt, j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue >= n && currentValue < m) {
m = currentValue;
}
}
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
// but guard against overflow
handledCPCountPlusOne = handledCPCount + 1;
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
error('overflow');
}
delta += (m - n) * handledCPCountPlusOne;
n = m;
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < n && ++delta > maxInt) {
error('overflow');
}
if (currentValue == n) {
// Represent delta as a generalized variable-length integer
for (q = delta, k = base; /* no condition */; k += base) {
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
if (q < t) {
break;
}
qMinusT = q - t;
baseMinusT = base - t;
output.push(
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
);
q = floor(qMinusT / baseMinusT);
}
output.push(stringFromCharCode(digitToBasic(q, 0)));
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
delta = 0;
++handledCPCount;
}
}
++delta;
++n;
}
return output.join('');
}
/**
* Converts a Punycode string representing a domain name or an email address
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
* it doesn't matter if you call it on a string that has already been
* converted to Unicode.
* @memberOf punycode
* @param {String} input The Punycoded domain name or email address to
* convert to Unicode.
* @returns {String} The Unicode representation of the given Punycode
* string.
*/
function toUnicode(input) {
return mapDomain(input, function(string) {
return regexPunycode.test(string)
? decode(string.slice(4).toLowerCase())
: string;
});
}
/**
* Converts a Unicode string representing a domain name or an email address to
* Punycode. Only the non-ASCII parts of the domain name will be converted,
* i.e. it doesn't matter if you call it with a domain that's already in
* ASCII.
* @memberOf punycode
* @param {String} input The domain name or email address to convert, as a
* Unicode string.
* @returns {String} The Punycode representation of the given domain name or
* email address.
*/
function toASCII(input) {
return mapDomain(input, function(string) {
return regexNonASCII.test(string)
? 'xn--' + encode(string)
: string;
});
}
/*--------------------------------------------------------------------------*/
/** Define the public API */
punycode = {
/**
* A string representing the current Punycode.js version number.
* @memberOf punycode
* @type String
*/
'version': '1.4.1',
/**
* An object of methods to convert from JavaScript's internal character
* representation (UCS-2) to Unicode code points, and back.
* @see <https://mathiasbynens.be/notes/javascript-encoding>
* @memberOf punycode
* @type Object
*/
'ucs2': {
'decode': ucs2decode,
'encode': ucs2encode
},
'decode': decode,
'encode': encode,
'toASCII': toASCII,
'toUnicode': toUnicode
};
/** Expose `punycode` */
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
define('punycode', function() {
return punycode;
});
} else if (freeExports && freeModule) {
if (module.exports == freeExports) {
// in Node.js, io.js, or RingoJS v0.8.0+
freeModule.exports = punycode;
} else {
// in Narwhal or RingoJS v0.7.0-
for (key in punycode) {
punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
}
}
} else {
// in Rhino or a web browser
root.punycode = punycode;
}
}(this));
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],22:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
module.exports = function(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
var regexp = /\+/g;
qs = qs.split(sep);
var maxKeys = 1000;
if (options && typeof options.maxKeys === 'number') {
maxKeys = options.maxKeys;
}
var len = qs.length;
// maxKeys <= 0 means that we should not limit keys count
if (maxKeys > 0 && len > maxKeys) {
len = maxKeys;
}
for (var i = 0; i < len; ++i) {
var x = qs[i].replace(regexp, '%20'),
idx = x.indexOf(eq),
kstr, vstr, k, v;
if (idx >= 0) {
kstr = x.substr(0, idx);
vstr = x.substr(idx + 1);
} else {
kstr = x;
vstr = '';
}
k = decodeURIComponent(kstr);
v = decodeURIComponent(vstr);
if (!hasOwnProperty(obj, k)) {
obj[k] = v;
} else if (isArray(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
return obj;
};
var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
},{}],23:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
var stringifyPrimitive = function(v) {
switch (typeof v) {
case 'string':
return v;
case 'boolean':
return v ? 'true' : 'false';
case 'number':
return isFinite(v) ? v : '';
default:
return '';
}
};
module.exports = function(obj, sep, eq, name) {
sep = sep || '&';
eq = eq || '=';
if (obj === null) {
obj = undefined;
}
if (typeof obj === 'object') {
return map(objectKeys(obj), function(k) {
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
if (isArray(obj[k])) {
return map(obj[k], function(v) {
return ks + encodeURIComponent(stringifyPrimitive(v));
}).join(sep);
} else {
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
}
}).join(sep);
}
if (!name) return '';
return encodeURIComponent(stringifyPrimitive(name)) + eq +
encodeURIComponent(stringifyPrimitive(obj));
};
var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
function map (xs, f) {
if (xs.map) return xs.map(f);
var res = [];
for (var i = 0; i < xs.length; i++) {
res.push(f(xs[i], i));
}
return res;
}
var objectKeys = Object.keys || function (obj) {
var res = [];
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
}
return res;
};
},{}],24:[function(require,module,exports){
'use strict';
exports.decode = exports.parse = require('./decode');
exports.encode = exports.stringify = require('./encode');
},{"./decode":22,"./encode":23}],25:[function(require,module,exports){
module.exports = require('./lib/_stream_duplex.js');
},{"./lib/_stream_duplex.js":26}],26:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a duplex stream is just a stream that is both readable and writable.
// Since JS doesn't have multiple prototypal inheritance, this class
// prototypally inherits from Readable, and then parasitically from
// Writable.
'use strict';
/*<replacement>*/
var processNextTick = require('process-nextick-args');
/*</replacement>*/
/*<replacement>*/
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
keys.push(key);
}return keys;
};
/*</replacement>*/
module.exports = Duplex;
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
var Readable = require('./_stream_readable');
var Writable = require('./_stream_writable');
util.inherits(Duplex, Readable);
var keys = objectKeys(Writable.prototype);
for (var v = 0; v < keys.length; v++) {
var method = keys[v];
if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
}
function Duplex(options) {
if (!(this instanceof Duplex)) return new Duplex(options);
Readable.call(this, options);
Writable.call(this, options);
if (options && options.readable === false) this.readable = false;
if (options && options.writable === false) this.writable = false;
this.allowHalfOpen = true;
if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;
this.once('end', onend);
}
// the no-half-open enforcer
function onend() {
// if we allow half-open state, or if the writable side ended,
// then we're ok.
if (this.allowHalfOpen || this._writableState.ended) return;
// no more data can be written.
// But allow more writes to happen in this tick.
processNextTick(onEndNT, this);
}
function onEndNT(self) {
self.end();
}
Object.defineProperty(Duplex.prototype, 'destroyed', {
get: function () {
if (this._readableState === undefined || this._writableState === undefined) {
return false;
}
return this._readableState.destroyed && this._writableState.destroyed;
},
set: function (value) {
// we ignore the value if the stream
// has not been initialized yet
if (this._readableState === undefined || this._writableState === undefined) {
return;
}
// backward compatibility, the user is explicitly
// managing destroyed
this._readableState.destroyed = value;
this._writableState.destroyed = value;
}
});
Duplex.prototype._destroy = function (err, cb) {
this.push(null);
this.end();
processNextTick(cb, err);
};
function forEach(xs, f) {
for (var i = 0, l = xs.length; i < l; i++) {
f(xs[i], i);
}
}
},{"./_stream_readable":28,"./_stream_writable":30,"core-util-is":34,"inherits":18,"process-nextick-args":36}],27:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a passthrough stream.
// basically just the most minimal sort of Transform stream.
// Every written chunk gets output as-is.
'use strict';
module.exports = PassThrough;
var Transform = require('./_stream_transform');
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
util.inherits(PassThrough, Transform);
function PassThrough(options) {
if (!(this instanceof PassThrough)) return new PassThrough(options);
Transform.call(this, options);
}
PassThrough.prototype._transform = function (chunk, encoding, cb) {
cb(null, chunk);
};
},{"./_stream_transform":29,"core-util-is":34,"inherits":18}],28:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
/*<replacement>*/
var processNextTick = require('process-nextick-args');
/*</replacement>*/
module.exports = Readable;
/*<replacement>*/
var isArray = require('isarray');
/*</replacement>*/
/*<replacement>*/
var Duplex;
/*</replacement>*/
Readable.ReadableState = ReadableState;
/*<replacement>*/
var EE = require('events').EventEmitter;
var EElistenerCount = function (emitter, type) {
return emitter.listeners(type).length;
};
/*</replacement>*/
/*<replacement>*/
var Stream = require('./internal/streams/stream');
/*</replacement>*/
// TODO(bmeurer): Change this back to const once hole checks are
// properly optimized away early in Ignition+TurboFan.
/*<replacement>*/
var Buffer = require('safe-buffer').Buffer;
var OurUint8Array = global.Uint8Array || function () {};
function _uint8ArrayToBuffer(chunk) {
return Buffer.from(chunk);
}
function _isUint8Array(obj) {
return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
}
/*</replacement>*/
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
/*<replacement>*/
var debugUtil = require('util');
var debug = void 0;
if (debugUtil && debugUtil.debuglog) {
debug = debugUtil.debuglog('stream');
} else {
debug = function () {};
}
/*</replacement>*/
var BufferList = require('./internal/streams/BufferList');
var destroyImpl = require('./internal/streams/destroy');
var StringDecoder;
util.inherits(Readable, Stream);
var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];
function prependListener(emitter, event, fn) {
// Sadly this is not cacheable as some libraries bundle their own
// event emitter implementation with them.
if (typeof emitter.prependListener === 'function') {
return emitter.prependListener(event, fn);
} else {
// This is a hack to make sure that our error handler is attached before any
// userland ones. NEVER DO THIS. This is here only because this code needs
// to continue to work with older versions of Node.js that do not include
// the prependListener() method. The goal is to eventually remove this hack.
if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];
}
}
function ReadableState(options, stream) {
Duplex = Duplex || require('./_stream_duplex');
options = options || {};
// object stream flag. Used to make read(n) ignore n and to
// make all the buffer merging and length checks go away
this.objectMode = !!options.objectMode;
if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode;
// the point at which it stops calling _read() to fill the buffer
// Note: 0 is a valid value, means "don't call _read preemptively ever"
var hwm = options.highWaterMark;
var defaultHwm = this.objectMode ? 16 : 16 * 1024;
this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
// cast to ints.
this.highWaterMark = Math.floor(this.highWaterMark);
// A linked list is used to store data chunks instead of an array because the
// linked list can remove elements from the beginning faster than
// array.shift()
this.buffer = new BufferList();
this.length = 0;
this.pipes = null;
this.pipesCount = 0;
this.flowing = null;
this.ended = false;
this.endEmitted = false;
this.reading = false;
// a flag to be able to tell if the event 'readable'/'data' is emitted
// immediately, or on a later tick. We set this to true at first, because
// any actions that shouldn't happen until "later" should generally also
// not happen before the first read call.
this.sync = true;
// whenever we return null, then we set a flag to say
// that we're awaiting a 'readable' event emission.
this.needReadable = false;
this.emittedReadable = false;
this.readableListening = false;
this.resumeScheduled = false;
// has it been destroyed
this.destroyed = false;
// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
this.defaultEncoding = options.defaultEncoding || 'utf8';
// the number of writers that are awaiting a drain event in .pipe()s
this.awaitDrain = 0;
// if true, a maybeReadMore has been scheduled
this.readingMore = false;
this.decoder = null;
this.encoding = null;
if (options.encoding) {
if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
this.decoder = new StringDecoder(options.encoding);
this.encoding = options.encoding;
}
}
function Readable(options) {
Duplex = Duplex || require('./_stream_duplex');
if (!(this instanceof Readable)) return new Readable(options);
this._readableState = new ReadableState(options, this);
// legacy
this.readable = true;
if (options) {
if (typeof options.read === 'function') this._read = options.read;
if (typeof options.destroy === 'function') this._destroy = options.destroy;
}
Stream.call(this);
}
Object.defineProperty(Readable.prototype, 'destroyed', {
get: function () {
if (this._readableState === undefined) {
return false;
}
return this._readableState.destroyed;
},
set: function (value) {
// we ignore the value if the stream
// has not been initialized yet
if (!this._readableState) {
return;
}
// backward compatibility, the user is explicitly
// managing destroyed
this._readableState.destroyed = value;
}
});
Readable.prototype.destroy = destroyImpl.destroy;
Readable.prototype._undestroy = destroyImpl.undestroy;
Readable.prototype._destroy = function (err, cb) {
this.push(null);
cb(err);
};
// Manually shove something into the read() buffer.
// This returns true if the highWaterMark has not been hit yet,
// similar to how Writable.write() returns true if you should
// write() some more.
Readable.prototype.push = function (chunk, encoding) {
var state = this._readableState;
var skipChunkCheck;
if (!state.objectMode) {
if (typeof chunk === 'string') {
encoding = encoding || state.defaultEncoding;
if (encoding !== state.encoding) {
chunk = Buffer.from(chunk, encoding);
encoding = '';
}
skipChunkCheck = true;
}
} else {
skipChunkCheck = true;
}
return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);
};
// Unshift should *always* be something directly out of read()
Readable.prototype.unshift = function (chunk) {
return readableAddChunk(this, chunk, null, true, false);
};
function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {
var state = stream._readableState;
if (chunk === null) {
state.reading = false;
onEofChunk(stream, state);
} else {
var er;
if (!skipChunkCheck) er = chunkInvalid(state, chunk);
if (er) {
stream.emit('error', er);
} else if (state.objectMode || chunk && chunk.length > 0) {
if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {
chunk = _uint8ArrayToBuffer(chunk);
}
if (addToFront) {
if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);
} else if (state.ended) {
stream.emit('error', new Error('stream.push() after EOF'));
} else {
state.reading = false;
if (state.decoder && !encoding) {
chunk = state.decoder.write(chunk);
if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);
} else {
addChunk(stream, state, chunk, false);
}
}
} else if (!addToFront) {
state.reading = false;
}
}
return needMoreData(state);
}
function addChunk(stream, state, chunk, addToFront) {
if (state.flowing && state.length === 0 && !state.sync) {
stream.emit('data', chunk);
stream.read(0);
} else {
// update the buffer info.
state.length += state.objectMode ? 1 : chunk.length;
if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);
if (state.needReadable) emitReadable(stream);
}
maybeReadMore(stream, state);
}
function chunkInvalid(state, chunk) {
var er;
if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
er = new TypeError('Invalid non-string/buffer chunk');
}
return er;
}
// if it's past the high water mark, we can push in some more.
// Also, if we have no data yet, we can stand some
// more bytes. This is to work around cases where hwm=0,
// such as the repl. Also, if the push() triggered a
// readable event, and the user called read(largeNumber) such that
// needReadable was set, then we ought to push more, so that another
// 'readable' event will be triggered.
function needMoreData(state) {
return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);
}
Readable.prototype.isPaused = function () {
return this._readableState.flowing === false;
};
// backwards compatibility.
Readable.prototype.setEncoding = function (enc) {
if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
this._readableState.decoder = new StringDecoder(enc);
this._readableState.encoding = enc;
return this;
};
// Don't raise the hwm > 8MB
var MAX_HWM = 0x800000;
function computeNewHighWaterMark(n) {
if (n >= MAX_HWM) {
n = MAX_HWM;
} else {
// Get the next highest power of 2 to prevent increasing hwm excessively in
// tiny amounts
n--;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
n++;
}
return n;
}
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function howMuchToRead(n, state) {
if (n <= 0 || state.length === 0 && state.ended) return 0;
if (state.objectMode) return 1;
if (n !== n) {
// Only flow one buffer at a time
if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;
}
// If we're asking for more than the current hwm, then raise the hwm.
if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
if (n <= state.length) return n;
// Don't have enough
if (!state.ended) {
state.needReadable = true;
return 0;
}
return state.length;
}
// you can override either this method, or the async _read(n) below.
Readable.prototype.read = function (n) {
debug('read', n);
n = parseInt(n, 10);
var state = this._readableState;
var nOrig = n;
if (n !== 0) state.emittedReadable = false;
// if we're doing read(0) to trigger a readable event, but we
// already have a bunch of data in the buffer, then just trigger
// the 'readable' event and move on.
if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {
debug('read: emitReadable', state.length, state.ended);
if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);
return null;
}
n = howMuchToRead(n, state);
// if we've ended, and we're now clear, then finish it up.
if (n === 0 && state.ended) {
if (state.length === 0) endReadable(this);
return null;
}
// All the actual chunk generation logic needs to be
// *below* the call to _read. The reason is that in certain
// synthetic stream cases, such as passthrough streams, _read
// may be a completely synchronous operation which may change
// the state of the read buffer, providing enough data when
// before there was *not* enough.
//
// So, the steps are:
// 1. Figure out what the state of things will be after we do
// a read from the buffer.
//
// 2. If that resulting state will trigger a _read, then call _read.
// Note that this may be asynchronous, or synchronous. Yes, it is
// deeply ugly to write APIs this way, but that still doesn't mean
// that the Readable class should behave improperly, as streams are
// designed to be sync/async agnostic.
// Take note if the _read call is sync or async (ie, if the read call
// has returned yet), so that we know whether or not it's safe to emit
// 'readable' etc.
//
// 3. Actually pull the requested chunks out of the buffer and return.
// if we need a readable event, then we need to do some reading.
var doRead = state.needReadable;
debug('need readable', doRead);
// if we currently have less than the highWaterMark, then also read some
if (state.length === 0 || state.length - n < state.highWaterMark) {
doRead = true;
debug('length less than watermark', doRead);
}
// however, if we've ended, then there's no point, and if we're already
// reading, then it's unnecessary.
if (state.ended || state.reading) {
doRead = false;
debug('reading or ended', doRead);
} else if (doRead) {
debug('do read');
state.reading = true;
state.sync = true;
// if the length is currently zero, then we *need* a readable event.
if (state.length === 0) state.needReadable = true;
// call internal read method
this._read(state.highWaterMark);
state.sync = false;
// If _read pushed data synchronously, then `reading` will be false,
// and we need to re-evaluate how much data we can return to the user.
if (!state.reading) n = howMuchToRead(nOrig, state);
}
var ret;
if (n > 0) ret = fromList(n, state);else ret = null;
if (ret === null) {
state.needReadable = true;
n = 0;
} else {
state.length -= n;
}
if (state.length === 0) {
// If we have nothing in the buffer, then we want to know
// as soon as we *do* get something into the buffer.
if (!state.ended) state.needReadable = true;
// If we tried to read() past the EOF, then emit end on the next tick.
if (nOrig !== n && state.ended) endReadable(this);
}
if (ret !== null) this.emit('data', ret);
return ret;
};
function onEofChunk(stream, state) {
if (state.ended) return;
if (state.decoder) {
var chunk = state.decoder.end();
if (chunk && chunk.length) {
state.buffer.push(chunk);
state.length += state.objectMode ? 1 : chunk.length;
}
}
state.ended = true;
// emit 'readable' now to make sure it gets picked up.
emitReadable(stream);
}
// Don't emit readable right away in sync mode, because this can trigger
// another read() call => stack overflow. This way, it might trigger
// a nextTick recursion warning, but that's not so bad.
function emitReadable(stream) {
var state = stream._readableState;
state.needReadable = false;
if (!state.emittedReadable) {
debug('emitReadable', state.flowing);
state.emittedReadable = true;
if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream);
}
}
function emitReadable_(stream) {
debug('emit readable');
stream.emit('readable');
flow(stream);
}
// at this point, the user has presumably seen the 'readable' event,
// and called read() to consume some data. that may have triggered
// in turn another _read(n) call, in which case reading = true if
// it's in progress.
// However, if we're not ended, or reading, and the length < hwm,
// then go ahead and try to read some more preemptively.
function maybeReadMore(stream, state) {
if (!state.readingMore) {
state.readingMore = true;
processNextTick(maybeReadMore_, stream, state);
}
}
function maybeReadMore_(stream, state) {
var len = state.length;
while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {
debug('maybeReadMore read 0');
stream.read(0);
if (len === state.length)
// didn't get any data, stop spinning.
break;else len = state.length;
}
state.readingMore = false;
}
// abstract method. to be overridden in specific implementation classes.
// call cb(er, data) where data is <= n in length.
// for virtual (non-string, non-buffer) streams, "length" is somewhat
// arbitrary, and perhaps not very meaningful.
Readable.prototype._read = function (n) {
this.emit('error', new Error('_read() is not implemented'));
};
Readable.prototype.pipe = function (dest, pipeOpts) {
var src = this;
var state = this._readableState;
switch (state.pipesCount) {
case 0:
state.pipes = dest;
break;
case 1:
state.pipes = [state.pipes, dest];
break;
default:
state.pipes.push(dest);
break;
}
state.pipesCount += 1;
debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;
var endFn = doEnd ? onend : unpipe;
if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn);
dest.on('unpipe', onunpipe);
function onunpipe(readable, unpipeInfo) {
debug('onunpipe');
if (readable === src) {
if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
unpipeInfo.hasUnpiped = true;
cleanup();
}
}
}
function onend() {
debug('onend');
dest.end();
}
// when the dest drains, it reduces the awaitDrain counter
// on the source. This would be more elegant with a .once()
// handler in flow(), but adding and removing repeatedly is
// too slow.
var ondrain = pipeOnDrain(src);
dest.on('drain', ondrain);
var cleanedUp = false;
function cleanup() {
debug('cleanup');
// cleanup event handlers once the pipe is broken
dest.removeListener('close', onclose);
dest.removeListener('finish', onfinish);
dest.removeListener('drain', ondrain);
dest.removeListener('error', onerror);
dest.removeListener('unpipe', onunpipe);
src.removeListener('end', onend);
src.removeListener('end', unpipe);
src.removeListener('data', ondata);
cleanedUp = true;
// if the reader is waiting for a drain event from this
// specific writer, then it would cause it to never start
// flowing again.
// So, if this is awaiting a drain, then we just call it now.
// If we don't know, then assume that we are waiting for one.
if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
}
// If the user pushes more data while we're writing to dest then we'll end up
// in ondata again. However, we only want to increase awaitDrain once because
// dest will only emit one 'drain' event for the multiple writes.
// => Introduce a guard on increasing awaitDrain.
var increasedAwaitDrain = false;
src.on('data', ondata);
function ondata(chunk) {
debug('ondata');
increasedAwaitDrain = false;
var ret = dest.write(chunk);
if (false === ret && !increasedAwaitDrain) {
// If the user unpiped during `dest.write()`, it is possible
// to get stuck in a permanently paused state if that write
// also returned false.
// => Check whether `dest` is still a piping destination.
if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
debug('false write response, pause', src._readableState.awaitDrain);
src._readableState.awaitDrain++;
increasedAwaitDrain = true;
}
src.pause();
}
}
// if the dest has an error, then stop piping into it.
// however, don't suppress the throwing behavior for this.
function onerror(er) {
debug('onerror', er);
unpipe();
dest.removeListener('error', onerror);
if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);
}
// Make sure our error handler is attached before userland ones.
prependListener(dest, 'error', onerror);
// Both close and finish should trigger unpipe, but only once.
function onclose() {
dest.removeListener('finish', onfinish);
unpipe();
}
dest.once('close', onclose);
function onfinish() {
debug('onfinish');
dest.removeListener('close', onclose);
unpipe();
}
dest.once('finish', onfinish);
function unpipe() {
debug('unpipe');
src.unpipe(dest);
}
// tell the dest that it's being piped to
dest.emit('pipe', src);
// start the flow if it hasn't been started already.
if (!state.flowing) {
debug('pipe resume');
src.resume();
}
return dest;
};
function pipeOnDrain(src) {
return function () {
var state = src._readableState;
debug('pipeOnDrain', state.awaitDrain);
if (state.awaitDrain) state.awaitDrain--;
if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
state.flowing = true;
flow(src);
}
};
}
Readable.prototype.unpipe = function (dest) {
var state = this._readableState;
var unpipeInfo = { hasUnpiped: false };
// if we're not piping anywhere, then do nothing.
if (state.pipesCount === 0) return this;
// just one destination. most common case.
if (state.pipesCount === 1) {
// passed in one, but it's not the right one.
if (dest && dest !== state.pipes) return this;
if (!dest) dest = state.pipes;
// got a match.
state.pipes = null;
state.pipesCount = 0;
state.flowing = false;
if (dest) dest.emit('unpipe', this, unpipeInfo);
return this;
}
// slow case. multiple pipe destinations.
if (!dest) {
// remove all.
var dests = state.pipes;
var len = state.pipesCount;
state.pipes = null;
state.pipesCount = 0;
state.flowing = false;
for (var i = 0; i < len; i++) {
dests[i].emit('unpipe', this, unpipeInfo);
}return this;
}
// try to find the right one.
var index = indexOf(state.pipes, dest);
if (index === -1) return this;
state.pipes.splice(index, 1);
state.pipesCount -= 1;
if (state.pipesCount === 1) state.pipes = state.pipes[0];
dest.emit('unpipe', this, unpipeInfo);
return this;
};
// set up data events if they are asked for
// Ensure readable listeners eventually get something
Readable.prototype.on = function (ev, fn) {
var res = Stream.prototype.on.call(this, ev, fn);
if (ev === 'data') {
// Start flowing on next tick if stream isn't explicitly paused
if (this._readableState.flowing !== false) this.resume();
} else if (ev === 'readable') {
var state = this._readableState;
if (!state.endEmitted && !state.readableListening) {
state.readableListening = state.needReadable = true;
state.emittedReadable = false;
if (!state.reading) {
processNextTick(nReadingNextTick, this);
} else if (state.length) {
emitReadable(this);
}
}
}
return res;
};
Readable.prototype.addListener = Readable.prototype.on;
function nReadingNextTick(self) {
debug('readable nexttick read 0');
self.read(0);
}
// pause() and resume() are remnants of the legacy readable stream API
// If the user uses them, then switch into old mode.
Readable.prototype.resume = function () {
var state = this._readableState;
if (!state.flowing) {
debug('resume');
state.flowing = true;
resume(this, state);
}
return this;
};
function resume(stream, state) {
if (!state.resumeScheduled) {
state.resumeScheduled = true;
processNextTick(resume_, stream, state);
}
}
function resume_(stream, state) {
if (!state.reading) {
debug('resume read 0');
stream.read(0);
}
state.resumeScheduled = false;
state.awaitDrain = 0;
stream.emit('resume');
flow(stream);
if (state.flowing && !state.reading) stream.read(0);
}
Readable.prototype.pause = function () {
debug('call pause flowing=%j', this._readableState.flowing);
if (false !== this._readableState.flowing) {
debug('pause');
this._readableState.flowing = false;
this.emit('pause');
}
return this;
};
function flow(stream) {
var state = stream._readableState;
debug('flow', state.flowing);
while (state.flowing && stream.read() !== null) {}
}
// wrap an old-style stream as the async data source.
// This is *not* part of the readable stream interface.
// It is an ugly unfortunate mess of history.
Readable.prototype.wrap = function (stream) {
var state = this._readableState;
var paused = false;
var self = this;
stream.on('end', function () {
debug('wrapped end');
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length) self.push(chunk);
}
self.push(null);
});
stream.on('data', function (chunk) {
debug('wrapped data');
if (state.decoder) chunk = state.decoder.write(chunk);
// don't skip over falsy values in objectMode
if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;
var ret = self.push(chunk);
if (!ret) {
paused = true;
stream.pause();
}
});
// proxy all the other methods.
// important when wrapping filters and duplexes.
for (var i in stream) {
if (this[i] === undefined && typeof stream[i] === 'function') {
this[i] = function (method) {
return function () {
return stream[method].apply(stream, arguments);
};
}(i);
}
}
// proxy certain important events.
for (var n = 0; n < kProxyEvents.length; n++) {
stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n]));
}
// when we try to consume some more bytes, simply unpause the
// underlying stream.
self._read = function (n) {
debug('wrapped _read', n);
if (paused) {
paused = false;
stream.resume();
}
};
return self;
};
// exposed for testing purposes only.
Readable._fromList = fromList;
// Pluck off n bytes from an array of buffers.
// Length is the combined lengths of all the buffers in the list.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function fromList(n, state) {
// nothing buffered
if (state.length === 0) return null;
var ret;
if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {
// read it all, truncate the list
if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);
state.buffer.clear();
} else {
// read part of list
ret = fromListPartial(n, state.buffer, state.decoder);
}
return ret;
}
// Extracts only enough buffered data to satisfy the amount requested.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function fromListPartial(n, list, hasStrings) {
var ret;
if (n < list.head.data.length) {
// slice is the same for buffers and strings
ret = list.head.data.slice(0, n);
list.head.data = list.head.data.slice(n);
} else if (n === list.head.data.length) {
// first chunk is a perfect match
ret = list.shift();
} else {
// result spans more than one buffer
ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);
}
return ret;
}
// Copies a specified amount of characters from the list of buffered data
// chunks.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function copyFromBufferString(n, list) {
var p = list.head;
var c = 1;
var ret = p.data;
n -= ret.length;
while (p = p.next) {
var str = p.data;
var nb = n > str.length ? str.length : n;
if (nb === str.length) ret += str;else ret += str.slice(0, n);
n -= nb;
if (n === 0) {
if (nb === str.length) {
++c;
if (p.next) list.head = p.next;else list.head = list.tail = null;
} else {
list.head = p;
p.data = str.slice(nb);
}
break;
}
++c;
}
list.length -= c;
return ret;
}
// Copies a specified amount of bytes from the list of buffered data chunks.
// This function is designed to be inlinable, so please take care when making
// changes to the function body.
function copyFromBuffer(n, list) {
var ret = Buffer.allocUnsafe(n);
var p = list.head;
var c = 1;
p.data.copy(ret);
n -= p.data.length;
while (p = p.next) {
var buf = p.data;
var nb = n > buf.length ? buf.length : n;
buf.copy(ret, ret.length - n, 0, nb);
n -= nb;
if (n === 0) {
if (nb === buf.length) {
++c;
if (p.next) list.head = p.next;else list.head = list.tail = null;
} else {
list.head = p;
p.data = buf.slice(nb);
}
break;
}
++c;
}
list.length -= c;
return ret;
}
function endReadable(stream) {
var state = stream._readableState;
// If we get here before consuming all the bytes, then that is a
// bug in node. Should never happen.
if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream');
if (!state.endEmitted) {
state.ended = true;
processNextTick(endReadableNT, state, stream);
}
}
function endReadableNT(state, stream) {
// Check that we didn't get one last unshift.
if (!state.endEmitted && state.length === 0) {
state.endEmitted = true;
stream.readable = false;
stream.emit('end');
}
}
function forEach(xs, f) {
for (var i = 0, l = xs.length; i < l; i++) {
f(xs[i], i);
}
}
function indexOf(xs, x) {
for (var i = 0, l = xs.length; i < l; i++) {
if (xs[i] === x) return i;
}
return -1;
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./_stream_duplex":26,"./internal/streams/BufferList":31,"./internal/streams/destroy":32,"./internal/streams/stream":33,"_process":20,"core-util-is":34,"events":16,"inherits":18,"isarray":35,"process-nextick-args":36,"safe-buffer":37,"string_decoder/":50,"util":12}],29:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// a transform stream is a readable/writable stream where you do
// something with the data. Sometimes it's called a "filter",
// but that's not a great name for it, since that implies a thing where
// some bits pass through, and others are simply ignored. (That would
// be a valid example of a transform, of course.)
//
// While the output is causally related to the input, it's not a
// necessarily symmetric or synchronous transformation. For example,
// a zlib stream might take multiple plain-text writes(), and then
// emit a single compressed chunk some time in the future.
//
// Here's how this works:
//
// The Transform stream has all the aspects of the readable and writable
// stream classes. When you write(chunk), that calls _write(chunk,cb)
// internally, and returns false if there's a lot of pending writes
// buffered up. When you call read(), that calls _read(n) until
// there's enough pending readable data buffered up.
//
// In a transform stream, the written data is placed in a buffer. When
// _read(n) is called, it transforms the queued up data, calling the
// buffered _write cb's as it consumes chunks. If consuming a single
// written chunk would result in multiple output chunks, then the first
// outputted bit calls the readcb, and subsequent chunks just go into
// the read buffer, and will cause it to emit 'readable' if necessary.
//
// This way, back-pressure is actually determined by the reading side,
// since _read has to be called to start processing a new chunk. However,
// a pathological inflate type of transform can cause excessive buffering
// here. For example, imagine a stream where every byte of input is
// interpreted as an integer from 0-255, and then results in that many
// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
// 1kb of data being output. In this case, you could write a very small
// amount of input, and end up with a very large amount of output. In
// such a pathological inflating mechanism, there'd be no way to tell
// the system to stop doing the transform. A single 4MB write could
// cause the system to run out of memory.
//
// However, even in such a pathological case, only a single written chunk
// would be consumed, and then the rest would wait (un-transformed) until
// the results of the previous transformed chunk were consumed.
'use strict';
module.exports = Transform;
var Duplex = require('./_stream_duplex');
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
util.inherits(Transform, Duplex);
function TransformState(stream) {
this.afterTransform = function (er, data) {
return afterTransform(stream, er, data);
};
this.needTransform = false;
this.transforming = false;
this.writecb = null;
this.writechunk = null;
this.writeencoding = null;
}
function afterTransform(stream, er, data) {
var ts = stream._transformState;
ts.transforming = false;
var cb = ts.writecb;
if (!cb) {
return stream.emit('error', new Error('write callback called multiple times'));
}
ts.writechunk = null;
ts.writecb = null;
if (data !== null && data !== undefined) stream.push(data);
cb(er);
var rs = stream._readableState;
rs.reading = false;
if (rs.needReadable || rs.length < rs.highWaterMark) {
stream._read(rs.highWaterMark);
}
}
function Transform(options) {
if (!(this instanceof Transform)) return new Transform(options);
Duplex.call(this, options);
this._transformState = new TransformState(this);
var stream = this;
// start out asking for a readable event once data is transformed.
this._readableState.needReadable = true;
// we have implemented the _read method, and done the other things
// that Readable wants before the first _read call, so unset the
// sync guard flag.
this._readableState.sync = false;
if (options) {
if (typeof options.transform === 'function') this._transform = options.transform;
if (typeof options.flush === 'function') this._flush = options.flush;
}
// When the writable side finishes, then flush out anything remaining.
this.once('prefinish', function () {
if (typeof this._flush === 'function') this._flush(function (er, data) {
done(stream, er, data);
});else done(stream);
});
}
Transform.prototype.push = function (chunk, encoding) {
this._transformState.needTransform = false;
return Duplex.prototype.push.call(this, chunk, encoding);
};
// This is the part where you do stuff!
// override this function in implementation classes.
// 'chunk' is an input chunk.
//
// Call `push(newChunk)` to pass along transformed output
// to the readable side. You may call 'push' zero or more times.
//
// Call `cb(err)` when you are done with this chunk. If you pass
// an error, then that'll put the hurt on the whole operation. If you
// never call cb(), then you'll never get another chunk.
Transform.prototype._transform = function (chunk, encoding, cb) {
throw new Error('_transform() is not implemented');
};
Transform.prototype._write = function (chunk, encoding, cb) {
var ts = this._transformState;
ts.writecb = cb;
ts.writechunk = chunk;
ts.writeencoding = encoding;
if (!ts.transforming) {
var rs = this._readableState;
if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
}
};
// Doesn't matter what the args are here.
// _transform does all the work.
// That we got here means that the readable side wants more data.
Transform.prototype._read = function (n) {
var ts = this._transformState;
if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
ts.transforming = true;
this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
} else {
// mark that we need a transform, so that any data that comes in
// will get processed, now that we've asked for it.
ts.needTransform = true;
}
};
Transform.prototype._destroy = function (err, cb) {
var _this = this;
Duplex.prototype._destroy.call(this, err, function (err2) {
cb(err2);
_this.emit('close');
});
};
function done(stream, er, data) {
if (er) return stream.emit('error', er);
if (data !== null && data !== undefined) stream.push(data);
// if there's nothing in the write buffer, then that means
// that nothing more will ever be provided
var ws = stream._writableState;
var ts = stream._transformState;
if (ws.length) throw new Error('Calling transform done when ws.length != 0');
if (ts.transforming) throw new Error('Calling transform done when still transforming');
return stream.push(null);
}
},{"./_stream_duplex":26,"core-util-is":34,"inherits":18}],30:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// A bit simpler than readable streams.
// Implement an async ._write(chunk, encoding, cb), and it'll handle all
// the drain event emission and buffering.
'use strict';
/*<replacement>*/
var processNextTick = require('process-nextick-args');
/*</replacement>*/
module.exports = Writable;
/* <replacement> */
function WriteReq(chunk, encoding, cb) {
this.chunk = chunk;
this.encoding = encoding;
this.callback = cb;
this.next = null;
}
// It seems a linked list but it is not
// there will be only 2 of these for each stream
function CorkedRequest(state) {
var _this = this;
this.next = null;
this.entry = null;
this.finish = function () {
onCorkedFinish(_this, state);
};
}
/* </replacement> */
/*<replacement>*/
var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;
/*</replacement>*/
/*<replacement>*/
var Duplex;
/*</replacement>*/
Writable.WritableState = WritableState;
/*<replacement>*/
var util = require('core-util-is');
util.inherits = require('inherits');
/*</replacement>*/
/*<replacement>*/
var internalUtil = {
deprecate: require('util-deprecate')
};
/*</replacement>*/
/*<replacement>*/
var Stream = require('./internal/streams/stream');
/*</replacement>*/
/*<replacement>*/
var Buffer = require('safe-buffer').Buffer;
var OurUint8Array = global.Uint8Array || function () {};
function _uint8ArrayToBuffer(chunk) {
return Buffer.from(chunk);
}
function _isUint8Array(obj) {
return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
}
/*</replacement>*/
var destroyImpl = require('./internal/streams/destroy');
util.inherits(Writable, Stream);
function nop() {}
function WritableState(options, stream) {
Duplex = Duplex || require('./_stream_duplex');
options = options || {};
// object stream flag to indicate whether or not this stream
// contains buffers or objects.
this.objectMode = !!options.objectMode;
if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
// the point at which write() starts returning false
// Note: 0 is a valid value, means that we always return false if
// the entire buffer is not flushed immediately on write()
var hwm = options.highWaterMark;
var defaultHwm = this.objectMode ? 16 : 16 * 1024;
this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
// cast to ints.
this.highWaterMark = Math.floor(this.highWaterMark);
// if _final has been called
this.finalCalled = false;
// drain event flag.
this.needDrain = false;
// at the start of calling end()
this.ending = false;
// when end() has been called, and returned
this.ended = false;
// when 'finish' is emitted
this.finished = false;
// has it been destroyed
this.destroyed = false;
// should we decode strings into buffers before passing to _write?
// this is here so that some node-core streams can optimize string
// handling at a lower level.
var noDecode = options.decodeStrings === false;
this.decodeStrings = !noDecode;
// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
this.defaultEncoding = options.defaultEncoding || 'utf8';
// not an actual buffer we keep track of, but a measurement
// of how much we're waiting to get pushed to some underlying
// socket or file.
this.length = 0;
// a flag to see when we're in the middle of a write.
this.writing = false;
// when true all writes will be buffered until .uncork() call
this.corked = 0;
// a flag to be able to tell if the onwrite cb is called immediately,
// or on a later tick. We set this to true at first, because any
// actions that shouldn't happen until "later" should generally also
// not happen before the first write call.
this.sync = true;
// a flag to know if we're processing previously buffered items, which
// may call the _write() callback in the same tick, so that we don't
// end up in an overlapped onwrite situation.
this.bufferProcessing = false;
// the callback that's passed to _write(chunk,cb)
this.onwrite = function (er) {
onwrite(stream, er);
};
// the callback that the user supplies to write(chunk,encoding,cb)
this.writecb = null;
// the amount that is being written when _write is called.
this.writelen = 0;
this.bufferedRequest = null;
this.lastBufferedRequest = null;
// number of pending user-supplied write callbacks
// this must be 0 before 'finish' can be emitted
this.pendingcb = 0;
// emit prefinish if the only thing we're waiting for is _write cbs
// This is relevant for synchronous Transform streams
this.prefinished = false;
// True if the error was already emitted and should not be thrown again
this.errorEmitted = false;
// count buffered requests
this.bufferedRequestCount = 0;
// allocate the first CorkedRequest, there is always
// one allocated and free to use, and we maintain at most two
this.corkedRequestsFree = new CorkedRequest(this);
}
WritableState.prototype.getBuffer = function getBuffer() {
var current = this.bufferedRequest;
var out = [];
while (current) {
out.push(current);
current = current.next;
}
return out;
};
(function () {
try {
Object.defineProperty(WritableState.prototype, 'buffer', {
get: internalUtil.deprecate(function () {
return this.getBuffer();
}, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')
});
} catch (_) {}
})();
// Test _writableState for inheritance to account for Duplex streams,
// whose prototype chain only points to Readable.
var realHasInstance;
if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
realHasInstance = Function.prototype[Symbol.hasInstance];
Object.defineProperty(Writable, Symbol.hasInstance, {
value: function (object) {
if (realHasInstance.call(this, object)) return true;
return object && object._writableState instanceof WritableState;
}
});
} else {
realHasInstance = function (object) {
return object instanceof this;
};
}
function Writable(options) {
Duplex = Duplex || require('./_stream_duplex');
// Writable ctor is applied to Duplexes, too.
// `realHasInstance` is necessary because using plain `instanceof`
// would return false, as no `_writableState` property is attached.
// Trying to use the custom `instanceof` for Writable here will also break the
// Node.js LazyTransform implementation, which has a non-trivial getter for
// `_writableState` that would lead to infinite recursion.
if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {
return new Writable(options);
}
this._writableState = new WritableState(options, this);
// legacy.
this.writable = true;
if (options) {
if (typeof options.write === 'function') this._write = options.write;
if (typeof options.writev === 'function') this._writev = options.writev;
if (typeof options.destroy === 'function') this._destroy = options.destroy;
if (typeof options.final === 'function') this._final = options.final;
}
Stream.call(this);
}
// Otherwise people can pipe Writable streams, which is just wrong.
Writable.prototype.pipe = function () {
this.emit('error', new Error('Cannot pipe, not readable'));
};
function writeAfterEnd(stream, cb) {
var er = new Error('write after end');
// TODO: defer error events consistently everywhere, not just the cb
stream.emit('error', er);
processNextTick(cb, er);
}
// Checks that a user-supplied chunk is valid, especially for the particular
// mode the stream is in. Currently this means that `null` is never accepted
// and undefined/non-string values are only allowed in object mode.
function validChunk(stream, state, chunk, cb) {
var valid = true;
var er = false;
if (chunk === null) {
er = new TypeError('May not write null values to stream');
} else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
er = new TypeError('Invalid non-string/buffer chunk');
}
if (er) {
stream.emit('error', er);
processNextTick(cb, er);
valid = false;
}
return valid;
}
Writable.prototype.write = function (chunk, encoding, cb) {
var state = this._writableState;
var ret = false;
var isBuf = _isUint8Array(chunk) && !state.objectMode;
if (isBuf && !Buffer.isBuffer(chunk)) {
chunk = _uint8ArrayToBuffer(chunk);
}
if (typeof encoding === 'function') {
cb = encoding;
encoding = null;
}
if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
if (typeof cb !== 'function') cb = nop;
if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {
state.pendingcb++;
ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
}
return ret;
};
Writable.prototype.cork = function () {
var state = this._writableState;
state.corked++;
};
Writable.prototype.uncork = function () {
var state = this._writableState;
if (state.corked) {
state.corked--;
if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
}
};
Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
// node::ParseEncoding() requires lower case.
if (typeof encoding === 'string') encoding = encoding.toLowerCase();
if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
this._writableState.defaultEncoding = encoding;
return this;
};
function decodeChunk(state, chunk, encoding) {
if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
chunk = Buffer.from(chunk, encoding);
}
return chunk;
}
// if we're already writing something, then just put this
// in the queue, and wait our turn. Otherwise, call _write
// If we return false, then we need a drain event, so set that flag.
function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
if (!isBuf) {
var newChunk = decodeChunk(state, chunk, encoding);
if (chunk !== newChunk) {
isBuf = true;
encoding = 'buffer';
chunk = newChunk;
}
}
var len = state.objectMode ? 1 : chunk.length;
state.length += len;
var ret = state.length < state.highWaterMark;
// we must ensure that previous needDrain will not be reset to false.
if (!ret) state.needDrain = true;
if (state.writing || state.corked) {
var last = state.lastBufferedRequest;
state.lastBufferedRequest = {
chunk: chunk,
encoding: encoding,
isBuf: isBuf,
callback: cb,
next: null
};
if (last) {
last.next = state.lastBufferedRequest;
} else {
state.bufferedRequest = state.lastBufferedRequest;
}
state.bufferedRequestCount += 1;
} else {
doWrite(stream, state, false, len, chunk, encoding, cb);
}
return ret;
}
function doWrite(stream, state, writev, len, chunk, encoding, cb) {
state.writelen = len;
state.writecb = cb;
state.writing = true;
state.sync = true;
if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
state.sync = false;
}
function onwriteError(stream, state, sync, er, cb) {
--state.pendingcb;
if (sync) {
// defer the callback if we are being called synchronously
// to avoid piling up things on the stack
processNextTick(cb, er);
// this can emit finish, and it will always happen
// after error
processNextTick(finishMaybe, stream, state);
stream._writableState.errorEmitted = true;
stream.emit('error', er);
} else {
// the caller expect this to happen before if
// it is async
cb(er);
stream._writableState.errorEmitted = true;
stream.emit('error', er);
// this can emit finish, but finish must
// always follow error
finishMaybe(stream, state);
}
}
function onwriteStateUpdate(state) {
state.writing = false;
state.writecb = null;
state.length -= state.writelen;
state.writelen = 0;
}
function onwrite(stream, er) {
var state = stream._writableState;
var sync = state.sync;
var cb = state.writecb;
onwriteStateUpdate(state);
if (er) onwriteError(stream, state, sync, er, cb);else {
// Check if we're actually ready to finish, but don't emit yet
var finished = needFinish(state);
if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
clearBuffer(stream, state);
}
if (sync) {
/*<replacement>*/
asyncWrite(afterWrite, stream, state, finished, cb);
/*</replacement>*/
} else {
afterWrite(stream, state, finished, cb);
}
}
}
function afterWrite(stream, state, finished, cb) {
if (!finished) onwriteDrain(stream, state);
state.pendingcb--;
cb();
finishMaybe(stream, state);
}
// Must force callback to be called on nextTick, so that we don't
// emit 'drain' before the write() consumer gets the 'false' return
// value, and has a chance to attach a 'drain' listener.
function onwriteDrain(stream, state) {
if (state.length === 0 && state.needDrain) {
state.needDrain = false;
stream.emit('drain');
}
}
// if there's something in the buffer waiting, then process it
function clearBuffer(stream, state) {
state.bufferProcessing = true;
var entry = state.bufferedRequest;
if (stream._writev && entry && entry.next) {
// Fast case, write everything using _writev()
var l = state.bufferedRequestCount;
var buffer = new Array(l);
var holder = state.corkedRequestsFree;
holder.entry = entry;
var count = 0;
var allBuffers = true;
while (entry) {
buffer[count] = entry;
if (!entry.isBuf) allBuffers = false;
entry = entry.next;
count += 1;
}
buffer.allBuffers = allBuffers;
doWrite(stream, state, true, state.length, buffer, '', holder.finish);
// doWrite is almost always async, defer these to save a bit of time
// as the hot path ends with doWrite
state.pendingcb++;
state.lastBufferedRequest = null;
if (holder.next) {
state.corkedRequestsFree = holder.next;
holder.next = null;
} else {
state.corkedRequestsFree = new CorkedRequest(state);
}
} else {
// Slow case, write chunks one-by-one
while (entry) {
var chunk = entry.chunk;
var encoding = entry.encoding;
var cb = entry.callback;
var len = state.objectMode ? 1 : chunk.length;
doWrite(stream, state, false, len, chunk, encoding, cb);
entry = entry.next;
// if we didn't call the onwrite immediately, then
// it means that we need to wait until it does.
// also, that means that the chunk and cb are currently
// being processed, so move the buffer counter past them.
if (state.writing) {
break;
}
}
if (entry === null) state.lastBufferedRequest = null;
}
state.bufferedRequestCount = 0;
state.bufferedRequest = entry;
state.bufferProcessing = false;
}
Writable.prototype._write = function (chunk, encoding, cb) {
cb(new Error('_write() is not implemented'));
};
Writable.prototype._writev = null;
Writable.prototype.end = function (chunk, encoding, cb) {
var state = this._writableState;
if (typeof chunk === 'function') {
cb = chunk;
chunk = null;
encoding = null;
} else if (typeof encoding === 'function') {
cb = encoding;
encoding = null;
}
if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
// .end() fully uncorks
if (state.corked) {
state.corked = 1;
this.uncork();
}
// ignore unnecessary end() calls.
if (!state.ending && !state.finished) endWritable(this, state, cb);
};
function needFinish(state) {
return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
}
function callFinal(stream, state) {
stream._final(function (err) {
state.pendingcb--;
if (err) {
stream.emit('error', err);
}
state.prefinished = true;
stream.emit('prefinish');
finishMaybe(stream, state);
});
}
function prefinish(stream, state) {
if (!state.prefinished && !state.finalCalled) {
if (typeof stream._final === 'function') {
state.pendingcb++;
state.finalCalled = true;
processNextTick(callFinal, stream, state);
} else {
state.prefinished = true;
stream.emit('prefinish');
}
}
}
function finishMaybe(stream, state) {
var need = needFinish(state);
if (need) {
prefinish(stream, state);
if (state.pendingcb === 0) {
state.finished = true;
stream.emit('finish');
}
}
return need;
}
function endWritable(stream, state, cb) {
state.ending = true;
finishMaybe(stream, state);
if (cb) {
if (state.finished) processNextTick(cb);else stream.once('finish', cb);
}
state.ended = true;
stream.writable = false;
}
function onCorkedFinish(corkReq, state, err) {
var entry = corkReq.entry;
corkReq.entry = null;
while (entry) {
var cb = entry.callback;
state.pendingcb--;
cb(err);
entry = entry.next;
}
if (state.corkedRequestsFree) {
state.corkedRequestsFree.next = corkReq;
} else {
state.corkedRequestsFree = corkReq;
}
}
Object.defineProperty(Writable.prototype, 'destroyed', {
get: function () {
if (this._writableState === undefined) {
return false;
}
return this._writableState.destroyed;
},
set: function (value) {
// we ignore the value if the stream
// has not been initialized yet
if (!this._writableState) {
return;
}
// backward compatibility, the user is explicitly
// managing destroyed
this._writableState.destroyed = value;
}
});
Writable.prototype.destroy = destroyImpl.destroy;
Writable.prototype._undestroy = destroyImpl.undestroy;
Writable.prototype._destroy = function (err, cb) {
this.end();
cb(err);
};
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./_stream_duplex":26,"./internal/streams/destroy":32,"./internal/streams/stream":33,"_process":20,"core-util-is":34,"inherits":18,"process-nextick-args":36,"safe-buffer":37,"util-deprecate":38}],31:[function(require,module,exports){
'use strict';
/*<replacement>*/
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Buffer = require('safe-buffer').Buffer;
/*</replacement>*/
function copyBuffer(src, target, offset) {
src.copy(target, offset);
}
module.exports = function () {
function BufferList() {
_classCallCheck(this, BufferList);
this.head = null;
this.tail = null;
this.length = 0;
}
BufferList.prototype.push = function push(v) {
var entry = { data: v, next: null };
if (this.length > 0) this.tail.next = entry;else this.head = entry;
this.tail = entry;
++this.length;
};
BufferList.prototype.unshift = function unshift(v) {
var entry = { data: v, next: this.head };
if (this.length === 0) this.tail = entry;
this.head = entry;
++this.length;
};
BufferList.prototype.shift = function shift() {
if (this.length === 0) return;
var ret = this.head.data;
if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
--this.length;
return ret;
};
BufferList.prototype.clear = function clear() {
this.head = this.tail = null;
this.length = 0;
};
BufferList.prototype.join = function join(s) {
if (this.length === 0) return '';
var p = this.head;
var ret = '' + p.data;
while (p = p.next) {
ret += s + p.data;
}return ret;
};
BufferList.prototype.concat = function concat(n) {
if (this.length === 0) return Buffer.alloc(0);
if (this.length === 1) return this.head.data;
var ret = Buffer.allocUnsafe(n >>> 0);
var p = this.head;
var i = 0;
while (p) {
copyBuffer(p.data, ret, i);
i += p.data.length;
p = p.next;
}
return ret;
};
return BufferList;
}();
},{"safe-buffer":37}],32:[function(require,module,exports){
'use strict';
/*<replacement>*/
var processNextTick = require('process-nextick-args');
/*</replacement>*/
// undocumented cb() API, needed for core, not for public API
function destroy(err, cb) {
var _this = this;
var readableDestroyed = this._readableState && this._readableState.destroyed;
var writableDestroyed = this._writableState && this._writableState.destroyed;
if (readableDestroyed || writableDestroyed) {
if (cb) {
cb(err);
} else if (err && (!this._writableState || !this._writableState.errorEmitted)) {
processNextTick(emitErrorNT, this, err);
}
return;
}
// we set destroyed to true before firing error callbacks in order
// to make it re-entrance safe in case destroy() is called within callbacks
if (this._readableState) {
this._readableState.destroyed = true;
}
// if this is a duplex stream mark the writable part as destroyed as well
if (this._writableState) {
this._writableState.destroyed = true;
}
this._destroy(err || null, function (err) {
if (!cb && err) {
processNextTick(emitErrorNT, _this, err);
if (_this._writableState) {
_this._writableState.errorEmitted = true;
}
} else if (cb) {
cb(err);
}
});
}
function undestroy() {
if (this._readableState) {
this._readableState.destroyed = false;
this._readableState.reading = false;
this._readableState.ended = false;
this._readableState.endEmitted = false;
}
if (this._writableState) {
this._writableState.destroyed = false;
this._writableState.ended = false;
this._writableState.ending = false;
this._writableState.finished = false;
this._writableState.errorEmitted = false;
}
}
function emitErrorNT(self, err) {
self.emit('error', err);
}
module.exports = {
destroy: destroy,
undestroy: undestroy
};
},{"process-nextick-args":36}],33:[function(require,module,exports){
module.exports = require('events').EventEmitter;
},{"events":16}],34:[function(require,module,exports){
(function (Buffer){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(arg) {
if (Array.isArray) {
return Array.isArray(arg);
}
return objectToString(arg) === '[object Array]';
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = Buffer.isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
}).call(this,{"isBuffer":require("../../../../insert-module-globals/node_modules/is-buffer/index.js")})
},{"../../../../insert-module-globals/node_modules/is-buffer/index.js":19}],35:[function(require,module,exports){
var toString = {}.toString;
module.exports = Array.isArray || function (arr) {
return toString.call(arr) == '[object Array]';
};
},{}],36:[function(require,module,exports){
(function (process){
'use strict';
if (!process.version ||
process.version.indexOf('v0.') === 0 ||
process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {
module.exports = nextTick;
} else {
module.exports = process.nextTick;
}
function nextTick(fn, arg1, arg2, arg3) {
if (typeof fn !== 'function') {
throw new TypeError('"callback" argument must be a function');
}
var len = arguments.length;
var args, i;
switch (len) {
case 0:
case 1:
return process.nextTick(fn);
case 2:
return process.nextTick(function afterTickOne() {
fn.call(null, arg1);
});
case 3:
return process.nextTick(function afterTickTwo() {
fn.call(null, arg1, arg2);
});
case 4:
return process.nextTick(function afterTickThree() {
fn.call(null, arg1, arg2, arg3);
});
default:
args = new Array(len - 1);
i = 0;
while (i < args.length) {
args[i++] = arguments[i];
}
return process.nextTick(function afterTick() {
fn.apply(null, args);
});
}
}
}).call(this,require('_process'))
},{"_process":20}],37:[function(require,module,exports){
/* eslint-disable node/no-deprecated-api */
var buffer = require('buffer')
var Buffer = buffer.Buffer
// alternative to using Object.keys for old browsers
function copyProps (src, dst) {
for (var key in src) {
dst[key] = src[key]
}
}
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
module.exports = buffer
} else {
// Copy properties from require('buffer')
copyProps(buffer, exports)
exports.Buffer = SafeBuffer
}
function SafeBuffer (arg, encodingOrOffset, length) {
return Buffer(arg, encodingOrOffset, length)
}
// Copy static methods from Buffer
copyProps(Buffer, SafeBuffer)
SafeBuffer.from = function (arg, encodingOrOffset, length) {
if (typeof arg === 'number') {
throw new TypeError('Argument must not be a number')
}
return Buffer(arg, encodingOrOffset, length)
}
SafeBuffer.alloc = function (size, fill, encoding) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
var buf = Buffer(size)
if (fill !== undefined) {
if (typeof encoding === 'string') {
buf.fill(fill, encoding)
} else {
buf.fill(fill)
}
} else {
buf.fill(0)
}
return buf
}
SafeBuffer.allocUnsafe = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return Buffer(size)
}
SafeBuffer.allocUnsafeSlow = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return buffer.SlowBuffer(size)
}
},{"buffer":13}],38:[function(require,module,exports){
(function (global){
/**
* Module exports.
*/
module.exports = deprecate;
/**
* Mark that a method should not be used.
* Returns a modified function which warns once by default.
*
* If `localStorage.noDeprecation = true` is set, then it is a no-op.
*
* If `localStorage.throwDeprecation = true` is set, then deprecated functions
* will throw an Error when invoked.
*
* If `localStorage.traceDeprecation = true` is set, then deprecated functions
* will invoke `console.trace()` instead of `console.error()`.
*
* @param {Function} fn - the function to deprecate
* @param {String} msg - the string to print to the console when `fn` is invoked
* @returns {Function} a new "deprecated" version of `fn`
* @api public
*/
function deprecate (fn, msg) {
if (config('noDeprecation')) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (config('throwDeprecation')) {
throw new Error(msg);
} else if (config('traceDeprecation')) {
console.trace(msg);
} else {
console.warn(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
}
/**
* Checks `localStorage` for boolean values for the given `name`.
*
* @param {String} name
* @returns {Boolean}
* @api private
*/
function config (name) {
// accessing global.localStorage can trigger a DOMException in sandboxed iframes
try {
if (!global.localStorage) return false;
} catch (_) {
return false;
}
var val = global.localStorage[name];
if (null == val) return false;
return String(val).toLowerCase() === 'true';
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],39:[function(require,module,exports){
module.exports = require('./readable').PassThrough
},{"./readable":40}],40:[function(require,module,exports){
exports = module.exports = require('./lib/_stream_readable.js');
exports.Stream = exports;
exports.Readable = exports;
exports.Writable = require('./lib/_stream_writable.js');
exports.Duplex = require('./lib/_stream_duplex.js');
exports.Transform = require('./lib/_stream_transform.js');
exports.PassThrough = require('./lib/_stream_passthrough.js');
},{"./lib/_stream_duplex.js":26,"./lib/_stream_passthrough.js":27,"./lib/_stream_readable.js":28,"./lib/_stream_transform.js":29,"./lib/_stream_writable.js":30}],41:[function(require,module,exports){
module.exports = require('./readable').Transform
},{"./readable":40}],42:[function(require,module,exports){
module.exports = require('./lib/_stream_writable.js');
},{"./lib/_stream_writable.js":30}],43:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
module.exports = Stream;
var EE = require('events').EventEmitter;
var inherits = require('inherits');
inherits(Stream, EE);
Stream.Readable = require('readable-stream/readable.js');
Stream.Writable = require('readable-stream/writable.js');
Stream.Duplex = require('readable-stream/duplex.js');
Stream.Transform = require('readable-stream/transform.js');
Stream.PassThrough = require('readable-stream/passthrough.js');
// Backwards-compat with node 0.4.x
Stream.Stream = Stream;
// old-style streams. Note that the pipe method (the only relevant
// part of this class) is overridden in the Readable class.
function Stream() {
EE.call(this);
}
Stream.prototype.pipe = function(dest, options) {
var source = this;
function ondata(chunk) {
if (dest.writable) {
if (false === dest.write(chunk) && source.pause) {
source.pause();
}
}
}
source.on('data', ondata);
function ondrain() {
if (source.readable && source.resume) {
source.resume();
}
}
dest.on('drain', ondrain);
// If the 'end' option is not supplied, dest.end() will be called when
// source gets the 'end' or 'close' events. Only dest.end() once.
if (!dest._isStdio && (!options || options.end !== false)) {
source.on('end', onend);
source.on('close', onclose);
}
var didOnEnd = false;
function onend() {
if (didOnEnd) return;
didOnEnd = true;
dest.end();
}
function onclose() {
if (didOnEnd) return;
didOnEnd = true;
if (typeof dest.destroy === 'function') dest.destroy();
}
// don't leave dangling pipes when there are errors.
function onerror(er) {
cleanup();
if (EE.listenerCount(this, 'error') === 0) {
throw er; // Unhandled stream error in pipe.
}
}
source.on('error', onerror);
dest.on('error', onerror);
// remove all the event listeners that were added.
function cleanup() {
source.removeListener('data', ondata);
dest.removeListener('drain', ondrain);
source.removeListener('end', onend);
source.removeListener('close', onclose);
source.removeListener('error', onerror);
dest.removeListener('error', onerror);
source.removeListener('end', cleanup);
source.removeListener('close', cleanup);
dest.removeListener('close', cleanup);
}
source.on('end', cleanup);
source.on('close', cleanup);
dest.on('close', cleanup);
dest.emit('pipe', source);
// Allow for unix-like usage: A.pipe(B).pipe(C)
return dest;
};
},{"events":16,"inherits":18,"readable-stream/duplex.js":25,"readable-stream/passthrough.js":39,"readable-stream/readable.js":40,"readable-stream/transform.js":41,"readable-stream/writable.js":42}],44:[function(require,module,exports){
(function (global){
var ClientRequest = require('./lib/request')
var IncomingMessage = require('./lib/response')
var extend = require('xtend')
var statusCodes = require('builtin-status-codes')
var url = require('url')
var http = exports
http.request = function (opts, cb) {
if (typeof opts === 'string')
opts = url.parse(opts)
else
opts = extend(opts)
// Normally, the page is loaded from http or https, so not specifying a protocol
// will result in a (valid) protocol-relative url. However, this won't work if
// the protocol is something else, like 'file:'
var defaultProtocol = global.location.protocol.search(/^https?:$/) === -1 ? 'http:' : ''
var protocol = opts.protocol || defaultProtocol
var host = opts.hostname || opts.host
var port = opts.port
var path = opts.path || '/'
// Necessary for IPv6 addresses
if (host && host.indexOf(':') !== -1)
host = '[' + host + ']'
// This may be a relative url. The browser should always be able to interpret it correctly.
opts.url = (host ? (protocol + '//' + host) : '') + (port ? ':' + port : '') + path
opts.method = (opts.method || 'GET').toUpperCase()
opts.headers = opts.headers || {}
// Also valid opts.auth, opts.mode
var req = new ClientRequest(opts)
if (cb)
req.on('response', cb)
return req
}
http.get = function get (opts, cb) {
var req = http.request(opts, cb)
req.end()
return req
}
http.ClientRequest = ClientRequest
http.IncomingMessage = IncomingMessage
http.Agent = function () {}
http.Agent.defaultMaxSockets = 4
http.STATUS_CODES = statusCodes
http.METHODS = [
'CHECKOUT',
'CONNECT',
'COPY',
'DELETE',
'GET',
'HEAD',
'LOCK',
'M-SEARCH',
'MERGE',
'MKACTIVITY',
'MKCOL',
'MOVE',
'NOTIFY',
'OPTIONS',
'PATCH',
'POST',
'PROPFIND',
'PROPPATCH',
'PURGE',
'PUT',
'REPORT',
'SEARCH',
'SUBSCRIBE',
'TRACE',
'UNLOCK',
'UNSUBSCRIBE'
]
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./lib/request":46,"./lib/response":47,"builtin-status-codes":48,"url":52,"xtend":57}],45:[function(require,module,exports){
(function (global){
exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream)
exports.writableStream = isFunction(global.WritableStream)
exports.abortController = isFunction(global.AbortController)
exports.blobConstructor = false
try {
new Blob([new ArrayBuffer(1)])
exports.blobConstructor = true
} catch (e) {}
// The xhr request to example.com may violate some restrictive CSP configurations,
// so if we're running in a browser that supports `fetch`, avoid calling getXHR()
// and assume support for certain features below.
var xhr
function getXHR () {
// Cache the xhr value
if (xhr !== undefined) return xhr
if (global.XMLHttpRequest) {
xhr = new global.XMLHttpRequest()
// If XDomainRequest is available (ie only, where xhr might not work
// cross domain), use the page location. Otherwise use example.com
// Note: this doesn't actually make an http request.
try {
xhr.open('GET', global.XDomainRequest ? '/' : 'https://example.com')
} catch(e) {
xhr = null
}
} else {
// Service workers don't have XHR
xhr = null
}
return xhr
}
function checkTypeSupport (type) {
var xhr = getXHR()
if (!xhr) return false
try {
xhr.responseType = type
return xhr.responseType === type
} catch (e) {}
return false
}
// For some strange reason, Safari 7.0 reports typeof global.ArrayBuffer === 'object'.
// Safari 7.1 appears to have fixed this bug.
var haveArrayBuffer = typeof global.ArrayBuffer !== 'undefined'
var haveSlice = haveArrayBuffer && isFunction(global.ArrayBuffer.prototype.slice)
// If fetch is supported, then arraybuffer will be supported too. Skip calling
// checkTypeSupport(), since that calls getXHR().
exports.arraybuffer = exports.fetch || (haveArrayBuffer && checkTypeSupport('arraybuffer'))
// These next two tests unavoidably show warnings in Chrome. Since fetch will always
// be used if it's available, just return false for these to avoid the warnings.
exports.msstream = !exports.fetch && haveSlice && checkTypeSupport('ms-stream')
exports.mozchunkedarraybuffer = !exports.fetch && haveArrayBuffer &&
checkTypeSupport('moz-chunked-arraybuffer')
// If fetch is supported, then overrideMimeType will be supported too. Skip calling
// getXHR().
exports.overrideMimeType = exports.fetch || (getXHR() ? isFunction(getXHR().overrideMimeType) : false)
exports.vbArray = isFunction(global.VBArray)
function isFunction (value) {
return typeof value === 'function'
}
xhr = null // Help gc
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],46:[function(require,module,exports){
(function (process,global,Buffer){
var capability = require('./capability')
var inherits = require('inherits')
var response = require('./response')
var stream = require('readable-stream')
var toArrayBuffer = require('to-arraybuffer')
var IncomingMessage = response.IncomingMessage
var rStates = response.readyStates
function decideMode (preferBinary, useFetch) {
if (capability.fetch && useFetch) {
return 'fetch'
} else if (capability.mozchunkedarraybuffer) {
return 'moz-chunked-arraybuffer'
} else if (capability.msstream) {
return 'ms-stream'
} else if (capability.arraybuffer && preferBinary) {
return 'arraybuffer'
} else if (capability.vbArray && preferBinary) {
return 'text:vbarray'
} else {
return 'text'
}
}
var ClientRequest = module.exports = function (opts) {
var self = this
stream.Writable.call(self)
self._opts = opts
self._body = []
self._headers = {}
if (opts.auth)
self.setHeader('Authorization', 'Basic ' + new Buffer(opts.auth).toString('base64'))
Object.keys(opts.headers).forEach(function (name) {
self.setHeader(name, opts.headers[name])
})
var preferBinary
var useFetch = true
if (opts.mode === 'disable-fetch' || ('requestTimeout' in opts && !capability.abortController)) {
// If the use of XHR should be preferred. Not typically needed.
useFetch = false
preferBinary = true
} else if (opts.mode === 'prefer-streaming') {
// If streaming is a high priority but binary compatibility and
// the accuracy of the 'content-type' header aren't
preferBinary = false
} else if (opts.mode === 'allow-wrong-content-type') {
// If streaming is more important than preserving the 'content-type' header
preferBinary = !capability.overrideMimeType
} else if (!opts.mode || opts.mode === 'default' || opts.mode === 'prefer-fast') {
// Use binary if text streaming may corrupt data or the content-type header, or for speed
preferBinary = true
} else {
throw new Error('Invalid value for opts.mode')
}
self._mode = decideMode(preferBinary, useFetch)
self.on('finish', function () {
self._onFinish()
})
}
inherits(ClientRequest, stream.Writable)
ClientRequest.prototype.setHeader = function (name, value) {
var self = this
var lowerName = name.toLowerCase()
// This check is not necessary, but it prevents warnings from browsers about setting unsafe
// headers. To be honest I'm not entirely sure hiding these warnings is a good thing, but
// http-browserify did it, so I will too.
if (unsafeHeaders.indexOf(lowerName) !== -1)
return
self._headers[lowerName] = {
name: name,
value: value
}
}
ClientRequest.prototype.getHeader = function (name) {
var header = this._headers[name.toLowerCase()]
if (header)
return header.value
return null
}
ClientRequest.prototype.removeHeader = function (name) {
var self = this
delete self._headers[name.toLowerCase()]
}
ClientRequest.prototype._onFinish = function () {
var self = this
if (self._destroyed)
return
var opts = self._opts
var headersObj = self._headers
var body = null
if (opts.method !== 'GET' && opts.method !== 'HEAD') {
if (capability.arraybuffer) {
body = toArrayBuffer(Buffer.concat(self._body))
} else if (capability.blobConstructor) {
body = new global.Blob(self._body.map(function (buffer) {
return toArrayBuffer(buffer)
}), {
type: (headersObj['content-type'] || {}).value || ''
})
} else {
// get utf8 string
body = Buffer.concat(self._body).toString()
}
}
// create flattened list of headers
var headersList = []
Object.keys(headersObj).forEach(function (keyName) {
var name = headersObj[keyName].name
var value = headersObj[keyName].value
if (Array.isArray(value)) {
value.forEach(function (v) {
headersList.push([name, v])
})
} else {
headersList.push([name, value])
}
})
if (self._mode === 'fetch') {
var signal = null
if (capability.abortController) {
var controller = new AbortController()
signal = controller.signal
self._fetchAbortController = controller
if ('requestTimeout' in opts && opts.requestTimeout !== 0) {
global.setTimeout(function () {
self.emit('requestTimeout')
if (self._fetchAbortController)
self._fetchAbortController.abort()
}, opts.requestTimeout)
}
}
global.fetch(self._opts.url, {
method: self._opts.method,
headers: headersList,
body: body || undefined,
mode: 'cors',
credentials: opts.withCredentials ? 'include' : 'same-origin',
signal: signal
}).then(function (response) {
self._fetchResponse = response
self._connect()
}, function (reason) {
self.emit('error', reason)
})
} else {
var xhr = self._xhr = new global.XMLHttpRequest()
try {
xhr.open(self._opts.method, self._opts.url, true)
} catch (err) {
process.nextTick(function () {
self.emit('error', err)
})
return
}
// Can't set responseType on really old browsers
if ('responseType' in xhr)
xhr.responseType = self._mode.split(':')[0]
if ('withCredentials' in xhr)
xhr.withCredentials = !!opts.withCredentials
if (self._mode === 'text' && 'overrideMimeType' in xhr)
xhr.overrideMimeType('text/plain; charset=x-user-defined')
if ('requestTimeout' in opts) {
xhr.timeout = opts.requestTimeout
xhr.ontimeout = function () {
self.emit('requestTimeout')
}
}
headersList.forEach(function (header) {
xhr.setRequestHeader(header[0], header[1])
})
self._response = null
xhr.onreadystatechange = function () {
switch (xhr.readyState) {
case rStates.LOADING:
case rStates.DONE:
self._onXHRProgress()
break
}
}
// Necessary for streaming in Firefox, since xhr.response is ONLY defined
// in onprogress, not in onreadystatechange with xhr.readyState = 3
if (self._mode === 'moz-chunked-arraybuffer') {
xhr.onprogress = function () {
self._onXHRProgress()
}
}
xhr.onerror = function () {
if (self._destroyed)
return
self.emit('error', new Error('XHR error'))
}
try {
xhr.send(body)
} catch (err) {
process.nextTick(function () {
self.emit('error', err)
})
return
}
}
}
/**
* Checks if xhr.status is readable and non-zero, indicating no error.
* Even though the spec says it should be available in readyState 3,
* accessing it throws an exception in IE8
*/
function statusValid (xhr) {
try {
var status = xhr.status
return (status !== null && status !== 0)
} catch (e) {
return false
}
}
ClientRequest.prototype._onXHRProgress = function () {
var self = this
if (!statusValid(self._xhr) || self._destroyed)
return
if (!self._response)
self._connect()
self._response._onXHRProgress()
}
ClientRequest.prototype._connect = function () {
var self = this
if (self._destroyed)
return
self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode)
self._response.on('error', function(err) {
self.emit('error', err)
})
self.emit('response', self._response)
}
ClientRequest.prototype._write = function (chunk, encoding, cb) {
var self = this
self._body.push(chunk)
cb()
}
ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () {
var self = this
self._destroyed = true
if (self._response)
self._response._destroyed = true
if (self._xhr)
self._xhr.abort()
else if (self._fetchAbortController)
self._fetchAbortController.abort()
}
ClientRequest.prototype.end = function (data, encoding, cb) {
var self = this
if (typeof data === 'function') {
cb = data
data = undefined
}
stream.Writable.prototype.end.call(self, data, encoding, cb)
}
ClientRequest.prototype.flushHeaders = function () {}
ClientRequest.prototype.setTimeout = function () {}
ClientRequest.prototype.setNoDelay = function () {}
ClientRequest.prototype.setSocketKeepAlive = function () {}
// Taken from http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method
var unsafeHeaders = [
'accept-charset',
'accept-encoding',
'access-control-request-headers',
'access-control-request-method',
'connection',
'content-length',
'cookie',
'cookie2',
'date',
'dnt',
'expect',
'host',
'keep-alive',
'origin',
'referer',
'te',
'trailer',
'transfer-encoding',
'upgrade',
'user-agent',
'via'
]
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./capability":45,"./response":47,"_process":20,"buffer":13,"inherits":18,"readable-stream":40,"to-arraybuffer":49}],47:[function(require,module,exports){
(function (process,global,Buffer){
var capability = require('./capability')
var inherits = require('inherits')
var stream = require('readable-stream')
var rStates = exports.readyStates = {
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4
}
var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode) {
var self = this
stream.Readable.call(self)
self._mode = mode
self.headers = {}
self.rawHeaders = []
self.trailers = {}
self.rawTrailers = []
// Fake the 'close' event, but only once 'end' fires
self.on('end', function () {
// The nextTick is necessary to prevent the 'request' module from causing an infinite loop
process.nextTick(function () {
self.emit('close')
})
})
if (mode === 'fetch') {
self._fetchResponse = response
self.url = response.url
self.statusCode = response.status
self.statusMessage = response.statusText
response.headers.forEach(function (header, key){
self.headers[key.toLowerCase()] = header
self.rawHeaders.push(key, header)
})
if (capability.writableStream) {
var writable = new WritableStream({
write: function (chunk) {
return new Promise(function (resolve, reject) {
if (self._destroyed) {
return
} else if(self.push(new Buffer(chunk))) {
resolve()
} else {
self._resumeFetch = resolve
}
})
},
close: function () {
if (!self._destroyed)
self.push(null)
},
abort: function (err) {
if (!self._destroyed)
self.emit('error', err)
}
})
try {
response.body.pipeTo(writable)
return
} catch (e) {} // pipeTo method isn't defined. Can't find a better way to feature test this
}
// fallback for when writableStream or pipeTo aren't available
var reader = response.body.getReader()
function read () {
reader.read().then(function (result) {
if (self._destroyed)
return
if (result.done) {
self.push(null)
return
}
self.push(new Buffer(result.value))
read()
}).catch(function(err) {
if (!self._destroyed)
self.emit('error', err)
})
}
read()
} else {
self._xhr = xhr
self._pos = 0
self.url = xhr.responseURL
self.statusCode = xhr.status
self.statusMessage = xhr.statusText
var headers = xhr.getAllResponseHeaders().split(/\r?\n/)
headers.forEach(function (header) {
var matches = header.match(/^([^:]+):\s*(.*)/)
if (matches) {
var key = matches[1].toLowerCase()
if (key === 'set-cookie') {
if (self.headers[key] === undefined) {
self.headers[key] = []
}
self.headers[key].push(matches[2])
} else if (self.headers[key] !== undefined) {
self.headers[key] += ', ' + matches[2]
} else {
self.headers[key] = matches[2]
}
self.rawHeaders.push(matches[1], matches[2])
}
})
self._charset = 'x-user-defined'
if (!capability.overrideMimeType) {
var mimeType = self.rawHeaders['mime-type']
if (mimeType) {
var charsetMatch = mimeType.match(/;\s*charset=([^;])(;|$)/)
if (charsetMatch) {
self._charset = charsetMatch[1].toLowerCase()
}
}
if (!self._charset)
self._charset = 'utf-8' // best guess
}
}
}
inherits(IncomingMessage, stream.Readable)
IncomingMessage.prototype._read = function () {
var self = this
var resolve = self._resumeFetch
if (resolve) {
self._resumeFetch = null
resolve()
}
}
IncomingMessage.prototype._onXHRProgress = function () {
var self = this
var xhr = self._xhr
var response = null
switch (self._mode) {
case 'text:vbarray': // For IE9
if (xhr.readyState !== rStates.DONE)
break
try {
// This fails in IE8
response = new global.VBArray(xhr.responseBody).toArray()
} catch (e) {}
if (response !== null) {
self.push(new Buffer(response))
break
}
// Falls through in IE8
case 'text':
try { // This will fail when readyState = 3 in IE9. Switch mode and wait for readyState = 4
response = xhr.responseText
} catch (e) {
self._mode = 'text:vbarray'
break
}
if (response.length > self._pos) {
var newData = response.substr(self._pos)
if (self._charset === 'x-user-defined') {
var buffer = new Buffer(newData.length)
for (var i = 0; i < newData.length; i++)
buffer[i] = newData.charCodeAt(i) & 0xff
self.push(buffer)
} else {
self.push(newData, self._charset)
}
self._pos = response.length
}
break
case 'arraybuffer':
if (xhr.readyState !== rStates.DONE || !xhr.response)
break
response = xhr.response
self.push(new Buffer(new Uint8Array(response)))
break
case 'moz-chunked-arraybuffer': // take whole
response = xhr.response
if (xhr.readyState !== rStates.LOADING || !response)
break
self.push(new Buffer(new Uint8Array(response)))
break
case 'ms-stream':
response = xhr.response
if (xhr.readyState !== rStates.LOADING)
break
var reader = new global.MSStreamReader()
reader.onprogress = function () {
if (reader.result.byteLength > self._pos) {
self.push(new Buffer(new Uint8Array(reader.result.slice(self._pos))))
self._pos = reader.result.byteLength
}
}
reader.onload = function () {
self.push(null)
}
// reader.onerror = ??? // TODO: this
reader.readAsArrayBuffer(response)
break
}
// The ms-stream case handles end separately in reader.onload()
if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') {
self.push(null)
}
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./capability":45,"_process":20,"buffer":13,"inherits":18,"readable-stream":40}],48:[function(require,module,exports){
module.exports = {
"100": "Continue",
"101": "Switching Protocols",
"102": "Processing",
"200": "OK",
"201": "Created",
"202": "Accepted",
"203": "Non-Authoritative Information",
"204": "No Content",
"205": "Reset Content",
"206": "Partial Content",
"207": "Multi-Status",
"208": "Already Reported",
"226": "IM Used",
"300": "Multiple Choices",
"301": "Moved Permanently",
"302": "Found",
"303": "See Other",
"304": "Not Modified",
"305": "Use Proxy",
"307": "Temporary Redirect",
"308": "Permanent Redirect",
"400": "Bad Request",
"401": "Unauthorized",
"402": "Payment Required",
"403": "Forbidden",
"404": "Not Found",
"405": "Method Not Allowed",
"406": "Not Acceptable",
"407": "Proxy Authentication Required",
"408": "Request Timeout",
"409": "Conflict",
"410": "Gone",
"411": "Length Required",
"412": "Precondition Failed",
"413": "Payload Too Large",
"414": "URI Too Long",
"415": "Unsupported Media Type",
"416": "Range Not Satisfiable",
"417": "Expectation Failed",
"418": "I'm a teapot",
"421": "Misdirected Request",
"422": "Unprocessable Entity",
"423": "Locked",
"424": "Failed Dependency",
"425": "Unordered Collection",
"426": "Upgrade Required",
"428": "Precondition Required",
"429": "Too Many Requests",
"431": "Request Header Fields Too Large",
"451": "Unavailable For Legal Reasons",
"500": "Internal Server Error",
"501": "Not Implemented",
"502": "Bad Gateway",
"503": "Service Unavailable",
"504": "Gateway Timeout",
"505": "HTTP Version Not Supported",
"506": "Variant Also Negotiates",
"507": "Insufficient Storage",
"508": "Loop Detected",
"509": "Bandwidth Limit Exceeded",
"510": "Not Extended",
"511": "Network Authentication Required"
}
},{}],49:[function(require,module,exports){
var Buffer = require('buffer').Buffer
module.exports = function (buf) {
// If the buffer is backed by a Uint8Array, a faster version will work
if (buf instanceof Uint8Array) {
// If the buffer isn't a subarray, return the underlying ArrayBuffer
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
return buf.buffer
} else if (typeof buf.buffer.slice === 'function') {
// Otherwise we need to get a proper copy
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
}
}
if (Buffer.isBuffer(buf)) {
// This is the slow version that will work with any Buffer
// implementation (even in old browsers)
var arrayCopy = new Uint8Array(buf.length)
var len = buf.length
for (var i = 0; i < len; i++) {
arrayCopy[i] = buf[i]
}
return arrayCopy.buffer
} else {
throw new Error('Argument must be a Buffer')
}
}
},{"buffer":13}],50:[function(require,module,exports){
'use strict';
var Buffer = require('safe-buffer').Buffer;
var isEncoding = Buffer.isEncoding || function (encoding) {
encoding = '' + encoding;
switch (encoding && encoding.toLowerCase()) {
case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':
return true;
default:
return false;
}
};
function _normalizeEncoding(enc) {
if (!enc) return 'utf8';
var retried;
while (true) {
switch (enc) {
case 'utf8':
case 'utf-8':
return 'utf8';
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return 'utf16le';
case 'latin1':
case 'binary':
return 'latin1';
case 'base64':
case 'ascii':
case 'hex':
return enc;
default:
if (retried) return; // undefined
enc = ('' + enc).toLowerCase();
retried = true;
}
}
};
// Do not cache `Buffer.isEncoding` when checking encoding names as some
// modules monkey-patch it to support additional encodings
function normalizeEncoding(enc) {
var nenc = _normalizeEncoding(enc);
if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
return nenc || enc;
}
// StringDecoder provides an interface for efficiently splitting a series of
// buffers into a series of JS strings without breaking apart multi-byte
// characters.
exports.StringDecoder = StringDecoder;
function StringDecoder(encoding) {
this.encoding = normalizeEncoding(encoding);
var nb;
switch (this.encoding) {
case 'utf16le':
this.text = utf16Text;
this.end = utf16End;
nb = 4;
break;
case 'utf8':
this.fillLast = utf8FillLast;
nb = 4;
break;
case 'base64':
this.text = base64Text;
this.end = base64End;
nb = 3;
break;
default:
this.write = simpleWrite;
this.end = simpleEnd;
return;
}
this.lastNeed = 0;
this.lastTotal = 0;
this.lastChar = Buffer.allocUnsafe(nb);
}
StringDecoder.prototype.write = function (buf) {
if (buf.length === 0) return '';
var r;
var i;
if (this.lastNeed) {
r = this.fillLast(buf);
if (r === undefined) return '';
i = this.lastNeed;
this.lastNeed = 0;
} else {
i = 0;
}
if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
return r || '';
};
StringDecoder.prototype.end = utf8End;
// Returns only complete characters in a Buffer
StringDecoder.prototype.text = utf8Text;
// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
StringDecoder.prototype.fillLast = function (buf) {
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
this.lastNeed -= buf.length;
};
// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
// continuation byte.
function utf8CheckByte(byte) {
if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;
return -1;
}
// Checks at most 3 bytes at the end of a Buffer in order to detect an
// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
// needed to complete the UTF-8 character (if applicable) are returned.
function utf8CheckIncomplete(self, buf, i) {
var j = buf.length - 1;
if (j < i) return 0;
var nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 1;
return nb;
}
if (--j < i) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 2;
return nb;
}
if (--j < i) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) {
if (nb === 2) nb = 0;else self.lastNeed = nb - 3;
}
return nb;
}
return 0;
}
// Validates as many continuation bytes for a multi-byte UTF-8 character as
// needed or are available. If we see a non-continuation byte where we expect
// one, we "replace" the validated continuation bytes we've seen so far with
// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding
// behavior. The continuation byte check is included three times in the case
// where all of the continuation bytes for a character exist in the same buffer.
// It is also done this way as a slight performance increase instead of using a
// loop.
function utf8CheckExtraBytes(self, buf, p) {
if ((buf[0] & 0xC0) !== 0x80) {
self.lastNeed = 0;
return '\ufffd'.repeat(p);
}
if (self.lastNeed > 1 && buf.length > 1) {
if ((buf[1] & 0xC0) !== 0x80) {
self.lastNeed = 1;
return '\ufffd'.repeat(p + 1);
}
if (self.lastNeed > 2 && buf.length > 2) {
if ((buf[2] & 0xC0) !== 0x80) {
self.lastNeed = 2;
return '\ufffd'.repeat(p + 2);
}
}
}
}
// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
function utf8FillLast(buf) {
var p = this.lastTotal - this.lastNeed;
var r = utf8CheckExtraBytes(this, buf, p);
if (r !== undefined) return r;
if (this.lastNeed <= buf.length) {
buf.copy(this.lastChar, p, 0, this.lastNeed);
return this.lastChar.toString(this.encoding, 0, this.lastTotal);
}
buf.copy(this.lastChar, p, 0, buf.length);
this.lastNeed -= buf.length;
}
// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
// partial character, the character's bytes are buffered until the required
// number of bytes are available.
function utf8Text(buf, i) {
var total = utf8CheckIncomplete(this, buf, i);
if (!this.lastNeed) return buf.toString('utf8', i);
this.lastTotal = total;
var end = buf.length - (total - this.lastNeed);
buf.copy(this.lastChar, 0, end);
return buf.toString('utf8', i, end);
}
// For UTF-8, a replacement character for each buffered byte of a (partial)
// character needs to be added to the output.
function utf8End(buf) {
var r = buf && buf.length ? this.write(buf) : '';
if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed);
return r;
}
// UTF-16LE typically needs two bytes per character, but even if we have an even
// number of bytes available, we need to check if we end on a leading/high
// surrogate. In that case, we need to wait for the next two bytes in order to
// decode the last character properly.
function utf16Text(buf, i) {
if ((buf.length - i) % 2 === 0) {
var r = buf.toString('utf16le', i);
if (r) {
var c = r.charCodeAt(r.length - 1);
if (c >= 0xD800 && c <= 0xDBFF) {
this.lastNeed = 2;
this.lastTotal = 4;
this.lastChar[0] = buf[buf.length - 2];
this.lastChar[1] = buf[buf.length - 1];
return r.slice(0, -1);
}
}
return r;
}
this.lastNeed = 1;
this.lastTotal = 2;
this.lastChar[0] = buf[buf.length - 1];
return buf.toString('utf16le', i, buf.length - 1);
}
// For UTF-16LE we do not explicitly append special replacement characters if we
// end on a partial character, we simply let v8 handle that.
function utf16End(buf) {
var r = buf && buf.length ? this.write(buf) : '';
if (this.lastNeed) {
var end = this.lastTotal - this.lastNeed;
return r + this.lastChar.toString('utf16le', 0, end);
}
return r;
}
function base64Text(buf, i) {
var n = (buf.length - i) % 3;
if (n === 0) return buf.toString('base64', i);
this.lastNeed = 3 - n;
this.lastTotal = 3;
if (n === 1) {
this.lastChar[0] = buf[buf.length - 1];
} else {
this.lastChar[0] = buf[buf.length - 2];
this.lastChar[1] = buf[buf.length - 1];
}
return buf.toString('base64', i, buf.length - n);
}
function base64End(buf) {
var r = buf && buf.length ? this.write(buf) : '';
if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
return r;
}
// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
function simpleWrite(buf) {
return buf.toString(this.encoding);
}
function simpleEnd(buf) {
return buf && buf.length ? this.write(buf) : '';
}
},{"safe-buffer":51}],51:[function(require,module,exports){
arguments[4][37][0].apply(exports,arguments)
},{"buffer":13,"dup":37}],52:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
var punycode = require('punycode');
var util = require('./util');
exports.parse = urlParse;
exports.resolve = urlResolve;
exports.resolveObject = urlResolveObject;
exports.format = urlFormat;
exports.Url = Url;
function Url() {
this.protocol = null;
this.slashes = null;
this.auth = null;
this.host = null;
this.port = null;
this.hostname = null;
this.hash = null;
this.search = null;
this.query = null;
this.pathname = null;
this.path = null;
this.href = null;
}
// Reference: RFC 3986, RFC 1808, RFC 2396
// define these here so at least they only have to be
// compiled once on the first module load.
var protocolPattern = /^([a-z0-9.+-]+:)/i,
portPattern = /:[0-9]*$/,
// Special case for a simple path URL
simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
// RFC 2396: characters reserved for delimiting URLs.
// We actually just auto-escape these.
delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
// RFC 2396: characters not allowed for various reasons.
unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
// Allowed by RFCs, but cause of XSS attacks. Always escape these.
autoEscape = ['\''].concat(unwise),
// Characters that are never ever allowed in a hostname.
// Note that any invalid chars are also handled, but these
// are the ones that are *expected* to be seen, so we fast-path
// them.
nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
hostEndingChars = ['/', '?', '#'],
hostnameMaxLen = 255,
hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
// protocols that can allow "unsafe" and "unwise" chars.
unsafeProtocol = {
'javascript': true,
'javascript:': true
},
// protocols that never have a hostname.
hostlessProtocol = {
'javascript': true,
'javascript:': true
},
// protocols that always contain a // bit.
slashedProtocol = {
'http': true,
'https': true,
'ftp': true,
'gopher': true,
'file': true,
'http:': true,
'https:': true,
'ftp:': true,
'gopher:': true,
'file:': true
},
querystring = require('querystring');
function urlParse(url, parseQueryString, slashesDenoteHost) {
if (url && util.isObject(url) && url instanceof Url) return url;
var u = new Url;
u.parse(url, parseQueryString, slashesDenoteHost);
return u;
}
Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
if (!util.isString(url)) {
throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
}
// Copy chrome, IE, opera backslash-handling behavior.
// Back slashes before the query string get converted to forward slashes
// See: https://code.google.com/p/chromium/issues/detail?id=25916
var queryIndex = url.indexOf('?'),
splitter =
(queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
uSplit = url.split(splitter),
slashRegex = /\\/g;
uSplit[0] = uSplit[0].replace(slashRegex, '/');
url = uSplit.join(splitter);
var rest = url;
// trim before proceeding.
// This is to support parse stuff like " http://foo.com \n"
rest = rest.trim();
if (!slashesDenoteHost && url.split('#').length === 1) {
// Try fast path regexp
var simplePath = simplePathPattern.exec(rest);
if (simplePath) {
this.path = rest;
this.href = rest;
this.pathname = simplePath[1];
if (simplePath[2]) {
this.search = simplePath[2];
if (parseQueryString) {
this.query = querystring.parse(this.search.substr(1));
} else {
this.query = this.search.substr(1);
}
} else if (parseQueryString) {
this.search = '';
this.query = {};
}
return this;
}
}
var proto = protocolPattern.exec(rest);
if (proto) {
proto = proto[0];
var lowerProto = proto.toLowerCase();
this.protocol = lowerProto;
rest = rest.substr(proto.length);
}
// figure out if it's got a host
// user@server is *always* interpreted as a hostname, and url
// resolution will treat //foo/bar as host=foo,path=bar because that's
// how the browser resolves relative URLs.
if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
var slashes = rest.substr(0, 2) === '//';
if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.substr(2);
this.slashes = true;
}
}
if (!hostlessProtocol[proto] &&
(slashes || (proto && !slashedProtocol[proto]))) {
// there's a hostname.
// the first instance of /, ?, ;, or # ends the host.
//
// If there is an @ in the hostname, then non-host chars *are* allowed
// to the left of the last @ sign, unless some host-ending character
// comes *before* the @-sign.
// URLs are obnoxious.
//
// ex:
// http://a@b@c/ => user:a@b host:c
// http://a@b?@c => user:a host:c path:/?@c
// v0.12 TODO(isaacs): This is not quite how Chrome does things.
// Review our test case against browsers more comprehensively.
// find the first instance of any hostEndingChars
var hostEnd = -1;
for (var i = 0; i < hostEndingChars.length; i++) {
var hec = rest.indexOf(hostEndingChars[i]);
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
hostEnd = hec;
}
// at this point, either we have an explicit point where the
// auth portion cannot go past, or the last @ char is the decider.
var auth, atSign;
if (hostEnd === -1) {
// atSign can be anywhere.
atSign = rest.lastIndexOf('@');
} else {
// atSign must be in auth portion.
// http://a@b/c@d => host:b auth:a path:/c@d
atSign = rest.lastIndexOf('@', hostEnd);
}
// Now we have a portion which is definitely the auth.
// Pull that off.
if (atSign !== -1) {
auth = rest.slice(0, atSign);
rest = rest.slice(atSign + 1);
this.auth = decodeURIComponent(auth);
}
// the host is the remaining to the left of the first non-host char
hostEnd = -1;
for (var i = 0; i < nonHostChars.length; i++) {
var hec = rest.indexOf(nonHostChars[i]);
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
hostEnd = hec;
}
// if we still have not hit it, then the entire thing is a host.
if (hostEnd === -1)
hostEnd = rest.length;
this.host = rest.slice(0, hostEnd);
rest = rest.slice(hostEnd);
// pull out port.
this.parseHost();
// we've indicated that there is a hostname,
// so even if it's empty, it has to be present.
this.hostname = this.hostname || '';
// if hostname begins with [ and ends with ]
// assume that it's an IPv6 address.
var ipv6Hostname = this.hostname[0] === '[' &&
this.hostname[this.hostname.length - 1] === ']';
// validate a little.
if (!ipv6Hostname) {
var hostparts = this.hostname.split(/\./);
for (var i = 0, l = hostparts.length; i < l; i++) {
var part = hostparts[i];
if (!part) continue;
if (!part.match(hostnamePartPattern)) {
var newpart = '';
for (var j = 0, k = part.length; j < k; j++) {
if (part.charCodeAt(j) > 127) {
// we replace non-ASCII char with a temporary placeholder
// we need this to make sure size of hostname is not
// broken by replacing non-ASCII by nothing
newpart += 'x';
} else {
newpart += part[j];
}
}
// we test again with ASCII char only
if (!newpart.match(hostnamePartPattern)) {
var validParts = hostparts.slice(0, i);
var notHost = hostparts.slice(i + 1);
var bit = part.match(hostnamePartStart);
if (bit) {
validParts.push(bit[1]);
notHost.unshift(bit[2]);
}
if (notHost.length) {
rest = '/' + notHost.join('.') + rest;
}
this.hostname = validParts.join('.');
break;
}
}
}
}
if (this.hostname.length > hostnameMaxLen) {
this.hostname = '';
} else {
// hostnames are always lower case.
this.hostname = this.hostname.toLowerCase();
}
if (!ipv6Hostname) {
// IDNA Support: Returns a punycoded representation of "domain".
// It only converts parts of the domain name that
// have non-ASCII characters, i.e. it doesn't matter if
// you call it with a domain that already is ASCII-only.
this.hostname = punycode.toASCII(this.hostname);
}
var p = this.port ? ':' + this.port : '';
var h = this.hostname || '';
this.host = h + p;
this.href += this.host;
// strip [ and ] from the hostname
// the host field still retains them, though
if (ipv6Hostname) {
this.hostname = this.hostname.substr(1, this.hostname.length - 2);
if (rest[0] !== '/') {
rest = '/' + rest;
}
}
}
// now rest is set to the post-host stuff.
// chop off any delim chars.
if (!unsafeProtocol[lowerProto]) {
// First, make 100% sure that any "autoEscape" chars get
// escaped, even if encodeURIComponent doesn't think they
// need to be.
for (var i = 0, l = autoEscape.length; i < l; i++) {
var ae = autoEscape[i];
if (rest.indexOf(ae) === -1)
continue;
var esc = encodeURIComponent(ae);
if (esc === ae) {
esc = escape(ae);
}
rest = rest.split(ae).join(esc);
}
}
// chop off from the tail first.
var hash = rest.indexOf('#');
if (hash !== -1) {
// got a fragment string.
this.hash = rest.substr(hash);
rest = rest.slice(0, hash);
}
var qm = rest.indexOf('?');
if (qm !== -1) {
this.search = rest.substr(qm);
this.query = rest.substr(qm + 1);
if (parseQueryString) {
this.query = querystring.parse(this.query);
}
rest = rest.slice(0, qm);
} else if (parseQueryString) {
// no query string, but parseQueryString still requested
this.search = '';
this.query = {};
}
if (rest) this.pathname = rest;
if (slashedProtocol[lowerProto] &&
this.hostname && !this.pathname) {
this.pathname = '/';
}
//to support http.request
if (this.pathname || this.search) {
var p = this.pathname || '';
var s = this.search || '';
this.path = p + s;
}
// finally, reconstruct the href based on what has been validated.
this.href = this.format();
return this;
};
// format a parsed object into a url string
function urlFormat(obj) {
// ensure it's an object, and not a string url.
// If it's an obj, this is a no-op.
// this way, you can call url_format() on strings
// to clean up potentially wonky urls.
if (util.isString(obj)) obj = urlParse(obj);
if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
return obj.format();
}
Url.prototype.format = function() {
var auth = this.auth || '';
if (auth) {
auth = encodeURIComponent(auth);
auth = auth.replace(/%3A/i, ':');
auth += '@';
}
var protocol = this.protocol || '',
pathname = this.pathname || '',
hash = this.hash || '',
host = false,
query = '';
if (this.host) {
host = auth + this.host;
} else if (this.hostname) {
host = auth + (this.hostname.indexOf(':') === -1 ?
this.hostname :
'[' + this.hostname + ']');
if (this.port) {
host += ':' + this.port;
}
}
if (this.query &&
util.isObject(this.query) &&
Object.keys(this.query).length) {
query = querystring.stringify(this.query);
}
var search = this.search || (query && ('?' + query)) || '';
if (protocol && protocol.substr(-1) !== ':') protocol += ':';
// only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
// unless they had them to begin with.
if (this.slashes ||
(!protocol || slashedProtocol[protocol]) && host !== false) {
host = '//' + (host || '');
if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
} else if (!host) {
host = '';
}
if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
if (search && search.charAt(0) !== '?') search = '?' + search;
pathname = pathname.replace(/[?#]/g, function(match) {
return encodeURIComponent(match);
});
search = search.replace('#', '%23');
return protocol + host + pathname + search + hash;
};
function urlResolve(source, relative) {
return urlParse(source, false, true).resolve(relative);
}
Url.prototype.resolve = function(relative) {
return this.resolveObject(urlParse(relative, false, true)).format();
};
function urlResolveObject(source, relative) {
if (!source) return relative;
return urlParse(source, false, true).resolveObject(relative);
}
Url.prototype.resolveObject = function(relative) {
if (util.isString(relative)) {
var rel = new Url();
rel.parse(relative, false, true);
relative = rel;
}
var result = new Url();
var tkeys = Object.keys(this);
for (var tk = 0; tk < tkeys.length; tk++) {
var tkey = tkeys[tk];
result[tkey] = this[tkey];
}
// hash is always overridden, no matter what.
// even href="" will remove it.
result.hash = relative.hash;
// if the relative url is empty, then there's nothing left to do here.
if (relative.href === '') {
result.href = result.format();
return result;
}
// hrefs like //foo/bar always cut to the protocol.
if (relative.slashes && !relative.protocol) {
// take everything except the protocol from relative
var rkeys = Object.keys(relative);
for (var rk = 0; rk < rkeys.length; rk++) {
var rkey = rkeys[rk];
if (rkey !== 'protocol')
result[rkey] = relative[rkey];
}
//urlParse appends trailing / to urls like http://www.example.com
if (slashedProtocol[result.protocol] &&
result.hostname && !result.pathname) {
result.path = result.pathname = '/';
}
result.href = result.format();
return result;
}
if (relative.protocol && relative.protocol !== result.protocol) {
// if it's a known url protocol, then changing
// the protocol does weird things
// first, if it's not file:, then we MUST have a host,
// and if there was a path
// to begin with, then we MUST have a path.
// if it is file:, then the host is dropped,
// because that's known to be hostless.
// anything else is assumed to be absolute.
if (!slashedProtocol[relative.protocol]) {
var keys = Object.keys(relative);
for (var v = 0; v < keys.length; v++) {
var k = keys[v];
result[k] = relative[k];
}
result.href = result.format();
return result;
}
result.protocol = relative.protocol;
if (!relative.host && !hostlessProtocol[relative.protocol]) {
var relPath = (relative.pathname || '').split('/');
while (relPath.length && !(relative.host = relPath.shift()));
if (!relative.host) relative.host = '';
if (!relative.hostname) relative.hostname = '';
if (relPath[0] !== '') relPath.unshift('');
if (relPath.length < 2) relPath.unshift('');
result.pathname = relPath.join('/');
} else {
result.pathname = relative.pathname;
}
result.search = relative.search;
result.query = relative.query;
result.host = relative.host || '';
result.auth = relative.auth;
result.hostname = relative.hostname || relative.host;
result.port = relative.port;
// to support http.request
if (result.pathname || result.search) {
var p = result.pathname || '';
var s = result.search || '';
result.path = p + s;
}
result.slashes = result.slashes || relative.slashes;
result.href = result.format();
return result;
}
var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
isRelAbs = (
relative.host ||
relative.pathname && relative.pathname.charAt(0) === '/'
),
mustEndAbs = (isRelAbs || isSourceAbs ||
(result.host && relative.pathname)),
removeAllDots = mustEndAbs,
srcPath = result.pathname && result.pathname.split('/') || [],
relPath = relative.pathname && relative.pathname.split('/') || [],
psychotic = result.protocol && !slashedProtocol[result.protocol];
// if the url is a non-slashed url, then relative
// links like ../.. should be able
// to crawl up to the hostname, as well. This is strange.
// result.protocol has already been set by now.
// Later on, put the first path part into the host field.
if (psychotic) {
result.hostname = '';
result.port = null;
if (result.host) {
if (srcPath[0] === '') srcPath[0] = result.host;
else srcPath.unshift(result.host);
}
result.host = '';
if (relative.protocol) {
relative.hostname = null;
relative.port = null;
if (relative.host) {
if (relPath[0] === '') relPath[0] = relative.host;
else relPath.unshift(relative.host);
}
relative.host = null;
}
mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
}
if (isRelAbs) {
// it's absolute.
result.host = (relative.host || relative.host === '') ?
relative.host : result.host;
result.hostname = (relative.hostname || relative.hostname === '') ?
relative.hostname : result.hostname;
result.search = relative.search;
result.query = relative.query;
srcPath = relPath;
// fall through to the dot-handling below.
} else if (relPath.length) {
// it's relative
// throw away the existing file, and take the new path instead.
if (!srcPath) srcPath = [];
srcPath.pop();
srcPath = srcPath.concat(relPath);
result.search = relative.search;
result.query = relative.query;
} else if (!util.isNullOrUndefined(relative.search)) {
// just pull out the search.
// like href='?foo'.
// Put this after the other two cases because it simplifies the booleans
if (psychotic) {
result.hostname = result.host = srcPath.shift();
//occationaly the auth can get stuck only in host
//this especially happens in cases like
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
var authInHost = result.host && result.host.indexOf('@') > 0 ?
result.host.split('@') : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
result.search = relative.search;
result.query = relative.query;
//to support http.request
if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}
result.href = result.format();
return result;
}
if (!srcPath.length) {
// no path at all. easy.
// we've already handled the other stuff above.
result.pathname = null;
//to support http.request
if (result.search) {
result.path = '/' + result.search;
} else {
result.path = null;
}
result.href = result.format();
return result;
}
// if a url ENDs in . or .., then it must get a trailing slash.
// however, if it ends in anything else non-slashy,
// then it must NOT get a trailing slash.
var last = srcPath.slice(-1)[0];
var hasTrailingSlash = (
(result.host || relative.host || srcPath.length > 1) &&
(last === '.' || last === '..') || last === '');
// strip single dots, resolve double dots to parent dir
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = srcPath.length; i >= 0; i--) {
last = srcPath[i];
if (last === '.') {
srcPath.splice(i, 1);
} else if (last === '..') {
srcPath.splice(i, 1);
up++;
} else if (up) {
srcPath.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (!mustEndAbs && !removeAllDots) {
for (; up--; up) {
srcPath.unshift('..');
}
}
if (mustEndAbs && srcPath[0] !== '' &&
(!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
srcPath.unshift('');
}
if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
srcPath.push('');
}
var isAbsolute = srcPath[0] === '' ||
(srcPath[0] && srcPath[0].charAt(0) === '/');
// put the host back
if (psychotic) {
result.hostname = result.host = isAbsolute ? '' :
srcPath.length ? srcPath.shift() : '';
//occationaly the auth can get stuck only in host
//this especially happens in cases like
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
var authInHost = result.host && result.host.indexOf('@') > 0 ?
result.host.split('@') : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
mustEndAbs = mustEndAbs || (result.host && srcPath.length);
if (mustEndAbs && !isAbsolute) {
srcPath.unshift('');
}
if (!srcPath.length) {
result.pathname = null;
result.path = null;
} else {
result.pathname = srcPath.join('/');
}
//to support request.http
if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}
result.auth = relative.auth || result.auth;
result.slashes = result.slashes || relative.slashes;
result.href = result.format();
return result;
};
Url.prototype.parseHost = function() {
var host = this.host;
var port = portPattern.exec(host);
if (port) {
port = port[0];
if (port !== ':') {
this.port = port.substr(1);
}
host = host.substr(0, host.length - port.length);
}
if (host) this.hostname = host;
};
},{"./util":53,"punycode":21,"querystring":24}],53:[function(require,module,exports){
'use strict';
module.exports = {
isString: function(arg) {
return typeof(arg) === 'string';
},
isObject: function(arg) {
return typeof(arg) === 'object' && arg !== null;
},
isNull: function(arg) {
return arg === null;
},
isNullOrUndefined: function(arg) {
return arg == null;
}
};
},{}],54:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"dup":18}],55:[function(require,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],56:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('./support/isBuffer');
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = require('inherits');
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./support/isBuffer":55,"_process":20,"inherits":54}],57:[function(require,module,exports){
module.exports = extend
var hasOwnProperty = Object.prototype.hasOwnProperty;
function extend() {
var target = {}
for (var i = 0; i < arguments.length; i++) {
var source = arguments[i]
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
target[key] = source[key]
}
}
}
return target
}
},{}],58:[function(require,module,exports){
"use strict";
var Shim = require("./shim");
var GenericCollection = require("./generic-collection");
var GenericMap = require("./generic-map");
// Burgled from https://github.com/domenic/dict
module.exports = Dict;
function Dict(values, getDefault) {
if (!(this instanceof Dict)) {
return new Dict(values, getDefault);
}
getDefault = getDefault || Function.noop;
this.getDefault = getDefault;
this.store = Object.create(null);
this.length = 0;
this.addEach(values);
}
Dict.Dict = Dict; // hack so require("dict").Dict will work in MontageJS.
Object.addEach(Dict.prototype, GenericCollection.prototype);
Object.addEach(Dict.prototype, GenericMap.prototype);
Dict.from = GenericCollection.from;
Dict.prototype.constructClone = function (values) {
return new this.constructor(values, this.getDefault);
};
Dict.prototype.assertString = function (key) {
if (typeof key !== "string") {
throw new TypeError("key must be a string but Got " + key);
}
}
Object.defineProperty(Dict.prototype,"$__proto__",{writable:true});
Object.defineProperty(Dict.prototype,"_hasProto",{
get:function() {
return this.hasOwnProperty("$__proto__") && typeof this._protoValue !== "undefined";
}
});
Object.defineProperty(Dict.prototype,"_protoValue",{
get:function() {
return this["$__proto__"];
},
set: function(value) {
this["$__proto__"] = value;
}
});
Object.defineProperty(Dict.prototype,"size",GenericCollection._sizePropertyDescriptor);
Dict.prototype.get = function (key, defaultValue) {
this.assertString(key);
if (key === "__proto__") {
if (this._hasProto) {
return this._protoValue;
} else if (arguments.length > 1) {
return defaultValue;
} else {
return this.getDefault(key);
}
}
else {
if (key in this.store) {
return this.store[key];
} else if (arguments.length > 1) {
return defaultValue;
} else {
return this.getDefault(key);
}
}
};
Dict.prototype.set = function (key, value) {
this.assertString(key);
var isProtoKey = (key === "__proto__");
if (isProtoKey ? this._hasProto : key in this.store) { // update
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, isProtoKey ? this._protoValue : this.store[key]);
}
isProtoKey
? this._protoValue = value
: this.store[key] = value;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
return false;
} else { // create
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, undefined);
}
this.length++;
isProtoKey
? this._protoValue = value
: this.store[key] = value;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
return true;
}
};
Dict.prototype.has = function (key) {
this.assertString(key);
return key === "__proto__" ? this._hasProto : key in this.store;
};
Dict.prototype["delete"] = function (key) {
this.assertString(key);
if (key === "__proto__") {
if (this._hasProto) {
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, this._protoValue);
}
this._protoValue = undefined;
this.length--;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, undefined);
}
return true;
}
return false;
}
else {
if (key in this.store) {
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, this.store[key]);
}
delete this.store[key];
this.length--;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, undefined);
}
return true;
}
return false;
}
};
Dict.prototype.clear = function () {
var key;
if (this._hasProto) {
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange("__proto__", this._protoValue);
}
this._protoValue = undefined;
if (this.dispatchesMapChanges) {
this.dispatchMapChange("__proto__", undefined);
}
}
for (key in this.store) {
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, this.store[key]);
}
delete this.store[key];
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, undefined);
}
}
this.length = 0;
};
Dict.prototype.reduce = function (callback, basis, thisp) {
if(this._hasProto) {
basis = callback.call(thisp, basis, "$__proto__", "__proto__", this);
}
var store = this.store;
for (var key in this.store) {
basis = callback.call(thisp, basis, store[key], key, this);
}
return basis;
};
Dict.prototype.reduceRight = function (callback, basis, thisp) {
var self = this;
var store = this.store;
basis = Object.keys(this.store).reduceRight(function (basis, key) {
return callback.call(thisp, basis, store[key], key, self);
}, basis);
if(this._hasProto) {
return callback.call(thisp, basis, this._protoValue, "__proto__", self);
}
return basis;
};
Dict.prototype.one = function () {
var key;
for (key in this.store) {
return this.store[key];
}
return this._protoValue;
};
Dict.prototype.toJSON = function () {
return this.toObject();
};
},{"./generic-collection":64,"./generic-map":65,"./shim":78}],59:[function(require,module,exports){
"use strict";
var Shim = require("./shim");
var Dict = require("./_dict");
var List = require("./_list");
var GenericCollection = require("./generic-collection");
var GenericSet = require("./generic-set");
var TreeLog = require("./tree-log");
var object_has = Object.prototype.hasOwnProperty;
module.exports = FastSet;
function FastSet(values, equals, hash, getDefault) {
if (!(this instanceof FastSet)) {
return new FastSet(values, equals, hash, getDefault);
}
equals = equals || Object.equals;
hash = hash || Object.hash;
getDefault = getDefault || Function.noop;
this.contentEquals = equals;
this.contentHash = hash;
this.getDefault = getDefault;
var self = this;
this.buckets = new this.Buckets(null, function getDefaultBucket() {
return new self.Bucket();
});
this.length = 0;
this.addEach(values);
}
FastSet.FastSet = FastSet; // hack so require("fast-set").FastSet will work in MontageJS
Object.addEach(FastSet.prototype, GenericCollection.prototype);
Object.addEach(FastSet.prototype, GenericSet.prototype);
FastSet.from = GenericCollection.from;
FastSet.prototype.Buckets = Dict;
FastSet.prototype.Bucket = List;
FastSet.prototype.constructClone = function (values) {
return new this.constructor(
values,
this.contentEquals,
this.contentHash,
this.getDefault
);
};
FastSet.prototype.has = function (value) {
var hash = this.contentHash(value);
return this.buckets.get(hash).has(value);
};
FastSet.prototype.get = function (value, equals) {
if (equals) {
throw new Error("FastSet#get does not support second argument: equals");
}
var hash = this.contentHash(value);
var buckets = this.buckets;
if (buckets.has(hash)) {
return buckets.get(hash).get(value);
} else {
return this.getDefault(value);
}
};
FastSet.prototype["delete"] = function (value, equals) {
if (equals) {
throw new Error("FastSet#delete does not support second argument: equals");
}
var hash = this.contentHash(value);
var buckets = this.buckets;
if (buckets.has(hash)) {
var bucket = buckets.get(hash);
if (bucket["delete"](value)) {
this.length--;
if (bucket.length === 0) {
buckets["delete"](hash);
}
return true;
}
}
return false;
};
FastSet.prototype.clear = function () {
this.buckets.clear();
this.length = 0;
};
FastSet.prototype.add = function (value) {
var hash = this.contentHash(value);
var buckets = this.buckets;
if (!buckets.has(hash)) {
buckets.set(hash, new this.Bucket(null, this.contentEquals));
}
if (!buckets.get(hash).has(value)) {
buckets.get(hash).add(value);
this.length++;
return true;
}
return false;
};
FastSet.prototype.reduce = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var buckets = this.buckets;
var index = 0;
return buckets.reduce(function (basis, bucket) {
return bucket.reduce(function (basis, value) {
return callback.call(thisp, basis, value, index++, this);
}, basis, this);
}, basis, this);
};
FastSet.prototype.one = function () {
if (this.length > 0) {
return this.buckets.one().one();
}
};
FastSet.prototype.iterate = function () {
return this.buckets.valuesArray().flatten().iterate();
};
FastSet.prototype.log = function (charmap, logNode, callback, thisp) {
charmap = charmap || TreeLog.unicodeSharp;
logNode = logNode || this.logNode;
if (!callback) {
callback = console.log;
thisp = console;
}
callback = callback.bind(thisp);
var buckets = this.buckets, bucketsSize = buckets.size,
mapIter = buckets.keys(), hash, index = 0,
branch, leader, bucket;
while (hash = mapIter.next().value) {
if (index === bucketsSize - 1) {
branch = charmap.fromAbove;
leader = ' ';
} else if (index === 0) {
branch = charmap.branchDown;
leader = charmap.strafe;
} else {
branch = charmap.fromBoth;
leader = charmap.strafe;
}
bucket = buckets.get(hash);
callback.call(thisp, branch + charmap.through + charmap.branchDown + ' ' + hash);
bucket.forEach(function (value, node) {
var branch, below, written;
if (node === bucket.head.prev) {
branch = charmap.fromAbove;
below = ' ';
} else {
branch = charmap.fromBoth;
below = charmap.strafe;
}
logNode(
node,
function (line) {
if (!written) {
callback.call(thisp, leader + ' ' + branch + charmap.through + charmap.through + line);
written = true;
} else {
callback.call(thisp, leader + ' ' + below + ' ' + line);
}
},
function (line) {
callback.call(thisp, leader + ' ' + charmap.strafe + ' ' + line);
}
);
});
index++;
}
//var hashes = buckets.keysArray();
// hashes.forEach(function (hash, index) {
// var branch;
// var leader;
// if (index === hashes.length - 1) {
// branch = charmap.fromAbove;
// leader = ' ';
// } else if (index === 0) {
// branch = charmap.branchDown;
// leader = charmap.strafe;
// } else {
// branch = charmap.fromBoth;
// leader = charmap.strafe;
// }
// var bucket = buckets.get(hash);
// callback.call(thisp, branch + charmap.through + charmap.branchDown + ' ' + hash);
// bucket.forEach(function (value, node) {
// var branch, below;
// if (node === bucket.head.prev) {
// branch = charmap.fromAbove;
// below = ' ';
// } else {
// branch = charmap.fromBoth;
// below = charmap.strafe;
// }
// var written;
// logNode(
// node,
// function (line) {
// if (!written) {
// callback.call(thisp, leader + ' ' + branch + charmap.through + charmap.through + line);
// written = true;
// } else {
// callback.call(thisp, leader + ' ' + below + ' ' + line);
// }
// },
// function (line) {
// callback.call(thisp, leader + ' ' + charmap.strafe + ' ' + line);
// }
// );
// });
// });
};
FastSet.prototype.logNode = function (node, write) {
var value = node.value;
if (Object(value) === value) {
JSON.stringify(value, null, 4).split("\n").forEach(function (line) {
write(" " + line);
});
} else {
write(" " + value);
}
};
},{"./_dict":58,"./_list":60,"./generic-collection":64,"./generic-set":67,"./shim":78,"./tree-log":79}],60:[function(require,module,exports){
"use strict";
module.exports = List;
var Shim = require("./shim");
var GenericCollection = require("./generic-collection");
var GenericOrder = require("./generic-order");
function List(values, equals, getDefault) {
return List._init(List, this, values, equals, getDefault);
}
List._init = function (constructor, object, values, equals, getDefault) {
if (!(object instanceof constructor)) {
return new constructor(values, equals, getDefault);
}
var head = object.head = new object.Node();
head.next = head;
head.prev = head;
object.contentEquals = equals || Object.equals;
object.getDefault = getDefault || Function.noop;
object.length = 0;
object.addEach(values);
}
List.List = List; // hack so require("list").List will work in MontageJS
Object.addEach(List.prototype, GenericCollection.prototype);
Object.addEach(List.prototype, GenericOrder.prototype);
List.from = GenericCollection.from;
List.prototype.constructClone = function (values) {
return new this.constructor(values, this.contentEquals, this.getDefault);
};
List.prototype.find = function (value, equals, index) {
equals = equals || this.contentEquals;
var head = this.head;
var at = this.scan(index, head.next);
while (at !== head) {
if (equals(at.value, value)) {
return at;
}
at = at.next;
}
};
List.prototype.findLast = function (value, equals, index) {
equals = equals || this.contentEquals;
var head = this.head;
var at = this.scan(index, head.prev);
while (at !== head) {
if (equals(at.value, value)) {
return at;
}
at = at.prev;
}
};
List.prototype.has = function (value, equals) {
return !!this.find(value, equals);
};
List.prototype.get = function (value, equals) {
var found = this.find(value, equals);
if (found) {
return found.value;
}
return this.getDefault(value);
};
// LIFO (delete removes the most recently added equivalent value)
List.prototype["delete"] = function (value, equals) {
var found = this.findLast(value, equals);
if (found) {
found["delete"]();
this.length--;
return true;
}
return false;
};
List.prototype.deleteAll = function (value, equals) {
equals = equals || this.contentEquals;
var head = this.head;
var at = head.next;
var count = 0;
while (at !== head) {
if (equals(value, at.value)) {
at["delete"]();
count++;
}
at = at.next;
}
this.length -= count;
return count;
};
List.prototype.clear = function () {
this.head.next = this.head.prev = this.head;
this.length = 0;
};
List.prototype.add = function (value) {
var node = new this.Node(value)
return this._addNode(node);
};
List.prototype._addNode = function (node) {
this.head.addBefore(node);
this.length++;
return true;
};
List.prototype.push = function () {
var head = this.head;
for (var i = 0; i < arguments.length; i++) {
var value = arguments[i];
var node = new this.Node(value);
head.addBefore(node);
}
this.length += arguments.length;
};
List.prototype.unshift = function () {
var at = this.head;
for (var i = 0; i < arguments.length; i++) {
var value = arguments[i];
var node = new this.Node(value);
at.addAfter(node);
at = node;
}
this.length += arguments.length;
};
List.prototype._shouldPop = function () {
var value;
var head = this.head;
if (head.prev !== head) {
value = head.prev.value;
}
return value;
}
List.prototype.pop = function (_before, _after) {
var value;
var head = this.head;
if (head.prev !== head) {
value = head.prev.value;
var index = this.length - 1;
var popDispatchValueArray = _before ? _before.call(this,value,index) : void 0;
head.prev['delete']();
this.length--;
_after ? _after.call(this,value,index, popDispatchValueArray) : void 0;
}
return value;
};
List.prototype.shift = function (_before, _after) {
var value;
var head = this.head;
if (head.prev !== head) {
value = head.next.value;
var dispatchValueArray = _before ? _before.call(this,value,0) : void 0;
head.next['delete']();
this.length--;
_after ? _after.call(this,value,0,dispatchValueArray) : void 0;
}
return value;
};
List.prototype.peek = function () {
if (this.head !== this.head.next) {
return this.head.next.value;
}
};
List.prototype.poke = function (value) {
if (this.head !== this.head.next) {
this.head.next.value = value;
} else {
this.push(value);
}
};
List.prototype.one = function () {
return this.peek();
};
// TODO
// List.prototype.indexOf = function (value) {
// };
// TODO
// List.prototype.lastIndexOf = function (value) {
// };
// an internal utility for coercing index offsets to nodes
List.prototype.scan = function (at, fallback) {
var head = this.head;
if (typeof at === "number") {
var count = at;
if (count >= 0) {
at = head.next;
while (count) {
count--;
at = at.next;
if (at == head) {
break;
}
}
} else {
at = head;
while (count < 0) {
count++;
at = at.prev;
if (at == head) {
break;
}
}
}
return at;
} else {
return at || fallback;
}
};
// at and end may both be positive or negative numbers (in which cases they
// correspond to numeric indicies, or nodes)
List.prototype.slice = function (at, end) {
var sliced = [];
var head = this.head;
at = this.scan(at, head.next);
end = this.scan(end, head);
while (at !== end && at !== head) {
sliced.push(at.value);
at = at.next;
}
return sliced;
};
List.prototype.splice = function (at, length /*...plus*/) {
return this.swap(at, length, Array.prototype.slice.call(arguments, 2));
};
List.prototype.swap = function (start, length, plus, _before, _after) {
var initial = start;
// start will be head if start is null or -1 (meaning from the end), but
// will be head.next if start is 0 (meaning from the beginning)
start = this.scan(start, this.head);
if (length == null) {
length = Infinity;
}
plus = Array.from(plus);
// collect the minus array
var minus = [];
var at = start;
while (length-- && length >= 0 && at !== this.head) {
minus.push(at.value);
at = at.next;
}
// before range change
var index, startNode;
index = _before ? _before.call(this, start, plus, minus) : void 0;
// delete minus
var at = start;
for (var i = 0, at = start; i < minus.length; i++, at = at.next) {
at["delete"]();
}
// add plus
if (initial == null && at === this.head) {
at = this.head.next;
}
for (var i = 0; i < plus.length; i++) {
var node = new this.Node(plus[i]);
at.addBefore(node);
}
// adjust length
this.length += plus.length - minus.length;
_after ? _after.call(this, start, plus, minus) : void 0;
return minus;
};
List.prototype.reverse = function () {
var at = this.head;
do {
var temp = at.next;
at.next = at.prev;
at.prev = temp;
at = at.next;
} while (at !== this.head);
return this;
};
List.prototype.sort = function () {
this.swap(0, this.length, this.sorted.apply(this, arguments));
};
// TODO account for missing basis argument
List.prototype.reduce = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var head = this.head;
var at = head.next;
while (at !== head) {
basis = callback.call(thisp, basis, at.value, at, this);
at = at.next;
}
return basis;
};
List.prototype.reduceRight = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var head = this.head;
var at = head.prev;
while (at !== head) {
basis = callback.call(thisp, basis, at.value, at, this);
at = at.prev;
}
return basis;
};
List.prototype.updateIndexes = function (node, index) {
while (node !== this.head) {
node.index = index++;
node = node.next;
}
};
List.prototype.iterate = function () {
return new ListIterator(this.head);
};
function ListIterator(head) {
this.head = head;
this.at = head.next;
};
ListIterator.prototype.__iterationObject = null;
Object.defineProperty(ListIterator.prototype,"_iterationObject", {
get: function() {
return this.__iterationObject || (this.__iterationObject = { done: false, value:null});
}
});
ListIterator.prototype.next = function () {
if (this.at === this.head) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
} else {
var value = this.at.value;
this.at = this.at.next;
this._iterationObject.value = value;
}
return this._iterationObject;
};
List.prototype.Node = Node;
function Node(value) {
this.value = value;
this.prev = null;
this.next = null;
};
Node.prototype["delete"] = function () {
this.prev.next = this.next;
this.next.prev = this.prev;
};
Node.prototype.addBefore = function (node) {
var prev = this.prev;
this.prev = node;
node.prev = prev;
prev.next = node;
node.next = this;
};
Node.prototype.addAfter = function (node) {
var next = this.next;
this.next = node;
node.next = next;
next.prev = node;
node.prev = this;
};
},{"./generic-collection":64,"./generic-order":66,"./shim":78}],61:[function(require,module,exports){
(function (global){
"use strict";
var Shim = require("./shim");
var GenericCollection = require("./generic-collection");
var Map, GlobalMap, CollectionsMap;
if((global.Map !== void 0) && (typeof global.Set.prototype.values === "function")) {
Map = module.exports = global.Map,
GlobalMap = Map;
Map.Map = Map; // hack so require("map").Map will work in MontageJS
// use different strategies for making sets observable between Internet
// Explorer and other browsers.
var protoIsSupported = {}.__proto__ === Object.prototype,
map_makeObservable;
if (protoIsSupported) {
map_makeObservable = function () {
this.__proto__ = ChangeDispatchMap;
};
} else {
map_makeObservable = function () {
Object.defineProperties(this, observableSetProperties);
};
}
Object.defineProperty(Map.prototype, "makeObservable", {
value: map_makeObservable,
writable: true,
configurable: true,
enumerable: false
});
//This is a no-op test in property-changes.js - PropertyChanges.prototype.makePropertyObservable, so might as well not pay the price every time....
Object.defineProperty(Map.prototype, "makePropertyObservable", {
value: function(){},
writable: true,
configurable: true,
enumerable: false
});
Map.prototype.constructClone = function (values) {
return new this.constructor(values);
};
Map.prototype.isMap = true;
Map.prototype.addEach = function (values) {
if (values && Object(values) === values) {
if (typeof values.forEach === "function") {
// copy map-alikes
if (values.isMap === true) {
values.forEach(function (value, key) {
this.set(key, value);
}, this);
// iterate key value pairs of other iterables
} else {
values.forEach(function (pair) {
this.set(pair[0], pair[1]);
}, this);
}
} else if (typeof values.length === "number") {
// Array-like objects that do not implement forEach, ergo,
// Arguments
for (var i = 0; i < values.length; i++) {
this.add(values[i], i);
}
} else {
// copy other objects as map-alikes
Object.keys(values).forEach(function (key) {
this.set(key, values[key]);
}, this);
}
} else if (values && typeof values.length === "number") {
// String
for (var i = 0; i < values.length; i++) {
this.add(values[i], i);
}
}
return this;
};
Map.prototype.add = function (value, key) {
return this.set(key, value);
};
Map.prototype.reduce = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
this.forEach(function(value, key, map) {
basis = callback.call(thisp, basis, value, key, this);
});
return basis;
};
Map.prototype.reduceRight = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var keysIterator = this.keys();
var size = this.size;
var reverseOrder = new Array(this.size);
var aKey, i = 0;
while ((aKey = keysIterator.next().value)) {
reverseOrder[--size] = aKey;
}
while (i++ < size) {
basis = callback.call(thisp, basis, this.get(reverseOrder[i]), reverseOrder[i], this);
}
return basis;
};
Map.prototype.equals = function (that, equals) {
equals = equals || Object.equals;
if (this === that) {
return true;
} else if (that && typeof that.every === "function") {
return that.size === this.size && that.every(function (value, key) {
return equals(this.get(key), value);
}, this);
} else {
var keys = Object.keys(that);
return keys.length === this.size && Object.keys(that).every(function (key) {
return equals(this.get(key), that[key]);
}, this);
}
};
var _keysArrayFunction = function(value,key) {return key;};
Map.prototype.keysArray = function() {
return this.map(_keysArrayFunction);
}
var _valuesArrayFunction = function(value,key) {return value;};
Map.prototype.valuesArray = function() {
return this.map(_valuesArrayFunction);
}
var _entriesArrayFunction = function(value,key) {return [key,value];};
Map.prototype.entriesArray = function() {
return this.map(_entriesArrayFunction);
}
Map.prototype.toJSON = function () {
return this.entriesArray();
};
// XXX deprecated
Map.prototype.items = function () {
return this.entriesArray();
};
// Map.prototype.contentEquals = Object.equals;
// Map.prototype.contentHash = Object.hash;
Map.from = function (value) {
var result = new this;
result.addEach(value);
return result;
};
//Backward compatibility:
Object.defineProperty(Map.prototype,"length",{
get: function() {
return this.size;
},
enumerable: true,
configurable:true
});
var map_clear = Map.prototype.clear,
map_set = Map.prototype.set,
map_delete = Map.prototype.delete;
var observableMapProperties = {
clear : {
value: function () {
var keys;
if (this.dispatchesMapChanges) {
this.forEach(function (value, key) {
this.dispatchBeforeMapChange(key, value);
}, this);
keys = this.keysArray();
}
map_clear.call(this);
if (this.dispatchesMapChanges) {
keys.forEach(function (key) {
this.dispatchMapChange(key);
}, this);
}
},
writable: true,
configurable: true
},
set : {
value: function (key, value) {
var found = this.get(key);
if (found) { // update
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, found);
}
map_set.call(this,key, value);
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
} else { // create
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, undefined);
}
map_set.call(this,key, value);
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
}
return this;
},
writable: true,
configurable: true
},
"delete": {
value: function (key) {
if (this.has(key)) {
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, this.get(key));
}
map_delete.call(this,key);
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, undefined);
}
return true;
}
return false;
}
}
};
Object.addEach(Map.prototype, GenericCollection.prototype, false);
var ChangeDispatchMap = Object.create(Map.prototype, observableMapProperties);
}
var Set = require("./_set").CollectionsSet;
var GenericMap = require("./generic-map");
CollectionsMap = Map = function Map(values, equals, hash, getDefault) {
if (!(this instanceof Map)) {
return new Map(values, equals, hash, getDefault);
}
equals = equals || Object.equals;
hash = hash || Object.hash;
getDefault = getDefault || Function.noop;
this.contentEquals = equals;
this.contentHash = hash;
this.getDefault = getDefault;
this.store = new Set(
undefined,
function keysEqual(a, b) {
return equals(a.key, b.key);
},
function keyHash(item) {
return hash(item.key);
}
);
this.length = 0;
this.addEach(values);
}
Map.Map = Map; // hack so require("map").Map will work in MontageJS
Object.addEach(Map.prototype, GenericCollection.prototype);
Object.addEach(Map.prototype, GenericMap.prototype); // overrides GenericCollection
Object.defineProperty(Map.prototype,"size",GenericCollection._sizePropertyDescriptor);
Map.from = GenericCollection.from;
Map.prototype.constructClone = function (values) {
return new this.constructor(
values,
this.contentEquals,
this.contentHash,
this.getDefault
);
};
Map.prototype.log = function (charmap, logNode, callback, thisp) {
logNode = logNode || this.logNode;
this.store.log(charmap, function (node, log, logBefore) {
logNode(node.value.value, log, logBefore);
}, callback, thisp);
};
Map.prototype.logNode = function (node, log) {
log(' key: ' + node.key);
log(' value: ' + node.value);
};
if(!GlobalMap) {
module.exports = CollectionsMap;
}
else {
module.exports = GlobalMap;
GlobalMap.CollectionsMap = CollectionsMap;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./_set":62,"./generic-collection":64,"./generic-map":65,"./shim":78}],62:[function(require,module,exports){
(function (global){
"use strict";
var Shim = require("./shim");
var GenericCollection = require("./generic-collection");
var GenericSet = require("./generic-set");
var Set, GlobalSet, CollectionsSet;
if((global.Set !== void 0) && (typeof global.Set.prototype.values === "function")) {
GlobalSet = module.exports = global.Set;
GlobalSet.Set = GlobalSet; // hack so require("set").Set will work in MontageJS
GlobalSet.prototype.reduce = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
this.forEach(function(value) {
basis = callback.call(thisp, basis, value, this);
});
return basis;
};
GlobalSet.prototype.reduceRight = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var setIterator = this.values();
var size = this.size;
var reverseOrder = new Array(this.size);
var value, i = 0;
while ((value = setIterator.next().value)) {
reverseOrder[--size] = value;
}
while (i++ < size) {
basis = callback.call(thisp, basis, value, this);
}
return basis;
};
GlobalSet.prototype.equals = function (that, equals) {
var self = this;
return (
that && typeof that.reduce === "function" &&
this.size === (that.size || that.length) &&
that.reduce(function (equal, value) {
return equal && self.has(value, equals);
}, true)
);
};
GlobalSet.prototype.constructClone = function (values) {
return new this.constructor(values, this.contentEquals, this.contentHash, this.getDefault);
};
GlobalSet.prototype.toJSON = function () {
return this.entriesArray();
};
GlobalSet.prototype.one = function () {
if (this.size > 0) {
return this.values().next().value;
}
return undefined;
};
GlobalSet.prototype.pop = function () {
if (this.size) {
var setIterator = this.values(), aValue, value;
while(aValue = setIterator.next().value) {
value = aValue;
}
this["delete"](value,this.size-1);
return value;
}
};
GlobalSet.prototype.shift = function () {
if (this.size) {
var firstValue = this.values().next().value;
this["delete"](firstValue,0);
return firstValue;
}
};
//Backward compatibility:
Object.defineProperty(GlobalSet.prototype,"length",{
get: function() {
return this.size;
},
enumerable: true,
configurable:true
});
GlobalSet.from = function (value) {
var result = (new this);
result.addEach(value);
return result;
};
Object.addEach(GlobalSet.prototype, GenericCollection.prototype, false);
Object.addEach(GlobalSet.prototype, GenericSet.prototype, false);
}
var List = require("./_list");
var FastSet = require("./_fast-set");
var Iterator = require("./iterator");
CollectionsSet = function CollectionsSet(values, equals, hash, getDefault) {
return CollectionsSet._init(CollectionsSet, this, values, equals, hash, getDefault);
}
CollectionsSet._init = function (constructor, object, values, equals, hash, getDefault) {
if (!(object instanceof constructor)) {
return new constructor(values, equals, hash, getDefault);
}
equals = equals || Object.equals;
hash = hash || Object.hash;
getDefault = getDefault || Function.noop;
object.contentEquals = equals;
object.contentHash = hash;
object.getDefault = getDefault;
// a list of values in insertion order, used for all operations that depend
// on iterating in insertion order
object.order = new object.Order(undefined, equals);
// a set of nodes from the order list, indexed by the corresponding value,
// used for all operations that need to quickly seek value in the list
object.store = new object.Store(
undefined,
function (a, b) {
return equals(a.value, b.value);
},
function (node) {
return hash(node.value);
}
);
object.length = 0;
object.addEach(values);
}
CollectionsSet.Set = CollectionsSet; // hack so require("set").Set will work in MontageJS
CollectionsSet.CollectionsSet = CollectionsSet;
Object.addEach(CollectionsSet.prototype, GenericCollection.prototype);
Object.addEach(CollectionsSet.prototype, GenericSet.prototype);
CollectionsSet.from = GenericCollection.from;
Object.defineProperty(CollectionsSet.prototype,"size",GenericCollection._sizePropertyDescriptor);
//Overrides for consistency:
// Set.prototype.forEach = GenericCollection.prototype.forEach;
CollectionsSet.prototype.Order = List;
CollectionsSet.prototype.Store = FastSet;
CollectionsSet.prototype.constructClone = function (values) {
return new this.constructor(values, this.contentEquals, this.contentHash, this.getDefault);
};
CollectionsSet.prototype.has = function (value) {
var node = new this.order.Node(value);
return this.store.has(node);
};
CollectionsSet.prototype.get = function (value, equals) {
if (equals) {
throw new Error("Set#get does not support second argument: equals");
}
var node = new this.order.Node(value);
node = this.store.get(node);
if (node) {
return node.value;
} else {
return this.getDefault(value);
}
};
CollectionsSet.prototype.add = function (value) {
var node = new this.order.Node(value);
if (!this.store.has(node)) {
var index = this.length;
this.order.add(value);
node = this.order.head.prev;
this.store.add(node);
this.length++;
return true;
}
return false;
};
CollectionsSet.prototype["delete"] = function (value, equals) {
if (equals) {
throw new Error("Set#delete does not support second argument: equals");
}
var node = new this.order.Node(value);
if (this.store.has(node)) {
node = this.store.get(node);
this.store["delete"](node); // removes from the set
this.order.splice(node, 1); // removes the node from the list
this.length--;
return true;
}
return false;
};
CollectionsSet.prototype.pop = function () {
if (this.length) {
var result = this.order.head.prev.value;
this["delete"](result);
return result;
}
};
CollectionsSet.prototype.shift = function () {
if (this.length) {
var result = this.order.head.next.value;
this["delete"](result);
return result;
}
};
CollectionsSet.prototype.one = function () {
if (this.length > 0) {
return this.store.one().value;
}
};
CollectionsSet.prototype.clear = function () {
this.store.clear();
this.order.clear();
this.length = 0;
};
Object.defineProperty(CollectionsSet.prototype,"_clear", {
value: CollectionsSet.prototype.clear
});
CollectionsSet.prototype.reduce = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var list = this.order;
var index = 0;
return list.reduce(function (basis, value) {
return callback.call(thisp, basis, value, index++, this);
}, basis, this);
};
CollectionsSet.prototype.reduceRight = function (callback, basis /*, thisp*/) {
var thisp = arguments[2];
var list = this.order;
var index = this.length - 1;
return list.reduceRight(function (basis, value) {
return callback.call(thisp, basis, value, index--, this);
}, basis, this);
};
CollectionsSet.prototype.iterate = function () {
return this.order.iterate();
};
CollectionsSet.prototype.values = function () {
return new Iterator(this.valuesArray());
};
CollectionsSet.prototype.log = function () {
var set = this.store;
return set.log.apply(set, arguments);
};
if(!GlobalSet) {
module.exports = CollectionsSet;
}
else {
GlobalSet.prototype.valuesArray = GenericSet.prototype.valuesArray;
GlobalSet.prototype.entriesArray = GenericSet.prototype.entriesArray;
module.exports = GlobalSet;
GlobalSet.CollectionsSet = CollectionsSet;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./_fast-set":59,"./_list":60,"./generic-collection":64,"./generic-set":67,"./iterator":68,"./shim":78}],63:[function(require,module,exports){
"use strict";
var Dict = require("./_dict");
var PropertyChanges = require("./listen/property-changes");
var MapChanges = require("./listen/map-changes");
// Burgled from https://github.com/domenic/dict
module.exports = Dict;
Object.addEach(Dict.prototype, PropertyChanges.prototype);
Object.addEach(Dict.prototype, MapChanges.prototype);
},{"./_dict":58,"./listen/map-changes":70,"./listen/property-changes":71}],64:[function(require,module,exports){
(function (global){
"use strict";
module.exports = GenericCollection;
function GenericCollection() {
throw new Error("Can't construct. GenericCollection is a mixin.");
}
var DOMTokenList = global.DOMTokenList || function(){};
GenericCollection.EmptyArray = Object.freeze([]);
/* TODO: optimize for DOMTokenList and Array to use for() instead of forEach */
GenericCollection.prototype.addEach = function (values) {
//We want to eliminate everything but array like: Strings, Arrays, DOMTokenList
if(values && (values instanceof Array || (values instanceof DOMTokenList) || values instanceof String)) {
for (var i = 0; i < values.length; i++) {
this.add(values[i], i);
}
}
else if (values && Object(values) === values) {
if (typeof values.forEach === "function") {
values.forEach(this.add, this);
} else if (typeof values.length === "number") {
// Array-like objects that do not implement forEach, ergo,
// Arguments
for (var i = 0; i < values.length; i++) {
this.add(values[i], i);
}
} else {
Object.keys(values).forEach(function (key) {
this.add(values[key], key);
}, this);
}
}
return this;
};
// This is sufficiently generic for Map (since the value may be a key)
// and ordered collections (since it forwards the equals argument)
GenericCollection.prototype.deleteEach = function (values, equals) {
values.forEach(function (value) {
this["delete"](value, equals);
}, this);
return this;
};
// all of the following functions are implemented in terms of "reduce".
// some need "constructClone".
GenericCollection.prototype.forEach = function (callback /*, thisp*/) {
var thisp = arguments[1];
return this.reduce(function (undefined, value, key, object, depth) {
callback.call(thisp, value, key, object, depth);
}, undefined);
};
GenericCollection.prototype.map = function (callback /*, thisp*/) {
var thisp = arguments[1];
var result = [];
this.reduce(function (undefined, value, key, object, depth) {
result.push(callback.call(thisp, value, key, object, depth));
}, undefined);
return result;
};
GenericCollection.prototype.enumerate = function (start) {
if (start == null) {
start = 0;
}
var result = [];
this.reduce(function (undefined, value) {
result.push([start++, value]);
}, undefined);
return result;
};
GenericCollection.prototype.group = function (callback, thisp, equals) {
equals = equals || Object.equals;
var groups = [];
var keys = [];
this.forEach(function (value, key, object) {
var key = callback.call(thisp, value, key, object);
var index = keys.indexOf(key, equals);
var group;
if (index === -1) {
group = [];
groups.push([key, group]);
keys.push(key);
} else {
group = groups[index][1];
}
group.push(value);
});
return groups;
};
GenericCollection.prototype.toArray = function () {
return this.map(Function.identity);
};
// this depends on stringable keys, which apply to Array and Iterator
// because they have numeric keys and all Maps since they may use
// strings as keys. List, Set, and SortedSet have nodes for keys, so
// toObject would not be meaningful.
GenericCollection.prototype.toObject = function () {
var object = {};
this.reduce(function (undefined, value, key) {
object[key] = value;
}, undefined);
return object;
};
GenericCollection.from = function () {
return this.apply(this,arguments);
};
GenericCollection.prototype.filter = function (callback /*, thisp*/) {
var thisp = arguments[1];
var result = this.constructClone();
this.reduce(function (undefined, value, key, object, depth) {
if (callback.call(thisp, value, key, object, depth)) {
result.add(value, key);
}
}, undefined);
return result;
};
GenericCollection.prototype.every = function (callback /*, thisp*/) {
var thisp = arguments[1];
return this.reduce(function (result, value, key, object, depth) {
return result && callback.call(thisp, value, key, object, depth);
}, true);
};
GenericCollection.prototype.some = function (callback /*, thisp*/) {
var thisp = arguments[1];
return this.reduce(function (result, value, key, object, depth) {
return result || callback.call(thisp, value, key, object, depth);
}, false);
};
GenericCollection.prototype.all = function () {
return this.every(Boolean);
};
GenericCollection.prototype.any = function () {
return this.some(Boolean);
};
GenericCollection.prototype.min = function (compare) {
compare = compare || this.contentCompare || Object.compare;
var first = true;
return this.reduce(function (result, value) {
if (first) {
first = false;
return value;
} else {
return compare(value, result) < 0 ? value : result;
}
}, undefined);
};
GenericCollection.prototype.max = function (compare) {
compare = compare || this.contentCompare || Object.compare;
var first = true;
return this.reduce(function (result, value) {
if (first) {
first = false;
return value;
} else {
return compare(value, result) > 0 ? value : result;
}
}, undefined);
};
GenericCollection.prototype.sum = function (zero) {
zero = zero === undefined ? 0 : zero;
return this.reduce(function (a, b) {
return a + b;
}, zero);
};
GenericCollection.prototype.average = function (zero) {
var sum = zero === undefined ? 0 : zero;
var count = zero === undefined ? 0 : zero;
this.reduce(function (undefined, value) {
sum += value;
count += 1;
}, undefined);
return sum / count;
};
GenericCollection.prototype.concat = function () {
var result = this.constructClone(this);
for (var i = 0; i < arguments.length; i++) {
result.addEach(arguments[i]);
}
return result;
};
GenericCollection.prototype.flatten = function () {
var self = this;
return this.reduce(function (result, array) {
array.forEach(function (value) {
this.push(value);
}, result, self);
return result;
}, []);
};
GenericCollection.prototype.zip = function () {
var table = Array.prototype.slice.call(arguments);
table.unshift(this);
return Array.unzip(table);
}
GenericCollection.prototype.join = function (delimiter) {
return this.reduce(function (result, string) {
// work-around for reduce that does not support no-basis form
if (result === void 0) {
return string;
} else {
return result + delimiter + string;
}
}, void 0);
};
GenericCollection.prototype.sorted = function (compare, by, order) {
compare = compare || this.contentCompare || Object.compare;
// account for comparators generated by Function.by
if (compare.by) {
by = compare.by;
compare = compare.compare || this.contentCompare || Object.compare;
} else {
by = by || Function.identity;
}
if (order === undefined)
order = 1;
return this.map(function (item) {
return {
by: by(item),
value: item
};
})
.sort(function (a, b) {
return compare(a.by, b.by) * order;
})
.map(function (pair) {
return pair.value;
});
};
GenericCollection.prototype.reversed = function () {
return this.constructClone(this).reverse();
};
GenericCollection.prototype.clone = function (depth, memo) {
if (depth === undefined) {
depth = Infinity;
} else if (depth === 0) {
return this;
}
var clone = this.constructClone();
this.forEach(function (value, key) {
clone.add(Object.clone(value, depth - 1, memo), key);
}, this);
return clone;
};
GenericCollection.prototype.only = function () {
if (this.length === 1) {
return this.one();
}
};
GenericCollection.prototype.iterator = function () {
return this.iterate.apply(this, arguments);
};
GenericCollection._sizePropertyDescriptor = {
get: function() {
return this.length;
},
enumerable: false,
configurable: true
};
Object.defineProperty(GenericCollection.prototype,"size",GenericCollection._sizePropertyDescriptor);
require("./shim-array");
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./shim-array":74}],65:[function(require,module,exports){
"use strict";
var Object = require("./shim-object");
var Iterator = require("./iterator");
module.exports = GenericMap;
function GenericMap() {
throw new Error("Can't construct. GenericMap is a mixin.");
}
// all of these methods depend on the constructor providing a `store` set
GenericMap.prototype.isMap = true;
GenericMap.prototype.addEach = function (values) {
var i;
if (values && Object(values) === values) {
if (typeof values.forEach === "function") {
// copy map-alikes
if (values.isMap === true) {
values.forEach(function (value, key) {
this.set(key, value);
}, this);
// iterate key value pairs of other iterables
} else {
values.forEach(function (pair) {
this.set(pair[0], pair[1]);
}, this);
}
} else if (typeof values.length === "number") {
// Array-like objects that do not implement forEach, ergo,
// Arguments
for (i = 0; i < values.length; i++) {
this.add(values[i], i);
}
} else {
// copy other objects as map-alikes
Object.keys(values).forEach(function (key) {
this.set(key, values[key]);
}, this);
}
} else if (values && typeof values.length === "number") {
// String
for (i = 0; i < values.length; i++) {
this.add(values[i], i);
}
}
return this;
};
GenericMap.prototype.get = function (key, defaultValue) {
var item = this.store.get(new this.Item(key));
if (item) {
return item.value;
} else if (arguments.length > 1) {
console.log("Use of a second argument as default value is deprecated to match standards");
return defaultValue;
} else {
return this.getDefault(key);
}
};
GenericMap.prototype.set = function (key, value) {
var item = new this.Item(key, value);
var found = this.store.get(item);
var grew = false;
if (found) { // update
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, found.value);
}
found.value = value;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
} else { // create
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, undefined);
}
if (this.store.add(item)) {
this.length++;
grew = true;
}
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, value);
}
}
return this;
};
GenericMap.prototype.add = function (value, key) {
return this.set(key, value);
};
GenericMap.prototype.has = function (key) {
return this.store.has(new this.Item(key));
};
GenericMap.prototype['delete'] = function (key) {
var item = new this.Item(key);
if (this.store.has(item)) {
var from = this.store.get(item).value;
if (this.dispatchesMapChanges) {
this.dispatchBeforeMapChange(key, from);
}
this.store["delete"](item);
this.length--;
if (this.dispatchesMapChanges) {
this.dispatchMapChange(key, undefined);
}
return true;
}
return false;
};
GenericMap.prototype.clear = function () {
var keys, key;
if (this.dispatchesMapChanges) {
this.forEach(function (value, key) {
this.dispatchBeforeMapChange(key, value);
}, this);
keys = this.keysArray();
}
this.store.clear();
this.length = 0;
if (this.dispatchesMapChanges) {
for(var i=0;(key = keys[i]);i++) {
this.dispatchMapChange(key);
}
// keys.forEach(function (key) {
// this.dispatchMapChange(key);
// }, this);
}
};
GenericMap.prototype.reduce = function (callback, basis, thisp) {
return this.store.reduce(function (basis, item) {
return callback.call(thisp, basis, item.value, item.key, this);
}, basis, this);
};
GenericMap.prototype.reduceRight = function (callback, basis, thisp) {
return this.store.reduceRight(function (basis, item) {
return callback.call(thisp, basis, item.value, item.key, this);
}, basis, this);
};
GenericMap.prototype.keysArray = function () {
return this.map(function (value, key) {
return key;
});
};
GenericMap.prototype.keys = function () {
return new Iterator(this.keysArray());
};
GenericMap.prototype.valuesArray = function () {
return this.map(Function.identity);
};
GenericMap.prototype.values = function () {
return new Iterator(this.valuesArray());
};
GenericMap.prototype.entriesArray = function () {
return this.map(function (value, key) {
return [key, value];
});
};
GenericMap.prototype.entries = function () {
return new Iterator(this.entriesArray());
};
// XXX deprecated
GenericMap.prototype.items = function () {
return this.entriesArray();
};
GenericMap.prototype.equals = function (that, equals) {
equals = equals || Object.equals;
if (this === that) {
return true;
} else if (that && typeof that.every === "function") {
return that.length === this.length && that.every(function (value, key) {
return equals(this.get(key), value);
}, this);
} else {
var keys = Object.keys(that);
return keys.length === this.length && Object.keys(that).every(function (key) {
return equals(this.get(key), that[key]);
}, this);
}
};
GenericMap.prototype.toJSON = function () {
return this.entriesArray();
};
GenericMap.prototype.Item = Item;
function Item(key, value) {
this.key = key;
this.value = value;
}
Item.prototype.equals = function (that) {
return Object.equals(this.key, that.key) && Object.equals(this.value, that.value);
};
Item.prototype.compare = function (that) {
return Object.compare(this.key, that.key);
};
},{"./iterator":68,"./shim-object":76}],66:[function(require,module,exports){
var Object = require("./shim-object");
module.exports = GenericOrder;
function GenericOrder() {
throw new Error("Can't construct. GenericOrder is a mixin.");
}
GenericOrder.prototype.equals = function (that, equals) {
equals = equals || this.contentEquals || Object.equals;
if (this === that) {
return true;
}
if (!that) {
return false;
}
var self = this;
return (
this.length === that.length &&
this.zip(that).every(function (pair) {
return equals(pair[0], pair[1]);
})
);
};
GenericOrder.prototype.compare = function (that, compare) {
compare = compare || this.contentCompare || Object.compare;
if (this === that) {
return 0;
}
if (!that) {
return 1;
}
var length = Math.min(this.length, that.length);
var comparison = this.zip(that).reduce(function (comparison, pair, index) {
if (comparison === 0) {
if (index >= length) {
return comparison;
} else {
return compare(pair[0], pair[1]);
}
} else {
return comparison;
}
}, 0);
if (comparison === 0) {
return this.length - that.length;
}
return comparison;
};
GenericOrder.prototype.toJSON = function () {
return this.toArray();
};
},{"./shim-object":76}],67:[function(require,module,exports){
module.exports = GenericSet;
function GenericSet() {
throw new Error("Can't construct. GenericSet is a mixin.");
}
GenericSet.prototype.isSet = true;
GenericSet.prototype.union = function (that) {
var union = this.constructClone(this);
union.addEach(that);
return union;
};
GenericSet.prototype.intersection = function (that) {
return this.constructClone(this.filter(function (value) {
return that.has(value);
}));
};
GenericSet.prototype.difference = function (that) {
var union = this.constructClone(this);
union.deleteEach(that);
return union;
};
GenericSet.prototype.symmetricDifference = function (that) {
var union = this.union(that);
var intersection = this.intersection(that);
return union.difference(intersection);
};
GenericSet.prototype.deleteAll = function (value) {
// deleteAll is equivalent to delete for sets since they guarantee that
// only one value exists for an equivalence class, but deleteAll returns
// the count of deleted values instead of whether a value was deleted.
return +this["delete"](value);
};
GenericSet.prototype.equals = function (that, equals) {
var self = this;
return (
that && typeof that.reduce === "function" &&
this.length === that.length &&
that.reduce(function (equal, value) {
return equal && self.has(value, equals);
}, true)
);
};
GenericSet.prototype.forEach = function (callback /*, thisp*/) {
var thisp = arguments[1];
return this.reduce(function (undefined, value, key, object, depth) {
//ECMASCRIPT Sets send value twice in callback to forEach
callback.call(thisp, value, value, object, depth);
}, undefined);
};
GenericSet.prototype.toJSON = function () {
return this.toArray();
};
// W3C DOMTokenList API overlap (does not handle variadic arguments)
GenericSet.prototype.contains = function (value) {
return this.has(value);
};
GenericSet.prototype.remove = function (value) {
return this["delete"](value);
};
GenericSet.prototype.toggle = function (value) {
if (this.has(value)) {
this["delete"](value);
} else {
this.add(value);
}
};
var _valuesArrayFunction = function(value,key) {return value;};
GenericSet.prototype.valuesArray = function() {
return this.map(_valuesArrayFunction);
}
var _entriesArrayFunction = function(value,key) {return [key,value];};
GenericSet.prototype.entriesArray = function() {
return this.map(_entriesArrayFunction);
}
},{}],68:[function(require,module,exports){
"use strict";
module.exports = Iterator;
var Object = require("./shim-object");
var GenericCollection = require("./generic-collection");
// upgrades an iterable to a Iterator
function Iterator(iterable) {
var values = iterable && iterable.values && iterable.values();
if(values && typeof values.next === "function" ) {
return values;
}
if (!(this instanceof Iterator)) {
return new Iterator(iterable);
}
if (Array.isArray(iterable) || typeof iterable === "string")
return Iterator.iterate(iterable);
iterable = Object(iterable);
if (iterable instanceof Iterator) {
return iterable;
} else if (iterable.next) {
this.next = function () {
return iterable.next();
};
} else if (iterable.iterate) {
var iterator = iterable.iterate();
this.next = function () {
return iterator.next();
};
} else if (Object.prototype.toString.call(iterable) === "[object Function]") {
this.next = iterable;
} else {
throw new TypeError("Can't iterate " + iterable);
}
}
Iterator.prototype.forEach = GenericCollection.prototype.forEach;
Iterator.prototype.map = GenericCollection.prototype.map;
Iterator.prototype.filter = GenericCollection.prototype.filter;
Iterator.prototype.every = GenericCollection.prototype.every;
Iterator.prototype.some = GenericCollection.prototype.some;
Iterator.prototype.any = GenericCollection.prototype.any;
Iterator.prototype.all = GenericCollection.prototype.all;
Iterator.prototype.min = GenericCollection.prototype.min;
Iterator.prototype.max = GenericCollection.prototype.max;
Iterator.prototype.sum = GenericCollection.prototype.sum;
Iterator.prototype.average = GenericCollection.prototype.average;
Iterator.prototype.flatten = GenericCollection.prototype.flatten;
Iterator.prototype.zip = GenericCollection.prototype.zip;
Iterator.prototype.enumerate = GenericCollection.prototype.enumerate;
Iterator.prototype.sorted = GenericCollection.prototype.sorted;
Iterator.prototype.group = GenericCollection.prototype.group;
Iterator.prototype.reversed = GenericCollection.prototype.reversed;
Iterator.prototype.toArray = GenericCollection.prototype.toArray;
Iterator.prototype.toObject = GenericCollection.prototype.toObject;
Iterator.prototype.iterator = GenericCollection.prototype.iterator;
Iterator.prototype.__iterationObject = null;
Object.defineProperty(Iterator.prototype,"_iterationObject", {
get: function() {
return this.__iterationObject || (this.__iterationObject = { done: false, value:void 0});
}
});
// this is a bit of a cheat so flatten and such work with the generic
// reducible
Iterator.prototype.constructClone = function (values) {
var clone = [];
clone.addEach(values);
return clone;
};
Iterator.prototype.mapIterator = function (callback /*, thisp*/) {
var self = Iterator(this),
thisp = arguments[1],
i = 0;
if (Object.prototype.toString.call(callback) != "[object Function]")
throw new TypeError();
return new self.constructor(function () {
if(self._iterationObject.done !== true) {
var callbackValue = callback.call(thisp, self.next().value, i++, self);
self._iterationObject.value = callbackValue;
}
return self._iterationObject;
});
};
Iterator.prototype.filterIterator = function (callback /*, thisp*/) {
var self = Iterator(this),
thisp = arguments[1],
i = 0;
if (Object.prototype.toString.call(callback) != "[object Function]")
throw new TypeError();
return new self.constructor(function () {
var nextEntry;
while (true) {
nextEntry = self.next();
if(nextEntry.done !== true) {
if (callback.call(thisp, nextEntry.value, i++, self))
return nextEntry;
}
else {
//done true and value undefined at this point
return nextEntry;
}
}
});
};
Iterator.prototype.reduce = function (callback /*, initial, thisp*/) {
var self = Iterator(this),
result = arguments[1],
thisp = arguments[2],
i = 0,
nextEntry;
if (Object.prototype.toString.call(callback) != "[object Function]")
throw new TypeError();
// first iteration unrolled
nextEntry = self.next();
if(nextEntry.done === true) {
if (arguments.length > 1) {
return arguments[1]; // initial
} else {
throw TypeError("cannot reduce a value from an empty iterator with no initial value");
}
}
if (arguments.length > 1) {
result = callback.call(thisp, result, nextEntry.value, i, self);
} else {
result = nextEntry.value;
}
i++;
// remaining entries
while (true) {
nextEntry = self.next();
if(nextEntry.done === true) {
return result;
}
result = callback.call(thisp, result, nextEntry.value, i, self);
i++;
}
};
Iterator.prototype.concat = function () {
return Iterator.concat(
Array.prototype.concat.apply(this, arguments)
);
};
Iterator.prototype.dropWhile = function (callback /*, thisp */) {
var self = Iterator(this),
thisp = arguments[1],
stopped = false,
stopValue,
nextEntry,
i = 0;
if (Object.prototype.toString.call(callback) != "[object Function]")
throw new TypeError();
while (true) {
nextEntry = self.next();
if(nextEntry.done === true) {
break;
}
if (!callback.call(thisp, nextEntry.value, i, self)) {
stopped = true;
stopValue = nextEntry.value;
break;
}
i++;
}
if (stopped) {
return self.constructor([stopValue]).concat(self);
} else {
return self.constructor([]);
}
};
Iterator.prototype.takeWhile = function (callback /*, thisp*/) {
var self = Iterator(this),
thisp = arguments[1],
nextEntry,
i = 0;
if (Object.prototype.toString.call(callback) != "[object Function]")
throw new TypeError();
return new self.constructor(function () {
if(self._iterationObject.done !== true) {
var value = self.next().value;
if(callback.call(thisp, value, i++, self)) {
self._iterationObject.value = value;
}
else {
self._iterationObject.done = true;
self._iterationObject.value = void 0;
}
}
return self._iterationObject;
});
};
Iterator.prototype.zipIterator = function () {
return Iterator.unzip(
Array.prototype.concat.apply(this, arguments)
);
};
Iterator.prototype.enumerateIterator = function (start) {
return Iterator.count(start).zipIterator(this);
};
// creates an iterator for Array and String
Iterator.iterate = function (iterable) {
var start;
start = 0;
return new Iterator(function () {
// advance to next owned entry
if (typeof iterable === "object") {
while (!(start in iterable)) {
// deliberately late bound
if (start >= iterable.length) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
break;
}
else start += 1;
}
} else if (start >= iterable.length) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
}
if(!this._iterationObject.done) {
this._iterationObject.value = iterable[start];
start += 1;
}
return this._iterationObject;
});
};
Iterator.cycle = function (cycle, times) {
var next;
if (arguments.length < 2)
times = Infinity;
//cycle = Iterator(cycle).toArray();
return new Iterator(function () {
var iteration, nextEntry;
if(next) {
nextEntry = next();
}
if(!next || nextEntry.done === true) {
if (times > 0) {
times--;
iteration = Iterator.iterate(cycle);
nextEntry = (next = iteration.next.bind(iteration))();
}
else {
this._iterationObject.done = true;
nextEntry = this._iterationObject; }
}
return nextEntry;
});
};
Iterator.concat = function (iterators) {
iterators = Iterator(iterators);
var next;
return new Iterator(function (){
var iteration, nextEntry;
if(next) nextEntry = next();
if(!nextEntry || nextEntry.done === true) {
nextEntry = iterators.next();
if(nextEntry.done === false) {
iteration = Iterator(nextEntry.value);
next = iteration.next.bind(iteration);
return next();
}
else {
return nextEntry;
}
}
else return nextEntry;
});
};
Iterator.unzip = function (iterators) {
iterators = Iterator(iterators).map(Iterator);
if (iterators.length === 0)
return new Iterator([]);
return new Iterator(function () {
var stopped, nextEntry;
var result = iterators.map(function (iterator) {
nextEntry = iterator.next();
if (nextEntry.done === true ) {
stopped = true;
}
return nextEntry.value;
});
if (stopped) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
}
else {
this._iterationObject.value = result;
}
return this._iterationObject;
});
};
Iterator.zip = function () {
return Iterator.unzip(
Array.prototype.slice.call(arguments)
);
};
Iterator.chain = function () {
return Iterator.concat(
Array.prototype.slice.call(arguments)
);
};
Iterator.range = function (start, stop, step) {
if (arguments.length < 3) {
step = 1;
}
if (arguments.length < 2) {
stop = start;
start = 0;
}
start = start || 0;
step = step || 1;
return new Iterator(function () {
if (start >= stop) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
}
var result = start;
start += step;
this._iterationObject.value = result;
return this._iterationObject;
});
};
Iterator.count = function (start, step) {
return Iterator.range(start, Infinity, step);
};
Iterator.repeat = function (value, times) {
return new Iterator.range(times).mapIterator(function () {
return value;
});
};
},{"./generic-collection":64,"./shim-object":76}],69:[function(require,module,exports){
/*
Copyright (c) 2016, Montage Studio Inc. All Rights Reserved.
3-Clause BSD License
https://github.com/montagejs/montage/blob/master/LICENSE.md
*/
var Map = require("../_map");
var ObjectChangeDescriptor = module.exports.ObjectChangeDescriptor = function ObjectChangeDescriptor(name) {
this.name = name;
this.isActive = false;
this._willChangeListeners = null;
this._changeListeners = null;
return this;
}
Object.defineProperties(ObjectChangeDescriptor.prototype,{
name: {
value:null,
writable: true
},
isActive: {
value:false,
writable: true
},
_willChangeListeners: {
value:null,
writable: true
},
willChangeListeners: {
get: function() {
return this._willChangeListeners || (this._willChangeListeners = new this.willChangeListenersRecordConstructor(this.name));
}
},
_changeListeners: {
value:null,
writable: true
},
changeListeners: {
get: function() {
return this._changeListeners || (this._changeListeners = new this.changeListenersRecordConstructor(this.name));
}
},
changeListenersRecordConstructor: {
value:ChangeListenersRecord,
writable: true
},
willChangeListenersRecordConstructor: {
value:ChangeListenersRecord,
writable: true
}
});
var ListenerGhost = module.exports.ListenerGhost = Object.create(null);
var ChangeListenerSpecificHandlerMethodName = new Map();
module.exports.ChangeListenersRecord = ChangeListenersRecord;
function ChangeListenersRecord(name) {
var specificHandlerMethodName = ChangeListenerSpecificHandlerMethodName.get(name);
if(!specificHandlerMethodName) {
specificHandlerMethodName = "handle";
specificHandlerMethodName += name;
specificHandlerMethodName += "Change";
ChangeListenerSpecificHandlerMethodName.set(name,specificHandlerMethodName);
}
this._current = null;
this._current = null;
this.specificHandlerMethodName = specificHandlerMethodName;
return this;
}
Object.defineProperties(ChangeListenersRecord.prototype,{
_current: {
value: null,
writable: true
},
current: {
get: function() {
// if(this._current) {
// console.log(this.constructor.name," with ",this._current.length," listeners: ", this._current);
// }
return this._current;
//return this._current || (this._current = []);
},
set: function(value) {
this._current = value;
}
},
ListenerGhost: {
value:ListenerGhost,
writable: true
},
ghostCount: {
value:0,
writable: true
},
maxListenerGhostRatio: {
value:0.3,
writable: true
},
listenerGhostFilter: {
value: function listenerGhostFilter(value) {
return value !== this.ListenerGhost;
}
},
removeCurrentGostListenersIfNeeded: {
value: function() {
if(this._current && this.ghostCount/this._current.length>this.maxListenerGhostRatio) {
this.ghostCount = 0;
this._current = this._current.filter(this.listenerGhostFilter,this);
}
return this._current;
}
},
dispatchBeforeChange: {
value: false,
writable: true
},
genericHandlerMethodName: {
value: "handlePropertyChange",
writable: true
}
});
module.exports.WillChangeListenersRecord = WillChangeListenersRecord;
var WillChangeListenerSpecificHandlerMethodName = new Map();
function WillChangeListenersRecord(name) {
var specificHandlerMethodName = WillChangeListenerSpecificHandlerMethodName.get(name);
if(!specificHandlerMethodName) {
specificHandlerMethodName = "handle";
specificHandlerMethodName += name;
specificHandlerMethodName += "WillChange";
WillChangeListenerSpecificHandlerMethodName.set(name,specificHandlerMethodName);
}
this.specificHandlerMethodName = specificHandlerMethodName;
return this;
}
WillChangeListenersRecord.prototype = new ChangeListenersRecord();
WillChangeListenersRecord.prototype.constructor = WillChangeListenersRecord;
WillChangeListenersRecord.prototype.genericHandlerMethodName = "handlePropertyWillChange";
},{"../_map":61}],70:[function(require,module,exports){
"use strict";
var WeakMap = require("../weak-map"),
Map = require("../_map"),
ChangeDescriptor = require("./change-descriptor"),
ObjectChangeDescriptor = ChangeDescriptor.ObjectChangeDescriptor,
ChangeListenersRecord = ChangeDescriptor.ChangeListenersRecord,
ListenerGhost = ChangeDescriptor.ListenerGhost;
module.exports = MapChanges;
function MapChanges() {
throw new Error("Can't construct. MapChanges is a mixin.");
}
var object_owns = Object.prototype.hasOwnProperty;
/*
Object map change descriptors carry information necessary for adding,
removing, dispatching, and shorting events to listeners for map changes
for a particular key on a particular object. These descriptors are used
here for shallow map changes.
{
willChangeListeners:Array(Fgunction)
changeListeners:Array(Function)
}
*/
var mapChangeDescriptors = new WeakMap();
function MapChangeDescriptor(name) {
this.name = name;
this.isActive = false;
this._willChangeListeners = null;
this._changeListeners = null;
};
MapChangeDescriptor.prototype = new ObjectChangeDescriptor();
MapChangeDescriptor.prototype.constructor = MapChangeDescriptor;
MapChangeDescriptor.prototype.changeListenersRecordConstructor = MapChangeListenersRecord;
MapChangeDescriptor.prototype.willChangeListenersRecordConstructor = MapWillChangeListenersRecord;
var MapChangeListenersSpecificHandlerMethodName = new Map();
function MapChangeListenersRecord(name) {
var specificHandlerMethodName = MapChangeListenersSpecificHandlerMethodName.get(name);
if(!specificHandlerMethodName) {
specificHandlerMethodName = "handle";
specificHandlerMethodName += name.slice(0, 1).toUpperCase();
specificHandlerMethodName += name.slice(1);
specificHandlerMethodName += "MapChange";
MapChangeListenersSpecificHandlerMethodName.set(name,specificHandlerMethodName);
}
this.specificHandlerMethodName = specificHandlerMethodName;
return this;
}
MapChangeListenersRecord.prototype = new ChangeListenersRecord();
MapChangeListenersRecord.prototype.constructor = MapChangeListenersRecord;
MapChangeListenersRecord.prototype.genericHandlerMethodName = "handleMapChange";
var MapWillChangeListenersSpecificHandlerMethodName = new Map();
function MapWillChangeListenersRecord(name) {
var specificHandlerMethodName = MapWillChangeListenersSpecificHandlerMethodName.get(name);
if(!specificHandlerMethodName) {
specificHandlerMethodName = "handle";
specificHandlerMethodName += name.slice(0, 1).toUpperCase();
specificHandlerMethodName += name.slice(1);
specificHandlerMethodName += "MapWillChange";
MapWillChangeListenersSpecificHandlerMethodName.set(name,specificHandlerMethodName);
}
this.specificHandlerMethodName = specificHandlerMethodName;
return this;
}
MapWillChangeListenersRecord.prototype = new ChangeListenersRecord();
MapWillChangeListenersRecord.prototype.constructor = MapWillChangeListenersRecord;
MapWillChangeListenersRecord.prototype.genericHandlerMethodName = "handleMapWillChange";
MapChanges.prototype.getAllMapChangeDescriptors = function () {
if (!mapChangeDescriptors.has(this)) {
mapChangeDescriptors.set(this, new Map());
}
return mapChangeDescriptors.get(this);
};
MapChanges.prototype.getMapChangeDescriptor = function (token) {
var tokenChangeDescriptors = this.getAllMapChangeDescriptors();
token = token || "";
if (!tokenChangeDescriptors.has(token)) {
tokenChangeDescriptors.set(token, new MapChangeDescriptor(token));
}
return tokenChangeDescriptors.get(token);
};
var ObjectsDispatchesMapChanges = new WeakMap(),
dispatchesMapChangesGetter = function() {
return ObjectsDispatchesMapChanges.get(this);
},
dispatchesMapChangesSetter = function(value) {
return ObjectsDispatchesMapChanges.set(this,value);
},
dispatchesChangesMethodName = "dispatchesMapChanges",
dispatchesChangesPropertyDescriptor = {
get: dispatchesMapChangesGetter,
set: dispatchesMapChangesSetter,
configurable: true,
enumerable: false
};
MapChanges.prototype.addMapChangeListener = function addMapChangeListener(listener, token, beforeChange) {
//console.log("this:",this," addMapChangeListener(",listener,",",token,",",beforeChange);
if (!this.isObservable && this.makeObservable) {
// for Array
this.makeObservable();
}
var descriptor = this.getMapChangeDescriptor(token);
var listeners;
if (beforeChange) {
listeners = descriptor.willChangeListeners;
} else {
listeners = descriptor.changeListeners;
}
// console.log("addMapChangeListener()",listener, token);
//console.log("this:",this," addMapChangeListener() listeners._current is ",listeners._current);
if(!listeners._current) {
listeners._current = listener;
}
else if(!Array.isArray(listeners._current)) {
listeners._current = [listeners._current,listener]
}
else {
listeners._current.push(listener);
}
if(Object.getOwnPropertyDescriptor((this.__proto__||Object.getPrototypeOf(this)),dispatchesChangesMethodName) === void 0) {
Object.defineProperty((this.__proto__||Object.getPrototypeOf(this)), dispatchesChangesMethodName, dispatchesChangesPropertyDescriptor);
}
this.dispatchesMapChanges = true;
var self = this;
return function cancelMapChangeListener() {
if (!self) {
// TODO throw new Error("Can't remove map change listener again");
return;
}
self.removeMapChangeListener(listener, token, beforeChange);
self = null;
};
};
MapChanges.prototype.removeMapChangeListener = function (listener, token, beforeChange) {
var descriptor = this.getMapChangeDescriptor(token);
var listeners;
if (beforeChange) {
listeners = descriptor.willChangeListeners;
} else {
listeners = descriptor.changeListeners;
}
if(listeners._current) {
if(listeners._current === listener) {
listeners._current = null;
}
else {
var index = listeners._current.lastIndexOf(listener);
if (index === -1) {
throw new Error("Can't remove map change listener: does not exist: token " + JSON.stringify(token));
}
else {
if(descriptor.isActive) {
listeners.ghostCount = listeners.ghostCount+1
listeners._current[index]=ListenerGhost
}
else {
listeners._current.spliceOne(index);
}
}
}
}
};
MapChanges.prototype.dispatchMapChange = function (key, value, beforeChange) {
var descriptors = this.getAllMapChangeDescriptors(),
Ghost = ListenerGhost;
descriptors.forEach(function (descriptor, token) {
if (descriptor.isActive) {
return;
}
var listeners = beforeChange ? descriptor.willChangeListeners : descriptor.changeListeners;
if(listeners && listeners._current) {
var tokenName = listeners.specificHandlerMethodName;
if(Array.isArray(listeners._current) && listeners._current.length) {
//removeGostListenersIfNeeded returns listeners.current or a new filtered one when conditions are met
var currentListeners = listeners.removeCurrentGostListenersIfNeeded(),
i, countI, listener;
descriptor.isActive = true;
try {
for(i=0, countI = currentListeners.length;i<countI;i++) {
// dispatch to each listener
if ((listener = currentListeners[i]) !== Ghost) {
if (listener[tokenName]) {
listener[tokenName](value, key, this);
} else if (listener.call) {
listener.call(listener, value, key, this);
} else {
throw new Error("Handler " + listener + " has no method " + tokenName + " and is not callable");
}
}
}
} finally {
descriptor.isActive = false;
}
}
else {
descriptor.isActive = true;
// dispatch each listener
try {
listener = listeners._current;
if (listener[tokenName]) {
listener[tokenName](value, key, this);
} else if (listener.call) {
listener.call(listener, value, key, this);
} else {
throw new Error("Handler " + listener + " has no method " + tokenName + " and is not callable");
}
} finally {
descriptor.isActive = false;
}
}
}
}, this);
};
MapChanges.prototype.addBeforeMapChangeListener = function (listener, token) {
return this.addMapChangeListener(listener, token, true);
};
MapChanges.prototype.removeBeforeMapChangeListener = function (listener, token) {
return this.removeMapChangeListener(listener, token, true);
};
MapChanges.prototype.dispatchBeforeMapChange = function (key, value) {
return this.dispatchMapChange(key, value, true);
};
},{"../_map":61,"../weak-map":80,"./change-descriptor":69}],71:[function(require,module,exports){
/*
Based in part on observable arrays from Motorola Mobility’s Montage
Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved.
3-Clause BSD License
https://github.com/motorola-mobility/montage/blob/master/LICENSE.md
*/
/*
This module is responsible for observing changes to owned properties of
objects and changes to the content of arrays caused by method calls.
The interface for observing array content changes establishes the methods
necessary for any collection with observable content.
*/
// objectHasOwnProperty.call(myObject, key) will be used instead of
// myObject.hasOwnProperty(key) to allow myObject have defined
// a own property called "hasOwnProperty".
var objectHasOwnProperty = Object.prototype.hasOwnProperty;
// Object property descriptors carry information necessary for adding,
// removing, dispatching, and shorting events to listeners for property changes
// for a particular key on a particular object. These descriptors are used
// here for shallow property changes. The current listeners are the ones
// modified by add and remove own property change listener methods. During
// property change dispatch, we capture a snapshot of the current listeners in
// the active change listeners array. The descriptor also keeps a memo of the
// corresponding handler method names.
//
// {
// willChangeListeners:{current, active:Array<Function>, ...method names}
// changeListeners:{current, active:Array<Function>, ...method names}
// }
// Maybe remove entries from this table if the corresponding object no longer
// has any property change listeners for any key. However, the cost of
// book-keeping is probably not warranted since it would be rare for an
// observed object to no longer be observed unless it was about to be disposed
// of or reused as an observable. The only benefit would be in avoiding bulk
// calls to dispatchOwnPropertyChange events on objects that have no listeners.
// To observe shallow property changes for a particular key of a particular
// object, we install a property descriptor on the object that overrides the previous
// descriptor. The overridden descriptors are stored in this weak map. The
// weak map associates an object with another object that maps property names
// to property descriptors.
//
// object.__overriddenPropertyDescriptors__[key]
//
// We retain the old descriptor for various purposes. For one, if the property
// is no longer being observed by anyone, we revert the property descriptor to
// the original. For "value" descriptors, we store the actual value of the
// descriptor on the overridden descriptor, so when the property is reverted, it
// retains the most recently set value. For "get" and "set" descriptors,
// we observe then forward "get" and "set" operations to the original descriptor.
module.exports = PropertyChanges;
function PropertyChanges() {
throw new Error("This is an abstract interface. Mix it. Don't construct it");
}
require("../shim");
var Map = require("../_map");
var WeakMap = require("../weak-map");
var ChangeDescriptor = require("./change-descriptor"),
ObjectChangeDescriptor = ChangeDescriptor.ObjectChangeDescriptor,
ListenerGhost = ChangeDescriptor.ListenerGhost;
PropertyChanges.debug = true;
var ObjectsPropertyChangeListeners = new WeakMap();
var ObjectChangeDescriptorName = new Map();
PropertyChanges.ObjectChangeDescriptor = function() {
}
PropertyChanges.prototype.getOwnPropertyChangeDescriptor = function (key) {
var objectPropertyChangeDescriptors = ObjectsPropertyChangeListeners.get(this), keyChangeDescriptor;
if (!objectPropertyChangeDescriptors) {
objectPropertyChangeDescriptors = Object.create(null);
ObjectsPropertyChangeListeners.set(this,objectPropertyChangeDescriptors);
}
if ( (keyChangeDescriptor = objectPropertyChangeDescriptors[key]) === void 0) {
var propertyName = ObjectChangeDescriptorName.get(key);
if(!propertyName) {
propertyName = String(key);
propertyName = propertyName && propertyName[0].toUpperCase() + propertyName.slice(1);
ObjectChangeDescriptorName.set(key,propertyName);
}
return objectPropertyChangeDescriptors[key] = new ObjectChangeDescriptor(propertyName);
}
else return keyChangeDescriptor;
};
PropertyChanges.prototype.hasOwnPropertyChangeDescriptor = function (key) {
var objectPropertyChangeDescriptors = ObjectsPropertyChangeListeners.get(this);
if (!objectPropertyChangeDescriptors) {
return false;
}
if (!key) {
return true;
}
if (objectPropertyChangeDescriptors[key] === void 0) {
return false;
}
return true;
};
PropertyChanges.prototype.addOwnPropertyChangeListener = function (key, listener, beforeChange) {
if (this.makeObservable && !this.isObservable) {
this.makeObservable(); // particularly for observable arrays, for
// their length property
}
var descriptor = PropertyChanges.getOwnPropertyChangeDescriptor(this, key),
listeners = beforeChange ? descriptor.willChangeListeners : descriptor.changeListeners;
PropertyChanges.makePropertyObservable(this, key);
if(!listeners._current) {
listeners._current = listener;
}
else if(!Array.isArray(listeners._current)) {
listeners._current = [listeners._current,listener]
}
else {
listeners._current.push(listener);
}
var self = this;
return function cancelOwnPropertyChangeListener() {
PropertyChanges.removeOwnPropertyChangeListener(self, key, listener, beforeChange);
self = null;
};
};
PropertyChanges.prototype.addBeforeOwnPropertyChangeListener = function (key, listener) {
return PropertyChanges.addOwnPropertyChangeListener(this, key, listener, true);
};
PropertyChanges.prototype.removeOwnPropertyChangeListener = function removeOwnPropertyChangeListener(key, listener, beforeChange) {
var descriptor = PropertyChanges.getOwnPropertyChangeDescriptor(this, key);
var listeners;
if (beforeChange) {
listeners = descriptor._willChangeListeners;
} else {
listeners = descriptor._changeListeners;
}
if(listeners) {
if(listeners._current) {
if(listeners._current === listener) {
listeners._current = null;
}
else {
var index = listeners._current.lastIndexOf(listener);
if (index === -1) {
throw new Error("Can't remove property change listener: does not exist: property name" + JSON.stringify(key));
}
if(descriptor.isActive) {
listeners.ghostCount = listeners.ghostCount+1;
listeners._current[index]=removeOwnPropertyChangeListener.ListenerGhost;
}
else {
listeners._current.spliceOne(index);
}
}
}
}
};
PropertyChanges.prototype.removeOwnPropertyChangeListener.ListenerGhost = ListenerGhost;
PropertyChanges.prototype.removeBeforeOwnPropertyChangeListener = function (key, listener) {
return PropertyChanges.removeOwnPropertyChangeListener(this, key, listener, true);
};
PropertyChanges.prototype.dispatchOwnPropertyChange = function dispatchOwnPropertyChange(key, value, beforeChange) {
var descriptor = PropertyChanges.getOwnPropertyChangeDescriptor(this, key),
listeners;
if (!descriptor.isActive) {
descriptor.isActive = true;
listeners = beforeChange ? descriptor._willChangeListeners: descriptor._changeListeners;
try {
dispatchOwnPropertyChange.dispatchEach(listeners, key, value, this);
} finally {
descriptor.isActive = false;
}
}
};
PropertyChanges.prototype.dispatchOwnPropertyChange.dispatchEach = dispatchEach;
function dispatchEach(listeners, key, value, object) {
if(listeners && listeners._current) {
// copy snapshot of current listeners to active listeners
var current,
listener,
i,
countI,
thisp,
specificHandlerMethodName = listeners.specificHandlerMethodName,
genericHandlerMethodName = listeners.genericHandlerMethodName,
Ghost = ListenerGhost;
if(Array.isArray(listeners._current)) {
//removeGostListenersIfNeeded returns listeners.current or a new filtered one when conditions are met
current = listeners.removeCurrentGostListenersIfNeeded();
//We use a for to guarantee we won't dispatch to listeners that would be added after we started
for(i=0, countI = current.length;i<countI;i++) {
if ((thisp = current[i]) !== Ghost) {
//This is fixing the issue causing a regression in Montage's repetition
listener = (
thisp[specificHandlerMethodName] ||
thisp[genericHandlerMethodName] ||
thisp
);
if (!listener.call) {
throw new Error("No event listener for " + listeners.specificHandlerName + " or " + listeners.genericHandlerName + " or call on " + listener);
}
listener.call(thisp, value, key, object);
}
}
}
else {
thisp = listeners._current;
listener = (
thisp[specificHandlerMethodName] ||
thisp[genericHandlerMethodName] ||
thisp
);
if (!listener.call) {
throw new Error("No event listener for " + listeners.specificHandlerName + " or " + listeners.genericHandlerName + " or call on " + listener);
}
listener.call(thisp, value, key, object);
}
}
}
dispatchEach.ListenerGhost = ListenerGhost;
PropertyChanges.prototype.dispatchBeforeOwnPropertyChange = function (key, listener) {
return PropertyChanges.dispatchOwnPropertyChange(this, key, listener, true);
};
var ObjectsOverriddenPropertyDescriptors = new WeakMap(),
Objects__state__ = new WeakMap(),
propertyListener = {
get: void 0,
set: void 0,
configurable: true,
enumerable: false
};
PropertyChanges.prototype.makePropertyObservable = function (key) {
// arrays are special. we do not support direct setting of properties
// on an array. instead, call .set(index, value). this is observable.
// 'length' property is observable for all mutating methods because
// our overrides explicitly dispatch that change.
var overriddenPropertyDescriptors = ObjectsOverriddenPropertyDescriptors.get(this);
if (overriddenPropertyDescriptors && overriddenPropertyDescriptors.get(key) !== void 0) {
// if we have already recorded an overridden property descriptor,
// we have already installed the observer, so short-here
return;
}
// memoize overridden property descriptor table
if (!overriddenPropertyDescriptors) {
if (Array.isArray(this)) {
return;
}
if (!Object.isExtensible(this)) {
throw new Error("Can't make property " + JSON.stringify(key) + " observable on " + this + " because object is not extensible");
}
overriddenPropertyDescriptors = new Map();
ObjectsOverriddenPropertyDescriptors.set(this,overriddenPropertyDescriptors);
}
// var state = Objects__state__.get(this);
// if (typeof state !== "object") {
// Objects__state__.set(this,(state = {}));
// }
// state[key] = this[key];
// walk up the prototype chain to find a property descriptor for
// the property name
var overriddenDescriptor;
var attached = this;
do {
overriddenDescriptor = Object.getOwnPropertyDescriptor(attached, key);
if (overriddenDescriptor) {
break;
}
attached = Object.getPrototypeOf(attached);
} while (attached);
// or default to an undefined value
if (!overriddenDescriptor) {
overriddenDescriptor = {
value: void 0,
enumerable: true,
writable: true,
configurable: true
};
} else {
if (!overriddenDescriptor.configurable) {
return;
}
if (!overriddenDescriptor.writable && !overriddenDescriptor.set) {
return;
}
}
// memoize the descriptor so we know not to install another layer,
// and so we can reuse the overridden descriptor when uninstalling
overriddenPropertyDescriptors.set(key,overriddenDescriptor);
// TODO reflect current value on a displayed property
// in both of these new descriptor variants, we reuse the overridden
// descriptor to either store the current value or apply getters
// and setters. this is handy since we can reuse the overridden
// descriptor if we uninstall the observer. We even preserve the
// assignment semantics, where we get the value from up the
// prototype chain, and set as an owned property.
if ('value' in overriddenDescriptor) {
propertyListener.get = function dispatchingGetter() {
return dispatchingGetter.overriddenDescriptor.value;
};
propertyListener.set = function dispatchingSetter(value) {
var descriptor,
isActive,
overriddenDescriptor = dispatchingSetter.overriddenDescriptor;
if (value !== overriddenDescriptor.value) {
if (!(isActive = (descriptor = dispatchingSetter.descriptor).isActive)) {
descriptor.isActive = true;
try {
dispatchingSetter.dispatchEach(descriptor._willChangeListeners, dispatchingSetter.key, overriddenDescriptor.value, this);
} finally {}
}
overriddenDescriptor.value = value;
if (!isActive) {
try {
dispatchingSetter.dispatchEach(descriptor._changeListeners, dispatchingSetter.key, value, this);
} finally {
descriptor.isActive = false;
}
}
}
};
propertyListener.set.dispatchEach = dispatchEach;
propertyListener.set.key = key;
propertyListener.get.overriddenDescriptor = propertyListener.set.overriddenDescriptor = overriddenDescriptor;
propertyListener.set.descriptor = ObjectsPropertyChangeListeners.get(this)[key];
propertyListener.enumerable = overriddenDescriptor.enumerable;
propertyListener.configurable = true
} else { // 'get' or 'set', but not necessarily both
propertyListener.get = overriddenDescriptor.get;
propertyListener.set = function dispatchingSetter() {
var formerValue = dispatchingSetter.overriddenGetter.call(this),
descriptor,
isActive,
newValue;
if(arguments.length === 1) {
dispatchingSetter.overriddenSetter.call(this,arguments[0]);
}
else if(arguments.length === 2) {
dispatchingSetter.overriddenSetter.call(this,arguments[0],arguments[1]);
}
else {
dispatchingSetter.overriddenSetter.apply(this, arguments);
}
if ((newValue = dispatchingSetter.overriddenGetter.call(this)) !== formerValue) {
descriptor = dispatchingSetter.descriptor;
if (!(isActive = descriptor.isActive)) {
descriptor.isActive = true;
try {
dispatchingSetter.dispatchEach(descriptor._willChangeListeners, key, formerValue, this);
} finally {}
}
if (!isActive) {
try {
dispatchingSetter.dispatchEach(descriptor._changeListeners, key, newValue, this);
} finally {
descriptor.isActive = false;
}
}
}
};
propertyListener.enumerable = overriddenDescriptor.enumerable;
propertyListener.configurable = true;
propertyListener.set.dispatchEach = dispatchEach;
propertyListener.set.overriddenSetter = overriddenDescriptor.set;
propertyListener.set.overriddenGetter = overriddenDescriptor.get;
propertyListener.set.descriptor = ObjectsPropertyChangeListeners.get(this)[key];
}
Object.defineProperty(this, key, propertyListener);
};
// constructor functions
PropertyChanges.getOwnPropertyChangeDescriptor = function (object, key) {
if (object.getOwnPropertyChangeDescriptor) {
return object.getOwnPropertyChangeDescriptor(key);
} else {
return PropertyChanges.prototype.getOwnPropertyChangeDescriptor.call(object, key);
}
};
PropertyChanges.hasOwnPropertyChangeDescriptor = function (object, key) {
if (object.hasOwnPropertyChangeDescriptor) {
return object.hasOwnPropertyChangeDescriptor(key);
} else {
return PropertyChanges.prototype.hasOwnPropertyChangeDescriptor.call(object, key);
}
};
PropertyChanges.addOwnPropertyChangeListener = function (object, key, listener, beforeChange) {
if (Object.isObject(object)) {
return object.addOwnPropertyChangeListener
? object.addOwnPropertyChangeListener(key, listener, beforeChange)
: this.prototype.addOwnPropertyChangeListener.call(object, key, listener, beforeChange);
}
};
PropertyChanges.removeOwnPropertyChangeListener = function (object, key, listener, beforeChange) {
if (!Object.isObject(object)) {
} else if (object.removeOwnPropertyChangeListener) {
return object.removeOwnPropertyChangeListener(key, listener, beforeChange);
} else {
return PropertyChanges.prototype.removeOwnPropertyChangeListener.call(object, key, listener, beforeChange);
}
};
PropertyChanges.dispatchOwnPropertyChange = function (object, key, value, beforeChange) {
if (!Object.isObject(object)) {
} else if (object.dispatchOwnPropertyChange) {
return object.dispatchOwnPropertyChange(key, value, beforeChange);
} else {
return PropertyChanges.prototype.dispatchOwnPropertyChange.call(object, key, value, beforeChange);
}
};
PropertyChanges.addBeforeOwnPropertyChangeListener = function (object, key, listener) {
return PropertyChanges.addOwnPropertyChangeListener(object, key, listener, true);
};
PropertyChanges.removeBeforeOwnPropertyChangeListener = function (object, key, listener) {
return PropertyChanges.removeOwnPropertyChangeListener(object, key, listener, true);
};
PropertyChanges.dispatchBeforeOwnPropertyChange = function (object, key, value) {
return PropertyChanges.dispatchOwnPropertyChange(object, key, value, true);
};
PropertyChanges.makePropertyObservable = function (object, key) {
if (object.makePropertyObservable) {
return object.makePropertyObservable(key);
} else {
return PropertyChanges.prototype.makePropertyObservable.call(object, key);
}
};
},{"../_map":61,"../shim":78,"../weak-map":80,"./change-descriptor":69}],72:[function(require,module,exports){
(function (global){
"use strict";
var Map = require("./_map");
var PropertyChanges = require("./listen/property-changes");
var MapChanges = require("./listen/map-changes");
module.exports = Map;
if((global.Map === void 0) || (typeof global.Set.prototype.values !== "function")) {
Object.addEach(Map.prototype, PropertyChanges.prototype);
Object.addEach(Map.prototype, MapChanges.prototype);
}
else {
Object.defineEach(Map.prototype, PropertyChanges.prototype, false, /*configurable*/true, /*enumerable*/ false, /*writable*/true);
Object.defineEach(Map.prototype, MapChanges.prototype, false, /*configurable*/true, /*enumerable*/ false, /*writable*/true);
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./_map":61,"./listen/map-changes":70,"./listen/property-changes":71}],73:[function(require,module,exports){
// Copyright (C) 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Install a leaky WeakMap emulation on platforms that
* don't provide a built-in one.
*
* <p>Assumes that an ES5 platform where, if {@code WeakMap} is
* already present, then it conforms to the anticipated ES6
* specification. To run this file on an ES5 or almost ES5
* implementation where the {@code WeakMap} specification does not
* quite conform, run <code>repairES5.js</code> first.
*
* <p>Even though WeakMapModule is not global, the linter thinks it
* is, which is why it is in the overrides list below.
*
* <p>NOTE: Before using this WeakMap emulation in a non-SES
* environment, see the note below about hiddenRecord.
*
* @author Mark S. Miller
* @requires crypto, ArrayBuffer, Uint8Array, navigator, console
* @overrides WeakMap, ses, Proxy
* @overrides WeakMapModule
*/
/**
* This {@code WeakMap} emulation is observably equivalent to the
* ES-Harmony WeakMap, but with leakier garbage collection properties.
*
* <p>As with true WeakMaps, in this emulation, a key does not
* retain maps indexed by that key and (crucially) a map does not
* retain the keys it indexes. A map by itself also does not retain
* the values associated with that map.
*
* <p>However, the values associated with a key in some map are
* retained so long as that key is retained and those associations are
* not overridden. For example, when used to support membranes, all
* values exported from a given membrane will live for the lifetime
* they would have had in the absence of an interposed membrane. Even
* when the membrane is revoked, all objects that would have been
* reachable in the absence of revocation will still be reachable, as
* far as the GC can tell, even though they will no longer be relevant
* to ongoing computation.
*
* <p>The API implemented here is approximately the API as implemented
* in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman,
* rather than the offially approved proposal page. TODO(erights):
* upgrade the ecmascript WeakMap proposal page to explain this API
* change and present to EcmaScript committee for their approval.
*
* <p>The first difference between the emulation here and that in
* FF6.0a1 is the presence of non enumerable {@code get___, has___,
* set___, and delete___} methods on WeakMap instances to represent
* what would be the hidden internal properties of a primitive
* implementation. Whereas the FF6.0a1 WeakMap.prototype methods
* require their {@code this} to be a genuine WeakMap instance (i.e.,
* an object of {@code [[Class]]} "WeakMap}), since there is nothing
* unforgeable about the pseudo-internal method names used here,
* nothing prevents these emulated prototype methods from being
* applied to non-WeakMaps with pseudo-internal methods of the same
* names.
*
* <p>Another difference is that our emulated {@code
* WeakMap.prototype} is not itself a WeakMap. A problem with the
* current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap
* providing ambient mutability and an ambient communications
* channel. Thus, if a WeakMap is already present and has this
* problem, repairES5.js wraps it in a safe wrappper in order to
* prevent access to this channel. (See
* PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js).
*/
/**
* If this is a full <a href=
* "http://code.google.com/p/es-lab/wiki/SecureableES5"
* >secureable ES5</a> platform and the ES-Harmony {@code WeakMap} is
* absent, install an approximate emulation.
*
* <p>If WeakMap is present but cannot store some objects, use our approximate
* emulation as a wrapper.
*
* <p>If this is almost a secureable ES5 platform, then WeakMap.js
* should be run after repairES5.js.
*
* <p>See {@code WeakMap} for documentation of the garbage collection
* properties of this WeakMap emulation.
*/
(function WeakMapModule() {
"use strict";
if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) {
// already too broken, so give up
return;
}
/**
* In some cases (current Firefox), we must make a choice betweeen a
* WeakMap which is capable of using all varieties of host objects as
* keys and one which is capable of safely using proxies as keys. See
* comments below about HostWeakMap and DoubleWeakMap for details.
*
* This function (which is a global, not exposed to guests) marks a
* WeakMap as permitted to do what is necessary to index all host
* objects, at the cost of making it unsafe for proxies.
*
* Do not apply this function to anything which is not a genuine
* fresh WeakMap.
*/
function weakMapPermitHostObjects(map) {
// identity of function used as a secret -- good enough and cheap
if (map.permitHostObjects___) {
map.permitHostObjects___(weakMapPermitHostObjects);
}
}
if (typeof ses !== 'undefined') {
ses.weakMapPermitHostObjects = weakMapPermitHostObjects;
}
// IE 11 has no Proxy but has a broken WeakMap such that we need to patch
// it using DoubleWeakMap; this flag tells DoubleWeakMap so.
var doubleWeakMapCheckSilentFailure = false;
// Check if there is already a good-enough WeakMap implementation, and if so
// exit without replacing it.
if (typeof WeakMap === 'function') {
var HostWeakMap = WeakMap;
// There is a WeakMap -- is it good enough?
if (typeof navigator !== 'undefined' &&
/Firefox/.test(navigator.userAgent)) {
// We're now *assuming not*, because as of this writing (2013-05-06)
// Firefox's WeakMaps have a miscellany of objects they won't accept, and
// we don't want to make an exhaustive list, and testing for just one
// will be a problem if that one is fixed alone (as they did for Event).
// If there is a platform that we *can* reliably test on, here's how to
// do it:
// var problematic = ... ;
// var testHostMap = new HostWeakMap();
// try {
// testHostMap.set(problematic, 1); // Firefox 20 will throw here
// if (testHostMap.get(problematic) === 1) {
// return;
// }
// } catch (e) {}
} else {
// IE 11 bug: WeakMaps silently fail to store frozen objects.
var testMap = new HostWeakMap();
var testObject = Object.freeze({});
testMap.set(testObject, 1);
if (testMap.get(testObject) !== 1) {
doubleWeakMapCheckSilentFailure = true;
// Fall through to installing our WeakMap.
} else {
module.exports = WeakMap;
return;
}
}
}
var hop = Object.prototype.hasOwnProperty;
var gopn = Object.getOwnPropertyNames;
var defProp = Object.defineProperty;
var isExtensible = Object.isExtensible;
/**
* Security depends on HIDDEN_NAME being both <i>unguessable</i> and
* <i>undiscoverable</i> by untrusted code.
*
* <p>Given the known weaknesses of Math.random() on existing
* browsers, it does not generate unguessability we can be confident
* of.
*
* <p>It is the monkey patching logic in this file that is intended
* to ensure undiscoverability. The basic idea is that there are
* three fundamental means of discovering properties of an object:
* The for/in loop, Object.keys(), and Object.getOwnPropertyNames(),
* as well as some proposed ES6 extensions that appear on our
* whitelist. The first two only discover enumerable properties, and
* we only use HIDDEN_NAME to name a non-enumerable property, so the
* only remaining threat should be getOwnPropertyNames and some
* proposed ES6 extensions that appear on our whitelist. We monkey
* patch them to remove HIDDEN_NAME from the list of properties they
* returns.
*
* <p>TODO(erights): On a platform with built-in Proxies, proxies
* could be used to trap and thereby discover the HIDDEN_NAME, so we
* need to monkey patch Proxy.create, Proxy.createFunction, etc, in
* order to wrap the provided handler with the real handler which
* filters out all traps using HIDDEN_NAME.
*
* <p>TODO(erights): Revisit Mike Stay's suggestion that we use an
* encapsulated function at a not-necessarily-secret name, which
* uses the Stiegler shared-state rights amplification pattern to
* reveal the associated value only to the WeakMap in which this key
* is associated with that value. Since only the key retains the
* function, the function can also remember the key without causing
* leakage of the key, so this doesn't violate our general gc
* goals. In addition, because the name need not be a guarded
* secret, we could efficiently handle cross-frame frozen keys.
*/
var HIDDEN_NAME_PREFIX = 'weakmap:';
var HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'ident:' + Math.random() + '___';
if (typeof crypto !== 'undefined' &&
typeof crypto.getRandomValues === 'function' &&
typeof ArrayBuffer === 'function' &&
typeof Uint8Array === 'function') {
var ab = new ArrayBuffer(25);
var u8s = new Uint8Array(ab);
crypto.getRandomValues(u8s);
HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'rand:' +
Array.prototype.map.call(u8s, function(u8) {
return (u8 % 36).toString(36);
}).join('') + '___';
}
function isNotHiddenName(name) {
return !(
name.substr(0, HIDDEN_NAME_PREFIX.length) == HIDDEN_NAME_PREFIX &&
name.substr(name.length - 3) === '___');
}
/**
* Monkey patch getOwnPropertyNames to avoid revealing the
* HIDDEN_NAME.
*
* <p>The ES5.1 spec requires each name to appear only once, but as
* of this writing, this requirement is controversial for ES6, so we
* made this code robust against this case. If the resulting extra
* search turns out to be expensive, we can probably relax this once
* ES6 is adequately supported on all major browsers, iff no browser
* versions we support at that time have relaxed this constraint
* without providing built-in ES6 WeakMaps.
*/
defProp(Object, 'getOwnPropertyNames', {
value: function fakeGetOwnPropertyNames(obj) {
return gopn(obj).filter(isNotHiddenName);
}
});
/**
* getPropertyNames is not in ES5 but it is proposed for ES6 and
* does appear in our whitelist, so we need to clean it too.
*/
if ('getPropertyNames' in Object) {
var originalGetPropertyNames = Object.getPropertyNames;
defProp(Object, 'getPropertyNames', {
value: function fakeGetPropertyNames(obj) {
return originalGetPropertyNames(obj).filter(isNotHiddenName);
}
});
}
/**
* <p>To treat objects as identity-keys with reasonable efficiency
* on ES5 by itself (i.e., without any object-keyed collections), we
* need to add a hidden property to such key objects when we
* can. This raises several issues:
* <ul>
* <li>Arranging to add this property to objects before we lose the
* chance, and
* <li>Hiding the existence of this new property from most
* JavaScript code.
* <li>Preventing <i>certification theft</i>, where one object is
* created falsely claiming to be the key of an association
* actually keyed by another object.
* <li>Preventing <i>value theft</i>, where untrusted code with
* access to a key object but not a weak map nevertheless
* obtains access to the value associated with that key in that
* weak map.
* </ul>
* We do so by
* <ul>
* <li>Making the name of the hidden property unguessable, so "[]"
* indexing, which we cannot intercept, cannot be used to access
* a property without knowing the name.
* <li>Making the hidden property non-enumerable, so we need not
* worry about for-in loops or {@code Object.keys},
* <li>monkey patching those reflective methods that would
* prevent extensions, to add this hidden property first,
* <li>monkey patching those methods that would reveal this
* hidden property.
* </ul>
* Unfortunately, because of same-origin iframes, we cannot reliably
* add this hidden property before an object becomes
* non-extensible. Instead, if we encounter a non-extensible object
* without a hidden record that we can detect (whether or not it has
* a hidden record stored under a name secret to us), then we just
* use the key object itself to represent its identity in a brute
* force leaky map stored in the weak map, losing all the advantages
* of weakness for these.
*/
function getHiddenRecord(key) {
if (key !== Object(key)) {
throw new TypeError('Not an object: ' + key);
}
var hiddenRecord = key[HIDDEN_NAME];
if (hiddenRecord && hiddenRecord.key === key) { return hiddenRecord; }
if (!isExtensible(key)) {
// Weak map must brute force, as explained in doc-comment above.
return void 0;
}
// The hiddenRecord and the key point directly at each other, via
// the "key" and HIDDEN_NAME properties respectively. The key
// field is for quickly verifying that this hidden record is an
// own property, not a hidden record from up the prototype chain.
//
// NOTE: Because this WeakMap emulation is meant only for systems like
// SES where Object.prototype is frozen without any numeric
// properties, it is ok to use an object literal for the hiddenRecord.
// This has two advantages:
// * It is much faster in a performance critical place
// * It avoids relying on Object.create(null), which had been
// problematic on Chrome 28.0.1480.0. See
// https://code.google.com/p/google-caja/issues/detail?id=1687
hiddenRecord = { key: key };
// When using this WeakMap emulation on platforms where
// Object.prototype might not be frozen and Object.create(null) is
// reliable, use the following two commented out lines instead.
// hiddenRecord = Object.create(null);
// hiddenRecord.key = key;
// Please contact us if you need this to work on platforms where
// Object.prototype might not be frozen and
// Object.create(null) might not be reliable.
try {
defProp(key, HIDDEN_NAME, {
value: hiddenRecord,
writable: false,
enumerable: false,
configurable: false
});
return hiddenRecord;
} catch (error) {
// Under some circumstances, isExtensible seems to misreport whether
// the HIDDEN_NAME can be defined.
// The circumstances have not been isolated, but at least affect
// Node.js v0.10.26 on TravisCI / Linux, but not the same version of
// Node.js on OS X.
return void 0;
}
}
/**
* Monkey patch operations that would make their argument
* non-extensible.
*
* <p>The monkey patched versions throw a TypeError if their
* argument is not an object, so it should only be done to functions
* that should throw a TypeError anyway if their argument is not an
* object.
*/
(function(){
var oldFreeze = Object.freeze;
defProp(Object, 'freeze', {
value: function identifyingFreeze(obj) {
getHiddenRecord(obj);
return oldFreeze(obj);
}
});
var oldSeal = Object.seal;
defProp(Object, 'seal', {
value: function identifyingSeal(obj) {
getHiddenRecord(obj);
return oldSeal(obj);
}
});
var oldPreventExtensions = Object.preventExtensions;
defProp(Object, 'preventExtensions', {
value: function identifyingPreventExtensions(obj) {
getHiddenRecord(obj);
return oldPreventExtensions(obj);
}
});
})();
function constFunc(func) {
func.prototype = null;
return Object.freeze(func);
}
var calledAsFunctionWarningDone = false;
function calledAsFunctionWarning() {
// Future ES6 WeakMap is currently (2013-09-10) expected to reject WeakMap()
// but we used to permit it and do it ourselves, so warn only.
if (!calledAsFunctionWarningDone && typeof console !== 'undefined') {
calledAsFunctionWarningDone = true;
console.warn('WeakMap should be invoked as new WeakMap(), not ' +
'WeakMap(). This will be an error in the future.');
}
}
var nextId = 0;
var OurWeakMap = function() {
if (!(this instanceof OurWeakMap)) { // approximate test for new ...()
calledAsFunctionWarning();
}
// We are currently (12/25/2012) never encountering any prematurely
// non-extensible keys.
var keys = []; // brute force for prematurely non-extensible keys.
var values = []; // brute force for corresponding values.
var id = nextId++;
function get___(key, opt_default) {
var index;
var hiddenRecord = getHiddenRecord(key);
if (hiddenRecord) {
return id in hiddenRecord ? hiddenRecord[id] : opt_default;
} else {
index = keys.indexOf(key);
return index >= 0 ? values[index] : opt_default;
}
}
function has___(key) {
var hiddenRecord = getHiddenRecord(key);
if (hiddenRecord) {
return id in hiddenRecord;
} else {
return keys.indexOf(key) >= 0;
}
}
function set___(key, value) {
var index;
var hiddenRecord = getHiddenRecord(key);
if (hiddenRecord) {
hiddenRecord[id] = value;
} else {
index = keys.indexOf(key);
if (index >= 0) {
values[index] = value;
} else {
// Since some browsers preemptively terminate slow turns but
// then continue computing with presumably corrupted heap
// state, we here defensively get keys.length first and then
// use it to update both the values and keys arrays, keeping
// them in sync.
index = keys.length;
values[index] = value;
// If we crash here, values will be one longer than keys.
keys[index] = key;
}
}
return this;
}
function delete___(key) {
var hiddenRecord = getHiddenRecord(key);
var index, lastIndex;
if (hiddenRecord) {
return id in hiddenRecord && delete hiddenRecord[id];
} else {
index = keys.indexOf(key);
if (index < 0) {
return false;
}
// Since some browsers preemptively terminate slow turns but
// then continue computing with potentially corrupted heap
// state, we here defensively get keys.length first and then use
// it to update both the keys and the values array, keeping
// them in sync. We update the two with an order of assignments,
// such that any prefix of these assignments will preserve the
// key/value correspondence, either before or after the delete.
// Note that this needs to work correctly when index === lastIndex.
lastIndex = keys.length - 1;
keys[index] = void 0;
// If we crash here, there's a void 0 in the keys array, but
// no operation will cause a "keys.indexOf(void 0)", since
// getHiddenRecord(void 0) will always throw an error first.
values[index] = values[lastIndex];
// If we crash here, values[index] cannot be found here,
// because keys[index] is void 0.
keys[index] = keys[lastIndex];
// If index === lastIndex and we crash here, then keys[index]
// is still void 0, since the aliasing killed the previous key.
keys.length = lastIndex;
// If we crash here, keys will be one shorter than values.
values.length = lastIndex;
return true;
}
}
return Object.create(OurWeakMap.prototype, {
get___: { value: constFunc(get___) },
has___: { value: constFunc(has___) },
set___: { value: constFunc(set___) },
delete___: { value: constFunc(delete___) }
});
};
OurWeakMap.prototype = Object.create(Object.prototype, {
get: {
/**
* Return the value most recently associated with key, or
* opt_default if none.
*/
value: function get(key, opt_default) {
return this.get___(key, opt_default);
},
writable: true,
configurable: true
},
has: {
/**
* Is there a value associated with key in this WeakMap?
*/
value: function has(key) {
return this.has___(key);
},
writable: true,
configurable: true
},
set: {
/**
* Associate value with key in this WeakMap, overwriting any
* previous association if present.
*/
value: function set(key, value) {
return this.set___(key, value);
},
writable: true,
configurable: true
},
'delete': {
/**
* Remove any association for key in this WeakMap, returning
* whether there was one.
*
* <p>Note that the boolean return here does not work like the
* {@code delete} operator. The {@code delete} operator returns
* whether the deletion succeeds at bringing about a state in
* which the deleted property is absent. The {@code delete}
* operator therefore returns true if the property was already
* absent, whereas this {@code delete} method returns false if
* the association was already absent.
*/
value: function remove(key) {
return this.delete___(key);
},
writable: true,
configurable: true
}
});
if (typeof HostWeakMap === 'function') {
(function() {
// If we got here, then the platform has a WeakMap but we are concerned
// that it may refuse to store some key types. Therefore, make a map
// implementation which makes use of both as possible.
// In this mode we are always using double maps, so we are not proxy-safe.
// This combination does not occur in any known browser, but we had best
// be safe.
if (doubleWeakMapCheckSilentFailure && typeof Proxy !== 'undefined') {
Proxy = undefined;
}
function DoubleWeakMap() {
if (!(this instanceof OurWeakMap)) { // approximate test for new ...()
calledAsFunctionWarning();
}
// Preferable, truly weak map.
var hmap = new HostWeakMap();
// Our hidden-property-based pseudo-weak-map. Lazily initialized in the
// 'set' implementation; thus we can avoid performing extra lookups if
// we know all entries actually stored are entered in 'hmap'.
var omap = undefined;
// Hidden-property maps are not compatible with proxies because proxies
// can observe the hidden name and either accidentally expose it or fail
// to allow the hidden property to be set. Therefore, we do not allow
// arbitrary WeakMaps to switch to using hidden properties, but only
// those which need the ability, and unprivileged code is not allowed
// to set the flag.
//
// (Except in doubleWeakMapCheckSilentFailure mode in which case we
// disable proxies.)
var enableSwitching = false;
function dget(key, opt_default) {
if (omap) {
return hmap.has(key) ? hmap.get(key)
: omap.get___(key, opt_default);
} else {
return hmap.get(key, opt_default);
}
}
function dhas(key) {
return hmap.has(key) || (omap ? omap.has___(key) : false);
}
var dset;
if (doubleWeakMapCheckSilentFailure) {
dset = function(key, value) {
hmap.set(key, value);
if (!hmap.has(key)) {
if (!omap) { omap = new OurWeakMap(); }
omap.set(key, value);
}
return this;
};
} else {
dset = function(key, value) {
if (enableSwitching) {
try {
hmap.set(key, value);
} catch (e) {
if (!omap) { omap = new OurWeakMap(); }
omap.set___(key, value);
}
} else {
hmap.set(key, value);
}
return this;
};
}
function ddelete(key) {
var result = !!hmap['delete'](key);
if (omap) { return omap.delete___(key) || result; }
return result;
}
return Object.create(OurWeakMap.prototype, {
get___: { value: constFunc(dget) },
has___: { value: constFunc(dhas) },
set___: { value: constFunc(dset) },
delete___: { value: constFunc(ddelete) },
permitHostObjects___: { value: constFunc(function(token) {
if (token === weakMapPermitHostObjects) {
enableSwitching = true;
} else {
throw new Error('bogus call to permitHostObjects___');
}
})}
});
}
DoubleWeakMap.prototype = OurWeakMap.prototype;
module.exports = DoubleWeakMap;
// define .constructor to hide OurWeakMap ctor
Object.defineProperty(WeakMap.prototype, 'constructor', {
value: WeakMap,
enumerable: false, // as default .constructor is
configurable: true,
writable: true
});
})();
} else {
// There is no host WeakMap, so we must use the emulation.
// Emulated WeakMaps are incompatible with native proxies (because proxies
// can observe the hidden name), so we must disable Proxy usage (in
// ArrayLike and Domado, currently).
if (typeof Proxy !== 'undefined') {
Proxy = undefined;
}
module.exports = OurWeakMap;
}
})();
},{}],74:[function(require,module,exports){
"use strict";
/*
Based in part on extras from Motorola Mobility’s Montage
Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved.
3-Clause BSD License
https://github.com/motorola-mobility/montage/blob/master/LICENSE.md
*/
var Function = require("./shim-function");
var GenericCollection = require("./generic-collection");
var GenericOrder = require("./generic-order");
var WeakMap = require("./weak-map");
module.exports = Array;
var array_splice = Array.prototype.splice;
var array_slice = Array.prototype.slice;
Array.empty = [];
if (Object.freeze) {
Object.freeze(Array.empty);
}
Array.from = function (values) {
var array = [];
array.addEach(values);
return array;
};
Array.unzip = function (table) {
var transpose = [];
var length = Infinity;
// compute shortest row
for (var i = 0; i < table.length; i++) {
var row = table[i];
table[i] = row.toArray();
if (row.length < length) {
length = row.length;
}
}
for (var i = 0; i < table.length; i++) {
var row = table[i];
for (var j = 0; j < row.length; j++) {
if (j < length && j in row) {
transpose[j] = transpose[j] || [];
transpose[j][i] = row[j];
}
}
}
return transpose;
};
function define(key, value) {
Object.defineProperty(Array.prototype, key, {
value: value,
writable: true,
configurable: true,
enumerable: false
});
}
define("addEach", GenericCollection.prototype.addEach);
define("deleteEach", GenericCollection.prototype.deleteEach);
define("toArray", GenericCollection.prototype.toArray);
define("toObject", GenericCollection.prototype.toObject);
define("all", GenericCollection.prototype.all);
define("any", GenericCollection.prototype.any);
define("min", GenericCollection.prototype.min);
define("max", GenericCollection.prototype.max);
define("sum", GenericCollection.prototype.sum);
define("average", GenericCollection.prototype.average);
define("only", GenericCollection.prototype.only);
define("flatten", GenericCollection.prototype.flatten);
define("zip", GenericCollection.prototype.zip);
define("enumerate", GenericCollection.prototype.enumerate);
define("group", GenericCollection.prototype.group);
define("sorted", GenericCollection.prototype.sorted);
define("reversed", GenericCollection.prototype.reversed);
define("constructClone", function (values) {
var clone = new this.constructor();
clone.addEach(values);
return clone;
});
define("has", function (value, equals) {
return this.findValue(value, equals) !== -1;
});
define("get", function (index, defaultValue) {
if (+index !== index) {
throw new Error("Indicies must be numbers");
} else if (!index in this) {
return defaultValue;
} else {
return this[index];
}
});
define("set", function (index, value) {
this[index] = value;
return true;
});
define("add", function (value) {
this.push(value);
return true;
});
define("delete", function (value, equals) {
var index = this.findValue(value, equals);
if (index !== -1) {
this.spliceOne(index);
return true;
}
return false;
});
define("deleteAll", function (value, equals) {
equals = equals || this.contentEquals || Object.equals;
var count = 0;
for (var index = 0; index < this.length;) {
if (equals(value, this[index])) {
this.swap(index, 1);
count++;
} else {
index++;
}
}
return count;
});
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
define("find", function(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
});
}
// TODO remove in v6 (not present in v2)
var deprecatedWarnNonce = {};
function deprecatedWarn(msg, notOnce) {
if (
typeof console !== 'undefined' &&
typeof console.warn === 'function' &&
(notOnce !== true && deprecatedWarnNonce.hasOwnProperty(msg) === false)
) {
console.warn(msg);
deprecatedWarnNonce[msg]++;
}
}
// Save Array.prototype.find in order to support legacy and display warning.
// TODO remove in v6 (not present in v2)
var ArrayFindPrototype = Object.getOwnPropertyDescriptor(Array.prototype, 'find').value;
define("find", function (value, equals, index) {
if (
typeof arguments[0] === 'function' &&
this instanceof Array
) {
return ArrayFindPrototype.apply(this, arguments);
} else {
deprecatedWarn('Array#find usage is deprecated please use Array#findValue');
return this.findValue.apply(this, arguments);
}
});
define("findValue", function (value, equals, index) {
if (index) {
throw new Error("Array#findValue does not support third argument: index");
}
equals = equals || this.contentEquals || Object.equals;
for (var index = 0; index < this.length; index++) {
if (index in this && equals(value, this[index])) {
return index;
}
}
return -1;
});
// TODO remove in v6 (not present in v2)
define("findLast", function (value, equals) {
deprecatedWarn('Array#findLast function is deprecated please use Array#findLastValue instead.');
return this.findLastValue.apply(this, arguments);
});
define("findLastValue", function (value, equals) {
equals = equals || this.contentEquals || Object.equals;
var index = this.length;
do {
index--;
if (index in this && equals(this[index], value)) {
return index;
}
} while (index > 0);
return -1;
});
define("swap", function (start, length, plus) {
var args, plusLength, i, j, returnValue;
if (start > this.length) {
this.length = start;
}
if (typeof plus !== "undefined") {
args = [start, length];
if (!Array.isArray(plus)) {
plus = array_slice.call(plus);
}
i = 0;
plusLength = plus.length;
// 1000 is a magic number, presumed to be smaller than the remaining
// stack length. For swaps this small, we take the fast path and just
// use the underlying Array splice. We could measure the exact size of
// the remaining stack using a try/catch around an unbounded recursive
// function, but this would defeat the purpose of short-circuiting in
// the common case.
if (plusLength < 1000) {
for (i; i < plusLength; i++) {
args[i+2] = plus[i];
}
return array_splice.apply(this, args);
} else {
// Avoid maximum call stack error.
// First delete the desired entries.
returnValue = array_splice.apply(this, args);
// Second batch in 1000s.
for (i; i < plusLength;) {
args = [start+i, 0];
for (j = 2; j < 1002 && i < plusLength; j++, i++) {
args[j] = plus[i];
}
array_splice.apply(this, args);
}
return returnValue;
}
// using call rather than apply to cut down on transient objects
} else if (typeof length !== "undefined") {
return array_splice.call(this, start, length);
} else if (typeof start !== "undefined") {
return array_splice.call(this, start);
} else {
return [];
}
});
define("peek", function () {
return this[0];
});
define("poke", function (value) {
if (this.length > 0) {
this[0] = value;
}
});
define("peekBack", function () {
if (this.length > 0) {
return this[this.length - 1];
}
});
define("pokeBack", function (value) {
if (this.length > 0) {
this[this.length - 1] = value;
}
});
define("one", function () {
for (var i in this) {
if (Object.owns(this, i)) {
return this[i];
}
}
});
if (!Array.prototype.clear) {
define("clear", function () {
this.length = 0;
return this;
});
}
define("compare", function (that, compare) {
compare = compare || Object.compare;
var i;
var length;
var lhs;
var rhs;
var relative;
if (this === that) {
return 0;
}
if (!that || !Array.isArray(that)) {
return GenericOrder.prototype.compare.call(this, that, compare);
}
length = (this.length < that.length) ? this.length : that.length;
for (i = 0; i < length; i++) {
if (i in this) {
if (!(i in that)) {
return -1;
} else {
lhs = this[i];
rhs = that[i];
relative = compare(lhs, rhs);
if (relative) {
return relative;
}
}
} else if (i in that) {
return 1;
}
}
return this.length - that.length;
});
define("equals", function (that, equals) {
equals = equals || Object.equals;
var i = 0;
var length = this.length;
var left;
var right;
if (this === that) {
return true;
}
if (!that || !Array.isArray(that)) {
return GenericOrder.prototype.equals.call(this, that);
}
if (length !== that.length) {
return false;
} else {
for (; i < length; ++i) {
if (i in this) {
if (!(i in that)) {
return false;
}
left = this[i];
right = that[i];
if (!equals(left, right)) {
return false;
}
} else {
if (i in that) {
return false;
}
}
}
}
return true;
});
define("clone", function (depth, memo) {
if (depth == null) {
depth = Infinity;
} else if (depth === 0) {
return this;
}
memo = memo || new WeakMap();
if (memo.has(this)) {
return memo.get(this);
}
var clone = new Array(this.length);
memo.set(this, clone);
for (var i in this) {
clone[i] = Object.clone(this[i], depth - 1, memo);
};
return clone;
});
define("iterate", function (start, end) {
return new ArrayIterator(this, start, end);
});
if(Array.prototype.spliceOne === void 0) {
define("spliceOne", function (index,itemToAdd) {
var len=this.length;
if (!len) { return }
if(arguments.length === 1) {
while (index<len) {
this[index] = this[index+1];
index++
}
this.length--;
}
else {
this[index] = itemToAdd;
}
});
}
define("Iterator", ArrayIterator);
function ArrayIterator(array, start, end) {
this.array = array;
this.start = start == null ? 0 : start;
this.end = end;
}
ArrayIterator.prototype.__iterationObject = null;
Object.defineProperty(ArrayIterator.prototype,"_iterationObject", {
get: function() {
return this.__iterationObject || (this.__iterationObject = { done: false, value:null});
}
});
ArrayIterator.prototype.next = function () {
if (this.start === (this.end == null ? this.array.length : this.end)) {
this._iterationObject.done = true;
this._iterationObject.value = void 0;
} else {
this._iterationObject.value = this.array[this.start++];
}
return this._iterationObject;
};
},{"./generic-collection":64,"./generic-order":66,"./shim-function":75,"./weak-map":80}],75:[function(require,module,exports){
module.exports = Function;
/**
A utility to reduce unnecessary allocations of <code>function () {}</code>
in its many colorful variations. It does nothing and returns
<code>undefined</code> thus makes a suitable default in some circumstances.
@function external:Function.noop
*/
Function.noop = function () {
};
/**
A utility to reduce unnecessary allocations of <code>function (x) {return
x}</code> in its many colorful but ultimately wasteful parameter name
variations.
@function external:Function.identity
@param {Any} any value
@returns {Any} that value
*/
Function.identity = function (value) {
return value;
};
/**
A utility for creating a comparator function for a particular aspect of a
figurative class of objects.
@function external:Function.by
@param {Function} relation A function that accepts a value and returns a
corresponding value to use as a representative when sorting that object.
@param {Function} compare an alternate comparator for comparing the
represented values. The default is <code>Object.compare</code>, which
does a deep, type-sensitive, polymorphic comparison.
@returns {Function} a comparator that has been annotated with
<code>by</code> and <code>compare</code> properties so
<code>sorted</code> can perform a transform that reduces the need to call
<code>by</code> on each sorted object to just once.
*/
Function.by = function (by , compare) {
compare = compare || Object.compare;
by = by || Function.identity;
var compareBy = function (a, b) {
return compare(by(a), by(b));
};
compareBy.compare = compare;
compareBy.by = by;
return compareBy;
};
// TODO document
Function.get = function (key) {
return function (object) {
return Object.get(object, key);
};
};
},{}],76:[function(require,module,exports){
"use strict";
var WeakMap = require("./weak-map");
module.exports = Object;
/*
Based in part on extras from Motorola Mobility’s Montage
Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved.
3-Clause BSD License
https://github.com/motorola-mobility/montage/blob/master/LICENSE.md
*/
/**
Defines extensions to intrinsic <code>Object</code>.
@see [Object class]{@link external:Object}
*/
/**
A utility object to avoid unnecessary allocations of an empty object
<code>{}</code>. This object is frozen so it is safe to share.
@object external:Object.empty
*/
Object.empty = Object.freeze(Object.create(null));
/**
Returns whether the given value is an object, as opposed to a value.
Unboxed numbers, strings, true, false, undefined, and null are not
objects. Arrays are objects.
@function external:Object.isObject
@param {Any} value
@returns {Boolean} whether the given value is an object
*/
Object.isObject = function (object) {
return Object(object) === object;
};
/**
Returns the value of an any value, particularly objects that
implement <code>valueOf</code>.
<p>Note that, unlike the precedent of methods like
<code>Object.equals</code> and <code>Object.compare</code> would suggest,
this method is named <code>Object.getValueOf</code> instead of
<code>valueOf</code>. This is a delicate issue, but the basis of this
decision is that the JavaScript runtime would be far more likely to
accidentally call this method with no arguments, assuming that it would
return the value of <code>Object</code> itself in various situations,
whereas <code>Object.equals(Object, null)</code> protects against this case
by noting that <code>Object</code> owns the <code>equals</code> property
and therefore does not delegate to it.
@function external:Object.getValueOf
@param {Any} value a value or object wrapping a value
@returns {Any} the primitive value of that object, if one exists, or passes
the value through
*/
Object.getValueOf = function (value) {
if (value && typeof value.valueOf === "function") {
value = value.valueOf();
}
return value;
};
var hashMap = new WeakMap();
Object.hash = function (object) {
if (object && typeof object.hash === "function") {
return "" + object.hash();
} else if (Object(object) === object) {
if (!hashMap.has(object)) {
hashMap.set(object, Math.random().toString(36).slice(2));
}
return hashMap.get(object);
} else {
return "" + object;
}
};
/**
A shorthand for <code>Object.prototype.hasOwnProperty.call(object,
key)</code>. Returns whether the object owns a property for the given key.
It does not consult the prototype chain and works for any string (including
"hasOwnProperty") except "__proto__".
@function external:Object.owns
@param {Object} object
@param {String} key
@returns {Boolean} whether the object owns a property wfor the given key.
*/
var owns = Object.prototype.hasOwnProperty;
Object.owns = function (object, key) {
return owns.call(object, key);
};
/**
A utility that is like Object.owns but is also useful for finding
properties on the prototype chain, provided that they do not refer to
methods on the Object prototype. Works for all strings except "__proto__".
<p>Alternately, you could use the "in" operator as long as the object
descends from "null" instead of the Object.prototype, as with
<code>Object.create(null)</code>. However,
<code>Object.create(null)</code> only works in fully compliant EcmaScript 5
JavaScript engines and cannot be faithfully shimmed.
<p>If the given object is an instance of a type that implements a method
named "has", this function defers to the collection, so this method can be
used to generically handle objects, arrays, or other collections. In that
case, the domain of the key depends on the instance.
@param {Object} object
@param {String} key
@returns {Boolean} whether the object, or any of its prototypes except
<code>Object.prototype</code>
@function external:Object.has
*/
Object.has = function (object, key) {
if (typeof object !== "object") {
throw new Error("Object.has can't accept non-object: " + typeof object);
}
// forward to mapped collections that implement "has"
if (object && typeof object.has === "function") {
return object.has(key);
// otherwise report whether the key is on the prototype chain,
// as long as it is not one of the methods on object.prototype
} else if (typeof key === "string") {
return key in object && object[key] !== Object.prototype[key];
} else {
throw new Error("Key must be a string for Object.has on plain objects");
}
};
/**
Gets the value for a corresponding key from an object.
<p>Uses Object.has to determine whether there is a corresponding value for
the given key. As such, <code>Object.get</code> is capable of retriving
values from the prototype chain as long as they are not from the
<code>Object.prototype</code>.
<p>If there is no corresponding value, returns the given default, which may
be <code>undefined</code>.
<p>If the given object is an instance of a type that implements a method
named "get", this function defers to the collection, so this method can be
used to generically handle objects, arrays, or other collections. In that
case, the domain of the key depends on the implementation. For a `Map`,
for example, the key might be any object.
@param {Object} object
@param {String} key
@param {Any} value a default to return, <code>undefined</code> if omitted
@returns {Any} value for key, or default value
@function external:Object.get
*/
Object.get = function (object, key, value) {
if (typeof object !== "object") {
throw new Error("Object.get can't accept non-object: " + typeof object);
}
// forward to mapped collections that implement "get"
if (object && typeof object.get === "function") {
return object.get(key, value);
} else if (Object.has(object, key)) {
return object[key];
} else {
return value;
}
};
/**
Sets the value for a given key on an object.
<p>If the given object is an instance of a type that implements a method
named "set", this function defers to the collection, so this method can be
used to generically handle objects, arrays, or other collections. As such,
the key domain varies by the object type.
@param {Object} object
@param {String} key
@param {Any} value
@returns <code>undefined</code>
@function external:Object.set
*/
Object.set = function (object, key, value) {
if (object && typeof object.set === "function") {
object.set(key, value);
} else {
object[key] = value;
}
};
Object.addEach = function (target, source, overrides) {
var overridesExistingProperty = arguments.length === 3 ? overrides : true;
if (!source) {
} else if (typeof source.forEach === "function" && !source.hasOwnProperty("forEach")) {
// copy map-alikes
if (source.isMap === true) {
source.forEach(function (value, key) {
target[key] = value;
});
// iterate key value pairs of other iterables
} else {
source.forEach(function (pair) {
target[pair[0]] = pair[1];
});
}
} else if (typeof source.length === "number") {
// arguments, strings
for (var index = 0; index < source.length; index++) {
target[index] = source[index];
}
} else {
// copy other objects as map-alikes
for(var keys = Object.keys(source), i = 0, key;(key = keys[i]); i++) {
if(overridesExistingProperty || !Object.owns(target,key)) {
target[key] = source[key];
}
}
}
return target;
};
/*
var defineEach = function defineEach(target, prototype) {
// console.log("Map defineEach: ",Object.keys(prototype));
var proto = Map.prototype;
for (var name in prototype) {
if(!proto.hasOwnProperty(name)) {
Object.defineProperty(proto, name, {
value: prototype[name],
writable: writable,
configurable: configurable,
enumerable: enumerable
});
}
}
}
*/
Object.defineEach = function (target, source, overrides, configurable, enumerable, writable) {
var overridesExistingProperty = arguments.length === 3 ? overrides : true;
if (!source) {
} else if (typeof source.forEach === "function" && !source.hasOwnProperty("forEach")) {
// copy map-alikes
if (source.isMap === true) {
source.forEach(function (value, key) {
Object.defineProperty(target, key, {
value: value,
writable: writable,
configurable: configurable,
enumerable: enumerable
});
});
// iterate key value pairs of other iterables
} else {
source.forEach(function (pair) {
Object.defineProperty(target, pair[0], {
value: pair[1],
writable: writable,
configurable: configurable,
enumerable: enumerable
});
});
}
} else if (typeof source.length === "number") {
// arguments, strings
for (var index = 0; index < source.length; index++) {
Object.defineProperty(target, index, {
value: source[index],
writable: writable,
configurable: configurable,
enumerable: enumerable
});
}
} else {
// copy other objects as map-alikes
for(var keys = Object.keys(source), i = 0, key;(key = keys[i]); i++) {
if(overridesExistingProperty || !Object.owns(target,key)) {
Object.defineProperty(target, key, {
value: source[key],
writable: writable,
configurable: configurable,
enumerable: enumerable
});
}
}
}
return target;
};
/**
Iterates over the owned properties of an object.
@function external:Object.forEach
@param {Object} object an object to iterate.
@param {Function} callback a function to call for every key and value
pair in the object. Receives <code>value</code>, <code>key</code>,
and <code>object</code> as arguments.
@param {Object} thisp the <code>this</code> to pass through to the
callback
*/
Object.forEach = function (object, callback, thisp) {
var keys = Object.keys(object), i = 0, iKey;
for(;(iKey = keys[i]);i++) {
callback.call(thisp, object[iKey], iKey, object);
}
};
/**
Iterates over the owned properties of a map, constructing a new array of
mapped values.
@function external:Object.map
@param {Object} object an object to iterate.
@param {Function} callback a function to call for every key and value
pair in the object. Receives <code>value</code>, <code>key</code>,
and <code>object</code> as arguments.
@param {Object} thisp the <code>this</code> to pass through to the
callback
@returns {Array} the respective values returned by the callback for each
item in the object.
*/
Object.map = function (object, callback, thisp) {
var keys = Object.keys(object), i = 0, result = [], iKey;
for(;(iKey = keys[i]);i++) {
result.push(callback.call(thisp, object[iKey], iKey, object));
}
return result;
};
/**
Returns the values for owned properties of an object.
@function external:Object.map
@param {Object} object
@returns {Array} the respective value for each owned property of the
object.
*/
Object.values = function (object) {
return Object.map(object, Function.identity);
};
// TODO inline document concat
Object.concat = function () {
var object = {};
for (var i = 0; i < arguments.length; i++) {
Object.addEach(object, arguments[i]);
}
return object;
};
Object.from = Object.concat;
/**
Returns whether two values are identical. Any value is identical to itself
and only itself. This is much more restictive than equivalence and subtly
different than strict equality, <code>===</code> because of edge cases
including negative zero and <code>NaN</code>. Identity is useful for
resolving collisions among keys in a mapping where the domain is any value.
This method does not delgate to any method on an object and cannot be
overridden.
@see http://wiki.ecmascript.org/doku.php?id=harmony:egal
@param {Any} this
@param {Any} that
@returns {Boolean} whether this and that are identical
@function external:Object.is
*/
Object.is = function (x, y) {
if (x === y) {
// 0 === -0, but they are not identical
return x !== 0 || 1 / x === 1 / y;
}
// NaN !== NaN, but they are identical.
// NaNs are the only non-reflexive value, i.e., if x !== x,
// then x is a NaN.
// isNaN is broken: it converts its argument to number, so
// isNaN("foo") => true
return x !== x && y !== y;
};
/**
Performs a polymorphic, type-sensitive deep equivalence comparison of any
two values.
<p>As a basic principle, any value is equivalent to itself (as in
identity), any boxed version of itself (as a <code>new Number(10)</code> is
to 10), and any deep clone of itself.
<p>Equivalence has the following properties:
<ul>
<li><strong>polymorphic:</strong>
If the given object is an instance of a type that implements a
methods named "equals", this function defers to the method. So,
this function can safely compare any values regardless of type,
including undefined, null, numbers, strings, any pair of objects
where either implements "equals", or object literals that may even
contain an "equals" key.
<li><strong>type-sensitive:</strong>
Incomparable types are not equal. No object is equivalent to any
array. No string is equal to any other number.
<li><strong>deep:</strong>
Collections with equivalent content are equivalent, recursively.
<li><strong>equivalence:</strong>
Identical values and objects are equivalent, but so are collections
that contain equivalent content. Whether order is important varies
by type. For Arrays and lists, order is important. For Objects,
maps, and sets, order is not important. Boxed objects are mutally
equivalent with their unboxed values, by virtue of the standard
<code>valueOf</code> method.
</ul>
@param this
@param that
@returns {Boolean} whether the values are deeply equivalent
@function external:Object.equals
*/
Object.equals = function (a, b, equals, memo) {
equals = equals || Object.equals;
//console.log("Object.equals: a:",a, "b:",b, "equals:",equals);
// unbox objects, but do not confuse object literals
a = Object.getValueOf(a);
b = Object.getValueOf(b);
if (a === b)
return true;
if (Object.isObject(a)) {
memo = memo || new WeakMap();
if (memo.has(a)) {
return true;
}
memo.set(a, true);
}
if (Object.isObject(a) && typeof a.equals === "function") {
return a.equals(b, equals, memo);
}
// commutative
if (Object.isObject(b) && typeof b.equals === "function") {
return b.equals(a, equals, memo);
}
if (Object.isObject(a) && Object.isObject(b)) {
if (Object.getPrototypeOf(a) === Object.prototype && Object.getPrototypeOf(b) === Object.prototype) {
for (var name in a) {
if (!equals(a[name], b[name], equals, memo)) {
return false;
}
}
for (var name in b) {
if (!(name in a) || !equals(b[name], a[name], equals, memo)) {
return false;
}
}
return true;
}
}
// NaN !== NaN, but they are equal.
// NaNs are the only non-reflexive value, i.e., if x !== x,
// then x is a NaN.
// isNaN is broken: it converts its argument to number, so
// isNaN("foo") => true
// We have established that a !== b, but if a !== a && b !== b, they are
// both NaN.
if (a !== a && b !== b)
return true;
if (!a || !b)
return a === b;
return false;
};
// Because a return value of 0 from a `compare` function may mean either
// "equals" or "is incomparable", `equals` cannot be defined in terms of
// `compare`. However, `compare` *can* be defined in terms of `equals` and
// `lessThan`. Again however, more often it would be desirable to implement
// all of the comparison functions in terms of compare rather than the other
// way around.
/**
Determines the order in which any two objects should be sorted by returning
a number that has an analogous relationship to zero as the left value to
the right. That is, if the left is "less than" the right, the returned
value will be "less than" zero, where "less than" may be any other
transitive relationship.
<p>Arrays are compared by the first diverging values, or by length.
<p>Any two values that are incomparable return zero. As such,
<code>equals</code> should not be implemented with <code>compare</code>
since incomparability is indistinguishable from equality.
<p>Sorts strings lexicographically. This is not suitable for any
particular international setting. Different locales sort their phone books
in very different ways, particularly regarding diacritics and ligatures.
<p>If the given object is an instance of a type that implements a method
named "compare", this function defers to the instance. The method does not
need to be an owned property to distinguish it from an object literal since
object literals are incomparable. Unlike <code>Object</code> however,
<code>Array</code> implements <code>compare</code>.
@param {Any} left
@param {Any} right
@returns {Number} a value having the same transitive relationship to zero
as the left and right values.
@function external:Object.compare
*/
Object.compare = function (a, b) {
// unbox objects, but do not confuse object literals
// mercifully handles the Date case
a = Object.getValueOf(a);
b = Object.getValueOf(b);
if (a === b)
return 0;
var aType = typeof a;
var bType = typeof b;
if (aType === "number" && bType === "number")
return a - b;
if (aType === "string" && bType === "string")
return a < b ? -Infinity : Infinity;
// the possibility of equality elimiated above
if (a && typeof a.compare === "function")
return a.compare(b);
// not commutative, the relationship is reversed
if (b && typeof b.compare === "function")
return -b.compare(a);
return 0;
};
/**
Creates a deep copy of any value. Values, being immutable, are
returned without alternation. Forwards to <code>clone</code> on
objects and arrays.
@function external:Object.clone
@param {Any} value a value to clone
@param {Number} depth an optional traversal depth, defaults to infinity.
A value of <code>0</code> means to make no clone and return the value
directly.
@param {Map} memo an optional memo of already visited objects to preserve
reference cycles. The cloned object will have the exact same shape as the
original, but no identical objects. Te map may be later used to associate
all objects in the original object graph with their corresponding member of
the cloned graph.
@returns a copy of the value
*/
Object.clone = function (value, depth, memo) {
value = Object.getValueOf(value);
memo = memo || new WeakMap();
if (depth === undefined) {
depth = Infinity;
} else if (depth === 0) {
return value;
}
if (Object.isObject(value)) {
if (!memo.has(value)) {
if (value && typeof value.clone === "function") {
memo.set(value, value.clone(depth, memo));
} else {
var prototype = Object.getPrototypeOf(value);
if (prototype === null || prototype === Object.prototype) {
var clone = Object.create(prototype);
memo.set(value, clone);
for (var key in value) {
clone[key] = Object.clone(value[key], depth - 1, memo);
}
} else {
throw new Error("Can't clone " + value);
}
}
}
return memo.get(value);
}
return value;
};
/**
Removes all properties owned by this object making the object suitable for
reuse.
@function external:Object.clear
@returns this
*/
Object.clear = function (object) {
if (object && typeof object.clear === "function") {
object.clear();
} else {
var keys = Object.keys(object),
i = keys.length;
while (i) {
i--;
delete object[keys[i]];
}
}
return object;
};
},{"./weak-map":80}],77:[function(require,module,exports){
/**
accepts a string; returns the string with regex metacharacters escaped.
the returned string can safely be used within a regex to match a literal
string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
|, #, [comma], and whitespace.
*/
if (!RegExp.escape) {
var special = /[-[\]{}()*+?.\\^$|,#\s]/g;
RegExp.escape = function (string) {
return string.replace(special, "\\$&");
};
}
},{}],78:[function(require,module,exports){
var Array = require("./shim-array");
var Object = require("./shim-object");
var Function = require("./shim-function");
var RegExp = require("./shim-regexp");
},{"./shim-array":74,"./shim-function":75,"./shim-object":76,"./shim-regexp":77}],79:[function(require,module,exports){
"use strict";
module.exports = TreeLog;
function TreeLog() {
}
TreeLog.ascii = {
intersection: "+",
through: "-",
branchUp: "+",
branchDown: "+",
fromBelow: ".",
fromAbove: "'",
fromBoth: "+",
strafe: "|"
};
TreeLog.unicodeRound = {
intersection: "\u254b",
through: "\u2501",
branchUp: "\u253b",
branchDown: "\u2533",
fromBelow: "\u256d", // round corner
fromAbove: "\u2570", // round corner
fromBoth: "\u2523",
strafe: "\u2503"
};
TreeLog.unicodeSharp = {
intersection: "\u254b",
through: "\u2501",
branchUp: "\u253b",
branchDown: "\u2533",
fromBelow: "\u250f", // sharp corner
fromAbove: "\u2517", // sharp corner
fromBoth: "\u2523",
strafe: "\u2503"
};
},{}],80:[function(require,module,exports){
module.exports = (typeof WeakMap !== 'undefined') ? WeakMap : require("weak-map");
},{"weak-map":73}],81:[function(require,module,exports){
(function (Buffer){
// Public API
// ==========
// The main governing power behind the http2 API design is that it should look very similar to the
// existing node.js [HTTPS API][1] (which is, in turn, almost identical to the [HTTP API][2]). The
// additional features of HTTP/2 are exposed as extensions to this API. Furthermore, node-http2
// should fall back to using HTTP/1.1 if needed. Compatibility with undocumented or deprecated
// elements of the node.js HTTP/HTTPS API is a non-goal.
//
// Additional and modified API elements
// ------------------------------------
//
// - **Class: http2.Endpoint**: an API for using the raw HTTP/2 framing layer. For documentation
// see [protocol/endpoint.js](protocol/endpoint.html).
//
// - **Class: http2.Server**
// - **Event: 'connection' (socket, [endpoint])**: there's a second argument if the negotiation of
// HTTP/2 was successful: the reference to the [Endpoint](protocol/endpoint.html) object tied to the
// socket.
//
// - **http2.createServer(options, [requestListener])**: additional option:
// - **log**: an optional [bunyan](https://github.com/trentm/node-bunyan) logger object
//
// - **Class: http2.ServerResponse**
// - **response.push(options)**: initiates a server push. `options` describes the 'imaginary'
// request to which the push stream is a response; the possible options are identical to the
// ones accepted by `http2.request`. Returns a ServerResponse object that can be used to send
// the response headers and content.
//
// - **Class: http2.Agent**
// - **new Agent(options)**: additional option:
// - **log**: an optional [bunyan](https://github.com/trentm/node-bunyan) logger object
// - **agent.sockets**: only contains TCP sockets that corresponds to HTTP/1 requests.
// - **agent.endpoints**: contains [Endpoint](protocol/endpoint.html) objects for HTTP/2 connections.
//
// - **http2.request(options, [callback])**:
// - similar to http.request
//
// - **http2.get(options, [callback])**:
// - similar to http.get
//
// - **Class: http2.ClientRequest**
// - **Event: 'socket' (socket)**: in case of an HTTP/2 incoming message, `socket` is a reference
// to the associated [HTTP/2 Stream](protocol/stream.html) object (and not to the TCP socket).
// - **Event: 'push' (promise)**: signals the intention of a server push associated to this
// request. `promise` is an IncomingPromise. If there's no listener for this event, the server
// push is cancelled.
// - **request.setPriority(priority)**: assign a priority to this request. `priority` is a number
// between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.
//
// - **Class: http2.IncomingMessage**
// - has two subclasses for easier interface description: **IncomingRequest** and
// **IncomingResponse**
// - **message.socket**: in case of an HTTP/2 incoming message, it's a reference to the associated
// [HTTP/2 Stream](protocol/stream.html) object (and not to the TCP socket).
//
// - **Class: http2.IncomingRequest (IncomingMessage)**
// - **message.url**: in case of an HTTP/2 incoming request, the `url` field always contains the
// path, and never a full url (it contains the path in most cases in the HTTPS api as well).
// - **message.scheme**: additional field. Mandatory HTTP/2 request metadata.
// - **message.host**: additional field. Mandatory HTTP/2 request metadata. Note that this
// replaces the old Host header field, but node-http2 will add Host to the `message.headers` for
// backwards compatibility.
//
// - **Class: http2.IncomingPromise (IncomingRequest)**
// - contains the metadata of the 'imaginary' request to which the server push is an answer.
// - **Event: 'response' (response)**: signals the arrival of the actual push stream. `response`
// is an IncomingResponse.
// - **Event: 'push' (promise)**: signals the intention of a server push associated to this
// request. `promise` is an IncomingPromise. If there's no listener for this event, the server
// push is cancelled.
// - **promise.cancel()**: cancels the promised server push.
// - **promise.setPriority(priority)**: assign a priority to this push stream. `priority` is a
// number between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.
//
// API elements not yet implemented
// --------------------------------
//
// - **Class: http2.Server**
// - **server.maxHeadersCount**
//
// API elements that are not applicable to HTTP/2
// ----------------------------------------------
//
// The reason may be deprecation of certain HTTP/1.1 features, or that some API elements simply
// don't make sense when using HTTP/2. These will not be present when a request is done with HTTP/2,
// but will function normally when falling back to using HTTP/1.1.
//
// - **Class: http2.Server**
// - **Event: 'checkContinue'**: not in the spec
// - **Event: 'upgrade'**: upgrade is deprecated in HTTP/2
// - **Event: 'timeout'**: HTTP/2 sockets won't timeout because of application level keepalive
// (PING frames)
// - **Event: 'connect'**: not yet supported
// - **server.setTimeout(msecs, [callback])**
// - **server.timeout**
//
// - **Class: http2.ServerResponse**
// - **Event: 'close'**
// - **Event: 'timeout'**
// - **response.writeContinue()**
// - **response.writeHead(statusCode, [reasonPhrase], [headers])**: reasonPhrase will always be
// ignored since [it's not supported in HTTP/2][3]
// - **response.setTimeout(timeout, [callback])**
//
// - **Class: http2.Agent**
// - **agent.maxSockets**: only affects HTTP/1 connection pool. When using HTTP/2, there's always
// one connection per host.
//
// - **Class: http2.ClientRequest**
// - **Event: 'upgrade'**
// - **Event: 'connect'**
// - **Event: 'continue'**
// - **request.setTimeout(timeout, [callback])**
// - **request.setNoDelay([noDelay])**
// - **request.setSocketKeepAlive([enable], [initialDelay])**
//
// - **Class: http2.IncomingMessage**
// - **Event: 'close'**
// - **message.setTimeout(timeout, [callback])**
//
// [1]: https://nodejs.org/api/https.html
// [2]: https://nodejs.org/api/http.html
// [3]: https://tools.ietf.org/html/rfc7540#section-8.1.2.4
// Common server and client side code
// ==================================
var net = require('net');
var url = require('url');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var PassThrough = require('stream').PassThrough;
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var protocol = require('./protocol');
var Endpoint = protocol.Endpoint;
var https = require('https');
var assign = Object.assign || require('object.assign');
exports.STATUS_CODES = {
'202': 'Accepted',
'502': 'Bad Gateway',
'400': 'Bad Request',
'409': 'Conflict',
'100': 'Continue',
'201': 'Created',
'417': 'Expectation Failed',
'424': 'Failed Dependency',
'403': 'Forbidden',
'504': 'Gateway Timeout',
'410': 'Gone',
'505': 'HTTP Version Not Supported',
'419': 'Insufficient Space on Resource',
'507': 'Insufficient Storage',
'500': 'Server Error',
'411': 'Length Required',
'423': 'Locked',
'420': 'Method Failure',
'405': 'Method Not Allowed',
'301': 'Moved Permanently',
'302': 'Moved Temporarily',
'207': 'Multi-Status',
'300': 'Multiple Choices',
'511': 'Network Authentication Required',
'204': 'No Content',
'203': 'Non Authoritative Information',
'406': 'Not Acceptable',
'404': 'Not Found',
'501': 'Not Implemented',
'304': 'Not Modified',
'200': 'OK',
'206': 'Partial Content',
'402': 'Payment Required',
'308': 'Permanent Redirect',
'412': 'Precondition Failed',
'428': 'Precondition Required',
'102': 'Processing',
'407': 'Proxy Authentication Required',
'431': 'Request Header Fields Too Large',
'408': 'Request Timeout',
'413': 'Request Entity Too Large',
'414': 'Request-URI Too Long',
'416': 'Requested Range Not Satisfiable',
'205': 'Reset Content',
'303': 'See Other',
'503': 'Service Unavailable',
'101': 'Switching Protocols',
'307': 'Temporary Redirect',
'429': 'Too Many Requests',
'401': 'Unauthorized',
'422': 'Unprocessable Entity',
'415': 'Unsupported Media Type',
'305': 'Use Proxy'
};
exports.IncomingMessage = IncomingMessage;
exports.OutgoingMessage = OutgoingMessage;
exports.protocol = protocol;
var deprecatedHeaders = [
'connection',
'host',
'keep-alive',
'proxy-connection',
'transfer-encoding',
'upgrade'
];
// When doing NPN/ALPN negotiation, HTTP/1.1 is used as fallback
var supportedProtocols = [protocol.VERSION, 'http/1.1', 'http/1.0'];
// Ciphersuite list based on the recommendations of https://wiki.mozilla.org/Security/Server_Side_TLS
// The only modification is that kEDH+AESGCM were placed after DHE and ECDHE suites
var cipherSuites = [
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'DHE-RSA-AES128-GCM-SHA256',
'DHE-DSS-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-SHA256',
'ECDHE-ECDSA-AES128-SHA256',
'ECDHE-RSA-AES128-SHA',
'ECDHE-ECDSA-AES128-SHA',
'ECDHE-RSA-AES256-SHA384',
'ECDHE-ECDSA-AES256-SHA384',
'ECDHE-RSA-AES256-SHA',
'ECDHE-ECDSA-AES256-SHA',
'DHE-RSA-AES128-SHA256',
'DHE-RSA-AES128-SHA',
'DHE-DSS-AES128-SHA256',
'DHE-RSA-AES256-SHA256',
'DHE-DSS-AES256-SHA',
'DHE-RSA-AES256-SHA',
'kEDH+AESGCM',
'AES128-GCM-SHA256',
'AES256-GCM-SHA384',
'ECDHE-RSA-RC4-SHA',
'ECDHE-ECDSA-RC4-SHA',
'AES128',
'AES256',
'RC4-SHA',
'HIGH',
'!aNULL',
'!eNULL',
'!EXPORT',
'!DES',
'!3DES',
'!MD5',
'!PSK'
].join(':');
// Logging
// -------
// Logger shim, used when no logger is provided by the user.
function noop() {}
var defaultLogger = {
fatal: noop,
error: noop,
warn : noop,
info : noop,
debug: noop,
trace: noop,
child: function() { return this; }
};
// Bunyan serializers exported by submodules that are worth adding when creating a logger.
exports.serializers = protocol.serializers;
// IncomingMessage class
// ---------------------
function IncomingMessage(stream) {
// * This is basically a read-only wrapper for the [Stream](protocol/stream.html) class.
PassThrough.call(this);
stream.pipe(this);
this.socket = this.stream = stream;
this._log = stream._log.child({ component: 'http' });
// * HTTP/2.0 does not define a way to carry the version identifier that is included in the
// HTTP/1.1 request/status line. Version is always 2.0.
this.httpVersion = '2.0';
this.httpVersionMajor = 2;
this.httpVersionMinor = 0;
// * `this.headers` will store the regular headers (and none of the special colon headers)
this.headers = {};
this.trailers = undefined;
this._lastHeadersSeen = undefined;
// * Other metadata is filled in when the headers arrive.
stream.once('headers', this._onHeaders.bind(this));
stream.once('end', this._onEnd.bind(this));
}
IncomingMessage.prototype = Object.create(PassThrough.prototype, { constructor: { value: IncomingMessage } });
// [Request Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.3)
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
// of key-value pairs. This includes the target URI for the request, the status code for the
// response, as well as HTTP header fields.
IncomingMessage.prototype._onHeaders = function _onHeaders(headers) {
// * Detects malformed headers
this._validateHeaders(headers);
// * Store the _regular_ headers in `this.headers`
for (var name in headers) {
if (name[0] !== ':') {
if (name === 'set-cookie' && !Array.isArray(headers[name])) {
this.headers[name] = [headers[name]];
} else {
this.headers[name] = headers[name];
}
}
}
// * The last header block, if it's not the first, will represent the trailers
var self = this;
this.stream.on('headers', function(headers) {
self._lastHeadersSeen = headers;
});
};
IncomingMessage.prototype._onEnd = function _onEnd() {
this.trailers = this._lastHeadersSeen;
};
IncomingMessage.prototype.setTimeout = noop;
IncomingMessage.prototype._checkSpecialHeader = function _checkSpecialHeader(key, value) {
if ((typeof value !== 'string') || (value.length === 0)) {
this._log.error({ key: key, value: value }, 'Invalid or missing special header field');
this.stream.reset('PROTOCOL_ERROR');
}
return value;
};
var headerNamePattern = /[A-Z]/;
IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) {
// * An HTTP/2.0 request or response MUST NOT include any of the following header fields:
// Connection, Host, Keep-Alive, Proxy-Connection, Transfer-Encoding, and Upgrade. A server
// MUST treat the presence of any of these header fields as a stream error of type
// PROTOCOL_ERROR.
// If the TE header is present, it's only valid value is 'trailers'
for (var i = 0; i < deprecatedHeaders.length; i++) {
var key = deprecatedHeaders[i];
if (key in headers || (key === 'te' && headers[key] !== 'trailers')) {
this._log.error({ key: key, value: headers[key] }, 'Deprecated header found');
this.stream.reset('PROTOCOL_ERROR');
return;
}
}
for (var headerName in headers) {
if (headers.hasOwnProperty(headerName)) {
// * Empty header name field is malformed
if (headerName.length <= 1) {
this.stream.reset('PROTOCOL_ERROR');
return;
}
// * A request or response containing uppercase header name field names MUST be
// treated as malformed (Section 8.1.3.5). Implementations that detect malformed
// requests or responses need to ensure that the stream ends.
if(headerNamePattern.test(headerName)) {
this.stream.reset('PROTOCOL_ERROR');
return;
}
}
}
};
// OutgoingMessage class
// ---------------------
function OutgoingMessage() {
// * This is basically a read-only wrapper for the [Stream](protocol/stream.html) class.
Writable.call(this);
this._headers = {};
this._trailers = undefined;
this.headersSent = false;
this.finished = false;
this.on('finish', this._finish);
}
OutgoingMessage.prototype = Object.create(Writable.prototype, { constructor: { value: OutgoingMessage } });
OutgoingMessage.prototype._write = function _write(chunk, encoding, callback) {
if (this.stream) {
this.stream.write(chunk, encoding, callback);
} else {
this.once('socket', this._write.bind(this, chunk, encoding, callback));
}
};
OutgoingMessage.prototype._finish = function _finish() {
if (this.stream) {
if (this._trailers) {
if (this.request) {
this.request.addTrailers(this._trailers);
} else {
this.stream.headers(this._trailers);
}
}
this.finished = true;
this.stream.end();
} else {
this.once('socket', this._finish.bind(this));
}
};
OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
if (this.headersSent) {
return this.emit('error', new Error('Can\'t set headers after they are sent.'));
} else {
name = name.toLowerCase();
if (deprecatedHeaders.indexOf(name) !== -1) {
return this.emit('error', new Error('Cannot set deprecated header: ' + name));
}
this._headers[name] = value;
}
};
OutgoingMessage.prototype.removeHeader = function removeHeader(name) {
if (this.headersSent) {
return this.emit('error', new Error('Can\'t remove headers after they are sent.'));
} else {
delete this._headers[name.toLowerCase()];
}
};
OutgoingMessage.prototype.getHeader = function getHeader(name) {
return this._headers[name.toLowerCase()];
};
OutgoingMessage.prototype.addTrailers = function addTrailers(trailers) {
this._trailers = trailers;
};
OutgoingMessage.prototype.setTimeout = noop;
OutgoingMessage.prototype._checkSpecialHeader = IncomingMessage.prototype._checkSpecialHeader;
// Server side
// ===========
exports.Server = Server;
exports.IncomingRequest = IncomingRequest;
exports.OutgoingResponse = OutgoingResponse;
exports.ServerResponse = OutgoingResponse; // for API compatibility
// Forward events `event` on `source` to all listeners on `target`.
//
// Note: The calling context is `source`.
function forwardEvent(event, source, target) {
function forward() {
var listeners = target.listeners(event);
var n = listeners.length;
// Special case for `error` event with no listeners.
if (n === 0 && event === 'error') {
var args = [event];
args.push.apply(args, arguments);
target.emit.apply(target, args);
return;
}
for (var i = 0; i < n; ++i) {
listeners[i].apply(source, arguments);
}
}
source.on(event, forward);
// A reference to the function is necessary to be able to stop
// forwarding.
return forward;
}
// Server class
// ------------
function Server(options) {
options = assign({}, options);
this._log = (options.log || defaultLogger).child({ component: 'http' });
this._settings = options.settings;
var start = this._start.bind(this);
var fallback = this._fallback.bind(this);
// HTTP2 over TLS (using NPN or ALPN)
if ((options.key && options.cert) || options.pfx) {
this._log.info('Creating HTTP/2 server over TLS');
this._mode = 'tls';
options.ALPNProtocols = supportedProtocols;
options.NPNProtocols = supportedProtocols;
options.ciphers = options.ciphers || cipherSuites;
options.honorCipherOrder = (options.honorCipherOrder !== false);
this._server = https.createServer(options);
this._originalSocketListeners = this._server.listeners('secureConnection');
this._server.removeAllListeners('secureConnection');
this._server.on('secureConnection', function(socket) {
var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
// It's true that the client MUST use SNI, but if it doesn't, we don't care, don't fall back to HTTP/1,
// since if the ALPN negotiation is otherwise successful, the client thinks we speak HTTP/2 but we don't.
if (negotiatedProtocol === protocol.VERSION) {
start(socket);
} else {
fallback(socket);
}
});
this._server.on('request', this.emit.bind(this, 'request'));
forwardEvent('error', this._server, this);
forwardEvent('listening', this._server, this);
}
// HTTP2 over any generic transport
else if (options.transport){
this._mode = 'plain';
this._server = options.transport(options, start);
}
// HTTP2 over plain TCP (Perhaps this should be deprecated??)
else if (options.plain) {
this._log.info('Creating HTTP/2 server over plain TCP');
this._mode = 'plain';
this._server = net.createServer(start);
}
// HTTP/2 with HTTP/1.1 upgrade
else {
this._log.error('Trying to create HTTP/2 server with Upgrade from HTTP/1.1');
throw new Error('HTTP1.1 -> HTTP2 upgrade is not yet supported. Please provide TLS keys.');
}
this._server.on('close', this.emit.bind(this, 'close'));
}
Server.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Server } });
// Starting HTTP/2
Server.prototype._start = function _start(socket) {
var endpoint = new Endpoint(this._log, 'SERVER', this._settings);
this._log.info({ e: endpoint,
client: socket.remoteAddress + ':' + socket.remotePort,
SNI: socket.servername
}, 'New incoming HTTP/2 connection');
endpoint.pipe(socket).pipe(endpoint);
var self = this;
endpoint.on('stream', function _onStream(stream) {
var response = new OutgoingResponse(stream);
var request = new IncomingRequest(stream);
// Some conformance to Node.js Https specs allows to distinguish clients:
request.remoteAddress = socket.remoteAddress;
request.remotePort = socket.remotePort;
request.connection = request.socket = response.socket = socket;
request.once('ready', self.emit.bind(self, 'request', request, response));
});
endpoint.on('error', this.emit.bind(this, 'clientError'));
socket.on('error', this.emit.bind(this, 'clientError'));
this.emit('connection', socket, endpoint);
};
Server.prototype._fallback = function _fallback(socket) {
var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
this._log.info({ client: socket.remoteAddress + ':' + socket.remotePort,
protocol: negotiatedProtocol,
SNI: socket.servername
}, 'Falling back to simple HTTPS');
for (var i = 0; i < this._originalSocketListeners.length; i++) {
this._originalSocketListeners[i].call(this._server, socket);
}
this.emit('connection', socket);
};
// There are [3 possible signatures][1] of the `listen` function. Every arguments is forwarded to
// the backing TCP or HTTPS server.
// [1]: https://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback
Server.prototype.listen = function listen(port, hostname) {
this._log.info({ on: ((typeof hostname === 'string') ? (hostname + ':' + port) : port) },
'Listening for incoming connections');
this._server.listen.apply(this._server, arguments);
return this._server;
};
Server.prototype.close = function close(callback) {
this._log.info('Closing server');
this._server.close(callback);
};
Server.prototype.setTimeout = function setTimeout(timeout, callback) {
if (this._mode === 'tls') {
this._server.setTimeout(timeout, callback);
}
};
Object.defineProperty(Server.prototype, 'timeout', {
get: function getTimeout() {
if (this._mode === 'tls') {
return this._server.timeout;
} else {
return undefined;
}
},
set: function setTimeout(timeout) {
if (this._mode === 'tls') {
this._server.timeout = timeout;
}
}
});
// Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
// `server`.There are events on the `http.Server` class where it makes difference whether someone is
// listening on the event or not. In these cases, we can not simply forward the events from the
// `server` to `this` since that means a listener. Instead, we forward the subscriptions.
Server.prototype.on = function on(event, listener) {
if ((event === 'upgrade') || (event === 'timeout')) {
return this._server.on(event, listener && listener.bind(this));
} else {
return EventEmitter.prototype.on.call(this, event, listener);
}
};
// `addContext` is used to add Server Name Indication contexts
Server.prototype.addContext = function addContext(hostname, credentials) {
if (this._mode === 'tls') {
this._server.addContext(hostname, credentials);
}
};
Server.prototype.address = function address() {
return this._server.address();
};
function createServerRaw(options, requestListener) {
if (typeof options === 'function') {
requestListener = options;
options = {};
}
if (options.pfx || (options.key && options.cert)) {
throw new Error('options.pfx, options.key, and options.cert are nonsensical!');
}
options.plain = true;
var server = new Server(options);
if (requestListener) {
server.on('request', requestListener);
}
return server;
}
function createServerTLS(options, requestListener) {
if (typeof options === 'function') {
throw new Error('options are required!');
}
if (!options.pfx && !(options.key && options.cert)) {
throw new Error('options.pfx or options.key and options.cert are required!');
}
options.plain = false;
var server = new Server(options);
if (requestListener) {
server.on('request', requestListener);
}
return server;
}
// Exposed main interfaces for HTTPS connections (the default)
exports.https = {};
exports.createServer = exports.https.createServer = createServerTLS;
exports.request = exports.https.request = requestTLS;
exports.get = exports.https.get = getTLS;
exports.post = exports.https.post = postTLS;
// Exposed main interfaces for raw TCP connections (not recommended)
exports.raw = {};
exports.raw.createServer = createServerRaw;
exports.raw.request = requestRaw;
exports.raw.get = getRaw;
// Exposed main interfaces for HTTP plaintext upgrade connections (not implemented)
function notImplemented() {
throw new Error('HTTP UPGRADE is not implemented!');
}
exports.http = {};
exports.http.createServer = exports.http.request = exports.http.get = notImplemented;
// IncomingRequest class
// ---------------------
function IncomingRequest(stream) {
IncomingMessage.call(this, stream);
}
IncomingRequest.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingRequest } });
// [Request Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.3)
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
// of key-value pairs. This includes the target URI for the request, the status code for the
// response, as well as HTTP header fields.
IncomingRequest.prototype._onHeaders = function _onHeaders(headers) {
// * The ":method" header field includes the HTTP method
// * The ":scheme" header field includes the scheme portion of the target URI
// * The ":authority" header field includes the authority portion of the target URI
// * The ":path" header field includes the path and query parts of the target URI.
// This field MUST NOT be empty; URIs that do not contain a path component MUST include a value
// of '/', unless the request is an OPTIONS request for '*', in which case the ":path" header
// field MUST include '*'.
// * All HTTP/2.0 requests MUST include exactly one valid value for all of these header fields. A
// server MUST treat the absence of any of these header fields, presence of multiple values, or
// an invalid value as a stream error of type PROTOCOL_ERROR.
this.method = this._checkSpecialHeader(':method' , headers[':method']);
this.scheme = this._checkSpecialHeader(':scheme' , headers[':scheme']);
this.host = this._checkSpecialHeader(':authority', headers[':authority'] );
this.url = this._checkSpecialHeader(':path' , headers[':path'] );
if (!this.method || !this.scheme || !this.host || !this.url) {
// This is invalid, and we've sent a RST_STREAM, so don't continue processing
return;
}
// * Host header is included in the headers object for backwards compatibility.
this.headers.host = this.host;
// * Handling regular headers.
IncomingMessage.prototype._onHeaders.call(this, headers);
// * Signaling that the headers arrived.
this._log.info({ method: this.method, scheme: this.scheme, host: this.host,
path: this.url, headers: this.headers }, 'Incoming request');
this.emit('ready');
};
// OutgoingResponse class
// ----------------------
function OutgoingResponse(stream) {
OutgoingMessage.call(this);
this._log = stream._log.child({ component: 'http' });
this.stream = stream;
this.statusCode = 200;
this.sendDate = true;
this.stream.once('headers', this._onRequestHeaders.bind(this));
}
OutgoingResponse.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingResponse } });
OutgoingResponse.prototype.writeHead = function writeHead(statusCode, reasonPhrase, headers) {
if (this.headersSent) {
return;
}
if (typeof reasonPhrase === 'string') {
this._log.warn('Reason phrase argument was present but ignored by the writeHead method');
} else {
headers = reasonPhrase;
}
for (var headerName in headers) {
if (headers.hasOwnProperty(headerName)) {
this.setHeader(headerName, headers[headerName]);
}
}
headers = this._headers;
if (this.sendDate && !('date' in this._headers)) {
headers.date = (new Date()).toUTCString();
}
this._log.info({ status: statusCode, headers: this._headers }, 'Sending server response');
headers[':status'] = this.statusCode = statusCode;
this.stream.headers(headers);
this.headersSent = true;
};
OutgoingResponse.prototype._implicitHeaders = function _implicitHeaders() {
if (!this.headersSent) {
this.writeHead(this.statusCode);
}
};
OutgoingResponse.prototype._implicitHeader = function() {
this._implicitHeaders();
};
OutgoingResponse.prototype.write = function write() {
this._implicitHeaders();
return OutgoingMessage.prototype.write.apply(this, arguments);
};
OutgoingResponse.prototype.end = function end() {
this.finished = true;
this._implicitHeaders();
return OutgoingMessage.prototype.end.apply(this, arguments);
};
OutgoingResponse.prototype._onRequestHeaders = function _onRequestHeaders(headers) {
this._requestHeaders = headers;
};
OutgoingResponse.prototype.push = function push(options) {
if (typeof options === 'string') {
options = url.parse(options);
}
if (!options.path) {
throw new Error('`path` option is mandatory.');
}
var promise = assign({
':method': (options.method || 'GET').toUpperCase(),
':scheme': (options.protocol && options.protocol.slice(0, -1)) || this._requestHeaders[':scheme'],
':authority': options.hostname || options.host || this._requestHeaders[':authority'],
':path': options.path
}, options.headers);
this._log.info({ method: promise[':method'], scheme: promise[':scheme'],
authority: promise[':authority'], path: promise[':path'],
headers: options.headers }, 'Promising push stream');
var pushStream = this.stream.promise(promise);
return new OutgoingResponse(pushStream);
};
OutgoingResponse.prototype.altsvc = function altsvc(host, port, protocolID, maxAge, origin) {
if (origin === undefined) {
origin = "";
}
this.stream.altsvc(host, port, protocolID, maxAge, origin);
};
// Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
// `request`. See `Server.prototype.on` for explanation.
OutgoingResponse.prototype.on = function on(event, listener) {
if (this.request && (event === 'timeout')) {
this.request.on(event, listener && listener.bind(this));
} else {
OutgoingMessage.prototype.on.call(this, event, listener);
}
};
// Client side
// ===========
exports.ClientRequest = OutgoingRequest; // for API compatibility
exports.OutgoingRequest = OutgoingRequest;
exports.IncomingResponse = IncomingResponse;
exports.Agent = Agent;
exports.globalAgent = undefined;
function requestRaw(options, callback) {
if (typeof options === "string") {
options = url.parse(options);
}
options.plain = true;
if (options.protocol && options.protocol !== "http:") {
throw new Error('This interface only supports http-schemed URLs');
}
if (options.agent && typeof(options.agent.request) === 'function') {
var agentOptions = assign({}, options);
delete agentOptions.agent;
return options.agent.request(agentOptions, callback);
}
return exports.globalAgent.request(options, callback);
}
function requestTLS(options, callback) {
if (typeof options === "string") {
options = url.parse(options);
}
options.plain = false;
if (options.protocol && options.protocol !== "https:") {
throw new Error('This interface only supports https-schemed URLs');
}
if (options.agent && typeof(options.agent.request) === 'function') {
var agentOptions = assign({}, options);
delete agentOptions.agent;
return options.agent.request(agentOptions, callback);
}
return exports.globalAgent.request(options, callback);
}
function getRaw(options, callback) {
if (typeof options === "string") {
options = url.parse(options);
}
options.plain = true;
if (options.protocol && options.protocol !== "http:") {
throw new Error('This interface only supports http-schemed URLs');
}
if (options.agent && typeof(options.agent.get) === 'function') {
var agentOptions = assign({}, options);
delete agentOptions.agent;
return options.agent.get(agentOptions, callback);
}
return exports.globalAgent.get(options, callback);
}
function getTLS(options, callback) {
if (typeof options === "string") {
options = url.parse(options);
}
options.plain = false;
if (options.protocol && options.protocol !== "https:") {
throw new Error('This interface only supports https-schemed URLs');
}
if (options.agent && typeof(options.agent.get) === 'function') {
var agentOptions = assign({}, options);
delete agentOptions.agent;
return options.agent.get(agentOptions, callback);
}
return exports.globalAgent.get(options, callback);
}
function postTLS(options, body, callback) {
if (typeof options === "string") {
options = url.parse(options);
}
options.plain = false;
if (options.protocol && options.protocol !== "https:") {
throw new Error('This interface only supports https-schemed URLs');
}
if (options.agent && typeof(options.agent.get) === 'function') {
var agentOptions = assign({}, options);
delete agentOptions.agent;
return options.agent.post(agentOptions, body, callback);
}
return exports.globalAgent.post(options, body, callback);
}
// Agent class
// -----------
function Agent(options) {
EventEmitter.call(this);
this.setMaxListeners(0);
options = assign({}, options);
this._settings = options.settings;
this._log = (options.log || defaultLogger).child({ component: 'http' });
this.endpoints = {};
// * Using an own HTTPS agent, because the global agent does not look at `NPN/ALPNProtocols` when
// generating the key identifying the connection, so we may get useless non-negotiated TLS
// channels even if we ask for a negotiated one. This agent will contain only negotiated
// channels.
options.ALPNProtocols = supportedProtocols;
options.NPNProtocols = supportedProtocols;
this._httpsAgent = new https.Agent(options);
this.sockets = this._httpsAgent.sockets;
this.requests = this._httpsAgent.requests;
}
Agent.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Agent } });
Agent.prototype.request = function request(options, callback) {
if (typeof options === 'string') {
options = url.parse(options);
} else {
options = assign({}, options);
}
options.method = (options.method || 'GET').toUpperCase();
options.protocol = options.protocol || 'https:';
options.host = options.hostname || options.host || 'localhost';
options.port = options.port || 443;
options.path = options.path || '/';
if (!options.plain && options.protocol === 'http:') {
this._log.error('Trying to negotiate client request with Upgrade from HTTP/1.1');
this.emit('error', new Error('HTTP1.1 -> HTTP2 upgrade is not yet supported.'));
}
var key, endpoint,
self = this,
request = new OutgoingRequest(self._log);
if (callback) {
request.on('response', callback);
}
// Re-use transportUrl endPoint if specified
if (options.transportUrl && options.transport) {
key = ([
options.transportUrl
]).join(':');
// Re-use host:port endPoint
} else {
key = ([
!!options.plain,
options.host,
options.port
]).join(':');
}
// * There's an existing HTTP/2 connection to this host
if (key in this.endpoints && this.endpoints[key]) {
endpoint = this.endpoints[key];
request._start(endpoint.createStream(), options, endpoint);
}
// * HTTP/2 over generic stream transport
else if(options.transport) {
endpoint = new Endpoint(this._log, 'CLIENT', this._settings);
endpoint.socket = options.transport;
endpoint.socket.on('error', function (error) {
self._log.error('Socket error: ' + error.toString());
request.emit('error', error);
});
endpoint.on('error', function(error){
self._log.error('Connection error: ' + error.toString());
request.emit('error', error);
});
endpoint.socket.on('close', function (error) {
delete self.endpoints[key];
});
this.endpoints[key] = endpoint;
endpoint.pipe(endpoint.socket).pipe(endpoint);
request._start(endpoint.createStream(), options, endpoint);
}
// * HTTP/2 over plain TCP
// TODO deprecate?
else if (options.plain) {
endpoint = new Endpoint(this._log, 'CLIENT', this._settings);
endpoint.socket = net.connect({
host: options.host,
port: options.port,
localAddress: options.localAddress
});
endpoint.socket.on('error', function (error) {
self._log.error('Socket error: ' + error.toString());
request.emit('error', error);
});
endpoint.on('error', function(error){
self._log.error('Connection error: ' + error.toString());
request.emit('error', error);
});
this.endpoints[key] = endpoint;
endpoint.pipe(endpoint.socket).pipe(endpoint);
request._start(endpoint.createStream(), options, endpoint);
}
// * HTTP/2 over TLS negotiated using NPN or ALPN, or fallback to HTTPS1
else {
var started = false;
var createAgent = hasAgentOptions(options);
options.ALPNProtocols = supportedProtocols;
options.NPNProtocols = supportedProtocols;
options.servername = options.host; // Server Name Indication
options.ciphers = options.ciphers || cipherSuites;
if (createAgent) {
options.agent = new https.Agent(options);
} else if (!options.agent) {
options.agent = this._httpsAgent;
}
var httpsRequest = https.request(options);
httpsRequest.on('error', function (error) {
self._log.error('Socket error: ' + error.toString());
self.removeAllListeners(key);
request.emit('error', error);
});
httpsRequest.on('socket', function(socket) {
var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
if (negotiatedProtocol) { // null in >=0.11.0, undefined in <0.11.0
negotiated();
} else {
socket.on('secureConnect', negotiated);
}
});
var negotiated = function () {
var endpoint;
var negotiatedProtocol = httpsRequest.socket.alpnProtocol || httpsRequest.socket.npnProtocol;
if (negotiatedProtocol === protocol.VERSION) {
httpsRequest.socket.emit('agentRemove');
unbundleSocket(httpsRequest.socket);
endpoint = new Endpoint(self._log, 'CLIENT', self._settings);
endpoint.socket = httpsRequest.socket;
endpoint.pipe(endpoint.socket).pipe(endpoint);
}
if (started) {
// ** In the meantime, an other connection was made to the same host...
if (endpoint) {
// *** and it turned out to be HTTP2 and the request was multiplexed on that one, so we should close this one
endpoint.close();
}
// *** otherwise, the fallback to HTTPS1 is already done.
} else {
if (endpoint) {
self._log.info({ e: endpoint, server: options.host + ':' + options.port },
'New outgoing HTTP/2 connection');
self.endpoints[key] = endpoint;
self.emit(key, endpoint);
} else {
self.emit(key, undefined);
}
}
};
this.once(key, function(endpoint) {
started = true;
if (endpoint) {
request._start(endpoint.createStream(), options, endpoint);
} else {
request._fallback(httpsRequest);
}
});
}
return request;
};
Agent.prototype.get = function get(options, callback) {
var request = this.request(options, callback);
request.end();
return request;
};
Agent.prototype.post = function get(options, body, callback) {
var request = this.request(options, callback);
request.end(body);
return request;
};
Agent.prototype.destroy = function(error) {
if (this._httpsAgent) {
this._httpsAgent.destroy();
}
for (var endpointName in this.endpoints) {
if (this.endpoints.hasOwnProperty(endpointName)) {
this.endpoints[endpointName].close(error);
}
}
};
function unbundleSocket(socket) {
socket.removeAllListeners('data');
socket.removeAllListeners('end');
socket.removeAllListeners('readable');
socket.removeAllListeners('close');
socket.removeAllListeners('error');
socket.unpipe();
delete socket.ondata;
delete socket.onend;
}
function hasValue(obj) {
return obj !== null && obj !== undefined;
}
function hasAgentOptions(options) {
return hasValue(options.pfx) ||
hasValue(options.key) ||
hasValue(options.passphrase) ||
hasValue(options.cert) ||
hasValue(options.ca) ||
hasValue(options.ciphers) ||
hasValue(options.rejectUnauthorized) ||
hasValue(options.secureProtocol);
}
Object.defineProperty(Agent.prototype, 'maxSockets', {
get: function getMaxSockets() {
return this._httpsAgent.maxSockets;
},
set: function setMaxSockets(value) {
this._httpsAgent.maxSockets = value;
}
});
exports.globalAgent = new Agent();
// OutgoingRequest class
// ---------------------
function OutgoingRequest() {
OutgoingMessage.call(this);
this._log = undefined;
this.stream = undefined;
}
OutgoingRequest.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingRequest } });
OutgoingRequest.prototype._retryAfterTimer = null;
OutgoingRequest.prototype._retryAfterBase = 200;
OutgoingRequest.prototype._retryAfterCap = 30000;
OutgoingRequest.prototype._retryAfterAttempt = null;
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
OutgoingRequest.prototype._retryAfter = function _retryAfter(retryAfterDelay) {
var options = this.options,
endpoint = this.endpoint,
newStream = endpoint.createStream(),
retryAfterDelayMs = retryAfterDelay * 1000;
// Clear request state
this._headers = {};
this.headersSent = false;
// Clear previous request retry
clearTimeout(this._retryAfterTimer);
this._retryAfterAttempt = this._retryAfterAttempt ? this._retryAfterAttempt++ : 1;
// Exponential backoff based on attempts:
// retryAfterDelayMs = max(retryAfter, random_between(0, min(cap, base * 2 ** attempt)))
// attempt intervals based on expression above and retryAfter = 0: [800,1600,3200,...30000]
retryAfterDelayMs = Math.max(retryAfterDelayMs,
randomIntFromInterval(0, Math.min(
this._retryAfterCap,
this._retryAfterBase * Math.pow(2, this._retryAfterAttempt)
))
);
// Schedule request retry
// TODO cancel retry on window onunload event?
// Note: has clearTimeout on Aborting
this._retryAfterTimer = setTimeout(this._start.bind(this, newStream, options, endpoint), retryAfterDelayMs);
};
OutgoingRequest.prototype._start = function _start(stream, options, endpoint) {
this.stream = stream;
this.options = options;
this.endpoint = endpoint;
this._log = stream._log.child({ component: 'http' });
for (var headerName in options.headers) {
if (options.headers.hasOwnProperty(headerName)) {
this.setHeader(headerName, options.headers[headerName]);
}
}
var headers = this._headers;
delete headers.host;
if (options.auth) {
headers.authorization = 'Basic ' + new Buffer(options.auth).toString('base64');
}
headers[':scheme'] = options.protocol.slice(0, -1);
headers[':method'] = options.method;
headers[':path'] = options.path;
if (options.port) {
headers[':authority'] = options.host + ':' + options.port;
} else {
headers[':authority'] = options.host;
}
// The app expects to handle the encoding
if (!headers['accept-encoding']) {
headers['accept-encoding'] = 'gzip';
}
this._log.info({ scheme: headers[':scheme'], method: headers[':method'],
authority: headers[':authority'], path: headers[':path'],
headers: (options.headers || {}) }, 'Sending request');
this.stream.headers(headers);
this.headersSent = true;
this.emit('socket', this.stream);
var response = new IncomingResponse(this.stream);
response.req = this;
response.once('ready', this.emit.bind(this, 'response', response));
this.stream.on('promise', this._onPromise.bind(this));
};
OutgoingRequest.prototype._fallback = function _fallback(request) {
request.on('response', this.emit.bind(this, 'response'));
this.stream = this.request = request;
this.emit('socket', this.socket);
};
OutgoingRequest.prototype.setPriority = function setPriority(priority) {
if (this.stream) {
this.stream.priority(priority);
} else {
this.once('socket', this.setPriority.bind(this, priority));
}
};
// Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
// `request`. See `Server.prototype.on` for explanation.
OutgoingRequest.prototype.on = function on(event, listener) {
if (this.request && (event === 'upgrade')) {
this.request.on(event, listener && listener.bind(this));
} else {
OutgoingMessage.prototype.on.call(this, event, listener);
}
};
// Methods only in fallback mode
OutgoingRequest.prototype.setNoDelay = function setNoDelay(noDelay) {
if (this.request) {
this.request.setNoDelay(noDelay);
} else if (!this.stream) {
this.on('socket', this.setNoDelay.bind(this, noDelay));
}
};
OutgoingRequest.prototype.setSocketKeepAlive = function setSocketKeepAlive(enable, initialDelay) {
if (this.request) {
this.request.setSocketKeepAlive(enable, initialDelay);
} else if (!this.stream) {
this.on('socket', this.setSocketKeepAlive.bind(this, enable, initialDelay));
}
};
OutgoingRequest.prototype.setTimeout = function setTimeout(timeout, callback) {
if (this.request) {
this.request.setTimeout(timeout, callback);
} else if (!this.stream) {
this.on('socket', this.setTimeout.bind(this, timeout, callback));
}
};
// Aborting the request
OutgoingRequest.prototype.abort = function abort() {
// Clear retry on abort
clearTimeout(this._retryAfterTimer);
if (this.request) {
this.request.abort();
} else if (this.stream) {
this.stream.reset('CANCEL');
} else {
this.on('socket', this.abort.bind(this));
}
};
// Receiving push promises
OutgoingRequest.prototype._onPromise = function _onPromise(stream, headers) {
this._log.info({ push_stream: stream.id }, 'Receiving push promise');
var promise = new IncomingPromise(stream, headers);
if (this.listeners('push').length > 0) {
this.emit('push', promise);
} else {
promise.cancel();
}
};
// IncomingResponse class
// ----------------------
function IncomingResponse(stream) {
IncomingMessage.call(this, stream);
}
IncomingResponse.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingResponse } });
// [Response Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.4)
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
// of key-value pairs. This includes the target URI for the request, the status code for the
// response, as well as HTTP header fields.
IncomingResponse.prototype.retryAfterStatusCodes = [503, 302, 429];
// Parse retry-after header delay to get next request retry attempt date in seconds
// * "Fri, 31 Dec 2018 23:59:59 GMT"
// "Thu Jul 12 2018 12:53:16 GMT-0700 (Pacific Daylight Time)"
// "120"
function parseRetryAfter(retryAfter) {
// Only parse once
if (typeof retryAfter === 'number') {
return retryAfter;
} else if (isNaN(retryAfter)) {
return Math.ceil((new Date(retryAfter).getTime() / 1000) - Date.now() / 1000);
} else {
return parseInt(retryAfter, 10);
}
}
IncomingResponse.prototype._onHeaders = function _onHeaders(headers) {
var self = this;
// * A single ":status" header field is defined that carries the HTTP status code field. This
// header field MUST be included in all responses.
// * A client MUST treat the absence of the ":status" header field, the presence of multiple
// values, or an invalid value as a stream error of type PROTOCOL_ERROR.
// Note: currently, we do not enforce it strictly: we accept any format, and parse it as int
// * HTTP/2.0 does not define a way to carry the reason phrase that is included in an HTTP/1.1
// status line.
self.statusCode = parseInt(self._checkSpecialHeader(':status', headers[':status']));
// TODO get other IncomingResponse that should share retryAfter directive to
// catch others request emited after this request IncomingResponse got locked in retryAfter.
// DEBUG:
//console.log('_onHeaders', headers[':status'], headers['retry-after']);
// If a Retry-After header ([RFC2616]) is present in the response, the client SHOULD<6> retry the
// request after waiting the number of seconds indicated by the Retry-After header. Any such value
// represents an estimate of when the server is expected to be able to process the request.
if (
self.retryAfterStatusCodes.indexOf(self.statusCode) !== -1 && // Match retry-after StatusCodes
headers.hasOwnProperty('retry-after') && headers['retry-after'] // Has retry-after and is not empty
) {
// Extract retryAfterDelay from retry-after header value in seconds
var retryAfterDelay = parseRetryAfter(headers['retry-after']);
// DEBUG:
//console.log('Incoming response with retry-after delay:' + retryAfterDelay);
// * Signaling that the headers arrived.
self._log.info({ status: self.statusCode, headers: self.headers}, 'Incoming response with retry-after delay:' + retryAfterDelay);
self.req._retryAfter(retryAfterDelay);
return;
}
// * Handling regular headers.
IncomingMessage.prototype._onHeaders.call(self, headers);
// * Signaling that the headers arrived.
self._log.info({ status: self.statusCode, headers: self.headers}, 'Incoming response');
self.emit('ready');
};
// IncomingPromise class
// -------------------------
function IncomingPromise(responseStream, promiseHeaders) {
var stream = new Readable();
stream._read = noop;
stream.push(null);
stream._log = responseStream._log;
IncomingRequest.call(this, stream);
this._onHeaders(promiseHeaders);
this._responseStream = responseStream;
var response = new IncomingResponse(this._responseStream);
response.once('ready', this.emit.bind(this, 'response', response));
this.stream.on('promise', this._onPromise.bind(this));
}
IncomingPromise.prototype = Object.create(IncomingRequest.prototype, { constructor: { value: IncomingPromise } });
IncomingPromise.prototype.cancel = function cancel() {
this._responseStream.reset('CANCEL');
};
IncomingPromise.prototype.setPriority = function setPriority(priority) {
this._responseStream.priority(priority);
};
IncomingPromise.prototype._onPromise = OutgoingRequest.prototype._onPromise;
}).call(this,require("buffer").Buffer)
},{"./protocol":88,"buffer":13,"events":16,"https":17,"net":10,"object.assign":91,"stream":43,"url":52,"util":56}],82:[function(require,module,exports){
// [node-http2][homepage] is an [HTTP/2][http2] implementation for [node.js][node].
//
// The core of the protocol is implemented in the protocol sub-directory. This directory provides
// two important features on top of the protocol:
//
// * Implementation of different negotiation schemes that can be used to start a HTTP2 connection.
// These include TLS ALPN, Upgrade and Plain TCP.
//
// * Providing an API very similar to the standard node.js [HTTPS module API][node-https]
// (which is in turn very similar to the [HTTP module API][node-http]).
//
// [homepage]: https://github.com/molnarg/node-http2
// [http2]: https://tools.ietf.org/html/rfc7540
// [node]: https://nodejs.org/
// [node-https]: https://nodejs.org/api/https.html
// [node-http]: https://nodejs.org/api/http.html
module.exports = require('./http');
/*
HTTP API
| ^
| |
+-------------|------------|------------------------------------------------------+
| | | Server/Agent |
| v | |
| +----------+ +----------+ |
| | Outgoing | | Incoming | |
| | req/res. | | req/res. | |
| +----------+ +----------+ |
| | ^ |
| | | |
| +---------|------------|-------------------------------------+ +----- |
| | | | Endpoint | | |
| | | | | | |
| | v | | | |
| | +-----------------------+ +-------------------- | | |
| | | Stream | | Stream ... | | |
| | +-----------------------+ +-------------------- | | |
| | | | |
| +------------------------------------------------------------+ +----- |
| | | |
| | | |
| v | |
| +------------------------------------------------------------+ +----- |
| | TCP stream | | ... |
| +------------------------------------------------------------+ +----- |
| |
+---------------------------------------------------------------------------------+
*/
},{"./http":81}],83:[function(require,module,exports){
(function (Buffer){
// The implementation of the [HTTP/2 Header Compression][http2-compression] spec is separated from
// the 'integration' part which handles HEADERS and PUSH_PROMISE frames. The compression itself is
// implemented in the first part of the file, and consists of three classes: `HeaderTable`,
// `HeaderSetDecompressor` and `HeaderSetCompressor`. The two latter classes are
// [Transform Stream][node-transform] subclasses that operate in [object mode][node-objectmode].
// These transform chunks of binary data into `[name, value]` pairs and vice versa, and store their
// state in `HeaderTable` instances.
//
// The 'integration' part is also implemented by two [Transform Stream][node-transform] subclasses
// that operate in [object mode][node-objectmode]: the `Compressor` and the `Decompressor`. These
// provide a layer between the [framer](framer.html) and the
// [connection handling component](connection.html).
//
// [node-transform]: https://nodejs.org/api/stream.html#stream_class_stream_transform
// [node-objectmode]: https://nodejs.org/api/stream.html#stream_new_stream_readable_options
// [http2-compression]: https://tools.ietf.org/html/rfc7541
exports.HeaderTable = HeaderTable;
exports.HuffmanTable = HuffmanTable;
exports.HeaderSetCompressor = HeaderSetCompressor;
exports.HeaderSetDecompressor = HeaderSetDecompressor;
exports.Compressor = Compressor;
exports.Decompressor = Decompressor;
var TransformStream = require('stream').Transform;
var assert = require('assert');
var util = require('util');
// Header compression
// ==================
// The HeaderTable class
// ---------------------
// The [Header Table] is a component used to associate headers to index values. It is basically an
// ordered list of `[name, value]` pairs, so it's implemented as a subclass of `Array`.
// In this implementation, the Header Table and the [Static Table] are handled as a single table.
// [Header Table]: https://tools.ietf.org/html/rfc7541#section-2.3.2
// [Static Table]: https://tools.ietf.org/html/rfc7541#section-2.3.1
function HeaderTable(log, limit) {
var self = HeaderTable.staticTable.map(entryFromPair);
self._log = log;
self._limit = limit || DEFAULT_HEADER_TABLE_LIMIT;
self._staticLength = self.length;
self._size = 0;
self._enforceLimit = HeaderTable.prototype._enforceLimit;
self.add = HeaderTable.prototype.add;
self.setSizeLimit = HeaderTable.prototype.setSizeLimit;
return self;
}
function entryFromPair(pair) {
var entry = pair.slice();
entry._size = size(entry);
return entry;
}
// The encoder decides how to update the header table and as such can control how much memory is
// used by the header table. To limit the memory requirements on the decoder side, the header table
// size is bounded.
//
// * The default header table size limit is 4096 bytes.
// * The size of an entry is defined as follows: the size of an entry is the sum of its name's
// length in bytes, of its value's length in bytes and of 32 bytes.
// * The size of a header table is the sum of the size of its entries.
var DEFAULT_HEADER_TABLE_LIMIT = 4096;
function size(entry) {
return (new Buffer(entry[0] + entry[1], 'utf8')).length + 32;
}
// The `add(index, entry)` can be used to [manage the header table][tablemgmt]:
// [tablemgmt]: https://tools.ietf.org/html/rfc7541#section-4
//
// * it pushes the new `entry` at the beggining of the table
// * before doing such a modification, it has to be ensured that the header table size will stay
// lower than or equal to the header table size limit. To achieve this, entries are evicted from
// the end of the header table until the size of the header table is less than or equal to
// `(this._limit - entry.size)`, or until the table is empty.
//
// <---------- Index Address Space ---------->
// <-- Static Table --> <-- Header Table -->
// +---+-----------+---+ +---+-----------+---+
// | 0 | ... | k | |k+1| ... | n |
// +---+-----------+---+ +---+-----------+---+
// ^ |
// | V
// Insertion Point Drop Point
HeaderTable.prototype._enforceLimit = function _enforceLimit(limit) {
var droppedEntries = [];
while ((this._size > 0) && (this._size > limit)) {
var dropped = this.pop();
this._size -= dropped._size;
droppedEntries.unshift(dropped);
}
return droppedEntries;
};
HeaderTable.prototype.add = function(entry) {
var limit = this._limit - entry._size;
var droppedEntries = this._enforceLimit(limit);
if (this._size <= limit) {
this.splice(this._staticLength, 0, entry);
this._size += entry._size;
}
return droppedEntries;
};
// The table size limit can be changed externally. In this case, the same eviction algorithm is used
HeaderTable.prototype.setSizeLimit = function setSizeLimit(limit) {
this._limit = limit;
this._enforceLimit(this._limit);
};
// [The Static Table](https://tools.ietf.org/html/rfc7541#section-2.3.1)
// ------------------
// The table is generated with feeding the table from the spec to the following sed command:
//
// sed -re "s/\s*\| [0-9]+\s*\| ([^ ]*)/ [ '\1'/g" -e "s/\|\s([^ ]*)/, '\1'/g" -e 's/ \|/],/g'
HeaderTable.staticTable = [
[ ':authority' , '' ],
[ ':method' , 'GET' ],
[ ':method' , 'POST' ],
[ ':path' , '/' ],
[ ':path' , '/index.html' ],
[ ':scheme' , 'http' ],
[ ':scheme' , 'https' ],
[ ':status' , '200' ],
[ ':status' , '204' ],
[ ':status' , '206' ],
[ ':status' , '304' ],
[ ':status' , '400' ],
[ ':status' , '404' ],
[ ':status' , '500' ],
[ 'accept-charset' , '' ],
[ 'accept-encoding' , 'gzip, deflate'],
[ 'accept-language' , '' ],
[ 'accept-ranges' , '' ],
[ 'accept' , '' ],
[ 'access-control-allow-origin' , '' ],
[ 'age' , '' ],
[ 'allow' , '' ],
[ 'authorization' , '' ],
[ 'cache-control' , '' ],
[ 'content-disposition' , '' ],
[ 'content-encoding' , '' ],
[ 'content-language' , '' ],
[ 'content-length' , '' ],
[ 'content-location' , '' ],
[ 'content-range' , '' ],
[ 'content-type' , '' ],
[ 'cookie' , '' ],
[ 'date' , '' ],
[ 'etag' , '' ],
[ 'expect' , '' ],
[ 'expires' , '' ],
[ 'from' , '' ],
[ 'host' , '' ],
[ 'if-match' , '' ],
[ 'if-modified-since' , '' ],
[ 'if-none-match' , '' ],
[ 'if-range' , '' ],
[ 'if-unmodified-since' , '' ],
[ 'last-modified' , '' ],
[ 'link' , '' ],
[ 'location' , '' ],
[ 'max-forwards' , '' ],
[ 'proxy-authenticate' , '' ],
[ 'proxy-authorization' , '' ],
[ 'range' , '' ],
[ 'referer' , '' ],
[ 'refresh' , '' ],
[ 'retry-after' , '' ],
[ 'server' , '' ],
[ 'set-cookie' , '' ],
[ 'strict-transport-security' , '' ],
[ 'transfer-encoding' , '' ],
[ 'user-agent' , '' ],
[ 'vary' , '' ],
[ 'via' , '' ],
[ 'www-authenticate' , '' ]
];
// The HeaderSetDecompressor class
// -------------------------------
// A `HeaderSetDecompressor` instance is a transform stream that can be used to *decompress a
// single header set*. Its input is a stream of binary data chunks and its output is a stream of
// `[name, value]` pairs.
//
// Currently, it is not a proper streaming decompressor implementation, since it buffer its input
// until the end os the stream, and then processes the whole header block at once.
util.inherits(HeaderSetDecompressor, TransformStream);
function HeaderSetDecompressor(log, table) {
TransformStream.call(this, { objectMode: true });
this._log = log.child({ component: 'compressor' });
this._table = table;
this._chunks = [];
}
// `_transform` is the implementation of the [corresponding virtual function][_transform] of the
// TransformStream class. It collects the data chunks for later processing.
// [_transform]: https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback
HeaderSetDecompressor.prototype._transform = function _transform(chunk, encoding, callback) {
this._chunks.push(chunk);
callback();
};
// `execute(rep)` executes the given [header representation][representation].
// [representation]: https://tools.ietf.org/html/rfc7541#section-6
// The *JavaScript object representation* of a header representation:
//
// {
// name: String || Integer, // string literal or index
// value: String || Integer, // string literal or index
// index: Boolean // with or without indexing
// }
//
// *Important:* to ease the indexing of the header table, indexes start at 0 instead of 1.
//
// Examples:
//
// Indexed:
// { name: 2 , value: 2 , index: false }
// Literal:
// { name: 2 , value: 'X', index: false } // without indexing
// { name: 2 , value: 'Y', index: true } // with indexing
// { name: 'A', value: 'Z', index: true } // with indexing, literal name
HeaderSetDecompressor.prototype._execute = function _execute(rep) {
this._log.trace({ key: rep.name, value: rep.value, index: rep.index },
'Executing header representation');
var entry, pair;
if (rep.contextUpdate) {
this._table.setSizeLimit(rep.newMaxSize);
}
// * An _indexed representation_ entails the following actions:
// * The header field corresponding to the referenced entry is emitted
else if (typeof rep.value === 'number') {
var index = rep.value;
entry = this._table[index];
pair = entry.slice();
this.push(pair);
}
// * A _literal representation_ that is _not added_ to the header table entails the following
// action:
// * The header is emitted.
// * A _literal representation_ that is _added_ to the header table entails the following further
// actions:
// * The header is added to the header table.
// * The header is emitted.
else {
if (typeof rep.name === 'number') {
pair = [this._table[rep.name][0], rep.value];
} else {
pair = [rep.name, rep.value];
}
if (rep.index) {
entry = entryFromPair(pair);
this._table.add(entry);
}
this.push(pair);
}
};
// `_flush` is the implementation of the [corresponding virtual function][_flush] of the
// TransformStream class. The whole decompressing process is done in `_flush`. It gets called when
// the input stream is over.
// [_flush]: https://nodejs.org/api/stream.html#stream_transform_flush_callback
HeaderSetDecompressor.prototype._flush = function _flush(callback) {
var buffer = concat(this._chunks);
// * processes the header representations
buffer.cursor = 0;
while (buffer.cursor < buffer.length) {
this._execute(HeaderSetDecompressor.header(buffer));
}
callback();
};
// The HeaderSetCompressor class
// -----------------------------
// A `HeaderSetCompressor` instance is a transform stream that can be used to *compress a single
// header set*. Its input is a stream of `[name, value]` pairs and its output is a stream of
// binary data chunks.
//
// It is a real streaming compressor, since it does not wait until the header set is complete.
//
// The compression algorithm is (intentionally) not specified by the spec. Therefore, the current
// compression algorithm can probably be improved in the future.
util.inherits(HeaderSetCompressor, TransformStream);
function HeaderSetCompressor(log, table) {
TransformStream.call(this, { objectMode: true });
this._log = log.child({ component: 'compressor' });
this._table = table;
this.push = TransformStream.prototype.push.bind(this);
}
HeaderSetCompressor.prototype.send = function send(rep) {
this._log.trace({ key: rep.name, value: rep.value, index: rep.index },
'Emitting header representation');
if (!rep.chunks) {
rep.chunks = HeaderSetCompressor.header(rep);
}
rep.chunks.forEach(this.push);
};
// `_transform` is the implementation of the [corresponding virtual function][_transform] of the
// TransformStream class. It processes the input headers one by one:
// [_transform]: https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback
HeaderSetCompressor.prototype._transform = function _transform(pair, encoding, callback) {
var name = pair[0].toLowerCase();
var value = pair[1];
var entry, rep;
// * tries to find full (name, value) or name match in the header table
var nameMatch = -1, fullMatch = -1;
for (var droppedIndex = 0; droppedIndex < this._table.length; droppedIndex++) {
entry = this._table[droppedIndex];
if (entry[0] === name) {
if (entry[1] === value) {
fullMatch = droppedIndex;
break;
} else if (nameMatch === -1) {
nameMatch = droppedIndex;
}
}
}
var mustNeverIndex = ((name === 'cookie' && value.length < 20) ||
(name === 'set-cookie' && value.length < 20) ||
name === 'authorization');
if (fullMatch !== -1 && !mustNeverIndex) {
this.send({ name: fullMatch, value: fullMatch, index: false });
}
// * otherwise, it will be a literal representation (with a name index if there's a name match)
else {
entry = entryFromPair(pair);
var indexing = (entry._size < this._table._limit / 2) && !mustNeverIndex;
if (indexing) {
this._table.add(entry);
}
this.send({ name: (nameMatch !== -1) ? nameMatch : name, value: value, index: indexing, mustNeverIndex: mustNeverIndex, contextUpdate: false });
}
callback();
};
// `_flush` is the implementation of the [corresponding virtual function][_flush] of the
// TransformStream class. It gets called when there's no more header to compress. The final step:
// [_flush]: https://nodejs.org/api/stream.html#stream_transform_flush_callback
HeaderSetCompressor.prototype._flush = function _flush(callback) {
callback();
};
// [Detailed Format](https://tools.ietf.org/html/rfc7541#section-5)
// -----------------
// ### Integer representation ###
//
// The algorithm to represent an integer I is as follows:
//
// 1. If I < 2^N - 1, encode I on N bits
// 2. Else, encode 2^N - 1 on N bits and do the following steps:
// 1. Set I to (I - (2^N - 1)) and Q to 1
// 2. While Q > 0
// 1. Compute Q and R, quotient and remainder of I divided by 2^7
// 2. If Q is strictly greater than 0, write one 1 bit; otherwise, write one 0 bit
// 3. Encode R on the next 7 bits
// 4. I = Q
HeaderSetCompressor.integer = function writeInteger(I, N) {
var limit = Math.pow(2,N) - 1;
if (I < limit) {
return [new Buffer([I])];
}
var bytes = [];
if (N !== 0) {
bytes.push(limit);
}
I -= limit;
var Q = 1, R;
while (Q > 0) {
Q = Math.floor(I / 128);
R = I % 128;
if (Q > 0) {
R += 128;
}
bytes.push(R);
I = Q;
}
return [new Buffer(bytes)];
};
// The inverse algorithm:
//
// 1. Set I to the number coded on the lower N bits of the first byte
// 2. If I is smaller than 2^N - 1 then return I
// 2. Else the number is encoded on more than one byte, so do the following steps:
// 1. Set M to 0
// 2. While returning with I
// 1. Let B be the next byte (the first byte if N is 0)
// 2. Read out the lower 7 bits of B and multiply it with 2^M
// 3. Increase I with this number
// 4. Increase M by 7
// 5. Return I if the most significant bit of B is 0
HeaderSetDecompressor.integer = function readInteger(buffer, N) {
var limit = Math.pow(2,N) - 1;
var I = buffer[buffer.cursor] & limit;
if (N !== 0) {
buffer.cursor += 1;
}
if (I === limit) {
var M = 0;
do {
I += (buffer[buffer.cursor] & 127) << M;
M += 7;
buffer.cursor += 1;
} while (buffer[buffer.cursor - 1] & 128);
}
return I;
};
// ### Huffman Encoding ###
function HuffmanTable(table) {
function createTree(codes, position) {
if (codes.length === 1) {
return [table.indexOf(codes[0])];
}
else {
position = position || 0;
var zero = [];
var one = [];
for (var i = 0; i < codes.length; i++) {
var string = codes[i];
if (string[position] === '0') {
zero.push(string);
} else {
one.push(string);
}
}
return [createTree(zero, position + 1), createTree(one, position + 1)];
}
}
this.tree = createTree(table);
this.codes = table.map(function(bits) {
return parseInt(bits, 2);
});
this.lengths = table.map(function(bits) {
return bits.length;
});
}
HuffmanTable.prototype.encode = function encode(buffer) {
var result = [];
var space = 8;
function add(data) {
if (space === 8) {
result.push(data);
} else {
result[result.length - 1] |= data;
}
}
for (var i = 0; i < buffer.length; i++) {
var byte = buffer[i];
var code = this.codes[byte];
var length = this.lengths[byte];
while (length !== 0) {
if (space >= length) {
add(code << (space - length));
code = 0;
space -= length;
length = 0;
} else {
var shift = length - space;
var msb = code >> shift;
add(msb);
code -= msb << shift;
length -= space;
space = 0;
}
if (space === 0) {
space = 8;
}
}
}
if (space !== 8) {
add(this.codes[256] >> (this.lengths[256] - space));
}
return new Buffer(result);
};
HuffmanTable.prototype.decode = function decode(buffer) {
var result = [];
var subtree = this.tree;
for (var i = 0; i < buffer.length; i++) {
var byte = buffer[i];
for (var j = 0; j < 8; j++) {
var bit = (byte & 128) ? 1 : 0;
byte = byte << 1;
subtree = subtree[bit];
if (subtree.length === 1) {
result.push(subtree[0]);
subtree = this.tree;
}
}
}
return new Buffer(result);
};
// The initializer arrays for the Huffman tables are generated with feeding the tables from the
// spec to this sed command:
//
// sed -e "s/^.* [|]//g" -e "s/|//g" -e "s/ .*//g" -e "s/^/ '/g" -e "s/$/',/g"
HuffmanTable.huffmanTable = new HuffmanTable([
'1111111111000',
'11111111111111111011000',
'1111111111111111111111100010',
'1111111111111111111111100011',
'1111111111111111111111100100',
'1111111111111111111111100101',
'1111111111111111111111100110',
'1111111111111111111111100111',
'1111111111111111111111101000',
'111111111111111111101010',
'111111111111111111111111111100',
'1111111111111111111111101001',
'1111111111111111111111101010',
'111111111111111111111111111101',
'1111111111111111111111101011',
'1111111111111111111111101100',
'1111111111111111111111101101',
'1111111111111111111111101110',
'1111111111111111111111101111',
'1111111111111111111111110000',
'1111111111111111111111110001',
'1111111111111111111111110010',
'111111111111111111111111111110',
'1111111111111111111111110011',
'1111111111111111111111110100',
'1111111111111111111111110101',
'1111111111111111111111110110',
'1111111111111111111111110111',
'1111111111111111111111111000',
'1111111111111111111111111001',
'1111111111111111111111111010',
'1111111111111111111111111011',
'010100',
'1111111000',
'1111111001',
'111111111010',
'1111111111001',
'010101',
'11111000',
'11111111010',
'1111111010',
'1111111011',
'11111001',
'11111111011',
'11111010',
'010110',
'010111',
'011000',
'00000',
'00001',
'00010',
'011001',
'011010',
'011011',
'011100',
'011101',
'011110',
'011111',
'1011100',
'11111011',
'111111111111100',
'100000',
'111111111011',
'1111111100',
'1111111111010',
'100001',
'1011101',
'1011110',
'1011111',
'1100000',
'1100001',
'1100010',
'1100011',
'1100100',
'1100101',
'1100110',
'1100111',
'1101000',
'1101001',
'1101010',
'1101011',
'1101100',
'1101101',
'1101110',
'1101111',
'1110000',
'1110001',
'1110010',
'11111100',
'1110011',
'11111101',
'1111111111011',
'1111111111111110000',
'1111111111100',
'11111111111100',
'100010',
'111111111111101',
'00011',
'100011',
'00100',
'100100',
'00101',
'100101',
'100110',
'100111',
'00110',
'1110100',
'1110101',
'101000',
'101001',
'101010',
'00111',
'101011',
'1110110',
'101100',
'01000',
'01001',
'101101',
'1110111',
'1111000',
'1111001',
'1111010',
'1111011',
'111111111111110',
'11111111100',
'11111111111101',
'1111111111101',
'1111111111111111111111111100',
'11111111111111100110',
'1111111111111111010010',
'11111111111111100111',
'11111111111111101000',
'1111111111111111010011',
'1111111111111111010100',
'1111111111111111010101',
'11111111111111111011001',
'1111111111111111010110',
'11111111111111111011010',
'11111111111111111011011',
'11111111111111111011100',
'11111111111111111011101',
'11111111111111111011110',
'111111111111111111101011',
'11111111111111111011111',
'111111111111111111101100',
'111111111111111111101101',
'1111111111111111010111',
'11111111111111111100000',
'111111111111111111101110',
'11111111111111111100001',
'11111111111111111100010',
'11111111111111111100011',
'11111111111111111100100',
'111111111111111011100',
'1111111111111111011000',
'11111111111111111100101',
'1111111111111111011001',
'11111111111111111100110',
'11111111111111111100111',
'111111111111111111101111',
'1111111111111111011010',
'111111111111111011101',
'11111111111111101001',
'1111111111111111011011',
'1111111111111111011100',
'11111111111111111101000',
'11111111111111111101001',
'111111111111111011110',
'11111111111111111101010',
'1111111111111111011101',
'1111111111111111011110',
'111111111111111111110000',
'111111111111111011111',
'1111111111111111011111',
'11111111111111111101011',
'11111111111111111101100',
'111111111111111100000',
'111111111111111100001',
'1111111111111111100000',
'111111111111111100010',
'11111111111111111101101',
'1111111111111111100001',
'11111111111111111101110',
'11111111111111111101111',
'11111111111111101010',
'1111111111111111100010',
'1111111111111111100011',
'1111111111111111100100',
'11111111111111111110000',
'1111111111111111100101',
'1111111111111111100110',
'11111111111111111110001',
'11111111111111111111100000',
'11111111111111111111100001',
'11111111111111101011',
'1111111111111110001',
'1111111111111111100111',
'11111111111111111110010',
'1111111111111111101000',
'1111111111111111111101100',
'11111111111111111111100010',
'11111111111111111111100011',
'11111111111111111111100100',
'111111111111111111111011110',
'111111111111111111111011111',
'11111111111111111111100101',
'111111111111111111110001',
'1111111111111111111101101',
'1111111111111110010',
'111111111111111100011',
'11111111111111111111100110',
'111111111111111111111100000',
'111111111111111111111100001',
'11111111111111111111100111',
'111111111111111111111100010',
'111111111111111111110010',
'111111111111111100100',
'111111111111111100101',
'11111111111111111111101000',
'11111111111111111111101001',
'1111111111111111111111111101',
'111111111111111111111100011',
'111111111111111111111100100',
'111111111111111111111100101',
'11111111111111101100',
'111111111111111111110011',
'11111111111111101101',
'111111111111111100110',
'1111111111111111101001',
'111111111111111100111',
'111111111111111101000',
'11111111111111111110011',
'1111111111111111101010',
'1111111111111111101011',
'1111111111111111111101110',
'1111111111111111111101111',
'111111111111111111110100',
'111111111111111111110101',
'11111111111111111111101010',
'11111111111111111110100',
'11111111111111111111101011',
'111111111111111111111100110',
'11111111111111111111101100',
'11111111111111111111101101',
'111111111111111111111100111',
'111111111111111111111101000',
'111111111111111111111101001',
'111111111111111111111101010',
'111111111111111111111101011',
'1111111111111111111111111110',
'111111111111111111111101100',
'111111111111111111111101101',
'111111111111111111111101110',
'111111111111111111111101111',
'111111111111111111111110000',
'11111111111111111111101110',
'111111111111111111111111111111'
]);
// ### String literal representation ###
//
// Literal **strings** can represent header names or header values. There's two variant of the
// string encoding:
//
// String literal with Huffman encoding:
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 1 | Value Length Prefix (7) |
// +---+---+---+---+---+---+---+---+
// | Value Length (0-N bytes) |
// +---+---+---+---+---+---+---+---+
// ...
// +---+---+---+---+---+---+---+---+
// | Huffman Encoded Data |Padding|
// +---+---+---+---+---+---+---+---+
//
// String literal without Huffman encoding:
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | Value Length Prefix (7) |
// +---+---+---+---+---+---+---+---+
// | Value Length (0-N bytes) |
// +---+---+---+---+---+---+---+---+
// ...
// +---+---+---+---+---+---+---+---+
// | Field Bytes Without Encoding |
// +---+---+---+---+---+---+---+---+
HeaderSetCompressor.string = function writeString(str) {
str = new Buffer(str, 'utf8');
var huffman = HuffmanTable.huffmanTable.encode(str);
if (huffman.length < str.length) {
var length = HeaderSetCompressor.integer(huffman.length, 7);
length[0][0] |= 128;
return length.concat(huffman);
}
else {
length = HeaderSetCompressor.integer(str.length, 7);
return length.concat(str);
}
};
HeaderSetDecompressor.string = function readString(buffer) {
var huffman = buffer[buffer.cursor] & 128;
var length = HeaderSetDecompressor.integer(buffer, 7);
var encoded = buffer.slice(buffer.cursor, buffer.cursor + length);
buffer.cursor += length;
return (huffman ? HuffmanTable.huffmanTable.decode(encoded) : encoded).toString('utf8');
};
// ### Header represenations ###
// The JavaScript object representation is described near the
// `HeaderSetDecompressor.prototype._execute()` method definition.
//
// **All binary header representations** start with a prefix signaling the representation type and
// an index represented using prefix coded integers:
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 1 | Index (7+) | Indexed Representation
// +---+---------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 1 | Index (6+) |
// +---+---+---+-------------------+ Literal w/ Indexing
// | Value Length (8+) |
// +-------------------------------+ w/ Indexed Name
// | Value String (Length octets) |
// +-------------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 1 | 0 |
// +---+---+---+-------------------+
// | Name Length (8+) |
// +-------------------------------+ Literal w/ Indexing
// | Name String (Length octets) |
// +-------------------------------+ w/ New Name
// | Value Length (8+) |
// +-------------------------------+
// | Value String (Length octets) |
// +-------------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 0 | Index (4+) |
// +---+---+---+-------------------+ Literal w/o Incremental Indexing
// | Value Length (8+) |
// +-------------------------------+ w/ Indexed Name
// | Value String (Length octets) |
// +-------------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 0 | 0 |
// +---+---+---+-------------------+
// | Name Length (8+) |
// +-------------------------------+ Literal w/o Incremental Indexing
// | Name String (Length octets) |
// +-------------------------------+ w/ New Name
// | Value Length (8+) |
// +-------------------------------+
// | Value String (Length octets) |
// +-------------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 1 | Index (4+) |
// +---+---+---+-------------------+ Literal never indexed
// | Value Length (8+) |
// +-------------------------------+ w/ Indexed Name
// | Value String (Length octets) |
// +-------------------------------+
//
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 1 | 0 |
// +---+---+---+-------------------+
// | Name Length (8+) |
// +-------------------------------+ Literal never indexed
// | Name String (Length octets) |
// +-------------------------------+ w/ New Name
// | Value Length (8+) |
// +-------------------------------+
// | Value String (Length octets) |
// +-------------------------------+
//
// The **Indexed Representation** consists of the 1-bit prefix and the Index that is represented as
// a 7-bit prefix coded integer and nothing else.
//
// After the first bits, **all literal representations** specify the header name, either as a
// pointer to the Header Table (Index) or a string literal. When the string literal representation
// is used, the Index is set to 0 and the string literal starts at the second byte.
//
// For **all literal representations**, the specification of the header value comes next. It is
// always represented as a string.
var representations = {
indexed : { prefix: 7, pattern: 0x80 },
literalIncremental : { prefix: 6, pattern: 0x40 },
contextUpdate : { prefix: 0, pattern: 0x20 },
literalNeverIndexed : { prefix: 4, pattern: 0x10 },
literal : { prefix: 4, pattern: 0x00 }
};
HeaderSetCompressor.header = function writeHeader(header) {
var representation, buffers = [];
if (header.contextUpdate) {
representation = representations.contextUpdate;
} else if (typeof header.value === 'number') {
representation = representations.indexed;
} else if (header.index) {
representation = representations.literalIncremental;
} else if (header.mustNeverIndex) {
representation = representations.literalNeverIndexed;
} else {
representation = representations.literal;
}
if (representation === representations.contextUpdate) {
buffers.push(HeaderSetCompressor.integer(header.newMaxSize, 5));
}
else if (representation === representations.indexed) {
buffers.push(HeaderSetCompressor.integer(header.value + 1, representation.prefix));
}
else {
if (typeof header.name === 'number') {
buffers.push(HeaderSetCompressor.integer(header.name + 1, representation.prefix));
} else {
buffers.push(HeaderSetCompressor.integer(0, representation.prefix));
buffers.push(HeaderSetCompressor.string(header.name));
}
buffers.push(HeaderSetCompressor.string(header.value));
}
buffers[0][0][0] |= representation.pattern;
return Array.prototype.concat.apply([], buffers); // array of arrays of buffers -> array of buffers
};
HeaderSetDecompressor.header = function readHeader(buffer) {
var representation, header = {};
var firstByte = buffer[buffer.cursor];
if (firstByte & 0x80) {
representation = representations.indexed;
} else if (firstByte & 0x40) {
representation = representations.literalIncremental;
} else if (firstByte & 0x20) {
representation = representations.contextUpdate;
} else if (firstByte & 0x10) {
representation = representations.literalNeverIndexed;
} else {
representation = representations.literal;
}
header.value = header.name = -1;
header.index = false;
header.contextUpdate = false;
header.newMaxSize = 0;
header.mustNeverIndex = false;
if (representation === representations.contextUpdate) {
header.contextUpdate = true;
header.newMaxSize = HeaderSetDecompressor.integer(buffer, 5);
}
else if (representation === representations.indexed) {
header.value = header.name = HeaderSetDecompressor.integer(buffer, representation.prefix) - 1;
}
else {
header.name = HeaderSetDecompressor.integer(buffer, representation.prefix) - 1;
if (header.name === -1) {
header.name = HeaderSetDecompressor.string(buffer);
}
header.value = HeaderSetDecompressor.string(buffer);
header.index = (representation === representations.literalIncremental);
header.mustNeverIndex = (representation === representations.literalNeverIndexed);
}
return header;
};
// Integration with HTTP/2
// =======================
// This section describes the interaction between the compressor/decompressor and the rest of the
// HTTP/2 implementation. The `Compressor` and the `Decompressor` makes up a layer between the
// [framer](framer.html) and the [connection handling component](connection.html). They let most
// frames pass through, except HEADERS and PUSH_PROMISE frames. They convert the frames between
// these two representations:
//
// { {
// type: 'HEADERS', type: 'HEADERS',
// flags: {}, flags: {},
// stream: 1, <===> stream: 1,
// headers: { data: Buffer
// N1: 'V1', }
// N2: ['V1', 'V2', ...],
// // ...
// }
// }
//
// There are possibly several binary frame that belong to a single non-binary frame.
var MAX_HTTP_PAYLOAD_SIZE = 16384;
// The Compressor class
// --------------------
// The Compressor transform stream is basically stateless.
util.inherits(Compressor, TransformStream);
function Compressor(log, type) {
TransformStream.call(this, { objectMode: true });
this._log = log.child({ component: 'compressor' });
assert((type === 'REQUEST') || (type === 'RESPONSE'));
this._table = new HeaderTable(this._log);
this.tableSizeChangePending = false;
this.lowestTableSizePending = 0;
this.tableSizeSetting = DEFAULT_HEADER_TABLE_LIMIT;
}
// Changing the header table size
Compressor.prototype.setTableSizeLimit = function setTableSizeLimit(size) {
this._table.setSizeLimit(size);
if (!this.tableSizeChangePending || size < this.lowestTableSizePending) {
this.lowestTableSizePending = size;
}
this.tableSizeSetting = size;
this.tableSizeChangePending = true;
};
// `compress` takes a header set, and compresses it using a new `HeaderSetCompressor` stream
// instance. This means that from now on, the advantages of streaming header encoding are lost,
// but the API becomes simpler.
Compressor.prototype.compress = function compress(headers) {
var compressor = new HeaderSetCompressor(this._log, this._table);
if (this.tableSizeChangePending) {
if (this.lowestTableSizePending < this.tableSizeSetting) {
compressor.send({contextUpdate: true, newMaxSize: this.lowestTableSizePending,
name: "", value: "", index: 0});
}
compressor.send({contextUpdate: true, newMaxSize: this.tableSizeSetting,
name: "", value: "", index: 0});
this.tableSizeChangePending = false;
}
var colonHeaders = [];
var nonColonHeaders = [];
// To ensure we send colon headers first
for (var name in headers) {
if (name.trim()[0] === ':') {
colonHeaders.push(name);
} else {
nonColonHeaders.push(name);
}
}
function compressHeader(name) {
var value = headers[name];
name = String(name).toLowerCase();
// * To allow for better compression efficiency, the Cookie header field MAY be split into
// separate header fields, each with one or more cookie-pairs.
if (name == 'cookie') {
if (!(value instanceof Array)) {
value = [value];
}
value = Array.prototype.concat.apply([], value.map(function(cookie) {
return String(cookie).split(';').map(trim);
}));
}
if (value instanceof Array) {
for (var i = 0; i < value.length; i++) {
compressor.write([name, String(value[i])]);
}
} else {
compressor.write([name, String(value)]);
}
}
colonHeaders.forEach(compressHeader);
nonColonHeaders.forEach(compressHeader);
compressor.end();
var chunk, chunks = [];
while (chunk = compressor.read()) {
chunks.push(chunk);
}
return concat(chunks);
};
// When a `frame` arrives
Compressor.prototype._transform = function _transform(frame, encoding, done) {
// * and it is a HEADERS or PUSH_PROMISE frame
// * it generates a header block using the compress method
// * cuts the header block into `chunks` that are not larger than `MAX_HTTP_PAYLOAD_SIZE`
// * for each chunk, it pushes out a chunk frame that is identical to the original, except
// the `data` property which holds the given chunk, the type of the frame which is always
// CONTINUATION except for the first frame, and the END_HEADERS/END_PUSH_STREAM flag that
// marks the last frame and the END_STREAM flag which is always false before the end
if (frame.type === 'HEADERS' || frame.type === 'PUSH_PROMISE') {
var buffer = this.compress(frame.headers);
// This will result in CONTINUATIONs from a PUSH_PROMISE being 4 bytes shorter than they could
// be, but that's not the end of the world, and it prevents us from going over MAX_HTTP_PAYLOAD_SIZE
// on the initial PUSH_PROMISE frame.
var adjustment = frame.type === 'PUSH_PROMISE' ? 4 : 0;
var chunks = cut(buffer, MAX_HTTP_PAYLOAD_SIZE - adjustment);
for (var i = 0; i < chunks.length; i++) {
var chunkFrame;
var first = (i === 0);
var last = (i === chunks.length - 1);
if (first) {
chunkFrame = util._extend({}, frame);
chunkFrame.flags = util._extend({}, frame.flags);
chunkFrame.flags['END_' + frame.type] = last;
} else {
chunkFrame = {
type: 'CONTINUATION',
flags: { END_HEADERS: last },
stream: frame.stream
};
}
chunkFrame.data = chunks[i];
this.push(chunkFrame);
}
}
// * otherwise, the frame is forwarded without taking any action
else {
this.push(frame);
}
done();
};
// The Decompressor class
// ----------------------
// The Decompressor is a stateful transform stream, since it has to collect multiple frames first,
// and the decoding comes after unifying the payload of those frames.
//
// If there's a frame in progress, `this._inProgress` is `true`. The frames are collected in
// `this._frames`, and the type of the frame and the stream identifier is stored in `this._type`
// and `this._stream` respectively.
util.inherits(Decompressor, TransformStream);
function Decompressor(log, type) {
TransformStream.call(this, { objectMode: true });
this._log = log.child({ component: 'compressor' });
assert((type === 'REQUEST') || (type === 'RESPONSE'));
this._table = new HeaderTable(this._log);
this._inProgress = false;
this._base = undefined;
}
// Changing the header table size
Decompressor.prototype.setTableSizeLimit = function setTableSizeLimit(size) {
this._table.setSizeLimit(size);
};
// `decompress` takes a full header block, and decompresses it using a new `HeaderSetDecompressor`
// stream instance. This means that from now on, the advantages of streaming header decoding are
// lost, but the API becomes simpler.
Decompressor.prototype.decompress = function decompress(block) {
var decompressor = new HeaderSetDecompressor(this._log, this._table);
decompressor.end(block);
var seenNonColonHeader = false;
var headers = {};
var pair;
while (pair = decompressor.read()) {
var name = pair[0];
var value = pair[1];
var isColonHeader = (name.trim()[0] === ':');
if (seenNonColonHeader && isColonHeader) {
this.emit('error', 'PROTOCOL_ERROR');
return headers;
}
seenNonColonHeader = !isColonHeader;
if (name in headers) {
if (headers[name] instanceof Array) {
headers[name].push(value);
} else {
headers[name] = [headers[name], value];
}
} else {
headers[name] = value;
}
}
// * If there are multiple Cookie header fields after decompression, these MUST be concatenated
// into a single octet string using the two octet delimiter of 0x3B, 0x20 (the ASCII
// string "; ").
if (('cookie' in headers) && (headers['cookie'] instanceof Array)) {
headers['cookie'] = headers['cookie'].join('; ');
}
return headers;
};
// When a `frame` arrives
Decompressor.prototype._transform = function _transform(frame, encoding, done) {
// * and the collection process is already `_inProgress`, the frame is simply stored, except if
// it's an illegal frame
if (this._inProgress) {
if ((frame.type !== 'CONTINUATION') || (frame.stream !== this._base.stream)) {
this._log.error('A series of HEADER frames were not continuous');
this.emit('error', 'PROTOCOL_ERROR');
return;
}
this._frames.push(frame);
}
// * and the collection process is not `_inProgress`, but the new frame's type is HEADERS or
// PUSH_PROMISE, a new collection process begins
else if ((frame.type === 'HEADERS') || (frame.type === 'PUSH_PROMISE')) {
this._inProgress = true;
this._base = util._extend({}, frame);
this._frames = [frame];
}
// * otherwise, the frame is forwarded without taking any action
else {
this.push(frame);
}
// * When the frame signals that it's the last in the series, the header block chunks are
// concatenated, the headers are decompressed, and a new frame gets pushed out with the
// decompressed headers.
if (this._inProgress && (frame.flags.END_HEADERS || frame.flags.END_PUSH_PROMISE)) {
var buffer = concat(this._frames.map(function(frame) {
return frame.data;
}));
try {
var headers = this.decompress(buffer);
} catch(error) {
this._log.error({ err: error }, 'Header decompression error');
this.emit('error', 'COMPRESSION_ERROR');
return;
}
this.push(util._extend(this._base, { headers: headers }));
this._inProgress = false;
}
done();
};
// Helper functions
// ================
// Concatenate an array of buffers into a new buffer
function concat(buffers) {
var size = 0;
for (var i = 0; i < buffers.length; i++) {
size += buffers[i].length;
}
var concatenated = new Buffer(size);
for (var cursor = 0, j = 0; j < buffers.length; cursor += buffers[j].length, j++) {
buffers[j].copy(concatenated, cursor);
}
return concatenated;
}
// Cut `buffer` into chunks not larger than `size`
function cut(buffer, size) {
var chunks = [];
var cursor = 0;
do {
var chunkSize = Math.min(size, buffer.length - cursor);
chunks.push(buffer.slice(cursor, cursor + chunkSize));
cursor += chunkSize;
} while(cursor < buffer.length);
return chunks;
}
function trim(string) {
return string.trim();
}
}).call(this,require("buffer").Buffer)
},{"assert":11,"buffer":13,"stream":43,"util":56}],84:[function(require,module,exports){
(function (global,Buffer){
var assert = require('assert');
// The Connection class
// ====================
// The Connection class manages HTTP/2 connections. Each instance corresponds to one transport
// stream (TCP stream). It operates by sending and receiving frames and is implemented as a
// [Flow](flow.html) subclass.
var Flow = require('./flow').Flow;
require('setimmediate');
exports.Connection = Connection;
// Public API
// ----------
// * **new Connection(log, firstStreamId, settings)**: create a new Connection
//
// * **Event: 'error' (type)**: signals a connection level error made by the other end
//
// * **Event: 'peerError' (type)**: signals the receipt of a GOAWAY frame that contains an error
// code other than NO_ERROR
//
// * **Event: 'stream' (stream)**: signals that there's an incoming stream
//
// * **createStream(): stream**: initiate a new stream
//
// * **set(settings, callback)**: change the value of one or more settings according to the
// key-value pairs of `settings`. The callback is called after the peer acknowledged the changes.
//
// * **ping([callback])**: send a ping and call callback when the answer arrives
//
// * **close([error])**: close the stream with an error code
// Constructor
// -----------
// The main aspects of managing the connection are:
function Connection(log, firstStreamId, settings) {
// * initializing the base class
Flow.call(this, 0);
// * logging: every method uses the common logger object
this._log = log.child({ component: 'connection' });
// * stream management
this._initializeStreamManagement(firstStreamId);
// * lifecycle management
this._initializeLifecycleManagement();
// * flow control
this._initializeFlowControl();
// * settings management
this._initializeSettingsManagement(settings);
this._initializeConnectionFlowControl();
// * multiplexing
this._initializeMultiplexing();
}
Connection.prototype = Object.create(Flow.prototype, { constructor: { value: Connection } });
// Overview
// --------
// | ^ | ^
// v | v |
// +--------------+ +--------------+
// +---| stream1 |---| stream2 |---- .... ---+
// | | +----------+ | | +----------+ | |
// | | | stream1. | | | | stream2. | | |
// | +-| upstream |-+ +-| upstream |-+ |
// | +----------+ +----------+ |
// | | ^ | ^ |
// | v | v | |
// | +-----+-------------+-----+-------- .... |
// | ^ | | | |
// | | v | | |
// | +--------------+ | | |
// | | stream0 | | | |
// | | connection | | | |
// | | management | multiplexing |
// | +--------------+ flow control |
// | | ^ |
// | _read() | | _write() |
// | v | |
// | +------------+ +-----------+ |
// | |output queue| |input queue| |
// +----------------+------------+-+-----------+-----------------+
// | ^
// read() | | write()
// v |
// Stream management
// -----------------
var Stream = require('./stream').Stream;
// Initialization:
Connection.prototype._initializeStreamManagement = function _initializeStreamManagement(firstStreamId) {
// * streams are stored in two data structures:
// * `_streamIds` is an id -> stream map of the streams that are allowed to receive frames.
// * `_streamPriorities` is a priority -> [stream] map of stream that allowed to send frames.
this._streamIds = [];
this._streamPriorities = [];
// * The next outbound stream ID and the last inbound stream id
this._nextStreamId = firstStreamId;
this._lastIncomingStream = 0;
// * Calling `_writeControlFrame` when there's an incoming stream with 0 as stream ID
this._streamIds[0] = { upstream: { write: this._writeControlFrame.bind(this) } };
// * By default, the number of concurrent outbound streams is not limited. The `_streamLimit` can
// be set by the SETTINGS_MAX_CONCURRENT_STREAMS setting.
this._streamSlotsFree = Infinity;
this._streamLimit = Infinity;
this.on('RECEIVING_SETTINGS_MAX_CONCURRENT_STREAMS', this._updateStreamLimit);
};
// `_writeControlFrame` is called when there's an incoming frame in the `_control` stream. It
// broadcasts the message by creating an event on it.
Connection.prototype._writeControlFrame = function _writeControlFrame(frame) {
if ((frame.type === 'SETTINGS') || (frame.type === 'PING') ||
(frame.type === 'GOAWAY') || (frame.type === 'WINDOW_UPDATE') ||
(frame.type === 'ALTSVC')) {
this._log.debug({ frame: frame }, 'Receiving connection level frame');
this.emit(frame.type, frame);
} else {
this._log.error({ frame: frame }, 'Invalid connection level frame');
this.emit('error', 'PROTOCOL_ERROR');
}
};
// Methods to manage the stream slot pool:
Connection.prototype._updateStreamLimit = function _updateStreamLimit(newStreamLimit) {
var wakeup = (this._streamSlotsFree === 0) && (newStreamLimit > this._streamLimit);
this._streamSlotsFree += newStreamLimit - this._streamLimit;
this._streamLimit = newStreamLimit;
if (wakeup) {
this.emit('wakeup');
}
};
Connection.prototype._changeStreamCount = function _changeStreamCount(change) {
if (change) {
this._log.trace({ free: this._streamSlotsFree, change: change },
'Changing active stream count.');
var wakeup = (this._streamSlotsFree === 0) && (change < 0);
this._streamSlotsFree -= change;
if (wakeup) {
this.emit('wakeup');
}
}
};
// Creating a new *inbound or outbound* stream with the given `id` (which is undefined in case of
// an outbound stream) consists of three steps:
//
// 1. var stream = new Stream(this._log, this);
// 2. this._allocateId(stream, id);
// 2. this._allocatePriority(stream);
// Allocating an ID to a stream
Connection.prototype._allocateId = function _allocateId(stream, id) {
// * initiated stream without definite ID
if (id === undefined) {
id = this._nextStreamId;
this._nextStreamId += 2;
}
// * incoming stream with a legitim ID (larger than any previous and different parity than ours)
else if ((id > this._lastIncomingStream) && ((id - this._nextStreamId) % 2 !== 0)) {
this._lastIncomingStream = id;
}
// * incoming stream with invalid ID
else {
this._log.error({ stream_id: id, lastIncomingStream: this._lastIncomingStream },
'Invalid incoming stream ID.');
this.emit('error', 'PROTOCOL_ERROR');
return undefined;
}
assert(!(id in this._streamIds));
// * adding to `this._streamIds`
this._log.trace({ s: stream, stream_id: id }, 'Allocating ID for stream.');
this._streamIds[id] = stream;
stream.id = id;
// * forwarding connection errors from streams
stream.on('connectionError', this.emit.bind(this, 'error'));
return id;
};
// Allocating a priority to a stream, and managing priority changes
Connection.prototype._allocatePriority = function _allocatePriority(stream) {
this._log.trace({ s: stream }, 'Allocating priority for stream.');
this._insert(stream, stream._priority);
stream.on('priority', this._reprioritize.bind(this, stream));
stream.upstream.on('readable', this.emit.bind(this, 'wakeup'));
this.emit('wakeup');
};
Connection.prototype._insert = function _insert(stream, priority) {
if (priority in this._streamPriorities) {
this._streamPriorities[priority].push(stream);
} else {
this._streamPriorities[priority] = [stream];
}
};
Connection.prototype._reprioritize = function _reprioritize(stream, priority) {
this._removePrioritisedStream(stream);
this._insert(stream, priority);
};
Connection.prototype._removePrioritisedStream = function _removePrioritisedStream(stream) {
var bucket = this._streamPriorities[stream._priority];
var index = bucket.indexOf(stream);
assert(index !== -1);
bucket.splice(index, 1);
if (bucket.length === 0) {
delete this._streamPriorities[stream._priority];
}
};
// Creating an *inbound* stream with the given ID. It is called when there's an incoming frame to
// a previously nonexistent stream.
Connection.prototype._createIncomingStream = function _createIncomingStream(id) {
this._log.debug({ stream_id: id }, 'New incoming stream.');
var stream = new Stream(this._log, this);
this._allocateId(stream, id);
this._allocatePriority(stream);
this.emit('stream', stream, id);
return stream;
};
// Creating an *outbound* stream
Connection.prototype.createStream = function createStream() {
this._log.trace('Creating new outbound stream.');
// * Receiving is enabled immediately, and an ID gets assigned to the stream
var stream = new Stream(this._log, this);
this._allocatePriority(stream);
this.emit('new_stream', stream);
stream.on('state', this._streamStateChange.bind(this, stream));
return stream;
};
Connection.prototype._streamStateChange = function _removeStream(stream, state) {
if (state === 'CLOSED') {
if (!stream._closedByUs) {
this._removeStream(stream)
} else {
// An endpoint MUST ignore frames that it receives on closed streams after
// it has sent a RST_STREAM frame. An endpoint MAY choose to limit the
// period over which it ignores frames and treat frames that arrive after
// this time as being in error.
setTimeout(this._removeStream.bind(self, stream), 30000) // TODO: make timeout configurable
}
}
};
Connection.prototype._removeStream = function _removeStream(stream) {
this._log.trace('Removing outbound stream.');
delete this._streamIds[stream.id];
this._removePrioritisedStream(stream);
};
// Multiplexing
// ------------
Connection.prototype._initializeMultiplexing = function _initializeMultiplexing() {
this.on('window_update', this.emit.bind(this, 'wakeup'));
this._sendScheduled = false;
this._firstFrameReceived = false;
};
// The `_send` method is a virtual method of the [Flow class](flow.html) that has to be implemented
// by child classes. It reads frames from streams and pushes them to the output buffer.
Connection.prototype._send = function _send(immediate) {
// * Do not do anything if the connection is already closed
if (this._closed) {
return;
}
// * Collapsing multiple calls in a turn into a single deferred call
if (immediate) {
this._sendScheduled = false;
} else {
if (!this._sendScheduled) {
this._sendScheduled = true;
global.setImmediate(this._send.bind(this, true));
}
return;
}
this._log.trace('Starting forwarding frames from streams.');
// * Looping through priority `bucket`s in priority order.
priority_loop:
for (var priority in this._streamPriorities) {
var bucket = this._streamPriorities[priority];
var nextBucket = [];
// * Forwarding frames from buckets with round-robin scheduling.
// 1. pulling out frame
// 2. if there's no frame, skip this stream
// 3. if forwarding this frame would make `streamCount` greater than `streamLimit`, skip
// this stream
// 4. adding stream to the bucket of the next round
// 5. assigning an ID to the frame (allocating an ID to the stream if there isn't already)
// 6. if forwarding a PUSH_PROMISE, allocate ID to the promised stream
// 7. forwarding the frame, changing `streamCount` as appropriate
// 8. stepping to the next stream if there's still more frame needed in the output buffer
// 9. switching to the bucket of the next round
while (bucket.length > 0) {
for (var index = 0; index < bucket.length; index++) {
var stream = bucket[index];
var frame = stream.upstream.read((this._window > 0) ? this._window : -1);
if (!frame) {
continue;
} else if (frame.count_change > this._streamSlotsFree) {
stream.upstream.unshift(frame);
continue;
}
nextBucket.push(stream);
if (frame.stream === undefined) {
frame.stream = stream.id || this._allocateId(stream);
}
if (frame.type === 'PUSH_PROMISE') {
this._allocatePriority(frame.promised_stream);
frame.promised_stream = this._allocateId(frame.promised_stream);
}
this._log.trace({ s: stream, frame: frame }, 'Forwarding outgoing frame');
var moreNeeded = this.push(frame);
this._changeStreamCount(frame.count_change);
if (!moreNeeded) {
break priority_loop;
}
}
bucket = nextBucket;
nextBucket = [];
}
}
// * if we couldn't forward any frame, then sleep until window update, or some other wakeup event
if (moreNeeded === undefined) {
this.once('wakeup', this._send.bind(this));
}
this._log.trace({ moreNeeded: moreNeeded }, 'Stopping forwarding frames from streams.');
};
// The `_receive` method is another virtual method of the [Flow class](flow.html) that has to be
// implemented by child classes. It forwards the given frame to the appropriate stream:
Connection.prototype._receive = function _receive(frame, done) {
this._log.trace({ frame: frame }, 'Forwarding incoming frame');
// * first frame needs to be checked by the `_onFirstFrameReceived` method
if (!this._firstFrameReceived) {
this._firstFrameReceived = true;
this._onFirstFrameReceived(frame);
}
// Do some sanity checking here before we create a stream
if ((frame.type == 'SETTINGS' ||
frame.type == 'PING' ||
frame.type == 'GOAWAY') &&
frame.stream != 0) {
// Got connection-level frame on a stream - EEP!
this.close('PROTOCOL_ERROR');
return;
} else if ((frame.type == 'DATA' ||
frame.type == 'HEADERS' ||
frame.type == 'PRIORITY' ||
frame.type == 'RST_STREAM' ||
frame.type == 'PUSH_PROMISE' ||
frame.type == 'CONTINUATION') &&
frame.stream == 0) {
// Got stream-level frame on connection - EEP!
this.close('PROTOCOL_ERROR');
return;
}
// WINDOW_UPDATE can be on either stream or connection
// * gets the appropriate stream from the stream registry
var stream = this._streamIds[frame.stream];
// * or creates one if it's not in `this.streams`
if (!stream) {
if (frame.type === 'PRIORITY') {
// Priority frames can be sent on closed streams that have already been
// removed, or idle streams. Because priority dependencies are missing in
// this implementation anyway, these frames can simply be ignored.
return;
}
stream = this._createIncomingStream(frame.stream);
}
// * in case of PUSH_PROMISE, replaces the promised stream id with a new incoming stream
if (frame.type === 'PUSH_PROMISE') {
frame.promised_stream = this._createIncomingStream(frame.promised_stream);
}
frame.count_change = this._changeStreamCount.bind(this);
// * and writes it to the `stream`'s `upstream`
stream.upstream.write(frame);
done();
};
// Settings management
// -------------------
// The initial connection flow control window is 6mb bytes.
var INITIAL_STREAM_WINDOW_SIZE = 6*1024*1024;
var DEFAULT_CONNECTION_WINDOW_SIZE = 65535;
var INITIAL_CONNECTION_WINDOW_SIZE = 15*1024*1024;
var defaultSettings = {
'SETTINGS_INITIAL_WINDOW_SIZE': INITIAL_STREAM_WINDOW_SIZE
};
// Settings management initialization:
Connection.prototype._initializeSettingsManagement = function _initializeSettingsManagement(settings) {
// * Setting up the callback queue for setting acknowledgements
this._settingsAckCallbacks = [];
// * Sending the initial settings.
this._log.debug({ settings: settings },
'Sending the first SETTINGS frame as part of the connection header.');
this.set(settings || defaultSettings);
// * Forwarding SETTINGS frames to the `_receiveSettings` method
this.on('SETTINGS', this._receiveSettings);
this.on('RECEIVING_SETTINGS_MAX_FRAME_SIZE', this._sanityCheckMaxFrameSize);
};
// * Checking that the first frame the other endpoint sends is SETTINGS
Connection.prototype._onFirstFrameReceived = function _onFirstFrameReceived(frame) {
if ((frame.stream === 0) && (frame.type === 'SETTINGS')) {
this._log.debug('Receiving the first SETTINGS frame as part of the connection header.');
} else {
this._log.fatal({ frame: frame }, 'Invalid connection header: first frame is not SETTINGS.');
this.emit('error', 'PROTOCOL_ERROR');
}
};
// Handling of incoming SETTINGS frames.
Connection.prototype._receiveSettings = function _receiveSettings(frame) {
// * If it's an ACK, call the appropriate callback
if (frame.flags.ACK) {
var callback = this._settingsAckCallbacks.shift();
if (callback) {
callback();
}
}
// * If it's a setting change request, then send an ACK and change the appropriate settings
else {
if (!this._closed) {
this.push({
type: 'SETTINGS',
flags: { ACK: true },
stream: 0,
settings: {}
});
}
for (var name in frame.settings) {
this.emit('RECEIVING_' + name, frame.settings[name]);
}
}
};
Connection.prototype._sanityCheckMaxFrameSize = function _sanityCheckMaxFrameSize(value) {
if ((value < 0x4000) || (value >= 0x01000000)) {
this._log.fatal('Received invalid value for max frame size: ' + value);
this.emit('error');
}
};
// Changing one or more settings value and sending out a SETTINGS frame
Connection.prototype.set = function set(settings, callback) {
// * Calling the callback and emitting event when the change is acknowledges
var self = this;
this._settingsAckCallbacks.push(function() {
for (var name in settings) {
self.emit('ACKNOWLEDGED_' + name, settings[name]);
}
if (callback) {
callback();
}
});
// * Sending out the SETTINGS frame
this.push({
type: 'SETTINGS',
flags: { ACK: false },
stream: 0,
settings: settings
});
for (var name in settings) {
this.emit('SENDING_' + name, settings[name]);
}
};
// Lifecycle management
// --------------------
// The main responsibilities of lifecycle management code:
//
// * keeping the connection alive by
// * sending PINGs when the connection is idle
// * answering PINGs
// * ending the connection
Connection.prototype._initializeLifecycleManagement = function _initializeLifecycleManagement() {
this._pings = {};
this.on('PING', this._receivePing);
this.on('GOAWAY', this._receiveGoaway);
this._closed = false;
};
// Generating a string of length 16 with random hexadecimal digits
Connection.prototype._generatePingId = function _generatePingId() {
do {
var id = '';
for (var i = 0; i < 16; i++) {
id += Math.floor(Math.random()*16).toString(16);
}
} while(id in this._pings);
return id;
};
// Sending a ping and calling `callback` when the answer arrives
Connection.prototype.ping = function ping(callback) {
var id = this._generatePingId();
var data = new Buffer(id, 'hex');
this._pings[id] = callback;
this._log.debug({ data: data }, 'Sending PING.');
this.push({
type: 'PING',
flags: {
ACK: false
},
stream: 0,
data: data
});
};
// Answering pings
Connection.prototype._receivePing = function _receivePing(frame) {
if (frame.flags.ACK) {
var id = frame.data.toString('hex');
if (id in this._pings) {
this._log.debug({ data: frame.data }, 'Receiving answer for a PING.');
var callback = this._pings[id];
if (callback) {
callback();
}
delete this._pings[id];
} else {
this._log.warn({ data: frame.data }, 'Unsolicited PING answer.');
}
} else {
this._log.debug({ data: frame.data }, 'Answering PING.');
this.push({
type: 'PING',
flags: {
ACK: true
},
stream: 0,
data: frame.data
});
}
};
// Terminating the connection
Connection.prototype.close = function close(error) {
if (this._closed) {
this._log.warn('Trying to close an already closed connection');
return;
}
this._log.debug({ error: error }, 'Closing the connection');
this.push({
type: 'GOAWAY',
flags: {},
stream: 0,
last_stream: this._lastIncomingStream,
error: error || 'NO_ERROR'
});
this.push(null);
this._closed = true;
};
Connection.prototype._receiveGoaway = function _receiveGoaway(frame) {
this._log.debug({ error: frame.error }, 'Other end closed the connection');
this.push(null);
this._closed = true;
if (frame.error !== 'NO_ERROR') {
this.emit('peerError', frame.error);
}
};
// Flow control
// ------------
Connection.prototype._initializeFlowControl = function _initializeFlowControl() {
// Handling of initial window size of individual streams.
this._initialStreamWindowSize = INITIAL_STREAM_WINDOW_SIZE;
this.on('new_stream', function(stream) {
stream.upstream.setInitialWindow(this._initialStreamWindowSize);
});
this.on('RECEIVING_SETTINGS_INITIAL_WINDOW_SIZE', this._setInitialStreamWindowSize);
this._streamIds[0].upstream.setInitialWindow = function noop() {};
};
Connection.prototype._initializeConnectionFlowControl = function _initializeConnectionFlowControl() {
// This WINDOW_UPDATE increases the connection budget to 15mb
var windowSize = INITIAL_CONNECTION_WINDOW_SIZE - DEFAULT_CONNECTION_WINDOW_SIZE;
if (windowSize > 0) {
this.push({
type: 'WINDOW_UPDATE',
flags: {},
stream: 0,
window_size: windowSize
});
}
};
// A SETTINGS frame can alter the initial flow control window size for all current streams. When the
// value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust the window size of all
// stream by calling the `setInitialStreamWindowSize` method. The window size has to be modified by
// the difference between the new value and the old value.
Connection.prototype._setInitialStreamWindowSize = function _setInitialStreamWindowSize(size) {
if ((this._initialStreamWindowSize === Infinity) && (size !== Infinity)) {
this._log.error('Trying to manipulate initial flow control window size after flow control was turned off.');
this.emit('error', 'FLOW_CONTROL_ERROR');
} else {
this._log.debug({ size: size }, 'Changing stream initial window size.');
this._initialStreamWindowSize = size;
this._streamIds.forEach(function(stream) {
stream.upstream.setInitialWindow(size);
});
}
};
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./flow":86,"./stream":89,"assert":11,"buffer":13,"setimmediate":118}],85:[function(require,module,exports){
(function (global,Buffer){
var assert = require('assert');
var Serializer = require('./framer').Serializer;
var Deserializer = require('./framer').Deserializer;
var Compressor = require('./compressor').Compressor;
var Decompressor = require('./compressor').Decompressor;
var Connection = require('./connection').Connection;
var Duplex = require('stream').Duplex;
var Transform = require('stream').Transform;
require('setimmediate');
exports.Endpoint = Endpoint;
// The Endpoint class
// ==================
// Public API
// ----------
// - **new Endpoint(log, role, settings, filters)**: create a new Endpoint.
//
// - `log`: bunyan logger of the parent
// - `role`: 'CLIENT' or 'SERVER'
// - `settings`: initial HTTP/2 settings
// - `filters`: a map of functions that filter the traffic between components (for debugging or
// intentional failure injection).
//
// Filter functions get three arguments:
// 1. `frame`: the current frame
// 2. `forward(frame)`: function that can be used to forward a frame to the next component
// 3. `done()`: callback to signal the end of the filter process
//
// Valid filter names and their position in the stack:
// - `beforeSerialization`: after compression, before serialization
// - `beforeCompression`: after multiplexing, before compression
// - `afterDeserialization`: after deserialization, before decompression
// - `afterDecompression`: after decompression, before multiplexing
//
// * **Event: 'stream' (Stream)**: 'stream' event forwarded from the underlying Connection
//
// * **Event: 'error' (type)**: signals an error
//
// * **createStream(): Stream**: initiate a new stream (forwarded to the underlying Connection)
//
// * **close([error])**: close the connection with an error code
// Constructor
// -----------
// The process of initialization:
function Endpoint(log, role, settings, filters) {
Duplex.call(this);
// * Initializing logging infrastructure
this._log = log.child({ component: 'endpoint', e: this });
// * First part of the handshake process: sending and receiving the client connection header
// prelude.
assert((role === 'CLIENT') || role === 'SERVER');
if (role === 'CLIENT') {
this._writePrelude();
} else {
this._readPrelude();
}
// * Initialization of component. This includes the second part of the handshake process:
// sending the first SETTINGS frame. This is done by the connection class right after
// initialization.
this._initializeDataFlow(role, settings, filters || {});
// * Initialization of management code.
this._initializeManagement();
// * Initializing error handling.
this._initializeErrorHandling();
}
Endpoint.prototype = Object.create(Duplex.prototype, { constructor: { value: Endpoint } });
// Handshake
// ---------
var CLIENT_PRELUDE = new Buffer('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
// Writing the client header is simple and synchronous.
Endpoint.prototype._writePrelude = function _writePrelude() {
this._log.debug('Sending the client connection header prelude.');
this.push(CLIENT_PRELUDE);
};
// The asynchronous process of reading the client header:
Endpoint.prototype._readPrelude = function _readPrelude() {
// * progress in the header is tracker using a `cursor`
var cursor = 0;
// * `_write` is temporarily replaced by the comparator function
this._write = function _temporalWrite(chunk, encoding, done) {
// * which compares the stored header with the current `chunk` byte by byte and emits the
// 'error' event if there's a byte that doesn't match
var offset = cursor;
while(cursor < CLIENT_PRELUDE.length && (cursor - offset) < chunk.length) {
if (CLIENT_PRELUDE[cursor] !== chunk[cursor - offset]) {
this._log.fatal({ cursor: cursor, offset: offset, chunk: chunk },
'Client connection header prelude does not match.');
this._error('handshake', 'PROTOCOL_ERROR');
return;
}
cursor += 1;
}
// * if the whole header is over, and there were no error then restore the original `_write`
// and call it with the remaining part of the current chunk
if (cursor === CLIENT_PRELUDE.length) {
this._log.debug('Successfully received the client connection header prelude.');
delete this._write;
chunk = chunk.slice(cursor - offset);
this._write(chunk, encoding, done);
}
};
};
// Data flow
// ---------
// +---------------------------------------------+
// | |
// | +-------------------------------------+ |
// | | +---------+ +---------+ +---------+ | |
// | | | stream1 | | stream2 | | ... | | |
// | | +---------+ +---------+ +---------+ | |
// | | connection | |
// | +-------------------------------------+ |
// | | ^ |
// | pipe | | pipe |
// | v | |
// | +------------------+------------------+ |
// | | compressor | decompressor | |
// | +------------------+------------------+ |
// | | ^ |
// | pipe | | pipe |
// | v | |
// | +------------------+------------------+ |
// | | serializer | deserializer | |
// | +------------------+------------------+ |
// | | ^ |
// | _read() | | _write() |
// | v | |
// | +------------+ +-----------+ |
// | |output queue| |input queue| |
// +------+------------+-----+-----------+-------+
// | ^
// read() | | write()
// v |
function createTransformStream(filter) {
var transform = new Transform({ objectMode: true });
var push = transform.push.bind(transform);
transform._transform = function(frame, encoding, done) {
filter(frame, push, done);
};
return transform;
}
function pipeAndFilter(stream1, stream2, filter) {
if (filter) {
stream1.pipe(createTransformStream(filter)).pipe(stream2);
} else {
stream1.pipe(stream2);
}
}
Endpoint.prototype._initializeDataFlow = function _initializeDataFlow(role, settings, filters) {
var firstStreamId, compressorRole, decompressorRole;
if (role === 'CLIENT') {
firstStreamId = 1;
compressorRole = 'REQUEST';
decompressorRole = 'RESPONSE';
} else {
firstStreamId = 2;
compressorRole = 'RESPONSE';
decompressorRole = 'REQUEST';
}
this._serializer = new Serializer(this._log);
this._deserializer = new Deserializer(this._log);
this._compressor = new Compressor(this._log, compressorRole);
this._decompressor = new Decompressor(this._log, decompressorRole);
this._connection = new Connection(this._log, firstStreamId, settings);
pipeAndFilter(this._connection, this._compressor, filters.beforeCompression);
pipeAndFilter(this._compressor, this._serializer, filters.beforeSerialization);
pipeAndFilter(this._deserializer, this._decompressor, filters.afterDeserialization);
pipeAndFilter(this._decompressor, this._connection, filters.afterDecompression);
this._connection.on('ACKNOWLEDGED_SETTINGS_HEADER_TABLE_SIZE',
this._decompressor.setTableSizeLimit.bind(this._decompressor));
this._connection.on('RECEIVING_SETTINGS_HEADER_TABLE_SIZE',
this._compressor.setTableSizeLimit.bind(this._compressor));
};
var noread = {};
Endpoint.prototype._read = function _read() {
this._readableState.sync = true;
var moreNeeded = noread, chunk;
while (moreNeeded && (chunk = this._serializer.read())) {
moreNeeded = this.push(chunk);
}
if (moreNeeded === noread) {
this._serializer.once('readable', this._read.bind(this));
}
this._readableState.sync = false;
};
Endpoint.prototype._write = function _write(chunk, encoding, done) {
this._deserializer.write(chunk, encoding, done);
};
// Management
// --------------
Endpoint.prototype._initializeManagement = function _initializeManagement() {
this._connection.on('stream', this.emit.bind(this, 'stream'));
};
Endpoint.prototype.createStream = function createStream() {
return this._connection.createStream();
};
// Error handling
// --------------
Endpoint.prototype._initializeErrorHandling = function _initializeErrorHandling() {
this._serializer.on('error', this._error.bind(this, 'serializer'));
this._deserializer.on('error', this._error.bind(this, 'deserializer'));
this._compressor.on('error', this._error.bind(this, 'compressor'));
this._decompressor.on('error', this._error.bind(this, 'decompressor'));
this._connection.on('error', this._error.bind(this, 'connection'));
this._connection.on('peerError', this.emit.bind(this, 'peerError'));
};
Endpoint.prototype._error = function _error(component, error) {
this._log.fatal({ source: component, message: error }, 'Fatal error, closing connection');
this.close(error);
global.setImmediate(this.emit.bind(this, 'error', error));
};
Endpoint.prototype.close = function close(error) {
this._connection.close(error);
};
// Bunyan serializers
// ------------------
exports.serializers = {};
var nextId = 0;
exports.serializers.e = function(endpoint) {
if (!('id' in endpoint)) {
endpoint.id = nextId;
nextId += 1;
}
return endpoint.id;
};
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./compressor":83,"./connection":84,"./framer":87,"assert":11,"buffer":13,"setimmediate":118,"stream":43}],86:[function(require,module,exports){
(function (global){
var assert = require('assert');
require('setimmediate');
// The Flow class
// ==============
// Flow is a [Duplex stream][1] subclass which implements HTTP/2 flow control. It is designed to be
// subclassed by [Connection](connection.html) and the `upstream` component of [Stream](stream.html).
// [1]: https://nodejs.org/api/stream.html#stream_class_stream_duplex
var Duplex = require('stream').Duplex;
exports.Flow = Flow;
// Public API
// ----------
// * **Event: 'error' (type)**: signals an error
//
// * **setInitialWindow(size)**: the initial flow control window size can be changed *any time*
// ([as described in the standard][1]) using this method
//
// [1]: https://tools.ietf.org/html/rfc7540#section-6.9.2
// API for child classes
// ---------------------
// * **new Flow([flowControlId])**: creating a new flow that will listen for WINDOW_UPDATES frames
// with the given `flowControlId` (or every update frame if not given)
//
// * **_send()**: called when more frames should be pushed. The child class is expected to override
// this (instead of the `_read` method of the Duplex class).
//
// * **_receive(frame, readyCallback)**: called when there's an incoming frame. The child class is
// expected to override this (instead of the `_write` method of the Duplex class).
//
// * **push(frame): bool**: schedules `frame` for sending.
//
// Returns `true` if it needs more frames in the output queue, `false` if the output queue is
// full, and `null` if did not push the frame into the output queue (instead, it pushed it into
// the flow control queue).
//
// * **read(limit): frame**: like the regular `read`, but the 'flow control size' (0 for non-DATA
// frames, length of the payload for DATA frames) of the returned frame will be under `limit`.
// Small exception: pass -1 as `limit` if the max. flow control size is 0. `read(0)` means the
// same thing as [in the original API](https://nodejs.org/api/stream.html#stream_stream_read_0).
//
// * **getLastQueuedFrame(): frame**: returns the last frame in output buffers
//
// * **_log**: the Flow class uses the `_log` object of the parent
// Constructor
// -----------
// When a HTTP/2.0 connection is first established, new streams are created with an initial flow
// control window size of 65535 bytes.
var INITIAL_WINDOW_SIZE = 65535;
// `flowControlId` is needed if only specific WINDOW_UPDATEs should be watched.
function Flow(flowControlId) {
Duplex.call(this, { objectMode: true });
this._window = this._initialWindow = INITIAL_WINDOW_SIZE;
this._flowControlId = flowControlId;
this._queue = [];
this._ended = false;
this._received = 0;
this._blocked = false;
}
Flow.prototype = Object.create(Duplex.prototype, { constructor: { value: Flow } });
// Incoming frames
// ---------------
// `_receive` is called when there's an incoming frame.
Flow.prototype._receive = function _receive(frame, callback) {
throw new Error('The _receive(frame, callback) method has to be overridden by the child class!');
};
// `_receive` is called by `_write` which in turn is [called by Duplex][1] when someone `write()`s
// to the flow. It emits the 'receiving' event and notifies the window size tracking code if the
// incoming frame is a WINDOW_UPDATE.
// [1]: https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback_1
Flow.prototype._write = function _write(frame, encoding, callback) {
var sentToUs = (this._flowControlId === undefined) || (frame.stream === this._flowControlId);
if (sentToUs && (frame.flags.END_STREAM || (frame.type === 'RST_STREAM'))) {
this._ended = true;
}
if ((frame.type === 'DATA') && (frame.data.length > 0)) {
this._receive(frame, function() {
this._received += frame.data.length;
if (!this._restoreWindowTimer) {
this._restoreWindowTimer = global.setImmediate(this._restoreWindow.bind(this));
}
callback();
}.bind(this));
}
else {
this._receive(frame, callback);
}
if (sentToUs && (frame.type === 'WINDOW_UPDATE')) {
this._updateWindow(frame);
}
};
// `_restoreWindow` basically acknowledges the DATA frames received since it's last call. It sends
// a WINDOW_UPDATE that restores the flow control window of the remote end.
// TODO: push this directly into the output queue. No need to wait for DATA frames in the queue.
Flow.prototype._restoreWindow = function _restoreWindow() {
delete this._restoreWindowTimer;
if (!this._ended && (this._received > 0)) {
this.push({
type: 'WINDOW_UPDATE',
flags: {},
stream: this._flowControlId,
window_size: this._received
});
this._received = 0;
}
};
// Outgoing frames - sending procedure
// -----------------------------------
// flow
// +-------------------------------------------------+
// | |
// +--------+ +---------+ |
// read() | output | _read() | flow | _send() |
// <----------| |<----------| control |<------------- |
// | buffer | | buffer | |
// +--------+ +---------+ |
// | input | |
// ---------->| |-----------------------------------> |
// write() | buffer | _write() _receive() |
// +--------+ |
// | |
// +-------------------------------------------------+
// `_send` is called when more frames should be pushed to the output buffer.
Flow.prototype._send = function _send() {
throw new Error('The _send() method has to be overridden by the child class!');
};
// `_send` is called by `_read` which is in turn [called by Duplex][1] when it wants to have more
// items in the output queue.
// [1]: https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback_1
Flow.prototype._read = function _read() {
// * if the flow control queue is empty, then let the user push more frames
if (this._queue.length === 0) {
this._send();
}
// * if there are items in the flow control queue, then let's put them into the output queue (to
// the extent it is possible with respect to the window size and output queue feedback)
else if (this._window > 0) {
this._blocked = false;
this._readableState.sync = true; // to avoid reentrant calls
do {
var moreNeeded = this._push(this._queue[0]);
if (moreNeeded !== null) {
this._queue.shift();
}
} while (moreNeeded && (this._queue.length > 0));
this._readableState.sync = false;
assert((!moreNeeded) || // * output queue is full
(this._queue.length === 0) || // * flow control queue is empty
(!this._window && (this._queue[0].type === 'DATA'))); // * waiting for window update
}
// * otherwise, come back when the flow control window is positive
else if (!this._blocked) {
this._parentPush({
type: 'BLOCKED',
flags: {},
stream: this._flowControlId
});
this.once('window_update', this._read);
this._blocked = true;
}
};
var MAX_PAYLOAD_SIZE = 4096; // Must not be greater than MAX_HTTP_PAYLOAD_SIZE which is 16383
// `read(limit)` is like the `read` of the Readable class, but it guarantess that the 'flow control
// size' (0 for non-DATA frames, length of the payload for DATA frames) of the returned frame will
// be under `limit`.
Flow.prototype.read = function read(limit) {
if (limit === 0) {
return Duplex.prototype.read.call(this, 0);
} else if (limit === -1) {
limit = 0;
} else if ((limit === undefined) || (limit > MAX_PAYLOAD_SIZE)) {
limit = MAX_PAYLOAD_SIZE;
}
// * Looking at the first frame in the queue without pulling it out if possible.
var frame = bufferHead(this._readableState.buffer);
if (!frame && !this._readableState.ended) {
this._read();
frame = bufferHead(this._readableState.buffer);
}
if (frame && (frame.type === 'DATA')) {
// * If the frame is DATA, then there's two special cases:
// * if the limit is 0, we shouldn't return anything
// * if the size of the frame is larger than limit, then the frame should be split
if (limit === 0) {
return Duplex.prototype.read.call(this, 0);
}
else if (frame.data.length > limit) {
this._log.trace({ frame: frame, size: frame.data.length, forwardable: limit },
'Splitting out forwardable part of a DATA frame.');
this.unshift({
type: 'DATA',
flags: {},
stream: frame.stream,
data: frame.data.slice(0, limit)
});
frame.data = frame.data.slice(limit);
}
}
return Duplex.prototype.read.call(this);
};
// `_parentPush` pushes the given `frame` into the output queue
Flow.prototype._parentPush = function _parentPush(frame) {
this._log.trace({ frame: frame }, 'Pushing frame into the output queue');
if (frame && (frame.type === 'DATA') && (this._window !== Infinity)) {
this._log.trace({ window: this._window, by: frame.data.length },
'Decreasing flow control window size.');
this._window -= frame.data.length;
assert(this._window >= 0);
}
return Duplex.prototype.push.call(this, frame);
};
// `_push(frame)` pushes `frame` into the output queue and decreases the flow control window size.
// It is capable of splitting DATA frames into smaller parts, if the window size is not enough to
// push the whole frame. The return value is similar to `push` except that it returns `null` if it
// did not push the whole frame to the output queue (but maybe it did push part of the frame).
Flow.prototype._push = function _push(frame) {
var data = frame && (frame.type === 'DATA') && frame.data;
var maxFrameLength = (this._window < 16384) ? this._window : 16384;
if (!data || (data.length <= maxFrameLength)) {
return this._parentPush(frame);
}
else if (this._window <= 0) {
return null;
}
else {
this._log.trace({ frame: frame, size: frame.data.length, forwardable: this._window },
'Splitting out forwardable part of a DATA frame.');
frame.data = data.slice(maxFrameLength);
this._parentPush({
type: 'DATA',
flags: {},
stream: frame.stream,
data: data.slice(0, maxFrameLength)
});
return null;
}
};
// Push `frame` into the flow control queue, or if it's empty, then directly into the output queue
Flow.prototype.push = function push(frame) {
if (frame === null) {
this._log.debug('Enqueueing outgoing End Of Stream');
} else {
this._log.debug({ frame: frame }, 'Enqueueing outgoing frame');
}
var moreNeeded = null;
if (this._queue.length === 0) {
moreNeeded = this._push(frame);
}
if (moreNeeded === null) {
this._queue.push(frame);
}
return moreNeeded;
};
// `getLastQueuedFrame` returns the last frame in output buffers. This is primarily used by the
// [Stream](stream.html) class to mark the last frame with END_STREAM flag.
Flow.prototype.getLastQueuedFrame = function getLastQueuedFrame() {
return this._queue[this._queue.length - 1] || bufferTail(this._readableState.buffer);
};
// Outgoing frames - managing the window size
// ------------------------------------------
// Flow control window size is manipulated using the `_increaseWindow` method.
//
// * Invoking it with `Infinite` means turning off flow control. Flow control cannot be enabled
// again once disabled. Any attempt to re-enable flow control MUST be rejected with a
// FLOW_CONTROL_ERROR error code.
// * A sender MUST NOT allow a flow control window to exceed 2^31 - 1 bytes. The action taken
// depends on it being a stream or the connection itself.
var WINDOW_SIZE_LIMIT = Math.pow(2, 31) - 1;
Flow.prototype._increaseWindow = function _increaseWindow(size) {
if ((this._window === Infinity) && (size !== Infinity)) {
this._log.error('Trying to increase flow control window after flow control was turned off.');
this.emit('error', 'FLOW_CONTROL_ERROR');
} else {
this._log.trace({ window: this._window, by: size }, 'Increasing flow control window size.');
this._window += size;
if ((this._window !== Infinity) && (this._window > WINDOW_SIZE_LIMIT)) {
this._log.error('Flow control window grew too large.');
this.emit('error', 'FLOW_CONTROL_ERROR');
} else {
if (size != 0) {
this.emit('window_update');
}
}
}
};
// The `_updateWindow` method gets called every time there's an incoming WINDOW_UPDATE frame. It
// modifies the flow control window:
//
// * Flow control can be disabled for an individual stream by sending a WINDOW_UPDATE with the
// END_FLOW_CONTROL flag set. The payload of a WINDOW_UPDATE frame that has the END_FLOW_CONTROL
// flag set is ignored.
// * A sender that receives a WINDOW_UPDATE frame updates the corresponding window by the amount
// specified in the frame.
Flow.prototype._updateWindow = function _updateWindow(frame) {
this._increaseWindow(frame.flags.END_FLOW_CONTROL ? Infinity : frame.window_size);
};
// A SETTINGS frame can alter the initial flow control window size for all current streams. When the
// value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust the size of all stream by
// calling the `setInitialWindow` method. The window size has to be modified by the difference
// between the new value and the old value.
Flow.prototype.setInitialWindow = function setInitialWindow(initialWindow) {
this._increaseWindow(initialWindow - this._initialWindow);
this._initialWindow = initialWindow;
};
// The node stream internal buffer was changed from an Array to a linked list in node v6.3.0
function bufferHead (buffer) {
if ('head' in buffer) return buffer.head && buffer.head.data
return buffer[0]
}
function bufferTail (buffer) {
if ('tail' in buffer) return buffer.tail && buffer.tail.data
return buffer[buffer.length - 1]
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"assert":11,"setimmediate":118,"stream":43}],87:[function(require,module,exports){
(function (process,Buffer){
// The framer consists of two [Transform Stream][1] subclasses that operate in [object mode][2]:
// the Serializer and the Deserializer
// [1]: https://nodejs.org/api/stream.html#stream_class_stream_transform
// [2]: https://nodejs.org/api/stream.html#stream_new_stream_readable_options
var assert = require('assert');
var Transform = require('stream').Transform;
var keys = require('object-keys');
exports.Serializer = Serializer;
exports.Deserializer = Deserializer;
var logData = (process !== 'undefined' && process.env !== 'undefined' && process.env.HTTP2_LOG_DATA);
var MAX_PAYLOAD_SIZE = 16384;
var WINDOW_UPDATE_PAYLOAD_SIZE = 4;
// Serializer
// ----------
//
// Frame Objects
// * * * * * * * --+---------------------------
// | |
// v v Buffers
// [] -----> Payload Ser. --[buffers]--> Header Ser. --> * * * *
// empty adds payload adds header
// array buffers buffer
function Serializer(log) {
this._log = log.child({ component: 'serializer' });
Transform.call(this, { objectMode: true });
}
Serializer.prototype = Object.create(Transform.prototype, { constructor: { value: Serializer } });
// When there's an incoming frame object, it first generates the frame type specific part of the
// frame (payload), and then then adds the header part which holds fields that are common to all
// frame types (like the length of the payload).
Serializer.prototype._transform = function _transform(frame, encoding, done) {
this._log.trace({ frame: frame }, 'Outgoing frame');
assert(frame.type in Serializer, 'Unknown frame type: ' + frame.type);
var buffers = [];
Serializer[frame.type](frame, buffers);
var length = Serializer.commonHeader(frame, buffers);
assert(length <= MAX_PAYLOAD_SIZE, 'Frame too large!');
for (var i = 0; i < buffers.length; i++) {
if (logData) {
this._log.trace({ data: buffers[i] }, 'Outgoing data');
}
this.push(buffers[i]);
}
done();
};
// Deserializer
// ------------
//
// Buffers
// * * * * --------+-------------------------
// | |
// v v Frame Objects
// {} -----> Header Des. --{frame}--> Payload Des. --> * * * * * * *
// empty adds parsed adds parsed
// object header properties payload properties
function Deserializer(log, role) {
this._role = role;
this._log = log.child({ component: 'deserializer' });
Transform.call(this, { objectMode: true });
this._next(COMMON_HEADER_SIZE);
}
Deserializer.prototype = Object.create(Transform.prototype, { constructor: { value: Deserializer } });
// The Deserializer is stateful, and it's two main alternating states are: *waiting for header* and
// *waiting for payload*. The state is stored in the boolean property `_waitingForHeader`.
//
// When entering a new state, a `_buffer` is created that will hold the accumulated data (header or
// payload). The `_cursor` is used to track the progress.
Deserializer.prototype._next = function(size) {
this._cursor = 0;
this._buffer = new Buffer(size);
this._waitingForHeader = !this._waitingForHeader;
if (this._waitingForHeader) {
this._frame = {};
}
};
// Parsing an incoming buffer is an iterative process because it can hold multiple frames if it's
// large enough. A `cursor` is used to track the progress in parsing the incoming `chunk`.
Deserializer.prototype._transform = function _transform(chunk, encoding, done) {
var cursor = 0;
if (logData) {
this._log.trace({ data: chunk }, 'Incoming data');
}
while(cursor < chunk.length) {
// The content of an incoming buffer is first copied to `_buffer`. If it can't hold the full
// chunk, then only a part of it is copied.
var toCopy = Math.min(chunk.length - cursor, this._buffer.length - this._cursor);
chunk.copy(this._buffer, this._cursor, cursor, cursor + toCopy);
this._cursor += toCopy;
cursor += toCopy;
// When `_buffer` is full, it's content gets parsed either as header or payload depending on
// the actual state.
// If it's header then the parsed data is stored in a temporary variable and then the
// deserializer waits for the specified length payload.
if ((this._cursor === this._buffer.length) && this._waitingForHeader) {
var payloadSize = Deserializer.commonHeader(this._buffer, this._frame);
if (payloadSize <= MAX_PAYLOAD_SIZE) {
this._next(payloadSize);
} else {
this.emit('error', 'FRAME_SIZE_ERROR');
return;
}
}
// If it's payload then the the frame object is finalized and then gets pushed out.
// Unknown frame types are ignored.
//
// Note: If we just finished the parsing of a header and the payload length is 0, this branch
// will also run.
if ((this._cursor === this._buffer.length) && !this._waitingForHeader) {
if (this._frame.type) {
var error = Deserializer[this._frame.type](this._buffer, this._frame, this._role);
if (error) {
this._log.error('Incoming frame parsing error: ' + error);
this.emit('error', error);
} else {
this._log.trace({ frame: this._frame }, 'Incoming frame');
this.push(this._frame);
}
} else {
this._log.error('Unknown type incoming frame');
// Ignore it other than logging
}
this._next(COMMON_HEADER_SIZE);
}
}
done();
};
// [Frame Header](https://tools.ietf.org/html/rfc7540#section-4.1)
// --------------------------------------------------------------
//
// HTTP/2 frames share a common base format consisting of a 9-byte header followed by 0 to 2^24 - 1
// bytes of data.
//
// Additional size limits can be set by specific application uses. HTTP limits the frame size to
// 16,384 octets by default, though this can be increased by a receiver.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Length (24) |
// +---------------+---------------+---------------+
// | Type (8) | Flags (8) |
// +-+-----------------------------+---------------+---------------+
// |R| Stream Identifier (31) |
// +-+-------------------------------------------------------------+
// | Frame Data (0...) ...
// +---------------------------------------------------------------+
//
// The fields of the frame header are defined as:
//
// * Length:
// The length of the frame data expressed as an unsigned 24-bit integer. The 9 bytes of the frame
// header are not included in this value.
//
// * Type:
// The 8-bit type of the frame. The frame type determines how the remainder of the frame header
// and data are interpreted. Implementations MUST ignore unsupported and unrecognized frame types.
//
// * Flags:
// An 8-bit field reserved for frame-type specific boolean flags.
//
// Flags are assigned semantics specific to the indicated frame type. Flags that have no defined
// semantics for a particular frame type MUST be ignored, and MUST be left unset (0) when sending.
//
// * R:
// A reserved 1-bit field. The semantics of this bit are undefined and the bit MUST remain unset
// (0) when sending and MUST be ignored when receiving.
//
// * Stream Identifier:
// A 31-bit stream identifier. The value 0 is reserved for frames that are associated with the
// connection as a whole as opposed to an individual stream.
//
// The structure and content of the remaining frame data is dependent entirely on the frame type.
var COMMON_HEADER_SIZE = 9;
var frameTypes = [];
var frameFlags = {};
var genericAttributes = ['type', 'flags', 'stream'];
var typeSpecificAttributes = {};
Serializer.commonHeader = function writeCommonHeader(frame, buffers) {
var headerBuffer = new Buffer(COMMON_HEADER_SIZE);
var size = 0;
for (var i = 0; i < buffers.length; i++) {
size += buffers[i].length;
}
headerBuffer.writeUInt8(0, 0);
headerBuffer.writeUInt16BE(size, 1);
var typeId = frameTypes.indexOf(frame.type); // If we are here then the type is valid for sure
headerBuffer.writeUInt8(typeId, 3);
var flagByte = 0;
for (var flag in frame.flags) {
var position = frameFlags[frame.type].indexOf(flag);
assert(position !== -1, 'Unknown flag for frame type ' + frame.type + ': ' + flag);
if (frame.flags[flag]) {
flagByte |= (1 << position);
}
}
headerBuffer.writeUInt8(flagByte, 4);
assert((0 <= frame.stream) && (frame.stream < 0x7fffffff), frame.stream);
headerBuffer.writeUInt32BE(frame.stream || 0, 5);
buffers.unshift(headerBuffer);
return size;
};
Deserializer.commonHeader = function readCommonHeader(buffer, frame) {
if (buffer.length < 9) {
return 'FRAME_SIZE_ERROR';
}
var totallyWastedByte = buffer.readUInt8(0);
var length = buffer.readUInt16BE(1);
// We do this just for sanity checking later on, to make sure no one sent us a
// frame that's super large.
length += totallyWastedByte << 16;
frame.type = frameTypes[buffer.readUInt8(3)];
if (!frame.type) {
// We are required to ignore unknown frame types
return length;
}
frame.flags = {};
var flagByte = buffer.readUInt8(4);
var definedFlags = frameFlags[frame.type];
for (var i = 0; i < definedFlags.length; i++) {
frame.flags[definedFlags[i]] = Boolean(flagByte & (1 << i));
}
frame.stream = buffer.readUInt32BE(5) & 0x7fffffff;
return length;
};
// Frame types
// ===========
// Every frame type is registered in the following places:
//
// * `frameTypes`: a register of frame type codes (used by `commonHeader()`)
// * `frameFlags`: a register of valid flags for frame types (used by `commonHeader()`)
// * `typeSpecificAttributes`: a register of frame specific frame object attributes (used by
// logging code and also serves as documentation for frame objects)
// [DATA Frames](https://tools.ietf.org/html/rfc7540#section-6.1)
// ------------------------------------------------------------
//
// DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a
// stream.
//
// The DATA frame defines the following flags:
//
// * END_STREAM (0x1):
// Bit 1 being set indicates that this frame is the last that the endpoint will send for the
// identified stream.
// * PADDED (0x08):
// Bit 4 being set indicates that the Pad Length field is present.
frameTypes[0x0] = 'DATA';
frameFlags.DATA = ['END_STREAM', 'RESERVED2', 'RESERVED4', 'PADDED'];
typeSpecificAttributes.DATA = ['data'];
Serializer.DATA = function writeData(frame, buffers) {
buffers.push(frame.data);
};
Deserializer.DATA = function readData(buffer, frame) {
var dataOffset = 0;
var paddingLength = 0;
if (frame.flags.PADDED) {
if (buffer.length < 1) {
// We must have at least one byte for padding control, but we don't. Bad peer!
return 'FRAME_SIZE_ERROR';
}
paddingLength = (buffer.readUInt8(dataOffset) & 0xff);
dataOffset = 1;
}
if (paddingLength) {
if (paddingLength >= (buffer.length - 1)) {
// We don't have enough room for the padding advertised - bad peer!
return 'FRAME_SIZE_ERROR';
}
frame.data = buffer.slice(dataOffset, -1 * paddingLength);
} else {
frame.data = buffer.slice(dataOffset);
}
};
// [HEADERS](https://tools.ietf.org/html/rfc7540#section-6.2)
// --------------------------------------------------------------
//
// The HEADERS frame (type=0x1) allows the sender to create a stream.
//
// The HEADERS frame defines the following flags:
//
// * END_STREAM (0x1):
// Bit 1 being set indicates that this frame is the last that the endpoint will send for the
// identified stream.
// * END_HEADERS (0x4):
// The END_HEADERS bit indicates that this frame contains the entire payload necessary to provide
// a complete set of headers.
// * PADDED (0x08):
// Bit 4 being set indicates that the Pad Length field is present.
// * PRIORITY (0x20):
// Bit 6 being set indicates that the Exlusive Flag (E), Stream Dependency, and Weight fields are
// present.
frameTypes[0x1] = 'HEADERS';
frameFlags.HEADERS = ['END_STREAM', 'RESERVED2', 'END_HEADERS', 'PADDED', 'RESERVED5', 'PRIORITY'];
typeSpecificAttributes.HEADERS = ['priorityDependency', 'priorityWeight', 'exclusiveDependency', 'headers', 'data'];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Pad Length? (8)|
// +-+-------------+---------------+-------------------------------+
// |E| Stream Dependency? (31) |
// +-+-------------+-----------------------------------------------+
// | Weight? (8) |
// +-+-------------+-----------------------------------------------+
// | Header Block Fragment (*) ...
// +---------------------------------------------------------------+
// | Padding (*) ...
// +---------------------------------------------------------------+
//
// The payload of a HEADERS frame contains a Headers Block
Serializer.HEADERS = function writeHeadersPriority(frame, buffers) {
if (frame.flags.PRIORITY) {
var buffer = new Buffer(5);
assert((0 <= frame.priorityDependency) && (frame.priorityDependency <= 0x7fffffff), frame.priorityDependency);
buffer.writeUInt32BE(frame.priorityDependency, 0);
if (frame.exclusiveDependency) {
buffer[0] |= 0x80;
}
assert((0 <= frame.priorityWeight) && (frame.priorityWeight <= 0xff), frame.priorityWeight);
buffer.writeUInt8(frame.priorityWeight, 4);
buffers.push(buffer);
}
buffers.push(frame.data);
};
Deserializer.HEADERS = function readHeadersPriority(buffer, frame) {
var minFrameLength = 0;
if (frame.flags.PADDED) {
minFrameLength += 1;
}
if (frame.flags.PRIORITY) {
minFrameLength += 5;
}
if (buffer.length < minFrameLength) {
// Peer didn't send enough data - bad peer!
return 'FRAME_SIZE_ERROR';
}
var dataOffset = 0;
var paddingLength = 0;
if (frame.flags.PADDED) {
paddingLength = (buffer.readUInt8(dataOffset) & 0xff);
dataOffset = 1;
}
if (frame.flags.PRIORITY) {
var dependencyData = new Buffer(4);
buffer.copy(dependencyData, 0, dataOffset, dataOffset + 4);
dataOffset += 4;
frame.exclusiveDependency = !!(dependencyData[0] & 0x80);
dependencyData[0] &= 0x7f;
frame.priorityDependency = dependencyData.readUInt32BE(0);
frame.priorityWeight = buffer.readUInt8(dataOffset);
dataOffset += 1;
}
if (paddingLength) {
if ((buffer.length - dataOffset) < paddingLength) {
// Not enough data left to satisfy the advertised padding - bad peer!
return 'FRAME_SIZE_ERROR';
}
frame.data = buffer.slice(dataOffset, -1 * paddingLength);
} else {
frame.data = buffer.slice(dataOffset);
}
};
// [PRIORITY](https://tools.ietf.org/html/rfc7540#section-6.3)
// -------------------------------------------------------
//
// The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream.
//
// The PRIORITY frame does not define any flags.
frameTypes[0x2] = 'PRIORITY';
frameFlags.PRIORITY = [];
typeSpecificAttributes.PRIORITY = ['priorityDependency', 'priorityWeight', 'exclusiveDependency'];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |E| Stream Dependency? (31) |
// +-+-------------+-----------------------------------------------+
// | Weight? (8) |
// +-+-------------+
//
// The payload of a PRIORITY frame contains an exclusive bit, a 31-bit dependency, and an 8-bit weight
Serializer.PRIORITY = function writePriority(frame, buffers) {
var buffer = new Buffer(5);
assert((0 <= frame.priorityDependency) && (frame.priorityDependency <= 0x7fffffff), frame.priorityDependency);
buffer.writeUInt32BE(frame.priorityDependency, 0);
if (frame.exclusiveDependency) {
buffer[0] |= 0x80;
}
assert((0 <= frame.priorityWeight) && (frame.priorityWeight <= 0xff), frame.priorityWeight);
buffer.writeUInt8(frame.priorityWeight, 4);
buffers.push(buffer);
};
Deserializer.PRIORITY = function readPriority(buffer, frame) {
if (buffer.length < 5) {
// PRIORITY frames are 5 bytes long. Bad peer!
return 'FRAME_SIZE_ERROR';
}
var dependencyData = new Buffer(4);
buffer.copy(dependencyData, 0, 0, 4);
frame.exclusiveDependency = !!(dependencyData[0] & 0x80);
dependencyData[0] &= 0x7f;
frame.priorityDependency = dependencyData.readUInt32BE(0);
frame.priorityWeight = buffer.readUInt8(4);
};
// [RST_STREAM](https://tools.ietf.org/html/rfc7540#section-6.4)
// -----------------------------------------------------------
//
// The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.
//
// No type-flags are defined.
frameTypes[0x3] = 'RST_STREAM';
frameFlags.RST_STREAM = [];
typeSpecificAttributes.RST_STREAM = ['error'];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Error Code (32) |
// +---------------------------------------------------------------+
//
// The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error
// code (see Error Codes). The error code indicates why the stream is being terminated.
Serializer.RST_STREAM = function writeRstStream(frame, buffers) {
var buffer = new Buffer(4);
var code = errorCodes.indexOf(frame.error);
assert((0 <= code) && (code <= 0xffffffff), code);
buffer.writeUInt32BE(code, 0);
buffers.push(buffer);
};
Deserializer.RST_STREAM = function readRstStream(buffer, frame) {
if (buffer.length < 4) {
// RST_STREAM is 4 bytes long. Bad peer!
return 'FRAME_SIZE_ERROR';
}
frame.error = errorCodes[buffer.readUInt32BE(0)];
if (!frame.error) {
// Unknown error codes are considered equivalent to INTERNAL_ERROR
frame.error = 'INTERNAL_ERROR';
}
};
// [SETTINGS](https://tools.ietf.org/html/rfc7540#section-6.5)
// -------------------------------------------------------
//
// The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
// communicate.
//
// The SETTINGS frame defines the following flag:
// * ACK (0x1):
// Bit 1 being set indicates that this frame acknowledges receipt and application of the peer's
// SETTINGS frame.
frameTypes[0x4] = 'SETTINGS';
frameFlags.SETTINGS = ['ACK'];
typeSpecificAttributes.SETTINGS = ['settings'];
// The payload of a SETTINGS frame consists of zero or more settings. Each setting consists of a
// 16-bit identifier, and an unsigned 32-bit value.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Identifier(16) | Value (32) |
// +-----------------+---------------------------------------------+
// ...Value |
// +---------------------------------+
//
// Each setting in a SETTINGS frame replaces the existing value for that setting. Settings are
// processed in the order in which they appear, and a receiver of a SETTINGS frame does not need to
// maintain any state other than the current value of settings. Therefore, the value of a setting
// is the last value that is seen by a receiver. This permits the inclusion of the same settings
// multiple times in the same SETTINGS frame, though doing so does nothing other than waste
// connection capacity.
Serializer.SETTINGS = function writeSettings(frame, buffers) {
var settings = [], settingsLeft = keys(frame.settings);
definedSettings.forEach(function(setting, id) {
if (setting.name in frame.settings) {
settingsLeft.splice(settingsLeft.indexOf(setting.name), 1);
var value = frame.settings[setting.name];
settings.push({ id: id, value: setting.flag ? Boolean(value) : value });
}
});
assert(settingsLeft.length === 0, 'Unknown settings: ' + settingsLeft.join(', '));
var buffer = new Buffer(settings.length * 6);
for (var i = 0; i < settings.length; i++) {
buffer.writeUInt16BE(settings[i].id & 0xffff, i*6);
buffer.writeUInt32BE(settings[i].value, i*6 + 2);
}
buffers.push(buffer);
};
Deserializer.SETTINGS = function readSettings(buffer, frame, role) {
frame.settings = {};
// Receipt of a SETTINGS frame with the ACK flag set and a length
// field value other than 0 MUST be treated as a connection error
// (Section 5.4.1) of type FRAME_SIZE_ERROR.
if(frame.flags.ACK && buffer.length != 0) {
return 'FRAME_SIZE_ERROR';
}
if (buffer.length % 6 !== 0) {
return 'PROTOCOL_ERROR';
}
for (var i = 0; i < buffer.length / 6; i++) {
var id = buffer.readUInt16BE(i*6) & 0xffff;
var setting = definedSettings[id];
if (setting) {
if (role == 'CLIENT' && setting.name == 'SETTINGS_ENABLE_PUSH') {
return 'SETTINGS frame on client got SETTINGS_ENABLE_PUSH';
}
var value = buffer.readUInt32BE(i*6 + 2);
frame.settings[setting.name] = setting.flag ? Boolean(value & 0x1) : value;
}
}
};
// The following settings are defined:
var definedSettings = [];
// * SETTINGS_HEADER_TABLE_SIZE (1):
// Allows the sender to inform the remote endpoint of the size of the header compression table
// used to decode header blocks.
definedSettings[1] = { name: 'SETTINGS_HEADER_TABLE_SIZE', flag: false };
// * SETTINGS_ENABLE_PUSH (2):
// This setting can be use to disable server push. An endpoint MUST NOT send a PUSH_PROMISE frame
// if it receives this setting set to a value of 0. The default value is 1, which indicates that
// push is permitted.
definedSettings[2] = { name: 'SETTINGS_ENABLE_PUSH', flag: true };
// * SETTINGS_MAX_CONCURRENT_STREAMS (3):
// indicates the maximum number of concurrent streams that the sender will allow.
definedSettings[3] = { name: 'SETTINGS_MAX_CONCURRENT_STREAMS', flag: false };
// * SETTINGS_INITIAL_WINDOW_SIZE (4):
// indicates the sender's initial stream window size (in bytes) for new streams.
definedSettings[4] = { name: 'SETTINGS_INITIAL_WINDOW_SIZE', flag: false };
// * SETTINGS_MAX_FRAME_SIZE (5):
// indicates the maximum size of a frame the receiver will allow.
definedSettings[5] = { name: 'SETTINGS_MAX_FRAME_SIZE', flag: false };
// [PUSH_PROMISE](https://tools.ietf.org/html/rfc7540#section-6.6)
// ---------------------------------------------------------------
//
// The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the
// sender intends to initiate.
//
// The PUSH_PROMISE frame defines the following flags:
//
// * END_PUSH_PROMISE (0x4):
// The END_PUSH_PROMISE bit indicates that this frame contains the entire payload necessary to
// provide a complete set of headers.
frameTypes[0x5] = 'PUSH_PROMISE';
frameFlags.PUSH_PROMISE = ['RESERVED1', 'RESERVED2', 'END_PUSH_PROMISE', 'PADDED'];
typeSpecificAttributes.PUSH_PROMISE = ['promised_stream', 'headers', 'data'];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Pad Length? (8)|
// +-+-------------+-----------------------------------------------+
// |X| Promised-Stream-ID (31) |
// +-+-------------------------------------------------------------+
// | Header Block Fragment (*) ...
// +---------------------------------------------------------------+
// | Padding (*) ...
// +---------------------------------------------------------------+
//
// The PUSH_PROMISE frame includes the unsigned 31-bit identifier of
// the stream the endpoint plans to create along with a minimal set of headers that provide
// additional context for the stream.
Serializer.PUSH_PROMISE = function writePushPromise(frame, buffers) {
var buffer = new Buffer(4);
var promised_stream = frame.promised_stream;
assert((0 <= promised_stream) && (promised_stream <= 0x7fffffff), promised_stream);
buffer.writeUInt32BE(promised_stream, 0);
buffers.push(buffer);
buffers.push(frame.data);
};
Deserializer.PUSH_PROMISE = function readPushPromise(buffer, frame) {
if (buffer.length < 4) {
return 'FRAME_SIZE_ERROR';
}
var dataOffset = 0;
var paddingLength = 0;
if (frame.flags.PADDED) {
if (buffer.length < 5) {
return 'FRAME_SIZE_ERROR';
}
paddingLength = (buffer.readUInt8(dataOffset) & 0xff);
dataOffset = 1;
}
frame.promised_stream = buffer.readUInt32BE(dataOffset) & 0x7fffffff;
dataOffset += 4;
if (paddingLength) {
if ((buffer.length - dataOffset) < paddingLength) {
return 'FRAME_SIZE_ERROR';
}
frame.data = buffer.slice(dataOffset, -1 * paddingLength);
} else {
frame.data = buffer.slice(dataOffset);
}
};
// [PING](https://tools.ietf.org/html/rfc7540#section-6.7)
// -----------------------------------------------
//
// The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the
// sender, as well as determining whether an idle connection is still functional.
//
// The PING frame defines one type-specific flag:
//
// * ACK (0x1):
// Bit 1 being set indicates that this PING frame is a PING response.
frameTypes[0x6] = 'PING';
frameFlags.PING = ['ACK'];
typeSpecificAttributes.PING = ['data'];
// In addition to the frame header, PING frames MUST contain 8 additional octets of opaque data.
Serializer.PING = function writePing(frame, buffers) {
buffers.push(frame.data);
};
Deserializer.PING = function readPing(buffer, frame) {
if (buffer.length !== 8) {
return 'FRAME_SIZE_ERROR';
}
frame.data = buffer;
};
// [GOAWAY](https://tools.ietf.org/html/rfc7540#section-6.8)
// ---------------------------------------------------
//
// The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection.
//
// The GOAWAY frame does not define any flags.
frameTypes[0x7] = 'GOAWAY';
frameFlags.GOAWAY = [];
typeSpecificAttributes.GOAWAY = ['last_stream', 'error'];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |X| Last-Stream-ID (31) |
// +-+-------------------------------------------------------------+
// | Error Code (32) |
// +---------------------------------------------------------------+
// | Additional Debug Data (*) |
// +---------------------------------------------------------------+
//
// The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier
// for which the sender of the GOAWAY frame has received frames on and might have taken some action
// on.
//
// The GOAWAY frame also contains a 32-bit error code (see Error Codes) that contains the reason for
// closing the connection.
Serializer.GOAWAY = function writeGoaway(frame, buffers) {
var buffer = new Buffer(8);
var last_stream = frame.last_stream;
assert((0 <= last_stream) && (last_stream <= 0x7fffffff), last_stream);
buffer.writeUInt32BE(last_stream, 0);
var code = errorCodes.indexOf(frame.error);
assert((0 <= code) && (code <= 0xffffffff), code);
buffer.writeUInt32BE(code, 4);
buffers.push(buffer);
};
Deserializer.GOAWAY = function readGoaway(buffer, frame) {
if (buffer.length < 8) {
// GOAWAY must have at least 8 bytes
return 'FRAME_SIZE_ERROR';
}
frame.last_stream = buffer.readUInt32BE(0) & 0x7fffffff;
frame.error = errorCodes[buffer.readUInt32BE(4)];
if (!frame.error) {
// Unknown error types are to be considered equivalent to INTERNAL ERROR
frame.error = 'INTERNAL_ERROR';
}
// Read remaining data into "debug_data"
// https://http2.github.io/http2-spec/#GOAWAY
// Endpoints MAY append opaque data to the payload of any GOAWAY frame
if (buffer.length > 8) {
frame.debug_data = buffer.slice(8);
}
};
// [WINDOW_UPDATE](https://tools.ietf.org/html/rfc7540#section-6.9)
// -----------------------------------------------------------------
//
// The WINDOW_UPDATE frame (type=0x8) is used to implement flow control.
//
// The WINDOW_UPDATE frame does not define any flags.
frameTypes[0x8] = 'WINDOW_UPDATE';
frameFlags.WINDOW_UPDATE = [];
typeSpecificAttributes.WINDOW_UPDATE = ['window_size'];
// The payload of a WINDOW_UPDATE frame is a 32-bit value indicating the additional number of bytes
// that the sender can transmit in addition to the existing flow control window. The legal range
// for this field is 1 to 2^31 - 1 (0x7fffffff) bytes; the most significant bit of this value is
// reserved.
Serializer.WINDOW_UPDATE = function writeWindowUpdate(frame, buffers) {
var buffer = new Buffer(4);
var window_size = frame.window_size;
assert((0 < window_size) && (window_size <= 0x7fffffff), window_size);
buffer.writeUInt32BE(window_size, 0);
buffers.push(buffer);
};
Deserializer.WINDOW_UPDATE = function readWindowUpdate(buffer, frame) {
if (buffer.length !== WINDOW_UPDATE_PAYLOAD_SIZE) {
return 'FRAME_SIZE_ERROR';
}
frame.window_size = buffer.readUInt32BE(0) & 0x7fffffff;
if (frame.window_size === 0) {
return 'PROTOCOL_ERROR';
}
};
// [CONTINUATION](https://tools.ietf.org/html/rfc7540#section-6.10)
// ------------------------------------------------------------
//
// The CONTINUATION frame (type=0x9) is used to continue a sequence of header block fragments.
//
// The CONTINUATION frame defines the following flag:
//
// * END_HEADERS (0x4):
// The END_HEADERS bit indicates that this frame ends the sequence of header block fragments
// necessary to provide a complete set of headers.
frameTypes[0x9] = 'CONTINUATION';
frameFlags.CONTINUATION = ['RESERVED1', 'RESERVED2', 'END_HEADERS'];
typeSpecificAttributes.CONTINUATION = ['headers', 'data'];
Serializer.CONTINUATION = function writeContinuation(frame, buffers) {
buffers.push(frame.data);
};
Deserializer.CONTINUATION = function readContinuation(buffer, frame) {
frame.data = buffer;
};
// [ALTSVC](https://tools.ietf.org/html/rfc7838#section-4)
// ------------------------------------------------------------
//
// The ALTSVC frame (type=0xA) advertises the availability of an alternative service to the client.
//
// The ALTSVC frame does not define any flags.
frameTypes[0xA] = 'ALTSVC';
frameFlags.ALTSVC = [];
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Origin-Len (16) | Origin? (*) ...
// +-------------------------------+----------------+--------------+
// | Alt-Svc-Field-Value (*) ...
// +---------------------------------------------------------------+
//
// The ALTSVC frame contains the following fields:
//
// Origin-Len: An unsigned, 16-bit integer indicating the length, in
// octets, of the Origin field.
//
// Origin: An OPTIONAL sequence of characters containing ASCII
// serialisation of an origin ([RFC6454](https://tools.ietf.org/html/rfc6454),
// Section 6.2) that the alternate service is applicable to.
//
// Alt-Svc-Field-Value: A sequence of octets (length determined by
// subtracting the length of all preceding fields from the frame
// length) containing a value identical to the Alt-Svc field value
// defined in (Section 3)[https://tools.ietf.org/html/rfc7838#section-3]
// (ABNF production "Alt-Svc").
typeSpecificAttributes.ALTSVC = ['maxAge', 'port', 'protocolID', 'host',
'origin'];
function istchar(c) {
return ('!#$&\'*+-.^_`|~1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.indexOf(c) > -1);
}
function hexencode(s) {
var t = '';
for (var i = 0; i < s.length; i++) {
if (!istchar(s[i])) {
t += '%';
t += new Buffer(s[i]).toString('hex');
} else {
t += s[i];
}
}
return t;
}
Serializer.ALTSVC = function writeAltSvc(frame, buffers) {
var buffer = new Buffer(2);
buffer.writeUInt16BE(frame.origin.length, 0);
buffers.push(buffer);
buffers.push(new Buffer(frame.origin, 'ascii'));
var fieldValue = hexencode(frame.protocolID) + '="' + frame.host + ':' + frame.port + '"';
if (frame.maxAge !== 86400) { // 86400 is the default
fieldValue += "; ma=" + frame.maxAge;
}
buffers.push(new Buffer(fieldValue, 'ascii'));
};
function stripquotes(s) {
var start = 0;
var end = s.length;
while ((start < end) && (s[start] === '"')) {
start++;
}
while ((end > start) && (s[end - 1] === '"')) {
end--;
}
if (start >= end) {
return "";
}
return s.substring(start, end);
}
function splitNameValue(nvpair) {
var eq = -1;
var inQuotes = false;
for (var i = 0; i < nvpair.length; i++) {
if (nvpair[i] === '"') {
inQuotes = !inQuotes;
continue;
}
if (inQuotes) {
continue;
}
if (nvpair[i] === '=') {
eq = i;
break;
}
}
if (eq === -1) {
return {'name': nvpair, 'value': null};
}
var name = stripquotes(nvpair.substring(0, eq).trim());
var value = stripquotes(nvpair.substring(eq + 1).trim());
return {'name': name, 'value': value};
}
function splitHeaderParameters(hv) {
return parseHeaderValue(hv, ';', splitNameValue);
}
function parseHeaderValue(hv, separator, callback) {
var start = 0;
var inQuotes = false;
var values = [];
for (var i = 0; i < hv.length; i++) {
if (hv[i] === '"') {
inQuotes = !inQuotes;
continue;
}
if (inQuotes) {
// Just skip this
continue;
}
if (hv[i] === separator) {
var newValue = hv.substring(start, i).trim();
if (newValue.length > 0) {
newValue = callback(newValue);
values.push(newValue);
}
start = i + 1;
}
}
var newValue = hv.substring(start).trim();
if (newValue.length > 0) {
newValue = callback(newValue);
values.push(newValue);
}
return values;
}
function rsplit(s, delim, count) {
var nsplits = 0;
var end = s.length;
var rval = [];
for (var i = s.length - 1; i >= 0; i--) {
if (s[i] === delim) {
var t = s.substring(i + 1, end);
end = i;
rval.unshift(t);
nsplits++;
if (nsplits === count) {
break;
}
}
}
if (end !== 0) {
rval.unshift(s.substring(0, end));
}
return rval;
}
function ishex(c) {
return ('0123456789ABCDEFabcdef'.indexOf(c) > -1);
}
function unescape(s) {
var i = 0;
var t = '';
while (i < s.length) {
if (s[i] != '%' || !ishex(s[i + 1]) || !ishex(s[i + 2])) {
t += s[i];
} else {
++i;
var hexvalue = '';
if (i < s.length) {
hexvalue += s[i];
++i;
}
if (i < s.length) {
hexvalue += s[i];
}
if (hexvalue.length > 0) {
t += new Buffer(hexvalue, 'hex').toString();
} else {
t += '%';
}
}
++i;
}
return t;
}
Deserializer.ALTSVC = function readAltSvc(buffer, frame) {
if (buffer.length < 2) {
return 'FRAME_SIZE_ERROR';
}
var originLength = buffer.readUInt16BE(0);
if ((buffer.length - 2) < originLength) {
return 'FRAME_SIZE_ERROR';
}
frame.origin = buffer.toString('ascii', 2, 2 + originLength);
var fieldValue = buffer.toString('ascii', 2 + originLength);
var values = parseHeaderValue(fieldValue, ',', splitHeaderParameters);
if (values.length > 1) {
// TODO - warn that we only use one here
}
if (values.length === 0) {
// Well that's a malformed frame. Just ignore it.
return;
}
var chosenAltSvc = values[0];
frame.maxAge = 86400; // Default
for (var i = 0; i < chosenAltSvc.length; i++) {
if (i === 0) {
// This corresponds to the protocolID="<host>:<port>" item
frame.protocolID = unescape(chosenAltSvc[i].name);
var hostport = rsplit(chosenAltSvc[i].value, ':', 1);
frame.host = hostport[0];
frame.port = parseInt(hostport[1], 10);
} else if (chosenAltSvc[i].name == 'ma') {
frame.maxAge = parseInt(chosenAltSvc[i].value, 10);
}
// Otherwise, we just ignore this
}
};
// BLOCKED
// ------------------------------------------------------------
//
// The BLOCKED frame (type=0xB) indicates that the sender is unable to send data
// due to a closed flow control window.
//
// The BLOCKED frame does not define any flags and contains no payload.
frameTypes[0xB] = 'BLOCKED';
frameFlags.BLOCKED = [];
typeSpecificAttributes.BLOCKED = [];
Serializer.BLOCKED = function writeBlocked(frame, buffers) {
};
Deserializer.BLOCKED = function readBlocked(buffer, frame) {
};
// [Error Codes](https://tools.ietf.org/html/rfc7540#section-7)
// ------------------------------------------------------------
var errorCodes = [
'NO_ERROR',
'PROTOCOL_ERROR',
'INTERNAL_ERROR',
'FLOW_CONTROL_ERROR',
'SETTINGS_TIMEOUT',
'STREAM_CLOSED',
'FRAME_SIZE_ERROR',
'REFUSED_STREAM',
'CANCEL',
'COMPRESSION_ERROR',
'CONNECT_ERROR',
'ENHANCE_YOUR_CALM',
'INADEQUATE_SECURITY',
'HTTP_1_1_REQUIRED'
];
// Logging
// -------
// [Bunyan serializers](https://github.com/trentm/node-bunyan#serializers) to improve logging output
// for debug messages emitted in this component.
exports.serializers = {};
// * `frame` serializer: it transforms data attributes from Buffers to hex strings and filters out
// flags that are not present.
var frameCounter = 0;
exports.serializers.frame = function(frame) {
if (!frame) {
return null;
}
if ('id' in frame) {
return frame.id;
}
frame.id = frameCounter;
frameCounter += 1;
var logEntry = { id: frame.id };
genericAttributes.concat(typeSpecificAttributes[frame.type]).forEach(function(name) {
logEntry[name] = frame[name];
});
if (frame.data instanceof Buffer) {
if (logEntry.data.length > 50) {
logEntry.data = frame.data.slice(0, 47).toString('hex') + '...';
} else {
logEntry.data = frame.data.toString('hex');
}
if (!('length' in logEntry)) {
logEntry.length = frame.data.length;
}
}
if (frame.promised_stream instanceof Object) {
logEntry.promised_stream = 'stream-' + frame.promised_stream.id;
}
logEntry.flags = keys(frame.flags || {}).filter(function(name) {
return frame.flags[name] === true;
});
return logEntry;
};
// * `data` serializer: it simply transforms a buffer to a hex string.
exports.serializers.data = function(data) {
return data.toString('hex');
};
}).call(this,require('_process'),require("buffer").Buffer)
},{"_process":20,"assert":11,"buffer":13,"object-keys":100,"stream":43}],88:[function(require,module,exports){
// This is an implementation of the [HTTP/2][http2]
// framing layer for [node.js][node].
//
// The main building blocks are [node.js streams][node-stream] that are connected through pipes.
//
// The main components are:
//
// * [Endpoint](endpoint.html): represents an HTTP/2 endpoint (client or server). It's
// responsible for the the first part of the handshake process (sending/receiving the
// [connection header][http2-connheader]) and manages other components (framer, compressor,
// connection, streams) that make up a client or server.
//
// * [Connection](connection.html): multiplexes the active HTTP/2 streams, manages connection
// lifecycle and settings, and responsible for enforcing the connection level limits (flow
// control, initiated stream limit)
//
// * [Stream](stream.html): implementation of the [HTTP/2 stream concept][http2-stream].
// Implements the [stream state machine][http2-streamstate] defined by the standard, provides
// management methods and events for using the stream (sending/receiving headers, data, etc.),
// and enforces stream level constraints (flow control, sending only legal frames).
//
// * [Flow](flow.html): implements flow control for Connection and Stream as parent class.
//
// * [Compressor and Decompressor](compressor.html): compression and decompression of HEADER and
// PUSH_PROMISE frames
//
// * [Serializer and Deserializer](framer.html): the lowest layer in the stack that transforms
// between the binary and the JavaScript object representation of HTTP/2 frames
//
// [http2]: https://tools.ietf.org/html/rfc7540
// [http2-connheader]: https://tools.ietf.org/html/rfc7540#section-3.5
// [http2-stream]: https://tools.ietf.org/html/rfc7540#section-5
// [http2-streamstate]: https://tools.ietf.org/html/rfc7540#section-5.1
// [node]: https://nodejs.org/
// [node-stream]: https://nodejs.org/api/stream.html
// [node-https]: https://nodejs.org/api/https.html
// [node-http]: https://nodejs.org/api/http.html
exports.VERSION = 'h2';
exports.Endpoint = require('./endpoint').Endpoint;
/* Bunyan serializers exported by submodules that are worth adding when creating a logger. */
exports.serializers = {};
var modules = ['./framer', './compressor', './flow', './connection', './stream', './endpoint'];
try {
modules.map(require).forEach(function (module) {
for (var name in module.serializers) {
exports.serializers[name] = module.serializers[name];
}
});
} catch (e) {
// NOOP, probably in browser
}
/*
Stream API Endpoint API
Stream data
| ^ | ^
| | | |
| | | |
+-----------|------------|---------------------------------------+
| | | Endpoint |
| | | |
| +-------|------------|-----------------------------------+ |
| | | | Connection | |
| | v | | |
| | +-----------------------+ +-------------------- | |
| | | Stream | | Stream ... | |
| | +-----------------------+ +-------------------- | |
| | | ^ | ^ | |
| | v | v | | |
| | +------------+--+--------+--+------------+- ... | |
| | | ^ | |
| | | | | |
| +-----------------------|--------|-----------------------+ |
| | | |
| v | |
| +--------------------------+ +--------------------------+ |
| | Compressor | | Decompressor | |
| +--------------------------+ +--------------------------+ |
| | ^ |
| v | |
| +--------------------------+ +--------------------------+ |
| | Serializer | | Deserializer | |
| +--------------------------+ +--------------------------+ |
| | ^ |
+---------------------------|--------|---------------------------+
| |
v |
Raw data
*/
},{"./endpoint":85}],89:[function(require,module,exports){
var assert = require('assert');
var pako = require('pako');
var Buffer = require('buffer').Buffer;
// The Stream class
// ================
// Stream is a [Duplex stream](https://nodejs.org/api/stream.html#stream_class_stream_duplex)
// subclass that implements the [HTTP/2 Stream](https://tools.ietf.org/html/rfc7540#section-5)
// concept. It has two 'sides': one that is used by the user to send/receive data (the `stream`
// object itself) and one that is used by a Connection to read/write frames to/from the other peer
// (`stream.upstream`).
var Duplex = require('stream').Duplex;
exports.Stream = Stream;
// Public API
// ----------
// * **new Stream(log, connection)**: create a new Stream
//
// * **Event: 'headers' (headers)**: signals incoming headers
//
// * **Event: 'promise' (stream, headers)**: signals an incoming push promise
//
// * **Event: 'priority' (priority)**: signals a priority change. `priority` is a number between 0
// (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.
//
// * **Event: 'error' (type)**: signals an error
//
// * **headers(headers)**: send headers
//
// * **promise(headers): Stream**: promise a stream
//
// * **priority(priority)**: set the priority of the stream. Priority can be changed by the peer
// too, but once it is set locally, it can not be changed remotely.
//
// * **reset(error)**: reset the stream with an error code
//
// * **upstream**: a [Flow](flow.js) that is used by the parent connection to write/read frames
// that are to be sent/arrived to/from the peer and are related to this stream.
//
// Headers are always in the [regular node.js header format][1].
// [1]: https://nodejs.org/api/http.html#http_message_headers
// Constructor
// -----------
// The main aspects of managing the stream are:
function Stream(log, connection) {
Duplex.call(this);
// * logging
this._log = log.child({ component: 'stream', s: this });
// * receiving and sending stream management commands
this._initializeManagement();
// * sending and receiving frames to/from the upstream connection
this._initializeDataFlow();
// * maintaining the state of the stream (idle, open, closed, etc.) and error detection
this._initializeState();
this.connection = connection;
}
Stream.prototype = Object.create(Duplex.prototype, { constructor: { value: Stream } });
// Managing the stream
// -------------------
// the default stream priority is 2^30
var DEFAULT_PRIORITY = Math.pow(2, 30);
var MAX_PRIORITY = Math.pow(2, 31) - 1;
// PUSH_PROMISE and HEADERS are forwarded to the user through events.
Stream.prototype._initializeManagement = function _initializeManagement() {
this._resetSent = false;
this._priority = DEFAULT_PRIORITY;
this._letPeerPrioritize = true;
};
Stream.prototype.promise = function promise(headers) {
var stream = new Stream(this._log, this.connection);
stream._priority = Math.min(this._priority + 1, MAX_PRIORITY);
this._pushUpstream({
type: 'PUSH_PROMISE',
flags: {},
stream: this.id,
promised_stream: stream,
headers: headers
});
return stream;
};
Stream.prototype._onPromise = function _onPromise(frame) {
this.emit('promise', frame.promised_stream, frame.headers);
};
Stream.prototype.headers = function headers(headers) {
this._pushUpstream({
type: 'HEADERS',
flags: {},
stream: this.id,
headers: headers
});
};
Stream.prototype._onHeaders = function _onHeaders(frame) {
if (frame.priority !== undefined) {
this.priority(frame.priority, true);
}
// transitioned just before this
if (
this.state === 'HALF_CLOSED_LOCAL' ||
this.state === 'OPEN'
) {
this.contentEncoding = frame.headers['content-encoding'];
}
this.emit('headers', frame.headers);
};
Stream.prototype.priority = function priority(priority, peer) {
if ((peer && this._letPeerPrioritize) || !peer) {
if (!peer) {
this._letPeerPrioritize = false;
var lastFrame = this.upstream.getLastQueuedFrame();
if (lastFrame && ((lastFrame.type === 'HEADERS') || (lastFrame.type === 'PRIORITY'))) {
lastFrame.priority = priority;
} else {
this._pushUpstream({
type: 'PRIORITY',
flags: {},
stream: this.id,
priority: priority
});
}
}
this._log.debug({ priority: priority }, 'Changing priority');
this.emit('priority', priority);
this._priority = priority;
}
};
Stream.prototype._onPriority = function _onPriority(frame) {
this.priority(frame.priority, true);
};
// Resetting the stream. Normally, an endpoint SHOULD NOT send more than one RST_STREAM frame for
// any stream.
Stream.prototype.reset = function reset(error) {
if (!this._resetSent) {
this._resetSent = true;
this._pushUpstream({
type: 'RST_STREAM',
flags: {},
stream: this.id,
error: error
});
}
};
// Specify an alternate service for the origin of this stream
Stream.prototype.altsvc = function altsvc(host, port, protocolID, maxAge, origin) {
var stream;
if (origin) {
stream = 0;
} else {
stream = this.id;
}
this._pushUpstream({
type: 'ALTSVC',
flags: {},
stream: stream,
host: host,
port: port,
protocolID: protocolID,
origin: origin,
maxAge: maxAge
});
};
// Data flow
// ---------
// The incoming and the generated outgoing frames are received/transmitted on the `this.upstream`
// [Flow](flow.html). The [Connection](connection.html) object instantiating the stream will read
// and write frames to/from it. The stream itself is a regular [Duplex stream][1], and is used by
// the user to write or read the body of the request.
// [1]: https://nodejs.org/api/stream.html#stream_class_stream_duplex
// upstream side stream user side
//
// +------------------------------------+
// | |
// +------------------+ |
// | upstream | |
// | | |
// +--+ | +--|
// read() | | _send() | _write() | | write(buf)
// <--------------|B |<--------------|--------------| B|<------------
// | | | | |
// frames +--+ | +--| buffers
// | | | | |
// -------------->|B |---------------|------------->| B|------------>
// write(frame) | | _receive() | _read() | | read()
// +--+ | +--|
// | | |
// | | |
// +------------------+ |
// | |
// +------------------------------------+
//
// B: input or output buffer
var Flow = require('./flow').Flow;
Stream.prototype._initializeDataFlow = function _initializeDataFlow() {
this.id = undefined;
this._ended = false;
this.upstream = new Flow();
this.upstream._log = this._log;
this.upstream._send = this._send.bind(this);
this.upstream._receive = this._receive.bind(this);
this.upstream.write = this._writeUpstream.bind(this);
this.upstream.on('error', this.emit.bind(this, 'error'));
this.on('finish', this._finishing);
};
Stream.prototype._pushUpstream = function _pushUpstream(frame) {
this.upstream.push(frame);
this._transition(true, frame);
};
// Overriding the upstream's `write` allows us to act immediately instead of waiting for the input
// queue to empty. This is important in case of control frames.
Stream.prototype._writeUpstream = function _writeUpstream(frame) {
this._log.debug({ frame: frame }, 'Receiving frame');
var moreNeeded = Flow.prototype.write.call(this.upstream, frame);
// * Transition to a new state if that's the effect of receiving the frame
this._transition(false, frame);
// * If it's a control frame. Call the appropriate handler method.
if (frame.type === 'HEADERS') {
if (this._processedHeaders && !frame.flags['END_STREAM']) {
this.emit('error', 'PROTOCOL_ERROR');
}
this._processedHeaders = true;
this._onHeaders(frame);
} else if (frame.type === 'PUSH_PROMISE') {
this._onPromise(frame);
} else if (frame.type === 'PRIORITY') {
this._onPriority(frame);
} else if (frame.type === 'ALTSVC') {
// TODO
} else if (frame.type === 'BLOCKED') {
// TODO
}
// * If it's an invalid stream level frame, emit error
else if ((frame.type !== 'DATA') &&
(frame.type !== 'WINDOW_UPDATE') &&
(frame.type !== 'RST_STREAM')) {
this._log.error({ frame: frame }, 'Invalid stream level frame');
this.emit('error', 'PROTOCOL_ERROR');
}
return moreNeeded;
};
// The `_receive` method (= `upstream._receive`) gets called when there's an incoming frame.
Stream.prototype._receive = function _receive(frame, ready) {
// * If it's a DATA frame, then push the payload into the output buffer on the other side.
// Call ready when the other side is ready to receive more.
if (!this._ended && (frame.type === 'DATA')) {
if (this.contentEncoding === 'gzip' && frame.data.length > 0)
{
if (!this.pakoInf)
{
var self = this;
this.pakoInf = new pako.Inflate();
this.pakoInf.onData = function(data) {
var moreNeeded = self.push(Buffer.from(data));
if (!moreNeeded)
{
this._receiveMore = ready;
}
};
}
var data = frame.data;
this.pakoInf.push(data, frame.END_STREAM);
}
else
{
var moreNeeded = this.push(frame.data);
if (!moreNeeded)
{
this._receiveMore = ready;
}
}
}
// * Any frame may signal the end of the stream with the END_STREAM flag
if (!this._ended && (frame.flags.END_STREAM || (frame.type === 'RST_STREAM'))) {
this.push(null);
this._ended = true;
}
// * Postpone calling `ready` if `push()` returned a falsy value
if (this._receiveMore !== ready) {
ready();
}
};
// The `_read` method is called when the user side is ready to receive more data. If there's a
// pending write on the upstream, then call its pending ready callback to receive more frames.
Stream.prototype._read = function _read() {
if (this._receiveMore) {
var receiveMore = this._receiveMore;
delete this._receiveMore;
receiveMore();
}
};
// The `write` method gets called when there's a write request from the user.
Stream.prototype._write = function _write(buffer, encoding, ready) {
// * Chunking is done by the upstream Flow.
var moreNeeded = this._pushUpstream({
type: 'DATA',
flags: {},
stream: this.id,
data: buffer
});
// * Call ready when upstream is ready to receive more frames.
if (moreNeeded) {
ready();
} else {
this._sendMore = ready;
}
};
// The `_send` (= `upstream._send`) method is called when upstream is ready to receive more frames.
// If there's a pending write on the user side, then call its pending ready callback to receive more
// writes.
Stream.prototype._send = function _send() {
if (this._sendMore) {
var sendMore = this._sendMore;
delete this._sendMore;
sendMore();
}
};
// When the stream is finishing (the user calls `end()` on it), then we have to set the `END_STREAM`
// flag on the last frame. If there's no frame in the queue, or if it doesn't support this flag,
// then we create a 0 length DATA frame. We could do this all the time, but putting the flag on an
// existing frame is a nice optimization.
var emptyBuffer = new Buffer(0);
Stream.prototype._finishing = function _finishing() {
var endFrame = {
type: 'DATA',
flags: { END_STREAM: true },
stream: this.id,
data: emptyBuffer
};
var lastFrame = this.upstream.getLastQueuedFrame();
if (lastFrame && ((lastFrame.type === 'DATA') || (lastFrame.type === 'HEADERS'))) {
this._log.debug({ frame: lastFrame }, 'Marking last frame with END_STREAM flag.');
lastFrame.flags.END_STREAM = true;
this._transition(true, endFrame);
} else {
this._pushUpstream(endFrame);
}
};
// [Stream States](https://tools.ietf.org/html/rfc7540#section-5.1)
// ----------------
//
// +--------+
// PP | | PP
// ,--------| idle |--------.
// / | | \
// v +--------+ v
// +----------+ | +----------+
// | | | H | |
// ,---| reserved | | | reserved |---.
// | | (local) | v | (remote) | |
// | +----------+ +--------+ +----------+ |
// | | ES | | ES | |
// | | H ,-------| open |-------. | H |
// | | / | | \ | |
// | v v +--------+ v v |
// | +----------+ | +----------+ |
// | | half | | | half | |
// | | closed | | R | closed | |
// | | (remote) | | | (local) | |
// | +----------+ | +----------+ |
// | | v | |
// | | ES / R +--------+ ES / R | |
// | `----------->| |<-----------' |
// | R | closed | R |
// `-------------------->| |<--------------------'
// +--------+
// Streams begin in the IDLE state and transitions happen when there's an incoming or outgoing frame
Stream.prototype._initializeState = function _initializeState() {
this.state = 'IDLE';
this._initiated = undefined;
this._closedByUs = undefined;
this._closedWithRst = undefined;
this._processedHeaders = false;
};
// Only `_setState` should change `this.state` directly. It also logs the state change and notifies
// interested parties using the 'state' event.
Stream.prototype._setState = function transition(state) {
assert(this.state !== state);
this._log.debug({ from: this.state, to: state }, 'State transition');
this.state = state;
this.emit('state', state);
};
// A state is 'active' if the stream in that state counts towards the concurrency limit. Streams
// that are in the "open" state, or either of the "half closed" states count toward this limit.
function activeState(state) {
return ((state === 'HALF_CLOSED_LOCAL') || (state === 'HALF_CLOSED_REMOTE') || (state === 'OPEN'));
}
// `_transition` is called every time there's an incoming or outgoing frame. It manages state
// transitions, and detects stream errors. A stream error is always caused by a frame that is not
// allowed in the current state.
Stream.prototype._transition = function transition(sending, frame) {
var receiving = !sending;
var connectionError;
var streamError;
var DATA = false, HEADERS = false, PRIORITY = false, ALTSVC = false, BLOCKED = false;
var RST_STREAM = false, PUSH_PROMISE = false, WINDOW_UPDATE = false;
switch(frame.type) {
case 'DATA' : DATA = true; break;
case 'HEADERS' : HEADERS = true; break;
case 'PRIORITY' : PRIORITY = true; break;
case 'RST_STREAM' : RST_STREAM = true; break;
case 'PUSH_PROMISE' : PUSH_PROMISE = true; break;
case 'WINDOW_UPDATE': WINDOW_UPDATE = true; break;
case 'ALTSVC' : ALTSVC = true; break;
case 'BLOCKED' : BLOCKED = true; break;
}
var previousState = this.state;
switch (this.state) {
// All streams start in the **idle** state. In this state, no frames have been exchanged.
//
// * Sending or receiving a HEADERS frame causes the stream to become "open".
//
// When the HEADERS frame contains the END_STREAM flags, then two state transitions happen.
case 'IDLE':
if (HEADERS) {
this._setState('OPEN');
if (frame.flags.END_STREAM) {
this._setState(sending ? 'HALF_CLOSED_LOCAL' : 'HALF_CLOSED_REMOTE');
}
this._initiated = sending;
} else if (sending && RST_STREAM) {
this._setState('CLOSED');
} else if (PRIORITY) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}
break;
// A stream in the **reserved (local)** state is one that has been promised by sending a
// PUSH_PROMISE frame.
//
// * The endpoint can send a HEADERS frame. This causes the stream to open in a "half closed
// (remote)" state.
// * Either endpoint can send a RST_STREAM frame to cause the stream to become "closed". This
// releases the stream reservation.
// * An endpoint may receive PRIORITY frame in this state.
// * An endpoint MUST NOT send any other type of frame in this state.
case 'RESERVED_LOCAL':
if (sending && HEADERS) {
this._setState('HALF_CLOSED_REMOTE');
} else if (RST_STREAM) {
this._setState('CLOSED');
} else if (PRIORITY) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}
break;
// A stream in the **reserved (remote)** state has been reserved by a remote peer.
//
// * Either endpoint can send a RST_STREAM frame to cause the stream to become "closed". This
// releases the stream reservation.
// * Receiving a HEADERS frame causes the stream to transition to "half closed (local)".
// * An endpoint MAY send PRIORITY frames in this state to reprioritize the stream.
// * Receiving any other type of frame MUST be treated as a stream error of type PROTOCOL_ERROR.
case 'RESERVED_REMOTE':
if (RST_STREAM) {
this._setState('CLOSED');
} else if (receiving && HEADERS) {
this._setState('HALF_CLOSED_LOCAL');
} else if (BLOCKED || PRIORITY) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}
break;
// The **open** state is where both peers can send frames. In this state, sending peers observe
// advertised stream level flow control limits.
//
// * From this state either endpoint can send a frame with a END_STREAM flag set, which causes
// the stream to transition into one of the "half closed" states: an endpoint sending a
// END_STREAM flag causes the stream state to become "half closed (local)"; an endpoint
// receiving a END_STREAM flag causes the stream state to become "half closed (remote)".
// * Either endpoint can send a RST_STREAM frame from this state, causing it to transition
// immediately to "closed".
case 'OPEN':
if (frame.flags.END_STREAM) {
this._setState(sending ? 'HALF_CLOSED_LOCAL' : 'HALF_CLOSED_REMOTE');
} else if (RST_STREAM) {
this._setState('CLOSED');
} else {
/* No state change */
}
break;
// A stream that is **half closed (local)** cannot be used for sending frames.
//
// * A stream transitions from this state to "closed" when a frame that contains a END_STREAM
// flag is received, or when either peer sends a RST_STREAM frame.
// * An endpoint MAY send or receive PRIORITY frames in this state to reprioritize the stream.
// * WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the END_STREAM flag.
case 'HALF_CLOSED_LOCAL':
if (RST_STREAM || (receiving && frame.flags.END_STREAM)) {
this._setState('CLOSED');
} else if (BLOCKED || ALTSVC || receiving || PRIORITY || (sending && WINDOW_UPDATE)) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}
break;
// A stream that is **half closed (remote)** is no longer being used by the peer to send frames.
// In this state, an endpoint is no longer obligated to maintain a receiver flow control window
// if it performs flow control.
//
// * If an endpoint receives additional frames for a stream that is in this state it MUST
// respond with a stream error of type STREAM_CLOSED.
// * A stream can transition from this state to "closed" by sending a frame that contains a
// END_STREAM flag, or when either peer sends a RST_STREAM frame.
// * An endpoint MAY send or receive PRIORITY frames in this state to reprioritize the stream.
// * A receiver MAY receive a WINDOW_UPDATE frame on a "half closed (remote)" stream.
case 'HALF_CLOSED_REMOTE':
if (RST_STREAM || (sending && frame.flags.END_STREAM)) {
this._setState('CLOSED');
} else if (BLOCKED || ALTSVC || sending || PRIORITY || (receiving && WINDOW_UPDATE)) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}
break;
// The **closed** state is the terminal state.
//
// * An endpoint MUST NOT send frames on a closed stream. An endpoint that receives a frame
// after receiving a RST_STREAM or a frame containing a END_STREAM flag on that stream MUST
// treat that as a stream error of type STREAM_CLOSED.
// * WINDOW_UPDATE, PRIORITY or RST_STREAM frames can be received in this state for a short
// period after a frame containing an END_STREAM flag is sent. Until the remote peer receives
// and processes the frame bearing the END_STREAM flag, it might send either frame type.
// Endpoints MUST ignore WINDOW_UPDATE frames received in this state, though endpoints MAY
// choose to treat WINDOW_UPDATE frames that arrive a significant time after sending
// END_STREAM as a connection error of type PROTOCOL_ERROR.
// * If this state is reached as a result of sending a RST_STREAM frame, the peer that receives
// the RST_STREAM might have already sent - or enqueued for sending - frames on the stream
// that cannot be withdrawn. An endpoint that sends a RST_STREAM frame MUST ignore frames that
// it receives on closed streams after it has sent a RST_STREAM frame. An endpoint MAY choose
// to limit the period over which it ignores frames and treat frames that arrive after this
// time as being in error.
// * An endpoint might receive a PUSH_PROMISE frame after it sends RST_STREAM. PUSH_PROMISE
// causes a stream to become "reserved". If promised streams are not desired, a RST_STREAM
// can be used to close any of those streams.
case 'CLOSED':
if (PRIORITY || (sending && RST_STREAM) ||
(sending && this._closedWithRst) ||
(receiving && WINDOW_UPDATE) ||
(receiving && this._closedByUs &&
(this._closedWithRst || RST_STREAM || ALTSVC))) {
/* No state change */
} else {
streamError = 'STREAM_CLOSED';
}
break;
}
// Noting that the connection was closed by the other endpoint. It may be important in edge cases.
// For example, when the peer tries to cancel a promised stream, but we already sent every data
// on it, then the stream is in CLOSED state, yet we want to ignore the incoming RST_STREAM.
if ((this.state === 'CLOSED') && (previousState !== 'CLOSED')) {
this._closedByUs = sending;
this._closedWithRst = RST_STREAM;
}
// Sending/receiving a PUSH_PROMISE
//
// * Sending a PUSH_PROMISE frame marks the associated stream for later use. The stream state
// for the reserved stream transitions to "reserved (local)".
// * Receiving a PUSH_PROMISE frame marks the associated stream as reserved by the remote peer.
// The state of the stream becomes "reserved (remote)".
if (PUSH_PROMISE && !connectionError && !streamError) {
/* This assertion must hold, because _transition is called immediately when a frame is written
to the stream. If it would be called when a frame gets out of the input queue, the state
of the reserved could have been changed by then. */
assert(frame.promised_stream.state === 'IDLE', frame.promised_stream.state);
frame.promised_stream._setState(sending ? 'RESERVED_LOCAL' : 'RESERVED_REMOTE');
frame.promised_stream._initiated = sending;
}
// Signaling how sending/receiving this frame changes the active stream count (-1, 0 or +1)
if (this._initiated) {
var change = (activeState(this.state) - activeState(previousState));
if (sending) {
frame.count_change = change;
} else {
frame.count_change(change);
}
} else if (sending) {
frame.count_change = 0;
}
// Common error handling.
if (connectionError || streamError) {
var info = {
error: connectionError,
frame: frame,
state: this.state,
closedByUs: this._closedByUs,
closedWithRst: this._closedWithRst
};
// * When sending something invalid, throwing an exception, since it is probably a bug.
if (sending) {
this._log.error(info, 'Sending illegal frame.');
return this.emit('error', new Error('Sending illegal frame (' + frame.type + ') in ' + this.state + ' state.'));
}
// * In case of a serious problem, emitting and error and letting someone else handle it
// (e.g. closing the connection)
// * When receiving something invalid, sending an RST_STREAM using the `reset` method.
// This will automatically cause a transition to the CLOSED state.
else {
this._log.error(info, 'Received illegal frame.');
if (connectionError) {
this.emit('connectionError', connectionError);
} else {
this.reset(streamError);
this.emit('error', streamError);
}
}
}
};
// Bunyan serializers
// ------------------
exports.serializers = {};
var nextId = 0;
exports.serializers.s = function(stream) {
if (!('_id' in stream)) {
stream._id = nextId;
nextId += 1;
}
return stream._id;
};
},{"./flow":86,"assert":11,"buffer":13,"pako":102,"stream":43}],90:[function(require,module,exports){
'use strict';
// modified from https://github.com/es-shims/es6-shim
var keys = require('object-keys');
var bind = require('function-bind');
var canBeObject = function (obj) {
return typeof obj !== 'undefined' && obj !== null;
};
var hasSymbols = require('has-symbols/shams')();
var toObject = Object;
var push = bind.call(Function.call, Array.prototype.push);
var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable);
var originalGetSymbols = hasSymbols ? Object.getOwnPropertySymbols : null;
module.exports = function assign(target, source1) {
if (!canBeObject(target)) { throw new TypeError('target must be an object'); }
var objTarget = toObject(target);
var s, source, i, props, syms, value, key;
for (s = 1; s < arguments.length; ++s) {
source = toObject(arguments[s]);
props = keys(source);
var getSymbols = hasSymbols && (Object.getOwnPropertySymbols || originalGetSymbols);
if (getSymbols) {
syms = getSymbols(source);
for (i = 0; i < syms.length; ++i) {
key = syms[i];
if (propIsEnumerable(source, key)) {
push(props, key);
}
}
}
for (i = 0; i < props.length; ++i) {
key = props[i];
value = source[key];
if (propIsEnumerable(source, key)) {
objTarget[key] = value;
}
}
}
return objTarget;
};
},{"function-bind":95,"has-symbols/shams":96,"object-keys":100}],91:[function(require,module,exports){
'use strict';
var defineProperties = require('define-properties');
var implementation = require('./implementation');
var getPolyfill = require('./polyfill');
var shim = require('./shim');
var polyfill = getPolyfill();
defineProperties(polyfill, {
getPolyfill: getPolyfill,
implementation: implementation,
shim: shim
});
module.exports = polyfill;
},{"./implementation":90,"./polyfill":97,"./shim":98,"define-properties":92}],92:[function(require,module,exports){
'use strict';
var keys = require('object-keys');
var foreach = require('foreach');
var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol';
var toStr = Object.prototype.toString;
var isFunction = function (fn) {
return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
};
var arePropertyDescriptorsSupported = function () {
var obj = {};
try {
Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
/* eslint-disable no-unused-vars, no-restricted-syntax */
for (var _ in obj) { return false; }
/* eslint-enable no-unused-vars, no-restricted-syntax */
return obj.x === obj;
} catch (e) { /* this is IE 8. */
return false;
}
};
var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported();
var defineProperty = function (object, name, value, predicate) {
if (name in object && (!isFunction(predicate) || !predicate())) {
return;
}
if (supportsDescriptors) {
Object.defineProperty(object, name, {
configurable: true,
enumerable: false,
value: value,
writable: true
});
} else {
object[name] = value;
}
};
var defineProperties = function (object, map) {
var predicates = arguments.length > 2 ? arguments[2] : {};
var props = keys(map);
if (hasSymbols) {
props = props.concat(Object.getOwnPropertySymbols(map));
}
foreach(props, function (name) {
defineProperty(object, name, map[name], predicates[name]);
});
};
defineProperties.supportsDescriptors = !!supportsDescriptors;
module.exports = defineProperties;
},{"foreach":93,"object-keys":100}],93:[function(require,module,exports){
var hasOwn = Object.prototype.hasOwnProperty;
var toString = Object.prototype.toString;
module.exports = function forEach (obj, fn, ctx) {
if (toString.call(fn) !== '[object Function]') {
throw new TypeError('iterator must be a function');
}
var l = obj.length;
if (l === +l) {
for (var i = 0; i < l; i++) {
fn.call(ctx, obj[i], i, obj);
}
} else {
for (var k in obj) {
if (hasOwn.call(obj, k)) {
fn.call(ctx, obj[k], k, obj);
}
}
}
};
},{}],94:[function(require,module,exports){
'use strict';
/* eslint no-invalid-this: 1 */
var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
var slice = Array.prototype.slice;
var toStr = Object.prototype.toString;
var funcType = '[object Function]';
module.exports = function bind(that) {
var target = this;
if (typeof target !== 'function' || toStr.call(target) !== funcType) {
throw new TypeError(ERROR_MESSAGE + target);
}
var args = slice.call(arguments, 1);
var bound;
var binder = function () {
if (this instanceof bound) {
var result = target.apply(
this,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
var boundLength = Math.max(0, target.length - args.length);
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
boundArgs.push('$' + i);
}
bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);
if (target.prototype) {
var Empty = function Empty() {};
Empty.prototype = target.prototype;
bound.prototype = new Empty();
Empty.prototype = null;
}
return bound;
};
},{}],95:[function(require,module,exports){
'use strict';
var implementation = require('./implementation');
module.exports = Function.prototype.bind || implementation;
},{"./implementation":94}],96:[function(require,module,exports){
'use strict';
/* eslint complexity: [2, 17], max-statements: [2, 33] */
module.exports = function hasSymbols() {
if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; }
if (typeof Symbol.iterator === 'symbol') { return true; }
var obj = {};
var sym = Symbol('test');
var symObj = Object(sym);
if (typeof sym === 'string') { return false; }
if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; }
if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; }
// temp disabled per https://github.com/ljharb/object.assign/issues/17
// if (sym instanceof Symbol) { return false; }
// temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4
// if (!(symObj instanceof Symbol)) { return false; }
// if (typeof Symbol.prototype.toString !== 'function') { return false; }
// if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; }
var symVal = 42;
obj[sym] = symVal;
for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax
if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; }
if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; }
var syms = Object.getOwnPropertySymbols(obj);
if (syms.length !== 1 || syms[0] !== sym) { return false; }
if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; }
if (typeof Object.getOwnPropertyDescriptor === 'function') {
var descriptor = Object.getOwnPropertyDescriptor(obj, sym);
if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; }
}
return true;
};
},{}],97:[function(require,module,exports){
'use strict';
var implementation = require('./implementation');
var lacksProperEnumerationOrder = function () {
if (!Object.assign) {
return false;
}
// v8, specifically in node 4.x, has a bug with incorrect property enumeration order
// note: this does not detect the bug unless there's 20 characters
var str = 'abcdefghijklmnopqrst';
var letters = str.split('');
var map = {};
for (var i = 0; i < letters.length; ++i) {
map[letters[i]] = letters[i];
}
var obj = Object.assign({}, map);
var actual = '';
for (var k in obj) {
actual += k;
}
return str !== actual;
};
var assignHasPendingExceptions = function () {
if (!Object.assign || !Object.preventExtensions) {
return false;
}
// Firefox 37 still has "pending exception" logic in its Object.assign implementation,
// which is 72% slower than our shim, and Firefox 40's native implementation.
var thrower = Object.preventExtensions({ 1: 2 });
try {
Object.assign(thrower, 'xy');
} catch (e) {
return thrower[1] === 'y';
}
return false;
};
module.exports = function getPolyfill() {
if (!Object.assign) {
return implementation;
}
if (lacksProperEnumerationOrder()) {
return implementation;
}
if (assignHasPendingExceptions()) {
return implementation;
}
return Object.assign;
};
},{"./implementation":90}],98:[function(require,module,exports){
'use strict';
var define = require('define-properties');
var getPolyfill = require('./polyfill');
module.exports = function shimAssign() {
var polyfill = getPolyfill();
define(
Object,
{ assign: polyfill },
{ assign: function () { return Object.assign !== polyfill; } }
);
return polyfill;
};
},{"./polyfill":97,"define-properties":92}],99:[function(require,module,exports){
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
},{}],100:[function(require,module,exports){
'use strict';
// modified from https://github.com/es-shims/es5-shim
var has = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;
var slice = Array.prototype.slice;
var isArgs = require('./isArguments');
var isEnumerable = Object.prototype.propertyIsEnumerable;
var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
var dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
];
var equalsConstructorPrototype = function (o) {
var ctor = o.constructor;
return ctor && ctor.prototype === o;
};
var excludedKeys = {
$console: true,
$external: true,
$frame: true,
$frameElement: true,
$frames: true,
$innerHeight: true,
$innerWidth: true,
$outerHeight: true,
$outerWidth: true,
$pageXOffset: true,
$pageYOffset: true,
$parent: true,
$scrollLeft: true,
$scrollTop: true,
$scrollX: true,
$scrollY: true,
$self: true,
$webkitIndexedDB: true,
$webkitStorageInfo: true,
$window: true
};
var hasAutomationEqualityBug = (function () {
/* global window */
if (typeof window === 'undefined') { return false; }
for (var k in window) {
try {
if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
try {
equalsConstructorPrototype(window[k]);
} catch (e) {
return true;
}
}
} catch (e) {
return true;
}
}
return false;
}());
var equalsConstructorPrototypeIfNotBuggy = function (o) {
/* global window */
if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
return equalsConstructorPrototype(o);
}
try {
return equalsConstructorPrototype(o);
} catch (e) {
return false;
}
};
var keysShim = function keys(object) {
var isObject = object !== null && typeof object === 'object';
var isFunction = toStr.call(object) === '[object Function]';
var isArguments = isArgs(object);
var isString = isObject && toStr.call(object) === '[object String]';
var theKeys = [];
if (!isObject && !isFunction && !isArguments) {
throw new TypeError('Object.keys called on a non-object');
}
var skipProto = hasProtoEnumBug && isFunction;
if (isString && object.length > 0 && !has.call(object, 0)) {
for (var i = 0; i < object.length; ++i) {
theKeys.push(String(i));
}
}
if (isArguments && object.length > 0) {
for (var j = 0; j < object.length; ++j) {
theKeys.push(String(j));
}
} else {
for (var name in object) {
if (!(skipProto && name === 'prototype') && has.call(object, name)) {
theKeys.push(String(name));
}
}
}
if (hasDontEnumBug) {
var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
for (var k = 0; k < dontEnums.length; ++k) {
if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
theKeys.push(dontEnums[k]);
}
}
}
return theKeys;
};
keysShim.shim = function shimObjectKeys() {
if (Object.keys) {
var keysWorksWithArguments = (function () {
// Safari 5.0 bug
return (Object.keys(arguments) || '').length === 2;
}(1, 2));
if (!keysWorksWithArguments) {
var originalKeys = Object.keys;
Object.keys = function keys(object) {
if (isArgs(object)) {
return originalKeys(slice.call(object));
} else {
return originalKeys(object);
}
};
}
} else {
Object.keys = keysShim;
}
return Object.keys || keysShim;
};
module.exports = keysShim;
},{"./isArguments":101}],101:[function(require,module,exports){
'use strict';
var toStr = Object.prototype.toString;
module.exports = function isArguments(value) {
var str = toStr.call(value);
var isArgs = str === '[object Arguments]';
if (!isArgs) {
isArgs = str !== '[object Array]' &&
value !== null &&
typeof value === 'object' &&
typeof value.length === 'number' &&
value.length >= 0 &&
toStr.call(value.callee) === '[object Function]';
}
return isArgs;
};
},{}],102:[function(require,module,exports){
// Top level file is just a mixin of submodules & constants
'use strict';
var assign = require('./lib/utils/common').assign;
var deflate = require('./lib/deflate');
var inflate = require('./lib/inflate');
var constants = require('./lib/zlib/constants');
var pako = {};
assign(pako, deflate, inflate, constants);
module.exports = pako;
},{"./lib/deflate":103,"./lib/inflate":104,"./lib/utils/common":105,"./lib/zlib/constants":108}],103:[function(require,module,exports){
'use strict';
var zlib_deflate = require('./zlib/deflate');
var utils = require('./utils/common');
var strings = require('./utils/strings');
var msg = require('./zlib/messages');
var ZStream = require('./zlib/zstream');
var toString = Object.prototype.toString;
/* Public constants ==========================================================*/
/* ===========================================================================*/
var Z_NO_FLUSH = 0;
var Z_FINISH = 4;
var Z_OK = 0;
var Z_STREAM_END = 1;
var Z_SYNC_FLUSH = 2;
var Z_DEFAULT_COMPRESSION = -1;
var Z_DEFAULT_STRATEGY = 0;
var Z_DEFLATED = 8;
/* ===========================================================================*/
/**
* class Deflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[deflate]],
* [[deflateRaw]] and [[gzip]].
**/
/* internal
* Deflate.chunks -> Array
*
* Chunks of output data, if [[Deflate#onData]] not overridden.
**/
/**
* Deflate.result -> Uint8Array|Array
*
* Compressed result, generated by default [[Deflate#onData]]
* and [[Deflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Deflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Deflate.err -> Number
*
* Error code after deflate finished. 0 (Z_OK) on success.
* You will not need it in real life, because deflate errors
* are possible only on wrong options or bad `onData` / `onEnd`
* custom handlers.
**/
/**
* Deflate.msg -> String
*
* Error message, if [[Deflate.err]] != 0
**/
/**
* new Deflate(options)
* - options (Object): zlib deflate options.
*
* Creates new deflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `level`
* - `windowBits`
* - `memLevel`
* - `strategy`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw deflate
* - `gzip` (Boolean) - create gzip wrapper
* - `to` (String) - if equal to 'string', then result will be "binary string"
* (each char code [0..255])
* - `header` (Object) - custom header for gzip
* - `text` (Boolean) - true if compressed data believed to be text
* - `time` (Number) - modification time, unix timestamp
* - `os` (Number) - operation system code
* - `extra` (Array) - array of bytes with extra data (max 65536)
* - `name` (String) - file name (binary string)
* - `comment` (String) - comment (binary string)
* - `hcrc` (Boolean) - true if header crc should be added
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var deflate = new pako.Deflate({ level: 3});
*
* deflate.push(chunk1, false);
* deflate.push(chunk2, true); // true -> last chunk
*
* if (deflate.err) { throw new Error(deflate.err); }
*
* console.log(deflate.result);
* ```
**/
function Deflate(options) {
if (!(this instanceof Deflate)) return new Deflate(options);
this.options = utils.assign({
level: Z_DEFAULT_COMPRESSION,
method: Z_DEFLATED,
chunkSize: 16384,
windowBits: 15,
memLevel: 8,
strategy: Z_DEFAULT_STRATEGY,
to: ''
}, options || {});
var opt = this.options;
if (opt.raw && (opt.windowBits > 0)) {
opt.windowBits = -opt.windowBits;
}
else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
opt.windowBits += 16;
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
var status = zlib_deflate.deflateInit2(
this.strm,
opt.level,
opt.method,
opt.windowBits,
opt.memLevel,
opt.strategy
);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
if (opt.header) {
zlib_deflate.deflateSetHeader(this.strm, opt.header);
}
if (opt.dictionary) {
var dict;
// Convert data if needed
if (typeof opt.dictionary === 'string') {
// If we need to compress text, change encoding to utf8.
dict = strings.string2buf(opt.dictionary);
} else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
dict = new Uint8Array(opt.dictionary);
} else {
dict = opt.dictionary;
}
status = zlib_deflate.deflateSetDictionary(this.strm, dict);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
this._dict_set = true;
}
}
/**
* Deflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
* converted to utf8 byte sequence.
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
* new compressed chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the compression context.
*
* On fail call [[Deflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* array format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
Deflate.prototype.push = function (data, mode) {
var strm = this.strm;
var chunkSize = this.options.chunkSize;
var status, _mode;
if (this.ended) { return false; }
_mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
// Convert data if needed
if (typeof data === 'string') {
// If we need to compress text, change encoding to utf8.
strm.input = strings.string2buf(data);
} else if (toString.call(data) === '[object ArrayBuffer]') {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new utils.Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = zlib_deflate.deflate(strm, _mode); /* no bad return value */
if (status !== Z_STREAM_END && status !== Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
if (this.options.to === 'string') {
this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
} else {
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
}
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
// Finalize on the last chunk.
if (_mode === Z_FINISH) {
status = zlib_deflate.deflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === Z_OK;
}
// callback interim results if Z_SYNC_FLUSH.
if (_mode === Z_SYNC_FLUSH) {
this.onEnd(Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Deflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
Deflate.prototype.onData = function (chunk) {
this.chunks.push(chunk);
};
/**
* Deflate#onEnd(status) -> Void
* - status (Number): deflate status. 0 (Z_OK) on success,
* other if not.
*
* Called once after you tell deflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
Deflate.prototype.onEnd = function (status) {
// On success - join
if (status === Z_OK) {
if (this.options.to === 'string') {
this.result = this.chunks.join('');
} else {
this.result = utils.flattenChunks(this.chunks);
}
}
this.chunks = [];
this.err = status;
this.msg = this.strm.msg;
};
/**
* deflate(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* Compress `data` with deflate algorithm and `options`.
*
* Supported options are:
*
* - level
* - windowBits
* - memLevel
* - strategy
* - dictionary
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Sugar (options):
*
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
* negative windowBits implicitly.
* - `to` (String) - if equal to 'string', then result will be "binary string"
* (each char code [0..255])
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
*
* console.log(pako.deflate(data));
* ```
**/
function deflate(input, options) {
var deflator = new Deflate(options);
deflator.push(input, true);
// That will never happens, if you don't cheat with options :)
if (deflator.err) { throw deflator.msg || msg[deflator.err]; }
return deflator.result;
}
/**
* deflateRaw(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* The same as [[deflate]], but creates raw data, without wrapper
* (header and adler32 crc).
**/
function deflateRaw(input, options) {
options = options || {};
options.raw = true;
return deflate(input, options);
}
/**
* gzip(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* The same as [[deflate]], but create gzip wrapper instead of
* deflate one.
**/
function gzip(input, options) {
options = options || {};
options.gzip = true;
return deflate(input, options);
}
exports.Deflate = Deflate;
exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;
},{"./utils/common":105,"./utils/strings":106,"./zlib/deflate":110,"./zlib/messages":115,"./zlib/zstream":117}],104:[function(require,module,exports){
'use strict';
var zlib_inflate = require('./zlib/inflate');
var utils = require('./utils/common');
var strings = require('./utils/strings');
var c = require('./zlib/constants');
var msg = require('./zlib/messages');
var ZStream = require('./zlib/zstream');
var GZheader = require('./zlib/gzheader');
var toString = Object.prototype.toString;
/**
* class Inflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[inflate]]
* and [[inflateRaw]].
**/
/* internal
* inflate.chunks -> Array
*
* Chunks of output data, if [[Inflate#onData]] not overridden.
**/
/**
* Inflate.result -> Uint8Array|Array|String
*
* Uncompressed result, generated by default [[Inflate#onData]]
* and [[Inflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Inflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Inflate.err -> Number
*
* Error code after inflate finished. 0 (Z_OK) on success.
* Should be checked if broken data possible.
**/
/**
* Inflate.msg -> String
*
* Error message, if [[Inflate.err]] != 0
**/
/**
* new Inflate(options)
* - options (Object): zlib inflate options.
*
* Creates new inflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `windowBits`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw inflate
* - `to` (String) - if equal to 'string', then result will be converted
* from utf8 to utf16 (javascript) string. When string output requested,
* chunk length can differ from `chunkSize`, depending on content.
*
* By default, when no options set, autodetect deflate/gzip data format via
* wrapper header.
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var inflate = new pako.Inflate({ level: 3});
*
* inflate.push(chunk1, false);
* inflate.push(chunk2, true); // true -> last chunk
*
* if (inflate.err) { throw new Error(inflate.err); }
*
* console.log(inflate.result);
* ```
**/
function Inflate(options) {
if (!(this instanceof Inflate)) return new Inflate(options);
this.options = utils.assign({
chunkSize: 16384,
windowBits: 0,
to: ''
}, options || {});
var opt = this.options;
// Force window size for `raw` data, if not set directly,
// because we have no header for autodetect.
if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
opt.windowBits = -opt.windowBits;
if (opt.windowBits === 0) { opt.windowBits = -15; }
}
// If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
!(options && options.windowBits)) {
opt.windowBits += 32;
}
// Gzip header has no info about windows size, we can do autodetect only
// for deflate. So, if window size not set, force it to max when gzip possible
if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
// bit 3 (16) -> gzipped data
// bit 4 (32) -> autodetect gzip/deflate
if ((opt.windowBits & 15) === 0) {
opt.windowBits |= 15;
}
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
var status = zlib_inflate.inflateInit2(
this.strm,
opt.windowBits
);
if (status !== c.Z_OK) {
throw new Error(msg[status]);
}
this.header = new GZheader();
zlib_inflate.inflateGetHeader(this.strm, this.header);
}
/**
* Inflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
* new output chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the decompression context.
*
* On fail call [[Inflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
Inflate.prototype.push = function (data, mode) {
var strm = this.strm;
var chunkSize = this.options.chunkSize;
var dictionary = this.options.dictionary;
var status, _mode;
var next_out_utf8, tail, utf8str;
var dict;
// Flag to properly process Z_BUF_ERROR on testing inflate call
// when we check that all output data was flushed.
var allowBufError = false;
if (this.ended) { return false; }
_mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
// Convert data if needed
if (typeof data === 'string') {
// Only binary strings can be decompressed on practice
strm.input = strings.binstring2buf(data);
} else if (toString.call(data) === '[object ArrayBuffer]') {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new utils.Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */
if (status === c.Z_NEED_DICT && dictionary) {
// Convert data if needed
if (typeof dictionary === 'string') {
dict = strings.string2buf(dictionary);
} else if (toString.call(dictionary) === '[object ArrayBuffer]') {
dict = new Uint8Array(dictionary);
} else {
dict = dictionary;
}
status = zlib_inflate.inflateSetDictionary(this.strm, dict);
}
if (status === c.Z_BUF_ERROR && allowBufError === true) {
status = c.Z_OK;
allowBufError = false;
}
if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.next_out) {
if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) {
if (this.options.to === 'string') {
next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
tail = strm.next_out - next_out_utf8;
utf8str = strings.buf2string(strm.output, next_out_utf8);
// move tail
strm.next_out = tail;
strm.avail_out = chunkSize - tail;
if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
this.onData(utf8str);
} else {
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
}
}
}
// When no more input data, we should check that internal inflate buffers
// are flushed. The only way to do it when avail_out = 0 - run one more
// inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
// Here we set flag to process this error properly.
//
// NOTE. Deflate does not return error in this case and does not needs such
// logic.
if (strm.avail_in === 0 && strm.avail_out === 0) {
allowBufError = true;
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);
if (status === c.Z_STREAM_END) {
_mode = c.Z_FINISH;
}
// Finalize on the last chunk.
if (_mode === c.Z_FINISH) {
status = zlib_inflate.inflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === c.Z_OK;
}
// callback interim results if Z_SYNC_FLUSH.
if (_mode === c.Z_SYNC_FLUSH) {
this.onEnd(c.Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Inflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
Inflate.prototype.onData = function (chunk) {
this.chunks.push(chunk);
};
/**
* Inflate#onEnd(status) -> Void
* - status (Number): inflate status. 0 (Z_OK) on success,
* other if not.
*
* Called either after you tell inflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
Inflate.prototype.onEnd = function (status) {
// On success - join
if (status === c.Z_OK) {
if (this.options.to === 'string') {
// Glue & convert here, until we teach pako to send
// utf8 aligned strings to onData
this.result = this.chunks.join('');
} else {
this.result = utils.flattenChunks(this.chunks);
}
}
this.chunks = [];
this.err = status;
this.msg = this.strm.msg;
};
/**
* inflate(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to decompress.
* - options (Object): zlib inflate options.
*
* Decompress `data` with inflate/ungzip and `options`. Autodetect
* format via wrapper header by default. That's why we don't provide
* separate `ungzip` method.
*
* Supported options are:
*
* - windowBits
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information.
*
* Sugar (options):
*
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
* negative windowBits implicitly.
* - `to` (String) - if equal to 'string', then result will be converted
* from utf8 to utf16 (javascript) string. When string output requested,
* chunk length can differ from `chunkSize`, depending on content.
*
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , input = pako.deflate([1,2,3,4,5,6,7,8,9])
* , output;
*
* try {
* output = pako.inflate(input);
* } catch (err)
* console.log(err);
* }
* ```
**/
function inflate(input, options) {
var inflator = new Inflate(options);
inflator.push(input, true);
// That will never happens, if you don't cheat with options :)
if (inflator.err) { throw inflator.msg || msg[inflator.err]; }
return inflator.result;
}
/**
* inflateRaw(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to decompress.
* - options (Object): zlib inflate options.
*
* The same as [[inflate]], but creates raw data, without wrapper
* (header and adler32 crc).
**/
function inflateRaw(input, options) {
options = options || {};
options.raw = true;
return inflate(input, options);
}
/**
* ungzip(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to decompress.
* - options (Object): zlib inflate options.
*
* Just shortcut to [[inflate]], because it autodetects format
* by header.content. Done for convenience.
**/
exports.Inflate = Inflate;
exports.inflate = inflate;
exports.inflateRaw = inflateRaw;
exports.ungzip = inflate;
},{"./utils/common":105,"./utils/strings":106,"./zlib/constants":108,"./zlib/gzheader":111,"./zlib/inflate":113,"./zlib/messages":115,"./zlib/zstream":117}],105:[function(require,module,exports){
'use strict';
var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
(typeof Uint16Array !== 'undefined') &&
(typeof Int32Array !== 'undefined');
function _has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
exports.assign = function (obj /*from1, from2, from3, ...*/) {
var sources = Array.prototype.slice.call(arguments, 1);
while (sources.length) {
var source = sources.shift();
if (!source) { continue; }
if (typeof source !== 'object') {
throw new TypeError(source + 'must be non-object');
}
for (var p in source) {
if (_has(source, p)) {
obj[p] = source[p];
}
}
}
return obj;
};
// reduce buffer size, avoiding mem copy
exports.shrinkBuf = function (buf, size) {
if (buf.length === size) { return buf; }
if (buf.subarray) { return buf.subarray(0, size); }
buf.length = size;
return buf;
};
var fnTyped = {
arraySet: function (dest, src, src_offs, len, dest_offs) {
if (src.subarray && dest.subarray) {
dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
return;
}
// Fallback to ordinary array
for (var i = 0; i < len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function (chunks) {
var i, l, len, pos, chunk, result;
// calculate data length
len = 0;
for (i = 0, l = chunks.length; i < l; i++) {
len += chunks[i].length;
}
// join chunks
result = new Uint8Array(len);
pos = 0;
for (i = 0, l = chunks.length; i < l; i++) {
chunk = chunks[i];
result.set(chunk, pos);
pos += chunk.length;
}
return result;
}
};
var fnUntyped = {
arraySet: function (dest, src, src_offs, len, dest_offs) {
for (var i = 0; i < len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function (chunks) {
return [].concat.apply([], chunks);
}
};
// Enable/Disable typed arrays use, for testing
//
exports.setTyped = function (on) {
if (on) {
exports.Buf8 = Uint8Array;
exports.Buf16 = Uint16Array;
exports.Buf32 = Int32Array;
exports.assign(exports, fnTyped);
} else {
exports.Buf8 = Array;
exports.Buf16 = Array;
exports.Buf32 = Array;
exports.assign(exports, fnUntyped);
}
};
exports.setTyped(TYPED_OK);
},{}],106:[function(require,module,exports){
// String encode/decode helpers
'use strict';
var utils = require('./common');
// Quick check if we can use fast array to bin string conversion
//
// - apply(Array) can fail on Android 2.2
// - apply(Uint8Array) can fail on iOS 5.1 Safari
//
var STR_APPLY_OK = true;
var STR_APPLY_UIA_OK = true;
try { String.fromCharCode.apply(null, [ 0 ]); } catch (__) { STR_APPLY_OK = false; }
try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
// Table with utf8 lengths (calculated by first byte of sequence)
// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
// because max possible codepoint is 0x10ffff
var _utf8len = new utils.Buf8(256);
for (var q = 0; q < 256; q++) {
_utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
}
_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
// convert string to array (typed, when possible)
exports.string2buf = function (str) {
var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
// count binary size
for (m_pos = 0; m_pos < str_len; m_pos++) {
c = str.charCodeAt(m_pos);
if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
c2 = str.charCodeAt(m_pos + 1);
if ((c2 & 0xfc00) === 0xdc00) {
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
m_pos++;
}
}
buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
}
// allocate buffer
buf = new utils.Buf8(buf_len);
// convert
for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
c = str.charCodeAt(m_pos);
if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
c2 = str.charCodeAt(m_pos + 1);
if ((c2 & 0xfc00) === 0xdc00) {
c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
m_pos++;
}
}
if (c < 0x80) {
/* one byte */
buf[i++] = c;
} else if (c < 0x800) {
/* two bytes */
buf[i++] = 0xC0 | (c >>> 6);
buf[i++] = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
/* three bytes */
buf[i++] = 0xE0 | (c >>> 12);
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
buf[i++] = 0x80 | (c & 0x3f);
} else {
/* four bytes */
buf[i++] = 0xf0 | (c >>> 18);
buf[i++] = 0x80 | (c >>> 12 & 0x3f);
buf[i++] = 0x80 | (c >>> 6 & 0x3f);
buf[i++] = 0x80 | (c & 0x3f);
}
}
return buf;
};
// Helper (used in 2 places)
function buf2binstring(buf, len) {
// use fallback for big arrays to avoid stack overflow
if (len < 65537) {
if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
}
}
var result = '';
for (var i = 0; i < len; i++) {
result += String.fromCharCode(buf[i]);
}
return result;
}
// Convert byte array to binary string
exports.buf2binstring = function (buf) {
return buf2binstring(buf, buf.length);
};
// Convert binary string (typed, when possible)
exports.binstring2buf = function (str) {
var buf = new utils.Buf8(str.length);
for (var i = 0, len = buf.length; i < len; i++) {
buf[i] = str.charCodeAt(i);
}
return buf;
};
// convert array to string
exports.buf2string = function (buf, max) {
var i, out, c, c_len;
var len = max || buf.length;
// Reserve max possible length (2 words per char)
// NB: by unknown reasons, Array is significantly faster for
// String.fromCharCode.apply than Uint16Array.
var utf16buf = new Array(len * 2);
for (out = 0, i = 0; i < len;) {
c = buf[i++];
// quick process ascii
if (c < 0x80) { utf16buf[out++] = c; continue; }
c_len = _utf8len[c];
// skip 5 & 6 byte codes
if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
// apply mask on first byte
c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
// join the rest
while (c_len > 1 && i < len) {
c = (c << 6) | (buf[i++] & 0x3f);
c_len--;
}
// terminated by end of string?
if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
if (c < 0x10000) {
utf16buf[out++] = c;
} else {
c -= 0x10000;
utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
utf16buf[out++] = 0xdc00 | (c & 0x3ff);
}
}
return buf2binstring(utf16buf, out);
};
// Calculate max possible position in utf8 buffer,
// that will not break sequence. If that's not possible
// - (very small limits) return max size as is.
//
// buf[] - utf8 bytes array
// max - length limit (mandatory);
exports.utf8border = function (buf, max) {
var pos;
max = max || buf.length;
if (max > buf.length) { max = buf.length; }
// go back from last position, until start of sequence found
pos = max - 1;
while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
// Very small and broken sequence,
// return max, because we should return something anyway.
if (pos < 0) { return max; }
// If we came to start of buffer - that means buffer is too small,
// return max too.
if (pos === 0) { return max; }
return (pos + _utf8len[buf[pos]] > max) ? pos : max;
};
},{"./common":105}],107:[function(require,module,exports){
'use strict';
// Note: adler32 takes 12% for level 0 and 2% for level 6.
// It isn't worth it to make additional optimizations as in original.
// Small size is preferable.
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
function adler32(adler, buf, len, pos) {
var s1 = (adler & 0xffff) |0,
s2 = ((adler >>> 16) & 0xffff) |0,
n = 0;
while (len !== 0) {
// Set limit ~ twice less than 5552, to keep
// s2 in 31-bits, because we force signed ints.
// in other case %= will fail.
n = len > 2000 ? 2000 : len;
len -= n;
do {
s1 = (s1 + buf[pos++]) |0;
s2 = (s2 + s1) |0;
} while (--n);
s1 %= 65521;
s2 %= 65521;
}
return (s1 | (s2 << 16)) |0;
}
module.exports = adler32;
},{}],108:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
module.exports = {
/* Allowed flush values; see deflate() and inflate() below for details */
Z_NO_FLUSH: 0,
Z_PARTIAL_FLUSH: 1,
Z_SYNC_FLUSH: 2,
Z_FULL_FLUSH: 3,
Z_FINISH: 4,
Z_BLOCK: 5,
Z_TREES: 6,
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
Z_OK: 0,
Z_STREAM_END: 1,
Z_NEED_DICT: 2,
Z_ERRNO: -1,
Z_STREAM_ERROR: -2,
Z_DATA_ERROR: -3,
//Z_MEM_ERROR: -4,
Z_BUF_ERROR: -5,
//Z_VERSION_ERROR: -6,
/* compression levels */
Z_NO_COMPRESSION: 0,
Z_BEST_SPEED: 1,
Z_BEST_COMPRESSION: 9,
Z_DEFAULT_COMPRESSION: -1,
Z_FILTERED: 1,
Z_HUFFMAN_ONLY: 2,
Z_RLE: 3,
Z_FIXED: 4,
Z_DEFAULT_STRATEGY: 0,
/* Possible values of the data_type field (though see inflate()) */
Z_BINARY: 0,
Z_TEXT: 1,
//Z_ASCII: 1, // = Z_TEXT (deprecated)
Z_UNKNOWN: 2,
/* The deflate compression method */
Z_DEFLATED: 8
//Z_NULL: null // Use -1 or null inline, depending on var type
};
},{}],109:[function(require,module,exports){
'use strict';
// Note: we can't get significant speed boost here.
// So write code to minimize size - no pregenerated tables
// and array tools dependencies.
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// Use ordinary array, since untyped makes no boost here
function makeTable() {
var c, table = [];
for (var n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
table[n] = c;
}
return table;
}
// Create table on load. Just 255 signed longs. Not a problem.
var crcTable = makeTable();
function crc32(crc, buf, len, pos) {
var t = crcTable,
end = pos + len;
crc ^= -1;
for (var i = pos; i < end; i++) {
crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
}
return (crc ^ (-1)); // >>> 0;
}
module.exports = crc32;
},{}],110:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
var utils = require('../utils/common');
var trees = require('./trees');
var adler32 = require('./adler32');
var crc32 = require('./crc32');
var msg = require('./messages');
/* Public constants ==========================================================*/
/* ===========================================================================*/
/* Allowed flush values; see deflate() and inflate() below for details */
var Z_NO_FLUSH = 0;
var Z_PARTIAL_FLUSH = 1;
//var Z_SYNC_FLUSH = 2;
var Z_FULL_FLUSH = 3;
var Z_FINISH = 4;
var Z_BLOCK = 5;
//var Z_TREES = 6;
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
var Z_OK = 0;
var Z_STREAM_END = 1;
//var Z_NEED_DICT = 2;
//var Z_ERRNO = -1;
var Z_STREAM_ERROR = -2;
var Z_DATA_ERROR = -3;
//var Z_MEM_ERROR = -4;
var Z_BUF_ERROR = -5;
//var Z_VERSION_ERROR = -6;
/* compression levels */
//var Z_NO_COMPRESSION = 0;
//var Z_BEST_SPEED = 1;
//var Z_BEST_COMPRESSION = 9;
var Z_DEFAULT_COMPRESSION = -1;
var Z_FILTERED = 1;
var Z_HUFFMAN_ONLY = 2;
var Z_RLE = 3;
var Z_FIXED = 4;
var Z_DEFAULT_STRATEGY = 0;
/* Possible values of the data_type field (though see inflate()) */
//var Z_BINARY = 0;
//var Z_TEXT = 1;
//var Z_ASCII = 1; // = Z_TEXT
var Z_UNKNOWN = 2;
/* The deflate compression method */
var Z_DEFLATED = 8;
/*============================================================================*/
var MAX_MEM_LEVEL = 9;
/* Maximum value for memLevel in deflateInit2 */
var MAX_WBITS = 15;
/* 32K LZ77 window */
var DEF_MEM_LEVEL = 8;
var LENGTH_CODES = 29;
/* number of length codes, not counting the special END_BLOCK code */
var LITERALS = 256;
/* number of literal bytes 0..255 */
var L_CODES = LITERALS + 1 + LENGTH_CODES;
/* number of Literal or Length codes, including the END_BLOCK code */
var D_CODES = 30;
/* number of distance codes */
var BL_CODES = 19;
/* number of codes used to transfer the bit lengths */
var HEAP_SIZE = 2 * L_CODES + 1;
/* maximum heap size */
var MAX_BITS = 15;
/* All codes must not exceed MAX_BITS bits */
var MIN_MATCH = 3;
var MAX_MATCH = 258;
var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
var PRESET_DICT = 0x20;
var INIT_STATE = 42;
var EXTRA_STATE = 69;
var NAME_STATE = 73;
var COMMENT_STATE = 91;
var HCRC_STATE = 103;
var BUSY_STATE = 113;
var FINISH_STATE = 666;
var BS_NEED_MORE = 1; /* block not completed, need more input or more output */
var BS_BLOCK_DONE = 2; /* block flush performed */
var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
function err(strm, errorCode) {
strm.msg = msg[errorCode];
return errorCode;
}
function rank(f) {
return ((f) << 1) - ((f) > 4 ? 9 : 0);
}
function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
/* =========================================================================
* Flush as much pending output as possible. All deflate() output goes
* through this function so some applications may wish to modify it
* to avoid allocating a large strm->output buffer and copying into it.
* (See also read_buf()).
*/
function flush_pending(strm) {
var s = strm.state;
//_tr_flush_bits(s);
var len = s.pending;
if (len > strm.avail_out) {
len = strm.avail_out;
}
if (len === 0) { return; }
utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
strm.next_out += len;
s.pending_out += len;
strm.total_out += len;
strm.avail_out -= len;
s.pending -= len;
if (s.pending === 0) {
s.pending_out = 0;
}
}
function flush_block_only(s, last) {
trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
s.block_start = s.strstart;
flush_pending(s.strm);
}
function put_byte(s, b) {
s.pending_buf[s.pending++] = b;
}
/* =========================================================================
* Put a short in the pending buffer. The 16-bit value is put in MSB order.
* IN assertion: the stream state is correct and there is enough room in
* pending_buf.
*/
function putShortMSB(s, b) {
// put_byte(s, (Byte)(b >> 8));
// put_byte(s, (Byte)(b & 0xff));
s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
s.pending_buf[s.pending++] = b & 0xff;
}
/* ===========================================================================
* Read a new buffer from the current input stream, update the adler32
* and total number of bytes read. All deflate() input goes through
* this function so some applications may wish to modify it to avoid
* allocating a large strm->input buffer and copying from it.
* (See also flush_pending()).
*/
function read_buf(strm, buf, start, size) {
var len = strm.avail_in;
if (len > size) { len = size; }
if (len === 0) { return 0; }
strm.avail_in -= len;
// zmemcpy(buf, strm->next_in, len);
utils.arraySet(buf, strm.input, strm.next_in, len, start);
if (strm.state.wrap === 1) {
strm.adler = adler32(strm.adler, buf, len, start);
}
else if (strm.state.wrap === 2) {
strm.adler = crc32(strm.adler, buf, len, start);
}
strm.next_in += len;
strm.total_in += len;
return len;
}
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
* return its length. Matches shorter or equal to prev_length are discarded,
* in which case the result is equal to prev_length and match_start is
* garbage.
* IN assertions: cur_match is the head of the hash chain for the current
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
* OUT assertion: the match length is not greater than s->lookahead.
*/
function longest_match(s, cur_match) {
var chain_length = s.max_chain_length; /* max hash chain length */
var scan = s.strstart; /* current string */
var match; /* matched string */
var len; /* length of current match */
var best_len = s.prev_length; /* best match length so far */
var nice_match = s.nice_match; /* stop if match long enough */
var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
var _win = s.window; // shortcut
var wmask = s.w_mask;
var prev = s.prev;
/* Stop when cur_match becomes <= limit. To simplify the code,
* we prevent matches with the string of window index 0.
*/
var strend = s.strstart + MAX_MATCH;
var scan_end1 = _win[scan + best_len - 1];
var scan_end = _win[scan + best_len];
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
// Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
/* Do not waste too much time if we already have a good match: */
if (s.prev_length >= s.good_match) {
chain_length >>= 2;
}
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
if (nice_match > s.lookahead) { nice_match = s.lookahead; }
// Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
do {
// Assert(cur_match < s->strstart, "no future");
match = cur_match;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below
* for insufficient lookahead only occur occasionally for performance
* reasons. Therefore uninitialized memory will be accessed, and
* conditional jumps will be made that depend on those values.
* However the length of the match is limited to the lookahead, so
* the output of deflate is not affected by the uninitialized values.
*/
if (_win[match + best_len] !== scan_end ||
_win[match + best_len - 1] !== scan_end1 ||
_win[match] !== _win[scan] ||
_win[++match] !== _win[scan + 1]) {
continue;
}
/* The check at best_len-1 can be removed because it will be made
* again later. (This heuristic is not always a win.)
* It is not necessary to compare scan[2] and match[2] since they
* are always equal when the other bytes match, given that
* the hash keys are equal and that HASH_BITS >= 8.
*/
scan += 2;
match++;
// Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart+258.
*/
do {
/*jshint noempty:false*/
} while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
scan < strend);
// Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
len = MAX_MATCH - (strend - scan);
scan = strend - MAX_MATCH;
if (len > best_len) {
s.match_start = cur_match;
best_len = len;
if (len >= nice_match) {
break;
}
scan_end1 = _win[scan + best_len - 1];
scan_end = _win[scan + best_len];
}
} while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
if (best_len <= s.lookahead) {
return best_len;
}
return s.lookahead;
}
/* ===========================================================================
* Fill the window when the lookahead becomes insufficient.
* Updates strstart and lookahead.
*
* IN assertion: lookahead < MIN_LOOKAHEAD
* OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
* At least one byte has been read, or avail_in == 0; reads are
* performed for at least two bytes (required for the zip translate_eol
* option -- not supported here).
*/
function fill_window(s) {
var _w_size = s.w_size;
var p, n, m, more, str;
//Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
do {
more = s.window_size - s.lookahead - s.strstart;
// JS ints have 32 bit, block below not needed
/* Deal with !@#$% 64K limit: */
//if (sizeof(int) <= 2) {
// if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
// more = wsize;
//
// } else if (more == (unsigned)(-1)) {
// /* Very unlikely, but possible on 16 bit machine if
// * strstart == 0 && lookahead == 1 (input done a byte at time)
// */
// more--;
// }
//}
/* If the window is almost full and there is insufficient lookahead,
* move the upper half to the lower one to make room in the upper half.
*/
if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
s.match_start -= _w_size;
s.strstart -= _w_size;
/* we now have strstart >= MAX_DIST */
s.block_start -= _w_size;
/* Slide the hash table (could be avoided with 32 bit values
at the expense of memory usage). We slide even when level == 0
to keep the hash table consistent if we switch back to level > 0
later. (Using level 0 permanently is not an optimal usage of
zlib, so we don't care about this pathological case.)
*/
n = s.hash_size;
p = n;
do {
m = s.head[--p];
s.head[p] = (m >= _w_size ? m - _w_size : 0);
} while (--n);
n = _w_size;
p = n;
do {
m = s.prev[--p];
s.prev[p] = (m >= _w_size ? m - _w_size : 0);
/* If n is not on any hash chain, prev[n] is garbage but
* its value will never be used.
*/
} while (--n);
more += _w_size;
}
if (s.strm.avail_in === 0) {
break;
}
/* If there was no sliding:
* strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
* more == window_size - lookahead - strstart
* => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
* => more >= window_size - 2*WSIZE + 2
* In the BIG_MEM or MMAP case (not yet supported),
* window_size == input_size + MIN_LOOKAHEAD &&
* strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
* Otherwise, window_size == 2*WSIZE so more >= 2.
* If there was sliding, more >= WSIZE. So in all cases, more >= 2.
*/
//Assert(more >= 2, "more < 2");
n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
s.lookahead += n;
/* Initialize the hash value now that we have some input: */
if (s.lookahead + s.insert >= MIN_MATCH) {
str = s.strstart - s.insert;
s.ins_h = s.window[str];
/* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
//#if MIN_MATCH != 3
// Call update_hash() MIN_MATCH-3 more times
//#endif
while (s.insert) {
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
s.prev[str & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = str;
str++;
s.insert--;
if (s.lookahead + s.insert < MIN_MATCH) {
break;
}
}
}
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
* but this is not important since only literal bytes will be emitted.
*/
} while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
/* If the WIN_INIT bytes after the end of the current data have never been
* written, then zero those bytes in order to avoid memory check reports of
* the use of uninitialized (or uninitialised as Julian writes) bytes by
* the longest match routines. Update the high water mark for the next
* time through here. WIN_INIT is set to MAX_MATCH since the longest match
* routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
*/
// if (s.high_water < s.window_size) {
// var curr = s.strstart + s.lookahead;
// var init = 0;
//
// if (s.high_water < curr) {
// /* Previous high water mark below current data -- zero WIN_INIT
// * bytes or up to end of window, whichever is less.
// */
// init = s.window_size - curr;
// if (init > WIN_INIT)
// init = WIN_INIT;
// zmemzero(s->window + curr, (unsigned)init);
// s->high_water = curr + init;
// }
// else if (s->high_water < (ulg)curr + WIN_INIT) {
// /* High water mark at or above current data, but below current data
// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
// * to end of window, whichever is less.
// */
// init = (ulg)curr + WIN_INIT - s->high_water;
// if (init > s->window_size - s->high_water)
// init = s->window_size - s->high_water;
// zmemzero(s->window + s->high_water, (unsigned)init);
// s->high_water += init;
// }
// }
//
// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
// "not enough room for search");
}
/* ===========================================================================
* Copy without compression as much as possible from the input stream, return
* the current block state.
* This function does not insert new strings in the dictionary since
* uncompressible data is probably not useful. This function is used
* only for the level=0 compression option.
* NOTE: this function should be optimized to avoid extra copying from
* window to pending_buf.
*/
function deflate_stored(s, flush) {
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited
* to pending_buf_size, and each stored block has a 5 byte header:
*/
var max_block_size = 0xffff;
if (max_block_size > s.pending_buf_size - 5) {
max_block_size = s.pending_buf_size - 5;
}
/* Copy as much as possible from input to output: */
for (;;) {
/* Fill the window as much as possible: */
if (s.lookahead <= 1) {
//Assert(s->strstart < s->w_size+MAX_DIST(s) ||
// s->block_start >= (long)s->w_size, "slide too late");
// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
// s.block_start >= s.w_size)) {
// throw new Error("slide too late");
// }
fill_window(s);
if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) {
break;
}
/* flush the current block */
}
//Assert(s->block_start >= 0L, "block gone");
// if (s.block_start < 0) throw new Error("block gone");
s.strstart += s.lookahead;
s.lookahead = 0;
/* Emit a stored block if pending_buf will be full: */
var max_start = s.block_start + max_block_size;
if (s.strstart === 0 || s.strstart >= max_start) {
/* strstart == 0 is possible when wraparound on 16-bit machine */
s.lookahead = s.strstart - max_start;
s.strstart = max_start;
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
/* Flush if we may have to slide, otherwise block_start may become
* negative and the data will be gone:
*/
if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.strstart > s.block_start) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_NEED_MORE;
}
/* ===========================================================================
* Compress as much as possible from the input stream, return the current
* block state.
* This function does not perform lazy evaluation of matches and inserts
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
function deflate_fast(s, flush) {
var hash_head; /* head of the hash chain */
var bflush; /* set if current block must be flushed */
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s.lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) {
break; /* flush the current block */
}
}
/* Insert the string window[strstart .. strstart+2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = 0/*NIL*/;
if (s.lookahead >= MIN_MATCH) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match_length < MIN_MATCH
*/
if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
s.match_length = longest_match(s, hash_head);
/* longest_match() sets match_start */
}
if (s.match_length >= MIN_MATCH) {
// check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
/*** _tr_tally_dist(s, s.strstart - s.match_start,
s.match_length - MIN_MATCH, bflush); ***/
bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
s.lookahead -= s.match_length;
/* Insert new strings in the hash table only if the match length
* is not too large. This saves time but degrades compression.
*/
if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
s.match_length--; /* string at strstart already in table */
do {
s.strstart++;
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
/* strstart never exceeds WSIZE-MAX_MATCH, so there are
* always MIN_MATCH bytes ahead.
*/
} while (--s.match_length !== 0);
s.strstart++;
} else
{
s.strstart += s.match_length;
s.match_length = 0;
s.ins_h = s.window[s.strstart];
/* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
//#if MIN_MATCH != 3
// Call UPDATE_HASH() MIN_MATCH-3 more times
//#endif
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
* matter since it will be recomputed at next deflate call.
*/
}
} else {
/* No match, output a literal byte */
//Tracevv((stderr,"%c", s.window[s.strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
}
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* Same as above, but achieves better compression. We use a lazy
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
function deflate_slow(s, flush) {
var hash_head; /* head of hash chain */
var bflush; /* set if current block must be flushed */
var max_insert;
/* Process the input block. */
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s.lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) { break; } /* flush the current block */
}
/* Insert the string window[strstart .. strstart+2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = 0/*NIL*/;
if (s.lookahead >= MIN_MATCH) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
/* Find the longest match, discarding those <= prev_length.
*/
s.prev_length = s.match_length;
s.prev_match = s.match_start;
s.match_length = MIN_MATCH - 1;
if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
s.match_length = longest_match(s, hash_head);
/* longest_match() sets match_start */
if (s.match_length <= 5 &&
(s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
/* If prev_match is also MIN_MATCH, match_start is garbage
* but we will ignore the current match anyway.
*/
s.match_length = MIN_MATCH - 1;
}
}
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
max_insert = s.strstart + s.lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
//check_match(s, s.strstart-1, s.prev_match, s.prev_length);
/***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
s.prev_length - MIN_MATCH, bflush);***/
bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
/* Insert in hash table all strings up to the end of the match.
* strstart-1 and strstart are already inserted. If there is not
* enough lookahead, the last two strings are not inserted in
* the hash table.
*/
s.lookahead -= s.prev_length - 1;
s.prev_length -= 2;
do {
if (++s.strstart <= max_insert) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
} while (--s.prev_length !== 0);
s.match_available = 0;
s.match_length = MIN_MATCH - 1;
s.strstart++;
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
} else if (s.match_available) {
/* If there was no match at the previous position, output a
* single literal. If there was a match but the current match
* is longer, truncate the previous match to a single literal.
*/
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
if (bflush) {
/*** FLUSH_BLOCK_ONLY(s, 0) ***/
flush_block_only(s, false);
/***/
}
s.strstart++;
s.lookahead--;
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
} else {
/* There is no previous match to compare with, wait for
* the next step to decide.
*/
s.match_available = 1;
s.strstart++;
s.lookahead--;
}
}
//Assert (flush != Z_NO_FLUSH, "no flush?");
if (s.match_available) {
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
s.match_available = 0;
}
s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* For Z_RLE, simply look for runs of bytes, generate matches only of distance
* one. Do not maintain a hash table. (It will be regenerated if this run of
* deflate switches away from Z_RLE.)
*/
function deflate_rle(s, flush) {
var bflush; /* set if current block must be flushed */
var prev; /* byte at distance one to match */
var scan, strend; /* scan goes up to strend for length of run */
var _win = s.window;
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the longest run, plus one for the unrolled loop.
*/
if (s.lookahead <= MAX_MATCH) {
fill_window(s);
if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) { break; } /* flush the current block */
}
/* See how many times the previous byte repeats */
s.match_length = 0;
if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
scan = s.strstart - 1;
prev = _win[scan];
if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
strend = s.strstart + MAX_MATCH;
do {
/*jshint noempty:false*/
} while (prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
scan < strend);
s.match_length = MAX_MATCH - (strend - scan);
if (s.match_length > s.lookahead) {
s.match_length = s.lookahead;
}
}
//Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
}
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
if (s.match_length >= MIN_MATCH) {
//check_match(s, s.strstart, s.strstart - 1, s.match_length);
/*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
s.lookahead -= s.match_length;
s.strstart += s.match_length;
s.match_length = 0;
} else {
/* No match, output a literal byte */
//Tracevv((stderr,"%c", s->window[s->strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
}
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
* (It will be regenerated if this run of deflate switches away from Huffman.)
*/
function deflate_huff(s, flush) {
var bflush; /* set if current block must be flushed */
for (;;) {
/* Make sure that we have a literal to write. */
if (s.lookahead === 0) {
fill_window(s);
if (s.lookahead === 0) {
if (flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
break; /* flush the current block */
}
}
/* Output a literal byte */
s.match_length = 0;
//Tracevv((stderr,"%c", s->window[s->strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* Values for max_lazy_match, good_match and max_chain_length, depending on
* the desired pack level (0..9). The values given below have been tuned to
* exclude worst case performance for pathological files. Better values may be
* found for specific files.
*/
function Config(good_length, max_lazy, nice_length, max_chain, func) {
this.good_length = good_length;
this.max_lazy = max_lazy;
this.nice_length = nice_length;
this.max_chain = max_chain;
this.func = func;
}
var configuration_table;
configuration_table = [
/* good lazy nice chain */
new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
new Config(4, 5, 16, 8, deflate_fast), /* 2 */
new Config(4, 6, 32, 32, deflate_fast), /* 3 */
new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
new Config(8, 16, 32, 32, deflate_slow), /* 5 */
new Config(8, 16, 128, 128, deflate_slow), /* 6 */
new Config(8, 32, 128, 256, deflate_slow), /* 7 */
new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
];
/* ===========================================================================
* Initialize the "longest match" routines for a new zlib stream
*/
function lm_init(s) {
s.window_size = 2 * s.w_size;
/*** CLEAR_HASH(s); ***/
zero(s.head); // Fill with NIL (= 0);
/* Set the default configuration parameters:
*/
s.max_lazy_match = configuration_table[s.level].max_lazy;
s.good_match = configuration_table[s.level].good_length;
s.nice_match = configuration_table[s.level].nice_length;
s.max_chain_length = configuration_table[s.level].max_chain;
s.strstart = 0;
s.block_start = 0;
s.lookahead = 0;
s.insert = 0;
s.match_length = s.prev_length = MIN_MATCH - 1;
s.match_available = 0;
s.ins_h = 0;
}
function DeflateState() {
this.strm = null; /* pointer back to this zlib stream */
this.status = 0; /* as the name implies */
this.pending_buf = null; /* output still pending */
this.pending_buf_size = 0; /* size of pending_buf */
this.pending_out = 0; /* next pending byte to output to the stream */
this.pending = 0; /* nb of bytes in the pending buffer */
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
this.gzhead = null; /* gzip header information to write */
this.gzindex = 0; /* where in extra, name, or comment */
this.method = Z_DEFLATED; /* can only be DEFLATED */
this.last_flush = -1; /* value of flush param for previous deflate call */
this.w_size = 0; /* LZ77 window size (32K by default) */
this.w_bits = 0; /* log2(w_size) (8..16) */
this.w_mask = 0; /* w_size - 1 */
this.window = null;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size.
*/
this.window_size = 0;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
this.prev = null;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
this.head = null; /* Heads of the hash chains or NIL. */
this.ins_h = 0; /* hash index of string to be inserted */
this.hash_size = 0; /* number of elements in hash table */
this.hash_bits = 0; /* log2(hash_size) */
this.hash_mask = 0; /* hash_size-1 */
this.hash_shift = 0;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
this.block_start = 0;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
this.match_length = 0; /* length of best match */
this.prev_match = 0; /* previous match */
this.match_available = 0; /* set if previous match exists */
this.strstart = 0; /* start of string to insert */
this.match_start = 0; /* start of matching string */
this.lookahead = 0; /* number of valid bytes ahead in window */
this.prev_length = 0;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
this.max_chain_length = 0;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
this.max_lazy_match = 0;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
// That's alias to max_lazy_match, don't use directly
//this.max_insert_length = 0;
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
this.level = 0; /* compression level (1..9) */
this.strategy = 0; /* favor or force Huffman coding*/
this.good_match = 0;
/* Use a faster search when the previous match is longer than this */
this.nice_match = 0; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to suppress compiler warning */
// struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
// struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
// struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
// Use flat array of DOUBLE size, with interleaved fata,
// because JS does not support effective
this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);
this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2);
this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2);
zero(this.dyn_ltree);
zero(this.dyn_dtree);
zero(this.bl_tree);
this.l_desc = null; /* desc. for literal tree */
this.d_desc = null; /* desc. for distance tree */
this.bl_desc = null; /* desc. for bit length tree */
//ush bl_count[MAX_BITS+1];
this.bl_count = new utils.Buf16(MAX_BITS + 1);
/* number of codes at each bit length for an optimal tree */
//int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */
zero(this.heap);
this.heap_len = 0; /* number of elements in the heap */
this.heap_max = 0; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
zero(this.depth);
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
this.l_buf = 0; /* buffer index for literals or lengths */
this.lit_bufsize = 0;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
this.last_lit = 0; /* running index in l_buf */
this.d_buf = 0;
/* Buffer index for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
this.opt_len = 0; /* bit length of current block with optimal trees */
this.static_len = 0; /* bit length of current block with static trees */
this.matches = 0; /* number of string matches in current block */
this.insert = 0; /* bytes at end of window left to insert */
this.bi_buf = 0;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
this.bi_valid = 0;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
// Used for window memory init. We safely ignore it for JS. That makes
// sense only for pointers and memory check tools.
//this.high_water = 0;
/* High water mark offset in window for initialized bytes -- bytes above
* this are set to zero in order to avoid memory check warnings when
* longest match routines access bytes past the input. This is then
* updated to the new high water mark.
*/
}
function deflateResetKeep(strm) {
var s;
if (!strm || !strm.state) {
return err(strm, Z_STREAM_ERROR);
}
strm.total_in = strm.total_out = 0;
strm.data_type = Z_UNKNOWN;
s = strm.state;
s.pending = 0;
s.pending_out = 0;
if (s.wrap < 0) {
s.wrap = -s.wrap;
/* was made negative by deflate(..., Z_FINISH); */
}
s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
strm.adler = (s.wrap === 2) ?
0 // crc32(0, Z_NULL, 0)
:
1; // adler32(0, Z_NULL, 0)
s.last_flush = Z_NO_FLUSH;
trees._tr_init(s);
return Z_OK;
}
function deflateReset(strm) {
var ret = deflateResetKeep(strm);
if (ret === Z_OK) {
lm_init(strm.state);
}
return ret;
}
function deflateSetHeader(strm, head) {
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
strm.state.gzhead = head;
return Z_OK;
}
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
if (!strm) { // === Z_NULL
return Z_STREAM_ERROR;
}
var wrap = 1;
if (level === Z_DEFAULT_COMPRESSION) {
level = 6;
}
if (windowBits < 0) { /* suppress zlib wrapper */
wrap = 0;
windowBits = -windowBits;
}
else if (windowBits > 15) {
wrap = 2; /* write gzip wrapper instead */
windowBits -= 16;
}
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
strategy < 0 || strategy > Z_FIXED) {
return err(strm, Z_STREAM_ERROR);
}
if (windowBits === 8) {
windowBits = 9;
}
/* until 256-byte window bug fixed */
var s = new DeflateState();
strm.state = s;
s.strm = strm;
s.wrap = wrap;
s.gzhead = null;
s.w_bits = windowBits;
s.w_size = 1 << s.w_bits;
s.w_mask = s.w_size - 1;
s.hash_bits = memLevel + 7;
s.hash_size = 1 << s.hash_bits;
s.hash_mask = s.hash_size - 1;
s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
s.window = new utils.Buf8(s.w_size * 2);
s.head = new utils.Buf16(s.hash_size);
s.prev = new utils.Buf16(s.w_size);
// Don't need mem init magic for JS.
//s.high_water = 0; /* nothing written to s->window yet */
s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
s.pending_buf_size = s.lit_bufsize * 4;
//overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
//s->pending_buf = (uchf *) overlay;
s.pending_buf = new utils.Buf8(s.pending_buf_size);
// It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
//s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
s.d_buf = 1 * s.lit_bufsize;
//s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
s.l_buf = (1 + 2) * s.lit_bufsize;
s.level = level;
s.strategy = strategy;
s.method = method;
return deflateReset(strm);
}
function deflateInit(strm, level) {
return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
}
function deflate(strm, flush) {
var old_flush, s;
var beg, val; // for gzip header write only
if (!strm || !strm.state ||
flush > Z_BLOCK || flush < 0) {
return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
}
s = strm.state;
if (!strm.output ||
(!strm.input && strm.avail_in !== 0) ||
(s.status === FINISH_STATE && flush !== Z_FINISH)) {
return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
}
s.strm = strm; /* just in case */
old_flush = s.last_flush;
s.last_flush = flush;
/* Write the header */
if (s.status === INIT_STATE) {
if (s.wrap === 2) { // GZIP header
strm.adler = 0; //crc32(0L, Z_NULL, 0);
put_byte(s, 31);
put_byte(s, 139);
put_byte(s, 8);
if (!s.gzhead) { // s->gzhead == Z_NULL
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, s.level === 9 ? 2 :
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
4 : 0));
put_byte(s, OS_CODE);
s.status = BUSY_STATE;
}
else {
put_byte(s, (s.gzhead.text ? 1 : 0) +
(s.gzhead.hcrc ? 2 : 0) +
(!s.gzhead.extra ? 0 : 4) +
(!s.gzhead.name ? 0 : 8) +
(!s.gzhead.comment ? 0 : 16)
);
put_byte(s, s.gzhead.time & 0xff);
put_byte(s, (s.gzhead.time >> 8) & 0xff);
put_byte(s, (s.gzhead.time >> 16) & 0xff);
put_byte(s, (s.gzhead.time >> 24) & 0xff);
put_byte(s, s.level === 9 ? 2 :
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
4 : 0));
put_byte(s, s.gzhead.os & 0xff);
if (s.gzhead.extra && s.gzhead.extra.length) {
put_byte(s, s.gzhead.extra.length & 0xff);
put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
}
if (s.gzhead.hcrc) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
}
s.gzindex = 0;
s.status = EXTRA_STATE;
}
}
else // DEFLATE header
{
var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
var level_flags = -1;
if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
level_flags = 0;
} else if (s.level < 6) {
level_flags = 1;
} else if (s.level === 6) {
level_flags = 2;
} else {
level_flags = 3;
}
header |= (level_flags << 6);
if (s.strstart !== 0) { header |= PRESET_DICT; }
header += 31 - (header % 31);
s.status = BUSY_STATE;
putShortMSB(s, header);
/* Save the adler32 of the preset dictionary: */
if (s.strstart !== 0) {
putShortMSB(s, strm.adler >>> 16);
putShortMSB(s, strm.adler & 0xffff);
}
strm.adler = 1; // adler32(0L, Z_NULL, 0);
}
}
//#ifdef GZIP
if (s.status === EXTRA_STATE) {
if (s.gzhead.extra/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
break;
}
}
put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
s.gzindex++;
}
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (s.gzindex === s.gzhead.extra.length) {
s.gzindex = 0;
s.status = NAME_STATE;
}
}
else {
s.status = NAME_STATE;
}
}
if (s.status === NAME_STATE) {
if (s.gzhead.name/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
//int val;
do {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
val = 1;
break;
}
}
// JS specific: little magic to add zero terminator to end of string
if (s.gzindex < s.gzhead.name.length) {
val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
} else {
val = 0;
}
put_byte(s, val);
} while (val !== 0);
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (val === 0) {
s.gzindex = 0;
s.status = COMMENT_STATE;
}
}
else {
s.status = COMMENT_STATE;
}
}
if (s.status === COMMENT_STATE) {
if (s.gzhead.comment/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
//int val;
do {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
val = 1;
break;
}
}
// JS specific: little magic to add zero terminator to end of string
if (s.gzindex < s.gzhead.comment.length) {
val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
} else {
val = 0;
}
put_byte(s, val);
} while (val !== 0);
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (val === 0) {
s.status = HCRC_STATE;
}
}
else {
s.status = HCRC_STATE;
}
}
if (s.status === HCRC_STATE) {
if (s.gzhead.hcrc) {
if (s.pending + 2 > s.pending_buf_size) {
flush_pending(strm);
}
if (s.pending + 2 <= s.pending_buf_size) {
put_byte(s, strm.adler & 0xff);
put_byte(s, (strm.adler >> 8) & 0xff);
strm.adler = 0; //crc32(0L, Z_NULL, 0);
s.status = BUSY_STATE;
}
}
else {
s.status = BUSY_STATE;
}
}
//#endif
/* Flush as much pending output as possible */
if (s.pending !== 0) {
flush_pending(strm);
if (strm.avail_out === 0) {
/* Since avail_out is 0, deflate will be called again with
* more output space, but possibly with both pending and
* avail_in equal to zero. There won't be anything to do,
* but this is not an error situation so make sure we
* return OK instead of BUF_ERROR at next call of deflate:
*/
s.last_flush = -1;
return Z_OK;
}
/* Make sure there is something to do and avoid duplicate consecutive
* flushes. For repeated and useless calls with Z_FINISH, we keep
* returning Z_STREAM_END instead of Z_BUF_ERROR.
*/
} else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
flush !== Z_FINISH) {
return err(strm, Z_BUF_ERROR);
}
/* User must not provide more input after the first FINISH: */
if (s.status === FINISH_STATE && strm.avail_in !== 0) {
return err(strm, Z_BUF_ERROR);
}
/* Start a new block or continue the current one.
*/
if (strm.avail_in !== 0 || s.lookahead !== 0 ||
(flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
(s.strategy === Z_RLE ? deflate_rle(s, flush) :
configuration_table[s.level].func(s, flush));
if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
s.status = FINISH_STATE;
}
if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
if (strm.avail_out === 0) {
s.last_flush = -1;
/* avoid BUF_ERROR next call, see above */
}
return Z_OK;
/* If flush != Z_NO_FLUSH && avail_out == 0, the next call
* of deflate should use the same flush parameter to make sure
* that the flush is complete. So we don't have to output an
* empty block here, this will be done at next call. This also
* ensures that for a very small output buffer, we emit at most
* one empty block.
*/
}
if (bstate === BS_BLOCK_DONE) {
if (flush === Z_PARTIAL_FLUSH) {
trees._tr_align(s);
}
else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
trees._tr_stored_block(s, 0, 0, false);
/* For a full flush, this empty block will be recognized
* as a special marker by inflate_sync().
*/
if (flush === Z_FULL_FLUSH) {
/*** CLEAR_HASH(s); ***/ /* forget history */
zero(s.head); // Fill with NIL (= 0);
if (s.lookahead === 0) {
s.strstart = 0;
s.block_start = 0;
s.insert = 0;
}
}
}
flush_pending(strm);
if (strm.avail_out === 0) {
s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
return Z_OK;
}
}
}
//Assert(strm->avail_out > 0, "bug2");
//if (strm.avail_out <= 0) { throw new Error("bug2");}
if (flush !== Z_FINISH) { return Z_OK; }
if (s.wrap <= 0) { return Z_STREAM_END; }
/* Write the trailer */
if (s.wrap === 2) {
put_byte(s, strm.adler & 0xff);
put_byte(s, (strm.adler >> 8) & 0xff);
put_byte(s, (strm.adler >> 16) & 0xff);
put_byte(s, (strm.adler >> 24) & 0xff);
put_byte(s, strm.total_in & 0xff);
put_byte(s, (strm.total_in >> 8) & 0xff);
put_byte(s, (strm.total_in >> 16) & 0xff);
put_byte(s, (strm.total_in >> 24) & 0xff);
}
else
{
putShortMSB(s, strm.adler >>> 16);
putShortMSB(s, strm.adler & 0xffff);
}
flush_pending(strm);
/* If avail_out is zero, the application will call deflate again
* to flush the rest.
*/
if (s.wrap > 0) { s.wrap = -s.wrap; }
/* write the trailer only once! */
return s.pending !== 0 ? Z_OK : Z_STREAM_END;
}
function deflateEnd(strm) {
var status;
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
return Z_STREAM_ERROR;
}
status = strm.state.status;
if (status !== INIT_STATE &&
status !== EXTRA_STATE &&
status !== NAME_STATE &&
status !== COMMENT_STATE &&
status !== HCRC_STATE &&
status !== BUSY_STATE &&
status !== FINISH_STATE
) {
return err(strm, Z_STREAM_ERROR);
}
strm.state = null;
return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
}
/* =========================================================================
* Initializes the compression dictionary from the given byte
* sequence without producing any compressed output.
*/
function deflateSetDictionary(strm, dictionary) {
var dictLength = dictionary.length;
var s;
var str, n;
var wrap;
var avail;
var next;
var input;
var tmpDict;
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
return Z_STREAM_ERROR;
}
s = strm.state;
wrap = s.wrap;
if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
return Z_STREAM_ERROR;
}
/* when using zlib wrappers, compute Adler-32 for provided dictionary */
if (wrap === 1) {
/* adler32(strm->adler, dictionary, dictLength); */
strm.adler = adler32(strm.adler, dictionary, dictLength, 0);
}
s.wrap = 0; /* avoid computing Adler-32 in read_buf */
/* if dictionary would fill window, just replace the history */
if (dictLength >= s.w_size) {
if (wrap === 0) { /* already empty otherwise */
/*** CLEAR_HASH(s); ***/
zero(s.head); // Fill with NIL (= 0);
s.strstart = 0;
s.block_start = 0;
s.insert = 0;
}
/* use the tail */
// dictionary = dictionary.slice(dictLength - s.w_size);
tmpDict = new utils.Buf8(s.w_size);
utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);
dictionary = tmpDict;
dictLength = s.w_size;
}
/* insert dictionary into window and hash */
avail = strm.avail_in;
next = strm.next_in;
input = strm.input;
strm.avail_in = dictLength;
strm.next_in = 0;
strm.input = dictionary;
fill_window(s);
while (s.lookahead >= MIN_MATCH) {
str = s.strstart;
n = s.lookahead - (MIN_MATCH - 1);
do {
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
s.prev[str & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = str;
str++;
} while (--n);
s.strstart = str;
s.lookahead = MIN_MATCH - 1;
fill_window(s);
}
s.strstart += s.lookahead;
s.block_start = s.strstart;
s.insert = s.lookahead;
s.lookahead = 0;
s.match_length = s.prev_length = MIN_MATCH - 1;
s.match_available = 0;
strm.next_in = next;
strm.input = input;
strm.avail_in = avail;
s.wrap = wrap;
return Z_OK;
}
exports.deflateInit = deflateInit;
exports.deflateInit2 = deflateInit2;
exports.deflateReset = deflateReset;
exports.deflateResetKeep = deflateResetKeep;
exports.deflateSetHeader = deflateSetHeader;
exports.deflate = deflate;
exports.deflateEnd = deflateEnd;
exports.deflateSetDictionary = deflateSetDictionary;
exports.deflateInfo = 'pako deflate (from Nodeca project)';
/* Not implemented
exports.deflateBound = deflateBound;
exports.deflateCopy = deflateCopy;
exports.deflateParams = deflateParams;
exports.deflatePending = deflatePending;
exports.deflatePrime = deflatePrime;
exports.deflateTune = deflateTune;
*/
},{"../utils/common":105,"./adler32":107,"./crc32":109,"./messages":115,"./trees":116}],111:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
function GZheader() {
/* true if compressed data believed to be text */
this.text = 0;
/* modification time */
this.time = 0;
/* extra flags (not used when writing a gzip file) */
this.xflags = 0;
/* operating system */
this.os = 0;
/* pointer to extra field or Z_NULL if none */
this.extra = null;
/* extra field length (valid if extra != Z_NULL) */
this.extra_len = 0; // Actually, we don't need it in JS,
// but leave for few code modifications
//
// Setup limits is not necessary because in js we should not preallocate memory
// for inflate use constant limit in 65536 bytes
//
/* space at extra (only when reading header) */
// this.extra_max = 0;
/* pointer to zero-terminated file name or Z_NULL */
this.name = '';
/* space at name (only when reading header) */
// this.name_max = 0;
/* pointer to zero-terminated comment or Z_NULL */
this.comment = '';
/* space at comment (only when reading header) */
// this.comm_max = 0;
/* true if there was or will be a header crc */
this.hcrc = 0;
/* true when done reading gzip header (not used when writing a gzip file) */
this.done = false;
}
module.exports = GZheader;
},{}],112:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// See state defs from inflate.js
var BAD = 30; /* got a data error -- remain here until reset */
var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
/*
Decode literal, length, and distance codes and write out the resulting
literal and match bytes until either not enough input or output is
available, an end-of-block is encountered, or a data error is encountered.
When large enough input and output buffers are supplied to inflate(), for
example, a 16K input buffer and a 64K output buffer, more than 95% of the
inflate execution time is spent in this routine.
Entry assumptions:
state.mode === LEN
strm.avail_in >= 6
strm.avail_out >= 258
start >= strm.avail_out
state.bits < 8
On return, state.mode is one of:
LEN -- ran out of enough output space or enough available input
TYPE -- reached end of block code, inflate() to interpret next block
BAD -- error in block data
Notes:
- The maximum input bits used by a length/distance pair is 15 bits for the
length code, 5 bits for the length extra, 15 bits for the distance code,
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
Therefore if strm.avail_in >= 6, then there is enough input to avoid
checking for available input while decoding.
- The maximum bytes that a single length/distance pair can output is 258
bytes, which is the maximum length that can be coded. inflate_fast()
requires strm.avail_out >= 258 for each loop to avoid checking for
output space.
*/
module.exports = function inflate_fast(strm, start) {
var state;
var _in; /* local strm.input */
var last; /* have enough input while in < last */
var _out; /* local strm.output */
var beg; /* inflate()'s initial strm.output */
var end; /* while out < end, enough space available */
//#ifdef INFLATE_STRICT
var dmax; /* maximum distance from zlib header */
//#endif
var wsize; /* window size or zero if not using window */
var whave; /* valid bytes in the window */
var wnext; /* window write index */
// Use `s_window` instead `window`, avoid conflict with instrumentation tools
var s_window; /* allocated sliding window, if wsize != 0 */
var hold; /* local strm.hold */
var bits; /* local strm.bits */
var lcode; /* local strm.lencode */
var dcode; /* local strm.distcode */
var lmask; /* mask for first level of length codes */
var dmask; /* mask for first level of distance codes */
var here; /* retrieved table entry */
var op; /* code bits, operation, extra bits, or */
/* window position, window bytes to copy */
var len; /* match length, unused bytes */
var dist; /* match distance */
var from; /* where to copy match from */
var from_source;
var input, output; // JS specific, because we have no pointers
/* copy state to local variables */
state = strm.state;
//here = state.here;
_in = strm.next_in;
input = strm.input;
last = _in + (strm.avail_in - 5);
_out = strm.next_out;
output = strm.output;
beg = _out - (start - strm.avail_out);
end = _out + (strm.avail_out - 257);
//#ifdef INFLATE_STRICT
dmax = state.dmax;
//#endif
wsize = state.wsize;
whave = state.whave;
wnext = state.wnext;
s_window = state.window;
hold = state.hold;
bits = state.bits;
lcode = state.lencode;
dcode = state.distcode;
lmask = (1 << state.lenbits) - 1;
dmask = (1 << state.distbits) - 1;
/* decode literals and length/distances until end-of-block or not enough
input data or output space */
top:
do {
if (bits < 15) {
hold += input[_in++] << bits;
bits += 8;
hold += input[_in++] << bits;
bits += 8;
}
here = lcode[hold & lmask];
dolen:
for (;;) { // Goto emulation
op = here >>> 24/*here.bits*/;
hold >>>= op;
bits -= op;
op = (here >>> 16) & 0xff/*here.op*/;
if (op === 0) { /* literal */
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
// "inflate: literal '%c'\n" :
// "inflate: literal 0x%02x\n", here.val));
output[_out++] = here & 0xffff/*here.val*/;
}
else if (op & 16) { /* length base */
len = here & 0xffff/*here.val*/;
op &= 15; /* number of extra bits */
if (op) {
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
}
len += hold & ((1 << op) - 1);
hold >>>= op;
bits -= op;
}
//Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) {
hold += input[_in++] << bits;
bits += 8;
hold += input[_in++] << bits;
bits += 8;
}
here = dcode[hold & dmask];
dodist:
for (;;) { // goto emulation
op = here >>> 24/*here.bits*/;
hold >>>= op;
bits -= op;
op = (here >>> 16) & 0xff/*here.op*/;
if (op & 16) { /* distance base */
dist = here & 0xffff/*here.val*/;
op &= 15; /* number of extra bits */
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
}
}
dist += hold & ((1 << op) - 1);
//#ifdef INFLATE_STRICT
if (dist > dmax) {
strm.msg = 'invalid distance too far back';
state.mode = BAD;
break top;
}
//#endif
hold >>>= op;
bits -= op;
//Tracevv((stderr, "inflate: distance %u\n", dist));
op = _out - beg; /* max distance in output */
if (dist > op) { /* see if copy from window */
op = dist - op; /* distance back in window */
if (op > whave) {
if (state.sane) {
strm.msg = 'invalid distance too far back';
state.mode = BAD;
break top;
}
// (!) This block is disabled in zlib defaults,
// don't enable it for binary compatibility
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
// if (len <= op - whave) {
// do {
// output[_out++] = 0;
// } while (--len);
// continue top;
// }
// len -= op - whave;
// do {
// output[_out++] = 0;
// } while (--op > whave);
// if (op === 0) {
// from = _out - dist;
// do {
// output[_out++] = output[from++];
// } while (--len);
// continue top;
// }
//#endif
}
from = 0; // window index
from_source = s_window;
if (wnext === 0) { /* very common case */
from += wsize - op;
if (op < len) { /* some from window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
}
else if (wnext < op) { /* wrap around window */
from += wsize + wnext - op;
op -= wnext;
if (op < len) { /* some from end of window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = 0;
if (wnext < len) { /* some from start of window */
op = wnext;
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
}
}
else { /* contiguous in window */
from += wnext - op;
if (op < len) { /* some from window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
}
while (len > 2) {
output[_out++] = from_source[from++];
output[_out++] = from_source[from++];
output[_out++] = from_source[from++];
len -= 3;
}
if (len) {
output[_out++] = from_source[from++];
if (len > 1) {
output[_out++] = from_source[from++];
}
}
}
else {
from = _out - dist; /* copy direct from output */
do { /* minimum length is three */
output[_out++] = output[from++];
output[_out++] = output[from++];
output[_out++] = output[from++];
len -= 3;
} while (len > 2);
if (len) {
output[_out++] = output[from++];
if (len > 1) {
output[_out++] = output[from++];
}
}
}
}
else if ((op & 64) === 0) { /* 2nd level distance code */
here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
continue dodist;
}
else {
strm.msg = 'invalid distance code';
state.mode = BAD;
break top;
}
break; // need to emulate goto via "continue"
}
}
else if ((op & 64) === 0) { /* 2nd level length code */
here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
continue dolen;
}
else if (op & 32) { /* end-of-block */
//Tracevv((stderr, "inflate: end of block\n"));
state.mode = TYPE;
break top;
}
else {
strm.msg = 'invalid literal/length code';
state.mode = BAD;
break top;
}
break; // need to emulate goto via "continue"
}
} while (_in < last && _out < end);
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
len = bits >> 3;
_in -= len;
bits -= len << 3;
hold &= (1 << bits) - 1;
/* update state and return */
strm.next_in = _in;
strm.next_out = _out;
strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
state.hold = hold;
state.bits = bits;
return;
};
},{}],113:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
var utils = require('../utils/common');
var adler32 = require('./adler32');
var crc32 = require('./crc32');
var inflate_fast = require('./inffast');
var inflate_table = require('./inftrees');
var CODES = 0;
var LENS = 1;
var DISTS = 2;
/* Public constants ==========================================================*/
/* ===========================================================================*/
/* Allowed flush values; see deflate() and inflate() below for details */
//var Z_NO_FLUSH = 0;
//var Z_PARTIAL_FLUSH = 1;
//var Z_SYNC_FLUSH = 2;
//var Z_FULL_FLUSH = 3;
var Z_FINISH = 4;
var Z_BLOCK = 5;
var Z_TREES = 6;
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
var Z_OK = 0;
var Z_STREAM_END = 1;
var Z_NEED_DICT = 2;
//var Z_ERRNO = -1;
var Z_STREAM_ERROR = -2;
var Z_DATA_ERROR = -3;
var Z_MEM_ERROR = -4;
var Z_BUF_ERROR = -5;
//var Z_VERSION_ERROR = -6;
/* The deflate compression method */
var Z_DEFLATED = 8;
/* STATES ====================================================================*/
/* ===========================================================================*/
var HEAD = 1; /* i: waiting for magic header */
var FLAGS = 2; /* i: waiting for method and flags (gzip) */
var TIME = 3; /* i: waiting for modification time (gzip) */
var OS = 4; /* i: waiting for extra flags and operating system (gzip) */
var EXLEN = 5; /* i: waiting for extra length (gzip) */
var EXTRA = 6; /* i: waiting for extra bytes (gzip) */
var NAME = 7; /* i: waiting for end of file name (gzip) */
var COMMENT = 8; /* i: waiting for end of comment (gzip) */
var HCRC = 9; /* i: waiting for header crc (gzip) */
var DICTID = 10; /* i: waiting for dictionary check value */
var DICT = 11; /* waiting for inflateSetDictionary() call */
var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
var STORED = 14; /* i: waiting for stored size (length and complement) */
var COPY_ = 15; /* i/o: same as COPY below, but only first time in */
var COPY = 16; /* i/o: waiting for input or output to copy stored block */
var TABLE = 17; /* i: waiting for dynamic block table lengths */
var LENLENS = 18; /* i: waiting for code length code lengths */
var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
var LEN_ = 20; /* i: same as LEN below, but only first time in */
var LEN = 21; /* i: waiting for length/lit/eob code */
var LENEXT = 22; /* i: waiting for length extra bits */
var DIST = 23; /* i: waiting for distance code */
var DISTEXT = 24; /* i: waiting for distance extra bits */
var MATCH = 25; /* o: waiting for output space to copy string */
var LIT = 26; /* o: waiting for output space to write literal */
var CHECK = 27; /* i: waiting for 32-bit check value */
var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
var DONE = 29; /* finished check, done -- remain here until reset */
var BAD = 30; /* got a data error -- remain here until reset */
var MEM = 31; /* got an inflate() memory error -- remain here until reset */
var SYNC = 32; /* looking for synchronization bytes to restart inflate() */
/* ===========================================================================*/
var ENOUGH_LENS = 852;
var ENOUGH_DISTS = 592;
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
var MAX_WBITS = 15;
/* 32K LZ77 window */
var DEF_WBITS = MAX_WBITS;
function zswap32(q) {
return (((q >>> 24) & 0xff) +
((q >>> 8) & 0xff00) +
((q & 0xff00) << 8) +
((q & 0xff) << 24));
}
function InflateState() {
this.mode = 0; /* current inflate mode */
this.last = false; /* true if processing last block */
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
this.havedict = false; /* true if dictionary provided */
this.flags = 0; /* gzip header method and flags (0 if zlib) */
this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
this.check = 0; /* protected copy of check value */
this.total = 0; /* protected copy of output count */
// TODO: may be {}
this.head = null; /* where to save gzip header information */
/* sliding window */
this.wbits = 0; /* log base 2 of requested window size */
this.wsize = 0; /* window size or zero if not using window */
this.whave = 0; /* valid bytes in the window */
this.wnext = 0; /* window write index */
this.window = null; /* allocated sliding window, if needed */
/* bit accumulator */
this.hold = 0; /* input bit accumulator */
this.bits = 0; /* number of bits in "in" */
/* for string and stored block copying */
this.length = 0; /* literal or length of data to copy */
this.offset = 0; /* distance back to copy string from */
/* for table and code decoding */
this.extra = 0; /* extra bits needed */
/* fixed and dynamic code tables */
this.lencode = null; /* starting table for length/literal codes */
this.distcode = null; /* starting table for distance codes */
this.lenbits = 0; /* index bits for lencode */
this.distbits = 0; /* index bits for distcode */
/* dynamic table building */
this.ncode = 0; /* number of code length code lengths */
this.nlen = 0; /* number of length code lengths */
this.ndist = 0; /* number of distance code lengths */
this.have = 0; /* number of code lengths in lens[] */
this.next = null; /* next available space in codes[] */
this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
this.work = new utils.Buf16(288); /* work area for code table building */
/*
because we don't have pointers in js, we use lencode and distcode directly
as buffers so we don't need codes
*/
//this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
this.distdyn = null; /* dynamic table for distance codes (JS specific) */
this.sane = 0; /* if false, allow invalid distance too far */
this.back = 0; /* bits back of last unprocessed length/lit */
this.was = 0; /* initial length of match */
}
function inflateResetKeep(strm) {
var state;
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
strm.total_in = strm.total_out = state.total = 0;
strm.msg = ''; /*Z_NULL*/
if (state.wrap) { /* to support ill-conceived Java test suite */
strm.adler = state.wrap & 1;
}
state.mode = HEAD;
state.last = 0;
state.havedict = 0;
state.dmax = 32768;
state.head = null/*Z_NULL*/;
state.hold = 0;
state.bits = 0;
//state.lencode = state.distcode = state.next = state.codes;
state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
state.sane = 1;
state.back = -1;
//Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
function inflateReset(strm) {
var state;
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
state.wsize = 0;
state.whave = 0;
state.wnext = 0;
return inflateResetKeep(strm);
}
function inflateReset2(strm, windowBits) {
var wrap;
var state;
/* get the state */
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
/* extract wrap request from windowBits parameter */
if (windowBits < 0) {
wrap = 0;
windowBits = -windowBits;
}
else {
wrap = (windowBits >> 4) + 1;
if (windowBits < 48) {
windowBits &= 15;
}
}
/* set number of window bits, free window if different */
if (windowBits && (windowBits < 8 || windowBits > 15)) {
return Z_STREAM_ERROR;
}
if (state.window !== null && state.wbits !== windowBits) {
state.window = null;
}
/* update state and reset the rest of it */
state.wrap = wrap;
state.wbits = windowBits;
return inflateReset(strm);
}
function inflateInit2(strm, windowBits) {
var ret;
var state;
if (!strm) { return Z_STREAM_ERROR; }
//strm.msg = Z_NULL; /* in case we return an error */
state = new InflateState();
//if (state === Z_NULL) return Z_MEM_ERROR;
//Tracev((stderr, "inflate: allocated\n"));
strm.state = state;
state.window = null/*Z_NULL*/;
ret = inflateReset2(strm, windowBits);
if (ret !== Z_OK) {
strm.state = null/*Z_NULL*/;
}
return ret;
}
function inflateInit(strm) {
return inflateInit2(strm, DEF_WBITS);
}
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
var virgin = true;
var lenfix, distfix; // We have no pointers in JS, so keep tables separate
function fixedtables(state) {
/* build fixed huffman tables if first call (may not be thread safe) */
if (virgin) {
var sym;
lenfix = new utils.Buf32(512);
distfix = new utils.Buf32(32);
/* literal/length table */
sym = 0;
while (sym < 144) { state.lens[sym++] = 8; }
while (sym < 256) { state.lens[sym++] = 9; }
while (sym < 280) { state.lens[sym++] = 7; }
while (sym < 288) { state.lens[sym++] = 8; }
inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
/* distance table */
sym = 0;
while (sym < 32) { state.lens[sym++] = 5; }
inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
/* do this just once */
virgin = false;
}
state.lencode = lenfix;
state.lenbits = 9;
state.distcode = distfix;
state.distbits = 5;
}
/*
Update the window with the last wsize (normally 32K) bytes written before
returning. If window does not exist yet, create it. This is only called
when a window is already in use, or when output has been written during this
inflate call, but the end of the deflate stream has not been reached yet.
It is also called to create a window for dictionary data when a dictionary
is loaded.
Providing output buffers larger than 32K to inflate() should provide a speed
advantage, since only the last 32K of output is copied to the sliding window
upon return from inflate(), and since all distances after the first 32K of
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
function updatewindow(strm, src, end, copy) {
var dist;
var state = strm.state;
/* if it hasn't been done already, allocate space for the window */
if (state.window === null) {
state.wsize = 1 << state.wbits;
state.wnext = 0;
state.whave = 0;
state.window = new utils.Buf8(state.wsize);
}
/* copy state->wsize or less output bytes into the circular window */
if (copy >= state.wsize) {
utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);
state.wnext = 0;
state.whave = state.wsize;
}
else {
dist = state.wsize - state.wnext;
if (dist > copy) {
dist = copy;
}
//zmemcpy(state->window + state->wnext, end - copy, dist);
utils.arraySet(state.window, src, end - copy, dist, state.wnext);
copy -= dist;
if (copy) {
//zmemcpy(state->window, end - copy, copy);
utils.arraySet(state.window, src, end - copy, copy, 0);
state.wnext = copy;
state.whave = state.wsize;
}
else {
state.wnext += dist;
if (state.wnext === state.wsize) { state.wnext = 0; }
if (state.whave < state.wsize) { state.whave += dist; }
}
}
return 0;
}
function inflate(strm, flush) {
var state;
var input, output; // input/output buffers
var next; /* next input INDEX */
var put; /* next output INDEX */
var have, left; /* available input and output */
var hold; /* bit buffer */
var bits; /* bits in bit buffer */
var _in, _out; /* save starting available input and output */
var copy; /* number of stored or match bytes to copy */
var from; /* where to copy match bytes from */
var from_source;
var here = 0; /* current decoding table entry */
var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
//var last; /* parent table entry */
var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
var len; /* length to copy for repeats, bits to drop */
var ret; /* return code */
var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
var opts;
var n; // temporary var for NEED_BITS
var order = /* permutation of code lengths */
[ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
if (!strm || !strm.state || !strm.output ||
(!strm.input && strm.avail_in !== 0)) {
return Z_STREAM_ERROR;
}
state = strm.state;
if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
//--- LOAD() ---
put = strm.next_out;
output = strm.output;
left = strm.avail_out;
next = strm.next_in;
input = strm.input;
have = strm.avail_in;
hold = state.hold;
bits = state.bits;
//---
_in = have;
_out = left;
ret = Z_OK;
inf_leave: // goto emulation
for (;;) {
switch (state.mode) {
case HEAD:
if (state.wrap === 0) {
state.mode = TYPEDO;
break;
}
//=== NEEDBITS(16);
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
state.check = 0/*crc32(0L, Z_NULL, 0)*/;
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = FLAGS;
break;
}
state.flags = 0; /* expect zlib header */
if (state.head) {
state.head.done = false;
}
if (!(state.wrap & 1) || /* check if zlib header allowed */
(((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
strm.msg = 'incorrect header check';
state.mode = BAD;
break;
}
if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
strm.msg = 'unknown compression method';
state.mode = BAD;
break;
}
//--- DROPBITS(4) ---//
hold >>>= 4;
bits -= 4;
//---//
len = (hold & 0x0f)/*BITS(4)*/ + 8;
if (state.wbits === 0) {
state.wbits = len;
}
else if (len > state.wbits) {
strm.msg = 'invalid window size';
state.mode = BAD;
break;
}
state.dmax = 1 << len;
//Tracev((stderr, "inflate: zlib header ok\n"));
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
state.mode = hold & 0x200 ? DICTID : TYPE;
//=== INITBITS();
hold = 0;
bits = 0;
//===//
break;
case FLAGS:
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.flags = hold;
if ((state.flags & 0xff) !== Z_DEFLATED) {
strm.msg = 'unknown compression method';
state.mode = BAD;
break;
}
if (state.flags & 0xe000) {
strm.msg = 'unknown header flags set';
state.mode = BAD;
break;
}
if (state.head) {
state.head.text = ((hold >> 8) & 1);
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = TIME;
/* falls through */
case TIME:
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (state.head) {
state.head.time = hold;
}
if (state.flags & 0x0200) {
//=== CRC4(state.check, hold)
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
hbuf[2] = (hold >>> 16) & 0xff;
hbuf[3] = (hold >>> 24) & 0xff;
state.check = crc32(state.check, hbuf, 4, 0);
//===
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = OS;
/* falls through */
case OS:
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (state.head) {
state.head.xflags = (hold & 0xff);
state.head.os = (hold >> 8);
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = EXLEN;
/* falls through */
case EXLEN:
if (state.flags & 0x0400) {
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.length = hold;
if (state.head) {
state.head.extra_len = hold;
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
}
else if (state.head) {
state.head.extra = null/*Z_NULL*/;
}
state.mode = EXTRA;
/* falls through */
case EXTRA:
if (state.flags & 0x0400) {
copy = state.length;
if (copy > have) { copy = have; }
if (copy) {
if (state.head) {
len = state.head.extra_len - state.length;
if (!state.head.extra) {
// Use untyped array for more convenient processing later
state.head.extra = new Array(state.head.extra_len);
}
utils.arraySet(
state.head.extra,
input,
next,
// extra field is limited to 65536 bytes
// - no need for additional size check
copy,
/*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
len
);
//zmemcpy(state.head.extra + len, next,
// len + copy > state.head.extra_max ?
// state.head.extra_max - len : copy);
}
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
state.length -= copy;
}
if (state.length) { break inf_leave; }
}
state.length = 0;
state.mode = NAME;
/* falls through */
case NAME:
if (state.flags & 0x0800) {
if (have === 0) { break inf_leave; }
copy = 0;
do {
// TODO: 2 or 1 bytes?
len = input[next + copy++];
/* use constant limit because in js we should not preallocate memory */
if (state.head && len &&
(state.length < 65536 /*state.head.name_max*/)) {
state.head.name += String.fromCharCode(len);
}
} while (len && copy < have);
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
if (len) { break inf_leave; }
}
else if (state.head) {
state.head.name = null;
}
state.length = 0;
state.mode = COMMENT;
/* falls through */
case COMMENT:
if (state.flags & 0x1000) {
if (have === 0) { break inf_leave; }
copy = 0;
do {
len = input[next + copy++];
/* use constant limit because in js we should not preallocate memory */
if (state.head && len &&
(state.length < 65536 /*state.head.comm_max*/)) {
state.head.comment += String.fromCharCode(len);
}
} while (len && copy < have);
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
if (len) { break inf_leave; }
}
else if (state.head) {
state.head.comment = null;
}
state.mode = HCRC;
/* falls through */
case HCRC:
if (state.flags & 0x0200) {
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (hold !== (state.check & 0xffff)) {
strm.msg = 'header crc mismatch';
state.mode = BAD;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
}
if (state.head) {
state.head.hcrc = ((state.flags >> 9) & 1);
state.head.done = true;
}
strm.adler = state.check = 0;
state.mode = TYPE;
break;
case DICTID:
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
strm.adler = state.check = zswap32(hold);
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = DICT;
/* falls through */
case DICT:
if (state.havedict === 0) {
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
return Z_NEED_DICT;
}
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
state.mode = TYPE;
/* falls through */
case TYPE:
if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
/* falls through */
case TYPEDO:
if (state.last) {
//--- BYTEBITS() ---//
hold >>>= bits & 7;
bits -= bits & 7;
//---//
state.mode = CHECK;
break;
}
//=== NEEDBITS(3); */
while (bits < 3) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.last = (hold & 0x01)/*BITS(1)*/;
//--- DROPBITS(1) ---//
hold >>>= 1;
bits -= 1;
//---//
switch ((hold & 0x03)/*BITS(2)*/) {
case 0: /* stored block */
//Tracev((stderr, "inflate: stored block%s\n",
// state.last ? " (last)" : ""));
state.mode = STORED;
break;
case 1: /* fixed block */
fixedtables(state);
//Tracev((stderr, "inflate: fixed codes block%s\n",
// state.last ? " (last)" : ""));
state.mode = LEN_; /* decode codes */
if (flush === Z_TREES) {
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
break inf_leave;
}
break;
case 2: /* dynamic block */
//Tracev((stderr, "inflate: dynamic codes block%s\n",
// state.last ? " (last)" : ""));
state.mode = TABLE;
break;
case 3:
strm.msg = 'invalid block type';
state.mode = BAD;
}
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
break;
case STORED:
//--- BYTEBITS() ---// /* go to byte boundary */
hold >>>= bits & 7;
bits -= bits & 7;
//---//
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
strm.msg = 'invalid stored block lengths';
state.mode = BAD;
break;
}
state.length = hold & 0xffff;
//Tracev((stderr, "inflate: stored length %u\n",
// state.length));
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = COPY_;
if (flush === Z_TREES) { break inf_leave; }
/* falls through */
case COPY_:
state.mode = COPY;
/* falls through */
case COPY:
copy = state.length;
if (copy) {
if (copy > have) { copy = have; }
if (copy > left) { copy = left; }
if (copy === 0) { break inf_leave; }
//--- zmemcpy(put, next, copy); ---
utils.arraySet(output, input, next, copy, put);
//---//
have -= copy;
next += copy;
left -= copy;
put += copy;
state.length -= copy;
break;
}
//Tracev((stderr, "inflate: stored end\n"));
state.mode = TYPE;
break;
case TABLE:
//=== NEEDBITS(14); */
while (bits < 14) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
//--- DROPBITS(5) ---//
hold >>>= 5;
bits -= 5;
//---//
state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
//--- DROPBITS(5) ---//
hold >>>= 5;
bits -= 5;
//---//
state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
//--- DROPBITS(4) ---//
hold >>>= 4;
bits -= 4;
//---//
//#ifndef PKZIP_BUG_WORKAROUND
if (state.nlen > 286 || state.ndist > 30) {
strm.msg = 'too many length or distance symbols';
state.mode = BAD;
break;
}
//#endif
//Tracev((stderr, "inflate: table sizes ok\n"));
state.have = 0;
state.mode = LENLENS;
/* falls through */
case LENLENS:
while (state.have < state.ncode) {
//=== NEEDBITS(3);
while (bits < 3) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
//--- DROPBITS(3) ---//
hold >>>= 3;
bits -= 3;
//---//
}
while (state.have < 19) {
state.lens[order[state.have++]] = 0;
}
// We have separate tables & no pointers. 2 commented lines below not needed.
//state.next = state.codes;
//state.lencode = state.next;
// Switch to use dynamic table
state.lencode = state.lendyn;
state.lenbits = 7;
opts = { bits: state.lenbits };
ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
state.lenbits = opts.bits;
if (ret) {
strm.msg = 'invalid code lengths set';
state.mode = BAD;
break;
}
//Tracev((stderr, "inflate: code lengths ok\n"));
state.have = 0;
state.mode = CODELENS;
/* falls through */
case CODELENS:
while (state.have < state.nlen + state.ndist) {
for (;;) {
here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if (here_val < 16) {
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.lens[state.have++] = here_val;
}
else {
if (here_val === 16) {
//=== NEEDBITS(here.bits + 2);
n = here_bits + 2;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
if (state.have === 0) {
strm.msg = 'invalid bit length repeat';
state.mode = BAD;
break;
}
len = state.lens[state.have - 1];
copy = 3 + (hold & 0x03);//BITS(2);
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
}
else if (here_val === 17) {
//=== NEEDBITS(here.bits + 3);
n = here_bits + 3;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
len = 0;
copy = 3 + (hold & 0x07);//BITS(3);
//--- DROPBITS(3) ---//
hold >>>= 3;
bits -= 3;
//---//
}
else {
//=== NEEDBITS(here.bits + 7);
n = here_bits + 7;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
len = 0;
copy = 11 + (hold & 0x7f);//BITS(7);
//--- DROPBITS(7) ---//
hold >>>= 7;
bits -= 7;
//---//
}
if (state.have + copy > state.nlen + state.ndist) {
strm.msg = 'invalid bit length repeat';
state.mode = BAD;
break;
}
while (copy--) {
state.lens[state.have++] = len;
}
}
}
/* handle error breaks in while */
if (state.mode === BAD) { break; }
/* check for end-of-block code (better have one) */
if (state.lens[256] === 0) {
strm.msg = 'invalid code -- missing end-of-block';
state.mode = BAD;
break;
}
/* build code tables -- note: do not change the lenbits or distbits
values here (9 and 6) without reading the comments in inftrees.h
concerning the ENOUGH constants, which depend on those values */
state.lenbits = 9;
opts = { bits: state.lenbits };
ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
// We have separate tables & no pointers. 2 commented lines below not needed.
// state.next_index = opts.table_index;
state.lenbits = opts.bits;
// state.lencode = state.next;
if (ret) {
strm.msg = 'invalid literal/lengths set';
state.mode = BAD;
break;
}
state.distbits = 6;
//state.distcode.copy(state.codes);
// Switch to use dynamic table
state.distcode = state.distdyn;
opts = { bits: state.distbits };
ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
// We have separate tables & no pointers. 2 commented lines below not needed.
// state.next_index = opts.table_index;
state.distbits = opts.bits;
// state.distcode = state.next;
if (ret) {
strm.msg = 'invalid distances set';
state.mode = BAD;
break;
}
//Tracev((stderr, 'inflate: codes ok\n'));
state.mode = LEN_;
if (flush === Z_TREES) { break inf_leave; }
/* falls through */
case LEN_:
state.mode = LEN;
/* falls through */
case LEN:
if (have >= 6 && left >= 258) {
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
inflate_fast(strm, _out);
//--- LOAD() ---
put = strm.next_out;
output = strm.output;
left = strm.avail_out;
next = strm.next_in;
input = strm.input;
have = strm.avail_in;
hold = state.hold;
bits = state.bits;
//---
if (state.mode === TYPE) {
state.back = -1;
}
break;
}
state.back = 0;
for (;;) {
here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if (here_bits <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if (here_op && (here_op & 0xf0) === 0) {
last_bits = here_bits;
last_op = here_op;
last_val = here_val;
for (;;) {
here = state.lencode[last_val +
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((last_bits + here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
//--- DROPBITS(last.bits) ---//
hold >>>= last_bits;
bits -= last_bits;
//---//
state.back += last_bits;
}
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.back += here_bits;
state.length = here_val;
if (here_op === 0) {
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
// "inflate: literal '%c'\n" :
// "inflate: literal 0x%02x\n", here.val));
state.mode = LIT;
break;
}
if (here_op & 32) {
//Tracevv((stderr, "inflate: end of block\n"));
state.back = -1;
state.mode = TYPE;
break;
}
if (here_op & 64) {
strm.msg = 'invalid literal/length code';
state.mode = BAD;
break;
}
state.extra = here_op & 15;
state.mode = LENEXT;
/* falls through */
case LENEXT:
if (state.extra) {
//=== NEEDBITS(state.extra);
n = state.extra;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
//--- DROPBITS(state.extra) ---//
hold >>>= state.extra;
bits -= state.extra;
//---//
state.back += state.extra;
}
//Tracevv((stderr, "inflate: length %u\n", state.length));
state.was = state.length;
state.mode = DIST;
/* falls through */
case DIST:
for (;;) {
here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if ((here_op & 0xf0) === 0) {
last_bits = here_bits;
last_op = here_op;
last_val = here_val;
for (;;) {
here = state.distcode[last_val +
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((last_bits + here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
//--- DROPBITS(last.bits) ---//
hold >>>= last_bits;
bits -= last_bits;
//---//
state.back += last_bits;
}
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.back += here_bits;
if (here_op & 64) {
strm.msg = 'invalid distance code';
state.mode = BAD;
break;
}
state.offset = here_val;
state.extra = (here_op) & 15;
state.mode = DISTEXT;
/* falls through */
case DISTEXT:
if (state.extra) {
//=== NEEDBITS(state.extra);
n = state.extra;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
//--- DROPBITS(state.extra) ---//
hold >>>= state.extra;
bits -= state.extra;
//---//
state.back += state.extra;
}
//#ifdef INFLATE_STRICT
if (state.offset > state.dmax) {
strm.msg = 'invalid distance too far back';
state.mode = BAD;
break;
}
//#endif
//Tracevv((stderr, "inflate: distance %u\n", state.offset));
state.mode = MATCH;
/* falls through */
case MATCH:
if (left === 0) { break inf_leave; }
copy = _out - left;
if (state.offset > copy) { /* copy from window */
copy = state.offset - copy;
if (copy > state.whave) {
if (state.sane) {
strm.msg = 'invalid distance too far back';
state.mode = BAD;
break;
}
// (!) This block is disabled in zlib defaults,
// don't enable it for binary compatibility
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
// Trace((stderr, "inflate.c too far\n"));
// copy -= state.whave;
// if (copy > state.length) { copy = state.length; }
// if (copy > left) { copy = left; }
// left -= copy;
// state.length -= copy;
// do {
// output[put++] = 0;
// } while (--copy);
// if (state.length === 0) { state.mode = LEN; }
// break;
//#endif
}
if (copy > state.wnext) {
copy -= state.wnext;
from = state.wsize - copy;
}
else {
from = state.wnext - copy;
}
if (copy > state.length) { copy = state.length; }
from_source = state.window;
}
else { /* copy from output */
from_source = output;
from = put - state.offset;
copy = state.length;
}
if (copy > left) { copy = left; }
left -= copy;
state.length -= copy;
do {
output[put++] = from_source[from++];
} while (--copy);
if (state.length === 0) { state.mode = LEN; }
break;
case LIT:
if (left === 0) { break inf_leave; }
output[put++] = state.length;
left--;
state.mode = LEN;
break;
case CHECK:
if (state.wrap) {
//=== NEEDBITS(32);
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
// Use '|' instead of '+' to make sure that result is signed
hold |= input[next++] << bits;
bits += 8;
}
//===//
_out -= left;
strm.total_out += _out;
state.total += _out;
if (_out) {
strm.adler = state.check =
/*UPDATE(state.check, put - _out, _out);*/
(state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
}
_out = left;
// NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
if ((state.flags ? hold : zswap32(hold)) !== state.check) {
strm.msg = 'incorrect data check';
state.mode = BAD;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
//Tracev((stderr, "inflate: check matches trailer\n"));
}
state.mode = LENGTH;
/* falls through */
case LENGTH:
if (state.wrap && state.flags) {
//=== NEEDBITS(32);
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (hold !== (state.total & 0xffffffff)) {
strm.msg = 'incorrect length check';
state.mode = BAD;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
//Tracev((stderr, "inflate: length matches trailer\n"));
}
state.mode = DONE;
/* falls through */
case DONE:
ret = Z_STREAM_END;
break inf_leave;
case BAD:
ret = Z_DATA_ERROR;
break inf_leave;
case MEM:
return Z_MEM_ERROR;
case SYNC:
/* falls through */
default:
return Z_STREAM_ERROR;
}
}
// inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
/*
Return from inflate(), updating the total counts and the check value.
If there was no progress during the inflate() call, return a buffer
error. Call updatewindow() to create and/or update the window state.
Note: a memory error from inflate() is non-recoverable.
*/
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
(state.mode < CHECK || flush !== Z_FINISH))) {
if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
state.mode = MEM;
return Z_MEM_ERROR;
}
}
_in -= strm.avail_in;
_out -= strm.avail_out;
strm.total_in += _in;
strm.total_out += _out;
state.total += _out;
if (state.wrap && _out) {
strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
(state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
}
strm.data_type = state.bits + (state.last ? 64 : 0) +
(state.mode === TYPE ? 128 : 0) +
(state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
ret = Z_BUF_ERROR;
}
return ret;
}
function inflateEnd(strm) {
if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
return Z_STREAM_ERROR;
}
var state = strm.state;
if (state.window) {
state.window = null;
}
strm.state = null;
return Z_OK;
}
function inflateGetHeader(strm, head) {
var state;
/* check state */
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
/* save header structure */
state.head = head;
head.done = false;
return Z_OK;
}
function inflateSetDictionary(strm, dictionary) {
var dictLength = dictionary.length;
var state;
var dictid;
var ret;
/* check state */
if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }
state = strm.state;
if (state.wrap !== 0 && state.mode !== DICT) {
return Z_STREAM_ERROR;
}
/* check for correct dictionary identifier */
if (state.mode === DICT) {
dictid = 1; /* adler32(0, null, 0)*/
/* dictid = adler32(dictid, dictionary, dictLength); */
dictid = adler32(dictid, dictionary, dictLength, 0);
if (dictid !== state.check) {
return Z_DATA_ERROR;
}
}
/* copy dictionary to window using updatewindow(), which will amend the
existing dictionary if appropriate */
ret = updatewindow(strm, dictionary, dictLength, dictLength);
if (ret) {
state.mode = MEM;
return Z_MEM_ERROR;
}
state.havedict = 1;
// Tracev((stderr, "inflate: dictionary set\n"));
return Z_OK;
}
exports.inflateReset = inflateReset;
exports.inflateReset2 = inflateReset2;
exports.inflateResetKeep = inflateResetKeep;
exports.inflateInit = inflateInit;
exports.inflateInit2 = inflateInit2;
exports.inflate = inflate;
exports.inflateEnd = inflateEnd;
exports.inflateGetHeader = inflateGetHeader;
exports.inflateSetDictionary = inflateSetDictionary;
exports.inflateInfo = 'pako inflate (from Nodeca project)';
/* Not implemented
exports.inflateCopy = inflateCopy;
exports.inflateGetDictionary = inflateGetDictionary;
exports.inflateMark = inflateMark;
exports.inflatePrime = inflatePrime;
exports.inflateSync = inflateSync;
exports.inflateSyncPoint = inflateSyncPoint;
exports.inflateUndermine = inflateUndermine;
*/
},{"../utils/common":105,"./adler32":107,"./crc32":109,"./inffast":112,"./inftrees":114}],114:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
var utils = require('../utils/common');
var MAXBITS = 15;
var ENOUGH_LENS = 852;
var ENOUGH_DISTS = 592;
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
var CODES = 0;
var LENS = 1;
var DISTS = 2;
var lbase = [ /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
];
var lext = [ /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
];
var dbase = [ /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577, 0, 0
];
var dext = [ /* Distance codes 0..29 extra */
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
28, 28, 29, 29, 64, 64
];
module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
{
var bits = opts.bits;
//here = opts.here; /* table entry for duplication */
var len = 0; /* a code's length in bits */
var sym = 0; /* index of code symbols */
var min = 0, max = 0; /* minimum and maximum code lengths */
var root = 0; /* number of index bits for root table */
var curr = 0; /* number of index bits for current table */
var drop = 0; /* code bits to drop for sub-table */
var left = 0; /* number of prefix codes available */
var used = 0; /* code entries in table used */
var huff = 0; /* Huffman code */
var incr; /* for incrementing code, index */
var fill; /* index for replicating entries */
var low; /* low bits for current root entry */
var mask; /* mask for low root bits */
var next; /* next available space in table */
var base = null; /* base value table to use */
var base_index = 0;
// var shoextra; /* extra bits table to use */
var end; /* use base and extra for symbol > end */
var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
var extra = null;
var extra_index = 0;
var here_bits, here_op, here_val;
/*
Process a set of code lengths to create a canonical Huffman code. The
code lengths are lens[0..codes-1]. Each length corresponds to the
symbols 0..codes-1. The Huffman code is generated by first sorting the
symbols by length from short to long, and retaining the symbol order
for codes with equal lengths. Then the code starts with all zero bits
for the first code of the shortest length, and the codes are integer
increments for the same length, and zeros are appended as the length
increases. For the deflate format, these bits are stored backwards
from their more natural integer increment ordering, and so when the
decoding tables are built in the large loop below, the integer codes
are incremented backwards.
This routine assumes, but does not check, that all of the entries in
lens[] are in the range 0..MAXBITS. The caller must assure this.
1..MAXBITS is interpreted as that code length. zero means that that
symbol does not occur in this code.
The codes are sorted by computing a count of codes for each length,
creating from that a table of starting indices for each length in the
sorted table, and then entering the symbols in order in the sorted
table. The sorted table is work[], with that space being provided by
the caller.
The length counts are used for other purposes as well, i.e. finding
the minimum and maximum length codes, determining if there are any
codes at all, checking for a valid set of lengths, and looking ahead
at length counts to determine sub-table sizes when building the
decoding tables.
*/
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
for (len = 0; len <= MAXBITS; len++) {
count[len] = 0;
}
for (sym = 0; sym < codes; sym++) {
count[lens[lens_index + sym]]++;
}
/* bound code lengths, force root to be within code lengths */
root = bits;
for (max = MAXBITS; max >= 1; max--) {
if (count[max] !== 0) { break; }
}
if (root > max) {
root = max;
}
if (max === 0) { /* no symbols to code at all */
//table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
//table.bits[opts.table_index] = 1; //here.bits = (var char)1;
//table.val[opts.table_index++] = 0; //here.val = (var short)0;
table[table_index++] = (1 << 24) | (64 << 16) | 0;
//table.op[opts.table_index] = 64;
//table.bits[opts.table_index] = 1;
//table.val[opts.table_index++] = 0;
table[table_index++] = (1 << 24) | (64 << 16) | 0;
opts.bits = 1;
return 0; /* no symbols, but wait for decoding to report error */
}
for (min = 1; min < max; min++) {
if (count[min] !== 0) { break; }
}
if (root < min) {
root = min;
}
/* check for an over-subscribed or incomplete set of lengths */
left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= count[len];
if (left < 0) {
return -1;
} /* over-subscribed */
}
if (left > 0 && (type === CODES || max !== 1)) {
return -1; /* incomplete set */
}
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0;
for (len = 1; len < MAXBITS; len++) {
offs[len + 1] = offs[len] + count[len];
}
/* sort symbols by length, by symbol order within each length */
for (sym = 0; sym < codes; sym++) {
if (lens[lens_index + sym] !== 0) {
work[offs[lens[lens_index + sym]]++] = sym;
}
}
/*
Create and fill in decoding tables. In this loop, the table being
filled is at next and has curr index bits. The code being used is huff
with length len. That code is converted to an index by dropping drop
bits off of the bottom. For codes where len is less than drop + curr,
those top drop + curr - len bits are incremented through all values to
fill the table with replicated entries.
root is the number of index bits for the root table. When len exceeds
root, sub-tables are created pointed to by the root entry with an index
of the low root bits of huff. This is saved in low to check for when a
new sub-table should be started. drop is zero when the root table is
being filled, and drop is root when sub-tables are being filled.
When a new sub-table is needed, it is necessary to look ahead in the
code lengths to determine what size sub-table is needed. The length
counts are used for this, and so count[] is decremented as codes are
entered in the tables.
used keeps track of how many table entries have been allocated from the
provided *table space. It is checked for LENS and DIST tables against
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
the initial root table size constants. See the comments in inftrees.h
for more information.
sym increments through all symbols, and the loop terminates when
all codes of length max, i.e. all codes, have been processed. This
routine permits incomplete codes, so another loop after this one fills
in the rest of the decoding tables with invalid code markers.
*/
/* set up for code type */
// poor man optimization - use if-else instead of switch,
// to avoid deopts in old v8
if (type === CODES) {
base = extra = work; /* dummy value--not used */
end = 19;
} else if (type === LENS) {
base = lbase;
base_index -= 257;
extra = lext;
extra_index -= 257;
end = 256;
} else { /* DISTS */
base = dbase;
extra = dext;
end = -1;
}
/* initialize opts for loop */
huff = 0; /* starting code */
sym = 0; /* starting code symbol */
len = min; /* starting code length */
next = table_index; /* current table to fill in */
curr = root; /* current table index bits */
drop = 0; /* current bits to drop from code for index */
low = -1; /* trigger new sub-table when len > root */
used = 1 << root; /* use root table entries */
mask = used - 1; /* mask for comparing low */
/* check available table space */
if ((type === LENS && used > ENOUGH_LENS) ||
(type === DISTS && used > ENOUGH_DISTS)) {
return 1;
}
/* process all codes and make table entries */
for (;;) {
/* create table entry */
here_bits = len - drop;
if (work[sym] < end) {
here_op = 0;
here_val = work[sym];
}
else if (work[sym] > end) {
here_op = extra[extra_index + work[sym]];
here_val = base[base_index + work[sym]];
}
else {
here_op = 32 + 64; /* end of block */
here_val = 0;
}
/* replicate for those indices with low len bits equal to huff */
incr = 1 << (len - drop);
fill = 1 << curr;
min = fill; /* save offset to next table */
do {
fill -= incr;
table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
} while (fill !== 0);
/* backwards increment the len-bit code huff */
incr = 1 << (len - 1);
while (huff & incr) {
incr >>= 1;
}
if (incr !== 0) {
huff &= incr - 1;
huff += incr;
} else {
huff = 0;
}
/* go to next symbol, update count, len */
sym++;
if (--count[len] === 0) {
if (len === max) { break; }
len = lens[lens_index + work[sym]];
}
/* create new sub-table if needed */
if (len > root && (huff & mask) !== low) {
/* if first time, transition to sub-tables */
if (drop === 0) {
drop = root;
}
/* increment past last table */
next += min; /* here min is 1 << curr */
/* determine length of next table */
curr = len - drop;
left = 1 << curr;
while (curr + drop < max) {
left -= count[curr + drop];
if (left <= 0) { break; }
curr++;
left <<= 1;
}
/* check for enough space */
used += 1 << curr;
if ((type === LENS && used > ENOUGH_LENS) ||
(type === DISTS && used > ENOUGH_DISTS)) {
return 1;
}
/* point entry in root table to sub-table */
low = huff & mask;
/*table.op[low] = curr;
table.bits[low] = root;
table.val[low] = next - opts.table_index;*/
table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
}
}
/* fill in remaining table entry if code is incomplete (guaranteed to have
at most one remaining entry, since if the code is incomplete, the
maximum code length that was allowed to get this far is one bit) */
if (huff !== 0) {
//table.op[next + huff] = 64; /* invalid code marker */
//table.bits[next + huff] = len - drop;
//table.val[next + huff] = 0;
table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
}
/* set return parameters */
//opts.table_index += used;
opts.bits = root;
return 0;
};
},{"../utils/common":105}],115:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
module.exports = {
2: 'need dictionary', /* Z_NEED_DICT 2 */
1: 'stream end', /* Z_STREAM_END 1 */
0: '', /* Z_OK 0 */
'-1': 'file error', /* Z_ERRNO (-1) */
'-2': 'stream error', /* Z_STREAM_ERROR (-2) */
'-3': 'data error', /* Z_DATA_ERROR (-3) */
'-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
'-5': 'buffer error', /* Z_BUF_ERROR (-5) */
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
};
},{}],116:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
var utils = require('../utils/common');
/* Public constants ==========================================================*/
/* ===========================================================================*/
//var Z_FILTERED = 1;
//var Z_HUFFMAN_ONLY = 2;
//var Z_RLE = 3;
var Z_FIXED = 4;
//var Z_DEFAULT_STRATEGY = 0;
/* Possible values of the data_type field (though see inflate()) */
var Z_BINARY = 0;
var Z_TEXT = 1;
//var Z_ASCII = 1; // = Z_TEXT
var Z_UNKNOWN = 2;
/*============================================================================*/
function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
// From zutil.h
var STORED_BLOCK = 0;
var STATIC_TREES = 1;
var DYN_TREES = 2;
/* The three kinds of block type */
var MIN_MATCH = 3;
var MAX_MATCH = 258;
/* The minimum and maximum match lengths */
// From deflate.h
/* ===========================================================================
* Internal compression state.
*/
var LENGTH_CODES = 29;
/* number of length codes, not counting the special END_BLOCK code */
var LITERALS = 256;
/* number of literal bytes 0..255 */
var L_CODES = LITERALS + 1 + LENGTH_CODES;
/* number of Literal or Length codes, including the END_BLOCK code */
var D_CODES = 30;
/* number of distance codes */
var BL_CODES = 19;
/* number of codes used to transfer the bit lengths */
var HEAP_SIZE = 2 * L_CODES + 1;
/* maximum heap size */
var MAX_BITS = 15;
/* All codes must not exceed MAX_BITS bits */
var Buf_size = 16;
/* size of bit buffer in bi_buf */
/* ===========================================================================
* Constants
*/
var MAX_BL_BITS = 7;
/* Bit length codes must not exceed MAX_BL_BITS bits */
var END_BLOCK = 256;
/* end of block literal code */
var REP_3_6 = 16;
/* repeat previous bit length 3-6 times (2 bits of repeat count) */
var REPZ_3_10 = 17;
/* repeat a zero length 3-10 times (3 bits of repeat count) */
var REPZ_11_138 = 18;
/* repeat a zero length 11-138 times (7 bits of repeat count) */
/* eslint-disable comma-spacing,array-bracket-spacing */
var extra_lbits = /* extra bits for each length code */
[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
var extra_dbits = /* extra bits for each distance code */
[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
var extra_blbits = /* extra bits for each bit length code */
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
var bl_order =
[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
/* eslint-enable comma-spacing,array-bracket-spacing */
/* The lengths of the bit length codes are sent in order of decreasing
* probability, to avoid transmitting the lengths for unused bit length codes.
*/
/* ===========================================================================
* Local data. These are initialized only once.
*/
// We pre-fill arrays with 0 to avoid uninitialized gaps
var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
var static_ltree = new Array((L_CODES + 2) * 2);
zero(static_ltree);
/* The static literal tree. Since the bit lengths are imposed, there is no
* need for the L_CODES extra codes used during heap construction. However
* The codes 286 and 287 are needed to build a canonical tree (see _tr_init
* below).
*/
var static_dtree = new Array(D_CODES * 2);
zero(static_dtree);
/* The static distance tree. (Actually a trivial tree since all codes use
* 5 bits.)
*/
var _dist_code = new Array(DIST_CODE_LEN);
zero(_dist_code);
/* Distance codes. The first 256 values correspond to the distances
* 3 .. 258, the last 256 values correspond to the top 8 bits of
* the 15 bit distances.
*/
var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1);
zero(_length_code);
/* length code for each normalized match length (0 == MIN_MATCH) */
var base_length = new Array(LENGTH_CODES);
zero(base_length);
/* First normalized length for each code (0 = MIN_MATCH) */
var base_dist = new Array(D_CODES);
zero(base_dist);
/* First normalized distance for each code (0 = distance of 1) */
function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
this.static_tree = static_tree; /* static tree or NULL */
this.extra_bits = extra_bits; /* extra bits for each code or NULL */
this.extra_base = extra_base; /* base index for extra_bits */
this.elems = elems; /* max number of elements in the tree */
this.max_length = max_length; /* max bit length for the codes */
// show if `static_tree` has data or dummy - needed for monomorphic objects
this.has_stree = static_tree && static_tree.length;
}
var static_l_desc;
var static_d_desc;
var static_bl_desc;
function TreeDesc(dyn_tree, stat_desc) {
this.dyn_tree = dyn_tree; /* the dynamic tree */
this.max_code = 0; /* largest code with non zero frequency */
this.stat_desc = stat_desc; /* the corresponding static tree */
}
function d_code(dist) {
return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
}
/* ===========================================================================
* Output a short LSB first on the stream.
* IN assertion: there is enough room in pendingBuf.
*/
function put_short(s, w) {
// put_byte(s, (uch)((w) & 0xff));
// put_byte(s, (uch)((ush)(w) >> 8));
s.pending_buf[s.pending++] = (w) & 0xff;
s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
}
/* ===========================================================================
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
function send_bits(s, value, length) {
if (s.bi_valid > (Buf_size - length)) {
s.bi_buf |= (value << s.bi_valid) & 0xffff;
put_short(s, s.bi_buf);
s.bi_buf = value >> (Buf_size - s.bi_valid);
s.bi_valid += length - Buf_size;
} else {
s.bi_buf |= (value << s.bi_valid) & 0xffff;
s.bi_valid += length;
}
}
function send_code(s, c, tree) {
send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
}
/* ===========================================================================
* Reverse the first len bits of a code, using straightforward code (a faster
* method would use a table)
* IN assertion: 1 <= len <= 15
*/
function bi_reverse(code, len) {
var res = 0;
do {
res |= code & 1;
code >>>= 1;
res <<= 1;
} while (--len > 0);
return res >>> 1;
}
/* ===========================================================================
* Flush the bit buffer, keeping at most 7 bits in it.
*/
function bi_flush(s) {
if (s.bi_valid === 16) {
put_short(s, s.bi_buf);
s.bi_buf = 0;
s.bi_valid = 0;
} else if (s.bi_valid >= 8) {
s.pending_buf[s.pending++] = s.bi_buf & 0xff;
s.bi_buf >>= 8;
s.bi_valid -= 8;
}
}
/* ===========================================================================
* Compute the optimal bit lengths for a tree and update the total bit length
* for the current block.
* IN assertion: the fields freq and dad are set, heap[heap_max] and
* above are the tree nodes sorted by increasing frequency.
* OUT assertions: the field len is set to the optimal bit length, the
* array bl_count contains the frequencies for each bit length.
* The length opt_len is updated; static_len is also updated if stree is
* not null.
*/
function gen_bitlen(s, desc)
// deflate_state *s;
// tree_desc *desc; /* the tree descriptor */
{
var tree = desc.dyn_tree;
var max_code = desc.max_code;
var stree = desc.stat_desc.static_tree;
var has_stree = desc.stat_desc.has_stree;
var extra = desc.stat_desc.extra_bits;
var base = desc.stat_desc.extra_base;
var max_length = desc.stat_desc.max_length;
var h; /* heap index */
var n, m; /* iterate over the tree elements */
var bits; /* bit length */
var xbits; /* extra bits */
var f; /* frequency */
var overflow = 0; /* number of elements with bit length too large */
for (bits = 0; bits <= MAX_BITS; bits++) {
s.bl_count[bits] = 0;
}
/* In a first pass, compute the optimal bit lengths (which may
* overflow in the case of the bit length tree).
*/
tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
n = s.heap[h];
bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
if (bits > max_length) {
bits = max_length;
overflow++;
}
tree[n * 2 + 1]/*.Len*/ = bits;
/* We overwrite tree[n].Dad which is no longer needed */
if (n > max_code) { continue; } /* not a leaf node */
s.bl_count[bits]++;
xbits = 0;
if (n >= base) {
xbits = extra[n - base];
}
f = tree[n * 2]/*.Freq*/;
s.opt_len += f * (bits + xbits);
if (has_stree) {
s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
}
}
if (overflow === 0) { return; }
// Trace((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
/* Find the first bit length which could increase: */
do {
bits = max_length - 1;
while (s.bl_count[bits] === 0) { bits--; }
s.bl_count[bits]--; /* move one leaf down the tree */
s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
s.bl_count[max_length]--;
/* The brother of the overflow item also moves one step up,
* but this does not affect bl_count[max_length]
*/
overflow -= 2;
} while (overflow > 0);
/* Now recompute all bit lengths, scanning in increasing frequency.
* h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
* lengths instead of fixing only the wrong ones. This idea is taken
* from 'ar' written by Haruhiko Okumura.)
*/
for (bits = max_length; bits !== 0; bits--) {
n = s.bl_count[bits];
while (n !== 0) {
m = s.heap[--h];
if (m > max_code) { continue; }
if (tree[m * 2 + 1]/*.Len*/ !== bits) {
// Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
tree[m * 2 + 1]/*.Len*/ = bits;
}
n--;
}
}
}
/* ===========================================================================
* Generate the codes for a given tree and bit counts (which need not be
* optimal).
* IN assertion: the array bl_count contains the bit length statistics for
* the given tree and the field len is set for all tree elements.
* OUT assertion: the field code is set for all tree elements of non
* zero code length.
*/
function gen_codes(tree, max_code, bl_count)
// ct_data *tree; /* the tree to decorate */
// int max_code; /* largest code with non zero frequency */
// ushf *bl_count; /* number of codes at each bit length */
{
var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */
var code = 0; /* running code value */
var bits; /* bit index */
var n; /* code index */
/* The distribution counts are first used to generate the code values
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
*/
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
// "inconsistent bit counts");
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
for (n = 0; n <= max_code; n++) {
var len = tree[n * 2 + 1]/*.Len*/;
if (len === 0) { continue; }
/* Now reverse the bits */
tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);
//Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
// n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
}
}
/* ===========================================================================
* Initialize the various 'constant' tables.
*/
function tr_static_init() {
var n; /* iterates over tree elements */
var bits; /* bit counter */
var length; /* length value */
var code; /* code value */
var dist; /* distance index */
var bl_count = new Array(MAX_BITS + 1);
/* number of codes at each bit length for an optimal tree */
// do check in _tr_init()
//if (static_init_done) return;
/* For some embedded targets, global variables are not initialized: */
/*#ifdef NO_INIT_GLOBAL_POINTERS
static_l_des
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment